总线42讲,LabVIEW+python在报文离线解析中的应用,光芒照进来

文摘   2024-09-11 12:34   上海  
愿所有在LabVIEW读取CAN方面的迷茫的人,重拾信心
最近在做blf离线解析的时候,发现LabVIEW的性能比较底下,一秒钟只能读取3000帧左右,极端情况下,录制一分钟的报文,居然要花2分钟去读取。

真是太过分了,婶可忍叔叔也不能忍!

这个时候,师子一号就开始思考了。

在目前的行业发展里,不太可能出现这样一个方案盲区,必然会有比较高效的读取办法的。


经过对比,我们最终选择了python,因为python做一些小功能模块的自动化,实在是太方便了,特别是大名鼎鼎的python-can库,简直是方便得不要不要的。

用LabVIEW的库,读取一个6M的blf文件,大约需要60秒,但是用python只需要3秒,效率提升20倍。

这可真是让人眼红啊,马克思都说了,如果有150%的利润,资本家就敢铤而走险,那这20倍的效率提升,实在是让人把持不住呀,师子一号估计也不能免俗,要沦陷了。

但是,还有个问题,无论是capl还是python还是LabVIEW,读取blf的时候,基本上都是读到内存里,很难串应用。

我们用python读,那基本上相关逻辑都是在python里做了。所以我们经常可以看到工程师用python处理CAN报文的时候,各种自定义txt记录格式,不规范。

并且python用来做大型测试系统,实在是有点勉为其难。

这该咋办呢?

非常好办,对只要有稍微的C语言基础或者数据结构基础,这个事情就很好解决。

我们用python读取之后,再写入成二进制文件,不就好了吗?

LabVIEW读取二进制文件,效率那可是杠杠的。

基本的思路是,定义一个二维数组,元素为U8,尺寸为N*80,N为报文帧数。每个报文用80个字节来存储,其中8个字节用来存储时间戳,64个字节用来存储数据区(兼容canfd),4个字节用来存储id,4个字节用来存储其他乱八七糟的属性信息。

存储成二进制文件之后,用labview读取完整的二进制内容,然后用强制数据转换,就可以直接转换成结构体数组啦,跟用LabVIEW直接读的效果是一样的,但是速度大大增加。

更过分的事

在面对更大尺寸的blf文件时,LabVIEW的blf库会更加拉胯,比如100M的blf文件,它可能需要1个小时,太尴尬了。

这种情况下,我们仍然可以用python进行二进制转存,而且为了防止转存出来的文件过大,在LabVIEW中出现内存不足的问题,我们可以在转存成二进制文件时,把它切割成1M左右的小的二进制文件,完全不影响后续的处理效率,串行读取效率更高。

下面讲一下详细的原理哈。

方法第一步,python读取

我们先写几个简单的python脚本,读取一个小的blf文件。
import canf = "D:\\blfs\\2.blf"log_data = can.BLFReader(f)print("message count = ",log_data.object_count)for message in log_data:    print(message)
结果如下:
message count =  8Timestamp: 1726023012.618641    ID:      123    S Tx                DL:  8    11 22 33 44 55 66 77 88     Channel: 0Timestamp: 1726023013.053281    ID:      456    S Tx     F          DL: 16    01 02 03 04 05 06 07 08 08 07 06 05 04 03 02 01    Channel: 1Timestamp: 1726023013.503856    ID:      123    S Tx                DL:  8    11 22 33 44 55 66 77 88     Channel: 0Timestamp: 1726023014.016656    ID:      456    S Tx     F          DL: 16    01 02 03 04 05 06 07 08 08 07 06 05 04 03 02 01    Channel: 1Timestamp: 1726023014.436349    ID:      123    S Tx                DL:  8    11 22 33 44 55 66 77 88     Channel: 0Timestamp: 1726023014.902429    ID:      456    S Tx     F          DL: 16    01 02 03 04 05 06 07 08 08 07 06 05 04 03 02 01    Channel: 1Timestamp: 1726023015.337538    ID:      123    S Tx                DL:  8    11 22 33 44 55 66 77 88     Channel: 0Timestamp: 1726023015.741603    ID:      456    S Tx     F          DL: 16    01 02 03 04 05 06 07 08 08 07 06 05 04 03 02 01    Channel: 1
Process finished with exit code 0
如何存成二进制文件呢?

