Files
DLD154V4B/docs/patches/v4.36.42-G1-G2-G3-lowq-hysteresis.diff
wangfq 0f8a0d6fbd fix(V4B): V4.36.42 — 低Q 临界悬停自激根治 (进/出参考统一 + 释放带夹紧 + 最小保持)
用户反馈: 金属板缓慢接近时判据乱跳; 35µH(128kHz)/46µH(112kHz) 线圈同样现象(46µH 在设计窗内且无告警)。

根因(三段链条, 现场日志与代码逐值吻合):
 ① 无车态 dlt_ORG=进表 49 ⇒ vac_ref() 门控 1×49; Origin−EMA=32~34 ≯49 ⇒ 参考=Origin ⇒ 进入线=Origin−49
 ② 进车瞬间 dlt_ORG 切成释表 23 ⇒ 同一 gap > 1×23 ⇒ vac_ref() 改用 EMA(低 32~34 counts)
 ③ 释放线 = EMA−1.8×23 ⇒ 比进入线还浅 ⇒ 深度 50~58 的静止凹脉冲"进门即满足释放"
   ⇒ 进入确认 5 + 释放确认 5 = 10 样本 = 100ms 周期自激(日志实测 ~30 组/3s)

实现:
 - G1 新增 vac_gate_dlt()(状态无关进表 dlt)供 vac_ref() 门控 (TaskLoop.c:297/307) ⇒ 进/出同一参考
 - G2 低Q 释放带夹紧 _band ≤ vac_gate_dlt()-1 (TaskLoop.c:339) ⇒ 只作未来兜底; 180(=41@SENS3, V4.36.28 现场值)一字未动
 - G3 REL_MIN_HOLD_TICKS=30 有车后 300ms 禁释放 (TaskLoop.h:69 + TaskLoop.c 调用点) ⇒ 只挡释放不延迟检出

单测: 新增场景 7 现场参数逐位复现 —— 22µH 悬停 300/300 → 1/0; 35µH 300/300 → 1/0; 撤板 1/1; V4.36.28 回摆仍释放; 非低Q 同深度不自激; 全套 8/8 全绿
文档: devlog V2.79(+条目) / spec 文档头 V2.61 / manual 表 V2.18 / cmcng.h 4.36.41→4.36.42 REV 42
待现场: 上板复测 + 锁死侧三线圈实验 (devlog 条目内 [ ] 占位)
2026-09-11 16:59:26 +08:00

109 lines
7.3 KiB
Diff
Raw Permalink 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 35d3d36..f37c3ef 100644
--- a/utilities/at32f421_freertos_demo/inc/TaskLoop.h
+++ b/utilities/at32f421_freertos_demo/inc/TaskLoop.h
@@ -66,6 +66,7 @@
#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 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 4d589a9..c987683 100644
--- a/utilities/at32f421_freertos_demo/src/TaskLoop.c
+++ b/utilities/at32f421_freertos_demo/src/TaskLoop.c
@@ -47,6 +47,7 @@ uint8_t g_q_lo = 0; // V4.36.19: 低Q 档标志 (空场 f>100
uint16_t g_origin_freeze_tick = 0; // V4.36.26/32: 释放后 Origin 全冻结计数 (1s)
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): 有车后最小保持计数 (禁释放, 掐断进/出自激)
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)
@@ -288,12 +289,22 @@ 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;
+}
+
static uint32_t vac_ref(void)
{
if (g_vacuum_ema == 0) return loop1_Origin;
/* V4.36.33: 仅明显锚错(Origin 高于 EMA > 1×dlt)才重锚 EMA — 边缘金属悬停拉低 EMA 的小偏差忽略 */
if ((int32_t)loop1_Origin - (int32_t)g_vacuum_ema >
- (int32_t)(loop1_dlt_ORG * VAC_REF_DELTA_DLT))
+ (int32_t)(vac_gate_dlt() * VAC_REF_DELTA_DLT))
return g_vacuum_ema;
return loop1_Origin;
}
@@ -321,8 +332,14 @@ static uint8_t rel_release_hit(void)
uint32_t _line = loop1_Origin - loop1_dlt_ORG;
if (g_q_lo) {
+ /* V4.36.42(G1/G2): 释放线与进入线必须同参考, 且带回不得越过进入阈值(否则反向滞回)
+ * G1 已保证同参考; 此处只做"未来参数变化"兜底夹紧 —— 绝不动现场验证过的 180
+ * (=41@SENS3: V4.36.28 修静态带回缺口, 23uH 回摆 Origin-36 靠它才释放) */
+ uint32_t _band = (loop1_dlt_ORG * REL_BAND_LO_MULT) / 100;
+ uint32_t _ent = vac_gate_dlt();
_cmp = g_rel_smooth;
- _line = vac_ref() - ((loop1_dlt_ORG * REL_BAND_LO_MULT) / 100); /* V4.36.31: 锚真空参考 */
+ if (_band > _ent) _band = _ent - 1;
+ _line = vac_ref() - _band;
}
return (_line < _cmp) ? 1 : 0;
}
@@ -579,6 +596,7 @@ void INIT_VD(void)
g_q_lo = 0; /* V4.36.19: 低Q 档标志清零 */
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_vacuum_ema = 0; /* V4.36.31: 真空 EMA 清零 (判稳后重建) */
g_vac_frac = 0; /* V4.37(D): 余数累加器同步清零 */
g_ready_hold_tick = 0; /* V4.36.36: 就绪巩固期清零 (重建判稳时会再置) */
@@ -1287,6 +1305,7 @@ void vd1_task(void)
g_origin_freeze_tick--;
else if (g_origin_lowlearn_tick > 0) /* V4.36.32: 冻结结束 → 降权期开始递减 */
g_origin_lowlearn_tick--;
+ if (g_rel_hold_tick > 0) g_rel_hold_tick--; /* V4.36.42(G3): 有车最小保持倒计时 */
/*--- 基线跟踪(仿 TLD-110:有车时冻结)
* V4.20 修复: 双向对称保护 — 负偏差(负variation)也冻结基线
@@ -1482,6 +1501,7 @@ void vd1_task(void)
#endif
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 禁释放 */
if (!SET_SAFE) {
loop1_LC_HOLD = 1;
@@ -1577,9 +1597,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) { // 方案A: 用慢滤波值对齐 PD132T 释放手感
+ if (((loop1_Origin - loop1_dlt_ORG) < loop1_CAPVD_slow) && (g_rel_hold_tick == 0)) { // 方案A + V4.36.42(G3) 最小保持
#else
- if (rel_release_hit()) { // V4.36.19: 低Q 平滑值+带回加宽; 高/中Q 退回原快值逻辑
+ if ((g_rel_hold_tick == 0) && rel_release_hit()) { // V4.36.42(G3) 最小保持 + V4.36.19 低Q 平滑/带回加宽
#endif
if (loop1_cnt_release == 0) {
/* 过渡事件: 第一次命中离开线 (定位"为什么开始释放") */
@@ -1605,6 +1625,7 @@ void vd1_task(void)
loop1_ORG_SUM = 0;
Hold_CNT = 0;
loop1_cnt_release = 0;
+ g_rel_hold_tick = 0; /* V4.36.42(G3): 释放即清保持 */
g_origin_freeze_tick = REL_ORIGIN_FREEZE_TICKS; /* V4.36.26: 释放后 Origin 均值窗冻结 */
g_origin_lowlearn_tick = ORIGIN_LOWLEARN_TICKS; /* V4.36.32: 冻结后降权期预置 */
}