首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

Matlab编程技巧:通过正则表达式解析DBC文件

  • 23-09-22 00:45
  • 2356
  • 9250
blog.csdn.net

本文通过Matlab函数regexp的正则表达式功能,解析DBC文件中的报文帧信息。DBC文件中的信号等其他信息都可以通过类似的方式解析出来。

文章目录

  • 1 DBC文件
  • 2 正则表达式函数
  • 3 实例:解析报文帧信息
  • 4 Matlab脚本
  • 5 总结
  • 附 完整代码

1 DBC文件

DBC数据库文件是用来描述CAN网络节点间数据通讯的一种文件,做汽车CAN网络通信的话肯定是绕不开DBC文件的。

关于DBC文件格式的内容可以参考另一位博主的文章关于DBC文件的格式解析(DBC文件系列其二),本文后面也会引用到其中的一些知识内容。

DBC文件的格式有很强的规律性,所以可以很轻松地通过正则表达式函数regexp解析出其中地信息。实际上,Matlab提供了封装好的函数canDatabase(),可以更加快速准确地解析DBC中的帧和信号。本文没有使用封装的函数,是希望以DBC为例,训练正则表达式的应用技巧,以便在遇到其他需求没有现成的函数时,自己也能造出轮子。

2 正则表达式函数

在Matlab中,正则表达式函数是regexp。关于正则表达式的语法不用死记硬背,用到的时候去查Matlab帮助文档就行。

3 实例:解析报文帧信息

首先,自己新建一个DBC文件,一般是通过CANdb++这类DBC工具。不过这里为了方便就不去手动建立了,直接把如下内容拷贝进文本文件,并命名为DBC_Demo.dbc。

BS_:
BU_: AVNT ACU HUD
BO_996 HUD_1_B: 8 HUD
 SG_ HUD_OffSt : 0|1@0- (1,0) [-1|0] "" ACU,AVNT
 SG_ HUD_HeightLv : 7|7@0+ (1,0) [0|127] "lv" ACU,AVNT
 SG_ HUD_BrightnessLv : 15|4@0+ (1,0) [0|15] "lv" ACU,AVNT
CM_ BO_ 996 "The message of control hud status";
CM_ SG_ 996 HUD_BrightnessLv "Control hud brighness level";
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

其中,BO_开头的那一行就是报文帧,其格式定义如下:
在这里插入图片描述

4 Matlab脚本

1)首先要将DBC文件的文本内容导入到Matlab中。在Matlab命令行输入

DBCText = fileread('DBC_Demo.dbc')
  • 1

就会将DBC文件内容作为字符串返回到DBCText变量中。
在这里插入图片描述
2)用正则表达式提取出报文帧那一行,也就是BO_开头的那一行。这里开始就要研究BO_这一行的模式了。

  1. BO关键字,在正则表达式模式中直接用BO_完全匹配即可;
  2. 报文ID,是若干个数字可以用d+表示1个或以上的阿拉伯数字;
  3. 报文名称,一般是由字母、数字和下划线组成的字符串,所以可以用w+表示;
  4. 报文数据域字节数,无符号整数,直接用d+表示;
  5. 网络节点:一般是由字母、数字和下划线组成的字符串,所以可以用w+表示;

所以报文帧这一行的模式可以写为:

>> pattern = 'BO_s*d+s+w+:s+d+s+w+';
  • 1

中间的s+或者s*代表空格符。

然后就可以通过regexp解析出BO这一行了。注意加上’match’这个参数以返回字符串。

>> BO_Cell = regexp(DBCText,pattern,'match')
  • 1

这里要注意,返回的的是一个字符串组成的元胞数组。由于demo中只有一个报文帧的定义,所以元胞数组中只有一个字符串。
在这里插入图片描述
3)解析元胞数组中的每一个报文帧行,提取出信息,这里只以一个报文帧为例。首先解析出报文ID,只要把之前的pattern改一下就行。

