MATLAB ode45 OutputFcn to monitor changing value of if loop - matlab

I try to save/see my variable m that is changed by an if loop during an ode45 differential equation solving process.
%Some parameter setting above
myfun=fprintf('m', num2str(m))
options = odeset('NonNegative',[1:3],'RelTol',1e-5,'AbsTol',1e-8, 'OutputFcn', #myfun);
[t,x] = ode45('myfunction', tspan, x0, options); %calculation
the if loop is in the equation file before all the other equations follows:
if x(1)>=threshold
m=1 ;
return
else
m=0 ;
end
I already took a look at the matlab description for the OutputFcn Option for ode45 and also read
https://de.mathworks.com/help/deeplearning/ug/customize-output-during-deep-learning-training.html
without understanding it properly. I am also open to other solutions to "see" which value m during the ode calculation has.

Create a separate file, and call this myOutputFcn.m, with the following code
function status = myOutputFcn(t,y,flag,threshold)
switch(flag)
case 'init' % code to run before integration
;
case '' % code to run after each integration step
% act on state
if y(1)>=threshold
m = 1;
else
m = 0;
end
% print m
fprintf('% 4.3f\t%i, t, m\n',t,m);
case 'done' % code to run when integation is finished
;
end
status = 0; % need to set status, otherwise integration will halt
end
Then to call this output function every iteration with the right threshold, you will have to do the following
threshold = 10; % idk, your threshold
options = odeset('NonNegative',[1:3],'RelTol',1e-5,'AbsTol',1e-8, 'OutputFcn', #(t,y,flag) myOutputFcn(t,y,flag,threshold));
[t,x] = ode45('myfunction', tspan, x0, options); %calculation

Related

How can I add a function of time requested previously as input in ODE 45? [MATLAB]

I'm having this problem: Let's suposse that a user wants to add an arbitrary Force (a function of time) to a spring mass damper system. In order to do that, we request the force as an input, i.e. F = cos(t). Well, I noticed that if we add a function of time in the code where the F is placed (inside ODE), then the solutions for the movement equations are correct. But i can't find a way to achieve this goal. I mean, to request the force as input so that ODE changes everytime i put a new force. I've tried almost everything like converting the input F to a function, etc.
I hope you could help me. Here is the problem in the code:
F = input('Insert force F(t)..............[N] = ','s');
u0 = [x0,v0]; % INITIAL CONDITIONS AS A VECTOR
ODE = #(t,u) [u(2) ; F - (c/m)*u(2) - (k/m)*u(1)]; % FORCED SPRING MASS DAMPER SYSTEM
[t,u] = ode45(ODE, [0 tf], u0);
The fix code results:
m = input('Insert mass of the system..........................[kg] = ');
c = input('Insert viscosity coefficient........................[ ] = ');
k = input('Insert elasticity constant..........................[m] = ');
x0 = input('Insert initial position.............................[m] = ');
v0 = input('Insert initial velocity...........................[m/s] = ');
tf = input('Insert time of complete movement....................[s] = ');
F = input('Insert external force as F(t).......................[N] = ','s');
F = str2func( ['#(t)' F] ); % CONVERT STRING TO FUNCTION
%=========================================================== ODE 45 =======
u0 = [x0,v0]; % INITIAL CONDITIONS AS A VECTOR
ODE = #(t,u) [u(2) ; F(t) - (c/m)*u(2) - (k/m)*u(1)];
[t,u] = ode45(ODE, [0 tf], u0);
u(:,3) = F(t) - (c/m)*u(:,2) - (k/m)*u(:,1); % ACCELERATION
%============================================================= PLOT =======
v = {'x','dx/dt','d2x/dt2'}; % CHAR VECTOR FOR PLOT
for i = 1:3 % PLOT WITH LOOP
subplot(3,1,i)
plot(t,u(:,i));
xlabel('t');
ylabel(v(i));
grid on;
end
Code just for personal uses. Not public because input allows malicious commands.
Thanks to #Wolfie and #Ander Biguri.
I'm going to take the liberty of simplifying your problem down to its main parts.
You have some char array from your user input which defines a function in terms of t. I'm going to entirely ignore all the reasons that blindly evaluating user-input functions is dangerous, but you shouldn't.
You want to combine this function with an existing function in terms of t to produce a single function
We can do this like so:
F = 'cos(t)'; % char version of function, e.g. from the input command
y = #(t) t; % some base function in terms of t
F = str2func( ['#(t)' F] ); % Convert function char to anonymous function
yF = #(t) y(t) + F(t); % combine the functions
You can test this with a quick plot
tt = 0:0.01:10; % axis data
figure; hold on;
plot( tt, y(tt), 'displayname', 'y(t)' );
plot( tt, yF(tt), 'displayname', 'yF(t)' );
legend('show');
In your actual example you have ODE in place of my example f, so assuming F is converted to an anonymous function as shown above, you would get
ODE = #(t,u) [u(2) ; F(t) - (c/m)*u(2) - (k/m)*u(1)];

Why is my third MATLAB function outputing only zeros when using ode45?

I need to model negative, positive and simple regulation of a gene for my systems biology class using MATLAB. The problem is that the functions for negative and simple regulation work but the positive regulation function is only outputting zeros.
My script is as follows:
% Simulation of simple regulation, negative autoregulation and positive
% autoregulation
% Define constants
global a b K n
a = 1;
b = 1;
K = 0.5;
n = 2; % Hill coefficient
% Simulation time
tspan = [0,10];
% Initial condition
X0 = 0;
% Run simulations
[t1,X1] = ode45(#autoregulation_f0,tspan,X0); % Simple regulation
[t2,X2] = ode45(#autoregulation_f1,tspan,X0); % Negative autoregulation
[t3,X3] = ode23(#autoregulation_f2,tspan,X0); % Positive autoregulation
% Plot results
figure;
plot(t1,X1,t2,X2,t3,X3);
legend('simple','negative','Location','southeast');
And my functions are:
function dxdt = autoregulation_f0(t,X)
global a b
dxdt = b - a*X;
end
function dxdt = autoregulation_f1(t,X)
global a b K n
dxdt = b/(1+(X^n)/(K^n)) - a*X;
end
function dxdt = autoregulation_f2(t,X)
global a b K n
dxdt = b*X.^n./(K.^n+X.^n) + a*X;
end
The third function "autoregulation_f2(t,X)" is the one that outputs zeros and therefore when plotting the graph I just get a straight line.
Does anyone know what could be causing this?
Thanks in advance!
It looks to be the correct result for the given function. Your provided dxdt has an X in every term. The initial X0=0 will result in dxdt=0, giving you no change in X. As a result you just end up with a flat line.

How to debug this Matlab code to model glider descent?

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.

how to importing m-file with internal function to simulink?

my problem is some hard to describe, but I try to express in the best.
I have a model with a main file by the name 'main.m' with some codes.
in 'main.m' file I used ode45 to solve differential equations.
here's my 'main.m' codes:
[t,x]=ode45(#vdp,[0 100],[0 0 -15 0]);
subplot(2,1,1);
plot(t,x(:,1),'r-',t,x(:,3),'b-');
title('Positions');
legend('Loco','Wagon');
xlabel('Time');
ylabel('Distance');
grid;
subplot(2,1,2);
plot(t,x(:,2),'r-',t,x(:,4),'b-');
title('Velocities');
legend('Loco','Wagon');
xlabel('Time');
ylabel('Velocity');
grid;
as you know, with ode45 we need a function to describe the differential equations and for this, I used another file by the name of 'vdp.m'.
my 'vdp.m' codes: Note that my input is "u" variable and outputs are "dx(1),dx(2),dx(3),dx(4)"?
function dx = vdp(t,x)
%% Setting Parameters
c0 = 7.6658*10^-3; % unit = Nkg^-1
cv = 1.08*10^-4; % unit = Ns(mkg)^-1
ca = 2.06*10^-5; % unit = Ns^2(m^2 kg)^-1
m1 = 50000; % unit = kg
m2 = 48500; % unit = kg
k1 = 85*10^2; % unit = Nm^-1
d1 = 85*10^4; % unit = kgs^-1
% Force Input
u = 3000; % unit = N 48750
%u2 = 0;
teta1 = 0;
teta2 = 0;
D1 = 0;
D2 = 0;
% dx=zeros(6,1); % a column vector
%% Generate Control Input
if t>=0 && t<=10
a=0;
u1=u*a;
elseif t>10 && t<=15
a=1;
u1=u*a;
elseif t>15 && t<=55
a=50;
u1=u*a;
elseif t>55 && t<=75
a=-97;
u1=u*a;
else
a=0;
u1=u*a;
end
%% State Equations
% x1 -> position of loco
% x2 -> velocity of loco
% x3 -> position of wagon
% x4 -> velocity of wagon
if t>=0 && t<=10
dx(1)=0; dx(2)=0; dx(3)=0; dx(4)=0;
dx = [dx(1);dx(2);dx(3);dx(4)];
elseif t>10 && t<=75
dx(1)=x(2);
dx(2)=(1/m1)*(u1-k1*(x(1)-x(3))-d1*(x(2)-x(4))-(c0+cv*x(2))*m1- ...
ca*((x(2))^2)*(m1+m2)-9.98*(sin(teta1))*m1-0.004*D1*m1);
dx(3)=x(4);
dx(4)=(1/m2)*(-k1*(x(3)-x(1))-d1*(x(4)-x(2))-(c0+cv*x(4))*m2- ...
9.98*(sin(teta2))*m2-0.004*D2*m2);
dx = [dx(1);dx(2);dx(3);dx(4)];
else
dx(1)=0; dx(2)=0; dx(3)=0; dx(4)=0;
dx = [dx(1);dx(2);dx(3);dx(4)];
end
Now I wanna use 'main.m' file program as a block in Simulink, because this codes are describing my model behavior.
Is there any way to import 'main.m' file to a block and use the block within my simulink model or a way to combining both two m-file to one file and making a function for using MATLAB Function Block?
Thanks all :)
I don't believe that you really want to do what your question says you want to do. Your main.m file is equivalent to the Simulink user interface, i.e. the bit where the solver and model run time (amongst other things) is specified. It doesn't make sense to want to use it within Simulink.
However, your second block of code, vdp, where the model functionality is defined, can certainly be used within Simulink. It (at least superficially) looks as if it can be dropped directly into a model using the MATLAB Function block. You'd feed its output (i.e. xdot) directly into a Continuous Time Integrator block, then feed the output of the integrator (which will be x) back into the second input of the MATLAB Function block. You'd feed a Clock block into the first input of the MATLAB Function block.
Of course you could also implement the vdp functionality using Simulink blocks rather than within m-code.

Can I use two separate ODE call functions for a system of two differential equations in MatLab?

I am trying to code a system of ODE's shown below.
As seen, the second ODE completely depends on the value of the first ODE.
How can I code the second ode?
I am using ode45.
Yes, that's quite possible. Define x as [c;ce], then you have something like:
function dx = my_ode(t,x)
% parameters definition
kf = ...; % whatever value you are using
P0 = ...; % whatever value you are using
Jer = ...; % whatever value you are using
J_serca = ...; % whatever value you are using
gamma = ...; % whatever value you are using
% differential equations
dc = (kf*P0+Jer)*(x(2)-x(1)) - J_serca;
dce = -gamma*dc;
dx = [dc;dce];
and then you can call the ode solver as:
tspan = [0 10]; % or whatever time interval you want to solve the odes on
x_init = [0;0]; % ot whatever initial conditions you want to use
[T,Y] = ode45(#my_ode,tspan,x_init);