从 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")

读取 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"])