Files
DLD154V4B/docs/patches/v4.36.44-P1-negvar-hold-and-minhold-100ms.diff
T
wangfq d5e6a3d55b feat(V4B): V4.36.44 — 铁板负偏差误释放防护(P1) + 有车最小保持定档 100ms
现场 154log260911d(22µH 铁板): 进入后 CAPVD 被磁导率抬到 dev +201/+198,
两次在 dev=+33/+96(≈2×进表dlt, 落在既有 ±4×dlt 正常跟踪窗内) 误判"离开" ⇒ 继电器掉。
修复: 有车期间 dev > +1×进表dlt ⇒ 冻结离开判定(含 band_timeout); 持续 5s ⇒ 重锚基线后放行(防锁死)。
同时 REL_MIN_HOLD_TICKS 30→10(100ms, 现场验证后正式化)。
单测场景8: 误释放 @1.04s → 冻结后 @6.04s, 正常撤板不受影响; 全套 8/8 全绿。

- P1: g_neg_rel_hold_cnt + REL_NEG_VAR_HOLD_TICKS=500; 门控普通释放与 band_timeout;
      Car_In/Car_Off 双向清零; 新增 EVT|neg_rel_hold / EVT|neg_rel_reanchor
- 边界: 真断开仍走 RELAY_HOLD_MS=1000; dev>=+4×dlt 强负 variation 仍归 V4.24 两段式环境逻辑
- 文档: devlog V2.81(+条目) / spec 头 V2.63 / manual 表 V2.20 / cmcng.h 4.36.43→4.36.44 REV 44
- 归档: docs/patches/v4.36.44-P1-negvar-hold-and-minhold-100ms.diff
2026-09-11 17:53:15 +08:00

138 lines
9.9 KiB
Diff
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.
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: 冻结后降权期预置 */
}