Main Content

本页翻译不是最新的。点击此处可查看最新英文版本。

解码 MDF 文件中的 CAN 数据并将结果写入 MDF 文件

此示例说明如何在 MATLAB® 中从 MDF 文件导入 CAN 数据并对其进行解码以供分析,然后将解码后的数据写回到同一个文件中。此示例中使用的 MDF 文件是使用 Vector 的 CANoe™ 基于“CAN - General System Configuration (CAN)”样本生成的。此示例还使用 Vector 示例配置提供的 CAN 数据库文件 PowerTrain.dbc

打开 MDF 文件

使用 mdf 函数来开启对 MDF 文件的访问。

m = mdf("Logging_MDF.mf4")
m = 
  MDF with properties:

   File Details
                 Name: 'Logging_MDF.mf4'
                 Path: 'C:\Users\michellw\OneDrive - MathWorks\Documents\MATLAB\ExampleManager\michellw.MDFDecodeCAN\vnt-ex42187575\Logging_MDF.mf4'
               Author: ''
           Department: ''
              Project: ''
              Subject: ''
              Comment: ''
              Version: '4.10'
             DataSize: 1542223
     InitialTimestamp: 2020-06-25 20:41:13.133000000

   Creator Details
    ProgramIdentifier: 'MDF4Lib'
              Creator: [1×1 struct]

   File Contents
           Attachment: [5×1 struct]
         ChannelNames: {62×1 cell}
         ChannelGroup: [1×62 struct]

   Options
           Conversion: Numeric

标识 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”。

使用 channelList 函数筛选与“CAN_DataFrame”精确匹配的通道名称。返回包含匹配通道信息的表。

channelList(m, "CAN_DataFrame", "ExactMatch", true)
ans=2×18 table
      ChannelName      ChannelGroupNumber    ChannelGroupNumSamples    ChannelGroupAcquisitionName    ChannelGroupComment    ChannelGroupSourceInfo    ChannelDisplayName    ChannelUnit    ChannelComment    ChannelDescription    ChannelExtendedNamePrefix    ChannelType    ChannelDataType    ChannelNumBits    ChannelComponentType    ChannelCompositionType    ChannelConversionType    ChannelSourceInfo
    _______________    __________________    ______________________    ___________________________    ___________________    ______________________    __________________    ___________    ______________    __________________    _________________________    ___________    _______________    ______________    ____________________    ______________________    _____________________    _________________

    "CAN_DataFrame"            17                     8889                        CAN1                    <undefined>              1×1 struct                  ""            <undefined>    bus event data     "bus event data"               CAN1               FixedLength       ByteArray            152                  None                  Structure                   None                1×1 struct    
    "CAN_DataFrame"            29                     7648                        CAN2                    <undefined>              1×1 struct                  ""            <undefined>    bus event data     "bus event data"               CAN2               FixedLength       ByteArray            152                  None                  Structure                   None                1×1 struct    

感兴趣的动力总成系统数据是从 CAN 2 网络记录的。上面的 channelList 输出显示来自 CAN 2 网络的数据已存储在 MDF 文件的通道组 29 中。使用 ChannelGroup 属性查看通道组详细信息。

m.ChannelGroup(29)
ans = struct with fields:
    AcquisitionName: 'CAN2'
            Comment: ''
         NumSamples: 7648
           DataSize: 206496
             Sorted: 1
         SourceInfo: [1×1 struct]
            Channel: [14×1 struct]

通道组内存储了每个通道的详细信息。查看通道组 29 中通道 2 的详细信息。

m.ChannelGroup(29).Channel(2)
ans = struct with fields:
                  Name: 'CAN_DataFrame.Flags'
           DisplayName: 'Flags'
    ExtendedNamePrefix: 'CAN2'
           Description: 'Combination of bit flags for the message.'
               Comment: 'Combination of bit flags for the message.'
                  Unit: ''
                  Type: FixedLength
              DataType: IntegerUnsignedLittleEndian
               NumBits: 8
         ComponentType: StructureMember
       CompositionType: None
        ConversionType: None
            SourceInfo: [1×1 struct]

从 MDF 文件中读取 CAN 数据帧

