I'd like to create a Matlab plot of propeller angular velocity in terms of applied current. The point is, this requires combining two interdependent sets of data.
Firstly, drag coefficient c_d depends on angular velocity omega (I have no formula, just data) as seen on the plot below - the characteristics c_d(omega) could be easily linearised as c_d(omega) = p*omega + p_0.
Secondly, omega depends not only on applied current i, but also on the drag coefficient c_d(omega).
A script that solves the case, where c_d is constant below. It must be somehow possible to join those two using Matlab commands. Thanks for any help.
%%Lookup table for drag coefficient c_d
c_d_lookup = [248.9188579 0.036688351; %[\omega c_d]
280.2300647 0.037199094;
308.6091183 0.037199094;
338.6636881 0.03779496;
365.8908244 0.038305703;
393.9557188 0.039156941;
421.9158934 0.039667683;
452.2846224 0.040348674;
480.663676 0.041199911;
511.032405 0.042051149;
538.9925796 0.042561892;
567.2669135 0.043242882;
598.4734005 0.043668501;
624.1297405 0.044264368;
651.9851954 0.044604863;
683.6105614 0.045200729];
subplot(2,1,1)
plot(c_d_lookup(:,1), c_d_lookup(:,2))
title('This is how c_d depends on \omega')
ylabel('c_d')
xlabel('\omega [rad/s]')
%%Calculate propeller angular speed in terms of applied current. omega
%%depends on c_d, which in turn depends on omega. The formula is:
% omega(i) = sqrt(a*i / (b * c_d(omega)))
% Where:
% i - applied current
% omega - propeller angular velocity
% a,b - coefficients
i = [1:15];
a = 0.0718;
b = 3.8589e-005;
%If c_d was constant, I'd do:
omega_i = sqrt(a .* i / (b * 0.042));
subplot(2,1,2)
plot(i, omega_i)
ylabel({'Propeller ang. vel.', '\omega [rad/s]'})
xlabel('Applied current i[A]')
title('Propeller angular velocity in terms of applied current')
EDIT:
Trying to follow bdecaf's solution. So I created a function c_d_find, like so:
function c_d = c_d_find(omega, c_d_lookup)
c_d = interp1(c_d_lookup(:,1), c_d_lookup(:,2), omega, 'linear', 'extrap');
end
I don't know anything about Matlab function handles, but seem to understand the idea... In Matlab command window I typed:
f = #(omega) omega - sqrt(a .* i / (b * c_d_find(omega, c_d_lookup)))
which I hope created the correct function handle. What do I do next? Executing the below doesn't work:
>> omega_consistent = fzero(f,0)
??? Operands to the || and && operators must be convertible to logical scalar
values.
Error in ==> fzero at 333
elseif ~isfinite(fx) || ~isreal(fx)
hmmm...
Wonder if I understand correctly - but looks like you are looking for a consistent solution.
Your equations don't look to complicated I would outline the solution like this:
Write a function function c_d = c_d_find(omega) that does some interpolation or so
make a function handle like f = #(omega) omega - sqrt(a .* i / (b * c_d_find(omega))) - this is zero for consistent omega
calculate a consistent omega with omega_consistent =fzero(f,omega_0)
Related
I have this 2nd order ODE to solve in Matlab:
(a + f(t))·(dx/dt)·(d²x/dt²) + g(t) + ((h(t) + i(t)·(d²x/dt² > b·(c-x)))·(dx/dt) + j(t))·(dx/dt)² + k(t)·(t > d) = 0
where
a,b,c,d are known constants
f(t),g(t),h(t),i(t),j(t),k(t) are known functions dependent on t
x is the position
dx/dt is the velocity
d²x/dt² is the acceleration
and notice the two conditions that
i(t) is introduced in the equation if (d²x/dt² > b·(c-x))
k(t) is introduced in the equation if (t > d)
So, the problem could be solved with a similar structure in Matlab as this example:
[T,Y] = ode45(#(t,y) [y(2); 'the expression of the acceleration'], tspan, [x0 v0]);
where
T is the time vector, Y is the vector of position (column 1 as y(1)) and velocity (column 2 as y(2)).
ode45 is the ODE solver, but another one could be used.
tspan,x0,v0 are known.
the expression of the acceleration means an expression for d²x/dt², but here comes the problem, since it is inside the condition for i(t) and 'outside' at the same time multiplying (a + f(t))·(dx/dt). So, the acceleration cannot be written in matlab as d²x/dt² = something
Some issues that could help:
once the condition (d²x/dt² > b·(c-x)) and/or (t > d) is satisfied, the respective term i(t) and/or k(t) will be introduced until the end of the determined time in tspan.
for the condition (d²x/dt² > b·(c-x)), the term d²x/dt² could be written as the difference of velocities, like y(2) - y(2)', if y(2)' is the velocity of the previous instant, divided by the step-time defined in tspan. But I do not know how to access the previous value of the velocity during the solving of the ODE
Thank you in advanced !
First of all, you should reduce your problem to a first-order differential equation, by substituting dx/dt with a dynamical variable for the velocity.
This is something you have to do anyway for solving the ODE and this way you do not need to access the previous values of the velocity.
As for realising your conditions, just modify the function you pass to ode45 to account for this.
For this purpose you can use that d²x/dt² is in the right-hand side of your ODE.
Keep in mind though that ODE solvers do not like discontinuities, so you may want to smoothen the step or just restart the solver with a different function, once the condition is met (credit to Steve).
The second conditional term k(t)*(t>d) should be simple enough to implement, so I'll pass over that.
I would split up your equation into two part:
F1(t,x,x',x'') := (a+f(t))x'x'' + g(t) + (h(t)x'+j(t))x'' + k(t)(t>d),
F2(t,x,x',x'') := F1(t,x,x',x'') + i(t)x'x'',
where prime denote time derivatives. As suggested in this other answer
[...] or just restart the solver with a different function
you could solve the ODE F1 for t \in [t0, t1] =: tspan. Next, you'd find the first time tstar where x''> b(c-x) and the values x(tstar) and x'(tstar), and solve F2 for t \in [tstar,t1] with x(tstar), x'(tstar) as starting conditions.
Having said all that, the proper implementation of this should be using events, as suggested in LutzL's comment.
So, I should use something that looks like this:
function [value,isterminal,direction] = ODE_events(t,y,b,c)
value = d²x/dt² - b*(c-y(1)); % detect (d²x/dt² > b·(c-x)), HOW DO I WRITE d²x/dt² HERE?
isterminal = 0; % continue integration
direction = 0; % zero can be approached in either direction
and then include in the file (.m), where my ode is, this:
refine = 4; % I do not get exactly how this number would affect the results
options = odeset('Events',#ODE_events,'OutputFcn',#odeplot,'OutputSel',1, 'Refine',refine);
[T,Y] = ode45(#(t,y) [y(2); ( 1/(a + f(t))*(y(2)))*( - g(t) - ((h(t) + i(t))·(y(2)) - j(t)·(y(2))² - k(t)*(t > d)) ], tspan, [x0 v0], options);
How do I handle i(t)? because i(t)*(d²x/dt² > b*(c-y(1))))*(y(2)) has to be included somehow.
Thank you again
MATLAB gives me the same expression back.
Here's my code
syms tau alpha phi
f = sign(alpha*cos(phi))*(abs(alpha*cos(phi)) - 2.5*(alpha*cos(phi))^2);
F=f*sin(phi);
int(F,phi, [pi/2, acos(tau/alpha)])
I did plug in the values of variables tau and alpha but it still gives me the same expression back. Anyone know how to solve it? Or some other numerical method which could give me answer in these symbols? Will wolfram-mathematica help?
Mathematica
Integrate[(Sign[alpha*Cos[phi]]*(Abs[alpha*Cos[phi]] - 5/2*
(alpha*Cos[phi])^2))*Sin[phi], {phi, Pi/2, ArcCos[tau/alpha]}]
(* ConditionalExpression[-(tau^2/(2 alpha)) + (5 alpha^3 Abs[tau]^3)/
(6 Abs[alpha]^4), ArcCos[tau/alpha] \[Element] Reals] *)
Thus the result is the expression inside the ConditionalExpression if the ArcCos[tau/alpha] is an element of the reals.
If you could specify something like -1<=tau/alpha<=1 && 0<=tau then it can provide an even simpler result, (tau^2 (-3 + 5 tau))/(6 alpha)
Please verify this before you depend on it.
Something like
syms tau alpha phi
f = sign(alpha*cos(phi))*(abs(alpha*cos(phi)) - 2.5*(alpha*cos(phi))^2);
will just generate another symbolic variable. Your goal however is to specify a symbolic function and for that you have to specify the function arguments:
syms tau alpha phi
f(tau,alpha,phi) = sign(alpha*cos(phi))*(abs(alpha*cos(phi)) - 2.5*(alpha*cos(phi))^2);
F(tau,alpha,phi) =f*sin(phi);
Then you can calculate the integral with
R = int(F,phi, [pi/2, acos(tau/alpha)])
Since your integral is dependent on tau and alpha, R is again a symbolic function R(tau,alpha).
Alternatively you could just specify the arguments at the end, e.g.
syms tau alpha phi
f = sign(alpha*cos(phi))*(abs(alpha*cos(phi)) - 2.5*(alpha*cos(phi))^2);
F=f*sin(phi);
R(tau,alpha) = int(F,phi, [pi/2, acos(tau/alpha)])
But I personally find that less clean.
Note that you could also write F directly as
F(tau,alpha,phi) = sin(phi)*(sign(alpha*cos(phi))*(abs(alpha*cos(phi)) - 2.5*(alpha*cos(phi))^2));
I have this function:
x[n] = (1/2) ^ n * u[n] + (-1/3) ^ n * u[n]
I need to do two things with this using MATLAB:
Find it's z-transform.
Plot it's poles and zeros.
I am using the following code:
syms n;
f = (1/2)^n + (-1/3)^n;
F = ztrans(f);
I get the z-transform in the F variable, but I can't see how to create it's pole-zero plot. I am using the built-in function pzmap (pzmap(F);), but it doesn't seem to work with the output of ztrans(f).
What am I doing wrong? Do I need to change the z-transform into some other form like like a transfer function model or a zero-pole gain model? If so, can someone explain how that can be done using the output of ztrans(f)?
The first bit of code you gave uses symbolic math to solve for the z-transform. You'll need to convert the output to a discrete-time model supported by the Control System toolbox.
syms n;
f = (1/2)^n + (-1/3)^n;
F = ztrans(f)
returns z/(z - 1/2) + z/(z + 1/3). You can optionally use collect to convert this
F2 = collect(F)
to (12*z^2 - z)/(6*z^2 - z - 1). Then you'll want to find the coefficients of the polynomials in the numerator and denominator and create a discrete-time transfer function object with tf for a particular sampling period:
[num,den] = numden(F2);
Ts = 0.1; % Sampling period
H = tf(sym2poly(num),sym2poly(den),Ts)
Then pzmap(H) will produce a plot like this:
The problem in the link:
can be integrated analytically and the answer is 4, however I'm interested in integrating it numerically using Matlab, because it's similar in form to a problem that I can't integrate analytically. The difficulty in the numerical integration arises because the function in the two inner integrals is a function of x,y and z and z can't be factored out.
by no means, this is elegant. hope someone can make better use of matlab functions than me. i have tried the brute force way just to practice numerical integration. i have tried to avoid the pole in the inner integral at z=0 by exploiting the fact that it is also being multiplied by z. i get 3.9993. someone must get better solution by using something better than trapezoidal rule
function []=sofn
clear all
global x y z xx yy zz dx dy
dx=0.05;
x=0:dx:1;
dy=0.002;
dz=0.002;
y=0:dy:1;
z=0:dz:2;
xx=length(x);
yy=length(y);
zz=length(z);
s1=0;
for i=1:zz-1
s1=s1+0.5*dz*(z(i+1)*exp(inte1(z(i+1)))+z(i)*exp(inte1(z(i))));
end
s1
end
function s2=inte1(localz)
global y yy dy
if localz==0
s2=0;
else
s2=0;
for j=1:yy-1
s2=s2+0.5*dy*(inte2(y(j),localz)+inte2(y(j+1),localz));
end
end
end
function s3=inte2(localy,localz)
global x xx dx
s3=0;
for k=1:xx-1
s3=s3+0.5*dx*(2/(localy+localz));
end
end
Well, this is strange, because on the poster's similar previous question I claimed this can't be done, and now after having looked at Guddu's answer I realize its not that complicated. What I wrote before, that a numerical integration results in a number but not a function, is true – but beside the point: One can just define a function that evaluates the integral for every given parameter, and this way effectively one does have a function as a result of a numerical integration.
Anyways, here it goes:
function q = outer
f = #(z) (z .* exp(inner(z)));
q = quad(f, eps, 2);
end
function qs = inner(zs)
% compute \int_0^1 1 / (y + z) dy for given z
qs = nan(size(zs));
for i = 1 : numel(zs)
z = zs(i);
f = #(y) (1 ./ (y + z));
qs(i) = quad(f, 0 , 1);
end
end
I applied the simplification suggested by myself in a comment, eliminating x. The function inner calculates the value of the inner integral over y as a function of z. Then the function outer computes the outer integral over z. I avoid the pole at z = 0 by letting the integration run from eps instead of 0. The result is
4.00000013663955
inner has to be implemented using a for loop because a function given to quad needs to be able to return its value simultaneously for several argument values.
We have an equation similar to the Fredholm integral equation of second kind.
To solve this equation we have been given an iterative solution that is guaranteed to converge for our specific equation. Now our only problem consists in implementing this iterative prodedure in MATLAB.
For now, the problematic part of our code looks like this:
function delta = delta(x,a,P,H,E,c,c0,w)
delt = #(x)delta_a(x,a,P,H,E,c0,w);
for i=1:500
delt = #(x)delt(x) - 1/E.*integral(#(xi)((c(1)-c(2)*delt(xi))*ms(xi,x,a,P,H,w)),0,a-0.001);
end
delta=delt;
end
delta_a is a function of x, and represent the initial value of the iteration. ms is a function of x and xi.
As you might see we want delt to depend on both x (before the integral) and xi (inside of the integral) in the iteration. Unfortunately this way of writing the code (with the function handle) does not give us a numerical value, as we wish. We can't either write delt as two different functions, one of x and one of xi, since xi is not defined (until integral defines it). So, how can we make sure that delt depends on xi inside of the integral, and still get a numerical value out of the iteration?
Do any of you have any suggestions to how we might solve this?
Using numerical integration
Explanation of the input parameters: x is a vector of numerical values, all the rest are constants. A problem with my code is that the input parameter x is not being used (I guess this means that x is being treated as a symbol).
It looks like you can do a nesting of anonymous functions in MATLAB:
f =
#(x)2*x
>> ff = #(x) f(f(x))
ff =
#(x)f(f(x))
>> ff(2)
ans =
8
>> f = ff;
>> f(2)
ans =
8
Also it is possible to rebind the pointers to the functions.
Thus, you can set up your iteration like
delta_old = #(x) delta_a(x)
for i=1:500
delta_new = #(x) delta_old(x) - integral(#(xi),delta_old(xi))
delta_old = delta_new
end
plus the inclusion of your parameters...
You may want to consider to solve a discretized version of your problem.
Let K be the matrix which discretizes your Fredholm kernel k(t,s), e.g.
K(i,j) = int_a^b K(x_i, s) l_j(s) ds
where l_j(s) is, for instance, the j-th lagrange interpolant associated to the interpolation nodes (x_i) = x_1,x_2,...,x_n.
Then, solving your Picard iterations is as simple as doing
phi_n+1 = f + K*phi_n
i.e.
for i = 1:N
phi = f + K*phi
end
where phi_n and f are the nodal values of phi and f on the (x_i).