docs(测试说明): 交流动态验证轮次加四张导读图(两 SVG 生成器 + 两 Mermaid)

§8 开头插「六轮速查卡」:3x2 面板,每轮注入信号缩略图数据驱动
(正弦 / 同峰值方波三角 / UA·UN 异相 / 扫频 / 负半周钉 0 / 谐波叠
加),一卡给接法、判据一句话、主读数出口,先立轮廓再进执行卡。

§8.5 插「为什么连取 10 行取中位数」概念图:左栏机理(定宽 20 拍
窗逐窗滑动 → 读数拍频跳),右栏操作(中位数 / 平均 / 真值三线
错位对照 + 毛刺行标注)——取数口径 4e4d597e 刚定,此图补原理。

§8.3 / §8.5 各加一张 Mermaid:接线拓扑(端接高阻、万用表并接、
单点共地、STM32 五路仅削顶轮支线);单轮执行主干(采集链与偏差
两级决策、分诊虚线回环,汇于关输出填表)。

新增生成器 gen_ac_rounds_svg.py / gen_ac_median_svg.py(纯标准库、
OVERFLOW 预检归零、generated-fresh 自动在册),README 补两行台账。

验证:两产物连跑两次 sha1 不变;check_generated_fresh rc=0 无
DIFF / NEW、漂移基线不增;mermaid-syntax 2 围栏新发 0;headless
Chrome 截图回读三轮,修掉两类只有渲染才暴露的真错(正文 x 在卡
循环外算导致第 2、3 列叠进第 1 列;三角波闭式值域 −2..4 画越界
尖峰)。六文件 BOM / CR / U+FFFD 均零。

