docs(measurement): 测量节拍是区间 —— 周期累积法的窗口量化(用户提出)+ 全仓回灌

- 新文件 docs/measurement-window-quantization.md:窗长 = ⌊BASE/Xn₀⌋·Xn₁ tick(LPCNT 整数除法 + 学习后冻结)
  · 标称 BASE/f_cap(10.92/21.85ms)是【上限】,实际 = 标称 ×(BASE−r₀)/BASE × f₀/f_now
  · 站点偏差:100kHz −0.39%(PD132T 10.88ms / PD136HA 21.76ms)、60kHz −2.34%、带内最差 −6.20%(Xn₀=2049)
  · 深占压(频偏 −5%)窗再 +5.3%;"检测阈值"量级(≤0.46%)可忽略
  ·  Δf/f 口径不受影响:Value/Origin = Xn₁/Xn₀ 精确(余数完全约掉)—— 灵敏度/交付结论全部保持
  · ⚠ 新发现:loop1_LPCNT 为 INT8U(≤255),同族靠 406<Xn<2050 保证 ≤80;
    PD136HA 该窗口已注释 ⇒ Xn<129 时 8 位截断 ⇒ 异常线圈可能报"堵车"而非"故障"(建议恢复或加钳位)
- 新增 tools/window_calc.py(内置六型号参数,实跑验证文档全部数字)
- 回灌:cross-model 总表(新增脚注 + 测频路线说明 + 待补证1条)、PD132T↔PD136HA 对比报告(§0/§3.1/§3.2/§4.3)、
  两份交付对齐报告("测量窗列 = 标称上限" + 区间脚注)、filter-coefficient 专题(M1H 8.19ms 勘误 + τ 复算 + 脚注)、
  README(新增"专题文档"段 + 目录树)
