Files
DLD154V4B/docs/env-resync-trigger-line-analysis.md
T
wangfq 5fd58e035a fix(V4B): V4.36.41 — 环境重校准后触发高度变低根治 (基准/派生参考同步 + EMA 余数累加)
用户反馈: 黄灯常亮故障补偿后, 金属板进入触发的高度比断电上电后低很多, 补偿结束也恢复不了正常灵敏度。

根因(两处, 均可复核): V4B 进入判定用 vac_ref()=min(Origin, 真空EMA) 而非 Origin (TaskLoop.c:1432)
 ① env_resync_apply() 只原子换 loop1_Origin, 没同步 g_vacuum_ema。补偿前提是 dev>+4×dlt 连续 7s,
    学到的 B≈当前 CAPVD ⇒ Δ≥4×dlt 必然 ⇒ Origin−EMA=Δ>1×dlt ⇒ vac_ref 必然切旧 EMA ⇒ 进入线整整低 Δ
 ② g_vacuum_ema += _ema_d/128 为整数除法, |d|<128 时步进恒 0 ⇒ EMA 粘在真空下方 ≤127 counts
    (2.59×dlt > 1×dlt 门槛) ⇒ 进入线常驻偏低 ≈0.100% Δf/f 且不自愈; 断电上电 EMA=Origin(偏差 0) 故持久正常

修复:
 - 新增 origin_set_atomic() (TaskLoop.c:308): "一步换 Origin"时 |ΔOrigin| > ORIGIN_JUMP_REANCH_DLT(=1)×dlt
   则同步重锚 g_vacuum_ema; 与 VAC_REF_DELTA_DLT 同口径 ⇒ 维持 |Origin−EMA| ≤ 1×dlt 不变式; 小步不动 EMA
 - 3 处 Origin 写入点改经它: env_resync_apply(:968) / 重连判稳完成(:1207) / 冻结超时更新(:1372)
 - EMA 更新改余数累加器 g_vac_frac(:1344) 消 ±127 counts 死区; g_vac_frac 在 INIT(:583)/判稳(:1266) 清零

单测(新增 tests/test_vac_ref_reanchor.c, 5 场景; gcc -O0 -Wall -Wextra 0 warning; 全套 8/8 全绿):
 补偿后进入线 130457(低 130 counts = 2.65×dlt = 0.100% Δf/f) → 130587(低 0); EMA 追赶偏差 127→0 counts

文档: devlog V2.78(+条目) / spec 文档头 V2.60 / manual 版本表 V2.17 / cmcng.h 4.36.40→4.36.41 (REV 41)
归档: docs/env-resync-trigger-line-analysis.md + docs/patches/v4.36.41-{A-B,D}*.diff

待现场(编译烧录后回填 devlog 条目): 4 项 [ ] + 2 处日志待填 (EVT|env_resync / DBG Origin·VEM·RLN)
2026-09-11 14:08:25 +08:00

