Applying runge kutta for coupled equations - matlab

so I have 2 second order nonlinear ODE and after applying the state-space theorm I have 4 first order ODE.
I'm trying to apply RK4 but I think I'm doing it wrong because the graphs diverge.
I'm getting a hard time applying it because the equations are coupled.
Those are the main equations. L and Fa also have state-space variables in them but it doesn't make a diffrence for my qustion.
Equations image
After applying the state-space theorm, Those are my equations:
f1 = #(x2) x2; % = x1'
f2 = #(x1, x2, x3) K/m*(l_0/sqrt((X_d(t, t1, t2, a_x0, X_d0, X_d0_tag)-x1).^2+(Z_d(t, t0, a_z0, Z_d0, Z_d0_tag)-x3).^2)-1)*(x1-X_d(t, t1, t2, a_x0, X_d0, X_d0_tag)) ...
- 0.5*Rho*A*C_d*(x2-Interpolation(Z_d(t, t0, a_z0, Z_d0, Z_d0_tag), data)).^2*sgn(x2, Z_d(t, t0, a_z0, Z_d0, Z_d0_tag), data)/m;
% = x2'
f3 = #(x1) x1; % = x3'
f4 = #(x1, x3) K/m*(l_0/sqrt((X_d(t, t1, t2, a_x0, X_d0, X_d0_tag)-x1).^2+(Z_d(t, t0, a_z0, Z_d0, Z_d0_tag)-x3).^2)-1)*(x3-Z_d(t, t0, a_z0, Z_d0, Z_d0_tag))-g;
% x4'
Than I tried to apply RK4. Heads up, it might be a complete nonsense. I also applied initial conditions but I don't want to make it messy.
h=0.2; % step size
t_array = 0:h:10;
w = zeros(1,length(t_array));
x = zeros(1,length(t_array));
y = zeros(1,length(t_array));
z = zeros(1,length(t_array));
for i=1:(length(t_array)-1) % calculation loop
t = 0 +h*i; % A parameter needed for the interpolation in f2
k_1 = f1(x(i));
k_2 = f1(x(i)+0.5*h*k_1);
k_3 = f1(x(i)+0.5*h*k_2);
k_4 = f1(x(i)+k_3*h);
x(i+1) = x(i) + (1/6)*(k_1+2*k_2+2*k_3+k_4)*h;
disp(x(i+1));
m_1 = f3(z(i));
m_2 = f3(z(i)+0.5*h*k_1);
m_3 = f3(z(i)+0.5*h*k_2);
m_4 = f3(z(i)+k_3*h);
z(i+1) = z(i) + (1/6)*(m_1+2*m_2+2*m_3+m_4)*h;
n_1 = f2(x(i), z(i), w(i));
n_2 = f2(x(i), z(i) ,w(i)+0.5*h*k_1);
n_3 = f2(x(i), z(i) ,w(i)+0.5*h*k_2);
n_4 = f2(x(i), z(i) ,w(i)+k_3*h);
w(i+1) = w(i) + (1/6)*(k_1+2*k_2+2*k_3+k_4)*h;
l_1 = f4(x(i), z(i));
l_2 = f4(x(i), z(i));
l_3 = f4(x(i), z(i));
l_4 = f4(x(i), z(i));
y(i+1) = y(i) + (1/6)*(k_1+2*k_2+2*k_3+k_4)*h;
end
As I said my graphs are divering (they souldn't be) so I suspect my code is wrong.
Please help me fix the algorithm.
Thank you very much!

What are XD and ZD? Why don't they have differential equations associated with them? Can you give more details about this?
Also, it would help if you used vectors for the state variable, and had one single function handle that produced a vector output. That cuts down on the code you write, and allows you to compare your results with ode45( ) since it can take the same function handle as input.
It appears that the fundamental flaw in your code is that although you state the equations are coupled, you are attempting to integrate them piecemeal. E.g., you do the RK4 scheme for one variable using k_1, k_2, k_3, k_4 to propagate x(i) to x(i+1). But during this process all the other coupled variables z(i) and w(i) and y(i) remain static in your code. This is a flaw. All of the coupled variables need to propagate at the same time through those intermediate calculations. I.e., you need to generate all of the k_1, m_1, n_1, and l_1 first, then using those results calculate all of the k_2, m_2, n_2, and l_2. Then using those results calculate all of the k_3, m_3, n_3, and l_3. Then using all of those results calculate k_4, m_4, n_4, and l_4. And finally use all of this to propagate all your variables forward one step. This is where a vector function handle can greatly help you. By making one function handle that takes a vector input (each element of the vector representing one of your variables) and returns a vector output, you can boil your code down to writing only one set of RK4 equations that automatically propagates all the variables forward at the same time because they are all part of the same vector. This will also make your code easier to debug.
Finally, you are mixing variables and derivatives. x's should go with k's, z's should go with m's, w's should go with n's, and y's should go with l's. In particular, the l's don't even have RK4 scheme implemented.

Related

Create function to use in ode45

So this is part of a larger project but I am stuck on number two of this section. I rewrote the system to get it in the required form:
dx(1)/dt = x(2)
dx(2)/dt = (-(M+m)/mL))x(4) + 1/(mL)u
dx(3)/dt = x(4)
dx(4)/dt = -(mg/M)x(1) + (1/M)u
After substituting the variables given in the problem I wrote the funcion:
function dx = fun(t,x)
dx = zeros(4,1);
dx(1) = x(2);
dx(2) = -((2+.1)/(.1*.5)).*x(4);
dx(3) = x(4);
dx(4) = -((.1*9.81)/2).*x(1);
end
I am confused on how to implement u(t) = 0 and how to create the theta function.
Any help even if its just pointing me in the right direction would be amazing. Thank you in advance :)
It's easy. You implement theta as another state. This is possible since you know the derivative, which does not even depend on the other states. To be more precise, you should add two more states here. One for theta and one for theta_dot.
dx(5) = x(6) % Theta'
dx(6) = -0.1 % Theta''
And by the way, you can also pass additional variables to your differential equation. You just add more arguments to it
function dx = diffeq(t,x,parameters)
...
end
and create a new function handle where you execute the ODE solver
[T,X] = ode45(#(t,x)diffeq(t,x,parameters),t_span,X0, ode_options);
This is just a hint since you're using magic numbers in your differential equation function.

How do I integrate a differential equation in MATLAB?

I want to integrate a differential equation dc/dt. Below is the code and the values of the variables.
clear all;
c1=.185;c0=2*10^-6;k3=.1*10^-6;
v1=6;v2=.11;v3=.09*10^-6;
Ca_ER=10*10^-6;Ca_cyto=1.7*10^-6;
p_open3=0.15;c=15*10^-6;
dcdt= (c1*(v1*(p_open3)+v2)*(Ca_ER)-c)-v3*((c)^2)/(c^2+(k3)^2);
I know there is an integral function but I am not sure how to apply for this equation. How do I proceed from here? Please help. The value of initial c, if needed, can be taken as 0.15*10^-6. Also, I need to plot the obtained result versus time. So will get an array of values or just a single value?
the link to the article. the equation i have used comes under Calcium Oscillations section
You could use Euler method to solve this problem to get a rough idea regarding the solution yet not accurate.
clear all
clc
t = 0;
dt = 0.0001;
c1 = 0.185;
c0 = 2*10^-6;
k3 = 0.1*10^-6;
v1 =6;
v2 =.11;
v3 =.09*10^-6;
Ca_ER =10*10^-6;
Ca_cyto =1.7*10^-6;
p_open3 =0.15;
c = 15*10^-6;
%store initial values
C(1) = c;
T(1) = t;
for i = 1:40000
dc = ( (c1*(v1*(p_open3)+v2)*(Ca_ER)-c)- v3*( c^2 /( c^2+(k3)^2) ) );
c = c + dt*dc;
t = t + dt;
%store data
C(i+1) = c;
T(i+1) = t;
end
plot(T,C, 'LineWidth',2)
xlabel('time (sec)')
ylabel('c(t)')
grid on
The result is
You can also use Wolfram which gives same result.

how to estimate and optimize the parameters of coupled nonlinear ODE's

I have a set of coupled nonlinear ODE's, i need to solve these ODE's, then estimate and optimize the parameters using genetic algorithm or any function so as to minimize the difference between experimental and simulated data.
i have all the initial values for all state variables and the range(1-10) for the parameters to be estimated. I am new to MATLAB please forgive if i had made any syntax errors.
following is the code:
function dx = reaction( t,x,k )
dx = zeros(6,1);
dx(1)=0;
dx(2)= k(1)*x(1) - k(2)*x(2) - k(3)*x(5) + k(4)*x(6);
dx(3)=0;
dx(4) = -k(2)*x(3)*x(4) + k(3)*x(5);
dx(5) = k(8)*x(3)*x(4) - k(7)*x(5) - k(3)*x(2)*x(5) + k(5)*x(6);
dx(6) = k(6)*x(2)*x(5) - k(3)*x(6) - k(4)*x(2)*x(6);
end
function objective
k01=1:10;
k02=1:10;
k03=1:10;
k04=1:10;
k05=1:10;
k06=1:10;
k07=1:10;
k08=1:10; %//range of parameters to lie in
exp=[8;0;0.8;12;0;0]; %//experimental data
time=[0;5;10;15;20;25]; %//time span
x01=8;
x02=0;
x03=0.8;
x04=12;
x05=0;
x06=0; %// initial values of state variables
tspan = [min(time),max(time)];
k_opt = fminsearch(#minimize, [k1,k2,k3,k4,k5,k6,k7,k8])
function e = minimize(k1,k2,k3,k4,k5,k6,k7,k8)
sol = ode45(#reaction, tspan, [x01,x02,x03,x04,x05,x06],[], [k1,k2,k3,k4,k5,k6,k7,k8]);
y_hat = deval(sol, time); % // evaluate solution at given times
e = sum((y_hat' - exp).^2); % // compute squarederror
end
% // plot with optimal parameter
[T,X] = ode45(#reaction, tspan, [x01,x02,x03,x04,x05,x06], [], k_opt);
figure
plot(time, exp,'ko', 'markersize',10,'markerfacecolor','black')
hold on
plot(T,Y, 'r--', 'linewidth', 2)
end
See this as a start (still needs some work). It is the best that i can come up with.
Your plot plot(time, exp,'ko', 'markersize',10,'markerfacecolor','black') doesn't make sense to me as it plots the data over the time, which (referring to your latest comment) is not what exp should be. Thats why i was asking in the comments
The optimization stops with an error of about 139.3828 for me, also raising some warnings about problems with the numerical integration. The optimal parameterset is
k_opt =
-0.2258 6.2298 -1.2666 3.6352 -1.8671 0.0001 2.5592 -2.2011
Here comes the code:
function main
k0 = ones(1,8);
exp=[8;0;0.8;12;0;0]; %//experimental data
time=[0;5;10;15;20;25]; %//time span
%// initial values of state variables
x01=8;
x02=0;
x03=0.8;
x04=12;
x05=0;
x06=0;
x0 = [x01,x02,x03,x04,x05,x06];
tspan = [min(time),max(time)];
k_opt = fminsearch(#minimize, k0)
function e = minimize(k0)
[t,y_hat] = ode45(#reaction, tspan, x0,[], k0);
% y_hat = deval(sol, time(end)); % // evaluate solution at given times
e = sum((y_hat(end,:)' - exp).^2) % // compute squarederror '
end
% // plot with optimal parameter
[T,Y] = ode45(#reaction, tspan, [x01,x02,x03,x04,x05,x06], [], k_opt);
figure
subplot(1,2,1)
plot(time(end), exp, '*', 'markersize',15)
hold on
plot(T,Y, 'linewidth', 2)
% // Scatter: data vs model
subplot(1,2,2)
scatter(Y(end,:), exp)
hold on
axis equal
grid on
xlabel('model')
ylabel('data')
disp('yay')
end
function dx = reaction(t, x, k)
dx = zeros(6,1);
dx(1)=0;
dx(2)= k(1)*x(1) - k(2)*x(2) - k(3)*x(5) + k(4)*x(6);
dx(3)=0;
dx(4) = -k(2)*x(3)*x(4) + k(3)*x(5);
dx(5) = k(8)*x(3)*x(4) - k(7)*x(5) - k(3)*x(2)*x(5) + k(5)*x(6);
dx(6) = k(6)*x(2)*x(5) - k(3)*x(6) - k(4)*x(2)*x(6);
end
And two plots of the result. Blue and red are fit quite well, however, they do not change while integrating. I do not know about the others i.e. if your equations are correct and actually can reproduce the result.

Simulations hang when running ode45

I'm suppose to make a model for an algae population. Here's the code I have so far (all written from examples online). When i run Solve_algaepop, it just hangs for a long time.
Any ideas why? Is there any obvious thing I'm doing wrong? The equations are from a research paper.
This is Solve_algaepop.m. In the equations for r1 and r2, P10 and P20 are supposed to be the values
P1 = x(1) and P2 = x(2) defined in algaepop_model.m. I don't know how to access the values when I'm in Solve_algaepop.m
% Initial conditions
P10 = 560000; %from Chattopadhyay; estimated from graph
P20 = 250000; %same as above
Z0 = 280000; %
N0 = 0.6; %from Edwards
%some variables that the expressions of the parameters use
lambda = .6;
mu = .035;
k = 0.05;
%define parameters (start with estimates from Edwards paper):
r1 = (N0/(.03+N0))*((.2*P10)/(.2 + .4*P10));
r2 = (N0/(.03+N0))*((.2*P20)/(.2 + .4*P20));
a = Z0*((lambda*P10^2)/(mu^2 + P10^2));%G1: zooplankton growth function from Edwards paper
% m1 = .15; %r in Edwards paper
m1 = .075; % q in Edwards
m2 = .15;% r in Edwards paper
m3 = .15; % r in Edwards paper
d = 0.5;
cN = k;%*(N-N0);
par = [r1 r2 a m1 m2 m3 d cN]; % Creates vector of parameter values to pass to the ode solver
tspan = 0:1:300; %(Note: can also use the function linspace)
x0 = [P10 P20 Z0 N0]; % Creates vector of initial conditions
[t,x] = ode45(#algaepop_model,tspan,x0,[],par);
plot(t,x)
And here is algaepop_model.m
function dxdt = algaepop_model(t,x,par)
P1 = x(1);
P2 = x(2);
Z = x(3);
N = x(4);
r1 = par(1);
r2 = par(2);
a = par(3);
m1 = par(4);
m2 = par(5);
m3 = par(6);
d = par(7);
cN = par(8);
dxdt = zeros(4,1);
dxdt(1) = r1*N*P1 - m3*P1 - a*P1*Z;
dxdt(2) = r2*N*P2 - a*P2*Z - m2*P2;
dxdt(3) = a*P2*Z + a*P1*Z - m1*Z;
dxdt(4) = d*m2*P2 + d*m1*Z + d*m3*P1 + cN - r2*N*P2 - r1*N*P1;
end
Thanks for the help.
Let's debug. One of the simplest things that you can do is print out t and x inside of your integration function, algaepop_model. As soon as you do this, you'll probably notice what's happening: ode45 is taking extremely small steps. They're on the order of 1.9e-9. With steps that small, it will take forever to simulate to t = 300 (and even longer if you print stuff out on each step).
This might be caused by a poor choice of initial conditions, poor scaling or dimensionalization, a typo resulting in the wrong equations, or simply that you're using an inappropriate solver (and/or tolerances) for the particular problem. I can't really address the first two situations and must assume that you don't have any errors. Thus, in this case you have what is effectively a stiff system and ode45 is not a particularly good choice in such cases. Simply changing the solver to ode15s results in the following plot almost immediately:
As you can see, there are very large changes over a short period of time in the initial portion of the plot. If you zoom in you'' see that the huge spike happens in the first unit of time (you might output more time points or just let tspan = [0 300]). Some state variables are changing rapidly while others are varying more gradually. Such high frequencies and differences in time scales are the hallmarks of stiff systems. I'd suggest that, in addition to confirming that your code is correct, you also try adjusting the integration tolerances as well via odeset. Make sure that tighter tolerances produce qualitatively similar results. You can also try the other stiff solvers in the ODE suite if you like.
Lastly, it's more efficient and up-to-date to pass your parameters via the function handle itself rather than how you're doing it. Here's how:
[t,x] = ode15s(#(t,x)algaepop_model(t,x,par),tspan,x0);

Solving coupled Differential Equation by Matlab or by calculations

Solving coupled non linear differential equation by Mat-lab or by calculations
equation 1: x'(t) = -a* x(t) /(x(t) + y(t))
equation 2: y'(t) = -b* y(t) /(x(t) + y(t))
I tried in mathematica but got a very comlicated solution.
Solve[{x'[t] == -a* x[t] /(x[t] + y[t]), y'[t] == -b* y[t] /(x[t] + y[t])}, {x, y}, t]
How can I plot it?
My initial conditions are
x(0) = xo
y(0) = yo
Also, a and b are constants.
I have to plot x and y wrt t after inserting values of a and b . ( a= 2 , b =5 say )
A lot of things to note in this situation:
You need to create a function that contains both a and b:
function dy =soProblem(t,y,a,b)
dy=[-a*y(1)/(y(1)+y(2)); -b*y(2)/(y(1)+y(2))];
end
Call the standard ode function:
a = 2;
b = 5; tend = 10; x0 = 1; y0 = 2;
[T,Y] = ode45(#(t,y)soProblem(t,y,a,b),[0 tend],[x0 y0]);
plot (T,Y)
Realize you may have a stiff equation on your hands.
Have fun identifying the ideal function call:
[T15,Y15] = ode15s(#(t,y)soProblem(t,y,a,b),[0 tend],[x0 y0]);
[T23t,Y23t] = ode23t(#(t,y)soProblem(t,y,a,b),[0 tend],[x0 y0]);
[T23tb,Y23tb] = ode23tb(#(t,y)soProblem(t,y,a,b),[0 tend],[x0 y0]);
%note ode23s doesn't converge (or at least takes forever)
plot (T,Y,T15,Y15,T23t,Y23t,T23tb,Y23tb)
Understand why mathematica becomes restless
In mathematica:
Try ndsolve
In matlab:
Create a function file yourfunction.m:
function [Y_prime]=yourfunction(t, Y)
Y_prime=[-2*Y(1)./(Y(1) + Y(2)) -5*Y(2)./(Y(1) + Y(2))];
end
and then
[T,Y] = ode45(yourfunction,[0 t_end],[x0 y0]);
plot(T,Y(:,1));
hold on
plot(T,Y(:,2));