在Matlab中指定的时间长度后停止集成

时间:2014-08-30 11:33:42

标签: matlab ode numerical-integration

如果需要超过指定的时间,我想停止在Matlab中求解微分方程。我尝试了以下方法,但它不起作用......

    options = odeset('AbsTol',1e-8,'RelTol',1e-5);
    RUNTIME=5;
    timerID = tic;
    while (toc(timerID) < RUNTIME)
        [t_pae,x_th_pae] = ode15s(@prosomoiwsh,[0 t_end],[80*pi/180;0;130*pi/180;0;th_initial(1);th_initial(2);th_initial(3);th_initial(4)],options);
    end

我该如何解决这个问题?

更新: 我尝试了霍克勒建议的内容,现在我的代码看起来像这样:

    interupt_time = 20;
    outputFun= @(t,y,flag)interuptFun(t,y,flag,interupt_time);
    options = odeset('AbsTol',1e-5,'RelTol',1e-5,'OutputFcn',outputFun);

    try
        [t_pae,x_b_th_pae] = ode15s(@prosomoiwsh,[0 t_end],[0;0;0;th_initial(1);th_initial(2);th_initial(3);th_initial(4);th_initial(5);th_initial(6);th_initial(7);th_initial(8);th_initial(9);th_initial(10);th_initial(11);th_initial(12)],options);
        u_pae=compute_input(epsilon,ke,kv,dD,IwF,IwG,IwD,IbF,IbG,IbD,p,m,t_pae,x_b_th_pae);  
    catch ME
        if strcmp(ME.identifier,'interuptFun:Interupt')
            disp(ME.message);
            input('got caught')
        else
            rethrow(ME); % It's possible the error was due to something else
        end
    end

   function dx_b_th = prosomoiwsh(t,x_b_th)
   ...
   end

outputFun与一个horchler建议的完全相同。但现在它每次都会超时,而以前这种情况偶尔会发生。我做错了什么?

1 个答案:

答案 0 :(得分:2)

首先,你不能做任何你正在尝试的事情。所有这一切都会发生ode15s只要它需要就会运行并像往常一样返回它的结果。当超过一定的指定时间时,您需要一种在执行过程中中断ODE求解器的方法。不幸的是,您没有提供可运行的代码,因此我必须提供一些可以适应您的问题的一般性建议。

实现此目的的一种方法是通过Output function。这是在Matlab求解器的每个(成功)积分步骤之后调用的函数。有几个输出函数的示例,您可以检查代码以查看您可以执行的操作:odeplotodeprintodephas2odephas3。只需在命令窗口中键入edit odeplot即可查看代码。

以下是如何使用vdp1000帮助中引用的内置示例函数ode15s来使用此功能的示例。您需要创建一个持久变量来保存初始时间,初始化它,然后检查相对于您传入的参数的已用时间。如果经过的时间超过指定的时间,则抛出错误以中止ode15s值。可以使用try-catch语句来捕获错误。

function ode_interupt_demo

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

try
    [t,y] = ode15s(@vdp1000,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


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

这种方法的一个缺点是你不会从ode15s获得返回值。在您的申请中,这可能是也可能不是。有可能解决这个问题,但他们需要更多代码。您可以做的一件简单事情是使用传递到输出函数的ty值,使用错误消息返回系统的上次和状态(当它被中断时)。 Event functions也可以用于根据已用时间终止集成 - 这些可能允许您仍然从ode15s返回输出。