#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""六型号总览图(窗长 / τ / 检测延迟)—— 纯 stdlib 手写 SVG
面板 A:测量窗长 与 IIR 时间常数 τ(横向条形,对数刻度)
面板 B:检测延迟 vs Δf/f(各型号按【本型号档0 判据】计算,对数-对数)
转 PNG:chromium --headless=new --disable-gpu --no-sandbox \
--screenshot=docs/img/family-overview.png --window-size=1520,1000 \
file://$PWD/docs/img/family-overview.svg
"""
import math
W, H = 1520, 1100
FONT = "'Noto Serif CJK SC','Noto Sans CJK SC',sans-serif"
MONO = "'DejaVu Sans Mono',monospace"
out = []
def esc(s):
return (s.replace('&', '&').replace('<', '<').replace('>', '>'))
def txt(x, y, s, size=14, fill='#222', anchor='start', weight='normal', family=None):
out.append('%s'
% (x, y, size, fill, anchor, weight, family or FONT, esc(s)))
def line(x1, y1, x2, y2, stroke='#999', w=1.0, dash=None):
d = ' stroke-dasharray="%s"' % dash if dash else ''
out.append(''
% (x1, y1, x2, y2, stroke, w, d))
def rect(x, y, w, h, fill='none', stroke='none', rx=3, sw=1.0, op=1.0, dash=None):
d = ' stroke-dasharray="%s"' % dash if dash else ''
out.append(''
% (x, y, w, h, rx, fill, op, stroke, sw, d))
def poly(pts, stroke='#1565c0', w=1.8, fill='none', dash=None):
d = ' stroke-dasharray="%s"' % dash if dash else ''
s = ' '.join('%.1f,%.1f' % p for p in pts)
out.append(''
% (s, fill, stroke, w, d))
def dot(x, y, r=4.0, fill='#c1121f'):
out.append('' % (x, y, r, fill))
def note(x, y, w, h, title, lines_, color='#0b6'):
rect(x, y, w, h, '#fbfdff', color, rx=6, sw=1.2, op=0.95)
txt(x + 12, y + 24, title, 14.5, color, weight='bold')
for i, s in enumerate(lines_):
txt(x + 12, y + 48 + i * 21, s, 13, '#333')
# ---- 型号数据(全部取证过;数值见 docs/cross-model-comparison.md)----
# name, 测量窗(ms), 滤波更新节拍(ms), α, 档0 判据(Δf/f %), 进入确认说明, 颜色
M = [
('DLD154Pro', 8.738, 8.74, 79, 0.1650, '3 tick 确认(5ms tick)', '#6a1b9a'),
('DLD154V4B', 1.092, 10.00, 79, 0.5140, '3~5 tick 确认(10ms tick)', '#2e7d32'),
('PD136HA', 21.845, 21.85, 64, 0.2472, '无(单次越线)', '#e65100'),
('PD132T', 10.923, 10.92, 79, 0.4578, '无(单次越线)', '#1565c0'),
('PD132L', 27.307, 27.31, 79, 0.4578, '无(单次越线)', '#00838f'),
('M1H', 8.192, 8.19, 79, 0.3296, '10 tick 确认(≈0.6s)', '#5d4037'),
]
def tau_line(tick, alfa):
return tick * 256.0 / alfa
def delay_ms(m, d_pct):
"""判据越线延迟:d_pct 以 % 传入;返回 (窗数, ms) 或 None(检不到)"""
tick, alfa, thr = m[2], m[3], m[4]
if d_pct < thr:
return None
y = 0.0
for n in range(1, 4001):
y = d_pct * (1.0 - (1.0 - alfa / 256.0) ** n)
if y >= thr:
return (n, n * tick)
return (4000, 4000 * tick)
# ================== 画布 ==================
out.append('')
open(OPEN, 'w', encoding='utf-8').write('\n'.join(out))
print('已写出 %s(%d 元素)' % (OPEN, len(out)))
for m in M:
nm = m[0]
f = lambda r: ('%.1f ms(%d 窗)' % (r[1], r[0])) if r else '—'
print(' %-11s 窗 %6.2f | 节拍 %6.2f | τ %6.1f | 档0 %6.4f%% | @1.1x: %-16s @2x: %-16s @10x: %s'
% (nm, m[1], m[2], tau_line(m[2], m[3]), m[4],
f(delay_ms(m, m[4] * 1.1)), f(delay_ms(m, m[4] * 2.0)), f(delay_ms(m, m[4] * 10.0))))