MATLAB: альтернативы вызову feval в ode45 - PullRequest
1 голос
/ 27 марта 2011

Надеюсь, я здесь по теме. Я спрашиваю здесь, так как он сказал на странице часто задаваемых вопросов: вопрос, касающийся (среди прочего) программного алгоритма :) Итак, вот оно:

Мне нужно решить систему ODE (например, $ \ dot x = A (t) x $. Матрица A может измениться и задается в виде строки в вызове функции (Calc_EDS_v2 ('Sys_EDS_a', ... )
Затем я использую ode45 в цикле, чтобы найти мой x:

function [intervals, testing] = EDS_calc_v2(smA,options,debug)  
[..]
for t=t_start:t_step:t_end)
    [Te,Qe]=func_int(@intQ_2_v2,[t,t+t_step],q);
    q=Qe(end,:);
    [..]
end
[..]

с func_int как ode45 и @ intQ_2_v2 мой m-файл. q возвращается к вызову как начальный вектор. Как вы видите, я просто использую ode45 на интервале [t, t + t_step]. Это потому, что моя системная матрица A может заставить ode45 выполнять много шагов, что приводит к быстрому попаданию в AbsTol или RelTol.

Теперь мой A - это что-то вроде B (t) * Q (t), поэтому в m-файле intQ_2_v2.m мне нужно оценить и B, и Q в моменты времени t. Сначала я сделал это так: (v1 -файл, поэтому имя функции другое)

function q=intQ_2_v1(t,X)  
[..] 
B(1)=...; ...   B(4)=...;
Q(1)=...; ...

чем это, естественно, только при условии, что A является матрицей 2x2. При такой настройке базовая система вычислялась где-то между 10 и 15 секундами.

Вместо вышеизложенного я теперь использую файлы B1.m до B4.m и Q1.m до B4.m (я знаю, что это не элегантно, но мне нужно использовать quadgk для B позже, и quadgk не поддерживает матричные функции.)

function q=intQ_2_v2(t,X)  
[..]
global funcnameQ, funcnameB, d
for k=1:d
Q(k)=feval(str2func([funcnameQ,int2str(k)]),t);
B(k)=feval(str2func([funcnameB,int2str(k)]),t);
end
[..]

funcname (строка), ссылающаяся на B или Q (с добавленным k), а d - это размерность системы.

Теперь я знал, что это будет стоить мне больше времени, чем первая версия, но я вижу, что время вычислений в десять раз выше! (получая от 150 до 160 секунд) Я понимаю, что открытие 4 файлов и оценка примерно 40 раз в цикле ode обходится дорого ... и я также не могу предварительно оценить B и Q, так как ode45 использует адаптивные размеры шагов ...

Есть ли способ не использовать этот последний цикл?

В основном меня интересует решение, позволяющее сократить время вычислений. У меня есть ощущение, что я что-то упускаю ... но не могу понять, как это сделать. Так как это занимает почти три минуты вместо 10 секунд, я могу выпить кофе между каждым тестом сейчас ... (пожалуйста, не говорите мне, чтобы получить более быстрый компьютер)

(простите за такой длинный вопрос)

1 Ответ

1 голос
/ 27 марта 2011

Я не уверен, что полностью понимаю, что вы здесь делаете, но могу предложить несколько советов.

  1. Используйте профилировщик, это поможет вам точно понять, гдеузкими местами являются.

  2. Использование feval медленнее, чем непосредственное использование функциональных дескрипторов, особенно при использовании str2func для создания дескриптора каждый раз.Также есть замедление от использования глобальных переменных (и это хорошая привычка избегать их, если в этом нет крайней необходимости).Каждый из них действительно складывается при многократном использовании (как это выглядит здесь).Сохраните дескрипторы функции для каждого из ваших mfiles в массиве ячеек и передайте их непосредственно в функцию или используйте вложенную функцию для оптимизации, чтобы массив ячеек ячеек был виден оптимизируемой функции.Лично я предпочитаю вложенный метод, но лучше передать его, если вы будете использовать эти mfiles в другом месте.

Я ожидаю, что это вернет время выполнения к тому, что дал первый метод.Обязательно сообщите нам, если это была проблема или вы нашли другое решение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...