feat(V4B): V4.30 — 故障补偿时序: 预判3s + 补偿8s + 恢复2s (总恢复 ~16s)

拍板: 预判 ENV_WARN_WAIT 500→300(3s); 补偿 ENV_RESYNC_WAIT 1000→800(8s);
恢复确认 ENV_RECOVER_WAIT 500→200(2s, 新基线替换后空闲稳定即灭灯)
时序: 3s 黄灯预判锁存 → 8s 进入学习 → 6s(3×200tick)学完原子替换 → 2s 确认灭
test_env_resync.c 重写: 镜像与固件逐分支一致(学习中压线=搁置不退出/学习仅高位段
计数/abort后循环重触发) → 5 场景 ALL PASS (warn@300, applied@1400, 灭@1600)
文档: devlog V2.28 / spec V2.9 / design doc v0.7
This commit is contained in:
wangfq
2026-09-03 16:08:21 +08:00
parent 71feb3e06d
commit 4200d96250
7 changed files with 288 additions and 232 deletions
+1
View File
@@ -13,6 +13,7 @@
| v0.4 | 2026-09-03 | **测频 4 倍偏差修正(V4.27**calc_freq_khz 60000→240000TMR3 实际 120MHz 计数 + 通道捕获 DIV_2)。本文 §3 中"Xn=3681→f=16.3kHz→L≈1.4mH 超限案例"为**测频 bug 假象**——修正后实为 f≈65.2kHz、L≈90µH 的正常线圈;该"红区案例"作废,需按真实频率重新采集现场数据 |
| v0.5 | 2026-09-03 | **L 估算标定(V4.28**:五组 LCR 实测反推振荡回路等效谐振电容 C_eff=41.3~45.5nF(均值 43),与名义 66nF 明显不符 → 固件改标定值 COIL_CAL_C_NF=43L_uH=2.533e7/(f²×C_eff));COIL_DEF_C_NF 保留为名义口径。残差 ±6% 内,待多线圈/标定电感进一步收口 |
| v0.6 | 2026-09-03 | **硬件修复后定稿(V4.29**:拨码三极管 5.1K→0Ω → 低频档并联全导通,C_eff=68.1~68.9(均值 68.4)≈名义 66。v0.5 的 43 为 5.1K 旧板带病特性(开关未饱和),**作废**COIL_CAL_C_NF 43→68,残差 ≤1.5%。33nF 档标定 34(旧板数据)待 0Ω 板复测 |
| v0.7 | 2026-09-03 | **故障补偿时序(V4.30**:预判 3sENV_WARN_WAIT 300)→ 补偿 8sENV_RESYNC_WAIT 800)→ 学习 3×2s → 替换后空闲 2s 恢复确认(ENV_RECOVER_WAIT 200)黄灯灭;总恢复 ~16s |
## 1. 背景
+35
View File
@@ -4,6 +4,40 @@
---
## 2026-09-03 — 故障补偿时序调整:预判3s + 补偿8s + 恢复2s(固件 V4.30
> **固件版本:V4.30**cmcng.hFIRMWARE_VER="4.30" + MAIN=4/SUB=30)。devlog 修订 V2.28。
### 拍板规格(2026-09-03
故障补偿节奏整体提速、现场手感更紧凑:
1. **预判 3 秒**ENV_WARN_WAIT 500→300):高位持续 3s 黄灯预判锁存常亮(原 5s)
2. **故障补偿 8 秒**ENV_RESYNC_WAIT 1000→800):累计 8s 高位进入基线学习(原 10s)
3. **新环境稳定 +2 秒**ENV_RECOVER_WAIT 500→200):学习完成原子替换 Origin 后,空闲连续 2s 恢复确认 → 黄灯灭(原 5s)
总恢复:~21s → **~16s**3s 预判 → 8s 触发 → 6s 学习(3×200tick) → 2s 确认灭)
### 改动
- ENV_WARN_WAIT 500→300~5s→~3s / ENV_RESYNC_WAIT 1000→800~10s→~8s / ENV_RECOVER_WAIT 500→200~5s→~2s
- tests/test_env_resync.c 重写(镜像与固件逐分支一致:学习中压线=搁置不退出、学习仅高位段计数、abort 后循环重触发语义)
- 版本 V4.29→V4.30spec V2.9 / devlog V2.28
### 验证(5 场景 ALL PASS
| 场景 | 期望 | 实测 |
|------|------|------|
| 永久变化 | warn@300 / applied@~1400 / 替换后 200tick 灭 | warn_at=300 ✓ applied_at=1400 ✓ 灭 ✓ |
| 瞬态 7s(<8s) | 锁存不学, 空闲 2s 灭, 二次 7s 再锁存 | ✓ |
| 学习期压线 | resync 保持=搁置, 走后再学完替换 | ✓ (applied_at=1401) |
| 不稳学习 | 预算 30s 放弃, 不污染, 黄灯保持 | abort=1 ✓ Origin 不变 ✓ warn=1 ✓ |
| 替换后稳态 | 无重复学习, 恢复确认后灭 | ✓ |
### 待现场验证
- A 拿走:~3s 黄灯亮 → ~14s 基线切 B(黄灯仍亮)→ 空场稳定 ~16s 黄灯灭
- ⚠ 补偿触发提前到 8s:持续 8~10s 的强磁干扰会触发学习(原 10s 边界)——现场观察确认可接受
## 2026-09-03 — C_eff 标定定稿 68(0Ω 板低频档)+ 硬件疑点闭环(固件 V4.29)
> **固件版本:V4.29**cmcng.hFIRMWARE_VER="4.29" + MAIN=4/SUB=29)。devlog 修订 V2.27。
@@ -1229,6 +1263,7 @@ if (dev >= dlt_ORG × 4) {
| 版本 | 时间 | 说明 |
|------|------|------|
| V2.28 | 2026-09-03 | V4.30 故障补偿时序: 预判3s(300)/补偿8s(800)/恢复2s(200), 总 ~16s |
| V2.27 | 2026-09-03 | V4.29 硬件修复(拨码三极管5.1K→0Ω)后 C_eff=68.1~68.9nF≈名义66, COIL_CAL_C_NF 43→68 (旧43为5.1K带病特性作废) |
| V2.26 | 2026-09-03 | V4.28 电感量估算引入标定 COIL_CAL_C_NF=43(名义 66nF vs 实测 C_eff≈435 组反推 41.3~45.5nF);残差 ±6% |
| V2.25 | 2026-09-03 | V4.27 频率测量 4 倍偏差修正(calc 60000→240000120MHz×DIV_2);coil_l_uH 随 f 修正;旧 f/L 日志需 ×4 |
+6 -5
View File
@@ -1,6 +1,6 @@
# DLD154V4B 技术规格书
> 单路线圈车辆检测器 | 固件版本: V4.29 | 文档版本: V2.8
> 单路线圈车辆检测器 | 固件版本: V4.30 | 文档版本: V2.9
> 本文档面向工程开发、系统集成及故障深度分析
---
@@ -365,7 +365,7 @@ if (!VD_FLAG) {
| 4× 冻结阈值 | 防止异常 CAPVD 上升污染基线(V1.5 |
| 5% 斜率限幅 | 过滤 EMI/闪电尖峰,保护 IIRV2.0 |
| 冻结超时 + 稳定性检查 | 防止永久冻结死锁(V2.3~2.5 |
| 环境重校准(V4.24/26 | dev>+4×dlt 高位连续 10sENV_RESYNC_WAITV4.26 60s 提速)→ 判定永久环境变化 → 学习基线 B(空闲窗均值+判稳,黄灯常亮)→ 原子替换 Origin;铁块类瞬态 10s 内仍只冻结不污染 |
| 环境重校准(V4.24/26/30 | dev>+4×dlt 高位连续 8sENV_RESYNC_WAITV4.26 60s→10sV4.30→8s)→ 判定永久环境变化 → 学习基线 B(空闲窗均值+判稳,黄灯常亮)→ 原子替换 Origin;铁块类瞬态 8s 内仍只冻结不污染 |
#### 4.4.3 基线更新速率(两阶段)
@@ -450,9 +450,9 @@ if (dev < dlt_ORG * 4) {
| STABLE_SETTLE_WINDOWS | 2 | ~2 s | 连续窗口漂移达标数 |
| STABLE_MAX_SAMPLES | 500 tick | **~5 s** | 自检硬兜底上限(超时强制判稳) |
| FREEZE_TIMEOUT | 1000 | **~10 s** | 基线冻结超时(连续稳定后更新 Origin) |
| ENV_WARN_WAIT | 500 tick | **~5 s** | 环境预判锁存(V4.25):dev>+4×dlt 高位连续 5s → 黄灯常亮预判(锁存) |
| ENV_RECOVER_WAIT | 500 tick | ~5 s | 恢复确认(V4.25):环境回正常空闲连续 5s 才解除预判锁存、黄灯灭(回摆/目标靠近保持常亮) |
| ENV_RESYNC_WAIT | 1000 tick | **~10 s** | 环境重校准等待:dev>+4×dlt 高位连续 10s 判定永久环境变化(V4.26 拍板:60s→10s |
| ENV_WARN_WAIT | 300 tick | **~3 s** | 环境预判锁存(V4.30):dev>+4×dlt 高位连续 3s → 黄灯常亮预判(锁存) |
| ENV_RECOVER_WAIT | 200 tick | ~2 s | 恢复确认(V4.30):新基线替换后 环境空闲连续 2s 才解除预判锁存、黄灯灭(回摆/目标靠近保持常亮) |
| ENV_RESYNC_WAIT | 800 tick | **~8 s** | 环境重校准等待:dev>+4×dlt 高位连续 8s 判定永久环境变化(V4.30 拍板:60s→10s→8s |
| ENV_LEARN_WINDOW | 200 tick | ~2 s | 环境学习窗口(基线 B 均值窗,学习期黄灯常亮) |
| ENV_LEARN_MAX_TICKS | 3000 tick | **~30 s** | 学习预算:窗口不稳超时放弃,保留旧 Origin(防死锁) |
| COIL_F_OK_MIN_KHZ | 20 kHz | — | 线圈频率合理窗下界(V4.26):默认低频档口径,f<20kHz → L偏大告警 |
@@ -774,3 +774,4 @@ DLD154V4B V1.4 起实现该专利的整数化版本,用于大车通行时的
| V2.6 | 2026-09-03 | 更新至 V4.27:频率测量 4 倍偏差修正(calc_freq_khz 60000→240000TMR3 实际 120MHz 计数 + 通道 DIV_2 边沿分频,原按 60MHz 假设漏乘 2×2);§4.1.2 流程文字更正 |
| V2.7 | 2026-09-03 | 更新至 V4.28L 估算引入标定等效谐振电容 COIL_CAL_C_NF=43(名义 66nF 与实测 C_eff≈43 不符;5 组实测 41.3~45.5nF |
| V2.8 | 2026-09-03 | 更新至 V4.29:硬件修复(拨码三极管 5.1K→0Ω)使低频档并联全导通,C_eff 43→68.4≈名义66COIL_CAL_C_NF 43→68 |
| V2.9 | 2026-09-03 | 更新至 V4.30:故障补偿时序 预判 5s→3s(300)/补偿 10s→8s(800)/恢复确认 5s→2s(200),总恢复 ~16s |
+241 -222
View File
@@ -1,133 +1,101 @@
/*
* test_env_resync.c (线) gcc (DLD154V4B V4.26)
* test_env_resync.c (线) gcc (DLD154V4B V4.30)
*
* : TaskLoop.c vd1_task() dev>0 (V4.24/25 , V4.26 )
* (2026-09-02 ): 线A上电 Origin (128096)
* A CAPVD 128856 dev=+761(0.59%) > +4dlt
* V4.26 : ENV_RESYNC_WAIT 60s10s(),
*
* (poll_yellow_led): 5s (g_env_warn, )
* 10s (g_env_resync, ) Origin 5s
*
* ( ENV_RESYNC_WAIT !)
* = TaskLoop.c vd1_task() dev>0 (V4.24/25/26/30), :
* - 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.30 : 3s + 8s + 2s
* ( ENV_* !)
*/
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <stdint.h>
#define ENV_WARN_WAIT 500
#define ENV_RECOVER_WAIT 500
#define ENV_RESYNC_WAIT 1000 /* V4.26: 60s->10s (拍板4) */
/* ===== 镜像固件宏 (TaskLoop.c/TaskLoop.h 同步) ===== */
#define ENV_WARN_WAIT 300 /* V4.30: 预判 3s */
#define ENV_RECOVER_WAIT 200 /* V4.30: 替换后空闲 2s 恢复确认 */
#define ENV_RESYNC_WAIT 800 /* V4.30: 补偿(学习等待) 8s */
#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) */
#define FREEZE_BAND_MULT 4 /* freeze_band = dlt*4 */
/* ===== 镜像全局 ===== */
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 uint32_t sim_Origin = 128095UL;
static uint32_t sim_CAPVD = 128856UL;
static uint32_t sim_dlt = 48UL;
static uint8_t sim_learn_start_cnt = 0;
static uint8_t sim_applied = 0;
static uint32_t sim_applied_origin = 0;
static uint32_t sim_applied_tick = 0;
static uint8_t sim_abort = 0;
static uint32_t sim_tick_cnt = 0;
static int env_warn_active(void) { return (g_env_warn != 0 || g_env_resync != 0); }
/* --- g_env_* 镜像 (与固件同名) --- */
static uint8_t g_env_resync = 0;
static uint16_t g_env_wait_cnt = 0;
static uint32_t g_env_sum = 0;
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;
static void env_reset(void)
/* ===== 镜像: env_resync_apply / env_resync_abort (TaskLoop.c 逻辑复刻) ===== */
static void env_resync_apply(uint32_t new_origin)
{
g_env_resync = 0;
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_warn = 0;
g_env_recover_cnt = 0;
sim_learn_start_cnt = 0;
sim_applied = 0;
sim_abort = 0;
sim_tick_cnt = 0;
}
static int env_warn_active(void)
{
return g_env_resync || g_env_warn; /* poll_yellow_led 模式4 条件镜像 */
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)
{
g_env_resync = 0;
g_env_sum = 0;
g_env_cnt = 0;
g_env_prev = 0;
g_env_settle = 0;
g_env_tick = 0;
sim_abort++;
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 分支的 env 相关逻辑镜像 (V4.26) */
static void sim_tick(void)
/* ===== 镜像: vd1_task 无车段 dev 分支 (TaskLoop.c 复刻, V4.30) ===== */
static void vd_env_branch(void)
{
int32_t dev;
int32_t freeze_band;
int32_t dev = (int32_t)sim_CAPVD - (int32_t)sim_Origin;
sim_tick_cnt++;
dev = (int32_t)sim_CAPVD - (int32_t)sim_Origin;
freeze_band = (int32_t)(sim_dlt * FREEZE_BAND_MULT);
if (dev < freeze_band && dev > -freeze_band) {
/* 对称窗口内 → 正常基线跟踪 (env 相关) */
g_env_wait_cnt = 0;
if (g_env_resync) env_resync_abort();
/* V4.25: 恢复确认 — 真空闲(未进进入线)连续 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;
g_env_recover_cnt = 0;
if (g_env_resync) env_resync_abort();
} else {
/* dev>0 高位 — 两段式 (V4.24) + 预判锁存 (V4.25) */
g_env_recover_cnt = 0;
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; /* 5s 预判锁存 */
g_env_warn = 1; /* 预判锁存 (只增不清) */
if (g_env_wait_cnt >= ENV_RESYNC_WAIT) {
sim_learn_start_cnt++;
g_env_resync = 1;
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;
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 {
/* 学习中: 窗口均值 + settle 判稳 */
/* ── 学习基线 B: 连续空闲窗口均值 + settle 判稳 ── */
g_env_tick++;
g_env_sum += sim_CAPVD;
g_env_cnt++;
@@ -138,198 +106,249 @@ static void sim_tick(void)
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)
if (_drift <= _band) {
g_env_settle++;
else
g_env_settle = 0;
if (g_env_settle >= STABLE_SETTLE_WINDOWS) {
sim_applied = 1;
sim_applied_origin = _m;
sim_applied_tick = sim_tick_cnt;
sim_Origin = _m; /* 原子替换 (空闲由上下文保证) */
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;
return;
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(); /* 预算超时放弃 (保留旧 Origin) */
}
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;
}
}
/* ============ 场景 1: 永久变化 (A拿走) ~21s 恢复 ============ */
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 拿走) — 3s 预判 → 8s 触发 → 3窗学完 ~14s 替换 → +2s 灭 ===== */
static void test_permanent_change_recovers(void)
{
int tick, warn_at = 0;
int tick, warn_at = 0;
int loop;
env_reset();
sim_Origin = 128095UL; sim_CAPVD = 128856UL;
for (tick = 0; tick < 4000 && !sim_applied; tick++) {
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=%d applied_at=%d Origin=%u (期望 warn 500, learn>=1000, applied~1600)\n",
warn_at, sim_learn_start_cnt, (int)sim_applied_tick, sim_Origin);
assert(warn_at == 500); /* 5s 预判锁存 */
printf("1. 永久变化: warn_at=%d learn_start=%d applied_at=%d Origin=%u (期望 300 / 1 / ~1400 / 128856)\n",
warn_at, sim_learn_start_cnt, (int)sim_tick_cnt, sim_Origin);
assert(warn_at == 300);
assert(sim_learn_start_cnt == 1);
assert(sim_applied == 1);
assert(sim_applied_origin == 128856UL); /* 替换到真空场 */
assert(sim_applied_cnt == 1);
assert(sim_Origin == 128856UL);
assert(env_warn_active() == 1); /* 替换后黄灯保持 (等待恢复确认) */
/* 空闲 5s 恢复确认 → 灭 */
for (tick = 0; tick < 600; tick++)
/* 替换后 +2s (200tick) 恢复确认 → 黄灯灭 */
for (tick = 0; tick < 200; tick++) {
sim_CAPVD = 128856UL; /* dev=0 空闲稳态 */
sim_tick();
assert(env_warn_active() == 0);
}
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: 瞬态高位 (<10s 回摆) 不学, 锁存保持到恢复确认 ============ */
static void test_transient_no_learn(void)
/* ===== 场景 2: 瞬态高位 7s (<8s) 不学 + 锁存保持 + 空闲 2s 灭 ===== */
static void test_transient_keeps_warn(void)
{
int i;
int loop;
env_reset();
sim_Origin = 128095UL; sim_CAPVD = 128856UL;
/* 高位 9s (900tick): 预判 5s 亮, 但 <10s 不学习 */
for (i = 0; i < 900; i++)
reset_all();
for (loop = 0; loop < 700; loop++) { /* 7s 高位 */
sim_CAPVD = 128856UL;
sim_tick();
}
printf("2. 瞬态 7s 高位: 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);
/* 回摆进窗口: wait 清零但预判锁存保持 */
sim_CAPVD = 128100UL; /* dev=+5 */
sim_CAPVD = 128000UL; /* 回摆 dev=-95 (目标压入) → 锁存保持 */
sim_tick();
assert(g_env_wait_cnt == 0);
assert(env_warn_active() == 1); /* 回摆不清黄灯 (拍板锁存语义) */
printf(" 回摆后: warn=%d resync=%d (期望 warn 1 保持)\n", g_env_warn, g_env_resync);
assert(g_env_warn == 1);
assert(g_env_resync == 0);
/* 窗口空闲 499tick (累计500恢复确认) → 灭 */
for (i = 0; i < 499; i++)
for (loop = 0; loop < 200; loop++) { /* 空闲 2s → 恢复确认 → 灭 */
sim_CAPVD = 128095UL;
sim_tick();
assert(env_warn_active() == 0);
assert(g_env_recover_cnt == 0);
/* 再高位 9s → 又锁存, 仍不学习 */
sim_CAPVD = 128856UL;
for (i = 0; i < 900; i++)
sim_tick();
assert(env_warn_active() == 1);
}
printf(" 空闲 200tick: warn=%d (期望 0 → 灭)\n", g_env_warn);
assert(g_env_warn == 0);
assert(sim_learn_start_cnt == 0);
assert(sim_applied == 0);
assert(sim_Origin == 128095UL);
printf("2. 瞬态高位(<10s)不学, 锁存保持, 恢复确认后灭 OK\n");
for (loop = 0; loop < 700; loop++) { /* 再 7s 高位 → 重新锁存, 仍不学 */
sim_CAPVD = 128856UL;
sim_tick();
}
printf(" 二次 7s 高位: 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. 瞬态高位(<8s)不学, 锁存保持, 恢复确认后灭 OK\n");
}
/* ============ 场景 3: 学习期打断重算 + 最终恢复 ============ */
static void test_learn_interrupt_retry(void)
/* ===== 场景 3: 学习期目标压线 = 搁置(不退出) → 走后再学完 → 替换 ===== */
static void test_interrupted_learn_recomputes(void)
{
int i;
int learn_start_before;
int loop;
int applied_at = 0;
env_reset();
sim_Origin = 128095UL; sim_CAPVD = 128856UL;
/* 10s 高位 → 学习开始 */
for (i = 0; i < 1000; i++)
reset_all();
for (loop = 0; loop < 800; loop++) { /* 8s → 学习开始 */
sim_CAPVD = 128856UL;
sim_tick();
}
assert(sim_learn_start_cnt == 1);
assert(g_env_resync == 1);
/* 学习 100 tick 后目标靠近 (dev=-95 进入确认区) → 打断 */
for (i = 0; i < 100; i++)
for (loop = 0; loop < 100; loop++) { /* 学习 100tick (801..900) */
sim_CAPVD = 128856UL;
sim_tick();
sim_CAPVD = 128000UL; /* dev=-95 */
}
sim_CAPVD = 128000UL; /* 目标压线 dev=-95: 学习中搁置 */
sim_tick();
assert(g_env_resync == 0); /* 打断退出学习 */
assert(sim_abort >= 1);
assert(env_warn_active() == 1); /* 预判锁存保持 (环境未确认恢复) */
assert(g_env_recover_cnt == 0); /* 目标在进入确认区 → 恢复计时清零 */
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);
/* 目标离开, 高位重现 → 重新等待 10s + 学习 3 窗 → 替换 */
learn_start_before = sim_learn_start_cnt;
sim_CAPVD = 128856UL;
for (i = 0; i < 4000 && !sim_applied; i++)
for (loop = 0; loop < 1600; loop++) { /* 目标走 → 继续高位学习 → 替换 */
sim_CAPVD = 128856UL;
sim_tick();
assert(sim_learn_start_cnt == learn_start_before + 1);
assert(sim_applied == 1);
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);
assert(env_warn_active() == 1); /* 替换后保持到恢复确认 */
/* 空闲 5s → 黄灯灭 */
for (i = 0; i < 600; i++)
for (loop = 0; loop < 200; loop++) { /* +2s 恢复确认 → 灭 */
sim_CAPVD = 128856UL;
sim_tick();
assert(env_warn_active() == 0);
printf("3. 学习期打断重算, 最终恢复 OK\n");
}
assert(g_env_warn == 0);
printf("3. 学习期压线=搁置, 恢复后学完替换, 灭 OK\n");
}
/* ============ 场景 4: 学习期持续不稳 → 30s 预算放弃 ============ */
static void test_learn_unstable_abort(void)
/* ===== 场景 4: 学习不稳 → 预算 30s 放弃 — 不污染, 黄灯保持 ===== */
static void test_unstable_learn_gives_up(void)
{
int i;
int loop;
int i;
env_reset();
sim_Origin = 128095UL;
/* 高位 10s → 学习开始; 然后窗口均值交替漂移 >0.1% (129056/129256) */
for (i = 0; i < 1000; i++) {
reset_all();
for (loop = 0; loop < 800; loop++) {
sim_CAPVD = 128856UL;
sim_tick();
}
assert(g_env_resync == 1);
assert(sim_learn_start_cnt == 1);
for (i = 0; i < 3500; i++) {
/* 每窗 200 样本交替 129056 / 129256 → 窗间漂移 200 > band~129 → settle 恒 0 */
for (i = 0; i < 3800 && !sim_abort_cnt; i++) { /* 每窗 200 样本交替 → 漂移 200 > band~129 → 恒不稳 */
sim_CAPVD = ((i / 200) & 1) ? 129256UL : 129056UL;
sim_tick();
}
/* 1000(等待) + 3000(学习预算) ≈ 放弃于 tick 4000; 总 tick 4500 < 再学阈值(5000) */
assert(sim_learn_start_cnt == 1); /* 只有一次学习启动 */
assert(sim_applied == 0); /* 未替换 */
assert(sim_Origin == 128095UL); /* 旧 Origin 保留 (不冒险污染) */
assert(g_env_resync == 0); /* 预算 30s 放弃 */
assert(env_warn_active() == 1); /* 环境仍异常 → 黄灯保持 */
printf("4. 学习不稳 30s 放弃, 保留旧 Origin, 黄灯保持 OK\n");
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_oscillation_after_apply(void)
/* ===== 场景 5: 替换后稳态无重复学习 ===== */
static void test_no_repeat_learn(void)
{
int i, lsc;
int loop;
env_reset();
sim_Origin = 128095UL; sim_CAPVD = 128856UL;
for (i = 0; i < 4000 && !sim_applied; i++)
reset_all();
for (loop = 0; loop < 800; loop++) {
sim_CAPVD = 128856UL;
sim_tick();
assert(sim_applied == 1);
lsc = sim_learn_start_cnt;
for (i = 0; i < 6000; i++)
sim_tick(); /* 窗口内持续 (dev≈0) */
assert(sim_learn_start_cnt == lsc); /* 无重复学习 */
assert(sim_applied == 1); /* 未被再次改写 */
}
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(env_warn_active() == 0); /* 恢复确认后黄灯已灭 */
printf("5. 替换后不震荡无重复学习 OK\n");
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.30: 预判3s/补偿8s/恢复2s)\n");
test_permanent_change_recovers();
test_transient_no_learn();
test_learn_interrupt_retry();
test_learn_unstable_abort();
test_no_oscillation_after_apply();
printf("\nALL PASS (ENV_RESYNC_WAIT=%d)\n", ENV_RESYNC_WAIT);
test_transient_keeps_warn();
test_interrupted_learn_recomputes();
test_unstable_learn_gives_up();
test_no_repeat_learn();
printf("ALL PASS (ENV_WARN 300 / RESYNC 800 / RECOVER 200)\n");
return 0;
}
@@ -46,8 +46,8 @@
#define ENTRY_CONFIRM 3 // 进入确认: 连续 N 次低于阈值才判定有车
#define FREEZE_TIMEOUT 1000 // 基线冻结超时: ~10s @ 10ms/tick, 持续偏高且稳定后强制更新基线
#define FREEZE_STABILITY_RATE 2 // 冻结稳定性窗口: 参考值的 ±2% (CAPVD 需在此范围内才累计超时)
#define ENV_WARN_WAIT 500 // 环境预判 (V4.25): dev>+4dlt 高位连续 ~5s → 黄灯预判锁存(回摆保持)
#define ENV_RECOVER_WAIT 500 // 恢复确认 (V4.25): 环境回正常(空闲)连续 ~5s 才解除预判, 黄灯灭
#define ENV_WARN_WAIT 300 // 环境预判 (V4.30): dev>+4dlt 高位连续 ~3s → 黄灯预判锁存(回摆保持)
#define ENV_RECOVER_WAIT 200 // 恢复确认 (V4.30): 新基线替换后 环境空闲连续 ~2s 才解除预判, 黄灯灭
#define COIL_F_OK_MIN_KHZ 20 // 线圈频率合理窗 (V4.26): 默认低频档口径, <20kHz → L偏大
#define COIL_F_OK_MAX_KHZ 120 // 线圈频率合理窗 (V4.26): >120kHz → L偏小
#define COIL_CAL_C_NF 68 // 标定等效谐振电容 nF (V4.29): 0Ω板 低频档(66nF名义)实测 C_eff=68.1~68.9 (均值68.4)
+2 -2
View File
@@ -14,10 +14,10 @@
#define __CMCNG_H__
#define PRODUCT_MODEL "DLD154"
#define FIRMWARE_VER "4.29"
#define FIRMWARE_VER "4.30"
#define HARDWARE_VER "3.00"
#define FIRMWARE_VER_MAIN 4
#define FIRMWARE_VER_SUB 29
#define FIRMWARE_VER_SUB 30
#define HARDWARE_VER_MAIN 3
#define HARDWARE_VER_SUB 0
@@ -875,7 +875,7 @@ void vd1_task(void)
#define STABLE_ORIGIN_PPT 1 // 基准稳定判据: 窗口均值漂移 ≤ Origin×1/1000 (0.1%)
#define STABLE_SETTLE_WINDOWS 2 // 连续 2 个窗口(每窗100样本≈1s)漂移达标 → 判稳
#define STABLE_MAX_SAMPLES 500 // 硬兜底: 5s 未判稳强制结束自检(防绿灯无限闪)
#define ENV_RESYNC_WAIT 1000 // V4.26: dev>+4dlt 高位连续 10s → 判定永久环境变化 (拍板: 故障补偿 60s→10s)
#define ENV_RESYNC_WAIT 800 // V4.30: dev>+4dlt 高位连续 8s → 判定永久环境变化 (拍板: 预判3s + 补偿8s + 恢复2s)
#define ENV_LEARN_WINDOW 200 // V4.24: 环境学习窗口 2s (200×10ms)
#define ENV_LEARN_MAX_TICKS 3000 // V4.24: 学习预算 30s, 超时放弃 (防黄灯常亮死锁)