Files
vd_960/vd960Loop/docs/devlog.md
T
wangfq 2a267967b4 feat(vd960Loop): 环境健康度算法 §10 + drift_health.py 参考实现
- variation-analysis.md §10: 无车漂移监测 (零成本, 不改协议)
  - 口径修正: 绝对峰=1.5×窗口漂移(Origin 滞后半窗) → 用峰谷差
  - 600ms 采样系统性低估 ~12% (峰在窗口末采不到)
  - 冻结态失效(>4×dlt_ORG) → 双指标: 漂移速率 + 冻结占比
  - 冻结判定双判据: 跨窗跳变消失 + 峰谷差突变(>4×前4窗中位数)
- tools/drift_health.py: CSV 逐窗统计/冻结检测/JSON/自测
- devlog 2026-08-25 条目追加环境健康度小节
- 自测: 慢漂移 0.02%/s 识别准确, 冻结窗正确排除
2026-08-25 10:09:36 +08:00

15 KiB
Raw Blame History

vd960Loop 开发日志

MCU: AT32F421 (Cortex-M4, 120MHz) | 线圈通道: 4路 | 调试口: TTL Tx (3.3V 9600 8N1)


2026-08-25 — variation ↔ ΔL/ΔL-L 物理对应分析与工具

背景

后台需要把上报的 variation(CAPVD 计数域)换算成物理电感变化量,用于标定灵敏度、分析车辆信号强度。

核心推导

CAPVD ∝ 周期 T = 2π√(LC),即 CAPVD ∝ √L 而非 L

