Вызов fmincon из Simulink

Я пытаюсь реализовать определенный тип прогнозирующего управления моделью в среде Simulink-Matlab. Для этого я планировал, чтобы динамическая модель в Simulink вызывала внешнюю S-функцию Matlab, которая, в свою очередь, запускала оптимизацию, вызывающую другой файл Simulink. Следовательно, поток программы будет следующим: Simulink -> Matlab (fmincon или quadprog) -> Simulink.

Как видите, S-функция Matlab будет вызывать либо fmincon, либо quadprog, но я хотел бы использовать fmincon для своего конкретного типа управления. Пожалуйста, пока игнорируйте любые вопросы, связанные с вычислительной эффективностью.

Я попробовал этот подход, но есть две очень явные проблемы: * Во-первых, чтобы скомпилировать код без ошибок (по сути, получение .mex-файла, мне пока не нужно программировать на C), я добавил команду

coder.extrinsic('fmincon');

Это было необходимо, поскольку в противном случае Simulink не сможет скомпилировать mex-файл. Однако, если вы сделаете это, вы получите следующую ошибку:

Function handles cannot be passed to extrinsic functions.

Я попытался изменить свою функцию стоимости, вызывающую Simulink, на другую, более простую функцию стоимости (x.^2), но все еще получаю сообщение об ошибке.

В поисках решения проблемы я нашел тот же вопрос (т.е. как вызвать fmincon из функции Matlab в Simulink) в блоге Mathworks, но без ответа (https://uk.mathworks.com/matlabcentral/answers/65202-optimization-calling-fmincon-in-simulink-embedded-block).

Может ли кто-нибудь дать мне руку? Заранее спасибо!


person Enrico Anderlini    schedule 05.02.2017    source источник
comment
Судя по вашему описанию, вы используете блок MATLAB Function, а не S-функцию m-кода. Блоки MATLAB Function преобразуются в C и компилируются во время инициализации модели и поддерживают только подмножество языка MATLAB. Вам нужно написать m-код S-функции. Они не преобразуют m-код в C, а запускают его (как интерпретируемый код) в стандартном вычислительном движке MATLAB и, следовательно, поддерживают полный язык MATLAB.   -  person Phil Goddard    schedule 05.02.2017
comment
Что вы также можете сделать, так это использовать только блок MATLAB Function в качестве оболочки вокруг другой функции m-кода. В MATLAB Function вы определяете свою другую функцию как внешнюю и просто передаете ей соответствующие входные данные и получаете результат обратно в модель Simulink. Затем в другой функции определите оптимизацию, которую необходимо выполнить.   -  person Phil Goddard    schedule 06.02.2017
comment
Спасибо! Вы правы, чтобы сэкономить время при программировании, я выбрал функциональный блок Matlab. Теперь я попробую еще раз и вместо этого выражу это как S-функцию.   -  person Enrico Anderlini    schedule 06.02.2017
comment
Я попробовал второй подход, и он также работает. Тем не менее, я думаю, что подход S-функции более аккуратен. Если вы опубликуете ответ, резюмирующий ваши два пункта, я проголосую за него.   -  person Enrico Anderlini    schedule 06.02.2017
comment
@PhilGoddard Поправьте меня, если я ошибаюсь, но из документации Mathworks (S-Func; MATLAB Func), может показаться, что оба они скомпилированы в C MEX. Кроме того, из второй ссылки: внешние функции выполняются в рабочей области во время моделирования модели, поэтому они интерпретируются в MATLAB. Не уверен, откуда берется ошибка OP, упомянутая с fmincon.   -  person Filip Cvejic    schedule 11.10.2020
comment
Я думаю, что есть некоторая информация об ошибке Function handles cannot be passed to extrinsic functions здесь.   -  person Filip Cvejic    schedule 11.10.2020
comment
Я решил проблему, но спасибо за это! Функция MATLAB действительно скомпилирована в C MEX, но S-функции обычно более настраиваемы.   -  person Enrico Anderlini    schedule 12.10.2020


Ответы (1)


Вместо того, чтобы использовать coder.extrinsic для функции fmincon, я обычно пишу оболочку для задачи оптимизации, которую мне нужно решить как файловую функцию .m для Matlab (а именно opt_problem), и объявляю coder.extrinsic('opt_problem') в функции Simulink Matlab. Я приведу простой пример:

Рассмотрим эту «модель» Simulink, в которой на каждом шаге интеграции я хочу решить задачу линейной регрессии для некоторых сгенерированных данных. Задача оптимизации имеет вид:

minimize (y - m x - q)²
subject to  0 ≤ m ≤ 1
            0 ≤ q ≤ 1

Схема действительно проста, спорим, регрессор вызывает fmincon:

введите здесь описание изображения

Заглянем внутрь регрессора:

function [m, q] = regressor(xs, ys, mic, qic)
  coder.extrinsic('opt_problem'); % <- Informing the Coder
  m = 0;
  q = 0;
  [m, q] = opt_problem(xs, ys, mic, qic); % <- Optimal problem wrapper call
end

эта функция является только оболочкой для внешней функции opt_problem. Давайте посмотрим на это (у него внутри две функции):

function [m, q] = opt_problem(xs, ys, mic, qic)
  fmincon_target = @(mq)(target(mq, xs, ys));
  mq = fmincon(fmincon_target, [mic; qic], [], [], [], [], [0; 0], [1; 1]);
  m = mq(1);
  q = mq(2);
end

function r = target(mq, xs, ys)
  r = norm(ys - xs.*mq(1) - mq(2));
end

и это все. Как вы можете видеть на рисунке, схема работает, и решением являются параметры m, q (на двух дисплеях), которые минимизируют целевую функцию при соблюдении ограничений (m = 1.2 → m_opt = 1).

person Matteo Ragni    schedule 29.05.2018