R2 底板:按用户布局重布风扇窗口 + L1 走廊重开 + 位号丝印重排

布线(窗口整体重布,已下发):
- 拆窗口内 43 段(用户手布的那批,用户选「拆掉重来」),补 139 段 / 7 孔,
  GND 回流孔 10 个;fan_check 对板上真实快照逐项净距达标(含「新孔 vs 内层线」)。
- ⛔ 根因:pcb_base.PD_L1 里的 L1 走廊是按**旧摆位**开的(注释坐标全是旧的),
  用户重摆后与件对不上 ⇒ 四条长途网必然布不通。重开六条走廊后未完成 4 → 2。
  走廊必须盖住焊盘正上方,只盖沿途不行。断面:几何 11.80 / 铺铜后实测 9.82(要 8.0)。
- 与拆线前逐网对比:没引入任何新的连通性问题(GND 未接 58→48、+3V3 2→0、
  两路 TACH 2/1→0、+12V 一字不差)。

定版:板上铜以**用户自己布好的那版**为准,不再改动。

丝印(silk_base.py,已下发并读回核对 150/150):
- 压焊盘 128→4、压过孔 48→8、越框 8→3、互相重叠 34 对→0;字号不变。
- 三条坑:rotation 是度且不归一化(900=180°);别拿「本体≥5mm」当保留白名单
  (会豁免掉 R9A/D3/U13 这些该重排的件);「离本体」必须设硬上限 + 降级策略。

新工具:silk_base.py(丝印重排)、l1_section.py(L1 12V 主块逐 y 断面核算)、
fan_rip.py(按窗口拆线,拆前后比对全板线/孔总数防连带删除)。

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_0168Bu6SEx3cXXCJLkdnE6zB
这个提交包含在:
zhou yang
2026-09-12 12:02:32 +08:00
共同撰写人 Claude Opus 5
父节点 51b570a59f
当前提交 312089326e
共修改 15 个文件,包含 5053 行新增和 1139 行删除
+71
查看文件
@@ -0,0 +1,71 @@
# -*- coding: utf-8 -*-
u"""L1 `+12V` 主块的**逐 y 水平断面**核算(§6.4 要 ≥ 8.0 mm)。
/c/Python314/python .claude/r2/l1_section.py # 核 pcb_base.PD_L1 现状
/c/Python314/python .claude/r2/l1_section.py --cfg # 核 _base_window.json 里的 pd_l1_extra
主块 x 0.5~27.8(宽 27.30),电流南北流 ⇒ 断面是水平线,线上被走廊占掉的 x 跨度要扣掉。
横带(沿 x 长)很贵、竖带(沿 y 长)几乎免费 —— 旧注释「一根 0.15 的线占约 0.5」说的就是竖线。
槽指头在 x ≥ 27.5,走廊 x 一律 ≤ 27.5 ⇒ 天然不碰任何一槽的供电路径。
"""
import io
import json
import os
import sys
sys.stdout.reconfigure(encoding='utf-8')
HERE = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, os.path.dirname(HERE))
sys.path.insert(0, HERE)
import pcb_base as B # noqa: E402
MIN_SECTION = 8.0
MAIN = B.l1_12v_rects()[0]
WIDTH = MAIN[2] - MAIN[0]
def check(corridors, step=0.05):
worst = (1e9, None)
y = MAIN[1]
while y <= MAIN[3]:
iv = []
for _n, r in corridors:
if r[1] - 1e-9 <= y <= r[3] + 1e-9:
iv.append((max(r[0], MAIN[0]), min(r[2], MAIN[2])))
iv.sort()
used, spans = 0.0, []
for a, b in iv:
if b <= a:
continue
if spans and a <= spans[-1][1]:
spans[-1] = (spans[-1][0], max(spans[-1][1], b))
else:
spans.append((a, b))
for a, b in spans:
used += b - a
left = WIDTH - used
if left < worst[0]:
worst = (left, y)
y += step
return worst
def main():
cor = [(n, r) for n, r in B.PD_L1 if n.startswith('FAN')]
if '--cfg' in sys.argv:
cfg = json.load(io.open(os.path.join(HERE, '_base_window.json'), encoding='utf-8'))
cor = [(n, tuple(r)) for n, r in (cfg.get('pd_l1_extra') or [])]
print(u'主块 x %.2f~%.2f(宽 %.2f);走廊 %d 条' % (MAIN[0], MAIN[2], WIDTH, len(cor)))
for n, r in cor:
kind = u'横带' if (r[2] - r[0]) >= (r[3] - r[1]) else u'竖带'
print(u' %-14s (%6.2f, %6.2f, %6.2f, %6.2f) %5.2f×%5.2f %s'
% (n, r[0], r[1], r[2], r[3], r[2] - r[0], r[3] - r[1], kind))
left, y = check(cor)
ok = left >= MIN_SECTION
print(u'%s 逐 y 最窄断面 %.2f mm(y=%.2f),判据 ≥ %.1f' %
(u'[OK]' if ok else u'[X]', left, y, MIN_SECTION))
return 0 if ok else 1
if __name__ == '__main__':
sys.exit(main())