pattern_MessageId = '(?<=BO_s*)d+(?=s+w+:s+d+s+w+)';
  • 1

在这里插入图片描述
这里用了正则表达式的上下文匹配,语法是*(?=test)和(?<=test)*,其中test是上下文内容。这样就能根据上下文匹配出报文帧了。

再比如说报文名称也用上下文匹配:

>> MessageName_Cell = regexp(BO_Cell{1},'(?<=BO_s*d+s+)w+(?=:s+d+s+w+)','match')

MessageName_Cell =

  1×1 cell 数组

    {'HUD_1_B'}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

5 总结

用正则表达式解析DBC文件比较容易,只是需要一点耐心慢慢地调。除了报文帧,其他信号、波特率、节点等信息都能通过类似的方式解析。这样的技术也可以迁移到其他文件,只要我们了解了该文件的书写规则就行。

>>返回个人博客总目录

附 完整代码

测试用的DBC文件如下:

BS_:
BU_: AVNT ACU HUD
BO_996 HUD_1_B: 8 HUD
 SG_ HUD_OffSt : 0|1@0- (1,0) [-1|0] "" ACU,AVNT
 SG_ HUD_HeightLv : 7|7@0+ (1,0) [0|127] "lv" ACU,AVNT
 SG_ HUD_BrightnessLv : 15|4@0+ (1,0) [0|15] "lv" ACU,AVNT
CM_ BO_ 996 "The message of control hud status";
CM_ SG_ 996 HUD_BrightnessLv "Control hud brighness level";
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

博主自己写的脚本,可能会有考虑不周的地方,不一定适用于任何DBC文件。但是思路和方法是这样的,可以在遇到问题时尝试修改脚本,不断迭代。脚本内容如下:

function Message_Struct = ImportDBC()
%% 导入DBC文本
DBCText = fileread('DBC_Demo.dbc');

%% 解析BO_和SG_
pattern = 'BO_s*d+s+w+:s+d+s+w+s*
(s*SG_.*?
)*';
BO_Cell = regexp(DBCText,pattern,'match');

