news 2026/6/10 13:23:06

python实现dbc生成矩阵(csv格式)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
python实现dbc生成矩阵(csv格式)

直接上代码。必要依赖库自行安装:

#!/usr/bin/env python3# -*- coding: utf-8 -*-""" dbc_to_matrix.py 解析 DBC 文件(不依赖 cantools),导出 signals.csv, messages.csv, 并为每个消息生成 64-bit bitmap 文本文件。 用法: python dbc_to_matrix.py path/to/file.dbc """importreimportsysimportosimportcsvfromcollectionsimportdefaultdict,OrderedDict# ---------- 辅助解析正则 ----------re_bo=re.compile(r'^\s*BO\_\s+(\d+)\s+(\w+)\s*:\s*(\d+)\s+(\w+)?')# SG_ MySignal : 0|16@1+ (0.1,0) [0|250] "km/h" Receiver1,Receiver2# SG_ SignalName M : start|len@bo+ (factor,offset) [min|max] "unit" rx...re_sg=re.compile(r'^\s*SG\_\s+(\w+)(?:\s+([mM]\d*|M))?\s*:\s*'r'(\d+)\|(\d+)@([01])([+-])\s*'r'\(\s*([^,]+)\s*,\s*([^\)]+)\s*\)\s*'r'\[\s*([^|\]]+)\s*\|\s*([^\]]+)\s*\]\s*'r'"([^"]*)"\s*(.*)$')# 兼容更简单的 SG_ 形式(缺少部分方括号或单位等)re_sg_relaxed=re.compile(r'^\s*SG\_\s+(\w+)(?:\s+([mM]\d*|M))?\s*:\s*'r'(\d+)\|(\d+)@([01])([+-])\s*'r'(?:\(\s*([^,]+)\s*,\s*([^\)]+)\s*\))?'r'(?:\s*\[\s*([^|\]]+)\s*\|\s*([^\]]+)\s*\])?'r'(?:\s*"([^"]*)")?\s*(.*)$')# VAL_ <id> <signal> <value> "text" ... ;re_val=re.compile(r'^\s*VAL\_\s+(\d+)\s+(\w+)\s+(.*);\s*$')# SIG_GROUP_ lines (可选解析,暂存)re_sig_group=re.compile(r'^\s*SIG_GROUP\_\s+(\d+)\s+(\w+)\s+(\d+)\s*:\s*(.*)$')# 通用 token 清理deftidy(s):returns.strip()# ---------- 位映射(bit index 0..63 -> Byte7..Byte0 display) ----------# DBC: start bit numbering: 0..63. 对 Intel (little endian @1) 可以认为连续位递增。# 对 Motorola (big endian @0) 位的映射比较奇怪:从同一个字节的 MSB 开始往下;为可视化占位,我们计算物理位索引。defintel_bit_indices(start,length):# little-endian: bits increase normallyreturn[start+iforiinrange(length)]defmotorola_bit_indices(start,length):# big-endian mapping: this maps according to CAN big-endian bit order used in DBC# algorithm: for a given start (0..63), compute byte = start // 8, bit_in_byte = start % 8# The "next" bit in big-endian goes to bit_in_byte-1; if bit_in_byte == 0, next goes to next byte's 7.indices=[]cur=startforiinrange(length):indices.append(cur)b=cur%8ifb==0:# move to next byte (higher-numbered bit index)# note: moving to next byte reduces address by 7 (in DBC indexing)cur=cur+7else:cur=cur-1returnindices# 映射到 0..63 的可视位位置(以 bit0 为最低字节最低位 -> 我们要生成 Byte7..Byte0 显示)# 用户通常希望看到 Byte7 .. Byte0 左到右,且每个 byte 显示 bit7..bit0defto_visual_positions(bit_indices):# visual index: 0..63 where 0 is leftmost (Byte7 bit7) or we will build layout later# Simpler:我们 create a 64-array with index 0 -> bit 63, index 63 -> bit 0# So for bit n (0..63), its visual pos = 63 - nreturn[63-bforbinbit_indicesif0<=b<64]# ---------- 主解析函数 ----------defparse_dbc(path):messages=OrderedDict()# id -> {name, id, dlc, sender, signals: []}signals=[]# list of signal dictsval_tables=defaultdict(dict)# (id, signal) -> {value: text}sig_groups={}# open and read lineswithopen(path,'r',encoding='gbk',errors='ignore')asf:forrawinf:line=raw.strip()ifnotline:continue# BO_m=re_bo.match(line)ifm:msg_id=int(m.group(1))name=m.group(2)dlc=int(m.group(3))sender=m.group(4)or''messages[msg_id]={'id':msg_id,'name':name,'dlc':dlc,'sender':sender,'signals':[]}continue# SG_m=re_sg.match(line)ifnotm:m=re_sg_relaxed.match(line)ifm:sig_name=m.group(1)mux=m.group(2)# None or 'M' or 'm<n>' etcstart=int(m.group(3))length=int(m.group(4))byte_order=int(m.group(5))# 1: intel (little), 0: motorola (big)sign=m.group(6)# '+' or '-'factor=Noneoffset=Noneminimum=Nonemaximum=Noneunit=''receivers=''try:factor=float(m.group(7))ifm.group(7)else1.0offset=float(m.group(8))ifm.group(8)else0.0exceptException:factor=Noneoffset=None# group(9)/group(10) might be min/max in strict; in relaxed they can be Nonetry:minimum=float(m.group(9))ifm.group(9)elseNoneexceptException:minimum=Nonetry:maximum=float(m.group(10))ifm.group(10)elseNoneexceptException:maximum=Noneifm.lastindexandm.group(m.lastindex):# last group contains receivers or unit etc; in strict pattern group(11) is unit, group(12) receivers# For relaxed, unit may be group(11) and receivers group(12)# We'll try to extract unit and receivers from tail if possiblepass# Attempt to extract unit and receivers from the original line using a simpler approach# split by quote " ... "unit_match=re.search(r'\"([^\"]*)\"',line)ifunit_match:unit=unit_match.group(1)# receivers are what's after the last quotetail=line.split(unit_match.group(0))[-1].strip()# tail may contain receiversreceivers=tail.strip()# clean commasreceivers=receivers.strip().strip(';')else:# no unit present: receivers likely at endparts=line.split()# take last token(s) after the ] or ) group# crude fallback:tail=line.split(')')[-1]receivers=tail.strip()# find which message this signal belongs to: it's the most recent message in messagesifnotmessages:# orphan signal (no BO_ seen yet) -> skipcontinue# get last message (most recent BO_)last_msg_id=next(reversed(messages))msg=messages[last_msg_id]is_signed=(sign=='-')sig={'message_id':last_msg_id,'message_name':msg['name'],'id':last_msg_id,'signal_name':sig_name,'start_bit':start,'length':length,'byte_order':'Intel'ifbyte_order==1else'Motorola','byte_order_code':byte_order,'is_signed':is_signed,'factor':factor,'offset':offset,'min':minimum,'max':maximum,'unit':unit,'receivers':receivers,'mux':mux}msg['signals'].append(sig)signals.append(sig)continue# VAL_ (枚举)m=re_val.match(line)ifm:msg_id=int(m.group(1))sig_name=m.group(2)rest=m.group(3).strip()# rest example: 'SIG 0 "Off" 1 "On"'# We'll parse sequences of <num> "text"pairs=re.findall(r'(-?\d+)\s+"([^"]*)"',rest)forval,txtinpairs:try:val_int=int(val)except:continueval_tables[(msg_id,sig_name)][val_int]=txtcontinue# SIG_GROUP_ (optional store)m=re_sig_group.match(line)ifm:gid=int(m.group(1))name=m.group(2)count=int(m.group(3))members=m.group(4).strip()sig_groups[gid]={'name':name,'members':members}continue# other lines ignored for nowreturnmessages,signals,val_tables,sig_groups# ---------- 导出 CSV ----------defexport_csv(messages,signals,val_tables,outdir='.'):os.makedirs(outdir,exist_ok=True)sig_file=os.path.join(outdir,'signals.csv')msg_file=os.path.join(outdir,'messages.csv')sig_fields=['Message','MessageID','Signal','StartBit','Length','ByteOrder','IsSigned','Factor','Offset','Min','Max','Unit','Receivers','Mux','ValueText']withopen(sig_file,'w',newline='',encoding='gbk')asf:w=csv.DictWriter(f,fieldnames=sig_fields)w.writeheader()forsinsignals:key=(s['message_id'],s['signal_name'])vt=val_tables.get(key,{})# convert value table to single string like "0:Off;1:On"vt_str=';'.join(f'{k}:{v}'fork,vinsorted(vt.items()))row={'Message':s['message_name'],'MessageID':hex(s['message_id']),'Signal':s['signal_name'],'StartBit':s['start_bit'],'Length':s['length'],'ByteOrder':s['byte_order'],'IsSigned':s['is_signed'],'Factor':s['factor'],'Offset':s['offset'],'Min':s['min'],'Max':s['max'],'Unit':s['unit'],'Receivers':s['receivers'],'Mux':s['mux'],'ValueText':vt_str}w.writerow(row)withopen(msg_file,'w',newline='',encoding='gbk')asf:mf=csv.DictWriter(f,fieldnames=['Message','MessageID','DLC','Sender','SignalsCount'])mf.writeheader()formid,minmessages.items():mf.writerow({'Message':m['name'],'MessageID':hex(mid),'DLC':m.get('dlc'),'Sender':m.get('sender'),'SignalsCount':len(m.get('signals',[]))})returnsig_file,msg_file# ---------- 生成每个消息的位图文本文件 ----------defexport_bitmaps(messages,outdir='bitmaps'):os.makedirs(outdir,exist_ok=True)formid,minmessages.items():# 64位数组canvas=['.'for_inrange(64)]forsinm.get('signals',[]):start=s['start_bit']length=s['length']bo=s['byte_order_code']ifbo==1:bits=intel_bit_indices(start,length)else:bits=motorola_bit_indices(start,length)vis=to_visual_positions(bits)forpinvis:if0<=p<64:canvas[p]='#'# produce rows of bytes Byte7..Byte0, each as 8 bits from MSB to LSBrows=[]# visual index 0..63 maps to bits (Byte7 bit7 .. Byte0 bit0)forbyte_idxinrange(8):# each row contains 8 bits for a byte across (we will label Byte7 .. Byte0)start_i=byte_idx*8row_bits=canvas[start_i:start_i+8]rows.append(''.join(row_bits))# write filefname=os.path.join(outdir,f"msg_{hex(mid)}_bitmap.txt")withopen(fname,'w',encoding='gbk')asf:f.write(f"Message{m['name']}({hex(mid)}) DLC={m.get('dlc')}\n")f.write("Left->Right: Byte7 Byte6 Byte5 Byte4 Byte3 Byte2 Byte1 Byte0\n")fori,rinenumerate(rows):f.write(f"Byte{7-i}:{r}\n")# ---------- 主流程 ----------defmain():iflen(sys.argv)<2:print("Usage: python dbc_to_matrix.py path/to/file.dbc [outdir]")sys.exit(1)path=sys.argv[1]outdir=sys.argv[2]iflen(sys.argv)>=3elseos.path.dirname(path)or'.'outdir=os.path.join(outdir,'dbc_out')os.makedirs(outdir,exist_ok=True)print("Parsing...",path)messages,signals,val_tables,sig_groups=parse_dbc(path)print(f"Found{len(messages)}messages,{len(signals)}signals,{len(val_tables)}VAL tables.")sig_file,msg_file=export_csv(messages,signals,val_tables,outdir=outdir)export_bitmaps(messages,outdir=os.path.join(outdir,'bitmaps'))print("Exported:")print(" signals ->",sig_file)print(" messages ->",msg_file)print(" bitmaps ->",os.path.join(outdir,'bitmaps'))print("Done.")if__name__=='__main__':main()
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/10 13:42:58

