Files
xdeSpace/docs/variation-analysis.md

349 lines
18 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# variation 上报量分析报告
> 分析对象:`uart_report_packet_loop_acs()` 中上报的 **变化量 variation**
> 涉及文件:`src/main.c`(组包)、`src/TaskLoop.c`(基线/IIR 更新)、`inc/TaskLoop.h`(参数宏)
> 协议版本:与《DLD960Loop_串口通信协议.md》**V1.05** 同步(2026-07-14variation 无符号 2B → **有符号 3B**,见 §5
> 结论层次:物理层 → 信号层 → 数据层 → 上报调度层
---
## 0. 一句话结论
`variation = loop_Origin loop_CAPVD`V1.05 起为 **3 字节有符号补码**:正 = 车辆/金属进入方向,负 = 反向漂移),是 **"慢阶跃基线"** 与 **"快速跟踪当前值"** 两个不同时间尺度量的瞬时差。
它在 **每次组包时实时计算**,本身无独立状态;真正决定其波形形态的是三个错位的时钟:
- `loop_CAPVD`**≈10ms** 采样
- `loop_Origin`**5s 阶跃** 更新
- 上报的 **150ms / 600ms** 采样窗
三者不同步 → 无车时 variation 天然呈 **锯齿波**
---
## 1. 定义位置
`src/main.c``uart_report_packet_loop_acs()` 组包段(V1.05 现行实现):
```c
// 变化量 (3B, LE, 有符号补码) — V1.05
// 定义: variation = Origin - CAPVD
// 正值 = 当前值低于基线(车辆/金属进入, 检测裕量方向)
// 负值 = 当前值高于基线(反向漂移/异常抬升)
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 饱和
g_pkg_uart_report.pkg[i++] = (uint8_t)(variation & 0xFF);
g_pkg_uart_report.pkg[i++] = (uint8_t)((variation >> 8) & 0xFF);
g_pkg_uart_report.pkg[i++] = (uint8_t)((variation >> 16) & 0xFF);
```
- **带符号带方向**:正 = 检测裕量方向(与旧版有车时的数值语义连续),负 = 反向漂移
- 3 字节小端补码,值域 ±2²³−1,发送端 **饱和限幅,不会回绕**
- 旧版(≤V1.04)为 2B 无符号绝对值,缺陷与变更动机见 **§5**
---
## 2. 三个操作数的更新节奏
| 量 | 物理含义 | 更新触发 | 真实周期 | 特性 |
|---|---|---|---|---|
| `loop_CAPVD` | IIR 后当前线圈值 | 每次 `loop_CAP_OK``vd1_task_per_channel()` | **≈10ms**(固定测量窗 `LPCNT×Xn≈131072` timer counts | 快,τ≈32ms,斜率限幅 5% |
| `loop_Origin` | 基线 | `update_moving_average()` 窗口满才写 | **阶跃式**(见 §3) | 慢,平台期恒定不动 |
| `variation` | 上报的变化量 | 每次组包现算 | 被 **上报窗采样**:事件 150ms / 空闲 600ms | 瞬时差,3 字节有符号(V1.05) |
> 关键点:`variation` 没有独立状态,它只是组包那一刻两值之差。
> 它的"更新周期"实际是 **上报采样周期**150/600ms);它的"波形形态"由 Origin 的阶跃周期决定。
上报间隔宏(`inc/TaskLoop.h`50ms tick):
```c
#define REPORT_IDLE_TICKS 12 // 空闲稳定: 12×50ms = 600ms
#define REPORT_EVENT_TICKS 3 // 事件/变化: 3×50ms = 150ms
```
上报调度还叠加了 **上电 3s 抑制**`misc_counter < 60` 跳过,等基线稳定)。
---
## 3. loop_Origin 基线更新的状态机(核心)
`update_moving_average()`**累加到窗口满才写一次**,中途 Origin 岿然不动:
```c
*p_sum += new_value; (*p_cnt)++;
if (*p_cnt >= window) { // 只有这里改写 Origin
*p_origin = *p_sum / window;
*p_cnt = 0; *p_sum = 0;
}
```
| 状态 | 判据 | window | 阶跃周期 @10ms | 对 variation 的影响 |
|---|---|---|---|---|
| **稳定期** | `!loop_stable``stable_cnt < 128` | 100 | **~1s** | 上电快速收敛,`CAPVD = Value` 直通 |
| **正常跟踪** | 无车 & `dev < dlt_ORG×4` | **500** | **~5s** | Origin 每 5s 阶跃一次,锯齿主因 |
| **冻结** | 无车 & `dev ≥ dlt_ORG×4` | — | `ORG_CNT/SUM` 清零,**不更新** | Origin 锁死,variation 保持大值 |
| **冻结超时** | 冻结持续 & 漂移 <±2% 达 1000 次 | — | **~10s 一次性抓取** | Origin 直接 = CAPVDvariation **突然归零** |
| **有车** | `loop_VD_FLAG == 1` | — | 不进基线分支 | Origin 全程冻结,variation 忠实跟随 CAPVD |
相关参数宏(`inc/TaskLoop.h`):
```c
#define STABLE_SAMPLES 128 // 稳定期样本数
#define WINDOW_ORIGIN 500 // 基线跟踪窗口 (500×10ms = 5s)
#define FREEZE_TIMEOUT 1000 // 冻结超时 ~10s @10ms
#define FREEZE_STABILITY_RATE 2 // 稳定性窗口 ±2%
#define MAX_SLOPE_RATE 5 // 斜率限幅 5%
#define ENTRY_CONFIRM 3 // 进入确认次数
```
---
## 4. variation 波形特征
### 场景 1 — 无车缓慢漂移(温漂 / 湿漂),最典型
```
CAPVD ─╱╱╱╱╱ 持续缓慢漂移(每10ms微动)
Origin ───┐ ┌───┐ ┌── 每5s阶跃追一次
└────────┘ └────────┘
variation: | | | | ← 锯齿波!
峰=5s漂移量, 谷≈0(基线刚追上)
```
- 5s 窗口内 Origin 恒定,CAPVD 漂 → variation 线性爬升
- 窗口边界 Origin 阶跃到近 5s 均值 → variation **突然跌回 ~0**
- **锯齿幅度 ≈ 漂移速率 × 5s**;变频器干扰下漂移快,齿更高
- **V1.05 起锯齿带方向**:CAPVD 向下漂(裕量方向)锯齿为正,向上漂为负——漂移方向后台直接可见。旧版绝对值把负向锯齿翻成正向,与正向漂移完全不可区分
### 场景 2 — 车辆进入 / 驻留(设计正确 ✅)
- 车进入瞬间 `ORG_CNT/SUM` 清零 + `VD_FLAG=1`Origin **完全冻结**
- variation 快速跟随 CAPVD 拉大(**恒为正值**)→ 真实反映车辆信号强度,干净无锯齿
### 场景 3 — 大干扰但非车(半截车 / 邻道串扰 / 金属堆放)
- `dev ≥ dlt_ORG×4` 触发冻结,variation 维持大值不被基线"吃掉"
- 偏差稳住 ±2% 达 10s 后,Origin 一次性重锁,variation 突降 → 防污染 + 慢速重学基线
- V1.05 起,若干扰使 CAPVD **高于**基线(如基线被污染后干扰源撤走),variation 呈 **持续负值**——这是旧版完全观测不到的形态,可作为"基线被污染"的诊断特征
---
## 5. V1.05 变更分析:无符号 2B → 有符号 3B2026-07-14
### 5.1 改动对照
| 项目 | 旧(≤V1.04 | 新(V1.05 |
|---|---|---|
| 计算式 | `\|Origin CAPVD\|` 取绝对值 | `Origin CAPVD` 带符号 |
| 编码 | 2 字节无符号,小端 | **3 字节有符号补码**,小端 |
| 值域 | 0~65535**溢出回绕** | ±8388607**发送端饱和限幅** |
| 方向信息 | 无 | 正 = 车/金属进入,负 = 反向漂移 |
| 每通道单元 | 11 字节 | **12 字节** |
| 帧 Len / 总长(4 路无分包) | 0x2F=47 / 52B | **0x33=51 / 56B**(仍 < `BUFF_STACK_SIZE=64`,缓冲安全) |
### 5.2 为什么必须改(旧版两个致命缺陷)
1. **回绕污染**variation 是 **CAPVD 计数域**的量(量级 ~131072 timer counts,不是 Hz)。大车 / 大金属全覆盖时偏差可超 65535,2B 无符号直接回绕成小值——单测实例:真实偏差 100000,旧版上报 **34464**。后台看到"大信号突然变小"的假象,判决裕量分析整段作废。
2. **方向丢失**:绝对值抹掉符号,分不清"车辆/金属进入(CAPVD 掉到基线下)"与"反向漂移/异常抬升(CAPVD 升到基线上)"——两者的判决意义**完全相反**。雨天漂移方向、邻道串扰极性、基线污染诊断都依赖符号。
### 5.3 符号语义(方案 B
```
variation = Origin CAPVD
> 0 : CAPVD 低于基线 → 金属进入 / 车辆压线(检测裕量方向)
与旧版语义连续:旧版有车时的数值 ≈ 新版正值,后台阈值可平移沿用
= 0 : 当前值与基线重合(基线刚追上 / 真空闲)
< 0 : CAPVD 高于基线 → 反向漂移 / 基线污染残留 / 线圈异常抬升
```
新版正值方向与检测判决方向一致,**有车时 variation 恒为正**;负值只出现在无车漂移或异常场景——这本身就是一个免费的诊断维度。
### 5.4 接收端解析:必须做 bit23 符号扩展
```c
int32_t v = b0 | (b1 << 8) | ((int32_t)b2 << 16);
if (v & 0x800000) v |= 0xFF000000; // bit23 = 1 → 负数,符号扩展
```
- 典型陷阱:按无符号 3B 拼接不扩展,**−10(F6 FF FF)会被读成 16777206**,后台曲线直接飞天
- 存储 / 传输链路上该字段类型必须是 **有符号整型**(int32 及以上),数据库建 UNSIGNED 列会写入失败或截断
### 5.5 影响范围(联动清单)
| 端 | 变更 | 风险点 |
|---|---|---|
| Loop 固件 `main.c` | `uint32_t``int32_t`,3B LE + 双向饱和 | 已完成,gcc 隔离单测通过 |
| 协议文档 | V1.05:字段表、Len 47→51、示例报文重算 | 已发布 |
| **vd960DBN** | 解析步长 **11→12**、misc 偏移右移 1B、3B 解码 + bit23 符号扩展、fast_mode 改用 `abs(variation)` | **步长死绑定**(见 5.6 |
| 后台 / 上位机 | 字段改有符号 int;阈值逻辑沿用正值方向;负值单独归类为漂移诊断量 | 无符号存储 / 不做符号扩展 |
### 5.6 兼容性风险(重点盯防)
1. **Loop 与 DBN 固件必须同版本发布**。单元步长 11↔12 死绑定,任一端用旧固件,4 通道数据整体错位。**且帧级 XOR/SUM 校验依然通过**(校验的是整帧,不感知单元边界)——这是**静默数据损坏**,不会报错,只会得到一堆"看起来合理"的错值。
2. 上位机若想兼容新旧固件,可用 **Len 字节区分**4 路无分包时 Len=0x2F(47) 为旧格式(2B 无符号),Len=0x33(51) 为新格式(3B 有符号),按帧动态选解析器。
3. 口径小注:协议文字写值域 ±8388607,代码负向饱和到 8388608(0x800000)。解析端符号扩展后无歧义,且实际物理量远到不了该量级(CAPVD 全量程才 ~1310723B 有 **~64 倍余量**),不构成问题,仅作记录。
### 5.7 对分析工作的直接增益
- **冻结场景幅度可信**:大偏差不再回绕,判决裕量、灵敏度档位标定可以直接拿 variation 定量
- **漂移方向可见**:锯齿极性 = 漂移方向,雨天 / 温漂 / 变频器干扰的方向特征可离线统计
- **基线污染可诊断**:持续负值 = 基线学高了,此前只能靠人工比对频率曲线猜
---
## 6. 需警惕的问题(直击要害)
1. **采样混叠**:用 600ms 上报窗去采一个 5s 阶跃量。后台若按单次 variation 做实时判断,会看到同一个齿被多次采到不同高度,叠加 600ms/5s 相位漂移 → 看似"忽大忽小"。
**后台不能拿单次 variation 当绝对阈值**,应看趋势或直接用 MCU 已判好的 `car_state`
2. ~~**2 字节截断 / 回绕**~~**已在 V1.05 解决**(3B 有符号 + 发送端饱和限幅,见 §5)。**DBN 解析端已核实升级完成**(2026-07-15 代码核对:`loop_uart_proto.c` 步长 12B + bit23 符号扩展、misc 偏移 c[8..11]、fast_mode 双向绝对值;详见 vd960DBN devlog 2026-07-14)。后台仅消费 JSON(带符号十进制),无二进制解析负担。
3. **锯齿谷值≈0 误导"无车确认"**:若有逻辑用 `|variation| < 小值` 判"绝对空闲",会在每个 5s 边界被误触发。
→ 判空闲以 `car_state` / `loop_VD_FLAG` 为准,variation 仅作辅助幅度参考。
4. **稳定期 window=100 → 正常 500 的切换**:上电 1s 尺度基线,128 样本后切 5s 尺度。过渡期 variation 锯齿周期从 1s 突变到 5s,后台做周期特征分析要注意此拐点。
---
## 7. 待现场验证
- `loop_CAP_OK` 的 ~10ms 为 devlog 设计值。**实际周期取决于 TMR3 时钟与线圈频率**,建议现场用示波器量相邻两次 `CAP_OK` 间隔确认。
- 新旧固件混跑的错位形态(Loop 新 + DBN 旧)建议在工装上**故意复现一次**,留存错位数据样本,方便日后现场快速识别。
---
## 8. 后续可选改进方向
- 将 variation 改为上报 **斜率 / 趋势** 而非瞬时差,削掉锯齿混叠
- ~~补 variation 饱和保护~~ → V1.05 已完成
- **随包上报当前基线状态(跟踪 / 冻结 / 有车)**,让后台区分锯齿谷与真空闲、冻结大值与真车
---
## 9. variation ↔ ΔL / ΔL-L 物理对应(2026-08-25 补充)
> 配套工具:`tools/variation_calc.py`(正向/反推/3B 补码解析/灵敏度对照,纯 stdlib)
### 9.1 物理链路:CAPVD 正比于 √L,不是 L
`main.c` 频率转换公式反推:
```c
freq = sclk_freq × input_div × LPCNT / CAPVD CAPVD 1/freq = T(周期)
```
LC 振荡器周期 `T = 2π√(LC)`,因此:
```
CAPVD = A·√(LC) (A = 系统归一化常数,含时钟/分频/MEASUREMENT_BASE=131072
```
**CAPVD 与周期成正比,与 √L 成正比**——这是 variation 换算 ΔL 的关键前提(平方根关系,不是线性)。
### 9.2 换算公式
设基线电感 L₀,有车后电感 L₀+ΔL:
```
Origin = A·√(L₀·C)
CAPVD = Origin·√(1 + ΔL/L₀)
variation = Origin CAPVD = Origin·[1 √(1 + ΔL/L₀)]
```
| 口径 | 公式 | 适用 |
|------|------|------|
| **精确** | `ΔL/L₀ = (1 variation/Origin)² 1 = (variation/Origin)² 2(variation/Origin)` | 大信号(如大车全覆盖) |
| **一阶近似** | `ΔL/L₀ ≈ 2 × variation/Origin` | 检测阈值区间,残差 <0.2% |
| 频域对应 | `Δf/f ≈ variation/Origin`CAPVD ∝ 1/f) | 与验收标准 §3 频偏口径衔接 |
符号语义:车辆进入 → 涡流 → ΔL<0 → CAPVD<Origin → **variation 恒为正**,与 V1.05 协议一致;负值 = 反向漂移 / 基线污染。
**一阶近似的误差上界**:二阶残差 ≈ (variation/Origin)²,最低灵敏度档 0.33% 时仅 0.0011%,相对误差 <0.2%——系数 2 直接可用。
### 9.3 灵敏度档位 → ΔL/L 触发阈值
进入条件 `CAPVD < Origin dlt_ORG`,进入瞬间 `variation ≈ dlt_ORG = Origin×SensTable/65536`,逐档对应:
| SENS | 进入表 | 离开表 | Δf/f 进入 (=vr) | **ΔL/L 进入 ≈ 2×vr** | ΔL/L 离开 |
|------|--------|--------|-----------------|----------------------|-----------|
| 0 低 | 216 | 108 | 0.3296% | **0.659%** | 0.330% |
| 1 中 | 108 | 72 | 0.1648% | **0.330%** | 0.220% |
| 2 高 | 36 | 18 | 0.0549% | **0.110%** | 0.055% |
| 3 最高 | 10 | 9 | 0.0153% | **0.031%** | 0.027% |
> 交叉验证:DLD154Pro 技术文档 sens_in {108,54,28,14} 标注 ΔL/L = 0.330%/0.165%/0.085%/0.043%,恰为 SensTable/65536 的 2 倍——产品线已统一使用 `ΔL/L ≈ 2×SensTable/65536` 口径。
### 9.4 电容档位无关性(33/43/66/76nF
四档电容只改绝对工作频率 f₀ = 1/(2π√(L₀C))
| C 档 | 频率 @ L₀≈59μH |
|------|----------------|
| 33nF | ~114 kHz |
| 43nF | ~100 kHz |
| 66nF | ~81 kHz |
| 76nF | ~75 kHz |
**Origin 与 CAPVD 均 ∝ √C,比值 variation/Origin 中 C 被消掉**
```
variation/Origin = 1 √(1 + ΔL/L₀) ← 与 C 无关
```
**结论:四档电容共用同一套 ΔL/L 换算表,现场换档不换标定。** 这是 LPCNT = MEASUREMENT_BASE/Xn 自适应归一化的直接收益。
### 9.4.1 四档电容硬件结构(2026-08-25 确认)
- **1 颗常接 33nF 基础电容** + **2 颗 IO 控制并联电容:33nF、10nF**
- 四档 = 2 个 IO 二进制组合(粗调 33nF 大步进 + 细调 10nF 小步进):
```
IO2(10nF) IO1(33nF) 总C 频率@L0≈59μH
断 断 33nF ~114 kHz
通 断 43nF ~100 kHz
断 通 66nF ~81 kHz
通 通 76nF ~75 kHz
```
推论:
1. **IO 可控 = 软件切档** → 固件可实现**上电自动调谐**(扫描 4 档测频,锁定最接近目标频率的档位),现场免人工跳线。建议作为后续改进项(见 §8)。
2. **切档瞬间频率跳变**`loop_Origin` / `loop_CAPVD` / IIR 全部失配——**切档只允许在上电稳定期或强制基线重置后进行**,运行中切档必须先重学基线。
3. **档位步进不均匀**+10 / +33 / +10 nF):66↔76 仅差 6kHz(8%),多车道相邻分配时**避开这两档配对**(见选档组合建议)。
4. 待验证:IO 开关器件(模拟开关 / MOS)导通电阻对谐振回路 Q 值的影响,以及 10nF 微调档在运行中切换是否引入频率毛刺。
### 9.5 绝对电感与 ΔL 完整换算
```
① 绝对电感: L₀ = 1/(4π²·f₀²·C) ← f₀ 用上报频率(3B),C 用当前档位电容
② 相对变化: ΔL/L₀ ≈ 2 × variation/Origin
③ 绝对变化: ΔL = L₀ × ΔL/L₀
```
示例(C=43nF, f₀=100kHz → L₀≈58.9μHSENS=1 触发,variation=216, Origin=131072):
```
variation/Origin = 0.1648%
ΔL/L₀ ≈ 0.330%
ΔL ≈ 58.9μH × 0.330% ≈ 0.194 μH
```
### 9.6 使用注意事项(后台/上位机口径)
1. **必须归一化**variation 是 CAPVD 计数域(~131072 量级),直接拿绝对值当 ΔL 会差 4~5 个数量级。所有换算先除 Origin。
2. **只有有车冻结期的 variation 干净**:有车时 Origin 冻结,variation 忠实反映信号强度,此刻换算 ΔL/L 最可信;无车时 Origin 5s 阶跃 → variation 呈锯齿,锯齿峰 = 5s 漂移量,不能当车辆信号。
3. **基线重锁识别**:冻结超时(10s 稳定)后 Origin 强制 = CAPVDvariation 突降归零——后台应识别为"基线重锁"事件,勿当车辆离开。
4. **文档口径 2 倍陷阱**SensTable/65536 直接读是 Δf/f0.33%),标成 ΔL/L 是 0.66%。验收/规格文档必须注明口径(推荐统一用 ΔL/L)。
5. **绝对 ΔL 依赖 C 档信息**:协议帧未带 C 档位,后台需按现场配置查表,或由 f₀ 与档位映射反推(f₀ 落在哪档频率区间即哪档)。
### 9.7 工具用法速查
```bash
cd tools
python3 variation_calc.py --freq 100 --cap 43 --variation 216 --origin 131072 # 正向
python3 variation_calc.py --freq 100 --cap 43 --dl-rel 0.33 # 反推
python3 variation_calc.py --parse-var F6FFFF # 3B LE 补码解析
python3 variation_calc.py --sens-table # 四档对照
python3 variation_calc.py --interactive # 交互
```