2. Modelica语言基础

Modelica 是一种面向对象的、非因果的物理系统建模语言。与传统的因果建模语言(如 Simulink 中信号从输入流向输出)不同,Modelica 的核心思想是用方程描述物理规律,由编译器自动决定求解顺序。理解变量与参数声明、数据类型、方程与算法段、初始方程、注释与单位这五个基础要素,是写出可运行、可复用模型的前提。本节以“是什么—怎么写—如何判断正确”为主线,配合一个机械与电气系统的建模示例,帮助读者建立第一手的建模直觉。

一、变量与参数声明

在 Modelica 中,所有物理量都必须先声明类型,再使用。声明的基本形式是 类型 修饰符 变量名(单位, 初值, 取值范围)。其中最常见的两类是 parameter 与普通变量:

  • parameter(参数):在仿真开始前由用户赋值,仿真过程中保持不变。例如质量 parameter Real m = 1.0、电阻 parameter Real R = 10。参数是模型的“可配置接口”。
  • 变量(variable):仿真过程中随时间变化,由方程求解得到。例如速度 Real v、电流 Real i。
  • 常量 constant:编译期确定,如 constant Real g = 9.80665。

修饰符 input、output 用于定义模型的对外接口;flow、stream 用于连接器中的守恒量。初学者最容易犯的错误是把本应作为参数的物理量写成普通变量,导致模型无法配置;或者把本应求解的变量写成参数,导致方程数不足。

二、数据类型

Modelica 内置了丰富的数据类型,常用的有:

类型含义典型用途
Real实数(连续量)位移、速度、电压、电流
Integer整数计数、状态编号
Boolean布尔量开关状态、事件条件
String字符串标签、注释信息
enumeration枚举离散工作模式

此外,Modelica 标准库还提供了带单位的类型,如 Modelica.Units.SI.Length、Modelica.Units.SI.Voltage。使用带单位类型可以让编译器进行量纲检查,避免“把电压当电流用”这类低级错误。数组、记录(record)和连接器(connector)也是常用结构,连接器本质上是一种特殊的记录类型,用于在组件之间传递物理量。

三、方程与算法段

Modelica 的方程段(equation section)是模型的主体,用 equation 关键字引导。方程是声明式的,等号两边没有“赋值”含义,而是表示“两边相等”。例如:

model MassSpring
  parameter Real m = 1.0;
  parameter Real k = 10.0;
  Real x(start = 1.0);
  Real v;
equation
  der(x) = v;
  m * der(v) = -k * x;
end MassSpring;

这里 der(x) 表示 x 对时间的导数。两个方程、两个未知量 x 和 v,系统可解。注意:方程数量必须与未知量数量匹配,否则编译报错。

算法段(algorithm section)则用 algorithm 引导,是命令式的,按顺序执行赋值语句,常用于实现离散逻辑、查表或迭代计算。例如:

algorithm
  if x > 0 then
    y := 1;
  else
    y := -1;
  end if;

经验规则:能用方程表达物理规律时优先用方程,因为方程更利于符号求解和复用;只有在需要显式控制流程(如状态机、条件分支)时才使用算法段。

四、初始方程

动态模型需要初始条件才能求解。Modelica 提供 initial equation 段专门用于设定初始状态,例如:

initial equation
  x = 1.0;
  v = 0.0;

如果不写初始方程,编译器会尝试用变量的 start 属性作为初值,但这只是“建议值”,不保证满足所有约束。对于高阶系统或存在代数环的模型,显式写出初始方程能显著提高求解成功率。判断初始条件是否合理的方法是:检查初始时刻所有方程是否同时成立,以及初始加速度是否与物理直觉一致。

五、注释与单位

Modelica 支持两种注释:// 单行注释和 /* ... */ 多行注释。更重要的是注解(annotation),它以 annotation(...) 形式出现,用于给工具传递元信息,如图标、文档、实验设置:

annotation(
  Icon(graphics = {Rectangle(extent = {{-100,100},{100,-100}})}),
  experiment(StartTime = 0, StopTime = 10, Tolerance = 1e-6)
);

单位信息通常写在变量声明的括号里,如 Real v(unit = "m/s")。配合 displayUnit 可以在结果查看器中自动换算显示单位。养成“每个物理量都写单位”的习惯,是工程级模型的基本素养。

六、简单机械与电气系统建模示例

下面给出一个“质量—弹簧—阻尼”机械系统与“电阻—电感—电容”电气系统的对照示例。两者在数学结构上完全同构,这正是 Modelica 跨领域建模能力的体现。

model MechanicalSystem
  parameter Real m = 1.0 "质量 kg";
  parameter Real c = 0.5 "阻尼 N·s/m";
  parameter Real k = 10.0 "刚度 N/m";
  Real x(start = 1.0) "位移 m";
  Real v "速度 m/s";
equation
  der(x) = v;
  m * der(v) = -c * v - k * x;
end MechanicalSystem;

model ElectricalSystem
  parameter Real L = 1.0 "电感 H";
  parameter Real R = 0.5 "电阻 Ω";
  parameter Real C = 0.1 "电容 F";
  Real q(start = 1.0) "电荷 C";
  Real i "电流 A";
equation
  der(q) = i;
  L * der(i) = -R * i - q / C;
end ElectricalSystem;

两个模型的方程形式完全一致:der(状态) = 速度类变量,惯性系数 * der(速度) = -阻尼项 - 刚度项。机械系统中 m 对应电感 L,c 对应电阻 R,k 对应 1/C。仿真时间设为 0~10 s,容差 1e-6,可以观察到欠阻尼振荡衰减过程。判断结果是否合理:位移从 1 m 出发,经过若干次振荡后趋于 0,且振荡周期约为 2π√(m/k) ≈ 1.99 s,与理论值一致。

建议在 OpenModelica 中新建两个模型,分别粘贴上述代码,使用默认求解器 dassl 仿真,然后在绘图窗口同时绘制 x 与 q,观察两条曲线是否重合。若重合,说明两个系统确实同构;若偏差较大,检查参数单位是否统一。
常见错误:忘记写 der(x) = v 导致方程数不足;把 parameter 写成普通变量导致无法配置;单位混用(如把 mm 当 m)导致数值异常。编译报错时优先检查“方程数与未知量数是否相等”。
机械系统与电气系统的同构关系 机械系统(质量-弹簧-阻尼) k c m x, v m·dv/dt = -c·v - k·x 电气系统(R-L-C 串联) R L C i, q L·di/dt = -R·i - q/C 参数同构映射 质量 m 电感 L 阻尼 c 电阻 R 刚度 k 1 / C ⇌ ⇌ ⇌