军工仿真软件如何实现三维公式与Word数据联动?

富文本编辑器集成文档处理与图片上传功能开发实录 作为一名独立开发网站的技术人员&#xff0c;我近期正全力攻克富文本编辑器在处理 Word 内容粘贴及多种文档导入时的一系列问题。以下是我详细的查找与开发过程记录。 一、需求精准定位 &#xff08;一&#xff09;核心功能…

作者头像 李华
网站建设 2026/6/10 10:45:18

2026 年 FPGA 行业现状:回归工程价值,进入稳定增长阶段

2026 年&#xff0c;FPGA 行业已经明显进入了一个与前几年不同的阶段。如果说 2022&#xff5e;2023 年更多是在消化库存、收缩投入&#xff0c;那么近两年行业的关键词正在逐步回到“落地”“交付”和“系统价值”本身。无论是通信、数据中心&#xff0c;还是工业与专用计算场…

作者头像 李华
网站建设 2026/6/10 10:46:35

系统软件找不到msxml3.dll文件 如何修复? 免费下载方法分享

在使用电脑系统时经常会出现丢失找不到某些文件的情况&#xff0c;由于很多常用软件都是采用 Microsoft Visual Studio 编写的&#xff0c;所以这类软件的运行需要依赖微软Visual C运行库&#xff0c;比如像 QQ、迅雷、Adobe 软件等等&#xff0c;如果没有安装VC运行库或者安装…

