114 行
4.8 KiB
Python
114 行
4.8 KiB
Python
# -*- 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())
|