按照您建议的方式(以及 @macduff 所示的方式)在 ODE 中插入大的不连续性可能会导致精度降低和计算时间更长(尤其是在使用ode45
- ode15s可能是更好的选择,或者至少确保您的绝对和相对公差合适)。你已经有效地制作了一个非常刚性系统。如果您想在特定时间开始向 ODE 添加一些数字,请记住,求解器仅在其自己选择的特定时间点计算这些方程。 (不要被以下事实误导:您可以通过指定获得固定步长输出tspan
作为两个以上的元素 - Matlab 的所有求解器都是可变步长求解器,并根据误差标准选择其真实步数。)
更好的选择是分段集成系统并将每次运行的结果输出附加在一起:
% t = 0 to t = 10, pass parameter a = 0 to add to ODEs
a = 0;
tspan = [0 10];
[T,Y] = ode45(@(t,y)myfun(t,y,a),tspan,y_0);
% t = 10 to t = 20, pass parameter a = 10 to add to ODEs
a = 10;
[t,y] = ode45(@(t,y)myfun(t,y,a),tspan+T(end),Y(end,:));
T = [T;t(2:end)];
Y = [Y;y(2:end,:)];
% t = 20 to t = 30, pass parameter a = 20 to add to ODEs
a = 20;
[t,y] = ode45(@(t,y)myfun(t,y,a),tspan+T(end),Y(end,:));
T = [T;t(2:end)];
Y = [Y;y(2:end,:)];
Matlab 编辑器可能会抱怨数组T
and Y
没有被预先分配和/或增长,但在这种情况下很好,因为它们只增长了几次大块。或者,如果您想要固定的输出步长,您可以这样做:
dt = 0.01;
T = 0:dt:30;
Y = zeros(length(T),length(y_0));
% t = 0 to t = 10, pass parameter a = 0 to add to ODEs
a = 0;
[~,Y(1:10/dt+1,:)] = ode45(@(t,y)myfun(t,y,a),T(1:10/dt+1),y_0);
% t = 10 to t = 20, pass parameter a = 10 to add to ODEs
a = 10;
[~,Y(10/dt+1:20/dt+1,:)] = ode45(@(t,y)myfun(t,y,a),T(10/dt+1:20/dt+1),Y(10/dt+1,:));
% t = 20 to t = 30, pass parameter a = 20 to add to ODEs
a = 20;
[~,Y(20/dt+1:end,:)] = ode45(@(t,y)myfun(t,y,a),T(20/dt+1:end),Y(20/dt+1,:));
人们可以轻松地将上述两个代码块转换为更紧凑的代码for
如果需要的话可以循环。
在这两种情况下你的 ODE 函数myfun
包含参数a
这边走:
function ydot = myfun(t,y,a)
y(1) = ... % add a however you like
...