Modelica 的 when/elsewhen 含 reinit() 时如何改写并处理 Dymola 报错?
结论
按照 Modelica 3.6 规范,reinit() 只能出现在 when-equation 中,不能直接移到 algorithm 里。x := y 也不能用来重新初始化连续状态。可以先尝试在 equation 中去掉当前触发报错的 elsewhen 结构。如果确实需要算法式计算,就将普通离散计算与状态重置分开,仍在方程区使用 reinit()。规范:reinit
Modelica 规范允许在方程区使用 elsewhen。仅凭简化片段和报错,无法确定 Dymola 不支持的具体组合,也无法判断是否与所用版本有关。
为什么不能只把等号改成赋值符号?
equation 中的等式共同约束当前值,求值顺序不由书写顺序决定。例如,在同一个已触发的 when-equation 中:
a = b + 1;
b = 2;
结果应满足 b = 2、a = 3。如果直接改成 algorithm 中的语句:
a := b + 1;
b := 2;
第一行读取执行到该处时的 b,第二行才更新 b。对于在该算法中赋值的离散变量,算法执行前会在概念上用 pre(b) 初始化;如果此前没有更新 b,第一行使用的就是这个值。因此,结果可能与原方程不同。规范:Algorithm Sections
这就是报错中“右侧依赖左侧变量”的含义。转换时要逐项确认:表达式需要当前事件中算出的值,还是需要 pre(...) 所表示的事件迭代前值。变量相互依赖时,单靠调整语句顺序也未必能保留原方程的语义。
可以怎样保留 equation 并改写 elsewhen?
对于两个标量 Boolean 条件,可以尝试合并触发入口,再根据条件的上升沿选择分支。下面是结构示例,实际模型中还需补齐变量声明、初始化和连续状态方程:
equation
when {c1, c2} then
v = if edge(c1) then
(if keep1 then pre(v) else value1)
else
(if keep2 then pre(v) else value2);
if edge(c1) then
if reset1 then
reinit(x, target1);
end if;
elseif edge(c2) then
if reset2 then
reinit(x, target2);
end if;
end if;
end when;
这里假设原逻辑是 when c1 ... elsewhen c2 ...,v 是事件更新的离散变量,x 是连续状态,keep1/keep2 和 reset1/reset2 分别代表各分支的保持条件与重置条件。
edge(c1) 等价于 c1 and not pre(c1)。用它选择分支,可以区分条件是一直为真,还是本次刚变为真。如果两个条件同时产生上升沿,前面的分支优先。规范:事件相关运算符
对于向量触发条件,需要逐元素处理上升沿。不要直接把 when {c1, c2} 改成 when c1 or c2:当 c1 已经为真时,c2 随后变为真可能不会让整个 or 表达式再次产生上升沿。
这是一种消除 elsewhen 的改写思路,尚未在题目对应的 Dymola 环境中验证。如果触发条件依赖正在更新的变量,还需要检查事件迭代能否收敛。
确实需要 algorithm 时怎么办?
可以让 algorithm 负责更新离散变量和计算重置目标值,再由独立的 when-equation 执行 reinit()。拆分时要特别注意保持原来的触发时机和分支优先级。
如果使用重置请求变量连接两个区域,要确认每次请求都能形成新的事件。例如,一个持续为 true 的 Boolean 请求不会在下一次需要重置时自动再次触发 when request。连续多次请求必须有可区分的变化,不能只反复赋值为 true。
算法中的条件分支可以省略某些离散变量的赋值,使其保留 pre(...) 值;但如果前面的语句已经更新了该变量,省略后续赋值会保留刚更新的值。迁移时应检查整个算法的执行顺序。
“什么也不做”需要区分变量类型
对于由 when-equation 更新的离散变量:
v = pre(v);
表示在该次更新中保持原值。普通变量的定义还需要满足 when-equation 的分支一致性要求。
对于连续状态 x,不需要重置时应让 reinit() 不执行,x 继续遵循原有连续方程。不要为了补齐分支而添加 x = pre(x)。reinit() 有专门的结构规则,不能直接套用普通赋值方程的补齐方式;同一个状态的重置也应集中在同一个 when-equation 中。规范:When-Equations 与 reinit
排查时,建议提供 Dymola 版本,以及包含变量类型、初始化、连续状态方程和两个相关分支的最小模型。题目中的省略号、变量名混用和示意条件不足以确定具体编译原因,也不能据此保证某种改写一定通过检查。
备注:内容仅供参考。
