diff --git a/docs/coil-range-alarm-design.md b/docs/coil-range-alarm-design.md index 8d8b463..28d2bc7 100644 --- a/docs/coil-range-alarm-design.md +++ b/docs/coil-range-alarm-design.md @@ -1,7 +1,7 @@ # 线圈电感量估算与不合理范围告警 — 设计讨论稿 -> **状态:已实现(V4.26,2026-09-03)** — 本文为设计讨论与实现归档;落地代码见 TaskLoop.c coil_monitor()(vd1_task 无车主路径调用)与 poll_yellow_led() 模式 5。 -> 固件版本基线:V4.26(cmcng.h);涉及产品:DLD154V4B(DLD154V4)。 +> **状态:已实现(V4.26/V4.27,2026-09-03)** — 本文为设计讨论与实现归档;落地代码见 TaskLoop.c coil_monitor()(vd1_task 无车主路径调用)与 poll_yellow_led() 模式 5。 +> 固件版本基线:V4.27(cmcng.h);涉及产品:DLD154V4B(DLD154V4)。 **修订记录:** @@ -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.26(672f143 后) | +| v0.4 | 2026-09-03 | **测频 4 倍偏差修正(V4.27)**:calc_freq_khz 60000→240000(TMR3 实际 120MHz 计数 + 通道捕获 DIV_2)。本文 §3 中"Xn=3681→f=16.3kHz→L≈1.4mH 超限案例"为**测频 bug 假象**——修正后实为 f≈65.2kHz、L≈90µH 的正常线圈;该"红区案例"作废,需按真实频率重新采集现场数据 | ## 1. 背景 diff --git a/docs/devlog.md b/docs/devlog.md index acc17e2..254b1cd 100644 --- a/docs/devlog.md +++ b/docs/devlog.md @@ -4,6 +4,44 @@ --- +## 2026-09-03 — 频率测量 4 倍偏差修正(固件 V4.27) + +> **固件版本:V4.27**(cmcng.h:FIRMWARE_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.27;spec §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 error;tests/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.h:FIRMWARE_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/CAPVD,V4.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/CAPVD(60MHz 捕获时钟),验证:无车 99kHz / 深车 124kHz ✓ +- `calc_freq_khz(capvd, lp_cnt)`:f_kHz = 240000×LPCNT/CAPVD(V4.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→240000:120MHz×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 删除) | diff --git a/docs/technical-spec.md b/docs/technical-spec.md index fa7d574..b00e190 100644 --- a/docs/technical-spec.md +++ b/docs/technical-spec.md @@ -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→240000:TMR3 实际 120MHz 计数 + 通道 DIV_2 边沿分频,原按 60MHz 假设漏乘 2×2);§4.1.2 流程文字更正 | diff --git a/utilities/at32f421_freertos_demo/inc/cmcng.h b/utilities/at32f421_freertos_demo/inc/cmcng.h index bc4cbae..636ee56 100644 --- a/utilities/at32f421_freertos_demo/inc/cmcng.h +++ b/utilities/at32f421_freertos_demo/inc/cmcng.h @@ -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 diff --git a/utilities/at32f421_freertos_demo/src/TaskLoop.c b/utilities/at32f421_freertos_demo/src/TaskLoop.c index e20348b..e7aea59 100644 --- a/utilities/at32f421_freertos_demo/src/TaskLoop.c +++ b/utilities/at32f421_freertos_demo/src/TaskLoop.c @@ -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 - * 无车: CAPVD≈131072, LPCNT≈218 → ≈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 → L≈27µ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) → L≈1445µH; Xn=685(f=87.6k) → L≈50µ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 → L≈420µH; f=65.2kHz → L≈90µH; f=120kHz → L≈27µ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,