文件
phonerail/.claude/pcb1_usb_corridor.py
T

114 行
4.8 KiB
Python
原始文件 Blame 文件历史

此文件含有模棱两可的 Unicode 字符
此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。
# -*- coding: utf-8 -*-
u"""下板 PCB1:USB 差分对(U20 IO19/IO20 → J22)的**束走廊**在哪(纯本地,不碰桥接)。
/c/Python314/python .claude/pcb1_usb_corridor.py # 跑一遍 usb_pair() + 两层走廊图
/c/Python314/python .claude/pcb1_usb_corridor.py --a 104,25.18 --b 147,52 # 换束的两端锚点再试
`pcb1_route_sig.usb_pair()` 把 DP/DM 当**一整束**(2W+S = 0.74 mm)布一条中心线,
布不通就整对跳过。这里:
1. 原样调一次 `usb_pair()`,把它卡在哪打印出来;
2. 在 x 95~156 / y 15~58 开窗,按引擎判据算「0.74 的束能走的格」(顶层 / 底层各一张),
压成 0.5 mm 一格的 ASCII 图 —— 一眼看出哪条走廊是通的;
3. 束宽从 0.74 往下试(0.60 = 两根 0.20 + 对内 0.20),看走廊差多少。
⚠️ 只读本地缓存,`eda.run` 被换成抛异常的桩。
"""
import math
import os
import sys
HERE = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, HERE)
import eda # noqa: E402
def _blocked(*a, **k):
raise RuntimeError(u'pcb1_usb_corridor.py 是纯本地工具,禁止碰桥接')
eda.run = _blocked
eda.port = _blocked
import numpy as np # noqa: E402
import pcb1_route_sig as R # noqa: E402
E = R.E
L_TOP, L_BOT = R.L_TOP, R.L_BOT
WIN = (95.0, 15.0, 156.0, 58.0)
CELL = 0.5 # ASCII 图一格
def ascii_map(f, ok, vok, a, b, title):
print(u'\n%s (每格 %.1f mm;. 束能走 v 还能打孔 # 不能;A/B 束两端)' % (title, CELL))
step = int(round(CELL / f.g))
xs = [f.x0 + i * f.g for i in range(0, f.nx, step)]
print(u' ' + ''.join(('%-10d' % int(x)) if abs(x - round(x)) < 1e-6 and int(round(x)) % 5 == 0 else ' '
for x in xs)[:len(xs)])
for j in range(f.ny - 1, -1, -step):
y = f.y0 + j * f.g
row = []
for i in range(0, f.nx, step):
x = f.x0 + i * f.g
ch = '.' if ok[j, i] else '#'
if ok[j, i] and vok[j, i]:
ch = 'v'
if abs(x - a[0]) < CELL / 2 and abs(y - a[1]) < CELL / 2:
ch = 'A'
if abs(x - b[0]) < CELL / 2 and abs(y - b[1]) < CELL / 2:
ch = 'B'
row.append(ch)
print(u'%6.1f %s' % (y, ''.join(row)))
def main():
argv = sys.argv[1:]
a, b = R.USB_A, R.USB_B
if '--a' in argv:
a = tuple(float(v) for v in argv[argv.index('--a') + 1].split(','))
if '--b' in argv:
b = tuple(float(v) for v in argv[argv.index('--b') + 1].split(','))
pads, vias, lines = R.board(False)
pours = R.pour_rects()
obstacles = R.obstacles_of(pads, vias, lines, pours)
bytag = {p['tag']: p for p in pads}
print(u'板上 %d 焊盘 / %d 孔 / %d 线;束锚点 A%s B%s,束宽 %.2f(W %.2f / S %.2f)' % (
len(pads), len(vias), len(lines), a, b, 2 * R.USB_W + R.USB_S, R.USB_W, R.USB_S))
R.USB_A, R.USB_B = a, b
up = R.usb_pair(pads, obstacles, bytag)
print(u'usb_pair() 结果:%s' % (u'布通 %d 条' % len(up) if up else u'**没布通**(原因见上一行)'))
obs = [(s, n) for s, n in obstacles if n not in ('USB_DP', 'USB_DM')]
f = E.Field(obs, WIN, skip_net='USB_BUNDLE', grid=0.1)
vok = f.via_ok()
for wb in (0.74, 0.60, 0.50):
okt, okb = f.free(L_TOP, wb), f.free(L_BOT, wb)
nt, nb = int(okt.sum()), int(okb.sum())
print(u'\n束宽 %.2f:顶层可走格 %d / 底层 %d(窗 %d x %d)' % (wb, nt, nb, f.nx, f.ny))
if wb == 0.74:
ascii_map(f, okt, vok, a, b, u'顶层 L1,束宽 %.2f' % wb)
ascii_map(f, okb, vok, a, b, u'底层 L2,束宽 %.2f' % wb)
# 两层一起能不能从 A 走到 B
src = {L_TOP: np.zeros((f.ny, f.nx), bool), L_BOT: np.zeros((f.ny, f.nx), bool)}
tgt = {L_TOP: np.zeros((f.ny, f.nx), bool), L_BOT: np.zeros((f.ny, f.nx), bool)}
ia, ja = f._idx(a[0], a[1])
ib, jb = f._idx(b[0], b[1])
for L in (L_TOP, L_BOT):
src[L][max(0, ja - 3):ja + 4, max(0, ia - 3):ia + 4] = True
tgt[L][max(0, jb - 3):jb + 4, max(0, ib - 3):ib + 4] = True
cells = E.route_grid(f, src, tgt, wb)
if cells is None:
print(u' → A 到 B **不通**')
else:
pts = E._runs(cells)
ln = sum(math.hypot((q[0] - p[0]) * f.g, (q[1] - p[1]) * f.g) for p, q in zip(pts, pts[1:]))
nvia = sum(1 for p, q in zip(cells, cells[1:]) if p[2] != q[2])
print(u' → A 到 B 通:%.1f mm,换层 %d 次;折点:' % (ln, nvia))
print(u' ' + ' '.join('(%.1f,%.1f)L%d' % (f.x0 + i * f.g, f.y0 + j * f.g, lay) for i, j, lay in pts))
return 0
if __name__ == '__main__':
sys.exit(main())