分析 uart_report_packet_loop_acs 中 variation=|Origin-CAPVD| 的更新机制: - 三操作数节奏: CAPVD~10ms / Origin 5s阶跃 / 上报窗150/600ms采样 - Origin 基线状态机: 稳定期(win100~1s)/正常(win500~5s)/冻结/冻结超时(~10s)/有车冻结 - 波形特征: 无车漂移锯齿波、车辆驻留干净跟随、大干扰防污染冻结 - 风险: 采样混叠、2B截断回绕、锯齿谷误判空闲、稳定期切换拐点
6.5 KiB
variation 上报量分析报告
分析对象:
uart_report_packet_loop_acs()中上报的 变化量 variation 涉及文件:src/main.c(组包)、src/TaskLoop.c(基线/IIR 更新)、inc/TaskLoop.h(参数宏) 结论层次:物理层 → 信号层 → 数据层 → 上报调度层
0. 一句话结论
variation = |loop_Origin − loop_CAPVD|,是 "慢阶跃基线" 与 "快速跟踪当前值" 两个不同时间尺度量的瞬时差。
它在 每次组包时实时计算,本身无独立状态;真正决定其波形形态的是三个错位的时钟:
loop_CAPVD的 ≈10ms 采样loop_Origin的 5s 阶跃 更新- 上报的 150ms / 600ms 采样窗
三者不同步 → 无车时 variation 天然呈 锯齿波。
1. 定义位置
src/main.c — uart_report_packet_loop_acs() 组包段:
// 变化量 (2B, LE)
uint32_t variation = (unit->loop_Origin > unit->loop_CAPVD)
? (unit->loop_Origin - unit->loop_CAPVD)
: (unit->loop_CAPVD - unit->loop_Origin);
g_pkg_uart_report.pkg[i++] = (uint8_t)(variation & 0xFF);
g_pkg_uart_report.pkg[i++] = (uint8_t)((variation >> 8) & 0xFF);
- 取
|Origin − CAPVD|,无符号,无方向信息 - 仅上报低 2 字节(≤ 65535),高位被截断
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 | 瞬时差,2 字节 |
关键点:
variation没有独立状态,它只是组包那一刻两值之差。 它的"更新周期"实际是 上报采样周期(150/600ms);它的"波形形态"由 Origin 的阶跃周期决定。
上报间隔宏(inc/TaskLoop.h,50ms tick):
#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 岿然不动:
*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 直接 = CAPVD,variation 突然归零 |
| 有车 | loop_VD_FLAG == 1 |
— | 不进基线分支 | Origin 全程冻结,variation 忠实跟随 CAPVD |
相关参数宏(inc/TaskLoop.h):
#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;变频器干扰下漂移快,齿更高
场景 2 — 车辆进入 / 驻留(设计正确 ✅)
- 车进入瞬间
ORG_CNT/SUM清零 +VD_FLAG=1,Origin 完全冻结 - variation 快速跟随 CAPVD 拉大 → 真实反映车辆信号强度,干净无锯齿
场景 3 — 大干扰但非车(半截车 / 邻道串扰 / 金属堆放)
dev ≥ dlt_ORG×4触发冻结,variation 维持大值不被基线"吃掉"- 偏差稳住 ±2% 达 10s 后,Origin 一次性重锁,variation 突降 → 防污染 + 慢速重学基线
5. 需警惕的问题(直击要害)
-
采样混叠:用 600ms 上报窗去采一个 5s 阶跃量。后台若按单次 variation 做实时判断,会看到同一个齿被多次采到不同高度,叠加 600ms/5s 相位漂移 → 看似"忽大忽小"。 → 后台不能拿单次 variation 当绝对阈值,应看趋势或直接用 MCU 已判好的
car_state。 -
2 字节截断:
variation仅发 2B(≤65535)。CAPVD≈131072 量级,正常 Δf/f 才百分之几,一般到不了 65535;但 冻结场景下偏差若超 65535 会回绕。 → 建议加饱和:if (variation > 0xFFFF) variation = 0xFFFF; -
锯齿谷值≈0 误导"无车确认":若有逻辑用
variation < 小值判"绝对空闲",会在每个 5s 边界被误触发。 → 判空闲以car_state/loop_VD_FLAG为准,variation 仅作辅助幅度参考。 -
稳定期 window=100 → 正常 500 的切换:上电 1s 尺度基线,128 样本后切 5s 尺度。过渡期 variation 锯齿周期从 1s 突变到 5s,后台做周期特征分析要注意此拐点。
6. 待现场验证
loop_CAP_OK的 ~10ms 为 devlog 设计值。实际周期取决于 TMR3 时钟与线圈频率,建议现场用示波器量相邻两次CAP_OK间隔确认。
7. 后续可选改进方向
- 将 variation 改为上报 斜率 / 趋势 而非瞬时差,削掉锯齿混叠
- 补 variation 饱和保护 + 随包上报当前状态(跟踪 / 冻结 / 有车),让后台区分锯齿谷与真空闲