如果需要超过指定的时间,我想停止在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建议的完全相同。但现在它每次都会超时,而以前这种情况偶尔会发生。我做错了什么?
答案 0 :(得分:2)
首先,你不能做任何你正在尝试的事情。所有这一切都会发生ode15s
只要它需要就会运行并像往常一样返回它的结果。当超过一定的指定时间时,您需要一种在执行过程中中断ODE求解器的方法。不幸的是,您没有提供可运行的代码,因此我必须提供一些可以适应您的问题的一般性建议。
实现此目的的一种方法是通过Output function。这是在Matlab求解器的每个(成功)积分步骤之后调用的函数。有几个输出函数的示例,您可以检查代码以查看您可以执行的操作:odeplot
,odeprint
,odephas2
和odephas3
。只需在命令窗口中键入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
获得返回值。在您的申请中,这可能是也可能不是。有可能解决这个问题,但他们需要更多代码。您可以做的一件简单事情是使用传递到输出函数的t
和y
值,使用错误消息返回系统的上次和状态(当它被中断时)。 Event functions也可以用于根据已用时间终止集成 - 这些可能允许您仍然从ode15s
返回输出。