feat(V4B): V4.24 — 环境重校准:永久环境变化自动恢复基线(金属板A拿走场景)
现场(2026-09-02实测): 线圈旁金属板A上电把Origin学低(128096),A拿走CAPVD弹回 真空场(128856) dev=+761(0.59%),被36321a1双向保护"dev>0永不更新"永久冻结 → B触发需809cnt(正常54cnt) 灵敏度假性降低且不恢复(V4.20分钟级可自愈) 修复: dev>+4dlt高位两段式受控重校准 ① 60s(ENV_RESYNC_WAIT)高位连续未回摆 → 判定永久环境变化(瞬态铁块类不污染) ② 学习基线B: 连续空闲窗200tick均值 + settle判稳(连续2窗漂移≤0.1%) ③ 空闲原子替换Origin, 清freeze/ORG/entry残留, slow snap, 黄灯恢复 - 学习期打断(回窗/dev<0/断线重连)→重算; 30s预算超时放弃保留旧Origin - 黄灯模式4: 环境学习中常亮(优先级: 断开快闪>学习常亮>N短闪>灭) - tests/test_env_resync.c 5场景ALL PASS(恢复66s/瞬态不学/打断重算/放弃/不震荡) - docs: devlog V2.22 + spec V2.3 + 产品手册 V2.7 同步
This commit is contained in:
@@ -14,10 +14,10 @@
|
||||
#define __CMCNG_H__
|
||||
|
||||
#define PRODUCT_MODEL "DLD154"
|
||||
#define FIRMWARE_VER "4.23"
|
||||
#define FIRMWARE_VER "4.24"
|
||||
#define HARDWARE_VER "3.00"
|
||||
#define FIRMWARE_VER_MAIN 4
|
||||
#define FIRMWARE_VER_SUB 23
|
||||
#define FIRMWARE_VER_SUB 24
|
||||
#define HARDWARE_VER_MAIN 3
|
||||
#define HARDWARE_VER_SUB 0
|
||||
|
||||
|
||||
@@ -75,6 +75,17 @@ uint8_t g_loop_stable;
|
||||
uint16_t g_stable_cnt = 0; // 稳定期累计样本 (每次 CAP_OK +1)
|
||||
uint16_t g_settle_cnt = 0; // 基准稳定连续窗口计数 (窗口=100样本≈1s)
|
||||
|
||||
/* V4.24: 环境重校准(受控基线更新)状态 — 现场永久环境变化(如金属板A拿走)自动恢复
|
||||
* 触发链: dev>+4dlt 高位连续 60s → 学习基线 B (连续空闲窗均值+判稳) → 空闲原子替换 Origin
|
||||
* 黄灯常亮指示学习过程; 与双向保护并存: 60s 内瞬态污染仍只冻结不污染 Origin */
|
||||
uint8_t g_env_resync = 0; // 1=学习中 (黄灯常亮指示)
|
||||
uint16_t g_env_wait_cnt = 0; // dev>+4dlt 高位连续累计 (≥ENV_RESYNC_WAIT 触发学习)
|
||||
uint32_t g_env_sum = 0; // 学习窗口 CAPVD 累加
|
||||
uint16_t g_env_cnt = 0; // 学习窗口样本数
|
||||
uint32_t g_env_prev = 0; // 上一窗口均值 (B 候选)
|
||||
uint8_t g_env_settle = 0; // 连续稳定窗口计数 (窗内均值漂移 ≤0.1% 则+1)
|
||||
uint16_t g_env_tick = 0; // 学习预算 (超时放弃防死锁)
|
||||
|
||||
#if USE_FLATNESS_EXIT
|
||||
uint8_t g_exit_state;
|
||||
uint16_t g_max_slope;
|
||||
@@ -310,6 +321,14 @@ void poll_yellow_led(void)
|
||||
return;
|
||||
}
|
||||
|
||||
/*--- V4.24 模式4: 环境重校准学习中 → 黄灯常亮 (优先级: 断开快闪 > 学习常亮 > N短闪 > 灭) ---*/
|
||||
if (g_env_resync) {
|
||||
LED_YELLOW_ON;
|
||||
g_fault_tick = 0;
|
||||
g_fault_phase = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t N = g_disconnect_count;
|
||||
|
||||
if (N == 0) {
|
||||
@@ -403,6 +422,15 @@ void INIT_VD(void)
|
||||
g_stable_cnt = 0; // V4.23: 自检计数从零开始
|
||||
g_settle_cnt = 0;
|
||||
|
||||
/* V4.24: 环境重校准复位 */
|
||||
g_env_resync = 0;
|
||||
g_env_wait_cnt = 0;
|
||||
g_env_sum = 0;
|
||||
g_env_cnt = 0;
|
||||
g_env_prev = 0;
|
||||
g_env_settle = 0;
|
||||
g_env_tick = 0;
|
||||
|
||||
/* M4 优化: 快速 IIR + 进入确认 */
|
||||
loop1_entry_cnt = 0;
|
||||
loop1_freeze_cnt = 0;
|
||||
@@ -704,6 +732,40 @@ static uint32_t calc_freq_khz(uint32_t capvd, uint16_t lp_cnt)
|
||||
return (60000UL * lp_cnt) / capvd;
|
||||
}
|
||||
|
||||
/*===========================================================================
|
||||
* V4.24: 环境重校准 — 学习被打断/放弃时复位 (黄灯恢复) / 完成时原子替换 Origin
|
||||
*
|
||||
* 替换安全设计:
|
||||
* - 仅空闲(无车, dev 高位)且学习 B 连续 2 窗稳定后才调用
|
||||
* - B ≈ 当前空闲 CAPVD → 替换瞬间 dev≈0, 无跳变不会触发继电器
|
||||
* - 同步清 freeze/ORG/entry 残留, slow 滤波 snap (同 V4.04 进入时)
|
||||
*===========================================================================*/
|
||||
static void env_resync_abort(void)
|
||||
{
|
||||
g_env_resync = 0;
|
||||
g_env_sum = 0;
|
||||
g_env_cnt = 0;
|
||||
g_env_prev = 0;
|
||||
g_env_settle = 0;
|
||||
g_env_tick = 0;
|
||||
}
|
||||
|
||||
static void env_resync_apply(uint32_t new_origin)
|
||||
{
|
||||
PRINT("EVT|env_resync Origin:%d->%d CAPVD:%d\n",
|
||||
loop1_Origin, new_origin, loop1_CAPVD);
|
||||
loop1_Origin = new_origin;
|
||||
loop1_freeze_cnt = 0;
|
||||
loop1_freeze_ref = 0;
|
||||
loop1_ORG_CNT = 0;
|
||||
loop1_ORG_SUM = 0;
|
||||
loop1_entry_cnt = 0;
|
||||
#if USE_SLOW_RELEASE
|
||||
loop1_CAPVD_slow = loop1_CAPVD; // 防替换后瞬态假释放 (同 V4.04 snap)
|
||||
#endif
|
||||
env_resync_abort();
|
||||
}
|
||||
|
||||
/*===========================================================================
|
||||
* vd1_task — 核心检测算法(对齐 M1H VD1_TASK)
|
||||
*
|
||||
@@ -719,6 +781,9 @@ void vd1_task(void)
|
||||
#define STABLE_ORIGIN_PPT 1 // 基准稳定判据: 窗口均值漂移 ≤ Origin×1/1000 (0.1%)
|
||||
#define STABLE_SETTLE_WINDOWS 2 // 连续 2 个窗口(每窗100样本≈1s)漂移达标 → 判稳
|
||||
#define STABLE_MAX_SAMPLES 500 // 硬兜底: 5s 未判稳强制结束自检(防绿灯无限闪)
|
||||
#define ENV_RESYNC_WAIT 6000 // V4.24: dev>+4dlt 高位连续 60s → 判定永久环境变化
|
||||
#define ENV_LEARN_WINDOW 200 // V4.24: 环境学习窗口 2s (200×10ms)
|
||||
#define ENV_LEARN_MAX_TICKS 3000 // V4.24: 学习预算 30s, 超时放弃 (防黄灯常亮死锁)
|
||||
|
||||
|
||||
if (loop1_Origin == 0) return;
|
||||
@@ -812,9 +877,13 @@ void vd1_task(void)
|
||||
/* 对称窗口内 → 正常基线跟踪 */
|
||||
loop1_freeze_cnt = 0;
|
||||
loop1_freeze_ref = 0; // V4.20: 清残留参考, 打印 FRZ 干净
|
||||
g_env_wait_cnt = 0; // V4.24: 高位回摆/目标靠近 → 等待重来
|
||||
env_resync_abort(); // V4.24: 学习中被打断 → 重算 (黄灯恢复)
|
||||
update_moving_average(&loop1_ORG_SUM, &loop1_ORG_CNT,
|
||||
&loop1_Origin, loop1_CAPVD, WINDOW_ORIGIN);
|
||||
} else if (dev < 0) {
|
||||
g_env_wait_cnt = 0; // V4.24: 目标靠近(车方向) → 等待重来
|
||||
env_resync_abort(); // V4.24: 学习中被打断 → 重算 (黄灯恢复)
|
||||
/* 正variation (CAPVD低于Origin, 疑似车辆) → 冻结, 保留原超时兜底更新 */
|
||||
if (loop1_freeze_cnt == 0) {
|
||||
loop1_freeze_ref = loop1_CAPVD;
|
||||
@@ -839,8 +908,13 @@ void vd1_task(void)
|
||||
loop1_ORG_SUM = 0;
|
||||
}
|
||||
} else {
|
||||
/* 负variation (CAPVD高于Origin, 特殊铁块磁导率主导/异常高) → 只冻结, 永不更新 Origin
|
||||
* 防 Origin 污染锁死; 权衡: 长时间负温漂基线不跟随(安全方向, 检测仍正常) */
|
||||
/* 负variation (CAPVD高于Origin, 特殊铁块磁导率主导/异常高)
|
||||
* V4.24 两段式:
|
||||
* ① 前 60s(ENV_RESYNC_WAIT): 只冻结, 不更新 Origin
|
||||
* (36321a1 双向保护原语义: 防铁块污染 Origin → 离开假进入锁死)
|
||||
* ② 高位连续 ≥60s 未回摆 → 判定"永久环境变化"(如金属板A拿走、基准被学低)
|
||||
* → 进入受控重校准: 连续空闲窗口均值 B + settle 判稳 → 空闲原子替换 Origin
|
||||
* 权衡: 铁块静止 60s+ 也会被学入 → 靠等待时长 + 黄灯常亮提示(操作接口) */
|
||||
if (loop1_freeze_cnt == 0) {
|
||||
loop1_freeze_ref = loop1_CAPVD;
|
||||
PRINT("EVT|neg_var_freeze CAPVD:%d Origin:%d dev:%d dlt:%d f:%dkHz\n",
|
||||
@@ -848,9 +922,57 @@ void vd1_task(void)
|
||||
calc_freq_khz(loop1_CAPVD, loop1_LPCNT));
|
||||
}
|
||||
loop1_freeze_cnt++;
|
||||
if (loop1_freeze_cnt > FREEZE_TIMEOUT) loop1_freeze_cnt = FREEZE_TIMEOUT; // 饱和, 不更新
|
||||
if (loop1_freeze_cnt > FREEZE_TIMEOUT) loop1_freeze_cnt = FREEZE_TIMEOUT; // 打印饱和, 不更新
|
||||
loop1_ORG_CNT = 0;
|
||||
loop1_ORG_SUM = 0;
|
||||
|
||||
if (!g_env_resync) {
|
||||
/*--- ① 等待确认: dev>+4dlt 高位连续累计 (回摆清零见窗口/dev<0分支) ---*/
|
||||
g_env_wait_cnt++;
|
||||
if (g_env_wait_cnt >= ENV_RESYNC_WAIT) {
|
||||
g_env_resync = 1;
|
||||
g_env_wait_cnt = 0;
|
||||
g_env_sum = 0;
|
||||
g_env_cnt = 0;
|
||||
g_env_prev = 0;
|
||||
g_env_settle = 0;
|
||||
g_env_tick = 0;
|
||||
PRINT("EVT|env_learn_start Origin:%d CAPVD:%d dev:%d\n",
|
||||
loop1_Origin, loop1_CAPVD, (int)dev);
|
||||
}
|
||||
} else {
|
||||
/*--- ② 学习基线 B: 连续空闲窗口均值 + settle 判稳 (同 V4.23 上电自检语义) ---*/
|
||||
g_env_tick++;
|
||||
g_env_sum += loop1_CAPVD;
|
||||
g_env_cnt++;
|
||||
if (g_env_cnt >= ENV_LEARN_WINDOW) {
|
||||
uint32_t _m = g_env_sum / g_env_cnt;
|
||||
uint32_t _drift, _band;
|
||||
g_env_sum = 0;
|
||||
g_env_cnt = 0;
|
||||
if (g_env_prev != 0) {
|
||||
_drift = (_m > g_env_prev) ? (_m - g_env_prev) : (g_env_prev - _m);
|
||||
_band = _m * STABLE_ORIGIN_PPT / 1000;
|
||||
if (_drift <= _band) {
|
||||
g_env_settle++;
|
||||
} else {
|
||||
g_env_settle = 0; // 窗口不稳 → 重算
|
||||
}
|
||||
if (g_env_settle >= STABLE_SETTLE_WINDOWS) {
|
||||
/* 连续 2 窗稳定 → B 可信; 空闲由上下文保证, 原子替换 */
|
||||
env_resync_apply(_m);
|
||||
return; // 本 tick 不再走进入判定
|
||||
}
|
||||
}
|
||||
g_env_prev = _m;
|
||||
}
|
||||
if (g_env_tick >= ENV_LEARN_MAX_TICKS) {
|
||||
/* 学习预算超时 → 放弃, 保留旧 Origin (宁可灵敏度低不冒险污染) */
|
||||
PRINT("EVT|env_learn_abort timeout Origin:%d CAPVD:%d\n",
|
||||
loop1_Origin, loop1_CAPVD);
|
||||
env_resync_abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1026,6 +1148,8 @@ void loop_task_function(void *pvParameters)
|
||||
g_disconnect_active = 0; // 重连,清除断开标记
|
||||
loop1_CAPVD = 0; // 强制 IIR 从首个有效值重新收敛
|
||||
loop1_CAPVD_slow = 0; // 方案A: 释放慢滤波同步收敛
|
||||
g_env_wait_cnt = 0; // V4.24: 断开重连后环境学习状态复位
|
||||
env_resync_abort();
|
||||
PRINT("EVT|loop_reconnect\n");
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user