Files
DLD154V4B/docs/devlog.md

10 KiB
Raw Blame History

DLD154V4B 开发日志

MCU: AT32F421F8P7 (Cortex-M4, 120MHz) | 线圈通道: 1路 | 调试口: TTL Tx


2026-06-23 — 跳出框框:去掉 >>6 精度浪费

背景

DLD154V4B 的检测算法继承自 M1HSTC12C5202, 2008和 TLD-110P87LPC762, 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.mdM1H + 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 平坦连续确认次数

整数化适配

专利原实现使用 floatHz 频率值DLD154V4B 用 uint32 定点Origin≈131K。 导数计算同样用 int32 整数差分,阈值 /K1、/K2 做整数除法,精度足够。


2026-06-23 — Origin 污染保护 & 宏开关

USE_FLATNESS_EXIT 宏

新增编译开关,一行切换离开判据:

#define USE_FLATNESS_EXIT  1   // 1=平坦性, 0=cnt_release防抖

所有平坦性状态变量和逻辑用 #if USE_FLATNESS_EXIT 包裹。

Origin 基线污染保护

问题:实测发现车辆驶入时 Xn 偶尔先增大再减小。无车状态下 Origin 跟踪上升, 被污染到虚高值。进入检测虽触发,但离开时 Origin 冻在虚高处, |f-f_b| 远超 SensTable_1 阈值 → 绿灯常亮、永远不释放。

根因CAPVD 异常上升期间moving average 持续将虚高值写入 Origin。

修复:在基线跟踪前增加保护条件:

dev = CAPVD - Origin;
if (dev < dlt_ORG × 4)
    update_moving_average(...);  // 安全跟踪
else
    freeze;                      // 冻结 + 重置累计

冻结阈值 = 进入阈值的 4 倍,随灵敏度自动缩放。

场景 CAPVD Origin dev 阈值(×4) 结果
正常无车 127081 127080 +1 276 跟踪 ✓
异常上升 127884 127085 +799 276 冻结 ✓

2026-06-24 — SW4 快速模式 & 接口修正

SW4 行为修正

旧行为SW_4=ON 时 FLAG_OUT 立即跳到 FLAG_PLUSE跳过离开延时FLAG_PLUSE 仍用正常 PULSE_DELAY950ms。语义混乱——名字叫"延时"实际是跳过延时。

新行为SW_4 重定义为快速模式。ON 时 OUT_DELAY 和 PULSE_DELAY 均缩短为 10 tick500msOFF 时维持原值1.9s/950ms

// TaskLoop.h 新增
#define OUT_DELAY_FAST    10    // 500ms
#define PULSE_DELAY_FAST  10    // 500ms

// TaskLoop.c 运行时选择
uint16_t out_delay   = SET_DLY ? OUT_DELAY_FAST   : OUT_DELAY;
uint16_t pulse_delay = SET_DLY ? PULSE_DELAY_FAST : PULSE_DELAY;

适用范围ETC 收费站等需要快速落杆的场景。

接口修正

  • 去除所有 RS485 相关描述:本产品只有 TTL 电平 UART Tx 调试口,无 RS485 通信能力
  • 产品手册端子定义RS485-A/B → Tx TTL 调试输出
  • 技术规格书 §9整节从 RS485 协议改为 TTL Tx 调试接口说明

文档同步

  • 产品手册 + 技术规格书同步更新SW4 描述、端子定义、时序参数表
  • README.md 同步更新

修订记录

版本 时间 说明
V1.6 2026-06-24 SW4 快速模式修正RS485→TTL Tx 接口更正
V1.5 2026-06-23 Origin 污染保护、USE_FLATNESS_EXIT 开关
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 参考分析文档