Files
DLD154V4B/tests/test_power_on_stable.c
wangfq cd0fd90770 feat(V4B): V4.23 — 红灯呼吸对齐vd960Loop(≈2.6s) + 上电自检基准判稳
现场测试 DLD154V4 反馈两问题修复:

1. 红灯呼吸太快 → 借鉴 vd960Loop 效果 (main.c poll_red_pwm)
   - 参数按 665/6800 缩放取整: 大步 100→39(≈5.9%), 近顶 20→10(≈1.5%),
     分界 585(88%), 峰值保持 660×3 步
   - 周期 ≈1.6s → ≈2.6s (仿真 42 步×60ms=2520ms)

2. 绿灯上电自检闪到"稳定基准值"才停 (TaskLoop.c 稳定期判稳)
   - 根因: 固定 128 样本即判稳, 与基准是否稳定无关; static 计数不清零,
     二次稳定期(安全复位)1 样本瞬间判稳
   - 修复: 全局 g_stable_cnt/g_settle_cnt, 每窗(100样本≈1s)Origin 均值
     漂移 ≤0.1% → settle++, 连续 2 窗 + 最少 128 样本判稳; 硬兜底 500
     样本(5s); 计数判稳退出/INIT_VD 清零

验证: tests/test_power_on_stable.c (200/300/500/200 样本 PASS),
      tests/test_red_breath.c (周期 2520ms/峰值保持/写值≤ARR PASS),
      gcc -fsyntax-only 两文件 0 error (借 vd960Loop AT32F421 库头)
文档: devlog 置顶 + 修订表回填 V2.12~V2.20 + V2.21; product-manual §5.1/
      核心特性; technical-spec V2.2 (§5.2 参数表/§7 判稳语义/§15 修订记录)

待现场验证: 呼吸观感、绿灯自检时长 (无车 2~3s / 首窗尖峰 3s / 5s 兜底)
2026-09-02 16:26:03 +08:00

141 lines
4.5 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_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 <stdio.h>
#include <stdint.h>
#include <assert.h>
#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;
}