152 lines
12 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.
# 黄灯常亮(环境重校准)后触发高度变低 — 根因分析
> 适用版本:**V4.36.31 及以后**(进入判定已切到 `vac_ref()`;判据 = DBG 行是否含 `VEM=` 字段)
> 现象:黄灯常亮故障补偿结束后,金属板进入触发的"高度"明显变低(要压得更近才触发);**断电上电后恢复正常**。
> 结论(一句话):**环境重校准 `env_resync_apply()` 原子替换了 `loop1_Origin`,但没有同步真空 EMA `g_vacuum_ema`;而进入判定用的是 `vac_ref() = min(Origin, EMA)`,于是补偿后进入线被留在旧真空上、整体低了 Δ(≥4×dlt)⇒ 必须多压出 Δ 的感应量才触发。断电上电时 EMA 由判稳重建 = Origin,故立刻恢复。**
---
## 1. 判定链(代码位置,全部可复核)
| 环节 | 位置 | 内容 |
|---|---|---|
| **进入线** | `TaskLoop.c:1432` | `if (loop1_CAPVD < (vac_ref() - loop1_dlt_ORG) && ...)`**用 vac_ref,不是 Origin** |
| 参考函数 | `TaskLoop.c:287-299` | `vac_ref() = (Origin EMA > VAC_REF_DELTA_DLT×dlt) ? EMA : Origin`(阈值 =1×dlt,取**低者** |
| 进入阈值 | `TaskLoop.c:1278` | `dlt = Origin × SensTable[SENS] >> 16`SENS3=25 ⇒ 0.038%SENS0=337 ⇒ 0.514% |
| **补偿替换** | `TaskLoop.c:945-958` | `env_resync_apply()``loop1_Origin = new_origin;` + 清 freeze/ORG/entry + snap slow**没有 EMA** |
| EMA 写点(全仓仅 3 处) | `564` / `1246` / `1309-1321` | INIT 清零 / 判稳完成 `EMA = Origin` / 无车对称窗内跟踪(α=128 τ≈1.28s,每步 ±3×dlt25% 自愈) |
| 黄灯常亮 | `TaskLoop.c:437-442` | 模式4 = `g_env_warn \|\| g_env_resync`(环境异常预判 / 重校准学习) |
| 补偿参数 | `TaskLoop.c:81,82,1082-1084` | 预判 2s → 补偿 7s → 学习窗 2s/窗 + 连续 2 窗判稳(0.1%) → 替换 → 恢复确认 2s 灭灯 |
**关键事实**`g_vacuum_ema` 的三个写点里**没有**环境重校准路径 ⇒ 补偿把 `Origin` 一次性抬到新真空电平后,EMA 仍停在补偿前的旧真空值。
---
## 2. 数值推演(Δ 必然 ≥ 4×dlt)
1. 触发补偿的前提是 `dev = CAPVD Origin > +4×dlt` **连续 7s**`ENV_RESYNC_WAIT=700`)。
2. 期间处于"负 variation 高位"分支 ⇒ **Origin 与 EMA 都被冻结**`1327-1425`),EMA 保持旧真空值。
3. 学习得到的 B = 当前 CAPVD 的 2s 窗均值(`1397-1416`)⇒ `Origin_new ≈ Origin_old + Δ`,其中 **Δ ≥ 4×dlt**
4. 替换后:`Origin EMA = Δ ≥ 4×dlt > 1×dlt``vac_ref()` 返回 **EMA(旧真空)**
5.**进入线 = 旧真空 dlt**,而物理正确应为 **新真空 − dlt = 旧真空 + Δ dlt****进入线整整低了 Δ(≥4×dlt)**
- SENS3dlt=48@130k):Δ ≥ 192 counts ⇒ 0.15% Δf/f 起的额外感应量才触发;
- devlog J1 实测位移 130~1513 counts ⇒ 观测即"触发高度下降一半甚至更多"。
---
## 3. 为什么断电上电就正常
`g_vacuum_ema` 在 INIT 清 0`564`),判稳完成时 `g_vacuum_ema = loop1_Origin``1246`)⇒ 两者重合 ⇒ `vac_ref() = Origin` ⇒ 进入线回到 `Origin dlt`
---
## 4. 为什么"黄灯灭"不等于灵敏度回来了
黄灯灭的条件只有**非高位、空闲连续 2s**(`ENV_RECOVER_WAIT=200``1290-1300`),**不检查 EMA 是否已追上新 Origin**。
补偿后 dev≈0 才落入 ±4×dlt 对称窗 ⇒ EMA 这时才开始以 τ≈1.28s 向上爬:
- 黄灯灭(替换后 2s)时 EMA 仅追回 1e^(2/1.28) ≈ **79%**
- Δ=130 时仍差 ~27 counts(≈0.56×dlt
---
## 5. 为什么"反复试板"会自持(越试越钝)
EMA 更新窗 = 无车 + `dev ∈ ±4×dlt``1302-1326`)。把板拿到感应边缘(未触发、dev −20~−40)时 **EMA 被向下拖**V4.36.33 devlog 实测 2~3s 拉低 20~40 counts);进入线 = `min(Origin, EMA) dlt`**每次试板都把线再拖低一截** ⇒ 主观上"补偿结束了但灵敏度回不来",直到彻底离开真空若干秒才慢慢回正。
> 这与 V4.36.33 已记录的老现象("金属板间隔几秒再压,触发高度下降一半甚至更多")是**同一机理**;本次新增的点是:**环境重校准会把 Δ 一次性甩到 4×dlt 以上**,比边缘悬停(0.4~0.8×dlt)严重一个量级,且黄灯灭的时刻刚好是 EMA 还差一截的时刻。
---
## 6. 第二个机制:真空 EMA 的整数步进死区(2026-09-11 单测实测)
第 5 节解释了"补偿后一次性被压低 Δ",但**为什么反复试板后仍感觉回不来**、而断电上电就彻底好?单测 `tests/test_vac_ref_reanchor.c` 实测出第二个机制:
```
现状公式 (V4.36.35): g_vacuum_ema += _ema_d / VACUUM_EMA_ALFA; /* 有符号整数除法 */
当 |_ema_d| < 128 时, 步进恒为 0 ⇒ 死区 ±127 counts
```
- 实测:让 EMA 从真空下方 200 counts 追赶,**40s 后停在真空下方 127 counts**= 2.59×dlt@SENS3)⇒ 因为 127 > 1×dlt`vac_ref()` 持续选中这个偏低的 EMA ⇒ **进入线常驻偏低 127 counts ≈ 0.10% Δf/f**
- 该偏差**不会自愈**:EMA 只会在 |d| ≥ 128 的样本上移动,而板离开后 d 稳定在 127 附近 ⇒ 需要长时间 CAPVD 噪声偶然越过阈值才缓慢爬升。
- 而**断电上电**时 `EMA = Origin`(判稳建立,精确相等,偏差 0),且此后 |d| < 128 ⇒ EMA 被"粘"在原地不动 ⇒ **永久保持正常灵敏度** ⇒ 这就是"断电上电就好了"的另一半原因。
- ⇒ 三层叠加:① 补偿一步拉开 Δ(≥4×dlt)② 边缘悬停把 EMA 拖低(≤4×dlt)③ **整数死区把 EMA 钉在真空下方 ~127 counts**。三者都让 `vac_ref()` 选到偏低的参考。
---
## 7. 现场验证(建议顺序)
**第 0 步先确认版本**DBG 行含 `VEM=`/`RLN=` ⇒ V4.36.31+,本分析适用;若老版本无 VEM,则走"Origin 被学高"的旧机理,需另判。
1. **抓日志**TTL):补偿会打印
- `EVT|env_learn_start Origin:.. CAPVD:.. dev:..`
- `EVT|env_resync Origin:..->.. CAPVD:..`
- 之后每 2s 的 `DBG|... Origin=.. VEM=.. RLN=..`
**判据**`Origin VEM > 1×dlt` 的持续时间 ≈ "触发高度异常"的持续时间;`RLN``Origindlt` 的差 ≈ 触发高度损失。
2. **单变量对照**(同一块板、同一高度序列):
(a) 补偿后立刻测 → (b) 黄灯灭后静置 10s(板远离)再测 → (c) 断电上电后测
预期 (b) 明显好于 (a)、(b)≈(c)。若 (b) 仍远差于 (c) ⇒ 另有固化路径(学习窗污染 Origin),需再取日志。
3. **固件对照实验(有权限时,最直接)**:临时在 `env_resync_apply()` 内加一行 `g_vacuum_ema = new_origin;` 复测 ⇒ 触发高度应与断电上电一致 ⇒ 根因钉死。
---
## 8. 修复候选(待拍板,暂不改源码)
| 方案 | 内容 | 风险/代价 |
|---|---|---|
| **A(最小对症)** | `env_resync_apply()``g_vacuum_ema = new_origin;`(与判稳完成建初值同语义:Origin 原子换 ⇒ 真空参考同步换) | 低。1 行;补偿后判定参考与 Origin 同时就位,黄灯灭即恢复正常灵敏度 |
| **B(通用护栏,建议叠加 A** | "Origin 大步跳变(\|Δ\| > k×dlt)即同步重锚 EMA":一次收口 `1188`(重连判稳对齐 Origin)、`1344`(冻结超时更新 Origin)等**同源**路径 | 低。把"Origin 动、EMA 不动"这类隐患统一堵住 |
| **C(稳健性,可选)** | 黄灯灭条件追加"\|Origin EMA\| ≤ 1×dlt" ⇒ 让"灯灭 = 判定参考已就位" | 低。可能让黄灯多亮 1~3s(现场需接受) |
| **D(建议叠加)** | EMA 更新改**余数累加器**(消 `d/128` 的 ±127 counts 整数死区) | 低。单测实测同条件偏差 **127→0 counts**;τ/噪声不变 |
| ✗ 不建议 | 进入线改回 `Origin dlt` | 会退回 V4.36.31 之前"Origin 学高 ⇒ 假 Car_In"devlog 20260904 已实锤) |
---
## 9. 待确认(现场)
- 测试固件的**版本号**(V4.36.31+ 才适用本文)
- 黄灯是**常亮**(=环境重校准,模式4)还是其他花样:一长一短=电感量出窗(模式5)/一长两短=156~171k(模式6)/快闪=断开·短路级(模式1)
- 线圈与 Q 档(33µH/23µH/35µH 现场差异大;V4.36.33 devlog 记 23µH 仍可复现)
- 触发补偿的动作("金属板拿走/搁置")与位移量 Δ 的量级
---
## 10. 补丁草案与验证(**已应用,未提交**)
| 产物 | 路径 | 规模 |
|---|---|---|
| 补丁 A+BOrigin/EMA 同步不变式) | `docs/patches/v4.36.41-A-B-origin-ema-sync.diff` | TaskLoop.h +1 TaskLoop.c +20 3 |
| 补丁 D(EMA 余数累加,消死区) | `docs/patches/v4.36.41-D-ema-frac-no-deadband.diff` | TaskLoop.c +13 2 |
| 新增单测 | `tests/test_vac_ref_reanchor.c` | 5 场景,`gcc -O0 -Wall -Wextra` 0 warning |
**A+B 核心**:新增 `origin_set_atomic()`,把"一步换 Origin"的 3 处(`env_resync_apply` / 重连判稳完成 `:1188` / 冻结超时更新 `:1344`)改为经由它 ⇒ 步长 > 1×dlt 时同步重锚 `g_vacuum_ema`(与 `VAC_REF_DELTA_DLT` 同口径 ⇒ 维持 `|OriginEMA| ≤ 1×dlt` 不变式)。上电首窗那处(`:701`)不需要改:EMA 在判稳完成建立、此前进入判定被 `g_loop_stable` 门控挡住。
**单测实测结论**
| 场景 | 现状行为 | 打补丁后 |
|---|---|---|
| 补偿(Δ=130 counts)后进入线 | 130457(低 130 = 2.65×dlt = **0.100% Δf/f** | 130587(低 **0** |
| 护栏:小步 20(≤1×dlt) / 大步 150 | — | 小步不动 EMA ✓ / 大步重锚 ✓ |
| V4.36.33 门控(OriginEMA = 30 / 130 | 用 Origin ✓ 用 EMA ✓ | 语义不变 ✓ |
| 上电(EMA=0 → 判稳=Origin | 进入线 = Origindlt ✓ | 不变 ✓ |
| EMA 追赶 40s(现状公式,起点 −200) | **停在真空下方 127 counts2.59×dlt** | 修复 D:偏差 **0** |
**已完成的验证**:① 两个补丁对干净树 `git apply --check` 通过,且 **A+B → D 顺序 apply** 通过;② `origin_set_atomic()` 独立 `gcc -fsyntax-only` 通过(确认在文件作用域,不在 `vac_ref()` 内);③ 大括号平衡 202/201 → **205/204**(成对增加);④ **8 个单测全绿**(原 7 个未受影响);⑤ 生成补丁过程中已修正两处结构缺陷(helper 误置于 `vac_ref()` 内、D 的 `if (_ema_d != 0)` 缺大括号)。
**应用/回退**`git apply docs/patches/v4.36.41-A-B-*.diff`(可再叠 `-D-*.diff`;两者 hunk 不重叠,已顺序 apply 验证);回退 `git apply -R``git checkout -- <file>`。**2026-09-11 更新:A+B 与 D 已按采纳决定应用到工作树(仍未提交)** —— `TaskLoop.h` +1 / `TaskLoop.c` +33 5(合计 +34 5);CRLF 保持(1825 行全 CR)、大括号 205/204 平衡、8 个单测全绿。回退:`git checkout -- utilities/`
**待拍板**:① 采用 A+B?② 叠加 D?③ 提交前要我同步 `version`/spec 表 + devlog 条目(V4.36.41)?
---
## 附:相关历史(devlog
| 版本 | 内容 |
|---|---|
| V4.36.29/30 | Origin 过冲 + 释放带压缩 → 低Q 卡死 75s;引入环带超时兜底 |
| V4.36.31 | 引入真空 EMA `vac_ref()=min(Origin,EMA)`,修"Origin 学高 ⇒ 释放线偏高/假触发" |
| V4.36.33 | vac_ref 加 1×dlt 门控,修"**边缘悬停拉低 EMA ⇒ 触发高度漂移**"(本文同机理,量级更大) |
| V4.36.34/35 | EMA 内存污染与 cast 爆炸源修复(`(uint32_t)(_ema_d/128)` |
| V4.36.36/38 | 就绪巩固期 Q 分级;电感量告警模式 6 |
---
*分析日期:2026-09-11 证据:`TaskLoop.c` / `TaskLoop.h` / `tests/test_env_resync.c` / `docs/devlog.md` 逐行核对*