注:当前 check_doc_links --all 报 27 处,全属并发会话在改的产品
需求三份文档,与本笔无关、未触碰。
This commit is contained in:
2026-10-30 12:21:02 +08:00
parent 4e4d597ed6
commit 6ffbb7d5b5
6 changed files with 846 additions and 0 deletions
+106
View File
@@ -0,0 +1,106 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1060" height="680" viewBox="0 0 1060 680" font-family="Microsoft YaHei, Segoe UI, PingFang SC, sans-serif">
<rect x="46.0" y="106.0" width="314.0" height="246.0" rx="10" fill="#eff6ff" stroke="#2563eb" stroke-width="2"/>
<text x="58.0" y="132.0" font-size="15" font-weight="700" fill="#0f172a">幅值轮</text>
<text x="348.0" y="132.0" font-size="10.5" text-anchor="end" font-weight="700" fill="#2563eb">先做 · 主用例</text>
<rect x="58.0" y="142.0" width="290.0" height="86.0" rx="6" fill="#ffffff" stroke="#cbd5e1" stroke-width="1"/>
<line x1="62.0" y1="185.0" x2="344.0" y2="185.0" stroke="#94a3b8" stroke-width="0.8" stroke-dasharray="3 3"/>
<line x1="68.0" y1="161.2" x2="338.0" y2="161.2" stroke="#2563eb" stroke-width="1" stroke-dasharray="5 4"/>
<line x1="68.0" y1="208.8" x2="338.0" y2="208.8" stroke="#2563eb" stroke-width="1" stroke-dasharray="5 4"/>
<polyline points="68.0,185.0 69.9,182.9 71.9,180.7 73.8,178.6 75.8,176.6 77.7,174.6 79.7,172.7 81.6,170.9 83.5,169.3 85.5,167.7 87.4,166.3 89.4,165.1 91.3,164.0 93.3,163.1 95.2,162.3 97.1,161.8 99.1,161.4 101.0,161.3 103.0,161.3 104.9,161.5 106.8,161.9 108.8,162.5 110.7,163.3 112.7,164.2 114.6,165.4 116.6,166.7 118.5,168.1 120.4,169.7 122.4,171.4 124.3,173.2 126.3,175.1 128.2,177.1 130.2,179.2 132.1,181.3 134.0,183.4 136.0,185.5 137.9,187.7 139.9,189.8 141.8,191.9 143.8,193.9 145.7,195.9 147.6,197.7 149.6,199.5 151.5,201.1 153.5,202.6 155.4,204.0 157.4,205.2 159.3,206.3 161.2,207.1 163.2,207.8 165.1,208.3 167.1,208.6 169.0,208.8 170.9,208.7 172.9,208.4 174.8,208.0 176.8,207.3 178.7,206.5 180.7,205.5 182.6,204.3 184.5,203.0 186.5,201.5 188.4,199.9 190.4,198.2 192.3,196.3 194.3,194.4 196.2,192.4 198.1,190.3 200.1,188.2 202.0,186.1 204.0,183.9 205.9,181.8 207.9,179.7 209.8,177.6 211.7,175.6 213.7,173.7 215.6,171.8 217.6,170.1 219.5,168.5 221.5,167.0 223.4,165.7 225.3,164.5 227.3,163.5 229.2,162.7 231.2,162.0 233.1,161.6 235.1,161.3 237.0,161.2 238.9,161.4 240.9,161.7 242.8,162.2 244.8,162.9 246.7,163.7 248.6,164.8 250.6,166.0 252.5,167.4 254.5,168.9 256.4,170.5 258.4,172.3 260.3,174.1 262.2,176.1 264.2,178.1 266.1,180.2 268.1,182.3 270.0,184.5 272.0,186.6 273.9,188.7 275.8,190.8 277.8,192.9 279.7,194.9 281.7,196.8 283.6,198.6 285.6,200.3 287.5,201.9 289.4,203.3 291.4,204.6 293.3,205.8 295.3,206.7 297.2,207.5 299.2,208.1 301.1,208.5 303.0,208.7 305.0,208.7 306.9,208.6 308.9,208.2 310.8,207.7 312.7,206.9 314.7,206.0 316.6,204.9 318.6,203.7 320.5,202.3 322.5,200.7 324.4,199.1 326.3,197.3 328.3,195.4 330.2,193.4 332.2,191.4 334.1,189.3 336.1,187.1 338.0,185.0" fill="none" stroke="#2563eb" stroke-width="2" stroke-linejoin="round"/>
<text x="68.0" y="151.0" font-size="10.5" fill="#64748b">峰 ±1.414 V · 基波 RMS 1.000 V</text>
<text x="58.0" y="244.0" font-size="11" font-weight="700" fill="#2563eb">注入</text>
<text x="94.0" y="244.0" font-size="11.5" fill="#64748b">UA(R31)端子侧,正弦 50.000 Hz、1.000 V</text>
<text x="94.0" y="260.0" font-size="11.5" fill="#64748b">rms</text>
<text x="58.0" y="280.0" font-size="11" font-weight="700" fill="#2563eb">判据</text>
<text x="94.0" y="280.0" font-size="11.5" fill="#0f172a">ua_mv 中位数 ≈ 万用表 × 1000,偏差 ≤2 %</text>
<text x="58.0" y="300.0" font-size="11" font-weight="700" fill="#2563eb">出口</text>
<text x="94.0" y="300.0" font-size="11.5" fill="#64748b">meas: ua_mv 为主;104 0x4011 只作交叉读</text>
<text x="94.0" y="316.0" font-size="11.5" fill="#64748b">数</text>
<rect x="372.0" y="106.0" width="314.0" height="246.0" rx="10" fill="#f0fdfa" stroke="#0d9488" stroke-width="2"/>
<text x="384.0" y="132.0" font-size="15" font-weight="700" fill="#0f172a">波形轮</text>
<text x="674.0" y="132.0" font-size="10.5" text-anchor="end" font-weight="700" fill="#0d9488">真 RMS ≠ 基波</text>
<rect x="384.0" y="142.0" width="290.0" height="86.0" rx="6" fill="#ffffff" stroke="#cbd5e1" stroke-width="1"/>
<line x1="394.0" y1="161.2" x2="664.0" y2="161.2" stroke="#94a3b8" stroke-width="0.9" stroke-dasharray="5 4"/>
<polyline points="400.0,185.0 400.7,182.5 401.3,180.0 402.0,177.6 402.6,175.3 403.3,173.0 403.9,170.9 404.6,169.0 405.2,167.2 405.9,165.7 406.6,164.3 407.2,163.2 407.9,162.3 408.5,161.7 409.2,161.3 409.8,161.2 410.5,161.4 411.1,161.8 411.8,162.5 412.5,163.5 413.1,164.6 413.8,166.0 414.4,167.7 415.1,169.5 415.7,171.4 416.4,173.6 417.0,175.8 417.7,178.2 418.4,180.6 419.0,183.1 419.7,185.6 420.3,188.1 421.0,190.6 421.6,193.0 422.3,195.3 422.9,197.5 423.6,199.6 424.3,201.5 424.9,203.2 425.6,204.7 426.2,206.0 426.9,207.0 427.5,207.9 428.2,208.4 428.8,208.7 429.5,208.7 430.2,208.5 430.8,208.0 431.5,207.3 432.1,206.3 432.8,205.0 433.4,203.6 434.1,201.9 434.7,200.1 435.4,198.0 436.1,195.9 436.7,193.6 437.4,191.2 438.0,188.7 438.7,186.3 439.3,183.7 440.0,181.3 440.6,178.8 441.3,176.4 441.9,174.1 442.6,172.0 443.3,169.9 443.9,168.1 444.6,166.4 445.2,165.0 445.9,163.7 446.5,162.7 447.2,162.0 447.8,161.5 448.5,161.3 449.2,161.3 449.8,161.6 450.5,162.1 451.1,163.0 451.8,164.0 452.4,165.3 453.1,166.8 453.7,168.5 454.4,170.4 455.1,172.5 455.7,174.7 456.4,177.0 457.0,179.4 457.7,181.9 458.3,184.4 459.0,186.9 459.6,189.4 460.3,191.8 461.0,194.2 461.6,196.4 462.3,198.6 462.9,200.5 463.6,202.3 464.2,204.0 464.9,205.4 465.5,206.5 466.2,207.5 466.9,208.2 467.5,208.6 468.2,208.8 468.8,208.7 469.5,208.3 470.1,207.7 470.8,206.8 471.4,205.7 472.1,204.3 472.8,202.8 473.4,201.0 474.1,199.1 474.7,197.0 475.4,194.7 476.0,192.4 476.7,190.0 477.3,187.5 478.0,185.0" fill="none" stroke="#0d9488" stroke-width="1.8" stroke-linejoin="round"/>
<text x="439.0" y="226.0" font-size="10.5" text-anchor="middle" fill="#64748b">正弦</text>
<polyline points="490.0,161.2 490.7,161.2 491.3,161.2 492.0,161.2 492.6,161.2 493.3,161.2 493.9,161.2 494.6,161.2 495.2,161.2 495.9,161.2 496.6,161.2 497.2,161.2 497.9,161.2 498.5,161.2 499.2,161.2 499.8,161.2 500.5,161.2 501.1,161.2 501.8,161.2 502.5,161.2 503.1,161.2 503.8,161.2 504.4,161.2 505.1,161.2 505.7,161.2 506.4,161.2 507.0,161.2 507.7,161.2 508.4,161.2 509.0,161.2 509.7,208.8 510.3,208.8 511.0,208.8 511.6,208.8 512.3,208.8 512.9,208.8 513.6,208.8 514.3,208.8 514.9,208.8 515.6,208.8 516.2,208.8 516.9,208.8 517.5,208.8 518.2,208.8 518.8,208.8 519.5,208.8 520.2,208.8 520.8,208.8 521.5,208.8 522.1,208.8 522.8,208.8 523.4,208.8 524.1,208.8 524.7,208.8 525.4,208.8 526.1,208.8 526.7,208.8 527.4,208.8 528.0,208.8 528.7,208.8 529.3,161.2 530.0,161.2 530.6,161.2 531.3,161.2 531.9,161.2 532.6,161.2 533.3,161.2 533.9,161.2 534.6,161.2 535.2,161.2 535.9,161.2 536.5,161.2 537.2,161.2 537.8,161.2 538.5,161.2 539.2,161.2 539.8,161.2 540.5,161.2 541.1,161.2 541.8,161.2 542.4,161.2 543.1,161.2 543.7,161.2 544.4,161.2 545.1,161.2 545.7,161.2 546.4,161.2 547.0,161.2 547.7,161.2 548.3,161.2 549.0,208.8 549.6,208.8 550.3,208.8 551.0,208.8 551.6,208.8 552.3,208.8 552.9,208.8 553.6,208.8 554.2,208.8 554.9,208.8 555.5,208.8 556.2,208.8 556.9,208.8 557.5,208.8 558.2,208.8 558.8,208.8 559.5,208.8 560.1,208.8 560.8,208.8 561.4,208.8 562.1,208.8 562.8,208.8 563.4,208.8 564.1,208.8 564.7,208.8 565.4,208.8 566.0,208.8 566.7,208.8 567.3,208.8 568.0,208.8" fill="none" stroke="#0d9488" stroke-width="1.8" stroke-linejoin="round"/>
<text x="529.0" y="226.0" font-size="10.5" text-anchor="middle" fill="#64748b">方波</text>
<polyline points="580.0,185.0 580.7,183.4 581.3,181.8 582.0,180.2 582.6,178.6 583.3,177.0 583.9,175.4 584.6,173.8 585.2,172.2 585.9,170.6 586.6,169.0 587.2,167.4 587.9,165.8 588.5,164.2 589.2,162.6 589.8,161.4 590.5,163.0 591.1,164.6 591.8,166.2 592.5,167.8 593.1,169.4 593.8,171.0 594.4,172.6 595.1,174.2 595.7,175.8 596.4,177.4 597.0,179.0 597.7,180.6 598.4,182.2 599.0,183.8 599.7,185.4 600.3,187.0 601.0,188.6 601.6,190.2 602.3,191.8 602.9,193.4 603.6,195.0 604.3,196.6 604.9,198.2 605.6,199.8 606.2,201.4 606.9,203.0 607.5,204.6 608.2,206.2 608.8,207.8 609.5,208.2 610.2,206.6 610.8,205.0 611.5,203.4 612.1,201.8 612.8,200.2 613.4,198.6 614.1,197.0 614.7,195.4 615.4,193.8 616.1,192.2 616.7,190.6 617.4,189.0 618.0,187.4 618.7,185.8 619.3,184.2 620.0,182.6 620.6,181.0 621.3,179.4 621.9,177.8 622.6,176.2 623.3,174.6 623.9,173.0 624.6,171.4 625.2,169.8 625.9,168.2 626.5,166.6 627.2,165.0 627.8,163.4 628.5,161.8 629.2,162.2 629.8,163.8 630.5,165.4 631.1,167.0 631.8,168.6 632.4,170.2 633.1,171.8 633.7,173.4 634.4,175.0 635.1,176.6 635.7,178.2 636.4,179.8 637.0,181.4 637.7,183.0 638.3,184.6 639.0,186.2 639.6,187.8 640.3,189.4 641.0,191.0 641.6,192.6 642.3,194.2 642.9,195.8 643.6,197.4 644.2,199.0 644.9,200.6 645.5,202.2 646.2,203.8 646.9,205.4 647.5,207.0 648.2,208.6 648.8,207.4 649.5,205.8 650.1,204.2 650.8,202.6 651.4,201.0 652.1,199.4 652.8,197.8 653.4,196.2 654.1,194.6 654.7,193.0 655.4,191.4 656.0,189.8 656.7,188.2 657.3,186.6 658.0,185.0" fill="none" stroke="#0d9488" stroke-width="1.8" stroke-linejoin="round"/>
<text x="619.0" y="226.0" font-size="10.5" text-anchor="middle" fill="#64748b">三角</text>
<text x="394.0" y="151.0" font-size="10.5" fill="#64748b">同峰值对齐(不是同 Vrms)</text>
<text x="384.0" y="244.0" font-size="11" font-weight="700" fill="#0d9488">注入</text>
<text x="420.0" y="244.0" font-size="11.5" fill="#64748b">同峰值 1.414 V 改方波 / 三角(面板有效值各</text>
<text x="420.0" y="260.0" font-size="11.5" fill="#64748b">异)</text>
<text x="384.0" y="280.0" font-size="11" font-weight="700" fill="#0d9488">判据</text>
<text x="420.0" y="280.0" font-size="11.5" fill="#0f172a">读数只跟基波:方波 ≈1278、三角 ≈817,±2 %</text>
<text x="384.0" y="300.0" font-size="11" font-weight="700" fill="#0d9488">出口</text>
<text x="420.0" y="300.0" font-size="11.5" fill="#64748b">meas: ua_mv;抬头记万用表响应类型</text>
<rect x="698.0" y="106.0" width="314.0" height="246.0" rx="10" fill="#f0fdf4" stroke="#16a34a" stroke-width="2"/>
<text x="710.0" y="132.0" font-size="15" font-weight="700" fill="#0f172a">相位轮</text>
<text x="1000.0" y="132.0" font-size="10.5" text-anchor="end" font-weight="700" fill="#16a34a">定量 · 取段</text>
<rect x="710.0" y="142.0" width="290.0" height="86.0" rx="6" fill="#ffffff" stroke="#cbd5e1" stroke-width="1"/>
<line x1="714.0" y1="185.0" x2="996.0" y2="185.0" stroke="#94a3b8" stroke-width="0.8" stroke-dasharray="3 3"/>
<polyline points="720.0,185.0 721.9,183.4 723.9,181.8 725.8,180.2 727.8,178.6 729.7,177.1 731.7,175.6 733.6,174.1 735.5,172.7 737.5,171.4 739.4,170.1 741.4,168.9 743.3,167.7 745.3,166.7 747.2,165.7 749.1,164.8 751.1,164.0 753.0,163.3 755.0,162.7 756.9,162.2 758.8,161.8 760.8,161.5 762.7,161.3 764.7,161.2 766.6,161.3 768.6,161.4 770.5,161.7 772.4,162.0 774.4,162.5 776.3,163.1 778.3,163.7 780.2,164.5 782.2,165.4 784.1,166.3 786.0,167.4 788.0,168.5 789.9,169.7 791.9,170.9 793.8,172.3 795.8,173.7 797.7,175.1 799.6,176.6 801.6,178.1 803.5,179.7 805.5,181.3 807.4,182.9 809.4,184.5 811.3,186.1 813.2,187.7 815.2,189.3 817.1,190.8 819.1,192.4 821.0,193.9 822.9,195.4 824.9,196.8 826.8,198.2 828.8,199.5 830.7,200.7 832.7,201.9 834.6,203.0 836.5,204.0 838.5,204.9 840.4,205.8 842.4,206.5 844.3,207.1 846.3,207.7 848.2,208.1 850.1,208.4 852.1,208.6 854.0,208.7 856.0,208.7 857.9,208.6 859.9,208.4 861.8,208.1 863.7,207.7 865.7,207.1 867.6,206.5 869.6,205.8 871.5,204.9 873.5,204.0 875.4,203.0 877.3,201.9 879.3,200.7 881.2,199.5 883.2,198.2 885.1,196.8 887.1,195.4 889.0,193.9 890.9,192.4 892.9,190.8 894.8,189.3 896.8,187.7 898.7,186.1 900.6,184.5 902.6,182.9 904.5,181.3 906.5,179.7 908.4,178.1 910.4,176.6 912.3,175.1 914.2,173.7 916.2,172.3 918.1,170.9 920.1,169.7 922.0,168.5 924.0,167.4 925.9,166.3 927.8,165.4 929.8,164.5 931.7,163.7 933.7,163.1 935.6,162.5 937.6,162.0 939.5,161.7 941.4,161.4 943.4,161.3 945.3,161.2 947.3,161.3 949.2,161.5 951.2,161.8 953.1,162.2 955.0,162.7 957.0,163.3 958.9,164.0 960.9,164.8 962.8,165.7 964.7,166.7 966.7,167.7 968.6,168.9 970.6,170.1 972.5,171.4 974.5,172.7 976.4,174.1 978.3,175.6 980.3,177.1 982.2,178.6 984.2,180.2 986.1,181.8 988.1,183.4 990.0,185.0" fill="none" stroke="#16a34a" stroke-width="2" stroke-linejoin="round"/>
<polyline points="720.0,161.2 721.9,161.3 723.9,161.5 725.8,161.7 727.8,162.1 729.7,162.6 731.7,163.2 733.6,163.9 735.5,164.7 737.5,165.5 739.4,166.5 741.4,167.5 743.3,168.7 745.3,169.9 747.2,171.2 749.1,172.5 751.1,173.9 753.0,175.4 755.0,176.8 756.9,178.4 758.8,179.9 760.8,181.5 762.7,183.1 764.7,184.7 766.6,186.3 768.6,187.9 770.5,189.5 772.4,191.1 774.4,192.6 776.3,194.2 778.3,195.6 780.2,197.0 782.2,198.4 784.1,199.7 786.0,200.9 788.0,202.1 789.9,203.2 791.9,204.2 793.8,205.1 795.8,205.9 797.7,206.6 799.6,207.2 801.6,207.7 803.5,208.2 805.5,208.5 807.4,208.7 809.4,208.8 811.3,208.7 813.2,208.6 815.2,208.4 817.1,208.0 819.1,207.6 821.0,207.0 822.9,206.4 824.9,205.6 826.8,204.8 828.8,203.8 830.7,202.8 832.7,201.7 834.6,200.5 836.5,199.3 838.5,197.9 840.4,196.6 842.4,195.1 844.3,193.7 846.3,192.1 848.2,190.6 850.1,189.0 852.1,187.4 854.0,185.8 856.0,184.2 857.9,182.6 859.9,181.0 861.8,179.4 863.7,177.9 865.7,176.3 867.6,174.9 869.6,173.4 871.5,172.1 873.5,170.7 875.4,169.5 877.3,168.3 879.3,167.2 881.2,166.2 883.2,165.2 885.1,164.4 887.1,163.6 889.0,163.0 890.9,162.4 892.9,162.0 894.8,161.6 896.8,161.4 898.7,161.3 900.6,161.2 902.6,161.3 904.5,161.5 906.5,161.8 908.4,162.3 910.4,162.8 912.3,163.4 914.2,164.1 916.2,164.9 918.1,165.8 920.1,166.8 922.0,167.9 924.0,169.1 925.9,170.3 927.8,171.6 929.8,173.0 931.7,174.4 933.7,175.8 935.6,177.4 937.6,178.9 939.5,180.5 941.4,182.1 943.4,183.7 945.3,185.3 947.3,186.9 949.2,188.5 951.2,190.1 953.1,191.6 955.0,193.2 957.0,194.6 958.9,196.1 960.9,197.5 962.8,198.8 964.7,200.1 966.7,201.3 968.6,202.5 970.6,203.5 972.5,204.5 974.5,205.3 976.4,206.1 978.3,206.8 980.3,207.4 982.2,207.9 984.2,208.3 986.1,208.5 988.1,208.7 990.0,208.8" fill="none" stroke="#e11d48" stroke-width="1.6" stroke-linejoin="round" stroke-dasharray="6 4"/>
<text x="720.0" y="226.0" font-size="10.5" font-weight="700" fill="#16a34a">UA 0° 实线</text>
<text x="798.0" y="226.0" font-size="10.5" font-weight="700" fill="#e11d48">UN +90° 红虚线</text>
<text x="710.0" y="244.0" font-size="11" font-weight="700" fill="#16a34a">注入</text>
<text x="746.0" y="244.0" font-size="11.5" fill="#64748b">UA(R31)与 UN(R28)同源同幅 1.000 Vrms</text>
<text x="710.0" y="264.0" font-size="11" font-weight="700" fill="#16a34a">判据</text>
<text x="746.0" y="264.0" font-size="11.5" fill="#0f172a">同段内相位差 ≈0°,B 通道改 90° 应跟到 ≈90</text>
<text x="746.0" y="280.0" font-size="11.5" fill="#0f172a">°,±2°</text>
<text x="710.0" y="300.0" font-size="11" font-weight="700" fill="#16a34a">出口</text>
<text x="746.0" y="300.0" font-size="11.5" fill="#64748b">wave_read.py fft 定量;phasor(hb) 只核</text>
<text x="746.0" y="316.0" font-size="11.5" fill="#64748b">象限</text>
<rect x="46.0" y="366.0" width="314.0" height="246.0" rx="10" fill="#fffbeb" stroke="#d97706" stroke-width="2"/>
<text x="58.0" y="392.0" font-size="15" font-weight="700" fill="#0f172a">测频轮</text>
<text x="348.0" y="392.0" font-size="10.5" text-anchor="end" font-weight="700" fill="#d97706">A 档无数 = 过</text>
<rect x="58.0" y="402.0" width="290.0" height="86.0" rx="6" fill="#ffffff" stroke="#cbd5e1" stroke-width="1"/>
<line x1="62.0" y1="445.0" x2="344.0" y2="445.0" stroke="#94a3b8" stroke-width="0.8" stroke-dasharray="3 3"/>
<polyline points="73.0,445.0 73.8,443.6 74.6,442.3 75.4,440.9 76.2,439.6 77.0,438.3 77.8,437.0 78.7,435.8 79.5,434.5 80.3,433.3 81.1,432.2 81.9,431.0 82.7,430.0 83.5,428.9 84.3,428.0 85.1,427.0 85.9,426.2 86.7,425.4 87.5,424.7 88.4,424.0 89.2,423.4 90.0,422.9 90.8,422.4 91.6,422.0 92.4,421.7 93.2,421.5 94.0,421.3 94.8,421.2 95.6,421.2 96.4,421.3 97.2,421.5 98.1,421.7 98.9,422.0 99.7,422.4 100.5,422.9 101.3,423.4 102.1,424.0 102.9,424.7 103.7,425.4 104.5,426.2 105.3,427.0 106.1,428.0 106.9,428.9 107.7,430.0 108.6,431.0 109.4,432.2 110.2,433.3 111.0,434.5 111.8,435.8 112.6,437.0 113.4,438.3 114.2,439.6 115.0,440.9 115.8,442.3 116.6,443.6 117.4,445.0 118.3,446.4 119.1,447.7 119.9,449.1 120.7,450.4 121.5,451.7 122.3,453.0 123.1,454.2 123.9,455.5 124.7,456.7 125.5,457.8 126.3,459.0 127.1,460.0 127.9,461.1 128.8,462.0 129.6,463.0 130.4,463.8 131.2,464.6 132.0,465.3 132.8,466.0 133.6,466.6 134.4,467.1 135.2,467.6 136.0,468.0 136.8,468.3 137.6,468.5 138.5,468.7 139.3,468.8 140.1,468.8 140.9,468.7 141.7,468.5 142.5,468.3 143.3,468.0 144.1,467.6 144.9,467.1 145.7,466.6 146.5,466.0 147.3,465.3 148.2,464.6 149.0,463.8 149.8,463.0 150.6,462.0 151.4,461.1 152.2,460.0 153.0,459.0" fill="none" stroke="#d97706" stroke-width="1.8" stroke-linejoin="round"/>
<text x="113.0" y="486.0" font-size="10.5" text-anchor="middle" fill="#64748b">45 Hz</text>
<polyline points="163.0,445.0 163.8,442.9 164.6,440.8 165.4,438.7 166.2,436.7 167.0,434.8 167.8,432.9 168.7,431.2 169.5,429.5 170.3,428.0 171.1,426.6 171.9,425.3 172.7,424.2 173.5,423.3 174.3,422.5 175.1,421.9 175.9,421.5 176.7,421.3 177.5,421.2 178.4,421.4 179.2,421.7 180.0,422.3 180.8,423.0 181.6,423.8 182.4,424.9 183.2,426.1 184.0,427.4 184.8,428.9 185.6,430.6 186.4,432.3 187.2,434.1 188.1,436.0 188.9,438.0 189.7,440.1 190.5,442.1 191.3,444.2 192.1,446.4 192.9,448.5 193.7,450.5 194.5,452.6 195.3,454.5 196.1,456.4 196.9,458.2 197.7,459.9 198.6,461.5 199.4,463.0 200.2,464.3 201.0,465.4 201.8,466.4 202.6,467.2 203.4,467.9 204.2,468.4 205.0,468.7 205.8,468.8 206.6,468.7 207.4,468.4 208.3,467.9 209.1,467.3 209.9,466.5 210.7,465.5 211.5,464.4 212.3,463.1 213.1,461.6 213.9,460.0 214.7,458.3 215.5,456.6 216.3,454.7 217.1,452.7 217.9,450.7 218.8,448.6 219.6,446.5 220.4,444.4 221.2,442.3 222.0,440.2 222.8,438.2 223.6,436.2 224.4,434.2 225.2,432.4 226.0,430.7 226.8,429.0 227.6,427.5 228.5,426.2 229.3,425.0 230.1,423.9 230.9,423.0 231.7,422.3 232.5,421.8 233.3,421.4 234.1,421.3 234.9,421.3 235.7,421.5 236.5,421.9 237.3,422.4 238.2,423.2 239.0,424.1 239.8,425.2 240.6,426.5 241.4,427.9 242.2,429.4 243.0,431.0" fill="none" stroke="#d97706" stroke-width="1.8" stroke-linejoin="round"/>
<text x="203.0" y="486.0" font-size="10.5" text-anchor="middle" fill="#64748b">50 Hz</text>
<polyline points="253.0,445.0 253.8,441.8 254.6,438.7 255.4,435.8 256.2,432.9 257.0,430.3 257.8,428.0 258.7,425.9 259.5,424.2 260.3,422.9 261.1,421.9 261.9,421.4 262.7,421.2 263.5,421.6 264.3,422.3 265.1,423.4 265.9,424.9 266.7,426.8 267.5,428.9 268.4,431.4 269.2,434.1 270.0,437.0 270.8,440.1 271.6,443.2 272.4,446.4 273.2,449.5 274.0,452.6 274.8,455.5 275.6,458.2 276.4,460.7 277.2,463.0 278.1,464.9 278.9,466.4 279.7,467.6 280.5,468.4 281.3,468.7 282.1,468.7 282.9,468.2 283.7,467.3 284.5,466.0 285.3,464.4 286.1,462.4 286.9,460.0 287.7,457.5 288.6,454.7 289.4,451.7 290.2,448.6 291.0,445.5 291.8,442.3 292.6,439.2 293.4,436.2 294.2,433.3 295.0,430.7 295.8,428.3 296.6,426.2 297.4,424.4 298.3,423.0 299.1,422.0 299.9,421.4 300.7,421.2 301.5,421.5 302.3,422.1 303.1,423.2 303.9,424.7 304.7,426.5 305.5,428.6 306.3,431.0 307.1,433.7 307.9,436.6 308.8,439.6 309.6,442.7 310.4,445.9 311.2,449.1 312.0,452.1 312.8,455.1 313.6,457.8 314.4,460.4 315.2,462.7 316.0,464.6 316.8,466.2 317.6,467.5 318.5,468.3 319.3,468.7 320.1,468.7 320.9,468.3 321.7,467.5 322.5,466.2 323.3,464.6 324.1,462.7 324.9,460.4 325.7,457.8 326.5,455.1 327.3,452.1 328.2,449.1 329.0,445.9 329.8,442.7 330.6,439.6 331.4,436.6 332.2,433.7 333.0,431.0" fill="none" stroke="#d97706" stroke-width="1.8" stroke-linejoin="round"/>
<text x="293.0" y="486.0" font-size="10.5" text-anchor="middle" fill="#64748b">55 Hz</text>
<text x="58.0" y="504.0" font-size="11" font-weight="700" fill="#d97706">注入</text>
<text x="94.0" y="504.0" font-size="11.5" fill="#64748b">UA 同幅值轮接法,扫 45 / 50 / 55 Hz</text>
<text x="58.0" y="524.0" font-size="11" font-weight="700" fill="#d97706">判据</text>
<text x="94.0" y="524.0" font-size="11.5" fill="#0f172a">A 档如实报不可测:valid=0、UI 显 --;报 5</text>
<text x="94.0" y="540.0" font-size="11.5" fill="#0f172a">0.00 反而是 bug</text>
<text x="58.0" y="560.0" font-size="11" font-weight="700" fill="#d97706">出口</text>
<text x="94.0" y="560.0" font-size="11.5" fill="#64748b">freq(hb) 0.01 Hz;UI Hz、104 0x401D</text>
<rect x="372.0" y="366.0" width="314.0" height="246.0" rx="10" fill="#fff1f2" stroke="#e11d48" stroke-width="2"/>
<text x="384.0" y="392.0" font-size="15" font-weight="700" fill="#0f172a">削顶轮</text>
<text x="674.0" y="392.0" font-size="10.5" text-anchor="end" font-weight="700" fill="#e11d48">负向 · 单独日志</text>
<rect x="384.0" y="402.0" width="290.0" height="86.0" rx="6" fill="#ffffff" stroke="#cbd5e1" stroke-width="1"/>
<line x1="394.0" y1="468.8" x2="664.0" y2="468.8" stroke="#e11d48" stroke-width="1.2" stroke-dasharray="5 4"/>
<polyline points="394.0,468.8 395.7,464.0 397.4,459.2 399.1,454.5 400.8,449.9 402.5,445.4 404.2,441.0 405.9,436.9 407.6,432.9 409.3,429.1 411.0,425.6 412.7,422.4 414.4,419.4 416.1,416.8 417.8,414.5 419.5,412.5 421.2,410.9 422.9,409.6 424.6,408.7 426.3,408.2 428.0,408.0 429.7,408.3 431.4,408.9 433.1,409.9 434.8,411.2 436.5,413.0 438.2,415.0 439.8,417.4 441.5,420.1 443.2,423.2 444.9,426.5 446.6,430.0 448.3,433.9 450.0,437.9 451.7,442.1 453.4,446.5 455.1,451.0 456.8,455.7 458.5,460.4 460.2,465.2 461.9,468.8 463.6,468.8 465.3,468.8 467.0,468.8 468.7,468.8 470.4,468.8 472.1,468.8 473.8,468.8 475.5,468.8 477.2,468.8 478.9,468.8 480.6,468.8 482.3,468.8 484.0,468.8 485.7,468.8 487.4,468.8 489.1,468.8 490.8,468.8 492.5,468.8 494.2,468.8 495.9,468.8 497.6,468.8 499.3,468.8 501.0,468.8 502.7,468.8 504.4,468.8 506.1,468.8 507.8,468.8 509.5,468.8 511.2,468.8 512.9,468.8 514.6,468.8 516.3,468.8 518.0,468.8 519.7,468.8 521.4,468.8 523.1,468.8 524.8,468.8 526.5,468.8 528.2,468.8 529.8,466.4 531.5,461.6 533.2,456.8 534.9,452.2 536.6,447.6 538.3,443.2 540.0,438.9 541.7,434.8 543.4,431.0 545.1,427.3 546.8,424.0 548.5,420.9 550.2,418.1 551.9,415.6 553.6,413.4 555.3,411.6 557.0,410.2 558.7,409.1 560.4,408.4 562.1,408.1 563.8,408.1 565.5,408.5 567.2,409.3 568.9,410.5 570.6,412.1 572.3,413.9 574.0,416.2 575.7,418.7 577.4,421.6 579.1,424.8 580.8,428.2 582.5,431.9 584.2,435.8 585.9,440.0 587.6,444.3 589.3,448.7 591.0,453.3 592.7,458.0 594.4,462.8 596.1,467.6 597.8,468.8 599.5,468.8 601.2,468.8 602.9,468.8 604.6,468.8 606.3,468.8 608.0,468.8 609.7,468.8 611.4,468.8 613.1,468.8 614.8,468.8 616.5,468.8 618.2,468.8 619.8,468.8 621.5,468.8 623.2,468.8 624.9,468.8 626.6,468.8 628.3,468.8 630.0,468.8 631.7,468.8 633.4,468.8 635.1,468.8 636.8,468.8 638.5,468.8 640.2,468.8 641.9,468.8 643.6,468.8 645.3,468.8 647.0,468.8 648.7,468.8 650.4,468.8 652.1,468.8 653.8,468.8 655.5,468.8 657.2,468.8 658.9,468.8 660.6,468.8 662.3,468.8 664.0,468.8" fill="none" stroke="#e11d48" stroke-width="2" stroke-linejoin="round"/>
<text x="394.0" y="411.0" font-size="10.5" fill="#64748b">负半周钉 0(贴下轨)</text>
<text x="384.0" y="504.0" font-size="11" font-weight="700" fill="#e11d48">注入</text>
<text x="420.0" y="504.0" font-size="11.5" fill="#64748b">UB(R52):DC −1.00 V 保持 ≥5 s,或 2.0 </text>
<text x="420.0" y="520.0" font-size="11.5" fill="#64748b">Hz 正弦</text>
<text x="384.0" y="540.0" font-size="11" font-weight="700" fill="#e11d48">判据</text>
<text x="420.0" y="540.0" font-size="11.5" fill="#0f172a">连续 20 拍贴底 → rail / edge 锁存 + 104 </text>
<text x="420.0" y="556.0" font-size="11.5" fill="#0f172a">该路 IV 清零;50 Hz 正弦不锁存 = 预期</text>
<text x="384.0" y="576.0" font-size="11" font-weight="700" fill="#e11d48">出口</text>
<text x="420.0" y="576.0" font-size="11.5" fill="#64748b">cal: rail / edge;取段再跑 shape 对表</text>
<rect x="698.0" y="366.0" width="314.0" height="246.0" rx="10" fill="#f5f3ff" stroke="#7c3aed" stroke-width="2"/>
<text x="710.0" y="392.0" font-size="15" font-weight="700" fill="#0f172a">谐波轮</text>
<text x="1000.0" y="392.0" font-size="10.5" text-anchor="end" font-weight="700" fill="#7c3aed">定量 · 取段</text>
<rect x="710.0" y="402.0" width="290.0" height="86.0" rx="6" fill="#ffffff" stroke="#cbd5e1" stroke-width="1"/>
<line x1="714.0" y1="445.0" x2="996.0" y2="445.0" stroke="#94a3b8" stroke-width="0.8" stroke-dasharray="3 3"/>
<polyline points="720.0,445.0 721.9,442.2 723.9,439.5 725.8,437.1 727.8,435.0 729.7,433.4 731.7,432.3 733.6,431.6 735.5,431.3 737.5,431.3 739.4,431.4 741.4,431.5 743.3,431.5 745.3,431.3 747.2,430.9 749.1,430.2 751.1,429.2 753.0,428.1 755.0,426.8 756.9,425.7 758.8,424.7 760.8,424.0 762.7,423.7 764.7,423.8 766.6,424.4 768.6,425.5 770.5,427.0 772.4,428.8 774.4,430.7 776.3,432.7 778.3,434.5 780.2,436.0 782.2,437.2 784.1,438.0 786.0,438.5 788.0,438.6 789.9,438.4 791.9,438.0 793.8,437.7 795.8,437.4 797.7,437.4 799.6,437.7 801.6,438.4 803.5,439.4 805.5,440.8 807.4,442.5 809.4,444.4 811.3,446.3 813.2,448.1 815.2,449.7 817.1,451.0 819.1,451.9 821.0,452.5 822.9,452.6 824.9,452.5 826.8,452.2 828.8,451.8 830.7,451.5 832.7,451.4 834.6,451.6 836.5,452.2 838.5,453.1 840.4,454.5 842.4,456.1 844.3,458.0 846.3,459.9 848.2,461.8 850.1,463.5 852.1,464.9 854.0,465.8 856.0,466.3 857.9,466.3 859.9,465.8 861.8,465.0 863.7,464.0 865.7,462.8 867.6,461.6 869.6,460.5 871.5,459.6 873.5,458.9 875.4,458.6 877.3,458.5 879.3,458.5 881.2,458.7 883.2,458.7 885.1,458.6 887.1,458.2 889.0,457.3 890.9,456.1 892.9,454.3 894.8,452.2 896.8,449.7 898.7,446.9 900.6,444.0 902.6,441.2 904.5,438.6 906.5,436.3 908.4,434.4 910.4,433.0 912.3,432.1 914.2,431.5 916.2,431.3 918.1,431.3 920.1,431.4 922.0,431.5 924.0,431.5 925.9,431.2 927.8,430.7 929.8,429.9 931.7,428.8 933.7,427.6 935.6,426.4 937.6,425.3 939.5,424.4 941.4,423.8 943.4,423.7 945.3,424.0 947.3,424.8 949.2,426.0 951.2,427.6 953.1,429.4 955.0,431.4 957.0,433.3 958.9,435.0 960.9,436.5 962.8,437.5 964.7,438.2 966.7,438.5 968.6,438.5 970.6,438.3 972.5,437.9 974.5,437.6 976.4,437.4 978.3,437.4 980.3,437.9 982.2,438.7 984.2,439.8 986.1,441.4 988.1,443.1 990.0,445.0" fill="none" stroke="#7c3aed" stroke-width="2" stroke-linejoin="round"/>
<text x="720.0" y="411.0" font-size="10.5" fill="#64748b">基波 + 2 次 + 5 次</text>
<text x="710.0" y="504.0" font-size="11" font-weight="700" fill="#7c3aed">注入</text>
<text x="746.0" y="504.0" font-size="11.5" fill="#64748b">IA(R19):基波 0.800 + 二次 0.160 + 五</text>
<text x="746.0" y="520.0" font-size="11.5" fill="#64748b">次 0.160 Vrms</text>
<text x="710.0" y="540.0" font-size="11" font-weight="700" fill="#7c3aed">判据</text>
<text x="746.0" y="540.0" font-size="11.5" fill="#0f172a">Ia2 / Ia5 各 ≈0.160 Vrms,±2 %(最坏峰值</text>
<text x="746.0" y="556.0" font-size="11.5" fill="#0f172a"> 1.58 V 留余量)</text>
<text x="710.0" y="576.0" font-size="11" font-weight="700" fill="#7c3aed">出口</text>
<text x="746.0" y="576.0" font-size="11.5" fill="#64748b">wave_read.py fft --ch 4;UI Ia2 / Ia5 </text>
<text x="746.0" y="592.0" font-size="11.5" fill="#64748b">目检旁证</text>
<line x1="46.0" y1="634.0" x2="1014.0" y2="634.0" stroke="#cbd5e1" stroke-width="1"/>
<text x="46.0" y="656.0" font-size="13" fill="#64748b">顺序与耗时见 §8.6(约 135 min 一趟 session);[ERR] 判读见 §8.7,失败先查 §8.8 分诊表。波形缩略图只表形状,不代表真实幅度刻度。</text>
</svg>

