# vd960Loop 开发日志

> MCU: AT32F421 (Cortex-M4, 120MHz) | 线圈通道: 4路 | 调试口: TTL Tx (3.3V 9600 8N1)

---

## 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` | 新增: 冻结参考值 |

---

## 修订记录

| 版本 | 时间 | 说明 |
|------|------|------|
| 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→实际频率转换 |