variation/Origin = 1  √(1 + ΔL/L₀)        精确
ΔL/L₀ ≈ 2 × variation/Origin              一阶(残差 <0.2%
Δf/f  ≈ variation/Origin                   频域对应
  • 系数 2 来源于 √(1+x) ≈ 1+x/2 展开
  • 符号:车辆进入 ΔL<0 → variation 恒为正,与 V1.05 协议语义一致
  • 电容档无关性Origin 与 CAPVD 均 ∝ √Cvariation/Origin 中 C 消掉 → 33/43/66/76nF 四档共用同一换算表,现场换档不换标定

灵敏度档位 → ΔL/L 触发阈值(SensTable {216,108,36,10}

SENS Δf/f 进入 (=SensTable/65536) ΔL/L 进入 ≈ 2×
0 低 0.330% 0.659%
1 中 0.165% 0.330%
2 高 0.055% 0.110%
3 最高 0.015% 0.031%

交叉验证:DLD154Pro 技术文档 sens_in {108,54,28,14} 标注 ΔL/L = 0.330%/0.165%/0.085%/0.043%,恰为 SensTable/65536 的 2 倍——产品线口径一致。

改动

文件 内容
docs/variation-analysis.md 新增 §9(物理链路/公式/档位表/电容无关性/示例/注意事项)
tools/variation_calc.py 新增换算工具:正向(freq+cap+variation+origin→L₀,ΔL,ΔL/L)、反推、3B LE 补码解析(V1.05)、灵敏度对照、交互模式

验证

工具四模式实测通过,正反算自洽(ΔL/L=0.33% ↔ variation=216 @ Origin=131072)。

协议文字勘误(协议 V1.07

用户指出 §5.6.3 记录的口径差异应直接改协议:原文 ±8388607 不对称,负向边界少了 1。统一为 8388608 ~ +8388607(3B 补码标准值域 −2²³ ~ +2²³−1,对齐代码负向饱和边界 0x800000),后台按文档实现时不会对 0x800000 边界犯嘀咕。

文件 变更
DLD960Loop_串口通信协议.md variation 字段值域文字修正 + 修订记录 V1.07
variation-analysis.md 头部版本引用 → V1.07;§1 值域;§5.1 表格;§5.6.3 口径小注改写

代码无改动(main.c 饱和边界本就是 8388608 ~ +8388607)。

环境健康度算法(§10

用户提出零成本环境健康度方案:无车时 variation 锯齿的峰 = 漂移信号,后台逐窗统计画健康度曲线。模拟验证后修正两处口径并落地:

  1. 绝对峰 ≠ 窗口漂移:Origin 更新到窗口均值(滞后半窗 2.5s),稳态绝对峰 = 1.5× 窗口漂移 → 改用峰谷差maxmin,误差 <1%
  2. 600ms 采样系统性低估 ~12%:峰恒在窗口末(500 tick),末采样点 480 tick 永远错过 → 单边偏差,趋势可用,绝对标定 ×1.14
  3. 冻结态失效:漂移 > 4×dlt_ORG(中档 0.13%/s)→ 锯齿消失,速率口径失效 → 双指标:漂移速率 = 峰谷差/Origin/5s + 冻结占比
  4. 冻结判定双判据:跨窗跳变消失(|jump|≈0)+ 峰谷差突变(>4×前 4 窗中位数),最后一窗也可判
文件 内容
docs/variation-analysis.md 新增 §10(口径修正表/双指标/冻结判定/工具用法)
tools/drift_health.py 新增参考实现:CSV 输入 + 逐窗统计 + 冻结检测 + JSON 输出 + 自测

自测:前 6 窗慢漂移 0.02%/s 全正常,后 2 窗快漂移正确标冻结,平均速率/冻结占比准确。


2026-07-14 — variation 上报量 2B→3B 有符号 (协议 V1.05)

背景

uart_report_packet_loop_acs 上报的变化量 variation 用于后台离线跟踪分析车检器算法(判决裕量、基线跟踪行为)。原实现为 2 字节无符号 + 取绝对值,存在两个致命缺陷:

  1. 回绕污染variation 是 CAPVD 域的量(量级 ~131072,非 Hz)。大车/大金属全覆盖时偏差可超 65535 → 2B 回绕成小值,后台看到"大信号突然变小"的假象,分析数据作废。
  2. 方向丢失|Origin CAPVD| 抹掉符号,分不清"车/金属进入(CAPVD 掉到基线下)"与"反向漂移/异常抬升(CAPVD 升到基线上)",两者判决意义相反。

改动 (组包段)

// 旧: uint32_t variation = |Origin - CAPVD|  (2B LE)
// 新: 3B LE 有符号补码, 方案B定义
int32_t variation = (int32_t)unit->loop_Origin - (int32_t)unit->loop_CAPVD;
if (variation >  8388607) variation =  8388607;   // +2^23-1 饱和防回绕
if (variation < -8388608) variation = -8388608;   // -2^23   饱和
// 低字节在前, 发 3 字节
  • 方案Bvariation = Origin CAPVD正值 = 当前值低于基线(车/裕量方向,与旧版语义连续);负值 = 反向漂移。
  • 饱和限幅 ±2²³,彻底杜绝回绕。
  • 每通道单元 11B → 12B,整帧 52B → 56B(仍 < BUFF_STACK_SIZE=64,缓冲安全)。

影响范围 & 联动

变更
main.c 组包 uint32_tint32_t3B LE + 饱和
协议文档 DLD960Loop_串口通信协议.md V1.05:字段表、Len 47→51、示例报文重算
vd960DBN 解析步长 11→12、misc 偏移右移 1B、3B 解码 + bit23 符号扩展、fast_mode 改 abs(variation)

⚠️ Loop 固件与 DBN 固件必须同版本发布——步长死绑定,任一端用旧固件则 4 通道数据整体错位。

验证

本地 gcc 隔离单测(编解码往返 / 符号扩展 / 双向饱和 / 方向语义 / fast_mode)全通过。关键:大车 diff=100000 旧版回绕成 34464,新版正确保留 100000。


2026-06-26 — 多项可配置化改造

1. 上报频率从 raw CAPVD 改为实际线圈频率

uart_report_packet_loop_acsCMD_DBN_GET_MCJQ_PARAM 中,频率字段原来直接上报 loop_CAPVD(IIR 累加值),现改为经过公式转换的实际频率:

freq = (sclk_freq × input_div × LPCNT) / CAPVD

使用 uint64_t 先乘后除避免整数截断,LPCNT>0 && CAPVD>0 防除零。

2. 有限存在时长可配置 (hold_time)

  • Loop154_Unit 新增 uint16_t hold_time 字段
  • storage.cexist_mode 计算: hold_time = exist_mode × 20 × 5tick 数,每 tick 50ms
  • vd1_task_per_channel 判定有车时: 若 hold_time > 0loop_VD_HOLD = 1,启用有限存在计时
  • TMR15_GLOBAL_IRQHandler: Hold_CNT > unit->hold_time 替代固定 HOLD_TIME
  • 超时后执行通道完整重启(LC_Reset=1, loop_INI_LOOP=1),相当于线圈重启重建基线,避免继电器释放后立即重新吸合
  • exist_mode=0 时不启用有限存在,兼容无限制存在场景

3. 离开延时可配置 (relay_delay)

  • Loop154_Unit 新增 uint16_t relay_delay 字段
  • storage.cdelay_time 计算: relay_delay = delay_time × 2tick 数)
  • TMR15_GLOBAL_IRQHandler: OUTCNT > unit->relay_delay 替代固定 OUT_DELAY

4. vTaskDelay 修正: 10ms → 50ms

loop_task_function 的主循环 vTaskDelay10ms 改为 50ms,对齐 DLD154V4B 原始设计(TMR15 5ms×10)。

影响:

  • 基线更新周期: 100×10ms=1s → 100×50ms=5s(对齐原始设计,Origin 更稳定)
  • CPU 占用: 主循环轮询频率降低 5×,节省 CPU

原因: TMR3 ISR ~1ms 产出一个 CAP_OK 样本,50ms 内有 ~50 个样本。vd1_task_per_channel 每个 tick 只取最新一个做 IIR10ms 轮询时 CAP_OK 总是 ready,改为 50ms 不影响有效测量速率——采集由 TMR3 ISR 硬件驱动,基线更新速率受 vd1_task tick 限制。


2026-06-29 — DLD154V4B V2.0~V2.5 M4 优化移植

参考: DLD154V4B 单路 M4 优化版算法,移植到 vd960Loop 四路并联

1. 时序加速: vTaskDelay 50ms → 10ms

主循环 tick 从 50ms 提升到 10ms(加速 5×)。TMR15 ISR 保持 5msTM1cnt 10 分频得到 50ms 中断,Hold_CNT/OUTCNT/INCNT 仍以 50ms 为单位。

影响:

  • 检测响应更快:进入确认 3×10ms=30ms 即可判定
  • 冻结超时 1000×10ms=10s
  • WINDOW_ORIGIN=500 → 基线跟踪窗口 500×10ms=5s(等效原 100×50ms

2. 斜率限幅 (Slope Limiter)

MAX_SLOPE_RATE = 5%   // 单次 IIR 输入变化不超过 CAPVD 的 5%

IIR 之前先对 loop_Value 做斜率限幅:与当前 loop_CAPVD 比较,变化幅度限制在 ±5% 以内(下限 100),防止突发电磁干扰污染 IIR 状态。

3. 进入确认 (Entry Confirm)

ENTRY_CONFIRM = 3   // 连续 3 次低于阈值才判定有车

替代原来的单次触发:loop_CAPVD < (Origin - dlt_ORG) 计数 loop_entry_cnt++,达到 3 次才置 loop_VD_FLAG=1。中途高于阈值则清零,消除偶发毛刺导致的误触发。

4. 基线冻结超时 (Freeze Timeout)

FREEZE_TIMEOUT        = 1000   // 10s @10ms/tick
FREEZE_STABILITY_RATE = 2      // 稳定性窗口 ±2%

有车期间基线被冻结(ORG_CNT/ORG_SUM 清零不更新),但新增超时机制:

  • 冻结时记录参考值 loop_freeze_ref
  • 若 CAPVD 波动超过 ±2%,重新计时(车还在动)
  • 若 CAPVD 在 ±2% 内稳定超过 10s,强制 Origin = CAPVD(视为长时间停车,基线应更新)
  • 解决长时间停车导致基线永久偏离的问题

5. IIR 简化: 双路 → 单路

初始移植了双路 IIR(慢速 α=18/256 + 快速 α=0.5),经测试发现快速 IIR 引入额外噪声,最终去掉快速 IIR,仅保留慢速:

ALFA_CAP1 = 79    // α = 79/256 ≈ 0.31, @10ms → τ ≈ 32ms

斜率限幅直接对慢速 IIR 输入做限制,简化逻辑且效果一致。

6. 稳定期快速收敛

稳定期 !loop_stable 绕过 IIR + 斜率限幅:

  • 直接用 loop_CAPVD = loop_Valueraw value
  • update_moving_average 窗口改为 100(小窗口快速收敛)
  • 128 样本约 1.28s 完成初始化

稳定后切换回正常 IIR + WINDOW_ORIGIN=500 慢跟踪。

7. 参数修正

参数 旧值 新值 说明
WINDOW_ORIGIN 100 500 基线窗口 5s @10ms
update_moving_average window uint8_t uint16_t 修复 500→256 溢出
loop_entry_cnt uint8_t 新增: 进入确认计数器
loop_freeze_cnt uint16_t 新增: 冻结持续计数
loop_freeze_ref uint32_t 新增: 冻结参考值

2026-07-03 — 时间量上报单位改为 10ms

背景

MISC_TYPE_TIME 上报的通过时间 / 车间距原来以 5ms 为单位(直接 report_counter - 时间戳),与外部协议期望的 10ms 单位不一致。

方案

内部时间戳 report_counter / passtime_start / last_exit_tick 保持 5ms 精度不动,仅在上报 misc_value/2 转为 10ms

// 进场 — 车间距 (10ms)
misc_value = (report_counter - last_exit_tick) / 2;

// 离场 — 通过时间 (10ms)
misc_value = (report_counter - passtime_start) / 2;

影响范围

位置 变更
TaskLoop.c 进场路径 misc_value /2
TaskLoop.c 离场 flatness misc_value /2
TaskLoop.c 离场 cnt_release misc_value /2
TaskLoop.h 注释 标注 /2→10ms

2026-07-03 — 时间量上报单位改为 50ms

背景

上一步 misc_value 以 10ms 为单位(内部 5ms tick /2),但协议期望 50ms。统一为 50ms 后与 Hold_CNT/OUTCNT/INCNT 一致。

方案

  1. report_counter 移入 50ms tick 块:原来在 5ms ISR 外层 ++,现移到 if (TM1cnt >= 10) 内部,每次加 1 = 50ms
  2. 去掉 /2misc_value = report_counter - timestamp(直接减,无除法)
  3. 上报间隔宏同步REPORT_IDLE_TICKS 120→12REPORT_EVENT_TICKS 30→3

影响范围

文件 变更
TaskLoop.c ISR report_counter++ 从 5ms 外层移入 50ms 块
TaskLoop.c 进场/离场 去掉 /2,注释 10ms→50ms
TaskLoop.h REPORT_*_TICKS /10,注释 5ms→50ms
main.c 间隔注释更新

2026-07-03 — ARMCC 编译修复 + 时间戳/上报完善 (V2.8~V3.1)

1. ARMCC 编译错误修复 (V2.8)

  • #991: g_loop_states 初始化去多余嵌套大括号 {{0}, {{{0}}}}{0}
  • #177-D: 删除未引用变量 _counter1_init
  • #188-D: 7处 at32_led_*() 调用加 (led_type) 强转

2. 车间距时间补齐 (V2.9)

Loop154_Unit 新增 last_exit_tick 字段:

  • 进场: misc_value = misc_counter - last_exit_tick(车间距,首车=0
  • 离场: 记录 last_exit_tick = misc_countermisc_value = misc_counter - passtime_start(通过时间)
  • 四通道独立计算,50ms tick 单位

3. report_counter 清零导致下溢修复 (V3.0)

根因: report_counter 被 UART 上报清零后,last_exit_tick/passtime_start 存旧值,再次进场时差值下溢 → 0xFFFFFFF7

修复: 新增 misc_counter 独立自由运行计数器(50ms,永不归零),所有时间戳操作改用 misc_counter

Loop154_States:
  report_counter  → 上报间隔调度 (会清零)
  misc_counter    → 时间戳 (永不清零)

report_counter 只负责上报调度,misc_counter 负责时间量计算,互不干扰。

4. 上电 3 秒抑制上报 (V3.1)

uart_report_packet_loop_acs 开头新增检查:misc_counter < 603s @50ms)时跳过上报并清零 report_counter,等线圈基线稳定后再开始主动上报。


修订记录

版本 时间 说明
V3.1 2026-07-03 上电3秒抑制主动上报
V3.0 2026-07-03 misc_counter 自由运行替代 report_counter 做时间戳
V2.9 2026-07-03 补齐车间距时间 (gap time)
V2.8 2026-07-03 ARMCC 编译修复 (多余大括号/未引用变量/枚举混用)
V2.7 2026-07-03 report_counter 改 50ms tick,时间量单位 10ms→50ms
V2.6 2026-07-03 misc_value 时间量单位 5ms→10ms
V2.5 2026-06-29 稳定期窗口 100 快速收敛
V2.4 2026-06-29 去掉快速 IIRALFA_CAP1=79 @10ms
V2.3 2026-06-29 基线冻结超时 + 稳定性检查
V2.2 2026-06-29 进入确认 ENTRY_CONFIRM=3
V2.1 2026-06-29 斜率限幅 MAX_SLOPE_RATE=5%
V2.0 2026-06-29 vTaskDelay 50→10ms, 双路 IIR 移植
V1.3 2026-06-26 vTaskDelay 10→50ms 对齐原始设计
V1.2 2026-06-26 hold_time/relay_delay 可配置,有限存在完整重启
V1.1 2026-06-26 频率上报 CAPVD→实际频率转换