How to solve an ODE equation in Simulink? - matlab

I'm studying a report about roll angle estimation. In the article I found the following scheme:
where vx is the longitudinal vehicle velocity, psi_dot is the horizontal yaw rate, lambda_dot is the roll rate and lambda is the roll angle. I need to verify this method on matlab/simulink
Here is my simulation:
I chose random values (reasonable, I hope) for vx and yaw rate, while lambda_dot is similar to the one used in the article. The MATLAB function block contains this code:
function lambda = fcn(vx, yaw_r)
g = 9.81;
lambda0 = -(vx*yaw_r)/g;
tspan = [0 40];
[t,lambda_var] = ode45(#(t,lambda_var) tan(0.9*lambda_var)*cos(lambda_var), tspan, lambda0);
t0 = 0:0.01:40;
lambda1 = zeros(1,4001);
lambda1 = interp1(t,lambda_var,t0);
lambda = [t0' lambda1'];
I used the equations I found in the paper in the lambda0 expression and in the [t,lambda_var] one. The "lambda_d" block contains a two-column vector, the first one with time values and the second one with the corresponding lambda_dot values. Also lambda (output of fcn block) should be defined in the same way, as you can see in the code above.
I thought the problem was the scope: if I run this simulation, I do not have a single signal plotted on the scope. Instead, I get as many signals as the size of the vector which contains something like 4000 values (0.01 seconds of sampling time on 40 seconds tot).
But I understand now that the problem is the ODE equation in the Simulink block. I need to write it in that block, because the two inputs will be variable in the next step. The equation I need to solve is:
tan(0.9*lambda)*cos(lambda) = -vx*yawrate /g
EDIT: I changed the main question according to your comments.

Related

Matlab ode15s: postive dx/dt, decreasing x(t)

In my script, I call the ODE solver ode15s which solves a system of 9 ODE's. A simplified structure of the code:
[t, x] = ode15s(#odefun,tini:tend,options)
...
function dx = odefun(t,x)
r1=... %rate equation 1, dependent on x(1) and x(3) for example
r2=... %rate equation 2
...
dx(1) = r1+r2-...
dx(2) = ...
...
dx(9) = ...
end
When reviewing the results I was curious why the profile of one state variable was increasing at a certain range. In order to investigate this, I used conditional debugging within the ode function so I could check all the rates and all the dx(i)/dt equations.
To my big surprise, I found out that the differential equation of the decreasing state variable was positive. So, I simulated multiple rounds with the F5-debug function, and noticed that indeed the state variable consistently decreased, while the dx(i)/dt would always remain positive.
Can anyone explain me how this is possible?
It is not advisable to pause the integration in the middle like that and examine the states and derivatives. ode15s does not simply step through the solution like a naive ODE solver. It makes a bunch of calls to the ODE function with semi-random states in order to compute higher-order derivatives. These states are not solutions to system but are used internally by ode15s to get a more accurate solution later.
If you want to get the derivative of your system at particular times, first compute the entire solution and then call your ODE function with slices of that solution at the times you are interested in.

Obtaining the constant that makes the integral equal to zero in Matlab

I'm trying to code a MATLAB program and I have arrived at a point where I need to do the following. I have this equation:
I must find the value of the constant "Xcp" (greater than zero), that is the value that makes the integral equal to zero.
In order to do so, I have coded a loop in which the the value of Xcp advances with small increments on each iteration and the integral is performed and checked if it's zero, if it reaches zero the loop finishes and the Xcp is stored with this value.
However, I think this is not an efficient way to do this task. The running time increases a lot, because this loop is long and has the to perform the integral and the integration limits substitution every time.
Is there a smarter way to do this in Matlab to obtain a better code efficiency?
P.S.: I have used conv() to multiply both polynomials. Since cl(x) and (x-Xcp) are both polynomials.
EDIT: Piece of code.
p = [1 -Xcp]; % polynomial (x-Xcp)
Xcp=0.001;
i=1;
found=false;
while(i<=x_te && found~=true) % Xcp is upper bounded by x_te
int_cl_p = polyint(conv(cl,p));
Cm_cp=(-1/c^2)*diff(polyval(int_cl_p,[x_le,x_te]));
if(Cm_cp==0)
found=true;
else
Xcp=Xcp+0.001;
end
end
This is the code I used to run this section. Another problem is that I have to do it for different cases (different cl functions), for this reason the code is even more slow.
As far as I understood, you need to solve the equation for X_CP.
I suggest using symbolic solver for this. This is not the most efficient way for large polynomials, but for polynomials of degree 20 it takes less than 1 second. I do not claim that this solution is fastest, but this provides generic solution to the problem. If your polynomial does not change every iteration, then you can use this generic solution many times and not spend time for calculating integral.
So, generic symbolic solution in terms of xLE and xTE is obtained using this:
syms xLE xTE c x xCP
a = 1:20;
%//arbitrary polynomial of degree 20
cl = sum(x.^a.*randi([-100,100],1,20));
tic
eqn = -1/c^2 * int(cl * (x-xCP), x, xLE, xTE) == 0;
xCP = solve(eqn,xCP);
pretty(xCP)
toc
Elapsed time is 0.550371 seconds.
You can further use matlabFunction for finding the numerical solutions:
xCP_numerical = matlabFunction(xCP);
%// we then just plug xLE = 10 and xTE = 20 values into function
answer = xCP_numerical(10,20)
answer =
19.8038
The slight modification of the code can allow you to use this for generic coefficients.
Hope that helps
If you multiply by -1/c^2, then you can rearrange as
and integrate however you fancy. Since c_l is a polynomial order N, if it's defined in MATLAB using the usual notation for polyval, where coefficients are stored in a vector a such that
then integration is straightforward:
MATLAB code might look something like this
int_cl_p = polyint(cl);
int_cl_x_p = polyint([cl 0]);
X_CP = diff(polyval(int_cl_x_p,[x_le,x_te]))/diff(polyval(int_cl_p,[x_le,x_te]));

Error in `ode45` matlab

The main function of ode is given as follows.
function dxdt = state( t,x,vgth,vgval1,vgval2)
vgval=vgval1+vgval2;
p=1;
k=10^0.7;
window1=1-((2*x)-1).^(2*p);
dxdt=k*(vgval-vgth+1.2)*window1;
end
The Script is given below.
step=0.01;
t = 0:step:10;
f=4*0.157;
vgate1= #(t) abs(5*sin(2*f*t)).*heaviside(5-t);
vgate2=#(t) -abs(5*sin(2*f*t)).*heaviside(t-5);
The Function call part is as follows.
x0=0.01;
vgth=1.9;
[t,x] = ode45(#(t,x) state1 (t,x,vgth,vgate1(t),vgate2(t)), t, x0);
plot(t,x)
Issue
It gives me error when I use the negative sign with vgate2 .
It works fine If i remove the negative sign of vgate2.
Desired Result
I want my plot with a negative sign in vgate2.Actually I want to use two positive sine pulses and two negative sign pulses.That is why I have used negative value of vgate2.
ODE integrators of order p expect the differential equation to be p+2 times continuously differentiable with decent sized derivatives.
Any deviation from that is seen as "stiffness" by step-size adaptation strategies, and reacted to by increasingly violent reductions in step-size. Any kink or jump in the lower derivatives is seen as similar to wild oscillations in the higher derivative, throwing the step-size adaptor for a loop.
However, if the integration is stopped directly at an event and then restarted using the values there as initial values, the integrator does not "see" the event, and thus has no need to react to it.

Finite Difference Time Domain (FTDT) method for 1D EM Wave

I have attempted to write a code in order to solve the following coupled partial differential EM wave equations:
The code employs finite difference time domain using the Yee algorithm which can be read about in the following two online documents:
http://www.eecs.wsu.edu/~schneidj/ufdtd/ufdtd.pdf
http://www.eecs.wsu.edu/~schneidj/ufdtd/chap3.pdf
I want my source at the left hand side boundary to be a sinusoidal wave with parameters as such:
Ex(0,t) = E0 sin(2πft) for 0 ≤ t ≤ 1/f
The code updates the electric and magnetic field properties of the wave with each loop.
My initial code is as follows:
%FDTD Yee algorithm to solve coupled EM wave equations
clear
clc
G=50; %Specify size of the grid
f=10^3; %choose initial frequency of wave in hertz
e=1; %specify permitivity and permeability (normalised condition)
u=1;
Nt=150; %time steps
E0=1; %Electric Field initial amplitude
%Specify step sizes using corruant condition
c=3*10^8;
dx=0.01;
dt=dx/2*c;
%make constant terms
c1=-dt/(dx*e);
c2=-dt/(dx*u);
%create vgector place holders
Ex=zeros(1,G);
Hy=zeros(1,G);
%create updating loop
M=moviein(Nt);
for t=1:Nt
% Spatial Ex
for k=2:G-1
Ex(k)=Ex(k)+c1*(Hy(k)-Hy(k-1));
end
Ex(G)=0; %PEC boundary condition
%E Source at LHS boundary
Ex(1)=E0*sin(2*pi*f*t);
%Spatial Hy
for n=1:G-1
Hy(n)=Hy(n)+c2*(Ex(n)-Ex(n+1));
end
Hy(G)=0; %PMC boundary condition
plot(Ex);
M(:,t) = getframe;
end
movie(M,1);
Basically I want to create an updating movie which shows the sinusoidal wave propagating to the right hand side boundary coded as a perfect electrical conductor; therefore reflecting the wave, and then propagating back to the left hand side boundary coded as a perfect insulator; absorbing the wave.
The problems I have are as follows:
1) I'm not sure how to properly implement my desired source. It don't appear to be purely sinusoidal.
2) The wave I've coded begins to propagate but it quickly disappears for the majority of the simulation. I do not know why this is occurring
3) I do not know much about running a movie simulation and the plot oscillates as the solution is being run. How can I stop this?
Your wave attenuates because the diference equations are not correctly implemented; instead:
Ex(k)=Ex(k)+c1*(Hy(k)-Hy(k-1));
you should use
Ex1(k)=Ex(k)+c1*(Hy(k)-Hy(k-1));
and instead of:
Hy(n)=Hy(n)+c2*(Ex(n)-Ex(n+1));
you should use:
Hy1(n)=Hy(n)+c2*(Ex(n)-Ex(n+1));
and, in the end of the loop update the current "dataframe":
Hy = Hy1;
Ey = Ey1;
(you should take care also the boundary conditions).
If you want a fixed plot frame that doesn't change when your data changes, create first a axis where you can plot into, with a defined xmin/max and ymin/max, see http://www.mathworks.com/help/matlab/ref/axis.html
You should set the Courant number closer to 1 say 0.995. Thus delta_t = 0.995*delta_x/c.
Also assuming delta_x is in METRIC units then e and u should be in metric units.
I do not know about the specific coding language used but in c or c++ there is no need for intermediate variable Ey1 etc.
Also there should be at least 10 samples per wavelength for accuracy ( preferably 60). Thus wavelength = 60*delta_x and thus the frequency equals roughly of the order 10 to power of 9. Also, I think the sinesoidal source should be E0 * sin(2* pi * f * t * delta_t). You need to adjust your constants, and try it again

