Остановить интеграцию через определенное время в Matlab
Я хочу прекратить решение дифференциального уравнения в 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 точно такой же, как предложенный один хоршлер. Но теперь это время истекает каждый раз, в то время как раньше это происходило только изредка Что я делаю неправильно?
1 ответ
Во-первых, вы не можете делать то, что пытаетесь. Все, что произойдет, это ode15s
будет работать столько времени, сколько потребуется, и вернет свой результат как обычно. Вам нужен способ прерывания решателя ODE в середине его выполнения, когда превышено определенное время. К сожалению, вы не предоставили исполняемый код, поэтому мне придется предоставить общие рекомендации, которые вы можете адаптировать к вашей проблеме.
Один из способов сделать это - через функцию вывода. Эта функция вызывается после каждого (успешного) шага интеграции решателя 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 могут использоваться для прекращения интеграции на основе истекшего времени - это может позволить вам по-прежнему возвращать выходные данные из ode15s
,