使用 read 函数将通道组 29 中的所有数据读入一个时间表中。时间表的结构遵循 ASAM MDF 标准日志记录格式。每行表示来自总线的一个原始 CAN 帧,而每列表示指定通道组中的一个通道。通道,如“CAN_DataFrame.Dir”,是按照总线日志记录标准命名的。但是,由于时间表列名称必须为有效的 MATLAB 变量名称,因此它们可能与通道名称不同。大多数不支持的字符会转换为下划线。由于 MATLAB 变量名称中不支持“.”,“CAN_DataFrame.Dir”在表中改为“CAN_DataFrame_Dir”。

canData = read(m, 29)
canData=7648×14 timetable
       Time       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                               CAN_DataFrame                              t   
    __________    ________________________    ___________________    _________________    ________________________    ____________________    ________________    _________________    ___________________________    ______________________    _________________    ________________________    ______________________________    ____________________________________________________________    ______

    2.2601 sec               2                         1                     1                       0                         0                     103                  0                      128000                         67                      2                       2                {[                       1 0]}    {[              1 2 103 0 0 0 1 0 0 0 8 0 0 0 0 244 1 0 67]}    2.2601
    2.2801 sec               2                         1                     1                       0                         0                     103                  0                      128000                         67                      2                       2                {[                       1 0]}    {[              1 2 103 0 0 0 1 0 0 0 6 0 0 0 0 244 1 0 67]}    2.2801
    2.3002 sec               2                         1                     1                       0                         0                     100                  0                      232000                        119                      8                       8                {[      238 2 25 1 0 0 238 2]}    {[       1 8 100 0 0 0 238 2 25 1 0 0 238 2 64 138 3 0 119]}    2.3002
    2.3005 sec               2                         1                     1                       0                         0                     102                  0                      240000                        123                      8                       8                {[       0 128 59 68 0 0 0 0]}    {[       1 8 102 0 0 0 0 128 59 68 0 0 0 0 128 169 3 0 123]}    2.3005
    2.3006 sec               2                         1                     1                       0                         0                     103                  0                      128000                         67                      2                       2                {[                       1 0]}    {[              1 2 103 0 0 0 1 0 0 0 6 0 0 0 0 244 1 0 67]}    2.3006
    2.3008 sec               2                         1                     1                       0                         0                     201                  0                      196000                        101                      6                       6                {[            0 0 0 0 172 38]}    {[        1 6 201 0 0 0 0 0 0 0 172 38 0 0 160 253 2 0 101]}    2.3008
    2.3009 sec               2                         1                     1                       0                         0                    1020                  0                      110000                         58                      1                       1                {[                         1]}    {[            1 1 252 3 0 0 1 0 0 0 8 0 0 0 176 173 1 0 58]}    2.3009
    2.3201 sec               2                         1                     1                       0                         0                     103                  0                      128000                         67                      2                       2                {[                       1 0]}    {[              1 2 103 0 0 0 1 0 0 0 6 0 0 0 0 244 1 0 67]}    2.3201
    2.3401 sec               2                         1                     1                       0                         0                     103                  0                      128000                         67                      2                       2                {[                       1 0]}    {[              1 2 103 0 0 0 1 0 0 0 6 0 0 0 0 244 1 0 67]}    2.3401
    2.3502 sec               2                         1                     1                       0                         0                     100                  0                      234000                        120                      8                       8                {[      4 0 25 2 119 1 238 2]}    {[       1 8 100 0 0 0 4 0 25 2 119 1 238 2 16 146 3 0 120]}    2.3502
    2.3505 sec               2                         1                     1                       0                         0                     102                  0                      228000                        117                      8                       8                {[53 127 119 64 0 128 187 67]}    {[1 8 102 0 0 0 53 127 119 64 0 128 187 67 160 122 3 0 117]}    2.3505
    2.3507 sec               2                         1                     1                       0                         0                     201                  0                      198000                        102                      6                       6                {[             0 0 0 0 35 40]}    {[           1 6 201 0 0 0 0 0 0 0 35 40 0 0 112 5 3 0 102]}    2.3507
    2.3508 sec               2                         1                     1                       0                         0                    1020                  0                      110000                         58                      1                       1                {[                         1]}    {[            1 1 252 3 0 0 1 0 0 0 9 0 0 0 176 173 1 0 58]}    2.3508
    2.3601 sec               2                         1                     1                       0                         0                     103                  0                      128000                         67                      2                       2                {[                       1 0]}    {[              1 2 103 0 0 0 1 0 0 0 9 0 0 0 0 244 1 0 67]}    2.3601
    2.3801 sec               2                         1                     1                       0                         0                     103                  0                      128000                         67                      2                       2                {[                       1 0]}    {[              1 2 103 0 0 0 1 0 0 0 6 0 0 0 0 244 1 0 67]}    2.3801
    2.4002 sec               2                         1                     1                       0                         0                     100                  0                      234000                        120                      8                       8                {[     10 0 25 3 119 1 238 2]}    {[      1 8 100 0 0 0 10 0 25 3 119 1 238 2 16 146 3 0 120]}    2.4002
      ⋮

