Files
DLD154V4B/docs/devlog.md
T
wangfq dd14e083fa feat(V4B): V4.26 调试打印 — DBG 周期行加 L 粗估(coil_l_uH, Xn精确) + coil_fault EVT 同步
DBG|t=2000ms f=16kHz L=1445uH Xn=3681 LPCNT=35 ...
- L_uH = Xn^2/(142×C), 默认低频档 C=66nF; 拨码 33nF 档结果×2
- 例: Xn=3681(f=16.3k)→1445uH; Xn=685(87.6k)→50uH; Xn=485(123.9k)→36uH? 边界自测
2026-09-03 11:31:03 +08:00

1140 lines
52 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-03 — 线圈电感量告警 + 故障补偿提速(固件 V4.26)
> **固件版本:V4.26**cmcng.hFIRMWARE_VER="4.26" + MAIN=4/SUB=26)。devlog 修订 V2.24。
### 背景
DLD154V4 线圈振荡两级频率(33/66nF 拨码,拨码不引 IO)。现场抓到 f=16.3kHz(Xn=3681) 超范围
线圈(L≈1.44mH@66nF),检测异常难排查 → 要求对不合理电感量自动告警。
另:环境重校准(V4.24/25)补偿总时长 ~66s 偏长 → 拍板提速。
### 拍板规格(2026-09-03
1. 按默认低频档计算,频率合理范围 **20 ~ 120 kHz**,出界即判定电感量不合理 → 告警(不做档位判定/灰带)
2. 告警形式:黄灯**一长一短**(长亮200ms/灭100ms/短亮100ms/灭800ms 循环)
3. 黄灯优先级:线圈断开快闪 > 故障补偿(学习补偿)常亮 > 电感量不合理一长一短 > 线圈断开 N 短亮 > 灭
4. 故障补偿黄灯常亮(等待学习)时间 **60s → 10s**ENV_RESYNC_WAIT 6000→1000
### 改动
- TaskLoop.c:新增 coil_monitor()(稳定+无车空闲由无车主路径调用;Origin 反推空场 f;
f<20kHz→L偏大 / f>120kHz→L偏小,1s 防抖置位/清除;EVT|coil_fault/coil_ok
- poll_yellow_led():新增模式5(一长一短 40/20/20/160 tick);优先级 1>4>5>3>2
- ENV_RESYNC_WAIT 6000→10005s 预判 → 10s 学习 → ~16s 替换 → 空闲 5s 确认灭,总 ~21s)
- TaskLoop.hCOIL_F_OK_MIN_KHZ=20 / COIL_F_OK_MAX_KHZ=120 / COIL_DEF_C_NF=66
- 行尾修复:V4.24~25 编辑期间源文件行尾被写成多 CR(\r\r\r\r\n),本次统一规范化回标准 CRLF
- DBG 周期打印(2s)增加 **L 粗估字段**coil_l_uH(): Xn 精确反推,默认 66nF 档;拨 33nF 档结果 ×2):
`DBG|t=2000ms f=16kHz L=1445uH Xn=3681 ...`EVT|coil_fault 同步改用 Xn 算法(精度优于 f 整数反推)
### 验证
- tests/test_coil_range.c 5 场景:L偏大/偏小 1s 防抖置位、恢复 1s 防抖清除、边界 19/20/120/121、抖动不误报 ALL PASS
- tests/test_env_resync.cENV_RESYNC_WAIT=1000):永久变化 applied_at=1600tick、瞬态<10s 不学、
锁存保持、打断重算、放弃不污染 ALL PASS
- gcc -fsyntax-only 0 error
### 待现场验证
- 超范围线圈(如 f=16.3kHz)应黄灯一长一短;正常 100~300µH 线圈(f 20~120k 内)不误报
- 故障补偿总时长 ~21s;环境高位 10s 即学(铁块静止 >10s 会被学入,黄灯常亮提示请勿移动目标)
- 电感告警阈值边界用标定线圈(100µH/300µH)实测微调
## 2026-09-02 — 环境异常黄灯预判:5s 常亮提示将进入重学(固件 V4.25)
> **固件版本:V4.25**cmcng.hFIRMWARE_VER="4.25" + MAIN=4/SUB=25)。devlog 修订 V2.23。
### 背景
V4.24 环境重校准的黄灯常亮只在**进入学习后**(dev>+4dlt 高位累计满 60s)才点亮,
前 60s 操作员无任何可视反馈,不知道检测器是否已感知环境变化。
### 改动
- 黄灯模式4 条件(poll_yellow_led):`g_env_resync || g_env_warn`
- 新增 `ENV_WARN_WAIT = 500 tick~5 s` + `ENV_RECOVER_WAIT = 500 tick~5 s`TaskLoop.h 文件级宏)
- **预判锁存状态机(g_env_warn**
- 高位(dev>+4dlt)连续 **5 s**`g_env_warn=1`,黄灯**预判常亮**(提示"环境已重大变化")
- **锁存**:回摆/目标靠近(wait 清零)**不灭灯**——只有环境回到正常空闲(dev 未进进入线)**连续 5 s**(恢复确认)才解除、黄灯灭
- 累计满 **60 s** 才真正进入重校准学习(学习期间黄灯保持常亮,学完替换 Origin 后仍需恢复确认 5 s 才灭)
- 高位重现 → 恢复确认计时清零,黄灯继续常亮
- 预判 ≠ 学习:短时瞬态(60 s 内回摆)只亮黄灯、不触发学习
### 验证
- tests/test_env_resync.c 扩展:预判点亮时刻 = 500 tick;回摆后黄灯**保持常亮**;稳定 5 s 后解除;高位重现再锁存;打断/放弃后锁存保持
- 5 场景 ALL PASSgcc `-fsyntax-only` 0 error
### 待现场验证
A 拿走场景:约 5 s 黄灯常亮(此后回摆也不灭)→ ~60 s 自动重学 → 替换完成 → 环境稳定再 5 s 黄灯灭、检测高度恢复。
---
## 2026-09-02 — 环境重校准:现场永久环境变化自动恢复基线(固件 V4.24)
> **固件版本:V4.24**cmcng.hFIRMWARE_VER="4.24" + MAIN=4/SUB=24)。devlog 修订 V2.22。
### 现场现象(V4.22 实测复现,DBG/EVT 串口日志)
线圈旁金属板 A 上电 → 稳定后 Origin 学低;A 拿走 → CAPVD 弹回真空场,
相对 Origin 恒高 dev=+761 cnt0.59% Origin,实测 CAPVD 128096→128856),
被 V4.20 双向保护(36321a1"dev>0 永不更新"永久冻结 → Origin 卡 128095 →
再拿金属板 B 测试需下跌 ~809 cnt(正常 54 cnt)才触发 → 触发高度明显降低、不恢复。
- V4.20(双向保护前,278d470):dev>0 走正常窗口平均 → 数分钟缓慢恢复(现场"等一段时间能恢复")
- V4.22(含双向保护):dev>0 只冻结、永不更新 → 永久不恢复
### 根因
36321a1 为防"铁块靠近污染 Origin → 离开假进入锁死",把 dev>+4×dlt 高位的
"无车环境异常"一律永久冻结。但"铁块靠近(瞬态,秒级回摆)"与"永久环境变化
(基准被学低,如 A 拿走)"数值不可分,仅**时间维度**可分——永久冻结把后者也卡死。
### 修复(V4.24 两段式受控重校准)
| 阶段 | 条件 | 动作 |
|------|------|------|
| ① 冻结等待 | dev>+4×dlt 高位连续 60 sENV_RESYNC_WAIT=6000 tick)未回摆 | 保持双向保护冻结语义(<60 s 瞬态不污染) |
| ② 学习基线 B | 连续空闲窗(ENV_LEARN_WINDOW=200 tick)均值 + settle 判稳(连续 2 窗漂移 ≤0.1%) | **黄灯常亮**指示学习过程 |
| ③ 原子替换 | B 可信且空闲 | Origin=B;清 freeze/ORG/entry 残留;slow snap(同 V4.04);黄灯恢复 |
- 学习期任何打断(CAPVD 回窗、dev<0 目标靠近、线圈断开重连)→ 重算重来
- 学习预算 ENV_LEARN_MAX_TICKS=300030 s)超时放弃,保留旧 Origin——宁可灵敏度低不冒险污染
- 替换瞬间 B≈当前空闲 CAPVD → dev≈0 无跳变,不会误触发继电器
- 黄灯优先级:断开快闪 > 学习常亮 > N 短闪(断开史)> 灭
### 验证
- `tests/test_env_resync.c`(新增):5 场景 ALL PASS
1. 永久变化(常量高位)→ 6600 tick~66 s)自动替换 Origin 128095→128856
2. 瞬态高位 60 s 内回摆 → 不学习不替换
3. 学习期打断 → abort 重算 → 最终恢复
4. 学习期窗口不稳 → 30 s 预算放弃,Origin 不被污染
5. 替换后 dev≈0 → 无重复学习不震荡
- gcc `-fsyntax-only` TaskLoop.c 0 error
### 权衡(待现场验证)
- 铁块静止 60 s+ 也会被学入 → 靠等待时长 + 黄灯常亮提示(操作员看到黄灯别移走目标)
- 恢复总时长 ≈66 s(V4.20 分钟级),A 拿走场景现场复测确认手感
- ENV_RESYNC_WAIT / ENV_LEARN_MAX_TICKS 为编译期宏,现场可调
---
## 2026-09-02 — 红灯呼吸对齐 vd960Loop + 上电自检基准判稳(固件 V4.23)
> **固件版本:V4.23**cmcng.hFIRMWARE_VER="4.23" + MAIN=4/SUB=23)。devlog 修订 V2.21。
### 现场反馈(用户测试 DLD154V4)
1. **红灯呼吸太快** → 借鉴 vd960Loop 红灯呼吸效果
2. **绿灯上电自检闪烁未体现完整自检逻辑** → 应等获得稳定基准值后才停止闪烁
### 修复 1:红灯呼吸节奏对齐 vd960Loopmain.c `poll_red_pwm`
| 项 | 修复前 (V4.22) | 修复后 (V4.23) |
|----|---------------|---------------|
| PWM 满量程 | TMR14 ARR=665 | 不变 |
| 大步长 | +100 (≈15% 量程) | **+39 (≈5.9%)** |
| 近顶小步 | +20 (≈3%) | **+10 (≈1.5%)** |
| 分界点 | 500/600 (75%/90%) | **585 (88%)** |
| 峰值保持 | 3 步 | 3 步 |
| 全周期 | **≈1.6s** | **≈2.6s(与 vd960Loop 观感一致)** |
- vd960Loop 参考参数:满量程 6800,升 <6000 大步 +400 / 近顶 +100,降 -40060ms/步
- V4B 按 `665/6800≈0.0978` 缩放取整:39/10/585/660
- 实测仿真:周期 42 步 × 60ms = 2520ms,峰值保持 ≥3 步,写值全程 ≤ ARR
### 修复 2:绿灯自检闪烁至基准值稳定(TaskLoop.c 稳定期判稳)
**根因**:原逻辑 `_stable_cnt` 达 128 样本(≈1.3s)即 `g_loop_stable=1`,与"基准值是否真稳定"无关;且 static 计数不清零 → 安全复位等二次稳定期 1 个样本即判稳(绿灯自检形同虚设)。
**修复**
- 新增 `g_stable_cnt`(累计样本)/ `g_settle_cnt`(连续窗口漂移达标计数),全局变量 `INIT_VD()` 清零、判稳退出时清零
- 每窗(100 样本≈1s)完成时比较窗口平均 Origin 漂移:≤ Origin×0.1% → settle+1,否则清零
- 判稳条件 = 最少样本 128 + 连续 2 窗漂移达标;**硬兜底 500 样本(5s)** 强制结束自检,防环境长期不稳绿灯无限闪
- 绿灯 `poll_green_led()` 条件不变(`INI_LOOP || !power_up || !g_loop_stable`),自检闪烁自然持续到基准值稳定
- 安全复位二次稳定期从零开始(原 1 样本瞬间判稳 bug 消除)
### 验证
- `tests/test_power_on_stable.c`:常量值判稳样本 200 / 首窗尖峰 300 / 持续漂移 500(兜底) / 二次稳定期 200 —— 4 项 PASS
- `tests/test_red_breath.c`:周期 2520ms / 峰值保持 ≥3 步 / 写值 ≤ARR —— PASS
- `gcc -fsyntax-only`(借 vd960Loop AT32F421 库头):main.c / TaskLoop.c 语法通过
**待现场验证**:呼吸周期观感、上电绿灯自检时长(预计无车 2~3s、首窗尖峰 3s、异常漂移至 5s 兜底)
---
## 2026-09-02 — DEBUG 改编译器 -DDEBUG 控制 + 版本号 V4.22
> **固件版本:V4.22**cmcng.hFIRMWARE_VER="4.22" + MAIN=4/SUB=22)。devlog 修订 V2.20。
- cmcng.h 删除 `DEBUG_ENABLE` 宏块——DEBUG 改由编译器预处理器设置(Keil C/C++ 预定义符号加 `DEBUG`
- 调试打印仍为 `#ifdef DEBUG` → PRINT 生效;发布版编译不带 DEBUG 即自动关闭
- 附带 V4.20 修复:DBG 行 t 恒 0 bug(先取时间再归零)、freeze_ref 残留清零(FRZ 打印干净)
- 负 variation 锁死修复(双向对称基线保护)在 V4.20 已生效,现场日志已验证:三次铁块测试 Origin 稳定、0 次锁死
---
## 2026-09-02 — 负variation铁块场景修复:基线跟踪双向对称保护(固件 V4.20)
> **固件版本:V4.20**。devlog 修订 V2.19。
### 现场现象(用户)
特殊形状铁块(磁导率主导)靠近线圈 → variation 为**负**(频率下降,CAPVD 高于 Origin):
- 靠近过程无输出(正常——检测只认正 variation,物理限制)
- 铁块慢慢离开时:有时一直无输出,有时**一旦输出就释放不了**(锁定)
### 根因(TaskLoop.c 基线跟踪单边保护)
```c
// 修复前: 只挡 dev > +4×dlt —— 负variation(CAPVD>Origin) 时基线照常更新
if (dev < (int32_t)(loop1_dlt_ORG * 4)) {
update_moving_average(..., &loop1_Origin, loop1_CAPVD, ...); // Origin 被污染
}
```
污染链:铁块靠近 → CAPVD 升 Origin+500 → 基线跟踪"无车"照常更新(或 FREEZE_TIMEOUT=10s 后直接跳污染值)→ Origin 抬高 → 铁块离开 CAPVD 回落 → 跨过**抬高的进入线** → 假进入 → Origin 冻结(有车)→ 释放线 = 污染 Origin - dlt(高)→ CAPVD 永远够不到 → **锁死不释放**
### 修复(双向对称保护)
1. **偏差窗口对称**`-4×dlt ≤ dev ≤ +4×dlt` 才正常跟踪(负偏差也冻结)
2. **负偏差(dev>0, CAPVD>Origin)只冻结、永不超时更新 Origin**——铁块停留多久都不污染
3. **正偏差(dev<0, 疑似车)保留原 FREEZE_TIMEOUT 兜底**(车辆长时间信号不丢)
4. 权衡:长时间负温漂基线不跟随(安全方向,正车检测仍正常)
5. 新增 `EVT|neg_var_freeze` 事件打印:负偏差首中时输出 CAPVD/Origin/dev/dlt/频率
### 验证
- `tests/test_neg_variation.c` 回归单测 6 项全过:决策方向 / 负偏差超时不污染 / 正偏差兜底保留 / 完整场景仿真(铁块靠近→停留→离开:无假进入、无锁定)✓
- 现有单测(方案A/B)不受影响
---
## 2026-09-02 — Debug 串口打印重组:频率/采样/基准全量输出(固件 V4.20)
> **固件版本:V4.20**。devlog 修订 V2.18。
> **目的**:现场有影响算法的异常情况待分析,扩充调试输出便于定位。
### 打印内容(TTL 调试口,波特率 230400)
**① 周期状态行(每 2s,前缀 `DBG|`**——频率/采样/基准全量:
```
DBG|t=2000ms f=99kHz Xn=600 LPCNT=218 Value=131072 CAPVD=131072 slow=131072 Origin=131072 dlt=32 SENS=3 VD=0 FRZ=0/0 LIM=0 LOOP=1 STBL=1
```
| 字段 | 含义 |
|------|------|
| f | 线圈振荡频率 kHz=60000×LPCNT/CAPVD,无车≈100 |
| Xn / LPCNT | 瞬时周期 / 自适应窗口 |
| Value / CAPVD / slow | 原始采样 / 主滤波 / 慢滤波(方案A) |
| Origin / dlt | 基准值 / 当前阈值(无车=进入线,有车=释放线) |
| SENS / VD | 灵敏度档 / 车辆状态 |
| FRZ | freeze_cnt / freeze_ref(基线冻结状态) |
| LIM | 斜率限幅截断计数(2s 内 EMI/干扰次数,周期清零) |
| LOOP / STBL | 线圈状态 / 稳定期标志 |
**② 事件行(前缀 `EVT|`**
- `enter_try`:进入线第一次命中(定位触发来源)
- `leave_try`:离开线第一次命中(定位释放来源)
- `loop_disconnect` / `loop_reconnect`:线圈断开/重连(带断开计数、断开瞬间 Xn/CAPVD/Origin/频率)
- 原有 `Car_In`/`Car_OFF`/`Loop stable`/`Baseline timeout`/`SENS changed` 保留
**③ 调试开关**cmcng.h):
```c
#define DEBUG_ENABLE 1 // 1=开启(现场分析) 0=关闭(发布)
```
### 辅助实现
- `calc_freq_khz(capvd, lp_cnt)`f_kHz = 60000×LPCNT/CAPVD60MHz 捕获时钟),验证:无车 99kHz / 深车 124kHz ✓
- `g_slope_limit_cnt`:斜率限幅截断计数(IIR 输入被 5% 限幅截断时 +1,周期打印带出后清零)
### 待办
- 现场抓数:串口 230400 收 `DBG|`/`EVT|` 行,异常复现时完整记录(至少覆盖异常前后 30s)
- 分析:重点看 f 是否突变(线圈/干扰)、Origin 是否异常更新(freeze 误触发)、LIM 是否高频(EMI)
---
## 2026-09-01 — 方案B 调校定稿:发布版本号 V4.20
> **固件版本:V4.20**cmcng.hFIRMWARE_VER="4.20" + MAIN=4/SUB=20)。devlog 修订 V2.17。
> **性质:发布定稿版**——内容与 V4.07(方案B 调校)一致,版本号按产品线规划跳到 V4.20。
- 灵敏度表(方案BUSE_PLANB_TABLE=1):进入 `{337,71,38,25}`、释放 `{51,27,18,12}`
- 配置:`USE_SLOW_RELEASE=0`(快滤波释放)+ `USE_PLANB_TABLE=1`(调校表)
- 单测:`test_planb_release.c`(方案B+ `test_release_slow_filter.c`(方案A)均通过
- 历史版本对照:V4.03(方案A α18)→ V4.04(方案A α21+snap)→ V4.05(方案B 实验,加深表失败)→ V4.06(调校表)→ V4.07SENS=0 回调)→ **V4.20(发布)**
---
## 2026-09-01 — 方案B 现场调校定稿:进入加深 + 释放调浅(固件 V4.06)
> **固件版本:V4.07**cmcng.hFIRMWARE_VER="4.07" + MAIN=4/SUB=7)。devlog 修订 V2.16。
> **状态:方案B 定稿候选**——SENS=3 现场实测接近 PD132T,等比推全档。
> **V4.07 微调**SENS=0 进入 357→**337**(等比值偏低档触发过深,现场回调折中)。最终表:进入 `{337,71,38,25}`、释放 `{51,27,18,12}`。
### 现场调校过程(用户金属板测试)
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.24 | 2026-09-03 | V4.26 线圈电感量告警(频率窗 20~120kHz 一长一短)+ 故障补偿 60s→10s;行尾规范化 CRLF |
| V2.23 | 2026-09-02 | V4.25 环境异常黄灯预判(锁存):dev>+4dlt 高位连续 5s 触发 g_env_warn 锁存常亮;回摆/目标靠近保持,环境空闲稳定 5s(ENV_RECOVER_WAIT)才解除;60s 才真正学习 |
| V2.20 | 2026-09-02 | V4.22 DEBUG 改编译器 -DDEBUG 控制(cmcng.h DEBUG_ENABLE 删除) |
| V2.19 | 2026-09-02 | V4.20 负variation铁块锁死修复:基线跟踪双向对称保护(±4×dlt 对称窗口) |
| V2.18 | 2026-09-02 | V4.20 Debug 串口打印重组:频率/采样/基准全量输出(DBG/EVT 前缀) |
| V2.17 | 2026-09-01 | V4.20 方案B 调校定稿发布版本号(内容同 V4.07) |
| V2.16 | 2026-09-01 | V4.06→V4.07 方案B 现场调校定稿:进入加深 + 释放调浅;SENS=0 回调 337 |
| V2.14 | 2026-09-01 | V4.05 方案B 实验:快滤波 + 调深释放阈值表(A/B 现场对比) |
| V2.13 | 2026-09-01 | V4.04 方案A 修正:RELEASE_ALFA 18→21(精确τ117ms+ 进入 snap 消除假释放 |
| V2.12 | 2026-08-31 | V4.03 释放手感对齐方案A:释放慢滤波 USE_SLOW_RELEASE(α18 |
| V2.11 | 2026-08-28 | 灵敏度 0/1 档对齐 PD132T216/108→300/60,Δf/f 0.33%/0.16%→0.46%/0.09%),客户现场替换平滑交付 |
| V2.10 | 2026-08-28 | 新增 IWDT 硬件看门狗(超时≈1.64s,双保险喂狗);修复 WDT_DIV 分频枚举传值 bug(勿传 16,用 WDT_CLK_DIV_16 |
| 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 | 参考分析文档 |