解码并将 CAN 数据写入 MDF 文件
此示例说明如何在 MATLAB® 中从 MDF 文件导入 CAN 数据并对其进行解码以供分析,然后将解码后的数据写回到同一个文件中。
此示例中使用的 MDF 文件是使用 Vector 的 CANoe™ 基于 CAN - General System Configuration (CAN) 采样生成的。此示例还使用 Vector 采样配置提供的 CAN 数据库文件 PowerTrain.dbc
。
查看 MDF 文件的详细信息
使用 mdfInfo
函数查看 MDF 文件的元数据。
mdfInfo("Logging_MDF.mf4")
ans = MDFInfo with properties: File Details Name: "Logging_MDF.mf4" Path: "/tmp/Bdoc24a_2511836_3070643/tp8879c7f7/vnt-ex42187575/Logging_MDF.mf4" Author: "" Department: "" Project: "" Subject: "" Comment: "" Version: "4.10" InitialTimestamp: 2020-06-25 20:41:13.133000000 Creator Details ProgramIdentifier: "MDF4Lib" CreatorVendorName: "Vector Informatik GmbH" CreatorToolName: "CANoe" CreatorToolVersion: "13.0.118" CreatorUserName: "michellw" CreatorComment: "Created using MdfLog version 1.5.4.0 and Mdf4Lib version 1.7.0.5 X64 (2019-10-22)" File Contents Attachment: [5x7 table] ChannelGroupCount: 62
标识 CAN 数据帧
根据总线日志记录的 ASAM MDF 相关联标准,为 CAN 总线系统定义的事件类型可以是“CAN_DataFrame”、“CAN_RemoteFrame”、“CAN_ErrorFrame”或“CAN_OverloadFrame”。此示例的重点是提取 CAN 数据帧,因此将使用“CAN_DataFrame”事件类型作为示例来讨论总线日志记录标准。此外,请注意,标准 CAN 数据帧的有效负载最多包含 8 个字节,用于传输信号值。
该标准规定事件结构体的通道名称应以事件类型名称为前缀,例如“CAN_DataFrame”。通常,使用点作为分隔符来指定成员通道,例如“CAN_DataFrame.ID”或“CAN_DataFrame.DataLength”。
使用 mdfChannelInfo
函数查找与“CAN_DataFrame.*”匹配的通道名称。返回包含匹配通道信息的表。
mdfChannelInfo("Logging_MDF.mf4", Channel="CAN_DataFrame.*")
ans=24×13 table
Name GroupNumber GroupNumSamples GroupAcquisitionName GroupComment GroupSourceName GroupSourcePath DisplayName Unit Comment ExtendedNamePrefix SourceName SourcePath
_____________________________ ___________ _______________ ____________________ ____________ _______________ _______________ _______________ ___________ __________________________________________________________ __________________ ___________ __________
"CAN_DataFrame.BitCount" 17 8889 CAN1 <undefined> <undefined> CAN_DataFrame "BitCount" <undefined> Frame length in bits. CAN1 <undefined> CAN1
"CAN_DataFrame.BitCount" 29 7648 CAN2 <undefined> <undefined> CAN_DataFrame "BitCount" <undefined> Frame length in bits. CAN2 <undefined> CAN2
"CAN_DataFrame.BusChannel" 17 8889 CAN1 <undefined> <undefined> CAN_DataFrame "BusChannel" <undefined> Logical bus channel number the frame was sent or received. CAN1 <undefined> CAN1
"CAN_DataFrame.BusChannel" 29 7648 CAN2 <undefined> <undefined> CAN_DataFrame "BusChannel" <undefined> Logical bus channel number the frame was sent or received. CAN2 <undefined> CAN2
"CAN_DataFrame.DLC" 17 8889 CAN1 <undefined> <undefined> CAN_DataFrame "DLC" <undefined> Data length code. CAN1 <undefined> CAN1
"CAN_DataFrame.DLC" 29 7648 CAN2 <undefined> <undefined> CAN_DataFrame "DLC" <undefined> Data length code. CAN2 <undefined> CAN2
"CAN_DataFrame.DataBytes" 17 8889 CAN1 <undefined> <undefined> CAN_DataFrame "DataBytes" <undefined> Payload data bytes containing the signal values. CAN1 <undefined> CAN1
"CAN_DataFrame.DataBytes" 29 7648 CAN2 <undefined> <undefined> CAN_DataFrame "DataBytes" <undefined> Payload data bytes containing the signal values. CAN2 <undefined> CAN2
"CAN_DataFrame.DataLength" 17 8889 CAN1 <undefined> <undefined> CAN_DataFrame "DataLength" <undefined> Length of stored payload in bytes. CAN1 <undefined> CAN1
"CAN_DataFrame.DataLength" 29 7648 CAN2 <undefined> <undefined> CAN_DataFrame "DataLength" <undefined> Length of stored payload in bytes. CAN2 <undefined> CAN2
"CAN_DataFrame.Dir" 17 8889 CAN1 <undefined> <undefined> CAN_DataFrame "Dir" <undefined> Bit signal indicating the direction (Rx, Tx). CAN1 <undefined> CAN1
"CAN_DataFrame.Dir" 29 7648 CAN2 <undefined> <undefined> CAN_DataFrame "Dir" <undefined> Bit signal indicating the direction (Rx, Tx). CAN2 <undefined> CAN2
"CAN_DataFrame.Flags" 17 8889 CAN1 <undefined> <undefined> CAN_DataFrame "Flags" <undefined> Combination of bit flags for the message. CAN1 <undefined> CAN1
"CAN_DataFrame.Flags" 29 7648 CAN2 <undefined> <undefined> CAN_DataFrame "Flags" <undefined> Combination of bit flags for the message. CAN2 <undefined> CAN2
"CAN_DataFrame.FrameDuration" 17 8889 CAN1 <undefined> <undefined> CAN_DataFrame "FrameDuration" ns Duration for transmission of the frame in nanoseconds. CAN1 <undefined> CAN1
"CAN_DataFrame.FrameDuration" 29 7648 CAN2 <undefined> <undefined> CAN_DataFrame "FrameDuration" ns Duration for transmission of the frame in nanoseconds. CAN2 <undefined> CAN2
⋮
感兴趣的动力总成系统数据是从 CAN 2 网络记录的。上面的输出显示来自 CAN 2 网络的数据已存储在 MDF 文件的通道组 29 中。通过指定 GroupNumber
选项,使用 mdfChannelGroupInfo
函数查看有关通道组 29 的详细信息。
mdfChannelGroupInfo("Logging_MDF.mf4", GroupNumber=29)
ans=1×13 table
GroupNumber AcquisitionName Comment NumSamples DataSize Sorted SourceName SourcePath SourceComment SourceType SourceBusType SourceBusChannelNumber SourceSimulated
___________ _______________ ___________ __________ ________ ______ ___________ _____________ _____________ __________ _____________ ______________________ _______________
29 CAN2 <undefined> 7648 206496 true <undefined> CAN_DataFrame <undefined> Bus CAN 2 false
使用 mdfChannelInfo
查看通道组 29 中所有通道的详细信息。
mdfChannelInfo("Logging_MDF.mf4", GroupNumber=29)
ans=13×13 table
Name GroupNumber GroupNumSamples GroupAcquisitionName GroupComment GroupSourceName GroupSourcePath DisplayName Unit Comment ExtendedNamePrefix SourceName SourcePath
_____________________________ ___________ _______________ ____________________ ____________ _______________ _______________ _______________ ___________ __________________________________________________________ __________________ ___________ ___________
"CAN_DataFrame.BitCount" 29 7648 CAN2 <undefined> <undefined> CAN_DataFrame "BitCount" <undefined> Frame length in bits. CAN2 <undefined> CAN2
"CAN_DataFrame.BusChannel" 29 7648 CAN2 <undefined> <undefined> CAN_DataFrame "BusChannel" <undefined> Logical bus channel number the frame was sent or received. CAN2 <undefined> CAN2
"CAN_DataFrame.DLC" 29 7648 CAN2 <undefined> <undefined> CAN_DataFrame "DLC" <undefined> Data length code. CAN2 <undefined> CAN2
"CAN_DataFrame.DataBytes" 29 7648 CAN2 <undefined> <undefined> CAN_DataFrame "DataBytes" <undefined> Payload data bytes containing the signal values. CAN2 <undefined> CAN2
"CAN_DataFrame.DataLength" 29 7648 CAN2 <undefined> <undefined> CAN_DataFrame "DataLength" <undefined> Length of stored payload in bytes. CAN2 <undefined> CAN2
"CAN_DataFrame.Dir" 29 7648 CAN2 <undefined> <undefined> CAN_DataFrame "Dir" <undefined> Bit signal indicating the direction (Rx, Tx). CAN2 <undefined> CAN2
"CAN_DataFrame.Flags" 29 7648 CAN2 <undefined> <undefined> CAN_DataFrame "Flags" <undefined> Combination of bit flags for the message. CAN2 <undefined> CAN2
"CAN_DataFrame.FrameDuration" 29 7648 CAN2 <undefined> <undefined> CAN_DataFrame "FrameDuration" ns Duration for transmission of the frame in nanoseconds. CAN2 <undefined> CAN2
"CAN_DataFrame.ID" 29 7648 CAN2 <undefined> <undefined> CAN_DataFrame "ID" <undefined> ID of the CAN message. CAN2 <undefined> CAN2
"CAN_DataFrame.IDE" 29 7648 CAN2 <undefined> <undefined> CAN_DataFrame "IDE" <undefined> Identifier Extension bit. CAN2 <undefined> CAN2
"CAN_DataFrame.SingleWire" 29 7648 CAN2 <undefined> <undefined> CAN_DataFrame "SingleWire" <undefined> Bit flag indicating a single wire operation. CAN2 <undefined> CAN2
"CAN_DataFrame.WakeUp" 29 7648 CAN2 <undefined> <undefined> CAN_DataFrame "WakeUp" <undefined> Bit flag indicating a wake-up message (high voltage). CAN2 <undefined> CAN2
"t" 29 7648 CAN2 <undefined> <undefined> CAN_DataFrame "" s <undefined> CAN2 <undefined> <undefined>
从 MDF 文件中读取 CAN 数据帧
使用 mdfRead
函数将通道组 29 中的所有数据读入一个时间表中。时间表的结构遵循 ASAM MDF 标准日志记录格式。每行表示来自总线的一个原始 CAN 帧,而每列表示指定通道组中的一个通道。通道,如“CAN_DataFrame.Dir”,是按照总线日志记录标准命名的。
data = mdfRead("Logging_MDF.mf4", GroupNumber=29)
data = 1x1 cell array
{7648x12 timetable}
canData = data{1}
canData=7648×12 timetable
t CAN_DataFrame.BusChannel CAN_DataFrame.Flags CAN_DataFrame.Dir CAN_DataFrame.SingleWire CAN_DataFrame.WakeUp CAN_DataFrame.ID CAN_DataFrame.IDE CAN_DataFrame.FrameDuration CAN_DataFrame.BitCount CAN_DataFrame.DLC CAN_DataFrame.DataLength CAN_DataFrame.DataBytes
__________ ________________________ ___________________ _________________ ________________________ ____________________ ________________ _________________ ___________________________ ______________________ _________________ ________________________ ______________________________
2.2601 sec 2 1 "Tx" 0 0 103 0 128000 67 2 2 {[ 1 0]}
2.2801 sec 2 1 "Tx" 0 0 103 0 128000 67 2 2 {[ 1 0]}
2.3002 sec 2 1 "Tx" 0 0 100 0 232000 119 8 8 {[ 238 2 25 1 0 0 238 2]}
2.3005 sec 2 1 "Tx" 0 0 102 0 240000 123 8 8 {[ 0 128 59 68 0 0 0 0]}
2.3006 sec 2 1 "Tx" 0 0 103 0 128000 67 2 2 {[ 1 0]}
2.3008 sec 2 1 "Tx" 0 0 201 0 196000 101 6 6 {[ 0 0 0 0 172 38]}
2.3009 sec 2 1 "Tx" 0 0 1020 0 110000 58 1 1 {[ 1]}
2.3201 sec 2 1 "Tx" 0 0 103 0 128000 67 2 2 {[ 1 0]}
2.3401 sec 2 1 "Tx" 0 0 103 0 128000 67 2 2 {[ 1 0]}
2.3502 sec 2 1 "Tx" 0 0 100 0 234000 120 8 8 {[ 4 0 25 2 119 1 238 2]}
2.3505 sec 2 1 "Tx" 0 0 102 0 228000 117 8 8 {[53 127 119 64 0 128 187 67]}
2.3507 sec 2 1 "Tx" 0 0 201 0 198000 102 6 6 {[ 0 0 0 0 35 40]}
2.3508 sec 2 1 "Tx" 0 0 1020 0 110000 58 1 1 {[ 1]}
2.3601 sec 2 1 "Tx" 0 0 103 0 128000 67 2 2 {[ 1 0]}
2.3801 sec 2 1 "Tx" 0 0 103 0 128000 67 2 2 {[ 1 0]}
2.4002 sec 2 1 "Tx" 0 0 100 0 234000 120 8 8 {[ 10 0 25 3 119 1 238 2]}
⋮
使用 DBC 文件解码 CAN 报文
使用 canDatabase
函数打开 DBC 文件。
canDB = canDatabase("PowerTrain_MDF.dbc")
canDB = Database with properties: Name: 'PowerTrain_MDF' Path: '/tmp/Bdoc24a_2511836_3070643/tp8879c7f7/vnt-ex42187575/PowerTrain_MDF.dbc' UTF8_File: '/tmp/Bdoc24a_2511836_3070643/tp8879c7f7/vnt-ex42187575/PowerTrain_MDF.dbc' Nodes: {2x1 cell} NodeInfo: [2x1 struct] Messages: {12x1 cell} MessageInfo: [12x1 struct] Attributes: {11x1 cell} AttributeInfo: [11x1 struct] UserData: []
canMessageTimetable
函数使用数据库来解码报文名称和信号。ASAM 标准日志记录格式数据的时间表转换为 Vehicle Network Toolbox™ CAN 报文时间表。
msgTimetable = canMessageTimetable(canData, canDB)
msgTimetable=7648×8 timetable
Time ID Extended Name Data Length Signals Error Remote
__________ ____ ________ __________________ ______________________________ ______ ____________ _____ ______
2.2601 sec 103 false {'Ignition_Info' } {[ 1 0]} 2 {1x1 struct} false false
2.2801 sec 103 false {'Ignition_Info' } {[ 1 0]} 2 {1x1 struct} false false
2.3002 sec 100 false {'EngineData' } {[ 238 2 25 1 0 0 238 2]} 8 {1x1 struct} false false
2.3005 sec 102 false {'EngineDataIEEE'} {[ 0 128 59 68 0 0 0 0]} 8 {1x1 struct} false false
2.3006 sec 103 false {'Ignition_Info' } {[ 1 0]} 2 {1x1 struct} false false
2.3008 sec 201 false {'ABSdata' } {[ 0 0 0 0 172 38]} 6 {1x1 struct} false false
2.3009 sec 1020 false {'GearBoxInfo' } {[ 1]} 1 {1x1 struct} false false
2.3201 sec 103 false {'Ignition_Info' } {[ 1 0]} 2 {1x1 struct} false false
2.3401 sec 103 false {'Ignition_Info' } {[ 1 0]} 2 {1x1 struct} false false
2.3502 sec 100 false {'EngineData' } {[ 4 0 25 2 119 1 238 2]} 8 {1x1 struct} false false
2.3505 sec 102 false {'EngineDataIEEE'} {[53 127 119 64 0 128 187 67]} 8 {1x1 struct} false false
2.3507 sec 201 false {'ABSdata' } {[ 0 0 0 0 35 40]} 6 {1x1 struct} false false
2.3508 sec 1020 false {'GearBoxInfo' } {[ 1]} 1 {1x1 struct} false false
2.3601 sec 103 false {'Ignition_Info' } {[ 1 0]} 2 {1x1 struct} false false
2.3801 sec 103 false {'Ignition_Info' } {[ 1 0]} 2 {1x1 struct} false false
2.4002 sec 100 false {'EngineData' } {[ 10 0 25 3 119 1 238 2]} 8 {1x1 struct} false false
⋮
查看“EngineData”报文中存储的信号。
msgTimetable.Signals{3}
ans = struct with fields:
PetrolLevel: 1
EngPower: 7.5000
EngForce: 0
IdleRunning: 0
EngTemp: 0
EngSpeed: 750
重新打包并可视化感兴趣的信号值
使用 canSignalTimetable
函数将来自总线上每个唯一报文的信号数据重新打包为一个信号时间表。此示例根据 CAN 报文时间表,为三个感兴趣的报文“ABSdata”、“EngineData”和“GearBoxInfo”创建三个单独的信号时间表。
signalTimetable1 = canSignalTimetable(msgTimetable, "ABSdata")
signalTimetable1=1147×4 timetable
Time AccelerationForce Diagnostics GearLock CarSpeed
__________ _________________ ___________ ________ ________
2.3008 sec -100 0 0 0
2.3507 sec 275 0 0 0
2.4008 sec 275 0 0 0
2.4507 sec 275 0 0 0
2.5008 sec 275 0 0 0
2.5507 sec 275 0 0 0
2.6008 sec 275 0 0 0
2.6507 sec 275 0 0 0
2.7008 sec 350 0 0 0
2.7507 sec 425 0 0 0.5
2.8008 sec 425 0 0 0.5
2.8507 sec 500 0 0 0.5
2.9008 sec 575 0 0 0.5
2.9507 sec 575 0 0 0.5
3.0008 sec 650 0 0 0.5
3.0507 sec 725 0 0 0.5
⋮
signalTimetable2 = canSignalTimetable(msgTimetable, "EngineData")
signalTimetable2=1147×6 timetable
Time PetrolLevel EngPower EngForce IdleRunning EngTemp EngSpeed
__________ ___________ ________ ________ ___________ _______ ________
2.3002 sec 1 7.5 0 0 0 750
2.3502 sec 2 7.5 375 0 0 4
2.4002 sec 3 7.5 375 0 0 10
2.4502 sec 4 7.5 375 0 0 17
2.5002 sec 5 7.5 375 0 0 23
2.5502 sec 6 7.5 375 0 0 30
2.6002 sec 7 7.5 375 0 0 36
2.6502 sec 8 7.5 375 0 0 43
2.7002 sec 9 9 450 0 0 50
2.7502 sec 10 10.5 525 0 0 59
2.8002 sec 10 10.5 525 0 0 69
2.8502 sec 11 12 600 0 0 80
2.9002 sec 11 13.5 675 0 0 92
2.9502 sec 12 13.5 675 0 0 106
3.0002 sec 13 15 750 0 0 121
3.0502 sec 13 16.5 825 0 0 136
⋮
signalTimetable3 = canSignalTimetable(msgTimetable, "GearBoxInfo")
signalTimetable3=1147×3 timetable
Time EcoMode ShiftRequest Gear
__________ _______ ____________ ____
2.3009 sec 0 0 1
2.3508 sec 0 0 1
2.4009 sec 0 0 1
2.4508 sec 0 0 1
2.5009 sec 0 0 1
2.5508 sec 0 0 1
2.6009 sec 0 0 1
2.6508 sec 0 0 1
2.7009 sec 0 0 1
2.7508 sec 0 0 1
2.8009 sec 0 0 1
2.8508 sec 0 0 1
2.9009 sec 0 0 1
2.9508 sec 0 0 1
3.0009 sec 0 0 1
3.0508 sec 0 0 1
⋮
为了可视化感兴趣的信号,可以绘制信号时间表中的列随时间变化的图,以便进一步分析。
subplot(3, 1, 1) plot(signalTimetable1.Time, signalTimetable1.CarSpeed, "r") title("{\itCarSpeed} Signal from {\itABSdata} Message", "FontWeight", "bold") xlabel("Timestamp") ylabel("Car Speed") subplot(3, 1, 2) plot(signalTimetable2.Time, signalTimetable2.EngSpeed, "b") title("{\itEngSpeed} Signal from {\itEngineData} Message", "FontWeight", "bold") xlabel("Timestamp") ylabel("Engine Speed") subplot(3, 1, 3) plot(signalTimetable3.Time, signalTimetable3.Gear, "y") title("{\itGear} Signal from {\itGearBoxInfo} Message", "FontWeight", "bold") xlabel("Timestamp") ylabel("Gear")
配置通道组和通道元数据
此示例的最终目标是将三条感兴趣的报文“ABSdata”、“EngineData”和“GearBoxInfo”解码后的信号数据写回到同一个 MDF 文件的三个新通道组中。这样,原始数据和解码后的数据可以存储在一个文件中。
除了每个时间表中的数据之外,元数据也是重要元素,它可以提供关于测量环境的描述性信息。本节说明如何配置数据附带的元数据,这是写入文件之前的可选准备步骤。
使用函数 mdfAddChannelGroupMetadata
将该特定通道组及其通道的默认或推断元数据添加到每个信号时间表中。
signalTimetable1 = mdfAddChannelGroupMetadata(signalTimetable1); signalTimetable2 = mdfAddChannelGroupMetadata(signalTimetable2); signalTimetable3 = mdfAddChannelGroupMetadata(signalTimetable3);
查看每个通道组及其通道的默认元数据。
signalTimetable1.Properties.CustomProperties
ans = CustomProperties with properties: ChannelGroupAcquisitionName: "" ChannelGroupComment: "" ChannelGroupSourceName: "" ChannelGroupSourcePath: "" ChannelGroupSourceComment: "" ChannelGroupSourceType: Unspecified ChannelGroupSourceBusType: Unspecified ChannelGroupSourceBusChannelNumber: 0 ChannelDisplayName: ["" "" "" ""] ChannelComment: ["" "" "" ""] ChannelUnit: ["" "" "" ""] ChannelType: [FixedLength FixedLength FixedLength FixedLength] ChannelDataType: [RealLittleEndian RealLittleEndian RealLittleEndian RealLittleEndian] ChannelNumBits: [64 64 64 64] ChannelComponentType: [None None None None] ChannelCompositionType: [None None None None] ChannelSourceName: ["" "" "" ""] ChannelSourcePath: ["" "" "" ""] ChannelSourceComment: ["" "" "" ""] ChannelSourceType: [Unspecified Unspecified Unspecified Unspecified] ChannelSourceBusType: [Unspecified Unspecified Unspecified Unspecified] ChannelSourceBusChannelNumber: [0 0 0 0] ChannelReadOption: [Missing Missing Missing Missing]
signalTimetable2.Properties.CustomProperties
ans = CustomProperties with properties: ChannelGroupAcquisitionName: "" ChannelGroupComment: "" ChannelGroupSourceName: "" ChannelGroupSourcePath: "" ChannelGroupSourceComment: "" ChannelGroupSourceType: Unspecified ChannelGroupSourceBusType: Unspecified ChannelGroupSourceBusChannelNumber: 0 ChannelDisplayName: ["" "" "" "" "" ""] ChannelComment: ["" "" "" "" "" ""] ChannelUnit: ["" "" "" "" "" ""] ChannelType: [FixedLength FixedLength FixedLength FixedLength FixedLength FixedLength] ChannelDataType: [RealLittleEndian RealLittleEndian RealLittleEndian RealLittleEndian RealLittleEndian RealLittleEndian] ChannelNumBits: [64 64 64 64 64 64] ChannelComponentType: [None None None None None None] ChannelCompositionType: [None None None None None None] ChannelSourceName: ["" "" "" "" "" ""] ChannelSourcePath: ["" "" "" "" "" ""] ChannelSourceComment: ["" "" "" "" "" ""] ChannelSourceType: [Unspecified Unspecified Unspecified Unspecified Unspecified Unspecified] ChannelSourceBusType: [Unspecified Unspecified Unspecified Unspecified Unspecified Unspecified] ChannelSourceBusChannelNumber: [0 0 0 0 0 0] ChannelReadOption: [Missing Missing Missing Missing Missing Missing]
signalTimetable3.Properties.CustomProperties
ans = CustomProperties with properties: ChannelGroupAcquisitionName: "" ChannelGroupComment: "" ChannelGroupSourceName: "" ChannelGroupSourcePath: "" ChannelGroupSourceComment: "" ChannelGroupSourceType: Unspecified ChannelGroupSourceBusType: Unspecified ChannelGroupSourceBusChannelNumber: 0 ChannelDisplayName: ["" "" ""] ChannelComment: ["" "" ""] ChannelUnit: ["" "" ""] ChannelType: [FixedLength FixedLength FixedLength] ChannelDataType: [RealLittleEndian RealLittleEndian RealLittleEndian] ChannelNumBits: [64 64 64] ChannelComponentType: [None None None] ChannelCompositionType: [None None None] ChannelSourceName: ["" "" ""] ChannelSourcePath: ["" "" ""] ChannelSourceComment: ["" "" ""] ChannelSourceType: [Unspecified Unspecified Unspecified] ChannelSourceBusType: [Unspecified Unspecified Unspecified] ChannelSourceBusChannelNumber: [0 0 0] ChannelReadOption: [Missing Missing Missing]
创建一个数组来包含三个报文名称,创建一个元胞数组来包含三个信号时间表。
msgNames = ["ABSdata", "EngineData", "GearBoxInfo"]; TTs = {signalTimetable1, signalTimetable2, signalTimetable3};
为 TTs
中的每个时间表设置属性 ChannelGroupComment
,以指示从其解码信号数据的 CAN 报文的名称。
for ii = 1:numel(TTs) TTs{ii}.Properties.CustomProperties.ChannelGroupComment = sprintf("Signal data from CAN message ""%s"".", msgNames(ii)); end
对于每个 CAN 报文,使用此脚本末尾提供的辅助函数 getSignalUnit
从 canDB
获取每个信号的单位。将每个时间表变量的属性 ChannelUnit
设置为获得的单位。
for ii = 1:numel(msgNames) sigNames = TTs{ii}.Properties.VariableNames; for jj = 1:numel(sigNames) sigUnit = getSignalUnit(canDB, msgNames(ii), sigNames(jj)); TTs{ii}.Properties.CustomProperties.ChannelUnit(jj) = sigUnit; end end
查看每个通道组及其通道的更新后的元数据。请注意属性 ChannelGroupComment
和 ChannelUnit
中更新后的值。
for ii = 1:numel(TTs) TTs{ii}.Properties.CustomProperties end
ans = CustomProperties with properties: ChannelGroupAcquisitionName: "" ChannelGroupComment: "Signal data from CAN message "ABSdata"." ChannelGroupSourceName: "" ChannelGroupSourcePath: "" ChannelGroupSourceComment: "" ChannelGroupSourceType: Unspecified ChannelGroupSourceBusType: Unspecified ChannelGroupSourceBusChannelNumber: 0 ChannelDisplayName: ["" "" "" ""] ChannelComment: ["" "" "" ""] ChannelUnit: ["N" "" "" "mph"] ChannelType: [FixedLength FixedLength FixedLength FixedLength] ChannelDataType: [RealLittleEndian RealLittleEndian RealLittleEndian RealLittleEndian] ChannelNumBits: [64 64 64 64] ChannelComponentType: [None None None None] ChannelCompositionType: [None None None None] ChannelSourceName: ["" "" "" ""] ChannelSourcePath: ["" "" "" ""] ChannelSourceComment: ["" "" "" ""] ChannelSourceType: [Unspecified Unspecified Unspecified Unspecified] ChannelSourceBusType: [Unspecified Unspecified Unspecified Unspecified] ChannelSourceBusChannelNumber: [0 0 0 0] ChannelReadOption: [Missing Missing Missing Missing]
ans = CustomProperties with properties: ChannelGroupAcquisitionName: "" ChannelGroupComment: "Signal data from CAN message "EngineData"." ChannelGroupSourceName: "" ChannelGroupSourcePath: "" ChannelGroupSourceComment: "" ChannelGroupSourceType: Unspecified ChannelGroupSourceBusType: Unspecified ChannelGroupSourceBusChannelNumber: 0 ChannelDisplayName: ["" "" "" "" "" ""] ChannelComment: ["" "" "" "" "" ""] ChannelUnit: ["l" "kW" "N" "" "degC" "rpm"] ChannelType: [FixedLength FixedLength FixedLength FixedLength FixedLength FixedLength] ChannelDataType: [RealLittleEndian RealLittleEndian RealLittleEndian RealLittleEndian RealLittleEndian RealLittleEndian] ChannelNumBits: [64 64 64 64 64 64] ChannelComponentType: [None None None None None None] ChannelCompositionType: [None None None None None None] ChannelSourceName: ["" "" "" "" "" ""] ChannelSourcePath: ["" "" "" "" "" ""] ChannelSourceComment: ["" "" "" "" "" ""] ChannelSourceType: [Unspecified Unspecified Unspecified Unspecified Unspecified Unspecified] ChannelSourceBusType: [Unspecified Unspecified Unspecified Unspecified Unspecified Unspecified] ChannelSourceBusChannelNumber: [0 0 0 0 0 0] ChannelReadOption: [Missing Missing Missing Missing Missing Missing]
ans = CustomProperties with properties: ChannelGroupAcquisitionName: "" ChannelGroupComment: "Signal data from CAN message "GearBoxInfo"." ChannelGroupSourceName: "" ChannelGroupSourcePath: "" ChannelGroupSourceComment: "" ChannelGroupSourceType: Unspecified ChannelGroupSourceBusType: Unspecified ChannelGroupSourceBusChannelNumber: 0 ChannelDisplayName: ["" "" ""] ChannelComment: ["" "" ""] ChannelUnit: ["" "" ""] ChannelType: [FixedLength FixedLength FixedLength] ChannelDataType: [RealLittleEndian RealLittleEndian RealLittleEndian] ChannelNumBits: [64 64 64] ChannelComponentType: [None None None] ChannelCompositionType: [None None None] ChannelSourceName: ["" "" ""] ChannelSourcePath: ["" "" ""] ChannelSourceComment: ["" "" ""] ChannelSourceType: [Unspecified Unspecified Unspecified] ChannelSourceBusType: [Unspecified Unspecified Unspecified] ChannelSourceBusChannelNumber: [0 0 0] ChannelReadOption: [Missing Missing Missing]
使用可自定义的通道组和通道元数据将数据写入 MDF 文件
使用 mdfWrite
函数,将 TTs
中的三个时间表逐个写入 Logging_MDF.mf4
。由于 MDF 文件当前有 62 个通道组,因此 TTs{1}
、TTs{2}
和 TTs{3}
将作为通道组 63、64 和 65 写入文件的末尾。
for ii = 1:numel(TTs) mdfWrite("Logging_MDF.mf4", TTs{ii}) end
将 DBC 文件作为附件添加到 MDF 文件中
为了方便地访问 PowerTrain_MDF.dbc
以便将来执行额外的数据解码,您可以使用 mdfAddAttachment
将 DBC 文件作为嵌入附件添加到 MDF 文件中。
mdfAddAttachment("Logging_MDF.mf4", "PowerTrain_MDF.dbc", Embedded=true)
关闭 DBC 文件
通过从工作区中清除 DBC 文件的变量,关闭对该 DBC 文件的访问。
clear canDB
辅助函数
function sigUnit = getSignalUnit(canDB, msgName, sigName) % Look up the unit of a signal in a message from a CAN database. Return the unit as a string. msgIdx = find(strcmp({canDB.MessageInfo.Name}, msgName)); sigIdx = find(strcmp({canDB.MessageInfo(msgIdx).SignalInfo.Name}, sigName)); sigUnit = string(canDB.MessageInfo(msgIdx).SignalInfo(sigIdx).Units); end