- 表格校验 0 异常
This commit is contained in:
wangfq
2026-09-11 09:25:49 +08:00
parent 0c05726699
commit fc243c010c
8 changed files with 345 additions and 15 deletions
+10
View File
@@ -22,6 +22,15 @@
| PD132T → DLD154V4B | [docs/pd132t-to-v4b-delivery-alignment.md](docs/pd132t-to-v4b-delivery-alignment.md) | 2026-08-28 | | PD132T → DLD154V4B | [docs/pd132t-to-v4b-delivery-alignment.md](docs/pd132t-to-v4b-delivery-alignment.md) | 2026-08-28 |
| **PD136HA → DLD154V4B** | [docs/pd136ha-to-dld154v4b-delivery-alignment.md](docs/pd136ha-to-dld154v4b-delivery-alignment.md) | 2026-09-11 | | **PD136HA → DLD154V4B** | [docs/pd136ha-to-dld154v4b-delivery-alignment.md](docs/pd136ha-to-dld154v4b-delivery-alignment.md) | 2026-09-11 |
## 专题文档
| 主题 | 路径 | 日期 |
|------|------|------|
| 硬件前级对比(PD132T vs V4B | [docs/hardware-loop-frontend-pd132t-vs-v4b.md](docs/hardware-loop-frontend-pd132t-vs-v4b.md) | 2026-09-01 |
| 滤波系数 79/64 量化对比 | [docs/filter-coefficient-79-vs-64.md](docs/filter-coefficient-79-vs-64.md) | 2026-08-28 |
| **测量节拍量化口径**(窗 = ⌊BASE/Xn⌋·Xn**节拍是区间** | [docs/measurement-window-quantization.md](docs/measurement-window-quantization.md) | 2026-09-11 |
| 参考代码分析方法论 | [docs/methodology.md](docs/methodology.md) | — |
> 对齐报告的通用骨架见 `docs/pd136ha-to-dld154v4b-delivery-alignment.md`:口径前提 → 灵敏度(进入/离开)→ 判据与滤波 → 输出与时序 → 超时与异常 → 拨码迁移 → 风险门 → 先进点 → 待实测清单。 > 对齐报告的通用骨架见 `docs/pd136ha-to-dld154v4b-delivery-alignment.md`:口径前提 → 灵敏度(进入/离开)→ 判据与滤波 → 输出与时序 → 超时与异常 → 拨码迁移 → 风险门 → 先进点 → 待实测清单。
## 目录结构 ## 目录结构
@@ -34,6 +43,7 @@ vd-analysis/
│ ├── cross-model-comparison.md # 跨型号参数对比总表 │ ├── cross-model-comparison.md # 跨型号参数对比总表
│ ├── pd132t-vs-pd136ha-comparison.md # 同血统两代对比(8051 → M0+2026-09-11 │ ├── pd132t-vs-pd136ha-comparison.md # 同血统两代对比(8051 → M0+2026-09-11
│ ├── filter-coefficient-79-vs-64.md # 滤波系数 79/64 专题 │ ├── filter-coefficient-79-vs-64.md # 滤波系数 79/64 专题
│ ├── measurement-window-quantization.md # 测量窗量化口径(节拍是区间,2026-09-11)
│ ├── hardware-loop-frontend-pd132t-vs-v4b.md # 硬件前级对比(PD132T vs V4B │ ├── hardware-loop-frontend-pd132t-vs-v4b.md # 硬件前级对比(PD132T vs V4B
│ ├── pd132t-to-v4b-delivery-alignment.md # 交付对齐:PD132T → DLD154V4B │ ├── pd132t-to-v4b-delivery-alignment.md # 交付对齐:PD132T → DLD154V4B
│ └── pd136ha-to-dld154v4b-delivery-alignment.md # 交付对齐:PD136HA → DLD154V4B │ └── pd136ha-to-dld154v4b-delivery-alignment.md # 交付对齐:PD136HA → DLD154V4B
+6 -1
View File
@@ -44,6 +44,8 @@
| **基线更新周期** | **0.82 s**100 窗;⚠ 勘误) | **2.73 s** | **1.09 s**(勘误) | **5.59 s**256 窗) | **5 s**500 窗) | **4.37 s**500 窗) | | **基线更新周期** | **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** | | 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 时间常数"三行数值均为标称上限**。站点实际值 = 标称 × `(BASEr₀)/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)。
>
> IIR 系数 79/64 的量化对比(α/τ/阶跃响应/噪声抑制/单频衰减/模拟验证)见 [filter-coefficient-79-vs-64.md](filter-coefficient-79-vs-64.md)2026-08-28 新增;**2026-08-31 v2 扩展:时间常数公式详解 + 释放路径影响 + 方案 A 案例**)。 > IIR 系数 79/64 的量化对比(α/τ/阶跃响应/噪声抑制/单频衰减/模拟验证)见 [filter-coefficient-79-vs-64.md](filter-coefficient-79-vs-64.md)2026-08-28 新增;**2026-08-31 v2 扩展:时间常数公式详解 + 释放路径影响 + 方案 A 案例**)。
> ⚠ **时序数值来源(2026-09-11 复核)**DLD154Pro 为 60MHz 实测配置(8.74ms);DLD154V4B 为实测/代码确认(10ms tick,τ=32ms);PD132 系(L/T/136HA**全部基于 12MHz 晶振** —— PD136HA:用户确认 + `CLK_INIT()` 直取 XTH + Keil `<Cpu> CLOCK(12000000)`**PD132TMA801 官方手册直证**`AUXR` b7/b6 = T0X12/T1X12 ⇒ 定时器按 1 个时钟周期计数;`CMOD` `CPS1:CPS0=10` ⇒ PCA 时钟 = 定时器 0 溢出);PD132L:代码注释。公式:测量节拍 = BASE / 捕获时钟。 > ⚠ **时序数值来源(2026-09-11 复核)**DLD154Pro 为 60MHz 实测配置(8.74ms);DLD154V4B 为实测/代码确认(10ms tick,τ=32ms);PD132 系(L/T/136HA**全部基于 12MHz 晶振** —— PD136HA:用户确认 + `CLK_INIT()` 直取 XTH + Keil `<Cpu> CLOCK(12000000)`**PD132TMA801 官方手册直证**`AUXR` b7/b6 = T0X12/T1X12 ⇒ 定时器按 1 个时钟周期计数;`CMOD` `CPS1:CPS0=10` ⇒ PCA 时钟 = 定时器 0 溢出);PD132L:代码注释。公式:测量节拍 = BASE / 捕获时钟。
@@ -61,7 +63,9 @@
纳入对比表的型号(M1H / PD132L / PD132T / PD136HA / DLD154V4B / DLD154Pro**全部采用周期累积法**: 纳入对比表的型号(M1H / PD132L / PD132T / PD136HA / DLD154V4B / DLD154Pro**全部采用周期累积法**:
``` ```
累加固定数量周期(周期域,LPCNT=BASE/Xn)→ 受周期抖动影响,LPCNT 自适应归一化 累加固定数量周期(周期域,LPCNT=BASE/Xn₀⌋,**学习后冻结**
⇒ 窗长 = LPCNT·Xn₁ 个 tick(≤ BASE tick**按站点线圈频率浮动 0 ~ −6.2%**,深占压再 +5%
⇒ 但比值口径精确:Value/Origin = Xn₁/Xn₀(floor 余数约掉)
``` ```
> TLD-110(2006,门控计数法)是唯一例外,已移出对比表,见 `models/TLD-110/analysis.md`。 > TLD-110(2006,门控计数法)是唯一例外,已移出对比表,见 `models/TLD-110/analysis.md`。
@@ -101,3 +105,4 @@ DLD 产品线(154V4B/154Pro/960Loop/110S)继承 M1H 血统,且 154Pro 是
- [ ] **PD136HA 的 TIM1 实际 tick**`ARR=0xF159` 与注释「5ms」不自洽,反推 82.4ms)—— 决定其 500ms / 300s / 240s 秒数的授权 - [ ] **PD136HA 的 TIM1 实际 tick**`ARR=0xF159` 与注释「5ms」不自洽,反推 82.4ms)—— 决定其 500ms / 300s / 240s 秒数的授权
- [ ] **PD132T「双沿 ⇒ 半周期」现场确认**(示波器量线圈频率或 P23)—— 确认线圈频段落 23.4~118kHz - [ ] **PD132T「双沿 ⇒ 半周期」现场确认**(示波器量线圈频率或 P23)—— 确认线圈频段落 23.4~118kHz
- [ ] **PD132L 捕获沿**已由 `models/PD132L/analysis.md`(TIM1_CC3 下降沿)说明,如需可再源码复核 - [ ] **PD132L 捕获沿**已由 `models/PD132L/analysis.md`(TIM1_CC3 下降沿)说明,如需可再源码复核
- [ ]**PD136HA 恢复/替代频率窗口检查**:其 `// if(Xn>400 && Xn<2030)` 被注释 ⇒ 8 位 `LPCNT` 失去保护(`Xn<129` 时截断 ⇒ 异常线圈可能报"堵车"而非"故障"),且丢失"线圈异常 → 故障"路径。见 `measurement-window-quantization.md` §5
+5 -3
View File
@@ -77,13 +77,15 @@ y[n] = 1 (1−α)^n
| 型号 | 测量节拍 T | τ(α=79) | τ(α=64) | | 型号 | 测量节拍 T | τ(α=79) | τ(α=64) |
|------|-----------|---------|---------| |------|-----------|---------|---------|
| M1H | 32.8 ms | 106 ms | 131 ms | | M1H | **8.19 ms**(⚠ 2026-09-11 勘误) | **26.5 ms** | **32.8 ms** |
| PD132L | 27.3 ms | 88 ms | 109 ms | | PD132L | 27.3 ms | 88 ms | 109 ms |
| PD132T | **10.92 ms**勘误 | **35.4 ms** | **43.7 ms** | | PD132T | **10.88 ms**100kHz 站点;标称上限 10.92 | **35.3 ms** | **43.5 ms** |
| PD136HA | 21.8 ms | 71 ms | 87 ms(实际生效) | | PD136HA | **21.76 ms**100kHz 站点;标称上限 21.85 | **70.5 ms** | **87.0 ms(实际生效)** |
| DLD154V4B | 10 ms | **32 ms** | 40 ms | | DLD154V4B | 10 ms | **32 ms** | 40 ms |
| DLD154Pro | 8.74 ms | 28 ms | 35 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)。
--- ---
## 3. 对触发(进入)的影响 ## 3. 对触发(进入)的影响
+180
View File
@@ -0,0 +1,180 @@
# 测量节拍不是常数:周期累积法的窗口量化(`floor(BASE/Xn)·Xn`
> **2026-09-11** · 起因:指出 `void CAP1_isr()` 里 `loop1_Value = loop1_CapSum`(累加 LPCNT 个 `Xn`)与 `loop1_LPCNT = 32768/loop1_Xn` 的**整数除法** ⇒ **测量节拍是区间,不是定值**。
> 适用:**PD132T / PD136HA / M1H**BASE=32768 同族,代码逐行同构);**DLD154V4B / 154Pro 同理**BASE 不同,误差更小,见 §7)。
## 0. 结论
| # | 结论 | 说明 |
|---|---|---|
| 1 | **测量窗 = `floor(BASE/Xn₀) · Xn₁ / f_cap`** | `Xn₀` = 学习时算得并**冻结**的周期计数;`Xn₁` = 当前周期计数 |
| 2 | **标称值 `BASE/f_cap`10.92 / 21.85ms)是上限,不是真值** | 实际窗 = `BASE (BASE mod Xn₀)` 个 tick ⇒ **只短不长** |
| 3 | 站点偏差 = `(BASE mod Xn₀)/BASE` ⇒ 带内 **0 ~ 6.2%** | Xn₀ 越接近带低端(2050)越短;典型 100kHz 线圈(Xn₀=480)为 **0.39%** |
| 4 | 另有**频率跟踪分量**:窗时长 ∝ `1/f_now` | 阈值量级(≤0.46%)可忽略;**深占压**(线圈频偏 −5%)时窗变长 +5.3% |
| 5 | ⭐ **Δf/f 口径完全不受影响** | `Value/Origin = Xn₁/Xn₀` **精确成立**(整除余数 r 在分子分母**完全约掉**)⇒ 既有灵敏度/交付结论全部保持 |
| 6 | ⚠ **`loop1_LPCNT` 声明为 `INT8U`(≤255** | 同族靠 `406 < Xn < 2050` 保证 `LPCNT ≤ 80`**PD136HA 已把该窗口注释掉** ⇒ `Xn < 129`(线圈 >372kHz)会 8 位溢出(§5 |
---
## 1. 代码机理(PD132T / PD136HA 逐行同构)
```c
/* PD132T main.c:96-105 / PD136HA main.c:163-172 —— 学习期:LPCNT 算一次后冻结 */
if (loop1_INI_LOOP) {
if (loop1_LPCNT == 0) {
if (loop1_CapCnt > 100) {
loop1_LPCNT = 32768 / loop1_Xn; // ← 整数除法,截断
if (loop1_LPCNT == 0) loop1_LPCNT = 1; // Xn>32768 时兜底
loop1_CAPVD = 0; loop1_CapSum = 0; loop1_CapCnt = 0;
}
}
}
/* 测量期:累加 LPCNT 个 Xn */
loop1_CapSum += loop1_Xn;
if (loop1_CapCnt >= loop1_LPCNT) {
loop1_Value = loop1_CapSum; // = Σ(LPCNT 个 Xn)
loop1_CapSum = 0; loop1_CapCnt = 0;
}
```
关键性质(两条都容易被忽略):
1. **`LPCNT` 是"一次冻结"**:只在 `LPCNT == 0``CapCnt > 100` 时计算一次,此后不再重算;只有 `INIT_VD()`(学习/复位)才 `LPCNT = 0` 重新标定。
2. **`CapCnt++` 发生在累加之前**PD132T:83 / PD136HA:148)⇒ 判据触发时 `CapSum` 恰好含 **LPCNT** 项 ⇒ `Value = LPCNT × Xn`Xn 恒定时)✓
⇒ 因此:**窗长(tick= `LPCNT × Xn₁` = `floor(BASE/Xn₀) × Xn₁`**,而**不是**恒定 `BASE`
---
## 2. 代数:窗为什么"只短不长",而口径为什么不受影响
`BASE = 32768``r₀ = BASE mod Xn₀`,则
```
LPCNT = (BASE r₀) / Xn₀ (整数除法)
窗长(tick) = LPCNT · Xn₁ = (BASE r₀) · (Xn₁ / Xn₀) Xn₁ = 当前值)
窗时长 = 窗长(tick) / f_cap
```
**两条分量**
| 分量 | 表达式 | 量级 | 性质 |
|---|---|---|---|
| ① 整除余数量化 | `(BASE r₀)/BASE` | 带内 **0 ~ 6.2%** | **站点确定值**(不抖动;随该站点线圈频率而定) |
| ② 频率跟踪 | `Xn₁/Xn₀ = f₀/f_now` | 阈值内 ≤ +0.46%;深占压 +5% 量级 | 与频偏**同向**(频率跌 ⇒ 窗变长) |
**口径为什么不受影响**(最重要):
```
Origin = LPCNT · Xn₀ = BASE r₀ (学习值)
Value = LPCNT · Xn₁ (当前值)
Value / Origin = Xn₁ / Xn₀ ← 精确,r₀ 完全约掉 ✓
```
⇒ 相对量 `Δf/f = 1 Value/Origin` **与 r₀、与 BASE、与 f_cap 全部无关** ✓(数值验证:Xn₀ = 406/480/800/2050 四种站点,频偏 0.5% 时 `Value/Origin` 均精确等于 `Xn₁/Xn₀`)。
唯一残留误差是判据阈值的**截断**`dlt = Origin × 表值 >> 16` ⇒ 有效阈值 = `表值/65536 ± 1/Origin`,即 **±0.003%**1/32768)—— 可忽略。
## 3. 数值表(按站点线圈频率)
`Xn₀ = C / f_coil`(族内 `C = 32·f_cap/边沿系数 = 4.8×10⁷`PD132T/PD136HA 通用):
| 线圈频率 | Xn₀ | LPCNT | 窗长(tick) | PD132T 窗@3MHz | 偏差 | PD136HA 窗@1.5MHz | 偏差 | M1H 窗@4MHz |
|---|---|---|---|---|---|---|---|---|
| 240 kHz | 200 | 163 | 32 600 | 10.867 ms | 0.51% | 21.733 ms | 0.51% | 8.150 ms |
| **100 kHz(标称)** | 480 | 68 | 32 640 | **10.880 ms** | **0.39%** | **21.760 ms** | **0.39%** | 8.160 ms |
| 60 kHz | 800 | 40 | 32 000 | 10.667 ms | 2.34% | 21.333 ms | 2.34% | 8.000 ms |
| 40 kHz | 1200 | 27 | 32 400 | 10.800 ms | 1.12% | 21.600 ms | 1.12% | 8.100 ms |
| 23.4 kHz(带低端) | 2050 | 15 | 30 750 | 10.250 ms | **6.16%** | 20.500 ms | 6.16% | 7.688 ms |
| (带内最差) | 2049 | 15 | 30 735 | 10.245 ms | **6.20%** | 20.490 ms | 6.20% | 7.684 ms |
**读法**`10.92 ms` / `21.85 ms` 是**标称上限**;具体站点按上表由**线圈频率**决定(偏差随 `LPCNT` 变小而变大 —— 低频线圈的窗更短、量化更粗)。
**积分深度**(每窗平均的有效线圈周期数)同样按此缩放:PD132T ≈ `16·LPCNT`、PD136HA ≈ `32·LPCNT`100kHz 站点:1088 / 2176 个线圈周期)。
---
## 4. 频率跟踪分量(窗随时间"伸缩")
因为 `LPCNT` 冻结、而窗累加的是**当前**周期,所以:
```
窗时长(t) = 窗长(tick)/f_cap = (BASE r₀)/f_cap × (f₀ / f_now)
```
| 线圈频偏 | 窗时长变化 | 现场含义 |
|---|---|---|
| 0.032%PD132T 档 3 阈值) | +0.032% | 可忽略 |
| 0.458%PD132T 档 0 阈值) | +0.460% | 可忽略 |
| 1% | +1.01% | 温度漂移量级 |
| **5%** | **+5.26%** | **大车/拖车深占压**:窗变长 ⇒ 恢复更慢 |
⇒ 结论:**在"检测阈值"量级上可忽略(≤0.5%),在"深占压"场景下会把响应/恢复时间再拉长百分之几**。这也解释了为什么"深占压后基线跟踪慢"的代码设计(冻结 + `LC_HOLD` 重学)是必要的。
---
## 5. ⚠ 位宽与窗口检查(本轮新发现)
| 变量 | 类型 | 上限 | 约束 | 风险 |
|---|---|---|---|---|
| `loop1_LPCNT` | `INT8U`PD132T main.h:37 / PD136HA main.h:64 | **255** | `LPCNT = 32768/Xn ≤ 255` ⇒ 需 `Xn ≥ 129` | ⚠ 见下 |
| `loop1_CapCnt` | `INT8U` | 255 | 需 `LPCNT ≤ 255`(同上) | 同上 |
| `loop1_CapSum` / `Value` / `CAPVD` | `INT16U` | 65 535 | 标称 32 768**余量 2×** | 频率下漂 >100%(Xn 翻倍)才溢出 ⇒ 现实不可达 |
**同族靠频率窗口保护 8 位 LPCNT**`406 < Xn < 2050``LPCNT ≤ 80` ✓(PD132T main.c:85、M1H 同构)。
**PD136HA 已把该窗口注释掉**`// if(loop1_Xn>400 && loop1_Xn<2030)`main.c:150V3.14 去环路 LED 时一并屏蔽)⇒ **保护消失**
-`Xn < 129`(等效线圈 > 372 kHz,例如线圈断线/短路的异常振荡、或强干扰产生的窄脉冲)⇒ `LPCNT` 真值 >255 ⇒ **8 位截断**(如 327 → 71)⇒ 窗长骤降(71×Xn)而 `Origin ≈ 32768``Value ≪ Origin dlt`**判为"持续有车"** ⇒ 继电器吸合 → HOLD 300s 超时 → 整机复位。
- 对比 **PD132T**:同样的异常会走 `LOOP_OK = 0` + LED 快闪(**故障指示**,不产生有车输出)。
-**行为差异**:同一种线圈异常,PD132T 报"故障"PD136HA 可能报"堵车"。
- **建议**(固件侧,待评估):PD136HA 恢复窗口检查,或至少加 `if (loop1_LPCNT > 80) → 判故障` 的兜底钳制。
> 同类检查也适用于 M1H(同 8 位 `LPCNT` + 无窗口检查 ⇒ 同风险)。**注意**:PD132T 的窗口检查同时承担"线圈异常 → 故障"的职责,恢复/删除前要确认异常语义有替代路径。
---
## 6. 受影响 / 不受影响(既有数值的正确读法)
| 类别 | 项目 | 处置 |
|---|---|---|
| ✅ **不受影响** | `Δf/f = 表值/65536` 口径、灵敏度表换算、跨型号档位对比、进入/离开判据、滞回语义 | 保持不动(§2 代数保证) |
| ⚠️ **同一因子缩放** | 测量节拍、基线更新周期、IIR 时间常数 τ、进入/离开响应时间、最小可检占压、积分深度 | 表中数值标注"**标称(上限)**",实际 = 标称 × `(BASEr₀)/BASE` × `f₀/f_now` |
**修正后的表述模板**(建议全仓沿用):
> 测量节拍 **≈10.88 ms**(标称上限 10.923 ms = 32768/3MHz;实际 = `floor(32768/Xn₀)·Xn₀/f_cap`100kHz 站点 0.39%,带内最差 6.2%)
例:PD132T 基线更新周期 = 100 × 10.88ms = **1.088 s**(标称上限 1.092s);PD136HA = 256 × 21.76ms = **5.571 s**(标称上限 5.593s)。
---
## 7. 跨型号意义:BASE 越大量化误差越小
站点量化误差上限 = `Xn₀/BASE`= `1/LPCNT`):
| 型号 | BASE | 100kHz 站点 Xn₀ | LPCNT | 窗量化误差上限 |
|---|---|---|---|---|
| M1H / PD132L / PD132T / PD136HA | 32 768 | 480PD132T/136HA | 68 | **≤1.46%**(带低端 ≤6.25% |
| DLD154V4B | 131 072 | 1200 | 109 | ≤0.92% |
| DLD154Pro | 524 288 | 600 | 873 | ≤0.11% |
**大基数的第二个好处**(除既有"绝对分辨率高 4×"之外):**同比降低窗量化误差** —— 因为 `LPCNT` 更大,"`floor` 截断"的相对损失更小。V4B 的 1.09ms 窗实际为 ≈1.09ms(−0.9% 上限),154Pro 的 8.74ms 窗几乎无量化损失。
---
## 8. 验证与复算方法
1. **纯计算**(现场 5 分钟):量出线圈频率 `f_coil``Xn₀ = C/f_coil``C = 4.8×10⁷`PD132T/PD136HA 通用)⇒ `LPCNT = ⌊32768/Xn₀⌋` ⇒ 窗长 = `LPCNT·Xn₀` tick ⇒ 窗时长 = 窗长/`f_cap`。可算到 0.1% 以内。
2. **固件侧**:把 `loop1_LPCNT` / `loop1_Value` 引到可用观测(PD132T 无 UART ⇒ 需临时改 LED 或 ISP 读 RAMPD136HA 有 SWD ⇒ 直接在线看变量最省事)。
3. **回归验证**:若实测"基线更新时间"与 `窗长×100(256)` 不符,说明 `LPCNT` 被二次重算过 —— 检查是否存在第二处 `LPCNT = 0`PD132T `INIT_VD()`、PD136HA main.c:411;其 430 行为注释状态)。
4. **台架**:信号发生器替代 CD4060 输出已知 f_in ⇒ 交替改频率 0.1%/0.5%/2%,观察继电器翻转窗口数与理论 `dlt` 是否一致(验证 §2 的"口径精确"结论)。
---
## 相关文档
- 双型号对比:`docs/pd132t-vs-pd136ha-comparison.md`(§3 测量与归一化)
- 跨型号总表:`docs/cross-model-comparison.md`(测量节拍/基线周期行)
- 滤波系数专题:`docs/filter-coefficient-79-vs-64.md`(τ 口径)
- 交付对齐:`docs/pd136ha-to-dld154v4b-delivery-alignment.md``docs/pd132t-to-v4b-delivery-alignment.md`
+2 -2
View File
@@ -68,14 +68,14 @@ const uint16_t SensTable_1[4] = { 60, 32, 21, 14}; // 离开:分档与 PD1
### 1.4 等效灵敏度修正(V4B 检测链路;**2026-09-11 勘误后:与 PD132T 同量级** ### 1.4 等效灵敏度修正(V4B 检测链路;**2026-09-11 勘误后:与 PD132T 同量级**
- IIR τ = 32ms vs 29.6ms**基本相当**;旧稿「快 4.4×」系 PD132T 节拍误算为 43.7ms,见文末勘误) - IIR τ = 32ms vs 29.6ms**基本相当**;旧稿「快 4.4×」系 PD132T 节拍误算为 43.7ms,见文末勘误)
- 测量节拍 10ms vs 10.92ms**基本相当**;同上勘误) - 测量节拍 10ms vs **10.88ms**100kHz 站点;标称上限 10.92ms**基本相当**;同上勘误)
- 进入确认 3 次 vs 单次 → 瞬时抖动不误触(等效更稳) - 进入确认 3 次 vs 单次 → 瞬时抖动不误触(等效更稳)
- 斜率限幅 5% → EMI/闪电尖峰单次截断 - 斜率限幅 5% → EMI/闪电尖峰单次截断
- 离开确认 3 次 vs 单次 → 释放响应 30ms vs ≤10.9ms**PD132T 单次更快;V4B 以 3 次确认换稳定** —— 方向与旧稿相反) - 离开确认 3 次 vs 单次 → 释放响应 30ms vs ≤10.9ms**PD132T 单次更快;V4B 以 3 次确认换稳定** —— 方向与旧稿相反)
净效果:**进入/离开阈值双向对齐后,V4B 因确认机制反而比 PD132T 稳**(代价:进入/释放各慢 ~20~30ms)。 净效果:**进入/离开阈值双向对齐后,V4B 因确认机制反而比 PD132T 稳**(代价:进入/释放各慢 ~20~30ms)。
> ⚠ **2026-09-11 勘误**PD132T 捕获时钟 = **3MHz**(旧稿 0.75MHz 无寄存器依据)⇒ 测量节拍 **10.92ms**(旧 43.7ms)、精确 τ(α79) **29.6ms**(旧口径 142ms)。本节 5 条对比中前两条的「快/密 4.4×」结论作废,改为「同量级」。**阈值/灵敏度口径不受影响**(与时钟无关)。推导见 `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),深占压再 +5%;**Δf/f 口径同样不受影响**。详见 `docs/measurement-window-quantization.md`。推导见 `docs/pd136ha-to-dld154v4b-delivery-alignment.md` §2.3。
## 2. 触发/释放手感(存在输出 + 延时模式) ## 2. 触发/释放手感(存在输出 + 延时模式)
+4 -4
View File
@@ -15,7 +15,7 @@
| 2 | 硬件前端 | **完全同构**:线圈 → 9015 PNP×2 振荡 → CD4060 施密特整形 + **÷32Q5** → MCU | ✅ | | 2 | 硬件前端 | **完全同构**:线圈 → 9015 PNP×2 振荡 → CD4060 施密特整形 + **÷32Q5** → 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)的真正原因 | ⭐ 关键 | | 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` 可**直接跨型号对比** | ✅ | | 4 | 归一化基数 | **同为 32768**(换 MCU 未重定标)⇒ 相对阈值 `表值/65536` 可**直接跨型号对比** | ✅ |
| 5 | 测量节拍 | **10.92ms → 21.85ms(慢 2×)** ⇒ 每窗有效平均 1092**2185** 个线圈周期(积分深度 ×2) | ⚖️ 权衡 | | 5 | 测量节拍 | **10.88ms → 21.76ms**(100kHz 站点实测口径;标称上限 10.923/21.845ms⇒ 每窗有效平均 1088**2176** 个线圈周期(积分深度 ×2|⚠ 节拍**是区间**:按站点线圈频率浮动 0 ~ −6.2%,深占压再 +5%(见 `measurement-window-quantization.md` | ⚖️ 权衡 |
| 6 | 滤波 / 基线 | IIR τ:**29.6~38ms → 76~87ms**(慢 2~2.9×);基线窗 **100 → 256**1.09s → 5.59s | ⚠ PD136HA 更稳更慢 | | 6 | 滤波 / 基线 | IIR τ:**29.6~38ms → 76~87ms**(慢 2~2.9×);基线窗 **100 → 256**1.09s → 5.59s | ⚠ PD136HA 更稳更慢 |
| 7 | 判据强度 | 两者**均为单次越线判定**(无进入/离开确认计数)—— 响应快、抗单点扰动弱 | ⚖️ 相同 | | 7 | 判据强度 | 两者**均为单次越线判定**(无进入/离开确认计数)—— 响应快、抗单点扰动弱 | ⚖️ 相同 |
| 8 | 灵敏度表 | **重标定**:进入 {300,60,32,21} → {162,81,54,28}。**档位一一照搬会产生 46%~+69% 偏差** ⇒ 跨代必须按 Δf/f 重新对齐 | ❌ 不可照搬档位 | | 8 | 灵敏度表 | **重标定**:进入 {300,60,32,21} → {162,81,54,28}。**档位一一照搬会产生 46%~+69% 偏差** ⇒ 跨代必须按 Δf/f 重新对齐 | ❌ 不可照搬档位 |
@@ -115,7 +115,7 @@ PD136HA:线圈 → 9015 PNP×2 振荡 → CD4060 施密特整形 +
| 捕获时钟源 | PCA 时钟 = **T0 溢出**`CMOD=0x04`)→ T0 8bit 自动重装 252(每 4 个 SYSCLK 溢出) | ADTIM4 计数时钟 = **PCLK0/8** | | 捕获时钟源 | PCA 时钟 = **T0 溢出**`CMOD=0x04`)→ T0 8bit 自动重装 252(每 4 个 SYSCLK 溢出) | ADTIM4 计数时钟 = **PCLK0/8** |
| 捕获时钟 | **3 MHz**(= 12MHz ÷ 4,官方手册直证) | **1.5 MHz**= 12MHz ÷ 8,源码 + Keil 时钟设置) | | 捕获时钟 | **3 MHz**(= 12MHz ÷ 4,官方手册直证) | **1.5 MHz**= 12MHz ÷ 8,源码 + Keil 时钟设置) |
| 中断 | `CAP1_isr() interrupt 6` | `Tim4_IRQHandler` | | 中断 | `CAP1_isr() interrupt 6` | `Tim4_IRQHandler` |
| 学习 | `loop1_LPCNT = 32768 / Xn``CapCnt > 100` | 同(`CapCnt > 100` | | 学习 | `loop1_LPCNT = 32768 / Xn``CapCnt > 100`,**算一次即冻结**) | 同(同条件冻结 |
| 测量 | 累积 `LPCNT` 个 Xn ⇒ `CAPVD` | 同(`CapSum``CAPVD` | | 测量 | 累积 `LPCNT` 个 Xn ⇒ `CAPVD` | 同(`CapSum``CAPVD` |
| 频率范围过滤 | ✅ 保留:`406 < Xn < 2050` | ❌ **已注释禁用**(V3.14 去掉环路指示 LED 时一并屏蔽)⇒ 当前无频率过滤 | | 频率范围过滤 | ✅ 保留:`406 < Xn < 2050` | ❌ **已注释禁用**(V3.14 去掉环路指示 LED 时一并屏蔽)⇒ 当前无频率过滤 |
@@ -126,8 +126,8 @@ PD136HA:线圈 → 9015 PNP×2 振荡 → CD4060 施密特整形 +
| 量 | 公式 | PD132T | PD136HA | 比值 | | 量 | 公式 | PD132T | PD136HA | 比值 |
|---|---|---|---|---| |---|---|---|---|---|
| 捕获时钟 | — | **3 MHz** | **1.5 MHz** | PD132T 快 2× | | 捕获时钟 | — | **3 MHz** | **1.5 MHz** | PD132T 快 2× |
| **测量节拍**CAPVD 更新) | `32768 / f_cap` | **10.92 ms** | **21.85 ms** | PD136HA 慢 2× | | **测量节拍**CAPVD 更新) | `32768/Xn₀⌋·Xn₁ / f_cap` | **10.88 ms**100kHz 站点) | **21.76 ms** | PD136HA 慢 2× |
| 每窗有效平均的线圈周期数 | `节拍 × f_coil`@100kHz 标称 | ≈ **1092** | ≈ **2185** | PD136HA 深 2× | | 每窗有效平均的线圈周期数 | `窗长(tick) / 32 × 边沿系数`@100kHz 站点 | ≈ **1088** | ≈ **2176** | PD136HA 深 2× |
| 状态机节拍 | — | 50msT1 5ms × 10 | 50msTIM1 × 10 | 相同 | | 状态机节拍 | — | 50msT1 5ms × 10 | 50msTIM1 × 10 | 相同 |
| 上电稳定 | — | 750ms 延时 + 学习 | 1s 延时 + LED 自检闪 6 次 + 学习 | 接近 | | 上电稳定 | — | 750ms 延时 + 学习 | 1s 延时 + LED 自检闪 6 次 + 学习 | 接近 |
@@ -34,8 +34,8 @@
| MCU | **HC32F003C4**(M0+,用户确认;⚠ Keil 工程档位仍为 F005C6PA,重编译前须改) | AT32F421F8P7M4120MHz | — | | MCU | **HC32F003C4**(M0+,用户确认;⚠ Keil 工程档位仍为 F005C6PA,重编译前须改) | AT32F421F8P7M4120MHz | — |
| 运行形态 | 裸机主循环 | FreeRTOS 多任务 | — | | 运行形态 | 裸机主循环 | FreeRTOS 多任务 | — |
| **归一化基数 BASE** | **32768**2^15 | **131072**2^17 | **差 4 倍** | | **归一化基数 BASE** | **32768**2^15 | **131072**2^17 | **差 4 倍** |
| 测量窗 | **21.85ms**12MHz 晶振**已确认**2026-09-11 | **1.09ms**131072 / 120MHz | 快 ~20× | | 测量窗 | **21.85ms**12MHz 晶振**已确认**;标称上限 | **1.09ms**131072 / 120MHz;标称上限,实际 ≤−0.9% | 快 ~20× |
| CAPVD 消费节拍 | 21.8ms | **10ms** | 快 2.2× | | CAPVD 消费节拍 | 21.76ms100kHz 站点;标称 21.85 | **10ms** | 快 2.2× |
| 阈值公式 | `dlt = Origin × SensTable[SensLevel] >> 16` | `dlt = Origin × SensTable[SENS] >> 16` | **逐字同构** | | 阈值公式 | `dlt = Origin × SensTable[SensLevel] >> 16` | `dlt = Origin × SensTable[SENS] >> 16` | **逐字同构** |
| **前端信号链** | 线圈 → 9015×2 振荡 → **CD4060 整形+分频** → P23 | 线圈 → 9015×2 振荡 → **直连** → PA7 | ⚠ 口径不变、抖动特性不同 → **§2** | | **前端信号链** | 线圈 → 9015×2 振荡 → **CD4060 整形+分频** → P23 | 线圈 → 9015×2 振荡 → **直连** → PA7 | ⚠ 口径不变、抖动特性不同 → **§2** |
@@ -108,12 +108,14 @@ CAPVD = LPCNT × Xn_分频后 = 32768 ← 与 N 无关
**捕获时钟(三型号,含本轮勘误)** **捕获时钟(三型号,含本轮勘误)**
| 型号 | 捕获时钟 | 寄存器依据 | 测量窗(32768 tick | | 型号 | 捕获时钟 | 寄存器依据 | 测量窗(**标称上限** = 32768 tick |
|---|---|---|---| |---|---|---|---|
| PD132T**MA801** | **3MHz** = 12MHz/4 ✅**全链官方手册直证** | ① `AUXR=0xC0` ⇒ T0X12=T1X12=1 ⇒ 定时器按 **1 个时钟周期**计数(手册 §14:「AUXR.T0X12 和 AUXR.T1X12 用来设置定时器 0/1 的定时器率为 1 个时钟周期」;`0`=SYSCLK/12、`1`=SYSCLK);② `TMOD=0x12` + `TH0=TL0=252` ⇒ T0 8bit 自动重载,每 **4** 个 SYSCLK 溢出(= 作者注释「时钟/4」);③ `CMOD=0x04``CPS1:CPS0=10`**PCA 时钟 = 定时器 0 溢出**(手册编码表;作者原注「时钟源为定时器0溢出」同此);④ T1 `TH1/TL1=0x15A0`→60000 计数 = **5ms**ISR 注释「定时5ms」/「5*10=50ms」)⇒ SYSCLK = **12MHz 晶振** ✓ ⇒ PCA 捕获时钟 = 12M/4 | **10.92 ms** | | PD132T**MA801** | **3MHz** = 12MHz/4 ✅**全链官方手册直证** | ① `AUXR=0xC0` ⇒ T0X12=T1X12=1 ⇒ 定时器按 **1 个时钟周期**计数(手册 §14:「AUXR.T0X12 和 AUXR.T1X12 用来设置定时器 0/1 的定时器率为 1 个时钟周期」;`0`=SYSCLK/12、`1`=SYSCLK);② `TMOD=0x12` + `TH0=TL0=252` ⇒ T0 8bit 自动重载,每 **4** 个 SYSCLK 溢出(= 作者注释「时钟/4」);③ `CMOD=0x04``CPS1:CPS0=10`**PCA 时钟 = 定时器 0 溢出**(手册编码表;作者原注「时钟源为定时器0溢出」同此);④ T1 `TH1/TL1=0x15A0`→60000 计数 = **5ms**ISR 注释「定时5ms」/「5*10=50ms」)⇒ SYSCLK = **12MHz 晶振** ✓ ⇒ PCA 捕获时钟 = 12M/4 | **10.92 ms**(标称上限) |
| PD132L | **1.2MHz** = 12MHz/10 | `TIM1_PSCRL=0x09`(10 分频)+ 外部 12MHz 晶振(`CLK_ECKR`/`CLK_SWR=0xB4``CLK_CKDIVR&=0xF8` 无分频) | 27.3 ms | | 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** | | 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 ⇒ 上表「测量窗」列全部为**标称上限**。实际 = 标称 × `(32768r₀)/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`。
>
> ⚠ **本轮勘误**:专项文档 `hardware-loop-frontend-pd132t-vs-v4b.md` 旧记 PD132T 捕获时钟 **0.75MHz / 测量窗 43.7ms ⇒ 修正为 3MHz / 10.92ms**。 > ⚠ **本轮勘误**:专项文档 `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)。 > 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)。
> **该勘误不影响任何相对阈值结论**(§1/§3/§4 全部基于 `表值/65536`,与时钟无关)。 > **该勘误不影响任何相对阈值结论**(§1/§3/§4 全部基于 `表值/65536`,与时钟无关)。
+131
View File
@@ -0,0 +1,131 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""测量窗量化计算器(周期累积法)
背景:检测器不是"累加固定 tick 数",而是"累加固定个数的周期"
LPCNT = floor(BASE / Xn0) # 整数除法,学习时算一次后【冻结】
窗长 = LPCNT * Xn1 # 单位:捕获时钟 tick ← 不是恒定 BASE!
窗时长 = 窗长 / f_cap
其中 Xn0 = 学习时的周期计数、Xn1 = 当前周期计数(Xn 与线圈频率成反比)。
结论(详见 docs/measurement-window-quantization.md):
* 表中 BASE/f_cap(如 10.92ms / 21.85ms)是【标称上限】,实际窗 = BASE - (BASE mod Xn0) tick
* 站点偏差 = r0/BASEr0 = BASE mod Xn0),带内 0 ~ -6.2%
* 深占压(线圈频偏 -d%)时窗时长再放大 1/(1-d)
* 【比值口径不受影响】:Value/Origin = Xn1/Xn0 精确(余数完全约掉)
用法:
python3 window_calc.py # 打印内置型号对照表
python3 window_calc.py --model PD132T --f-coil 100k
python3 window_calc.py --f-cap 3M --base 32768 --edge 2 --divider 32 --f-coil 60k
参数:--f-coil 线圈频率(Hz 或 100k/60k)、--f-cap 捕获时钟、--base 归一化基数、
--edge 捕获沿系数(双沿=2 / 单沿=1)、--divider 前端分频比(CD4060 ÷32 或直连=1)
"""
import argparse
import sys
# 内置型号参数: (BASE, f_cap, edge_factor, front_divider, note)
MODELS = {
"M1H": (32768, 4.0e6, 2, 32, "STC12C5202, PCA 双沿, ÷32(推断), 4MHz"),
"PD132L": (32768, 1.2e6, 1, 32, "STM8S003, TIM1_CC3 下降沿, ÷32, 1.2MHz"),
"PD132T": (32768, 3.0e6, 2, 32, "MA801, PCA 双沿, ÷32(Q5), 3MHz"),
"PD136HA": (32768, 1.5e6, 1, 32, "HC32F003C4, ADTIM4 单沿, ÷32, 1.5MHz"),
"DLD154V4B": (131072, 120e6, 1, 1, "AT32F421, TIM3 直连振荡(1 Xn = 1 原始周期), 120MHz"),
"DLD154Pro": (524288, 60e6, 1, 1, "CH591R, TMR0 下降沿直连, 60MHz 实测"),
}
def parse_freq(text):
"""'100k' / '3M' / '1.5e6' / '480' -> float Hz"""
t = str(text).strip()
mult = 1.0
if t[-1] in "kK":
mult, t = 1e3, t[:-1]
elif t[-1] in "mM":
mult, t = 1e6, t[:-1]
return float(t) * mult
def window(base, f_cap, edge, divider, f_coil, f_now=None):
"""返回 dictXn、LPCNT、窗长(tick)、窗时长(s)、偏差、口径验证"""
f_now = f_coil if f_now is None else f_now
C = divider * f_cap / float(edge) # 判据常数: Xn = C / f_coil
xn0 = C / f_coil
lpcnt = int(base // xn0)
if lpcnt == 0: # 固件兜底: Xn > BASE 时 LPCNT=1
lpcnt = 1
xn_float0 = xn0
xn0 = round(xn0) # 固件里 Xn 是整数计数
xn1 = round(C / f_now)
window_ticks = lpcnt * xn0 # 学习时/稳态
window_ticks_now = lpcnt * xn1 # 当前频率下
r0 = base % xn0 if xn0 <= base else base
return {
"C": C, "Xn0": xn0, "LPCNT": lpcnt, "r0": r0,
"window_ticks": window_ticks,
"nominal_ticks": base,
"window_s": window_ticks / f_cap,
"nominal_s": base / f_cap,
"dev_pct": (window_ticks / base - 1.0) * 100.0,
"window_s_now": window_ticks_now / f_cap,
"dev_now_pct": (window_ticks_now / base - 1.0) * 100.0, # vs 标称上限
"dev_now_vs_learned_pct": (window_ticks_now / float(window_ticks) - 1.0) * 100.0, # vs 学习时窗
"ratio_exact": xn1 / float(xn0), # Value/Origin 应为该值
"ratio_formula": f_now and (f_coil / f_now),
}
def main():
ap = argparse.ArgumentParser(description="周期累积法测量窗量化计算器")
ap.add_argument("--model", choices=sorted(MODELS), help="内置型号")
ap.add_argument("--base", type=int, default=32768)
ap.add_argument("--f-cap", default="3M")
ap.add_argument("--edge", type=int, choices=(1, 2), default=2, help="捕获沿系数: 双沿=2 单沿=1")
ap.add_argument("--divider", type=int, default=32, help="前端分频比 (CD4060 ÷32=32, 直连=1)")
ap.add_argument("--f-coil", default="100k", help="线圈频率 (100k / 3M / 480)")
ap.add_argument("--f-now", default=None, help="当前频率(默认=f-coil),用于看频率跟踪分量")
a = ap.parse_args()
if a.model:
base, fcap, edge, div, note = MODELS[a.model]
print("型号 %s: %s" % (a.model, note))
else:
base, fcap, edge, div = a.base, parse_freq(a.f_cap), a.edge, a.divider
f_coil = parse_freq(a.f_coil)
f_now = parse_freq(a.f_now) if a.f_now else None
w = window(base, fcap, edge, div, f_coil, f_now)
print("参数: BASE=%d f_cap=%.6g Hz 边沿系数=%d 分频=%d 线圈=%.6g Hz"
% (base, fcap, edge, div, f_coil))
print("判据常数 C = 分频·f_cap/边沿 = %.4g (Xn = C/f_coil)" % w["C"])
print("Xn0 = %.2f -> 取整 %d ; LPCNT = floor(%d/%d) = %d ; r0 = BASE mod Xn0 = %d"
% (w["C"] / f_coil, w["Xn0"], base, w["Xn0"], w["LPCNT"], w["r0"]))
print("窗长 = LPCNT·Xn0 = %d tick (标称上限 %d tick)" % (w["window_ticks"], w["nominal_ticks"]))
print("窗时长 = %.4f ms (标称上限 %.4f ms) 偏差 %+.2f%%"
% (w["window_s"] * 1e3, w["nominal_s"] * 1e3, w["dev_pct"]))
if f_now and abs(f_now - f_coil) > 1e-9:
print("频率跟踪: f_now=%.6g Hz -> 窗 %.4f msvs 标称 %+.2f%% / vs 学习时窗 %+.2f%%"
% (f_now, w["window_s_now"] * 1e3, w["dev_now_pct"], w["dev_now_vs_learned_pct"]))
print(" 比值口径验证: Value/Origin = %.6f ← 应等于 f0/f_now = %.6f"
% (w["ratio_exact"], f_coil / f_now))
print("口径提示: Δf/f = 表值/65536 不受窗长/ BASE 影响(余数约掉);"
"量化误差上限 = Xn0/BASE = %.2f%%" % (w["Xn0"] / base * 100.0))
# 无参时打印族内对照表
if not any([a.model, a.f_now]) and a.f_coil == "100k":
print("\n附:内置型号对照(同为 100kHz 线圈,前端均按各自 divider)")
print("%-11s %8s %6s %5s %8s %11s %8s" % ("型号", "f_cap", "Xn0", "LPCNT", "窗tick", "窗时长", "偏差"))
for name, (b, fc, e, dv, _n) in MODELS.items():
C = dv * fc / float(e)
if not (1 <= C / 1e5 <= b): # 该频率不在其频段内则跳过
continue
ww = window(b, fc, e, dv, 1e5)
print("%-11s %7.3gM %6d %5d %8d %9.4fms %+7.2f%%"
% (name, fc / 1e6, ww["Xn0"], ww["LPCNT"], ww["window_ticks"],
ww["window_s"] * 1e3, ww["dev_pct"]))
return 0
if __name__ == "__main__":
sys.exit(main())