绿灯上电自检快闪: 原固定 128 样本(≈1.3s)即判稳, 与基准是否真稳无关;
stable_cnt 仅 init_vd_single 清零, 有限存在超时/安全复位(LC_Reset=1)
重学阶段残留计数 → 二次稳定期 1 样本瞬间判稳 (同 V4B 旧缺陷)。
修复 (四路 unit 独立):
- TaskLoop.h: +STABLE_ORIGIN_PPT 1 / STABLE_SETTLE_WINDOWS 2 /
STABLE_MAX_SAMPLES 500(≈5s兜底); Loop154_Unit +settle_cnt
- TaskLoop.c vd1_task_per_channel 稳定期: 每窗(100样本≈1s)完成比较
Origin 均值漂移 ≤0.1% → settle++, 否则清零; 判稳=最少128样本+
连续2窗稳定 或 500 样本兜底; 判稳退出清零
- init_vd_single / 有限存在超时 / 安全复位超时重学路径统一清零自检计数
- poll_green_led 条件不变: 绿灯闪至本路基准稳定才停 (四路独立)
验证: tests/test_stable_settle.c 5 项 PASS (常量200/首窗尖峰400/
持续漂移500兜底/重学复位200防呆/Origin=0守卫);
gcc -fsyntax-only TaskLoop.c 0 error
文档: vd960Loop/docs/devlog V1.03 置顶; DLD960_技术规格书/产品手册
V1.04 (上电稳定期/绿灯自检语义 + 修订记录)
cmcng.h: FIRMWARE_VER "1.02"→"1.03" (MAIN=1/SUB=3, SSUB=1保持)
待现场验证: 绿灯自检时长(干净≈2s/扰动3~4s/兜底5s)与四路独立闪烁
551 lines
27 KiB
Markdown
551 lines
27 KiB
Markdown
# vd960Loop 开发日志
|
||
|
||
> MCU: AT32F421 (Cortex-M4, 120MHz) | 线圈通道: 4路 | 调试口: TTL Tx (3.3V 9600 8N1)
|
||
|
||
---
|
||
|
||
## 2026-09-02 — V1.03:上电自检基准判稳同步 V4B V4.23(版本号 V1.03)
|
||
|
||
> **固件版本:V1.03**(cmcng.h:FIRMWARE_VER="1.03" + MAIN=1/SUB=3,SSUB=1 保持)。devlog 修订。
|
||
|
||
### 背景(源自 DLD154V4B 现场反馈,V4B V4.23 已实测通过)
|
||
|
||
绿灯上电自检快闪:原逻辑固定 128 样本(≈1.3 s)即判稳,**与基准值是否真稳定无关**;
|
||
且 `stable_cnt` 只在 `init_vd_single` 清零,**有限存在超时 / 安全复位(LC_Reset=1)重学阶段不清零**,
|
||
残留计数会让二次稳定期几乎瞬间判稳(绿灯自检形同虚设)。V4B V4.23 修复后本仓四路同步。
|
||
|
||
### 改动
|
||
|
||
- `TaskLoop.h`:新增 `STABLE_ORIGIN_PPT 1`(窗口 Origin 均值漂移 ≤ Origin×0.1%)/
|
||
`STABLE_SETTLE_WINDOWS 2`(连续 2 窗判稳)/ `STABLE_MAX_SAMPLES 500`(≈5 s 硬兜底);
|
||
`Loop154_Unit` 新增 `settle_cnt`
|
||
- `TaskLoop.c`:
|
||
- 稳定期:每窗(100 样本≈1 s)完成时比较 Origin 均值漂移,≤0.1% → `settle_cnt++` 否则清零;
|
||
判稳 = 最少 128 样本 + 连续 2 窗稳定,或 500 样本硬兜底;判稳退出时 `stable_cnt/settle_cnt` 清零
|
||
- `init_vd_single` / 有限存在超时 / 安全复位超时(重学路径)统一清零自检计数 → 二次稳定期从零开始
|
||
- 绿灯 `poll_green_led` 条件不变:该路绿灯闪至**本路基准稳定**才停(四路独立)
|
||
|
||
### 验证
|
||
|
||
- `tests/test_stable_settle.c`:常量 → 200 样本判稳;首窗尖峰 → 400(扰动后需 2 个干净窗口);
|
||
持续漂移 → 500 硬兜底;重学复位后 → 200(防呆:非瞬间判稳)ALL PASS
|
||
|
||
### 待现场验证
|
||
|
||
上电绿灯自检时长(干净启动 ≈2 s / 有扰动 3~4 s / 干扰大 5 s 兜底)与四路独立闪烁观感。
|
||
|
||
---
|
||
|
||
## 2026-09-02 — V1.02:基线跟踪双向对称保护同步 V4B V4.20(版本号 V1.02)
|
||
|
||
> **固件版本:V1.02**(cmcng.h:FIRMWARE_VER="1.02" + MAIN=1/SUB=2,SSUB=1 保持)。devlog 修订。
|
||
|
||
### 背景(现场问题,源自 DLD154V4B 同步)
|
||
|
||
特殊形状铁块(磁导率主导)靠近线圈 → variation 为**负**(CAPVD 高于 Origin):
|
||
- 原基线跟踪**单边保护**(只挡 `dev > +4×dlt`),负 variation 时基线照常更新 → **Origin 被污染抬高**
|
||
- 铁块离开时 CAPVD 回落 → 跨过抬高的进入线 → **假进入** → 进入后 Origin 冻结 → 释放线抬高 → **锁死不释放**
|
||
- DLD154V4B V4.20 已修复并现场验证(三次铁块测试 0 锁死),本仓同步
|
||
|
||
### 改动(TaskLoop.c,四路 unit 结构同步)
|
||
|
||
```
|
||
原逻辑: dev < +4×dlt → 更新基线 ← 单边, 负variation漏网
|
||
修复后: |dev| < 4×dlt → 更新基线 ← 对称窗口 [-4×dlt, +4×dlt]
|
||
dev < 0 (正variation,疑似车) → 冻结 + FREEZE_TIMEOUT 超时兜底更新(保留)
|
||
dev > 0 (负variation,铁块) → 只冻结, 永不超时更新Origin ← 核心
|
||
```
|
||
|
||
- 对称窗口内正常跟踪时补 `loop_freeze_ref = 0`(残留清零,与 V4B 一致)
|
||
- 权衡:长时间负温漂基线不跟随(安全方向,正车检测仍正常)
|
||
- 逻辑与 DLD154V4B V4.20 `test_neg_variation.c` 6 项回归单测覆盖一致
|
||
|
||
### 版本
|
||
|
||
- cmcng.h:FIRMWARE_VER "1.01"→"1.02",FIRMWARE_VER_SUB 1→2
|
||
- 同步仓:DLD154Pro(5f7082c)、DLD110SV4(fd6ee79)同期完成
|
||
|
||
---
|
||
|
||
## 2026-08-28 — 看门狗升级:双保险喂狗模式 + 超时对齐 V4B(1.64s)
|
||
|
||
### 背景
|
||
|
||
与 DLD154V4B(同款 AT32F421)看门狗实现对照后发现三个问题:
|
||
|
||
| 问题 | 说明 |
|
||
|------|------|
|
||
| **直喂模式缺 ISR 活性检测** | 原实现主循环每 10ms 无条件 `wdt_feed()`——TMR15 ISR 死掉但主循环活着时,看门狗照样被喂,系统"假活"(时序状态机全停但永不复位) |
|
||
| **超时 3s 偏长** | `div=64, rld=1875` → 3s;V4B 已用 1.64s,复位自愈更快 |
|
||
| **注释矛盾** | `main.c` 注释写"重载值=4687 超时≈3秒"(4687 是 7.5s 的算法),实际 1875→3s |
|
||
|
||
### 改动(对齐 DLD154V4B V2.10)
|
||
|
||
```c
|
||
// TaskLoop.h
|
||
#define WDT_COUNTER_LIMIT 100 // 喂狗周期 500ms (TMR15 5ms × 100)
|
||
#define WDT_DIV 2 // IWDT 分频枚举值: 2 = WDT_CLK_DIV_16 (实际分频 16)
|
||
#define WDT_RLD 4095 // 12bit 重装载 → 超时 ≈ 1.64s
|
||
```
|
||
|
||
| 文件 | 变更 |
|
||
|------|------|
|
||
| `src/main.c` | `wdt_init()`:`WDT_CLK_DIV_64/1875` → `WDT_CLK_DIV_16/4095`(超时 3s→1.64s);`wdt_feed` 定义删除(移至 TaskLoop.c);注释修正 |
|
||
| `src/TaskLoop.c` | +`g_wdg_counter` + `poll_wdg()`(500ms 才 reload);TMR15 ISR 5ms 递增;调用点 `wdt_feed()`→`poll_wdg()` |
|
||
| `inc/TaskLoop.h` | +WDT 宏 + `poll_wdg` 声明 + `g_wdg_counter` extern(删 `wdt_feed`) |
|
||
|
||
### 验证
|
||
|
||
- 隔离测试(host gcc mock 3bit 寄存器语义)3 项断言全过:分频 16/重载 4095/超时 1638ms > 500ms 喂狗周期、10s 喂狗 20 次(500ms 精确)、ISR 死不喂狗
|
||
- 双保险语义:ISR 死 → 计数不涨 → 永不喂狗;主循环死 → poll_wdg 不执行 → 超时复位
|
||
- 待现场验证:LSI 实际频率偏差对复位时间的影响
|
||
|
||
### ⚠ 踩坑提醒(V4B 同源事故)
|
||
|
||
`wdt_divider_set()` 参数是**枚举值**不是分频数值(`WDT_CLK_DIV_16=0x02`,寄存器只取低 3 位)——V4B 曾把 `WDT_DIV=16` 当数值传入 → 实际分频 4 → 超时 410ms < 500ms 喂狗周期 → **不断复位重启**。本次 vd960Loop 直接沿用枚举写法,避免同坑。
|
||
|
||
---
|
||
|
||
## 2026-08-27 — LOOP_MEASURE_BASE 归一化基数上报(协议 V1.09)
|
||
|
||
### 背景
|
||
|
||
跨产品 MEASUREMENT_BASE 对齐(2026-08-26 DLD110S ×4 事故:第三方小程序把 ΔL/L 报成 8.85%,真实 2.21%)。variation 是周期域计数值(`variation = Origin − CAPVD`,CAPVD ∝ √L),归一化必须除**设备自身**的 MEASUREMENT_BASE。960Loop 是产品线中唯一未上报基数的型号——0x64 读参响应裸发参数,第三方平台无从换算(写死 131072 恰好蒙对,写 524288 就 ÷4 失真)。
|
||
|
||
### 改动
|
||
|
||
| 文件 | 内容 |
|
||
|------|------|
|
||
| `docs/DLD960Loop_串口通信协议.md`(vd_960 仓库) | **V1.09**:0x64 响应尾部追加 3B LE `LOOP_MEASURE_BASE`(响应 34B→37B)+ 换算公式 + 修订记录 |
|
||
| `inc/cmcng.h` | `#define LOOP_MEASURE_BASE 131072L`(注释标明与 TaskLoop.h MEASUREMENT_BASE 同步) |
|
||
| `src/main.c` | `CMD_DBN_GET_MCJQ_PARAM` (0x64) handler for 循环后追加 3B LE(小端,响应 2+8×4+3=37B) |
|
||
|
||
### 换算公式(写入协议文档)
|
||
|
||
```
|
||
Δf/f ≈ variation / LOOP_MEASURE_BASE (131072, AT32@120MHz)
|
||
ΔL/L ≈ -2 × variation / LOOP_MEASURE_BASE (系数 2 来自 CAPVD ∝ √L 展开)
|
||
```
|
||
|
||
### 设计决策
|
||
|
||
- 常量放 **0x64 查询响应**(低频),不进 0xC0 高频帧(每线圈 12B 已贴边,加字段触发分包)
|
||
- 向后兼容:老客户端只读前 34B 不受影响;新客户端读 37B 拿基数
|
||
- ⚠ 联动待办:DBN 侧对外(BLE/TCP/MQTT)暴露基数未落地——平台走网络协议评估时仍需加字段
|
||
|
||
### 验证
|
||
|
||
- ✅ `check_c_balance.py` 语法平衡 OK;编码保持 UTF-8+CRLF
|
||
- [ ] 板级验证:0x64 响应长度 37B、尾部 3B = `00 00 02`(131072 LE)
|
||
|
||
---
|
||
|
||
## 2026-08-25 — 灵敏度 4 级制修复(协议 V1.08)
|
||
|
||
### 背景
|
||
|
||
现场用金属块测感应高度,设置不同灵敏度档位**感应高度无区别**。排查发现三个根因:
|
||
|
||
| # | 根因 | 位置 |
|
||
|---|------|------|
|
||
| 1 | **运行中配置命令不同步检测单元**:`unpack_pkg_set_mcjq_param()` 只更新 `g_loop_cng_info.loop_cng[].sensitvity` + 写 flash,**没有同步 `g_loop_states.loop_unit[].loop_SensLevel`** → 改灵敏度不重启不生效(对比上电路径 `para_store_init()` 有同步) | main.c:576 |
|
||
| 2 | **9级制映射 `& 0x03` 折叠**:协议 0~9 级(默认 7),`sensitvity & 0x03` 只取低 2 位 → 7→3、**3→3(从默认 7 改到 3 无效)**、8→0(反向折叠) | storage.c:184 |
|
||
| 3 | 测试陷阱:金属块过大/过近信号饱和,4 档阈值都在饱和区 → 感应高度差异不可见(建议小金属块/测临界距离) | 测试方法 |
|
||
|
||
### 修复(方案 B:4 级制)
|
||
|
||
- 提取映射函数 `sens_level_from_config()`(storage.c/h):**4级制 0~3 一一对应**,9 级制后续实现时只改这一处
|
||
- `unpack_pkg_set_mcjq_param()` 补 `loop_SensLevel` 同步 → 运行中配置立即生效
|
||
- `para_store_init()` 上电路径改用同一函数(消除双处映射漂移)
|
||
- 协议 V1.08:Sensitivity 语义 0~9 级 → **4 级制 0~3**(默认 2)
|
||
- 新增 `tests/test_sens_mapping.c` gcc 隔离单测(mock flash.h/FreeRTOS.h/task.h + FLP GPIO 宏):验证 0~3 无折叠、兼容旧默认 7→3、SensTable 单调
|
||
|
||
### 改动
|
||
|
||
| 文件 | 内容 |
|
||
|------|------|
|
||
| `src/storage.c` | 新增 `sens_level_from_config()`;`para_store_init` 改用 |
|
||
| `src/main.c` | `unpack_pkg_set_mcjq_param` 补 loop_SensLevel 同步(运行中生效) |
|
||
| `inc/storage.h` | sensitvity 注释 4 级制;函数声明 |
|
||
| `tests/test_sens_mapping.c` | 新增映射单测(gcc PASS) |
|
||
| `tests/mock/` | flash.h/FreeRTOS.h/task.h 隔离测试 mock |
|
||
| `docs/DLD960Loop_串口通信协议.md` | V1.08:灵敏度 4 级制 |
|
||
|
||
### 验证
|
||
|
||
gcc 单测 PASS:0→0, 1→1, 2→2, 3→3 无折叠;`7&0x0F → 3` 兼容旧默认。实机待金属块复测(建议小金属块测临界感应高度)。
|
||
|
||
### 9 级制灵敏度表设计(2026-08-25)
|
||
|
||
用户给行业典型范围:**0.01% ~ 5.00% ΔL/L**(跨度 546 倍)。9 级等比公比 2.198,方向 0=最低、8=最高(与 4 级一致)。
|
||
|
||
| SENS | sens_in | ΔL/L 进入 | sens_out | ΔL/L 离开 | out/in |
|
||
|------|---------|-----------|----------|-----------|--------|
|
||
| 0 | 1638 | 5.00% | 819 | 2.50% | 50% |
|
||
| 1 | 745 | 2.27% | 373 | 1.14% | 50% |
|
||
| 2 | 339 | 1.03% | 170 | 0.52% | 50% |
|
||
| 3 | 154 | 0.47% | 100 | 0.31% | 65% |
|
||
| 4 | 70 | 0.21% | 46 | 0.14% | 65% |
|
||
| 5 | 32 | 0.098% | 21 | 0.064% | 65% |
|
||
| 6 | 15 | 0.046% | 14 | 0.043% | 90% |
|
||
| 7 | 7 | 0.021% | 6 | 0.018% | 90% |
|
||
| 8 | 3 | 0.01% | 3 | 0.01% | 100% |
|
||
|
||
设计要点:
|
||
- 滞回渐变 50%→65%→90%/100%:高档 out 低于噪声底会不释放(对齐 DLD154Pro 最高档 86% 经验)
|
||
- 4 级→9 级迁移(就近):0→3、1→4、2→5、3→7(端点不再保留,需现场复测)
|
||
- 工程警示:SENS=8 dlt≈6 counts 贴噪声底(仅低噪声环境);SENS=0 dlt≈3275(只认重型车)
|
||
- 溢出检查:Origin×1638 = 214M < 2³² ✓
|
||
|
||
落地:
|
||
| 文件 | 内容 |
|
||
|------|------|
|
||
| `docs/variation-analysis.md` | §9.3.1 9 级制表(设计稿) |
|
||
| `tools/variation_calc.py` | `--sens-table 9` 支持 9 级显示(4 级默认兼容) |
|
||
|
||
验证:工具 9 级端点 0.0092%/4.9988% ≈ 0.01%/5.00% ✓。代码落地(set_factory_param/sens_level_from_config)待 9 级立项。
|
||
|
||
### 补充根因(同日):INIT_VDs 硬编码覆盖配置 + flash 坏数据
|
||
|
||
现场串口日志(`Read_Cng_Store`)显示:配置 4 通道 SENS=3/2/1/0,但检测时 `Car_In` 全部打印 `sens_in:36`(SENS=2 表值)——4 通道检测全用 SENS=2。定位两个根因:
|
||
|
||
**① `init_vd_single()` 硬编码 `loop_SensLevel = 2`(TaskLoop.c:111)**
|
||
|
||
时序:`main → para_store_init()`(同步 loop_SensLevel=配置)→ 任务启动 → `INIT_VDs()` → `init_vd_single()` **把 loop_SensLevel 重置为 2**,覆盖配置值 → 全通道 SENS=2。
|
||
|
||
修复:`init_vd_single` 改为从配置读——`sens_level_from_config(g_loop_cng_info.loop_cng[unit->loop_num].sensitvity)`(unit->loop_num 由 INIT_VDs 先设置)。
|
||
|
||
**② flash 灵敏度表 sens[0]={512,400} 是 0x8A 配置值(更正:非坏数据)**
|
||
|
||
解析 `Read_Cng_Store` flash 数据(0x40 起小端 2B):`{512,400},{108,72},{36,18},{10,9}`。**512/400 是 `CMD_DBN_LOOP_SENS_LIST (0x8A)` 配置的自定义 SENS=0 档阈值**(main.c:946:写 → `memcpy(g_loop_sens_list.sens)` → `storage_dev()` 持久化 → `para_store_init()` 重读),链路完整。值大 = 阈值高 = 更不灵敏(0.78% vs 出厂 0.33% Δf/f),属于用户自定义,**勿恢复出厂(会清掉配置)**。修复 ① 后 loop_3(SENS=0)将使用 512/400 配置值,符合预期。
|
||
|
||
---
|
||
|
||
## 2026-08-25 — variation ↔ ΔL/ΔL-L 物理对应分析与工具
|
||
|
||
### 背景
|
||
|
||
后台需要把上报的 `variation`(CAPVD 计数域)换算成物理电感变化量,用于标定灵敏度、分析车辆信号强度。
|
||
|
||
### 核心推导
|
||
|
||
CAPVD ∝ 周期 T = 2π√(LC),即 **CAPVD ∝ √L 而非 L**:
|
||
|
||
```
|
||
variation/Origin = 1 − √(1 + ΔL/L₀) 精确
|
||
ΔL/L₀ ≈ −2 × variation/Origin 一阶(残差 <0.2%)
|
||
Δf/f ≈ variation/Origin 频域对应
|
||
```
|
||
|
||
- 系数 2 来源于 √(1+x) ≈ 1+x/2 展开
|
||
- 符号:车辆进入 ΔL<0 → variation 恒为正,与 V1.05 协议语义一致
|
||
- **电容档无关性**:Origin 与 CAPVD 均 ∝ √C,variation/Origin 中 C 消掉 → 33/43/66/76nF 四档共用同一换算表,现场换档不换标定
|
||
|
||
### 灵敏度档位 → ΔL/L 触发阈值(SensTable {216,108,36,10})
|
||
|
||
| SENS | Δf/f 进入 (=SensTable/65536) | ΔL/L 进入 ≈ −2× |
|
||
|------|------------------------------|-----------------|
|
||
| 0 低 | 0.330% | −0.659% |
|
||
| 1 中 | 0.165% | −0.330% |
|
||
| 2 高 | 0.055% | −0.110% |
|
||
| 3 最高 | 0.015% | −0.031% |
|
||
|
||
交叉验证:DLD154Pro 技术文档 sens_in {108,54,28,14} 标注 ΔL/L = 0.330%/0.165%/0.085%/0.043%,恰为 SensTable/65536 的 2 倍——产品线口径一致。
|
||
|
||
### 改动
|
||
|
||
| 文件 | 内容 |
|
||
|------|------|
|
||
| `docs/variation-analysis.md` | 新增 §9(物理链路/公式/档位表/电容无关性/示例/注意事项) |
|
||
| `tools/variation_calc.py` | 新增换算工具:正向(freq+cap+variation+origin→L₀,ΔL,ΔL/L)、反推、3B LE 补码解析(V1.05)、灵敏度对照、交互模式 |
|
||
|
||
### 验证
|
||
|
||
工具四模式实测通过,正反算自洽(ΔL/L=0.33% ↔ variation=216 @ Origin=131072)。
|
||
|
||
### 协议文字勘误(协议 V1.07)
|
||
|
||
用户指出 §5.6.3 记录的口径差异应直接改协议:原文 `±8388607` 不对称,负向边界少了 1。统一为 **−8388608 ~ +8388607**(3B 补码标准值域 −2²³ ~ +2²³−1,对齐代码负向饱和边界 0x800000),后台按文档实现时不会对 0x800000 边界犯嘀咕。
|
||
|
||
| 文件 | 变更 |
|
||
|------|------|
|
||
| `DLD960Loop_串口通信协议.md` | variation 字段值域文字修正 + 修订记录 V1.07 |
|
||
| `variation-analysis.md` | 头部版本引用 → V1.07;§1 值域;§5.1 表格;§5.6.3 口径小注改写 |
|
||
|
||
代码无改动(`main.c` 饱和边界本就是 −8388608 ~ +8388607)。
|
||
|
||
### 环境健康度算法(§10)
|
||
|
||
用户提出零成本环境健康度方案:无车时 variation 锯齿的峰 = 漂移信号,后台逐窗统计画健康度曲线。模拟验证后修正两处口径并落地:
|
||
|
||
1. **绝对峰 ≠ 窗口漂移**:Origin 更新到窗口均值(滞后半窗 2.5s),稳态绝对峰 = **1.5×** 窗口漂移 → 改用**峰谷差**(max−min,误差 <1%)
|
||
2. **600ms 采样系统性低估 ~12%**:峰恒在窗口末(500 tick),末采样点 480 tick 永远错过 → 单边偏差,趋势可用,绝对标定 ×1.14
|
||
3. **冻结态失效**:漂移 > 4×dlt_ORG(中档 0.13%/s)→ 锯齿消失,速率口径失效 → 双指标:`漂移速率 = 峰谷差/Origin/5s` + `冻结占比`
|
||
4. 冻结判定双判据:跨窗跳变消失(|jump|≈0)+ 峰谷差突变(>4×前 4 窗中位数),最后一窗也可判
|
||
|
||
| 文件 | 内容 |
|
||
|------|------|
|
||
| `docs/variation-analysis.md` | 新增 §10(口径修正表/双指标/冻结判定/工具用法) |
|
||
| `tools/drift_health.py` | 新增参考实现:CSV 输入 + 逐窗统计 + 冻结检测 + JSON 输出 + 自测 |
|
||
|
||
自测:前 6 窗慢漂移 0.02%/s 全正常,后 2 窗快漂移正确标冻结,平均速率/冻结占比准确。
|
||
|
||
---
|
||
|
||
## 2026-07-14 — variation 上报量 2B→3B 有符号 (协议 V1.05)
|
||
|
||
### 背景
|
||
|
||
`uart_report_packet_loop_acs` 上报的变化量 `variation` 用于**后台离线跟踪分析车检器算法**(判决裕量、基线跟踪行为)。原实现为 **2 字节无符号 + 取绝对值**,存在两个致命缺陷:
|
||
|
||
1. **回绕污染**:`variation` 是 CAPVD 域的量(量级 ~131072,非 Hz)。大车/大金属全覆盖时偏差可超 65535 → 2B 回绕成小值,后台看到"大信号突然变小"的假象,分析数据作废。
|
||
2. **方向丢失**:`|Origin − CAPVD|` 抹掉符号,分不清"车/金属进入(CAPVD 掉到基线下)"与"反向漂移/异常抬升(CAPVD 升到基线上)",两者判决意义相反。
|
||
|
||
### 改动 (组包段)
|
||
|
||
```c
|
||
// 旧: uint32_t variation = |Origin - CAPVD| (2B LE)
|
||
// 新: 3B LE 有符号补码, 方案B定义
|
||
int32_t variation = (int32_t)unit->loop_Origin - (int32_t)unit->loop_CAPVD;
|
||
if (variation > 8388607) variation = 8388607; // +2^23-1 饱和防回绕
|
||
if (variation < -8388608) variation = -8388608; // -2^23 饱和
|
||
// 低字节在前, 发 3 字节
|
||
```
|
||
|
||
- **方案B**:`variation = Origin − CAPVD`。**正值** = 当前值低于基线(车/裕量方向,与旧版语义连续);**负值** = 反向漂移。
|
||
- **饱和限幅** ±2²³,彻底杜绝回绕。
|
||
- 每通道单元 **11B → 12B**,整帧 52B → **56B**(仍 < `BUFF_STACK_SIZE=64`,缓冲安全)。
|
||
|
||
### 影响范围 & 联动
|
||
|
||
| 端 | 变更 |
|
||
|------|------|
|
||
| `main.c` 组包 | `uint32_t`→`int32_t`,3B LE + 饱和 |
|
||
| 协议文档 | `DLD960Loop_串口通信协议.md` V1.05:字段表、Len 47→51、示例报文重算 |
|
||
| **vd960DBN** | 解析步长 11→12、misc 偏移右移 1B、3B 解码 + **bit23 符号扩展**、fast_mode 改 `abs(variation)` |
|
||
|
||
⚠️ **Loop 固件与 DBN 固件必须同版本发布**——步长死绑定,任一端用旧固件则 4 通道数据整体错位。
|
||
|
||
### 验证
|
||
|
||
本地 gcc 隔离单测(编解码往返 / 符号扩展 / 双向饱和 / 方向语义 / fast_mode)全通过。关键:大车 diff=100000 旧版回绕成 34464,新版正确保留 100000。
|
||
|
||
---
|
||
|
||
## 2026-06-26 — 多项可配置化改造
|
||
|
||
### 1. 上报频率从 raw CAPVD 改为实际线圈频率
|
||
|
||
`uart_report_packet_loop_acs` 和 `CMD_DBN_GET_MCJQ_PARAM` 中,频率字段原来直接上报 `loop_CAPVD`(IIR 累加值),现改为经过公式转换的实际频率:
|
||
|
||
```c
|
||
freq = (sclk_freq × input_div × LPCNT) / CAPVD
|
||
```
|
||
|
||
使用 `uint64_t` 先乘后除避免整数截断,`LPCNT>0 && CAPVD>0` 防除零。
|
||
|
||
### 2. 有限存在时长可配置 (hold_time)
|
||
|
||
- `Loop154_Unit` 新增 `uint16_t hold_time` 字段
|
||
- `storage.c` 从 `exist_mode` 计算: `hold_time = exist_mode × 20 × 5`(tick 数,每 tick 50ms)
|
||
- `vd1_task_per_channel` 判定有车时: 若 `hold_time > 0` 则 `loop_VD_HOLD = 1`,启用有限存在计时
|
||
- `TMR15_GLOBAL_IRQHandler`: `Hold_CNT > unit->hold_time` 替代固定 `HOLD_TIME`
|
||
- 超时后执行通道完整重启(`LC_Reset=1, loop_INI_LOOP=1`),相当于线圈重启重建基线,避免继电器释放后立即重新吸合
|
||
- `exist_mode=0` 时不启用有限存在,兼容无限制存在场景
|
||
|
||
### 3. 离开延时可配置 (relay_delay)
|
||
|
||
- `Loop154_Unit` 新增 `uint16_t relay_delay` 字段
|
||
- `storage.c` 从 `delay_time` 计算: `relay_delay = delay_time × 2`(tick 数)
|
||
- `TMR15_GLOBAL_IRQHandler`: `OUTCNT > unit->relay_delay` 替代固定 `OUT_DELAY`
|
||
|
||
### 4. vTaskDelay 修正: 10ms → 50ms
|
||
|
||
`loop_task_function` 的主循环 `vTaskDelay` 从 `10ms` 改为 `50ms`,对齐 DLD154V4B 原始设计(TMR15 5ms×10)。
|
||
|
||
**影响:**
|
||
- 基线更新周期: 100×10ms=1s → 100×50ms=5s(对齐原始设计,Origin 更稳定)
|
||
- CPU 占用: 主循环轮询频率降低 5×,节省 CPU
|
||
|
||
**原因:** TMR3 ISR ~1ms 产出一个 CAP_OK 样本,50ms 内有 ~50 个样本。`vd1_task_per_channel` 每个 tick 只取最新一个做 IIR,10ms 轮询时 CAP_OK 总是 ready,改为 50ms 不影响有效测量速率——采集由 TMR3 ISR 硬件驱动,基线更新速率受 `vd1_task` tick 限制。
|
||
|
||
---
|
||
|
||
## 2026-06-29 — DLD154V4B V2.0~V2.5 M4 优化移植
|
||
|
||
> 参考: DLD154V4B 单路 M4 优化版算法,移植到 vd960Loop 四路并联
|
||
|
||
### 1. 时序加速: vTaskDelay 50ms → 10ms
|
||
|
||
主循环 tick 从 50ms 提升到 **10ms**(加速 5×)。TMR15 ISR 保持 5ms,TM1cnt 10 分频得到 50ms 中断,`Hold_CNT/OUTCNT/INCNT` 仍以 50ms 为单位。
|
||
|
||
**影响:**
|
||
- 检测响应更快:进入确认 3×10ms=30ms 即可判定
|
||
- 冻结超时 1000×10ms=10s
|
||
- WINDOW_ORIGIN=500 → 基线跟踪窗口 500×10ms=5s(等效原 100×50ms)
|
||
|
||
### 2. 斜率限幅 (Slope Limiter)
|
||
|
||
```c
|
||
MAX_SLOPE_RATE = 5% // 单次 IIR 输入变化不超过 CAPVD 的 5%
|
||
```
|
||
|
||
IIR 之前先对 `loop_Value` 做斜率限幅:与当前 `loop_CAPVD` 比较,变化幅度限制在 ±5% 以内(下限 100),防止突发电磁干扰污染 IIR 状态。
|
||
|
||
### 3. 进入确认 (Entry Confirm)
|
||
|
||
```c
|
||
ENTRY_CONFIRM = 3 // 连续 3 次低于阈值才判定有车
|
||
```
|
||
|
||
替代原来的单次触发:`loop_CAPVD < (Origin - dlt_ORG)` 计数 `loop_entry_cnt++`,达到 3 次才置 `loop_VD_FLAG=1`。中途高于阈值则清零,消除偶发毛刺导致的误触发。
|
||
|
||
### 4. 基线冻结超时 (Freeze Timeout)
|
||
|
||
```c
|
||
FREEZE_TIMEOUT = 1000 // 10s @10ms/tick
|
||
FREEZE_STABILITY_RATE = 2 // 稳定性窗口 ±2%
|
||
```
|
||
|
||
有车期间基线被冻结(`ORG_CNT/ORG_SUM` 清零不更新),但新增超时机制:
|
||
- 冻结时记录参考值 `loop_freeze_ref`
|
||
- 若 CAPVD 波动超过 ±2%,重新计时(车还在动)
|
||
- 若 CAPVD 在 ±2% 内稳定超过 10s,强制 `Origin = CAPVD`(视为长时间停车,基线应更新)
|
||
- 解决长时间停车导致基线永久偏离的问题
|
||
|
||
### 5. IIR 简化: 双路 → 单路
|
||
|
||
初始移植了双路 IIR(慢速 α=18/256 + 快速 α=0.5),经测试发现快速 IIR 引入额外噪声,最终**去掉快速 IIR**,仅保留慢速:
|
||
|
||
```c
|
||
ALFA_CAP1 = 79 // α = 79/256 ≈ 0.31, @10ms → τ ≈ 32ms
|
||
```
|
||
|
||
斜率限幅直接对慢速 IIR 输入做限制,简化逻辑且效果一致。
|
||
|
||
### 6. 稳定期快速收敛
|
||
|
||
稳定期 `!loop_stable` 绕过 IIR + 斜率限幅:
|
||
- 直接用 `loop_CAPVD = loop_Value`(raw value)
|
||
- `update_moving_average` 窗口改为 **100**(小窗口快速收敛)
|
||
- 128 样本约 1.28s 完成初始化
|
||
|
||
稳定后切换回正常 IIR + WINDOW_ORIGIN=500 慢跟踪。
|
||
|
||
### 7. 参数修正
|
||
|
||
| 参数 | 旧值 | 新值 | 说明 |
|
||
|------|------|------|------|
|
||
| `WINDOW_ORIGIN` | 100 | 500 | 基线窗口 5s @10ms |
|
||
| `update_moving_average` window | `uint8_t` | `uint16_t` | 修复 500→256 溢出 |
|
||
| `loop_entry_cnt` | — | `uint8_t` | 新增: 进入确认计数器 |
|
||
| `loop_freeze_cnt` | — | `uint16_t` | 新增: 冻结持续计数 |
|
||
| `loop_freeze_ref` | — | `uint32_t` | 新增: 冻结参考值 |
|
||
|
||
---
|
||
|
||
## 2026-07-03 — 时间量上报单位改为 10ms
|
||
|
||
### 背景
|
||
|
||
`MISC_TYPE_TIME` 上报的通过时间 / 车间距原来以 5ms 为单位(直接 `report_counter - 时间戳`),与外部协议期望的 10ms 单位不一致。
|
||
|
||
### 方案
|
||
|
||
内部时间戳 `report_counter` / `passtime_start` / `last_exit_tick` 保持 5ms 精度不动,仅在上报 `misc_value` 时 `/2` 转为 10ms:
|
||
|
||
```c
|
||
// 进场 — 车间距 (10ms)
|
||
misc_value = (report_counter - last_exit_tick) / 2;
|
||
|
||
// 离场 — 通过时间 (10ms)
|
||
misc_value = (report_counter - passtime_start) / 2;
|
||
```
|
||
|
||
### 影响范围
|
||
|
||
| 位置 | 变更 |
|
||
|------|------|
|
||
| `TaskLoop.c` 进场路径 | `misc_value` /2 |
|
||
| `TaskLoop.c` 离场 flatness | `misc_value` /2 |
|
||
| `TaskLoop.c` 离场 cnt_release | `misc_value` /2 |
|
||
| `TaskLoop.h` 注释 | 标注 `/2→10ms` |
|
||
|
||
---
|
||
|
||
## 2026-07-03 — 时间量上报单位改为 50ms
|
||
|
||
### 背景
|
||
|
||
上一步 `misc_value` 以 10ms 为单位(内部 5ms tick `/2`),但协议期望 50ms。统一为 50ms 后与 `Hold_CNT/OUTCNT/INCNT` 一致。
|
||
|
||
### 方案
|
||
|
||
1. **`report_counter` 移入 50ms tick 块**:原来在 5ms ISR 外层 `++`,现移到 `if (TM1cnt >= 10)` 内部,每次加 1 = 50ms
|
||
2. **去掉 `/2`**:`misc_value = report_counter - timestamp`(直接减,无除法)
|
||
3. **上报间隔宏同步**:`REPORT_IDLE_TICKS 120→12`,`REPORT_EVENT_TICKS 30→3`
|
||
|
||
### 影响范围
|
||
|
||
| 文件 | 变更 |
|
||
|------|------|
|
||
| `TaskLoop.c` ISR | `report_counter++` 从 5ms 外层移入 50ms 块 |
|
||
| `TaskLoop.c` 进场/离场 | 去掉 `/2`,注释 10ms→50ms |
|
||
| `TaskLoop.h` | `REPORT_*_TICKS` /10,注释 5ms→50ms |
|
||
| `main.c` | 间隔注释更新 |
|
||
|
||
---
|
||
|
||
## 2026-07-03 — ARMCC 编译修复 + 时间戳/上报完善 (V2.8~V3.1)
|
||
|
||
### 1. ARMCC 编译错误修复 (V2.8)
|
||
|
||
- **#991**: `g_loop_states` 初始化去多余嵌套大括号 `{{0}, {{{0}}}}` → `{0}`
|
||
- **#177-D**: 删除未引用变量 `_counter1_init`
|
||
- **#188-D**: 7处 `at32_led_*()` 调用加 `(led_type)` 强转
|
||
|
||
### 2. 车间距时间补齐 (V2.9)
|
||
|
||
`Loop154_Unit` 新增 `last_exit_tick` 字段:
|
||
- **进场**: `misc_value = misc_counter - last_exit_tick`(车间距,首车=0)
|
||
- **离场**: 记录 `last_exit_tick = misc_counter`,`misc_value = misc_counter - passtime_start`(通过时间)
|
||
- 四通道独立计算,50ms tick 单位
|
||
|
||
### 3. report_counter 清零导致下溢修复 (V3.0)
|
||
|
||
**根因**: `report_counter` 被 UART 上报清零后,`last_exit_tick`/`passtime_start` 存旧值,再次进场时差值下溢 → `0xFFFFFFF7`
|
||
|
||
**修复**: 新增 `misc_counter` 独立自由运行计数器(50ms,永不归零),所有时间戳操作改用 `misc_counter`:
|
||
```
|
||
Loop154_States:
|
||
report_counter → 上报间隔调度 (会清零)
|
||
misc_counter → 时间戳 (永不清零)
|
||
```
|
||
`report_counter` 只负责上报调度,`misc_counter` 负责时间量计算,互不干扰。
|
||
|
||
### 4. 上电 3 秒抑制上报 (V3.1)
|
||
|
||
`uart_report_packet_loop_acs` 开头新增检查:`misc_counter < 60`(3s @50ms)时跳过上报并清零 `report_counter`,等线圈基线稳定后再开始主动上报。
|
||
|
||
---
|
||
|
||
## 修订记录
|
||
|
||
| 版本 | 时间 | 说明 |
|
||
|------|------|------|
|
||
| V3.1 | 2026-07-03 | 上电3秒抑制主动上报 |
|
||
| V3.0 | 2026-07-03 | misc_counter 自由运行替代 report_counter 做时间戳 |
|
||
| V2.9 | 2026-07-03 | 补齐车间距时间 (gap time) |
|
||
| V2.8 | 2026-07-03 | ARMCC 编译修复 (多余大括号/未引用变量/枚举混用) |
|
||
| V2.7 | 2026-07-03 | report_counter 改 50ms tick,时间量单位 10ms→50ms |
|
||
| V2.6 | 2026-07-03 | misc_value 时间量单位 5ms→10ms |
|
||
| V2.5 | 2026-06-29 | 稳定期窗口 100 快速收敛 |
|
||
| V2.4 | 2026-06-29 | 去掉快速 IIR,ALFA_CAP1=79 @10ms |
|
||
| V2.3 | 2026-06-29 | 基线冻结超时 + 稳定性检查 |
|
||
| V2.2 | 2026-06-29 | 进入确认 ENTRY_CONFIRM=3 |
|
||
| V2.1 | 2026-06-29 | 斜率限幅 MAX_SLOPE_RATE=5% |
|
||
| V2.0 | 2026-06-29 | vTaskDelay 50→10ms, 双路 IIR 移植 |
|
||
| V1.3 | 2026-06-26 | vTaskDelay 10→50ms 对齐原始设计 |
|
||
| V1.2 | 2026-06-26 | hold_time/relay_delay 可配置,有限存在完整重启 |
|
||
| V1.1 | 2026-06-26 | 频率上报 CAPVD→实际频率转换 |
|