How to debug this Matlab code to model glider descent? - matlab

I have this Matlab project but for some reason I just cannot stop thinking about it because I could not get it to work.
Objective:
This is a MATLAB script that would calculate the change of pressure, temperature and density of a glider that is being dropped from 10000 feet. As it falls, we want to use those new values calculated and then plugged in a function that has 4 equations that need to be differentiated at every point using ode45 as well as the new values of P T and Rho.
Here is the main code:
% HouseKeeping:
clc
clear all
close all
% Constants:
S = 232; % ft^2
Cd0 = 0.02;
K = 0.07;
W = 11000; % lbf
Cl_max = sqrt(Cd0/K);
Cd_max = 2*K*Cl_max^2;
Rho_10000 = .001756; % slugs/ ft^3
%Initial conditions:
t = 0; % Sec
x = 0; % ft
h = 10000; % ft
v = sqrt((2*W)/(Rho_10000*S*Cl_max)); %ft/s
gamma = -Cd_max/Cl_max;
% Find Endurance:
V_RD= sqrt((2*W)/(S* Rho_10000* sqrt(3*Cd0/K)));
RD= V_RD/((sqrt(3*Cd0/K))/(2*Cd0)) ; % ft/s
Endurcance= h/RD; % 958.3515 sec
% Sea Level values:
TSL = 518.69; % Rankine
PSL = 2116.199414; % lbs/ft^2
RhoSL = 0.0023769; % slugs/ft^3
while h > 0
tspan = [t t+1];
i=1;
X = [x;h;v;gamma;Rho_10000];
Time(i)= t;
% Calling ODE45:
[F] = ode45(# D,tspan, X)
% Hight Varying Parameters:
T = TSL - 0.00356616*h;
P = (1.137193514E-11)*(T)^5.2560613;
Rho = (RhoSL * TSL / PASL)*(P / T);
a = 49.0214 * (T)^.5;
H_Del(i) = (-Cd_max/Cl_max)*(plotted_x(i))+10000;
V_Del(i) = sqrt((2*W)/(Rho*S*Cl_max));
Gamma_Del(i) = -Cd_max/Cl_max;
i= i+1;
X = [ x ; H_Del(i); V_Del(i); Gamma_Del(i); Rho];
end
% Plots:
%1
figure (1)
plot(F(:,1),'-r',F(:,3),'-b')
title('Velocity vs Distance');
xlabel('x (ft)');
ylabel('v (ft/s)');
%2
Figure (2)
plot(F(:,1),'-r',F(:,2),'-b')
title('Altitude vs Distance ');
xlabel('x (ft)');
ylabel('h (ft)');
%3
figure (3)
plot(F(:,1),'-r',F(:,4),'-b')
title('Gamma vs Distance');
xlabel('x (ft)');
ylabel('Gamma (rad)');
%4
figure (4)
plot(t,'-r',F(:,3),'-b')
title('Velocity vs Time');
xlabel(' t (s)');
ylabel('v (ft/s)');
%5
figure (5)
plot(t,'-r',F(:,1),'-b')
title(' Distance vs Time ');
xlabel('t (s)');
ylabel('x (ft)');
%6
figure (6)
plot(t,'-r',F(:,4),'-b')
title('Gamma vs Time ');
xlabel('t (s)');
ylabel('Gamma (rad)');
%7
figure (7)
plot(t,'-r',F(:,3),'-b')
title('Velocity vs Time');
xlabel('t (s)');
ylabel('V (ft/s)');
Here is the Function
function [F] = D(X)
% Constants:
S = 232; % ft^2
Cd0 = 0.02;
K = 0.07;
W = 11000; % lbf
Cl_max = sqrt(Cd0/K);
Cd_max = 2*K*Cl_max^2;
Rho_10000 = .001756; % slugs/ ft^3
% Initial conditions:
t = 0; % Sec
x = 0; % ft
h = 10000; % ft
v = sqrt((2*W)/(Rho_10000*S*Cl_max)); % ft/s
gamma = -Cd_max/Cl_max;
g= 32.2; % ft/s^2
% Equations:
X_Pr = X(3)*cos(X(4));
H_Pr = X(3)*sin(X(4));
V_Pr = (-32.2./W)*(0.5*X(5)*Cd_max*S*X(3)^2 + W*sin(X(4)));
G_Pr = (32.2./(W*X(3)))*(0.5*X(5)*Cl_max*S*X(3)^2 - W*cos(X(4)));
F = [X_Pr;H_Pr;V_Pr;G_Pr];
I am not very good with Matlab but I did my very best! I went to my professors for help but they said they were too busy. I even stalked every senior I knew and they all said they did not know how to do it. My next project will be assigned soon and I think that if I cannot do this then I would not be able to do the next one.

Your code produces the following error:
Error using main>D
Too many input arguments.
This means that ode45 tries to call your provided function D with too many input arguments. You should check the desired odefun format in the ode45 documentation: dydt = odefun(t,y)
So, you should change your function declaration of D to
function [F] = D(t, X)
This should solve your first problem, but a following error pops up:
D returns a vector of length 4, but the length of initial conditions
vector is 5. The vector returned by D and the initial conditions
vector must have the same number of elements.
Again, you should check the ode45 documentation. Your function should return the derivatives of all your input variables X: F = dX/dt. You should also return the derivate of the fifth element Rho_10000.
Next, I got some error about undefined variables such as PASL. Probably because you did not post your full code.
Besides of the errors, you should really check your code again. You have written an infinite while loop while h > 0. You never change h in the loop, nor you use the output of ode45 in your loop. Furthermore you always overwrite your i and X value at the beginning of the loop, which is probably not what you want.
This is not a full answer to your question, but I hope you will be able to continue and post smaller, well defined problems, instead of one big problem which is very difficult to answer completely.

Related

Negative values obtained in the solution of the 1D advection-dispersion equation using FD method

I am trying to solve the 1D ADE
This is my code so far:
clc; clear; close all
%Input parameters
Ao = 1; %Initial value
L = 0.08; %Column length [m]
nx = 40; %spatial gridpoints
dx = L/nx; %Length step size [m]
T = 20/24; %End time [days]
nt = 100; %temporal gridpoints
dt = T/nt; %Time step size [days]
Vel = dx/dt; %Velocity in each cell [m/day]
alpha = 0.002; %Dispersivity [m]
De = alpha*Vel; % Dispersion coeff. [m2/day]
%Gridblocks
x = 0:dx:L;
t = 0:dt:T;
%Initial and boundary conditions
f = #(x) x; % initial cond.
% boundary conditions
g1 = #(t) Ao;
g2 = #(t) 0;
%Initialization
A = zeros(nx+1, nt+1);
A(:,1) = f(x);
A(1,:) = g1(t);
gamma = dt/(dx^2);
beta = dt/dx;
% Implementation of the explicit method
for j= 1:nt-1 % Time Loop
for i= 2:nx-1 % Space Loop
A(i,j+1) = (A(i-1,j))*(Vel*beta + De*gamma)...
+ A(i,j)*(1-2*De*gamma-Vel*beta) + A(i+1,j)*(De*gamma);
end
% Insert boundary conditions for i = 1 and i = N
A(2,j+1) = A(1,j)*(Vel*beta + De*gamma) + A(2,j)*(1-2*De*gamma-Vel*beta) + A(3,j)*(De*gamma);
A(nx,j+1) = A(nx-1,j)*(Vel*beta + 2*De*gamma) + A(nx,j)*(1-2*De*gamma-Vel*beta)+ (2*De*gamma*dx*g2(t));
end
figure
plot(t, A(end,:), 'r*', 'MarkerSize', 2)
title('A Vs time profile (Using FDM)')
xlabel('t'),ylabel('A')
Now, I have been able to solve the problem using MATLAB’s pdepe function (see plot), but I am trying to compare the result with the finite difference method (implemented in the code above). I am however getting negative values of the dependent variable, but I am not sure what exactly I could be doing wrong. I therefore will really appreciate if anyone can help me out here. Many thanks in anticipation.
PS: I can post the code I used for the pdepe if anyone would like to see it.

MATLAB's lsim() vs for-loop Simulation // Different results for the same system

I've spent quite some time trying to simulate a simple SISO system using two approaches:
1) Using lsim() in MATLAB
2) By writing down the difference equations myself and iterate over them in a loop.
I was never able to get the same simulation results from both approaches, and I have no idea what I am doing wrong.
I stacked my code in a single m-file so it's easier to follow. Here is the code:
function main()
clear all
clc
simulateUsing_lsim()
simulateUsing_loop()
end
%%%%%% Simulating using lsim %%%%%%%
function simulateUsing_lsim()
% Define the continuous-time closed-loop system
P = getContPlant();
[Kp,Ki,Kd] = get_PIDgains();
C = pid(Kp,Ki,Kd);
clSys_cont = feedback(C*P,1);
% Define the discrete-time closed-loop system
hk = get_sampling_time();
clSys_disc = c2d(clSys_cont,hk);
% Generate the reference signal and the time vector
[r,t] = getReference(hk);
%% Simulate and plot using lsim
figure
lsim(clSys_disc,r,t)
%% Finding and plotting the error
y = lsim(clSys_disc,r);
e = r - y;
figure
p = plot(t,e,'b--');
set(p,'linewidth',2)
legend('error')
xlabel('Time (seconds)')
ylabel('error')
% xlim([-.1 10.1])
end
%%%%%% Simulating using loop iteration (difference equations) %%%%%%%
function simulateUsing_loop()
% Get the cont-time ol-sys
P = getContPlant();
% Get the sampling time
hk = get_sampling_time();
% Get the disc-time ol-sys in SS representation
P_disc = ss(c2d(P,hk));
Ad = P_disc.A;
Bd = P_disc.B;
Cd = P_disc.C;
% Get the PID gains
[Kp,Ki,Kd] = get_PIDgains();
% Generate the reference signal and the time vector
[r,t] = getReference(hk);
%% Perform the system simulation
x = [0 0]'; % Set initial states
e = 0; % Set initial errors
integral_sum = 0; % Set initial integral part value
for i=2:1:length(t)
% Calculate the output signal "y"
y(:,i) = Cd*x;
% Calculate the error "e"
e(:,i) = y(:,i) - r(i);
% Calculate the control signal vector "u"
integral_sum = integral_sum + Ki*hk*e(i);
u(:,i) = Kp*e(i) + integral_sum + (1/hk)*Kd*(e(:,i)-e(:,i-1));
% Saturation. Limit the value of u withing the range [-tol tol]
% tol = 100;
% if abs(u(:,i)) > tol
% u(:,i) = tol * abs(u(:,i))/u(:,i);
% else
% end
% Calculate the state vector "x"
x = Ad*x + Bd*u(:,i); % State transitions to time n
end
%% Subplots
figure
plot(t,y,'b',t,r,'g--')
%% Plotting the error
figure
p = plot(t,e,'r');
set(p,'linewidth',2)
legend('error')
xlabel('Time (seconds)')
ylabel('error')
end
function P = getContPlant()
s = tf('s');
P = 1/(s^2 + 10*s + 20);
end
function [Kp,Ki,Kd] = get_PIDgains()
Kp = 350;
Ki = 300;
Kd = 50;
end
function hk = get_sampling_time()
hk = 0.01;
end
function [r,t] = getReference(hk)
[r,t] = gensig('square',4,10,hk);
end
I got the plant model P and its PID controller from this page (see equation 10), where the system is simulated against a step reference and the result looks pretty much exactly like the lsim() result (just for a single step peak).
However, the result of simulating the system using lsim() is this:
whereas, using the for loop, I got this performance:
I would highly appreciate any help or clarification why I am getting different results.

