刚开始使用Modelica并且无法理解它是如何工作的。
在模型的下面'方法'中,qInflow和qOutflow用于第二行来评估der(h),但它们还没有收到值! (它们没有在方法的“数据”中定义)?代码的执行顺序是什么。
equation
assert(minV >= 0, "minV must be greater or equal to zero");
der(h)=(qInflow - qOutflow)/area;
qInflow=if time > 150 then 3*flowLevel else flowLevel;
qOutflow=Functions.LimitValue(minV, maxV, -flowGain*outCtr);
error=ref - h;
der(x)=error/T;
outCtr=K*(error + x);
end FlatTank;
来自http://www.mathcore.com/resources/documents/ie_tank_system.pdf
答案 0 :(得分:5)
当来自使用命令式语义的语言和系统时,这是一个可以理解的混淆点。但Modelica并不像那样工作。
使用Modelica时,务必了解equation
部分包含公式,不是作业。考虑一下,如果我给你以下方程式:
x + y = 3;
x + 2*y = 5;
如果您了解这是一个数学上下文,那么您可以确定x
的值必须为1而y
的值必须为2.换句话说,您必须解决联立方程组。你会注意到这些方程的左边是不变量(一般来说),它们是表达式。方程只是一个关系,它将左侧的一个表达式与右侧的另一个表达式相等。此外,这种关系总是为真,因此顺序无关紧要。
这与具有命令性语义的命令式编程语言完全不同。但它也非常强大,因为你可以陈述这些关系(线性方程组,非线性方程组,隐式方程等),编译器将找出解决它们的最有效方法。
回到您的示例,当您查看问题中的代码时,您将这些方程解释为赋值语句。这个概念得到了加强,因为它们碰巧在左侧有变量。但他们确实是方程式。在基于方程式的系统中,您不必担心先前是否已将指定变量分配给该系统。相反,要求仅仅是对于每个变量,存在(某处)方程,并且没有额外的方程。换句话说,您应该拥有与未知数相同数量的变量,并且方程组具有唯一解。这就是Modelica所需要的。
现在,Modelica支持您习惯的那种命令式语义。但它们仅用于特殊情况,因为它们限制了对数学行为的解释,从而干扰了允许Modelica编译器生成真正快速代码的符号操作。所以这不仅仅是一种风格问题。如果可能的话,你应该使用方程式,并且Modelica中的算法只应作为最后的手段使用。
最后一点。有些人可能会疑惑“你是否告诉我这些方程式将被放入一些巨大的方程组中并通过矩阵求逆或Newton-Raphson或其他方法解决?为什么它显然会变得如此复杂,显然可以用更简单的方式解决!”但它不会被解决为一个巨大的方程组。如果它可以作为一组简单的分配来解决它将。这是将应用的不同符号操纵技术中的一种(在众多中)。事实上,这是关于Modelica的一个关键点......您不需要担心优化解决方案方法,该工具将会解决这个问题。更重要的是,如果以一种同时出现系统的方式连接组件,您也不必担心这一点。 Modelica工具可以为您处理这样的“代数循环”,他们会优化它以找到计算效率最高的公式,并且不依赖于您为这些情况重新制定模型。
这有帮助吗?
答案 1 :(得分:1)
在您运行Modelica工具之前,您无法知道Modelica模型中方程的执行顺序(您可以重新排序源模型中的任何方程并获得相同的结果)。然后订单仅适用于使用您使用的设置的此工具。
这是OpenModelica编译器选择的顺序(omc + s + simCodeTarget = Dump model.mo):
error = ref - h;
outCtr = K * (error + x);
der(x) = DIVISION(error, T, #SHARED_LITERAL_2(String#);
qOutflow = LimitValue(minV, maxV, (-flowGain) * outCtr);
qInflow = if time > 150.0 then 3.0 * flowLevel else flowLevel;
der(h) = DIVISION(qInflow - qOutflow, area, #SHARED_LITERAL_3(String#);
这个例子有点无聊,因为没有等式的左右两边都改变了位置(h = error - ref
如果没有选择h作为状态变量等就可行。)