Остановить интеграцию по истечении заданного промежутка времени в 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 точно такой же, как предложил один Хорхлер. Но теперь это происходит каждый раз, а раньше это случалось только изредка. Что я делаю не так?


person Controller    schedule 30.08.2014    source источник
comment
Что значит не работает? Есть ли ошибка? Пожалуйста, будьте конкретны.   -  person darthbith    schedule 30.08.2014
comment
Почему вы хотите прервать численное интегрирование по времени? Лучше пересмотрите свои допуски на ошибки.   -  person fuesika    schedule 30.08.2014
comment
@pyStarter: я не знаю о случае OP, но я могу представить случаи, когда можно не иметь полного контроля над параметрами или начальными условиями. Или, если кто-то просматривает пространство параметров, некоторые ОДУ могут иметь сингулярности или другие явления, которые могут вызывать числовые или другие проблемы. Простая настройка допусков только снизит точность результатов, которые возвращаются в течение заданного промежутка времени.   -  person horchler    schedule 30.08.2014
comment
Да, дело именно в том, что сказал @horchler ... Я вызываю ODE из GA, и для некоторых конфигураций параметров требуется много времени, пока не появится предупреждение о невозможности уменьшить минимальный размер шага. Пробовал увеличивать минимальный шаг решателя,но так как прямого способа сделать это нет,а через допуски либо не получилось либо мне не удалось этого добиться...   -  person Controller    schedule 30.08.2014
comment
@darthbith ошибки нет, но если я попытаюсь повторить код, который я написал 5 раз, это не займет 25 секунд ... Это может занять 5 часов ...   -  person Controller    schedule 30.08.2014


Ответы (1)


Во-первых, вы не можете сделать ничего подобного тому, что пытаетесь сделать. Все, что произойдет, это то, что ode15s будет работать столько, сколько ему нужно, и вернет результат, как обычно. Вам нужен способ прерывания решателя ОДУ в середине его выполнения, когда превышено определенное заданное количество времени. К сожалению, вы не предоставили исполняемый код, поэтому мне придется дать общие рекомендации, которые вы можете адаптировать к своей проблеме.

Одним из способов сделать это является использование функции вывода. Это функция, которая вызывается после каждого (успешного) шага интеграции решателя 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, переданные в выходную функцию. Также возможно, что для прекращения интеграция на основе прошедшего времени — это может позволить вам по-прежнему возвращать вывод из ode15s.

person horchler    schedule 30.08.2014
comment
Я не знаю, получают ли люди уведомление, когда первоначальный пост редактируется, так что не могли бы вы взглянуть, пожалуйста? - person Controller; 02.09.2014
comment
@PavlosTriantafyllou: Трудно сказать, так как ваш обновленный код тоже не работает. Абсолютные допуски интегрирования различаются в этих двух случаях. Если вы установите interupt_time на гораздо большее значение, будет возвращаться некоторое время или все время (вы упомянули 25 секунд в комментарии выше)? - person horchler; 02.09.2014
comment
Я повторно запускаю код, и кажется, что все конфигурации, которые я пробовал раньше, были проблематичными. Это работает нормально. Извините за потраченное время и еще раз спасибо! - person Controller; 02.09.2014