3. MIL验证环境搭建
MIL(Model-in-the-Loop)验证的第一步不是“跑仿真”,而是把工程环境搭对。电机控制器模型一旦涉及FOC电流环、SVPWM、位置/速度采样和故障保护,模型规模会迅速膨胀。如果工程结构混乱、求解器与采样周期不匹配、信号记录随意,后续SIL阶段几乎无法复用。本节围绕一个可落地的MIL工程骨架展开,给出目录组织、模型配置、求解器选择、信号记录与数据字典、版本管理五个关键环节的具体做法。
一、工程目录结构:让模型、参数、脚本、数据各归其位
推荐采用“单一工程根目录 + 分层子目录”的方式,避免把 .slx、.m、.mat、.xlsx 全部堆在同一层。一个可直接使用的结构如下:
MCU_MIL_Project/
├─ models/ % 模型文件
│ ├─ mcu_top.slx % 顶层模型(含控制器与被控对象)
│ ├─ ctrl_foc.slx % 控制器子系统(可独立测试)
│ └─ plant_pmsm.slx % 电机+逆变器被控对象
├─ params/ % 参数脚本与数据字典
│ ├─ mcu_params.m % 电机、逆变器、控制参数
│ └─ MCU_DD.sldd % Simulink Data Dictionary
├─ scripts/ % 自动化脚本
│ ├─ init_project.m % 工程初始化
│ └─ run_mil_test.m % 批量仿真入口
├─ data/ % 输入激励与记录数据
│ ├─ testcases/ % 工况定义
│ └─ logs/ % 仿真输出
└─ docs/ % 需求、接口、测试说明
顶层模型 mcu_top.slx 只做信号连接和接口定义,不写具体算法;控制器与被控对象分别封装为引用模型(Model Reference),这样在SIL阶段可以把控制器替换为C代码生成的S-Function,而被控对象保持不变。参数脚本 mcu_params.m 只负责赋值,不参与计算逻辑,便于版本对比。
二、模型配置参数:把“仿真正确性”固化到配置里
模型配置参数决定了仿真是否可信。对电机控制器MIL,重点检查以下几项:
- 求解器类型:选择“定步长(Fixed-step)”,因为后续要生成嵌入式代码,变步长无法直接映射到实际控制器任务。
- 固定步长:与控制器实际中断周期一致。例如电流环10 kHz,则步长设为
1e-4s;若速度环1 kHz,可在模型内用Rate Transition或独立采样保持实现。 - 求解器:定步长下推荐
ode4(Runge-Kutta)或ode1(Euler)。ode4精度更高,适合含连续被控对象的场景;若被控对象已离散化,ode1即可。 - 任务模式:单任务时所有模块继承同一采样时间;多速率时需显式设置各子系统采样时间,并检查Rate Transition模块是否插入正确。
- 代码生成兼容性:勾选“仅生成代码”相关检查项,避免使用不支持代码生成的模块(如连续传递函数、部分查表模块)。
mcu_mil_config.m,在 init_project.m 中通过 set_param 统一设置,避免每次手动改配置导致仿真结果不一致。三、求解器选择:定步长与采样周期的匹配关系
求解器选择的核心是“仿真步长 ≤ 控制器最小采样周期”,且尽量取整数倍关系。以某永磁同步电机FOC为例:电流环采样周期 Ts_i = 100 μs,速度环 Ts_s = 1 ms,PWM开关频率 f_sw = 10 kHz。若仿真步长取 Ts = 100 μs,则电流环每个周期执行一次,速度环每10个周期执行一次,PWM每周期更新一次,三者关系清晰。
若步长取 50 μs,虽然精度更高,但仿真时间翻倍,且与实际控制器任务周期不一致,容易掩盖多速率调度问题。因此MIL阶段建议直接采用与目标控制器一致的最小采样周期作为固定步长。对于含连续被控对象的场景,可在被控对象内部用 ode4 以更小步长积分,但控制器侧仍保持 100 μs 离散执行。
四、信号记录与数据字典:让每次仿真可追溯
MIL验证需要观察电流、转速、转矩、母线电压、故障标志等信号。推荐使用“信号记录(Signal Logging)+ Dataset”方式,而不是把每个信号都手动连到 To Workspace。具体做法:在顶层模型选中需要记录的信号线,右键 → Properties → 勾选“Log signal data”;在配置参数中设置 Signal logging 名称,例如 logsout。仿真结束后,logsout 是一个 Simulink.SimulationData.Dataset,可用 logsout.get('Ia') 按名称提取。
数据字典 MCU_DD.sldd 用于集中管理参数和信号对象。把 mcu_params.m 中的变量迁移到数据字典,并设置 Simulink.Parameter 的 StorageClass(如 ExportedGlobal 或 Model default),这样在SIL代码生成时参数能正确映射为C变量。数据字典还支持版本对比,便于追踪参数变更。
eval 或 assignin('base', ...) 在脚本中动态创建参数,这会导致数据字典与脚本不一致,SIL阶段容易出现“参数找不到”或“值被覆盖”的问题。五、版本管理基础:模型文件与脚本的协同
Simulink 的 .slx 是二进制压缩包,Git 无法逐行对比。推荐策略:
- 模型文件使用 Git LFS 管理,避免仓库膨胀;
- 参数脚本、初始化脚本、测试脚本用普通 Git 管理,可逐行 diff;
- 数据字典
.sldd同样用 LFS,但关键参数变更需在提交信息中写明; - 每次提交前运行
init_project.m和run_mil_test.m,确保模型可加载、仿真可运行; - 为每个MIL测试用例建立独立分支或标签,例如
mil/current-loop-step,便于回溯。
一个实用的提交前检查清单如下:
| 检查项 | 判断依据 |
|---|---|
| 模型能否无警告加载 | load_system('mcu_top') 无报错 |
| 参数是否全部来自数据字典 | Model Explorer 中无未定义变量 |
| 求解器与步长是否一致 | 配置参数中 Fixed-step = 1e-4 |
| 信号记录是否开启 | logsout 包含 Ia、Ib、Ic、Speed、Torque |
| 仿真是否可复现 | 同一提交两次运行结果一致 |