From 60413be73f57fb49ac92d5cd9cc3c8afbe8529c2 Mon Sep 17 00:00:00 2001 From: wangfq Date: Tue, 1 Sep 2026 13:48:22 +0800 Subject: [PATCH] =?UTF-8?q?feat(V4B):=20=E6=96=B9=E6=A1=88B=E5=AE=9E?= =?UTF-8?q?=E9=AA=8C=20V4.05=20=E2=80=94=20USE=5FSLOW=5FRELEASE=3D0=20+=20?= =?UTF-8?q?=E8=B0=83=E6=B7=B1=E9=87=8A=E6=94=BE=E9=98=88=E5=80=BC=E8=A1=A8?= =?UTF-8?q?=20ReleaseTable=5FB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 对比路线(与V4.04方案A A/B): 释放走快滤波(无慢滤波状态, 消除悬停风险), 手感对齐改由调深释放表 {80,42,27,18}(原始{60,32,21,14}加深30%)承担。 ⚠关键认知(仿真+单测双确认): 释放方向是CAPVD向Origin恢复, dlt增大(调深)→释放线降低→释放更早(与'调深=更严格'直觉相反)。 仿真预测: 深信号(≥0.2%)原始表更接近PD132T; 浅信号(0.1%)加深表更接近。 单测: tests/test_planb_release.c 新增(滞回为正✓/加深表释放≤原始表✓/释放时刻合理✓) test_release_slow_filter.c(方案A)仍通过, 两方案可回归 文档: devlog V2.14 + technical-spec §4.3.3 方案B段 --- docs/devlog.md | 52 +++++++++++ docs/technical-spec.md | 2 + tests/test_planb_release.c | 89 +++++++++++++++++++ .../at32f421_freertos_demo/inc/TaskLoop.h | 12 ++- utilities/at32f421_freertos_demo/inc/cmcng.h | 4 +- .../at32f421_freertos_demo/src/TaskLoop.c | 9 +- 6 files changed, 164 insertions(+), 4 deletions(-) create mode 100644 tests/test_planb_release.c diff --git a/docs/devlog.md b/docs/devlog.md index 29ecfd3..dfe9f30 100644 --- a/docs/devlog.md +++ b/docs/devlog.md @@ -4,6 +4,58 @@ --- +## 2026-09-01 — 方案B 实验:快滤波释放 + 调深释放阈值表(固件 V4.05) + +> **固件版本:V4.05**(cmcng.h:FIRMWARE_VER="4.05" + MAIN=4/SUB=5)。devlog 修订 V2.14。 +> **状态:实验对比版**——与 V4.04(方案A)现场 A/B 对比后定稿,二选一保留。 + +### 背景 + +V4.04(方案A:慢滤波释放 α21 + 进入 snap)已修两现象,但现场想对比另一条路线:不用慢滤波状态(消除任何滤波悬停风险),改由**释放阈值表**承担手感对齐。 + +### 方案B 配置(TaskLoop.h) + +| 宏 | 值 | 含义 | +|----|----|------| +| `USE_SLOW_RELEASE` | **0** | 释放走快滤波(α79@10ms, τ≈22ms),无慢滤波状态 | +| `USE_PLANB_TABLE` | **1** | 释放判定用 `ReleaseTable_B`(调深表) | +| `ReleaseTable_B` | `{80, 42, 27, 18}` | 原始表 `{60,32,21,14}` 加深 ~30% | + +各档滞回验证:ReleaseTable_B < SensTable(进入表)→ 滞回为正,无结构假释放。 + +### ⚠ 关键认知:加深方向的物理含义(仿真+单测双重确认) + +释放方向是 CAPVD 从车辆深度**向 Origin 恢复**(从深往浅)。释放线 = Origin − dlt: +- **dlt 增大(调深)→ 释放线降低 → CAPVD 恢复中更早碰到 → 释放更早**(与"调深=更严格"的直觉相反) +- 单测 `tests/test_planb_release.c`:4 档 × 4 速度全部确认"加深表释放 ≤ 原始表"(如 SENS=3, 3s 抬:原始@2960ms → 加深@2930ms) + +### 仿真预测(现场实测验证点) + +| 板信号深度 | 加深表 vs PD132T | 结论 | +|-----------|------------------|------| +| ≥0.2%(200cnt+) | 加深表比 PD132T 早(差 3~6 counts) | 深信号下原始表 `{60,32,21,14}` 更接近 PD132T | +| ~0.1%(100cnt) | 加深表与 PD132T 差 ~1.3 counts | 浅信号下加深表更接近 | + +**现场验证**:若实测"加深表释放比 V4.04 更早(板抬更低就释放)",说明方向如仿真;若与 PD132T 手感更近,则加深表定稿;否则 `USE_PLANB_TABLE=0` 一行切回原始表对比。 + +### 单测 + +- `tests/test_planb_release.c` 新增(gcc 编译通过):滞回为正 ✓ / 加深表释放不晚于原始表 ✓ / 释放时刻合理 ✓ +- `tests/test_release_slow_filter.c`(方案A 单测)仍通过,两方案可回归 + +### 与方案A 的取舍(待现场数据) + +- 方案A:释放曲线"跟手速"与 PD132T 同构(τ 对齐),但有慢滤波悬停状态(V4.04 已 snap 堵死) +- 方案B:无慢滤波状态(结构简单),但释放曲线是"速度无关的固定偏移",深信号下与 PD132T 有固有偏差 +- HR0/2 假释放:方案B 结构性免疫(快滤波进入后已同步到车辆深度,无悬停) + +### 文档同步 + +- technical-spec §4.3.3 补方案B 实验说明 +- analysis/docs/filter-coefficient-79-vs-64.md §4.5 方案B 段(待补) + +--- + ## 2026-09-01 — 方案A 现场复核修正:RELEASE_ALFA 18→21 + 进入 snap(固件 V4.04) > **固件版本:V4.04**(cmcng.h:FIRMWARE_VER="4.04" + MAIN=4/SUB=4)。devlog 修订 V2.13。 diff --git a/docs/technical-spec.md b/docs/technical-spec.md index 7d30ef2..855827a 100644 --- a/docs/technical-spec.md +++ b/docs/technical-spec.md @@ -278,6 +278,8 @@ if ((Origin - dlt_ORG) < CAPVD) { // CAPVD 回升至距基线不 > **⚠ V4.04(2026-09-01)方案A 现场复核修正(RELEASE_ALFA 18→21 + 进入 snap)**:金属板复测两现象——① 慢速抬板释放高度 V4B 仍比 PD132T 高一点(跟手速有关);② 定在 HR0/2(释放高度一半)保持 ~1s V4B 释放、PD132T 不释放。根因:① **τ 对齐用了近似口径**——α18 精确 τ≈137ms vs PD132T α79@43.7ms 精确 τ≈118ms(α=79 时 `T×256/α` 近似公式高估 19.6%),叠加 3 次确认 30ms;② **双滤波进入瞬态假释放**——进入由快滤波 30ms 确认、释放判定用慢滤波,进入确认瞬间慢滤波还悬在基线附近,残余信号落在窄带(SENS=3 时 0.032%~0.044%)时释放条件瞬时为真 → 假释放;PD132T 进出共用同一滤波,结构性免疫。修正:① `RELEASE_ALFA` 18→**21**(精确 τ≈117ms 对齐 PD132T 118ms);② 进入确认处 **snap `loop1_CAPVD_slow = loop1_CAPVD`**(进入线 0.032% 恒深于离开线 0.021%,snap 后释放条件结构性为假)。单测:τ fast=30ms/slow=120ms,释放时机差 200ms;仿真 3s 抬升高度差 +9mm→+3mm,0.10% 板 HR0/2 假释放消除。⚠ 待板级复测。 +> **⚠ V4.05(2026-09-01)方案B 实验(USE_SLOW_RELEASE=0 + USE_PLANB_TABLE=1)**:对比路线——释放走**快滤波**(无慢滤波状态),手感对齐改由**调深释放阈值表** `ReleaseTable_B={80,42,27,18}`(原始 `{60,32,21,14}` 加深 ~30%)承担。⚠ **关键认知:释放方向是 CAPVD 向 Origin 恢复,dlt 增大(调深)→ 释放线降低 → 释放更早**(与"调深=更严格"直觉相反,仿真+单测双确认)。仿真预测:深信号(≥0.2%)加深表比 PD132T 早 3~6 counts,原始表更接近;浅信号(~0.1%)加深表更接近(差 ~1.3 counts)。HR0/2 假释放结构性免疫(无悬停状态)。现场 A/B 对比后定稿,`USE_SLOW_RELEASE`/`USE_PLANB_TABLE` 两宏二选一保留。 + ##### 模式 2:平坦性判定 (USE_FLATNESS_EXIT=1) — ⚠ 默认禁用(#if 0,代码保留) 基于专利 **CN200910309382**(中山大学),解决大车通行时频率多峰导致的多次误触发。 diff --git a/tests/test_planb_release.c b/tests/test_planb_release.c new file mode 100644 index 0000000..21d8b73 --- /dev/null +++ b/tests/test_planb_release.c @@ -0,0 +1,89 @@ +/* + * test_planb_release.c — 方案B (快滤波 + 调深释放阈值表) 单测 + * + * 验证 (V4.05, USE_SLOW_RELEASE=0, USE_PLANB_TABLE=1): + * 1. ReleaseTable_B 各档 < SensTable(进入表) → 滞回为正, 无结构假释放 + * 2. 同快滤波下, 加深表(ReleaseTable_B)释放早于原始表(SensTable_1) + * (物理方向: 释放线低 → CAPVD 恢复更早碰到 → 释放更早) + * 3. 慢速抬板场景: 方案B 释放时刻合理, 无 NaN + * + * 编译: gcc -o /tmp/test_planb test_planb_release.c && /tmp/test_planb + */ +#include +#include +#include + +#define ALFA_FAST 79 /* 主滤波 @10ms, τ≈22ms */ +#define TICK_MS 10 +#define ORIGIN 100000UL + +/* 与 TaskLoop.h 方案B 配置保持一致 */ +static const uint16_t SensTable[4] = {300, 60, 32, 21}; /* 进入表 */ +static const uint16_t SensTable_1[4] = { 60, 32, 21, 14}; /* 原始离开表 */ +static const uint16_t ReleaseTable_B[4] = { 80, 42, 27, 18}; /* 方案B 加深表 */ + +static uint32_t iir(uint32_t v, uint32_t flt, int alfa) +{ + return flt + (uint32_t)(((int32_t)v - (int32_t)flt) * alfa >> 8); +} + +/* 快滤波释放仿真: 板信号 dev0 匀速恢复, 返回释放时刻 ms (0=未释放) */ +static int sim_release_ms(uint32_t dev0, uint32_t leave_l, int T_ms) +{ + uint32_t flt = ORIGIN - dev0; + int cnt = 0, n = T_ms / TICK_MS, i; + for (i = 1; i <= n; i++) { + uint32_t true_v = ORIGIN - dev0 * (n - i) / n; + flt = iir(true_v, flt, ALFA_FAST); + if (flt > ORIGIN - leave_l) { + if (++cnt >= 3) return i * TICK_MS; + } else { + cnt = 0; + } + } + return 0; +} + +static void test_hysteresis_positive(void) +{ + int s; + for (s = 0; s < 4; s++) { + assert(ReleaseTable_B[s] < SensTable[s]); + assert(SensTable_1[s] < SensTable[s]); + } + printf("[OK] 滞回为正: ReleaseTable_B/SensTable_1 各档均 < 进入表\n"); +} + +static void test_deep_table_earlier(void) +{ + int s, T_ms; + for (s = 0; s < 4; s++) { + for (T_ms = 2000; T_ms <= 5000; T_ms += 1000) { + int t_orig = sim_release_ms(400, SensTable_1[s], T_ms); + int t_deep = sim_release_ms(400, ReleaseTable_B[s], T_ms); + assert(t_orig > 0 && t_deep > 0); + /* 加深表释放不晚于原始表 (同快滤波, 线低 → 早碰) */ + assert(t_deep <= t_orig); + printf("[OK] SENS=%d T=%dms: 原始表@%dms, 加深表@%dms (加深≤原始 ✓)\n", + s, T_ms, t_orig, t_deep); + } + } +} + +static void test_release_reasonable(void) +{ + /* 慢速抬板 3s: 各档都必须能释放, 且加深表 SENS=3 释放时刻在 2~3s 内 */ + int t = sim_release_ms(200, ReleaseTable_B[3], 3000); + assert(t > 0 && t <= 3000); + printf("[OK] SENS=3 加深表 3s 抬板释放@%dms (合理范围)\n", t); +} + +int main(void) +{ + printf("=== 方案B (快滤波+调深释放表) 单测 ===\n"); + test_hysteresis_positive(); + test_deep_table_earlier(); + test_release_reasonable(); + printf("\n全部通过 ✓\n"); + return 0; +} diff --git a/utilities/at32f421_freertos_demo/inc/TaskLoop.h b/utilities/at32f421_freertos_demo/inc/TaskLoop.h index 6a6f1ad..7707802 100644 --- a/utilities/at32f421_freertos_demo/inc/TaskLoop.h +++ b/utilities/at32f421_freertos_demo/inc/TaskLoop.h @@ -36,7 +36,14 @@ *===========================================================================*/ #define ALFA_CAP1 79 // IIR α = 79/256 ≈ 0.31 (@10ms → τ≈32ms) #define RELEASE_ALFA 21 // 释放慢滤波 α = 21/256 ≈ 0.082 (@10ms → 精确τ≈117ms, V4.04: 对齐 PD132T α79@43.7ms 精确τ≈118ms; 原18→精确τ137ms偏慢) -#define USE_SLOW_RELEASE 1 // 方案A总开关: 1=释放走慢滤波(对齐PD132T) 0=原快滤波释放 +#define USE_SLOW_RELEASE 0 // 方案A总开关: 1=释放走慢滤波(对齐PD132T) 0=原快滤波释放 +#define USE_PLANB_TABLE 1 // 方案B: 快滤波释放 + 调深释放阈值表 (2026-09-01 实验, V4.05) + // 1=释放判定用 ReleaseTable_B(加深30%, 各档滞回仍为正) + // 0=释放判定用 SensTable_1(原始PD132T对齐表) + // ⚠仿真预测: 加深→释放线低→CAPVD恢复更早碰到→释放更早(与直觉相反) + // 深信号(≥0.2%)下原始表更接近PD132T; 浅信号(0.1%)下加深表更接近 + // 现场实测对比后定稿, 后续二选一保留 +#define RELEASE_TABLE_B { 80, 42, 27, 18} // 方案B 释放表 (V2.11 原始表 {60,32,21,14} 加深~30%) #define MAX_SLOPE_RATE 5 // 斜率限幅: 单次最大变化 5% (物理限制, 拒绝 EMI 尖峰) #define ENTRY_CONFIRM 3 // 进入确认: 连续 N 次低于阈值才判定有车 #define FREEZE_TIMEOUT 1000 // 基线冻结超时: ~10s @ 10ms/tick, 持续偏高且稳定后强制更新基线 @@ -74,6 +81,9 @@ *===========================================================================*/ extern const uint16_t SensTable[4]; extern const uint16_t SensTable_1[4]; +#if USE_PLANB_TABLE +extern const uint16_t ReleaseTable_B[4]; // 方案B: 调深释放表 (V4.05 实验) +#endif /*=========================================================================== * 全局状态变量 — 捕获 & 测量 diff --git a/utilities/at32f421_freertos_demo/inc/cmcng.h b/utilities/at32f421_freertos_demo/inc/cmcng.h index 8854a29..b772482 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.04" +#define FIRMWARE_VER "4.05" #define HARDWARE_VER "3.00" #define FIRMWARE_VER_MAIN 4 -#define FIRMWARE_VER_SUB 4 +#define FIRMWARE_VER_SUB 5 #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 927ac95..c867002 100644 --- a/utilities/at32f421_freertos_demo/src/TaskLoop.c +++ b/utilities/at32f421_freertos_demo/src/TaskLoop.c @@ -15,6 +15,9 @@ *===========================================================================*/ const uint16_t SensTable[4] = {300, 60, 32, 21}; // V2.11: 全档与 PD132T SensTable 完全一致 (0.458%/0.092%/0.049%/0.032% df/f) const uint16_t SensTable_1[4] = { 60, 32, 21, 14}; // V2.11: 离开分档与 PD132T 完全一致 (SENUP 标贴OFF=SET_ASB=1=出厂默认) +#if USE_PLANB_TABLE +const uint16_t ReleaseTable_B[4] = RELEASE_TABLE_B; // 方案B: 调深释放表 (V4.05 实验, 见 TaskLoop.h 注释) +#endif /*=========================================================================== * 全局状态变量 — 捕获 & 测量 @@ -881,12 +884,16 @@ void vd1_task(void) /*================================================================ * 有车状态 — 简单 cnt_release 防抖离开 *================================================================*/ +#if USE_PLANB_TABLE + loop1_dlt_ORG = ((uint32_t)loop1_Origin * ReleaseTable_B[loop1_SensLevel]) >> 16; // 方案B: 调深释放表(V4.05) +#else loop1_dlt_ORG = ((uint32_t)loop1_Origin * SensTable_1[loop1_SensLevel]) >> 16; +#endif #if USE_SLOW_RELEASE if ((loop1_Origin - loop1_dlt_ORG) < loop1_CAPVD_slow) { // 方案A: 用慢滤波值对齐 PD132T 释放手感 #else - if ((loop1_Origin - loop1_dlt_ORG) < loop1_CAPVD) { // 原逻辑: 快滤波直接判释放 + if ((loop1_Origin - loop1_dlt_ORG) < loop1_CAPVD) { // 方案B/原逻辑: 快滤波直接判释放 #endif loop1_cnt_release++; if (loop1_cnt_release >= 3) {