Simulink软件在环仿真SIL详解:配置流程与MIL批量对比方法
如果你已经做过 MBD基于模型的设计开发那么对 MIL、PIL、HIL 这三个缩写不会陌生。但很多人在搭验证流程时会把软件在环仿真Software-in-the-LoopSIL这一环忽略掉或者干脆把它和 MIL、PIL 混在一起。这篇文章把 SIL 单独拆开讲清楚它到底是什么、解决什么问题、怎么在 Simulink 里配置以及如何用一套测试用例把 MIL 和 SIL 结果做批量对比。先给结论SIL 是把控制器模型生成 C 代码然后在 PC 上运行这段代码完成仿真验证。它不需要目标硬件不需要实时仿真机一台装了 MATLAB 的电脑就能跑。它的核心价值是验证“生成的代码”和“模型”在数值行为上是否一致正好填补 MIL 之后的代码验证空档。这篇文章按实际使用顺序展开会包含SIL 在 V 模型里的定位、Simulink 中 SIL 的完整配置流程、MIL/SIL 结果对比方法、脚本化批量回归、常见报错排查以及从 SIL 衔接 PIL/HIL 的路线。适合已经在做 Simulink 控制模型开发准备接触代码生成或正在梳理测试流程的工程师。1. Simulink 软件在环仿真 SIL 核心能力速览能力项说明项目类型Simulink 软件在环仿真Software-in-the-Loop核心功能将控制器模型生成 C 代码并在 PC 仿真环境中运行验证硬件门槛普通办公 PC无需目标硬件、无需实时仿真机软件依赖MATLAB/Simulink、Simulink Coder以及 MATLAB 支持的 C 编译器与 MIL 关系MIL 验证模型逻辑SIL 验证生成代码与模型的一致性与 PIL/HIL 关系SIL 在 PC 上跑代码PIL 在目标处理器跑代码HIL 接入真实控制器和实时机启动方式在 Simulink 中配置控制器子系统的仿真模式或生成 SIL 块API 接口无 Web API但可通过 MATLAB 脚本、命令行和 Simulink Test 自动化执行批量任务支持可对同一组测试用例批量运行 MIL/SIL 并自动汇总对比推荐使用阶段MIL 之后、PIL 之前用于早期发现代码生成引入的差异适合场景控制器算法代码生成验证、测试用例回归、MIL/SIL/PIL 流程搭建2. SIL 在 V 字开发流程中的位置在基于模型的设计里V 流程左侧是逐级细化和实现右侧是逐级验证。控制策略开发通常经过需求建模 - MIL 验证 - 代码生成 - SIL/PIL 验证 - HIL 验证 - 实车试验。MIL 阶段控制器和被控对象都以 Simulink 模型形式运行验证的是算法逻辑本身。问题是从模型到代码的转换过程中C 编译器、数据类型转换、代码生成选项都可能引入新的差异MIL 通过不代表生成代码也通过。SIL 就是在这个环节插入的验证。它把控制器模型生成 C 代码编译成可执行程序然后在 PC 上运行其他部分仍然以普通 Simulink 模型方式运行。这样仿真环境不变但控制器部分变成真实生成的代码。下面是 MIL、SIL、PIL、HIL 四种验证方式的关键区别验证方式验证对象运行环境是否需要目标硬件是否能反映目标处理器性能MIL 模型在环模型逻辑PC否否SIL 软件在环生成的 C 代码PC否否PIL 处理器在环生成的 C 代码目标处理器是是HIL 硬件在环真实控制器整机实时仿真机 真实控制器是是从表格可以看出SIL 和 MIL 一样都跑在 PC 上都不依赖硬件。但 SIL 运行的不再是模型而是代码。SIL 通过与否直接决定后续 PIL、HIL 测试是否还有必要继续推进。3. SIL 的适用场景与使用边界3.1 适合用 SIL 的场景控制器算法已经做完 MIL 验证准备做代码相关验证但目标硬件还没到位。这时候可以用 SIL 提前验证代码行为。测试用例很多需要大规模回归。SIL 跑在 PC 上重复运行时成本低适合做自动化回归和持续集成。需要检查代码生成选项对结果的影响。比如数据类型从 double 改成 single或者改成定点数SIL 可以直观地看到数值误差变化。3.2 不适合用 SIL 的场景想验证目标处理器上程序的执行时间、RAM/ROM 占用、堆栈深度。这些数据只有 PIL 或 HIL 才能反映SIL 在 PC 上跑不出真实性能。想验证控制器与真实执行器、传感器的接口时序。这属于系统集成测试需要 HIL。控制器依赖外部硬件驱动或专用芯片寄存器操作。这种代码往往无法在 PC 上直接编译运行SIL 就不适用。3.3 合规与安全边界SIL 本身不涉及特殊风险但要注意如果控制器模型、被控对象模型、测试数据来自第三方或实际产品使用前需要确认授权范围。涉及真实产品数据的测试注意脱敏和保密。生成代码如果用于量产软件还需要遵守团队或公司的代码规范与安全标准要求。4. 环境准备与前置条件4.1 软件环境清单SIL 的运行前提是能够为控制器模型生成 C 代码并完成本地编译因此软件环境比普通 Simulink 仿真多两个要求。MATLAB/Simulink建议使用较新版本不同版本菜单路径略有差异但 SIL 思路一致。Simulink Coder 许可证没有这个工具箱SIL 选项无法激活。MATLAB 支持的 C 编译器Windows 下常用 MinGW-w64 或 Microsoft Visual C。可以在 MATLAB 命令行里确认环境是否就绪% 检查工具箱版本 ver(MATLAB) ver(Simulink) ver(SimulinkCoder) % 检查可用的 C 编译器 mex -setup如果mex -setup提示找不到编译器需要先安装 MATLAB 支持的编译器并配置好环境变量。4.2 硬件环境SIL 对硬件要求不高普通办公 PC 即可。模型规模较大时代码编译和仿真耗时会长一些建议 8GB 以上内存多核 CPU 对编译速度有帮助。4.3 模型准备要求SIL 只对支持代码生成的模块有效。控制器子系统内部不能有只用于显示的 Scope 模块也不能有不支持代码生成的第三方模块。推荐把一个完整的控制策略封装成独立子系统把被控对象、输入信号、输出记录放在子系统外部。一个适合做 SIL 的最小模型结构测试模型结构 - 被控对象子系统二阶传递函数或状态空间模型 - 控制器子系统PID 控制器或自定义状态机 - 输入信号阶跃、正弦、带噪声信号 - 数据记录To Workspace 或信号日志用于 MIL/SIL 对比5. Simulink 中 SIL 配置与实现步骤5.1 准备测试模型以一个简单的 PID 闭环控制为例。被控对象用二阶传递函数控制器用 PID Controller 模块。重点是控制器独立成子系统这样只需对控制器生成代码。5.2 设置定步长求解器SIL 对比测试建议使用定步长求解器。因为代码生成后按固定采样周期执行如果 MIL 用变步长SIL 用定步长两条曲线差异会非常大无法判断是代码问题还是步长问题。在 Configuration Parameters 中设置Solver Selection - Type: Fixed-step - Solver: discrete 或 ode4按模型实际情况选择 - Fixed-step size: 按系统动态选择例如 0.0015.3 配置代码生成参数进入 Configuration Parameters选择 Code Generation设置系统目标文件。Code Generation - System target file: grt.tlc - Language: Cgrt.tlc是通用实时目标文件适合 PC 上的 SIL 验证。如果项目使用 Embedded Coder 并计划后续做 PIL也可以选择ert.tlc但需要确认目标硬件配置与代码生成选项。5.4 将控制器子系统切换为 SIL 模式打开控制器子系统的 Block Parameters找到与仿真模式相关的选项把仿真模式设置为“软件在环 (SIL)”或“SIL”模式。不同 MATLAB 版本菜单名称略有不同但操作思路一致。另一种方式是生成 SIL 块在 Configuration Parameters 的 Code Generation Verification 中勾选创建软件在环 (SIL) 块选项然后执行代码生成。Simulink 会生成一个带_sil后缀的新模块替换原控制器模块。第一次切换 SIL 模式会触发代码生成和编译需要等待一段时间。编译期间 MATLAB 命令行会输出进度信息。5.5 运行 SIL 仿真并记录结果运行仿真观察输出波形是否正常。SIL 模式下控制器部分运行的是生成的 C 代码如果代码有数值错误、初始化问题或数据溢出会在这一阶段暴露出来。% 运行仿真脚本模板 out sim(your_model_name); % 假设输出信号保存在 out.yout sil_result out.yout; save(sil_result.mat, sil_result);注意out.yout只是示例实际信号名要看模型中记录信号的名称可能需要按out.logsout或out.simout调整。6. MIL 与 SIL 功能测试与效果验证6.1 测试用例设计SIL 验证的核心是同一组输入MIL 和 SIL 的结果是否一致。因此测试用例要先在 MIL 上跑一遍再切到 SIL 上跑一遍。测试用例输入信号考察重点用例1阶跃信号响应时间、超调量用例2正弦信号跟踪误差用例3带噪声信号抗扰行为用例4边界输入稳定性和限幅6.2 运行 MIL 仿真先把控制器子系统的仿真模式改回 Normal运行仿真保存结果作为基线。% 运行 MIL set_param(your_model_name/Controller, SimulationMode, Normal); out_mil sim(your_model_name); mil_result out_mil.yout; save(mil_result.mat, mil_result);6.3 运行 SIL 仿真再把控制器子系统的仿真模式改为 SIL运行仿真保存结果。% 运行 SIL set_param(your_model_name/Controller, SimulationMode, Software-in-the-loop (SIL)); out_sil sim(your_model_name); sil_result out_sil.yout; save(sil_result.mat, sil_result);注意set_param中的参数名和值在不同 MATLAB 版本可能不同。更稳妥的方法是先手动完成一次 SIL 切换再用get_param查看当前仿真模式名称。6.4 对比两条曲线加载两组结果画图对比并计算最大差异。load(mil_result.mat); load(sil_result.mat); % 曲线对比 t mil_result.Time; y_mil mil_result.Data; y_sil sil_result.Data; plot(t, y_mil, b, t, y_sil, r--); legend(MIL, SIL); xlabel(时间); ylabel(输出); % 计算最大绝对差异 max_diff max(abs(y_mil - y_sil)); fprintf(最大绝对差异: %e\n, max_diff);如果两条曲线完全重合或者差异在数值精度范围内说明生成代码与模型行为一致SIL 通过。如果差异明显需要进一步检查数据类型转换、代码生成优化选项或求解器设置。6.5 容差判断工程上通常不要求绝对一致可以设置相对容差和绝对容差。function ok compare_signals(y_mil, y_sil, rel_tol, abs_tol) diff abs(y_mil - y_sil); scale max(abs(y_mil), abs(y_sil)); ok all(diff (rel_tol * scale abs_tol)); end容差大小取决于系统量级。第一次可以先输出最大差异再根据差异量级定容差。6.6 代码覆盖率检查进阶如果安装了 Simulink Coverage可以在 SIL 仿真时收集代码覆盖率检查生成代码中哪些分支没有被执行。覆盖率检查不是 SIL 的必选项但能帮助发现测试用例盲区。7. 批量任务与回归测试手工跑几条测试用例没问题但项目测试用例可能有几十条甚至上百条。SIL 的价值在于能够把这些用例重复执行所以最好做成脚本化批量回归。7.1 用脚本批量运行多种输入通过 MATLAB 脚本切换输入信号并依次运行 MIL/SIL最后汇总结果。% 批量回归脚本模板 test_cases {step, sine, noise, ramp}; results struct(); for i 1:numel(test_cases) % 切换输入信号这里以 From Workspace 方式为例 assignin(base, input_signal, generate_signal(test_cases{i})); % 运行 MIL set_param(your_model_name/Controller, SimulationMode, Normal); out_mil sim(your_model_name); % 运行 SIL set_param(your_model_name/Controller, SimulationMode, Software-in-the-loop (SIL)); out_sil sim(your_model_name); % 计算差异 results.(test_cases{i}) compare_signals(... out_mil.yout.Data, out_sil.yout.Data, 1e-3, 1e-6); end disp(results);实际项目中输入信号往往放在模型工作区或通过From Workspace模块读取脚本里用assignin赋值就能实现批量切换。7.2 用 Simulink Test 固化测试用例如果团队需要长期维护测试用例建议使用 Simulink Test。它可以把同一组测试用例分别绑定到 MIL 和 SIL 模式下执行直接输出对比报告不需要自己写太多对比逻辑。Simulink Test 的流程大致是创建测试文件新增测试用例。在测试用例中指定仿真模式和外部输入。多次运行选择 MIL 和 SIL 两种模式。查看通过/失败结果导出测试报告。这种方式适合需要反复回归的控制器项目。7.3 批量结果汇总批量任务跑完后整理成一张汇总表测试用例MIL 是否通过SIL 是否通过最大差异结论step通过通过1.2e-6PASSsine通过通过8.7e-7PASSnoise通过失败2.3e-2FAIL一旦某个用例在 SIL 下失败优先排查数据类型、限幅、状态初始化这三个方向。8. 常见问题与排查方法问题现象可能原因排查方式解决方案SIL 选项灰色不可选缺少 Simulink Coder 许可证或当前子系统不支持代码生成检查许可证检查子系统内是否有 Scope 等不支持代码生成的模块安装 Simulink Coder清理模块或重新封装子系统编译失败C 编译器未安装或未配置好执行mex -setup安装 MATLAB 支持的编译器并重新配置找不到 SIL 模式入口MATLAB 版本不同菜单名称不同搜索 Simulink 帮助文档中的 SIL 关键词改用 Configuration Parameters 中的代码生成验证选项SIL 结果与 MIL 差异大求解器不一致、数据类型转换、代码生成优化对比两者求解器设置检查信号数据类型统一定步长和步长检查数据的 double/single 设置每次修改模型都要重新编译速度很慢SIL 模式每次生成代码并编译观察编译输出的文件变化避免频繁修改控制器结构把可调参数放到工作区SIL 仿真运行崩溃存在未初始化状态或代数环查看仿真错误日志检查模型初始化添加状态初值消除代数环批量脚本中 set_param 报错仿真模式名称不匹配用get_param查看实际参数名按实际版本替换参数名第一次做 SIL 遇到编译失败是最常见的。编译器配置正确后后续问题基本都是模型本身对代码生成的支持问题或参数设置问题。9. 最佳实践与使用建议9.1 先跑通 MIL 再做 SILSIL 的前提是 MIL 已经通过。如果 MIL 结果本身不稳定SIL 对比没有意义。9.2 固定求解器与步长SIL 和 MIL 必须使用相同的定步长求解器。变步长与定步长混用是差异过大的最常见原因。9.3 控制器独立成子系统控制器和被控对象分离不仅方便 SIL也为后续 PIL/HIL 做好准备。9.4 保存每次运行的测试结果把mil_result.mat、sil_result.mat按日期或用例名保存方便回溯。这也是做回归测试的基本要求。9.5 用脚本固化批量回归手工点击运行不适用于大量用例。把 MIL/SIL 批量对比写成脚本并接入持续集成流程中。9.6 注意数据合规如果测试数据来自真实产品或者控制器模型来自供应商使用前确认授权范围输出结果注意脱敏。10. 总结与下一步SIL 的价值可以概括为一句话在“模型逻辑”和“目标代码”之间加一道校验。它不接硬件不测实时性但能提前发现代码生成引入的问题。对入门者来说第一次做 SIL 最值得验证的是同一输入、同一求解器下MIL 和 SIL 两条输出曲线能不能对上。最容易踩的坑有三个编译器没配好、求解器步长不一致、把 SIL 当成性能测试工具。跑通 SIL 后下一步是 PIL。把同样的生成代码放到目标处理器上运行观察计算耗时和存储占用。PIL 跑通后再进 HIL整个从模型到代码的验证链路就完整了。建议把 SIL 环节固化到模型开发规范中作为代码生成前的必选项。