CAN 报文的多路复用和解复用
简介
此示例说明如何对 CAN 报文应用多路复用和解复用。
多路复用是一种在 CAN 总线通信中用于增加传输信号数量的方法,但其代价是降低了每个信号的有效采样率。
多路复用信号属于同一 CAN 帧,但其位布局可能重叠。位模式的解释是有条件的,取决于另一个信号的值,该信号称为多路复用器。
假设有以下使用 CAN 通信管理器检索的多路复用 OBD-II(板载诊断)帧序列:
前两个数据字节的解释取决于第三个字节的值,该字节对应于 OBD-II PID。
具体来说,该帧携带三个不同信号,具有重叠的位布局,如以下各图所示。
发动机扭矩,OBD-II PID = 98(十进制),62(十六进制)
加速踏板位置,OBD-II PID = 73(十进制),49(十六进制)
车速,OBD-II PID = 13(十进制),0D(十六进制)
多路复用器信号
请注意,多路复用器信号的位布局不与其他三个信号的位布局重叠。
在以下各节中,将使用 Simulink® 模型对实际记录的信号进行多路复用和传输。
然后,在 CAN 通信管理器中接收 CAN 帧,最后用几行 MATLAB® 代码进行解复用。
Simulink 中的多路复用和传输
实际发动机百分比扭矩、加速踏板位置和车速的记录信号在 MAT 文件中以时间序列形式提供。在 0 到 25 秒的时间内记录数据。
load("Logged_OBD2_Data.mat");
检查记录的信号很有意义;特别是,如下所示,当加速踏板位置变为 0 时,发动机扭矩为负值。这是一种称为发动机制动的常见情况,此时车速确实会相应降低。
figure; yyaxis("left"); plot(Accelerator); yyaxis("right"); plot(Engine_Torque); title("Accelerator and Engine Torque");
figure
plot(Vehicle_Speed);
title("Vehicle Speed");
此数据通过 From Workspace 模块输入到以下 Simulink 模型。
CAN Pack 模块是基于 DBC 文件 CAN_OBD2_Multiplexed.dbc
按如下方式配置的。该文件包含单个多路复用 CAN 帧的定义,具有一个名为 OBD2Mode
的多路复用器。
输入信号馈送到 Multiplexer 模块中,该模块是使用 Stateflow® 图实现的。这是一种特别方便的基于时间的多路复用方法。
此状态机包含三个互斥状态。当 Transmit_Engine_Torque 状态被激活时,系统会传输发动机扭矩信号及其对应的 OBD-II PID,而其他两个信号设置为零。类似的逻辑也适用于其他两个状态,即 Transmit_Accelerator 和 Transmit_Vehicle_Speed。
状态之间的切换遵循基于时间的逻辑:Transmit_Engine_Torque 状态持续两个仿真时间步,Transmit_Accelerator 状态持续 1 个时间步,Transmit_Vehicle_Speed 状态持续 3 个时间步,然后切换回第一个状态。Stateflow 中的 tick
关键字指在每个时间步激活一次图,该激活由 Simulink 求解器触发。
以下参数用于控制 Simulink 模型的仿真。要实现接近挂钟时间执行的效果,可以启用仿真调速。
Ts = 0.1; % [s] StartTime = 0; % [s] StopTime = 25; % [s]
运行仿真后,需要检查多路复用信号以及多路复用器。
多路复用器周期性地在值 98、73 和 13(对应于三个信号的 OBD-II PID)之间切换。
此图传达多路复用有效地引入原始时间序列的下采样的概念,如原始速度信号和多路复用速度信号的比较所示。请注意,尽管信号的值根据 OBD-II PID 有意设置为零,但并未引入新信息:多路复用信号无法“原样”解释,需要在下游使用之前进行解复用。
MATLAB 中的接收和解复用
打开并配置 CAN 通信管理器以在 MathWorks Virtual Channel 1 上接收报文。然后,运行 Simulink 模型以接收报文,并将其导出到 MATLAB 工作区变量。在此示例中,变量称为 canExplorerMsgs
,在 canExplorerMsgs.mat
文件中提供。
为文件 CAN_OBD2_Multiplexed.dbc
创建一个 CAN 数据库对象。使用该数据库对象以及 canMessageTimetable
和 canSignalTimetable
函数对报文进行解码。
load("canExplorerMsgs.mat"); db = canDatabase("CAN_OBD2_Multiplexed.dbc"); msgsTT = canMessageTimetable(canExplorerMsgs, db); sigsTT = canSignalTimetable(msgsTT)
sigsTT=251×4 timetable
Time Vehicle_Speed Accelerator OBD2Mode Engine_Torque
__________ _____________ ___________ ________ _____________
12.557 sec 1 12.157 98 0
12.657 sec 1 12.157 98 0
12.882 sec 0 0 73 -125
12.976 sec 0 0 13 -125
13.07 sec 0 0 13 -125
13.281 sec 0 0 13 -125
13.797 sec 1 12.157 98 0
13.967 sec 1 12.157 98 0
14.057 sec 0 0 73 -125
14.147 sec 0 0 13 -125
14.237 sec 0 0 13 -125
14.327 sec 0 0 13 -125
14.417 sec 2 12.941 98 7
14.507 sec 2 14.51 98 23
14.597 sec 6 39.608 73 23
14.687 sec 0 0 13 -125
⋮
这些函数独立处理每个信号,因此不应用解复用。sigsTT
时间表中的信号需要根据多路复用器的值(即 OBD2Mode 信号)提取。为此,可以应用逻辑索引,如下所示。
Accelerator_Demultiplexed = sigsTT(sigsTT.OBD2Mode == 73, "Accelerator")
Accelerator_Demultiplexed=42×1 timetable
Time Accelerator
__________ ___________
12.882 sec 0
14.057 sec 0
14.597 sec 39.608
15.137 sec 95.294
15.677 sec 83.137
16.217 sec 67.843
16.757 sec 57.647
17.297 sec 58.039
17.837 sec 59.608
18.377 sec 71.373
18.917 sec 86.275
19.457 sec 96.078
20.004 sec 98.824
20.578 sec 98.824
21.158 sec 44.706
21.757 sec 14.902
⋮
Engine_Torque_Demultiplexed = sigsTT(sigsTT.OBD2Mode == 98, "Engine_Torque")
Engine_Torque_Demultiplexed=84×1 timetable
Time Engine_Torque
__________ _____________
12.557 sec 0
12.657 sec 0
13.797 sec 0
13.967 sec 0
14.417 sec 7
14.507 sec 23
14.957 sec 95
15.047 sec 98
15.497 sec 75
15.587 sec 76
16.037 sec 79
16.127 sec 79
16.577 sec 71
16.667 sec 68
17.117 sec 63
17.207 sec 63
⋮
Vehicle_Speed_Demultiplexed = sigsTT(sigsTT.OBD2Mode == 13, "Vehicle_Speed")
Vehicle_Speed_Demultiplexed=125×1 timetable
Time Vehicle_Speed
__________ _____________
12.976 sec 0
13.07 sec 0
13.281 sec 0
14.147 sec 0
14.237 sec 0
14.327 sec 0
14.687 sec 0
14.777 sec 0
14.867 sec 0
15.227 sec 2
15.317 sec 3
15.407 sec 4
15.767 sec 6
15.857 sec 7
15.947 sec 7
16.307 sec 10
⋮
figure; yyaxis("left"); plot(Accelerator_Demultiplexed.Time, Accelerator_Demultiplexed.Accelerator); ylabel("Accelerator Percent Pedal Position (%)") yyaxis("right"); plot(Engine_Torque_Demultiplexed.Time, Engine_Torque_Demultiplexed.Engine_Torque); ylabel("Actual Engine Percent Torque (%)") title("Accelerator and Engine Torque - Demultiplexed");
figure
plot(Vehicle_Speed_Demultiplexed.Time, Vehicle_Speed_Demultiplexed.Vehicle_Speed)
title("Vehicle Speed - Demultiplexed");
请注意,信号实际上经过下采样,并且初始时间不同于仿真的初始时间,这是因为用户在启动 CAN 通信管理器和启动 Simulink 仿真之间引入了延迟。然而,由于仿真调速,大约 25 秒的时间范围与仿真时间范围一致。