结论:这份笔记覆盖九份 DBC、合计 238 条报文与 1,066 条信号,分属 Coda 的 B/C/D 三总线、VTRUX 的 OBD/PT 两总线、Bel 逆变器的 J1939 扩展帧,以及一辆 1975 Porsche 914 改装车的自定义 VCU 遥测。它的价值不在清单本身,而在把「反编译出来的标签」和「验证过的信号」分成五档,并如实记录了一次被纠正三次的电芯索引映射与八条被推翻的假设。
九份 DBC 的量级与定义来源
仓库统计明确说明:下面的报文 / 信号数来自拷进来的 DBC 文件本身,而不是上游 README 的表格——后者已经过期。Coda 的 B、D 两总线在上游 README 里写的是 35 和 22,实际文件是 34 和 23;914 的 README 还在描述一份 75 报文 / 496 信号的 schema 3.0,而文件已经是 schema 4.2、hash 0x09EB175A。
| DBC 文件 | 报文 / 信号 | 总线 | 定义来源 | 证据边界 |
|---|---|---|---|---|
CODA-B-CAN.dbc |
34 / 156 | B CAN | 原厂 CODACAN LabVIEW 诊断应用 + 实车抓包 | 上游 README 的 35 为过期值,以文件为准 |
CODA-C-CAN-cells.dbc |
26 / 104 | C CAN | 26 帧 0x000–0x019,每帧 4 个 16 位 Motorola 电芯,1 mV/bit | 电芯编号自 2026-07-22 起改为 1-based |
CODA-D-CAN.dbc |
23 / 44 | D CAN | LabVIEW 反编译 + 日志 | 上游 README 的 22 为过期值 |
epri-obd-bus.dbc |
12 / 18 | OBD | EPRI Logger iPhone 应用的 Ghidra ARMv7 反编译,再用车辆日志比对修正 | 字节位置与刻度并非一律正确 |
epri-pt-bus.dbc |
26 / 101 | PT | 同上 | 同上 |
vtrux-obd-experimental.dbc |
3 / 5 | OBD | 作者由日志推导的实验性定义 | 含未解析报文桩 |
vtrux-powertrain-experimental.dbc |
19 / 26 | PT | 同上 | 同上 |
BelInverter-v2.dbc |
8 / 73 | J1939 扩展 ID | EPRI 结论 + 一份更早的 DBC 合并 | 原始作者与部分字节布局未确认 |
914-telemetry.dbc |
87 / 539 | 自定义 VCU 遥测 | 改装 914 的 VCU 映射,非原厂 Porsche 协议 | 标准 11 位 ID 为真实车辆帧;29 位扩展 ID 为 VCU 串行遥测里的内部合成值 |
确认档位:怎么区分「反编译出来的」和「验证过的」
这份仓库最值得抄的一点是它不给信号打勾,而是打档。反编译只能告诉你应用把哪个字节当什么读,不能告诉你它读对了;日志相关只能告诉你两件事一起动,不能告诉你它们是不是一件事。于是每条信号都落在下面五档之一,档位直接写在验证表里。
| 档位 | 含义 |
|---|---|
| CONFIRMED | 编码与角色都被独立验证过:物理测试、行为日志证据、与已知参考相关、或跨 DBC 比对一致 |
| CONFIRMED-SYMM | 靠与某个 CONFIRMED 信号的结构对称性确认,没有独立测试 |
| CONFIRMED-DECOMPILE | 编码由 Ghidra 确认,角色只是应用自己的标签,没有独立物理或行为检查 |
| PARTIAL | 编码确认,角色或刻度还有一条具体问题挂着 |
| REMOVED | 按 DBC 信号策略删掉 SG_ 条目,原因记在 CM_ 注释里 |
档位不是形式主义
PT 总线上 0x0054 的 GENE_EmergcyStp_flg 是 CONFIRMED-DECOMPILE:Ghidra 里写着 (pbVar15[6] 与 8) 不等于 0,但所有日志里它一次都没触发过,没有行为测试。同理 0x0580 的 tcm_CAN_ERR。这类条目可以读,但不能当成「已经证明这个位是这个意思」来用。
0x381 与 C CAN 电芯索引:一条被纠正了三次的映射
C CAN 只在少数几次采集里被同时录下(需要第三个适配器),所以能回答这个问题的只有三份日志。总线识别靠内容而不是总线号:0x000–0x019 的电芯帧是 C CAN,0x381/0x382/0x383/0x390/0x439 是 B CAN,0x308/0x312/0x325/0x330/0x55C 是 D CAN——两次会话给同一条物理总线编的总线号并不一致。
| 会话 | 日志 | 配对样本 | 偏移 +1 严格命中率 |
|---|---|---|---|
| 2026-07-21 Android 三适配器 | coda_20260721_192435_T0..T2、_201109_T0/T1、_202031_T0 |
660 | 82–87% |
| 2026-02 Bonnydoon 行驶 33 min | projects/coda/logs/frombonnydoon.log |
1,972 | 80–84% |
| 2026-07-22 充至 100% | coda_20260722_173203_T0..T21 |
979 | 100% |
合计 43 万帧以上的 C CAN 电芯帧、8,300 帧以上 0x381、3,600 对以上时间配对样本,且配对时刻 C CAN 数组完整、没有帧旧于 2 秒。充电会话最干净:负荷低而稳,电芯在 B 与 C 两轮扫掠之间几乎不重排,严格测试在 VmaxId(591 样本)与 VminId(706 样本)上都命中 100.0%。
| 会话 | 信号 | 严格样本数 | 命中偏移 +1 | 不同 ID 数 | ID 范围 |
|---|---|---|---|---|---|
| Android | VmaxId | 135 | 82.2% | 11 | 6–104 |
| Android | VminId | 146 | 87.0% | 26 | 1–101 |
| Bonnydoon | VmaxId | 225 | 79.6% | 44 | 6–104 |
| Bonnydoon | VminId | 376 | 84.3% | 33 | 1–104 |
| 充电 07-22 | VmaxId | 591 | 100.0% | 2 | 82–95 |
| 充电 07-22 | VminId | 706 | 100.0% | 1 | 96 |
「严格」的口径是:只保留 C CAN 数组自身的极值恰好等于所报极值、该极值由唯一一只电芯持有、且领先第二名至少 3 mV 的样本。行驶会话里没有任何竞争偏移超过 4%;剩下约 15% 也不是反例——两条总线不是同时采样的,C CAN 扫完 26 帧要约 800 ms,而 0x381 只有约 1.1 Hz,行驶中负荷波动会在两个时刻之间把几乎并列的电芯重排。签名也说明这是偏斜而不是置换:未命中的配对集中在少数几个本来就常年处于极值的 C CAN 索引上(max 侧 81/83/94/102,min 侧 76/80/95),真置换会把它们撒满整个数组。
三次纠正各纠正了什么
第一次是编号口径:映射被发现时 C CAN DBC 还是 0-based,关系是「上报 id 等于旧索引加 1」;2026-07-22 改为 1-based 后加 1 消失,两套编号重合。这也推翻了更早那句「id 用的是与 C CAN 位置无关的 BMS 内部编号」——BMS 编号就是 C CAN 的发送顺序(1-based)。
第二次是字节序。2026-07-15 之前 0x381 的归属是 B0-1=MinCellVoltage、B2-3=MaxCellVoltage、B4-5=AvgCellVoltage、B6=VminId、B7=VmaxId;修正后是 B0-1=Avg、B2-3=Max、B4-5=Min、B6=VmaxId、B7=VminId。当年的错误来自照着 LabVIEW cluster 的名字「VminVmax」排,而不是按 LabVIEW 字段顺序 Vavg、Vmax、Vmin、VmaxId、VminId。重跑严格测试可以量化这两种读法的差距。
| 归属方式 | Android 样本 / 命中 +1 | Bonnydoon 样本 / 命中 +1 |
|---|---|---|
| 修正后 max — 值 B2-3,id B6 | 135 / 111(82.2%) | 225 / 179(79.6%) |
| 修正后 min — 值 B4-5,id B7 | 146 / 127(87.0%) | 376 / 317(84.3%) |
| 旧 max — 值 B2-3,id B7 | 135 / 0(0.0%) | 225 / 1(0.4%) |
| 旧 min — 值 B0-1,id B6 | 0 / 0 | 0 / 0 |
两端的失效并不对称。min 侧当时根本没有信号可用:旧的 MinCellVoltage 读 B0-B1,而那其实是包平均值;平均值几乎不可能唯一且带余量地等于某一只电芯,所以两次会话里都是零样本存活,没有东西可相关。min 侧还有第二个错:id 也取自错误的字节(B6 其实是真正的 VmaxId)。max 侧则是「值对、id 错」:B2-B3 在两种读法下都真是最大值,但索引来自 B7(真正的 VminId),于是正确的最大电压配上了最小电芯的编号,噪声里最好的偏移只有 21%——读起来很像「另一套编号约定」,非常容易被误判。
第三次是对比方式。frombonnydoon.log 同时带 C CAN 与 0x381,它自己的 0x381 报 VminId 95 / VmaxId 84,正是那次笔记已经点名的两只电芯。也就是说这条映射在单份日志内部就可验,而当时的笔记却拿它们去和另一次(充电)会话的 96/76 比,把差距读成了编码差异。结论成了方法:只要两条总线同时在场,就在同一会话内部比。
还有一条适用范围限制:本节的「+1」只适用于经 DBC 从原始字节解出来的值。从 CODACAN 界面截图上读到的数字(如充电分析里的 VminId=96 / VmaxId=76)来自 LabVIEW cluster,它一直是对的,不受 DBC 错误影响。哨兵值 255 也要单独处理:104 只电芯的包里 255 不可能是索引,它是无效 / 无数据哨兵,不要当成「第 254 只电芯」。
证据边界:部分解码、未解与已推翻
「已确认且完整」的信号有其编码摘要,例如 0x275 BMSDriveLimits 的 B0 = 放电限值(uint8 乘 2 得 A)、B1 = 充电限值(乘 2 得 A)、B2-B3 = 包电流(BE uint16 乘 0.1 A,零点 0x8000)、B4-B5 = 包电压(BE uint16,1 V/bit)、B6 = HVAC 限值(乘 2 得 A)、B7 未知(基线 0xDD)。下面列的是还没收口的。
| ID | 名称 | 已知 | 还缺什么 |
|---|---|---|---|
| 0x050 | BMSChargerCmd | B0-B1 = HVCurrentCmd(BE uint16 乘 0.1 A,R2 = 0.992;基线 0x00DC = 22 A);B2-B3 = MaxVoltage(乘 0.1 V,R2 = 0.605;基线 0x0FF7 = 408.7 V);中位帧 00 dc 0f f7 00 01 3e 01 |
B4-B5 取非基线值会把 Main Current 压到约 6 A,疑似帧校验或滚动计数;B6-B7 未知;需注入测试 |
| 0x270 | BMS_FaultStatus | B0 为故障字节(0x00 无故障,0x12 = 故障码 18,bit 1 = 0x02 与 bit 4 = 0x10 置位);比 0x271 早一帧;drop 后 CODACAN 的 BMS Fault Severity 掉下去 | B0 内部故障码与严重度的分界未扫;B6-B7 未知 |
| 0x2C1 | BMSDrivingRange | B0 状态字节(raw = 0x70 时翻转);B1 / B3 / B5 分别为 Exp / Max / Min,R2 约 0.96–0.97;比例暂定约 1.1 乘 raw 减 19 | 刻度 / 偏移未精确确认;B2、B4、B6-B7 未扫;单位可能是英里 |
| 0x330 | Long_Accel | 被抑制时会掉,但与噪声边界模糊;VICD 刻度为有符号字节乘 0.08 m/s² | 未确认为模拟量;需要一次含急刹的行驶事件做时序提取 |
| 0x383 | BMSBattStatus | SoC 在 B0-B1(BE uint16 除以 10 得 %)已确认;同时带 HVBattCharging、ChrgPortOpen、ChargeCableConnected | 三个布尔位的确切位号未记录 |
| 0x410 | AC_Compressor_Command | B2 = compressor_on_off / CASS_on_off / warmup_cycle_cntr_incr;B6 = 目标转速(乘 60 rpm/bit);B7 = 最大功耗(乘 0.1 kW/bit) | B0 的三个布尔位(HVAC FaultRed、FaultYellow、KeepWakeNetworkHVAC)位号未解;也可能是扫描引起的 ECU 响应假象 |
| 0x241 | MCM_Thermal | 角色已确认:drop-ID 后 Rotor / Stator / IGBT 三个字段归零;DLC = 8 已由日志确认 | 逐字节归属未确认;偏移假定为减 40 摄氏度;B4 恒为 0x00,疑似哨兵或非温度字段 |
| 0x491 / 0x273 | IPK 帧 | 两者都带 Primary ODO(km)、Interior Illum、Side Light Active、Low Beam Active;0x491 还会点亮 Overview 的 IPK 指示,0x273 不会 |
ODO 的字节位置与编码(可能是 BE uint24 或 uint32);灯光的位号 |
八条被推翻的早期假设
这些条目都曾写进笔记或报告,后来被数据推翻。留着不是自曝,而是让下一个人不用再踩一遍。
| 早期假设 | 更正为 |
|---|---|
| 0x212 = EPS_SAM_1(转向角,0.25 deg/count) | 0x212 = DLCM Torque Request;转向角在 0x080 |
| 0x210 = Vehicle_Mode 含 VBatt(乘 0.4 V/count) | 0x210 B2 = ThrottlePedalPos(乘 0.4 %/count) |
| 0x271 = Death Counter 的一部分(整数字节计数) | 0x271 = GWM 心跳 + VehFaults 的源 |
| 0x55C = VehFaults(3 字节:灯 / 严重度 / 故障字) | 0x55C = TCM 心跳 |
| 0x381 = BMSDriveLimits 候选(哨兵 1000.0 A) | 0x381 = BMSVminVmax;BMSDriveLimits 在 0x275 |
| 0x382 B0 = 充电阶段计数器(0x8B 到 0x8E 步进) | B0 = Cell_T_avg;充电过程中包升温时为 11–14 摄氏度 |
| 0x275 B4 = HV Active 布尔标志 | B4-B5 = PackVoltage(BE uint16,1 V/bit);104 串 LFP 包始终使 uint16 的最高位置位 |
| BattSentDischargeLimit / ChargeLimit 刻度 = 1 | 刻度 = 2(uint8 乘 2 得 A) |
常见问题
反编译出来的 DBC 能直接拿来解日志吗?
不能直接。反编译只证明应用把某个字节按某种方式读,不证明它读对了。所以这里把信号分成 CONFIRMED、CONFIRMED-SYMM、CONFIRMED-DECOMPILE、PARTIAL、REMOVED 五档,只有前两档带独立验证,第三档只是「应用自己这么命名」。
电芯编号到底是 0 起还是 1 起?
C CAN DBC 自 2026-07-22 起改为 1-based(Cell1 到 Cell104),与 BMS 自己的 VmaxId / VminId 直接对应,VmaxId 82 就是 Cell82。此前是 0-based,老 CSV、老图、老导出都要加 1 才能对上,例如旧 Cell94 等于现 Cell95。MinTempId / MaxTempId 是另一套索引,不受影响。
为什么 0x381 的映射要改字节序?
因为最初的归属照着 LabVIEW cluster 的名字「VminVmax」排,把 Min 与 Avg、VminId 与 VmaxId 都放反了;按 LabVIEW 字段顺序应是 Vavg、Vmax、Vmin、VmaxId、VminId。重跑严格测试后,旧的 max 读法命中 0.0%,旧的 min 读法零样本存活,修正后分别是 82.2% 与 87.0%。
偏航率刻度为什么判不出来?
两种说法分别是 0.0045(转向角 / 轴距运动学模型)与 0.003924(后轮差速几何法),但它们不是两条独立标定:同一几何法随速度窗口与轮距取值会给出 0.00347 到 0.00488。系统误差预算合计 43.4%(左右不对称 34.1%、速度窗口 21.5%、旅程间 16.0%),远大于两者相差的 14.7%,因此只能记为「判不出」。
这份素材的许可证状况如何?
被检查的上游快照里没有许可证文件,本文所依据的是一份离线私有研究副本。公开仓库可访问并不等于取得再分发或制作衍生作品的权利,对那些从第三方应用推断出来的定义尤其如此。共享或商用之前应与相关权利人确认。
延伸阅读
- 2330 份 DBC、294 个来源:公开 CAN 数据集的收录与分级 —— 判断一份社区 DBC 值不值得进管线
- UDS 诊断工具为什么不能随手调:只读、会话与写 ECU 的分权设计 —— 只读边界的工程实现
- 车载信号为什么会说谎:TTL、源时间与 500 ms 新鲜度阈值 —— 为什么「相关」不等于「识别」
- foxBMS 2 的 CAN 报文:41 条组件级定义与双许可证边界 —— 另一份电池侧 DBC 的许可证口径
- 车型 CAN 数据库
参考资料
- 项目 01 ——
public-can-dbc-datasets/additional/nickyivyca-vtrux-coda/SOURCE.md(九份 DBC 的报文 / 信号数与权利边界) - 项目 01 ——
public-can-dbc-datasets/additional/nickyivyca-vtrux-coda/projects/coda/notes/codacan-signal-decode-notes.md(CODACAN 台架方法、分阶段完成表、模块在位映射与已推翻假设) - 项目 01 ——
public-can-dbc-datasets/additional/nickyivyca-vtrux-coda/projects/coda/notes/cell-index-mapping.md(0x381 VmaxId/VminId 与 C CAN 电芯数组的三次纠正与严格测试口径) - 项目 01 ——
public-can-dbc-datasets/additional/nickyivyca-vtrux-coda/projects/vtrux/notes/epri-verification.md(PT 与 OBD 总线的逐信号确认档位与 Gap)
免责声明
本文所述信号定义全部来自社区逆向工程,不代表车辆制造商的官方数据。Coda 与 VTRUX 两家整车企业均已退出市场,无原厂文档可核对;VTRUX 的 EPRI 定义最初由一款 iPhone 日志应用的二进制反编译重建,再用车辆日志比对修正,字节位置与比例并非一律正确。上游快照未包含许可证文件,公开仓库可访问不构成再分发或衍生权利。涉及安全相关用途时请仅作参考,并以实际测量为准。
更新记录
- 2026-10-15 初稿