一、硬件在环测试里信号同步失真的典型场景
我们做嵌入式算法开发的,尤其是汽车、储能这类需要硬件在环(HIL)测试的项目,肯定遇见过这种情况:调试Simulink跑的控制算法,本来该精准同步的信号,要么延迟了几帧,要么跳变异常,最后算出来的控制结果差了一大截。比如我2022年参与的某款纯电动车BMS项目,在HIL平台测试时,连续快充场景下SOC估算值比实际低了5%,花了3天才定位问题,最后发现是信号同步的问题。这类信号不同步、数值失真的情况,就是我们常说的“信号同步失真”,在HIL测试里属于高频出现的典型bug,尤其是当模型里有多个不同采样周期的信号,或者对接真实硬件IO的时候,更容易踩坑。
二、信号同步失真的两大核心诱因
大部分情况下,信号同步失真的根源都出在两个地方:要么是接口数据转换没处理好,要么是实时任务的调度优先级设错了。下面我们分别拆开讲,每个部分都配实际项目里的可复用示例。
2.1 接口数据类型不匹配导致的延时
Simulink模型里的信号类型,和实际硬件IO的类型经常不一样,比如模型里用的是方便计算的double类型,而硬件IO板的GPIO只能支持uint16这种整型。如果只靠Simulink的自动隐式转换,就会出现两个问题:一是转换逻辑可能依赖代码生成后的优化,导致运行时每几个采样点就有一个延时;二是如果原信号数值超出硬件类型的范围,会悄悄截断,导致信号失真。 这里给大家一个错误配置和正确配置的对比示例,技术栈用大家最常用的Matlab R2023b + Simulink,直接复制就能改自己的模型:
% 技术栈:Matlab R2023b + Simulink
% -------------------错误配置(隐式转换)-------------------
% 操作步骤:
% 1. 打开你的Simulink模型,进入Configuration Parameters -> Hardware Implementation
% 2. 找到对应硬件IO的输入端口,直接设置数据类型为double,完全没考虑硬件支持的类型
% 问题:Simulink会自动在代码生成时添加转换逻辑,但这个逻辑不是同步的,每10个采样点就会出现一个转换延时,导致信号不同步
% -------------------正确配置(显式类型转换)-------------------
% 操作步骤:
% 1. 在模型中添加一个子系统,命名为Signal_Interface_Converter
% 2. 拖入三个模块:In1(输入端口,类型double,采样时间1e-3s,也就是1ms)、DataTypeConversion(类型转换块)、Out1(输出端口,类型uint16,匹配硬件IO)
% 3. 配置DataTypeConversion块:设置为'uint16',饱和模式选'Saturate on overflow',四舍五入模式选'Floor'
% 4. 连接三个模块:In1 -> DataTypeConversion -> Out1
% 示例注释:
% 显式转换的好处是在Simulink仿真阶段就完成类型校验,代码生成时转换逻辑是固定的,不会出现随机延时,而且我们手动设置了饱和模式,超出范围的数值会被截断到最大值,不会出现隐式转换的异常跳变
刚才的BMS项目里,我一开始就是用的错误配置,导致电流信号每10个采样点就丢一个,改成显式转换后,信号同步的问题立刻解决了,SOC估算的误差降到了0.5%以内。
2.2 实时任务优先级配置导致的时序混乱
如果Simulink模型是部署到实时硬件上(比如用Simulink Real-Time、Embedded Coder生成代码,部署到xPC Target、NI HIL这类平台),那实时任务的调度优先级就是关键。比如,负责同步收发信号的任务,优先级比计算SOC、电机转速的任务低,那当高负载的算法任务运行时,同步任务就会被强制打断,导致信号延迟几ms,看起来就是不同步。 这里给大家一个实际项目里用的优先级配置示例,还是用Matlab R2023b + Simulink Real-Time,这个示例针对的是xPC Target平台,优先级数值越大优先级越高:
% 技术栈:Matlab R2023b + Simulink Real-Time
% -------------------实时任务优先级配置示例-------------------
% 步骤1:启动实时目标,获取目标对象
tg = slrt;
% 步骤2:加载你的Simulink模型(这里替换成你自己的模型名,比如BMS_Model)
tg.load('BMS_Model');
% 步骤3:配置信号同步任务的优先级:模型里的Signal_Sync_Task是管1ms信号收发的任务,优先级设为30(xPC Target最高优先级是31)
set_param('BMS_Model/Signal_Sync_Task', 'Priority', '30');
% 步骤4:配置算法计算任务(比如SOC_Calc_Task,负责估算SOC),优先级设为10,比同步任务低,避免被抢占
set_param('BMS_Model/SOC_Calc_Task', 'Priority', '10');
% 步骤5:启动实时目标,开始测试
tg.start;
% 示例注释:
% 为什么要这么设?同步任务是保证信号按时收发的核心,必须让它不受其他任务的干扰,所以优先级要设成最高的几个,算法任务可以稍低,这样既保证了信号同步,又不会影响算法的计算效率
之前我做另一个储能项目时,就是把同步任务的优先级设成了10,算法任务设成了20,结果一到高充放电功率时,同步任务就被算法打断,信号延迟了2ms,改成同步任务优先级30后,时序立刻正常了。
三、排查信号同步失真的具体步骤
遇到这类问题不用慌,按以下步骤来,大部分都能快速定位:
- 先查接口类型:打开Simulink模型的硬件配置,看输入输出端口的类型,和硬件IO的类型是否一致,有没有隐式转换的情况,用刚才的显式转换方法修正;
- 再查任务优先级:如果是部署到实时硬件的,用Simulink Real-Time的
tg.taskinfo命令,查看所有实时任务的优先级,看同步任务的优先级是不是比算法任务高,不对的话按刚才的示例修改; - 再查采样时间:所有和同步相关的信号,采样时间必须完全一致,比如都是1ms,不能一个是1ms,一个是1.0001ms,不然会有相位差,导致不同步;
- 最后看数值范围:类型转换时,原信号的数值有没有超出目标类型的范围,比如double转uint16时,数值超过65535的话,要加饱和处理,避免失真。
四、技术优缺点分析
4.1 接口数据类型转换的优缺点
优点:操作简单,不需要改太多代码,只要加个转换块就行,适合快速排查问题,对新手友好;缺点:如果转换逻辑复杂(比如带多段饱和、缩放),会增加一点算力,对于低性能的硬件(比如8位单片机)要注意优化,不然会影响整体性能。
4.2 实时优先级配置的优缺点
优点:灵活,可以针对不同任务调整优先级,适合复杂的多任务系统,能从根本上解决时序抢占的问题;缺点:要求开发人员懂实时系统的调度规则,不同硬件平台的优先级规则不一样(比如STM32的优先级是数值越小越高,xPC Target是数值越大越高),容易搞混,调试起来需要一定的经验。
五、注意事项
- 类型转换时一定要设置饱和模式,不能随便用默认设置,不然超出范围的数值会悄悄截断,导致信号失真;
- 采样时间必须严格一致,尤其是同一路信号的收发和处理,采样时间不一样会产生相位差,看起来就是信号不同步;
- 实时优先级不能设到最高的1-2个,要留一定的空间给系统任务,不然会导致系统任务饿死,比如实时目标的心跳任务,会出现连接断开的情况;
- 如果是对接第三方硬件(比如NI的HIL),要查硬件的IO手册,确认IO的类型和采样时间,不要自己乱猜。
六、总结
Simulink HIL测试里的信号同步失真,其实大部分都是“没做好类型转换”或者“优先级设错了”这两个问题,不用想得太复杂,按刚才的排查步骤来,先查类型,再查优先级,再查采样时间,再查数值范围,很快就能解决。这次分享的两个示例,都是我实际项目里用过的,直接复制就能用,不管你是刚接触Simulink的新手,还是有经验的开发者,都能用上。
Comments