如上所述:我希望计算连续变量随时间的最小值(和/或最大值)。这是一个演示的最小例子:
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
是任意连续变量(出于演示目的,是一个简单的正弦波)。
u_min
/ u_max
是随时间变化的最小值/最大值。
显然,预期结果为u_min=-1
和u_max=1
。不幸的是,模拟以“Matrix奇异!”崩溃了。错误。任何人都可以指导我如何避免这种情况吗?
我正在使用OpenModelica 1.15(原为1.9.2)
由于我对Modelica很陌生,我很难理解以下方法之间的差异:
u_min = if noEvent(u < u_min) then u else pre(u_min);
if noEvent(u < u_min) then
u_min = u;
else
u_min = pre(u_min);
end if;
u_min = if noEvent(u < u_min) then u else u_min;
u_min = if u < u_min then u else pre(u_min);
u_min = if u < u_min then u else u_min;
when u < u_min then
u_min = u;
end when;
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中使用它。它似乎工作如果我比较常数值(对于这个特定问题没有用)。
u_min = smooth(0, if u < u_min then u else pre(u_min));
有趣的是,这也有效。
答案 0 :(得分: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
会“卡住”达到该时间点达到的最大值。
很抱歉,但由于这是我的第一个回复,因此无法发布模型的运行图像。
答案 1 :(得分:2)
这里的主要问题是你得到一个单数的方程,因为你试图解决方程 u_min = min(u,u_min)
。如果u_min取决于u和u_min,并且u_min
的{{1>}的每个值小于u
都适合等式,那么工具也可能会尝试为此使用非线性求解器。
另一个解决方案可能是延迟算子:
u_min = min(u, delay(u_min,0));
u_max = max(u, delay(u_max,0));
关于不同方法的一些注释:
u_min = if noEvent(u < u_min) then u else pre(u_min);
if noEvent(u < u_min) then
u_min = u;
else
u_min = pre(u_min);
end if;
这两者在语义上是相同的,因此结果应该是相同的。此外,pre运算符的使用解决了这个问题,因为此处u_min
取决于u
和pre(u_min)
,因此不需要非线性求解器。
u_min = if noEvent(u < u_min) then u else u_min;
如上所述min()
使用u_min
,u
的解决方案取决于u_min
和noEvent()
,这导致非线性解决方案。
u < u_min
运算符的语义在字面上使用了if-expression,在这种情况下,触发事件u_min = u
并且始终使用表达式u_min = if u < u_min then u else u_min;
。 / p>
when u < u_min the
u_min = u;
end when;
是的,它结合了3和4的问题。
u_min
此处u_min
的解决方案再次取决于u
和u_min + T*der(u_min) = if u <= u_min then u else u_min;
。
activity starter
这里u_min是一个状态,因此u_min的计算由积分器完成,此方程现在求解为der(u_min),然后影响u_min。
答案 2 :(得分:1)
对于您的初步问题,OpenModelica中似乎正常工作的是:
u_min = min(u, pre(u_min));
u_max = max(u, pre(u_max));
对我来说,编译,模拟并给出预期的结果,但也会说“Matrix singular!”。另一方面,如果我将u_max的初始声明更改为:
Real u_max(start = 0);
然后,“矩阵奇异!”走开了。
我不知道为什么,但这似乎确实起到了作用,我建议比你列出的其他选项更直接。