使用 DBC 文件解码 CAN 报文

使用 canDatabase 函数打开数据库文件。

canDB = canDatabase("PowerTrain_MDF.dbc")
canDB = 
  Database with properties:

             Name: 'PowerTrain_MDF'
             Path: 'C:\Users\michellw\OneDrive - MathWorks\Documents\MATLAB\ExampleManager\michellw.MDFDecodeCAN\vnt-ex42187575\PowerTrain_MDF.dbc'
        UTF8_File: 'C:\Users\michellw\OneDrive - MathWorks\Documents\MATLAB\ExampleManager\michellw.MDFDecodeCAN\vnt-ex42187575\PowerTrain_MDF.dbc'
            Nodes: {2×1 cell}
         NodeInfo: [2×1 struct]
         Messages: {12×1 cell}
      MessageInfo: [12×1 struct]
       Attributes: {11×1 cell}
    AttributeInfo: [11×1 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       {1×1 struct}    false    false 
    2.2801 sec     103     false      {'Ignition_Info' }    {[                       1 0]}      2       {1×1 struct}    false    false 
    2.3002 sec     100     false      {'EngineData'    }    {[      238 2 25 1 0 0 238 2]}      8       {1×1 struct}    false    false 
    2.3005 sec     102     false      {'EngineDataIEEE'}    {[       0 128 59 68 0 0 0 0]}      8       {1×1 struct}    false    false 
    2.3006 sec     103     false      {'Ignition_Info' }    {[                       1 0]}      2       {1×1 struct}    false    false 
    2.3008 sec     201     false      {'ABSdata'       }    {[            0 0 0 0 172 38]}      6       {1×1 struct}    false    false 
    2.3009 sec    1020     false      {'GearBoxInfo'   }    {[                         1]}      1       {1×1 struct}    false    false 
    2.3201 sec     103     false      {'Ignition_Info' }    {[                       1 0]}      2       {1×1 struct}    false    false 
    2.3401 sec     103     false      {'Ignition_Info' }    {[                       1 0]}      2       {1×1 struct}    false    false 
    2.3502 sec     100     false      {'EngineData'    }    {[      4 0 25 2 119 1 238 2]}      8       {1×1 struct}    false    false 
    2.3505 sec     102     false      {'EngineDataIEEE'}    {[53 127 119 64 0 128 187 67]}      8       {1×1 struct}    false    false 
    2.3507 sec     201     false      {'ABSdata'       }    {[             0 0 0 0 35 40]}      6       {1×1 struct}    false    false 
    2.3508 sec    1020     false      {'GearBoxInfo'   }    {[                         1]}      1       {1×1 struct}    false    false 
    2.3601 sec     103     false      {'Ignition_Info' }    {[                       1 0]}      2       {1×1 struct}    false    false 
    2.3801 sec     103     false      {'Ignition_Info' }    {[                       1 0]}      2       {1×1 struct}    false    false 
    2.4002 sec     100     false      {'EngineData'    }    {[     10 0 25 3 119 1 238 2]}      8       {1×1 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: ""
         ChannelGroupSourceInfo: [1×1 struct]
             ChannelDisplayName: [""    ""    ""    ""]
      ChannelExtendedNamePrefix: [""    ""    ""    ""]
             ChannelDescription: [""    ""    ""    ""]
                 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]
              ChannelSourceInfo: [1×4 struct]

signalTimetable2.Properties.CustomProperties
ans = 
CustomProperties with properties:

    ChannelGroupAcquisitionName: ""
            ChannelGroupComment: ""
         ChannelGroupSourceInfo: [1×1 struct]
             ChannelDisplayName: [""    ""    ""    ""    ""    ""]
      ChannelExtendedNamePrefix: [""    ""    ""    ""    ""    ""]
             ChannelDescription: [""    ""    ""    ""    ""    ""]
                 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]
              ChannelSourceInfo: [1×6 struct]

