尧图精选

MIL/SIL自动化测试实战:用PolarTest跑通模型到代码的测试闭环

🕒 发布时间:2026/9/11 2:07:13 📁 来源:尧图网络
干嵌入式控制器开发这一行的人应该都绕不开MIL和SIL这两个词。这几年我们团队在给整车和零部件客户做控制器算法验证时测试工具换过好几款最后固定下来用PolarTest这个自动化测试软件来跑MIL/SIL测试。今天抽空把它在我们项目里的实际用法、踩过的坑、以及我怎么理解这套测试闭环的完整写出来希望能给正在搭模型测试环境的朋友一些参考。我先说结论PolarTest的MIL/SIL功能解决的不是能不能测的问题而是怎么高效地反复测、批量测、可追溯地测的问题。它把模型阶段的MIL测试和代码阶段的SIL测试放到同一个工具框架里测试用例可以复用结果可以自动比对报告也省去手写的时间。这篇文章就围绕它到底是什么、为什么需要它、怎么落地用起来三条线展开适合刚接触模型在环测试的测试工程师也适合已经在用Simulink但想引入自动化测试体系的算法开发人员。1. MIL和SIL到底在测什么为什么自动化测试工具不可或缺想理解PolarTest这类工具的价值先把MIL和SIL这两个概念彻底捋清楚。很多新手容易把这两者混淆实际上它们在V模型开发流程里处于两个不同阶段测试目标和侧重点都不一样。1.1 MIL测试模型阶段就要把算法逻辑夯实MIL全称Model-in-the-Loop中文常叫模型在环。这是整个控制器开发流程里最早的一级测试。简单理解算法还在Simulink或者其他建模环境里以模型形式存在的时候你直接给模型灌输入信号观察输出是否满足预期这个动作就是MIL测试。为什么MIL重要因为在这个阶段代码还没生成硬件还不存在算法逻辑上的错误是改起来最便宜的时候。等代码生成、刷到硬件里再去改一条控制逻辑成本可能翻几十倍。所以我一直跟组里的人强调MIL测试不是走过场它是整个质量保障体系里性价比最高的一环。MIL测试的核心关注点是算法正确性。比如你写了一个PID控制器模型输入一个阶跃信号理想输出应该是快速稳定到目标值且超调量在允许范围。在MIL阶段你重点检查的是这个控制逻辑本身是否写对了积分限幅有没有生效抗积分饱和逻辑有没有触发。在这种场景下模型中使用的都是理想化信号源、理想化执行器不涉及硬件延迟、信号干扰这些物理因素。这里就有一个关键认知MIL测试不是HIL测试的替代品而是一个快速反馈手段。在模型上发现问题几十分钟就能改完重新仿真如果在台架上发现同样的问题可能就得重新安排试验、改代码、刷写、再试验周期是周级别的。所以MIL测试在项目早期做得越充分后面HIL和实车阶段踩到低级逻辑错误的概率就越低。不过MIL测试也有它的局限性。模型毕竟是环境里的抽象表达跟最终生成的C代码之间还存在差异。有些问题只有跑到代码层面才能暴露这就引出了SIL。1.2 SIL测试从模型到代码验证一致性SILSoftware-in-the-Loop软件在环。它测试的对象从模型换成了从模型自动生成的代码。简单说就是先用MATLAB的代码生成工具把Simulink模型生成C代码再把这段代码交给PolarTest加载运行用跟MIL阶段相同或者相近的输入激励它看输出是否和模型仿真结果一致。做SIL测试的核心目的是验证代码和模型是否等价。你可能会想代码是模型生成的为什么不直接等价实际上代码生成过程中涉及到的数据类型转换、代码优化、定点化处理、函数封装顺序等等都可能带来数值上甚至行为上的细微差异。尤其在做定点模型或者目标平台不是原生双精度浮点的时候这种差异会被放大。如果SIL阶段不把这个差异抓出来等代码做到HIL阶段再发现算法行为不对定位问题就变得很难因为你没法确定是模型的问题、代码生成的问题还是硬件适配的问题。从MIL到SIL测试用例理论上应该是同一套或者说SIL的测试用例可以通过MIL用例做移植。但SIL阶段额外多了一项工作分析MIL和SIL的输出差异。差异不是简单地说相等就完事要结合数据精度、容差、采样周期这些问题来看。这里还要补充一个容易混淆的概念有些人把SIL和PIL混为一谈。PIL是Processor-in-the-Loop处理器在环是把代码跑在实际目标芯片上只是通过调试器控制运行。SIL则是代码跑在PC或者其他通用环境上跟目标硬件无关。区别很明确SIL验证的是生成的代码逻辑PIL验证的是代码在具体芯片上的行为包含CPU算力、中断、外设初始化这些影响。PolarTest这类工具主要覆盖的是MIL和SIL这两级PIL往往要配合调试器和硬件板卡来单独做。1.3 为什么要用自动化工具而不是手动点仿真现在回到一个很实际的问题我不上工具直接在Simulink里跑仿真一样能看到结果为什么要专门用PolarTest来做自动化测试我把理由分成四个层面来讲。第一是批量执行能力。一个控制器模型对应的测试用例往往有几十条甚至几百条覆盖不同工况、输入组合和极限边界。手动一条一条去改输入信号、启动仿真、看波形、记录结果一个用例几分钟到几十分钟一晚上都未必跑得完而且人盯久了必然看漏。自动化工具可以批量执行用例跑完自动记录结果这是效率层面的碾压。第二是回归测试的重复性。模型不是写完就不动了控制策略在项目迭代过程中会不断调整。每次修改模型都需要重新验证之前所有用例。手动做一次回归可能是一天到几天的工时自动化做回归只需要在工具里点一下运行下班前就能拿到结果。这对项目节奏的要求是决定性的。第三是结果判断的可复现与可追溯。人眼看波形不同的人判断可能不同同一人不同状态下的判断也不同。自动化工具在用例里定义了明确的断言条件比如稳态误差小于多少、超调量小于多少、响应时间在什么范围内每次执行都用同一个标准判定结果稳定、可复现还能追溯到对应的需求编号。第四是MIL到SIL的统一管理。这个最贴近PolarTest的功能亮点。同一套工程文件里既配置MIL的模型执行环境也配置SIL的代码执行环境测试用例在两个阶段之间复用。这意味着你在MIL阶段定义好的输入激励和输出预期直接切到SIL阶段再跑一遍差异对比由工具自动完成。省去自己写脚本去串联两个阶段的痛苦也避免了在Excel表格里手工维护用例映射关系。2. PolarTest的MIL/SIL功能拆解从测试用例到报告一次打通PolarTest这个软件我接触了将近两年从最初的试用版本到现在的正式版本功能演进比较明显。这里我不讲随处可见的产品宣传话术直接把它在MIL/SIL测试里实际承担的角色拆开讲讲它在我的工作流里到底干了哪些脏活累活。2.1 PolarTest定位与核心能力如果把MIL/SIL测试的完整流程拆成搭建被测对象环境、管理测试用例、执行测试、判断结果、生成报告这五个环节PolarTest的核心能力就是把它们串成一条完整的链路。它不是一个单纯的仿真工具而是一个测试自动化管理平台Simulink更像是它调用的仿真引擎。在这套体系下PolarTest可以被看作中间调度层。它通过接口控制MATLAB/Simulink运行模型仿真也支持直接加载编译好的SIL动态库或可执行文件来跑代码然后把激励信号喂给被测对象采集输出信号再跟我们预先设定的预期值做比对最后给出通过/失败的结论。我特别认可它的一点是对测试数据的组织方式。每条测试用例包含的不仅仅是输入信号和预期值还包括前置条件、依赖的需求条目、被测模型版本、代码版本、判定容差、执行状态等等。这些元信息对项目级追溯非常关键特别是做功能安全相关项目的时候审核员问这条需求对应的测试用例是什么、结果如何你不需要再翻历史邮件和个人笔记直接在工具里导出报告就能交代。此外PolarTest对批量任务的处理也做得比较扎实。我们项目里有200多个模型子系统测试用例配置好之后一次任务执行可以全部跑完中间某个用例失败不会影响后续用例继续执行所有失败项在汇总报告里都列得清清楚楚。这对持续集成场景特别重要模型或代码有变更自动触发回归所有失败项直接被标记出来。2.2 与Simulink和Python工具链的集成方式接入PolarTest的时候最关心的第一个问题就是它跟现有工具链怎么配合。我们的工作环境以MATLAB/Simulink为主同时也写了不少Python脚本来做一些辅助的数据分析和格式转换所以工具必须两头都打通。跟Simulink的集成是MIL/SIL测试的基础能力。PolarTest通过命令行接口或者仿真接口控制Simulink配置待测模型路径、仿真起止时间、求解器类型、采样步长然后启动仿真。这里有一个体验很好的点它不强制改变模型本身的架构。你在Simulink里该怎么建模还怎么建模测试过程是在模型外部被驱动的。这意味着对模型本身的侵入性极小不会因为测试工具在你模型里塞了一堆测试相关的模块导致交付给客户的模型变得不干净。对于SIL测试PolarTest支持加载通过代码生成工具生成的动态库文件或者直接接入生成的C代码跑在本地环境中。我们一般的做法是先用MATLAB Code Generation把模型转成C代码编译成动态库然后在PolarTest里新建一个SIL测试工程指定动态库路径和对应的接口函数就可以把MIL阶段用过的测试用例直接切换执行环境。切换过程不需要重新写用例只需要改被测对象配置这个省下的工作量非常可观。Python集成方面PolarTest预留了Python脚本扩展的入口。我们用它做了两个事情一是写自定义的用例生成器从Excel或者数据库里读取需求矩阵自动批量生成测试用例省去手工录入的时间二是写后处理脚本把PolarTest导出的原始测试结果跟我们自己内部的数据分析平台做对接自动生成带图表的中文测试报告。如果你平时习惯用Python做数据分析这个扩展点基本就是为你准备的。2.3 测试用例组织与复用测试用例的组织方式决定了这套自动化体系能不能长期跑下去。PolarTest里的用例组织逻辑更接近文件夹条目的结构一个测试集下面可以挂多条测试用例每条用例可配置独立的参数组和断言条件也支持参数化就是多条用例共用一个模板只换输入和预期值。我比较喜欢它把激励输入和信号比对分成两个独立部分的设计。激励输入定义了测试执行时投喂给模型的信号可以是一组常值、一列时间序列数据或者是通过表达式自动生成的数据。信号比对则定义了从模型/代码输出里采集哪些信号以及用什么规则判定通过或失败。用例复用在MIL和SIL之间是最直观的收益。我们在建MIL用例时对每个用例都做了足够的参数化设计比如输入信号的幅值、时间点、容差范围都做成可变参数。这样切到SIL阶段时只需要整体复制用例组把被测对象环境从模型切换成动态库再用SIL特有的数据精度去调整一下容差参数即可。有些用例甚至不需要任何修改直接复用。另外PolarTest还支持在用例之间建立依赖关系。比如某个测试用例只有在前置用例执行通过之后才有意义工具会按照依赖关系决定执行顺序。这个设计在实际使用中避免了SIL阶段某个接口没初始化导致后续一堆用例全部失败的连锁问题。3. 实操用PolarTest从零跑通MIL/SIL测试闭环概念讲完接下来是大家最关心的部分具体怎么落地。我以自己的一个实际项目为例详细记录一下从模型准备到MIL测试完成、再到SIL测试跑通的完整过程。这个项目是一个简单的电机控制算法模块模型是Simulink环境下的包含电流环和速度环两层控制逻辑不算复杂但足以说明整个流程。3.1 准备工作与模型环境配置动手之前先把基础工作做好。你需要确保以下几点模型能够在Simulink中正常打开并手动仿真通过如果是做SIL还需要确认代码生成工具链可用代码生成配置已经调好PolarTest安装完成并成功配置了MATLAB的安装路径保证它能够识别并启动MATLAB。第一步是在PolarTest里新建一个MIL测试工程。工程的作用相当于一个容器后续的用例、仿真配置、结果记录都在这个容器里管理。新建工程时工具会让你选择被测对象类型这里直接选择Simulink Model然后浏览到你要测试的模型文件路径。模型的接口映射是整个配置里最容易出问题的一步。PolarTest需要知道怎么跟模型交换数据。比如你的模型有输入端口Throttle和输出端口Speed你需要把这两个端口转换成测试工程里的信号变量。PolarTest会自动扫描模型端口并显示在界面上你只需要手动确认哪些端口是输入、哪些是输出以及信号的数据类型和维度。这里有一个经验如果模型端口名称里有特殊字符或者中文建议提前在模型里改成规范的英文命名不然映射的时候容易出莫名其妙的问题。仿真参数也在这个阶段配置。包括仿真的起止时间、求解器类型固定步长还是变步长、固定步长大小以及信号采样周期。关于步长选择我多说一句。MIL阶段如果模型比较简单固定步长1ms或者更小通常没问题但如果模型比较大仿真步长太大会让结果偏差较大太小会让仿真时间成倍增加。实际项目中先按需求里要求的控制周期来定步长比如电机电流环控制周期是125微秒就把固定步长设成125微秒这样和实际代码运行节拍是吻合的。配置完成后先用一组手动的简单输入验证一下通路是否正常。直接在PolarTest里运行一次仿真看它能不能正常启动MATLAB、加载模型、完成仿真、把输出信号记录下来。这一步如果跑通了后面的用例加入只是量的增加不是质的改变。3.2 配置测试工程信号映射、仿真参数、断言容差工程新建完成接下来就是把怎么测的规则配置清楚。这个过程我建议按下面的顺序做可以减少混淆。第一是信号映射把模型的输入输出端口和测试工程中的物理信号一一对应。比如模型的输入Throttle对应测试工程里的Input.Throttle输出Speed对应Output.Speed。信号的数据类型必须和模型端口一致否则PolarTest在运行时可能报类型不匹配的错。多维信号也不复杂只要你把维度范围定义准确就行。第二是仿真配置。这里有一个相对核心的参数采样时间。它决定了PolarTest在仿真结束后以什么频率来采集输出信号。一般来说采样时间设为与控制周期一致或者更小这样能捕捉到信号跳变的细节如果设得太大可能错过超调峰值导致不准确的判定。不过采样时间设太小数据量大报告文件也会膨胀。我们通常用控制周期的二分之一。第三是断言容差设置。这是整个配置环节里最需要经验的地方。你定义输出期望值的时候MIL阶段的仿真结果通常是理想化的SIL阶段由于数据精度和代码实现方式的不同结果会和MIL有一点偏差。这个偏差并不是错但如果你把容差设成0SIL阶段的用例大概率会一批批失败。容差怎么设我的建议是结合信号量纲和工程意义来定。以电机转速为例输出范围可能达到几千转每分钟那容差设成±1转每分钟就足够严格如果是电流信号范围几十安培容差可以设成±0.1安培。不要拍脑袋而是先用一两条典型用例跑一遍观察MIL和SIL输出的实际差异量级再来设定容差。你可以把这个过程叫做试跑定容差听起来不够自动化但这恰恰是工程里最务实的做法。3.3 编写MIL/SIL批量测试用例配置好工程环境接下来就是编写测试用例。这一步是自动化测试的核心资产因为用例写得好不好直接决定测试覆盖率和工作效率。先说单条用例的基本元素。一个典型的PolarTest测试用例包括输入激励定义、仿真时长、输出期望值、判定容差、用例描述和关联需求。输入激励可以是阶跃、斜坡、正弦、脉冲序列或者是从文件导入的真实工况数据。对于电机控制模型我通常先用几组基础输入验证基本逻辑零输入状态下输出应为零或稳定值、阶跃输入下的响应时间和超调量、斜坡输入下的跟踪误差以及满幅值输入下的限幅行为。批量生成用例是PolarTest比较实用的能力。如果你要测试模型在一组不同幅值阶跃输入下的响应不需要手工创建几十条用例而是可以在一条用例里定义参数列表每个参数组合执行一次。比如阶跃幅值从10%、25%、50%、75%到100%分别形成独立执行场景。PolarTest的参数化机制会把每一种组合当作独立用例执行并单独记录结果。我特别喜欢这个功能因为它让数据驱动测试这个概念落到实处。MIL用例和SIL用例的差异主要体现在被测对象和容差上。我的做法是在PolarTest里建两组测试集一组被测对象是Simulink模型就叫MIL_Sim_Test另一组被测对象是编译好的SIL动态库就叫SIL_Lib_Test。这两组测试集的用例内容完全一样只是在被测对象配置和容差参数上有区别。MIL的容差可以收紧SIL的容差根据试跑结果适当放宽。补充一个重要细节SIL测试中如果被测动态库需要串行化初始化比如某个全局变量只在程序启动时设置一次那每执行一条SIL用例时最好加一个重置运行环境的前置动作。PolarTest支持在用例或测试集级别配置初始化脚本不要让上一条用例的残留状态污染下一条用例的结果。3.4 执行测试与结果比对用例配置完成剩下就是执行和读取结果了。在PolarTest里执行测试集工具会按照配置依次启动MATLAB、运行模型仿真或者加载动态库、驱动被测对象、采集输出信号、执行断言判定、记录结果。整个过程你基本不需要干预跑完看汇总就行。执行结束后第一件事是看执行总览多少条通过、多少条失败、多少条被跳过。失败的用例会标出具体是哪一步断言没过期望值是多少、实际值是多少以及两者偏差的百分比。这个信息对定位问题非常关键。MIL和SIL的结果比对是PolarTest一个比较顺手的用法。你可以把MIL和SIL两组测试集的结果导出到同一个对比报告里工具按用例一一对应把MIL输出和SIL输出画在同一张图里。如果某条用例MIL通过、SIL失败那优先怀疑代码生成环节是否有问题如果两组都失败那问题大概率在模型本身MIL阶段就应该发现。说一个我在结果分析时比较依赖的细节信号时域对比。PolarTest导出的结果里除了最终的通过/失败结论还会保留完整的信号采样点数据。这意味着当断言失败时我不需要重新跑一遍才能看到曲线而是可以直接在报告里查看失败时刻附近的信号细节。比如阶跃响应超调量超标我能从曲线图里看到超调发生在哪个时间点、峰值多大、是振荡导致还是稳态漂移导致。这个回溯能力比只看一个Fail结论要实用太多了。4. 常见问题与排查技巧实录MIL/SIL自动化测试看着流程清晰实际操作中仍然会遇到不少坑。我这里整理了一份实务问题速查表配合我自己的排查经验供参考。4.1 典型问题速查表问题现象可能原因排查思路解决建议仿真初始化失败MATLAB报模型路径错误工程配置时填写的模型路径不是绝对路径或者模型文件被移动过检查工程配置中被测对象路径确认模型文件确实存在于该路径直接修改工程配置指向正确的模型文件路径信号映射时找不到目标端口模型端口名称变化或端口被封装在子系统内部未暴露在Simulink中打开模型确认端口名称和层级修改模型端口命名或调整信号映射的层级配置MIL执行通过SIL执行时大量用例失败SIL阶段数据精度和代码生成方式导致数值偏差容差设置过小先不急着分析代码重点查看MIL与SIL输出曲线的差异量级根据试跑结果放宽SIL用例的判定容差并检查代码生成配置中是否有导致明显数值变化的高阶优化开关多条SIL用例连续失败但重新执行后单条通过前一条用例修改了全局状态或共享变量影响后续用例检查被测代码里是否有静态变量或全局变量未重置在测试集前置脚本中添加重置全局状态逻辑或者强制每条用例独立加载动态库输出信号在报告里为空采样时间设置过大导致输出采集点太少输出信号名称不匹配检查仿真配置中的采样时间和信号采集配置调小采样时间重新确认输出信号名称与模型端口完全一致执行到一半卡住MATLAB进程无响应模型仿真陷入死循环或者某些子系统内部产生了状态冲突先按暂停查看模型具体卡在哪个模块检查模型是否有初始条件缺失必要时在Simulink中单独跑一次仿真来定位卡点自动生成的报告里没有需求追溯信息测试用例没有关联需求条目或者关联编号输入错误检查用例管理页面的需求链接配置补齐用例与需求的关联关系重新生成报告4.2 我在实际项目中踩过的坑与规避方法踩坑经验这种东西书上很难学到我在这里多说几条我亲身经历的事。第一条关于SIL测试的全局变量污染问题。早期我们做SIL测试时把几百条用例放在同一个测试集里连续执行前十几条跑得好好的到后面突然开始一批批失败而且失败模式毫无规律。排查了很久最后发现是代码里有一个全局标志位在某条用例执行时被误置位了后面所有用例读到这个标志位后行为都发生了变化。这个问题的解决方式有两个层面代码层面加初始化逻辑测试层面在每条用例前重置全局状态。现在我再搭SIL测试体系都会第一时间确认被测代码的全局变量清单并且在测试配置里明确初始化和重置策略。第二条是关于容差设置的拍脑袋陷阱。刚开始用PolarTest时我把MIL和SIL的容差都设成了同一个很小的值自以为很严谨结果SIL用例几乎全挂。后来仔细看MIL和SIL的差异曲线发现有些信号的稳态差异虽然很小但动态过程中因为计算顺序不同峰值位置和宽度有细微差别。如果容差太小这种合理偏差也会被判失败。所以我现在有一条原则MIL用例的容差以模型规格要求的指标为准SIL用例的容差以MIL/SIL试跑差异的实测值放宽1.5到2倍为准而不是一刀切。第三条是仿真步长与断言采样时间的匹配问题。有一次我设置固定步长1ms采样时间设成100ms导致输出信号在采样点之间把一次短暂超调的峰值给漏掉了那条用例居然通过了但实际上模型的超调已经超标。这个案例让我意识到在自动化测试里怎么采样和怎么跑仿真同等重要。如果关心峰值或者快速变化信号采样时间必须足够密。我做测试配置时会先针对每条关键用例做一次预扫描用MATLAB自带的仿真数据检查器观察信号的最高变化速率再决定采样频率。第四点是关于模型版本和代码版本的同步。MIL测试用的是模型SIL测试用的是代码如果模型版本更新了代码没有同步重新生成那SIL测试跑出来的结果完全没有参考意义。以前吃过亏后来我要求项目组在PolarTest的测试工程里记录被测对象的版本信息并且每次执行前由工具自动校验模型文件时间戳和代码生成时间戳不一致就警告。PolarTest支持这些元信息配置用起来不费事但能避免很多张冠李戴的低级错误。再说一个小技巧。如果你测试的模型很大仿真一次要十几分钟批量跑几百条用例可能要跑一整个通宵。这种情况下我建议把测试集按子系统拆成多个小测试集先跑那些可能受到最近模型改动影响的核心用例快速发现明显问题再把完整回归放在夜间执行。虽然PolarTest支持跑完所有用例再汇总但在实际项目节奏中先快后全的策略能更早暴露问题给开发人员留出修复时间。5. 关于自动化测试体系的一点个人体会写到这我估摸着关于PolarTest MIL/SIL测试功能的实操内容基本讲全了。最后分享一点个人在项目推进中的心得也算收尾。工具终究是工具真正决定自动化测试体系能不能跑起来的往往是规范和执行。刚开始推这套东西时团队里也有人觉得多此一举明明手动仿真能解决的事情为什么非要花时间搭测试工程。但坚持了几轮迭代之后大家发现最大的收益不是省下了多少手动测试的时间而是模型和代码的每一次改动都有了历史可追溯、失败可定位的保障。没有自动化测试体系之前改动一个控制策略心里发慌总会下意识地问有没有影响到以前的功能有了这套体系后任何时候改动完都能快速批量回归信心完全不一样。如果你正打算引入MIL/SIL自动化测试我的建议是不要一开始就追求大而全先选一个比较稳定的模块用PolarTest把MIL到SIL的完整链路跑通积累一版种子用例再逐步扩展到其他模块。自动化测试体系的建立是一个逐步积累资产的过程用例库越丰富工具的价值就越大。希望这篇关于PolarTest MIL/SIL测试功能的实际经验能帮你少走一些弯路。
上一篇/下一篇内容由系统自动关联 返回资讯列表 →