主要内容

从 BLF 文件中解码 CAN 数据

此示例说明如何在 MATLAB® 中从 BLF 文件中导入和解码 CAN 数据进行分析。此示例中使用的 BLF 文件是使用“CAN - General System Configuration (CAN)”示例在 Vector CANoe™ 中生成的。此示例还使用 Vector 示例配置提供的 CAN 数据库文件 PowerTrain_BLF.dbc

打开 DBC 文件

使用 canDatabase 函数打开描述源 CAN 网络的数据库文件。

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

             Name: 'PowerTrain_BLF'
             Path: '/tmp/Bdoc26a_3233028_2210314/tp94d33388/vnt-ex06202590/PowerTrain_BLF.dbc'
        UTF8_File: '/tmp/Bdoc26a_3233028_2210314/tp94d33388/vnt-ex06202590/PowerTrain_BLF.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: []

调查 BLF 文件

检索和查看有关 BLF 文件的信息。函数 blfinfo 解析有关 Vector 二进制记录格式 BLF 文件的格式和内容的一般信息,并将信息以结构体形式返回。

binf = blfinfo("Logging_BLF.blf")
binf = struct with fields:
                  Name: "Logging_BLF.blf"
                  Path: "/tmp/Bdoc26a_3233028_2210314/tp94d33388/vnt-ex06202590/Logging_BLF.blf"
           Application: "CANoe"
    ApplicationVersion: "11.0.55"
               Objects: 43344
             StartTime: 01-Jul-2020 14:47:34.427
               EndTime: 01-Jul-2020 14:48:33.487
           ChannelList: [2×3 table]

binf.ChannelList
ans=2×3 table
    ChannelID    Protocol    Objects
    _________    ________    _______

        1         "CAN"       8801  
        2         "CAN"       7575  

从 BLF 文件中读取数据

从动力总成系统总线记录感兴趣的数据,并存储在 BLF 文件的通道 2 中。使用 blfread 函数读取 CAN 数据。您还可以向函数调用提供 DBC 文件,该函数调用将启用报文名称查找和信号值解码。

blfData = blfread("Logging_BLF.blf", 2, "Database", canDB)
blfData=7575×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”报文的信号。

blfData.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(blfData, "ABSdata")
signalTimetable1=1136×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(blfData, "EngineData")
signalTimetable2=1136×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(blfData, "GearBoxInfo")
signalTimetable3=1136×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 {\itEngData} 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")

Figure contains 3 axes objects. Axes object 1 with title CarSpeed Signal from ABSdata Message, xlabel Timestamp, ylabel Car Speed contains an object of type line. Axes object 2 with title EngSpeed Signal from EngData Message, xlabel Timestamp, ylabel Engine Speed contains an object of type line. Axes object 3 with title Gear Signal from GearBoxInfo Message, xlabel Timestamp, ylabel Gear contains an object of type line.

读取 BLF 文件的一部分

到目前为止,您已从 BLF 文件导入并可视化整个 CAN 数据集,这会提供所记录车辆数据的全面概况。然而,在许多实际场景中,您可能希望将分析重点放在特定的时间窗或感兴趣的事件上,例如信号值的突然变化或试驾期间检测到的异常。

例如,在上面的信号图中,您可以观察到车速在 20 到 30 秒之间的快速变化。要更详细地研究此期间的 CAN 流和信号行为,您可以直接从 BLF 文件中仅提取数据的相关部分。使用具有 "TimeRange" 名称-值对组的 blfread 函数提取在此时间范围内发生的来自通道 2 的所有报文。