我们要发挥想象力了。

代码如下所示:
import canimport structimport numpy as npf = "D:\\blfs\\2.blf"log_data = can.BLFReader(f)print("message count = ",log_data.object_count)data_arr = (struct.pack('i', 0) +            struct.pack('i', 0) +            struct.pack('i', 0) +            struct.pack('i', 0) +            struct.pack('i', 0) +            struct.pack('i', 0) +            struct.pack('i', 0) +            struct.pack('i', 0) +            struct.pack('i', 0) +            struct.pack('i', 0) +            struct.pack('i', 0) +            struct.pack('i', 0) +            struct.pack('i', 0) +            struct.pack('i', 0) +            struct.pack('i', 0) +            struct.pack('i', 0))
python_arr = [struct.pack('d', obj.timestamp) + struct.pack('i', obj.arbitration_id) + struct.pack('i', obj.channel)[0:1] + struct.pack('i', obj.dlc)[0:1] + struct.pack('i', obj.is_rx)[0:1] + struct.pack('i', obj.is_fd)[0:1] + obj.data + data_arr[len(obj.data):] for obj in log_data]arr = np.array(python_arr)binary1 = arr.tobytes()print(binary1)with open("D:\\blfs\\2-ok.blf", 'wb') as f:    f.write(binary1)
大致意思就是,创建一个结构体数组,保证其每个报文占据的字节数都是一样的,然后多个报文打包成结构体数组,以二进制的形式写入文件。

下面我们来到LabVIEW中,展示如何处理:

需要解释的点有:

1、如下图所示,python封装的结构体,包含了5+1总共6个元素,其中前5个分别为id、channel、dlc、is_rx、is_fd,第六个为64字节的u8数组(有效数据靠前存储,后面放默认值填充)。
struct.pack('d', obj.timestamp) +              struct.pack('i', obj.arbitration_id) +              struct.pack('i', obj.channel)[0:1] +              struct.pack('i', obj.dlc)[0:1] +              struct.pack('i', obj.is_rx)[0:1] +              struct.pack('i', obj.is_fd)[0:1
2、python的时间戳是浮点数,其含义为从1970年1月1日早上8点距今的秒数,所以我们在LabVIEW中解析时,要加上这个数。

3、data要根据dlc的值,在最后的64个字节中进行截断读取。之所以这么做,是为了内存对齐,进一步提升处理速度。

通过上述方法,我们就实现了python和LabVIEW的联合,发挥各自的优势,实现了对blf文件的高效处理。

请相信师子一号,这是目前全行业所能想到的性价比最高、最省钱、可扩展最简单的办法了。

我们这么折腾,绝对不是脱了裤子放气,事实上,对于一个100M的blf文件,这两个环节加一起所消耗的时间,也不到1分钟,完全可以接受了。

当然,还需要说明的是,二进制文件大约比blf文件的体积大7倍左右,但是鉴于二进制文件的临时性,我们在做完分析之后,可以直接将其删除。

至于文章前面所说的分割成1M的二进制文件,其办法也很简单,在python的for循环中判断一下循环索引%N是否为0即可,为0则做一次保存,并初始化数组。N的值随便定,如果定为100000的话,二进制文件大约就是6M,读取也很快。

这种情况下,你完全不用等python分割完,就可以开始进行LabVIEW读取和逻辑处理,会更加节省时间。
【本文完】



【推荐】
汽车行业,千万不要去干外包
恒润和意昂,两扇窗户,看懂行业的过去、当下和未来

总线10讲,东半球最好用的excel2dbc工具,永远免费送

【课程】汽车和LabVIEW完美结合,干货十足,助您掌握核心技术,提升职场竞争力

专题技术交流群,用户讨论组,大合集(加各种工具交流群,请后台联系)

培训测试技术,居然需要将近2万?太过分了!!!
[汽车改装市场]针对新款大灯的LIN转换模块

车辆技术
致力于汽车研发测试技术的研究推广,帮助同行互通有无,为提升职业价值感,为产业崛起而奋斗!
 最新文章