Decode J1939 Data from MDF Files
This example shows you how to import and decode J1939 data from MDF files in MATLAB® for analysis. The MDF file used in this example was generated from Vector CANoe using the "System Configuration (J1939)" sample. This example also uses the CAN database file, Powertrain_J1939_MDF.dbc
, provided with the Vector sample configuration.
View Details of the MDF File
View metadata of an MDF file using the mdfInfo
function.
mdfInfo("LoggingMDF_J1939.mf4")
ans = MDFInfo with properties: File Details Name: "LoggingMDF_J1939.mf4" Path: "/tmp/Bdoc24b_2679053_3932096/tp5211b350/vnt-ex76385747/LoggingMDF_J1939.mf4" Author: "" Department: "" Project: "" Subject: "" Comment: "" Version: "4.10" InitialTimestamp: 2021-04-21 14:05:13.232000000 Creator Details ProgramIdentifier: "MDF4Lib" CreatorVendorName: "Vector Informatik GmbH" CreatorToolName: "CANoe" CreatorToolVersion: "12.0.167" CreatorUserName: "sdange" CreatorComment: "Created using MdfLog version 1.5.1.0 and Mdf4Lib version 1.6.1.0 X64 (2018-03-13)" File Contents Attachment: [5x7 table] ChannelGroupCount: 43 Event: [0x8 eventtable]
Identify J1939 CAN Data Frames
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". J1939 is a protocol built on top of the CAN protocol. A J1939 parameter group (PG) is a set of parameters belonging to the same topic and sharing the same transmission rate. For example, the Electronic Engine Controller 1 (EEC1) PG contains engine speed, engine torque demand percent, actual engine torque percent, etc. Each parameter group is addressed via a unique number called the parameter group number (PGN). J1939 PGs are transmitted as CAN frames, and the MDF file reflects that a J1939 PG is logged as a "CAN_DataFrame".
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 a separator character to specify the member channels, for instance, "CAN_DataFrame.ID" or "CAN_DataFrame.DataLength".
Use the mdfChannelInfo
function to locate channel names matching "CAN_DataFrame.*". A table with information on matched channels is returned.
mdfChannelInfo("LoggingMDF_J1939.mf4", Channel="CAN_DataFrame.*")
ans=24×13 table
Name GroupNumber GroupNumSamples GroupAcquisitionName GroupComment GroupSourceName GroupSourcePath DisplayName Unit Comment ExtendedNamePrefix SourceName SourcePath
_____________________________ ___________ _______________ ____________________ ____________ _______________ _______________ _______________ ___________ __________________________________________________________ __________________ ___________ __________
"CAN_DataFrame.BitCount" 13 26054 CAN2 <undefined> <undefined> CAN_DataFrame "BitCount" <undefined> Frame length in bits. CAN2 <undefined> CAN2
"CAN_DataFrame.BitCount" 14 92720 CAN1 <undefined> <undefined> CAN_DataFrame "BitCount" <undefined> Frame length in bits. CAN1 <undefined> CAN1
"CAN_DataFrame.BusChannel" 13 26054 CAN2 <undefined> <undefined> CAN_DataFrame "BusChannel" <undefined> Logical bus channel number the frame was sent or received. CAN2 <undefined> CAN2
"CAN_DataFrame.BusChannel" 14 92720 CAN1 <undefined> <undefined> CAN_DataFrame "BusChannel" <undefined> Logical bus channel number the frame was sent or received. CAN1 <undefined> CAN1
"CAN_DataFrame.DLC" 13 26054 CAN2 <undefined> <undefined> CAN_DataFrame "DLC" <undefined> Data length code. CAN2 <undefined> CAN2
"CAN_DataFrame.DLC" 14 92720 CAN1 <undefined> <undefined> CAN_DataFrame "DLC" <undefined> Data length code. CAN1 <undefined> CAN1
"CAN_DataFrame.DataBytes" 13 26054 CAN2 <undefined> <undefined> CAN_DataFrame "DataBytes" <undefined> Payload data bytes containing the signal values. CAN2 <undefined> CAN2
"CAN_DataFrame.DataBytes" 14 92720 CAN1 <undefined> <undefined> CAN_DataFrame "DataBytes" <undefined> Payload data bytes containing the signal values. CAN1 <undefined> CAN1
"CAN_DataFrame.DataLength" 13 26054 CAN2 <undefined> <undefined> CAN_DataFrame "DataLength" <undefined> Length of stored payload in bytes. CAN2 <undefined> CAN2
"CAN_DataFrame.DataLength" 14 92720 CAN1 <undefined> <undefined> CAN_DataFrame "DataLength" <undefined> Length of stored payload in bytes. CAN1 <undefined> CAN1
"CAN_DataFrame.Dir" 13 26054 CAN2 <undefined> <undefined> CAN_DataFrame "Dir" <undefined> Bit signal indicating the direction (Rx, Tx). CAN2 <undefined> CAN2
"CAN_DataFrame.Dir" 14 92720 CAN1 <undefined> <undefined> CAN_DataFrame "Dir" <undefined> Bit signal indicating the direction (Rx, Tx). CAN1 <undefined> CAN1
"CAN_DataFrame.Flags" 13 26054 CAN2 <undefined> <undefined> CAN_DataFrame "Flags" <undefined> Combination of bit flags for the message. CAN2 <undefined> CAN2
"CAN_DataFrame.Flags" 14 92720 CAN1 <undefined> <undefined> CAN_DataFrame "Flags" <undefined> Combination of bit flags for the message. CAN1 <undefined> CAN1
"CAN_DataFrame.FrameDuration" 13 26054 CAN2 <undefined> <undefined> CAN_DataFrame "FrameDuration" ns Duration for transmission of the frame in nanoseconds. CAN2 <undefined> CAN2
"CAN_DataFrame.FrameDuration" 14 92720 CAN1 <undefined> <undefined> CAN_DataFrame "FrameDuration" ns Duration for transmission of the frame in nanoseconds. CAN1 <undefined> CAN1
⋮
The J1939 powertrain data of interest was logged from the CAN 2 network. The output above shows that the data from CAN 2 network has been stored in channel group 13 of the MDF file. View details about channel group 13 using the mdfChannelGroupInfo
function by specifying the GroupNumber
option.
mdfChannelGroupInfo("LoggingMDF_J1939.mf4", GroupNumber=13)
ans=1×13 table
GroupNumber AcquisitionName Comment NumSamples DataSize Sorted SourceName SourcePath SourceComment SourceType SourceBusType SourceBusChannelNumber SourceSimulated
___________ _______________ ___________ __________ ________ ______ ___________ _____________ _____________ __________ _____________ ______________________ _______________
13 CAN2 <undefined> 26054 703458 true <undefined> CAN_DataFrame <undefined> Bus CAN 2 false
View details about all the channels within channel group 13 using mdfChannelInfo
.
mdfChannelInfo("LoggingMDF_J1939.mf4", GroupNumber=13)
ans=13×13 table
Name GroupNumber GroupNumSamples GroupAcquisitionName GroupComment GroupSourceName GroupSourcePath DisplayName Unit Comment ExtendedNamePrefix SourceName SourcePath
_____________________________ ___________ _______________ ____________________ ____________ _______________ _______________ _______________ ___________ __________________________________________________________ __________________ ___________ ___________
"CAN_DataFrame.BitCount" 13 26054 CAN2 <undefined> <undefined> CAN_DataFrame "BitCount" <undefined> Frame length in bits. CAN2 <undefined> CAN2
"CAN_DataFrame.BusChannel" 13 26054 CAN2 <undefined> <undefined> CAN_DataFrame "BusChannel" <undefined> Logical bus channel number the frame was sent or received. CAN2 <undefined> CAN2
"CAN_DataFrame.DLC" 13 26054 CAN2 <undefined> <undefined> CAN_DataFrame "DLC" <undefined> Data length code. CAN2 <undefined> CAN2
"CAN_DataFrame.DataBytes" 13 26054 CAN2 <undefined> <undefined> CAN_DataFrame "DataBytes" <undefined> Payload data bytes containing the signal values. CAN2 <undefined> CAN2
"CAN_DataFrame.DataLength" 13 26054 CAN2 <undefined> <undefined> CAN_DataFrame "DataLength" <undefined> Length of stored payload in bytes. CAN2 <undefined> CAN2
"CAN_DataFrame.Dir" 13 26054 CAN2 <undefined> <undefined> CAN_DataFrame "Dir" <undefined> Bit signal indicating the direction (Rx, Tx). CAN2 <undefined> CAN2
"CAN_DataFrame.Flags" 13 26054 CAN2 <undefined> <undefined> CAN_DataFrame "Flags" <undefined> Combination of bit flags for the message. CAN2 <undefined> CAN2
"CAN_DataFrame.FrameDuration" 13 26054 CAN2 <undefined> <undefined> CAN_DataFrame "FrameDuration" ns Duration for transmission of the frame in nanoseconds. CAN2 <undefined> CAN2
"CAN_DataFrame.ID" 13 26054 CAN2 <undefined> <undefined> CAN_DataFrame "ID" <undefined> ID of the CAN message. CAN2 <undefined> CAN2
"CAN_DataFrame.IDE" 13 26054 CAN2 <undefined> <undefined> CAN_DataFrame "IDE" <undefined> Identifier Extension bit. CAN2 <undefined> CAN2
"CAN_DataFrame.SingleWire" 13 26054 CAN2 <undefined> <undefined> CAN_DataFrame "SingleWire" <undefined> Bit flag indicating a single wire operation. CAN2 <undefined> CAN2
"CAN_DataFrame.WakeUp" 13 26054 CAN2 <undefined> <undefined> CAN_DataFrame "WakeUp" <undefined> Bit flag indicating a wake-up message (high voltage). CAN2 <undefined> CAN2
"t" 13 26054 CAN2 <undefined> <undefined> CAN_DataFrame "" s <undefined> CAN2 <undefined> <undefined>
Read J1939 CAN Data Frames from the MDF File
Read all data in channel group 13 into a timetable using the mdfRead
function. The timetable is structured to follow the ASAM MDF standard logging format. Each 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.
data = mdfRead("LoggingMDF_J1939.mf4", GroupNumber=13)
data = 1x1 cell array
{26054x12 timetable}
canData = data{1}
canData=26054×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
____________ ________________________ ___________________ _________________ ________________________ ____________________ ________________ _________________ ___________________________ ______________________ _________________ ________________________ ___________________________________
0.000568 sec 2 1 "Tx" 0 0 2565799910 1 0 0 8 8 {[ 105 52 169 232 0 131 0 16]}
0.27057 sec 2 1 "Tx" 0 0 2565866726 1 0 0 8 8 {[ 255 255 255 208 7 255 255 255]}
0.29057 sec 2 1 "Tx" 0 0 2565866726 1 0 0 8 8 {[ 255 255 255 208 7 255 255 255]}
0.30058 sec 2 1 "Tx" 0 0 2565866470 1 0 0 8 8 {[ 255 0 255 255 255 255 255 255]}
0.30116 sec 2 1 "Tx" 0 0 2566810854 1 0 0 8 8 {[255 255 255 255 255 255 255 255]}
0.31057 sec 2 1 "Tx" 0 0 2565866726 1 0 0 8 8 {[ 255 255 255 208 7 255 255 255]}
0.33057 sec 2 1 "Tx" 0 0 2565866726 1 0 0 8 8 {[ 255 255 255 208 7 255 255 255]}
0.35058 sec 2 1 "Tx" 0 0 2565866470 1 0 0 8 8 {[ 255 0 255 255 255 255 255 255]}
0.35115 sec 2 1 "Tx" 0 0 2565866726 1 0 0 8 8 {[ 255 255 255 208 7 255 255 255]}
0.35173 sec 2 1 "Tx" 0 0 2566810854 1 0 0 8 8 {[255 255 255 255 255 255 255 255]}
0.3523 sec 2 1 "Tx" 0 0 2566844902 1 0 0 8 8 {[ 255 0 0 12 255 255 224 255]}
0.37057 sec 2 1 "Tx" 0 0 2565866726 1 0 0 8 8 {[ 255 255 255 208 7 255 255 255]}
0.39057 sec 2 1 "Tx" 0 0 2565866726 1 0 0 8 8 {[ 255 255 255 208 7 255 255 255]}
0.40058 sec 2 1 "Tx" 0 0 2565866470 1 0 0 8 8 {[ 255 0 255 255 255 255 255 255]}
0.40116 sec 2 1 "Tx" 0 0 2566810854 1 0 0 8 8 {[255 255 255 255 255 255 255 255]}
0.41057 sec 2 1 "Tx" 0 0 2565866726 1 0 0 8 8 {[ 255 255 255 208 7 255 255 255]}
⋮
Decode J1939 Parameter Groups Using the DBC File
Open the DBC file using the canDatabase
function.
canDB = canDatabase("Powertrain_J1939_MDF.dbc")
canDB = Database with properties: Name: 'Powertrain_J1939_MDF' Path: '/tmp/Bdoc24b_2679053_3932096/tp5211b350/vnt-ex76385747/Powertrain_J1939_MDF.dbc' UTF8_File: '/tmp/Bdoc24b_2679053_3932096/tp25605c35_9c60_48da_96b4_c868222c2171' Nodes: {12x1 cell} NodeInfo: [12x1 struct] Messages: {93x1 cell} MessageInfo: [93x1 struct] Attributes: {3x1 cell} AttributeInfo: [3x1 struct] UserData: []
The j1939ParameterGroupTimetable
function uses the database to decode the raw CAN Data into PGs, PGNs and signals. The timetable of ASAM standard logging format data is converted into a Vehicle Network Toolbox™ J1939 parameter group timetable.
j1939PGTimetable = j1939ParameterGroupTimetable(canData, canDB)
j1939PGTimetable=26054×8 timetable
Time Name PGN Priority PDUFormatType SourceAddress DestinationAddress Data Signals
____________ ________ _____ ________ _____________________ _____________ __________________ ___________________________________ ____________
0.000568 sec ACL 60928 6 Peer-to-Peer (Type 1) 230 255 {[ 105 52 169 232 0 131 0 16]} {1x1 struct}
0.27057 sec EEC1_EMS 61444 6 Broadcast (Type 2) 230 255 {[ 255 255 255 208 7 255 255 255]} {1x1 struct}
0.29057 sec EEC1_EMS 61444 6 Broadcast (Type 2) 230 255 {[ 255 255 255 208 7 255 255 255]} {1x1 struct}
0.30058 sec EEC2_EMS 61443 6 Broadcast (Type 2) 230 255 {[ 255 0 255 255 255 255 255 255]} {1x1 struct}
0.30116 sec TCO1_TCO 65132 6 Broadcast (Type 2) 230 255 {[255 255 255 255 255 255 255 255]} {1x1 struct}
0.31057 sec EEC1_EMS 61444 6 Broadcast (Type 2) 230 255 {[ 255 255 255 208 7 255 255 255]} {1x1 struct}
0.33057 sec EEC1_EMS 61444 6 Broadcast (Type 2) 230 255 {[ 255 255 255 208 7 255 255 255]} {1x1 struct}
0.35058 sec EEC2_EMS 61443 6 Broadcast (Type 2) 230 255 {[ 255 0 255 255 255 255 255 255]} {1x1 struct}
0.35115 sec EEC1_EMS 61444 6 Broadcast (Type 2) 230 255 {[ 255 255 255 208 7 255 255 255]} {1x1 struct}
0.35173 sec TCO1_TCO 65132 6 Broadcast (Type 2) 230 255 {[255 255 255 255 255 255 255 255]} {1x1 struct}
0.3523 sec CCVS_EMS 65265 6 Broadcast (Type 2) 230 255 {[ 255 0 0 12 255 255 224 255]} {1x1 struct}
0.37057 sec EEC1_EMS 61444 6 Broadcast (Type 2) 230 255 {[ 255 255 255 208 7 255 255 255]} {1x1 struct}
0.39057 sec EEC1_EMS 61444 6 Broadcast (Type 2) 230 255 {[ 255 255 255 208 7 255 255 255]} {1x1 struct}
0.40058 sec EEC2_EMS 61443 6 Broadcast (Type 2) 230 255 {[ 255 0 255 255 255 255 255 255]} {1x1 struct}
0.40116 sec TCO1_TCO 65132 6 Broadcast (Type 2) 230 255 {[255 255 255 255 255 255 255 255]} {1x1 struct}
0.41057 sec EEC1_EMS 61444 6 Broadcast (Type 2) 230 255 {[ 255 255 255 208 7 255 255 255]} {1x1 struct}
⋮
View the signal data stored in the third PG of the timetable, which is one instance of the "EEC1_EMS" PG.
signalData = j1939PGTimetable.Signals{3}
signalData = struct with fields:
EngDemandPercentTorque: 130
EngStarterMode: 15
SrcAddrssOfCtrllngDvcForEngCtrl: 255
EngSpeed: 250
ActualEngPercentTorque: 130
DriversDemandEngPercentTorque: 130
EngTorqueMode: 15
Repackage and Visualize Signal Values of Interest
Use the j1939SignalTimetable
function to repackage signal data from each unique PGN on the bus into a signal timetable. This example creates two individual signal timetables for the two PGs of interest, "EEC1_EMS" and "TCO1_TCO", from the J1939 PG timetable.
signalTimetable1 = j1939SignalTimetable(j1939PGTimetable, "ParameterGroups", "EEC1_EMS")
signalTimetable1=12043×7 timetable
Time EngDemandPercentTorque EngStarterMode SrcAddrssOfCtrllngDvcForEngCtrl EngSpeed ActualEngPercentTorque DriversDemandEngPercentTorque EngTorqueMode
___________ ______________________ ______________ _______________________________ ________ ______________________ _____________________________ _____________
0.27057 sec 130 15 255 250 130 130 15
0.29057 sec 130 15 255 250 130 130 15
0.31057 sec 130 15 255 250 130 130 15
0.33057 sec 130 15 255 250 130 130 15
0.35115 sec 130 15 255 250 130 130 15
0.37057 sec 130 15 255 250 130 130 15
0.39057 sec 130 15 255 250 130 130 15
0.41057 sec 130 15 255 250 130 130 15
0.43057 sec 130 15 255 250 130 130 15
0.45115 sec 130 15 255 250 130 130 15
0.47057 sec 130 15 255 250 130 130 15
0.49057 sec 130 15 255 250 130 130 15
0.51057 sec 130 15 255 250 130 130 15
0.53057 sec 130 15 255 250 130 130 15
0.55115 sec 130 15 255 250 130 130 15
0.57057 sec 130 15 255 250 130 130 15
⋮
signalTimetable2 = j1939SignalTimetable(j1939PGTimetable, "ParameterGroups", "TCO1_TCO")
signalTimetable2=4817×14 timetable
Time TachographVehicleSpeed TachographOutputShaftSpeed DirectionIndicator TachographPerformance HandlingInformation SystemEvent DriverCardDriver2 Driver2TimeRelatedStates Overspeed DriverCardDriver1 Driver1TimeRelatedStates DriveRecognize Driver2WorkingState Driver1WorkingState
___________ ______________________ __________________________ __________________ _____________________ ___________________ ___________ _________________ ________________________ _________ _________________ ________________________ ______________ ___________________ ___________________
0.30116 sec 256 8191.9 3 3 3 3 3 15 3 3 15 3 7 7
0.35173 sec 256 8191.9 3 3 3 3 3 15 3 3 15 3 7 7
0.40116 sec 256 8191.9 3 3 3 3 3 15 3 3 15 3 7 7
0.45173 sec 256 8191.9 3 3 3 3 3 15 3 3 15 3 7 7
0.50116 sec 256 8191.9 3 3 3 3 3 15 3 3 15 3 7 7
0.55173 sec 256 8191.9 3 3 3 3 3 15 3 3 15 3 7 7
0.60116 sec 256 8191.9 3 3 3 3 3 15 3 3 15 3 7 7
0.65173 sec 256 8191.9 3 3 3 3 3 15 3 3 15 3 7 7
0.70116 sec 256 8191.9 3 3 3 3 3 15 3 3 15 3 7 7
0.75173 sec 256 8191.9 3 3 3 3 3 15 3 3 15 3 7 7
0.80116 sec 256 8191.9 3 3 3 3 3 15 3 3 15 3 7 7
0.85173 sec 256 8191.9 3 3 3 3 3 15 3 3 15 3 7 7
0.90116 sec 256 8191.9 3 3 3 3 3 15 3 3 15 3 7 7
0.95173 sec 256 8191.9 3 3 3 3 3 15 3 3 15 3 7 7
1.0012 sec 256 8191.9 3 3 3 3 3 15 3 3 15 3 7 7
1.0517 sec 256 8191.9 3 3 3 3 3 15 3 3 15 3 7 7
⋮
You can alternatively choose to convert the whole J1939 PG timetable into a struct containing multiple J1939 signal timetables for each individual PG, and index into it to get data for a particular PG.
signalTimetables = j1939SignalTimetable(j1939PGTimetable)
signalTimetables = struct with fields:
ACL: [1x14 timetable]
CCVS_EMS: [2408x19 timetable]
DD: [240x5 timetable]
EEC1_EMS: [12043x7 timetable]
EEC2_EMS: [4817x10 timetable]
ET1_EMS: [240x6 timetable]
HOURS_EMS: [240x2 timetable]
LFC_EMS: [480x2 timetable]
SERV: [240x6 timetable]
TCO1_TCO: [4817x14 timetable]
VDHR_EMS: [240x2 timetable]
VI_EMS: [24x1 timetable]
VW_SSC: [240x4 timetable]
signalTimetables.EEC1_EMS
ans=12043×7 timetable
Time EngDemandPercentTorque EngStarterMode SrcAddrssOfCtrllngDvcForEngCtrl EngSpeed ActualEngPercentTorque DriversDemandEngPercentTorque EngTorqueMode
___________ ______________________ ______________ _______________________________ ________ ______________________ _____________________________ _____________
0.27057 sec 130 15 255 250 130 130 15
0.29057 sec 130 15 255 250 130 130 15
0.31057 sec 130 15 255 250 130 130 15
0.33057 sec 130 15 255 250 130 130 15
0.35115 sec 130 15 255 250 130 130 15
0.37057 sec 130 15 255 250 130 130 15
0.39057 sec 130 15 255 250 130 130 15
0.41057 sec 130 15 255 250 130 130 15
0.43057 sec 130 15 255 250 130 130 15
0.45115 sec 130 15 255 250 130 130 15
0.47057 sec 130 15 255 250 130 130 15
0.49057 sec 130 15 255 250 130 130 15
0.51057 sec 130 15 255 250 130 130 15
0.53057 sec 130 15 255 250 130 130 15
0.55115 sec 130 15 255 250 130 130 15
0.57057 sec 130 15 255 250 130 130 15
⋮
To visualize a signal of interest, variables from the signal timetables can be plotted over time for further analysis. For this example, look at the "EngineSpeed" signal from the "EEC1_EMS" PG.
plot(signalTimetable1.Time, signalTimetable1.EngSpeed, "r") title("{\itEngineSpeed} signal from {\itEEC1\_EMS} PG", "FontWeight", "bold") xlabel("Timestamp") ylabel("Engine Speed")
Close DBC File
Close access to the DBC files by clearing its variable from the workspace.
clear canDB