/* * test_env_resync.c — 环境重校准(受控基线更新) gcc 隔离单测 (DLD154V4B V4.26) * * 验证对象: TaskLoop.c vd1_task() 无车段 dev>0 分支 (V4.24/25 两段式, V4.26 参数更新) * ─ 现场场景 (2026-09-02 实测): 线圈旁金属板A上电 → Origin 学低(128096) * A 拿走 → CAPVD 弹回 128856 dev=+761(0.59%) > +4dlt → 冻结累计 * ─ V4.26 拍板: ENV_RESYNC_WAIT 60s→10s(故障补偿提速), 其余语义不变 * * 黄灯语义 (poll_yellow_led): 5s 预判锁存(g_env_warn, 回摆保持) → * 10s 进入学习(g_env_resync, 常亮) → 空闲原子替换 Origin → 空闲 5s 恢复确认 → 灭 * * 镜像宏与固件一致(改 ENV_RESYNC_WAIT 时同步此处!) */ #include #include #include #define ENV_WARN_WAIT 500 #define ENV_RECOVER_WAIT 500 #define ENV_RESYNC_WAIT 1000 /* V4.26: 60s->10s (拍板4) */ #define ENV_LEARN_WINDOW 200 #define ENV_LEARN_MAX_TICKS 3000 #define STABLE_ORIGIN_PPT 1 #define STABLE_SETTLE_WINDOWS 2 #define FREEZE_BAND_MULT 4 /* freeze_band = dlt*4 */ /* --- 镜像状态 --- */ static uint32_t sim_Origin = 128095UL; static uint32_t sim_CAPVD = 128856UL; static uint32_t sim_dlt = 48UL; static uint8_t sim_learn_start_cnt = 0; static uint8_t sim_applied = 0; static uint32_t sim_applied_origin = 0; static uint32_t sim_applied_tick = 0; static uint8_t sim_abort = 0; static uint32_t sim_tick_cnt = 0; /* --- g_env_* 镜像 (与固件同名) --- */ static uint8_t g_env_resync = 0; static uint16_t g_env_wait_cnt = 0; static uint32_t g_env_sum = 0; static uint16_t g_env_cnt = 0; static uint32_t g_env_prev = 0; static uint8_t g_env_settle = 0; static uint16_t g_env_tick = 0; static uint8_t g_env_warn = 0; static uint16_t g_env_recover_cnt = 0; static void env_reset(void) { 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; g_env_warn = 0; g_env_recover_cnt = 0; sim_learn_start_cnt = 0; sim_applied = 0; sim_abort = 0; sim_tick_cnt = 0; } static int env_warn_active(void) { return g_env_resync || g_env_warn; /* poll_yellow_led 模式4 条件镜像 */ } 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; sim_abort++; } /* vd1_task 无车段 dev 三分支的 env 相关逻辑镜像 (V4.26) */ static void sim_tick(void) { int32_t dev; int32_t freeze_band; sim_tick_cnt++; dev = (int32_t)sim_CAPVD - (int32_t)sim_Origin; freeze_band = (int32_t)(sim_dlt * FREEZE_BAND_MULT); if (dev < freeze_band && dev > -freeze_band) { /* 对称窗口内 → 正常基线跟踪 (env 相关) */ g_env_wait_cnt = 0; if (g_env_resync) env_resync_abort(); /* V4.25: 恢复确认 — 真空闲(未进进入线)连续 5s 解除预判锁存 */ if (dev > -(int32_t)sim_dlt) { if (g_env_warn) { g_env_recover_cnt++; if (g_env_recover_cnt >= ENV_RECOVER_WAIT) { g_env_warn = 0; g_env_recover_cnt = 0; } } } else { g_env_recover_cnt = 0; /* 目标在进入确认区 → 恢复计时重来 */ } } else if (dev < 0) { /* 车方向 → 冻结 (env 相关) */ g_env_wait_cnt = 0; g_env_recover_cnt = 0; if (g_env_resync) env_resync_abort(); } else { /* dev>0 高位 — 两段式 (V4.24) + 预判锁存 (V4.25) */ g_env_recover_cnt = 0; if (!g_env_resync) { g_env_wait_cnt++; if (g_env_wait_cnt >= ENV_WARN_WAIT) g_env_warn = 1; /* 5s 预判锁存 */ if (g_env_wait_cnt >= ENV_RESYNC_WAIT) { sim_learn_start_cnt++; 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; } } else { /* 学习中: 窗口均值 + settle 判稳 */ g_env_tick++; g_env_sum += sim_CAPVD; g_env_cnt++; if (g_env_cnt >= ENV_LEARN_WINDOW) { uint32_t _m = g_env_sum / g_env_cnt; g_env_sum = 0; g_env_cnt = 0; if (g_env_prev != 0) { uint32_t _drift = (_m > g_env_prev) ? (_m - g_env_prev) : (g_env_prev - _m); uint32_t _band = _m * STABLE_ORIGIN_PPT / 1000; if (_drift <= _band) g_env_settle++; else g_env_settle = 0; if (g_env_settle >= STABLE_SETTLE_WINDOWS) { sim_applied = 1; sim_applied_origin = _m; sim_applied_tick = sim_tick_cnt; sim_Origin = _m; /* 原子替换 (空闲由上下文保证) */ 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; return; } } g_env_prev = _m; } if (g_env_tick >= ENV_LEARN_MAX_TICKS) { env_resync_abort(); /* 预算超时放弃 (保留旧 Origin) */ } } } } /* ============ 场景 1: 永久变化 (A拿走) ~21s 恢复 ============ */ static void test_permanent_change_recovers(void) { int tick, warn_at = 0; env_reset(); sim_Origin = 128095UL; sim_CAPVD = 128856UL; for (tick = 0; tick < 4000 && !sim_applied; tick++) { sim_tick(); if (!warn_at && env_warn_active()) warn_at = (int)sim_tick_cnt; } printf("1. 永久变化: warn_at=%d learn=%d applied_at=%d Origin=%u (期望 warn 500, learn>=1000, applied~1600)\n", warn_at, sim_learn_start_cnt, (int)sim_applied_tick, sim_Origin); assert(warn_at == 500); /* 5s 预判锁存 */ assert(sim_learn_start_cnt == 1); assert(sim_applied == 1); assert(sim_applied_origin == 128856UL); /* 替换到真空场 */ assert(sim_Origin == 128856UL); assert(env_warn_active() == 1); /* 替换后黄灯保持 (等待恢复确认) */ /* 空闲 5s 恢复确认 → 灭 */ for (tick = 0; tick < 600; tick++) sim_tick(); assert(env_warn_active() == 0); printf(" 恢复确认后黄灯灭 OK\n"); } /* ============ 场景 2: 瞬态高位 (<10s 回摆) 不学, 锁存保持到恢复确认 ============ */ static void test_transient_no_learn(void) { int i; env_reset(); sim_Origin = 128095UL; sim_CAPVD = 128856UL; /* 高位 9s (900tick): 预判 5s 亮, 但 <10s 不学习 */ for (i = 0; i < 900; i++) sim_tick(); assert(env_warn_active() == 1); assert(sim_learn_start_cnt == 0); /* 回摆进窗口: wait 清零但预判锁存保持 */ sim_CAPVD = 128100UL; /* dev=+5 */ sim_tick(); assert(g_env_wait_cnt == 0); assert(env_warn_active() == 1); /* 回摆不清黄灯 (拍板锁存语义) */ /* 窗口空闲 499tick (累计500恢复确认) → 灭 */ for (i = 0; i < 499; i++) sim_tick(); assert(env_warn_active() == 0); assert(g_env_recover_cnt == 0); /* 再高位 9s → 又锁存, 仍不学习 */ sim_CAPVD = 128856UL; for (i = 0; i < 900; i++) sim_tick(); assert(env_warn_active() == 1); assert(sim_learn_start_cnt == 0); assert(sim_applied == 0); assert(sim_Origin == 128095UL); printf("2. 瞬态高位(<10s)不学, 锁存保持, 恢复确认后灭 OK\n"); } /* ============ 场景 3: 学习期打断重算 + 最终恢复 ============ */ static void test_learn_interrupt_retry(void) { int i; int learn_start_before; env_reset(); sim_Origin = 128095UL; sim_CAPVD = 128856UL; /* 10s 高位 → 学习开始 */ for (i = 0; i < 1000; i++) sim_tick(); assert(sim_learn_start_cnt == 1); assert(g_env_resync == 1); /* 学习 100 tick 后目标靠近 (dev=-95 进入确认区) → 打断 */ for (i = 0; i < 100; i++) sim_tick(); sim_CAPVD = 128000UL; /* dev=-95 */ sim_tick(); assert(g_env_resync == 0); /* 打断退出学习 */ assert(sim_abort >= 1); assert(env_warn_active() == 1); /* 预判锁存保持 (环境未确认恢复) */ assert(g_env_recover_cnt == 0); /* 目标在进入确认区 → 恢复计时清零 */ /* 目标离开, 高位重现 → 重新等待 10s + 学习 3 窗 → 替换 */ learn_start_before = sim_learn_start_cnt; sim_CAPVD = 128856UL; for (i = 0; i < 4000 && !sim_applied; i++) sim_tick(); assert(sim_learn_start_cnt == learn_start_before + 1); assert(sim_applied == 1); assert(sim_Origin == 128856UL); assert(env_warn_active() == 1); /* 替换后保持到恢复确认 */ /* 空闲 5s → 黄灯灭 */ for (i = 0; i < 600; i++) sim_tick(); assert(env_warn_active() == 0); printf("3. 学习期打断重算, 最终恢复 OK\n"); } /* ============ 场景 4: 学习期持续不稳 → 30s 预算放弃 ============ */ static void test_learn_unstable_abort(void) { int i; env_reset(); sim_Origin = 128095UL; /* 高位 10s → 学习开始; 然后窗口均值交替漂移 >0.1% (129056/129256) */ for (i = 0; i < 1000; i++) { sim_CAPVD = 128856UL; sim_tick(); } assert(g_env_resync == 1); for (i = 0; i < 3500; i++) { /* 每窗 200 样本交替 129056 / 129256 → 窗间漂移 200 > band~129 → settle 恒 0 */ sim_CAPVD = ((i / 200) & 1) ? 129256UL : 129056UL; sim_tick(); } /* 1000(等待) + 3000(学习预算) ≈ 放弃于 tick 4000; 总 tick 4500 < 再学阈值(5000) */ assert(sim_learn_start_cnt == 1); /* 只有一次学习启动 */ assert(sim_applied == 0); /* 未替换 */ assert(sim_Origin == 128095UL); /* 旧 Origin 保留 (不冒险污染) */ assert(g_env_resync == 0); /* 预算 30s 放弃 */ assert(env_warn_active() == 1); /* 环境仍异常 → 黄灯保持 */ printf("4. 学习不稳 30s 放弃, 保留旧 Origin, 黄灯保持 OK\n"); } /* ============ 场景 5: 替换后不震荡, 无重复学习 ============ */ static void test_no_oscillation_after_apply(void) { int i, lsc; env_reset(); sim_Origin = 128095UL; sim_CAPVD = 128856UL; for (i = 0; i < 4000 && !sim_applied; i++) sim_tick(); assert(sim_applied == 1); lsc = sim_learn_start_cnt; for (i = 0; i < 6000; i++) sim_tick(); /* 窗口内持续 (dev≈0) */ assert(sim_learn_start_cnt == lsc); /* 无重复学习 */ assert(sim_applied == 1); /* 未被再次改写 */ assert(sim_Origin == 128856UL); assert(env_warn_active() == 0); /* 恢复确认后黄灯已灭 */ printf("5. 替换后不震荡无重复学习 OK\n"); } int main(void) { test_permanent_change_recovers(); test_transient_no_learn(); test_learn_interrupt_retry(); test_learn_unstable_abort(); test_no_oscillation_after_apply(); printf("\nALL PASS (ENV_RESYNC_WAIT=%d)\n", ENV_RESYNC_WAIT); return 0; }