作者头像 李华
网站建设 2026/6/10 10:38:59

是时候,让数据开口说话,反哺业务了

前言&#xff1a; 在讨论到AI是否可以用来做数据分析和决策时&#xff0c;我想到太古可口可乐的案例—企业问数&#xff0c;但是&#xff0c;其实很多的企业数字化水平&#xff0c;还是处于信息化与数字化交界的地带&#xff0c;因此&#xff0c;今天说说数据在数字化中的情况。…

作者头像 李华
网站建设 2026/6/10 10:41:45

优秀的服务器性能要看哪些方面

服务器性能指标主要看的是速度和稳定性&#xff0c;服务器的性能要求是什么&#xff1f;服务器的多处理器特性、内存容量、磁盘性能及可扩展性是选择服务器要考虑的主要因素。互联网时代的发展服务器的种类也越来越多。服务器的性能要求是什么&#xff1f;运行服务器软件的计算…

作者头像 李华
网站建设 2026/6/9 21:31:07

Java中接口相关

格式1为默认方法服务&#xff0c;格式2为静态方法服务&#xff0c;用于提取共性内容。 在实现类中抽象方法必须重写&#xff0c;默认方法可重可不重&#xff0c;静态方法不能重写。 接口的应用 适配器设计模式 此时如果实现类有其他父类的解决方式&#xff08;Java中不能多继承…

作者头像 李华