Files
DLD154V4B/docs/patches/v4.36.41-D-ema-frac-no-deadband.diff
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

50 lines
3.7 KiB
Diff

diff --git a/utilities/at32f421_freertos_demo/src/TaskLoop.c b/utilities/at32f421_freertos_demo/src/TaskLoop.c
index afbe2d1..a8bc9d6 100644
--- a/utilities/at32f421_freertos_demo/src/TaskLoop.c
+++ b/utilities/at32f421_freertos_demo/src/TaskLoop.c
@@ -48,6 +48,7 @@ uint16_t g_origin_freeze_tick = 0; // V4.36.26/32: 释放后 Origin 全冻
uint16_t g_origin_lowlearn_tick = 0; // V4.36.32: 冻结后降权低速补偿计数 (2s, 残余低值降权学入)
uint16_t g_rel_band_cnt = 0; // V4.36.30: 低Q 环带超时兜底计数 (离开触发深度持续 2.5s → 强制释放)
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)
uint32_t loop1_Origin;
uint32_t loop1_ORG_SUM;
@@ -562,6 +563,7 @@ void INIT_VD(void)
g_origin_freeze_tick = 0; /* V4.36.26: 释放冻结计数清零 */
g_rel_band_cnt = 0; /* V4.36.30: 环带兜底计数清零 */
g_vacuum_ema = 0; /* V4.36.31: 真空 EMA 清零 (判稳后重建) */
+ g_vac_frac = 0; /* V4.37(D): 余数累加器同步清零 */
g_ready_hold_tick = 0; /* V4.36.36: 就绪巩固期清零 (重建判稳时会再置) */
g_origin_lowlearn_tick = 0; /* V4.36.32: 降权期计数清零 */
loop1_CAP_OK = 0;
@@ -1244,6 +1246,7 @@ void vd1_task(void)
g_stable_cnt = 0; // 计数退出时清零: 二次稳定期(安全复位)从零开始
g_settle_cnt = 0;
g_vacuum_ema = loop1_Origin; /* V4.36.31: 判稳完成建立真空基线 */
+ g_vac_frac = 0; /* V4.37(D): 余数累加器同步清零 */
/* V4.36.36: 就绪巩固期按 Q 分档 (高Q 5s/中Q 7s/低Q 10s) — 绿灯继续慢闪期间系统收敛 */
{
uint32_t _f0 = calc_freq_khz(loop1_Origin, loop1_LPCNT);
@@ -1315,10 +1318,18 @@ void vd1_task(void)
int32_t _ema_lim = (int32_t)(loop1_dlt_ORG * 3);
if (_ema_d > _ema_lim) _ema_d = _ema_lim;
else if (_ema_d < -_ema_lim) _ema_d = -_ema_lim;
- if (_ema_d != 0)
+ if (_ema_d != 0) {
/* V4.36.35: cast 顺序修复 — (uint32_t)负值/128 = +3355万/样本(爆炸源!)
* 必须 有符号先除: -10/128=0, -200/128=-1(wrap 减) — 20260908 实锤根因 */
- g_vacuum_ema += (uint32_t)(_ema_d / VACUUM_EMA_ALFA);
+ /* 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;
+ }
+ }
if (((int32_t)loop1_Origin - (int32_t)g_vacuum_ema) > (int32_t)(loop1_Origin >> 2) ||
((int32_t)g_vacuum_ema - (int32_t)loop1_Origin) > (int32_t)(loop1_Origin >> 2))
g_vacuum_ema = loop1_Origin;