This example shows you how to import and decode CAN data from MDF-files in MATLAB for analysis. The MDF-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.dbc, provided with the Vector sample configuration.
Open access to the MDF-file using the mdf function.
m = mdf("Logging_MDF.mf4")m =
MDF with properties:
File Details
Name: 'Logging_MDF.mf4'
Path: '/tmp/Bdoc21a_2203895_17225/tp0e4392da/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: [1x1 struct]
File Contents
Attachment: [5x1 struct]
ChannelNames: {62x1 cell}
ChannelGroup: [1x62 struct]
Options
Conversion: Numeric
According to the ASAM MDF associated standard for bus logging, the event types defined for a CAN bus system can be "CAN_DataFrame", "CAN_RemoteFrame", "CAN_ErrorFrame" or "CAN_OverloadFrame". This example focuses on extracting the CAN data frames, so the bus logging standard will be discussed using "CAN_DataFrame" event type as example. Additionally, note that a standard CAN data frame has up to 8 bytes for its payload and is used to transfer signal values.
The standard specifies that the channel names of the event structure should be prefixed by the event type name, for instance, "CAN_DataFrame". Typically a dot is used as separator character to specify the member channels, for instance, "CAN_DataFrame.ID" or "CAN_DataFrame.DataLength".
Use the channelList function to filter on channel names exactly matching "CAN_DataFrame". A table with information on matched channels is returned.
channelList(m, "CAN_DataFrame", "ExactMatch", true)
ans=2×9 table
ChannelName ChannelGroupNumber ChannelGroupNumSamples ChannelGroupAcquisitionName ChannelGroupComment ChannelDisplayName ChannelUnit ChannelComment ChannelDescription
_______________ __________________ ______________________ ___________________________ ___________________ __________________ ___________ ______________ __________________
"CAN_DataFrame" 17 8889 CAN1 <undefined> "" <undefined> bus event data "bus event data"
"CAN_DataFrame" 29 7648 CAN2 <undefined> "" <undefined> bus event data "bus event data"
The powetrain data of interest was logged from the CAN 2 network. The channelList output above shows that the data from CAN 2 network has been stored in channel group 29 of the MDF-file. View the channel group details using the ChannelGroup property.
m.ChannelGroup(29)
ans = struct with fields:
AcquisitionName: 'CAN2'
Comment: ''
NumSamples: 7648
DataSize: 206496
Sorted: 1
Channel: [14x1 struct]
Within a channel group, details about each channel are stored. View details about channel 2 within channel group 29.
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
Read all data from all channels in channel group 29 into a timetable using the read function. The timetable is structured to follow the ASAM MDF standard logging format. Every row represents one raw CAN frame from the bus, while each column represents a channel within the specified channel group. The channels, such as "CAN_DataFrame.Dir", are named to follow the bus logging standard. However, because timetable column names must be valid MATLAB variable names, they may not be identical to the channel names. Most unsupported characters are converted to underscores. Since "." is not supported in a MATLAB variable name, "CAN_DataFrame.Dir" is altered to "CAN_DataFrame_Dir" in the table.
canData = read(m, 29, m.ChannelNames{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
⋮
Open the database file using the canDatabase function.
canDB = canDatabase("PowerTrain_MDF.dbc")canDB =
Database with properties:
Name: 'PowerTrain_MDF'
Path: '/tmp/Bdoc21a_2203895_17225/tp0e4392da/vnt-ex42187575/PowerTrain_MDF.dbc'
Nodes: {2x1 cell}
NodeInfo: [2x1 struct]
Messages: {12x1 cell}
MessageInfo: [12x1 struct]
Attributes: {11x1 cell}
AttributeInfo: [11x1 struct]
UserData: []
The canMessageTimetable function uses the database to decode the message names and signals. The timetable of ASAM standard logging format data is converted into a Vehicle Network Toolbox™ CAN message timetable.
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
⋮
View the signals stored in the "EngineData" message.
msgTimetable.Signals{3}ans = struct with fields:
PetrolLevel: 1
EngPower: 7.5000
EngForce: 0
IdleRunning: 0
EngTemp: 0
EngSpeed: 750
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(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
⋮
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 {\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')

Close access to the MDF-file and the DBC-file by clearing their variables from the workspace.
clear m clear canDB