Files
DLD154V4B/docs/devlog.md
T
wangfq 778664067e feat(V4B): 方案B现场调校定稿 V4.06 — 进入加深+释放调浅双表, 全档等比
现场实测: SENS=3 进入21→25 + 释放14→12 接近PD132T最高灵敏手感(用户调校)
- 关键认知: 释放方向是CAPVD向Origin恢复, 释放线调浅(dlt小)→更晚释放
  (V4.05加深方向失败已记录, 现场实测确认调小有效)
- 全档等比: 进入×25/21 {300,60,32,21}→{357,71,38,25}
          释放×12/14 {60,32,21,14}→{51,27,18,12}
- 滞回 66%→47%, 触发更严+释放更晚, 行为等效PD132T(表值不再一致)
- 废弃 ReleaseTable_B 独立表(方向错误, 并入 SensTable_1 调校)

单测: test_planb_release.c 更新(滞回正/表值/调浅释放≥原始4档×4速/释放时刻) ✓
      test_release_slow_filter.c(方案A)仍通过
文档: devlog V2.15 + technical-spec §4.3.3 V4.06段
⚠ SENS=0 进入300→357变化大, 现场低档漏检可单独回调
2026-09-01 14:38:52 +08:00

857 lines
36 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# DLD154V4B 开发日志
> MCU: AT32F421F8P7 (Cortex-M4, 120MHz) | 线圈通道: 1路 | 调试口: TTL Tx
---
## 2026-09-01 — 方案B 现场调校定稿:进入加深 + 释放调浅(固件 V4.06)
> **固件版本:V4.06**cmcng.hFIRMWARE_VER="4.06" + MAIN=4/SUB=6)。devlog 修订 V2.15。
> **状态:方案B 定稿候选**——SENS=3 现场实测接近 PD132T,等比推全档。
### 现场调校过程(用户金属板测试)
1. V4.05 加深表 {80,42,27,18}:释放比 PD132T 更早 → 加深方向失败
2. V4.05 原始表 {60,32,21,14}:也早于 PD132T → 快滤波+原始表不够
3. **用户改 SENS=3:进入 21→25、释放 14→12 → 接近 PD132T 最高灵敏手感**
- 关键:**进入加深(触发更严)+ 释放调浅(释放更晚)** 组合有效
- 滞回 66%→47%(释放线更接近进入线,释放更严格)
### V4.06 灵敏度表(等比 ×25/21 进入、×12/14 释放)
| SENS | 进入原表 | 进入新表 | 释放原表 | 释放新表 | 滞回 |
|------|---------|---------|---------|---------|------|
| 0 | 300 | **357** | 60 | **51** | 14% |
| 1 | 60 | **71** | 32 | **27** | 38% |
| 2 | 32 | **38** | 21 | **18** | 47% |
| 3 | 21 | **25** | 14 | **12** | 48% |
- 物理含义:进入加深(误触发更少)+ 释放调浅(释放更晚,等效 PD132T 手感)
- ⚠ 与 PD132T 表值不再一致(行为等效);SENS=0 进入 300→357 变化大,现场低档漏检可单独回调
- 代码:`USE_PLANB_TABLE=1` 时双表生效(TaskLoop.c),`=0` 切回原始 PD132T 对齐表
- 废弃:V4.05 的 `ReleaseTable_B` 独立表已删除(方向错误,并入 SensTable_1 调校)
### 单测
- `tests/test_planb_release.c` 更新:滞回正 ✓ / V4.06 表值 ✓ / 调浅释放≥原始(4档×4速)✓ / 释放时刻 ✓
- `tests/test_release_slow_filter.c`(方案A)仍通过
### 待现场
- 全档实测(尤其 SENS=0 进入 357 是否漏检大车)
- HR0/2 定住 1~2s:预期稳定(快滤波无悬停状态)
- 方案AV4.04)对比数据补测
---
## 2026-09-01 — 方案B 实验:快滤波释放 + 调深释放阈值表(固件 V4.05)
> **固件版本:V4.05**cmcng.hFIRMWARE_VER="4.05" + MAIN=4/SUB=5)。devlog 修订 V2.14。
> **状态:实验对比版**——与 V4.04(方案A)现场 A/B 对比后定稿,二选一保留。
### 背景
V4.04(方案A:慢滤波释放 α21 + 进入 snap)已修两现象,但现场想对比另一条路线:不用慢滤波状态(消除任何滤波悬停风险),改由**释放阈值表**承担手感对齐。
### 方案B 配置(TaskLoop.h
| 宏 | 值 | 含义 |
|----|----|------|
| `USE_SLOW_RELEASE` | **0** | 释放走快滤波(α79@10ms, τ≈22ms),无慢滤波状态 |
| `USE_PLANB_TABLE` | **1** | 释放判定用 `ReleaseTable_B`(调深表) |
| `ReleaseTable_B` | `{80, 42, 27, 18}` | 原始表 `{60,32,21,14}` 加深 ~30% |
各档滞回验证:ReleaseTable_B < SensTable(进入表)→ 滞回为正,无结构假释放。
### ⚠ 关键认知:加深方向的物理含义(仿真+单测双重确认)
释放方向是 CAPVD 从车辆深度**向 Origin 恢复**(从深往浅)。释放线 = Origin − dlt
- **dlt 增大(调深)→ 释放线降低 → CAPVD 恢复中更早碰到 → 释放更早**(与"调深=更严格"的直觉相反)
- 单测 `tests/test_planb_release.c`:4 档 × 4 速度全部确认"加深表释放 ≤ 原始表"(如 SENS=3, 3s 抬:原始@2960ms → 加深@2930ms
### 仿真预测(现场实测验证点)
| 板信号深度 | 加深表 vs PD132T | 结论 |
|-----------|------------------|------|
| ≥0.2%200cnt+ | 加深表比 PD132T 早(差 3~6 counts | 深信号下原始表 `{60,32,21,14}` 更接近 PD132T |
| ~0.1%100cnt | 加深表与 PD132T 差 ~1.3 counts | 浅信号下加深表更接近 |
**现场验证**:若实测"加深表释放比 V4.04 更早(板抬更低就释放)",说明方向如仿真;若与 PD132T 手感更近,则加深表定稿;否则 `USE_PLANB_TABLE=0` 一行切回原始表对比。
### 单测
- `tests/test_planb_release.c` 新增(gcc 编译通过):滞回为正 ✓ / 加深表释放不晚于原始表 ✓ / 释放时刻合理 ✓
- `tests/test_release_slow_filter.c`(方案A 单测)仍通过,两方案可回归
### 现场实测结果(2026-09-01 用户金属板测试)
| 配置 | 释放高度 vs PD132T | 结论 |
|------|-------------------|------|
| V4.05 + USE_PLANB_TABLE=1(加深 {80,42,27,18} | **更低于 PD132T(更早)** | 加深方向被实测否定,与仿真预测一致 |
| V4.05 + USE_PLANB_TABLE=0(原始 {60,32,21,14} | **低于 PD132T(更早)** | 快滤波释放早于 PD132T(历史行为复现) |
**实验结论:方案B 不可行。** 根因:PD132T 的"晚释放"来自慢滤波滞后(速度相关),阈值表只能给"速度无关的固定偏移",快滤波(τ≈22ms)无论怎么调阈值(滞回为正前提下)释放都早于 PD132T(τ≈118ms)。仿真方向预测(加深→更早)被现场完全验证。
**路线定稿:回到方案A(慢滤波释放)。** 下一步现场测 **v4.04-planA**(α21 + 进入 snap,用户尚未测过该完整修正版)。
### 文档同步
- technical-spec §4.3.3 补方案B 实验说明
- analysis/docs/filter-coefficient-79-vs-64.md §4.5 方案B 段(待补)
---
## 2026-09-01 — 方案A 现场复核修正:RELEASE_ALFA 18→21 + 进入 snap(固件 V4.04
> **固件版本:V4.04**cmcng.hFIRMWARE_VER="4.04" + MAIN=4/SUB=4)。devlog 修订 V2.13。
### 背景(现场复核)
方案A(V4.03)落地后金属板复测,两个现象:
1. **慢速抬板释放高度 V4B 仍比 PD132T 高一点**,且跟手速有关(抬得越慢越接近)
2. **定在 HR0/2(释放高度一半)保持 ~1s,V4B 释放继电器,PD132T 不释放**
### 根因分析
| 现象 | 根因 | 证据 |
|------|------|------|
| 1 释放偏高 | τ 对齐用了近似口径:方案A α18 精确 τ≈137msPD132T α79@43.7ms 精确 τ≈118ms(α=79 时 `T×256/α` 近似公式高估 19.6%+ V4B 释放 3 次确认 30ms | 仿真:2s 抬升 V4B +14mm、8s 抬升 +2mm,与现场"跟手速有关"吻合 |
| 2 HR0/2 假释放 | 双滤波结构(快进+慢出):进入由快滤波(τ≈22ms)30ms 确认,释放判定用慢滤波——进入确认瞬间慢滤波还悬在基线附近,残余信号落在窄带(SENS=3 时 0.032%~0.044%)时释放条件瞬时为真 → 3 次确认数满 → 假释放。PD132T 进出共用同一滤波,进入确认时滤波值已沉过离开线,结构性免疫 | 仿真:0.10% 板 HR0/2 放置 V4B 释放@0.18sPD132T 不释放 |
### 修正(V4.04
1. **RELEASE_ALFA 18 → 21**:精确 τ = T/ln(1−α) = 10/ln(121/256) ≈ **117ms**,对齐 PD132T α79@43.7ms 精确 τ≈118ms。仿真释放高度差 3s 抬升 +9mm → **+3mm**(剩余为 3 次确认 30ms 固有延迟)
2. **进入确认 snap**`loop1_CAPVD_slow = loop1_CAPVD`(进入线档3 0.032% 恒深于离开线 0.021%,snap 后释放条件结构性为假)→ HR0/2 假释放窗口彻底消除
### 验证
- `tests/test_release_slow_filter.c` 更新 ALFA_SLOW=21:τ fast=30ms/slow=120ms(理论 22/117ms);释放时机差 200ms ✓
- 仿真(Origin=100000, SENS=3):α21+snap 下 0.10% 板 HR0/2 放置,原版释放@0.18s → 未释放 ✓
- ⚠ 待板级:真机金属板复测确认释放高度对齐 + HR0/2 保持不再释放
### 文档同步
- technical-spec §4.3.3 补 V4.04 修正说明
- analysis/docs/filter-coefficient-79-vs-64.md §4.4 方案A 同步 α21 + snap
- release-notes 待发布时更新
---
## 2026-08-31 — 释放手感对齐 PD132T:释放慢滤波(方案 A,固件 V4.03)
> **固件版本:V4.03**cmcng.hFIRMWARE_VER="4.03" + MAIN=4/SUB=3;⚠ 顺带修正字符串 "4.00" 与数字 4/2 不一致的历史问题)。devlog 修订 V2.12。
### 背景(现场测试)
PD132T 替换交付后金属板测试(从上往下接近触发、从下往上离开释放):**触发高度两边一致,释放高度不一致**——V4B 刚离开触发位置一点点就释放,PD132T 要离得更远才释放。
### 根因分析
| 项 | V4B | PD132T |
|----|-----|--------|
| 检测节拍 | 10ms | 43.7ms |
| IIR 系数 | ALFA_CAP1=79 | 79(SET_FLT=ON)/64(OFF) |
| τ | ≈32ms | ≈142~175ms |
| 释放确认 | 3×10ms | 单次 |
- 判定公式与阈值表**完全一致**`(Origin-dlt_ORG) < CAPVD`,表 {60,32,21,14} 已对齐)
- 差异在 **CAPVD 恢复速度**V4B 快 4.4~5.5× → 刚离开即恢复过浅阈值 → 早释放
- 释放阈值浅(进入的 20%)放大差异;触发阈值深 + 接近过程信号斜率大 → 触发高度差不明显
### 方案 A 实现(USE_SLOW_RELEASE
- 新增独立慢滤波 `loop1_CAPVD_slow`(α=18/256 @10ms → τ≈142ms,复刻 PD132T 恢复速度),吃原始 Value(不经斜率限幅)
- 离开判定改用慢滤波值,进入路径不变
- 开关 `USE_SLOW_RELEASE`TaskLoop.h 默认 1,0=原快滤波释放,现场可对比回退)
- 同步:INIT_VD 复位、稳定期直锁、线圈重连强制收敛
- ⚠ 若现场 PD132T SET_FLT=ON(α64 → τ≈175ms),调 `RELEASE_ALFA` 15(τ≈170ms)更贴近
### 验证
- `tests/test_release_slow_filter.c`gcc 单测):τ fast=30ms/slow=140ms(理论 32/142ms);模拟金属板离开(信号每 10ms +80),释放时机 fast=150ms/slow=410ms**差 260ms** ✓
- 括号结构三版本(原始/改动/回退)计数一致,无结构影响
- ⚠ 待板级:真机金属板测试确认释放高度对齐;MRS 编译
### 文档同步
- technical-spec §4.3.3 模式 1 补 V4.03 慢滤波说明
- release-notes 待发布时更新
---
## 2026-08-28 — 灵敏度进入/离开对齐 PD132TV2.11
### 背景
客户现场在用 PD132T8051),替换 DLD154V4B(同款芯片平台 AT32F421 的单路产品)。交付要求:**平滑——灵敏度表现一致、触发/释放手感无感**。
对照 PD132T 源码(`SensTable {300,60,32,21}` / `SensTable1 {60,32,21,14}`,阈值 `Origin×表>>16`;**离开阈值受 SET_ASB 拨码控制**,出厂默认 OFF → 恒 14):
进入表对比:
| 档 | PD132T Δf/f | V4B 原 Δf/f | 差异 |
|----|------------|------------|------|
| 0 | 0.458% | 0.330% | V4B 灵敏 1.39× |
| 1 | 0.092% | 0.165% | V4B 钝 1.79× |
| 2 | 0.049% | 0.055% | 几乎一致 |
| 3 | 0.032% | 0.031% | 几乎一致 |
离开表对比(PD132T **SENUP 标贴 OFF** → 电平1 → SET_ASB=1 → 分档 {60,32,21,14} = 出厂默认态):
| 档 | PD132T 离开 | V4B 原离开 | 差异 |
|----|------------|------------|------|
| 0 | 0.092%60 | 0.165%108 | V4B 钝 1.8×,释放偏慢 ⚠ |
| 1 | 0.049%32 | 0.110%72 | V4B 钝 2.25× ⚠ |
| 2 | 0.032%21 | 0.027%18 | V4B 灵敏 1.16× |
| 3 | 0.021%14 | 0.021%14 | 一致 |
### 决定
```c
// TaskLoop.c
const uint16_t SensTable[4] = {300, 60, 32, 21}; // V2.11(全档与 PD132T 完全一致)
const uint16_t SensTable_1[4] = { 60, 32, 21, 14}; // V2.11(与 PD132T 完全一致)
```
- **进入表全档与 PD132T 完全一致**216/108/36/20 → 300/60/32/21,Δf/f 0.33%/0.16%/0.055%/0.031% → 0.458%/0.092%/0.049%/0.032%
- **离开表 {108,72,18,14} → {60,32,21,14}**(对齐 PD132T **SENUP 标贴 OFF**=SET_ASB=1 的分档释放,**出厂默认态**;拨码低有效,若现场 SENUP 标贴 ON 需改恒 14 表)
- 等效手感修正:V4B IIR τ=32ms vs 142ms、节拍 10ms vs 43.7ms → 同档位下 V4B 检测更快;3 次进入确认 → 调表后仍比 PD132T 抗瞬态误触
- **增强滤波 FLT 不纳入对齐**:现场少用(2026-08-28 决策),V4B 恒 79 + 斜率限幅组合更优
### 相关交付文档
- 完整交付对齐分析:`vd-analysis/docs/pd132t-to-v4b-delivery-alignment.md`
- 决策记录:脉冲模式不比较(现场少用);有限存在搁置待确认 V4B 是否启用
---
## 2026-08-28 — 新增 IWDT 硬件看门狗(V2.10
### 背景
V4B 是全产品线唯一**无看门狗**的型号(对比:M1H 有 WDT_CONTR、PD132 系有 IWDG/WWDG、154Pro V3.03 有 WWDG 558ms)。现场若主循环卡死/FreeRTOS 调度异常,表现为"假活"——指示灯正常但检测逻辑已死,只能断电恢复。
### 实现(对齐 154Pro V3.03 双保险模式)
```c
// main(): wdt_init() — IWDT 分频16 + 重装载4095, 使能后立即喂一次
// TMR15 ISR: g_wdg_counter++ (5ms)
// 主循环: poll_wdg() — 计数达 100 (500ms) 才 wdt_counter_reload()
```
- **超时** ≈ 1.64sLSI≈40kHz16×4096/40k),喂狗周期 500ms,余量 >3×
- **双保险语义**:ISR 死 → 计数不涨 → 永不喂狗;主循环死 → poll_wdg 不执行 → 超时复位
- FreeRTOS 调度失败/任务创建失败 → 无人喂狗 → 复位(避免"假活"
### 涉及文件
| 文件 | 变更 |
|------|------|
| `src/main.c` | `Timr6_Init()` 后调 `wdt_init()` |
| `src/TaskLoop.c` | +`g_wdg_counter` + `wdt_init()` + `poll_wdg()`;TMR15 ISR 计数;主循环喂狗 |
| `inc/TaskLoop.h` | +WDT 宏 + extern + 函数声明 |
### 验证
- 隔离测试(host gcc mock wdt_* 驱动)5 项断言全过:init 配置、10s 喂狗 20 次(500ms 精确)、ISR 死不喂狗、边界 99/100 tick
- 待现场验证:实际复位时间(LSI 实际频率),用 `RST_REASON` 类机制确认复位源
### ⚠ 现场发现并修复:WDT_DIV 传值 bugV2.10.1
**现象**:现场实测 `WDT_COUNTER_LIMIT=100`(500ms 喂狗)不断复位重启,改为 50(250ms)才正常。
**根因**`wdt_divider_set()` 参数是**枚举值**不是分频数值——`WDT_CLK_DIV_16 = 0x02`,寄存器只取低 3 位。宏误写 `WDT_DIV=16`0b10000)→ 寄存器写入 0 = `WDT_CLK_DIV_4`**实际分频 4,实际超时 410ms < 喂狗周期 500ms** → 每次喂狗前已超时,不断复位。
**修复**`#define WDT_DIV 2`(枚举值)+ 调用处显式 `(wdt_division_type)` 转换;隔离测试升级 mock 为"寄存器 3bit 截断 + 反推实际分频",复现 bug 机制并断言修复后超时 1638ms > 500ms。
**对照教训**vd960Loop 原实现用 `wdt_divider_set(WDT_CLK_DIV_64)` 枚举写法 ✓ 无此问题——**AT32 WDT 分频参数一律用枚举常量,勿传数值**。
---
## 2026-08-28 — 平坦性离开判定默认关闭(现场实测不理想)
### 背景
同一现场(广告杆/道闸)与 V2.8 SENS=3 调档同源。广告杆落杆误触发排查中发现,平坦性三条件离开判定(CN200910309382V1.4 移植)在真实场景**响应不理想**:
- 平坦性依赖"第一上升坡面"动态计算 Δ2/Δ3,车辆离开缓慢/多次驻留时,坡面特征不稳定,Δ2/Δ3 失真
- 三条件(|f-fb|<dlt && |f'|<Δ2 && |f''|<Δ3)对离开过程平坦度要求苛刻,现场车辆(半挂、缓慢通过)离开确认滞后/不触发
- 与简单 cnt_release 防抖对比实测,平坦性未体现出大车防误触优势,反而引入离开延迟
### 决定
```c
// TaskLoop.h
#define USE_FLATNESS_EXIT 0 // V2.9 默认: 简单 cnt_release 防抖
```
- 离开判定切回**滞回 + 连续 3 次确认**(`(Origin-dlt) < CAPVD``cnt_release>=3`),与 DLD154Pro 当前行为一致
- 平坦性代码完整保留在 `#if USE_FLATNESS_EXIT` 内,可一行开启做现场对比
- 全部平坦性状态变量/初始化/进入重置均带 `#if` 包裹,改 0 直接编译剔除,无残留引用
### 同步文档
- `technical-spec.md` §4.3.3:模式 1 标为默认(V2.9 起),模式 2 标"默认禁用(#if 0,代码保留)";修正模式 1 伪代码方向错误(`CAPVD < Origin + dlt``(Origin - dlt) < CAPVD`
- `product-manual.md` / `release-notes.md` / `roadmap.md`:离开判定口径统一为"滞回 + 连续确认(平坦性可选)"
- 版本历史补 V2.7/V2.8(此前 release-notes/product-manual 缺行),本次记 **V2.9**
---
## 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.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 | 平坦连续确认次数 |
### 整数化适配
专利原实现使用 floatHz 频率值),DLD154V4B 用 uint32 定点(Origin≈131K)。
导数计算同样用 int32 整数差分,阈值 /K1、/K2 做整数除法,精度足够。
---
## 2026-06-23 — Origin 污染保护 & 宏开关
### USE_FLATNESS_EXIT 宏
新增编译开关,一行切换离开判据:
```c
#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。
**修复**:在基线跟踪前增加保护条件:
```c
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 — 时序参数修正 & 接口更正
### 时序参数修正
OUT_DELAY 和 PULSE_DELAY 之前沿用 M1H 的值(1.9s / 950ms),现修正为 500ms
| 参数 | M1H 旧值 | DLD154V4B 新值 |
|------|---------|---------------|
| OUT_DELAY | 1.9s (38 tick) | **500ms (10 tick)**SW_4 控制开关 |
| PULSE_DELAY | 950ms (19 tick) | **500ms (10 tick)**,固定 |
SW_4 语义:0 = 无离开延时(立即脉冲),1 = 离开延时 500ms。删除 OUT_DELAY_FAST / PULSE_DELAY_FAST 宏,因只有一组值。
```c
// TaskLoop.h
#define OUT_DELAY 10 // 离开防抖 500ms(仅 SW_4=ON 时生效)
#define PULSE_DELAY 10 // 脉冲宽度 500ms
// TaskLoop.c
if (SET_DLY) {
loop1_OUTCNT++;
if (loop1_OUTCNT > OUT_DELAY) { ... } // 500ms 延时
} else {
// 无离开延时:立即 FLAG_PLUSE
}
```
### 接口修正
- 去除所有 RS485 相关描述:本产品只有 TTL 电平 UART Tx 调试口
- 产品手册端子定义:RS485-A/B → Tx TTL 调试输出
- 技术规格书 §9:整节从 RS485 协议改为 TTL Tx 调试接口说明
## 2026-06-26 — M4 核心优化:双路 IIR + 进入确认 + 斜率限幅
### 背景
DLD154V4B 的 8051 时代设计在 M4 上可以做得更好。8051 的 50ms tick 是 CPU 限制,不是最优选择。
### 三项改进
#### 1. 10ms tick + 双路 IIR
| 滤波器 | α | τ | 用途 |
|--------|---|-----|------|
| CAPVD (慢速) | 18/256 ≈ 0.07 | 135ms | 基线跟踪,等效原 50ms 的 79/256 |
| CAPVD_fast (快速) | 128/256 = 0.5 | 28ms | 进入/离开检测判定 |
tick 提升到 10ms,但通过调整 α 保持与 50ms 设计相同的滤波强度。快速 IIR 用于检测,慢速 IIR 用于基线,两路各司其职。
#### 2. 斜率限幅
EMI/闪电等瞬态干扰会造成 CAPVD 瞬间跳变。物理车辆不可能让线圈频率瞬间改变 >5%:
```c
max_step = CAPVD × 5 / 100; // 5% 限幅
if (|delta| > max_step) delta = clamp(delta, -max_step, max_step);
```
尖峰被截断,真实车辆信号(缓慢的频率漂移)不受影响。
#### 3. 进入确认
原设计:单次 CAPVD < Origin-dlt → 立即 VD_FLAG=1(同 8051
新设计:CAPVD_fast 连续 3 次低于阈值 → 才判定有车
```c
if (CAPVD_fast < Origin - dlt)
entry_cnt++;
if (entry_cnt >= 3) { VD_FLAG = 1; ... }
else
entry_cnt = 0; // 一旦恢复就重置
```
对真实车辆:CAPVD_fast τ=28ms3 次确认 = 30ms,加上 IN_DELAY 500ms = 总响应 ~530ms,比原来的 550ms 还快。
对瞬态干扰:单个尖峰无法连续 3 次 → 被过滤。
### 对比
| 指标 | 8051 原设计 | M4 优化 |
|------|-----------|---------|
| tick 周期 | 50ms | **10ms** |
| IIR τ (检测) | 135ms | **28ms** (5× 快) |
| IIR τ (基线) | 135ms | 135ms (相同) |
| 进入判定 | 单次阈值 | **3 次连续确认** |
| 瞬态抑制 | 无 | **斜率限幅 + 确认** |
| 进入响应 | ~550ms | **~530ms** |
| 误触发风险 | 中 | **低** |
### 兼容性
- 离开检测路径不变(cnt_release 平坦性均已带确认)
- 灵敏度表、IN_DELAY、OUT_DELAY 等参数不变
- 可通过 `ENTRY_CONFIRM` 宏调整确认次数,`MAX_SLOPE_RATE` 调整限幅强度
---
## 2026-06-26 — CAPVD_fast 初始化修复
### 问题
M4 V2.0 引入双路 IIR 后,进入检测使用 `CAPVD_fast`(快速 IIR,α=0.5)。但 `CAPVD_fast` 始终为 0,导致首次进入判定就触发有车。
### 根因
```c
// 原代码(错误):
if (loop1_CAPVD_fast != 0) {
loop1_CAPVD_fast = (loop1_CAPVD_fast + loop1_CAPVD) / 2;
}
```
TMR3 ISR 首次捕获时直接设置 `loop1_CAPVD`(不为 0),`INIT_VD``CAPVD_fast` 初始化为 0。`vd1_task` 进入时 `CAPVD != 0``if (CAPVD_fast != 0)` 永远为 false → `CAPVD_fast` 保持 0 不更新。
### 修复
条件反转:`== 0` 时首次锁定当前 CAPVD 值,之后正常执行快速 IIR。
```c
// 修复后:
if (loop1_CAPVD_fast == 0) {
loop1_CAPVD_fast = loop1_CAPVD; // 首次直接锁定
} else {
loop1_CAPVD_fast = (loop1_CAPVD_fast + loop1_CAPVD) / 2;
}
```
---
## 2026-06-26 — 稳定期绕过 IIR 和斜率限幅
### 问题
上电后很快输出有车状态。日志显示:
```
First_capSum:177406, Origin:177406 ← 首测为瞬态高值
Loop stable, Origin:149755 ← 稳定期后 Origin 仍偏高
Car_In, Value:128654, Origin:149755 ← Origin - Value = 21067 >> dlt=82
```
### 根因
V2.0 引入的 **5% 斜率限幅** 在稳定期内仍然生效。首测 CAPVD=177406 是瞬态高值(~38% 偏高),斜率限幅让 CAPVD 在 128 个采样周期内只能缓慢下降到 149755 — 无法在稳定期内充分收敛。100 窗口滑动平均被前半段的高值污染,导致 Origin 停在 149755,远高于真实值 ~128688。
### 修复
稳定期内不走 IIR 和斜率限幅——**直接用 raw Value** 建立基线:
```c
if (!g_loop_stable) {
/* 稳定期内不做斜率限幅和 IIR — 直接用 Value 快速收敛到真实基线 */
loop1_CAPVD = loop1_Value;
loop1_CAPVD_fast = loop1_Value;
// ... 滑动平均跟踪 ...
return;
}
```
稳定期结束后恢复正常 IIR + 斜率限幅用于检测。
| 场景 | 修复前 | 修复后 |
|------|--------|--------|
| 首测瞬态 | 177406 被限幅缓慢下降 | 直接被 128688 覆盖 |
| Origin 收敛 | 149755 (偏离 +16%) | ~128688 (正确) |
| 稳定期结束 | Origin 偏离 → 误判有车 | Origin 准确 → 正常检测 |
---
## 2026-06-29 — 基线冻结超时自动恢复
### 问题
V1.5 引入的 Origin 污染保护机制在 CAPVD 异常偏高时**永久冻结**基线。如果线圈因环境变化(温度漂移、器件老化、更换线圈)稳定在新的频率值,Origin 永远不会更新 → 绿灯常亮、永久误判有车。
### 方案
在冻结路径上增加**超时自动恢复 + 稳定性验证**:
```c
#define FREEZE_TIMEOUT 3000 // ~30s @ 10ms/tick
#define FREEZE_STABILITY_RATE 2 // 稳定性窗口: 参考值的 ±2%
if (dev >= dlt_ORG × 4) {
if (freeze_cnt == 0)
freeze_ref = CAPVD; // 记录冻结起始值
else if (|CAPVD - freeze_ref| > freeze_ref × 2%)
reset(freeze_cnt, freeze_ref); // 波动过大 → 重新计时
freeze_cnt++;
if (freeze_cnt >= 3000) {
Origin = CAPVD; // 连续30s稳定在±2%窗口内 → 接受
}
}
```
### 行为表格
| 场景 | CAPVD 行为 | 稳定性检查 | 结果 |
|------|-----------|-----------|------|
| 车辆驶入(Xn 先增) | 偏高 2~3s 后下降 | 中途恢复 → `freeze_cnt` 清零 | 正常冻结保护 ✓ |
| 温度漂移 | 缓慢爬升到新值并稳定 | 爬升阶段频繁重置;稳定后连续 10s | Origin 更新 ✓ |
| 更换线圈 | 瞬间跳到新频率 | 稳定后连续 10s | Origin 更新 ✓ |
| 车辆缓慢驶入(CAPVD 持续爬升) | 持续偏高且不断上升 | 每超出 ±2% 就重置 → 永远到不了 10s | **不触发更新** ✓ |
最后一行是关键:如果没有稳定性检查,车辆缓慢驶入时 CAPVD 持续偏高 10s 也会触发 Origin 更新——这是错误的。
---
## 2026-06-29 — 架构简化:单路 IIR ALFA_CAP1=79 + WINDOW_ORIGIN=500
### 背景
双路 IIR(慢速 α=18/256 + 快速 α=0.5)在 ALFA_CAP1=18 时斜率限幅参考 CAPVD 拖累了快速通路,
多次修补后发现:**ALFA_CAP1=79 @10ms 本身就 τ≈32ms,已经足够快**,无需双路复杂度。
### 改动
| 项目 | 改前 | 改后 |
|------|------|------|
| ALFA_CAP1 | 18 (@10ms, τ=135ms) | **79 (@10ms, τ=32ms)** |
| IIR 路数 | 双路(慢+快) | **单路** |
| WINDOW_ORIGIN | 100 (1s) | **500 (5s)** |
| 稳定期窗口 | 500 | **100** |
| `update_moving_average` window | uint8_t | **uint16_t** |
| 快速 IIR 输入 | CAPVD(慢速输出,滞后) | 已删除 |
| 斜率限幅 | 快/慢双参考(CAPVD + CAPVD_fast | **单参考 CAPVD** |
### 保留的 V2 保护机制
- 斜率限幅 (MAX_SLOPE_RATE=5%)
- 进入确认 (ENTRY_CONFIRM=3)
- 基线冻结超时 (10s + ±2% 稳定性检查)
- 稳定期绕过 IIR/限幅 (V2.2)
### 两阶段基线策略
```
稳定期: 100 样本 × 10ms = 1s → 快速收敛,开机即用
正常: 500 样本 × 10ms = 5s → 强噪声抑制,稳定跟踪
```
---
## 2026-06-30 — 项目文档补全
- **验收标准 V1.0**: 环路车辆检测器验收标准文档,涵盖电气特性、检测精度、响应时间、环境适应性
- **发展路线图 V1.0**: M1H→V4B 演进回顾 + V3.0 目标规划
---
## 2026-08-27 — 灵敏度最高档调整:SENS=3 阈值 10→20(防误触发)
### 改动
| 文件 | 内容 |
|------|------|
| `src/TaskLoop.c` | `SensTable[3]` 10→**20**(Δf/f 0.015%→0.031%,ΔL/L 0.031%→0.061%);`SensTable_1[3]` 9→**14**(滞回 90%→70% |
| `src/main.c` | 注释掉重复定义 `g_input_div = 1`TaskLoop.c:23 已有定义,清理 ODR 重复) |
### 原因(现场)
现场**广告杆/道闸落杆时最高灵敏度档(10/9)易误触发**——落杆机械动作 + 电机电磁扰动使 CAPVD 波动越过 0.015% Δf/f 阈值,误判有车(落杆瞬间继电器误动作)。提高至 20(0.031% Δf/f)并加大滞回(离开 14/进入 20 = 70%),落杆扰动不再越线,正常车辆信号(轿车典型 ΔL/L 1~5%)不受影响。
### 文档同步
- `docs/technical-spec.md` §4.3.1 灵敏度表 + 表格(含 ΔL/L 口径说明)
- `docs/reference_analysis.md` §5.6 灵敏度表
---
## 修订记录
| 版本 | 时间 | 说明 |
|------|------|------|
| V2.10 | 2026-08-28 | 新增 IWDT 硬件看门狗(超时≈1.64s,双保险喂狗);修复 WDT_DIV 分频枚举传值 bug(勿传 16,用 WDT_CLK_DIV_16 |
| V2.11 | 2026-08-28 | 灵敏度 0/1 档对齐 PD132T216/108→300/60,Δf/f 0.33%/0.16%→0.46%/0.09%),客户现场替换平滑交付 |
| V2.9 | 2026-08-28 | 平坦性离开判定默认关闭(现场实测不理想),切回简单 cnt_release 防抖 |
| V2.8 | 2026-08-27 | 灵敏度最高档 SENS=3 阈值 10→20、离开 9→14(防误触发);清理 g_input_div 重复定义 |
| V2.7 | 2026-06-30 | 验收标准 + 发展路线图文档 |
| V2.6 | 2026-06-29 | 架构简化: 单路 IIR ALFA_CAP1=79, WINDOW_ORIGIN=500, 稳定期100 |
| V2.5 | 2026-06-29 | 冻结超时 30s→10s,加快环境变化响应 |
| V2.4 | 2026-06-29 | 冻结超时增加稳定性检查: ±2% 窗口内连续稳定 |
| V2.3 | 2026-06-29 | 基线冻结超时: 持续偏高后强制更新 Origin,防止死锁 |
|------|------|------|
| V2.2 | 2026-06-26 | 稳定期绕过 IIR/斜率限幅,用 Value 直接收敛基线 |
| V2.1 | 2026-06-26 | CAPVD_fast 初始化修复(条件反转为 ==0 首次锁定) |
| V2.0 | 2026-06-26 | M4 优化: 双路 IIR + 斜率限幅 + 进入确认;tick 10ms |
| V1.7 | 2026-06-26 | vTaskDelay 10→50ms 修正(对齐原始 TMR15 5ms×10 设计);基线更新 1s→5s |
| V1.6 | 2026-06-24 | 时序修正:OUT_DELAY/PULSE_DELAY→500msRS485→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 | 参考分析文档 |