diff --git a/utilities/at32f421_freertos_demo/inc/TaskLoop.h b/utilities/at32f421_freertos_demo/inc/TaskLoop.h index f37c3ef..f5dedf4 100644 --- a/utilities/at32f421_freertos_demo/inc/TaskLoop.h +++ b/utilities/at32f421_freertos_demo/inc/TaskLoop.h @@ -66,7 +66,8 @@ #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 REL_MIN_HOLD_TICKS 10 // V4.36.44: 有车后最小保持 100ms 禁释放 (V4.36.42 首发 300ms; 2026-09-11 现场以 10=100ms 验证通过后正式化; 0.2s 内必释放) +#define REL_NEG_VAR_HOLD_TICKS 500 // V4.36.44(P1): 有车期间负偏差(铁块/异常高)持续上限 5s, 到顶重锚基线后放行(防永久锁死) #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 2e0f53b..370fbd6 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 → 强制释放) uint16_t g_rel_hold_tick = 0; // V4.36.42(G3): 有车后最小保持计数 (禁释放, 掐断进/出自激) +uint16_t g_neg_rel_hold_cnt = 0; // V4.36.44(P1): 有车期间负偏差(>+1×dlt)持续计数 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) @@ -289,16 +290,16 @@ 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; -} - +/* 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; @@ -597,6 +598,7 @@ void INIT_VD(void) 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_neg_rel_hold_cnt = 0; /* V4.36.44(P1): 负偏差离开冻结计数清零 */ g_vacuum_ema = 0; /* V4.36.31: 真空 EMA 清零 (判稳后重建) */ g_vac_frac = 0; /* V4.37(D): 余数累加器同步清零 */ g_ready_hold_tick = 0; /* V4.36.36: 就绪巩固期清零 (重建判稳时会再置) */ @@ -1502,6 +1504,7 @@ void vd1_task(void) 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 禁释放 */ + g_neg_rel_hold_cnt = 0; /* V4.36.44(P1): 进入即重置 */ if (!SET_SAFE) { loop1_LC_HOLD = 1; @@ -1533,6 +1536,30 @@ void vd1_task(void) * 有车期间永不递减 ⇒ 首次进入后 g_rel_hold_tick 常驻 ⇒ 正常释放被永久挡住, 只能靠 band_timeout * 兜底 (现场日志 2026-09-11 17:02: 4 次 Car_OFF 全是 band_timeout, 离开延迟 3.5~4.7s) */ if (g_rel_hold_tick > 0) g_rel_hold_tick--; + /* V4.36.44(P1): 有车期间 CAPVD 进负偏差侧(dev > +1×进表dlt) = 铁块/环境异常高, 不是"离开"证据 + * ⇒ 冻结离开判定(含 band_timeout 兜底); 持续 REL_NEG_VAR_HOLD_TICKS(5s) ⇒ 判为真空位移, + * 重锚基线后放行(防永久锁死)。真实"车走了"只让 CAPVD 回到 Origin 附近(dev≈0) ⇒ 不受影响。 + * 现场依据: 2026-09-11 铁板日志(22µH)两次误释放发生在 dev=+96(≈2×进表dlt), 落在"-4dlt..+4dlt 正常跟踪窗"内 */ + { + int32_t _neg_dev = (int32_t)loop1_CAPVD - (int32_t)loop1_Origin; + if (_neg_dev > (int32_t)vac_gate_dlt()) { + if (g_neg_rel_hold_cnt == 0) { + PRINT("EVT|neg_rel_hold CAPVD:%d Origin:%d dev:%d dlt:%d (离开判定冻结)\n", + loop1_CAPVD, loop1_Origin, (int)_neg_dev, (int)vac_gate_dlt()); + } + if (g_neg_rel_hold_cnt < REL_NEG_VAR_HOLD_TICKS) { + g_neg_rel_hold_cnt++; + } else { + origin_set_atomic(loop1_CAPVD); /* 异常持续 5s ⇒ 判真空位移, 重锚基线 */ + g_origin_freeze_tick = REL_ORIGIN_FREEZE_TICKS; + g_neg_rel_hold_cnt = 0; /* 放行: 基线已跟上, dev 归零 */ + PRINT("EVT|neg_rel_reanchor Origin->%d (异常持续 %dms, 重锚后放行)\n", + loop1_Origin, REL_NEG_VAR_HOLD_TICKS * 10); + } + } else { + g_neg_rel_hold_cnt = 0; + } + } #if USE_FLATNESS_EXIT /*================================================================ * 有车状态 — 平坦性判定离开(专利 CN200910309382) @@ -1601,9 +1628,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) && (g_rel_hold_tick == 0)) { // 方案A + V4.36.42(G3) 最小保持 + if (((loop1_Origin - loop1_dlt_ORG) < loop1_CAPVD_slow) && (g_rel_hold_tick == 0) && (g_neg_rel_hold_cnt == 0)) { // 方案A + V4.36.42(G3) 最小保持 #else - if ((g_rel_hold_tick == 0) && rel_release_hit()) { // V4.36.42(G3) 最小保持 + V4.36.19 低Q 平滑/带回加宽 + if ((g_rel_hold_tick == 0) && (g_neg_rel_hold_cnt == 0) && rel_release_hit()) { // V4.36.42(G3) 最小保持 + V4.36.19 低Q 平滑/带回加宽 #endif if (loop1_cnt_release == 0) { /* 过渡事件: 第一次命中离开线 (定位"为什么开始释放") */ @@ -1630,6 +1657,7 @@ void vd1_task(void) Hold_CNT = 0; loop1_cnt_release = 0; g_rel_hold_tick = 0; /* V4.36.42(G3): 释放即清保持 */ + g_neg_rel_hold_cnt = 0; /* V4.36.44(P1): 负偏差离开冻结计数清零 */ g_origin_freeze_tick = REL_ORIGIN_FREEZE_TICKS; /* V4.36.26: 释放后 Origin 均值窗冻结 */ g_origin_lowlearn_tick = ORIGIN_LOWLEARN_TICKS; /* V4.36.32: 冻结后降权期预置 */ } @@ -1643,7 +1671,7 @@ void vd1_task(void) if (g_q_lo) { uint32_t _entry_ln = vac_ref() - (((uint32_t)loop1_Origin * SensTable[loop1_SensLevel]) >> 16); /* V4.36.31: 锚真空参考 */ - if (g_rel_smooth > _entry_ln) { + if ((g_rel_smooth > _entry_ln) && (g_neg_rel_hold_cnt == 0)) { /* V4.36.44(P1) */ g_rel_band_cnt++; if (g_rel_band_cnt >= REL_BAND_TIMEOUT_TICKS) { g_rel_band_cnt = 0; @@ -1657,6 +1685,7 @@ void vd1_task(void) loop1_ORG_SUM = 0; Hold_CNT = 0; loop1_cnt_release = 0; + g_neg_rel_hold_cnt = 0; /* V4.36.44(P1) */ g_origin_freeze_tick = REL_ORIGIN_FREEZE_TICKS; g_origin_lowlearn_tick = ORIGIN_LOWLEARN_TICKS; /* V4.36.32: 冻结后降权期预置 */ }