Let's suppose that we have the following solver for a system of first-order ODEs:
% func.m
function dydt = func(t,y)
dydt = [y(2); (1-y(1)^2)*y(2)-y(1)];
and the main code:
% solver.m
tspan=0:1:10;
[t,y] = ode45(#func,tspan,[2; 0]);
How to display in real-time the results, y1(t) and y2(t), for each time step t that the ode45 makes (t=0,1,2,...,10), without waiting for the whole code to finish?
The OutputFcn ode solver option should be used. For example, to plot the solution vs time, the built-in output function odeplot can be used:
options= odeset('OutputFcn',#odeplot);
[t,y] = ode45(#func,[0 200],[2; 0],options);
You can use your own output function. Here is an example:
myOutputFcn= #(t,y,flag)fprintf('t= %s y= %s\n',mat2str(t),mat2str(y))*0;
options= odeset('OutputFcn',myOutputFcn);
[t,y] = ode45(#f,0:1:10,[2; 0],options);
Related
I am trying to solve, using MATLAB, the time dependent Harmonic oscillator equation numerically. But I have no idea how to even get started as I have never learned this method in university:
X'' + w(t)^2 X = 0
with boundary conditions X_0 = 1, X_0' = 0 and Y_0 = 0, Y'_0 = 1
ode45 is a good start point.
Basic examples :
clear;close all;clc
tspan=[0 100]; % time
x_init=[5;0]; % known initial conditions
[t,y] = ode45(#vdp1,tspan,x_init);
figure(1)
plot(t,y(:,1),'r',t,y(:,2),'b')
grid on
title('Solution with ODE45');
xlabel('Time t');
ylabel('Solution y');
legend('y_1','y_2')
f=.5
[t,y] = ode45(#(t,y) vdp2(t,y,f),tspan,x_init);
figure(2)
plot(t,y(:,1),'r',t,y(:,2),'b')
grid on
title(['Solution with ODE45 and f = ' num2str(f)]);
xlabel('Time t');
ylabel('Solution y');
legend('y_1','y_2')
support functions:
function dydt = vdp1(t,y)
%
f=.1;
dydt = [y(2); sin(2*pi*f*t)*y(1)];
function dydt = vdp2(t,y,f)
%
dydt = [y(2); sin(2*pi*f*t)*y(1)];
This: https://uk.mathworks.com/matlabcentral/fileexchange/69951-runge-kutta-fixed-step-solvers?s_tid=srchtitle_harmonic%2520oscillator_81 among other examples has example1 solving damped and driven harmonic oscillators
And another harmonic oscillator solution with ODE solver:
https://uk.mathworks.com/matlabcentral/fileexchange/83233-matlab_program_solving_odes_harmonic_oscillators?s_tid=srchtitle_harmonic%20oscillator_9
You can also solve with symbolic expressions, this is Loren's post comparing symbolic and numerical solving
https://blogs.mathworks.com/loren/2010/04/08/odes-from-symbolic-to-numeric-code/?s_tid=srchtitle_harmonic%2520oscillator_105
I find the following concise introduction to ODE solving by Cleve Moler more useful than some full year university modules.
https://blogs.mathworks.com/cleve/2016/11/14/my-favorite-ode/?s_tid=srchtitle_harmonic%2520oscillator_131
When solving oscillators in polar coordinates you may need to have a look at
https://blogs.mathworks.com/cleve/2017/11/06/three-term-recurrence-relations-and-bessel-functions/?s_tid=srchtitle_harmonic%2520oscillator_140
In point 6 there's a wonderful introduction to Bessel functions and their zeros.
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
I am setting up a function that can solve the following differential equation for a laser system with the listed parameters. Whenever I run my code though, I keep getting errors that there are not enough input arguments for the equation (dydt). I am unsure where the fault in the code is occurring, but I believe it may have something to do with how I defined y. I expect to get a gaussian distribution in a plot, but the code keeps stopping at dydt. It does not process the variables. Thank you!
function dydt = 4_Lasers(t,y)
beta=1;
p0=10;
tau2=1e-7;
t = 1;
taupulse=tau2*100000;
taup=tau2/100;
p=p0*exp(-(t/taupulse)^2);
dydt = [(1/tau2)*(p-y(1)-y(1)*y(2)); (y(2)/taup)*
(y(1)-1)+beta*y(1)/tau2];
end
clear; close all;
[t,y] = ode45(#4_Lasers,[0 1e-6],[0; 0]);
plot(t,y(:,1),'r',t,y(:,2),'b')
title('p0=10,taupulse/tau2=1.5,tau2/taup=100');
xlabel('Time t');
ylabel('Amplitude');
legend('Photodensity','population inversion')
Cannot reproduce with this code:
clear; close all;
[t,y] = ode45(#Lasers,[0 1e-6],[0 0]);
plot(t,y(:,1),'r',t,y(:,2),'b')
title('p0=10,taupulse/tau2=1.5,tau2/taup=100');
xlabel('Time t');
ylabel('Amplitude');
legend('Photodensity','population inversion')
function dydt = Lasers(t,y)
beta=1;
p0=10;
tau2=1e-7;
t = 1;
taupulse=tau2*100000;
taup=tau2/100;
p=p0*exp(-(t/taupulse)^2);
dydt = [(1/tau2)*(p-y(1)-y(1)*y(2)); (y(2)/taup)*(y(1)-1)+beta*y(1)/tau2];
end
I have two differential equations: da/dt=a(.3/a^3+.7)^1/2 and dτ/dt=1/a. The initial conditions are t=0; a=1 and τ=0, respectively. How can I solve the equations in Matlab? I need to calculate different values of a, t and τ also plot τ vs a. Thanks.
That's quite easy.
First write a function to implement your differential equation and save it with a filename corresponding to the function name:
function dy = my_ode(t,y)
dy(1) = y(1)*(0.3/y(1)^3 + 0.)^(1/2); % a
dy(2) = 1/dy(1); % tau
Then in MATLAB, call the ode45 solver with your function
[t,y] = ode45(#my_ode,[0 10],[1; 0]);
This is the result:
My function is:
function [tout, yout] = Lorenz (rho, x0)
%define constants
sigma = 10;
beta = 8/3;
%initial conditions
y0 = [x0; 1; 0];
f = #(t, y) [sigma*(y(2)-y(1)); (y(1)*(rho-y(3)))-y(2); (y(1)*y(2)) - (beta*y(3))];
[tout, yout] = ode45(f, [0 100], y0, 'RelTol', 1e-6, 'AbsTol', 1e-8);
end
When I run the function in the command window with
Lorenz(14,0)
I return
Error using Lorenz>#(t,y)[sigma*(y(2)-y(1));(y(1)*(rho-y(3)))-y(2);(y(1)*y(2))-(beta*y(3))]
Too many input arguments.
Any help would be much appreciated.
Although the syntax is not officially documented by MathWorks, the ODE suite does accept the syntax:
[t,y] = ode45(odefun,tspan,y0,options,extra1,extra2,...);
where options should be a struct created by odeset (not falling inline with the name-value system of other functions) and extra1,extra2,... is any number of extra, solve-constant parameters to be passed to odefun. I imagine it's a hold over from before anonymous functions possessed their own workspace to allow creation-time function parametrization.
So, since the options you're passing are not part of a struct, ode45 takes the syntax to be
[t,y] = ode45(odefun,tspan,y0,extra1,extra2,extra3,extra4);
and, via feval, will make the call odefun(t,y,extra1,extra2,extra3,extra4). A minor rewrite using odeset should do the job nicely:
options = odeset('RelTol', 1e-6, 'AbsTol', 1e-8);
[tout, yout] = ode45(f, [0 100], y0, options);