modelica: вычислить минимум / максимум непрерывной переменной во времени

Как указано выше: я хочу вычислить минимум (и / или максимум) непрерывной переменной с течением времени. Вот минимальный пример для демонстрации:

model MinMaxTest
  Real u;
  Real u_min(start = 10);
  Real u_max(start = -10);
equation
  u = sin(time / 180 * Modelica.Constants.pi);
  u_min = min(u, u_min);
  u_max = max(u, u_max);
  annotation(experiment(StartTime = 0, StopTime = 360, Tolerance = 1e-06, Interval = 1));
end MinMaxTest;

u - произвольная непрерывная переменная (для демонстрационных целей простая синусовая волна). _3 _ / _ 4_ - это минимум / максимум с течением времени.

Очевидно, что ожидаемый результат - u_min=-1 и u_max=1. К сожалению, симуляция вылетает с сообщением «Матрица единственного числа!» ошибка. Может ли кто-нибудь указать мне, как этого избежать?


ИЗМЕНИТЬ 1

Я использую OpenModelica 1.15 (было 1.9.2)

РЕДАКТИРОВАТЬ 2

Поскольку я новичок в Modelica, мне сложно понять разницу между следующими подходами:

  1. u_min = if noEvent(u < u_min) then u else pre(u_min);
  2. if noEvent(u < u_min) then u_min = u; else u_min = pre(u_min); end if;
  3. u_min = if noEvent(u < u_min) then u else u_min;
  4. u_min = if u < u_min then u else pre(u_min);
  5. u_min = if u < u_min then u else u_min;
  6. when u < u_min then u_min = u; end when;
  7. u_min + T*der(u_min) = if u <= u_min then u else u_min;

1 и 2 эквивалентны и приводят к ожидаемому поведению.

3 дает желаемый результат, но дает «Уведомление о переводе» о «алгебраическом цикле», почему?

4 так далеко, что результирующая u_min кривая идентична u ?! Почему?

5 объединяет 3 и 4.

6 не компилируется с Sorry - Support for Discrete Equation Systems is not yet implemented

7 Я не понимаю, в чем заключается идея, но это работает, если T имеет рекомендуемый размер.

Если я правильно понимаю документацию Modelica, то у 1-5 есть общее, что ровно одно уравнение всегда активно. noEvent подавляет генерацию события при указанном переходе через нуль. У меня сложилось впечатление, что это в основном повышение эффективности. Почему его игнорирование приводит к отказу 4? pre относится к предыдущему значению переменной, поэтому я думаю, это имеет смысл, если мы хотим сохранить переменную постоянной, но почему 7 работает без нее? Мое понимание when заключалось в том, что его уравнение активно только в этом конкретном событии, а в противном случае сохраняет предыдущее значение, поэтому я попытался использовать его в 6. Кажется, это сработает, если я сравниваю с константой values ​​(что бесполезно для этой конкретной проблемы).

РЕДАКТИРОВАТЬ3

  1. u_min = smooth(0, if u < u_min then u else pre(u_min));

Интересно, что это тоже работает.


person PeterE    schedule 09.06.2015    source источник
comment
Для этой проблемы существует старый нерешенный тикет: trac.modelica.org/Modelica/ticket/109 < / а>. В SimulationX существует простое решение: u_min = min(u,last(u_min))   -  person Tobias    schedule 29.06.2015
comment
Оператор last не содержится в спецификации Modelica (до последней версии 3.3 rev.1). Это особенность SimulationX (и описана в ее документации). Возможно, вы имеете в виду pre-оператор.   -  person Tobias    schedule 29.06.2015
comment
@Tobias, ты прав. Я неправильно прочитал это как pre. Я понял это сразу после публикации и удалил свой комментарий. Извините за путаницу.   -  person PeterE    schedule 29.06.2015
comment
Я поместил специальное решение SimulationX в stackoverflow.com/questions/31134220/   -  person Tobias    schedule 30.06.2015


Ответы (3)


Я протестировал вашу модель с Dymola 2016, и она работает, однако вы можете попробовать использовать альтернативный подход. В Modelica вы должны думать в терминах уравнений, а не в терминах заданий.

u_min = min(u, u_min);

Это то, что вы сделали бы, если бы код выполнялся как последовательность инструкций. Под капотом инструмент Modelica преобразует это уравнение в нелинейную систему, которая решается в процессе моделирования.

Это статистика, которую я получаю при моделировании вашей модели.

Statistics

Original Model
Number of components: 1
Variables: 3
Unknowns: 3 (3 scalars)
Equations: 3
Nontrivial: 3

