2、系统架构设计:基于dSPACE的HIL/SIL/MIL架构选型、硬件资源规划与软件分层
好,咱们进入第二章。系统架构设计,说白了就是给项目搭骨架。骨架搭歪了,后面填再多肉也白搭。我见过太多项目,前期架构没想清楚,到集成阶段才发现硬件资源不够用,或者MIL和HIL的模型根本没法复用——那叫一个痛苦。
这一章,我会结合我自己在几个量产项目里的经验,聊聊怎么选MIL/SIL/HIL架构,怎么规划DS1006、DS1202这些硬件,以及软件层怎么分才清爽。
2.1 MIL/SIL/HIL架构选型:别一上来就上HIL
很多刚接触dSPACE的工程师,容易犯一个毛病:觉得HIL最牛,直接上HIL。其实不是这样的。你想想看,一个控制算法还在改来改去的时候,你拿HIL去跑,那不是杀鸡用牛刀吗?
我个人习惯,按这个节奏来:
- MIL(模型在环):算法开发初期用。说白了,就是Simulink里跑跑,看看控制逻辑对不对。这时候连代码都没生成呢。
- SIL(软件在环):代码生成了,但跑在PC上。验证代码和模型是否一致。这一步我建议别省,很多数据类型不匹配的问题,SIL一跑就现原形。
- HIL(硬件在环):代码烧到控制器里了,接上dSPACE的实时硬件。这时候才真正考验控制器和真实负载的交互。
我的经验之谈:我曾经在一个项目中,客户非要跳过SIL直接上HIL。结果呢?代码里有个uint16溢出,在MIL里根本看不出来,HIL上一跑,电机直接抖起来了。后来老老实实补了SIL测试,半天就定位了问题。所以,别图快,一步一个脚印。
选型时,你可以参考这个表格:
| 架构 | 适用阶段 | 实时性要求 | 硬件成本 | 我推荐的使用场景 |
|---|---|---|---|---|
| MIL | 算法开发 | 无 | 低(仅需Simulink) | 控制策略验证、参数整定 |
| SIL | 代码生成后 | 无 | 低(PC即可) | 代码一致性测试、回归测试 |
| HIL | 集成测试 | 硬实时 | 高(需dSPACE硬件) | 故障注入、极限工况测试、标定 |
2.2 硬件资源规划:DS1006和DS1202怎么选?
硬件选型这块,我经常被问到:“DS1006和DS1202到底哪个好?” 其实没有绝对的好,只有合不合适。
DS1006 是dSPACE的老将了,多核PowerPC架构。我个人觉得它最大的优点是稳定。我在一个动力总成项目里,用DS1006跑了整整两年的HIL测试,没出过一次硬件故障。它的IO扩展性也强,适合那种通道数特别多的项目,比如整车控制器HIL。
DS1202 是后起之秀,基于Xilinx Zynq UltraScale+。说白了,它把FPGA和ARM揉在一起了。好处是什么?跑高速信号特别爽。比如电机控制里的PWM信号、旋变解码,用DS1202的FPGA来处理,延迟可以做到微秒级。我有个做电机HIL的朋友,换了DS1202之后,仿真精度直接上了一个台阶。
避坑指南:我曾经在一个项目中,用DS1006跑一个需要高速PWM输出的测试。结果发现CPU负载太高,PWM周期抖动超标。后来换成了DS1202,把PWM生成逻辑放到FPGA里,问题就解决了。所以,如果你的项目里有很多高速IO或者需要自定义协议,DS1202是更好的选择。
硬件资源规划时,我建议你考虑这几点:
- CPU负载:别超过70%。留点余量给后续的测试用例扩展。
- IO通道数:数清楚你需要的AI、AO、DI、DO、PWM、CAN、LIN、FlexRay通道。我习惯多预留20%的通道。
- 实时性:步长要求是多少?1ms?100us?10us?这直接决定了你用DS1006还是DS1202。
- 扩展性:未来会不会增加测试节点?如果会,建议选支持PHS总线的机箱,方便以后加板卡。
2.3 软件架构分层设计:让模型像乐高一样可拼插
软件架构这块,我踩过不少坑。早期我做项目,喜欢把所有的逻辑都写在一个巨大的Simulink模型里。结果呢?模型打开要5分钟,改一个参数要全局搜索,团队协作更是噩梦。
后来我学乖了,开始做分层设计。我的分层思路是这样的:
- 接口层:负责和硬件打交道。比如IO读取、CAN报文收发、PWM捕获。这一层只做信号转换,不做控制逻辑。
- 应用层:控制算法、状态机、诊断逻辑。这是核心,应该和硬件完全解耦。
- 调度层:管理任务的执行顺序和周期。比如10ms任务、100ms任务、事件触发任务。
这样做的好处很明显:接口层换了硬件,应用层不用动。我曾经在一个项目中,把HIL平台的IO板卡从DS2211换成了DS26555,只需要改接口层的模型,应用层一行代码没动。这就是分层设计的威力。
举个例子:假设你要做一个电池管理系统(BMS)的HIL测试。接口层负责采集电压、电流、温度信号,并转换成物理值。应用层负责SOC估算、均衡策略、故障诊断。调度层决定什么时候执行SOC估算(比如每100ms一次),什么时候执行故障诊断(比如事件触发)。这样,即使你换了不同的电池模型,或者换了不同的IO板卡,应用层的SOC算法依然可以复用。
嗯,这里要注意一点:分层不是越细越好。我见过有人分了七八层,结果信号传递的延迟比控制周期还长。一般来说,3到4层就足够了。
最后,分享一个我常用的模型组织方式:
ProjectRoot/
├── 00_Requirements/ # 需求文档
├── 01_Architecture/ # 架构设计
├── 02_InterfaceLayer/ # 接口层模型
│ ├── IO_Config.slx
│ └── CAN_Config.slx
├── 03_ApplicationLayer/ # 应用层模型
│ ├── ControlLogic.slx
│ └── Diagnostic.slx
├── 04_Scheduler/ # 调度层
│ └── TaskManager.slx
├── 05_TestCases/ # 测试用例
└── 06_Results/ # 测试结果
这样组织,不管是自己维护还是交接给同事,都一目了然。好了,这一章就到这里。下一章我们聊聊测试用例的设计,那又是一个大坑。