常量、参数与离散变量:原理与诊断验证
解释 constant、parameter、discrete 与 continuous 四种可变性构成的偏序、表达式可变性的传播规则,以及 when 与 pre 在事件时刻的取值约定,并给出一个采样 PI 控制器的可手算算例。
常量、参数与离散变量:原理与诊断验证
Modelica 把"变量会不会变、在什么时候变"编码进声明前缀,形成一套可变性偏序。编译期就能定的量可以做数组维度,仿真前可改的量适合做设计变量,只在事件时刻跳变的量必须用 when 驱动。离散变量的故障很少表现为数值偏差,更多表现为求解变慢、事件数暴涨或结果在两次运行间不一致。可信度验证要回答的是三个可量化的问题:事件率是否落在物理预期内、事件迭代是否在有限步内收敛、参数取值是否经得起扰动反证。
从求解日志里提取离散证据
在动任何参数之前,先把四类量记下来:
- 仿真区间内的事件总数 ;
- 每个事件处的事件迭代次数 ;
- 离散变量的首拍值与
pre值; - 参数被修改符覆盖后的实际生效值。
工具会把这些量写进日志。OpenModelica 输出 number of events,Dymola 在 dslog.txt 中给出 Number of state events 与 Number of time events。缺少这些量时,任何"结果看起来对"的判断都没有区分力,因为抖动与真实高频切换在结果曲线上长得一样。
可变性是一个偏序而非四个并列标签
四种可变性从"最不可变"到"最可变"排列为 constant < parameter < discrete < continuous。constant 在编译期求值,可以出现在数组维度、if 条件的结构分支里;parameter 在一次仿真中固定,但在编译与初始化之间可被修改符覆盖;discrete 是分段常数,只在事件时刻改变;continuous 在时间上连续可微。
这条偏序直接决定赋值合法性:把高可变性的表达式赋给低可变性的变量是非法的。写成 parameter Real T = time; 会得到 Cannot assign a continuous-time expression to a parameter,因为 time 的可变性高于 parameter。反过来永远合法:discrete Real y = kp * u; 中 kp 是参数、u 是连续量,只要整条语句位于 when 分支内即可。
表达式可变性的传播规则
表达式本身也有可变性,取子表达式中的最大值:
这条规则解释了为什么 parameter Real A[3] = {1.0, 2.0, 3.0} * scale; 在 scale 为 parameter 时仍然合法——右侧是参数表达式,数组维度可确定;而一旦 scale 变成普通 Real,数组维度就无法在编译期确定,报错 Array dimension is not a parameter expression。
final parameter 是在偏序上加锁:它仍然是参数,但禁止下游用修改符覆盖。库作者在基类里写 final parameter Real k = 1.0,可以防止使用者无意改变内部标定,同时保持参数的可见性。
采样 PI 控制器的可变性设计
block SampledPI
parameter Real kp = 2.0 "比例增益";
parameter Modelica.Units.SI.Time Ti = 0.5 "积分时间常数";
parameter Modelica.Units.SI.Time Ts = 0.1 "采样周期";
Modelica.Blocks.Interfaces.RealInput u;
Modelica.Blocks.Interfaces.RealOutput y;
discrete Real e;
discrete Real I;
equation
when sample(0, Ts) then
e = u;
I = pre(I) + kp * Ts / Ti * e;
end when;
y = kp * e + I;
end SampledPI;
e 与 I 声明为 discrete Real,因为它们的值只在采样时刻改变;y 是普通 Real,在两次采样之间保持常数但仍按连续变量参与求解。这种"离散量进入连续方程"的写法是合法的,因为分段常数在区间内部不引入新的自由度。
手算第一拍:设 (阶跃误差),初值 I 的 pre 为 0.0。采样时刻 处 ,积分项 ,输出 。第二拍 仍为 1.0 时 ,。每拍积分增量恒为 ,10 拍后 ,这些整数序列可以逐拍核对仿真输出。
事件时刻与 pre 的取值约定
when 分支内的赋值不是连续赋值,而是事件时刻的一次性更新。pre(x) 给出该变量在上一个事件时刻之后、当前事件之前的取值:
没有 pre() 就无法写出带记忆的离散状态,例如 I = pre(I) + kp * Ts / Ti * e;。如果漏掉 pre() 直接写 I = I + ...,工具会报代数环或报 Non-linear equation system,因为等号两边出现同一个离散变量,构成隐式关系。
采样由内建函数触发:when sample(0, Ts) then ... end when; 在 时刻激活。仿真区间 内的事件次数为
取 、,得到 次采样。这个数可以与工具的 number of events 统计直接对照,用来确认采样逻辑没有写错。
迟滞带的取值下限
迟滞带不能任意取小。设求解器容差为 、温度量级为 ,相对容差对应的绝对分辨率约 。迟滞带必须显著大于这个分辨率,否则阈值仍会被数值噪声穿越。工程上取迟滞带不低于量级分辨率的 100 倍,即
取 有约 57 倍余量,是安全的。若实际物理迟滞只有 ,就应把 tolerance 收紧到 再评估,而不是把迟滞带放大到失真。
物性参数与常量表达式的边界
参数的可变性边界也体现在量纲换算上。取导热系数 、密度 、比热 ,三者都是 parameter,热扩散率
因为三个输入都是参数, 也是参数,可以安全地用于 parameter Real dx = sqrt(alpha * t_end); 这类需要在编译期定维的表达式。若把 改成随温度变化的连续量, 立刻升级为连续变量,上面这行会失效。
参数取值的反证设计
参数诊断不是重读一遍数值,而是构造能推翻结论的扰动。以比例增益 为例,做 扰动( 与 ),若输出幅值随之变化约 ,说明系统在该工作点近似线性、参数可信;若幅值变化超过 ,说明工作点靠近饱和或分岔,原参数值不能外推。无量纲敏感度定义为
表示线性响应, 表示参数不可信。把 与事件率、迭代次数一起记录,才能说明一次离散仿真的结论覆盖了哪些工况。
故障模式与判定试验
| 现象 | 根因 | 判定试验 |
|---|---|---|
Cannot assign a continuous-time expression to a parameter |
参数初值里引用了 time 或连续变量 |
把该变量提到 equation 段,或改声明为 discrete |
Array dimension is not a parameter expression |
数组维度依赖了非参数变量 | 用 final parameter 或 constant 重新声明维度来源 |
| 离散变量首拍结果等于稳态值 | when 分支内漏写 pre(),I 被当成连续量解出 |
把 I 的更新式改为含 pre(I) 的形式重跑 |
| 事件次数远多于 | when 条件里含连续比较,触发抖动 |
用 sample(0, Ts) 或加 noEvent 限定比较 |
| 修改子模型参数无效 | 基类中该参数被 final 锁定 |
用 checkModel 查看参数的 final 属性 |
| 事件数在 1 s 内超过 1000 次 | 连续比较缺迟滞,布尔量在阈值附近抖动 | 加 迟滞带,看事件率是否降到 量级 |
日志出现 Event iteration did not converge |
离散方程组无不动点或迭代上限过小 | 把 when 内赋值改写成含 pre() 的显式形式 |
| 两次运行结果不同 | 离散初值未固定,依赖工具默认值 | 给所有 discrete 变量加 fixed = true 与显式 start |
| 参数扰动 5% 引起输出变化 40% | 工作点接近饱和,敏感度 | 把扰动缩到 重测,确认是局部非线性 |
noEvent 包裹后事件数归零 |
真实切换被抑制,物理行为被抹掉 | 去掉 noEvent 并改为迟滞实现,比较两者能量收支 |
恒温器的抖动诊断
下面的模型没有迟滞,heating 直接由连续温度比较得出:
model ThermostatNoHysteresis
parameter Modelica.Units.SI.Temperature Ton = 350.15;
parameter Modelica.Units.SI.Temperature Tamb = 293.15;
parameter Modelica.Units.SI.HeatCapacity C = 1000.0;
parameter Modelica.Units.SI.Power Qmax = 2000.0;
parameter Modelica.Units.SI.ThermalConductance h = 20.0;
Modelica.Units.SI.Temperature T(start = 300.15, fixed = true);
Boolean heating;
equation
heating = T < Ton;
C * der(T) = (if heating then Qmax else 0.0) - h * (T - Tamb);
end ThermostatNoHysteresis;
升温阶段净功率为 。在 处损耗为 ,净功率 ,升温速率 ,从 升到 需要约 。到达阈值后温度立即回落,条件再次为真,于是进入抖动。
加入迟滞带 后,开启阈值 、关闭阈值 。在 处损耗为 ,降温速率 ,降温段耗时 ;加热段净功率 ,速率 ,耗时 。周期 ,事件率 。若日志里的事件率远高于 ,迟滞带就没有生效。
事件抖动与事件迭代不收敛的区分
两者的现象相似,机制不同。抖动是物理模型缺少迟滞,导致布尔条件在阈值附近反复穿越;事件迭代不收敛是离散方程组 本身没有不动点,或不动点迭代被限制在过少的迭代次数内。
判定迭代是否收敛,看相邻两次迭代的差:
OpenModelica 的默认 与求解容差同量级,取 。若 打到上限(常见为 20 次)仍未满足上式,日志会出现 Event iteration did not converge。抖动则相反:每次迭代都迅速收敛,但事件被触发的次数远超物理预期。
区分试验很直接:把阈值比较换成带迟滞的形式。若事件数从数千降到个位数而结果形态不变,根因就是抖动;若事件数不变、只是迭代次数下降,根因在离散方程组本身。
参考资料
- Modelica Association. Modelica Language Specification, Version 3.6, 2023 — 第 3.8 节 Variability of Expressions 给出四种可变性的偏序与传播规则。
- Modelica Association. Modelica Language Specification, Version 3.6, 2023 — 第 8.4 节 Events and Synchronization 规定
when与pre的语义。 - Fritzson, P. Principles of Object-Oriented Modeling and Simulation with Modelica 3.3. Wiley-IEEE Press, 2015 — 第 5 章讨论离散事件与混合系统建模。
- Elmqvist, H., Mattsson, S. E., Otter, M. “Modelica — The New Object-Oriented Modeling Language.” ESM, 1998.
- Tiller, M. Modelica by Example, 在线版 2014 — 第 6 章给出采样控制系统与
pre的用法。 - Modelica Association. Modelica Standard Library 4.0.0,
Modelica.Blocks.Discrete与Modelica.Blocks.Interfaces.RealInput, 2020. - Modelica Association. Modelica Language Specification, Version 3.6, 2023 — 第 8.5 节 Event Iteration 规定离散方程组不动点迭代的终止条件。
- Modelica Association. Modelica Language Specification, Version 3.6, 2023 — 第 3.8 节 Variability of Expressions 界定
discrete与continuous的赋值边界。 - Cellier, F. E., Kofman, E. Continuous System Simulation. Springer, 2006 — 第 9 章讨论混合系统的抖动与迟滞建模。
- Fritzson, P. Principles of Object-Oriented Modeling and Simulation with Modelica 3.3. Wiley-IEEE Press, 2015 — 第 9 章给出事件迭代与
noEvent的实现细节。 - Modelica Association. Modelica Standard Library 4.0.0,
Modelica.Blocks.Logical.Hysteresis与Modelica.Thermal.HeatTransfer, 2020. - Mosterman, P. J. “An Overview of Hybrid Simulation Phenomena and Their Support by Simulation Packages.” HSCC, 1999.