blfDataChannel2 = blfread("Logging_BLF.blf", 2, TimeRange = seconds([20, 30]))
blfDataChannel2=1333×8 timetable
       Time        ID     Extended       Name                    Data                 Length      Signals       Error    Remote
    __________    ____    ________    __________    ______________________________    ______    ____________    _____    ______

    20 sec         100     false      {0×0 char}    {[   29 14 42 45 97 5 226 29]}      8       {0×0 struct}    false    false 
    20 sec         102     false      {0×0 char}    {[ 187 207 97 69 0 32 172 68]}      8       {0×0 struct}    false    false 
    20.001 sec     103     false      {0×0 char}    {[                       1 0]}      2       {0×0 struct}    false    false 
    20.001 sec     201     false      {0×0 char}    {[           77 0 0 0 153 42]}      6       {0×0 struct}    false    false 
    20.001 sec    1020     false      {0×0 char}    {[                         4]}      1       {0×0 struct}    false    false 
    20.02 sec      103     false      {0×0 char}    {[                       1 0]}      2       {0×0 struct}    false    false 
    20.04 sec      103     false      {0×0 char}    {[                       1 0]}      2       {0×0 struct}    false    false 
    20.05 sec      100     false      {0×0 char}    {[  38 14 42 45 124 5 120 30]}      8       {0×0 struct}    false    false 
    20.05 sec      102     false      {0×0 char}    {[  41 88 98 69 0 128 175 68]}      8       {0×0 struct}    false    false 
    20.051 sec     201     false      {0×0 char}    {[           77 0 0 0 178 42]}      6       {0×0 struct}    false    false 
    20.051 sec    1020     false      {0×0 char}    {[                         4]}      1       {0×0 struct}    false    false 
    20.06 sec      103     false      {0×0 char}    {[                       1 0]}      2       {0×0 struct}    false    false 
    20.08 sec      103     false      {0×0 char}    {[                       1 0]}      2       {0×0 struct}    false    false 
    20.1 sec       100     false      {0×0 char}    {[  46 14 42 45 124 5 120 30]}      8       {0×0 struct}    false    false 
    20.1 sec       102     false      {0×0 char}    {[147 227 98 69 0 128 175 68]}      8       {0×0 struct}    false    false 
    20.101 sec     103     false      {0×0 char}    {[                       1 0]}      2       {0×0 struct}    false    false 
      ⋮

同样,您可能需要从另一个通道提取特定数量的报文。例如,要读取来自通道 1 的前 50 条报文,请使用 "IndexRange" 名称-值对组。

blfDataChannel1 = blfread("Logging_BLF.blf", 1, IndexRange = [1 50])
blfDataChannel1=50×8 timetable
       Time       ID     Extended       Name                Data              Length      Signals       Error    Remote
    __________    ___    ________    __________    _______________________    ______    ____________    _____    ______

    2.2002 sec    272     false      {0×0 char}    {[              6 0 0]}      3       {0×0 struct}    false    false 
    2.2202 sec    416     false      {0×0 char}    {[           0 0 0 32]}      4       {0×0 struct}    false    false 
    2.2203 sec    496     false      {0×0 char}    {[                  0]}      1       {0×0 struct}    false    false 
    2.2204 sec    497     false      {0×0 char}    {[                  0]}      1       {0×0 struct}    false    false 
    2.2402 sec    416     false      {0×0 char}    {[           0 0 0 32]}      4       {0×0 struct}    false    false 
    2.2501 sec    496     false      {0×0 char}    {[                  0]}      1       {0×0 struct}    false    false 
    2.2502 sec    497     false      {0×0 char}    {[                  0]}      1       {0×0 struct}    false    false 
    2.2602 sec    416     false      {0×0 char}    {[           0 0 0 32]}      4       {0×0 struct}    false    false 
    2.2802 sec    416     false      {0×0 char}    {[           0 0 0 32]}      4       {0×0 struct}    false    false 
    2.2803 sec    496     false      {0×0 char}    {[                  0]}      1       {0×0 struct}    false    false 
    2.2804 sec    497     false      {0×0 char}    {[                  0]}      1       {0×0 struct}    false    false 
    2.3002 sec    272     false      {0×0 char}    {[            135 0 0]}      3       {0×0 struct}    false    false 
    2.3003 sec    416     false      {0×0 char}    {[           0 0 0 32]}      4       {0×0 struct}    false    false 
    2.3006 sec    273     false      {0×0 char}    {[0 0 0 238 2 1 120 0]}      8       {0×0 struct}    false    false 
    2.3101 sec    496     false      {0×0 char}    {[                  0]}      1       {0×0 struct}    false    false 
    2.3102 sec    497     false      {0×0 char}    {[                  0]}      1       {0×0 struct}    false    false 
      ⋮

将数据写入 BLF 文件

从两个通道提取相关数据部分后,您可以将它们保存到新 BLF 文件供以后分析或共享。需要注意的是,blfwrite 函数无法覆盖现有 BLF 文件。如果指定的输出文件已存在,blfwrite 将返回错误。为避免这种情况,您应首先检查文件是否存在,并在写入新数据之前根据需要将其删除。

outputFile = "SubsetLoggingBLF.blf";
if isfile(outputFile)
    delete(outputFile);
end

一旦确保输出文件不存在,您就可以将提取的 CAN 数据部分写入 BLF 文件。blfwrite 函数要求每个通道的数据以元胞数组形式提供。您还需要指定通道编号及其对应的类型。在本例中,两个通道的类型都是 "CAN"。

blfwrite(outputFile, {blfDataChannel1, blfDataChannel2}, [1 2], ["CAN", "CAN"])