feat(vd960Loop): 环境健康度算法 §10 + drift_health.py 参考实现

- variation-analysis.md §10: 无车漂移监测 (零成本, 不改协议)
  - 口径修正: 绝对峰=1.5×窗口漂移(Origin 滞后半窗) → 用峰谷差
  - 600ms 采样系统性低估 ~12% (峰在窗口末采不到)
  - 冻结态失效(>4×dlt_ORG) → 双指标: 漂移速率 + 冻结占比
  - 冻结判定双判据: 跨窗跳变消失 + 峰谷差突变(>4×前4窗中位数)
- tools/drift_health.py: CSV 逐窗统计/冻结检测/JSON/自测
- devlog 2026-08-25 条目追加环境健康度小节
- 自测: 慢漂移 0.02%/s 识别准确, 冻结窗正确排除
This commit is contained in:
wangfq
2026-08-25 10:09:36 +08:00
parent e919ff477a
commit 2a267967b4
3 changed files with 258 additions and 0 deletions
+16
View File
@@ -57,6 +57,22 @@ variation/Origin = 1 √(1 + ΔL/L₀) 精确
代码无改动(`main.c` 饱和边界本就是 8388608 ~ +8388607)。
### 环境健康度算法(§10
用户提出零成本环境健康度方案:无车时 variation 锯齿的峰 = 漂移信号,后台逐窗统计画健康度曲线。模拟验证后修正两处口径并落地:
1. **绝对峰 ≠ 窗口漂移**:Origin 更新到窗口均值(滞后半窗 2.5s),稳态绝对峰 = **1.5×** 窗口漂移 → 改用**峰谷差**maxmin,误差 <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)
+65
View File
@@ -327,3 +327,68 @@ python3 variation_calc.py --parse-var F6FFFF
python3 variation_calc.py --sens-table # 四档对照
python3 variation_calc.py --interactive # 交互
```
---
## 10. 环境健康度算法:无车漂移监测(2026-08-25 补充)
> 配套工具:`tools/drift_health.py`。零成本方案——不改协议、不改固件,直接用现有 `variation` 锯齿。
### 10.1 思路
无车时 Origin 每 5s 阶跃更新(窗口均值),CAPVD 缓慢漂移 → variation 呈锯齿。**锯齿就是漂移信号**:峰谷差 = 窗口内漂移量,后台逐窗口统计即可画环境健康度曲线(湿度突变、变频器干扰加剧提前可见)。
### 10.2 正确口径(踩坑修正)
| 口径 | 关系 | 结论 |
|------|------|------|
| 绝对峰 \|variation\| | = **1.5×** 窗口漂移量 | ❌ 高估 50%——Origin 更新到**窗口均值**(滞后半窗 2.5s),峰含半窗累积 |
| **峰谷差**(窗口内 max−min) | ≈ 窗口漂移量(误差 <1%) | ✅ 正确 |
| 600ms 采样(8 点/窗) | 峰谷差**系统性低估 ~12%** | ⚠ 峰恒在窗口末(500 tick),末采样点 480 tick 永远错过它;实测 11%~14% |
**推荐公式:**
```
漂移速率(%/s) = (窗口内 max min) / Origin / 5s × 100
```
- 方向保留:V1.05 带符号,正向锯齿(CAPVD 下降/频率上升)= 正速率,反向为负
- 采样低估 ~12% 为单边已知偏差:趋势曲线看相对变化可直接接受;要绝对标定乘 1.14
### 10.3 失效场景:冻结态(必须双指标)
`dev ≥ 4×dlt_ORG` 基线冻结 → **锯齿消失**,variation 跨窗口单调累积不归零,"每窗口取峰"变成取历史累积,速率口径失效:
| 灵敏度档 | 冻结门槛(窗口漂移) | 对应速率 |
|---------|-------------------|---------|
| 0 低 | 1.32% / 5s | 0.26%/s |
| 1 中 | 0.66% / 5s | **0.13%/s** |
| 3 最高 | 0.06% / 5s | 0.012%/s |
变频器启动、湿度突变轻松超中档 0.13%/s → 冻结。**冻结本身 + 累积 variation 就是更强的恶化信号**,健康度曲线用双指标:
```
① 漂移速率 = 峰谷差 / Origin / 5s ← 慢漂移场景(温/湿度),慢且稳
② 冻结占比 = 冻结 tick / 总 tick ← 快干扰场景(变频器),触发即预警
```
**冻结判定**(后台可用跨窗回落检测):正常锯齿窗口边界 variation **跳回谷值**,跳变幅度 ≈ 峰谷差;冻结时 Origin 不动,窗口边界无跳变、variation 继续同向爬升。
```
jump = variation[下窗起点] variation[本窗终点]
正常: |jump| ≈ 峰谷差(窗口边界跳回谷值)
冻结: |jump| ≈ 0Origin 不动, 连续爬升)
```
### 10.4 工具用法
```bash
cd tools
python3 drift_health.py --selftest # 模拟数据自测
python3 drift_health.py --csv drift.csv --window 500 # CSV: tick,origin,variation
python3 drift_health.py --csv drift.csv --window 500 --json # JSON 输出
```
### 10.5 与 §8"改上报斜率"的关系
当前零成本方案精度受上报窗限制(600ms 采样 vs 固件 10ms tick,斜率分辨率差 60 倍)。§8 的固件侧斜率字段是**远期升级**:先跑通后台算法验证指标价值,确认值得后,再由固件直接上报 dCAPVD/dt 消除采样混叠与相位滞后。