2. Modelica建模基础回顾

在进入模型降阶与实时仿真之前,有必要把 Modelica 建模中最容易被“会用但说不清”的四个基础机制重新梳理一遍:方程与算法的分工、连接器的物理语义、层次化模型的组合方式,以及事件处理与求解器接口的协作关系。这四点决定了模型能否被正确编译、能否稳定求解,也直接影响后续降阶时哪些状态可以被保留、哪些代数约束必须被消去。

方程与算法:声明式与过程式的边界

Modelica 的核心是声明式方程。在 equation 段中写下的等式,例如 m*der(v) = F - c*v,并不规定计算顺序,而是描述变量之间必须同时满足的约束。编译器会通过符号分析、索引缩减(index reduction)和因果化,把方程系统转换为可求解的形式。与之相对,algorithm 段是过程式的,赋值语句有明确先后顺序,类似传统编程语言。

两者的关键差异在于:方程可以双向使用,同一个 v = der(x) 既能由 x 求 v,也能在积分时由 v 更新 x;而算法中的 v := der(x) 只能单向赋值。因此,凡是描述物理守恒、本构关系、连接约束的内容,应优先用方程表达;只有在需要条件分支、迭代、查表插值或状态机逻辑时,才使用算法。一个常见误区是把本可用方程表达的动态关系写成算法,导致模型失去可重用性和符号求解能力。

判断准则:如果一条关系在物理上“同时成立、不区分输入输出”,用 equation;如果它本质上是“先判断再计算”的过程,用 algorithm。

连接器:物理接口的势变量与流变量

连接器(connector)是 Modelica 组件复用的基础。它通常包含两类变量:势变量(potential,如电压、温度、位移、压力)和流变量(flow,如电流、热流、力、质量流量)。当两个连接器用 connect() 连接时,Modelica 自动生成两类方程:势变量相等,流变量之和为零(基尔霍夫型守恒)。

以电气接口为例:

connector Pin
  Modelica.Units.SI.Voltage v;
  flow Modelica.Units.SI.Current i;
end Pin;

连接 connect(p1, p2) 后自动得到 p1.v = p2.v 与 p1.i + p2.i = 0。这正是“连接即守恒”的体现。理解这一点后,就能明白为什么连接器变量不能随意增删:每增加一个势变量,就增加一条等值约束;每增加一个流变量,就增加一条守恒约束。连接器的设计质量,直接决定了模型拓扑能否被正确组装。

连接器语义与层次化模型组合 组件 A equation 段 v_A, i_A Pin 组件 B equation 段 v_B, i_B Pin connect(A.pin, B.pin) 自动生成约束 v_A = v_B (势相等) i_A + i_B = 0 (流守恒) 层次化模型:Top 模型包含 SubA 与 SubB SubA SubB 内部 connect

层次化模型:从组件到系统的组合

Modelica 用“模型即类”的方式支持层次化。一个 model 可以实例化其他模型作为子组件,再通过 connect() 把子组件的连接器对接起来。顶层模型不需要知道子组件内部是方程还是算法,只需要知道接口语义。这种“接口契约 + 内部实现”的分离,使得同一套组件可以反复用于不同系统。

层次化带来的一个实际问题是方程规模膨胀。每个子组件都贡献若干方程和变量,连接又引入额外约束。编译器在扁平化(flattening)后得到的是一个大型微分代数方程(DAE)系统。对于后续降阶而言,层次结构既是资产也是负担:资产在于可以按子系统分别降阶再组装;负担在于跨层次的连接约束可能引入难以消去的代数环。因此,在建模阶段就应保持接口简洁、避免不必要的跨层耦合。

事件处理:离散跳变与求解器的协作

真实系统常含离散行为:开关通断、限幅饱和、状态机切换。Modelica 用 when 语句描述这类事件:

when x >= x_max then
  y = y_max;
end when;

事件在仿真中分为两类:时间事件(由 sample() 等触发)和状态事件(由条件表达式过零触发)。求解器在积分过程中监测事件函数,一旦检测到过零,就暂停积分、定位事件时刻、执行 when 中的赋值,然后以新的状态继续积分。这个过程称为“事件迭代”。

事件处理对实时仿真尤其关键:事件定位需要额外迭代,可能造成步长收缩和计算抖动。若事件过于频繁,实时性会显著下降。因此在面向实时仿真的建模中,应尽量用连续近似替代高频离散切换,或把事件集中到固定采样周期上。

仿真求解器接口:模型与算法的分工

Modelica 工具通常把模型编译为 C 代码,再通过标准接口(如 FMI)交给求解器。求解器负责步长控制、误差估计、非线性迭代和事件检测;模型负责提供残差、雅可比和事件函数。两者的接口可以概括为:模型给出 f(x, t) 与事件条件,求解器决定“下一步走多大、何时停”。

接口要素模型侧职责求解器侧职责
状态导数提供 der(x) 表达式积分推进状态
代数约束提供 0 = g(x, y, t)迭代求解代数变量
事件函数提供过零条件检测、定位、触发
雅可比可选解析或数值提供用于隐式积分与牛顿迭代

理解这一分工后,就能解释很多仿真现象:为什么刚性系统需要隐式求解器、为什么代数环会导致初始化失败、为什么事件密集时实时步长难以保证。对降阶而言,这意味着降阶模型不仅要保留主导动态,还要保留必要的事件接口和代数约束结构,否则接入原求解器后会出现行为偏差。

常见陷阱:把 when 写成 if。在方程段中,if 表达式是连续可切换的,而 when 才产生离散事件。两者语义不同,混用会导致事件丢失或求解器反复重启。