V4.30 基础上现场手感再收紧: ENV_WARN_WAIT 300→200(2s); ENV_RESYNC_WAIT 800→700(7s); 恢复确认 200(2s) 不变 时序: 2s 黄灯预判锁存 → 7s 进入学习 → 6s 学完原子替换 → 2s 确认灭 test_env_resync.c 同步 → 5 场景 ALL PASS (warn@200, applied@1300, 灭@1500) 文档: devlog V2.29 / spec V2.10 / design doc v0.8
355 lines
13 KiB
C
355 lines
13 KiB
C
/*
|
||
* test_env_resync.c — 环境重校准(受控基线更新) gcc 隔离单测 (DLD154V4B V4.31)
|
||
*
|
||
* 镜像 = TaskLoop.c vd1_task() 无车段 dev>0 分支 (V4.24/25/26/30/31), 逻辑与固件一致:
|
||
* - 高位 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.31 拍板: 预判 2s + 补偿 7s + 替换后空闲 2s 灭
|
||
* 镜像宏与固件一致(改 ENV_* 时同步此处!)
|
||
*/
|
||
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
#include <assert.h>
|
||
#include <stdint.h>
|
||
|
||
/* ===== 镜像固件宏 (TaskLoop.c/TaskLoop.h 同步) ===== */
|
||
#define ENV_WARN_WAIT 200 /* V4.31: 预判 2s */
|
||
#define ENV_RECOVER_WAIT 200 /* V4.30: 替换后空闲 2s 恢复确认 */
|
||
#define ENV_RESYNC_WAIT 700 /* V4.31: 补偿(学习等待) 7s */
|
||
#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) */
|
||
|
||
/* ===== 镜像全局 ===== */
|
||
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 int env_warn_active(void) { return (g_env_warn != 0 || g_env_resync != 0); }
|
||
|
||
/* ===== 镜像: env_resync_apply / env_resync_abort (TaskLoop.c 逻辑复刻) ===== */
|
||
static void env_resync_apply(uint32_t new_origin)
|
||
{
|
||
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_recover_cnt = 0; /* 替换后重新计恢复确认 */
|
||
}
|
||
|
||
static void env_resync_abort(void)
|
||
{
|
||
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 分支 (TaskLoop.c 复刻, V4.30) ===== */
|
||
static void vd_env_branch(void)
|
||
{
|
||
int32_t dev = (int32_t)sim_CAPVD - (int32_t)sim_Origin;
|
||
|
||
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; /* 预判锁存 (只增不清) */
|
||
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;
|
||
sim_learn_start_cnt++;
|
||
}
|
||
} else {
|
||
/* ── 学习基线 B: 连续空闲窗口均值 + 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++;
|
||
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(); /* 预算超时 → 放弃不污染 */
|
||
}
|
||
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;
|
||
}
|
||
}
|
||
|
||
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 拿走) — 2s 预判 → 7s 触发 → 3窗学完 ~13s 替换 → +2s 灭 ===== */
|
||
static void test_permanent_change_recovers(void)
|
||
{
|
||
int tick, warn_at = 0;
|
||
int loop;
|
||
|
||
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_start=%d applied_at=%d Origin=%u (期望 200 / 1 / ~1300 / 128856)\n",
|
||
warn_at, sim_learn_start_cnt, (int)sim_tick_cnt, sim_Origin);
|
||
assert(warn_at == 200);
|
||
assert(sim_learn_start_cnt == 1);
|
||
assert(sim_applied_cnt == 1);
|
||
assert(sim_Origin == 128856UL);
|
||
|
||
/* 替换后 +2s (200tick) 恢复确认 → 黄灯灭 */
|
||
for (tick = 0; tick < 200; tick++) {
|
||
sim_CAPVD = 128856UL; /* dev=0 空闲稳态 */
|
||
sim_tick();
|
||
}
|
||
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: 瞬态高位 7s (<8s) 不学 + 锁存保持 + 空闲 2s 灭 ===== */
|
||
static void test_transient_keeps_warn(void)
|
||
{
|
||
int loop;
|
||
|
||
reset_all();
|
||
for (loop = 0; loop < 600; loop++) { /* 6s 高位 */
|
||
sim_CAPVD = 128856UL;
|
||
sim_tick();
|
||
}
|
||
printf("2. 瞬态 6s 高位: 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);
|
||
|
||
sim_CAPVD = 128000UL; /* 回摆 dev=-95 (目标压入) → 锁存保持 */
|
||
sim_tick();
|
||
printf(" 回摆后: warn=%d resync=%d (期望 warn 1 保持)\n", g_env_warn, g_env_resync);
|
||
assert(g_env_warn == 1);
|
||
assert(g_env_resync == 0);
|
||
|
||
for (loop = 0; loop < 200; loop++) { /* 空闲 2s → 恢复确认 → 灭 */
|
||
sim_CAPVD = 128095UL;
|
||
sim_tick();
|
||
}
|
||
printf(" 空闲 200tick: warn=%d (期望 0 → 灭)\n", g_env_warn);
|
||
assert(g_env_warn == 0);
|
||
assert(sim_learn_start_cnt == 0);
|
||
|
||
for (loop = 0; loop < 600; loop++) { /* 再 6s 高位 → 重新锁存, 仍不学 */
|
||
sim_CAPVD = 128856UL;
|
||
sim_tick();
|
||
}
|
||
printf(" 二次 6s 高位: 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. 瞬态高位(<7s)不学, 锁存保持, 恢复确认后灭 OK\n");
|
||
}
|
||
|
||
/* ===== 场景 3: 学习期目标压线 = 搁置(不退出) → 走后再学完 → 替换 ===== */
|
||
static void test_interrupted_learn_recomputes(void)
|
||
{
|
||
int loop;
|
||
int applied_at = 0;
|
||
|
||
reset_all();
|
||
for (loop = 0; loop < 700; loop++) { /* 7s → 学习开始 */
|
||
sim_CAPVD = 128856UL;
|
||
sim_tick();
|
||
}
|
||
assert(sim_learn_start_cnt == 1);
|
||
assert(g_env_resync == 1);
|
||
|
||
for (loop = 0; loop < 100; loop++) { /* 学习 100tick (801..900) */
|
||
sim_CAPVD = 128856UL;
|
||
sim_tick();
|
||
}
|
||
sim_CAPVD = 128000UL; /* 目标压线 dev=-95: 学习中搁置 */
|
||
sim_tick();
|
||
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);
|
||
|
||
for (loop = 0; loop < 1600; loop++) { /* 目标走 → 继续高位学习 → 替换 */
|
||
sim_CAPVD = 128856UL;
|
||
sim_tick();
|
||
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);
|
||
|
||
for (loop = 0; loop < 200; loop++) { /* +2s 恢复确认 → 灭 */
|
||
sim_CAPVD = 128856UL;
|
||
sim_tick();
|
||
}
|
||
assert(g_env_warn == 0);
|
||
printf("3. 学习期压线=搁置, 恢复后学完替换, 灭 OK\n");
|
||
}
|
||
|
||
/* ===== 场景 4: 学习窗不稳 → 预算 30s 放弃 — 不污染, 黄灯保持 ===== */
|
||
static void test_unstable_learn_gives_up(void)
|
||
{
|
||
int loop;
|
||
int i;
|
||
|
||
reset_all();
|
||
for (loop = 0; loop < 700; loop++) {
|
||
sim_CAPVD = 128856UL;
|
||
sim_tick();
|
||
}
|
||
assert(g_env_resync == 1);
|
||
assert(sim_learn_start_cnt == 1);
|
||
|
||
for (i = 0; i < 3800 && !sim_abort_cnt; i++) { /* 每窗 200 样本交替 → 漂移 200 > band~129 → 恒不稳 */
|
||
sim_CAPVD = ((i / 200) & 1) ? 129256UL : 129056UL;
|
||
sim_tick();
|
||
}
|
||
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_repeat_learn(void)
|
||
{
|
||
int loop;
|
||
|
||
reset_all();
|
||
for (loop = 0; loop < 700; loop++) {
|
||
sim_CAPVD = 128856UL;
|
||
sim_tick();
|
||
}
|
||
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(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.31: 预判2s/补偿7s/恢复2s)\n");
|
||
test_permanent_change_recovers();
|
||
test_transient_keeps_warn();
|
||
test_interrupted_learn_recomputes();
|
||
test_unstable_learn_gives_up();
|
||
test_no_repeat_learn();
|
||
printf("ALL PASS (ENV_WARN 200 / RESYNC 700 / RECOVER 200)\n");
|
||
return 0;
|
||
}
|