Matlab - 有时 ode45 需要很长时间才能 return

Matlab - sometimes ode45 takes long time to return

这是代码

global a b c
a=35
b=3
c=28

for R = a-3 : a+3
    for N = b-2 : b+2
        for L = c-2 : c+2
            a=R;
            b=N;
            c=L;
            ode_interupt_demo
            plot3(x(:,3), x(:,2), x(:,1));
            S= [R N L]
            pause(1)
            close
        end
    end
end

function dxdt=fun1(t,x)
global a b c
 
dxdt(1)=a*(x(2)-x(1));
dxdt(2)=(c-a)*x(1)-x(1)*x(3)+c*x(2);
dxdt(3)=x(1)*x(2)-b*x(3);
dxdt=dxdt';
end

function status = interuptFun(t,y,flag,interupt_time)   %#ok<INUSL>
persistent INIT_TIME;
status = 0;
switch(flag)
    case 'init'
        INIT_TIME = tic;
    case 'done'
        clear INIT_TIME;
    otherwise
        elapsed_time = toc(INIT_TIME);
        if elapsed_time > interupt_time
            clear INIT_TIME;
            str = sprintf('%.6f',elapsed_time);
            error('interuptFun:Interupt',...
                 ['Interupted integration. Elapsed time is ' str ' seconds.']);
        end
end


function ode_interupt_demo

tspan = [0 10]; y0 = [0.5 1 1];
interupt_time = 10;
outputFun= @(t,y,flag)interuptFun(t,y,flag,interupt_time);
opts = odeset('AbsTol',1e-8,'RelTol',1e-5,'OutputFcn',outputFun);

try
    [t,x] = ode45(@fun1,tspan,y0,opts);
    
catch ME
    if strcmp(ME.identifier,'interuptFun:Interupt')
        disp(ME.message);
        % Do other things
    else
        rethrow(ME); % It's possible the error was due to something else
    end
end

在 Matlab 中我正在求解一个微分方程,但有时需要 ode45 很长时间才能 return。我使用了 this post 中建议的代码来解决我的类似问题,但它不会 return 来自 ode45 的值。相反,我得到

??? Undefined variable x.

Error in ==> goo at 13
plot3(x(:,3), x(:,2), x(:,1));

错误如其所言...未定义的变量x。您没有在代码中的任何地方定义它,但您在第 13 行立即开始使用它。但是,在第 13 行之前有一个函数调用,看起来 ODE 求解是在那里执行的......但是你不从函数调用返回 x。请记住,函数中定义的任何变量都在局部范围内。这意味着在退出时,那些先前声明的变量将消失...除非您将变量设置为 globalpersistent

因为您想在函数调用后使用 x,修复代码最简单的方法是修改函数定义,使其 returns x,然后赋值x 在您使用它之前作为函数调用的输出。

因此,修改您的 ode_interupt_demo 函数声明,使其执行以下操作:

function x = ode_interupt_demo

接下来,让第 12 行执行此操作:

x = ode_interupt_demo;

代码现在应该可以工作了。