ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Simulink模型在环测试(MIL)实战:从概念到全覆盖率

Simulink模型在环测试(MIL)实战:从概念到全覆盖率 1. MIL测试到底是个什么玩意儿1.1 模型在环这个环指什么MIL是Model-In-the-Loop的缩写中文叫模型在环测试。很多刚接触Simulink的人一听到这名字就懵了什么环在哪环其实说白了就是把你的控制算法模型放在一个虚拟的闭环环境里跑起来看它能不能按预期工作。这个环就是闭环反馈的意思你的控制器模型算出一个值送给被控对象模型被控对象反馈回状态量再回到控制器模型输入端一圈一圈转下去形成一个完整的仿真回路。我经常跟刚入行的同事打比方你在Simulink里搭了一个PID控制器模型旁边再放一个电机模型或者车辆动力学模型用信号线把它们连起来点击运行看转速、电流、车速这些曲线对不对这就是最朴素的MIL。关键点在于这时候被测对象是模型而不是实际的控制器硬件、不是编译后的C代码、更不是整车或者台架。所有东西都在你的电脑屏幕里纯粹靠Simulink仿真引擎跑。和MIL经常一起出现的还有SILSoftware-In-the-Loop软件在环、PILProcessor-In-the-Loop处理器在环、HILHardware-In-the-Loop硬件在环。很多新人分不清它们我习惯用一个递进逻辑来解释MIL阶段验证的是我的控制逻辑对不对SIL阶段验证的是生成的代码和我模型逻辑一不一致PIL阶段验证的是代码在目标芯片上算得对不对HIL阶段验证的是控制器硬件接上真实传感器和执行器信号后还灵不灵。每一步都是在上一步基础上加上更多真实感当然成本和复杂度也是成倍上涨的。所以MIL是整个测试链条里最便宜、最灵活、最容易发现问题的一环。它不需要任何硬件设备不需要刷写固件不需要搭台架只要有一台装了MATLAB和Simulink的电脑就能干。正因为门槛低它非常适合在算法开发早期就把逻辑错误、边界问题、需求歧义这些地雷排掉而不是等到造出样机再去返工。1.2 为什么要在Simulink里专门做MIL有人可能会问Simulink本身不就是用来仿真的吗我搭好模型直接跑不就完了为什么还要专门谈测试这两个字这个问题的答案在于跑一下和系统地测之间有本质区别。平时开发时点那个绿色的运行按钮拿Scope看看波形那叫看一眼有没有明显问题。而MIL测试是一种有组织、有记录、可重复、可追溯的验证活动你得先写测试用例规定输入是什么、期望输出是什么然后跑模型把实际输出和期望值对比最后还要看覆盖率确认模型的每条分支、每个条件都被测到了。这个过程要能回归也就是说今天改了一行逻辑明天要能一键把之前的用例全部重跑一遍确保没把旧功能弄坏。这才是MIL测试的核心价值——它不是随便跑跑而是把仿真变成一种工程化管理的手段。在汽车电子、航空航天、工业控制这些对安全性要求极高的领域MIL测试是功能安全流程比如ISO 26262里明确要求的活动。哪怕你不在这些行业做嵌入式控制算法开发养成MIL测试的习惯也能帮你省下大量调试时间。另外Simulink里做MIL还有个所有老工程师都知道的好处模型本身就是活的文档。你设计的每一个测试用例、每一次测试结果都可以通过Simulink Test工具箱关联到需求条目上实现需求、用例、结果三层追溯。这个追溯链到了项目评审或者功能安全认证的时候就是最有力的证据。没有这一步你光说我测过了没人会信。2. MIL测试解决的核心问题与实战场景2.1 从需求歧义到逻辑漏洞MIL到底能抓住什么我做过好几个项目发现MIL阶段最容易暴露的问题有三种类型。第一类是需求理解偏差。需求文档上写着当车速大于30km/h时禁止升挡但实现的时候条件写成了当车速大于等于30km/h时禁止升挡。这1km/h的差别肉眼很难发现但是用测试用例一测输入车速正好等于30的时候实际输出和期望输出就打架了。这种问题在代码里可能埋藏很久但在模型测试阶段一分钟就能暴露。第二类是边界和极端工况处理不当。比如查表模块输入超出表格范围时是取端点值还是线性外推除法运算分母接近零的时候会不会溢出滞环比较器在临界点会不会反复抖动这些情况在正常工况仿真里根本不会出现只有专门设计边界测试用例才能逼出来。第三类是状态机逻辑死锁或者状态跳转异常。Stateflow写的状态机如果某个事件触发条件永远无法满足或者两个状态之间互相使能形成死循环模型跑起来要么卡住要么状态在错误的时间切换到错误的节点。这种问题靠人盯波形图很难定位但设计好覆盖各种事件序列的测试用例后跑一次就能看到异常。MIL测试也不能解决所有问题。它毕竟是纯虚拟环境传感器噪声、通信延迟、执行器非线性这些物理特性在MIL阶段通常被刻意简化了。所以MIL发现不了的问题需要留给后面SIL、PIL和HIL去补。但反过来讲MIL阶段能解决的问题越早解决成本越低。这个逻辑在软件行业叫左移测试在汽车电子行业其实就是V模型的基本理念——每一层开发都有对应的测试活动测试越早介入返工成本越小。2.2 哪些项目最适合上MIL测试不是所有Simulink模型都值得投入精力做完整的MIL测试。我在实际项目中一般这样判断优先级。逻辑复杂、状态多的模型最值得做。比如自动变速箱控制策略、混动能量管理策略、电池管理系统里的SOC估算和均衡逻辑这些模型动辄几百个模块、几十个状态靠人工看波形根本盯不过来必须靠自动化测试用例跑覆盖面。与安全强相关的功能必须做。转向助力、制动防抱死、车身稳定控制这类功能一旦逻辑出错可能直接威胁人身安全。在MIL阶段把逻辑验证清楚是对后面所有环节负责。需求变更频繁的项目尤其需要。控制策略开发很少有一版定案的尤其是前期算法迭代快的时候可能一周改好几次模型。如果没有一套可以自动回归的MIL测试用例每次改完都靠手工重新验证消耗极大。有了测试套件模型改完一键跑完所有用例哪里挂了立刻知道大大提升迭代效率。反过来纯数学计算、没有反馈控制的简单模型或者一次性用完就扔的仿真脚本就不必兴师动众搭MIL测试环境。测试投入要跟代码的重要性和生命周期匹配这也是工程经验的一部分。3. Simulink中MIL测试的完整实操流程3.1 模型准备与信号规划开始MIL测试之前先把被测模型整理干净。我见过太多新手拿一个乱糟糟的模型直接开测结果信号连错、命名混乱测试结果根本没法追溯。这里分享几个我固定的准备工作。第一步给模型做分层。被测对象通常是控制器模型把它封装成带明确输入输出端口的子系统。输入端口放传感器信号、上位指令、反馈状态输出端口放控制量、诊断状态、标定参数。外部激励和观测模块全部放在被测子系统外面这样测试时只需掐住输入输出端口逻辑非常清晰。第二步统一信号线和数据类型的命名规范。信号线不要用默认的Signal1Signal2要起有意义的名字比如VehSpd_KmhEngSpd_rpmPedalPos_pct。数据类型也要提前定死是double还是single还是定点数MIL阶段最好跟目标代码生成后的类型保持一致免得后面SIL阶段冒出一堆类型转换问题。第三步确认模型用的求解器配置。MIL测试针对的是离散控制算法一般建议用固定步长离散求解器步长根据实际控制周期来比如10毫秒或者1毫秒。千万不要用变步长变步长仿真的行为跟实际代码运行时的离散特性不一致测试结果不可信。这一步经常被忽略但非常关键。第四步如果模型中包含Goto/From或者Data Store Memory这种全局数据传递方式最好在测试前把它们理清楚。隐藏的数据依赖会让测试用例的设计变得困难因为你不知道某个信号从哪里来、受什么影响。经验做法是把被测子系统改造成纯端口数据流所有跨层数据都通过Input/Output端口显式传递测试时才能精确控制每个激励。3.2 测试用例设计从功能出发用边界逼出问题测试用例是MIL测试的灵魂。很多新手一上来就纠结工具怎么用其实工具只是执行者真正决定测试价值的是你怎么设计用例。我的用例设计思路分为四个层次。第一个层次是正常功能用例。对应需求文档里明确描述的正常场景比如油门踏板踩到50%车速应该从0平稳上升到80km/h。这类用例验证的是正常情况下模型能不能干好活属于最基础的冒烟测试。第二个层次是边界值用例。这是MIL测试性价比最高的部分。每个输入信号都要考虑最小值、最大值、临界阈值附近的值。比如温度传感器量程是-40到125摄氏度你至少得测-40、125、以及报警阈值附近的-20和85。边界用例最容易暴露比较条件等于号的错误、查表端点设置不合理这些问题。第三个层次是异常输入用例。给模型喂信号超范围的值、NaN、Inf、阶跃突变信号、频率异常的信号看模型是优雅地进入安全状态还是直接崩掉或者输出乱跳。控制算法必须有容错能力异常注入就是检验这道防线的。第四个层次是时序用例。控制的本质是随时间变化的有些bug只在特定时序下触发。比如两个事件几乎同时到达或者某个状态在极小时间窗口内被反复触发。设计用例时可以故意构造这些竞争条件观察状态机是否出现毛刺或者卡死。用例要写成可执行的形式。最简单的方式是用Signal Editor模块编辑激励信号把时间点和信号值做成表格直接在仿真里播放。更工程化的做法是用Simulink Test工具箱的Test Manager统一管理每个用例包含输入激励、预期输出、容忍范围、关联需求编号一键批量执行自动生成测试报告。如果项目还处于手工测试阶段也至少要把每个用例的输入输出截图存下来标明测试时间、模型版本、期望结果和实际结果。没有记录的测试等于没测。3.3 用Simulink Test搭起自动化测试环境当用例量超过几十个手工在模型上一个个改信号再点运行根本不可持续。这时候就得上Simulink Test。用Simulink Test建立自动化测试套件的步骤我简单梳理一下。先打开Test Manager创建一个测试文件.mldatx然后新建测试用例。每个用例可以关联一个仿真输入Signal Editor的.mat文件或者Excel表格设定信号组指定被测模型和要观测的输出。最关键的是要设置评估逻辑——也就是断定这个用例过没过的判据。你可以选择Signal Tolerance信号容差比较、Baseline与基准曲线对比、Equality精确相等等方式把模型实际输出和一份期望数据做对比超出容差就标记为失败。执行的时候可以选中所有用例一起跑Test Manager会依次仿真每个用例并把结果汇总到一张表里Pass、Fail、Error一目了然。跑完以后还可以导出HTML或者PDF报告发给同事或者归档都方便。这套环境搭好以后每次模型有改动我只需要打开Test Manager点一下Run All几十个用例几分钟之内跑完哪个功能被改坏了立刻就能定位。这个习惯真心建议所有做控制算法开发的人都养成它带来的效率提升是数量级的。3.4 覆盖率分析没有覆盖率的MIL测试不算完整我见过一些团队说自己在做MIL测试追问一句打到多少覆盖率了对方愣住。MIL测试如果只做功能验证而无视覆盖率那跟点运行看看波形的差距没那么大。Simulink Coverage工具箱专门干这个事。它能在仿真结束后统计模型的执行覆盖率主要有以下几种。语句覆盖率Statement Coverage是基础中的基础统计每个模块被执行的次数。如果你的模型里有某个模块从来没被触发过说明对应的逻辑分支在现有用例下从未走到那这个逻辑是否有问题就完全未知。决策覆盖率Decision Coverage统计每个逻辑分支的True和False是否都被执行过。比如一个if判断如果只测了条件成立的场景没测条件不成立的场景决策覆盖就是不完整的。条件覆盖率Condition Coverage要求每个条件表达式的每个原子条件都出现过真和假两种情况。MCDC修正条件判定覆盖更严格要求每个条件独立影响判定结果。在汽车功能安全等级比较高的模块里MCDC往往是强制要求。用Simulink Coverage的时候在Simulation菜单里勾选Coverage Settings选择要统计的覆盖率类型跑完测试集后打开Coverage Analyzer就能看到每个模块的覆盖百分比以及未覆盖的具体分支。看到红色标记的未覆盖逻辑就要回头补充对应的测试用例把覆盖率一点一点拉上去。我一般把语句覆盖率的底线定在90%以上决策覆盖率80%以上MCDC尽量达到100%。达不到不可怕可怕的是不知道哪些分支没测到覆盖率工具就是给你照出这些盲区的探照灯。4. MIL测试常见问题与排查技巧实录4.1 数据类型和维数不匹配最烦人的隐性地雷用MIL测试跑一个项目我最常遇到的第一类问题就是Simulink报Dimension mismatch或者Data type mismatch。模型平时看着好好的一上测试用例就报错原因通常是测试用例里注入的信号维数或者类型跟被测模块端口的预期不一致。排查这个问题的技巧是在模型配置里打开信号维数和类型的显示。在Format菜单下勾选Signal Dimensions和Port Data Types每条信号线上就能直接看到维数和类型一眼就能定位谁跟谁对不上。另外养成好习惯所有输入端口用Signal Specification模块把类型和维数显式定义出来而不是靠Simulink自动推断。自动推断在简单模型里没问题模型一复杂就容易出现被推断成奇怪类型的情况。还有一类跟数据类型相关的问题就是溢出和饱和。MIL仿真默认double类型所以不会暴露定点数溢出问题。如果你的目标代码是定点实现MIL阶段最好就用Fixed-Point Designer工具把模型配置成定点仿真或者至少在关键计算环节加上Saturation模块模拟真实行为。不然等到SIL阶段发现算法结果偏差很大回头改模型就费劲了。4.2 求解器设置不当导致仿真结果不可信模型跑起来曲线很漂亮结果一检查发现那是在变步长、连续求解器下跑出来的而实际嵌入式代码是固定步长离散执行——这种测试结果基本等于白测。我在V模型开发项目里吃过这个亏。有一年做一个电机控制器的MIL测试模型里积分模块用的是连续求解器仿真波形非常平滑测试结果也全Pass。结果生成代码烧到芯片上一跑实际电流波形有轻微抖动跟仿真对不上。后来排查半天才发现问题就出在求解器配置上。MIL仿真必须和实际控制器的执行方式保持一致控制器是1毫秒周期跑一次任务MIL就必须用固定步长1毫秒离散求解器跑。连续求解器算出来的中间状态在真实代码里根本不存在自然对不上。检查办法很简单打开模型配置参数Solver选项里面看清楚Type是Fixed-step还是Variable-stepSolver选的是discrete还是ode。做控制算法MIL测试标准配置就是Fixed-step加discrete如果模型里有连续被控对象模型那连续对象部分可以单独用ode求解器但被控对象要跟控制器分开仿真或者通过适当方法离散化。4.3 代数环报警信号直接绕回导致计算死锁Model contains algebraic loop这种报警很多新手一看到就头皮发麻。代数环的本质是某个模块的输出直接或者通过纯直通路径影响了自己的输入中间没有任何延迟单元。比如你把一个增益模块的输出直接连回它的输入端这个方程在每一个仿真步长里都要求解一个隐式方程Simulink虽然能迭代求解但速度变慢而且容易出现数值问题。在MIL测试里代数环出现后最直接的负面影响是仿真可能跑得很慢甚至报错。处理办法通常有三种。第一种是在环路上插入一个Unit Delay模块离散系统或者Memory模块连续系统打破直通路径这是最常用的做法。第二种是重写模型结构用状态空间方式避开直接反馈。第三种是如果代数环是模型固有特征且无法消除可以调整模型配置里的Algebraic Loop Solver参数但这不是根治办法。我在MIL测试前都会专门跑一遍静态检查用Simulink Check工具箱扫描模型里的代数环和无效结构提前处理干净再开始测试。你在Test Manager里跑批量用例的时候如果某个用例因为代数环数值问题报错整个测试集都得停下来处理非常影响效率。4.4 测试用例管理混乱版本对不上报告没法看测试用例也是代码也有版本。我见过不止一个团队用Excel管理测试用例文件名写着v1.0里面内容已经改得面目全非到底哪个版本对应哪个模型版本完全说不清。等到客户审核或者功能安全评估的时候资料对不上一大堆返工。我推荐的方案是测试文件跟模型文件放在同一个Simulink工程Project里统一管理每次模型有变更都同步更新测试用例并且把模型版本号和测试用例版本号绑定起来。用Simulink Test的测试文件本身就把用例、输入数据、评估标准、执行结果打包在一起天然适合版本管理。配合Simulink Project的依赖分析功能随时能找到这个模型版本对应的测试集是哪一版。另外一定要在测试报告里写清楚环境信息MATLAB版本、Simulink版本、工具箱版本、操作系统。很多看似玄学的测试差异最后查根因都是版本不一致导致的。把这些信息留在报告里能省掉后面大量的扯皮。5. MIL测试工具链选型与后续扩展思路5.1 工具配置清单与推荐组合做MIL测试不一定需要全套最贵的工具箱但要干活干得舒服下面这几样是我最常用的组合。Simulink Test是核心负责测试用例管理、批量执行、报告生成。Simulink Coverage负责覆盖率统计。Signal Editor负责编辑激励信号支持导入Excel或者MAT文件批量造数据很方便。如果项目里有Stateflow状态机需要下载Stateflow的测试插件可以自动生成状态转换覆盖率的用例。如果团队有静态代码规范要求Simulink Check可以做模型静态检查比如命名规范、死逻辑检测、可疑结构扫描和MIL测试是互补关系。Simulink Requirements负责把需求和测试用例关联起来功能安全项目基本是标配。还有一个小工具我特别喜欢——Simulink Test里的Test Sequence Block。它可以用来写时序逻辑比较复杂的测试场景比如先给一个高电平保持100毫秒再给一个低电平同时监测某个输出是否在50毫秒内响应。比纯信号编辑器灵活得多适合设计带时间约束的用例。至于被控对象模型如果团队没有自研的高保真对象模型前期用简单的传递函数或者一阶惯性环节凑合一下也够用。MIL测试的核心是把控制器逻辑测透被控对象的精度要求可以放低一点。但要注意被控对象不能太失真否则控制器的参数整定结果没有参考价值。5.2 从MIL往SIL、PIL走路子怎么衔接MIL测试做完不等于万事大吉它是整个验证链条的第一环。我建议在项目初期就把MIL、SIL、PIL的衔接关系想清楚不然后面每一步都要重新搭环境。SIL测试是把Simulink模型通过Embedded Coder生成C代码然后在电脑上跑这个代码验证代码行为和模型行为是否一致。做法非常成熟把模型配置成支持代码生成再用Simulink Test里相同的那套测试用例跑一遍SIL模式最后对比MIL和SIL的结果差异。如果差异超过容忍范围说明代码生成配置有问题或者模型里有代码生成不支持的构造。PIL测试则需要目标处理器环境比如你用TI的TMS320系列芯片做控制器PIL就是把这套代码烧到芯片上跑用处理器在环的方式对比结果。PIL能发现编译器优化、芯片字长、浮点精度这些问题。MIL、SIL、PIL三层测试最好用同一套测试用例和同一个Test Manager工程来管理。这样能实现一键迁移模型在MIL阶段准备好用例SIL阶段直接复用PIL阶段也差不多。我在多个项目里验证过只要MIL用例设计时充分考虑了数据类型和步长的真实性后面的SIL和PIL阶段很少需要大量重写用例。5.3 别忘了需求追溯和回归测试这两个收尾动作MIL测试最后有两个收尾动作很多人会漏掉一个是需求追溯一个是回归测试策略。需求追溯是指每条测试用例都要跟需求条目对应上。用Simulink Requirements把需求文档导入然后在Test Manager里给每条用例关联需求ID。这样最终测试报告里会自动生成一张追溯矩阵哪条需求被哪几条用例覆盖覆盖率有没有达标一目了然。功能安全审核的时候审核员问的第一句话往往就是你的测试怎么证明覆盖了所有需求有了追溯矩阵这个问题就能直接拿报告说话。回归测试策略解决的是模型改了以后我怎么知道没改坏其他功能的问题。我的做法是每次模型迭代后至少把之前所有的MIL测试用例完整跑一遍任何一条Fail了都必须解释清楚原因是新功能改变了预期行为还是改坏了旧逻辑绝不允许这个用例先标记为失败后面再说这种状态遗留。测试结果只有Pass和Fail两种Pending就是在积累技术债。写在最后回头说点实在话。MIL测试在我眼里是所有模型开发里性价比最高的一项投资。它不需要昂贵硬件不需要复杂环境只需要一台电脑、一套Simulink、加上认真设计的测试用例就能把控制逻辑里绝大多数问题拦截在开发早期。我一个朋友常开玩笑说MIL测试就是给模型照X光——平时表面看着没毛病一照才发现骨子里全是隐患。我个人这几年做下来最深的体会是MIL测试的难点从来不是工具怎么操作而是愿不愿意在设计测试用例上花心思。工具是死的用例是活的一个精心设计的边界用例可能比一百个普通仿真里偶然瞄一眼波形更有价值。另一个体会是测试一定要跟版本管理绑定模型要进版本库测试用例和测试报告同样要进版本库这样整个开发过程才经得起追溯。如果你刚开始接触Simulink里的MIL测试我的建议很简单先从一个小模型开始把Signal Editor加Simulink Test加Simulink Coverage这条路走通跑出第一份带覆盖率报告的测试结果你就理解这套方法论的全部价值了。工具熟练以后再往SIL和PIL扩展就是水到渠成的事。
返回列表