用户反馈: 黄灯常亮故障补偿后, 金属板进入触发的高度比断电上电后低很多, 补偿结束也恢复不了正常灵敏度。
根因(两处, 均可复核): 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)
12 KiB
黄灯常亮(环境重校准)后触发高度变低 — 根因分析
适用版本:V4.36.31 及以后(进入判定已切到
vac_ref();判据 = DBG 行是否含VEM=字段) 现象:黄灯常亮故障补偿结束后,金属板进入触发的"高度"明显变低(要压得更近才触发);断电上电后恢复正常。 结论(一句话):环境重校准env_resync_apply()原子替换了loop1_Origin,但没有同步真空 EMAg_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×dlt,25% 自愈) |
| 黄灯常亮 | 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)
- 触发补偿的前提是
dev = CAPVD − Origin > +4×dlt连续 7s(ENV_RESYNC_WAIT=700)。 - 期间处于"负 variation 高位"分支 ⇒ Origin 与 EMA 都被冻结(
1327-1425),EMA 保持旧真空值。 - 学习得到的 B = 当前 CAPVD 的 2s 窗均值(
1397-1416)⇒Origin_new ≈ Origin_old + Δ,其中 Δ ≥ 4×dlt。 - 替换后:
Origin − EMA = Δ ≥ 4×dlt > 1×dlt⇒vac_ref()返回 EMA(旧真空)。 - ⇒ 进入线 = 旧真空 − dlt,而物理正确应为 新真空 − dlt = 旧真空 + Δ − dlt ⇒ 进入线整整低了 Δ(≥4×dlt)。
- SENS3(dlt=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 仅追回 1−e^(−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 实测 23s 拉低 2040 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 被学高"的旧机理,需另判。
- 抓日志(TTL):补偿会打印
EVT|env_learn_start Origin:.. CAPVD:.. dev:..EVT|env_resync Origin:..->.. CAPVD:..- 之后每 2s 的
DBG|... Origin=.. VEM=.. RLN=..判据:Origin − VEM > 1×dlt的持续时间 ≈ "触发高度异常"的持续时间;RLN与Origin−dlt的差 ≈ 触发高度损失。
- 单变量对照(同一块板、同一高度序列): (a) 补偿后立刻测 → (b) 黄灯灭后静置 10s(板远离)再测 → (c) 断电上电后测 预期 (b) 明显好于 (a)、(b)≈(c)。若 (b) 仍远差于 (c) ⇒ 另有固化路径(学习窗污染 Origin),需再取日志。
- 固件对照实验(有权限时,最直接):临时在
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+B(Origin/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 同口径 ⇒ 维持 |Origin−EMA| ≤ 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 门控(Origin−EMA = 30 / 130) | 用 Origin ✓ / 用 EMA ✓ | 语义不变 ✓ |
| 上电(EMA=0 → 判稳=Origin) | 进入线 = Origin−dlt ✓ | 不变 ✓ |
| EMA 追赶 40s(现状公式,起点 −200) | 停在真空下方 127 counts(2.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 逐行核对