After

Width:  |  Height:  |  Size: 26 KiB

+100
View File
@@ -0,0 +1,100 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1060" height="566" viewBox="0 0 1060 566" font-family="Microsoft YaHei, Segoe UI, PingFang SC, sans-serif">
<rect x="0" y="0" width="1060" height="566" fill="#ffffff"/>
<text x="46.0" y="42.0" font-size="21" font-weight="700" fill="#0f172a">交流轮为什么连取 10 行、取中位数 —— 机理与操作</text>
<text x="46.0" y="68.0" font-size="12.5" fill="#64748b">meas: 是瞬时基波有效值透传:200 ms 是上送节拍、不是平均窗(数据可信 §4.5)——单行可能恰好抓到波峰或波谷,毛刺行会拖偏算术平均,中位数对两头都钝感</text>
<text x="46.0" y="146.0" font-size="13.5" font-weight="700" fill="#0f172a">机理:窗定宽 20 拍,截到的相位逐窗滑动</text>
<polyline points="46.0,276.0 47.7,272.1 49.5,268.3 51.2,264.4 53.0,260.6 54.7,256.8 56.5,253.1 58.2,249.5 60.0,245.9 61.7,242.4 63.5,239.0 65.2,235.7 66.9,232.5 68.7,229.4 70.4,226.5 72.2,223.7 73.9,221.0 75.7,218.5 77.4,216.1 79.2,213.9 80.9,211.9 82.7,210.1 84.4,208.4 86.1,206.9 87.9,205.6 89.6,204.5 91.4,203.6 93.1,202.9 94.9,202.4 96.6,202.1 98.4,202.0 100.1,202.1 101.9,202.4 103.6,202.9 105.3,203.6 107.1,204.5 108.8,205.6 110.6,206.9 112.3,208.4 114.1,210.1 115.8,211.9 117.6,213.9 119.3,216.1 121.1,218.5 122.8,221.0 124.5,223.7 126.3,226.5 128.0,229.4 129.8,232.5 131.5,235.7 133.3,239.0 135.0,242.4 136.8,245.9 138.5,249.5 140.3,253.1 142.0,256.8 143.7,260.6 145.5,264.4 147.2,268.3 149.0,272.1 150.7,276.0 152.5,279.9 154.2,283.7 156.0,287.6 157.7,291.4 159.5,295.2 161.2,298.9 162.9,302.5 164.7,306.1 166.4,309.6 168.2,313.0 169.9,316.3 171.7,319.5 173.4,322.6 175.2,325.5 176.9,328.3 178.7,331.0 180.4,333.5 182.1,335.9 183.9,338.1 185.6,340.1 187.4,341.9 189.1,343.6 190.9,345.1 192.6,346.4 194.4,347.5 196.1,348.4 197.9,349.1 199.6,349.6 201.3,349.9 203.1,350.0 204.8,349.9 206.6,349.6 208.3,349.1 210.1,348.4 211.8,347.5 213.6,346.4 215.3,345.1 217.1,343.6 218.8,341.9 220.5,340.1 222.3,338.1 224.0,335.9 225.8,333.5 227.5,331.0 229.3,328.3 231.0,325.5 232.8,322.6 234.5,319.5 236.3,316.3 238.0,313.0 239.7,309.6 241.5,306.1 243.2,302.5 245.0,298.9 246.7,295.2 248.5,291.4 250.2,287.6 252.0,283.7 253.7,279.9 255.5,276.0 257.2,272.1 258.9,268.3 260.7,264.4 262.4,260.6 264.2,256.8 265.9,253.1 267.7,249.5 269.4,245.9 271.2,242.4 272.9,239.0 274.7,235.7 276.4,232.5 278.1,229.4 279.9,226.5 281.6,223.7 283.4,221.0 285.1,218.5 286.9,216.1 288.6,213.9 290.4,211.9 292.1,210.1 293.9,208.4 295.6,206.9 297.3,205.6 299.1,204.5 300.8,203.6 302.6,202.9 304.3,202.4 306.1,202.1 307.8,202.0 309.6,202.1 311.3,202.4 313.1,202.9 314.8,203.6 316.5,204.5 318.3,205.6 320.0,206.9 321.8,208.4 323.5,210.1 325.3,211.9 327.0,213.9 328.8,216.1 330.5,218.5 332.3,221.0 334.0,223.7 335.7,226.5 337.5,229.4 339.2,232.5 341.0,235.7 342.7,239.0 344.5,242.4 346.2,245.9 348.0,249.5 349.7,253.1 351.5,256.8 353.2,260.6 354.9,264.4 356.7,268.3 358.4,272.1 360.2,276.0 361.9,279.9 363.7,283.7 365.4,287.6 367.2,291.4 368.9,295.2 370.7,298.9 372.4,302.5 374.1,306.1 375.9,309.6 377.6,313.0 379.4,316.3 381.1,319.5 382.9,322.6 384.6,325.5 386.4,328.3 388.1,331.0 389.9,333.5 391.6,335.9 393.3,338.1 395.1,340.1 396.8,341.9 398.6,343.6 400.3,345.1 402.1,346.4 403.8,347.5 405.6,348.4 407.3,349.1 409.1,349.6 410.8,349.9 412.5,350.0 414.3,349.9 416.0,349.6 417.8,349.1 419.5,348.4 421.3,347.5 423.0,346.4 424.8,345.1 426.5,343.6 428.3,341.9 430.0,340.1" fill="none" stroke="#334155" stroke-width="1.8" stroke-linejoin="round"/>
<rect x="46.0" y="186.0" width="174.5" height="180.0" rx="6" fill="none" stroke="#2563eb" stroke-width="1.8"/>
<text x="50.0" y="180.0" font-size="10.5" font-weight="700" fill="#2563eb">窗 A</text>
<rect x="220.5" y="186.0" width="174.5" height="180.0" rx="6" fill="none" stroke="#e11d48" stroke-width="1.4"/>
<text x="224.5" y="180.0" font-size="10.5" font-weight="700" fill="#e11d48">窗 B(下一行心跳)</text>
<line x1="46.0" y1="374.0" x2="46.0" y2="380.0" stroke="#94a3b8" stroke-width="0.8"/>
<line x1="54.7" y1="374.0" x2="54.7" y2="380.0" stroke="#94a3b8" stroke-width="0.8"/>
<line x1="63.5" y1="374.0" x2="63.5" y2="380.0" stroke="#94a3b8" stroke-width="0.8"/>
<line x1="72.2" y1="374.0" x2="72.2" y2="380.0" stroke="#94a3b8" stroke-width="0.8"/>
<line x1="80.9" y1="374.0" x2="80.9" y2="380.0" stroke="#94a3b8" stroke-width="0.8"/>
<line x1="89.6" y1="374.0" x2="89.6" y2="380.0" stroke="#94a3b8" stroke-width="0.8"/>
<line x1="98.4" y1="374.0" x2="98.4" y2="380.0" stroke="#94a3b8" stroke-width="0.8"/>
<line x1="107.1" y1="374.0" x2="107.1" y2="380.0" stroke="#94a3b8" stroke-width="0.8"/>
<line x1="115.8" y1="374.0" x2="115.8" y2="380.0" stroke="#94a3b8" stroke-width="0.8"/>
<line x1="124.5" y1="374.0" x2="124.5" y2="380.0" stroke="#94a3b8" stroke-width="0.8"/>
<line x1="133.3" y1="374.0" x2="133.3" y2="380.0" stroke="#94a3b8" stroke-width="0.8"/>
<line x1="142.0" y1="374.0" x2="142.0" y2="380.0" stroke="#94a3b8" stroke-width="0.8"/>
<line x1="150.7" y1="374.0" x2="150.7" y2="380.0" stroke="#94a3b8" stroke-width="0.8"/>
<line x1="159.5" y1="374.0" x2="159.5" y2="380.0" stroke="#94a3b8" stroke-width="0.8"/>
<line x1="168.2" y1="374.0" x2="168.2" y2="380.0" stroke="#94a3b8" stroke-width="0.8"/>
<line x1="176.9" y1="374.0" x2="176.9" y2="380.0" stroke="#94a3b8" stroke-width="0.8"/>
<line x1="185.6" y1="374.0" x2="185.6" y2="380.0" stroke="#94a3b8" stroke-width="0.8"/>
<line x1="194.4" y1="374.0" x2="194.4" y2="380.0" stroke="#94a3b8" stroke-width="0.8"/>
<line x1="203.1" y1="374.0" x2="203.1" y2="380.0" stroke="#94a3b8" stroke-width="0.8"/>
<line x1="211.8" y1="374.0" x2="211.8" y2="380.0" stroke="#94a3b8" stroke-width="0.8"/>
<line x1="220.5" y1="374.0" x2="220.5" y2="380.0" stroke="#94a3b8" stroke-width="0.8"/>
<line x1="229.3" y1="374.0" x2="229.3" y2="380.0" stroke="#94a3b8" stroke-width="0.8"/>
<line x1="238.0" y1="374.0" x2="238.0" y2="380.0" stroke="#94a3b8" stroke-width="0.8"/>
<line x1="246.7" y1="374.0" x2="246.7" y2="380.0" stroke="#94a3b8" stroke-width="0.8"/>
<line x1="255.5" y1="374.0" x2="255.5" y2="380.0" stroke="#94a3b8" stroke-width="0.8"/>
<line x1="264.2" y1="374.0" x2="264.2" y2="380.0" stroke="#94a3b8" stroke-width="0.8"/>
<line x1="272.9" y1="374.0" x2="272.9" y2="380.0" stroke="#94a3b8" stroke-width="0.8"/>
<line x1="281.6" y1="374.0" x2="281.6" y2="380.0" stroke="#94a3b8" stroke-width="0.8"/>
<line x1="290.4" y1="374.0" x2="290.4" y2="380.0" stroke="#94a3b8" stroke-width="0.8"/>
<line x1="299.1" y1="374.0" x2="299.1" y2="380.0" stroke="#94a3b8" stroke-width="0.8"/>
<line x1="307.8" y1="374.0" x2="307.8" y2="380.0" stroke="#94a3b8" stroke-width="0.8"/>
<line x1="316.5" y1="374.0" x2="316.5" y2="380.0" stroke="#94a3b8" stroke-width="0.8"/>
<line x1="325.3" y1="374.0" x2="325.3" y2="380.0" stroke="#94a3b8" stroke-width="0.8"/>
<line x1="334.0" y1="374.0" x2="334.0" y2="380.0" stroke="#94a3b8" stroke-width="0.8"/>
<line x1="342.7" y1="374.0" x2="342.7" y2="380.0" stroke="#94a3b8" stroke-width="0.8"/>
<line x1="351.5" y1="374.0" x2="351.5" y2="380.0" stroke="#94a3b8" stroke-width="0.8"/>
<line x1="360.2" y1="374.0" x2="360.2" y2="380.0" stroke="#94a3b8" stroke-width="0.8"/>
<line x1="368.9" y1="374.0" x2="368.9" y2="380.0" stroke="#94a3b8" stroke-width="0.8"/>
<line x1="377.6" y1="374.0" x2="377.6" y2="380.0" stroke="#94a3b8" stroke-width="0.8"/>
<line x1="386.4" y1="374.0" x2="386.4" y2="380.0" stroke="#94a3b8" stroke-width="0.8"/>
<line x1="395.1" y1="374.0" x2="395.1" y2="380.0" stroke="#94a3b8" stroke-width="0.8"/>
<line x1="46.0" y1="380.0" x2="454.0" y2="380.0" stroke="#cbd5e1" stroke-width="1"/>
<text x="454.0" y="394.0" font-size="10.5" text-anchor="end" fill="#64748b">拍(1 kHz)</text>
<text x="46.0" y="410.0" font-size="11.5" fill="#64748b">发生器频率与 1 kHz 时基不严格同步:每过一个窗,尾部多算 / 少算一小段 →</text>
<text x="46.0" y="428.0" font-size="11.5" fill="#64748b">基波值围绕真值上下小幅摆动(拍频式)→ 每一行心跳落在摆动带的不同位置</text>
<text x="522.0" y="146.0" font-size="13.5" font-weight="700" fill="#0f172a">操作:这 10 行里取哪个数当代表</text>
<line x1="522.0" y1="172.0" x2="522.0" y2="402.0" stroke="#334155" stroke-width="1.6"/>
<line x1="522.0" y1="402.0" x2="864.0" y2="402.0" stroke="#334155" stroke-width="1.6"/>
<line x1="518.0" y1="387.2" x2="864.0" y2="387.2" stroke="#cbd5e1" stroke-width="0.8"/>
<text x="514.0" y="391.2" font-size="10.5" text-anchor="end" fill="#64748b">990</text>
<line x1="518.0" y1="343.0" x2="864.0" y2="343.0" stroke="#e2e8f0" stroke-width="0.8"/>
<text x="514.0" y="347.0" font-size="10.5" text-anchor="end" fill="#64748b">1000</text>
<line x1="518.0" y1="298.8" x2="864.0" y2="298.8" stroke="#e2e8f0" stroke-width="0.8"/>
<text x="514.0" y="302.8" font-size="10.5" text-anchor="end" fill="#64748b">1010</text>
<line x1="518.0" y1="210.5" x2="864.0" y2="210.5" stroke="#e2e8f0" stroke-width="0.8"/>
<text x="514.0" y="214.5" font-size="10.5" text-anchor="end" fill="#64748b">1030</text>
<text x="514.0" y="168.0" font-size="10.5" text-anchor="end" fill="#64748b">ua_mv</text>
<line x1="528.0" y1="343.0" x2="864.0" y2="343.0" stroke="#64748b" stroke-width="1.2" stroke-dasharray="6 4"/>
<text x="872.0" y="358.0" font-size="10.5" fill="#64748b">真值(万用表 × 1000)</text>
<line x1="528.0" y1="336.4" x2="864.0" y2="336.4" stroke="#16a34a" stroke-width="2.4"/>
<text x="872.0" y="333.4" font-size="10.5" font-weight="700" fill="#16a34a">中位数 1001.5 ← 本条取它</text>
<line x1="528.0" y1="327.1" x2="864.0" y2="327.1" stroke="#2563eb" stroke-width="1.4" stroke-dasharray="2 3"/>
<text x="872.0" y="307.1" font-size="10.5" fill="#2563eb">平均 1003.6(被拖高)</text>
<circle cx="546.0" cy="351.8" r="3.6" fill="#334155"/>
<text x="546.0" y="418.0" font-size="10.5" text-anchor="middle" fill="#64748b">1</text>
<circle cx="579.6" cy="329.8" r="3.6" fill="#334155"/>
<text x="579.6" y="418.0" font-size="10.5" text-anchor="middle" fill="#64748b">2</text>
<circle cx="613.1" cy="360.7" r="3.6" fill="#334155"/>
<text x="613.1" y="418.0" font-size="10.5" text-anchor="middle" fill="#64748b">3</text>
<circle cx="646.7" cy="338.6" r="3.6" fill="#334155"/>
<text x="646.7" y="418.0" font-size="10.5" text-anchor="middle" fill="#64748b">4</text>
<circle cx="680.2" cy="347.4" r="3.6" fill="#334155"/>
<text x="680.2" y="418.0" font-size="10.5" text-anchor="middle" fill="#64748b">5</text>
<circle cx="713.8" cy="316.5" r="3.6" fill="#334155"/>
<text x="713.8" y="418.0" font-size="10.5" text-anchor="middle" fill="#64748b">6</text>
<circle cx="747.3" cy="356.2" r="3.6" fill="#334155"/>
<text x="747.3" y="418.0" font-size="10.5" text-anchor="middle" fill="#64748b">7</text>
<circle cx="780.9" cy="325.3" r="3.6" fill="#334155"/>
<text x="780.9" y="418.0" font-size="10.5" text-anchor="middle" fill="#64748b">8</text>
<circle cx="814.4" cy="334.2" r="3.6" fill="#334155"/>
<text x="814.4" y="418.0" font-size="10.5" text-anchor="middle" fill="#64748b">9</text>
<circle cx="848.0" cy="210.5" r="4.6" fill="#e11d48"/>
<text x="848.0" y="418.0" font-size="10.5" text-anchor="middle" fill="#64748b">10</text>
<text x="848.0" y="200.5" font-size="10.5" text-anchor="middle" font-weight="700" fill="#e11d48">毛刺行</text>
<text x="546.0" y="436.0" font-size="10.5" fill="#64748b">心跳行号(每行间隔 200 ms)</text>
<line x1="497.0" y1="120.0" x2="497.0" y2="452.0" stroke="#cbd5e1" stroke-width="1"/>
<text x="46.0" y="462.0" font-size="11.5" font-weight="700" fill="#0f172a">操作:稳定 ≥30 s 后,把连续 10 行心跳的 ua_mv 记进记录表(备注顺手记跳动区间 min–max),排序取第 5、6 个的平均 = 本条代表数;偏差 % 用它对万用表 × 1000。</text>
<line x1="46.0" y1="502.0" x2="1014.0" y2="502.0" stroke="#cbd5e1" stroke-width="1"/>
<text x="46.0" y="522.0" font-size="12.5" fill="#64748b">非整 50 Hz 时 meas: 来回跳是预期(§8.8 分诊同一条);扫频时读 freq(hb),别读 meas:。左图频差为示意刻意夸大,实拍跳动只有几个 LSB 的量级。</text>
</svg>