Translated Model
Time-varying variables: 3 scalars
Number of mixed real/discrete systems of equations: 0
Sizes of linear systems of equations: { }
Sizes after manipulation of the linear systems: { }
Sizes of nonlinear systems of equations: {1, 1}
Sizes after manipulation of the nonlinear systems: {1, 1}
Number of numerical Jacobians: 0

Как видите, есть две нелинейные системы: одна для u_min, а другая для u_max.

Альтернативным решением вашей проблемы является следующее

model Test
  Real x;
  Real y;
  Real u_min;
  Real u_max;
  parameter Real T = 1e-4;
equation 
  x = sin(time) + 0.1*time;
  y = sin(time) - 0.1*time;
  u_min + T*der(u_min) = if y <= u_min then y else u_min;
  u_max + T*der(u_max) = if x >= u_max then x else u_max;

end Test;

В этом случае u_min и u_max - две переменные состояния, и они следуют за переменными x и y в зависимости от их значений. Например, когда x ниже, чем u_max, тогда u_max "застревает" на максимальном значении, достигнутом к этому моменту времени.

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

person Marco Bonvini    schedule 09.06.2015
comment
Спасибо за вашу помощь. Я знал, что u_min = min(u, u_min); приведет к нелинейному уравнению, но я не мог придумать ничего лучшего. В качестве альтернативы, почему вы используете u_min + T*der(u_min) как левую часть, а не просто u_min? - person PeterE; 10.06.2015
comment
Привет @peter, в моем решении введение переменной состояния похоже на добавление небольшого расслабления к исходной проблеме. Это делает задачу линейной, однако количество переменных состояния увеличивается. Вы можете рассматривать этот метод как непрерывную временную версию одноступенчатой ​​задержки в системе, которая периодически дискретизируется. Чем меньше T, тем ближе она к исходной проблеме. С другой стороны, небольшие значения T уменьшают постоянную времени системы и потенциально могут сделать ее жесткой. Вы должны выбрать T в зависимости от динамики наблюдаемых вами переменных. - person Marco Bonvini; 11.06.2015

Что касается вашего первоначального вопроса, то, как мне кажется, правильно работает в OpenModelica:

u_min = min(u, pre(u_min));
u_max = max(u, pre(u_max));

Для меня это компилирует, моделирует и дает ожидаемые результаты, но также говорит: «Матрица единственная!». С другой стороны, если я изменю начальное объявление для u_max на это:

Real u_max(start = 0);

Тогда "Матрица сингулярная!" уходит.
Я не знаю почему, но, похоже, это работает, и я бы посоветовал сделать его более простым, чем другие варианты, которые вы перечислили.

person Adam    schedule 10.06.2015

Основная проблема здесь в том, что вы получаете уравнение, которое является сингулярным, поскольку вы пытаетесь решить уравнение u_min = min(u,u_min). Если u_min зависит от u и u_min, а каждое значение u_min, которое меньше u, вписывается в это уравнение, инструмент также может попытаться использовать нелинейный решатель для что. Другим решением для этого может быть оператор задержки:

  u_min = min(u, delay(u_min,0));
  u_max = max(u, delay(u_max,0));

Некоторые примечания о различных подходах:

  1. u_min = if noEvent(u < u_min) then u else pre(u_min);
  2. if noEvent(u < u_min) then u_min = u; else u_min = pre(u_min); end if;

Оба они семантически идентичны, поэтому результат должен быть одинаковым. Также использование оператора pre решает проблему, поскольку здесь u_min зависит от u и pre(u_min), поэтому нет необходимости в нелинейном решателе.

  1. u_min = if noEvent(u < u_min) then u else u_min;

Как и выше, где здесь используется min(), решение u_min зависит от u и u_min, что приводит к нелинейному решению.

  1. u_min = если u ‹u_min, то u else pre (u_min);

Семантика оператора noEvent() приводит к буквальному использованию выражения if, в этом случае здесь запускается событие u < u_min, а выражение u_min = u используется все время.

  1. u_min = if u < u_min then u else u_min;

Да, он сочетает в себе задачи 3 и 4.

  1. when u < u_min the u_min = u; end when;

Здесь снова решение u_min зависит от u_min и u.

  1. u_min + T*der(u_min) = if u <= u_min then u else u_min;

Здесь u_min - это состояние, поэтому вычисление u_min выполняется интегратором, и теперь это уравнение решается для der (u_min), которое затем влияет на u_min.

person Willi    schedule 10.06.2015