fix(V4B): V4.25 黄灯预判改锁存语义 — 触发后回摆保持常亮, 环境空闲稳定5s才灭
原(V4.25首个提交): 黄灯条件 wait_cnt>=5s, 回摆(wait清零)即灭 — 用户反馈应锁存: 一旦5s黄灯常亮, 高位回摆/目标靠近也保持常亮; 只有"新的没有变化的环境" 超过5s 确认恢复, 黄灯才灭。 改动: - 新增 g_env_warn 预判锁存标志(只增不清): dev>+4dlt 高位累计满 ENV_WARN_WAIT=500tick(~5s) → g_env_warn=1, 黄灯常亮 - 新增 g_env_recover_cnt 恢复确认: 环境回窗口内且 dev 未进进入线(>-dlt) 连续 ENV_RECOVER_WAIT=500tick(~5s) → 解除锁存, 黄灯灭 - 目标进确认区(dev<-dlt)/深压(dev<-4dlt) → 恢复计时清零 - 高位重现 → 恢复计时清零, 黄灯保持 - abort/apply 均不清 g_env_warn (替换后也需恢复确认5s才灭) - 黄灯模式4条件 = g_env_resync || g_env_warn tests 5 场景: 回摆保持常亮→稳定5s灭→高位重现再锁存; 学习打断/放弃后锁存保持 docs: devlog V2.23 + spec V2.4 + 手册 V2.8 同步锁存语义
This commit is contained in:
+11
-9
@@ -15,21 +15,23 @@ V4.24 环境重校准的黄灯常亮只在**进入学习后**(dev>+4dlt 高位
|
|||||||
|
|
||||||
### 改动
|
### 改动
|
||||||
|
|
||||||
- 黄灯模式4 条件放宽为两段(poll_yellow_led):
|
- 黄灯模式4 条件(poll_yellow_led):`g_env_resync || g_env_warn`
|
||||||
`g_env_resync || g_env_wait_cnt >= ENV_WARN_WAIT`
|
- 新增 `ENV_WARN_WAIT = 500 tick(~5 s)` + `ENV_RECOVER_WAIT = 500 tick(~5 s)`(TaskLoop.h 文件级宏)
|
||||||
- 新增 `ENV_WARN_WAIT = 500 tick(~5 s)`(TaskLoop.h 文件级宏):
|
- **预判锁存状态机(g_env_warn)**:
|
||||||
- 高位(dev>+4dlt)持续 **5 s** 未回摆 → 黄灯**预判常亮**(提示"环境已重大变化,将进入重校准学习")
|
- 高位(dev>+4dlt)连续 **5 s** → `g_env_warn=1`,黄灯**预判常亮**(提示"环境已重大变化")
|
||||||
- 累计满 **60 s** 才真正进入学习(学习期间黄灯保持常亮,学完替换 Origin 后灭)
|
- **锁存**:回摆/目标靠近(wait 清零)**不灭灯**——只有环境回到正常空闲(dev 未进进入线)**连续 5 s**(恢复确认)才解除、黄灯灭
|
||||||
- 预判 ≠ 学习:回摆/目标靠近(wait 清零)→ 黄灯立即灭,不触发学习
|
- 累计满 **60 s** 才真正进入重校准学习(学习期间黄灯保持常亮,学完替换 Origin 后仍需恢复确认 5 s 才灭)
|
||||||
|
- 高位重现 → 恢复确认计时清零,黄灯继续常亮
|
||||||
|
- 预判 ≠ 学习:短时瞬态(60 s 内回摆)只亮黄灯、不触发学习
|
||||||
|
|
||||||
### 验证
|
### 验证
|
||||||
|
|
||||||
- tests/test_env_resync.c 扩展:黄灯预判点亮时刻 = 500 tick;瞬态高位 4000 tick 预判亮但未学习;打断回摆后预判灭
|
- tests/test_env_resync.c 扩展:预判点亮时刻 = 500 tick;回摆后黄灯**保持常亮**;稳定 5 s 后解除;高位重现再锁存;打断/放弃后锁存保持
|
||||||
- 5 场景 ALL PASS;gcc `-fsyntax-only` 0 error
|
- 5 场景 ALL PASS;gcc `-fsyntax-only` 0 error
|
||||||
|
|
||||||
### 待现场验证
|
### 待现场验证
|
||||||
|
|
||||||
A 拿走场景:约 5 s 后黄灯常亮 → 60 s 后自动重学(黄灯保持常亮数秒)→ 替换完成黄灯灭、检测高度恢复。
|
A 拿走场景:约 5 s 黄灯常亮(此后回摆也不灭)→ ~60 s 自动重学 → 替换完成 → 环境稳定再 5 s 黄灯灭、检测高度恢复。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -1063,7 +1065,7 @@ if (dev >= dlt_ORG × 4) {
|
|||||||
|
|
||||||
| 版本 | 时间 | 说明 |
|
| 版本 | 时间 | 说明 |
|
||||||
|------|------|------|
|
|------|------|------|
|
||||||
| V2.23 | 2026-09-02 | V4.25 环境异常黄灯预判:dev>+4dlt 高位连续 5s(ENV_WARN_WAIT=500tick)即黄灯常亮预判,60s 才真正学习;预判≠学习,回摆即灭 |
|
| V2.23 | 2026-09-02 | V4.25 环境异常黄灯预判(锁存):dev>+4dlt 高位连续 5s 触发 g_env_warn 锁存常亮;回摆/目标靠近保持,环境空闲稳定 5s(ENV_RECOVER_WAIT)才解除;60s 才真正学习 |
|
||||||
| V2.20 | 2026-09-02 | V4.22 DEBUG 改编译器 -DDEBUG 控制(cmcng.h DEBUG_ENABLE 删除) |
|
| V2.20 | 2026-09-02 | V4.22 DEBUG 改编译器 -DDEBUG 控制(cmcng.h DEBUG_ENABLE 删除) |
|
||||||
| V2.19 | 2026-09-02 | V4.20 负variation铁块锁死修复:基线跟踪双向对称保护(±4×dlt 对称窗口) |
|
| V2.19 | 2026-09-02 | V4.20 负variation铁块锁死修复:基线跟踪双向对称保护(±4×dlt 对称窗口) |
|
||||||
| V2.18 | 2026-09-02 | V4.20 Debug 串口打印重组:频率/采样/基准全量输出(DBG/EVT 前缀) |
|
| V2.18 | 2026-09-02 | V4.20 Debug 串口打印重组:频率/采样/基准全量输出(DBG/EVT 前缀) |
|
||||||
|
|||||||
@@ -185,10 +185,10 @@ DLD154V4B 是一款基于 ARM Cortex-M4 微控制器的**单通道环形线圈
|
|||||||
|
|
||||||
| 状态 | 红灯 | 绿灯 | 黄灯 | 说明 |
|
| 状态 | 红灯 | 绿灯 | 黄灯 | 说明 |
|
||||||
|------|------|------|------|------|
|
|------|------|------|------|------|
|
||||||
| 环境校准学习中 | 呼吸 | 灭(无车) | **常亮** | 检测到**永久环境变化**(如旁置金属板被移走使基准被学低):高位持续 **5 s** 黄灯预判常亮,累计 **60 s** 后自动学习新基线并替换,恢复灵敏度 |
|
| 环境校准学习中 | 呼吸 | 灭(无车) | **常亮** | 检测到**永久环境变化**(如旁置金属板被移走使基准被学低):高位持续 **5 s** 黄灯预判**锁存**常亮,累计 **60 s** 后自动学习新基线并替换,恢复灵敏度 |
|
||||||
|
|
||||||
- 线圈旁金属等目标在**上电时**在场会把空车基准学低;目标移走后检测高度会明显变低(V4.22 及以前需断电重上电或等基线慢跟恢复)。V4.24 起自动恢复;V4.25 起环境变化 **~5 s** 黄灯即常亮预判(提示"检测器已感知环境变化、即将进入重学")
|
- 线圈旁金属等目标在**上电时**在场会把空车基准学低;目标移走后检测高度会明显变低(V4.22 及以前需断电重上电或等基线慢跟恢复)。V4.24 起自动恢复;V4.25 起环境变化 **~5 s** 黄灯即常亮预判(提示"检测器已感知环境变化")
|
||||||
- **黄灯常亮 = 环境异常预判/学习中**:请勿移动线圈附近的目标(铁块静止 60s+ 也会被学入);回摆(干扰消失)黄灯自动灭,不触发学习
|
- **黄灯常亮(锁存)= 环境异常预判/学习中**:一旦点亮,目标移走/回摆**不会立即灭灯**——需环境恢复正常(空闲)且稳定 **~5 s** 才解除。请勿在黄灯常亮期间移动线圈附近的金属目标(铁块静止 60 s+ 也会被学入)
|
||||||
- 黄灯优先级:断开快闪 > 环境预判/学习常亮 > N 短闪(断开史)> 灭
|
- 黄灯优先级:断开快闪 > 环境预判/学习常亮 > N 短闪(断开史)> 灭
|
||||||
|
|
||||||
- **快闪**:200ms 亮 / 200ms 灭
|
- **快闪**:200ms 亮 / 200ms 灭
|
||||||
|
|||||||
@@ -449,7 +449,8 @@ if (dev < dlt_ORG * 4) {
|
|||||||
| STABLE_SETTLE_WINDOWS | 2 | ~2 s | 连续窗口漂移达标数 |
|
| STABLE_SETTLE_WINDOWS | 2 | ~2 s | 连续窗口漂移达标数 |
|
||||||
| STABLE_MAX_SAMPLES | 500 tick | **~5 s** | 自检硬兜底上限(超时强制判稳) |
|
| STABLE_MAX_SAMPLES | 500 tick | **~5 s** | 自检硬兜底上限(超时强制判稳) |
|
||||||
| FREEZE_TIMEOUT | 1000 | **~10 s** | 基线冻结超时(连续稳定后更新 Origin) |
|
| FREEZE_TIMEOUT | 1000 | **~10 s** | 基线冻结超时(连续稳定后更新 Origin) |
|
||||||
| ENV_WARN_WAIT | 500 tick | **~5 s** | 环境预判黄灯(V4.25):dev>+4×dlt 高位连续 5s 即黄灯常亮预判(将进入重学);预判≠学习,回摆即灭 |
|
| 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 | 6000 tick | **~60 s** | 环境重校准等待:dev>+4×dlt 高位连续 60s 判定永久环境变化(V4.24) |
|
| ENV_RESYNC_WAIT | 6000 tick | **~60 s** | 环境重校准等待:dev>+4×dlt 高位连续 60s 判定永久环境变化(V4.24) |
|
||||||
| ENV_LEARN_WINDOW | 200 tick | ~2 s | 环境学习窗口(基线 B 均值窗,学习期黄灯常亮) |
|
| ENV_LEARN_WINDOW | 200 tick | ~2 s | 环境学习窗口(基线 B 均值窗,学习期黄灯常亮) |
|
||||||
| ENV_LEARN_MAX_TICKS | 3000 tick | **~30 s** | 学习预算:窗口不稳超时放弃,保留旧 Origin(防死锁) |
|
| ENV_LEARN_MAX_TICKS | 3000 tick | **~30 s** | 学习预算:窗口不稳超时放弃,保留旧 Origin(防死锁) |
|
||||||
@@ -758,4 +759,4 @@ DLD154V4B V1.4 起实现该专利的整数化版本,用于大车通行时的
|
|||||||
| V2.1 | 2026-06-29 | 更新至 V2.6:单路 IIR ALFA_CAP1=79, WINDOW_ORIGIN=500, 两阶段基线 |
|
| V2.1 | 2026-06-29 | 更新至 V2.6:单路 IIR ALFA_CAP1=79, WINDOW_ORIGIN=500, 两阶段基线 |
|
||||||
| V2.2 | 2026-09-02 | 更新至 V4.23:上电稳定期判稳语义(基准漂移≤0.1%×2窗 + 5s兜底)、红灯呼吸周期≈2.6s、绿灯自检描述 |
|
| V2.2 | 2026-09-02 | 更新至 V4.23:上电稳定期判稳语义(基准漂移≤0.1%×2窗 + 5s兜底)、红灯呼吸周期≈2.6s、绿灯自检描述 |
|
||||||
| V2.3 | 2026-09-02 | 更新至 V4.24:环境重校准(dev>+4dlt 高位连续 60s → 学习基线 B → 空闲原子替换 Origin,黄灯常亮指示;瞬态 60s 内不污染、30s 学习预算兜底) |
|
| V2.3 | 2026-09-02 | 更新至 V4.24:环境重校准(dev>+4dlt 高位连续 60s → 学习基线 B → 空闲原子替换 Origin,黄灯常亮指示;瞬态 60s 内不污染、30s 学习预算兜底) |
|
||||||
| V2.4 | 2026-09-02 | 更新至 V4.25:环境异常黄灯预判(ENV_WARN_WAIT=5s 常亮,预判≠学习,回摆即灭) |
|
| V2.4 | 2026-09-02 | 更新至 V4.25:环境异常黄灯预判锁存(ENV_WARN_WAIT=5s 触发;回摆保持,ENV_RECOVER_WAIT 空闲 5s 才解除);预判≠学习 |
|
||||||
|
|||||||
+59
-20
@@ -21,7 +21,8 @@
|
|||||||
#define STABLE_SETTLE_WINDOWS 2 // 连续 2 窗漂移达标
|
#define STABLE_SETTLE_WINDOWS 2 // 连续 2 窗漂移达标
|
||||||
#define FREEZE_TIMEOUT 1000 // 打印饱和(dev>0 不再超时更新 Origin)
|
#define FREEZE_TIMEOUT 1000 // 打印饱和(dev>0 不再超时更新 Origin)
|
||||||
#define ENV_RESYNC_WAIT 6000 // V4.24: dev>+4dlt 高位连续 60s → 判定永久环境变化
|
#define ENV_RESYNC_WAIT 6000 // V4.24: dev>+4dlt 高位连续 60s → 判定永久环境变化
|
||||||
#define ENV_WARN_WAIT 500 // V4.25: 高位连续 ~5s → 黄灯预判常亮 (TaskLoop.h)
|
#define ENV_WARN_WAIT 500 // V4.25: 高位连续 ~5s → 黄灯预判锁存 (TaskLoop.h)
|
||||||
|
#define ENV_RECOVER_WAIT 500 // V4.25: 环境回正常空闲连续 ~5s → 解除预判 (TaskLoop.h)
|
||||||
#define ENV_LEARN_WINDOW 200 // V4.24: 环境学习窗口 2s
|
#define ENV_LEARN_WINDOW 200 // V4.24: 环境学习窗口 2s
|
||||||
#define ENV_LEARN_MAX_TICKS 3000 // V4.24: 学习预算 30s, 超时放弃
|
#define ENV_LEARN_MAX_TICKS 3000 // V4.24: 学习预算 30s, 超时放弃
|
||||||
|
|
||||||
@@ -33,6 +34,8 @@ static uint16_t g_env_cnt = 0;
|
|||||||
static uint32_t g_env_prev = 0;
|
static uint32_t g_env_prev = 0;
|
||||||
static uint8_t g_env_settle = 0;
|
static uint8_t g_env_settle = 0;
|
||||||
static uint16_t g_env_tick = 0;
|
static uint16_t g_env_tick = 0;
|
||||||
|
static uint8_t g_env_warn = 0;
|
||||||
|
static uint16_t g_env_recover_cnt = 0;
|
||||||
|
|
||||||
/* 场景镜像 (loop1_* 对应量) */
|
/* 场景镜像 (loop1_* 对应量) */
|
||||||
static uint32_t sim_Origin;
|
static uint32_t sim_Origin;
|
||||||
@@ -53,17 +56,20 @@ static void env_reset(void)
|
|||||||
g_env_prev = 0;
|
g_env_prev = 0;
|
||||||
g_env_settle = 0;
|
g_env_settle = 0;
|
||||||
g_env_tick = 0;
|
g_env_tick = 0;
|
||||||
|
g_env_warn = 0;
|
||||||
|
g_env_recover_cnt = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* V4.25: 黄灯模式4 条件镜像 (TaskLoop.c poll_yellow_led) */
|
/* V4.25: 黄灯模式4 条件镜像 (TaskLoop.c poll_yellow_led) — 预判锁存 */
|
||||||
static int env_warn_active(void)
|
static int env_warn_active(void)
|
||||||
{
|
{
|
||||||
return g_env_resync || g_env_wait_cnt >= ENV_WARN_WAIT;
|
return g_env_resync || g_env_warn;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 与 TaskLoop.c env_resync_abort/apply 逐行一致 */
|
/* 与 TaskLoop.c env_resync_abort/apply 逐行一致 */
|
||||||
static void env_resync_abort(void)
|
static void env_resync_abort(void)
|
||||||
{
|
{
|
||||||
|
/* V4.25: abort 只退出学习, 不清预判锁存 g_env_warn (环境未恢复前黄灯保持) */
|
||||||
g_env_resync = 0;
|
g_env_resync = 0;
|
||||||
g_env_sum = 0;
|
g_env_sum = 0;
|
||||||
g_env_cnt = 0;
|
g_env_cnt = 0;
|
||||||
@@ -91,15 +97,31 @@ static void sim_tick(void)
|
|||||||
g_env_wait_cnt = 0;
|
g_env_wait_cnt = 0;
|
||||||
if (g_env_resync) ev_abort++;
|
if (g_env_resync) ev_abort++;
|
||||||
env_resync_abort();
|
env_resync_abort();
|
||||||
|
/* V4.25: 恢复确认 — 空闲(dev>-dlt)连续 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) {
|
} else if (dev < 0) {
|
||||||
/* 车方向 → 冻结 (env 相关) */
|
/* 车方向 → 冻结 (env 相关) */
|
||||||
g_env_wait_cnt = 0;
|
g_env_wait_cnt = 0;
|
||||||
if (g_env_resync) ev_abort++;
|
if (g_env_resync) ev_abort++;
|
||||||
env_resync_abort();
|
env_resync_abort();
|
||||||
|
g_env_recover_cnt = 0; /* 目标深压 → 恢复计时清零 */
|
||||||
} else {
|
} else {
|
||||||
/* dev>0 高位 — V4.24 两段式 */
|
/* dev>0 高位 — V4.24 两段式 / V4.25 预判锁存 */
|
||||||
|
g_env_recover_cnt = 0; /* 高位异常中 → 恢复确认失效 */
|
||||||
if (!g_env_resync) {
|
if (!g_env_resync) {
|
||||||
g_env_wait_cnt++;
|
g_env_wait_cnt++;
|
||||||
|
if (g_env_wait_cnt >= ENV_WARN_WAIT)
|
||||||
|
g_env_warn = 1; /* 预判锁存 (只增不清) */
|
||||||
if (g_env_wait_cnt >= ENV_RESYNC_WAIT) {
|
if (g_env_wait_cnt >= ENV_RESYNC_WAIT) {
|
||||||
g_env_resync = 1;
|
g_env_resync = 1;
|
||||||
g_env_wait_cnt = 0;
|
g_env_wait_cnt = 0;
|
||||||
@@ -176,13 +198,15 @@ static void test_permanent_change_recovers(void)
|
|||||||
assert(ev_applied == 1);
|
assert(ev_applied == 1);
|
||||||
assert(tick == 6600); /* 6000 等待 + 3×200 窗 */
|
assert(tick == 6600); /* 6000 等待 + 3×200 窗 */
|
||||||
assert(sim_Origin == 128856UL);
|
assert(sim_Origin == 128856UL);
|
||||||
assert(g_env_resync == 0); /* 替换后复位, 黄灯灭 */
|
assert(g_env_resync == 0); /* 学习结束 */
|
||||||
|
assert(env_warn_active() == 1);/* V4.25: 替换后黄灯保持 (恢复确认前不灭) */
|
||||||
|
|
||||||
/* 替换后 dev≈0 → 走窗口分支, 不再进 freeze/学习 */
|
/* 替换后 dev≈0 → 窗口分支; 空闲连续 5s 恢复确认 → 黄灯灭 */
|
||||||
for (int i = 0; i < 500; i++)
|
for (int i = 0; i < 500; i++)
|
||||||
sim_tick();
|
sim_tick();
|
||||||
assert(ev_applied == 1); /* 不再重复替换 */
|
assert(ev_applied == 1); /* 不再重复替换 */
|
||||||
printf(" 场景1 PASS — 永久环境变化 ~66s 自动恢复, Origin 128095->128856\n\n");
|
assert(env_warn_active() == 0);/* 恢复确认 5s 后黄灯灭 */
|
||||||
|
printf(" 场景1 PASS — 永久环境变化 5s 预判锁存, ~66s 自动恢复, 恢复确认后灭\n\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_transient_never_learns(void)
|
static void test_transient_never_learns(void)
|
||||||
@@ -196,21 +220,28 @@ static void test_transient_never_learns(void)
|
|||||||
assert(env_warn_active() == 1); /* 黄灯预判已亮 (wait=4000) */
|
assert(env_warn_active() == 1); /* 黄灯预判已亮 (wait=4000) */
|
||||||
printf("瞬态高位短停: 4000tick 时黄灯预判亮=%d (未学习)\n", env_warn_active());
|
printf("瞬态高位短停: 4000tick 时黄灯预判亮=%d (未学习)\n", env_warn_active());
|
||||||
|
|
||||||
/* 回摆进窗口 (CAPVD 回 Origin 附近), wait 清零 → 黄灯预判灭 */
|
/* 回摆进窗口 (CAPVD 回 Origin 附近): wait 清零, 但预判锁存保持 (V4.25 核心语义) */
|
||||||
sim_CAPVD = 128100UL; /* dev=+5 窗口内 */
|
sim_CAPVD = 128100UL; /* dev=+5 窗口内 */
|
||||||
sim_tick();
|
sim_tick();
|
||||||
assert(g_env_wait_cnt == 0);
|
assert(g_env_wait_cnt == 0);
|
||||||
assert(env_warn_active() == 0); /* 回摆解除, 黄灯灭 */
|
assert(env_warn_active() == 1); /* 回摆不清黄灯, 保持常亮 */
|
||||||
|
|
||||||
/* 再次高位 59s(5900tick) — 仍不足 60s 连续 → 不学 */
|
/* 窗口内连续 499 tick (累计 500 恢复确认) → 环境稳定, 解除预判 */
|
||||||
|
for (int i = 0; i < 499; i++)
|
||||||
|
sim_tick();
|
||||||
|
assert(env_warn_active() == 0); /* 新环境稳定 5s, 黄灯灭 */
|
||||||
|
assert(g_env_recover_cnt == 0);
|
||||||
|
|
||||||
|
/* 再次高位 59s(5900tick): 5s 后预判重新锁存, 但 <60s 不学习 */
|
||||||
sim_CAPVD = 128856UL;
|
sim_CAPVD = 128856UL;
|
||||||
for (int i = 0; i < 5900; i++)
|
for (int i = 0; i < 5900; i++)
|
||||||
sim_tick();
|
sim_tick();
|
||||||
assert(ev_learn_start == 0);
|
assert(ev_learn_start == 0);
|
||||||
assert(ev_applied == 0);
|
assert(ev_applied == 0);
|
||||||
assert(sim_Origin == 128095UL);
|
assert(sim_Origin == 128095UL);
|
||||||
printf("瞬态高位短停: 不学习不替换, Origin 保持 (等待计数=%d)\n", g_env_wait_cnt);
|
assert(env_warn_active() == 1); /* 高位重现 → 预判重新锁存 */
|
||||||
printf(" 场景2 PASS — 铁块类瞬态(60s内回摆)不触发重校准\n\n");
|
printf("瞬态高位短停: 回摆保持常亮→稳定5s灭→高位重现再锁存 (未学习)\n");
|
||||||
|
printf(" 场景2 PASS — 铁块类瞬态(60s内回摆)不触发重校准, 预判锁存语义正确\n\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_learn_interrupted_restarts(void)
|
static void test_learn_interrupted_restarts(void)
|
||||||
@@ -226,9 +257,10 @@ static void test_learn_interrupted_restarts(void)
|
|||||||
sim_tick(); /* 学习窗1 未完 */
|
sim_tick(); /* 学习窗1 未完 */
|
||||||
sim_CAPVD = 128000UL; /* dev=-95 窗口内(B 目标) */
|
sim_CAPVD = 128000UL; /* dev=-95 窗口内(B 目标) */
|
||||||
sim_tick();
|
sim_tick();
|
||||||
assert(g_env_resync == 0); /* 打断退出 */
|
assert(g_env_resync == 0); /* 打断退出学习 */
|
||||||
assert(ev_abort == 1);
|
assert(ev_abort == 1);
|
||||||
assert(env_warn_active() == 0); /* wait 清零, 黄灯预判灭 */
|
assert(env_warn_active() == 1); /* 预判锁存保持 (环境未确认恢复) */
|
||||||
|
assert(g_env_recover_cnt == 0); /* 目标在进入确认区, 恢复计时清零 */
|
||||||
|
|
||||||
/* 目标离开, 高位重新 60s → 学习 3 窗 → 替换 */
|
/* 目标离开, 高位重新 60s → 学习 3 窗 → 替换 */
|
||||||
sim_CAPVD = 128856UL;
|
sim_CAPVD = 128856UL;
|
||||||
@@ -240,7 +272,11 @@ static void test_learn_interrupted_restarts(void)
|
|||||||
assert(ev_applied == 1);
|
assert(ev_applied == 1);
|
||||||
assert(ev_learn_start == 2);
|
assert(ev_learn_start == 2);
|
||||||
assert(sim_Origin == 128856UL);
|
assert(sim_Origin == 128856UL);
|
||||||
printf(" 场景3 PASS — 学习期任何打断都重算, 完成后恢复\n\n");
|
assert(env_warn_active() == 1); /* 替换后黄灯保持到恢复确认 */
|
||||||
|
for (int i = 0; i < 500; i++)
|
||||||
|
sim_tick(); /* 窗口恢复确认 5s */
|
||||||
|
assert(env_warn_active() == 0); /* 黄灯灭 */
|
||||||
|
printf(" 场景3 PASS — 学习期打断重算+锁存保持, 恢复确认后灭\n\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_unstable_learn_gives_up(void)
|
static void test_unstable_learn_gives_up(void)
|
||||||
@@ -259,13 +295,14 @@ static void test_unstable_learn_gives_up(void)
|
|||||||
sim_tick();
|
sim_tick();
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("学习期不稳: 预算放弃 tick=%d applied=%d resync=%d Origin=%lu\n",
|
printf("学习期不稳: 预算放弃 tick=%d applied=%d resync=%d warn=%d Origin=%lu\n",
|
||||||
tick, ev_applied, g_env_resync, (unsigned long)sim_Origin);
|
tick, ev_applied, g_env_resync, g_env_warn, (unsigned long)sim_Origin);
|
||||||
assert(ev_applied == 0);
|
assert(ev_applied == 0);
|
||||||
assert(g_env_resync == 0); /* 超时放弃, 黄灯灭 */
|
assert(g_env_resync == 0); /* 超时退出学习 */
|
||||||
|
assert(env_warn_active() == 1); /* 环境仍异常 → 黄灯保持锁存 */
|
||||||
assert(ev_abort >= 1);
|
assert(ev_abort >= 1);
|
||||||
assert(sim_Origin == 128095UL); /* Origin 不被污染 */
|
assert(sim_Origin == 128095UL); /* Origin 不被污染 */
|
||||||
printf(" 场景4 PASS — 学习不稳定 30s 放弃, 宁可灵敏度低不冒险污染\n\n");
|
printf(" 场景4 PASS — 学习不稳定 30s 放弃保留旧 Origin, 黄灯保持异常指示\n\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_no_learning_after_replace(void)
|
static void test_no_learning_after_replace(void)
|
||||||
@@ -280,7 +317,9 @@ static void test_no_learning_after_replace(void)
|
|||||||
for (int i = 0; i < 6000; i++)
|
for (int i = 0; i < 6000; i++)
|
||||||
sim_tick(); /* 新 Origin 下高位条件消失 */
|
sim_tick(); /* 新 Origin 下高位条件消失 */
|
||||||
assert(ev_learn_start == before); /* 无新学习 */
|
assert(ev_learn_start == before); /* 无新学习 */
|
||||||
printf("替换后稳态: 高位条件消失, 无重复学习 (Origin=%lu)\n", (unsigned long)sim_Origin);
|
assert(env_warn_active() == 0); /* 恢复确认 5s 后黄灯已灭 */
|
||||||
|
printf("替换后稳态: 高位条件消失, 无重复学习, 黄灯灭 (Origin=%lu)\n",
|
||||||
|
(unsigned long)sim_Origin);
|
||||||
printf(" 场景5 PASS — 恢复后进入正常跟踪, 不震荡\n\n");
|
printf(" 场景5 PASS — 恢复后进入正常跟踪, 不震荡\n\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -46,7 +46,8 @@
|
|||||||
#define ENTRY_CONFIRM 3 // 进入确认: 连续 N 次低于阈值才判定有车
|
#define ENTRY_CONFIRM 3 // 进入确认: 连续 N 次低于阈值才判定有车
|
||||||
#define FREEZE_TIMEOUT 1000 // 基线冻结超时: ~10s @ 10ms/tick, 持续偏高且稳定后强制更新基线
|
#define FREEZE_TIMEOUT 1000 // 基线冻结超时: ~10s @ 10ms/tick, 持续偏高且稳定后强制更新基线
|
||||||
#define FREEZE_STABILITY_RATE 2 // 冻结稳定性窗口: 参考值的 ±2% (CAPVD 需在此范围内才累计超时)
|
#define FREEZE_STABILITY_RATE 2 // 冻结稳定性窗口: 参考值的 ±2% (CAPVD 需在此范围内才累计超时)
|
||||||
#define ENV_WARN_WAIT 500 // 环境预判 (V4.25): dev>+4dlt 高位连续 ~5s 未回摆 → 黄灯常亮预判提示
|
#define ENV_WARN_WAIT 500 // 环境预判 (V4.25): dev>+4dlt 高位连续 ~5s → 黄灯预判锁存(回摆保持)
|
||||||
|
#define ENV_RECOVER_WAIT 500 // 恢复确认 (V4.25): 环境回正常(空闲)连续 ~5s 才解除预判, 黄灯灭
|
||||||
|
|
||||||
/*===========================================================================
|
/*===========================================================================
|
||||||
* 离开检测模式
|
* 离开检测模式
|
||||||
|
|||||||
@@ -86,6 +86,11 @@ uint32_t g_env_prev = 0; // 上一窗口均值 (B 候选)
|
|||||||
uint8_t g_env_settle = 0; // 连续稳定窗口计数 (窗内均值漂移 ≤0.1% 则+1)
|
uint8_t g_env_settle = 0; // 连续稳定窗口计数 (窗内均值漂移 ≤0.1% 则+1)
|
||||||
uint16_t g_env_tick = 0; // 学习预算 (超时放弃防死锁)
|
uint16_t g_env_tick = 0; // 学习预算 (超时放弃防死锁)
|
||||||
|
|
||||||
|
/* V4.25+: 环境异常预判锁存 — 一旦触发黄灯常亮, 回摆/目标靠近不灭;
|
||||||
|
* 仅当环境回正常(空闲, dev 未进入线以下)连续 ENV_RECOVER_WAIT 才解除 */
|
||||||
|
uint8_t g_env_warn = 0; // 1=环境异常预判锁存 (黄灯常亮)
|
||||||
|
uint16_t g_env_recover_cnt = 0; // 恢复确认计数 (空闲持续 5s → 解除预判)
|
||||||
|
|
||||||
#if USE_FLATNESS_EXIT
|
#if USE_FLATNESS_EXIT
|
||||||
uint8_t g_exit_state;
|
uint8_t g_exit_state;
|
||||||
uint16_t g_max_slope;
|
uint16_t g_max_slope;
|
||||||
@@ -322,10 +327,11 @@ void poll_yellow_led(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*--- V4.25 模式4: 环境异常预判/重校准学习 → 黄灯常亮
|
/*--- V4.25 模式4: 环境异常预判/重校准学习 → 黄灯常亮
|
||||||
* g_env_wait_cnt >= ENV_WARN_WAIT(~5s): 环境重大变化预判 (高位未回摆, 即将进入重学)
|
* g_env_warn == 1: 环境重大变化预判锁存 (高位连续 ~5s 触发; 回摆/目标靠近保持,
|
||||||
* g_env_resync == 1: 已进入重校准学习 (高位累计 60s 后自动开始, 学完原子替换 Origin 后灭)
|
* 环境回正常空闲连续 ~5s 才解除)
|
||||||
|
* g_env_resync == 1: 已进入重校准学习 (高位累计 60s 后自动开始, 学完原子替换 Origin)
|
||||||
* 优先级: 断开快闪 > 环境预判/学习常亮 > N短闪 > 灭 ---*/
|
* 优先级: 断开快闪 > 环境预判/学习常亮 > N短闪 > 灭 ---*/
|
||||||
if (g_env_resync || g_env_wait_cnt >= ENV_WARN_WAIT) {
|
if (g_env_resync || g_env_warn) {
|
||||||
LED_YELLOW_ON;
|
LED_YELLOW_ON;
|
||||||
g_fault_tick = 0;
|
g_fault_tick = 0;
|
||||||
g_fault_phase = 0;
|
g_fault_phase = 0;
|
||||||
@@ -433,6 +439,8 @@ void INIT_VD(void)
|
|||||||
g_env_prev = 0;
|
g_env_prev = 0;
|
||||||
g_env_settle = 0;
|
g_env_settle = 0;
|
||||||
g_env_tick = 0;
|
g_env_tick = 0;
|
||||||
|
g_env_warn = 0; // V4.25+: 环境预判锁存复位
|
||||||
|
g_env_recover_cnt = 0;
|
||||||
|
|
||||||
/* M4 优化: 快速 IIR + 进入确认 */
|
/* M4 优化: 快速 IIR + 进入确认 */
|
||||||
loop1_entry_cnt = 0;
|
loop1_entry_cnt = 0;
|
||||||
@@ -881,12 +889,26 @@ void vd1_task(void)
|
|||||||
loop1_freeze_cnt = 0;
|
loop1_freeze_cnt = 0;
|
||||||
loop1_freeze_ref = 0; // V4.20: 清残留参考, 打印 FRZ 干净
|
loop1_freeze_ref = 0; // V4.20: 清残留参考, 打印 FRZ 干净
|
||||||
g_env_wait_cnt = 0; // V4.24: 高位回摆/目标靠近 → 等待重来
|
g_env_wait_cnt = 0; // V4.24: 高位回摆/目标靠近 → 等待重来
|
||||||
env_resync_abort(); // V4.24: 学习中被打断 → 重算 (黄灯恢复)
|
env_resync_abort(); // V4.24: 学习中被打断 → 重算
|
||||||
|
/* V4.25: 恢复确认 — 环境回正常(dev 未进进入线以下)连续 5s → 解除预判锁存
|
||||||
|
* (预判一旦触发, 回摆/目标靠近都保持黄灯常亮; 只有稳定空闲才灭) */
|
||||||
|
if (dev > -(int32_t)loop1_dlt_ORG) {
|
||||||
|
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; // 目标进入确认区 → 恢复计时重来
|
||||||
|
}
|
||||||
update_moving_average(&loop1_ORG_SUM, &loop1_ORG_CNT,
|
update_moving_average(&loop1_ORG_SUM, &loop1_ORG_CNT,
|
||||||
&loop1_Origin, loop1_CAPVD, WINDOW_ORIGIN);
|
&loop1_Origin, loop1_CAPVD, WINDOW_ORIGIN);
|
||||||
} else if (dev < 0) {
|
} else if (dev < 0) {
|
||||||
g_env_wait_cnt = 0; // V4.24: 目标靠近(车方向) → 等待重来
|
g_env_wait_cnt = 0; // V4.24: 目标靠近(车方向) → 等待重来
|
||||||
env_resync_abort(); // V4.24: 学习中被打断 → 重算 (黄灯恢复)
|
env_resync_abort(); // V4.24: 学习中被打断 → 重算
|
||||||
|
g_env_recover_cnt = 0; // V4.25: 目标深压 → 恢复确认计时清零
|
||||||
/* 正variation (CAPVD低于Origin, 疑似车辆) → 冻结, 保留原超时兜底更新 */
|
/* 正variation (CAPVD低于Origin, 疑似车辆) → 冻结, 保留原超时兜底更新 */
|
||||||
if (loop1_freeze_cnt == 0) {
|
if (loop1_freeze_cnt == 0) {
|
||||||
loop1_freeze_ref = loop1_CAPVD;
|
loop1_freeze_ref = loop1_CAPVD;
|
||||||
@@ -930,8 +952,13 @@ void vd1_task(void)
|
|||||||
loop1_ORG_SUM = 0;
|
loop1_ORG_SUM = 0;
|
||||||
|
|
||||||
if (!g_env_resync) {
|
if (!g_env_resync) {
|
||||||
/*--- ① 等待确认: dev>+4dlt 高位连续累计 (回摆清零见窗口/dev<0分支) ---*/
|
/*--- ① 等待确认: dev>+4dlt 高位连续累计 (回摆清零见窗口/dev<0分支)
|
||||||
|
* V4.25: 累计满 5s(ENV_WARN_WAIT) → 预判锁存 g_env_warn=1 (黄灯常亮),
|
||||||
|
* 锁存后回摆/目标靠近不解除; 高位重现则恢复计时清零 ---*/
|
||||||
g_env_wait_cnt++;
|
g_env_wait_cnt++;
|
||||||
|
if (g_env_wait_cnt >= ENV_WARN_WAIT)
|
||||||
|
g_env_warn = 1; // 预判锁存 (只增不清)
|
||||||
|
g_env_recover_cnt = 0; // 高位异常中 → 恢复确认失效
|
||||||
if (g_env_wait_cnt >= ENV_RESYNC_WAIT) {
|
if (g_env_wait_cnt >= ENV_RESYNC_WAIT) {
|
||||||
g_env_resync = 1;
|
g_env_resync = 1;
|
||||||
g_env_wait_cnt = 0;
|
g_env_wait_cnt = 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user