# DLD154V4B 开发日志 > MCU: AT32F421F8P7 (Cortex-M4, 120MHz) | 线圈通道: 1路 | 通信: RS485 --- ## 2026-06-23 — 跳出框框:去掉 >>6 精度浪费 ### 背景 DLD154V4B 的检测算法继承自 M1H(STC12C5202, 2008)和 TLD-110(P87LPC762, 2003),但有几个关键硬件差异: | 特性 | M1H / TLD-110 | DLD154V4B | |------|--------------|-----------| | 主频 | ~12MHz (8051) | 120MHz (Cortex-M4) | | 分频芯片 | CD4060 (Pin5, ÷32) | **无**,直连 PA7 | | MCU 内分频 | 无 | TIM3 DIV_4 → **DIV_2** | | 有效分频比 | ÷32 | ÷2 | | 捕获方式 | PCA 周期捕获 / 门控计数 | TIM3_CH2 硬件输入捕获 | ### 问题:<<6 和 >>6 的精度浪费 原始代码的数据流存在一个"膨胀再压缩"的精度陷阱: ``` TMR3 ISR: Xn = 周期差值 (4800 ticks @ DIV_4) LPCNT = (32768 << 6) / Xn = 437 ← 窗口开大 64×,降噪 Value = Σ 437次 Xn ≈ 2,097,600 ← 437 样本精密累加 vd1_task: tmp = Value >> 6 = 32,775 ← 6bit 精度全部丢弃! CAPVD = IIR(tmp...) ← IIR 只看到 ~6 样本有效信息 ``` `<<6` 和 `>>6` 在数学上互相抵消——437 个样本累加,然后右移 6 位,等效仅用 ~7 个样本(437/64 ≈ 6.8)。窗口开大降噪了,但精度被自己扔掉了。 ### 方案:去掉 <<6/>>6,用 MEASUREMENT_BASE ``` TMR3 ISR: LPCNT = 131072 / Xn = 27~54 ← 自适应窗口,不丢精度 Value = Σ Xn ≈ 131072 ← 直接作为检测输入 vd1_task: CAPVD = IIR(Value) ← 全精度参与滤波 ``` | 参数 | 旧方案 | 新方案 | |------|--------|--------| | LPCNT (100kHz, DIV_2) | — | **54** | | 测量窗口 | 17.5ms (DIV_4) | **~1ms** | | 有效精度/窗口 | ~6 样本 (>>6 后) | **54 样本 (全保留)** | | Origin 范围 | ~32K | **~131K** | | 灵敏度阈值 | 百分比公式,自动按比例缩放 ✓ | 同 ✓ | | 进入响应 | ~50ms | **~3ms** | ### 同步改进 | # | 改动 | 原因 | |---|------|------| | 1 | TIM3 分频 DIV_4 → DIV_2 | 提高采样率,中断率 2× 仍安全 (CPU<3%) | | 2 | MEASUREMENT_BASE = 131072 (2^17) | 平衡精度和 Origin 范围 | | 3 | 去除所有 >>6 | 保留全采样精度 | | 4 | 离开增加 `cnt_release >= 3` 防抖 | 防瞬间噪声导致误落杆 | | 5 | 基线冻结 + 100 窗口慢跟踪 | 仿 TLD-110,有车不更新基线 | ### 为什么不需要 CD4060 外部分频 AT32F421 的 TIM3 有内置输入分频器,配合 120MHz 主频: | 线圈频率 | DIV_2 中断率 | CPU 占用 (50周期/ISR) | |---------|------------|----------------------| | 100 kHz | 50k/s | 2.1% | | 150 kHz | 75k/s | 3.1% | | 200 kHz | 100k/s | 4.2% | 均在安全范围内,无需外部分频芯片。 ### 对比 M1H/TLD-110 | 指标 | M1H (CD4060÷32) | DLD154V4B (新) | |------|----------------|---------------| | 测量间隔 | ~50ms (固定) | **~1ms (自适应)** | | 进入防抖 | 500ms IN_DELAY | 500ms IN_DELAY | | 离开防抖 | 1.9s OUT_DELAY | **3次连续确认** + 1.9s OUT_DELAY | | 基线跟踪 | 100次 (有车也跟) | 100次 (有车冻结) | --- ## 2026-06-23 — 精简重构,对齐参考实现 - 删除二阶差分滤波(计算但从未参与判决) - 删除 FltHistoryManager 死代码(20+ 未用字段) - 删除 StageRangeConfig(区间约束未引用) - 删除动态窗口切换(LOOP_WINDOW_SIZE_LOW→FAST) - 时序状态机简化:去掉 PLUSE_IN_F/PLUSE_IN 中间层 - 拨码去抖 10→5(对齐 M1H) - 代码量:1177→706 行(-40%) --- ## 2026-06-22 — 参考分析 见 [reference_analysis.md](reference_analysis.md):M1H + TLD-110 完整算法分析。 --- ## 2026-06-23 — 指示灯行为规范化 ### LED 硬件对应 | 硬件 | 引脚 | 宏 | 行为 | |------|------|-----|------| | 红灯 | PB1 | *(无宏, TMR14 PWM)* | 始终呼吸,不干预 | | 绿灯 (LEDA) | PA9 | `LEDA_ON`/`LEDA_OFF` | 自检慢闪 / 有车亮 / 无车灭 | | 黄灯 (LEDC) | PA10 | `LED_YELLOW_ON`/`OFF` | 故障快闪 / 断开次数编码 | > 注: `LEDA` 宏在 BSP 遗留代码中指向 PB1(红灯),已修正为 PA9(绿灯)。`LEDB` 宏无实际 IO,已删除。 ### 绿灯行为 | 状态 | 绿灯 | |------|------| | 上电自检 (Origin 未确立) | 慢闪 200ms | | 数值稳定期 (128 样本 ≈ 128ms) | 慢闪 200ms | | 正常工作,无车 | 灭 | | 正常工作,有车 | 亮 | | 线圈断开中 | **灭**(黄灯快闪负责故障指示) | ### 黄灯行为 | 条件 | 黄灯 | |------|------| | 上电后从未接线圈 | 快闪 200ms | | 线圈当前断开中 | 快闪 200ms | | 重连后,断开过 1 次 | 1 短闪 (80ms 亮) + 1.2s 间隔 | | 重连后,断开过 2 次 | 2 短闪 + 1.2s 间隔 | | 重连后,断开过 3+ 次 | 3 短闪 + 1.2s 间隔 | | 正常,无断开记录 | 灭 | > "不接线圈上电,上电后再接线圈"不计入断开次数。 --- ## 2026-06-23 — 上电稳定期 & 线圈重连 ### 上电稳定期 Origin 首次确立后,线圈振荡需要时间稳定。新增 `g_loop_stable` 标志: - `INIT_VD()` → `g_loop_stable = 0` - `vd1_task()`: 稳定期内只做 IIR + 基线跟踪,**跳过进入检测** - 128 样本 (~128ms) 后 `g_loop_stable = 1`,正式启用检测 - 安全复位时重置 `g_loop_stable = 0` ### 线圈重连状态保持 断开时**不丢 VD_FLAG**,重连后**快速收敛 IIR**: ``` 断开: 保留 loop1_VD_FLAG,仅关断继电器 重连: loop1_CAPVD = 0 → 首个样本直锁 Value → IIR 后续正常跟踪 ``` | 断开前 | 断开期间 | 重连后 | 检测结果 | |--------|---------|--------|---------| | 有车 | 车还在,绿灯灭 | 车还在 | CAPVD < Origin-dlt → VD_FLAG=1 → 绿灯亮 | | 有车 | 车离开 | 车离开 | CAPVD ≈ Origin → cnt_release→3 → VD_FLAG=0 | | 无车 | 车进入 | 车进入 | CAPVD < Origin-dlt → VD_FLAG=1 → 绿灯亮 | --- ## 2026-06-23 — 移植平坦性离开判定(CN200910309382) ### 来源 专利 CN200910309382(中山大学,张辉/黄永强/陈古典)提出**平坦性三条件判定法**, 解决大车通行时频率曲线的负波峰和近零波谷导致单一阈值法多次误触发的问题。 ### 算法 ``` 车辆到达 → 单一阈值法 f(i) - f_b > Δ1 (沿用 SensTable) 车辆离开 → 平坦性三条件 同时满足: ① |f - f_b| < Δ1 频率回归基频 (SensTable_1) ② |f'| < Δ2 一阶导数近零 ③ |f''| < Δ3 二阶导数近零 ``` **Phase 1** (g_exit_state=0): 车辆进入线圈后,追踪第一上升坡面, 记录最大 |f'| 和 |f''|。当斜率连续 3 次降到 `SLOPE_FLAT_THRESH` 以下, 计算动态阈值: ``` Δ2 = max_slope / K1 (K1=8) Δ3 = max_slope_rate / K2 (K2=8) ``` **Phase 2** (g_exit_state=1): 每帧检查三条件。连续 3 次全部满足 → 车辆离开。 ### 与传统方法对比 | 方法 | 离开判据 | 大车防误检 | |------|---------|-----------| | M1H/TLD-110 | 单一滞回阈值 | ❌ 多峰可能多次触发 | | 原 cnt_release | 连续 3 次超阈值 | ⚠️ 固定阈值,大车波谷可能误判 | | **平坦性判定** | |f-f_b|+一阶+二阶 三条件 | ✅ 动态阈值,跟随坡面特征 | ### 参数说明 | 常量 | 值 | 含义 | |------|-----|------| | K1, K2 | 8 | 动态阈值除数(专利推荐值) | | SLOPE_FLAT_THRESH | 100 | 斜率趋零判断阈值 | | MIN_DELTA2 | 5 | Δ2 下限(防除数过小) | | MIN_DELTA3 | 2 | Δ3 下限 | | FLAT_CONFIRM_CNT | 3 | 平坦连续确认次数 | ### 整数化适配 专利原实现使用 float(Hz 频率值),DLD154V4B 用 uint32 定点(Origin≈131K)。 导数计算同样用 int32 整数差分,阈值 /K1、/K2 做整数除法,精度足够。 --- ## 修订记录 | 版本 | 时间 | 说明 | |------|------|------| | V1.4 | 2026-06-23 | 移植 CN200910309382 平坦性离开判定 | | V1.3 | 2026-06-23 | 指示灯行为、稳定期、重连状态保持 | | V1.2 | 2026-06-23 | <<6/>>6 精度浪费分析与改进 | | V1.1 | 2026-06-23 | 精简重构,对齐 M1H/TLD-110 | | V1.0 | 2026-06-22 | 参考分析文档 |