fix(V4B): V4.25 黄灯预判改锁存语义 — 触发后回摆保持常亮, 环境空闲稳定5s才灭
原(V4.25首个提交): 黄灯条件 wait_cnt>=5s, 回摆(wait清零)即灭 — 用户反馈应锁存: 一旦5s黄灯常亮, 高位回摆/目标靠近也保持常亮; 只有"新的没有变化的环境" 超过5s 确认恢复, 黄灯才灭。 改动: - 新增 g_env_warn 预判锁存标志(只增不清): dev>+4dlt 高位累计满 ENV_WARN_WAIT=500tick(~5s) → g_env_warn=1, 黄灯常亮 - 新增 g_env_recover_cnt 恢复确认: 环境回窗口内且 dev 未进进入线(>-dlt) 连续 ENV_RECOVER_WAIT=500tick(~5s) → 解除锁存, 黄灯灭 - 目标进确认区(dev<-dlt)/深压(dev<-4dlt) → 恢复计时清零 - 高位重现 → 恢复计时清零, 黄灯保持 - abort/apply 均不清 g_env_warn (替换后也需恢复确认5s才灭) - 黄灯模式4条件 = g_env_resync || g_env_warn tests 5 场景: 回摆保持常亮→稳定5s灭→高位重现再锁存; 学习打断/放弃后锁存保持 docs: devlog V2.23 + spec V2.4 + 手册 V2.8 同步锁存语义
This commit is contained in:
+59
-20
@@ -21,7 +21,8 @@
|
||||
#define STABLE_SETTLE_WINDOWS 2 // 连续 2 窗漂移达标
|
||||
#define FREEZE_TIMEOUT 1000 // 打印饱和(dev>0 不再超时更新 Origin)
|
||||
#define ENV_RESYNC_WAIT 6000 // V4.24: dev>+4dlt 高位连续 60s → 判定永久环境变化
|
||||
#define ENV_WARN_WAIT 500 // V4.25: 高位连续 ~5s → 黄灯预判常亮 (TaskLoop.h)
|
||||
#define ENV_WARN_WAIT 500 // V4.25: 高位连续 ~5s → 黄灯预判锁存 (TaskLoop.h)
|
||||
#define ENV_RECOVER_WAIT 500 // V4.25: 环境回正常空闲连续 ~5s → 解除预判 (TaskLoop.h)
|
||||
#define ENV_LEARN_WINDOW 200 // V4.24: 环境学习窗口 2s
|
||||
#define ENV_LEARN_MAX_TICKS 3000 // V4.24: 学习预算 30s, 超时放弃
|
||||
|
||||
@@ -33,6 +34,8 @@ 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;
|
||||
|
||||
/* 场景镜像 (loop1_* 对应量) */
|
||||
static uint32_t sim_Origin;
|
||||
@@ -53,17 +56,20 @@ static void env_reset(void)
|
||||
g_env_prev = 0;
|
||||
g_env_settle = 0;
|
||||
g_env_tick = 0;
|
||||
g_env_warn = 0;
|
||||
g_env_recover_cnt = 0;
|
||||
}
|
||||
|
||||
/* V4.25: 黄灯模式4 条件镜像 (TaskLoop.c poll_yellow_led) */
|
||||
/* V4.25: 黄灯模式4 条件镜像 (TaskLoop.c poll_yellow_led) — 预判锁存 */
|
||||
static int env_warn_active(void)
|
||||
{
|
||||
return g_env_resync || g_env_wait_cnt >= ENV_WARN_WAIT;
|
||||
return g_env_resync || g_env_warn;
|
||||
}
|
||||
|
||||
/* 与 TaskLoop.c env_resync_abort/apply 逐行一致 */
|
||||
static void env_resync_abort(void)
|
||||
{
|
||||
/* V4.25: abort 只退出学习, 不清预判锁存 g_env_warn (环境未恢复前黄灯保持) */
|
||||
g_env_resync = 0;
|
||||
g_env_sum = 0;
|
||||
g_env_cnt = 0;
|
||||
@@ -91,15 +97,31 @@ static void sim_tick(void)
|
||||
g_env_wait_cnt = 0;
|
||||
if (g_env_resync) ev_abort++;
|
||||
env_resync_abort();
|
||||
/* V4.25: 恢复确认 — 空闲(dev>-dlt)连续 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;
|
||||
if (g_env_resync) ev_abort++;
|
||||
env_resync_abort();
|
||||
g_env_recover_cnt = 0; /* 目标深压 → 恢复计时清零 */
|
||||
} else {
|
||||
/* dev>0 高位 — V4.24 两段式 */
|
||||
/* 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; /* 预判锁存 (只增不清) */
|
||||
if (g_env_wait_cnt >= ENV_RESYNC_WAIT) {
|
||||
g_env_resync = 1;
|
||||
g_env_wait_cnt = 0;
|
||||
@@ -176,13 +198,15 @@ static void test_permanent_change_recovers(void)
|
||||
assert(ev_applied == 1);
|
||||
assert(tick == 6600); /* 6000 等待 + 3×200 窗 */
|
||||
assert(sim_Origin == 128856UL);
|
||||
assert(g_env_resync == 0); /* 替换后复位, 黄灯灭 */
|
||||
assert(g_env_resync == 0); /* 学习结束 */
|
||||
assert(env_warn_active() == 1);/* V4.25: 替换后黄灯保持 (恢复确认前不灭) */
|
||||
|
||||
/* 替换后 dev≈0 → 走窗口分支, 不再进 freeze/学习 */
|
||||
/* 替换后 dev≈0 → 窗口分支; 空闲连续 5s 恢复确认 → 黄灯灭 */
|
||||
for (int i = 0; i < 500; i++)
|
||||
sim_tick();
|
||||
assert(ev_applied == 1); /* 不再重复替换 */
|
||||
printf(" 场景1 PASS — 永久环境变化 ~66s 自动恢复, Origin 128095->128856\n\n");
|
||||
assert(env_warn_active() == 0);/* 恢复确认 5s 后黄灯灭 */
|
||||
printf(" 场景1 PASS — 永久环境变化 5s 预判锁存, ~66s 自动恢复, 恢复确认后灭\n\n");
|
||||
}
|
||||
|
||||
static void test_transient_never_learns(void)
|
||||
@@ -196,21 +220,28 @@ static void test_transient_never_learns(void)
|
||||
assert(env_warn_active() == 1); /* 黄灯预判已亮 (wait=4000) */
|
||||
printf("瞬态高位短停: 4000tick 时黄灯预判亮=%d (未学习)\n", env_warn_active());
|
||||
|
||||
/* 回摆进窗口 (CAPVD 回 Origin 附近), wait 清零 → 黄灯预判灭 */
|
||||
/* 回摆进窗口 (CAPVD 回 Origin 附近): wait 清零, 但预判锁存保持 (V4.25 核心语义) */
|
||||
sim_CAPVD = 128100UL; /* dev=+5 窗口内 */
|
||||
sim_tick();
|
||||
assert(g_env_wait_cnt == 0);
|
||||
assert(env_warn_active() == 0); /* 回摆解除, 黄灯灭 */
|
||||
assert(env_warn_active() == 1); /* 回摆不清黄灯, 保持常亮 */
|
||||
|
||||
/* 再次高位 59s(5900tick) — 仍不足 60s 连续 → 不学 */
|
||||
/* 窗口内连续 499 tick (累计 500 恢复确认) → 环境稳定, 解除预判 */
|
||||
for (int i = 0; i < 499; i++)
|
||||
sim_tick();
|
||||
assert(env_warn_active() == 0); /* 新环境稳定 5s, 黄灯灭 */
|
||||
assert(g_env_recover_cnt == 0);
|
||||
|
||||
/* 再次高位 59s(5900tick): 5s 后预判重新锁存, 但 <60s 不学习 */
|
||||
sim_CAPVD = 128856UL;
|
||||
for (int i = 0; i < 5900; i++)
|
||||
sim_tick();
|
||||
assert(ev_learn_start == 0);
|
||||
assert(ev_applied == 0);
|
||||
assert(sim_Origin == 128095UL);
|
||||
printf("瞬态高位短停: 不学习不替换, Origin 保持 (等待计数=%d)\n", g_env_wait_cnt);
|
||||
printf(" 场景2 PASS — 铁块类瞬态(60s内回摆)不触发重校准\n\n");
|
||||
assert(env_warn_active() == 1); /* 高位重现 → 预判重新锁存 */
|
||||
printf("瞬态高位短停: 回摆保持常亮→稳定5s灭→高位重现再锁存 (未学习)\n");
|
||||
printf(" 场景2 PASS — 铁块类瞬态(60s内回摆)不触发重校准, 预判锁存语义正确\n\n");
|
||||
}
|
||||
|
||||
static void test_learn_interrupted_restarts(void)
|
||||
@@ -226,9 +257,10 @@ static void test_learn_interrupted_restarts(void)
|
||||
sim_tick(); /* 学习窗1 未完 */
|
||||
sim_CAPVD = 128000UL; /* dev=-95 窗口内(B 目标) */
|
||||
sim_tick();
|
||||
assert(g_env_resync == 0); /* 打断退出 */
|
||||
assert(g_env_resync == 0); /* 打断退出学习 */
|
||||
assert(ev_abort == 1);
|
||||
assert(env_warn_active() == 0); /* wait 清零, 黄灯预判灭 */
|
||||
assert(env_warn_active() == 1); /* 预判锁存保持 (环境未确认恢复) */
|
||||
assert(g_env_recover_cnt == 0); /* 目标在进入确认区, 恢复计时清零 */
|
||||
|
||||
/* 目标离开, 高位重新 60s → 学习 3 窗 → 替换 */
|
||||
sim_CAPVD = 128856UL;
|
||||
@@ -240,7 +272,11 @@ static void test_learn_interrupted_restarts(void)
|
||||
assert(ev_applied == 1);
|
||||
assert(ev_learn_start == 2);
|
||||
assert(sim_Origin == 128856UL);
|
||||
printf(" 场景3 PASS — 学习期任何打断都重算, 完成后恢复\n\n");
|
||||
assert(env_warn_active() == 1); /* 替换后黄灯保持到恢复确认 */
|
||||
for (int i = 0; i < 500; i++)
|
||||
sim_tick(); /* 窗口恢复确认 5s */
|
||||
assert(env_warn_active() == 0); /* 黄灯灭 */
|
||||
printf(" 场景3 PASS — 学习期打断重算+锁存保持, 恢复确认后灭\n\n");
|
||||
}
|
||||
|
||||
static void test_unstable_learn_gives_up(void)
|
||||
@@ -259,13 +295,14 @@ static void test_unstable_learn_gives_up(void)
|
||||
sim_tick();
|
||||
}
|
||||
|
||||
printf("学习期不稳: 预算放弃 tick=%d applied=%d resync=%d Origin=%lu\n",
|
||||
tick, ev_applied, g_env_resync, (unsigned long)sim_Origin);
|
||||
printf("学习期不稳: 预算放弃 tick=%d applied=%d resync=%d warn=%d Origin=%lu\n",
|
||||
tick, ev_applied, g_env_resync, g_env_warn, (unsigned long)sim_Origin);
|
||||
assert(ev_applied == 0);
|
||||
assert(g_env_resync == 0); /* 超时放弃, 黄灯灭 */
|
||||
assert(g_env_resync == 0); /* 超时退出学习 */
|
||||
assert(env_warn_active() == 1); /* 环境仍异常 → 黄灯保持锁存 */
|
||||
assert(ev_abort >= 1);
|
||||
assert(sim_Origin == 128095UL); /* Origin 不被污染 */
|
||||
printf(" 场景4 PASS — 学习不稳定 30s 放弃, 宁可灵敏度低不冒险污染\n\n");
|
||||
printf(" 场景4 PASS — 学习不稳定 30s 放弃保留旧 Origin, 黄灯保持异常指示\n\n");
|
||||
}
|
||||
|
||||
static void test_no_learning_after_replace(void)
|
||||
@@ -280,7 +317,9 @@ static void test_no_learning_after_replace(void)
|
||||
for (int i = 0; i < 6000; i++)
|
||||
sim_tick(); /* 新 Origin 下高位条件消失 */
|
||||
assert(ev_learn_start == before); /* 无新学习 */
|
||||
printf("替换后稳态: 高位条件消失, 无重复学习 (Origin=%lu)\n", (unsigned long)sim_Origin);
|
||||
assert(env_warn_active() == 0); /* 恢复确认 5s 后黄灯已灭 */
|
||||
printf("替换后稳态: 高位条件消失, 无重复学习, 黄灯灭 (Origin=%lu)\n",
|
||||
(unsigned long)sim_Origin);
|
||||
printf(" 场景5 PASS — 恢复后进入正常跟踪, 不震荡\n\n");
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user