signalTimetable3.Properties.CustomProperties
ans = 
CustomProperties with properties:

    ChannelGroupAcquisitionName: ""
            ChannelGroupComment: ""
         ChannelGroupSourceInfo: [1×1 struct]
             ChannelDisplayName: [""    ""    ""]
      ChannelExtendedNamePrefix: [""    ""    ""]
             ChannelDescription: [""    ""    ""]
                 ChannelComment: [""    ""    ""]
                    ChannelUnit: [""    ""    ""]
                    ChannelType: [FixedLength    FixedLength    FixedLength]
                ChannelDataType: [RealLittleEndian    RealLittleEndian    RealLittleEndian]
                 ChannelNumBits: [64 64 64]
           ChannelComponentType: [None    None    None]
         ChannelCompositionType: [None    None    None]
              ChannelSourceInfo: [1×3 struct]

创建一个数组来包含三个报文名称,创建一个元胞数组来包含三个信号时间表。

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 报文,使用此脚本末尾提供的辅助函数 getSignalUnitcanDB 获取每个信号的单位。将每个时间表变量的属性 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

查看每个通道组及其通道的更新后的元数据。请注意属性 ChannelGroupCommentChannelUnit 中更新后的值。

for ii = 1:numel(TTs)
    TTs{ii}.Properties.CustomProperties
end
ans = 
CustomProperties with properties:

    ChannelGroupAcquisitionName: ""
            ChannelGroupComment: "Signal data from CAN message "ABSdata"."
         ChannelGroupSourceInfo: [1×1 struct]
             ChannelDisplayName: [""    ""    ""    ""]
      ChannelExtendedNamePrefix: [""    ""    ""    ""]
             ChannelDescription: [""    ""    ""    ""]
                 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]
              ChannelSourceInfo: [1×4 struct]

ans = 
CustomProperties with properties:

    ChannelGroupAcquisitionName: ""
            ChannelGroupComment: "Signal data from CAN message "EngineData"."
         ChannelGroupSourceInfo: [1×1 struct]
             ChannelDisplayName: [""    ""    ""    ""    ""    ""]
      ChannelExtendedNamePrefix: [""    ""    ""    ""    ""    ""]
             ChannelDescription: [""    ""    ""    ""    ""    ""]
                 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]
              ChannelSourceInfo: [1×6 struct]

ans = 
CustomProperties with properties:

    ChannelGroupAcquisitionName: ""
            ChannelGroupComment: "Signal data from CAN message "GearBoxInfo"."
         ChannelGroupSourceInfo: [1×1 struct]
             ChannelDisplayName: [""    ""    ""]
      ChannelExtendedNamePrefix: [""    ""    ""]
             ChannelDescription: [""    ""    ""]
                 ChannelComment: [""    ""    ""]
                    ChannelUnit: [""    ""    ""]
                    ChannelType: [FixedLength    FixedLength    FixedLength]
                ChannelDataType: [RealLittleEndian    RealLittleEndian    RealLittleEndian]
                 ChannelNumBits: [64 64 64]
           ChannelComponentType: [None    None    None]
         ChannelCompositionType: [None    None    None]
              ChannelSourceInfo: [1×3 struct]

使用自定义设置通道组和通道元数据将数据写入 MDF 文件

由于 Logging_MDF.mf4 在 MATLAB 中仍处于打开状态,因此需要先关闭该文件。从工作区中清除 MDF 对象 m

clear m

使用 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