/* * test_power_on_stable.c — 上电自检: 基准值稳定后才结束自检 (V4.23) * * 背景: 原逻辑 _stable_cnt 达 128 样本(≈1.3s)即判稳, 与"基准值是否真稳定"无关; * 且 static 计数不清零, 二次稳定期(安全复位)1 个样本即判稳(绿灯自检形同虚设)。 * 修复: 稳定期累计样本 g_stable_cnt + 连续窗口 Origin 均值漂移 ≤0.1% 的 * g_settle_cnt; 两者达标才 g_loop_stable=1; 硬兜底 500 样本(5s)。 * * 验证: * 1. 干净常量值 → 第 200 样本判稳 (窗口100/200 两次漂移 0) * 2. 首窗 Origin 尖峰(1.3×) → 多等一窗, 第 300 样本判稳 * 3. 持续漂移(每窗 +500, >0.1% 带) → 永不 settle, 第 500 样本硬兜底判稳 * 4. 判稳退出后计数清零, 二次稳定期重新从 0 累计(不瞬间判稳) * * 编译: gcc -Wall -o test_power_on_stable test_power_on_stable.c && ./test_power_on_stable *===========================================================================*/ #include #include #include #define WIN 100 /* 稳定期小窗口 */ #define STABLE_SAMPLES 128 /* 稳定期最少样本数 */ #define STABLE_ORIGIN_PPT 1 /* 0.1% */ #define STABLE_SETTLE_WINDOWS 2 #define STABLE_MAX_SAMPLES 500 static uint32_t origin; static uint32_t g_origin_prev; static uint16_t g_stable_cnt; static uint16_t g_settle_cnt; static uint8_t g_loop_stable; /* 仿真 vd1_task 稳定期单样本处理; 返回 1=本样本判稳 */ static int stable_step(uint32_t value) { static uint32_t sum = 0; static uint16_t cnt = 0; uint32_t prev_origin; int win_done = 0; if (g_loop_stable) return 1; if (origin == 0) return 0; prev_origin = origin; sum += value; cnt++; g_stable_cnt++; if (cnt >= WIN) { win_done = 1; origin = sum / WIN; sum = 0; cnt = 0; } if (win_done) { uint32_t drift = (origin > prev_origin) ? (origin - prev_origin) : (prev_origin - origin); uint32_t band = (uint32_t)(origin * STABLE_ORIGIN_PPT / 1000); if (drift <= band) { if (g_settle_cnt < 0xFFFF) g_settle_cnt++; } else { g_settle_cnt = 0; } } if ((g_stable_cnt >= STABLE_SAMPLES && g_settle_cnt >= STABLE_SETTLE_WINDOWS) || g_stable_cnt >= STABLE_MAX_SAMPLES) { g_loop_stable = 1; g_stable_cnt = 0; g_settle_cnt = 0; return 1; } return 0; } static void reset(uint32_t initial_origin) { origin = initial_origin; g_origin_prev = 0; g_stable_cnt = 0; g_settle_cnt = 0; g_loop_stable = 0; } int main(void) { const uint32_t BASE = 128844UL; int i, done; /* --- 1. 干净常量值: 第 200 样本判稳 --- */ reset(BASE); done = 0; for (i = 1; i <= 600 && !done; i++) { done = stable_step(BASE); if (done) break; } printf("1. 常量值 判稳样本=%d (期望 200)\n", i); assert(i == 200); assert(g_stable_cnt == 0 && g_settle_cnt == 0); /* --- 2. 首窗 Origin 尖峰(1.3×, 实际值正常): 第 300 样本判稳 --- */ reset((uint32_t)(BASE * 1.3)); done = 0; for (i = 1; i <= 600 && !done; i++) { done = stable_step(BASE); if (done) break; } printf("2. 首窗尖峰 判稳样本=%d (期望 300)\n", i); assert(i == 300); /* --- 3. 持续漂移: 每窗均值 +500 (>0.1% 带) → 硬兜底 500 --- */ reset(BASE); done = 0; for (i = 1; i <= 600 && !done; i++) { uint32_t w = (uint32_t)((i - 1) / WIN); done = stable_step(BASE + 500UL * w); if (done) break; } printf("3. 持续漂移 判稳样本=%d (期望 500 硬兜底)\n", i); assert(i == 500); /* --- 4. 二次稳定期: 计数清零, 重新累计 → 第 200 样本判稳(非 1 样本) --- */ reset(BASE); done = 0; for (i = 1; i <= 600 && !done; i++) { done = stable_step(BASE); if (done) break; } assert(i == 200); /* 第一次完成 */ /* 模拟安全复位: 仅清 g_loop_stable, 计数应已是 0 */ g_loop_stable = 0; done = 0; for (i = 1; i <= 600 && !done; i++) { done = stable_step(BASE); if (done) break; } printf("4. 二次稳定期 判稳样本=%d (期望 200, 修掉原 1 样本瞬间判稳)\n", i); assert(i == 200); printf("ALL PASS (test_power_on_stable)\n"); return 0; }