2. Simulink 建模基础回顾
MIL 与 SIL 验证能否顺利开展,很大程度上不取决于测试脚本写得多漂亮,而取决于被验证的模型本身是否具备“可测试性”。一个随手搭建、信号类型混乱、采样时间随意、层次结构扁平的模型,往往在 MIL 阶段就频繁报错,到了 SIL 阶段更会因为代码生成接口不匹配而寸步难行。本节围绕四个基础要素——常用模块库、信号与数据类型、采样时间、子系统与模型引用——梳理如何建立一个面向后续验证的模型基线。
常用模块库:先分清“连续”与“离散”
Simulink 的库浏览器中模块众多,但对控制类模型而言,真正高频使用的集中在几个库:Sources(Step、Sine Wave、Constant、Signal Builder)、Sinks(Scope、To Workspace、Display)、Continuous(Integrator、Transfer Fcn、State-Space)、Discrete(Unit Delay、Discrete Transfer Fcn、Zero-Order Hold)、Math Operations(Gain、Sum、Product)、Logic and Bit Operations、Signal Routing(Mux、Demux、Switch)以及 User-Defined Functions(MATLAB Function、Fcn)。
这里有一个容易被忽视但直接影响 SIL 的关键点:连续模块无法直接生成嵌入式 C 代码。Integrator、Transfer Fcn 这类模块在代码生成时会被要求离散化,或者必须配合定步长求解器。因此,如果模型最终要走向 SIL 甚至产品代码,从建模之初就应优先使用 Discrete 库中的模块,把控制器部分建成离散形式,而把被控对象(Plant)保留为连续形式,仅在 MIL 阶段用连续求解器验证算法正确性。这种“控制器离散、对象连续”的划分,是后续 MIL/SIL 对比能够对齐的前提。
信号与数据类型:验证对齐的隐形基础
Simulink 默认的信号类型是 double,但嵌入式目标通常使用 single、int16、uint8、boolean 等类型。如果模型内部全是 double,而生成代码时又要求定点或单精度,就会出现大量隐式类型转换,SIL 与 MIL 的结果差异往往就来自这些转换。
建议在建模阶段就显式指定信号类型。可以通过 Signal Attributes 中的 Data Type 设置,也可以在模型配置参数里开启 “信号解析”相关的诊断。对于需要严格对齐的验证场景,推荐使用 Simulink.Bus 定义总线对象,把一组相关信号打包,这样接口清晰,SIL 阶段的 C 结构体也能一一对应。
另一个实用做法是给关键信号命名并开启 信号记录(Signal Logging)。在 MIL 与 SIL 对比时,同名信号的记录数据可以直接做差值分析,而不需要手动去 Scope 里找曲线。命名规范建议采用“模块名_信号含义”的形式,例如 Ctrl_GainOut、Plant_Speed,避免出现 Out1、Signal3 这类无意义名称。
采样时间:决定模型能否被代码生成
采样时间是 Simulink 建模中最容易埋雷的地方。模型中如果存在多个不同采样率的模块,Simulink 会以最慢的采样率作为基础采样时间,并可能触发速率转换。对于 SIL 验证,多速率模型会显著增加代码生成的复杂度,因为每个采样率都需要独立的任务调度。
面向验证的建模建议是:尽量使用单一采样时间。例如控制器统一用 Ts = 0.001 s(1 kHz),被控对象若为连续则用连续求解器,若也要离散则同样取 0.001 s 或整数倍关系。设置方式是在模块参数中把 Sample time 显式写成 0.001,而不是留 -1(继承)。留 -1 虽然方便,但会让采样时间在模型各处传播,后期排查非常困难。
可以用 Ctrl+D 更新模型后,在 Diagnostics → Sample Time 中查看采样时间图例,确认没有意外的速率转换。如果确实需要多速率,应使用 Rate Transition 模块显式处理跨速率信号,而不是让 Simulink 自动插入。
子系统与模型引用:为验证划分边界
当模型规模增大,扁平结构会让 MIL 测试难以定位问题。此时应使用子系统(Subsystem)把功能相关的模块封装起来,例如把控制器封装为 Controller 子系统,把被控对象封装为 Plant 子系统。子系统不仅让模型层次清晰,更重要的是它定义了测试边界:MIL 阶段可以单独给 Controller 子系统输入激励,观察其输出;SIL 阶段则可以把 Controller 子系统单独生成代码,与 Plant 在 Simulink 中联合仿真。
如果多个模型需要共享同一个控制器,或者控制器要独立生成代码,则应使用模型引用(Model Reference)。模型引用把被引用模型当作独立单元编译和代码生成,支持增量编译,也支持 SIL/PIL 模式切换。典型做法是:顶层模型 Top 引用 Controller.slx 和 Plant.slx,在 Top 的配置中把 Controller 的 Model block 设置为 SIL 模式,即可在不改动顶层结构的情况下完成 MIL→SIL 的切换。
可测试模型基线的检查要点
综合以上四点,一个面向 MIL/SIL 的模型基线应满足:控制器使用离散模块、采样时间显式且统一、关键信号有明确类型和名称、功能边界用子系统或模型引用划分。下面这张图把四个要素与验证阶段的对应关系整理在一起,便于建模时逐项核对。
需要强调的是,上述基线不是一次性配置完就万事大吉。随着模型迭代,采样时间可能被新加入的模块破坏,信号类型可能被隐式转换覆盖,模型引用的接口也可能因参数变更而失配。因此建议在每次 MIL 测试前,用 Simulink.BlockDiagram.getSampleTimes 或模型顾问(Model Advisor)中的“采样时间检查”快速扫描一遍,把问题挡在验证之前。
当模型满足这些基础条件后,MIL 阶段的测试用例才能稳定复现,SIL 阶段的代码生成才有明确的接口边界,后续的对比分析也才有可靠的数据来源。下一阶段的工作,就是在这个基线上搭建具体的测试框架与激励信号。