Files
DLD154V4B/tests/test_env_resync.c
wangfq 7983bfd72d feat(V4B): V4.31 — 故障补偿时序再调: 预判2s + 补偿7s (总恢复 ~15s)
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
2026-09-03 16:16:37 +08:00

355 lines
13 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* 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;
}