feat(V4B): V4.30 — 故障补偿时序: 预判3s + 补偿8s + 恢复2s (总恢复 ~16s)

拍板: 预判 ENV_WARN_WAIT 500→300(3s); 补偿 ENV_RESYNC_WAIT 1000→800(8s);
恢复确认 ENV_RECOVER_WAIT 500→200(2s, 新基线替换后空闲稳定即灭灯)
时序: 3s 黄灯预判锁存 → 8s 进入学习 → 6s(3×200tick)学完原子替换 → 2s 确认灭
test_env_resync.c 重写: 镜像与固件逐分支一致(学习中压线=搁置不退出/学习仅高位段
计数/abort后循环重触发) → 5 场景 ALL PASS (warn@300, applied@1400, 灭@1600)
文档: devlog V2.28 / spec V2.9 / design doc v0.7
This commit is contained in:
wangfq
2026-09-03 16:08:21 +08:00
parent 71feb3e06d
commit 4200d96250
7 changed files with 288 additions and 232 deletions
+241 -222
View File
@@ -1,133 +1,101 @@
/*
* test_env_resync.c — 环境重校准(受控基线更新) gcc 隔离单测 (DLD154V4B V4.26)
* test_env_resync.c — 环境重校准(受控基线更新) gcc 隔离单测 (DLD154V4B V4.30)
*
* 验证对象: 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 时同步此处!)
* 镜像 = TaskLoop.c vd1_task() 无车段 dev>0 分支 (V4.24/25/26/30), 逻辑与固件一致:
* - 高位 dev>+4dlt: 等待确认(g_env_wait_cnt) → 满 ENV_WARN_WAIT 预判锁存 g_env_warn
* - 满 ENV_RESYNC_WAIT → 进入学习 g_env_resync(高位段才计数; 压线/回摆=搁置)
* - 学习: 200 样本/窗, 窗均值漂移 ≤0.1% 连续 2 窗 → env_resync_apply 原子替换
* - 预算 ENV_LEARN_MAX_TICKS 超时 → abort 不污染
* - 非高位空闲 dev>-dlt 连续 ENV_RECOVER_WAIT → 清 g_env_warn (黄灯灭)
* V4.30 拍板: 预判 3s + 补偿 8s + 替换后空闲 2s
* 镜像宏与固件一致(改 ENV_* 时同步此处!)
*/
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <stdint.h>
#define ENV_WARN_WAIT 500
#define ENV_RECOVER_WAIT 500
#define ENV_RESYNC_WAIT 1000 /* V4.26: 60s->10s (拍板4) */
/* ===== 镜像固件宏 (TaskLoop.c/TaskLoop.h 同步) ===== */
#define ENV_WARN_WAIT 300 /* V4.30: 预判 3s */
#define ENV_RECOVER_WAIT 200 /* V4.30: 替换后空闲 2s 恢复确认 */
#define ENV_RESYNC_WAIT 800 /* V4.30: 补偿(学习等待) 8s */
#define ENV_LEARN_WINDOW 200
#define ENV_LEARN_MAX_TICKS 3000
#define STABLE_ORIGIN_PPT 1
#define STABLE_SETTLE_WINDOWS 2
#define dlt_4x 192 /* dlt=48 → 4×dlt (SENS=3) */
#define FREEZE_BAND_MULT 4 /* freeze_band = dlt*4 */
/* ===== 镜像全局 ===== */
static uint32_t sim_Origin = 128095UL; /* A 在场基线 */
static uint32_t sim_CAPVD = 128095UL;
static uint32_t g_env_wait_cnt = 0;
static uint32_t g_env_recover_cnt = 0;
static uint32_t g_env_resync = 0; /* 学习中 */
static uint32_t g_env_warn = 0; /* 预判锁存 */
static uint32_t g_env_tick = 0; /* 学习预算计数 */
static uint32_t g_env_sum = 0; /* 学习窗累加 */
static uint32_t g_env_cnt = 0; /* 学习窗样本数 */
static uint32_t g_env_prev = 0; /* 上一窗均值 */
static uint32_t g_env_settle = 0; /* 连续稳定窗数 */
static uint32_t sim_learn_start_cnt = 0;
static uint32_t sim_applied_cnt = 0;
static uint32_t sim_abort_cnt = 0;
static uint32_t sim_tick_cnt = 0;
/* --- 镜像状态 --- */
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;
static int env_warn_active(void) { return (g_env_warn != 0 || g_env_resync != 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)
/* ===== 镜像: env_resync_apply / env_resync_abort (TaskLoop.c 逻辑复刻) ===== */
static void env_resync_apply(uint32_t new_origin)
{
g_env_resync = 0;
sim_Origin = new_origin; /* 空闲原子替换 */
sim_applied_cnt++;
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 条件镜像 */
g_env_sum = 0;
g_env_cnt = 0;
g_env_prev = 0;
g_env_settle = 0;
g_env_tick = 0;
g_env_recover_cnt = 0; /* 替换后重新计恢复确认 */
}
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++;
sim_abort_cnt++;
g_env_resync = 0;
g_env_sum = 0;
g_env_cnt = 0;
g_env_prev = 0;
g_env_settle = 0;
g_env_tick = 0;
g_env_wait_cnt = 0;
}
/* vd1_task 无车段 dev 分支的 env 相关逻辑镜像 (V4.26) */
static void sim_tick(void)
/* ===== 镜像: vd1_task 无车段 dev 分支 (TaskLoop.c 复刻, V4.30) ===== */
static void vd_env_branch(void)
{
int32_t dev;
int32_t freeze_band;
int32_t dev = (int32_t)sim_CAPVD - (int32_t)sim_Origin;
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 (dev > (int32_t)dlt_4x) {
/* ── 高位: 等待确认 / 学习 ── */
if (!g_env_resync) {
g_env_wait_cnt++;
g_env_recover_cnt = 0; /* 高位异常中恢复确认失效 */
if (g_env_wait_cnt >= ENV_WARN_WAIT)
g_env_warn = 1; /* 5s 预判锁存 */
g_env_warn = 1; /* 预判锁存 (只增不清) */
if (g_env_wait_cnt >= ENV_RESYNC_WAIT) {
sim_learn_start_cnt++;
g_env_resync = 1;
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;
g_env_sum = 0;
g_env_cnt = 0;
g_env_prev = 0;
g_env_settle = 0;
g_env_tick = 0;
sim_learn_start_cnt++;
}
} else {
/* 学习中: 窗口均值 + settle 判稳 */
/* ── 学习基线 B: 连续空闲窗口均值 + settle 判稳 ── */
g_env_tick++;
g_env_sum += sim_CAPVD;
g_env_cnt++;
@@ -138,198 +106,249 @@ static void sim_tick(void)
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)
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;
if (g_env_settle >= STABLE_SETTLE_WINDOWS) {
env_resync_apply(_m); /* 连续 2 窗稳定 → B 可信, 原子替换 */
return;
}
} else {
g_env_settle = 0; /* 窗口不稳 → 重算 */
}
}
g_env_prev = _m;
}
if (g_env_tick >= ENV_LEARN_MAX_TICKS) {
env_resync_abort(); /* 预算超时放弃 (保留旧 Origin) */
}
if (g_env_tick >= ENV_LEARN_MAX_TICKS)
env_resync_abort(); /* 预算超时 → 放弃不污染 */
}
return;
}
/* ── 非高位: 高位累计清零 (回摆/压线/空闲); 学习中则搁置(不计数) ── */
g_env_wait_cnt = 0;
if (dev < -48) { /* 目标压入进入确认区 */
g_env_recover_cnt = 0;
return;
}
/* 空闲 (dev > -dlt): 环境恢复正常 → 恢复确认计时 → 清预判(黄灯灭) */
g_env_recover_cnt++;
if (g_env_recover_cnt >= ENV_RECOVER_WAIT) {
g_env_warn = 0; /* 稳定 2s → 解除预判 */
g_env_recover_cnt = 0;
}
}
/* ============ 场景 1: 永久变化 (A拿走) ~21s 恢复 ============ */
static void sim_tick(void)
{
sim_tick_cnt++;
vd_env_branch();
}
/* ===== 场景隔离 ===== */
static void reset_all(void)
{
sim_Origin = 128095UL;
sim_CAPVD = 128095UL;
g_env_wait_cnt = 0;
g_env_recover_cnt = 0;
g_env_resync = 0;
g_env_warn = 0;
g_env_tick = 0;
g_env_sum = 0;
g_env_cnt = 0;
g_env_prev = 0;
g_env_settle = 0;
sim_learn_start_cnt = 0;
sim_applied_cnt = 0;
sim_abort_cnt = 0;
sim_tick_cnt = 0;
}
/* ===== 场景 1: 永久变化 (A 拿走) — 3s 预判 → 8s 触发 → 3窗学完 ~14s 替换 → +2s 灭 ===== */
static void test_permanent_change_recovers(void)
{
int tick, warn_at = 0;
int tick, warn_at = 0;
int loop;
env_reset();
sim_Origin = 128095UL; sim_CAPVD = 128856UL;
for (tick = 0; tick < 4000 && !sim_applied; tick++) {
reset_all();
for (loop = 0; loop < 2500; loop++) {
sim_CAPVD = 128856UL; /* dev=761 恒高位 */
sim_tick();
if (!warn_at && env_warn_active())
warn_at = (int)sim_tick_cnt;
if (sim_applied_cnt)
break;
}
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 预判锁存 */
printf("1. 永久变化: warn_at=%d learn_start=%d applied_at=%d Origin=%u (期望 300 / 1 / ~1400 / 128856)\n",
warn_at, sim_learn_start_cnt, (int)sim_tick_cnt, sim_Origin);
assert(warn_at == 300);
assert(sim_learn_start_cnt == 1);
assert(sim_applied == 1);
assert(sim_applied_origin == 128856UL); /* 替换到真空场 */
assert(sim_applied_cnt == 1);
assert(sim_Origin == 128856UL);
assert(env_warn_active() == 1); /* 替换后黄灯保持 (等待恢复确认) */
/* 空闲 5s 恢复确认 → 灭 */
for (tick = 0; tick < 600; tick++)
/* 替换后 +2s (200tick) 恢复确认 → 黄灯灭 */
for (tick = 0; tick < 200; tick++) {
sim_CAPVD = 128856UL; /* dev=0 空闲稳态 */
sim_tick();
assert(env_warn_active() == 0);
}
printf(" 替换后 200tick: warn=%d resync=%d (期望 0/0 → 灭)\n", g_env_warn, g_env_resync);
assert(g_env_warn == 0);
assert(g_env_resync == 0);
assert(sim_applied_cnt == 1);
printf(" 恢复确认后黄灯灭 OK\n");
}
/* ============ 场景 2: 瞬态高位 (<10s 回摆) 不学, 锁存保持到恢复确认 ============ */
static void test_transient_no_learn(void)
/* ===== 场景 2: 瞬态高位 7s (<8s) 不学 + 锁存保持 + 空闲 2s 灭 ===== */
static void test_transient_keeps_warn(void)
{
int i;
int loop;
env_reset();
sim_Origin = 128095UL; sim_CAPVD = 128856UL;
/* 高位 9s (900tick): 预判 5s 亮, 但 <10s 不学习 */
for (i = 0; i < 900; i++)
reset_all();
for (loop = 0; loop < 700; loop++) { /* 7s 高位 */
sim_CAPVD = 128856UL;
sim_tick();
}
printf("2. 瞬态 7s 高位: warn=%d learn=%d (期望 1 / 0)\n", g_env_warn, sim_learn_start_cnt);
assert(env_warn_active() == 1);
assert(sim_learn_start_cnt == 0);
/* 回摆进窗口: wait 清零但预判锁存保持 */
sim_CAPVD = 128100UL; /* dev=+5 */
sim_CAPVD = 128000UL; /* 回摆 dev=-95 (目标压入) → 锁存保持 */
sim_tick();
assert(g_env_wait_cnt == 0);
assert(env_warn_active() == 1); /* 回摆不清黄灯 (拍板锁存语义) */
printf(" 回摆后: warn=%d resync=%d (期望 warn 1 保持)\n", g_env_warn, g_env_resync);
assert(g_env_warn == 1);
assert(g_env_resync == 0);
/* 窗口空闲 499tick (累计500恢复确认) → 灭 */
for (i = 0; i < 499; i++)
for (loop = 0; loop < 200; loop++) { /* 空闲 2s → 恢复确认 → 灭 */
sim_CAPVD = 128095UL;
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);
}
printf(" 空闲 200tick: warn=%d (期望 0 → 灭)\n", g_env_warn);
assert(g_env_warn == 0);
assert(sim_learn_start_cnt == 0);
assert(sim_applied == 0);
assert(sim_Origin == 128095UL);
printf("2. 瞬态高位(<10s)不学, 锁存保持, 恢复确认后灭 OK\n");
for (loop = 0; loop < 700; loop++) { /* 再 7s 高位 → 重新锁存, 仍不学 */
sim_CAPVD = 128856UL;
sim_tick();
}
printf(" 二次 7s 高位: warn=%d learn=%d (期望 1 / 0)\n", g_env_warn, sim_learn_start_cnt);
assert(g_env_warn == 1);
assert(sim_learn_start_cnt == 0);
printf("2. 瞬态高位(<8s)不学, 锁存保持, 恢复确认后灭 OK\n");
}
/* ============ 场景 3: 学习期打断重算 + 最终恢复 ============ */
static void test_learn_interrupt_retry(void)
/* ===== 场景 3: 学习期目标压线 = 搁置(不退出) → 走后再学完 → 替换 ===== */
static void test_interrupted_learn_recomputes(void)
{
int i;
int learn_start_before;
int loop;
int applied_at = 0;
env_reset();
sim_Origin = 128095UL; sim_CAPVD = 128856UL;
/* 10s 高位 → 学习开始 */
for (i = 0; i < 1000; i++)
reset_all();
for (loop = 0; loop < 800; loop++) { /* 8s → 学习开始 */
sim_CAPVD = 128856UL;
sim_tick();
}
assert(sim_learn_start_cnt == 1);
assert(g_env_resync == 1);
/* 学习 100 tick 后目标靠近 (dev=-95 进入确认区) → 打断 */
for (i = 0; i < 100; i++)
for (loop = 0; loop < 100; loop++) { /* 学习 100tick (801..900) */
sim_CAPVD = 128856UL;
sim_tick();
sim_CAPVD = 128000UL; /* dev=-95 */
}
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); /* 目标在进入确认区 → 恢复计时清零 */
printf("3. 压线打断: resync=%d tick=%u learn=%d warn=%d (期望 resync 1 保持=搁置)\n",
g_env_resync, g_env_tick, sim_learn_start_cnt, g_env_warn);
assert(g_env_resync == 1); /* 不退出学习 */
assert(g_env_warn == 1);
/* 目标离开, 高位重现 → 重新等待 10s + 学习 3 窗 → 替换 */
learn_start_before = sim_learn_start_cnt;
sim_CAPVD = 128856UL;
for (i = 0; i < 4000 && !sim_applied; i++)
for (loop = 0; loop < 1600; loop++) { /* 目标走 → 继续高位学习 → 替换 */
sim_CAPVD = 128856UL;
sim_tick();
assert(sim_learn_start_cnt == learn_start_before + 1);
assert(sim_applied == 1);
if (sim_applied_cnt) { applied_at = (int)sim_tick_cnt; break; }
}
printf(" 继续学后: applied_at=%d learn=%d Origin=%u (期望 ~1400 / 1 / 128856)\n",
applied_at, sim_learn_start_cnt, sim_Origin);
assert(sim_applied_cnt == 1);
assert(sim_learn_start_cnt == 1); /* 全程仅一次学习启动 */
assert(sim_Origin == 128856UL);
assert(env_warn_active() == 1); /* 替换后保持到恢复确认 */
/* 空闲 5s → 黄灯灭 */
for (i = 0; i < 600; i++)
for (loop = 0; loop < 200; loop++) { /* +2s 恢复确认 → 灭 */
sim_CAPVD = 128856UL;
sim_tick();
assert(env_warn_active() == 0);
printf("3. 学习期打断重算, 最终恢复 OK\n");
}
assert(g_env_warn == 0);
printf("3. 学习期压线=搁置, 恢复后学完替换, 灭 OK\n");
}
/* ============ 场景 4: 学习期持续不稳 → 30s 预算放弃 ============ */
static void test_learn_unstable_abort(void)
/* ===== 场景 4: 学习不稳 → 预算 30s 放弃 — 不污染, 黄灯保持 ===== */
static void test_unstable_learn_gives_up(void)
{
int i;
int loop;
int i;
env_reset();
sim_Origin = 128095UL;
/* 高位 10s → 学习开始; 然后窗口均值交替漂移 >0.1% (129056/129256) */
for (i = 0; i < 1000; i++) {
reset_all();
for (loop = 0; loop < 800; loop++) {
sim_CAPVD = 128856UL;
sim_tick();
}
assert(g_env_resync == 1);
assert(sim_learn_start_cnt == 1);
for (i = 0; i < 3500; i++) {
/* 每窗 200 样本交替 129056 / 129256 → 窗间漂移 200 > band~129 → settle 恒 0 */
for (i = 0; i < 3800 && !sim_abort_cnt; i++) { /* 每窗 200 样本交替 → 漂移 200 > band~129 → 恒不稳 */
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");
printf("4. 不稳学习: resync=%d abort=%d applied=%d warn=%d Origin=%u (期望 0/1/0/1/128095)\n",
g_env_resync, sim_abort_cnt, sim_applied_cnt, g_env_warn, sim_Origin);
assert(g_env_resync == 0);
assert(sim_abort_cnt >= 1);
assert(sim_applied_cnt == 0);
assert(sim_Origin == 128095UL); /* 不污染 */
assert(g_env_warn == 1); /* 环境仍异常 → 黄灯保持 */
printf("4. 学习放弃不污染, 黄灯保持 OK\n");
}
/* ============ 场景 5: 替换后不震荡, 无重复学习 ============ */
static void test_no_oscillation_after_apply(void)
/* ===== 场景 5: 替换后稳态无重复学习 ===== */
static void test_no_repeat_learn(void)
{
int i, lsc;
int loop;
env_reset();
sim_Origin = 128095UL; sim_CAPVD = 128856UL;
for (i = 0; i < 4000 && !sim_applied; i++)
reset_all();
for (loop = 0; loop < 800; loop++) {
sim_CAPVD = 128856UL;
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); /* 未被再次改写 */
}
for (loop = 0; loop < 1000; loop++) {
sim_CAPVD = 128856UL;
sim_tick();
if (sim_applied_cnt)
break;
}
printf("5. 替换后稳态: applied=%d learn=%d warn=%d Origin=%u (期望 1/1/1/128856)\n",
sim_applied_cnt, sim_learn_start_cnt, g_env_warn, sim_Origin);
assert(sim_applied_cnt == 1);
assert(sim_learn_start_cnt == 1);
assert(sim_Origin == 128856UL);
assert(env_warn_active() == 0); /* 恢复确认后黄灯已灭 */
printf("5. 替换后不震荡无重复学习 OK\n");
assert(g_env_warn == 1); /* 替换后 warn 锁存, 待恢复确认 */
for (loop = 0; loop < 1000; loop++) { /* 空闲稳态 10s → 灭且无重复学习 */
sim_CAPVD = 128856UL;
sim_tick();
}
assert(sim_applied_cnt == 1);
assert(sim_learn_start_cnt == 1);
assert(g_env_warn == 0);
printf("5. 替换后无重复学习, 恢复确认后灭 OK\n");
}
int main(void)
{
printf("test_env_resync (V4.30: 预判3s/补偿8s/恢复2s)\n");
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);
test_transient_keeps_warn();
test_interrupted_learn_recomputes();
test_unstable_learn_gives_up();
test_no_repeat_learn();
printf("ALL PASS (ENV_WARN 300 / RESYNC 800 / RECOVER 200)\n");
return 0;
}