fix(V4B): V4.36.42 — 低Q 临界悬停自激根治 (进/出参考统一 + 释放带夹紧 + 最小保持)
用户反馈: 金属板缓慢接近时判据乱跳; 35µH(128kHz)/46µH(112kHz) 线圈同样现象(46µH 在设计窗内且无告警)。 根因(三段链条, 现场日志与代码逐值吻合): ① 无车态 dlt_ORG=进表 49 ⇒ vac_ref() 门控 1×49; Origin−EMA=32~34 ≯49 ⇒ 参考=Origin ⇒ 进入线=Origin−49 ② 进车瞬间 dlt_ORG 切成释表 23 ⇒ 同一 gap > 1×23 ⇒ vac_ref() 改用 EMA(低 32~34 counts) ③ 释放线 = EMA−1.8×23 ⇒ 比进入线还浅 ⇒ 深度 50~58 的静止凹脉冲"进门即满足释放" ⇒ 进入确认 5 + 释放确认 5 = 10 样本 = 100ms 周期自激(日志实测 ~30 组/3s) 实现: - G1 新增 vac_gate_dlt()(状态无关进表 dlt)供 vac_ref() 门控 (TaskLoop.c:297/307) ⇒ 进/出同一参考 - G2 低Q 释放带夹紧 _band ≤ vac_gate_dlt()-1 (TaskLoop.c:339) ⇒ 只作未来兜底; 180(=41@SENS3, V4.36.28 现场值)一字未动 - G3 REL_MIN_HOLD_TICKS=30 有车后 300ms 禁释放 (TaskLoop.h:69 + TaskLoop.c 调用点) ⇒ 只挡释放不延迟检出 单测: 新增场景 7 现场参数逐位复现 —— 22µH 悬停 300/300 → 1/0; 35µH 300/300 → 1/0; 撤板 1/1; V4.36.28 回摆仍释放; 非低Q 同深度不自激; 全套 8/8 全绿 文档: devlog V2.79(+条目) / spec 文档头 V2.61 / manual 表 V2.18 / cmcng.h 4.36.41→4.36.42 REV 42 待现场: 上板复测 + 锁死侧三线圈实验 (devlog 条目内 [ ] 占位)
This commit is contained in:
@@ -4,6 +4,52 @@
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## 2026-09-11 — 低Q 临界悬停自激根治:进/出判定参考统一 + 释放带夹紧 + 最小保持(固件 V4.36.42)
|
||||||
|
|
||||||
|
用户反馈:拿金属板**缓慢接近**的时候,判据**乱跳**;随后用 **35µH**(128kHz)、**46µH**(112kHz)线圈复测,同样现象。
|
||||||
|
|
||||||
|
**现场实证(三根线圈,两份日志逐位复核)**:
|
||||||
|
| 线圈 | f | 设计窗 | 进表/释表 dlt | 进车瞬间 Origin−EMA | 悬停深度 | 自激 |
|
||||||
|
|---|---|---|---|---|---|---|
|
||||||
|
| 22µH | 163kHz | 出窗(20~24µH 段) | 49 / 23 | 34 | 50 counts | ~100ms × 3.0s |
|
||||||
|
| 35µH | 128kHz | 出窗(超 125k 上限) | 49 / 23 | 32 | 53 counts | ~100ms × 2.8s |
|
||||||
|
| 46µH | 112kHz | **合规(无告警)** | — | — | — | 同 |
|
||||||
|
⇒ 46µH 完全落在设计合理窗内且不触发 coil_fault ⇒ **不是测试线圈特例**;按 f>100kHz 判低Q,暴露段 = **L 37~58µH(f 100~125kHz)**,正是量产主力区间。
|
||||||
|
|
||||||
|
**根因(三段链条,日志与代码逐值吻合)**:
|
||||||
|
1. 无车态:`loop1_dlt_ORG` = 进表值(49) ⇒ `vac_ref()` 门控 = 1×49;`Origin−EMA` = 32~34 ≯ 49 ⇒ 参考 = Origin ⇒ 进入线 = `Origin − 49`
|
||||||
|
2. **进车瞬间**:`loop1_dlt_ORG` 被切成释表值(23) ⇒ 同一 gap 现在 > 1×23 ⇒ **`vac_ref()` 改用 EMA**(低 32~34 counts)
|
||||||
|
3. 释放线 = `EMA − 1.8×23` = EMA−41 ⇒ **比进入线还浅** ⇒ 深度 50~58 的静止凹脉冲"进门即满足释放" ⇒ 进入确认 5 + 释放确认 5 = 10 样本 = **100ms 周期自激**
|
||||||
|
|
||||||
|
**实现**:
|
||||||
|
- **G1(根因)** 新增 `vac_gate_dlt()`(= `Origin×SensTable[Sens]>>16`,**状态无关**)并让 `vac_ref()` 用它做门控 ⇒ 进/出车同一参考;与 band_timeout 既有写法统一(`TaskLoop.c:297 / :307`)
|
||||||
|
- **G2(滞回兜底)** 低Q 释放带夹紧:`if (_band > vac_gate_dlt()) _band = vac_gate_dlt()-1;` ⇒ 只在未来参数变化造成反向滞回时生效;**180(=41@SENS3)一字未动** —— 它是 V4.36.28 现场验证值,缩小它会把"静态带回缺口锁死"改回来
|
||||||
|
- **G3(通用抗抖)** `REL_MIN_HOLD_TICKS=30`:Car_In 后 300ms 内禁释放(覆盖两种 `USE_SLOW_RELEASE` 配置),Car_OFF 清零;**只挡释放、不延迟检出**
|
||||||
|
- 单测 `tests/test_vac_ref_reanchor.c` 扩到 7 场景(新增 6 = 参考抖动;7 = 低Q 自激,含双线圈参数与"非低Q 不跳"判别)
|
||||||
|
|
||||||
|
**单测实测(现场参数逐位)**:
|
||||||
|
| 场景 | 现状 V4.36.41 | 修后(G1+G2+G3) |
|
||||||
|
|---|---|---|
|
||||||
|
| 22µH 悬停(深 50)3s | Car_In **300** / OFF 300 | **1 / 0** |
|
||||||
|
| 35µH 悬停(深 53)3s | **300 / 300** | **1 / 0** |
|
||||||
|
| 撤板 | — | 1 / 1 ✓ |
|
||||||
|
| V4.36.28 回摆(深 36 < 带回 41) | 释放 ✓ | 释放 ✓(未被打破) |
|
||||||
|
| 非低Q(f<100kHz)同深度 | — | **不自激 1/0** ✓ |
|
||||||
|
|
||||||
|
**与 V4.36.41 的关系**:V4.36.41 的 D(EMA 余数累加,消 ±127 counts 死区)把此处的表现从"**锁死**(不释放)"变成"**抖**",方向上更接近真因;本版才修掉结构本身。
|
||||||
|
|
||||||
|
**现场验证(待填)**:
|
||||||
|
- [ ] 上板:慢放/停在边界不再跳、撤板能释放、快车/半截车正常
|
||||||
|
- [ ] 锁死侧:22/35/46µH 板停在"快释放位置"不动 ⇒ 是否长时间不释放(判据:`CAPVD` 回摆是否超过 `Origin−41`)
|
||||||
|
- [ ] 日志片段粘贴区:
|
||||||
|
```
|
||||||
|
(待填:修后 DBG|… Origin / VEM / RLN,确认有车态参考恒为 Origin)
|
||||||
|
```
|
||||||
|
|
||||||
|
语法:待 MRS 编译确认(本机无 AT32 工具链);单测 8/8 全绿(gcc -O0 -Wall -Wextra 0 warning);REV 4.36.42;spec V2.61 / devlog V2.79。
|
||||||
|
|
||||||
|
> 归档:`docs/env-resync-trigger-line-analysis.md` §11/§12(根因与修复实证);补丁 `docs/patches/v4.36.42-G1-G2-G3-lowq-hysteresis.diff`(`v4.36.42-E-ema-oneway.diff` 为备查方案)。
|
||||||
|
|
||||||
## 2026-09-11 — 环境重校准后触发高度变低根治:基准/派生参考同步 + EMA 余数累加(固件 V4.36.41)
|
## 2026-09-11 — 环境重校准后触发高度变低根治:基准/派生参考同步 + EMA 余数累加(固件 V4.36.41)
|
||||||
|
|
||||||
用户反馈:黄灯常亮故障补偿后,金属板进入触发的高度比断电上电后低很多,感觉补偿结束后恢复不了正常灵敏度的触发高度。
|
用户反馈:黄灯常亮故障补偿后,金属板进入触发的高度比断电上电后低很多,感觉补偿结束后恢复不了正常灵敏度的触发高度。
|
||||||
@@ -2189,6 +2235,7 @@ if (dev >= dlt_ORG × 4) {
|
|||||||
|
|
||||||
| 版本 | 时间 | 说明 |
|
| 版本 | 时间 | 说明 |
|
||||||
|------|------|------|
|
|------|------|------|
|
||||||
|
| V2.79 | 2026-09-11 | V4.36.42 低Q 临界悬停自激根治: vac_ref() 门控改用状态无关进表 dlt(G1) + 低Q 释放带夹紧守卫(G2, 不动 180) + 有车 300ms 最小保持(G3); 22µH/35µH 现场自激(100ms 周期)修后 300/300→1/0; 新增"非低Q不跳"判别用例 |
|
||||||
| V2.78 | 2026-09-11 | V4.36.41 环境重校准后触发高度变低根治: 新增 origin_set_atomic() 同步真空 EMA(3 处写入点; 维持 Origin−EMA ≤1×dlt 不变式) + EMA 余数累加消 ±127 counts 整数死区; 新增镜像单测 test_vac_ref_reanchor 5 场景全绿 |
|
| V2.78 | 2026-09-11 | V4.36.41 环境重校准后触发高度变低根治: 新增 origin_set_atomic() 同步真空 EMA(3 处写入点; 维持 Origin−EMA ≤1×dlt 不变式) + EMA 余数累加消 ±127 counts 整数死区; 新增镜像单测 test_vac_ref_reanchor 5 场景全绿 |
|
||||||
| V2.77 | 2026-09-08 | 注释同步: TaskLoop.c/h + tests 全部 疾闪 → 一长两短 (V4.36.38 现役描述, 历史版本行保留变更记录) |
|
| V2.77 | 2026-09-08 | 注释同步: TaskLoop.c/h + tests 全部 疾闪 → 一长两短 (V4.36.38 现役描述, 历史版本行保留变更记录) |
|
||||||
| V2.76 | 2026-09-08 | V4.36.40 热切换修复: fault3 强制期 Origin/LPCNT 冻结 → recover 改 TMR3 实时 Xn 判回窗(240000/Xn); 恢复后 LOOP_OK 回位自动发起重连确认+判稳重建 Origin, 换线圈不断电 ~6s 自愈 |
|
| V2.76 | 2026-09-08 | V4.36.40 热切换修复: fault3 强制期 Origin/LPCNT 冻结 → recover 改 TMR3 实时 Xn 判回窗(240000/Xn); 恢复后 LOOP_OK 回位自动发起重连确认+判稳重建 Origin, 换线圈不断电 ~6s 自愈 |
|
||||||
|
|||||||
@@ -137,6 +137,61 @@ EMA 更新窗 = 无车 + `dev ∈ ±4×dlt`(`1302-1326`)。把板拿到感
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## 11. 现场日志实证(2026-09-11 `154log260911a.txt`):低Q 自激振荡的完整链条
|
||||||
|
|
||||||
|
**现象**:金属板缓慢接近并停在触发边界时,`Car_In`/`Car_OFF` 以 ~100ms 周期连续反复(16:34:50.179–16:34:53.168 约 3s 内 ~30 次)。线圈 22µH / f=163kHz(`EVT|coil_fault below_l_min_20_24u`)⇒ `g_q_lo=1` 低Q 路径。
|
||||||
|
|
||||||
|
**关键实测值**:`Origin=129254`、进表 dlt=49(SensTable 25)、释表 dlt=23(SensTable_1 12)、`EMA≈129220`、`CAPVD/慢滤波≈129204`(深度 50 counts)
|
||||||
|
|
||||||
|
**三步链条(全部可复核)**
|
||||||
|
1. **无车**:`loop1_dlt_ORG`=49 ⇒ `vac_ref()` 门控阈值 = 1×49 = 49;`Origin−EMA`=34 **≯** 49 ⇒ **参考 = Origin** ⇒ 进入线 = 129254−49 = **129205**。CAPVD=129204(差 1 count)+ 5 样本确认 ⇒ `Car_In` ✓
|
||||||
|
2. **进车瞬间**:`loop1_dlt_ORG` 被切成释表值 23(`TaskLoop.c:1577`)⇒ 同一个 gap(34) 现在 **> 1×23** ⇒ **`vac_ref()` 改用 EMA** ⇒ 释放线 = EMA − 1.8×23 = 129220−41 = **129179**(= 日志 `RLN` 字段精确吻合 ✓)
|
||||||
|
3. **释放**:`g_rel_smooth`(129204) > 129179 ⇒ 命中 ⇒ 5 样本确认 ⇒ `Car_OFF` ✓ ⇒ 回到步骤 1 ⇒ **自激**
|
||||||
|
|
||||||
|
**⇒ 滞回带反向重叠**:进入需"深于 **49**",释放只需"浅于 **75**"(= 34 + 41)⇒ 深度落在 **(49, 75)** 的静止凹脉冲**同时满足两条判定** ⇒ 必然振荡。周期 = 进入确认 5 + 释放确认 5 = 10 样本 = **100ms**(与日志完全一致)。
|
||||||
|
|
||||||
|
**与 V4.36.41(A+B/D)的关系**
|
||||||
|
- `vac_ref()` 切到 EMA 的**根因**是「门控阈值用了会随状态切换的 `loop1_dlt_ORG`」+「低Q ×1.8 释放带浅于 ×1.0 进入线」——V4.36.31/33 引入 vac_ref 时就埋下,**与 A+B/D 无关**。
|
||||||
|
- 但 **D(EMA 精确化)是"改变表象"的那一环**:旧版 EMA 有 ±127 死区,此深度下会被粘在 CAPVD 上方 ⇒ gap 为负 ⇒ 参考恒为 Origin ⇒ 释放线 = Origin−41 = 129213 ⇒ 够不着 ⇒ 表现为**锁死**(不释放)而非抖动。⇒ D 把"锁死"变成了"抖",两者都不对。
|
||||||
|
- 另注:本文 §1–§10 的主结论(补偿后触发高度变低)**不受影响** —— 那段日志里 `Origin−VEM ≤ 34 < 1×dlt`,`vac_ref()` 全程取 Origin ✓(先前仿真的"EMA 追赶扫开关"在实机上被"释放后 1s 冻结"抑制,量级被高估)。
|
||||||
|
|
||||||
|
**修复方向(待评审,先出方案不动代码)**
|
||||||
|
|
||||||
|
| 方案 | 内容 | 说明 |
|
||||||
|
|---|---|---|
|
||||||
|
| **G1 根因** | `vac_ref()` 门控阈值改用**固定进入表 dlt**(状态无关) | 参考线不再"进门瞬间跳 34 counts";进/出判定共用同一参考 |
|
||||||
|
| **G2 滞回一致** | 低Q 释放线强制**浅于**进入线:`rel_line ≥ vac_ref − k×dlt_进`(k<1,如 0.5)或夹紧 `rel_line ≥ entry_line + margin` | 消除 (49,75) 重叠带,恢复正向滞回 |
|
||||||
|
| **G3 通用抗抖** | 最小保持时间(进入后/释放后各 N ms 禁止反向) | 对所有 Q 档生效,掐断 100ms 级自激 |
|
||||||
|
| G4 现场 | 22µH/163kHz 落在电感量告警带(20–24µH);确认量产线圈选型 | 非量产线圈也要做 G1–G3(30µH 也可能落进重叠带) |
|
||||||
|
|
||||||
|
## 12. 修复 G1+G2+G3(2026-09-11 采纳并已应用到工作树)
|
||||||
|
|
||||||
|
> 决定:**D 保留 + 上 G1+G2+G3**(E 单向方案留在 `docs/patches/v4.36.42-E-ema-oneway.diff` 备查,未采用)。
|
||||||
|
> ⚠ 关键前提(devlog 救命):`REL_BAND_LO_MULT=180`(=41@SENS3)是 **V4.36.28 现场验证过的值** —— 23µH 板"快释放停住"回摆只到 `Origin−36`,靠 41 才释放;**任何"缩小释放带"的改法都会把那个锁死改回来** ⇒ G2 只做兜底夹紧,绝不动 180。
|
||||||
|
|
||||||
|
| 方案 | 改动 | 位置 |
|
||||||
|
|---|---|---|
|
||||||
|
| **G1 根因** | 新增 `vac_gate_dlt()`(= `Origin×SensTable[SENS]>>16`,**状态无关**)并让 `vac_ref()` 用它做门控 ⇒ 进/出车用同一参考,不再在进门瞬间阶跃;与 `band_timeout` 的既有写法统一 | `TaskLoop.c:297` / `:307` |
|
||||||
|
| **G2 滞回兜底** | 低Q 释放带夹紧:`if (_band > vac_gate_dlt()) _band = vac_gate_dlt()-1;` ⇒ 未来参数变化若造成"反向滞回"自动兜住;今天 41<49 **不生效**(行为零变化) | `TaskLoop.c:341` |
|
||||||
|
| **G3 通用抗抖** | `REL_MIN_HOLD_TICKS=30`(300ms):`Car_In` 后最小保持期内禁释放(`rel_release_hit()` 调用点加门),`Car_OFF` 清零;覆盖两种 `USE_SLOW_RELEASE` 配置。**不延迟检出**(只挡释放) | `TaskLoop.h:68` + `TaskLoop.c:1504/1600/1602/1628` |
|
||||||
|
|
||||||
|
**单测实证**(`tests/test_vac_ref_reanchor.c` 场景 7,现场参数逐位复现 Origin=129254 / dlt 49·23 / EMA≈129220 / CAPVD 深 50):
|
||||||
|
| 版本 | 静止悬停 3s 内 Car_In / OFF |
|
||||||
|
|---|---|
|
||||||
|
| 现状 V4.36.41 | **300 / 300**(100ms 周期自激,与现场日志一致) |
|
||||||
|
| 同上,**35µH/128kHz** 参数(Origin=129141 / EMA 129109 / 深 53,日志 `154log260911b`) | **300 / 300** → 修后 **1 / 0** ✓ |
|
||||||
|
| G1 | 1 / 0 ✓ |
|
||||||
|
| G1+G2 | 1 / 0 ✓ |
|
||||||
|
| G1+G2+G3 | 1 / 0 ✓ |
|
||||||
|
|
||||||
|
回归保护:撤板仍释放(1/1)✓;**V4.36.28 回摆释放(深度 36 < 带回 41)仍成立** ✓;全套 8 个单测全绿 ✓。
|
||||||
|
|
||||||
|
**双线圈差分验证(2026-09-11 两份现场日志)**:22µH/163kHz(深 50、gap 34)与 35µH/128kHz(深 53、gap 32)**同构自激** ⇒ 机理与线圈无关,只取决于
|
||||||
|
① `f>100kHz`(两者都判 QLO=1,而设计窗上限 120~125kHz 对应 L≳37~40µH ⇒ **量产线圈同样落在低Q 档**)② 板停在深度 (49, 41+gap) 的重叠带。
|
||||||
|
⇒ 这不是测试线圈特例;停走排队车辆恰好停在环线边缘时同样会踩到(对流量计数即重复计数)。
|
||||||
|
|
||||||
|
**G3 权衡(现场可选调)**:300ms 最小保持会让**真实车辆离开时的释放**最多晚 300ms(对存在型/流量计数无影响;若做速度估计或需要更快的释放沿,可把 `REL_MIN_HOLD_TICKS` 降到 10=100ms)。
|
||||||
|
|
||||||
## 附:相关历史(devlog)
|
## 附:相关历史(devlog)
|
||||||
|
|
||||||
| 版本 | 内容 |
|
| 版本 | 内容 |
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
diff --git a/utilities/at32f421_freertos_demo/src/TaskLoop.c b/utilities/at32f421_freertos_demo/src/TaskLoop.c
|
||||||
|
index 4d589a9..ec77d25 100644
|
||||||
|
--- a/utilities/at32f421_freertos_demo/src/TaskLoop.c
|
||||||
|
+++ b/utilities/at32f421_freertos_demo/src/TaskLoop.c
|
||||||
|
@@ -1341,10 +1341,16 @@ void vd1_task(void)
|
||||||
|
/* V4.37(D): 余数累加 —— d/128 整数截断有 ±127 counts 死区
|
||||||
|
* (|d|<128 步进=0 ⇒ EMA 常驻真空下方 ~127 counts ⇒ vac_ref 被拉低
|
||||||
|
* ⇒ 进入线偏低 ⇒ 触发高度漂移, 只能断电上电复位; 2026-09-11 单测实测 127) */
|
||||||
|
- g_vac_frac += _ema_d;
|
||||||
|
- { int32_t _st = g_vac_frac / VACUUM_EMA_ALFA;
|
||||||
|
- g_vac_frac -= _st * VACUUM_EMA_ALFA;
|
||||||
|
- g_vacuum_ema += (uint32_t)_st;
|
||||||
|
+ /* V4.36.42(E): EMA 单向 —— 只允许向"真空回升"方向跟随
|
||||||
|
+ * ① 真空真下降由 Origin 块平均承担, vac_ref 取 min 天然选 Origin(EMA 偏高无害)
|
||||||
|
+ * ② 若 EMA 跟随近场金属向下, vac_ref 的"min + 1×dlt" 硬开关会被反复扫过
|
||||||
|
+ * (板缓慢接近/悬停时 进入线跳变 ±150 counts ⇒ 判据乱跳; 2026-09-11 仿真 sweep 实测)
|
||||||
|
+ * 保留 D 的余数累加 ⇒ 向上收敛无 ±127 counts 死区 */
|
||||||
|
+ if (_ema_d > 0) {
|
||||||
|
+ g_vac_frac += _ema_d;
|
||||||
|
+ int32_t _st = g_vac_frac / VACUUM_EMA_ALFA;
|
||||||
|
+ g_vac_frac -= _st * VACUUM_EMA_ALFA;
|
||||||
|
+ g_vacuum_ema += (uint32_t)_st;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (((int32_t)loop1_Origin - (int32_t)g_vacuum_ema) > (int32_t)(loop1_Origin >> 2) ||
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
diff --git a/utilities/at32f421_freertos_demo/inc/TaskLoop.h b/utilities/at32f421_freertos_demo/inc/TaskLoop.h
|
||||||
|
index 35d3d36..f37c3ef 100644
|
||||||
|
--- a/utilities/at32f421_freertos_demo/inc/TaskLoop.h
|
||||||
|
+++ b/utilities/at32f421_freertos_demo/inc/TaskLoop.h
|
||||||
|
@@ -66,6 +66,7 @@
|
||||||
|
#define ENTRY_CONFIRM_MID 4 // 中Q(80~100k)
|
||||||
|
#define ENTRY_CONFIRM_LO 5 // 低Q(f>100k): 抖动大, 多样本防假进入
|
||||||
|
#define REL_ORIGIN_FREEZE_TICKS 100 // V4.36.26/32: 释放后 Origin 全冻结 1000ms — 残余缓离窗口不入均值窗
|
||||||
|
+#define REL_MIN_HOLD_TICKS 30 // V4.36.42(G3): 有车后最小保持 300ms 禁释放 (掐断进/出 100ms 级自激; 不延迟检出)
|
||||||
|
#define ORIGIN_LOWLEARN_TICKS 200 // V4.36.32: 冻结后降权低速补偿期 2000ms: 残余低值样本权重降 ×1/MULT
|
||||||
|
// 仿 PD132T 慢采样等效(10ms 快采样让 5s 窗装得快, 残余易拉低 Origin; 慢学更稳)
|
||||||
|
#define ORIGIN_LOWLEARN_MULT 5 // V4.36.32: 降权期均值窗放大 500→2500 样本(25s 窗), 学习速率 1/5
|
||||||
|
diff --git a/utilities/at32f421_freertos_demo/src/TaskLoop.c b/utilities/at32f421_freertos_demo/src/TaskLoop.c
|
||||||
|
index 4d589a9..c987683 100644
|
||||||
|
--- a/utilities/at32f421_freertos_demo/src/TaskLoop.c
|
||||||
|
+++ b/utilities/at32f421_freertos_demo/src/TaskLoop.c
|
||||||
|
@@ -47,6 +47,7 @@ uint8_t g_q_lo = 0; // V4.36.19: 低Q 档标志 (空场 f>100
|
||||||
|
uint16_t g_origin_freeze_tick = 0; // V4.36.26/32: 释放后 Origin 全冻结计数 (1s)
|
||||||
|
uint16_t g_origin_lowlearn_tick = 0; // V4.36.32: 冻结后降权低速补偿计数 (2s, 残余低值降权学入)
|
||||||
|
uint16_t g_rel_band_cnt = 0; // V4.36.30: 低Q 环带超时兜底计数 (离开触发深度持续 2.5s → 强制释放)
|
||||||
|
+uint16_t g_rel_hold_tick = 0; // V4.36.42(G3): 有车后最小保持计数 (禁释放, 掐断进/出自激)
|
||||||
|
uint32_t g_vacuum_ema = 0; // V4.36.31: 真空 EMA 基线 (B3: 释放/触发参考与锚错 Origin 解耦)
|
||||||
|
static int32_t g_vac_frac = 0; // V4.37(D): EMA 余数累加器 (消 ±127 counts 整数死区)
|
||||||
|
uint16_t g_ready_hold_tick = 0; // V4.36.36: 判稳后就绪巩固期计数 (5ms tick, poll_green_led 递减; 按 Q 档置 5s/7s/10s)
|
||||||
|
@@ -288,12 +289,22 @@ uint32_t get_flt_value_rel(uint32_t new_value, uint32_t last_value)
|
||||||
|
/* V4.36.31: B3 判定参考 — min(Origin, 真空 EMA)
|
||||||
|
* Origin 可能被 env 学习锚到高位(板搁置态/过冲, J1: 130636 vs 真空 130506) → 释放线偏高
|
||||||
|
* → 撤板真空也够不着; 取 min 使参考锚向实时真空(低者=保守方向), 双侧自动正确 */
|
||||||
|
+/* V4.36.42(G1): 真空门控阈值 — 必须"状态无关"
|
||||||
|
+ * 现场 20260911 日志: loop1_dlt_ORG 在进车瞬间被切成释放表值(49→23) ⇒ 同一 EMA 偏差(34)
|
||||||
|
+ * 原本不触发切换、进车后却触发 ⇒ vac_ref() 从 Origin 阶跃到 EMA ⇒ 释放线瞬间浅 34 counts
|
||||||
|
+ * ⇒ 深度 50~58 counts 的静止凹脉冲"进门即满足释放" ⇒ 100ms 周期自激(约 30 次/3s)
|
||||||
|
+ * 修法: 门控一律用进表 dlt(与 :band_timeout 的写法统一) ⇒ 进/出车用同一参考 */
|
||||||
|
+static uint32_t vac_gate_dlt(void)
|
||||||
|
+{
|
||||||
|
+ return ((uint32_t)loop1_Origin * SensTable[loop1_SensLevel]) >> 16;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static uint32_t vac_ref(void)
|
||||||
|
{
|
||||||
|
if (g_vacuum_ema == 0) return loop1_Origin;
|
||||||
|
/* V4.36.33: 仅明显锚错(Origin 高于 EMA > 1×dlt)才重锚 EMA — 边缘金属悬停拉低 EMA 的小偏差忽略 */
|
||||||
|
if ((int32_t)loop1_Origin - (int32_t)g_vacuum_ema >
|
||||||
|
- (int32_t)(loop1_dlt_ORG * VAC_REF_DELTA_DLT))
|
||||||
|
+ (int32_t)(vac_gate_dlt() * VAC_REF_DELTA_DLT))
|
||||||
|
return g_vacuum_ema;
|
||||||
|
return loop1_Origin;
|
||||||
|
}
|
||||||
|
@@ -321,8 +332,14 @@ static uint8_t rel_release_hit(void)
|
||||||
|
uint32_t _line = loop1_Origin - loop1_dlt_ORG;
|
||||||
|
|
||||||
|
if (g_q_lo) {
|
||||||
|
+ /* V4.36.42(G1/G2): 释放线与进入线必须同参考, 且带回不得越过进入阈值(否则反向滞回)
|
||||||
|
+ * G1 已保证同参考; 此处只做"未来参数变化"兜底夹紧 —— 绝不动现场验证过的 180
|
||||||
|
+ * (=41@SENS3: V4.36.28 修静态带回缺口, 23uH 回摆 Origin-36 靠它才释放) */
|
||||||
|
+ uint32_t _band = (loop1_dlt_ORG * REL_BAND_LO_MULT) / 100;
|
||||||
|
+ uint32_t _ent = vac_gate_dlt();
|
||||||
|
_cmp = g_rel_smooth;
|
||||||
|
- _line = vac_ref() - ((loop1_dlt_ORG * REL_BAND_LO_MULT) / 100); /* V4.36.31: 锚真空参考 */
|
||||||
|
+ if (_band > _ent) _band = _ent - 1;
|
||||||
|
+ _line = vac_ref() - _band;
|
||||||
|
}
|
||||||
|
return (_line < _cmp) ? 1 : 0;
|
||||||
|
}
|
||||||
|
@@ -579,6 +596,7 @@ void INIT_VD(void)
|
||||||
|
g_q_lo = 0; /* V4.36.19: 低Q 档标志清零 */
|
||||||
|
g_origin_freeze_tick = 0; /* V4.36.26: 释放冻结计数清零 */
|
||||||
|
g_rel_band_cnt = 0; /* V4.36.30: 环带兜底计数清零 */
|
||||||
|
+ g_rel_hold_tick = 0; /* V4.36.42(G3): 最小保持清零 */
|
||||||
|
g_vacuum_ema = 0; /* V4.36.31: 真空 EMA 清零 (判稳后重建) */
|
||||||
|
g_vac_frac = 0; /* V4.37(D): 余数累加器同步清零 */
|
||||||
|
g_ready_hold_tick = 0; /* V4.36.36: 就绪巩固期清零 (重建判稳时会再置) */
|
||||||
|
@@ -1287,6 +1305,7 @@ void vd1_task(void)
|
||||||
|
g_origin_freeze_tick--;
|
||||||
|
else if (g_origin_lowlearn_tick > 0) /* V4.36.32: 冻结结束 → 降权期开始递减 */
|
||||||
|
g_origin_lowlearn_tick--;
|
||||||
|
+ if (g_rel_hold_tick > 0) g_rel_hold_tick--; /* V4.36.42(G3): 有车最小保持倒计时 */
|
||||||
|
|
||||||
|
/*--- 基线跟踪(仿 TLD-110:有车时冻结)
|
||||||
|
* V4.20 修复: 双向对称保护 — 负偏差(负variation)也冻结基线
|
||||||
|
@@ -1482,6 +1501,7 @@ void vd1_task(void)
|
||||||
|
#endif
|
||||||
|
g_rel_smooth = loop1_CAPVD; /* V4.36.19: 低Q 释放平滑 snap 到进入点 */
|
||||||
|
g_rel_band_cnt = 0; /* V4.36.30: 环带兜底计数进入时清零 */
|
||||||
|
+ g_rel_hold_tick = REL_MIN_HOLD_TICKS; /* V4.36.42(G3): 进入后 300ms 禁释放 */
|
||||||
|
|
||||||
|
if (!SET_SAFE) {
|
||||||
|
loop1_LC_HOLD = 1;
|
||||||
|
@@ -1577,9 +1597,9 @@ void vd1_task(void)
|
||||||
|
loop1_dlt_ORG = ((uint32_t)loop1_Origin * SensTable_1[loop1_SensLevel]) >> 16; // 方案B(V4.06): 调浅释放表已并入 SensTable_1
|
||||||
|
|
||||||
|
#if USE_SLOW_RELEASE
|
||||||
|
- if ((loop1_Origin - loop1_dlt_ORG) < loop1_CAPVD_slow) { // 方案A: 用慢滤波值对齐 PD132T 释放手感
|
||||||
|
+ if (((loop1_Origin - loop1_dlt_ORG) < loop1_CAPVD_slow) && (g_rel_hold_tick == 0)) { // 方案A + V4.36.42(G3) 最小保持
|
||||||
|
#else
|
||||||
|
- if (rel_release_hit()) { // V4.36.19: 低Q 平滑值+带回加宽; 高/中Q 退回原快值逻辑
|
||||||
|
+ if ((g_rel_hold_tick == 0) && rel_release_hit()) { // V4.36.42(G3) 最小保持 + V4.36.19 低Q 平滑/带回加宽
|
||||||
|
#endif
|
||||||
|
if (loop1_cnt_release == 0) {
|
||||||
|
/* 过渡事件: 第一次命中离开线 (定位"为什么开始释放") */
|
||||||
|
@@ -1605,6 +1625,7 @@ void vd1_task(void)
|
||||||
|
loop1_ORG_SUM = 0;
|
||||||
|
Hold_CNT = 0;
|
||||||
|
loop1_cnt_release = 0;
|
||||||
|
+ g_rel_hold_tick = 0; /* V4.36.42(G3): 释放即清保持 */
|
||||||
|
g_origin_freeze_tick = REL_ORIGIN_FREEZE_TICKS; /* V4.36.26: 释放后 Origin 均值窗冻结 */
|
||||||
|
g_origin_lowlearn_tick = ORIGIN_LOWLEARN_TICKS; /* V4.36.32: 冻结后降权期预置 */
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
# DLD154V4B 产品手册
|
# DLD154V4B 产品手册
|
||||||
|
|
||||||
> 单路线圈车辆检测器 | 型号: DLD154V4B | 版本: V2.17
|
> 单路线圈车辆检测器 | 型号: DLD154V4B | 版本: V2.18
|
||||||
> 适用于停车场、收费站、交通卡口等场景的车辆到达/离开检测
|
> 适用于停车场、收费站、交通卡口等场景的车辆到达/离开检测
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -281,6 +281,7 @@ SW_5 = ON 时:车辆(金属)持续压线超过 **4 分钟**(LC_HOLD_TIME
|
|||||||
| V2.14 | 2026-09-08 | 电感分级降级(固件 V4.36.37 方案A):f>156k 拆分——156~171k 可用级(恒判车)、f>171k 短路级快闪200ms(宏=1 等同断开);真短路阈 20µH |
|
| V2.14 | 2026-09-08 | 电感分级降级(固件 V4.36.37 方案A):f>156k 拆分——156~171k 可用级(恒判车)、f>171k 短路级快闪200ms(宏=1 等同断开);真短路阈 20µH |
|
||||||
| V2.15 | 2026-09-08 | 可用级黄灯改**一长两短**(固件 V4.36.38):900/300/100/300/100/700ms 循环,与一长一短(出窗)/快闪(断开)区分 |
|
| V2.15 | 2026-09-08 | 可用级黄灯改**一长两短**(固件 V4.36.38):900/300/100/300/100/700ms 循环,与一长一短(出窗)/快闪(断开)区分 |
|
||||||
| V2.16 | 2026-09-08 | 短路级宏默认=1(固件 V4.36.39,用户拍板):L<20µH 出厂即等同断开;=0 可关恢复仅指示 |
|
| V2.16 | 2026-09-08 | 短路级宏默认=1(固件 V4.36.39,用户拍板):L<20µH 出厂即等同断开;=0 可关恢复仅指示 |
|
||||||
|
| V2.18 | 2026-09-11 | **边界悬停不再反复跳变**(固件 V4.36.42):金属板缓慢接近、或车辆停在环线边缘时,此前会出现"有车/无车"以约 100ms 周期连续反复(流量计数会重复计数);本版进入/离开判定改用同一参考,并增加进入后 300ms 最小保持(离开判别最多晚 300ms) |
|
||||||
| V2.17 | 2026-09-11 | **环境重校准后灵敏度恢复**(固件 V4.36.41):黄灯常亮故障补偿结束后,进入判定参考与基准同步;此前会残留"旧真空参考" ⇒ 金属板进入触发高度偏低、需断电重启才恢复 |
|
| V2.17 | 2026-09-11 | **环境重校准后灵敏度恢复**(固件 V4.36.41):黄灯常亮故障补偿结束后,进入判定参考与基准同步;此前会残留"旧真空参考" ⇒ 金属板进入触发高度偏低、需断电重启才恢复 |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# DLD154V4B 技术规格书
|
# DLD154V4B 技术规格书
|
||||||
|
|
||||||
> 单路线圈车辆检测器 | 固件版本: V4.36.41 | 文档版本: V2.60
|
> 单路线圈车辆检测器 | 固件版本: V4.36.42 | 文档版本: V2.61
|
||||||
> 本文档面向工程开发、系统集成及故障深度分析
|
> 本文档面向工程开发、系统集成及故障深度分析
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -863,4 +863,5 @@ DLD154V4B V1.4 起实现该专利的整数化版本,用于大车通行时的
|
|||||||
| V2.57 | 2026-09-08 | V4.36.39: COIL_UNDER_MIN_AS_OPEN 默认值 0→1 (用户拍板) —— L<20µH 短路级出厂即等同断开(判车停+继电器释放+绿灯灭) |
|
| V2.57 | 2026-09-08 | V4.36.39: COIL_UNDER_MIN_AS_OPEN 默认值 0→1 (用户拍板) —— L<20µH 短路级出厂即等同断开(判车停+继电器释放+绿灯灭) |
|
||||||
| V2.58 | 2026-09-08 | V4.36.40 热切换修复: recover 恢复判定改 TMR3 实时 Xn(240000/Xn) —— 原 calc_freq_khz(冻结Origin,LPCNT) 永不回窗致换线圈死锁; 恢复后自然走重连+判稳重建 Origin |
|
| V2.58 | 2026-09-08 | V4.36.40 热切换修复: recover 恢复判定改 TMR3 实时 Xn(240000/Xn) —— 原 calc_freq_khz(冻结Origin,LPCNT) 永不回窗致换线圈死锁; 恢复后自然走重连+判稳重建 Origin |
|
||||||
| V2.59 | 2026-09-08 | 注释同步: 代码/测试全部 疾闪 → 一长两短 (V2.55~58 历史版本行保留当时变更记录) |
|
| V2.59 | 2026-09-08 | 注释同步: 代码/测试全部 疾闪 → 一长两短 (V2.55~58 历史版本行保留当时变更记录) |
|
||||||
|
| V2.61 | 2026-09-11 | **V4.36.42 低Q 临界悬停自激根治**:`vac_ref()` 门控原先用会随状态切换的 `loop1_dlt_ORG`(无车=进表 49 / 有车=释表 23)⇒ 进门瞬间参考由 Origin 阶跃到 EMA,与低Q ×1.8 释放带叠加成**反向滞回** ⇒ 深度 1.0~1.8×dlt 的静止凹脉冲自激(100ms 周期)。新增 `vac_gate_dlt()`(G1) 统一参考 + 低Q 释放带夹紧(G2) + 有车 300ms 最小保持(G3);22µH/35µH 现场实测 300/300 → 1/0 |
|
||||||
| V2.60 | 2026-09-11 | **V4.36.41 环境重校准后触发高度变低根治**:进入判定用 `vac_ref()=min(Origin,真空EMA)`,环境重校准路径未同步该参考 ⇒ 新增 `origin_set_atomic()`(3 处 Origin 写入点;维持 Origin−EMA ≤1×dlt 不变式)+ EMA 余数累加消 ±127 counts 整数死区;新增镜像单测 test_vac_ref_reanchor(5 场景) |
|
| V2.60 | 2026-09-11 | **V4.36.41 环境重校准后触发高度变低根治**:进入判定用 `vac_ref()=min(Origin,真空EMA)`,环境重校准路径未同步该参考 ⇒ 新增 `origin_set_atomic()`(3 处 Origin 写入点;维持 Origin−EMA ≤1×dlt 不变式)+ EMA 余数累加消 ±127 counts 整数死区;新增镜像单测 test_vac_ref_reanchor(5 场景) |
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ static const uint16_t SensTable[4] = { 337, 71, 38, 25 }; /* SENS3 = 25 */
|
|||||||
#define VAC_REF_DELTA_DLT 1 /* V4.36.33: vac_ref 重锚阈值 (×dlt) */
|
#define VAC_REF_DELTA_DLT 1 /* V4.36.33: vac_ref 重锚阈值 (×dlt) */
|
||||||
#define ORIGIN_JUMP_REANCH_DLT 1 /* V4.36.41 草案: 原子换 Origin 重锚阈值 (×dlt) */
|
#define ORIGIN_JUMP_REANCH_DLT 1 /* V4.36.41 草案: 原子换 Origin 重锚阈值 (×dlt) */
|
||||||
#define VACUUM_EMA_ALFA 128 /* V4.36.31: EMA 平滑因子 (τ≈1.28s@10ms) */
|
#define VACUUM_EMA_ALFA 128 /* V4.36.31: EMA 平滑因子 (τ≈1.28s@10ms) */
|
||||||
|
#define REL_BAND_LO_MULT 180 /* 镜像 TaskLoop.h (V4.36.28 现场验证; G2 只夹紧不改它) */
|
||||||
|
|
||||||
/* ===== 镜像全局 ===== */
|
/* ===== 镜像全局 ===== */
|
||||||
static uint32_t loop1_Origin = 0, loop1_CAPVD = 0, loop1_dlt_ORG = 0;
|
static uint32_t loop1_Origin = 0, loop1_CAPVD = 0, loop1_dlt_ORG = 0;
|
||||||
@@ -104,9 +105,144 @@ static void reset_all(uint32_t origin)
|
|||||||
g_vac_frac = 0;
|
g_vac_frac = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ================= 场景 6: vac_ref 硬开关抖动(缓慢接近/悬停)=================
|
||||||
|
* V4.36.41 现场发现: 板缓慢接近时判据"乱跳"。机理 = EMA 跟随近场金属向下时,
|
||||||
|
* vac_ref 的 "min + 1×dlt" 硬开关被反复扫过 ⇒ 进入线跳变(±40~150 counts) ⇒ 抖动。
|
||||||
|
* mode: 0=旧截断(死区) 1=D余数累加 2=E单向(只上不下); profile: 0=悬停 1=手抖 2=极慢接近
|
||||||
|
*/
|
||||||
|
static int sim_switch_cnt(int mode, int profile)
|
||||||
|
{
|
||||||
|
uint32_t Origin = VAC_ANCHOR, EMA = VAC_ANCHOR, capvd;
|
||||||
|
int32_t frac = 0, d;
|
||||||
|
int i, cnt500 = 0, prev_ref = -1, sw = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < 3000; i++) { /* 30s @10ms */
|
||||||
|
int x;
|
||||||
|
if (profile == 0) x = (i < 400) ? i * 3 / 10 : 120; /* 4s 接近到 x=120 后悬停 */
|
||||||
|
else if (profile == 1) x = ((i % 300) < 150) ? 20 + (i % 300) * 100 / 150 /* 手抖 20~120, 周期 3s */
|
||||||
|
: 120 - ((i % 300) - 150) * 100 / 150;
|
||||||
|
else x = ((i < 1000) ? i * 200 / 1000 : 200) + ((i % 200 < 100) ? 8 : -8);
|
||||||
|
capvd = VAC_ANCHOR - (uint32_t)x;
|
||||||
|
d = (int32_t)capvd - (int32_t)EMA;
|
||||||
|
if (d > 3 * (int32_t)loop1_dlt_ORG) d = 3 * (int32_t)loop1_dlt_ORG;
|
||||||
|
else if (d < -3 * (int32_t)loop1_dlt_ORG) d = -3 * (int32_t)loop1_dlt_ORG;
|
||||||
|
++cnt500; if (cnt500 >= 500) { Origin = capvd; cnt500 = 0; } /* Origin 块平均 5s */
|
||||||
|
if (d != 0) {
|
||||||
|
if (mode == 0) EMA += (uint32_t)(d / 128);
|
||||||
|
else if (mode == 1) { frac += d;
|
||||||
|
int32_t st = frac / 128; frac -= st * 128; EMA += (uint32_t)st; }
|
||||||
|
else if (d > 0) { frac += d; /* E: 只上不下 */
|
||||||
|
int32_t st = frac / 128; frac -= st * 128; EMA += (uint32_t)st; }
|
||||||
|
}
|
||||||
|
{
|
||||||
|
int ref = ((int32_t)Origin - (int32_t)EMA > (int32_t)loop1_dlt_ORG) ? (int)EMA : (int)Origin;
|
||||||
|
if (prev_ref >= 0 && ref != prev_ref) ++sw;
|
||||||
|
prev_ref = ref;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sw;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_chatter(void)
|
||||||
|
{
|
||||||
|
int p, s_old, s_frac, s_one;
|
||||||
|
for (p = 0; p < 3; p++) {
|
||||||
|
s_old = sim_switch_cnt(0, p);
|
||||||
|
s_frac = sim_switch_cnt(1, p);
|
||||||
|
s_one = sim_switch_cnt(2, p);
|
||||||
|
printf(" [抖动] profile%d vac_ref 切换/30s: 旧死区=%d D余数=%d E单向=%d\n", p, s_old, s_frac, s_one);
|
||||||
|
assert(s_one <= 8); /* E: 抖动回到旧水平 */
|
||||||
|
assert(s_frac > s_one); /* D 单独: 显著放大 = 本次现场"乱跳" */
|
||||||
|
}
|
||||||
|
printf("场景 6: vac_ref 抖动 ✓ 通过 (E 单向 ≤8 次/30s; D 余数显著放大, 保持旧死区水平)\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ================= 场景 7: 低Q 临界悬停自激(现场日志 154log260911a 复现)=================
|
||||||
|
* 现场: Origin=129254 进表 dlt=49 释表 dlt=23 TEMA≈129220 CAPVD≈129204(深 50)
|
||||||
|
* 现状(V4.36.41): 进门瞬间 dlt_ORG 切成 23 ⇒ vac_ref() 门控由 49 变 23 ⇒ 同意偏差(34)下参考从
|
||||||
|
* Origin 阶跃到 EMA ⇒ 释放线 EMA-41=129179 比进入线 Origin-49=129205 还浅
|
||||||
|
* ⇒ 深度 50~58 的静止凹脉冲"进门即满足释放" ⇒ 100ms 周期自激
|
||||||
|
* G1: 门控用状态无关进表 dlt; G2: 带回夹紧 ≤ 进表 dlt(不动 180=B4.36.28 的 41); G3: 进入后 300ms 禁释放
|
||||||
|
*/
|
||||||
|
static uint32_t gate_dlt(uint32_t origin, int sens) { return (uint32_t)(((uint64_t)origin * SensTable[sens]) >> 16); }
|
||||||
|
|
||||||
|
static void sim_flap_x(int mode, int n, uint32_t (*capvd_at)(int), uint32_t org, int32_t ema0, int *p_in, int *p_off)
|
||||||
|
{
|
||||||
|
uint32_t Origin = org; int32_t EMA = ema0, frac = 0;
|
||||||
|
uint32_t dlt_ent = gate_dlt(Origin, SENS_LEVEL), dlt_rel = (uint32_t)(((uint64_t)Origin * 12) >> 16);
|
||||||
|
uint8_t vd = 0; int i, cnt_in = 0, cnt_off = 0, ent = 0, rel = 0, hold = 0, freeze = 0;
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
uint32_t capvd = capvd_at(i), ref, d = dlt_ent;
|
||||||
|
if (mode == 0 && vd) d = dlt_rel; /* 现状: 门控用"当前状态"dlt */
|
||||||
|
ref = ((int32_t)Origin - EMA > (int32_t)(d * VAC_REF_DELTA_DLT)) ? (uint32_t)EMA : Origin;
|
||||||
|
if (!vd) {
|
||||||
|
if (capvd < ref - dlt_ent) { if (++ent >= 5) { vd = 1; ent = 0; cnt_in++; hold = (mode >= 3) ? 30 : 0; } }
|
||||||
|
else ent = 0;
|
||||||
|
if (freeze > 0) freeze--; /* 释放后 1s 全冻结(REL_ORIGIN_FREEZE_TICKS) */
|
||||||
|
else if (capvd > Origin - 4*dlt_ent && capvd < Origin + 4*dlt_ent) { /* 对称窗内 EMA 跟踪(D: 余数累加) */
|
||||||
|
int32_t dd = (int32_t)capvd - EMA, lim = (int32_t)(3*dlt_ent);
|
||||||
|
if (dd > lim) dd = lim;
|
||||||
|
if (dd < -lim) dd = -lim;
|
||||||
|
frac += dd; { int32_t st = frac / VACUUM_EMA_ALFA; frac -= st * VACUUM_EMA_ALFA; EMA += st; }
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (hold > 0) { hold--; rel = 0; }
|
||||||
|
else {
|
||||||
|
uint32_t band = (uint32_t)(((uint64_t)dlt_rel * REL_BAND_LO_MULT) / 100); /* 41 */
|
||||||
|
if (mode >= 2 && band > dlt_ent) band = dlt_ent - 1; /* G2 兜底夹紧 */
|
||||||
|
/* mode 4 = 非低Q(QLO=0): 释放线 = Origin − dlt_rel, 不经 vac_ref ⇒ 结构上无重叠 */
|
||||||
|
uint32_t line = (mode == 4) ? (Origin - dlt_rel) : (ref - band);
|
||||||
|
if (line < capvd) { if (++rel >= 5) { vd = 0; rel = 0; cnt_off++; freeze = 100; } }
|
||||||
|
else rel = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*p_in = cnt_in; *p_off = cnt_off;
|
||||||
|
}
|
||||||
|
static void sim_flap(int mode, int n, uint32_t (*capvd_at)(int), int *p_in, int *p_off)
|
||||||
|
{ sim_flap_x(mode, n, capvd_at, 129254, 129220, p_in, p_off); } /* 22µH/163kHz 现场参数 */
|
||||||
|
static uint32_t tl_hold(int i) { (void)i; return 129204; } /* 静止悬停 深 50 */
|
||||||
|
static uint32_t tl_rebound(int i){ return i < 50 ? 129194 : 129218; } /* 深 60 → 回摆到 Origin-36 */
|
||||||
|
static uint32_t tl_leave(int i) { return i < 50 ? 129194 : 129254; } /* 深 60 → 撤板 */
|
||||||
|
static uint32_t tl_hold35(int i) { (void)i; return 129088; } /* 35µH/128kHz: Origin 129141 深 53 */
|
||||||
|
static uint32_t tl_leave35(int i){ return i < 50 ? 129070 : 129141; } /* 35µH 撤板 */
|
||||||
|
|
||||||
|
static void test_lowq_limit_cycle(void)
|
||||||
|
{
|
||||||
|
int i, ci, co, ci22 = 0, ci35 = 0;
|
||||||
|
printf("\n--- 场景 7: 低Q 临界悬停自激(现场参数逐位复现)---\n");
|
||||||
|
struct { int mode; const char *name; } M[4] = {
|
||||||
|
{0, "现状 V4.36.41"}, {1, "G1"}, {2, "G1+G2"}, {3, "G1+G2+G3"} };
|
||||||
|
printf(" 静止悬停(深 50) 3s: ");
|
||||||
|
for (i = 0; i < 4; i++) { sim_flap(M[i].mode, 3000, tl_hold, &ci, &co);
|
||||||
|
printf("[%s: Car_In %d / OFF %d] ", M[i].name, ci, co); }
|
||||||
|
printf("\n");
|
||||||
|
sim_flap(0, 3000, tl_hold, &ci, &co);
|
||||||
|
assert(ci >= 10); /* 现状必然自激(现场日志 ~30 次/3s) */
|
||||||
|
sim_flap(3, 3000, tl_hold, &ci, &co);
|
||||||
|
assert(ci == 1 && co == 0); /* 修后: 进入一次, 悬停期间不释放 */
|
||||||
|
sim_flap(3, 3000, tl_leave, &ci, &co);
|
||||||
|
assert(ci == 1 && co == 1); /* 撤板仍能释放 */
|
||||||
|
sim_flap(2, 3000, tl_rebound, &ci, &co);
|
||||||
|
assert(co >= 1); /* V4.36.28 回摆释放(VACVD Origin-36)不被打破 */
|
||||||
|
sim_flap(0, 3000, tl_hold, &ci, &co); { ci22 = ci; }
|
||||||
|
printf(" 35µH/128kHz 悬停(深 53) 3s: ");
|
||||||
|
sim_flap_x(0, 3000, tl_hold35, 129141, 129109, &ci, &co); printf("[现状: In %d / OFF %d] ", ci, co);
|
||||||
|
sim_flap_x(3, 3000, tl_hold35, 129141, 129109, &ci, &co); printf("[G1+G2+G3: In %d / OFF %d]\n", ci, co);
|
||||||
|
sim_flap_x(0, 3000, tl_hold35, 129141, 129109, &ci, &co); assert(ci >= 10); /* 35µH 同样自激 */
|
||||||
|
ci35 = ci;
|
||||||
|
sim_flap_x(3, 3000, tl_hold35, 129141, 129109, &ci, &co); assert(ci == 1 && co == 0);
|
||||||
|
sim_flap_x(3, 3000, tl_leave35, 129141, 129109, &ci, &co); assert(ci == 1 && co == 1);
|
||||||
|
printf(" 现状自激: 22µH Car_In=%d 次/3s, 35µH Car_In=%d 次/3s (≥10 OK, 现场日志同为 ~100ms 周期)\n", ci22, ci35);
|
||||||
|
sim_flap_x(4, 3000, tl_hold, 129254, 129220, &ci, &co);
|
||||||
|
assert(ci == 1 && co == 0); /* 判别预测: 非低Q(f<100kHz) 结构上不自激 */
|
||||||
|
printf(" 判别预测 OK: 非低Q(f<100kHz) 同深度悬停不自激(1/0) ⇒ 现场换 L≳68µH 应完全不跳\n");
|
||||||
|
printf(" 修后: 悬停 1/0 OK | 撤板 1/1 OK | V4.36.28 回摆仍释放 OK\n");
|
||||||
|
}
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
printf("test_vac_ref_reanchor (V4.36.41 草案: A+B 同步 + D 死区)\n");
|
printf("test_vac_ref_reanchor (V4.36.42: A+B 同步 / D 死区 / E 单向 / G1+G2+G3 低Q自激)\n");
|
||||||
|
|
||||||
/* ================= 场景 1: 复现 + 补丁效果 ================= */
|
/* ================= 场景 1: 复现 + 补丁效果 ================= */
|
||||||
reset_all(VAC_ANCHOR);
|
reset_all(VAC_ANCHOR);
|
||||||
@@ -200,6 +336,12 @@ int main(void)
|
|||||||
}
|
}
|
||||||
printf("5. 死区实测 OK(现状 127 counts 常驻偏差 → 修复 D 归零)\n");
|
printf("5. 死区实测 OK(现状 127 counts 常驻偏差 → 修复 D 归零)\n");
|
||||||
|
|
||||||
printf("ALL PASS (A+B 同步 / 护栏 / 门控回归 / 上电语义 / 死区)\n");
|
/* ================= 场景 6: vac_ref 硬开关抖动 ================= */
|
||||||
|
test_chatter();
|
||||||
|
|
||||||
|
/* ================= 场景 7: 低Q 临界悬停自激 ================= */
|
||||||
|
test_lowq_limit_cycle();
|
||||||
|
|
||||||
|
printf("ALL PASS (A+B 同步 / 护栏 / 门控回归 / 上电语义 / 死区 / 抖动 / 低Q自激)\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,6 +66,7 @@
|
|||||||
#define ENTRY_CONFIRM_MID 4 // 中Q(80~100k)
|
#define ENTRY_CONFIRM_MID 4 // 中Q(80~100k)
|
||||||
#define ENTRY_CONFIRM_LO 5 // 低Q(f>100k): 抖动大, 多样本防假进入
|
#define ENTRY_CONFIRM_LO 5 // 低Q(f>100k): 抖动大, 多样本防假进入
|
||||||
#define REL_ORIGIN_FREEZE_TICKS 100 // V4.36.26/32: 释放后 Origin 全冻结 1000ms — 残余缓离窗口不入均值窗
|
#define REL_ORIGIN_FREEZE_TICKS 100 // V4.36.26/32: 释放后 Origin 全冻结 1000ms — 残余缓离窗口不入均值窗
|
||||||
|
#define REL_MIN_HOLD_TICKS 30 // V4.36.42(G3): 有车后最小保持 300ms 禁释放 (掐断进/出 100ms 级自激; 不延迟检出)
|
||||||
#define ORIGIN_LOWLEARN_TICKS 200 // V4.36.32: 冻结后降权低速补偿期 2000ms: 残余低值样本权重降 ×1/MULT
|
#define ORIGIN_LOWLEARN_TICKS 200 // V4.36.32: 冻结后降权低速补偿期 2000ms: 残余低值样本权重降 ×1/MULT
|
||||||
// 仿 PD132T 慢采样等效(10ms 快采样让 5s 窗装得快, 残余易拉低 Origin; 慢学更稳)
|
// 仿 PD132T 慢采样等效(10ms 快采样让 5s 窗装得快, 残余易拉低 Origin; 慢学更稳)
|
||||||
#define ORIGIN_LOWLEARN_MULT 5 // V4.36.32: 降权期均值窗放大 500→2500 样本(25s 窗), 学习速率 1/5
|
#define ORIGIN_LOWLEARN_MULT 5 // V4.36.32: 降权期均值窗放大 500→2500 样本(25s 窗), 学习速率 1/5
|
||||||
|
|||||||
@@ -14,11 +14,11 @@
|
|||||||
#define __CMCNG_H__
|
#define __CMCNG_H__
|
||||||
|
|
||||||
#define PRODUCT_MODEL "DLD154"
|
#define PRODUCT_MODEL "DLD154"
|
||||||
#define FIRMWARE_VER "4.36.41" // 主.子.修订 (2026-09-03 起: 小改动只增 REV; MAIN/SUB 由产品定)
|
#define FIRMWARE_VER "4.36.42" // 主.子.修订 (2026-09-03 起: 小改动只增 REV; MAIN/SUB 由产品定)
|
||||||
#define HARDWARE_VER "3.00"
|
#define HARDWARE_VER "3.00"
|
||||||
#define FIRMWARE_VER_MAIN 4
|
#define FIRMWARE_VER_MAIN 4
|
||||||
#define FIRMWARE_VER_SUB 36
|
#define FIRMWARE_VER_SUB 36
|
||||||
#define FIRMWARE_VER_REV 41
|
#define FIRMWARE_VER_REV 42
|
||||||
#define HARDWARE_VER_MAIN 3
|
#define HARDWARE_VER_MAIN 3
|
||||||
#define HARDWARE_VER_SUB 0
|
#define HARDWARE_VER_SUB 0
|
||||||
|
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ uint8_t g_q_lo = 0; // V4.36.19: 低Q 档标志 (空场 f>100
|
|||||||
uint16_t g_origin_freeze_tick = 0; // V4.36.26/32: 释放后 Origin 全冻结计数 (1s)
|
uint16_t g_origin_freeze_tick = 0; // V4.36.26/32: 释放后 Origin 全冻结计数 (1s)
|
||||||
uint16_t g_origin_lowlearn_tick = 0; // V4.36.32: 冻结后降权低速补偿计数 (2s, 残余低值降权学入)
|
uint16_t g_origin_lowlearn_tick = 0; // V4.36.32: 冻结后降权低速补偿计数 (2s, 残余低值降权学入)
|
||||||
uint16_t g_rel_band_cnt = 0; // V4.36.30: 低Q 环带超时兜底计数 (离开触发深度持续 2.5s → 强制释放)
|
uint16_t g_rel_band_cnt = 0; // V4.36.30: 低Q 环带超时兜底计数 (离开触发深度持续 2.5s → 强制释放)
|
||||||
|
uint16_t g_rel_hold_tick = 0; // V4.36.42(G3): 有车后最小保持计数 (禁释放, 掐断进/出自激)
|
||||||
uint32_t g_vacuum_ema = 0; // V4.36.31: 真空 EMA 基线 (B3: 释放/触发参考与锚错 Origin 解耦)
|
uint32_t g_vacuum_ema = 0; // V4.36.31: 真空 EMA 基线 (B3: 释放/触发参考与锚错 Origin 解耦)
|
||||||
static int32_t g_vac_frac = 0; // V4.37(D): EMA 余数累加器 (消 ±127 counts 整数死区)
|
static int32_t g_vac_frac = 0; // V4.37(D): EMA 余数累加器 (消 ±127 counts 整数死区)
|
||||||
uint16_t g_ready_hold_tick = 0; // V4.36.36: 判稳后就绪巩固期计数 (5ms tick, poll_green_led 递减; 按 Q 档置 5s/7s/10s)
|
uint16_t g_ready_hold_tick = 0; // V4.36.36: 判稳后就绪巩固期计数 (5ms tick, poll_green_led 递减; 按 Q 档置 5s/7s/10s)
|
||||||
@@ -288,12 +289,22 @@ uint32_t get_flt_value_rel(uint32_t new_value, uint32_t last_value)
|
|||||||
/* V4.36.31: B3 判定参考 — min(Origin, 真空 EMA)
|
/* V4.36.31: B3 判定参考 — min(Origin, 真空 EMA)
|
||||||
* Origin 可能被 env 学习锚到高位(板搁置态/过冲, J1: 130636 vs 真空 130506) → 释放线偏高
|
* Origin 可能被 env 学习锚到高位(板搁置态/过冲, J1: 130636 vs 真空 130506) → 释放线偏高
|
||||||
* → 撤板真空也够不着; 取 min 使参考锚向实时真空(低者=保守方向), 双侧自动正确 */
|
* → 撤板真空也够不着; 取 min 使参考锚向实时真空(低者=保守方向), 双侧自动正确 */
|
||||||
|
/* V4.36.42(G1): 真空门控阈值 — 必须"状态无关"
|
||||||
|
* 现场 20260911 日志: loop1_dlt_ORG 在进车瞬间被切成释放表值(49→23) ⇒ 同一 EMA 偏差(34)
|
||||||
|
* 原本不触发切换、进车后却触发 ⇒ vac_ref() 从 Origin 阶跃到 EMA ⇒ 释放线瞬间浅 34 counts
|
||||||
|
* ⇒ 深度 50~58 counts 的静止凹脉冲"进门即满足释放" ⇒ 100ms 周期自激(约 30 次/3s)
|
||||||
|
* 修法: 门控一律用进表 dlt(与 :band_timeout 的写法统一) ⇒ 进/出车用同一参考 */
|
||||||
|
static uint32_t vac_gate_dlt(void)
|
||||||
|
{
|
||||||
|
return ((uint32_t)loop1_Origin * SensTable[loop1_SensLevel]) >> 16;
|
||||||
|
}
|
||||||
|
|
||||||
static uint32_t vac_ref(void)
|
static uint32_t vac_ref(void)
|
||||||
{
|
{
|
||||||
if (g_vacuum_ema == 0) return loop1_Origin;
|
if (g_vacuum_ema == 0) return loop1_Origin;
|
||||||
/* V4.36.33: 仅明显锚错(Origin 高于 EMA > 1×dlt)才重锚 EMA — 边缘金属悬停拉低 EMA 的小偏差忽略 */
|
/* V4.36.33: 仅明显锚错(Origin 高于 EMA > 1×dlt)才重锚 EMA — 边缘金属悬停拉低 EMA 的小偏差忽略 */
|
||||||
if ((int32_t)loop1_Origin - (int32_t)g_vacuum_ema >
|
if ((int32_t)loop1_Origin - (int32_t)g_vacuum_ema >
|
||||||
(int32_t)(loop1_dlt_ORG * VAC_REF_DELTA_DLT))
|
(int32_t)(vac_gate_dlt() * VAC_REF_DELTA_DLT))
|
||||||
return g_vacuum_ema;
|
return g_vacuum_ema;
|
||||||
return loop1_Origin;
|
return loop1_Origin;
|
||||||
}
|
}
|
||||||
@@ -321,8 +332,14 @@ static uint8_t rel_release_hit(void)
|
|||||||
uint32_t _line = loop1_Origin - loop1_dlt_ORG;
|
uint32_t _line = loop1_Origin - loop1_dlt_ORG;
|
||||||
|
|
||||||
if (g_q_lo) {
|
if (g_q_lo) {
|
||||||
|
/* V4.36.42(G1/G2): 释放线与进入线必须同参考, 且带回不得越过进入阈值(否则反向滞回)
|
||||||
|
* G1 已保证同参考; 此处只做"未来参数变化"兜底夹紧 —— 绝不动现场验证过的 180
|
||||||
|
* (=41@SENS3: V4.36.28 修静态带回缺口, 23uH 回摆 Origin-36 靠它才释放) */
|
||||||
|
uint32_t _band = (loop1_dlt_ORG * REL_BAND_LO_MULT) / 100;
|
||||||
|
uint32_t _ent = vac_gate_dlt();
|
||||||
_cmp = g_rel_smooth;
|
_cmp = g_rel_smooth;
|
||||||
_line = vac_ref() - ((loop1_dlt_ORG * REL_BAND_LO_MULT) / 100); /* V4.36.31: 锚真空参考 */
|
if (_band > _ent) _band = _ent - 1;
|
||||||
|
_line = vac_ref() - _band;
|
||||||
}
|
}
|
||||||
return (_line < _cmp) ? 1 : 0;
|
return (_line < _cmp) ? 1 : 0;
|
||||||
}
|
}
|
||||||
@@ -579,6 +596,7 @@ void INIT_VD(void)
|
|||||||
g_q_lo = 0; /* V4.36.19: 低Q 档标志清零 */
|
g_q_lo = 0; /* V4.36.19: 低Q 档标志清零 */
|
||||||
g_origin_freeze_tick = 0; /* V4.36.26: 释放冻结计数清零 */
|
g_origin_freeze_tick = 0; /* V4.36.26: 释放冻结计数清零 */
|
||||||
g_rel_band_cnt = 0; /* V4.36.30: 环带兜底计数清零 */
|
g_rel_band_cnt = 0; /* V4.36.30: 环带兜底计数清零 */
|
||||||
|
g_rel_hold_tick = 0; /* V4.36.42(G3): 最小保持清零 */
|
||||||
g_vacuum_ema = 0; /* V4.36.31: 真空 EMA 清零 (判稳后重建) */
|
g_vacuum_ema = 0; /* V4.36.31: 真空 EMA 清零 (判稳后重建) */
|
||||||
g_vac_frac = 0; /* V4.37(D): 余数累加器同步清零 */
|
g_vac_frac = 0; /* V4.37(D): 余数累加器同步清零 */
|
||||||
g_ready_hold_tick = 0; /* V4.36.36: 就绪巩固期清零 (重建判稳时会再置) */
|
g_ready_hold_tick = 0; /* V4.36.36: 就绪巩固期清零 (重建判稳时会再置) */
|
||||||
@@ -1287,6 +1305,7 @@ void vd1_task(void)
|
|||||||
g_origin_freeze_tick--;
|
g_origin_freeze_tick--;
|
||||||
else if (g_origin_lowlearn_tick > 0) /* V4.36.32: 冻结结束 → 降权期开始递减 */
|
else if (g_origin_lowlearn_tick > 0) /* V4.36.32: 冻结结束 → 降权期开始递减 */
|
||||||
g_origin_lowlearn_tick--;
|
g_origin_lowlearn_tick--;
|
||||||
|
if (g_rel_hold_tick > 0) g_rel_hold_tick--; /* V4.36.42(G3): 有车最小保持倒计时 */
|
||||||
|
|
||||||
/*--- 基线跟踪(仿 TLD-110:有车时冻结)
|
/*--- 基线跟踪(仿 TLD-110:有车时冻结)
|
||||||
* V4.20 修复: 双向对称保护 — 负偏差(负variation)也冻结基线
|
* V4.20 修复: 双向对称保护 — 负偏差(负variation)也冻结基线
|
||||||
@@ -1482,6 +1501,7 @@ void vd1_task(void)
|
|||||||
#endif
|
#endif
|
||||||
g_rel_smooth = loop1_CAPVD; /* V4.36.19: 低Q 释放平滑 snap 到进入点 */
|
g_rel_smooth = loop1_CAPVD; /* V4.36.19: 低Q 释放平滑 snap 到进入点 */
|
||||||
g_rel_band_cnt = 0; /* V4.36.30: 环带兜底计数进入时清零 */
|
g_rel_band_cnt = 0; /* V4.36.30: 环带兜底计数进入时清零 */
|
||||||
|
g_rel_hold_tick = REL_MIN_HOLD_TICKS; /* V4.36.42(G3): 进入后 300ms 禁释放 */
|
||||||
|
|
||||||
if (!SET_SAFE) {
|
if (!SET_SAFE) {
|
||||||
loop1_LC_HOLD = 1;
|
loop1_LC_HOLD = 1;
|
||||||
@@ -1577,9 +1597,9 @@ void vd1_task(void)
|
|||||||
loop1_dlt_ORG = ((uint32_t)loop1_Origin * SensTable_1[loop1_SensLevel]) >> 16; // 方案B(V4.06): 调浅释放表已并入 SensTable_1
|
loop1_dlt_ORG = ((uint32_t)loop1_Origin * SensTable_1[loop1_SensLevel]) >> 16; // 方案B(V4.06): 调浅释放表已并入 SensTable_1
|
||||||
|
|
||||||
#if USE_SLOW_RELEASE
|
#if USE_SLOW_RELEASE
|
||||||
if ((loop1_Origin - loop1_dlt_ORG) < loop1_CAPVD_slow) { // 方案A: 用慢滤波值对齐 PD132T 释放手感
|
if (((loop1_Origin - loop1_dlt_ORG) < loop1_CAPVD_slow) && (g_rel_hold_tick == 0)) { // 方案A + V4.36.42(G3) 最小保持
|
||||||
#else
|
#else
|
||||||
if (rel_release_hit()) { // V4.36.19: 低Q 平滑值+带回加宽; 高/中Q 退回原快值逻辑
|
if ((g_rel_hold_tick == 0) && rel_release_hit()) { // V4.36.42(G3) 最小保持 + V4.36.19 低Q 平滑/带回加宽
|
||||||
#endif
|
#endif
|
||||||
if (loop1_cnt_release == 0) {
|
if (loop1_cnt_release == 0) {
|
||||||
/* 过渡事件: 第一次命中离开线 (定位"为什么开始释放") */
|
/* 过渡事件: 第一次命中离开线 (定位"为什么开始释放") */
|
||||||
@@ -1605,6 +1625,7 @@ void vd1_task(void)
|
|||||||
loop1_ORG_SUM = 0;
|
loop1_ORG_SUM = 0;
|
||||||
Hold_CNT = 0;
|
Hold_CNT = 0;
|
||||||
loop1_cnt_release = 0;
|
loop1_cnt_release = 0;
|
||||||
|
g_rel_hold_tick = 0; /* V4.36.42(G3): 释放即清保持 */
|
||||||
g_origin_freeze_tick = REL_ORIGIN_FREEZE_TICKS; /* V4.36.26: 释放后 Origin 均值窗冻结 */
|
g_origin_freeze_tick = REL_ORIGIN_FREEZE_TICKS; /* V4.36.26: 释放后 Origin 均值窗冻结 */
|
||||||
g_origin_lowlearn_tick = ORIGIN_LOWLEARN_TICKS; /* V4.36.32: 冻结后降权期预置 */
|
g_origin_lowlearn_tick = ORIGIN_LOWLEARN_TICKS; /* V4.36.32: 冻结后降权期预置 */
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user