111 行
4.3 KiB
Python
111 行
4.3 KiB
Python
# -*- coding: utf-8 -*-
|
||
u"""下板 PCB1:清掉 `C609` / `C612` 转 180° 之后留下的**接错脚的旧铜**。
|
||
|
||
/c/Python314/python .claude/pcb1_satflip_fix.py # 只列
|
||
/c/Python314/python .claude/pcb1_satflip_fix.py --push # 删 + 存盘 + 回查
|
||
|
||
## 怎么来的
|
||
|
||
`pcb1_place.SAT_FLIP` 把 C609 / C612(DAC63204 的 VREF 电容)转了 180°,
|
||
好让 VREF 脚朝南正对 U6.16 / U7.16(§26.22 的 A 类唯一几何解)。
|
||
转完两个脚**南北互换**,而板上那几段铜还是按旧朝向画的,于是:
|
||
|
||
| 旧铜 | 现在落在 | 后果 |
|
||
|---|---|---|
|
||
| GND 扇出短线(从电容南脚往南到 GND 过孔)| 南脚现在是 **`$6N532`/`$6N547`** | **GND 短到 VREF** |
|
||
| `$6N532`/`$6N547` 出线(从北脚往北去 U6.16)| 北脚现在是 **GND** | **VREF 短到 GND** |
|
||
|
||
⚠️ **这两条是真短路,不是 DRC 挑剔** —— 端点直接落在对方焊盘的轮廓里
|
||
(DRC 报「距离为 0mil」)。`pcb1_place.py` 里预告过「下发时要删 2 段扇出短线」,
|
||
就是这件事。
|
||
|
||
删完这四段之后:
|
||
* `$6N532` / `$6N547` 剩下的那截会变成悬空 → 跑 `pcb1_orphan_cu.py --push` 收掉;
|
||
* 两颗电容的 GND 脚没有扇出孔了 → 跑 `pcb_fanout.py --net GND --only C609,C612 --push`;
|
||
* VREF 那条 0.8 mm 的短连接交给 `pcb1_route_sig.py`。
|
||
"""
|
||
import json
|
||
import os
|
||
import sys
|
||
|
||
HERE = os.path.dirname(os.path.abspath(__file__))
|
||
sys.path.insert(0, HERE)
|
||
from eda import run
|
||
|
||
PCB = '7e9415a16a909c51'
|
||
MIL = 39.3700787
|
||
|
||
# (网络, 层, x0, y0, x1, y1, 为什么删)。坐标 mm,两端顺序无关,带 0.005 容差匹配。
|
||
DEAD = [
|
||
('GND', 1, 78.030, 40.277, 78.030, 39.608,
|
||
u'C609 的旧 GND 扇出短线;北端 40.277 落在 C609.2($6N532, y 40.205~40.745) 里 = 短路'),
|
||
('$6N532', 1, 78.031, 41.318, 78.031, 41.869,
|
||
u'C609 的旧 VREF 出线;南端 41.318 落在 C609.1(GND, y 41.045~41.586) 里 = 短路'),
|
||
('GND', 1, 108.021, 36.975, 108.021, 36.306,
|
||
u'C612 的旧 GND 扇出短线;北端落在 C612.2($6N547) 里 = 短路'),
|
||
('$6N547', 1, 108.022, 38.016, 108.022, 38.566,
|
||
u'C612 的旧 VREF 出线;南端落在 C612.1(GND) 里 = 短路'),
|
||
]
|
||
|
||
|
||
def call(js, timeout=300):
|
||
r = run(js, timeout=timeout)
|
||
if not r.get('success'):
|
||
raise RuntimeError(json.dumps(r, ensure_ascii=False)[:900])
|
||
return r['result']
|
||
|
||
|
||
JS = u"""
|
||
await eda.dmt_EditorControl.openDocument('%s');
|
||
await new Promise(r => setTimeout(r, 2000));
|
||
const MIL = %f, D = %s, PUSH = %s;
|
||
const TOL = 0.005;
|
||
const near = (a, b) => Math.abs(a - b) < TOL;
|
||
const same = (r, a, b, c, d) =>
|
||
(near(r[2], a) && near(r[3], b) && near(r[4], c) && near(r[5], d)) ||
|
||
(near(r[2], c) && near(r[3], d) && near(r[4], a) && near(r[5], b));
|
||
const found = [], ids = [];
|
||
for (const l of await eda.pcb_PrimitiveLine.getAll()) {
|
||
const net = l.net || '', lay = l.layer;
|
||
const a = l.startX/MIL, b = l.startY/MIL, c = l.endX/MIL, d = l.endY/MIL;
|
||
for (let k = 0; k < D.length; k++) {
|
||
const r = D[k];
|
||
if (r[0] === net && r[1] === lay && same(r, a, b, c, d)) {
|
||
found.push(k); ids.push(l.getState_PrimitiveId());
|
||
}
|
||
}
|
||
}
|
||
let deleted = 0;
|
||
if (PUSH) {
|
||
for (const id of ids) { await eda.pcb_PrimitiveLine.delete(id); deleted++; }
|
||
await eda.pcb_Document.save();
|
||
}
|
||
return {found, deleted, nLine: (await eda.pcb_PrimitiveLine.getAll()).length};
|
||
"""
|
||
|
||
|
||
def main():
|
||
push = '--push' in sys.argv
|
||
rows = [[d[0], d[1], d[2], d[3], d[4], d[5]] for d in DEAD]
|
||
r = call(JS % (PCB, MIL, json.dumps(rows), 'true' if push else 'false'))
|
||
hit = set(r['found'])
|
||
print(u'板上匹配到 %d / %d 段:' % (len(hit), len(DEAD)))
|
||
for k, d in enumerate(DEAD):
|
||
print(u' [%s] %-8s L%d (%7.3f,%6.3f)-(%7.3f,%6.3f)'
|
||
% ('✔' if k in hit else ' ', d[0], d[1], d[2], d[3], d[4], d[5]))
|
||
print(u' %s' % d[6])
|
||
if not push:
|
||
print(u'\n加 --push 删除并存盘')
|
||
return
|
||
print(u'\n已删 %d 段,板上还剩 %d 条导线' % (r['deleted'], r['nLine']))
|
||
back = call(JS % (PCB, MIL, json.dumps(rows), 'false'))
|
||
if back['found']:
|
||
sys.exit(u'⛔ 回查还剩 %d 段没删干净' % len(set(back['found'])))
|
||
print(u' ✔ 回查:四段全部不在板上了')
|
||
print(u'\n接着跑:pcb1_orphan_cu.py --push → '
|
||
u'pcb_fanout.py --net GND --only C609,C612 --push → drc_read.py')
|
||
|
||
|
||
if __name__ == '__main__':
|
||
main()
|