for i = 1:length(BO_Cell)
    BO_Str = BO_Cell{i};
    Message_Struct = Parse_Message(BO_Str);
    SG_Cell = regexp(BO_Str,'SG.*?
','match');
    Signal_Cell = {};
    for j = 1:length(SG_Cell)
        SG_Str = SG_Cell{j};
        Signal_Struct = Parse_Signal(SG_Str);
        Signal_Cell{end+1} = Signal_Struct;
    end
    Message_Struct = setfield(Message_Struct,'Signal',Signal_Cell);
end
end

%解析信号属性
function Signal_Struct = Parse_Signal(SG_Str)
%pattern:SG_s*w+s*:s*d+|d+@(0|1)s*(+|-)s*(-*d+,-*d+)s*[-*d+|-*d+]s*"w*"s*(w|,)+rn
%SignalName
Temp = regexp(SG_Str,'(?<=SG_s*)w+(?=s*:s*d+|d+@(0|1)s*(+|-)s*(-*d+,-*d+)s*[-*d+|-*d+]s*"w*"s*(w|,)+
)','match');
SignalName = Temp{1};
%StartBit
Temp = regexp(SG_Str,'(?<=SG_s*w+s*:s*)d+(?=|d+@(0|1)s*(+|-)s*(-*d+,-*d+)s*[-*d+|-*d+]s*"w*"s*(w|,)+
)','match');
StartBit = Temp{1};
%SignalSize
Temp = regexp(SG_Str,'(?<=SG_s*w+s*:s*d+|)d+(?=@(0|1)s*(+|-)s*(-*d+,-*d+)s*[-*d+|-*d+]s*"w*"s*(w|,)+
)','match');
SignalSize = Temp{1};
%ByteOrder
Temp = regexp(SG_Str,'(?<=SG_s*w+s*:s*d+|d+@)(0|1)(?=s*(+|-)s*(-*d+,-*d+)s*[-*d+|-*d+]s*"w*"s*(w|,)+
)','match');
if(strcmp(Temp{1},'0'))
    ByteOrder = 'Motorola';
else
    ByteOrder = 'Intel';
end
%ValueType
Temp = regexp(SG_Str,'(?<=SG_s*w+s*:s*d+|d+@(0|1)s*)(+|-)(?=s*(-*d+,-*d+)s*[-*d+|-*d+]s*"w*"s*(w|,)+
)','match');
if(strcmp(Temp{1},'+'))
    ValueType = 'Unsigned';
else
    ValueType = 'Signed';
end
%Factor
Temp = regexp(SG_Str,'(?<=SG_s*w+s*:s*d+|d+@(0|1)s*(+|-)s*()-*d+(?=,-*d+)s*[-*d+|-*d+]s*"w*"s*(w|,)+
)','match');
Factor = Temp{1};
%Offset
Temp = regexp(SG_Str,'(?<=SG_s*w+s*:s*d+|d+@(0|1)s*(+|-)s*(-*d+,)-*d+(?=)s*[-*d+|-*d+]s*"w*"s*(w|,)+
)','match');
Offset = Temp{1};
%Min
Temp = regexp(SG_Str,'(?<=SG_s*w+s*:s*d+|d+@(0|1)s*(+|-)s*(-*d+,-*d+)s*[)-*d+(?=|-*d+]s*"w*"s*(w|,)+
)','match');
Min = Temp{1};
%Max
Temp = regexp(SG_Str,'(?<=SG_s*w+s*:s*d+|d+@(0|1)s*(+|-)s*(-*d+,-*d+)s*[-*d+|)-*d+(?=]s*"w*"s*(w|,)+
)','match');
Max = Temp{1};
%Unit
Temp = regexp(SG_Str,'(?<=SG_s*w+s*:s*d+|d+@(0|1)s*(+|-)s*(-*d+,-*d+)s*[-*d+|-*d+]s*)"w*"(?=s*(w|,)+
)','match');
Unit = Temp{1};
%Receiver
Temp = regexp(SG_Str,'(?<=SG_s*w+s*:s*d+|d+@(0|1)s*(+|-)s*(-*d+,-*d+)s*[-*d+|-*d+]s*"w*"s*)(w|,)+(?=
)','match');
Receiver = Temp{1};
%Signal_Struct
Signal_Struct = struct('SignalName',SignalName,'StartBit',StartBit,'SignalSize',SignalSize,'ByteOrder',ByteOrder,'ValueType',ValueType,...
    'Factor',Factor,'Offset',Offset,'Min',Min,'Max',Max,'Unit',Unit,'Receiver',Receiver);
end

% 解析报文属性
function Message_Struct = Parse_Message(BO_Str)
%pattern:'BO_s*d+s+w+:s+d+s+w+'
%MessageId
Temp = regexp(BO_Str,'(?<=BO_s*)d+(?=s+w+:s+d+s+w+)','match');
MessageId = Temp{1};
%MessageName
Temp = regexp(BO_Str,'(?<=BO_s*d+s+)w+(?=:s+d+s+w+)','match');
MessageName = Temp{1};
%MessageSize
Temp = regexp(BO_Str,'(?<=BO_s*d+s+w+:s+)d+(?=s+w+)','match');
MessageSize = Temp{1};
%Transmitter
Temp = regexp(BO_Str,'(?<=BO_s*d+s+w+:s+d+s+)w+','match');
Transmitter = Temp{1};
%Message_Struct
Message_Struct = struct('MessageId',MessageId,'MessageName',MessageName,'MessageSize',MessageSize,'Transmitter',Transmitter,'Signal','');
end
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
注:本文转载自blog.csdn.net的chhttty的文章"https://blog.csdn.net/u013288925/article/details/107280302"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2492) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

101
推荐
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2024 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top