R2 底板改 4 层(D15):规则 / 几何 / 背面摆位 / 4 层布线与铺铜,已下发
- 规则:铜层 2→4,差分 0.28/0.18,间距 0.15,过孔 0.3/0.2(rules_base) - 几何:98×98 板框 + 4×M3,槽阵居中,L1 12V 大铜 + 指头(pcb_base) - 摆位:五插槽留 L1,其余 133 件翻到 L4;背面镜像规则实测;Hub 放走廊 2、 东移 2.5 mm;扇出圈 / 小件间距 1.5(去耦例外)/ 9 A 过孔阵禁区(place_base) - 叠层按用户决定改为 L1 槽面 / L2 整层 +3V3 / L3 整层 GND / L4 器件面 - 布线:D± 七对按构造布通(USB3 掉头、USB1/2 北去掉头、USB4/5 东绕、 J23 桥),+3V3 / GND / +12V 平面网每脚一孔,0.125 网格 + PathFinder 开关(route_base、remote_route.ps1);剩 37 个网待手工补 - 铺铜:4 层重写,入口链自南向北切段 + 断面校核(pour_base); 已下发布线 / 缝合孔 / 铜面轮廓,填铜未成功(待查) - 工具:plot_base / plot_routes / shot_base,board_check 通孔两层都算 Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_0168Bu6SEx3cXXCJLkdnE6zB
这个提交包含在:
+157
-64
@@ -71,6 +71,11 @@ J24 焊盘 x 6.97~57.03、J25 x 102.97~153.03,两排 y 61.2 / 63.8,Ø1.8 焊
|
||||
|
||||
**南边要 5.6 A**(CH1 + CH4 + CH5 各 1.6 A,加左右四个风扇约 0.4+0.4 A)。
|
||||
分法:**中桥喂 CH1 + CH4 + 左风扇 = 3.6 A,右通道喂 CH5 + 右风扇 = 2.0 A。**
|
||||
|
||||
> ⚠️ 2026-09-07 FAN-R2:五个 3 针风扇座删成两个 4 针,而且挪到了**北边两个上角**,
|
||||
> 供电也从 `+12V` 改成 Q7 开关之后的 `FAN_12V_SW`。所以**南边现在只有 4.8 A**
|
||||
> (中桥 3.2 / 右通道 1.6),风扇那 1.34 A 全部走北带经 Q7。上面两个 3.6 / 2.0 的
|
||||
> 判据没改,现在只是更保守,不用重算。
|
||||
左通道不用 —— 它的北端要从 J1 (6.0,74) 和 C2.1 (4.8,82) 两个通孔旁边挤过去,
|
||||
只剩 2.8 mm、带 2.06 A,够不上一路通道的量,而且那一片正好在 8 A 输入链的顶层大铜下面,
|
||||
留成 GND 底填**比塞一条 12V 细带有用得多**。
|
||||
@@ -135,7 +140,15 @@ VIN_RAW, VIN_FUSED, VIN_SW = AUTO['VIN_RAW'], AUTO['VIN_FUSED'], AUTO['VIN_SW']
|
||||
CHAIN = ((VIN_RAW, 'VIN_RAW'), (VIN_FUSED, 'VIN_FUSED'), (VIN_SW, 'VIN_SW'))
|
||||
|
||||
MIL = 39.3700787401575
|
||||
BW, BH = 160.0, 125.0
|
||||
# ⚠️⚠️ 2026-09-08:这里原来写的是 `BW, BH = 160.0, 125.0`,栅格从 (0,0) 起索引 ——
|
||||
# 那是**过期的假板框**,和 `pcb1_place.py` 当年那条是同一个病(它已在第三十轮改掉)。
|
||||
# 真板框是 **220 × 135、左下角 (−30, −5)**(`pcb1_outline.py` 就是这么画的)。
|
||||
# 后果:**本地校核看不见 x<0 / y<0 那两条边**,落在那里的铜一律算成 0 ——
|
||||
# 板上的铜不受影响(多边形是原样下发给 EasyEDA 的、由它去填),
|
||||
# 但**任何摆到负坐标的东西,断面/连通性校核都会静悄悄地给出 0**。
|
||||
# 第三十四轮把输入首级西移到 x −17~2 之后当场撞上:三块顶层铜全报「碎成 0 块」。
|
||||
BX0, BY0 = -30.0, -5.0 # 板框左下角
|
||||
BW, BH = 220.0, 135.0 # 板框尺寸
|
||||
INSET = 0.5 # 铜面离板边
|
||||
CLEAR = 0.2 # 安全间距(pcb1_rules.MIN_CLEARANCE)
|
||||
|
||||
@@ -167,6 +180,24 @@ def rect(x0, y0, x1, y1):
|
||||
return [(x0, y0), (x1, y0), (x1, y1), (x0, y1)]
|
||||
|
||||
|
||||
# ── 毫米 ↔ 栅格:**一律走这四个函数,不要再写 int(x / G)** ──────────────
|
||||
# 板框左下角不是 (0,0),直接除 G 会把负坐标截成 0(见上面 BX0/BY0 那段)。
|
||||
def gi(x):
|
||||
return int((x - BX0) / G)
|
||||
|
||||
|
||||
def gj(y):
|
||||
return int((y - BY0) / G)
|
||||
|
||||
|
||||
def gx(i):
|
||||
return BX0 + (i + 0.5) * G
|
||||
|
||||
|
||||
def gy(j):
|
||||
return BY0 + (j + 0.5) * G
|
||||
|
||||
|
||||
CORNER_R = 5.0
|
||||
|
||||
|
||||
@@ -179,10 +210,10 @@ def board_poly(inset=INSET, seg=6):
|
||||
"""
|
||||
r = CORNER_R - inset
|
||||
pts = []
|
||||
for cx, cy, a0 in ((BW - CORNER_R, CORNER_R, -90.0),
|
||||
(BW - CORNER_R, BH - CORNER_R, 0.0),
|
||||
(CORNER_R, BH - CORNER_R, 90.0),
|
||||
(CORNER_R, CORNER_R, 180.0)):
|
||||
for cx, cy, a0 in ((BX0 + BW - CORNER_R, BY0 + CORNER_R, -90.0),
|
||||
(BX0 + BW - CORNER_R, BY0 + BH - CORNER_R, 0.0),
|
||||
(BX0 + CORNER_R, BY0 + BH - CORNER_R, 90.0),
|
||||
(BX0 + CORNER_R, BY0 + CORNER_R, 180.0)):
|
||||
for k in range(seg + 1):
|
||||
a = math.radians(a0 + 90.0 * k / seg)
|
||||
pts.append((cx + r * math.cos(a), cy + r * math.sin(a)))
|
||||
@@ -201,12 +232,18 @@ REGIONS = [
|
||||
# 载板 `pcb2_pour.py` 文件头第 4 条)。
|
||||
# ⇒ 把中桥并进南西、右通道并进南东、风扇指并进北带,凑成三个 L / T 形多边形,
|
||||
# 每块各自含 J28.1 / J26.1+J27.1 / J29.1+J30.1,**不依赖扇出就活得下来**。
|
||||
# ⚠️⚠️ **2026-09-07 FAN-R2 之后上面这句不再成立**:J28/J29/J30 删了,J26/J27 挪到两个上角
|
||||
# 而且 pin2 已经从 `+12V` 改成开关后的 `FAN_12V_SW`(经 Q7)——
|
||||
# 三块 +12V 里**一个风扇座的通孔焊盘都不剩了**,现在靠 `pcb_fanout` 打的过孔活着
|
||||
# (实测三块各填出 1 段,没被当孤岛删)。⇒ **重铺之前必须先扇出**,
|
||||
# 否则会退回「边框还在、nPoured=0」那个状态。整板重布时把这三块各自含一个本网
|
||||
# 通孔焊盘的条件重新落实一次,别再依赖扇出的运气。
|
||||
dict(net='+12V', layer=L_PWR, name='12V-N', poly=[
|
||||
# 北大块 y 88~124.5 通板 + 风扇指下伸到 y 66.5,**挖掉 U13 那一角**(Kelvin 脚,§10.4)
|
||||
(0.5, 88.0), (96.5, 88.0), (96.5, 66.5), (112.0, 66.5), (112.0, 88.0),
|
||||
(159.5, 88.0), (159.5, 124.5), (0.5, 124.5),
|
||||
(0.5, 102.4), (12.5, 102.4), (12.5, 95.6), (0.5, 95.6)],
|
||||
note=u'北带(CH2/CH3 的 Cin、U19、U29、J28)+ 风扇指(R730/C738/D2);'
|
||||
note=u'北带(CH2/CH3 的 Cin、U19、U29;FAN-R2 之后还含 Q7 源极 = 风扇 1.34 A 的入口)+ 风扇指(现已空载);'
|
||||
u'**源 Rs6.2 的焊盘是 (8.93~10.21, 91.77~95.23)** —— U13 那个缺口原来写成 y 93.0~101.5,'
|
||||
u'正好把 Rs6.2 的中心咬掉,扇出于是把这颗 8 A 源判成「不在铜面里」一个过孔都没打(2026-09-06 抓到)。'
|
||||
u'缺口收成 y 95.6~102.4,只罩住 U13 十个脚(96.08~101.92)与 C11'),
|
||||
@@ -225,11 +262,11 @@ REGIONS = [
|
||||
# 把 +12V 推到 72.6,缝就没了;离 3V3-SE 还有 0.4,够。
|
||||
(0.5, 9.0), (72.6, 9.0), (72.6, 88.0), (61.5, 88.0), (61.5, 40.7),
|
||||
(54.0, 40.7), (54.0, 34.0), (0.5, 34.0)],
|
||||
note=u'CH1 + CH4 的 Cin、J26/J27 左风扇;中桥穿中间通道下来,喂 3.6 A'),
|
||||
note=u'CH1 + CH4 的 Cin(FAN-R2 之后南边没有风扇了);中桥穿中间通道下来,喂 3.2 A,校核仍按 3.6 A 卡'),
|
||||
dict(net='+12V', layer=L_PWR, name='12V-SE+RC', poly=[
|
||||
# 南东块 + 右通道:L 形。J22 只有两个无网络的壳体通孔在 x=151.9,不挡 x≥153.5
|
||||
(116.0, 9.0), (159.5, 9.0), (159.5, 88.0), (153.5, 88.0), (153.5, 34.0), (116.0, 34.0)],
|
||||
note=u'CH5 的 Cin、J29/J30 右风扇;右通道接回北带,喂 2.0 A'),
|
||||
note=u'CH5 的 Cin(FAN-R2 之后南边没有风扇了);右通道接回北带,喂 1.6 A,校核仍按 2.0 A 卡'),
|
||||
|
||||
# ── +3V3:南部两块,各自从北边的源单独引底层干线(见文件头「绕不过去的结论」)──
|
||||
dict(net='+3V3', layer=L_PWR, name='3V3-SW', poly=rect(0.8, 41.0, 58.5, 58.5),
|
||||
@@ -273,19 +310,36 @@ REGIONS = [
|
||||
# ⚠️ 顶层和内层挡路的东西不一样(Grid 的表):这一片里 J1/C2/C3 的通孔、
|
||||
# D1/C4/C5/C6/R1 的 GND 贴片焊盘、以及扇出给它们打的 9 个 GND 过孔 + 短线,
|
||||
# **每一样都要躲**。下面每一条边界后面括号里写的就是它躲的那个东西。
|
||||
# ⚠️⚠️ 2026-09-08 第三十四轮**整段重画**:输入首级(J1/F1/Q1/D1 + 栅极卫星)西移了 30 mm
|
||||
# (J1 换圆形 DC 座并挪到真西板边)。旧的那一版坐标写在 x 11.9~22.5,
|
||||
# 那一片现在**一个本网焊盘都没有** —— 铺出来是孤岛、会被整块删掉,
|
||||
# 而断面校核量到的是空气(报 0.00 mm)。这是本文件第二次踩同一条,
|
||||
# 第一次是第二十三轮(注释还在下面 CUTS 里)。⇒ **摆位一改就要回来重画这三块。**
|
||||
#
|
||||
# 新链路是**单向**的,比旧版顺:J1(−18.8) → F1(−12.5) → Q1(−6) → D1(1) → 东北去 C2/C3/Rs6。
|
||||
# 旧版是 J1 一路向东到 Q1、再折回西边找 Rs6,多绕了一圈。
|
||||
dict(net=VIN_RAW, layer=L_TOP, name='VINRAW-TOP',
|
||||
poly=[(11.9, 65.4), (19.6, 65.4), (19.6, 73.08), (18.58, 73.08),
|
||||
(18.58, 73.78), (15.0, 73.78), (15.0, 73.0), (11.9, 73.0)],
|
||||
note=u'J1.2(13.5,69.5) → F1.1(17.5,73.06)。F1 竖着放之后这一段是一片 7.7×7.7 的大铜;'
|
||||
u'西北那个阶梯是躲 J1.1 的 GND 通孔(Φ2.5, 净距后 r=1.45),'
|
||||
u'东边 19.6 躲 Q1.4 栅极脚(20.215)与 DZ1.1(19.890),'
|
||||
u'北边两段台阶各给 VINFUSED 让 0.2'),
|
||||
poly=[(-17.0, 70.7), (-11.5, 70.7), (-11.5, 73.80),
|
||||
(-13.65, 73.80), (-13.65, 76.5), (-17.0, 76.5)],
|
||||
note=u'J1.1(−15.80,74.35,中心正极,通孔盘 1.6×3.8) → F1.1(−12.50,73.06)。'
|
||||
u'南边 70.7 躲 J1.3 的 GND 通孔盘(顶 70.450);'
|
||||
u'东边 −11.5 刚好盖住 F1.1(东 −11.637),离 Q1 源极三脚(西 −9.786) 还有 1.7;'
|
||||
u'x −13.65 那级台阶是躲 F1.2(西 −13.364, 南 75.350) —— 台阶以东只铺到 73.80,'
|
||||
u'盖住 F1.1(顶 73.651) 并给 VIN_FUSED 让 0.30。'
|
||||
u'**载流断面在 J1.1 与 F1.1 之间**(x≈−14.2),那里是满高 5.8 mm;'
|
||||
u'台阶以东那 3.10 mm 不走穿过电流,F1.1 就是终点。'
|
||||
u'⚠️ 两块的**竖直边**也要拉开:VINRAW 东界 −11.5 与 VINFUSED 的台阶 −11.15 '
|
||||
u'差 0.35 —— 第一版这两条边只隔 0.20(正好压在下限上),是校核报出来的'),
|
||||
dict(net=VIN_FUSED, layer=L_TOP, name='VINFUSED-TOP',
|
||||
poly=[(16.4, 74.0), (18.8, 74.0), (18.8, 73.3), (22.5, 73.3),
|
||||
(22.5, 78.5), (16.4, 78.5)],
|
||||
note=u'F1.2(17.5,75.95) → Q1.1~3(源极三脚, x 20.2~22.2)。'
|
||||
u'南边两段:西半 74.0 躲 F1.1(顶 73.651),东半 73.3 躲 Q1.4(顶 72.882) '
|
||||
u'并盖住 Q1.3(底 73.578);北边 78.5 给 VIN_SW 西行干道让 0.35'),
|
||||
poly=[(-13.4, 74.10), (-11.15, 74.10), (-11.15, 73.3),
|
||||
(-7.5, 73.3), (-7.5, 77.8), (-13.4, 77.8)],
|
||||
note=u'F1.2(−12.50,75.95) → Q1.1~3(源极三脚, x −9.786~−7.751)。'
|
||||
u'南边两段:西半 74.10 同时躲 F1.1(顶 73.651) 和 VINRAW 的台阶(顶 73.80,让 0.30),'
|
||||
u'东半 73.3 躲 Q1.4 栅极脚(顶 72.882) 并盖住 Q1.3(底 73.578);'
|
||||
u'东边 −7.5 离 Q1 漏极四脚(西 −4.250) 还有 3.25。'
|
||||
u'断面在 F1.2 与源极之间(x≈−10.7)= 4.5 mm。'
|
||||
u'⚠️ DZ1.1/C1.1 这两个栅极钳位件同属本网但在 y≈68,**不进这块铜** ——'
|
||||
u'µA 级,交给 pcb1_route_sig 拉一条细线'),
|
||||
|
||||
# ⚠ `VIN_SW` 必须是**一个铺铜对象**,不能拆成几块靠互相重叠连起来。
|
||||
# 同层同网两块铜重叠时,低优先级那块会被高优先级那块裁掉 —— 裁的时候
|
||||
@@ -294,16 +348,17 @@ REGIONS = [
|
||||
# ⇒ 宁可手写 18 个点。下面的 `rects` 是这 18 个点该等于的矩形并集,
|
||||
# `report()` 里逐格对照,写错一个点当场就报(check_poly_rects)。
|
||||
dict(net=VIN_SW, layer=L_TOP, name='VINSW-TOP',
|
||||
poly=[(25.6, 72.1), (29.68, 72.1), (29.68, 73.45), (32.3, 73.45),
|
||||
(32.3, 78.85), (30.47, 78.85), (30.47, 86.47), (28.6, 86.47),
|
||||
poly=[(-4.45, 72.10), (-0.30, 72.10), (-0.30, 73.40), (2.40, 73.40),
|
||||
(2.40, 78.85), (30.46, 78.85), (30.46, 86.47), (28.6, 86.47),
|
||||
(28.6, 83.49), (16.72, 83.49), (16.72, 85.5), (12.5, 85.5),
|
||||
(12.5, 83.49), (6.65, 83.49), (6.65, 87.0), (5.3, 87.0),
|
||||
(5.3, 95.25), (1.5, 95.25), (1.5, 78.85), (25.6, 78.85)],
|
||||
rects=[(25.6, 72.1, 29.68, 78.85), # Q1 漏极四脚(南边 72.1 躲 R1 的 GND 过孔 26.675,71.5)
|
||||
(25.6, 73.45, 32.3, 78.85), # D1.1 TVS(南边 73.45 躲 D1.2 的 GND 盘顶 73.163 与它 6 个扇出孔)
|
||||
(28.6, 78.85, 30.47, 86.47), # C4.2/C5.2/C6.2 去耦(东边 30.47 躲 C6.1 的 GND 盘 30.670)
|
||||
(1.5, 78.85, 28.6, 83.49), # ★ 8 A 西行干道,y 净宽 4.64 mm;
|
||||
# 南边 78.85 躲 J1 的机械脚 J1.4(顶 78.401),北边 83.49 躲 C2/C3 的四个通孔(底 83.700)
|
||||
(5.3, 95.25), (1.5, 95.25), (1.5, 83.49), (-4.45, 83.49)],
|
||||
rects=[(-4.45, 72.10, -0.30, 78.85), # Q1 漏极四脚(x −4.250~−2.215)。南边 72.10 躲 R1 两脚(顶 71.772),留 0.328
|
||||
(-0.30, 73.40, 2.40, 78.85), # D1.1 TVS(−0.096~2.096, 75.838~77.885)。
|
||||
# 南边抬到 73.40 是躲 D1.2 的 GND 盘(顶 73.163) 和它正下方 6 个扇出孔
|
||||
(-4.45, 78.85, 28.6, 83.49), # ★ 8 A 干道,y 净宽 4.64 mm。**西端由 1.5 延到 −4.45**:
|
||||
# 旧版西端卡在 1.5 是因为老 J1 的机械脚 J1.4(顶 78.401) 顶着,那颗件已经挪走
|
||||
(28.6, 78.85, 30.46, 86.47), # C4.2/C5.2/C6.2 去耦(东边 30.46 躲 C6.1 的 GND 盘 30.670)
|
||||
(12.5, 83.49, 16.72, 85.5), # C3.1 口袋(东边 16.72 躲 C3.2 GND 通孔 16.950)
|
||||
(1.5, 83.49, 6.65, 87.0), # C2.1 口袋(净宽 5.15 mm)
|
||||
(1.5, 87.0, 5.3, 95.25)], # 北柱到 Rs6.1(净宽 **3.8 mm** = 8.5 A)
|
||||
@@ -312,8 +367,11 @@ REGIONS = [
|
||||
# 顶到 y 95.4 —— 离 U13.2 只剩 0.379 mm,`pcb1_escape_audit` 报「被围死」。
|
||||
# 收窄之后 U13 南边是一整片 x 5.5~14 / y 91.6~96 的空地。
|
||||
# (Rs6.2 那两根往西甩的 1 mm 扇出短线也一起没了 —— 见 pcb_fanout.FORCE_ARRAY)
|
||||
note=u'**8 A 主干**:Q1 漏极 → 北上 → 西行干道 → C3.1/C2.1 → 北柱 → Rs6.1,一路无过孔;'
|
||||
u'东边挂 D1(TVS) 与 C4/C5/C6 去耦。干道比 v10 北提了 2.8 mm —— XT30 的机械脚占到 y 78.4'),
|
||||
note=u'**8 A 主干**:Q1 漏极(−3.2) → 东经 D1 → 北上 → **东行**干道 → C2.1/C3.1 → 北柱 → Rs6.1,'
|
||||
u'一路无过孔;东端挂 C4/C5/C6 去耦。'
|
||||
u'⚠️ 第三十四轮之后干道是**东行**不是西行 —— 源头 Q1 从 x 24 挪到了 x −6,'
|
||||
u'而 C2/C3/Rs6/C4~C6 一颗没动,于是电流方向整个翻过来了。'
|
||||
u'旧注释「干道比 v10 北提 2.8 mm 躲 XT30 机械脚」已作废:那颗 XT30 已经不在这块板上'),
|
||||
]
|
||||
|
||||
# ── 断面校核:每一条都是「这里必须能过多少安」──────────────────────────
|
||||
@@ -332,7 +390,9 @@ CUTS = [
|
||||
(u'南西块 → CH1', '+12V', L_PWR, 'x', 33.0, (9.0, 34.0), 2.0),
|
||||
(u'南西块 → CH4+CH1', '+12V', L_PWR, 'x', 61.0, (9.0, 34.0), 3.6),
|
||||
(u'南东块 → CH5', '+12V', L_PWR, 'x', 140.0, (9.0, 34.0), 1.6),
|
||||
(u'风扇指 @接北带', '+12V', L_PWR, 'y', 87.0, (94.0, 114.0), 1.0),
|
||||
# FAN-R2 之后风扇指下面已经没有 +12V 负载(风扇改吃开关后的 FAN_12V_SW)。
|
||||
# 这一条留着当**几何回归**:北带往南这一指还在,断面别被后来的布线啃掉。
|
||||
(u'风扇指 @接北带(现空载)', '+12V', L_PWR, 'y', 87.0, (94.0, 114.0), 1.0),
|
||||
(u'北大块 @Rs6 东出', '+12V', L_PWR, 'x', 20.0, (86.0, 124.5), 8.0),
|
||||
(u'3V3 南西块', '+3V3', L_PWR, 'x', 33.0, (41.0, 58.5), 0.5),
|
||||
(u'3V3 南东块 @控制块', '+3V3', L_PWR, 'x', 95.0, (9.0, 58.5), 0.5),
|
||||
@@ -341,10 +401,14 @@ CUTS = [
|
||||
# 8 A 输入链(顶层 1 oz)。J1 → F1 → Q1 → D1/C4~C6 → C3/C2 → Rs6,分叉之前全程 8 A。
|
||||
# ⚠ 这一排坐标跟着摆位走,**摆位一改就要重定**:2026-09-06 第二十三轮把
|
||||
# F1 竖过来、D1 与 C4/C5/C6 挪到东列之后,旧的 `x=10` 那一刀量到的是空气(报 0.00 mm)。
|
||||
(u'RAW J1→F1 颈', VIN_RAW, L_TOP, 'y', 73.4, (14.0, 20.0), 8.0),
|
||||
(u'RAW J1.2 东出', VIN_RAW, L_TOP, 'x', 15.5, (64.0, 76.0), 8.0),
|
||||
(u'FUSED F1.2→Q1 源极', VIN_FUSED, L_TOP, 'x', 19.5, (72.0, 80.0), 8.0),
|
||||
(u'SW Q1 漏极北出', VIN_SW, L_TOP, 'y', 77.5, (24.0, 34.0), 8.0),
|
||||
# 2026-09-08:输入首级西移 30 mm,下面前四条**全部重定**。
|
||||
# ⚠️ 断面要卡在「电流真正流过的那一段」,不是随便找个地方量:
|
||||
# VIN_RAW 的载流段是 J1.1 与 F1.1 **之间**(x≈−14.2);台阶以东那 3.15 mm
|
||||
# 是 F1.1 的落脚区、不走穿过电流,在那里量会得到一个偏严且没意义的数。
|
||||
(u'RAW J1.1→F1.1', VIN_RAW, L_TOP, 'x', -14.2, (68.0, 79.0), 8.0),
|
||||
(u'FUSED F1.2→Q1 源极', VIN_FUSED, L_TOP, 'x', -10.7, (70.0, 80.0), 8.0),
|
||||
(u'SW Q1 漏极东出', VIN_SW, L_TOP, 'x', -1.5, (69.0, 81.0), 8.0),
|
||||
(u'SW 过 D1 北上', VIN_SW, L_TOP, 'x', 2.0, (70.0, 86.0), 8.0),
|
||||
(u'SW 干道 @x24 东端', VIN_SW, L_TOP, 'x', 24.0, (74.0, 86.0), 8.0),
|
||||
(u'SW 干道 @x12', VIN_SW, L_TOP, 'x', 12.0, (74.0, 86.0), 8.0),
|
||||
(u'SW 干道拐北 @y84', VIN_SW, L_TOP, 'y', 84.0, (0.5, 12.0), 8.0),
|
||||
@@ -373,7 +437,6 @@ ROUTED_PADS = {
|
||||
'U12.9': u'Kelvin(IN−):单独引线到 Rs501.1 的焊盘,不进 VO5_P 小岛',
|
||||
'C11.1': u'陪 U13 一起挖出去,走顶层到 L2 输出',
|
||||
'U13.6': u'INA226 的 VS+,陪 U13 一起挖出去(C11 就在旁边)',
|
||||
'C739.1': u'孤零零落在风扇指里,走 11 mm 顶层线到 U33.10',
|
||||
# U23 西侧那两颗(v11 控制块退火重排之后落到 x 71.9~72.4):
|
||||
# 那一条 x 是 `12V-SW+BR`(东界 72.6) 与 `3V3-SE`(西界 73.0) 中间的 0.4 mm 缝,
|
||||
# 两块内层平面谁都够不着。**贴片焊盘对内层透明,所以不是错误**,走顶层短线即可:
|
||||
@@ -385,12 +448,24 @@ ROUTED_PADS = {
|
||||
u'不能从大铜面上随便找个点接',
|
||||
'DZ1.1': u'Q1 栅极钳位齐纳的上端,µA 级;夹在 F1.1 与 Q1.4 之间只有 3.1 mm,走细线',
|
||||
'C1.1': u'Q1 栅极 RC 的上端,µA 级;同 DZ1.1',
|
||||
# 2026-09-08 第三十四轮:两路 TACH 接收跟着风扇座搬到了东西**板边**
|
||||
# (R753 在 x −25.6、R757 在 x 181,都在 y≈100),离 `3V3-SW`/`3V3-SE` 两块内层
|
||||
# 平面各有 80~100 mm。**不要为这两颗把平面拉过去** —— 10 kΩ 上拉到 3.3 V
|
||||
# 只有 **0.33 mA**,外层 0.2 mm 线绰绰有余,而拉一条 100 mm 的内层电源面
|
||||
# 会把 Inner2 的分割搅乱。它们是「接收电路在信号源头整形」那条设计决定的代价。
|
||||
'R753.2': u'进风 TACH 的 3.3V 上拉(10k, 0.33 mA),随风扇座在西板边;走顶层细线',
|
||||
'R757.2': u'排风 TACH 的 3.3V 上拉(10k, 0.33 mA),随风扇座在东板边;走顶层细线',
|
||||
}
|
||||
# 整块「有意不进平面」的区域(位号前缀 → 说明)
|
||||
ROUTED_BLOCKS = [
|
||||
((14.0, 100.0, 30.0, 124.0), u'北左辅助 Buck 那一窝:12V 与 3V3 在 16×24 mm 里交错,整窝走顶层'),
|
||||
((36.0, 70.0, 58.0, 84.0), u'CH2 的 +3V3(5 个,50 mA):沿 y≈84 走顶层到中间那块'),
|
||||
((126.0, 70.0, 146.0, 84.0), u'CH3 的 +3V3(5 个,50 mA):同上'),
|
||||
# `R518.1`(CH5 的 +3V3):2026-09-06 第二十六轮起不再落在 Inner2 的 +3V3 上 ——
|
||||
# 它本来就是「短线 + 扇出孔」那一类,只是以前**碰巧**还压着平面所以没被点名。
|
||||
# 实测通路:R518.1 → 顶层 0.66 mm → +3V3 扇出孔 (134.575, 51.000) → 平面,
|
||||
# `pcb1_netlist` 里 +3V3 整网连通(不在「还差」名单里)。框只罩这一颗。
|
||||
((135.0, 50.4, 136.0, 51.6), u'CH5 的 R518.1:顶层 0.66 mm 短线到 (134.575,51.000) 的 +3V3 扇出孔'),
|
||||
]
|
||||
|
||||
|
||||
@@ -531,6 +606,16 @@ def inside(poly, x, y):
|
||||
# ══════════════════ 栅格化 + 校核 ══════════════════
|
||||
G = 0.25 # 栅格(mm)。0.25 下 45 mm 的通道是 180 格,够细
|
||||
|
||||
#: 浮铜检查的**最小面积**(mm²)。小于它的当栅格碎屑放过,只打印不判红。
|
||||
#:
|
||||
#: ⚠️ 这不是"把检查关小声点",是给它一个说得出理由的下限:布线一多,
|
||||
#: 过孔的反焊盘之间必然夹出 0.25×0.25(**正好一个栅格**)这种碎屑 ——
|
||||
#: 2026-09-06 第二十五轮实测两粒:Inner1 (68.9,74.6) 0.06 mm²、Inner2 (138.5,75.2) 0.19 mm²,
|
||||
#: 都比一个过孔盘还小,电气上没有意义,而且嘉立创铺铜自己也会按死铜阈值清掉。
|
||||
#: 门槛定在 1.0 mm²(1×1 mm):这一轮真正抓到的两条 —— 南沿那条 **1312.8 mm²** 的
|
||||
#: GND 底填、`3V3-SW` 里那块 **7.2 mm²** 的孤岛 —— 都远在门槛之上,一条都不会漏。
|
||||
MIN_FLOAT_AREA = 1.0
|
||||
|
||||
|
||||
class Grid(object):
|
||||
u"""某一层上某个网络的铜:先按区域填,再挖异网的反焊盘 / 过孔 / 走线。
|
||||
@@ -554,11 +639,11 @@ class Grid(object):
|
||||
for r in regions:
|
||||
xs = [p[0] for p in r['poly']]
|
||||
ys = [p[1] for p in r['poly']]
|
||||
i0, i1 = int(min(xs) / G), int(max(xs) / G) + 1
|
||||
j0, j1 = int(min(ys) / G), int(max(ys) / G) + 1
|
||||
i0, i1 = gi(min(xs)), gi(max(xs)) + 1
|
||||
j0, j1 = gj(min(ys)), gj(max(ys)) + 1
|
||||
for j in range(max(0, j0), min(self.ny, j1)):
|
||||
for i in range(max(0, i0), min(self.nx, i1)):
|
||||
if not self.c[j][i] and inside(r['poly'], (i + .5) * G, (j + .5) * G):
|
||||
if not self.c[j][i] and inside(r['poly'], gx(i), gy(j)):
|
||||
self.c[j][i] = True
|
||||
# 反焊盘:异网焊盘(内层只算通孔,外层连贴片一起算)
|
||||
self.carved = 0
|
||||
@@ -580,21 +665,21 @@ class Grid(object):
|
||||
# 天线禁铺(全层)
|
||||
for j in range(self.ny):
|
||||
for i in range(self.nx):
|
||||
if self.c[j][i] and ANT[0] <= (i + .5) * G <= ANT[2] \
|
||||
and ANT[1] <= (j + .5) * G <= ANT[3]:
|
||||
if self.c[j][i] and ANT[0] <= gx(i) <= ANT[2] \
|
||||
and ANT[1] <= gy(j) <= ANT[3]:
|
||||
self.c[j][i] = False
|
||||
self.label()
|
||||
|
||||
def _carve(self, x0, y0, x1, y1):
|
||||
u"""挖掉一个矩形(已经把净距算进去了)。返回有没有真挖到东西。"""
|
||||
hit = False
|
||||
for j in range(max(0, int(y0 / G)), min(self.ny, int(y1 / G) + 1)):
|
||||
yc = (j + .5) * G
|
||||
for j in range(max(0, gj(y0)), min(self.ny, gj(y1) + 1)):
|
||||
yc = gy(j)
|
||||
if not (y0 <= yc <= y1):
|
||||
continue
|
||||
row = self.c[j]
|
||||
for i in range(max(0, int(x0 / G)), min(self.nx, int(x1 / G) + 1)):
|
||||
if row[i] and x0 <= (i + .5) * G <= x1:
|
||||
for i in range(max(0, gi(x0)), min(self.nx, gi(x1) + 1)):
|
||||
if row[i] and x0 <= gx(i) <= x1:
|
||||
row[i] = False
|
||||
hit = True
|
||||
return hit
|
||||
@@ -628,15 +713,15 @@ class Grid(object):
|
||||
u"""沿一条线量本网铜的总宽与最长连续段(mm)。"""
|
||||
tot = run_max = run = 0
|
||||
if axis == 'y':
|
||||
j = int(coord / G)
|
||||
for i in range(int(span[0] / G), int(span[1] / G) + 1):
|
||||
j = gj(coord)
|
||||
for i in range(gi(span[0]), gi(span[1]) + 1):
|
||||
v = 0 <= i < self.nx and 0 <= j < self.ny and self.c[j][i]
|
||||
tot += 1 if v else 0
|
||||
run = run + 1 if v else 0
|
||||
run_max = max(run_max, run)
|
||||
else:
|
||||
i = int(coord / G)
|
||||
for j in range(int(span[0] / G), int(span[1] / G) + 1):
|
||||
i = gi(coord)
|
||||
for j in range(gj(span[0]), gj(span[1]) + 1):
|
||||
v = 0 <= i < self.nx and 0 <= j < self.ny and self.c[j][i]
|
||||
tot += 1 if v else 0
|
||||
run = run + 1 if v else 0
|
||||
@@ -645,8 +730,8 @@ class Grid(object):
|
||||
|
||||
def hit(self, x, y, hx, hy):
|
||||
u"""这个焊盘有没有落在本网主连通域上(焊盘框内任一格)。"""
|
||||
i0, i1 = int((x - hx) / G), int((x + hx) / G) + 1
|
||||
j0, j1 = int((y - hy) / G), int((y + hy) / G) + 1
|
||||
i0, i1 = gi(x - hx), gi(x + hx) + 1
|
||||
j0, j1 = gj(y - hy), gj(y + hy) + 1
|
||||
for j in range(max(0, j0), min(self.ny, j1 + 1)):
|
||||
for i in range(max(0, i0), min(self.nx, i1 + 1)):
|
||||
if self.lab[j][i]:
|
||||
@@ -1004,7 +1089,9 @@ def ascii_map_top(pads, obs=()):
|
||||
看不出「是被 GND 扇出孔啃的还是被自己的边界切的」。
|
||||
"""
|
||||
g = 0.5
|
||||
x0, x1, y0, y1 = 1.0, 31.0, 65.0, 95.0
|
||||
# 2026-09-08:窗口跟着输入首级西移 —— 旧值 (1,31,65,95) 现在只剩右半条链。
|
||||
# 链路实际占 x −17~30.5 / y 70~95.3,取 0.5 mm/格 一行 96 字,够宽。
|
||||
x0, x1, y0, y1 = -18.0, 32.0, 69.0, 96.0
|
||||
sym = [(VIN_RAW, 'R'), (VIN_FUSED, 'F'), (VIN_SW, 'S')]
|
||||
grids = [(s, Grid(net, L_TOP,
|
||||
[r for r in REGIONS if r['layer'] == L_TOP and r['net'] == net],
|
||||
@@ -1029,7 +1116,7 @@ def ascii_map_top(pads, obs=()):
|
||||
x = x0 + (i + .5) * g
|
||||
ch = '.'
|
||||
for s, gr in grids:
|
||||
ii, jj = int(x / G), int(y / G)
|
||||
ii, jj = gi(x), gj(y)
|
||||
if 0 <= ii < gr.nx and 0 <= jj < gr.ny and gr.c[jj][ii]:
|
||||
ch = s
|
||||
break
|
||||
@@ -1058,10 +1145,10 @@ def ascii_map(pads, obs=()):
|
||||
for j in range(ny - 1, -1, -1):
|
||||
row = ''
|
||||
for i in range(nx):
|
||||
x, y = (i + .5) * g, (j + .5) * g
|
||||
x, y = BX0 + (i + .5) * g, BY0 + (j + .5) * g
|
||||
ch = ' '
|
||||
for net, gr in grids:
|
||||
ii, jj = int(x / G), int(y / G)
|
||||
ii, jj = gi(x), gj(y)
|
||||
if 0 <= ii < gr.nx and 0 <= jj < gr.ny and gr.c[jj][ii]:
|
||||
ch = sym[net]
|
||||
break
|
||||
@@ -1214,10 +1301,10 @@ def _cells_from_rings(rings):
|
||||
xs_ = pts[0::2]
|
||||
ys_ = pts[1::2]
|
||||
n = len(xs_)
|
||||
j0 = max(0, int(min(ys_) / G))
|
||||
j1 = min(ny - 1, int(max(ys_) / G) + 1)
|
||||
j0 = max(0, gj(min(ys_)))
|
||||
j1 = min(ny - 1, gj(max(ys_)) + 1)
|
||||
for j in range(j0, j1 + 1):
|
||||
y = (j + 0.5) * G
|
||||
y = gy(j)
|
||||
cr = []
|
||||
for k in range(n):
|
||||
y1, y2 = ys_[k], ys_[(k + 1) % n]
|
||||
@@ -1227,10 +1314,10 @@ def _cells_from_rings(rings):
|
||||
cr.sort()
|
||||
row = acc[j]
|
||||
for a in range(0, len(cr) - 1, 2):
|
||||
ia = max(0, int(cr[a] / G))
|
||||
ib = min(nx - 1, int(cr[a + 1] / G))
|
||||
ia = max(0, gi(cr[a]))
|
||||
ib = min(nx - 1, gi(cr[a + 1]))
|
||||
for i in range(ia, ib + 1):
|
||||
xc = (i + 0.5) * G
|
||||
xc = gx(i)
|
||||
if cr[a] <= xc <= cr[a + 1]:
|
||||
row[i] ^= 1
|
||||
return [[bool(v) for v in r] for r in acc]
|
||||
@@ -1317,16 +1404,22 @@ def verify(refresh=True):
|
||||
g = G_[k]
|
||||
live = set()
|
||||
for x, y in anchors.get(k, ()):
|
||||
i, j = int(x / G), int(y / G)
|
||||
i, j = gi(x), gj(y)
|
||||
if 0 <= i < g.nx and 0 <= j < g.ny and g.lab[j][i]:
|
||||
live.add(g.lab[j][i])
|
||||
dead = [(cid, n) for cid, n in g.sizes.items() if cid not in live]
|
||||
big = [(c, n) for c, n in dead if n * G * G >= MIN_FLOAT_AREA]
|
||||
dust = [(c, n) for c, n in dead if n * G * G < MIN_FLOAT_AREA]
|
||||
lay = {1: 'Top', 2: 'Bottom', 15: 'Inner1', 16: 'Inner2'}[k[1]]
|
||||
chk(not dead,
|
||||
if dust:
|
||||
print(u' (%s %s 另有 %d 粒 < %.1f mm² 的碎屑,按 MIN_FLOAT_AREA 放过:%s mm²)'
|
||||
% (lay, k[0], len(dust), MIN_FLOAT_AREA,
|
||||
' '.join('%.2f' % (n * G * G) for _c, n in sorted(dust, key=lambda t: -t[1])[:6])))
|
||||
chk(not big,
|
||||
u'%s %s 的 %d 块碎片各自都有本网焊盘/过孔落脚' % (lay, k[0], g.ncomp),
|
||||
u'%s %s 有 %d 块**浮铜**(没有任何本网落脚点):%s mm²'
|
||||
% (lay, k[0], len(dead),
|
||||
' '.join('%.1f' % (n * G * G) for _c, n in sorted(dead, key=lambda t: -t[1])[:6])))
|
||||
% (lay, k[0], len(big),
|
||||
' '.join('%.1f' % (n * G * G) for _c, n in sorted(big, key=lambda t: -t[1])[:6])))
|
||||
|
||||
grid_checks(G_, pads, chk)
|
||||
return bad
|
||||
|
||||
在新工单中引用
屏蔽一个用户