fix(V4B): V4.27 — 频率测量 4 倍偏差修正 (示波器 30.23k vs 打印 7k)

根因(两处2倍叠加):
1. calc_freq_khz 常数 60000 按 60MHz 假设; 实际 TMR3 计数时钟=sclk=120MHz (HEXT×10, AHB/APB1÷1)
2. 输入捕获 DIV_2 (每2边沿捕获, Xn 翻倍), g_input_div 从未参与换算
→ Xn=2×120M/f_real, f_print=f_real/4 (30.23/4=7.56✓ 36.82/4=9.21✓)

改动: calc 60000→240000 (注释推导); coil_l_uH 改随 f_kHz (25330000/(f²×C66));
      DBG/EVT 用同一 _fk; 版本 V4.27; spec §4.1.2 文字更正 + devlog/design v0.4 标注影响

影响: 旧日志 f/L 需×4 (16.3kHz 假象实为 65.2kHz≈90µH 正常线圈); V4.26 告警窗随真实 f 自洽
This commit is contained in:
wangfq
2026-09-03 11:49:43 +08:00
parent dd14e083fa
commit 6b7d624ff0
5 changed files with 70 additions and 21 deletions
+3 -2
View File
@@ -1,7 +1,7 @@
# 线圈电感量估算与不合理范围告警 — 设计讨论稿
> **状态:已实现(V4.262026-09-03)** — 本文为设计讨论与实现归档;落地代码见 TaskLoop.c coil_monitor()vd1_task 无车主路径调用)与 poll_yellow_led() 模式 5。
> 固件版本基线:V4.26cmcng.h);涉及产品:DLD154V4BDLD154V4)。
> **状态:已实现(V4.26/V4.272026-09-03)** — 本文为设计讨论与实现归档;落地代码见 TaskLoop.c coil_monitor()vd1_task 无车主路径调用)与 poll_yellow_led() 模式 5。
> 固件版本基线:V4.27cmcng.h);涉及产品:DLD154V4BDLD154V4)。
**修订记录:**
@@ -10,6 +10,7 @@
| v0.1 | 2026-09-02 | 初稿(合理范围按 50~300 µ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.26672f143 后) |
| 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 的正常线圈;该"红区案例"作废,需按真实频率重新采集现场数据 |
## 1. 背景
+41 -2
View File
@@ -4,6 +4,44 @@
---
## 2026-09-03 — 频率测量 4 倍偏差修正(固件 V4.27)
> **固件版本:V4.27**cmcng.hFIRMWARE_VER="4.27" + MAIN=4/SUB=27)。devlog 修订 V2.25。
### 问题(用户现场实测对比示波器)
DBG 打印低频 **7kHz** / 高频 **9kHz**;示波器实测 **30.23kHz** / **36.82kHz**——固件少算 4 倍
30.23/4=7.56、36.82/4=9.21,整数截断吻合)。
### 根因(两处 2 倍叠加)
1. `calc_freq_khz` 常数 60000 按 **60MHz** 计数时钟假设;实际 TMR3 计数时钟 = sclk = **120MHz**
HEXT×10、AHB÷1、APB1÷1,见 at32f421_clock.c
2. 输入捕获配置 `TMR_CHANNEL_INPUT_DIV_2`(每 2 个信号边沿捕获一次 → Xn 翻倍);
board.c 算出的 `g_input_div` 从未参与频率换算
→ Xn = 2×120MHz/f_real → f_print = 60000/Xn = f_real/4。
spec §4.1.2 曾把"DIV_2"误述为"120MHz→60MHz 时钟"——实际是**边沿计数分频**,
不是时钟分频;等效采样率是 240M/周期而非 60M/周期。
### 改动
- `calc_freq_khz`60000 → **240000**240000 = 120MHz×DIV_2 的 kHz 口径;注释完整推导)
- `coil_l_uH`:改用修正后 f_kHz 计算(L_uH = 2.533e7/(f_kHz²×C_nF)),DBG/EVT 用同一 _fk
- 版本 V4.26→V4.27spec §4.1.2 流程文字更正;devlog 解读表同步 240000
### 影响面(重要)
- **旧日志全部 f/L 需 ×4 修正**:如"16.3kHz→L1445µH 超限"实为 **65.2kHz→L≈90µH 正常线圈**
- V4.26 线圈告警窗口(20~120kHz)判定随 calc 同步用真实频率,行为自洽;此前据
"16.3kHz 案例"的结论需按真实频率重新评估(该案例实为测频 bug 假象)
- LPCNT 自适应窗口/CAPVD/dlt/灵敏度等基于 Xn 比值,不受影响
### 验证
- gcc -fsyntax-only 0 errortests/env_resync/coil_range/power_on_stable/red_breath 全 PASS
- 待现场:串口 f ≈ 示波器(低频 30.23 / 高频 36.82);L 打印 ≈420µH@30.2kHz(默认 66nF 档)
## 2026-09-03 — 线圈电感量告警 + 故障补偿提速(固件 V4.26)
> **固件版本:V4.26**cmcng.hFIRMWARE_VER="4.26" + MAIN=4/SUB=26)。devlog 修订 V2.24。
@@ -232,7 +270,7 @@ DBG|t=2000ms f=99kHz Xn=600 LPCNT=218 Value=131072 CAPVD=131072 slow=131072 Orig
```
| 字段 | 含义 |
|------|------|
| f | 线圈振荡频率 kHz=60000×LPCNT/CAPVD无车≈100 |
| f | 线圈振荡频率 kHz=240000×LPCNT/CAPVDV4.27 修正:TMR3=120MHz 计数 + 通道 DIV_2 |
| Xn / LPCNT | 瞬时周期 / 自适应窗口 |
| Value / CAPVD / slow | 原始采样 / 主滤波 / 慢滤波(方案A) |
| Origin / dlt | 基准值 / 当前阈值(无车=进入线,有车=释放线) |
@@ -254,7 +292,7 @@ DBG|t=2000ms f=99kHz Xn=600 LPCNT=218 Value=131072 CAPVD=131072 slow=131072 Orig
### 辅助实现
- `calc_freq_khz(capvd, lp_cnt)`f_kHz = 60000×LPCNT/CAPVD60MHz 捕获时钟),验证:无车 99kHz / 深车 124kHz ✓
- `calc_freq_khz(capvd, lp_cnt)`f_kHz = 240000×LPCNT/CAPVDV4.27 修正:TMR3 计数 120MHz × 通道捕获 DIV_2 → 等效 240MHz/周期;旧 60000 按 60MHz 假设漏算 4 倍)
- `g_slope_limit_cnt`:斜率限幅截断计数(IIR 输入被 5% 限幅截断时 +1,周期打印带出后清零)
### 待办
@@ -1106,6 +1144,7 @@ if (dev >= dlt_ORG × 4) {
| 版本 | 时间 | 说明 |
|------|------|------|
| V2.25 | 2026-09-03 | V4.27 频率测量 4 倍偏差修正(calc 60000→240000120MHz×DIV_2);coil_l_uH 随 f 修正;旧 f/L 日志需 ×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.20 | 2026-09-02 | V4.22 DEBUG 改编译器 -DDEBUG 控制(cmcng.h DEBUG_ENABLE 删除) |
+5 -3
View File
@@ -1,6 +1,6 @@
# DLD154V4B 技术规格书
> 单路线圈车辆检测器 | 固件版本: V4.26 | 文档版本: V2.5
> 单路线圈车辆检测器 | 固件版本: V4.27 | 文档版本: V2.6
> 本文档面向工程开发、系统集成及故障深度分析
---
@@ -129,8 +129,9 @@ DLD154V4B **不使用** CD4060 外部分频芯片。线圈直接驱动 PA7 (TIM3
线圈边沿 → PA7 (TIM3_CH2)
TIM3 自由运行 (16-bit, 120MHz/DIV_2 = 60MHz 时钟)
└─ 每个边沿 → CH2 捕获 → 读 CCR2
TIM3 自由运行 (16-bit, 计数时钟 = sclk = 120MHz)
└─ 通道输入捕获 DIV_2 (每 2 个信号边沿捕获一次) → CH2 捕获 → 读 CCR2
Xn = 2 × 120MHz / f_real → f_kHz = 240000 × LPCNT / CAPVD (V4.27 修正)
TMR3 ISR:
@@ -770,3 +771,4 @@ DLD154V4B V1.4 起实现该专利的整数化版本,用于大车通行时的
| 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.5 | 2026-09-03 | 更新至 V4.26:线圈电感量告警(频率窗 20~120kHz 单窗,黄灯一长一短);故障补偿 ENV_RESYNC_WAIT 60s→10s;黄灯优先级 1>4>5>3>2 |
| V2.6 | 2026-09-03 | 更新至 V4.27:频率测量 4 倍偏差修正(calc_freq_khz 60000→240000TMR3 实际 120MHz 计数 + 通道 DIV_2 边沿分频,原按 60MHz 假设漏乘 2×2);§4.1.2 流程文字更正 |
+2 -2
View File
@@ -14,10 +14,10 @@
#define __CMCNG_H__
#define PRODUCT_MODEL "DLD154"
#define FIRMWARE_VER "4.26"
#define FIRMWARE_VER "4.27"
#define HARDWARE_VER "3.00"
#define FIRMWARE_VER_MAIN 4
#define FIRMWARE_VER_SUB 26
#define FIRMWARE_VER_SUB 27
#define HARDWARE_VER_MAIN 3
#define HARDWARE_VER_SUB 0
+19 -12
View File
@@ -755,16 +755,21 @@ void TMR15_GLOBAL_IRQHandler(void)
* V4.20 debug (2026-09-01)
*
* calc_freq_khz: 线
* f = (60MHz) / Xn_avg, Xn_avg = CAPVD / LPCNT
* f_kHz = 60000 × LPCNT / CAPVD
* : CAPVD131072, LPCNT218 99.8kHz; : Xn f
* : 线 PA7(TMR3_CH2) , ÷2 (DIV_2),
* TMR3 = sclk = 120MHz (HEXT×10, AHB/APB1 ÷1, at32f421_clock.c)
* Xn = = 2 × 120MHz / f_real f_kHz = 240000 / Xn
* CAPVD LPCNT × Xn 240000 × LPCNT / CAPVD
* f_kHz = 240000 × LPCNT / CAPVD
* V4.27 : 60000 60MHz + DIV_2, 4
* ( 30.23kHz 7kHz ; 16.3kHz ~65.2kHz)
* L : f=120kHz @66nF L27µH (, )
*===========================================================================*/
uint32_t g_slope_limit_cnt = 0; // 斜率限幅截断计数 (EMI/干扰线索, 周期打印带出)
static uint32_t calc_freq_khz(uint32_t capvd, uint16_t lp_cnt)
{
if (capvd == 0) return 0;
return (60000UL * lp_cnt) / capvd;
return (240000UL * lp_cnt) / capvd;
}
/*===========================================================================
@@ -801,13 +806,14 @@ static void env_resync_apply(uint32_t new_origin)
env_resync_abort();
}
/*===========================================================================
* V4.26: 线 ( C=66nF; 33nF ×2)
* f = 60MHz/Xn L_uH = Xn^2 / (4π^2 × 60MHz^2×1e-9... Xn^2/(142×C_nF)
* : Xn=3681(f=16.3k) L1445µH; Xn=685(f=87.6k) L50µH
* V4.26/27: 线 ( C=66nF; 33nF ×2)
* L_uH = 2.533e7 / (f_kHz² × C_nF) [f=1/(2π(LC)), f_kHz ]
* : f=30.2kHz L420µH; f=65.2kHz L90µH; f=120kHz L27µH
*===========================================================================*/
static uint32_t coil_l_uH(uint32_t xn)
static uint32_t coil_l_uH(uint32_t f_khz)
{
return (uint32_t)(((uint64_t)xn * xn) / ((uint64_t)COIL_DEF_C_NF * 142u));
if (f_khz == 0) return 0;
return 25330000UL / (f_khz * f_khz * COIL_DEF_C_NF);
}
/*===========================================================================
@@ -838,7 +844,7 @@ static void coil_monitor(void)
if (g_coil_bad_cnt >= 100) {
if (g_coil_fault == 0)
PRINT("EVT|coil_fault f:%d kHz L~%lu uH(C66/×2C33) Xn:%d %s\n",
f_khz, coil_l_uH(loop1_Xn), loop1_Xn,
f_khz, coil_l_uH(f_khz), loop1_Xn,
want == 1 ? "too_large" : "too_small");
else
PRINT("EVT|coil_ok f:%d kHz\n", f_khz);
@@ -1306,11 +1312,12 @@ void loop_task_function(void *pvParameters)
if (_dbg_cnt >= 200) { // 200 × 10ms = 2s
uint32_t _t_ms = _dbg_cnt * 10; // V4.20: 先取时间再归零
_dbg_cnt = 0;
uint32_t _fk = calc_freq_khz(loop1_CAPVD, loop1_LPCNT);
PRINT("DBG|t=%ums f=%dkHz L=%luuH Xn=%d LPCNT=%d Value=%d CAPVD=%d slow=%d "
"Origin=%d dlt=%d SENS=%d VD=%d FRZ=%d/%d LIM=%d LOOP=%d STBL=%d\n",
_t_ms,
calc_freq_khz(loop1_CAPVD, loop1_LPCNT),
coil_l_uH(loop1_Xn),
_fk,
coil_l_uH(_fk),
loop1_Xn, loop1_LPCNT, loop1_Value, loop1_CAPVD, loop1_CAPVD_slow,
loop1_Origin, loop1_dlt_ORG, loop1_SensLevel, loop1_VD_FLAG,
loop1_freeze_cnt, loop1_freeze_ref, g_slope_limit_cnt,