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
This commit is contained in:
@@ -244,6 +244,59 @@ static void test_lowq_limit_cycle(void)
|
||||
printf(" 修后: 悬停 1/0 OK | 撤板 1/1 OK | V4.36.28 回摆仍释放 OK\n");
|
||||
}
|
||||
|
||||
/* ================= 场景 8: 铁板负偏差误释放 (P1) =================
|
||||
* 现场依据: 2026-09-11 154log260911d (22µH) 两次"铁板还在但被抬到 dev=+33/+96 ⇒ 释放"
|
||||
* 时间线: 深压进入(dev −128) → CAPVD 回升穿过 Origin 停在 +96 (铁板仍在)
|
||||
* 期望: 现状(V4.36.43) ~1.0s 即误释放; P1 冻结离开 ⇒ 持续 5s 后重锚基线再放行(1 次)
|
||||
*/
|
||||
#define SIM_ORG 129310u
|
||||
static uint32_t tl8_iron(int i) { return (i < 100) ? (SIM_ORG - 128u) : (SIM_ORG + 96u); }
|
||||
static uint32_t tl8_leave(int i) { return (i < 200) ? (SIM_ORG - 128u) : (SIM_ORG); }
|
||||
|
||||
static void sim_iron(int p1_on, uint32_t (*capvd_at)(int), int n, int *p_off_tick, int *p_off_total)
|
||||
{
|
||||
uint32_t dlt_e = gate_dlt(SIM_ORG, SENS_LEVEL);
|
||||
uint32_t dlt_rel = (uint32_t)(((uint64_t)SIM_ORG * 12) >> 16);
|
||||
uint32_t origin = SIM_ORG;
|
||||
int i, ent = 0, rel = 0, hold = 0, neg = 0, off_tick = -1, off_total = 0;
|
||||
uint8_t vd = 0;
|
||||
for (i = 0; i < n; i++) {
|
||||
int32_t capvd = (int32_t)capvd_at(i);
|
||||
if (!vd) {
|
||||
if (capvd < (int32_t)(origin - dlt_e)) { if (++ent >= 5) { vd = 1; ent = 0; hold = 10; } }
|
||||
else ent = 0;
|
||||
} else {
|
||||
if (hold > 0) hold--;
|
||||
if (p1_on) { /* P1: dev > +1×进表dlt 期间冻结离开 */
|
||||
if (capvd - (int32_t)origin > (int32_t)dlt_e) {
|
||||
if (neg < 500) neg++;
|
||||
else { origin = (uint32_t)capvd; neg = 0; } /* 持续 5s ⇒ 重锚基线后放行 */
|
||||
} else neg = 0;
|
||||
}
|
||||
if (hold == 0 && neg == 0) {
|
||||
if (capvd > (int32_t)(origin - (dlt_rel * 180) / 100)) {
|
||||
if (++rel >= 5) { vd = 0; rel = 0; off_total++; if (off_tick < 0) off_tick = i; }
|
||||
} else rel = 0;
|
||||
} else rel = 0;
|
||||
}
|
||||
}
|
||||
*p_off_tick = off_tick; *p_off_total = off_total;
|
||||
}
|
||||
|
||||
static void test_iron_neg_var_release(void)
|
||||
{
|
||||
int t1 = -1, c1 = 0, t2 = -1, c2 = 0, t3 = -1, c3 = 0;
|
||||
sim_iron(0, tl8_iron, 2000, &t1, &c1); /* 现状: 无 P1 */
|
||||
sim_iron(1, tl8_iron, 2000, &t2, &c2); /* P1: 冻结离开 */
|
||||
sim_iron(1, tl8_leave, 2000, &t3, &c3); /* P1: 正常撤板(dev→0) */
|
||||
printf(" 铁板停留 dev=+96: 现状 释放%d次@%.2fs | P1 释放%d次@%.2fs\n",
|
||||
c1, t1 * 0.01, c2, t2 * 0.01);
|
||||
printf(" P1 正常撤板(dev→0): 释放%d次@%.2fs\n", c3, t3 * 0.01);
|
||||
assert(c1 >= 1 && t1 <= 200); /* 现状: ≈1s 内误释放 */
|
||||
assert(c2 == 1 && t2 >= 550); /* P1: 冻结≥5s 后重锚放行, 且仅 1 次 */
|
||||
assert(c3 == 1 && t3 <= 260); /* P1: 正常离开不受影响 */
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
printf("test_vac_ref_reanchor (V4.36.42: A+B 同步 / D 死区 / E 单向 / G1+G2+G3 低Q自激)\n");
|
||||
@@ -346,6 +399,9 @@ int main(void)
|
||||
/* ================= 场景 7: 低Q 临界悬停自激 ================= */
|
||||
test_lowq_limit_cycle();
|
||||
|
||||
printf("ALL PASS (A+B 同步 / 护栏 / 门控回归 / 上电语义 / 死区 / 抖动 / 低Q自激)\n");
|
||||
/* ================= 场景 8: 铁板负偏差误释放 (P1) ================= */
|
||||
test_iron_neg_var_release();
|
||||
|
||||
printf("ALL PASS (A+B 同步 / 护栏 / 门控回归 / 上电语义 / 死区 / 抖动 / 低Q自激 / P1负偏差)\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user