MATLAB - passing a sinusoidal forcing function to ode45

I'm new to Matlab and am really struggling even to get to grips with the basics.
I've got a function, myspring, that solves position and velocity of a mass/spring system with damping and a driving force. I can specify values for the spring stiffness (k), damping coefficient (c), and mass (m), in the command window prior to running ode45. What I am unable to do is to define a forcing function (even something simple like g = sin(t)) and use that as the forcing function, rather than having it written into the myspring function.
Can anyone help? Here's my function:
function pdot = myspring(t,p,c,k,m)
w = sqrt(k/m);
g = sin(t); % This is the forcing function
pdot = zeros(size(p));
pdot(1) = p(2);
pdot(2) = g - c*p(2) - (w^2)*p(1);
end
and how I'm using it in the command window:
>> k = 2; c = 2; m = 4;
>> tspan = linspace(0,10,100);
>> x0 = [1 0];
>> [t,x] = ode45(#(t,p)myspring(t,p,c,k,m),tspan,x0);
That works, but what I want should look something like this (I imagine):
function pdot = myspring(t,p,c,k,m,g)
w = sqrt(k/m);
pdot = zeros(size(p));
pdot(1) = p(2);
pdot(2) = g - c*p(2) - (w^2)*p(1);
end
Then
g = sin(t);
[t,x] = ode45(#(t,p)myspring(t,p,c,k,m,g),tspan,x0);
But what I get is this
In an assignment A(:) = B, the number of elements in A and B must be the same.
Error in myspring (line 7)
pdot(2) = g - c*p(2) - (w^2)*p(1);
Error in #(t,p)myspring(t,p,c,k,m,g)
Error in odearguments (line 87)
f0 = feval(ode,t0,y0,args{:}); % ODE15I sets args{1} to yp0.
Error in ode45 (line 115)
odearguments(FcnHandlesUsed, solver_name, ode, tspan, y0, options, varargin);
Horchler, thank you for the reply. I can do as you suggested and it works. I am now faced with another problem that I hope you could advise me on.
I have a script that calculates the force on a structure due to wave interaction using Morison's equation. I gave it an arbitrary time span to begin with. I would like to use the force F that script calculates as the input driving force to myspring. Here is my Morison script:
H = 3.69; % Wave height (m)
A = H/2; % Wave amplitude (m)
Tw = 9.87; % Wave period (s)
omega = (2*pi)/Tw; % Angular frequency (rad/s)
lambda = 128.02; % Wavelength (m)
k = (2*pi)/lambda; % Wavenumber (1/m)
dw = 25; % Water depth (m)
Cm = 2; % Mass coefficient (-)
Cd = 0.7; % Drag coefficient (-)
rho = 1025; % Density of water (kg/m^3)
D = 3; % Diameter of structure (m)
x = 0; % Fix the position at x = 0 for simplicity
t = linspace(0,6*pi,n); % Define the vector t with n time steps
eta = A*cos(k*x - omega*t); % Create the surface elevation vector with size equal to t
F_M = zeros(1,n); % Initiate an inertia force vector with same dimension as t
F_D = zeros(1,n); % Initiate a drag force vector with same dimension as t
F = zeros(1,n); % Initiate a total force vector with same dimension as t
fun_inertia = #(z)cosh(k*(z+dw)); % Define the inertia function to be integrated
fun_drag = #(z)(cosh(k*(z+dw)).*abs(cosh(k*(z+dw)))); % Define the drag function to be integrated
for i = 1:n
F_D(i) = abs(((H*pi)/Tw) * (1/sinh(k*dw)) * cos(k*x - omega*t(i))) * ((H*pi)/Tw) * (1/sinh(k*dw)) * cos(k*x - omega*t(i)) * integral(fun_drag,-dw,eta(i));
F_M(i) = (Cm*rho*pi*(D^2)/4) * ((2*H*pi^2)/(Tw^2)) * (1/(sin(k*dw))) * sin(k*x - omega*t(i)) * integral(fun_inertia,-dw,eta(i));
F(i) = F_D(i) + F_M(i);
end
Any further advice would be much appreciated.
You can't pre-calculate your forcing function. It depends on time, which ode45 determines. You need to define g as a function and pass a handle to it into your integration function:
...
g = #(t)sin(t);
[t,x] = ode45(#(t,p)myspring(t,p,c,k,m,g),tspan,x0);
And then call it I n your integration function, passing in the current time:
...
pdot(2) = g(t) - c*p(2) - (w^2)*p(1);
...

Solving ODEs with Matlab, with varying Parameters

Lets say I have a simple logistic equation
dx/dt = 2ax(1 - x/N)
where N is the carrying capacity, a is some growth rate, and both a and N are parameters I'd like to vary.
So what I want to do is to plot a 3D graph of my fixed point and the two parameters.
I understand how to find a fixed point of a single parameter.
Here is my sample code
function xprime = MyLogisticFunction(t,X) %% The ODE
% Parameters
N = 10 % Carrying Capacity
a = 0.5 % Growth Rate
x1prime = 2*a*X(1)*(1 - X(1)/N );
xprime = [x1prime ]';
end
Next my solver
% Initial Number
x0 = 0.4;
%Time Window
tspan=[0 100];
[t,x]=ode45(#MyLogisticFunction,tspan,x0);
clf
x(end,1) % This gives me the fixed point for the parameters above.
So my real question is, how do I put a for loop across two functions, that allows me to vary a and N, so that I can plot out a 3D graph of a and N and my fixed point x*.
I've tried combining both functions into one .m file but it does not seem to work
You need to pass the parameters to your function:
function xprime = MyLogisticFunction(t,X,a,N) %% The ODE
% Parameters (passed as function arguments)
% N = 10 % Carrying Capacity
% a = 0.5 % Growth Rate
x1prime = 2*a*X(1)*(1 - X(1)/N );
xprime = [x1prime ]';
end
and then when you call the ode solver:
% Initial Number
x0 = 0.4;
%Time Window
tspan=[0 100];
a = 0.1:0.1:1; % or whatever
N = 1:10; % or whatever
x_end = zeros(length(a),length(N));
for ii = 1:length(a)
for jj = 1:length(N)
[t,x]=ode45(#(t,X)MyLogisticFunction(t,X,a(ii),N(jj)),tspan,x0);
x_end(ii,jj) = x(end,1);
end
end

Matlab plot in loop error

I am creating figures in a for loop. The figure is a 2D mesh plot, which is supposed to be updated every iteration. The value to be plotted in a 200x200 array.
My problem is: It seems the calculation is running every iteration, but the plot is always the first one created, no matter I just plot or save to file.
Here is my code:
x = 1:200;
y = x;
for i = 1:100000
c = calculate(stuff, c); % value to be created, nothing to do with x and y
h = figure;
mesh(x,y,c);
saveas(h, sprintf('FIG%d.jpg',i);
drawnow; % did not work with or without this command
close(h);
end
First, thank you for all your inputs and suggestions! I didn't expect to get so many help within such a short time!
Then, I can answer some of the confusions here.
To Daniel: yes the c is changing. The program is calculating c based on its previous value. And there is sufficient step for c to change.
To R.Schifini: I tried pause(.1) but it didn't help unfortunately
To Andrew: thanks for pointing it. The complete program is attached now. And as to Daniel, the program calculate the value of c based on its previous values.
To The-Duck: I tried clf(h, 'reset') but unfortunately it didn't help.
Complete code:
Main program: please refer to wikipedia for the physical equation if you are interested
http://en.wikipedia.org/wiki/Cahn%E2%80%93Hilliard_equation
% Program to calculate composition evolution for nucleation and growth
% by solving Cahn-Hilliard equation - Time dependent non-linear
% differential equation
% Parameter
sig = 0.1; % J/m^2
delta = 10E-9; % m
D = 1E-9; %m^2/s
A = 10*sig/delta; % J/m
K = 3*sig*delta; % J/m^3
M = D/(2*A); % m^2/s
N = 200; % mesh size
dt = 1E-12; %s
h = delta/10;
% Rng control
r = -1+2.*rand(N);
beta = 1E-3;
n = 10000;
% initialization
c0 = zeros(200);
c0 = c0+ 0.1+beta.*r;
c = c0;
x = h.*linspace(-N/2,N/2,N);
y=x;
% Iteration
for i = 1:n
LP_c = laplacian(c,h);
d_f = A*(4*(c.^3)-6*(c.^2)+2*c);
sub = d_f - (2*K)*LP_c;
LP_RHS = laplacian(sub,h);
RHS = M*LP_RHS;
c = c + dt.*RHS;
% Save image every 2000 steps
% if ( i==1000 || i==10000 || i==100000)
% h = mesh(x,y,c);
% pause(.1);
% saveas(h, sprintf('FIG%d.jpg',i));
% clf(h,'reset');
% end
end
%h = figure;
mesh(x,y,c);
Laplacian function:
function LP_c = laplacian(c,h)
v1 = circshift(c,[0 -1]);
v2 = circshift(c,[0 1]);
v3 = circshift(c,[-1 0]);
v4 = circshift(c,[1 0]);
LP_c = (v1+v2+v3+v4-4.*c)./(h^2);
end
Result:
You can see the commented part in main program is for plotting periodically. They all give the same plots for each iteration. I tried the current OR version, also tried if ( mod(i,2000) == 0) to plot more pics. There is no difference. Shown:
However, if I comment out the periodic plotting, just run the program for different values of n, I got different plots, and they obey physical laws (evolving structure), shown in time order
Therefore I excluded the possibility that c might not update itself. It has to be some misuse of the plotting function of matlab. Or maybe some memory issue?
An interesting point I discovered during edition session: If I put the command h = figure in front of the loop and plot after the loop end, like this:
h = figure;
% Iteration
for i = 1:n
LP_c = laplacian(c,h);
d_f = A*(4*(c.^3)-6*(c.^2)+2*c);
sub = d_f - (2*K)*LP_c;
LP_RHS = laplacian(sub,h);
RHS = M*LP_RHS;
c = c + dt.*RHS;
end
mesh(x,y,c);
It seems all value of c calculated during the loop will overlap and give a figure shown below: I guess this indicates some facts about the plotting function of matlab, but I am not sure
Btw, can I answer directly to each comment and high light the new added section in my post? Sorry I am not as familiar with Stack Overlow as I should have :)
I ran your routine and with the following changes it works for me:
% Iteration
for i = 1:n
LP_c = laplacian(c,h);
d_f = A*(4*(c.^3)-6*(c.^2)+2*c);
sub = d_f - (2*K)*LP_c;
LP_RHS = laplacian(sub,h);
RHS = M*LP_RHS;
c = c + dt.*RHS;
% Save image every 2000 steps
if ( mod(i,2000)==0)
h1 = mesh(x,y,c);
drawnow;
saveas(h1, sprintf('FIG%d.jpg',i));
end
end
The main change is the figure handle variable from h to h1. Why? You are already using variable h in your equations.
Regards,