Остановить интеграцию через определенное время в 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,

Другие вопросы по тегам