How to have square wave in Matlab symbolic equation

My project require me to use Matlab to create a symbolic equation with square wave inside.
I tried to write it like this but to no avail:
syms t;
a=square(t);
Input arguments must be 'double'.
What can i do to solve this problem? Thanks in advance for the helps offered.
here are a couple of general options using floor and sign functions:
f=#(A,T,x0,x) A*sign(sin((2*pi*(x-x0))/T));
f=#(A,T,x0,x) A*(-1).^(floor(2*(x-x0)/T));
So for example using the floor function:
syms x
sqr=2*floor(x)-floor(2*x)+1;
ezplot(sqr, [-2, 2])
Here is something to get you started. Recall that we can express a square wave as a Fourier Series expansion. I won't bother you with the details, but you can represent any periodic function as a summation of cosines and sines (à la #RTL). Without going into the derivation, this is the closed-form equation for a square wave of frequency f, with a peak-to-peak amplitude of 2 (i.e. it goes from -1 to 1). Recall that the frequency is the amount of cycles per seconds. Therefore, f = 1 means that we repeat our square wave every second.
Basically, what you have to do is code up the first line of the equation... but how in the world would you do that? Welcome to the world of the Symbolic Math Toolbox. What we will need to do before hand is declare what our frequency is. Let's assume f = 1 for now. With the Symbolic Math Toolbox, you can define what are considered as mathematics variables within MATLAB. After, MATLAB has a whole suite of tools that you can use to evaluate functions that rely on these variables. A good example would be if you want to use this to define a closed-form solution of a function f(x). You can then use diff to differentiate and see what the derivative is. Try it yourself:
syms x;
f = x^4;
df = diff(f);
syms denotes that you are declaring anything coming after the statement to be a mathematical variable. In this case, x is just that. df should now give you 4x^3. Cool eh? In any case, let's get back to our problem at hand. We see that there are in fact two variables in the periodic square function that need to be defined: t and k. Once we do this, we need to create our function that is inside the summation first. We can do this by:
syms t k;
f = 1; %//Define frequency here
funcSum = (sin(2*pi*(2*k - 1)*f*t) / (2*k - 1));
That settles that problem... now how do we encapsulate this into an infinite sum!? The sum command in MATLAB assumes that we have a finite array to sum over. If you want to symbolically sum over a function, we must use the symsum function. We usually call it like this:
funcOut = symsum(func, v, start, finish);
func is the function we wish to sum over. v is the summation variable that we wish to use to index in the sum. In our case, that's k. start is the beginning of the sum, which is 1 in our case, and finish is where we wish to finish up our summation. In our case, that's infinity, and so MATLAB has a special keyword called Inf to denote that. Therefore:
xsquare = (4/pi) * symsum(funcSum, k, 1, Inf);
xquare now contains your representation of a square wave defined in terms of the Symbolic Math Toolbox. Now, if you want to plot your square wave and see if we have this right. We can do the following. Let's go between -3 <= t <= 3. As such, you would do something like this:
tVector = -3 : 0.01 : 3; %// Choose a step size of 0.01
yout = subs(xsquare, t, tVector);
You will notice though that there will be some values that are NaN. The reason why is because right at a multiple of the period (T = 1, 2, 3, ...), the behaviour is undefined as the derivative right at these points is undefined. As such, we can fill this in using either 1 or -1. Let's just choose 1 for now. Also, because the Fourier Series is generally a complex-valued function, and the square-wave is purely real, the output of this function will actually give you a complex-valued vector. As such, simply chop off the complex parts to get the real parts only:
yout = real(double(yout)); %// To cast back to double.
yout(isnan(yout)) = 1;
plot(tVector, yout);
You'll get something like:
You could also do this the ezplot way by doing: ezplot(xsquare). However, you'll see that at the points where the wave repeats itself, we get NaN values and so there is a disconnect between the high peak and low peak.
Note:
Natan's solution is much more elegant. I was still writing this post by the time he put something up. Either way, I wanted to give a more signal processing perspective to how to do this. Go Fourier!
A Fourier series for the square wave of unit amplitude is:
alpha + 2/Pi*sum(sin( n * Pi*alpha)/n*cos(n*theta),n=1..infinity)
Here is a handy trick:
cos(n*theta) = Re( exp( I * n * theta))
and
1/n*exp(I*n*theta) = I*anti-derivative(exp(I*n*theta),theta)
Put it all together: pull the anti-derivative ( or integral ) operator out of the sum, and you get a geometric series. Then integrate and finally take the real part.
Result:
squarewave=
alpha+ 1/Pi*Re(I*ln((1-exp(I*(theta+Pi*alpha)))/(1-exp(I*(theta-Pi*alpha)))))
I tried it in MAPLE and it works great! (probably not very practical though)