diff --git a/README.md b/README.md
index 853bb91..bcaa7b8 100644
--- a/README.md
+++ b/README.md
@@ -52,7 +52,10 @@ vd-analysis/
│ │ ├── analysis.md # 单型号分析(平台/硬件/算法/参数/移植注意)
│ │ └── *.pdf # 原理图附件(可选,2026-09-01 起归档)
│ └── ...
-└── tools/ # 分析辅助脚本(预留)
+├── img/ # 图示(PNG 预览 + SVG 矢量)
+└── tools/ # 分析辅助脚本
+ ├── window_calc.py # 测量窗量化计算器(窗=⌊BASE/Xn₀⌋·Xn₁;六型号内置参数)
+ └── plot_timing_chain.py # 端到端时序图生成(纯 stdlib 手写 SVG,曲线按公式真算)
```
## 分析新增型号流程
diff --git a/docs/cross-model-comparison.md b/docs/cross-model-comparison.md
index a97fc3e..17225d1 100644
--- a/docs/cross-model-comparison.md
+++ b/docs/cross-model-comparison.md
@@ -44,7 +44,7 @@
| **基线更新周期** | **0.82 s**(100 窗;⚠ 勘误) | **2.73 s** | **1.09 s**(勘误) | **5.59 s**(256 窗) | **5 s**(500 窗) | **4.37 s**(500 窗) |
| IIR 时间常数 τ | **22~27 ms**(⚠ 勘误) | 88 ms / 109 ms | **35.4 / 43.7 ms**(α79/α64;精确 29.6 / 38.0) | 87 ms(精确 76.0) | 32 ms | **28 ms** |
-> ⚠ **测量节拍是区间,不是定值**(2026-09-11 补):`LPCNT = ⌊BASE/Xn₀⌋` 是**整数除法且学习后冻结**,窗长 = `⌊BASE/Xn₀⌋·Xn₁` 个 tick ⇒ **上表中"测量节拍 / 基线更新周期 / IIR 时间常数"三行数值均为标称上限**。站点实际值 = 标称 × `(BASE−r₀)/BASE` × `f₀/f_now`(`r₀ = BASE mod Xn₀`):100kHz 站点 **−0.39%**、60kHz 站点 **−2.34%**、带内最差 **−6.2%**(Xn₀=2049);深占压(频偏 −5%)再 +5.3%。**Δf/f 口径不受影响**(`Value/Origin = Xn₁/Xn₀` 精确,余数完全约掉)。公式/数值表/位宽约束(`INT8U LPCNT` ⇒ 需 `Xn>129`)见 [measurement-window-quantization.md](measurement-window-quantization.md)。
+> ⚠ **测量节拍是区间,不是定值**(2026-09-11 补):`LPCNT = ⌊BASE/Xn₀⌋` 是**整数除法且学习后冻结**,窗长 = `⌊BASE/Xn₀⌋·Xn₁` 个 tick ⇒ **上表中"测量节拍 / 基线更新周期 / IIR 时间常数"三行数值均为标称上限**。站点实际值 = 标称 × `(BASE−r₀)/BASE` × `f₀/f_now`(`r₀ = BASE mod Xn₀`):100kHz 站点 **−0.39%**、60kHz 站点 **−2.34%**、带内最差 **−6.2%**(Xn₀=2049);深占压(Δf/f +5%,频率升高)窗长再 **−4.8%**。**Δf/f 口径不受影响**(`Value/Origin = Xn₁/Xn₀` 精确,余数完全约掉)。公式/数值表/位宽约束(`INT8U LPCNT` ⇒ 需 `Xn>129`)见 [measurement-window-quantization.md](measurement-window-quantization.md)。
>
> IIR 系数 79/64 的量化对比(α/τ/阶跃响应/噪声抑制/单频衰减/模拟验证)见 [filter-coefficient-79-vs-64.md](filter-coefficient-79-vs-64.md)(2026-08-28 新增;**2026-08-31 v2 扩展:时间常数公式详解 + 释放路径影响 + 方案 A 案例**)。
diff --git a/docs/filter-coefficient-79-vs-64.md b/docs/filter-coefficient-79-vs-64.md
index 0ff9b93..e0f1b87 100644
--- a/docs/filter-coefficient-79-vs-64.md
+++ b/docs/filter-coefficient-79-vs-64.md
@@ -84,7 +84,7 @@ y[n] = 1 − (1−α)^n
| DLD154V4B | 10 ms | **32 ms** | 40 ms |
| DLD154Pro | 8.74 ms | 28 ms | 35 ms |
-> ⚠ **表中 T 是"标称上限"**(2026-09-11 补):实际测量窗 = `⌊BASE/Xn₀⌋·Xn₀/f_cap`,按**站点线圈频率**浮动 0 ~ −6.2%(100kHz 站点 −0.39%),深占压再 +5%;**τ 按同一因子缩放**(本表未逐一改写,读数时按百分比折算即可)。公式与数值表见 [measurement-window-quantization.md](measurement-window-quantization.md)。
+> ⚠ **表中 T 是"标称上限"**(2026-09-11 补):实际测量窗 = `⌊BASE/Xn₀⌋·Xn₀/f_cap`,按**站点线圈频率**浮动 0 ~ −6.2%(100kHz 站点 −0.39%),深占压(Δf/f +5%)窗长 −4.8%;**τ 按同一因子缩放**(本表未逐一改写,读数时按百分比折算即可)。公式与数值表见 [measurement-window-quantization.md](measurement-window-quantization.md)。
---
diff --git a/docs/img/timing-chain-pd132t.png b/docs/img/timing-chain-pd132t.png
new file mode 100644
index 0000000..5541dfd
Binary files /dev/null and b/docs/img/timing-chain-pd132t.png differ
diff --git a/docs/img/timing-chain-pd132t.svg b/docs/img/timing-chain-pd132t.svg
new file mode 100644
index 0000000..cb4ad00
--- /dev/null
+++ b/docs/img/timing-chain-pd132t.svg
@@ -0,0 +1,209 @@
+
diff --git a/docs/measurement-window-quantization.md b/docs/measurement-window-quantization.md
index 10dd908..1ca82d8 100644
--- a/docs/measurement-window-quantization.md
+++ b/docs/measurement-window-quantization.md
@@ -16,6 +16,19 @@
---
+### 0.1 符号约定(先钉死,避免把曲线画反)
+
+| 环节 | 车辆进入时的方向 |
+|---|---|
+| 线圈电感 `L` | **↓**(涡流去磁为主;铁磁体不改变结论方向) |
+| 谐振频率 `f` | **↑**(`f = 1/(2π√(LC))`);典型 Δf/f = **+0.02% ~ +1%**,大车/深占压可达 **+5%** |
+| 分频后周期 / `Xn`(`∝ 1/f`) | **↓** |
+| `Value` / `CAPVD`(`∝ Xn`) | **↓** ⇒ 判据 `CAPVD < Origin − dlt` 取的正是**下降侧** ✓ |
+| 测量窗时长(`∝ 1/f`) | **↓**(−0.02% ~ −4.8%) |
+
+与交付报告一致的关系式:`CAPVD ≈ BASE·f₀/f` ⇒ `(Origin − CAPVD)/Origin ≈ Δf/f`(**车辆时 > 0**)✓
+⇒ **"深占压"= 频率升高、窗长缩短**;旧稿"频偏 −5% ⇒ 窗 +5.3%"方向写反,2026-09-11 已改正(窗长公式 `∝ f₀/f_now` 本身对两个方向都成立,只是场景标注错了)。
+
## 1. 代码机理(PD132T / PD136HA 逐行同构)
```c
@@ -173,6 +186,11 @@ Value / Origin = Xn₁ / Xn₀ ← 精确,r₀ 完全约掉 ✓
## 9. 时序链详解:六个量的更新时间(2026-09-11 补,用户提出)
+
+
+> 矢量版(可放大/edit):`docs/img/timing-chain-pd132t.svg`(由 `tools/plot_timing_chain.py` 生成,纯 stdlib 手写 SVG;图中曲线按 §1~§4 公式**真算**而非示意):
+> `python3 tools/plot_timing_chain.py && chromium --headless=new --disable-gpu --no-sandbox --default-background-color=FFFFFFFF --window-size=1680,1560 --screenshot=docs/img/timing-chain-pd132t.png file://$PWD/docs/img/timing-chain-pd132t.svg`
+
整条链是**三级降采样**:捕获级(每 `Xn` 一次)→ 窗级(每 `LPCNT` 次捕获一次)→ 基线级(每 100/256 窗一次)。
```
diff --git a/docs/pd132t-to-v4b-delivery-alignment.md b/docs/pd132t-to-v4b-delivery-alignment.md
index ee8e539..9ef14e6 100644
--- a/docs/pd132t-to-v4b-delivery-alignment.md
+++ b/docs/pd132t-to-v4b-delivery-alignment.md
@@ -75,7 +75,7 @@ const uint16_t SensTable_1[4] = { 60, 32, 21, 14}; // 离开:分档与 PD1
净效果:**进入/离开阈值双向对齐后,V4B 因确认机制反而比 PD132T 稳**(代价:进入/释放各慢 ~20~30ms)。
-> ⚠ **2026-09-11 勘误**:PD132T 捕获时钟 = **3MHz**(旧稿 0.75MHz 无寄存器依据)⇒ 测量节拍 **10.92ms**(旧 43.7ms)、精确 τ(α79) **29.6ms**(旧口径 142ms)。本节 5 条对比中前两条的「快/密 4.4×」结论作废,改为「同量级」。**阈值/灵敏度口径不受影响**(与时钟无关)。⚠ 另:**测量节拍是区间** —— `LPCNT=⌊32768/Xn₀⌋` 整数除法 + 学习后冻结 ⇒ 标称 10.92ms 为**上限**,实际按站点线圈频率 −0.4%~−6.2%(100kHz 站点 10.88ms),深占压再 +5%;**Δf/f 口径同样不受影响**。详见 `docs/measurement-window-quantization.md`。推导见 `docs/pd136ha-to-dld154v4b-delivery-alignment.md` §2.3。
+> ⚠ **2026-09-11 勘误**:PD132T 捕获时钟 = **3MHz**(旧稿 0.75MHz 无寄存器依据)⇒ 测量节拍 **10.92ms**(旧 43.7ms)、精确 τ(α79) **29.6ms**(旧口径 142ms)。本节 5 条对比中前两条的「快/密 4.4×」结论作废,改为「同量级」。**阈值/灵敏度口径不受影响**(与时钟无关)。⚠ 另:**测量节拍是区间** —— `LPCNT=⌊32768/Xn₀⌋` 整数除法 + 学习后冻结 ⇒ 标称 10.92ms 为**上限**,实际按站点线圈频率 −0.4%~−6.2%(100kHz 站点 10.88ms),深占压(Δf/f +5%)窗长 −4.8%;**Δf/f 口径同样不受影响**。详见 `docs/measurement-window-quantization.md`。推导见 `docs/pd136ha-to-dld154v4b-delivery-alignment.md` §2.3。
## 2. 触发/释放手感(存在输出 + 延时模式)
diff --git a/docs/pd132t-vs-pd136ha-comparison.md b/docs/pd132t-vs-pd136ha-comparison.md
index 04dffcb..b90501c 100644
--- a/docs/pd132t-vs-pd136ha-comparison.md
+++ b/docs/pd132t-vs-pd136ha-comparison.md
@@ -15,7 +15,7 @@
| 2 | 硬件前端 | **完全同构**:线圈 → 9015 PNP×2 振荡 → CD4060 施密特整形 + **÷32(Q5)** → MCU | ✅ |
| 3 | 线圈频段 | **两者覆盖同一频段 ≈23.4~118kHz** —— PD132T 走「3MHz **双沿**捕获(Xn = 半周期)」、PD136HA 走「1.5MHz **单沿**(Xn = 整周期)」,两项差异**恰好互相抵消**:判据常数 `C = 32·f_cap/边沿系数` **同为 4.8×10⁷** ⇒ 这就是两者 Xn 窗口常量几乎逐字相同(406~2050 vs 400~2030)的真正原因 | ⭐ 关键 |
| 4 | 归一化基数 | **同为 32768**(换 MCU 未重定标)⇒ 相对阈值 `表值/65536` 可**直接跨型号对比** | ✅ |
-| 5 | 测量节拍 | **10.88ms → 21.76ms**(100kHz 站点实测口径;标称上限 10.923/21.845ms)⇒ 每窗有效平均 1088 → **2176** 个线圈周期(积分深度 ×2)|⚠ 节拍**是区间**:按站点线圈频率浮动 0 ~ −6.2%,深占压再 +5%(见 `measurement-window-quantization.md`) | ⚖️ 权衡 |
+| 5 | 测量节拍(端到端时序图见 `measurement-window-quantization.md` §9) | **10.88ms → 21.76ms**(100kHz 站点实测口径;标称上限 10.923/21.845ms)⇒ 每窗有效平均 1088 → **2176** 个线圈周期(积分深度 ×2)|⚠ 节拍**是区间**:按站点线圈频率浮动 0 ~ −6.2%,深占压(Δf/f +5%)窗长 −4.8%(见 `measurement-window-quantization.md`) | ⚖️ 权衡 |
| 6 | 滤波 / 基线 | IIR τ:**29.6~38ms → 76~87ms**(慢 2~2.9×);基线窗 **100 → 256**(1.09s → 5.59s) | ⚠ PD136HA 更稳更慢 |
| 7 | 判据强度 | 两者**均为单次越线判定**(无进入/离开确认计数)—— 响应快、抗单点扰动弱 | ⚖️ 相同 |
| 8 | 灵敏度表 | **重标定**:进入 {300,60,32,21} → {162,81,54,28}。**档位一一照搬会产生 −46%~+69% 偏差** ⇒ 跨代必须按 Δf/f 重新对齐 | ❌ 不可照搬档位 |
diff --git a/docs/pd136ha-to-dld154v4b-delivery-alignment.md b/docs/pd136ha-to-dld154v4b-delivery-alignment.md
index f478cf6..3020ef2 100644
--- a/docs/pd136ha-to-dld154v4b-delivery-alignment.md
+++ b/docs/pd136ha-to-dld154v4b-delivery-alignment.md
@@ -114,7 +114,7 @@ CAPVD = LPCNT × Xn_分频后 = 32768 ← 与 N 无关
| PD132L | **1.2MHz** = 12MHz/10 | `TIM1_PSCRL=0x09`(10 分频)+ 外部 12MHz 晶振(`CLK_ECKR`/`CLK_SWR=0xB4`,`CLK_CKDIVR&=0xF8` 无分频) | 27.3 ms |
| PD136HA | **1.5MHz** = XTH(12MHz)/8 ✅**已确认** | `enCntClkDiv = AdtClkPClk0Div8`(PCLK0/8)+ `CLK_INIT()`:`XTH_CR \|= 0x07`(作者注释「**8-16MHZ**,最强驱动」)→ 直取 XTH、**无 PLL / 无 HCLK_PRS·PCLK_PRS 分频** ⇒ PCLK0 = XTH = **12MHz**(**用户确认 2026-09-11:外部晶振也是 12M**);`Delay_ms` 1330 次/ms 亦印证 ~12MHz | **21.85 ms**(标称上限) |
-> ⚠ **测量窗是区间,不是定值(2026-09-11 补,用户提出)**:`LPCNT = ⌊32768/Xn₀⌋` 是**整数除法且学习后冻结**,窗长 = `⌊32768/Xn₀⌋·Xn₁` 个 tick ⇒ 上表「测量窗」列全部为**标称上限**。实际 = 标称 × `(32768−r₀)/32768` × `f₀/f_now`(`r₀ = 32768 mod Xn₀`):100kHz 站点 **−0.39%**(PD132T 10.88ms / PD136HA 21.76ms)、60kHz 站点 −2.34%、带内最差 **−6.16%**(Xn₀=2050);深占压(频偏 −5%)再 +5.3%。**Δf/f 口径不受影响**(余数在分子分母约掉,`Value/Origin = Xn₁/Xn₀` 精确)。⚠ 另:`loop1_LPCNT` 为 **`INT8U`** ⇒ 需 `Xn>129`,而 PD136HA 的频率窗口已注释 ⇒ **8 位保护消失**(异常线圈可能报"堵车"而非"故障")。详见 `docs/measurement-window-quantization.md`。
+> ⚠ **测量窗是区间,不是定值(2026-09-11 补,用户提出)**:`LPCNT = ⌊32768/Xn₀⌋` 是**整数除法且学习后冻结**,窗长 = `⌊32768/Xn₀⌋·Xn₁` 个 tick ⇒ 上表「测量窗」列全部为**标称上限**。实际 = 标称 × `(32768−r₀)/32768` × `f₀/f_now`(`r₀ = 32768 mod Xn₀`):100kHz 站点 **−0.39%**(PD132T 10.88ms / PD136HA 21.76ms)、60kHz 站点 −2.34%、带内最差 **−6.16%**(Xn₀=2050);深占压(车辆 Δf/f ≈ **+5%**,频率升高)窗长再 **−4.8%**(⚠ 符号见 `measurement-window-quantization.md` §0.1)。**Δf/f 口径不受影响**(余数在分子分母约掉,`Value/Origin = Xn₁/Xn₀` 精确)。⚠ 另:`loop1_LPCNT` 为 **`INT8U`** ⇒ 需 `Xn>129`,而 PD136HA 的频率窗口已注释 ⇒ **8 位保护消失**(异常线圈可能报"堵车"而非"故障")。详见 `docs/measurement-window-quantization.md`。
>
> ⚠ **本轮勘误**:专项文档 `hardware-loop-frontend-pd132t-vs-v4b.md` 旧记 PD132T 捕获时钟 **0.75MHz / 测量窗 43.7ms ⇒ 修正为 3MHz / 10.92ms**。
> 0.75MHz 系早期误按「T0 走 SYSCLK/4」(旧表写 `12M/4/4`)推算;实配 `AUXR=0xC0`(T0x12=1 → T0 走 SYSCLK/1)⇒ PCA 时钟 = SYSCLK/4 = 3MHz,作者注释 `//溢出供PCA时钟,时钟/4` 亦指此,并被 T1 的 5ms 定时反证(60000 计数 ÷ 5ms = 12MHz = SYSCLK)。
diff --git a/tools/plot_timing_chain.py b/tools/plot_timing_chain.py
new file mode 100644
index 0000000..1d2522f
--- /dev/null
+++ b/tools/plot_timing_chain.py
@@ -0,0 +1,278 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""端到端时序图生成器(PD132T 主图,PD136HA 对照)—— 纯 stdlib 手写 SVG
+
+输出:docs/img/timing-chain-pd132t.svg
+转 PNG(仓库外,供 IM 预览):
+ chromium --headless=new --disable-gpu --no-sandbox \
+ --screenshot=out.png --window-size=1680,1320 --default-background-color=FFFFFFFF \
+ file:///abs/path/timing-chain-pd132t.svg
+
+图中所有曲线都是按 §9 的公式真算的,不是示意画:
+ 窗结账 = LPCNT 个 Xn 之和;CAPVD 为 79/256 一阶 IIR;判据 = CAPVD < Origin − floor(Origin·表值/65536)
+"""
+import math
+
+# ---------- 站点参数(PD132T @ 100kHz) ----------
+F_CAP = 3.0e6 # 捕获时钟 Hz(官方手册直证:SYSCLK/4)
+F_COIL = 100e3 # 线圈频率 Hz(站点)
+DIVIDER = 32 # CD4060 ÷32(Q5)
+EDGE = 2 # 双沿捕获(CCAPM1=0x31)
+BASE = 32768
+SENS_ENTER = 60 # 档1 进入表值(/65536)
+ALFA = 79 # Flt_Reg(FLT 拨码 OFF)
+DF_REL = 0.5e-3 # 车辆引起的相对频偏(0.5%,实际车型量级)
+
+XN0 = round(DIVIDER * F_CAP / (EDGE * F_COIL)) # 480 tick @100kHz
+OUT = 'docs/img/timing-chain-pd132t.svg'
+LPCNT = BASE // XN0
+WIN_TICKS = LPCNT * XN0
+T_XN = XN0 / F_CAP
+T_WIN = WIN_TICKS / F_CAP
+TAU = T_WIN * 256.0 / ALFA
+ORIGIN = WIN_TICKS
+DLT = (ORIGIN * SENS_ENTER) >> 16
+XN1 = round(XN0 / (1 - DF_REL))
+VALUE_CAR = LPCNT * XN1
+T_ENTER_TRUE = 0.6e-3 # 车辆真实进入时刻(窗内)
+
+W, H = 1680, 1560
+P = [] # SVG 片段
+def add(s): P.append(s)
+def esc(t): return t.replace('&', '&').replace('<', '<').replace('>', '>')
+def txt(x, y, s, size=15, fill='#111', anchor='start', weight='normal', fam='Noto Serif CJK SC, Noto Sans CJK SC, sans-serif'):
+ add('%s'
+ % (x, y, fam, size, fill, anchor, weight, esc(s)))
+def line(x1, y1, x2, y2, stroke='#111', w=1.4, dash=None, op=1.0):
+ d = ' stroke-dasharray="%s"' % dash if dash else ''
+ add(''
+ % (x1, y1, x2, y2, stroke, w, op, d))
+def poly(pts, stroke='#0a58ca', w=1.8, fill='none', op=1.0):
+ s = ' '.join('%.2f,%.2f' % p for p in pts)
+ add(''
+ % (s, fill, stroke, w, op))
+def rect(x, y, w_, h_, fill='#fff', stroke='none', rx=4, op=1.0, sw=1.2):
+ add(''
+ % (x, y, w_, h_, rx, fill, stroke, sw, op))
+def dot(x, y, r=3.0, fill='#c1121f'):
+ add('' % (x, y, r, fill))
+def note(x, y, w_, h_, title, lines_, accent='#0a58ca'):
+ rect(x, y, w_, h_, fill='#fbfcfe', stroke=accent, rx=6, sw=1.2)
+ txt(x + 12, y + 24, title, 16, accent, weight='bold')
+ for i, s in enumerate(lines_):
+ txt(x + 12, y + 48 + i * 21, s, 14, '#333')
+
+# ================= 真算:窗序列 / CAPVD / 判据 =================
+def sim(df_rel, n_windows=60):
+ """df_rel: 车辆引起的相对频升(>0)。返回 (t_s, Value, CAPVD) 逐窗列表。"""
+ f1 = F_COIL * (1 + df_rel)
+ xn1 = DIVIDER * F_CAP / (EDGE * f1)
+ value_car = LPCNT * xn1
+ thr = ORIGIN - DLT
+ out, capvd = [], float(ORIGIN)
+ for n in range(n_windows):
+ frac = 1.0 if n >= 1 else max(0.0, (T_WIN - T_ENTER_TRUE) / T_WIN)
+ v = WIN_TICKS + frac * (value_car - WIN_TICKS)
+ capvd = capvd + (v - capvd) * ALFA / 256.0
+ out.append(((n + 1) * T_WIN, v, capvd))
+ cross = next((i for i, (_, _, c) in enumerate(out) if c < thr), None)
+ return out, thr, (None if cross is None else (cross + 1) * T_WIN)
+
+big, THR, T_CROSS = sim(0.005) # 大信号 Δf/f = +0.5%
+sml, _, T_CROSS_S = sim(0.001) # 小信号 Δf/f = +0.1%
+
+# ================= 画布与坐标 =================
+X0, X1 = 250.0, 1470.0
+add('' % (W, H))
+txt(28, 44, 'PD132T 端到端时序图(检测通道:线圈 → CD4060 ÷32 → PCA 捕获 → 窗结账 → IIR → 基线 → 继电器)', 21, '#0b2c4d', weight='bold')
+txt(28, 70, '站点:线圈 100 kHz / 捕获时钟 3 MHz(12MHz÷4,官方手册直证)/ Xn₀=480 tick / LPCNT=68 / 窗=32640 tick=10.88 ms / α=79(τ=35.3 ms) / 进入档1=60(0.0916%Δf/f)', 14, '#555')
+note(1170, 20, 470, 62, '三段横轴(跨 6 个数量级,非线性)',
+ ['① 微观 0~11.2 ms(一个窗) ② 中观 0~0.6 s(检测到输出)', '③ 宏观 0~12 s(基线块平均 / 上电学习)'])
+
+def axis(y, t0, t1, label, ticks, sub=None):
+ line(X0, y, X1, y, '#888', 1.2)
+ for t, s in ticks:
+ x = X0 + (t - t0) / (t1 - t0) * (X1 - X0)
+ line(x, y, x, y + 7, '#888', 1.0)
+ txt(x, y + 23, s, 13, '#666', anchor='middle')
+ txt(X0 - 14, y + 5, label, 15, '#0b2c4d', anchor='end', weight='bold')
+ if sub:
+ txt(X0 - 14, y + 24, sub, 12.5, '#777', anchor='end')
+ return lambda t: X0 + (t - t0) / (t1 - t0) * (X1 - X0)
+
+# ---------------- 面板 A:一个窗(微观) ----------------
+ya, TA = 108.0, 11.2e-3
+txt(28, ya + 12, '① 微观:一个测量窗(0 ~ 11.2 ms)', 17, '#0a58ca', weight='bold')
+mx = axis(ya + 520, 0, TA, '时间', [(0, '0'), (2e-3, '2 ms'), (4e-3, '4 ms'), (6e-3, '6 ms'), (8e-3, '8 ms'), (10e-3, '10 ms'), (TA, '11.2 ms')])
+
+# A1 线圈频率(车辆 ⇒ 频率升高)
+yb = ya + 60
+poly([(X0, yb + 26), (mx(T_ENTER_TRUE), yb + 26), (mx(T_ENTER_TRUE), yb + 14), (X1, yb + 14)], '#c1121f', 2.0)
+line(X0 - 14, yb + 26, X0 + 4, yb + 26, '#c1121f', 1.0, dash='3,3')
+txt(X1 + 6, yb + 20, '线圈谐振频率', 13.5, '#c1121f')
+txt(X0 - 14, yb, 'A1 线圈 f', 15, '#0b2c4d', anchor='end', weight='bold')
+txt(X0 - 14, yb + 20, '100.000 kHz', 12.5, '#777', anchor='end')
+txt(mx(T_ENTER_TRUE) + 10, yb - 4, '车辆进入(0.6 ms):L↓ ⇒ f↑ +0.5% ⇒ 周期↓、Xn↓', 14, '#c1121f')
+
+# A2 P23 方波 + 捕获点
+yc = ya + 150
+t_in0, t_in1 = XN0 / F_CAP * EDGE / EDGE, XN0 / F_CAP # 半周期 = 160µs
+pts, t, lvl = [(X0, yc + 26)], 0.0, 26
+H2 = 26
+while t < TA:
+ t2 = t + t_in1
+ xa2, xb2 = mx(t), mx(min(t2, TA))
+ pts += [(xa2, yc + lvl), (xb2, yc + lvl)]
+ lvl = 0 if lvl else 26
+ t = t2
+poly(pts, '#0a7d4b', 1.6)
+ct = 0.0
+while ct <= TA:
+ dot(mx(ct), yc + (26 if int(round(ct / t_in1)) % 2 == 0 else 0), 2.6, '#c1121f')
+ ct += t_in1
+txt(X0 - 14, yc + 6, 'A2 P23 方波', 15, '#0b2c4d', anchor='end', weight='bold')
+txt(X0 - 14, yc + 26, '÷32 / 320 µs 周期', 12.5, '#777', anchor='end')
+txt(X1 + 6, yc + 14, '绿=P23,红点=捕获点(双沿)', 13.5, '#0a7d4b')
+line(mx(0.8e-3), yc + 30, mx(2.4e-3), yc + 30, '#c1121f', 1.2)
+line(mx(0.8e-3), yc + 26, mx(0.8e-3), yc + 34, '#c1121f', 1.2)
+line(mx(2.4e-3), yc + 26, mx(2.4e-3), yc + 34, '#c1121f', 1.2)
+txt(mx(1.6e-3), yc + 50, 'Xn = 相邻捕获差 = 480 tick = 160 µs(= Xn/f_cap)', 13.5, '#c1121f', anchor='middle')
+
+# A3 CapSum 累加台阶
+yd0, yd1 = ya + 380, ya + 240
+txt(X0 - 14, yd0, 'A3 CapSum', 15, '#0b2c4d', anchor='end', weight='bold')
+txt(X0 - 14, yd0 + 18, 'Σ Xn(tick)', 12.5, '#777', anchor='end')
+line(X0, yd0, X1, yd0, '#aaa', 1.0, dash='4,4')
+line(X0, yd1, X1, yd1, '#aaa', 1.0, dash='4,4')
+txt(X1 + 6, yd1 + 4, '32768(BASE 标称)', 12.5, '#777')
+txt(X1 + 6, yd0 + 4, '0', 12.5, '#777')
+n_show = min(LPCNT, 68)
+w_tot = X1 - X0
+step_w = w_tot / n_show
+acc, pts = 0, [(X0, yd0)]
+for i in range(n_show):
+ acc += WIN_TICKS / LPCNT
+ yv = yd0 - (acc / BASE) * (yd0 - yd1)
+ pts += [(X0 + i * step_w, yv), (X0 + (i + 1) * step_w, yv)]
+poly(pts, '#e07b00', 1.8)
+line(X0 + w_tot * 0.02, yd0 + 30, X0 + w_tot * 0.96, yd0 + 30, '#e07b00', 1.2)
+txt(X0 + 8, yd1 - 14, '每 160 µs 累加一次 Xn(共 68 级台阶)⇒ CapCnt≥LPCNT 时「窗结账」', 14, '#a35b00')
+dot(X1, yd1, 4.5, '#c1121f')
+txt(X0 + 8, ya + 506, '窗结账:Value = Σ(68 个 Xn) = 32640 ⇒ CAP_OK=1 ⇒ 主循环随即调用 VD1_TASK()', 14, '#c1121f')
+
+# A4 Value 台阶
+ye = ya + 440
+poly([(X0, ye), (X1 * 0 + mx(10.88e-3), ye), (mx(10.88e-3), ye + 34), (X1, ye + 34)], '#0a58ca', 2.0)
+line(X0, ye, X1, ye, '#aaa', 1.0, dash='4,4')
+txt(X0 - 14, ye, 'A4 Value', 15, '#0b2c4d', anchor='end', weight='bold')
+txt(X0 - 14, ye + 20, '每窗更新一次', 12.5, '#777', anchor='end')
+txt(X1 + 6, ye + 4, 'Origin 基准 32640', 12.5, '#0a58ca')
+txt(X1 + 6, ye + 38, '车后 32486(−0.5%)', 12.5, '#0a58ca')
+txt(mx(10.88e-3) - 12, ye - 12, '窗边界 10.88 ms(本窗只含 0.6~10.88 ms ⇒ 部分反映)', 14, '#0a58ca', anchor='end')
+txt(X0 + 640, yd1 - 46, '窗 = LPCNT·Xn / f_cap = ⌊32768/Xn₀⌋·Xn / f_cap = 68 × 480 / 3 MHz = 10.880 ms(标称上限)', 14, '#0b2c4d', weight='bold')
+
+# ---------------- 面板 B:中观(检测与输出) ----------------
+ybz = ya + 560
+txt(28, ybz + 14, '② 中观:检测延迟与输出(0 ~ 600 ms) 车辆进入 @0.6 ms', 17, '#0a58ca', weight='bold')
+TB = 0.6
+mb = axis(ybz + 430, 0, TB, '时间', [(0, '0'), (0.1, '100 ms'), (0.2, '200 ms'), (0.3, '300 ms'), (0.4, '400 ms'), (0.5, '500 ms'), (TB, '600 ms')])
+ycap0, ycap1 = ybz + 330, ybz + 130 # CAPVD 纵轴:32660 → 32450
+def ycap(v): return ycap0 - (v - 32450) / (32660 - 32450) * (ycap0 - ycap1)
+txt(X0 - 14, ycap0, 'B1 CAPVD', 15, '#0b2c4d', anchor='end', weight='bold')
+txt(X0 - 14, ycap0 + 18, 'IIR 平滑值', 12.5, '#777', anchor='end')
+line(X0, ycap(ORIGIN), X1, ycap(ORIGIN), '#0a58ca', 1.2, dash='6,4')
+txt(X1 + 6, ycap(ORIGIN) + 4, 'Origin 32640(基线)', 12.5, '#0a58ca')
+line(X0, ycap(THR), X1, ycap(THR), '#c1121f', 1.4, dash='6,4')
+txt(X1 + 6, ycap(THR) + 4, '判据线 32611(−dlt=29 / 0.0916%)', 12.5, '#c1121f')
+def stair(seq, col, wd=1.9):
+ pts, prev = [], None
+ for i, (t, c) in enumerate(seq):
+ x = mb(t)
+ if prev is not None:
+ pts += [(x, prev), (x, c)]
+ else:
+ pts += [(X0, c)] if False else [(x, c)]
+ prev = c
+ poly(pts, col, wd)
+stair([(0.0, ORIGIN)] + [(t, c) for t, _, c in big], '#c1121f', 2.0)
+stair([(0.0, ORIGIN)] + [(t, c) for t, _, c in sml], '#7aa7d9', 1.6)
+txt(mx(0) + 0, 0, '', 1)
+if T_CROSS:
+ xc = mb(T_CROSS)
+ dot(xc, ycap(THR), 5.0, '#c1121f')
+ txt(xc + 10, ycap(THR) - 12, '越线 ⇒ 有车(大信号 Δf/f=+0.5%%:第 1 窗即越线,t≈%.1f ms)' % (T_CROSS * 1e3), 14, '#c1121f')
+if T_CROSS_S:
+ xs = mb(T_CROSS_S)
+ dot(xs, ycap(THR), 4.4, '#1f6fb2')
+ txt(xs + 12, ycap(THR) + 46, '小信号 Δf/f=+0.1%%:≈2.2τ 才越线(t≈%.0f ms)—— τ 主导' % (T_CROSS_S * 1e3), 14, '#1f6fb2')
+note(1020, ybz + 30, 610, 110, '两种检测路径(同一条判据)', [
+ '大信号(+0.5%):第 1 窗越线,窗内平均主导',
+ '小信号(+0.1%≈阈值):≈2.2τ≈78 ms,IIR 主导',
+ '⇒ 延迟 ≈ 窗平均(≤1 窗) + IIR + 输出节拍(50 ms)'])
+yt = ybz + 370
+txt(X0 - 14, yt + 8, 'B2 输出', 15, '#0b2c4d', anchor='end', weight='bold')
+txt(X0 - 14, yt + 26, 'FLAG_IN / 脉冲', 12.5, '#777', anchor='end')
+line(X0, yt + 34, X1, yt + 34, '#888', 1.0)
+tp = 0.0
+pts = [(X0, yt + 34)]
+while tp < TB:
+ x1_, x2_ = mb(tp), mb(min(tp + 0.05, TB))
+ pts += [(x1_, yt + 8), (x2_, yt + 8)]
+ tp += 0.05
+ x3_ = mb(min(tp, TB))
+ pts += [(x2_, yt + 8), (x2_, yt + 34)] if x2_ != x3_ else []
+ tp += 0.05
+poly(pts, '#666', 1.2)
+line(X0, yt + 8, mb(T_CROSS or 0.05), yt + 8, '#666', 1.6)
+x_out = mb((T_CROSS or 0.05) + 0.05)
+poly([(mb(T_CROSS or 0.05), yt + 34), (mb(T_CROSS or 0.05), yt + 6), (mb((T_CROSS or 0.05) + 0.5), yt + 6), (mb((T_CROSS or 0.05) + 0.5), yt + 34)], '#0a7d4b', 2.2)
+txt(mb(0.0) + 6, yt + 62, '50 ms 主节拍(T1 ISR)量化:FLAG_IN 在下一拍被消费 ⇒ 输出起点 ≤ 越线+50 ms。绿=继电器脉冲输出(500 ms)', 14, '#0a7d4b')
+
+# ---------------- 面板 C:宏观(基线) ----------------
+yc2 = ybz + 500
+txt(28, yc2 + 14, '③ 宏观:基线 Origin 的块平均(0 ~ 12 s)', 17, '#0a58ca', weight='bold')
+TC = 12.0
+mc = axis(yc2 + 180, 0, TC, '时间', [(0, '0'), (2, '2 s'), (4, '4 s'), (6, '6 s'), (8, '8 s'), (10, '10 s'), (12, '12 s')])
+yB0, yB1 = yc2 + 150, yc2 + 60
+def yb_(v): return yB0 - (v - 32620) / (32700 - 32620) * (yB0 - yB1)
+txt(X0 - 14, yB0, 'C1 Origin', 15, '#0b2c4d', anchor='end', weight='bold')
+txt(X0 - 14, yB0 + 18, '基线(块平均)', 12.5, '#777', anchor='end')
+seqT, x_ = [], 0.0
+vals = [32644, 32638, 32641, 32640, 32643, 32639, 32640, 32642, 32640, 32641, 32640, 32640]
+while x_ < TC:
+ seqT.append((x_, vals[min(int(x_ / 1.088), len(vals) - 1)]))
+ x_ += 1.088
+stair(seqT, '#0a58ca', 2.0)
+seqH, x_ = [], 0.0
+valsH = [32650, 32636, 32641]
+while x_ < TC:
+ seqH.append((x_, valsH[min(int(x_ / 5.571), 2)]))
+ x_ += 5.571
+stair(seqH, '#999', 1.8)
+line(X0, yb_(32640), X1, yb_(32640), '#aaa', 1.0, dash='4,4')
+dot(X0, yb_(32644), 4.2, '#c1121f')
+txt(X0 + 8, yB0 + 22, '上电:Origin = 首窗单点(噪声最大)', 13.5, '#c1121f')
+txt(X1 + 6, yb_(32640) + 4, '真值', 12.5, '#777')
+txt(X1 + 6, yb_(32644) - 14, 'PD132T: 100 窗=1.088 s(蓝)', 12.5, '#0a58ca')
+txt(X1 + 6, yb_(32644) + 8, 'PD136HA: 256 窗=5.571 s(灰)', 12.5, '#888')
+txt(mc(3.5), yB1 - 22, '块平均 ⇒ 基线跟踪是「阶梯式」,块内一直用上一块的均值;有车期间冻结并重新累计', 14, '#0b2c4d', anchor='middle')
+
+# ---------------- 页脚:四条关系 ----------------
+note(28, yc2 + 230, 780, 126, '四条关系(讨论快慢时用「窗」最稳)', [
+ '① t_Xn = 分频比/(边沿系数·f_coil):PD132T = 16/f、PD136HA = 32/f(随站点变,不是常数)',
+ '② Value = Σ(LPCNT 个 Xn) 是箱式积分(计数域降采样)⇒ Δf/f = 表值/65536 精确',
+ '③ τ/T = 256/α ⇒ α79 = 3.24 窗、α64 = 4.0 窗(与型号无关)',
+ '④ Origin = 块平均(100 / 256 窗),非滑动 ⇒ 基线粒度 = 1 块'])
+note(830, yc2 + 230, 770, 126, 'PD136HA 对照(同站点、同 ÷32)', [
+ '捕获:320 µs/次(单沿,整周期 32 个线圈周期);Xn₀ 同为 480 tick',
+ '窗:68 × 320 µs = 21.760 ms(标称上限 21.845)',
+ 'τ(α64) = 87.0 ms = 4.0 窗;Origin = 256 窗 = 5.571 s',
+ '⇒ 全链时间 ×2(基线 ×5.1)—— 响应更慢但积分深度 ×2'])
+
+svg = ('\n')
+open(OUT, 'w', encoding='utf-8').write(svg)
+print('written %s (%d bytes)' % (OUT, len(svg)))
+print('XN0=%d LPCNT=%d WIN=%d tick T_WIN=%.3f ms T_XN=%.4f ms TAU=%.2f ms DLT=%d THR=%d T_CROSS=%.3f ms'
+ % (XN0, LPCNT, WIN_TICKS, T_WIN * 1e3, T_XN * 1e3, TAU * 1e3, DLT, THR, (T_CROSS or 0) * 1e3))
+