简体   繁体   English

在Matlab中使用ode45

[英]Using ode45 in Matlab

I'm trying to simulate the time behavior for a physical process governed by a system of ODEs. 我正在尝试模拟由ODE系统控制的物理过程的时间行为。 When I switch the width of the input pulse from 20 to 19 , there is no depletion of the y(1) state, which doesn't make sense physically. 当我将输入脉冲的width20切换到19 ,不会耗尽y(1)状态,这在物理上是没有意义的。 What am I doing wrong? 我究竟做错了什么? Am I using ode45 incorrectly? 我是否使用ode45错误?

function test

width = 20;
center = 100;

tspan = 0:0.1:center+50*(width/2);

[t,y] = ode45(@ODEsystem,tspan,[1 0 0 0]);

plot(t,y(:,1),'k*',t,y(:,2),'k:',t,y(:,3),'k--',t,y(:,4),'k');
hold on;
axis([center-3*(width/2) center+50*(width/2) -0.1 1.1])
xlabel('Time')
ylabel('Relative values')
legend({'y1','y2','y3','y4'});

    function dy = ODEsystem(t,y)
        k1 = 0.1;
        k2 = 0.000333;
        k3 = 0.1;

        dy = zeros(size(y));

        % rectangular pulse
        I = rectpuls(t-center,width);

        % ODE system
        dy(1) = -k1*I*y(1);
        dy(2) = k1*I*y(1) - k2*y(2);
        dy(3) = k2*y(2) - k3*I*y(3);
        dy(4) = k3*I*y(3);
    end
end

You are changing the parameters of your your ODEs discontinuously in time. 您正在不连续地更改ODE的参数。 This results in a very stiff system and less accurate, or even completely wrong, results. 这样会导致系统非常僵硬 ,结果准确性会降低,甚至完全错误。 In this case, because the your ODE is so simple when I = 0 , an adaptive solver like ode45 will take very large steps. 在这种情况下,由于当I = 0时ODE非常简单,因此像ode45这样的自适应求解器将采取非常大的步骤。 Thus, there's a high probability that it will step right over the region where you inject the impulse and never see it. 因此,很有可能会在您注入脉冲的区域上空步进,并且永远看不到它。 See my answer here if you're confused as to why the code in your question misses the pulse even though you've specified tspan to have (output) steps of just 0.1 . 如果您对问题中的代码为何错过了脉冲感到困惑,即使您已将tspan指定为(输出)步长仅为0.1 ,也请在此处查看我的答案

In general it is a bad idea to have any discontinuities ( if statements, abs , min / max , functions like rectpuls , etc.) in your integration function. 通常,在集成函数中具有任何不连续性( if语句, absmin / max ,诸如rectpuls等的函数)是一个坏主意。 Instead, you need to break up the integration and calculate your results piecewise in time. 相反,您需要拆分积分并按时间分段计算结果。 Here's a modified version of your code that implements this: 这是实现此目的的代码的修改版本:

function test_fixed

width = 19;
center = 100;

t = 0:0.1:center+50*(width/2);
I = rectpuls(t-center,width); % Removed from ODE function, kept if wanted for plotting

% Before pulse
tspan = t(t<=center-width/2);
y0 = [1 0 0 0];
[~,out] = ode45(@(t,y)ODEsystem(t,y,0),tspan,y0); % t pre-calculated, no need to return
y = out;

% Pulse
tspan = t(t>=center-width/2&t<=center+width/2);
y0 = out(end,:); % Initial conditions same as last stage from previous integration
[~,out] = ode45(@(t,y)ODEsystem(t,y,1),tspan,y0);
y = [y;out(2:end,:)]; % Append new data removing identical initial condition

% After pulse
tspan = t(t>=center+width/2);
y0 = out(end,:);
[~,out] = ode45(@(t,y)ODEsystem(t,y,0),tspan,y0);
y = [y;out(2:end,:)];

plot(t,y(:,1),'k*',t,y(:,2),'k:',t,y(:,3),'k--',t,y(:,4),'k');
hold on;
axis([center-3*(width/2) center+50*(width/2) -0.1 1.1])
xlabel('Time')
ylabel('Relative values')
legend({'y1','y2','y3','y4'});

    function dy = ODEsystem(t,y,I)
        k1 = 0.1;
        k2 = 0.000333;
        k3 = 0.1;

        dy = zeros(size(y));

        % ODE system
        dy(1) = -k1*I*y(1);
        dy(2) = k1*I*y(1) - k2*y(2);
        dy(3) = k2*y(2) - k3*I*y(3);
        dy(4) = k3*I*y(3);
    end
end

See also my answer to a similar question . 另请参阅我对类似问题的回答

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM