Plotting a function defined by a system of ODEs with MATLAB - matlab

I am trying to solve with MATLAB the first order ODEs system,
$$\left\{
\begin{array}{l}
x_{1}^{\prime }=-\frac{1}{t+1}x_{1}+x_{2} \\
x_{2}^{\prime }=-(1+e^{-2t})x_{1}-\frac{1}{t+1}x_{2}+\frac{e^{-3t}}{t+1}x_{3}
\\
x_{3}^{\prime }=-\frac{1}{t+1}x_{3}+x_{4} \\
x_{4}^{\prime }=e^{-3t}\left( t+1\right) x_{1}-\left( 1+e^{-2t}\right) x_{3}-%
\frac{1}{t+1}x_{4}-\frac{1}{t+1}x_{3}^{2}%
\end{array}%
\right. $$
I've defined the function:
function dzdt=odefun(t,z)
dzdt=zeros(4,1);
dzdt(1)=-(1/(t+1))*z(1)+z(2);
dzdt(2)=-(1+exp(-2*t))*z(1)-(1/(t+1))*z(2)+(exp(-3*t))/(t+1)*z(3);
dzdt(3)=z(4)-(1/(t+1))*z(3);
dzdt(4)=(exp(-3*t))*(t+1)*z(1)-(1+exp(-2*t))*z(3)-(1/(t+1))*z(4)-(1/(t+1))*z(3)^2;
end
The time interval is [0,100] and the initial conditions are z0 = [0.01 0.01 0.01 0.01].
With the ode45 solver, I've used the commands:
>> tspan = [0 100];
>> z0 = [0.01 0.01 0.01 0.01];
>> [t,z] = ode45(#(t,z) odefun(t,z), tspan, z0);
>> plot(t,z(:,1),'r')
and I've obtained easily the graph of z(1)=x_1.
But I want to plot the function f(t)=(t+1)*x_1(t), t\in [0,100], where x_1=z(1) is the first unknown of the system. How could I do this ?

Just use per element multiplication .*
plot((t+1).*z(:,1))

Related

Plotting three functions in the same output

I've defined the function
function dzdt=odefun2222(t,z)
beta=1+exp(-t); delta=1+exp(-t); rho=1+exp(-t);
gama=exp(-t); theta=exp(-t);
f1=1/2+1/(t+1); f2=1/2+1/(t+1);
dzdt=zeros(6,1);
dzdt(1)=z(2)-f1*z(1);
dzdt(2)=(1/4+1/(t+1)-beta)*z(1)+gama*z(3)-f1*z(2)-f1*(z(1)^2);
dzdt(3)=z(4);
dzdt(4)=gama*z(1)-delta*z(3)+theta*z(5);
dzdt(5)=z(6)-f2*z(5);
dzdt(6)=(1/4+1/(t+1)-rho)*z(5)+theta*z(3)-f2*z(6)-f2*(z(5)^2);
end
and I've used the commands
tspan = [0 20];
z0 = [0.001 0.001 0.001 0.001 0.001 0.001];
[t,z] = ode45(#(t,z) odefun2222(t,z), tspan, z0);
plot(t,z(:,1),'b',t,z(:,3),'r',t,z(:,5),'g')
I've obtained the plotting only of z(3) and z(5), z(1) is not plotted at all. What can I do in order to get the plotting of all three functions z(1), z(3), z(5) in the same output ?

Plotting a function on a specified domain

I am trying to plot the solution of a system of ODEs.
The code is:
tspan = [0 10];
z0 = [0.01 0.01 0.01 0.01];
[t,z] = ode45(#(t,z) odefun3(t,z), tspan, z0);
plot(z(:,3))
Why the output is plotted on the interval [0,60] and not on [0,10], as in the code ?
I fixed it, by adding the first variable under the plot command: plot(t,z(:,3)).

Solving 2nd order differential equation with boundary condition z(inf) = 0

How can I solve a 2nd order differential equation with boundary condition like z(inf)?
2(x+0.1)·z'' + 2.355·z' - 0.71·z = 0
z(0) = 1
z(inf) = 0
z'(0) = -4.805
I can't understand where the boundary value z(inf) is to be used in ode45() function.
I used in the following condition [z(0) z'(0) z(inf)], but this does not give accurate output.
function [T, Y]=test()
% some random x function
x = #(t) t;
t=[0 :.01 :7];
% integrate numerically
[T, Y] = ode45(#linearized, t, [1 -4.805 0]);
% plot the result
plot(T, Y(:,1))
% linearized ode
function dy = linearized(t,y)
dy = zeros(3,1);
dy(1) = y(2);
dy(2) = y(3);
dy(3) = (-2.355*y(2)+0.71*y(1))/((2*x(t))+0.2);
end
end
please help me to solve this differential equation.
You seem to have a fairly advanced problem on your hands, but very limited knowledge of MATLAB and/or ODE theory. I'm happy to explain more if you want, but that should be in chat (I'll invite you) or via personal e-mail (my last name AT the most popular mail service from Google DOT com)
Now that you've clarified a few things and explained the whole problem, things are a bit more clear and I was able to come up with a reasonable solution. I think the following is at least in the general direction of what you'd need to do:
function [tSpan, Y2, Y3] = test
%%# Parameters
%# Time parameters
tMax = 1e3;
tSpan = 0 : 0.01 : 7;
%# Initial values
y02 = [1 -4.805]; %# second-order ODE
y03 = [0 0 4.8403]; %# third-order ODE
%# Optimization options
opts = optimset(...
'display', 'off',...
'TolFun' , 1e-5,...
'TolX' , 1e-5);
%%# Main procedure
%# Find X so that z2(t,X) -> 0 for t -> inf
sol2 = fminsearch(#obj2, 0.9879680932400429, opts);
%# Plug this solution into the original
%# NOTE: we need dense output, which is done via deval()
Z = ode45(#(t,y) linearized2(t,y,sol2), [0 tMax], y02);
%# plot the result
Y2 = deval(Z,tSpan,1);
plot(tSpan, Y2, 'b');
%# Find X so that z3(t,X) -> 1 for t -> inf
sol3 = fminsearch(#obj3, 1.215435887288112, opts);
%# Plug this solution into the original
[~, Y3] = ode45(#(t,y) linearized3(t,y,sol3), tSpan, y03);
%# plot the result
hold on, plot(tSpan, Y3(:,1), 'r');
%# Finish plots
legend('Second order ODE', 'Third order ODE')
xlabel('T [s]')
ylabel('Function value [-]');
%%# Helper functions
%# Function to optimize X for the second-order ODE
function val = obj2(X)
[~, y] = ode45(#(t,y) linearized2(t,y,X), [0 tMax], y02);
val = abs(y(end,1));
end
%# linearized second-order ODE with parameter X
function dy = linearized2(t,y,X)
dy = [
y(2)
(-2.355*y(2) + 0.71*y(1))/2/(X*t + 0.1)
];
end
%# Function to optimize X for the third-order ODE
function val = obj3(X3)
[~, y] = ode45(#(t,y) linearized3(t,y,X3), [0 tMax], y03);
val = abs(y(end,2) - 1);
end
%# linearized third-order ODE with parameters X and Z
function dy = linearized3(t,y,X)
zt = deval(Z, t, 1);
dy = [
y(2)
y(3)
(-1 -0.1*zt + y(2) -2.5*y(3))/2/(X*t + 0.1)
];
end
end
As in my comment above, I think you're confusing a couple of things. I suspect this is what is requested:
function [T,Y] = test
tMax = 1e3;
function val = obj(X)
[~, y] = ode45(#(t,y) linearized(t,y,X), [0 tMax], [1 -4.805]);
val = abs(y(end,1));
end
% linearized ode with parameter X
function dy = linearized(t,y,X)
dy = [
y(2)
(-2.355*y(2) + 0.71*y(1))/2/(X*t + 0.1)
];
end
% Find X so that z(t,X) -> 0 for t -> inf
sol = fminsearch(#obj, 0.9879);
% Plug this ssolution into the original
[T, Y] = ode45(#(t,y) linearized(t,y,sol), [0 tMax], [1 -4.805]);
% plot the result
plot(T, Y(:,1));
end
but I can't get it to converge anymore for tMax beyond 1000 seconds. You may be running into the limits of ode45 capabilities w.r.t. accuracy (switch to ode113), or your initial value is not accurate enough, etc.

Vectorizing ODE in Octave / Matlab

If I have an ode and wrote it in two ways, like here:
function re=rabdab()
x=linspace(0,2000,2000)';
tic;
[T,Y] = ode45(#fun,[x],[0 1 1]);
[T,Y] = ode45(#fun,[x],[0 1 1]);
[T,Y] = ode45(#fun,[x],[0 1 1]);
toc;
tic;
[A,B] = ode45(#fun2,[x],[0 1 1]);
[A,B] = ode45(#fun2,[x],[0 1 1]);
[A,B] = ode45(#fun2,[x],[0 1 1]);
toc;
function dy = fun(t,y)
dy = zeros(3,1); % a column vector
dy = [y(2) * y(3);...
-y(1) * y(3);...
-0.51 * y(1) * y(2);];
function dy = fun2(t,y)
dy = zeros(3,1); % a column vector
dy(1) = y(2) * y(3);
dy(2) = -y(1) * y(3);
dy(3) = -0.51 * y(1) * y(2);
There is almost no difference in time. One takes just as long as the other. But I thought that fun is the vectorized version of fun2. Or am I mistaken here?
The purpose is to speed up my code a little. The example is taken from the matlab webpage.
I think I haven't really understood what "vectorized" means.
If this is already vectorized, what would a non-vectorized code look like?
Vectorization is a concept which is closely related to functional programming. In MATLAB it means performing operations on arrays (vectors or matrices) without implicitly writing a loop.
For example, if you were to compute the function f(x) = 2x for every integer x between 1 and 100, you could write:
for x = 1:100
f(x) = 2 * x;
end
which is not vectorized code. The vectorized version is:
x = 1:100; %// Declare a vector of integer values from 1 to 100
f = 2 * x; %// Vectorized operation "*"
or even shorter:
f = 2 * (1:100);
MATLAB is an interpreted language, so obviously the interpreter translates this into some kind of loop "under the hood", but it's optimized and is usually much faster than actually interpreting a loop (read this question for reference). Well, sort of -- it's been like that until the recent releases of MATLAB, where JIT acceleration has been integrated (read here).
Now getting back to your code: what you have here is two vectorized versions of your code: one that concatenates vertically three values and one that directly assigns these values into a column vector. That's basically the same thing. Should you have done it with an explicit for loop, this would not have been "vectorized". Regarding the actual performance gain from "vectorizing" a loop (that is, converting a for loop into a vectorized operation), this depends on the how fast the for loop actually was due to JIT acceleration in the first place.
It doesn't seem that there's much to be done to speed up your code. Your functions are pretty basic, so it boils down to the internal implementation of ode45, which you cannot modify.
If you're interested in further reading about vectorization and writing faster MATLAB code in general, here's an interesting article: Loren on the Art of MATLAB: "Speeding Up MATLAB Applications".
Happy coding!
While the previous answer is correct in general terms, vectorized in the context of ODEs means something more specific. In short, a function f(t,y) is vectorized iff f(t,[y1 y2 ...]) returns [f(t,y1) f(t,y2) ...], for y1,y2 column vectors. As per the documentation [1], "this allows the solver to reduce the number of function evaluations required to compute all the columns of the Jacobian matrix."
Functions fun3 and fun4 below are properly vectorized in the ODE sense:
function re=rabdab()
x=linspace(0,20000,20000)';
opts=odeset('Vectorized','on');
tic;
[T,Y] = ode45(#fun,[x],[0 1 1]);
[T,Y] = ode45(#fun,[x],[0 1 1]);
[T,Y] = ode45(#fun,[x],[0 1 1]);
toc;
tic;
[A,B] = ode45(#fun2,[x],[0 1 1]);
[A,B] = ode45(#fun2,[x],[0 1 1]);
[A,B] = ode45(#fun2,[x],[0 1 1]);
toc;
tic;
[A,B] = ode45(#fun3,[x],[0 1 1],opts);
[A,B] = ode45(#fun3,[x],[0 1 1],opts);
[A,B] = ode45(#fun3,[x],[0 1 1],opts);
toc;
tic;
[A,B] = ode45(#fun4,[x],[0 1 1],opts);
[A,B] = ode45(#fun4,[x],[0 1 1],opts);
[A,B] = ode45(#fun4,[x],[0 1 1],opts);
toc;
function dy = fun(t,y)
dy = zeros(3,1); % a column vector
dy = [y(2) * y(3);...
-y(1) * y(3);...
-0.51 * y(1) * y(2);];
function dy = fun2(t,y)
dy = zeros(3,1); % a column vector
dy(1) = y(2) * y(3);
dy(2) = -y(1) * y(3);
dy(3) = -0.51 * y(1) * y(2);
function dy = fun3(t,y)
dy = zeros(size(y)); % a matrix with arbitrarily many columns, rather than a column vector
dy = [y(2,:) .* y(3,:);...
-y(1,:) .* y(3,:);...
-0.51 .* y(1,:) .* y(2,:);];
function dy = fun4(t,y)
dy = [y(2,:) .* y(3,:);... % same as fun3()
-y(1,:) .* y(3,:);...
-0.51 .* y(1,:) .* y(2,:);];
(As a side remark: omitting the unnecessary memory allocation with zeros lets fun4 run slightly faster than fun3.)
Q: What about vectorizing with respect to the first argument?
A: For the ODE solvers, the ODE function is vectorized only with respect to the second argument. The boundary value problem solver bvp4c, however, does require vectorization with respect to the first and second arguments. [1]
The official documentation [1] provides further details on ODE-specific vectorization (see section "Description of Jacobian Properties").
[1] https://www.mathworks.com/help/releases/R2015b/matlab/ref/odeset.html

Second Order Diff Eq with ode45 in Matlab

So I need to solve x''(t) = -x(t)^p with initial conditions x(0)= 0 and v(0) = x'(0) = v_o = 1.
The value of the parameter p is 1.
This is what I have:
function [t, velocity, x] = ode_oscilation(p)
y=[0;0;0];
% transform system to the canonical form
function y = oscilation_equation(x,p)
y=zeros(2,1);
y(1)=y(2);
y(2)=-(x)^p;
% to make matlab happy we need to return a column vector
% so we transpose (note the dot in .')
y=y.';
end
tspan=[0, 30]; % time interval of interest
[t,velocity,x] = ode45(#oscilation_equation, tspan, 1);
t = y(:,1);
xposition=y(:,3);
velocity=y(:,2);
end
and this is the error message I receive:
ode_oscillation(1)
Error using odearguments (line 91)
ODE_OSCILLATION/OSCILATION_EQUATION must return a
column vector.
Error in ode45 (line 114)
[neq, tspan, ntspan, next, t0, tfinal, tdir, y0, f0,
odeArgs, odeFcn, ...
Error in ode_oscillation (line 17)
[t,velocity,x] = ode45(#oscilation_equation, tspan,1);
There's a few things going wrong here. First, from help ode45:
ode45 Solve non-stiff differential equations, medium order method.
[TOUT,YOUT] = ode45(ODEFUN,TSPAN,Y0) with TSPAN = [T0 TFINAL] integrates
the system of differential equations y' = f(t,y) from time T0 to TFINAL
with initial conditions Y0.
Note that ode45 expects a function f(t,y), where size(t) == [1 1] for time and size(y) == [1 N] or [N 1] for solution values. Your oscilation_equation has the order of input arguments inverted, and you input a constant parameter p instead of time t.
Also, the initial conditions Y0 should have the same size as y; so size(y0) == [N 1] or [1 N]. You just have 1, which is clearly causing errors.
Also, your output arguments t, xposition and velocity will be completely ignored and erroneous, since y is not set as output argument from ode45, and most of all, their names do not correspond to ode_oscilation's output arguments. Also, their order of extracting from columns of y is incorrect.
So, in summary, change everything to this:
function [t, v, x] = ode_oscilation(p)
% initial values
y0 = [0 1];
% time interval of interest
tspan =[0 30];
% solve system
[t,y] = ode45(#(t,y) [y(2); -y(1)^p], tspan, y0);
% and return values of interest
x = y(:,1);
v = y(:,2);
end