Contenuto principale

Decode CAN Data from BLF Files

This example shows you how to import and decode CAN data from BLF files in MATLAB® for analysis. The BLF file used in this example was generated from Vector CANoe™ using the "CAN - General System Configuration (CAN)" sample. This example also uses the CAN database file, PowerTrain_BLF.dbc, provided with the Vector sample configuration.

Open the DBC File

Open the database file describing the source CAN network using the canDatabase function.

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

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

Investigate the BLF File

Retrieve and view information about the BLF file. The blfinfo function parses general information about the format and contents of the Vector Binary Logging Format BLF file and returns the information as a structure.

binf = blfinfo("Logging_BLF.blf")
binf = struct with fields:
                  Name: "Logging_BLF.blf"
                  Path: "/tmp/Bdoc26a_3146167_4178462/tp338fd2cf/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  

Read Data from BLF File

The data of interest was logged from the powertrain bus which is stored in channel 2 of the BLF file. Read the CAN data using the blfread function. You can also provide the DBC file to the function call which will enable message name lookup and signal value decoding.

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 
      ⋮

View signals from an "EngineData" message.

blfData.Signals{3}
ans = struct with fields:
    PetrolLevel: 1
       EngPower: 7.5000
       EngForce: 0
    IdleRunning: 0
        EngTemp: 0
       EngSpeed: 750

Repackage and Visualize Signal Values of Interest

Use the canSignalTimetable function to repackage signal data from each unique message on the bus into a signal timetable. This example creates three individual signal timetables for the three messages of interest, "ABSdata", "EngineData" and "GearBoxInfo", from the CAN message timetable.

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  
      ⋮

To visualize the signals of interest, columns from the signal timetables can be plotted over time for further analysis.

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.

Read Subset of BLF File

So far, you have imported and visualized the entire CAN dataset from the BLF file, which provides a comprehensive overview of the logged vehicle data. However, in many real-world scenarios, you may want to focus your analysis on a specific time window or event of interest, such as a sudden change in a signal value or an anomaly detected during a test drive.

For example, in the signal plots above, you can observe a rapid change in vehicle speed between 20 and 30 seconds. To investigate the CAN traffic and signal behavior in greater detail during this period, you can extract only the relevant portion of the data directly from the BLF file. Use the blfread function with the "TimeRange" name-value pair to extract all messages from channel 2 that occurred within this timeframe.

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 
      ⋮

Similarly, you might need to extract a specific number of messages from another channel. For example, to read the first 50 messages from channel 1, use the "IndexRange" name-value pair.

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 
      ⋮

Write Data to BLF File

After extracting the relevant data subsets from both channels, you can save them to a new BLF file for later analysis or sharing. It is important to note that the blfwrite function cannot overwrite an existing BLF file. If the specified output file already exists, blfwrite returns an error. To avoid this, you should first check if the file exists and delete it if necessary before writing the new data.

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

Once you have ensured that the output file does not exist, you can write your extracted CAN data subsets to the BLF file. The blfwrite function requires the data for each channel to be provided in a cell array. You also need to specify the channel numbers and their corresponding types. In this case, both channels are of the "CAN" type.

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