After

Width:  |  Height:  |  Size: 12 KiB

@@ -291,6 +291,10 @@ TPAFE 是双极性、二进制补码,可以注负压;STM32 是单极性,
>
> **引用写法**:本节凡引用判据文档的小节,一律写成「文件名 + 小节号」的紧邻形式;只写 §8.x 的是本文自己的节。
先下图建立全局轮廓——每一轮注什么波形、验什么、读哪个出口,再进 §8.5 逐轮执行卡:
![六轮一图速查:注入信号形状 → 接法与设定 → 判据一句话 → 主读数出口;过判据属主在 数据可信.md §4.6.2](../../images/交流六轮速查.svg)
### 8.1 动手前先把出口分辨率算清楚(决定今天能判到哪一档)
这一轮和直流轮次**不一样:样本出口已经有了**。2026-10-29 故障录波的数据面并入主干,一次触发就是一段
@@ -369,6 +373,18 @@ TPAFE 是双极性、二进制补码,可以注负压;STM32 是单极性,
4. **电流通道也是注电压**:`IA` 的注入点同样是电压进 R19 端子侧。这一轮证的是"给定引脚电压算得对不对",
不是"一次侧 1 A 怎么办"——后者要变比,属 `docs/任务规划/数据可信.md` §5 的端子 / 子板变比确认。
四条接线画在一张图上(发生器 → 端子侧焊盘是一条主干,万用表并接、共地是两条必须存在的旁路):
```mermaid
flowchart LR
G["信号发生器<br/>输出端接 = 高阻<br/>(按 50 Ω 端接读数差 2 倍)"] -->|"注 UA / UN / IA:端子侧焊盘<br/>(1:1 已由直流轮次实测)"| R31["串阻 1 k 的 1 脚侧<br/>R31 / R28 / R19 …"]
R31 --> FE["前端分压 / 滤波"] --> U5["U5 排针 → 转换器引脚<br/>(TPAFE AIN_x 或 STM32 脚)"]
M["万用表 AC 档<br/>记响应类型"] -.->|"并接同一注入点<br/>量真实加到板上的电压"| R31
G -.->|"LO/GND 与板 AGND<br/>单点共地"| AGND["板 AGND"]
AGND -->|"不共地量到的是两地之差"| U5
G -.->|"注 UB 等 STM32 那五路(仅削顶轮)<br/>负半周经片内钳位 ≈1.1 mA"| R52["R52 端子侧"] --> STM["STM32 ADC 脚<br/>(无外置钳位 / 隔直电容)"]
```
### 8.4 记录表抬头(每条用例一份,与日志一起归档)
```text
@@ -389,6 +405,31 @@ TPAFE 是双极性、二进制补码,可以注负压;STM32 是单极性,
**瞬时基波有效值透传**、200 ms 是上送节拍不是平均窗(`docs/任务规划/数据可信.md` §4.5),
单行读数带拍频式跳动,必须看一片取**中间水平(中位数)**才能定数。
通用动作主干与两处分岔(采集链没清 → 回头修;偏差没进 → 先复核查再判):
```mermaid
flowchart TD
W["接好本路,开机前置门已过(§8.2)"] --> ON["开发生器输出"]
ON --> ST["等 ≥30 s:相量窗与 meas 轨稳定"]
ST --> HB["取连续 ≥10 行心跳"]
HB --> Q1{"frames 在涨、adc1_err = 0 ?"}
Q1 -->|"否:是节拍 / 丢帧问题"| TRI["先查 §8.8 分诊<br/>别归因给波形"]
TRI -.->|"修复后重来"| ST
Q1 -->|是| MED["10 行读数排序<br/>取第 5、6 个的平均 = 中位数"]
MED --> Q2{"与期望的偏差在判据内?"}
Q2 -->|是| OK["记通过"]
Q2 -->|"否"| CHK["先复核查:发生器端接、<br/>万用表响应类型、共地"]
CHK -->|"复查仍超"| BAD["记不通过,进 §8.8 分诊"]
CHK -->|"查出问题改完重测"| ST
OK --> OFF["关输出,填记录表"]
BAD --> OFF
OFF --> NEXT["下一条 / 下一轮"]
```
为什么这一步是"中位数"而不是单行或平均——机理与操作:
![为什么连取 10 行取中位数:窗滑动让读数拍频式上下跳(左);中位数贴着密集簇,平均被毛刺拖走(右)](../../images/交流定数取中位数.svg)
#### 幅值轮:基波幅值(主用例,先做)
| 项 | 内容 |
+2
View File
@@ -25,6 +25,8 @@
| `gen_sample_ring_why_svg.py` | 采样环缓冲_为什么需要 | 上游 1 kHz 覆盖写只交最新一帧 vs 下游要 20 点滑窗:缺口 19 点与三个消费者 |
| `gen_sample_ring_layout_svg.py` | 采样环缓冲_环形布局 | 40 格环里哪 20 格是本窗、写指针指「下一格」、回绕与三条设计不变量 |
| `gen_sample_ring_start_svg.py` | 采样环缓冲_窗首下标 | 窗首 = head − n 的圆周走法,与「直接减 / 16 位回绕 / 先加 DEPTH」三种写法对照 |
| `gen_ac_rounds_svg.py` | 交流六轮速查 | 执行手册 §8 六轮总览卡:每轮注什么波形(正弦/方波三角/异相/扫频/削顶/谐波叠加缩略图)、判据一句话、主读数出口 |
| `gen_ac_median_svg.py` | 交流定数取中位数 | 「连取 10 行取中位数」的机理(全周窗滑动 → 读数拍频跳)与操作(中位数 vs 平均 vs 单行对真值)两栏数值示意 |
## 使用方式
+274
View File
@@ -0,0 +1,274 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""生成 docs/images/交流定数取中位数.svg —— 交流轮为什么必须「连取 10 行心跳、取中位数」:
左半讲机理(全周窗逐拍滑动 → 单行带拍频跳动),右半讲操作(10 行里任何单行都可能撞
波峰波谷、毛刺行拖偏算术平均,中位数对两头都钝感)。
为什么不用 Mermaid:本图是两幅带刻度的数值示意图(正弦 + 窗框、散点 + 三条水平基准线),
坐标与数值就是语义本身;Mermaid 只能画盒子和箭头,画不出「中位数线贴着密集簇、
平均线被毛刺拽走」这个高度差对比。
用法(仓库根目录,任意 python3):
python tools/arch_diagram/gen_ac_median_svg.py
输出:
docs/images/交流定数取中位数.svg
改内容:`vals` / 文案变了才重跑;调坐标编辑下方常量。数值一律硬编码,保证逐字节幂等。
"""
import html
import math
import os
import sys
import xml.etree.ElementTree as ET
def emit(s):
"""控制台打印按目标编码替换,绝不因 GBK 终端遇上 −/≈ 之类字符而崩
(generated-fresh 钩子会把本脚本拷进临时目录重跑,崩了就是一片假红)。"""
enc = getattr(sys.stdout, "encoding", None) or "ascii"
sys.stdout.write(s.encode(enc, "replace").decode(enc, "replace") + "\n")
ROOT = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
OUT = os.path.join(ROOT, "docs", "images", "交流定数取中位数.svg")
# ----------------------------- 画布与尺寸 -----------------------------
W = 1060
H = 566
PAD = 46
RIGHT = W - PAD
FONT = "Microsoft YaHei, Segoe UI, PingFang SC, sans-serif"
TITLE_FONT = 21
SUB_FONT = 12.5
HEAD_FONT = 13.5
BODY_FONT = 11.5
TINY_FONT = 10.5
INK = "#0f172a"
LINE = "#334155"
MUTED = "#64748b"
FAINT = "#94a3b8"
RULE = "#cbd5e1"
WHITE = "#ffffff"
C_BLUE = "#2563eb"
BG_BLUE = "#eff6ff"
C_GREEN = "#16a34a"
C_ROSE = "#e11d48"
BG_ROSE = "#fff1f2"
C_AMBER = "#d97706"
# ----------------------------- 数据(改这里) -----------------------------
TITLE = "交流轮为什么连取 10 行、取中位数 —— 机理与操作"
SUB1 = ("meas: 是瞬时基波有效值透传:200 ms 是上送节拍、不是平均窗(数据可信 §4.5)——"
"单行可能恰好抓到波峰或波谷,毛刺行会拖偏算术平均,中位数对两头都钝感")
# 十行 ua_mv(1 mV 分辨率):第 9 行是偶发毛刺行
VALS = [998, 1003, 996, 1001, 999, 1006, 997, 1004, 1002, 1030]
GLITCH_I = 9
TRUE_V = 1000.0
YLO, YHI = 988.0, 1036.0
OPS_NOTE = ("操作:稳定 ≥30 s 后,把连续 10 行心跳的 ua_mv 记进记录表(备注顺手记跳动区间 min–max),"
"排序取第 5、6 个的平均 = 本条代表数;偏差 % 用它对万用表 × 1000。")
FOOTNOTE = ("非整 50 Hz 时 meas: 来回跳是预期(§8.8 分诊同一条);扫频时读 freq(hb),别读 meas:。"
"左图频差为示意刻意夸大,实拍跳动只有几个 LSB 的量级。")
# ----------------------------- 布局 -----------------------------
LPX, LPW = PAD, 424 # 左面板(机理)
RPX, RPW = 522, RIGHT - 522 # 右面板(操作)
PLOT_T, PLOT_B = 176.0, 404.0
HDR_Y = 146.0
# ----------------------------- 工具函数 -----------------------------
def esc(s):
return html.escape(s, quote=True)
def text_w(s, fs):
"""粗略估算文本像素宽:CJK/全角 ≈ 1.0em,其余 ≈ 0.58em(宁可偏大)。"""
return sum(fs * (1.0 if ord(ch) >= 0x2E80 else 0.58) for ch in s)
OVERFLOW = []
def check_fit(s, fs, avail, where):
if text_w(s, fs) > avail:
OVERFLOW.append("%s: %.0f > %.0f [%s]" % (where, text_w(s, fs), avail, s))
def txt(x, y, s, fs, fill, weight=400, anchor=None):
a = "" if anchor is None else ' text-anchor="%s"' % anchor
w = "" if weight == 400 else ' font-weight="%d"' % weight
return ('<text x="%.1f" y="%.1f" font-size="%g"%s%s fill="%s">%s</text>'
% (x, y, fs, a, w, fill, esc(s)))
def line(x1, y1, x2, y2, color=LINE, width=2.0, dash=None):
d = "" if dash is None else ' stroke-dasharray="%s"' % dash
return ('<line x1="%.1f" y1="%.1f" x2="%.1f" y2="%.1f" stroke="%s" stroke-width="%g"%s/>'
% (x1, y1, x2, y2, color, width, d))
def rect(x, y, w, h, fill, stroke=None, rx=8, sw=1.6):
s = "" if stroke is None else ' stroke="%s" stroke-width="%g"' % (stroke, sw)
return '<rect x="%.1f" y="%.1f" width="%.1f" height="%.1f" rx="%g" fill="%s"%s/>' % (
x, y, w, h, rx, fill, s)
def poly(pts, color, sw=2.0, dash=None):
d = "" if dash is None else ' stroke-dasharray="%s"' % dash
p = " ".join("%.1f,%.1f" % (x, y) for x, y in pts)
return ('<polyline points="%s" fill="none" stroke="%s" stroke-width="%g" '
'stroke-linejoin="round"%s/>' % (p, color, sw, d))
def wrap(s, fs, avail, max_lines, where=""):
if text_w(s, fs) <= avail:
return [s]
lines = []
cur = ""
for ch in s:
if text_w(cur + ch, fs) > avail:
lines.append(cur)
cur = ch
else:
cur += ch
if cur:
lines.append(cur)
if len(lines) > max_lines:
OVERFLOW.append("%s: 折行 %d > %d" % (where, len(lines), max_lines))
lines = lines[:max_lines]
lines[max_lines - 1] = lines[max_lines - 1][:-1] + "…"
return lines
# ----------------------------- 左:窗滑动机理 -----------------------------
def mechanism():
out = []
add = out.append
x0, x1 = LPX, LPX + LPW - 40
per = 24.0 # 示意:信号周期 24 拍(真实约 20 拍;频差夸大)
win = 20.0 # 全周窗固定 20 拍
tmax = 44.0
def X(t):
return x0 + (x1 - x0) * t / tmax
yc = (PLOT_T + PLOT_B) / 2 - 14
amp = 74.0
add(txt(LPX, HDR_Y, "机理:窗定宽 20 拍,截到的相位逐窗滑动", HEAD_FONT, INK, weight=700))
# 信号
pts = []
for i in range(221):
t = 44.0 * i / 220.0
pts.append((X(t), yc - amp * math.sin(2 * math.pi * t / per)))
add(poly(pts, LINE, 1.8))
# 两个窗
for (t0, c, dash, name) in ((0.0, C_BLUE, None, "窗 A"),
(20.0, C_ROSE, "6 4", "窗 B(下一行心跳)")):
add(rect(X(t0), yc - amp - 16, X(t0 + win) - X(t0), 2 * amp + 32, "none", c, rx=6,
sw=1.8 if dash is None else 1.4))
add(txt(X(t0) + 4, yc - amp - 22, name, TINY_FONT, c, weight=700))
# 拍刻度(每拍一根,只在窗内画,避免刷屏)
for k in range(0, 41):
add(line(X(k), PLOT_B - 30, X(k), PLOT_B - 24, FAINT, 0.8))
add(line(x0, PLOT_B - 24, x1 + 24, PLOT_B - 24, RULE, 1.0))
add(txt(x1 + 24, PLOT_B - 10, "拍(1 kHz)", TINY_FONT, MUTED, anchor="end"))
# 尾部相位差说明
add(txt(x0, PLOT_B + 6,
"发生器频率与 1 kHz 时基不严格同步:每过一个窗,尾部多算 / 少算一小段 →",
BODY_FONT, MUTED))
add(txt(x0, PLOT_B + 24,
"基波值围绕真值上下小幅摆动(拍频式)→ 每一行心跳落在摆动带的不同位置",
BODY_FONT, MUTED))
return out
# ----------------------------- 右:取数操作 -----------------------------
def operation():
out = []
add = out.append
add(txt(RPX, HDR_Y, "操作:这 10 行里取哪个数当代表", HEAD_FONT, INK, weight=700))
ax0, ax1 = RPX, RPX + RPW - 150
ay0, ay1 = PLOT_T + 8, PLOT_B - 8
def Y(v):
return ay1 - (v - YLO) / (YHI - YLO) * (ay1 - ay0)
def X(i):
return ax0 + 24 + i * ((ax1 - ax0 - 40) / 9.0)
add(line(ax0, ay0 - 12, ax0, ay1 + 6, LINE, 1.6))
add(line(ax0, ay1 + 6, ax1, ay1 + 6, LINE, 1.6))
for v in (990, 1000, 1010, 1030):
add(line(ax0 - 4, Y(v), ax1, Y(v), "#e2e8f0" if v != 990 else RULE, 0.8))
add(txt(ax0 - 8, Y(v) + 4, str(v), TINY_FONT, MUTED, anchor="end"))
add(txt(ax0 - 8, ay0 - 16, "ua_mv", TINY_FONT, MUTED, anchor="end"))
srt = sorted(VALS)
med = (srt[4] + srt[5]) / 2.0
mean = sum(VALS) / float(len(VALS))
# 三条水平基准:右侧标签逐条错开(线位太近,同高必叠字)
lx = ax1 + 8
add(line(ax0 + 6, Y(TRUE_V), ax1, Y(TRUE_V), MUTED, 1.2, dash="6 4"))
add(txt(lx, Y(TRUE_V) + 15, "真值(万用表 × 1000)", TINY_FONT, MUTED))
check_fit("真值(万用表 × 1000)", TINY_FONT, RIGHT - lx, "lbl true")
add(line(ax0 + 6, Y(med), ax1, Y(med), C_GREEN, 2.4))
add(txt(lx, Y(med) - 3, "中位数 %g ← 本条取它" % med, TINY_FONT, C_GREEN, weight=700))
check_fit("中位数 %g ← 本条取它" % med, TINY_FONT, RIGHT - lx, "lbl med")
add(line(ax0 + 6, Y(mean), ax1, Y(mean), C_BLUE, 1.4, dash="2 3"))
add(txt(lx, Y(mean) - 20, "平均 %g(被拖高)" % mean, TINY_FONT, C_BLUE))
check_fit("平均 %g(被拖高)" % mean, TINY_FONT, RIGHT - lx, "lbl mean")
# 十个点
for i, v in enumerate(VALS):
c = C_ROSE if i == GLITCH_I else LINE
r = 4.6 if i == GLITCH_I else 3.6
add('<circle cx="%.1f" cy="%.1f" r="%.1f" fill="%s"/>' % (X(i), Y(v), r, c))
add(txt(X(i), ay1 + 22, str(i + 1), TINY_FONT, MUTED, anchor="middle"))
add(txt(X(GLITCH_I), Y(VALS[GLITCH_I]) - 10, "毛刺行", TINY_FONT, C_ROSE, weight=700,
anchor="middle"))
add(txt(ax0 + 24, ay1 + 40, "心跳行号(每行间隔 200 ms)", TINY_FONT, MUTED))
return out
# ----------------------------- 生成 -----------------------------
def build():
avail = RIGHT - PAD
check_fit(TITLE, TITLE_FONT, avail, "title")
check_fit(SUB1, SUB_FONT, avail, "sub1")
out = ['<rect x="0" y="0" width="%d" height="%d" fill="%s"/>' % (W, H, WHITE)]
out.append(txt(PAD, 42, TITLE, TITLE_FONT, INK, weight=700))
out.append(txt(PAD, 68, SUB1, SUB_FONT, MUTED))
out.extend(mechanism())
out.extend(operation())
# 竖向分隔
out.append(line(497.0, 120.0, 497.0, 452.0, RULE, 1.0))
ny = 462
for i, ln in enumerate(wrap(OPS_NOTE, BODY_FONT, avail, 2, "ops")):
out.append(txt(PAD, ny + i * 17, ln, BODY_FONT, INK, weight=700))
fy = ny + 40
out.append(line(PAD, fy, RIGHT, fy, RULE, 1.0))
for i, ln in enumerate(wrap(FOOTNOTE, SUB_FONT, avail, 2, "foot")):
out.append(txt(PAD, fy + 20 + i * 18, ln, SUB_FONT, MUTED))
svg = ('<svg xmlns="http://www.w3.org/2000/svg" width="%d" height="%d" '
'viewBox="0 0 %d %d" font-family="%s">\n%s\n</svg>\n'
% (W, H, W, H, FONT, "\n".join(out)))
d = os.path.dirname(OUT)
if not os.path.isdir(d):
os.makedirs(d)
with open(OUT, "w", encoding="utf-8", newline="\n") as fp:
fp.write(svg)
ET.fromstring(svg)
emit("OK %d bytes, canvas %dx%d -> %s" % (len(svg.encode("utf-8")), W, H, OUT))
if OVERFLOW:
for o in OVERFLOW:
emit("OVERFLOW WARN " + o)
emit("!! %d overflow warnings" % len(OVERFLOW))
if __name__ == "__main__":
build()
+323
View File
@@ -0,0 +1,323 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""生成 docs/images/交流六轮速查.svg —— 交流(正弦)动态验证六轮:每一轮注什么信号、
验什么、主读数走哪个出口,一张图先给全局轮廓,再进 §8.5 逐轮执行卡。
为什么不用 Mermaid:本图的语义重心是「每轮注入信号的波形形状」与「三块小面板里
信号缩略图 + 判据 + 出口的固定排版对位」——Mermaid 画不出正弦/方波/三角/削顶/谐波
叠加这些波形,也无法把六格对齐成 3x2 卡片。它只适合关系拓扑(那部分另在
docs/测试说明/专项验证/ADC前端注入验证流程.md §8.3 / §8.5 用 Mermaid 表达)。
用法(仓库根目录,任意 python3):
python tools/arch_diagram/gen_ac_rounds_svg.py
输出:
docs/images/交流六轮速查.svg
改内容:轮次事实(接法 / 判据 / 出口)变了才重画;调坐标 / 文案编辑下方常量后重跑。
"""
import html
import math
import os
import sys
import xml.etree.ElementTree as ET
def emit(s):
"""控制台打印按目标编码替换,绝不因 GBK 终端遇上 ≤/≈ 之类字符而崩
(generated-fresh 钩子会把本脚本拷进临时目录重跑,崩了就是一片假红)。"""
enc = getattr(sys.stdout, "encoding", None) or "ascii"
sys.stdout.write(s.encode(enc, "replace").decode(enc, "replace") + "\n")
ROOT = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
OUT = os.path.join(ROOT, "docs", "images", "交流六轮速查.svg")
# ----------------------------- 画布与尺寸 -----------------------------
W = 1060
H = 680
PAD = 46
RIGHT = W - PAD
FONT = "Microsoft YaHei, Segoe UI, PingFang SC, sans-serif"
TITLE_FONT = 21
SUB_FONT = 13
HEAD_FONT = 15
LABEL_FONT = 11
BODY_FONT = 11.5
TINY_FONT = 10.5
INK = "#0f172a"
LINE = "#334155"
MUTED = "#64748b"
FAINT = "#94a3b8"
RULE = "#cbd5e1"
WHITE = "#ffffff"
C_BLUE = "#2563eb"
BG_BLUE = "#eff6ff"
C_TEAL = "#0d9488"
BG_TEAL = "#f0fdfa"
C_GREEN = "#16a34a"
BG_GREEN = "#f0fdf4"
C_AMBER = "#d97706"
BG_AMBER = "#fffbeb"
C_ROSE = "#e11d48"
BG_ROSE = "#fff1f2"
C_PURPLE = "#7c3aed"
BG_PURPLE = "#f5f3ff"
# ----------------------------- 布局 -----------------------------
COLS = 3
CW = 314
CH = 246
GAPX = 12
GAPY = 14
X0 = PAD
Y0 = 106
THUMB_H = 86
LABEL_W = 36 # 「注入 / 判据 / 出口」标签列宽
# ----------------------------- 数据(改这里) -----------------------------
TITLE = "交流动态验证六轮 —— 每一轮注什么信号、读哪个口"
SUB1 = ("一卡一轮:注入信号缩略图 → 接法与设定 → 判据一句话 → 主读数出口。"
"先看图建立全局轮廓,再按 §8.5 的对应执行卡逐轮跑")
SUB2 = ("六轮共用同一套接线与通用动作;过判据的属主是 docs/任务规划/数据可信.md §4.6.2,"
"本图只是导航,不含新判据")
# 每卡:(轮名, 角标, 主色, 底色, 波形类型, 注入, 判据, 出口)
CARDS = [
("幅值轮", "先做 · 主用例", C_BLUE, BG_BLUE, "amp",
"UA(R31)端子侧,正弦 50.000 Hz、1.000 Vrms",
"ua_mv 中位数 ≈ 万用表 × 1000,偏差 ≤2 %",
"meas: ua_mv 为主;104 0x4011 只作交叉读数"),
("波形轮", "真 RMS ≠ 基波", C_TEAL, BG_TEAL, "three",
"同峰值 1.414 V 改方波 / 三角(面板有效值各异)",
"读数只跟基波:方波 ≈1278、三角 ≈817,±2 %",
"meas: ua_mv;抬头记万用表响应类型"),
("相位轮", "定量 · 取段", C_GREEN, BG_GREEN, "phase",
"UA(R31)与 UN(R28)同源同幅 1.000 Vrms",
"同段内相位差 ≈0°,B 通道改 90° 应跟到 ≈90°,±2°",
"wave_read.py fft 定量;phasor(hb) 只核象限"),
("测频轮", "A 档无数 = 过", C_AMBER, BG_AMBER, "sweep",
"UA 同幅值轮接法,扫 45 / 50 / 55 Hz",
"A 档如实报不可测:valid=0、UI 显 --;报 50.00 反而是 bug",
"freq(hb) 0.01 Hz;UI Hz、104 0x401D"),
("削顶轮", "负向 · 单独日志", C_ROSE, BG_ROSE, "clip",
"UB(R52):DC −1.00 V 保持 ≥5 s,或 2.0 Hz 正弦",
"连续 20 拍贴底 → rail / edge 锁存 + 104 该路 IV 清零;50 Hz 正弦不锁存 = 预期",
"cal: rail / edge;取段再跑 shape 对表"),
("谐波轮", "定量 · 取段", C_PURPLE, BG_PURPLE, "harm",
"IA(R19):基波 0.800 + 二次 0.160 + 五次 0.160 Vrms",
"Ia2 / Ia5 各 ≈0.160 Vrms,±2 %(最坏峰值 1.58 V 留余量)",
"wave_read.py fft --ch 4;UI Ia2 / Ia5 目检旁证"),
]
FOOTNOTE = ("顺序与耗时见 §8.6(约 135 min 一趟 session);[ERR] 判读见 §8.7,失败先查 §8.8 分诊表。"
"波形缩略图只表形状,不代表真实幅度刻度。")
# ----------------------------- 工具函数 -----------------------------
def esc(s):
return html.escape(s, quote=True)
def text_w(s, fs):
"""粗略估算文本像素宽:CJK/全角/圈码/箭头 ≈ 1.0em,其余 ≈ 0.58em(宁可偏大)。"""
return sum(fs * (1.0 if ord(ch) >= 0x2E80 else 0.58) for ch in s)
OVERFLOW = []
def check_fit(s, fs, avail, where):
if text_w(s, fs) > avail:
OVERFLOW.append("%s: %.0f > %.0f [%s]" % (where, text_w(s, fs), avail, s))
def txt(x, y, s, fs, fill, weight=400, anchor=None):
a = "" if anchor is None else ' text-anchor="%s"' % anchor
w = "" if weight == 400 else ' font-weight="%d"' % weight
return ('<text x="%.1f" y="%.1f" font-size="%g"%s%s fill="%s">%s</text>'
% (x, y, fs, a, w, fill, esc(s)))
def line(x1, y1, x2, y2, color=LINE, width=2.0, dash=None):
d = "" if dash is None else ' stroke-dasharray="%s"' % dash
return ('<line x1="%.1f" y1="%.1f" x2="%.1f" y2="%.1f" stroke="%s" stroke-width="%g"%s/>'
% (x1, y1, x2, y2, color, width, d))
def rect(x, y, w, h, fill, stroke=None, rx=8, sw=1.6):
s = "" if stroke is None else ' stroke="%s" stroke-width="%g"' % (stroke, sw)
return '<rect x="%.1f" y="%.1f" width="%.1f" height="%.1f" rx="%g" fill="%s"%s/>' % (
x, y, w, h, rx, fill, s)
def poly(pts, color, sw=2.0, dash=None):
d = "" if dash is None else ' stroke-dasharray="%s"' % dash
p = " ".join("%.1f,%.1f" % (x, y) for x, y in pts)
return ('<polyline points="%s" fill="none" stroke="%s" stroke-width="%g" '
'stroke-linejoin="round"%s/>' % (p, color, sw, d))
def wrap(s, fs, avail, max_lines, where=""):
"""按估算宽度折行(CJK 逐字可断)。超出 max_lines 用省略号收尾——
宁可提示文案太长,也不让字溢出盒子。"""
if text_w(s, fs) <= avail:
return [s]
lines = []
cur = ""
for ch in s:
if text_w(cur + ch, fs) > avail:
lines.append(cur)
cur = ch
else:
cur += ch
if cur:
lines.append(cur)
if len(lines) > max_lines:
OVERFLOW.append("%s: 折行 %d > %d" % (where, len(lines), max_lines))
lines = lines[:max_lines]
lines[max_lines - 1] = lines[max_lines - 1][:-1] + "…"
return lines
# ----------------------------- 波形缩略图 -----------------------------
def _sample(fv, x, y0, w, h, n=140):
"""把 [-1,1] 的值函数 fv(t in 0..1) 画进框 (x, y0, w, h)。"""
yc = y0 + h / 2.0
amp = h * 0.36
pts = []
for i in range(n):
t = float(i) / (n - 1)
pts.append((x + w * t, yc - amp * fv(t)))
return pts
def thumb(x, y, w, h, kind, c):
out = [rect(x, y, w, h, WHITE, RULE, rx=6, sw=1.0)]
pad = 10.0
ix, iw, ih = x + pad, w - 2 * pad, h - 2 * pad
if kind == "amp":
out.append(line(x + 4, y + h / 2, x + w - 4, y + h / 2, FAINT, 0.8, dash="3 3"))
yc = y + h / 2.0
amp = ih * 0.36
out.append(line(x + pad, yc - amp, x + w - pad, yc - amp, c, 1.0, dash="5 4"))
out.append(line(x + pad, yc + amp, x + w - pad, yc + amp, c, 1.0, dash="5 4"))
out.append(poly(_sample(lambda t: math.sin(2 * math.pi * 2 * t), ix, y + pad, iw, ih), c))
out.append(txt(x + pad, y + pad - 1, "峰 ±1.414 V · 基波 RMS 1.000 V", TINY_FONT, MUTED))
elif kind == "three":
yc = y + h / 2.0
amp = ih * 0.36
out.append(line(x + pad, yc - amp, x + w - pad, yc - amp, FAINT, 0.9, dash="5 4"))
slot = iw / 3.0
kinds = [lambda t: math.sin(4 * math.pi * t),
lambda t: 1.0 if math.sin(4 * math.pi * t) >= 0 else -1.0,
lambda t: (2.0 / math.pi) * math.asin(math.sin(4 * math.pi * t))]
names = ["正弦", "方波", "三角"]
for i, fv in enumerate(kinds):
sx = ix + i * slot
out.append(poly(_sample(fv, sx + 6, y + pad, slot - 12, ih, n=120), c, 1.8))
out.append(txt(sx + slot / 2, y + h - 2, names[i], TINY_FONT, MUTED, anchor="middle"))
out.append(txt(x + pad, y + pad - 1, "同峰值对齐(不是同 Vrms)", TINY_FONT, MUTED))
elif kind == "phase":
out.append(line(x + 4, y + h / 2, x + w - 4, y + h / 2, FAINT, 0.8, dash="3 3"))
out.append(poly(_sample(lambda t: math.sin(2 * math.pi * 1.5 * t), ix, y + pad, iw, ih),
c, 2.0))
out.append(poly(_sample(lambda t: math.sin(2 * math.pi * 1.5 * t + math.pi / 2),
ix, y + pad, iw, ih), C_ROSE, 1.6, dash="6 4"))
out.append(txt(x + pad, y + h - 2, "UA 0° 实线", TINY_FONT, c, weight=700))
out.append(txt(x + pad + 78, y + h - 2, "UN +90° 红虚线", TINY_FONT, C_ROSE, weight=700))
elif kind == "sweep":
out.append(line(x + 4, y + h / 2, x + w - 4, y + h / 2, FAINT, 0.8, dash="3 3"))
slot = iw / 3.0
cyc = [0.9, 1.4, 2.1]
labs = ["45 Hz", "50 Hz", "55 Hz"]
for i in range(3):
sx = ix + i * slot
out.append(poly(_sample(lambda t, cc=cyc[i]: math.sin(2 * math.pi * cc * t),
sx + 5, y + pad, slot - 10, ih, n=100), c, 1.8))
out.append(txt(sx + slot / 2, y + h - 2, labs[i], TINY_FONT, MUTED, anchor="middle"))
elif kind == "clip":
floor_y = y + pad + ih * 0.86
out.append(line(x + pad, floor_y, x + w - pad, floor_y, C_ROSE, 1.2, dash="5 4"))
yc = y + pad + ih * 0.40
amp = ih * 0.46
pts = []
n = 160
for i in range(n):
t = float(i) / (n - 1)
v = math.sin(2 * math.pi * 2 * t)
vv = max(v, 0.0) * 2.0 - 1.0
pts.append((ix + iw * t, yc - amp * vv))
out.append(poly(pts, c, 2.0))
out.append(txt(x + pad, y + pad - 1, "负半周钉 0(贴下轨)", TINY_FONT, MUTED))
elif kind == "harm":
out.append(line(x + 4, y + h / 2, x + w - 4, y + h / 2, FAINT, 0.8, dash="3 3"))
def fv(t):
w1 = 2 * math.pi * 1.5 * t
return (math.sin(w1) + 0.2 * math.sin(2 * w1) + 0.2 * math.sin(5 * w1)) / 1.35
out.append(poly(_sample(fv, ix, y + pad, iw, ih), c, 2.0))
out.append(txt(x + pad, y + pad - 1, "基波 + 2 次 + 5 次", TINY_FONT, MUTED))
return out
# ----------------------------- 生成 -----------------------------
def build():
out = []
add = out.append
avail = RIGHT - PAD
for s, fs, where in ((TITLE, TITLE_FONT, "title"), (SUB1, SUB_FONT, "sub1"),
(SUB2, SUB_FONT, "sub2")):
check_fit(s, fs, avail, where)
body_x = X0 + 12 + LABEL_W
body_avail = CW - 24 - LABEL_W
for idx, (name, tag, c, bg, kind, inj, rule, ex) in enumerate(CARDS):
cx = X0 + (idx % COLS) * (CW + GAPX)
cy = Y0 + (idx // COLS) * (CH + GAPY)
body_x = cx + 12 + LABEL_W
check_fit(name + tag, HEAD_FONT, CW - 24, "card %s head" % name)
for s, where in ((inj, "inj"), (rule, "rule"), (ex, "exit")):
check_fit(s[:14], BODY_FONT, body_avail, "card %s %s firstline" % (name, where))
add(rect(cx, cy, CW, CH, bg, c, rx=10, sw=2.0))
add(txt(cx + 12, cy + 26, name, HEAD_FONT, INK, weight=700))
add(txt(cx + CW - 12, cy + 26, tag, TINY_FONT, c, weight=700, anchor="end"))
for el in thumb(cx + 12, cy + 36, CW - 24, THUMB_H, kind, c):
add(el)
ty = cy + 36 + THUMB_H + 16
for label, s, mx in (("注入", inj, 2), ("判据", rule, 2), ("出口", ex, 2)):
add(txt(cx + 12, ty, label, LABEL_FONT, c, weight=700))
for ln in wrap(s, BODY_FONT, body_avail, mx, "card %s %s" % (name, label)):
add(txt(body_x, ty, ln, BODY_FONT, INK if label == "判据" else MUTED))
ty += 16
ty += 4
fy = Y0 + 2 * CH + GAPY + 22
add(line(PAD, fy, RIGHT, fy, RULE, 1.0))
for i, ln in enumerate(wrap(FOOTNOTE, SUB_FONT, avail, 2, "foot wrap")):
add(txt(PAD, fy + 22 + i * 19, ln, SUB_FONT, MUTED))
svg = ('<svg xmlns="http://www.w3.org/2000/svg" width="%d" height="%d" '
'viewBox="0 0 %d %d" font-family="%s">\n%s\n</svg>\n'
% (W, H, W, H, FONT, "\n".join(out)))
d = os.path.dirname(OUT)
if not os.path.isdir(d):
os.makedirs(d)
with open(OUT, "w", encoding="utf-8", newline="\n") as fp:
fp.write(svg)
ET.fromstring(svg)
emit("OK %d bytes, canvas %dx%d -> %s" % (len(svg.encode("utf-8")), W, H, OUT))
if OVERFLOW:
for o in OVERFLOW:
emit("OVERFLOW WARN " + o)
emit("!! %d overflow warnings" % len(OVERFLOW))
if __name__ == "__main__":
build()