Matlab ode求解器:改变状态和指定时间

时间:2013-06-28 01:51:54

标签: matlab solver ode numerical-integration

我在t = 0处求解一组ODE(dy / dt),所有初始条件t = 0 y_0 =(0,0,0)。我可以在不同的时间向y值添加一些数字(例如,在t = 10时,y1应该添加到该数字;在t = 20时,y2应该添加到该数字,等等)并求解方程式?< / p>

2 个答案:

答案 0 :(得分:0)

好的,就像Simon McKenzie说我们确实需要更多关于紧急问题的信息,但我想我可以提供帮助。根据你给我们的内容,我假设你有一个函数myfun,你传递给ode45

y_0 = [0,0,0];
% here Tfinal is the time in seconds that you want to simulate to
% and specify the tspan so that you will get a solution at each whole
% number of seconds, I believe
[t,y] = ode45(@myfun,[0:0.1:Tfinal],y_0);

在某个地方你定义了你的功能,我在这里称之为myfun

function dy = myfun(t,y)
  % here let's check to see if it's time to add your offsets
  % still, you may want to put a little fudge factor for the time, but
  % you'll have to experiment, I'll set it up though
  EPS = 1e-12;
  if( t < 10 + EPS || t > 10 - EPS )
    y(1) = y(1) + 10;
  .
  .
  .
  .
  % this only makes sense if you then use y(1) in the compuatation

否则,只需将偏移量添加到返回的解决方案向量中,即

idx10 = find( t == 10 ); % should be there since it's in the tspan
y(idx10:end) = y(idx10:end) + 10; % I guess you add it from that point on?

答案 1 :(得分:0)

以您建议的方式(以及@macduff所示的方式)在您的ODE中插入大的不连续性会导致精度降低和计算时间延长(尤其是使用ode45 - ode15s可能会更好选项或至少确保您的绝对和相对公差是合适的)。你已经有效地制作了一部stiff system。如果要在特定时间开始向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编辑器可能会抱怨数组TY未被预先分配和/或增长,但在这种情况下它很好,因为它们只在大块中生长了几次。或者,如果您想要固定输出步长,您可以这样做:

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
    ...