feat(V4B): V4.26 — 线圈电感量告警(一长一短) + 故障补偿 60s→10s (4点拍板)
1. 默认低频档频率合理窗 20~120kHz, 出界即告警(不做档位判定/灰带):
TaskLoop.c 新增 coil_monitor() — 稳定+无车空闲由无车主路径调用,
Origin 反推空场 f, f<20kHz→L偏大/f>120kHz→L偏小, 1s 防抖置位/清除
2. 告警形式: 黄灯"一长一短" 200ms亮/100ms灭/100ms亮/800ms灭 循环 (模式5)
3. 黄灯优先级: 断开快闪 > 故障补偿(学习)常亮 > 电感量一长一短 > N短闪 > 灭
4. 故障补偿等待 ENV_RESYNC_WAIT 6000→1000 (60s→10s): 总补偿 ~66s→~21s
验证: tests/test_coil_range.c 5场景(边界19/20/120/121+防抖) ALL PASS;
test_env_resync.c 适配10s(applied_at=1600tick) 5场景 ALL PASS; 语法 0 error
文档: devlog V2.24/spec V2.5/manual V2.9/design doc v0.3(标记已实现)
修复: 源文件行尾多CR污染(\\r\\r\\r\\r\\n)统一规范化回标准CRLF
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
# 线圈电感量估算与不合理范围告警 — 设计讨论稿
|
# 线圈电感量估算与不合理范围告警 — 设计讨论稿
|
||||||
|
|
||||||
> **状态:设计讨论稿(未实现)** — 本文仅存档讨论结论,代码未落地。
|
> **状态:已实现(V4.26,2026-09-03)** — 本文为设计讨论与实现归档;落地代码见 TaskLoop.c coil_monitor()(vd1_task 无车主路径调用)与 poll_yellow_led() 模式 5。
|
||||||
> 固件版本基线:V4.25(cmcng.h);涉及产品:DLD154V4B(DLD154V4)。
|
> 固件版本基线:V4.26(cmcng.h);涉及产品:DLD154V4B(DLD154V4)。
|
||||||
|
|
||||||
**修订记录:**
|
**修订记录:**
|
||||||
|
|
||||||
@@ -9,6 +9,7 @@
|
|||||||
|------|------|------|
|
|------|------|------|
|
||||||
| v0.1 | 2026-09-02 | 初稿(合理范围按 50~300 µH,三区制) |
|
| v0.1 | 2026-09-02 | 初稿(合理范围按 50~300 µH,三区制) |
|
||||||
| v0.2 | 2026-09-03 | 合理范围改 **50 ~ 1000 µH(规格书口径,两档任意一档合法即不告警)**,三区窗口重算 |
|
| v0.2 | 2026-09-03 | 合理范围改 **50 ~ 1000 µH(规格书口径,两档任意一档合法即不告警)**,三区窗口重算 |
|
||||||
|
| v0.3 | 2026-09-03 | **用户 4 点拍板收口(取代 v0.2 三区/灰带)**:默认低频档频率窗 **20~120 kHz** 出界即告警;黄灯**一长一短**;优先级 1 断开快闪 > 4 故障补偿常亮 > 5 电感一长一短 > 3 N短亮 > 2 灭;故障补偿 ENV_RESYNC_WAIT **60s→10s**。已实现于 V4.26(672f143 后) |
|
||||||
|
|
||||||
## 1. 背景
|
## 1. 背景
|
||||||
|
|
||||||
@@ -17,7 +18,8 @@ DLD154V4 线圈振荡电路:固定电容 **33 nF** + 拨码开关可并联另
|
|||||||
|
|
||||||
需求(用户最终口径):
|
需求(用户最终口径):
|
||||||
1. 由实测振荡频率推算线圈电感量 L(粗略值即可)
|
1. 由实测振荡频率推算线圈电感量 L(粗略值即可)
|
||||||
2. 对不合理电感量范围的线圈告警:**两档任意 L ∈ [50, 1000] µH 合法**(规格书范围),超出才告警
|
2. 对不合理电感量范围的线圈告警(**v0.3 拍板,取代 §4 三区制**):按默认低频档计算,频率合理范围
|
||||||
|
**20 ~ 120 kHz,不在合理范围内一律判定电感量不合理 → 告警**(不做档位判定、不做灰带提示)
|
||||||
3. 预留 C_eff 校准公式/系数,测试时微调
|
3. 预留 C_eff 校准公式/系数,测试时微调
|
||||||
4. 持续监视
|
4. 持续监视
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,45 @@
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## 2026-09-03 — 线圈电感量告警 + 故障补偿提速(固件 V4.26)
|
||||||
|
|
||||||
|
> **固件版本:V4.26**(cmcng.h:FIRMWARE_VER="4.26" + MAIN=4/SUB=26)。devlog 修订 V2.24。
|
||||||
|
|
||||||
|
### 背景
|
||||||
|
|
||||||
|
DLD154V4 线圈振荡两级频率(33/66nF 拨码,拨码不引 IO)。现场抓到 f=16.3kHz(Xn=3681) 超范围
|
||||||
|
线圈(L≈1.44mH@66nF),检测异常难排查 → 要求对不合理电感量自动告警。
|
||||||
|
另:环境重校准(V4.24/25)补偿总时长 ~66s 偏长 → 拍板提速。
|
||||||
|
|
||||||
|
### 拍板规格(2026-09-03)
|
||||||
|
|
||||||
|
1. 按默认低频档计算,频率合理范围 **20 ~ 120 kHz**,出界即判定电感量不合理 → 告警(不做档位判定/灰带)
|
||||||
|
2. 告警形式:黄灯**一长一短**(长亮200ms/灭100ms/短亮100ms/灭800ms 循环)
|
||||||
|
3. 黄灯优先级:线圈断开快闪 > 故障补偿(学习补偿)常亮 > 电感量不合理一长一短 > 线圈断开 N 短亮 > 灭
|
||||||
|
4. 故障补偿黄灯常亮(等待学习)时间 **60s → 10s**(ENV_RESYNC_WAIT 6000→1000)
|
||||||
|
|
||||||
|
### 改动
|
||||||
|
|
||||||
|
- TaskLoop.c:新增 coil_monitor()(稳定+无车空闲由无车主路径调用;Origin 反推空场 f;
|
||||||
|
f<20kHz→L偏大 / f>120kHz→L偏小,1s 防抖置位/清除;EVT|coil_fault/coil_ok)
|
||||||
|
- poll_yellow_led():新增模式5(一长一短 40/20/20/160 tick);优先级 1>4>5>3>2
|
||||||
|
- ENV_RESYNC_WAIT 6000→1000(5s 预判 → 10s 学习 → ~16s 替换 → 空闲 5s 确认灭,总 ~21s)
|
||||||
|
- TaskLoop.h:COIL_F_OK_MIN_KHZ=20 / COIL_F_OK_MAX_KHZ=120 / COIL_DEF_C_NF=66
|
||||||
|
- 行尾修复:V4.24~25 编辑期间源文件行尾被写成多 CR(\r\r\r\r\n),本次统一规范化回标准 CRLF
|
||||||
|
|
||||||
|
### 验证
|
||||||
|
|
||||||
|
- tests/test_coil_range.c 5 场景:L偏大/偏小 1s 防抖置位、恢复 1s 防抖清除、边界 19/20/120/121、抖动不误报 ALL PASS
|
||||||
|
- tests/test_env_resync.c(ENV_RESYNC_WAIT=1000):永久变化 applied_at=1600tick、瞬态<10s 不学、
|
||||||
|
锁存保持、打断重算、放弃不污染 ALL PASS
|
||||||
|
- gcc -fsyntax-only 0 error
|
||||||
|
|
||||||
|
### 待现场验证
|
||||||
|
|
||||||
|
- 超范围线圈(如 f=16.3kHz)应黄灯一长一短;正常 100~300µH 线圈(f 20~120k 内)不误报
|
||||||
|
- 故障补偿总时长 ~21s;环境高位 10s 即学(铁块静止 >10s 会被学入,黄灯常亮提示请勿移动目标)
|
||||||
|
- 电感告警阈值边界用标定线圈(100µH/300µH)实测微调
|
||||||
|
|
||||||
## 2026-09-02 — 环境异常黄灯预判:5s 常亮提示将进入重学(固件 V4.25)
|
## 2026-09-02 — 环境异常黄灯预判:5s 常亮提示将进入重学(固件 V4.25)
|
||||||
|
|
||||||
> **固件版本:V4.25**(cmcng.h:FIRMWARE_VER="4.25" + MAIN=4/SUB=25)。devlog 修订 V2.23。
|
> **固件版本:V4.25**(cmcng.h:FIRMWARE_VER="4.25" + MAIN=4/SUB=25)。devlog 修订 V2.23。
|
||||||
@@ -1065,6 +1104,7 @@ if (dev >= dlt_ORG × 4) {
|
|||||||
|
|
||||||
| 版本 | 时间 | 说明 |
|
| 版本 | 时间 | 说明 |
|
||||||
|------|------|------|
|
|------|------|------|
|
||||||
|
| V2.24 | 2026-09-03 | V4.26 线圈电感量告警(频率窗 20~120kHz 一长一短)+ 故障补偿 60s→10s;行尾规范化 CRLF |
|
||||||
| V2.23 | 2026-09-02 | V4.25 环境异常黄灯预判(锁存):dev>+4dlt 高位连续 5s 触发 g_env_warn 锁存常亮;回摆/目标靠近保持,环境空闲稳定 5s(ENV_RECOVER_WAIT)才解除;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 对称窗口) |
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# DLD154V4B 产品手册
|
# DLD154V4B 产品手册
|
||||||
|
|
||||||
> 单路线圈车辆检测器 | 型号: DLD154V4B | 版本: V2.8
|
> 单路线圈车辆检测器 | 型号: DLD154V4B | 版本: V2.9
|
||||||
> 适用于停车场、收费站、交通卡口等场景的车辆到达/离开检测
|
> 适用于停车场、收费站、交通卡口等场景的车辆到达/离开检测
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -177,6 +177,7 @@ DLD154V4B 是一款基于 ARM Cortex-M4 微控制器的**单通道环形线圈
|
|||||||
| 故障类型 | 红灯 | 绿灯 | 黄灯 | 说明 |
|
| 故障类型 | 红灯 | 绿灯 | 黄灯 | 说明 |
|
||||||
|---------|------|------|------|------|
|
|---------|------|------|------|------|
|
||||||
| 线圈断开(当前) | 呼吸 | 灭 | **快闪** (200ms) | 检查线圈连接 |
|
| 线圈断开(当前) | 呼吸 | 灭 | **快闪** (200ms) | 检查线圈连接 |
|
||||||
|
| 线圈电感量不合理(V4.26) | 呼吸 | 灭(无车) | **一长一短** (200ms亮/100ms灭/100ms亮/800ms灭 循环) | 空场频率出 20~120kHz(默认低频档):L偏大(f<20k)/L偏小(f>120k),检查线圈匝数/尺寸 |
|
||||||
| 线圈重连,断开 1 次 | 呼吸 | 正常 | **1 短闪** + 1.2s 灭 | 发生过 1 次断开,已恢复 |
|
| 线圈重连,断开 1 次 | 呼吸 | 正常 | **1 短闪** + 1.2s 灭 | 发生过 1 次断开,已恢复 |
|
||||||
| 线圈重连,断开 2 次 | 呼吸 | 正常 | **2 短闪** + 1.2s 灭 | 发生过 2 次断开,已恢复 |
|
| 线圈重连,断开 2 次 | 呼吸 | 正常 | **2 短闪** + 1.2s 灭 | 发生过 2 次断开,已恢复 |
|
||||||
| 线圈重连,断开 3+ 次 | 呼吸 | 正常 | **3 短闪** + 1.2s 灭 | 多次断开,建议检查接头 |
|
| 线圈重连,断开 3+ 次 | 呼吸 | 正常 | **3 短闪** + 1.2s 灭 | 多次断开,建议检查接头 |
|
||||||
@@ -185,14 +186,15 @@ DLD154V4B 是一款基于 ARM Cortex-M4 微控制器的**单通道环形线圈
|
|||||||
|
|
||||||
| 状态 | 红灯 | 绿灯 | 黄灯 | 说明 |
|
| 状态 | 红灯 | 绿灯 | 黄灯 | 说明 |
|
||||||
|------|------|------|------|------|
|
|------|------|------|------|------|
|
||||||
| 环境校准学习中 | 呼吸 | 灭(无车) | **常亮** | 检测到**永久环境变化**(如旁置金属板被移走使基准被学低):高位持续 **5 s** 黄灯预判**锁存**常亮,累计 **60 s** 后自动学习新基线并替换,恢复灵敏度 |
|
| 环境校准学习中 | 呼吸 | 灭(无车) | **常亮** | 检测到**永久环境变化**(如旁置金属板被移走使基准被学低):高位持续 **5 s** 黄灯预判**锁存**常亮,累计 **10 s**(V4.26 起,原 60s)后自动学习新基线并替换,恢复灵敏度 |
|
||||||
|
|
||||||
- 线圈旁金属等目标在**上电时**在场会把空车基准学低;目标移走后检测高度会明显变低(V4.22 及以前需断电重上电或等基线慢跟恢复)。V4.24 起自动恢复;V4.25 起环境变化 **~5 s** 黄灯即常亮预判(提示"检测器已感知环境变化")
|
- 线圈旁金属等目标在**上电时**在场会把空车基准学低;目标移走后检测高度会明显变低(V4.22 及以前需断电重上电或等基线慢跟恢复)。V4.24 起自动恢复;V4.25 起环境变化 **~5 s** 黄灯即常亮预判;V4.26 起故障补偿提速:约 **5s 预判 → 10s 学习 → ~16s 替换 → 空闲 5s 恢复确认后灭(总 ~21s)**
|
||||||
- **黄灯常亮(锁存)= 环境异常预判/学习中**:一旦点亮,目标移走/回摆**不会立即灭灯**——需环境恢复正常(空闲)且稳定 **~5 s** 才解除。请勿在黄灯常亮期间移动线圈附近的金属目标(铁块静止 60 s+ 也会被学入)
|
- **黄灯常亮(锁存)= 环境异常预判/学习中**:一旦点亮,目标移走/回摆**不会立即灭灯**——需环境恢复正常(空闲)且稳定 **~5 s** 才解除。请勿在黄灯常亮期间移动线圈附近的金属目标(铁块静止 60 s+ 也会被学入)
|
||||||
- 黄灯优先级:断开快闪 > 环境预判/学习常亮 > N 短闪(断开史)> 灭
|
- 黄灯优先级(V4.26):断开快闪 > 故障补偿(环境预判/学习)常亮 > **线圈电感量不合理一长一短** > N 短闪(断开史)> 灭
|
||||||
|
|
||||||
- **快闪**:200ms 亮 / 200ms 灭
|
- **快闪**:200ms 亮 / 200ms 灭
|
||||||
- **N 短闪**:N × (80ms 亮 + 200ms 灭),循环间隔 1.2s
|
- **N 短闪**:N × (80ms 亮 + 200ms 灭),循环间隔 1.2s
|
||||||
|
- **一长一短**(V4.26):200ms 亮 + 100ms 灭 + 100ms 亮 + 800ms 灭,循环(线圈电感量不合理)
|
||||||
- **呼吸**:PWM 渐变,系统运行指示(周期≈2.6s,V4.23 起对齐 vd960Loop 观感)
|
- **呼吸**:PWM 渐变,系统运行指示(周期≈2.6s,V4.23 起对齐 vd960Loop 观感)
|
||||||
- **绿灯慢闪(上电自检)**:200ms 亮/灭,持续至基准值稳定(连续窗口 Origin 漂移 ≤0.1%)才停止 (V4.23)
|
- **绿灯慢闪(上电自检)**:200ms 亮/灭,持续至基准值稳定(连续窗口 Origin 漂移 ≤0.1%)才停止 (V4.23)
|
||||||
|
|
||||||
|
|||||||
+27
-17
@@ -1,6 +1,6 @@
|
|||||||
# DLD154V4B 技术规格书
|
# DLD154V4B 技术规格书
|
||||||
|
|
||||||
> 单路线圈车辆检测器 | 固件版本: V4.25 | 文档版本: V2.4
|
> 单路线圈车辆检测器 | 固件版本: V4.26 | 文档版本: V2.5
|
||||||
> 本文档面向工程开发、系统集成及故障深度分析
|
> 本文档面向工程开发、系统集成及故障深度分析
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -364,7 +364,7 @@ if (!VD_FLAG) {
|
|||||||
| 4× 冻结阈值 | 防止异常 CAPVD 上升污染基线(V1.5) |
|
| 4× 冻结阈值 | 防止异常 CAPVD 上升污染基线(V1.5) |
|
||||||
| 5% 斜率限幅 | 过滤 EMI/闪电尖峰,保护 IIR(V2.0) |
|
| 5% 斜率限幅 | 过滤 EMI/闪电尖峰,保护 IIR(V2.0) |
|
||||||
| 冻结超时 + 稳定性检查 | 防止永久冻结死锁(V2.3~2.5) |
|
| 冻结超时 + 稳定性检查 | 防止永久冻结死锁(V2.3~2.5) |
|
||||||
| 环境重校准(V4.24) | dev>+4×dlt 高位连续 60s(ENV_RESYNC_WAIT)→ 判定永久环境变化 → 学习基线 B(空闲窗均值+判稳,黄灯常亮)→ 原子替换 Origin;铁块类瞬态 60s 内仍只冻结不污染 |
|
| 环境重校准(V4.24/26) | dev>+4×dlt 高位连续 10s(ENV_RESYNC_WAIT,V4.26 由 60s 提速)→ 判定永久环境变化 → 学习基线 B(空闲窗均值+判稳,黄灯常亮)→ 原子替换 Origin;铁块类瞬态 10s 内仍只冻结不污染 |
|
||||||
|
|
||||||
#### 4.4.3 基线更新速率(两阶段)
|
#### 4.4.3 基线更新速率(两阶段)
|
||||||
|
|
||||||
@@ -451,9 +451,12 @@ if (dev < dlt_ORG * 4) {
|
|||||||
| 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_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 | 1000 tick | **~10 s** | 环境重校准等待:dev>+4×dlt 高位连续 10s 判定永久环境变化(V4.26 拍板:60s→10s) |
|
||||||
| 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(防死锁) |
|
||||||
|
| COIL_F_OK_MIN_KHZ | 20 kHz | — | 线圈频率合理窗下界(V4.26):默认低频档口径,f<20kHz → L偏大告警 |
|
||||||
|
| COIL_F_OK_MAX_KHZ | 120 kHz | — | 线圈频率合理窗上界(V4.26):f>120kHz → L偏小告警 |
|
||||||
|
| COIL_DEF_C_NF | 66 nF | — | 默认档电容(拨码不可读,粗估 L 打印用;33nF 档结果 ×2) |
|
||||||
|
|
||||||
> **M4 优化**:V2.0 将 tick 从 50ms (TMR15 5ms×10) 提升到 10ms (vTaskDelay 10ms)。IIR 系数同步调整(α 从 79/256→18/256),保持等效时间常数。进入确认 3×10ms + 500ms IN_DELAY = ~530ms,比旧设计 (50ms + 500ms = 550ms) 略快。基线更新从 5s 加速到 1s。
|
> **M4 优化**:V2.0 将 tick 从 50ms (TMR15 5ms×10) 提升到 10ms (vTaskDelay 10ms)。IIR 系数同步调整(α 从 79/256→18/256),保持等效时间常数。进入确认 3×10ms + 500ms IN_DELAY = ~530ms,比旧设计 (50ms + 500ms = 550ms) 略快。基线更新从 5s 加速到 1s。
|
||||||
|
|
||||||
@@ -498,23 +501,28 @@ void poll_green_led(void) {
|
|||||||
|
|
||||||
### 6.3 黄灯行为表
|
### 6.3 黄灯行为表
|
||||||
|
|
||||||
| 条件 | 行为 | 参数 | 诊断含义 |
|
| 优先级 | 条件 | 行为 | 参数 | 诊断含义 |
|
||||||
|------|------|------|---------|
|
|--------|------|------|------|---------|
|
||||||
| `g_disconnect_active == 1` | **快闪** | 200ms 亮 / 200ms 灭 | 线圈当前断开中 |
|
| 1 | `g_disconnect_active == 1` 或 `!g_loop_power_up_state` | **快闪** | 200ms 亮 / 200ms 灭 | 线圈当前断开中 / 从无线圈上电 |
|
||||||
| `!g_loop_power_up_state` | **快闪** | 200ms 亮 / 200ms 灭 | 上电后从未连接线圈 |
|
| 4 | `g_env_warn` 或 `g_env_resync` | **常亮** | — | 环境异常预判/重校准学习(V4.24/25;故障补偿 ~10 s 内完成) |
|
||||||
| `g_disconnect_count == 1` | **1 短闪** | 80ms 亮 / 200ms 灭 → 1.2s 灭(循环) | 断开 1 次,已恢复 |
|
| 5 | `g_coil_fault`(V4.26) | **一长一短** | 长亮 200ms / 灭 100ms / 短亮 100ms / 灭 800ms 循环 | 电感量不合理:1=L偏大(f<20kHz) 2=L偏小(f>120kHz) |
|
||||||
| `g_disconnect_count == 2` | **2 短闪** | 同上 | 断开 2 次 |
|
| 3 | `g_disconnect_count == 1` | **1 短闪** | 80ms 亮 / 200ms 灭 → 1.2s 灭(循环) | 断开 1 次,已恢复 |
|
||||||
| `g_disconnect_count >= 3` | **3 短闪** | 同上 | 断开 3+ 次 |
|
| 3 | `g_disconnect_count == 2` | **2 短闪** | 同上 | 断开 2 次 |
|
||||||
| 正常 | **灭** | — | 一切正常 |
|
| 3 | `g_disconnect_count >= 3` | **3 短闪** | 同上 | 断开 3+ 次 |
|
||||||
|
| 2 | 正常 | **灭** | — | 一切正常 |
|
||||||
|
|
||||||
```c
|
```c
|
||||||
void poll_yellow_led(void) {
|
void poll_yellow_led(void) { // 优先级 1 > 4 > 5 > 3 > 2 (V4.26)
|
||||||
if (g_disconnect_active || !g_loop_power_up_state)
|
if (g_disconnect_active || !g_loop_power_up_state)
|
||||||
fast_blink_200ms(); // 断开中快闪
|
fast_blink_200ms(); // ① 断开中快闪
|
||||||
|
else if (g_env_warn || g_env_resync)
|
||||||
|
led_on(); // ④ 环境预判/学习中常亮 (V4.24/25)
|
||||||
|
else if (g_coil_fault)
|
||||||
|
long_short_blink(); // ⑤ 电感量不合理: 一长一短 (V4.26)
|
||||||
else if (g_disconnect_count > 0)
|
else if (g_disconnect_count > 0)
|
||||||
n_short_flash(g_disconnect_count); // N 短闪编码
|
n_short_flash(g_disconnect_count); // ③ N 短闪编码
|
||||||
else
|
else
|
||||||
led_off(); // 正常
|
led_off(); // ② 正常
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -617,14 +625,15 @@ if (!g_loop_stable) {
|
|||||||
|--------|---------|---------|
|
|--------|---------|---------|
|
||||||
| 线圈断开 | `loop1_RF_FLAG == 0` 持续 | 黄灯快闪 / 继电器释放 |
|
| 线圈断开 | `loop1_RF_FLAG == 0` 持续 | 黄灯快闪 / 继电器释放 |
|
||||||
| 线圈短路 | Xn 持续为 0 或极小 | 黄灯快闪 / 继电器释放 |
|
| 线圈短路 | Xn 持续为 0 或极小 | 黄灯快闪 / 继电器释放 |
|
||||||
| 频率过低 | Value 持续 < MIN_FREQ | 黄灯编码闪烁 |
|
| 电感量不合理(L偏大) | 空场 f 持续 < 20 kHz(默认低频档,V4.26) | 黄灯**一长一短**(g_coil_fault=1)/ 持续监视 1s 防抖 |
|
||||||
| 频率过高 | Value 持续 > MAX_FREQ | 黄灯编码闪烁 |
|
| 电感量不合理(L偏小) | 空场 f 持续 > 120 kHz | 黄灯**一长一短**(g_coil_fault=2)/ 持续监视 1s 防抖 |
|
||||||
|
|
||||||
### 10.2 黄灯编码设计
|
### 10.2 黄灯编码设计
|
||||||
|
|
||||||
断开次数编码提供了比 TLD-110 的均匀闪烁更丰富的诊断信息:
|
断开次数编码提供了比 TLD-110 的均匀闪烁更丰富的诊断信息:
|
||||||
- **快闪=当前故障** → 现场立即处理
|
- **快闪=当前故障** → 现场立即处理
|
||||||
- **N短闪=历史故障** → 判断是偶发还是持续问题
|
- **N短闪=历史故障** → 判断是偶发还是持续问题
|
||||||
|
- **一长一短=线圈电感量不合理**(V4.26):空场频率出 20~120kHz 窗(默认低频档);用标定线圈实测后微调阈值
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -760,3 +769,4 @@ DLD154V4B V1.4 起实现该专利的整数化版本,用于大车通行时的
|
|||||||
| 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 触发;回摆保持,ENV_RECOVER_WAIT 空闲 5s 才解除);预判≠学习 |
|
| V2.4 | 2026-09-02 | 更新至 V4.25:环境异常黄灯预判锁存(ENV_WARN_WAIT=5s 触发;回摆保持,ENV_RECOVER_WAIT 空闲 5s 才解除);预判≠学习 |
|
||||||
|
| V2.5 | 2026-09-03 | 更新至 V4.26:线圈电感量告警(频率窗 20~120kHz 单窗,黄灯一长一短);故障补偿 ENV_RESYNC_WAIT 60s→10s;黄灯优先级 1>4>5>3>2 |
|
||||||
|
|||||||
@@ -0,0 +1,116 @@
|
|||||||
|
/*
|
||||||
|
* test_coil_range.c — 线圈电感量合理范围监视 gcc 隔离单测 (DLD154V4B V4.26)
|
||||||
|
*
|
||||||
|
* 验证对象: TaskLoop.c coil_monitor() (V4.26 拍板规格)
|
||||||
|
* 默认低频档口径: 空场频率合理窗 20~120kHz, 出界即判定电感量不合理
|
||||||
|
* g_coil_fault: 0=正常 1=L偏大(f<20kHz) 2=L偏小(f>120kHz)
|
||||||
|
* 防抖: 越界/恢复均连续 100tick(=1s) 才置位/清除 (调用点=稳定无车空闲)
|
||||||
|
*
|
||||||
|
* 镜像宏与固件一致 (改 COIL_* 时同步此处!)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define COIL_F_OK_MIN_KHZ 20
|
||||||
|
#define COIL_F_OK_MAX_KHZ 120
|
||||||
|
#define COIL_DEF_C_NF 66
|
||||||
|
|
||||||
|
static uint8_t g_coil_fault = 0;
|
||||||
|
static uint16_t g_coil_bad_cnt = 0;
|
||||||
|
|
||||||
|
/* coil_monitor() 纯逻辑镜像 (不含 Origin==0 守卫, 由调用点保证) */
|
||||||
|
static void coil_step(uint32_t f_khz)
|
||||||
|
{
|
||||||
|
uint8_t want = 0;
|
||||||
|
|
||||||
|
if (f_khz < COIL_F_OK_MIN_KHZ)
|
||||||
|
want = 1;
|
||||||
|
else if (f_khz > COIL_F_OK_MAX_KHZ)
|
||||||
|
want = 2;
|
||||||
|
|
||||||
|
if (want == g_coil_fault) {
|
||||||
|
g_coil_bad_cnt = 0;
|
||||||
|
} else {
|
||||||
|
g_coil_bad_cnt++;
|
||||||
|
if (g_coil_bad_cnt >= 100) {
|
||||||
|
g_coil_fault = want;
|
||||||
|
g_coil_bad_cnt = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void run_ticks(uint32_t f_khz, int n)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < n; i++)
|
||||||
|
coil_step(f_khz);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_too_large(void)
|
||||||
|
{
|
||||||
|
g_coil_fault = 0; g_coil_bad_cnt = 0;
|
||||||
|
|
||||||
|
/* f=16.3kHz(实测超限线圈) 持续 <1s 不置位 */
|
||||||
|
run_ticks(16, 99);
|
||||||
|
assert(g_coil_fault == 0);
|
||||||
|
/* 满 1s → L 偏大 */
|
||||||
|
coil_step(16);
|
||||||
|
assert(g_coil_fault == 1);
|
||||||
|
/* 保持 → 状态稳定不抖 */
|
||||||
|
run_ticks(16, 1000);
|
||||||
|
assert(g_coil_fault == 1);
|
||||||
|
printf("1. L偏大 (f=16kHz, 1s 防抖置位, 保持稳定) OK\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_too_small(void)
|
||||||
|
{
|
||||||
|
g_coil_fault = 0; g_coil_bad_cnt = 0;
|
||||||
|
run_ticks(150, 100);
|
||||||
|
assert(g_coil_fault == 2);
|
||||||
|
printf("2. L偏小 (f=150kHz, 1s 防抖置位) OK\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_recover(void)
|
||||||
|
{
|
||||||
|
g_coil_fault = 1; g_coil_bad_cnt = 0;
|
||||||
|
run_ticks(62, 99);
|
||||||
|
assert(g_coil_fault == 1); /* 恢复防抖 <1s 不清除 */
|
||||||
|
coil_step(62);
|
||||||
|
assert(g_coil_fault == 0); /* 满 1s 恢复正常 */
|
||||||
|
printf("3. 恢复正常 (1s 防抖清除) OK\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_boundaries(void)
|
||||||
|
{
|
||||||
|
g_coil_fault = 0; g_coil_bad_cnt = 0;
|
||||||
|
run_ticks(19, 100); assert(g_coil_fault == 1); /* 19 → 偏大 */
|
||||||
|
run_ticks(62, 100); assert(g_coil_fault == 0); /* 20~120 正常 */
|
||||||
|
run_ticks(20, 100); assert(g_coil_fault == 0); /* 边界 20 正常 */
|
||||||
|
run_ticks(120, 100); assert(g_coil_fault == 0); /* 边界 120 正常 */
|
||||||
|
run_ticks(121, 100); assert(g_coil_fault == 2); /* 121 → 偏小 */
|
||||||
|
printf("4. 边界 19/20/120/121 OK\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_jitter_no_alarm(void)
|
||||||
|
{
|
||||||
|
/* 抖动: 16 与 62 交替 (每 50tick) → 计数永远到不了 100 → 不误报 */
|
||||||
|
int i;
|
||||||
|
g_coil_fault = 0; g_coil_bad_cnt = 0;
|
||||||
|
for (i = 0; i < 2000; i++)
|
||||||
|
coil_step((i & 1) ? 62 : 16);
|
||||||
|
assert(g_coil_fault == 0);
|
||||||
|
printf("5. 频率抖动不误报 OK\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
test_too_large();
|
||||||
|
test_too_small();
|
||||||
|
test_recover();
|
||||||
|
test_boundaries();
|
||||||
|
test_jitter_no_alarm();
|
||||||
|
printf("\nALL PASS (窗口 20~120kHz, 防抖 1s)\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
+185
-185
@@ -1,32 +1,43 @@
|
|||||||
/*
|
/*
|
||||||
* test_env_resync.c — 环境重校准(受控基线更新) gcc 隔离单测 (DLD154V4B V4.24)
|
* test_env_resync.c — 环境重校准(受控基线更新) gcc 隔离单测 (DLD154V4B V4.26)
|
||||||
*
|
*
|
||||||
* 验证对象: TaskLoop.c vd1_task() 无车段 dev>0 分支 (V4.24 两段式)
|
* 验证对象: TaskLoop.c vd1_task() 无车段 dev>0 分支 (V4.24/25 两段式, V4.26 参数更新)
|
||||||
* ─ 现场场景 (2026-09-02 实测): 线圈旁金属板A上电 → Origin 学低(128096)
|
* ─ 现场场景 (2026-09-02 实测): 线圈旁金属板A上电 → Origin 学低(128096)
|
||||||
* A 拿走 → CAPVD 弹回真空场(128856) dev=+761 → 双向保护(36321a1)永不更新
|
* A 拿走 → CAPVD 弹回 128856 dev=+761(0.59%) > +4dlt → 冻结累计
|
||||||
* → B 触发需 809cnt (正常 54cnt) 灵敏度假性降低
|
* ─ V4.26 拍板: ENV_RESYNC_WAIT 60s→10s(故障补偿提速), 其余语义不变
|
||||||
* ─ 修复: dev>+4dlt 高位连续 60s(ENV_RESYNC_WAIT) 未回摆 → 判定永久环境变化
|
|
||||||
* → 学习基线 B (连续空闲窗均值 + settle 判稳) → 空闲原子替换 Origin
|
|
||||||
*
|
*
|
||||||
* 运行: gcc -Wall tests/test_env_resync.c && ./a.out
|
* 黄灯语义 (poll_yellow_led): 5s 预判锁存(g_env_warn, 回摆保持) →
|
||||||
* 期望: 4 场景 ALL PASS (瞬态 60s 内短停不学; 永久变化 ~66s 恢复)
|
* 10s 进入学习(g_env_resync, 常亮) → 空闲原子替换 Origin → 空闲 5s 恢复确认 → 灭
|
||||||
|
*
|
||||||
|
* 镜像宏与固件一致(改 ENV_RESYNC_WAIT 时同步此处!)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
/*========== 与固件一致的参数宏 (TaskLoop.c vd1_task 内) ==========*/
|
#define ENV_WARN_WAIT 500
|
||||||
#define STABLE_ORIGIN_PPT 1 // 判稳带: 窗口均值漂移 ≤ Origin×1/1000 (0.1%)
|
#define ENV_RECOVER_WAIT 500
|
||||||
#define STABLE_SETTLE_WINDOWS 2 // 连续 2 窗漂移达标
|
#define ENV_RESYNC_WAIT 1000 /* V4.26: 60s->10s (拍板4) */
|
||||||
#define FREEZE_TIMEOUT 1000 // 打印饱和(dev>0 不再超时更新 Origin)
|
#define ENV_LEARN_WINDOW 200
|
||||||
#define ENV_RESYNC_WAIT 6000 // V4.24: dev>+4dlt 高位连续 60s → 判定永久环境变化
|
#define ENV_LEARN_MAX_TICKS 3000
|
||||||
#define ENV_WARN_WAIT 500 // V4.25: 高位连续 ~5s → 黄灯预判锁存 (TaskLoop.h)
|
#define STABLE_ORIGIN_PPT 1
|
||||||
#define ENV_RECOVER_WAIT 500 // V4.25: 环境回正常空闲连续 ~5s → 解除预判 (TaskLoop.h)
|
#define STABLE_SETTLE_WINDOWS 2
|
||||||
#define ENV_LEARN_WINDOW 200 // V4.24: 环境学习窗口 2s
|
|
||||||
#define ENV_LEARN_MAX_TICKS 3000 // V4.24: 学习预算 30s, 超时放弃
|
|
||||||
|
|
||||||
/*========== 与固件同名的 env 全局镜像 (TaskLoop.c :80-90) ==========*/
|
#define FREEZE_BAND_MULT 4 /* freeze_band = dlt*4 */
|
||||||
|
|
||||||
|
/* --- 镜像状态 --- */
|
||||||
|
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;
|
||||||
|
|
||||||
|
/* --- g_env_* 镜像 (与固件同名) --- */
|
||||||
static uint8_t g_env_resync = 0;
|
static uint8_t g_env_resync = 0;
|
||||||
static uint16_t g_env_wait_cnt = 0;
|
static uint16_t g_env_wait_cnt = 0;
|
||||||
static uint32_t g_env_sum = 0;
|
static uint32_t g_env_sum = 0;
|
||||||
@@ -37,16 +48,6 @@ static uint16_t g_env_tick = 0;
|
|||||||
static uint8_t g_env_warn = 0;
|
static uint8_t g_env_warn = 0;
|
||||||
static uint16_t g_env_recover_cnt = 0;
|
static uint16_t g_env_recover_cnt = 0;
|
||||||
|
|
||||||
/* 场景镜像 (loop1_* 对应量) */
|
|
||||||
static uint32_t sim_Origin;
|
|
||||||
static uint32_t sim_CAPVD;
|
|
||||||
static int32_t sim_dlt; /* 进阈 dlt */
|
|
||||||
|
|
||||||
/* 事件计数 */
|
|
||||||
static int ev_learn_start = 0;
|
|
||||||
static int ev_applied = 0;
|
|
||||||
static int ev_abort = 0;
|
|
||||||
|
|
||||||
static void env_reset(void)
|
static void env_reset(void)
|
||||||
{
|
{
|
||||||
g_env_resync = 0;
|
g_env_resync = 0;
|
||||||
@@ -58,46 +59,43 @@ static void env_reset(void)
|
|||||||
g_env_tick = 0;
|
g_env_tick = 0;
|
||||||
g_env_warn = 0;
|
g_env_warn = 0;
|
||||||
g_env_recover_cnt = 0;
|
g_env_recover_cnt = 0;
|
||||||
|
sim_learn_start_cnt = 0;
|
||||||
|
sim_applied = 0;
|
||||||
|
sim_abort = 0;
|
||||||
|
sim_tick_cnt = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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_warn;
|
return g_env_resync || g_env_warn; /* poll_yellow_led 模式4 条件镜像 */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 与 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;
|
||||||
g_env_prev = 0;
|
g_env_prev = 0;
|
||||||
g_env_settle = 0;
|
g_env_settle = 0;
|
||||||
g_env_tick = 0;
|
g_env_tick = 0;
|
||||||
|
sim_abort++;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void env_resync_apply(uint32_t new_origin)
|
/* vd1_task 无车段 dev 三分支的 env 相关逻辑镜像 (V4.26) */
|
||||||
{
|
|
||||||
(void)new_origin;
|
|
||||||
/* 固件此处打印 + 替换 Origin + 清 freeze/ORG/entry + slow snap */
|
|
||||||
ev_applied++;
|
|
||||||
env_resync_abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*========== 模拟 vd1_task 无车段基线块 env 逻辑 (逐行复刻 V4.24) ==========*/
|
|
||||||
static void sim_tick(void)
|
static void sim_tick(void)
|
||||||
{
|
{
|
||||||
int32_t dev = (int32_t)sim_CAPVD - (int32_t)sim_Origin;
|
int32_t dev;
|
||||||
int32_t freeze_band = sim_dlt * 4;
|
int32_t freeze_band;
|
||||||
|
|
||||||
|
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) {
|
if (dev < freeze_band && dev > -freeze_band) {
|
||||||
/* 对称窗口内 → 正常基线跟踪 (env 相关) */
|
/* 对称窗口内 → 正常基线跟踪 (env 相关) */
|
||||||
g_env_wait_cnt = 0;
|
g_env_wait_cnt = 0;
|
||||||
if (g_env_resync) ev_abort++;
|
if (g_env_resync) env_resync_abort();
|
||||||
env_resync_abort();
|
/* V4.25: 恢复确认 — 真空闲(未进进入线)连续 5s 解除预判锁存 */
|
||||||
/* V4.25: 恢复确认 — 空闲(dev>-dlt)连续 5s → 解除预判锁存 */
|
|
||||||
if (dev > -(int32_t)sim_dlt) {
|
if (dev > -(int32_t)sim_dlt) {
|
||||||
if (g_env_warn) {
|
if (g_env_warn) {
|
||||||
g_env_recover_cnt++;
|
g_env_recover_cnt++;
|
||||||
@@ -107,229 +105,231 @@ static void sim_tick(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
g_env_recover_cnt = 0; /* 目标进入确认区 → 恢复计时重来 */
|
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++;
|
g_env_recover_cnt = 0;
|
||||||
env_resync_abort();
|
if (g_env_resync) env_resync_abort();
|
||||||
g_env_recover_cnt = 0; /* 目标深压 → 恢复计时清零 */
|
|
||||||
} else {
|
} else {
|
||||||
/* dev>0 高位 — V4.24 两段式 / V4.25 预判锁存 */
|
/* dev>0 高位 — 两段式 (V4.24) + 预判锁存 (V4.25) */
|
||||||
g_env_recover_cnt = 0; /* 高位异常中 → 恢复确认失效 */
|
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)
|
if (g_env_wait_cnt >= ENV_WARN_WAIT)
|
||||||
g_env_warn = 1; /* 预判锁存 (只增不清) */
|
g_env_warn = 1; /* 5s 预判锁存 */
|
||||||
if (g_env_wait_cnt >= ENV_RESYNC_WAIT) {
|
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_wait_cnt = 0;
|
||||||
g_env_sum = 0;
|
g_env_sum = 0; g_env_cnt = 0; g_env_prev = 0;
|
||||||
g_env_cnt = 0;
|
g_env_settle = 0; g_env_tick = 0;
|
||||||
g_env_prev = 0;
|
|
||||||
g_env_settle = 0;
|
|
||||||
g_env_tick = 0;
|
|
||||||
ev_learn_start++;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
/* 学习中: 窗口均值 + settle 判稳 */
|
||||||
g_env_tick++;
|
g_env_tick++;
|
||||||
g_env_sum += sim_CAPVD;
|
g_env_sum += sim_CAPVD;
|
||||||
g_env_cnt++;
|
g_env_cnt++;
|
||||||
if (g_env_cnt >= ENV_LEARN_WINDOW) {
|
if (g_env_cnt >= ENV_LEARN_WINDOW) {
|
||||||
uint32_t _m = g_env_sum / g_env_cnt;
|
uint32_t _m = g_env_sum / g_env_cnt;
|
||||||
uint32_t _drift, _band;
|
|
||||||
g_env_sum = 0;
|
g_env_sum = 0;
|
||||||
g_env_cnt = 0;
|
g_env_cnt = 0;
|
||||||
if (g_env_prev != 0) {
|
if (g_env_prev != 0) {
|
||||||
_drift = (_m > g_env_prev) ? (_m - g_env_prev) : (g_env_prev - _m);
|
uint32_t _drift = (_m > g_env_prev) ? (_m - g_env_prev) : (g_env_prev - _m);
|
||||||
_band = _m * STABLE_ORIGIN_PPT / 1000;
|
uint32_t _band = _m * STABLE_ORIGIN_PPT / 1000;
|
||||||
if (_drift <= _band) {
|
if (_drift <= _band)
|
||||||
g_env_settle++;
|
g_env_settle++;
|
||||||
} else {
|
else
|
||||||
g_env_settle = 0;
|
g_env_settle = 0;
|
||||||
}
|
|
||||||
if (g_env_settle >= STABLE_SETTLE_WINDOWS) {
|
if (g_env_settle >= STABLE_SETTLE_WINDOWS) {
|
||||||
sim_Origin = _m; /* env_resync_apply 替换 */
|
sim_applied = 1;
|
||||||
env_resync_apply(_m);
|
sim_applied_origin = _m;
|
||||||
return; /* 本 tick 不再走进入判定 */
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
g_env_prev = _m;
|
g_env_prev = _m;
|
||||||
}
|
}
|
||||||
if (g_env_tick >= ENV_LEARN_MAX_TICKS) {
|
if (g_env_tick >= ENV_LEARN_MAX_TICKS) {
|
||||||
ev_abort++;
|
env_resync_abort(); /* 预算超时放弃 (保留旧 Origin) */
|
||||||
env_resync_abort();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*========== 测试工具 ==========*/
|
/* ============ 场景 1: 永久变化 (A拿走) ~21s 恢复 ============ */
|
||||||
static void t_set(uint32_t origin, uint32_t capvd, int32_t dlt)
|
|
||||||
{
|
|
||||||
sim_Origin = origin;
|
|
||||||
sim_CAPVD = capvd;
|
|
||||||
sim_dlt = dlt;
|
|
||||||
env_reset();
|
|
||||||
ev_learn_start = 0;
|
|
||||||
ev_applied = 0;
|
|
||||||
ev_abort = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*========== 场景 ==========*/
|
|
||||||
static void test_permanent_change_recovers(void)
|
static void test_permanent_change_recovers(void)
|
||||||
{
|
{
|
||||||
/* ① 常量高位稳定 (A 拿走): Origin=128095, 空场 CAPVD=128856, dev=+761>192 */
|
int tick, warn_at = 0;
|
||||||
t_set(128095UL, 128856UL, 48);
|
|
||||||
|
|
||||||
int tick = 0;
|
env_reset();
|
||||||
int warn_at = 0;
|
sim_Origin = 128095UL; sim_CAPVD = 128856UL;
|
||||||
for (; tick < 7000 && !ev_applied; tick++) {
|
|
||||||
|
for (tick = 0; tick < 4000 && !sim_applied; tick++) {
|
||||||
sim_tick();
|
sim_tick();
|
||||||
if (!warn_at && env_warn_active())
|
if (!warn_at && env_warn_active())
|
||||||
warn_at = tick + 1; /* 首次黄灯预判条件成立 (wait>=500) */
|
warn_at = (int)sim_tick_cnt;
|
||||||
}
|
}
|
||||||
|
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);
|
||||||
|
|
||||||
printf("常量高位稳定: 黄灯预判=%d 学习启动=%d 替换=%d 替换tick=%d resync=%d\n",
|
assert(warn_at == 500); /* 5s 预判锁存 */
|
||||||
warn_at, ev_learn_start, ev_applied, tick, g_env_resync);
|
assert(sim_learn_start_cnt == 1);
|
||||||
assert(warn_at == 500); /* V4.25: 高位 5s 即黄灯常亮预判 */
|
assert(sim_applied == 1);
|
||||||
assert(ev_learn_start == 1);
|
assert(sim_applied_origin == 128856UL); /* 替换到真空场 */
|
||||||
assert(ev_applied == 1);
|
|
||||||
assert(tick == 6600); /* 6000 等待 + 3×200 窗 */
|
|
||||||
assert(sim_Origin == 128856UL);
|
assert(sim_Origin == 128856UL);
|
||||||
assert(g_env_resync == 0); /* 学习结束 */
|
assert(env_warn_active() == 1); /* 替换后黄灯保持 (等待恢复确认) */
|
||||||
assert(env_warn_active() == 1);/* V4.25: 替换后黄灯保持 (恢复确认前不灭) */
|
|
||||||
|
|
||||||
/* 替换后 dev≈0 → 窗口分支; 空闲连续 5s 恢复确认 → 黄灯灭 */
|
/* 空闲 5s 恢复确认 → 灭 */
|
||||||
for (int i = 0; i < 500; i++)
|
for (tick = 0; tick < 600; tick++)
|
||||||
sim_tick();
|
sim_tick();
|
||||||
assert(ev_applied == 1); /* 不再重复替换 */
|
assert(env_warn_active() == 0);
|
||||||
assert(env_warn_active() == 0);/* 恢复确认 5s 后黄灯灭 */
|
printf(" 恢复确认后黄灯灭 OK\n");
|
||||||
printf(" 场景1 PASS — 永久环境变化 5s 预判锁存, ~66s 自动恢复, 恢复确认后灭\n\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_transient_never_learns(void)
|
/* ============ 场景 2: 瞬态高位 (<10s 回摆) 不学, 锁存保持到恢复确认 ============ */
|
||||||
|
static void test_transient_no_learn(void)
|
||||||
{
|
{
|
||||||
/* ② 瞬态高位短停 (铁块模拟): 40s(4000tick) 高位后回摆 → 不学习
|
int i;
|
||||||
* 但 5s 后黄灯预判已亮 (wait>=500) — 预判亮 ≠ 进入学习 */
|
|
||||||
t_set(128095UL, 128856UL, 48);
|
|
||||||
for (int i = 0; i < 4000; i++)
|
|
||||||
sim_tick();
|
|
||||||
assert(ev_learn_start == 0);
|
|
||||||
assert(env_warn_active() == 1); /* 黄灯预判已亮 (wait=4000) */
|
|
||||||
printf("瞬态高位短停: 4000tick 时黄灯预判亮=%d (未学习)\n", env_warn_active());
|
|
||||||
|
|
||||||
/* 回摆进窗口 (CAPVD 回 Origin 附近): wait 清零, 但预判锁存保持 (V4.25 核心语义) */
|
env_reset();
|
||||||
sim_CAPVD = 128100UL; /* dev=+5 窗口内 */
|
sim_Origin = 128095UL; sim_CAPVD = 128856UL;
|
||||||
|
|
||||||
|
/* 高位 9s (900tick): 预判 5s 亮, 但 <10s 不学习 */
|
||||||
|
for (i = 0; i < 900; i++)
|
||||||
|
sim_tick();
|
||||||
|
assert(env_warn_active() == 1);
|
||||||
|
assert(sim_learn_start_cnt == 0);
|
||||||
|
|
||||||
|
/* 回摆进窗口: wait 清零但预判锁存保持 */
|
||||||
|
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() == 1); /* 回摆不清黄灯, 保持常亮 */
|
assert(env_warn_active() == 1); /* 回摆不清黄灯 (拍板锁存语义) */
|
||||||
|
|
||||||
/* 窗口内连续 499 tick (累计 500 恢复确认) → 环境稳定, 解除预判 */
|
/* 窗口空闲 499tick (累计500恢复确认) → 灭 */
|
||||||
for (int i = 0; i < 499; i++)
|
for (i = 0; i < 499; i++)
|
||||||
sim_tick();
|
sim_tick();
|
||||||
assert(env_warn_active() == 0); /* 新环境稳定 5s, 黄灯灭 */
|
assert(env_warn_active() == 0);
|
||||||
assert(g_env_recover_cnt == 0);
|
assert(g_env_recover_cnt == 0);
|
||||||
|
|
||||||
/* 再次高位 59s(5900tick): 5s 后预判重新锁存, 但 <60s 不学习 */
|
/* 再高位 9s → 又锁存, 仍不学习 */
|
||||||
sim_CAPVD = 128856UL;
|
sim_CAPVD = 128856UL;
|
||||||
for (int i = 0; i < 5900; i++)
|
for (i = 0; i < 900; i++)
|
||||||
sim_tick();
|
sim_tick();
|
||||||
assert(ev_learn_start == 0);
|
assert(env_warn_active() == 1);
|
||||||
assert(ev_applied == 0);
|
assert(sim_learn_start_cnt == 0);
|
||||||
|
assert(sim_applied == 0);
|
||||||
assert(sim_Origin == 128095UL);
|
assert(sim_Origin == 128095UL);
|
||||||
assert(env_warn_active() == 1); /* 高位重现 → 预判重新锁存 */
|
printf("2. 瞬态高位(<10s)不学, 锁存保持, 恢复确认后灭 OK\n");
|
||||||
printf("瞬态高位短停: 回摆保持常亮→稳定5s灭→高位重现再锁存 (未学习)\n");
|
|
||||||
printf(" 场景2 PASS — 铁块类瞬态(60s内回摆)不触发重校准, 预判锁存语义正确\n\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_learn_interrupted_restarts(void)
|
/* ============ 场景 3: 学习期打断重算 + 最终恢复 ============ */
|
||||||
|
static void test_learn_interrupt_retry(void)
|
||||||
{
|
{
|
||||||
/* ③ 学习期打断重算: 60s 后进入学习, 途中目标靠近(回窗) → abort → 重来并最终恢复 */
|
int i;
|
||||||
t_set(128095UL, 128856UL, 48);
|
int learn_start_before;
|
||||||
|
|
||||||
/* 第一次 60s + 学习 100 tick 后, B 靠近把 CAPVD 压回窗口 */
|
env_reset();
|
||||||
for (int i = 0; i < 6000; i++)
|
sim_Origin = 128095UL; sim_CAPVD = 128856UL;
|
||||||
sim_tick(); /* 进入学习 */
|
|
||||||
|
/* 10s 高位 → 学习开始 */
|
||||||
|
for (i = 0; i < 1000; i++)
|
||||||
|
sim_tick();
|
||||||
|
assert(sim_learn_start_cnt == 1);
|
||||||
assert(g_env_resync == 1);
|
assert(g_env_resync == 1);
|
||||||
for (int i = 0; i < 100; i++)
|
|
||||||
sim_tick(); /* 学习窗1 未完 */
|
/* 学习 100 tick 后目标靠近 (dev=-95 进入确认区) → 打断 */
|
||||||
sim_CAPVD = 128000UL; /* dev=-95 窗口内(B 目标) */
|
for (i = 0; i < 100; i++)
|
||||||
|
sim_tick();
|
||||||
|
sim_CAPVD = 128000UL; /* dev=-95 */
|
||||||
sim_tick();
|
sim_tick();
|
||||||
assert(g_env_resync == 0); /* 打断退出学习 */
|
assert(g_env_resync == 0); /* 打断退出学习 */
|
||||||
assert(ev_abort == 1);
|
assert(sim_abort >= 1);
|
||||||
assert(env_warn_active() == 1); /* 预判锁存保持 (环境未确认恢复) */
|
assert(env_warn_active() == 1); /* 预判锁存保持 (环境未确认恢复) */
|
||||||
assert(g_env_recover_cnt == 0); /* 目标在进入确认区, 恢复计时清零 */
|
assert(g_env_recover_cnt == 0); /* 目标在进入确认区 → 恢复计时清零 */
|
||||||
|
|
||||||
/* 目标离开, 高位重新 60s → 学习 3 窗 → 替换 */
|
/* 目标离开, 高位重现 → 重新等待 10s + 学习 3 窗 → 替换 */
|
||||||
|
learn_start_before = sim_learn_start_cnt;
|
||||||
sim_CAPVD = 128856UL;
|
sim_CAPVD = 128856UL;
|
||||||
for (int i = 0; i < 7000 && !ev_applied; i++)
|
for (i = 0; i < 4000 && !sim_applied; i++)
|
||||||
sim_tick();
|
sim_tick();
|
||||||
|
assert(sim_learn_start_cnt == learn_start_before + 1);
|
||||||
printf("学习期打断: abort=%d 重新学习启动=%d 最终替换tick计数=%d Origin=%lu\n",
|
assert(sim_applied == 1);
|
||||||
ev_abort, ev_learn_start, 0, (unsigned long)sim_Origin);
|
|
||||||
assert(ev_applied == 1);
|
|
||||||
assert(ev_learn_start == 2);
|
|
||||||
assert(sim_Origin == 128856UL);
|
assert(sim_Origin == 128856UL);
|
||||||
assert(env_warn_active() == 1); /* 替换后黄灯保持到恢复确认 */
|
assert(env_warn_active() == 1); /* 替换后保持到恢复确认 */
|
||||||
for (int i = 0; i < 500; i++)
|
|
||||||
sim_tick(); /* 窗口恢复确认 5s */
|
/* 空闲 5s → 黄灯灭 */
|
||||||
assert(env_warn_active() == 0); /* 黄灯灭 */
|
for (i = 0; i < 600; i++)
|
||||||
printf(" 场景3 PASS — 学习期打断重算+锁存保持, 恢复确认后灭\n\n");
|
sim_tick();
|
||||||
|
assert(env_warn_active() == 0);
|
||||||
|
printf("3. 学习期打断重算, 最终恢复 OK\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_unstable_learn_gives_up(void)
|
/* ============ 场景 4: 学习期持续不稳 → 30s 预算放弃 ============ */
|
||||||
|
static void test_learn_unstable_abort(void)
|
||||||
{
|
{
|
||||||
/* ④ 学习期每窗均值漂移 >0.1% (CAPVD 高位大幅交替 128856±200..400)
|
int i;
|
||||||
* → settle 永远到不了 2 → 30s 预算超时放弃, 保留旧 Origin */
|
|
||||||
t_set(128095UL, 128856UL, 48);
|
|
||||||
for (int i = 0; i < 6000; i++)
|
|
||||||
sim_tick(); /* 进入学习 */
|
|
||||||
assert(g_env_resync == 1);
|
|
||||||
|
|
||||||
int tick = 0;
|
env_reset();
|
||||||
for (; tick < 3500 && !ev_applied && g_env_resync; tick++) {
|
sim_Origin = 128095UL;
|
||||||
/* 交替高值: 窗与窗之间均值漂移 ~200 > band(~129), 且 dev 恒 >192 */
|
|
||||||
sim_CAPVD = ((tick / ENV_LEARN_WINDOW) & 1) ? 129256UL : 129056UL;
|
/* 高位 10s → 学习开始; 然后窗口均值交替漂移 >0.1% (129056/129256) */
|
||||||
|
for (i = 0; i < 1000; i++) {
|
||||||
|
sim_CAPVD = 128856UL;
|
||||||
sim_tick();
|
sim_tick();
|
||||||
}
|
}
|
||||||
|
assert(g_env_resync == 1);
|
||||||
|
|
||||||
printf("学习期不稳: 预算放弃 tick=%d applied=%d resync=%d warn=%d Origin=%lu\n",
|
for (i = 0; i < 3500; i++) {
|
||||||
tick, ev_applied, g_env_resync, g_env_warn, (unsigned long)sim_Origin);
|
/* 每窗 200 样本交替 129056 / 129256 → 窗间漂移 200 > band~129 → settle 恒 0 */
|
||||||
assert(ev_applied == 0);
|
sim_CAPVD = ((i / 200) & 1) ? 129256UL : 129056UL;
|
||||||
assert(g_env_resync == 0); /* 超时退出学习 */
|
sim_tick();
|
||||||
assert(env_warn_active() == 1); /* 环境仍异常 → 黄灯保持锁存 */
|
}
|
||||||
assert(ev_abort >= 1);
|
/* 1000(等待) + 3000(学习预算) ≈ 放弃于 tick 4000; 总 tick 4500 < 再学阈值(5000) */
|
||||||
assert(sim_Origin == 128095UL); /* Origin 不被污染 */
|
assert(sim_learn_start_cnt == 1); /* 只有一次学习启动 */
|
||||||
printf(" 场景4 PASS — 学习不稳定 30s 放弃保留旧 Origin, 黄灯保持异常指示\n\n");
|
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");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_no_learning_after_replace(void)
|
/* ============ 场景 5: 替换后不震荡, 无重复学习 ============ */
|
||||||
|
static void test_no_oscillation_after_apply(void)
|
||||||
{
|
{
|
||||||
/* ⑤ 替换后 Origin≈CAPVD → dev≈0 正常窗口跟踪, 不再触发二次学习 */
|
int i, lsc;
|
||||||
t_set(128095UL, 128856UL, 48);
|
|
||||||
for (int i = 0; i < 7000 && !ev_applied; i++)
|
|
||||||
sim_tick();
|
|
||||||
assert(ev_applied == 1);
|
|
||||||
|
|
||||||
int before = ev_learn_start;
|
env_reset();
|
||||||
for (int i = 0; i < 6000; i++)
|
sim_Origin = 128095UL; sim_CAPVD = 128856UL;
|
||||||
sim_tick(); /* 新 Origin 下高位条件消失 */
|
|
||||||
assert(ev_learn_start == before); /* 无新学习 */
|
for (i = 0; i < 4000 && !sim_applied; i++)
|
||||||
assert(env_warn_active() == 0); /* 恢复确认 5s 后黄灯已灭 */
|
sim_tick();
|
||||||
printf("替换后稳态: 高位条件消失, 无重复学习, 黄灯灭 (Origin=%lu)\n",
|
assert(sim_applied == 1);
|
||||||
(unsigned long)sim_Origin);
|
|
||||||
printf(" 场景5 PASS — 恢复后进入正常跟踪, 不震荡\n\n");
|
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); /* 未被再次改写 */
|
||||||
|
assert(sim_Origin == 128856UL);
|
||||||
|
assert(env_warn_active() == 0); /* 恢复确认后黄灯已灭 */
|
||||||
|
printf("5. 替换后不震荡无重复学习 OK\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
test_permanent_change_recovers();
|
test_permanent_change_recovers();
|
||||||
test_transient_never_learns();
|
test_transient_no_learn();
|
||||||
test_learn_interrupted_restarts();
|
test_learn_interrupt_retry();
|
||||||
test_unstable_learn_gives_up();
|
test_learn_unstable_abort();
|
||||||
test_no_learning_after_replace();
|
test_no_oscillation_after_apply();
|
||||||
printf("ALL PASS (5 scenarios)\n");
|
printf("\nALL PASS (ENV_RESYNC_WAIT=%d)\n", ENV_RESYNC_WAIT);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,6 +48,9 @@
|
|||||||
#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 才解除预判, 黄灯灭
|
#define ENV_RECOVER_WAIT 500 // 恢复确认 (V4.25): 环境回正常(空闲)连续 ~5s 才解除预判, 黄灯灭
|
||||||
|
#define COIL_F_OK_MIN_KHZ 20 // 线圈频率合理窗 (V4.26): 默认低频档口径, <20kHz → L偏大
|
||||||
|
#define COIL_F_OK_MAX_KHZ 120 // 线圈频率合理窗 (V4.26): >120kHz → L偏小
|
||||||
|
#define COIL_DEF_C_NF 66 // 默认档电容 (V4.26): 拨码不可读, 粗估 L 打印用; 33nF 档 ×2
|
||||||
|
|
||||||
/*===========================================================================
|
/*===========================================================================
|
||||||
* 离开检测模式
|
* 离开检测模式
|
||||||
|
|||||||
@@ -14,10 +14,10 @@
|
|||||||
#define __CMCNG_H__
|
#define __CMCNG_H__
|
||||||
|
|
||||||
#define PRODUCT_MODEL "DLD154"
|
#define PRODUCT_MODEL "DLD154"
|
||||||
#define FIRMWARE_VER "4.25"
|
#define FIRMWARE_VER "4.26"
|
||||||
#define HARDWARE_VER "3.00"
|
#define HARDWARE_VER "3.00"
|
||||||
#define FIRMWARE_VER_MAIN 4
|
#define FIRMWARE_VER_MAIN 4
|
||||||
#define FIRMWARE_VER_SUB 25
|
#define FIRMWARE_VER_SUB 26
|
||||||
#define HARDWARE_VER_MAIN 3
|
#define HARDWARE_VER_MAIN 3
|
||||||
#define HARDWARE_VER_SUB 0
|
#define HARDWARE_VER_SUB 0
|
||||||
|
|
||||||
|
|||||||
@@ -139,6 +139,8 @@ uint8_t g_disconnect_count = 0;
|
|||||||
uint8_t g_disconnect_active = 0;
|
uint8_t g_disconnect_active = 0;
|
||||||
uint8_t g_fault_phase = 0;
|
uint8_t g_fault_phase = 0;
|
||||||
uint16_t g_fault_tick = 0;
|
uint16_t g_fault_tick = 0;
|
||||||
|
uint8_t g_coil_fault = 0; // V4.26: 线圈电感量异常 0=正常 1=L偏大(f<20kHz) 2=L偏小(f>120kHz)
|
||||||
|
uint16_t g_coil_bad_cnt = 0; // V4.26: 电感异常防抖计数 (100tick=1s 置位/清除)
|
||||||
|
|
||||||
/*===========================================================================
|
/*===========================================================================
|
||||||
* 调试计数器
|
* 调试计数器
|
||||||
@@ -300,12 +302,16 @@ void poll_green_led(void)
|
|||||||
*
|
*
|
||||||
* 由 TMR15 ISR 每 5ms 驱动一次。
|
* 由 TMR15 ISR 每 5ms 驱动一次。
|
||||||
*
|
*
|
||||||
* 模式判定:
|
* 模式判定 (V4.26 优先级: 1>4>5>3>2):
|
||||||
* 当前线圈断开 或 上电后从未接线圈:
|
* 1 当前线圈断开 或 上电后从未接线圈:
|
||||||
* → 快闪 (200ms 亮 / 200ms 灭)
|
* → 快闪 (200ms 亮 / 200ms 灭)
|
||||||
* 线圈已恢复连接, 且上电后有断开记录 (g_disconnect_count >= 1):
|
* 4 环境异常预判/重校准学习 (g_env_warn/g_env_resync):
|
||||||
|
* → 常亮 (V4.24/25, 故障补偿 10s 内完成)
|
||||||
|
* 5 线圈电感量不合理 (g_coil_fault, 频率 20~120kHz 窗之外):
|
||||||
|
* → 一长一短 (长亮200ms/灭100ms/短亮100ms/灭800ms 循环)
|
||||||
|
* 3 线圈已恢复连接, 且上电后有断开记录 (g_disconnect_count >= 1):
|
||||||
* → N 短闪 (80ms亮/200ms灭 × N, 1.2s间隔, N=断开次数≤3)
|
* → N 短闪 (80ms亮/200ms灭 × N, 1.2s间隔, N=断开次数≤3)
|
||||||
* 线圈正常连接, 无断开记录:
|
* 2 线圈正常连接, 无断开记录:
|
||||||
* → 灭
|
* → 灭
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
void poll_yellow_led(void)
|
void poll_yellow_led(void)
|
||||||
@@ -338,6 +344,24 @@ void poll_yellow_led(void)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*--- V4.26 模式5: 线圈电感量不合理 → 一长一短
|
||||||
|
* 长亮200ms(40tick) → 灭100ms(20) → 短亮100ms(20) → 灭800ms(160), 循环
|
||||||
|
* g_coil_fault: 1=L偏大(f<20kHz) 2=L偏小(f>120kHz)
|
||||||
|
* 优先级: 断开(1) > 环境(4) > 电感量(5) > N短闪(3) > 灭 ---*/
|
||||||
|
if (g_coil_fault) {
|
||||||
|
static const uint16_t dur[4] = { 40, 20, 20, 160 };
|
||||||
|
if (g_fault_phase > 3) g_fault_phase = 0;
|
||||||
|
if (g_fault_phase & 1)
|
||||||
|
LED_YELLOW_OFF;
|
||||||
|
else
|
||||||
|
LED_YELLOW_ON;
|
||||||
|
if (g_fault_tick >= dur[g_fault_phase]) {
|
||||||
|
g_fault_tick = 0;
|
||||||
|
g_fault_phase++;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t N = g_disconnect_count;
|
uint8_t N = g_disconnect_count;
|
||||||
|
|
||||||
if (N == 0) {
|
if (N == 0) {
|
||||||
@@ -776,6 +800,43 @@ static void env_resync_apply(uint32_t new_origin)
|
|||||||
#endif
|
#endif
|
||||||
env_resync_abort();
|
env_resync_abort();
|
||||||
}
|
}
|
||||||
|
/*===========================================================================
|
||||||
|
* V4.26: 线圈电感量合理范围监视
|
||||||
|
* 拍板规格: 默认低频档口径, 空场频率合理窗 20~120kHz, 出界即判定电感量不合理
|
||||||
|
* (黄灯"一长一短"告警, 见 poll_yellow_led 模式5)
|
||||||
|
* 调用点保证: 仅稳定 + 无车空闲 + 未断开时执行 (车压/自检/断开不判)
|
||||||
|
* g_coil_fault: 0=正常 1=L偏大(f<20kHz) 2=L偏小(f>120kHz)
|
||||||
|
* 防抖: 越界/恢复均连续 100tick(=1s) 才置位/清除
|
||||||
|
*===========================================================================*/
|
||||||
|
static void coil_monitor(void)
|
||||||
|
{
|
||||||
|
uint32_t f_khz = calc_freq_khz(loop1_Origin, loop1_LPCNT);
|
||||||
|
uint8_t want = 0;
|
||||||
|
|
||||||
|
if (loop1_Origin == 0 || f_khz == 0)
|
||||||
|
return; /* 无有效基准 → 维持原状 */
|
||||||
|
|
||||||
|
if (f_khz < COIL_F_OK_MIN_KHZ)
|
||||||
|
want = 1; /* L 偏大 (>合理上限) */
|
||||||
|
else if (f_khz > COIL_F_OK_MAX_KHZ)
|
||||||
|
want = 2; /* L 偏小 (<合理下限) */
|
||||||
|
|
||||||
|
if (want == g_coil_fault) {
|
||||||
|
g_coil_bad_cnt = 0; /* 状态一致 → 计时复位 */
|
||||||
|
} else {
|
||||||
|
g_coil_bad_cnt++;
|
||||||
|
if (g_coil_bad_cnt >= 100) {
|
||||||
|
if (g_coil_fault == 0)
|
||||||
|
PRINT("EVT|coil_fault f:%d kHz L~%lu uH(C66/×2C33) %s\n",
|
||||||
|
f_khz, 25330000UL / (uint32_t)(f_khz * f_khz * COIL_DEF_C_NF),
|
||||||
|
want == 1 ? "too_large" : "too_small");
|
||||||
|
else
|
||||||
|
PRINT("EVT|coil_ok f:%d kHz\n", f_khz);
|
||||||
|
g_coil_fault = want;
|
||||||
|
g_coil_bad_cnt = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*===========================================================================
|
/*===========================================================================
|
||||||
* vd1_task — 核心检测算法(对齐 M1H VD1_TASK)
|
* vd1_task — 核心检测算法(对齐 M1H VD1_TASK)
|
||||||
@@ -792,7 +853,7 @@ void vd1_task(void)
|
|||||||
#define STABLE_ORIGIN_PPT 1 // 基准稳定判据: 窗口均值漂移 ≤ Origin×1/1000 (0.1%)
|
#define STABLE_ORIGIN_PPT 1 // 基准稳定判据: 窗口均值漂移 ≤ Origin×1/1000 (0.1%)
|
||||||
#define STABLE_SETTLE_WINDOWS 2 // 连续 2 个窗口(每窗100样本≈1s)漂移达标 → 判稳
|
#define STABLE_SETTLE_WINDOWS 2 // 连续 2 个窗口(每窗100样本≈1s)漂移达标 → 判稳
|
||||||
#define STABLE_MAX_SAMPLES 500 // 硬兜底: 5s 未判稳强制结束自检(防绿灯无限闪)
|
#define STABLE_MAX_SAMPLES 500 // 硬兜底: 5s 未判稳强制结束自检(防绿灯无限闪)
|
||||||
#define ENV_RESYNC_WAIT 6000 // V4.24: dev>+4dlt 高位连续 60s → 判定永久环境变化
|
#define ENV_RESYNC_WAIT 1000 // V4.26: dev>+4dlt 高位连续 10s → 判定永久环境变化 (拍板: 故障补偿 60s→10s)
|
||||||
#define ENV_LEARN_WINDOW 200 // V4.24: 环境学习窗口 2s (200×10ms)
|
#define ENV_LEARN_WINDOW 200 // V4.24: 环境学习窗口 2s (200×10ms)
|
||||||
#define ENV_LEARN_MAX_TICKS 3000 // V4.24: 学习预算 30s, 超时放弃 (防黄灯常亮死锁)
|
#define ENV_LEARN_MAX_TICKS 3000 // V4.24: 学习预算 30s, 超时放弃 (防黄灯常亮死锁)
|
||||||
|
|
||||||
@@ -935,7 +996,7 @@ void vd1_task(void)
|
|||||||
} else {
|
} else {
|
||||||
/* 负variation (CAPVD高于Origin, 特殊铁块磁导率主导/异常高)
|
/* 负variation (CAPVD高于Origin, 特殊铁块磁导率主导/异常高)
|
||||||
* V4.24 两段式:
|
* V4.24 两段式:
|
||||||
* ① 前 60s(ENV_RESYNC_WAIT): 只冻结, 不更新 Origin
|
* ① 前 10s(ENV_RESYNC_WAIT): 只冻结, 不更新 Origin
|
||||||
* (36321a1 双向保护原语义: 防铁块污染 Origin → 离开假进入锁死)
|
* (36321a1 双向保护原语义: 防铁块污染 Origin → 离开假进入锁死)
|
||||||
* ② 高位连续 ≥60s 未回摆 → 判定"永久环境变化"(如金属板A拿走、基准被学低)
|
* ② 高位连续 ≥60s 未回摆 → 判定"永久环境变化"(如金属板A拿走、基准被学低)
|
||||||
* → 进入受控重校准: 连续空闲窗口均值 B + settle 判稳 → 空闲原子替换 Origin
|
* → 进入受控重校准: 连续空闲窗口均值 B + settle 判稳 → 空闲原子替换 Origin
|
||||||
@@ -1006,6 +1067,9 @@ void vd1_task(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*--- V4.26: 线圈电感量监视 (调用点=稳定无车空闲, 见 coil_monitor) ---*/
|
||||||
|
coil_monitor();
|
||||||
|
|
||||||
/*--- 进入确认 — 连续 ENTRY_CONFIRM 次低于阈值才判有车 ---*/
|
/*--- 进入确认 — 连续 ENTRY_CONFIRM 次低于阈值才判有车 ---*/
|
||||||
if (loop1_CAPVD < (loop1_Origin - loop1_dlt_ORG)) {
|
if (loop1_CAPVD < (loop1_Origin - loop1_dlt_ORG)) {
|
||||||
if (loop1_entry_cnt == 0) {
|
if (loop1_entry_cnt == 0) {
|
||||||
|
|||||||
Reference in New Issue
Block a user