06c62e04f8
DC/AC resistance, power dissipation, and via/injection-area currents of copper zone fills. KiCad 10 IPC-API plugin (kicad-python/kipy): multi-layer via-coupled FDM solver, multi-part terminals via User.1/User.2 marker layers, pads as contacts, uniform-injection and equipotential contact models, per-foil skin effect, optional solder/copper buildup on mask openings. 54-case test suite incl. exact analytic references. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
75 lines
2.6 KiB
Python
75 lines
2.6 KiB
Python
"""Synthetic Problem builders for tests. Dimensions in mm here, nm inside."""
|
|
import numpy as np
|
|
|
|
from fill_resistance.geometry import (Electrode, LayerFill, Polygon, Problem,
|
|
Rect, ViaLink)
|
|
|
|
NM = 1_000_000 # nm per mm
|
|
|
|
|
|
def ring_mm(points_mm) -> np.ndarray:
|
|
return (np.asarray(points_mm, dtype=float) * NM).astype(np.int64)
|
|
|
|
|
|
def _polys(polygons_mm) -> list[Polygon]:
|
|
return [
|
|
Polygon(outline=ring_mm(outline), holes=[ring_mm(h) for h in holes])
|
|
for outline, holes in polygons_mm
|
|
]
|
|
|
|
|
|
def rect_mm(r, layer="User.1") -> Rect:
|
|
return Rect.normalized(int(r[0] * NM), int(r[1] * NM),
|
|
int(r[2] * NM), int(r[3] * NM), layer)
|
|
|
|
|
|
def make_multilayer(layers_mm, rect1_mm, rect2_mm, contact1="all",
|
|
contact2="all", vias_mm=(), t_um=70.0, gap_mm=1.0,
|
|
drill_mm=0.3, plating_um=18.0, rho=1.68e-8) -> Problem:
|
|
"""layers_mm: one list of (outline_pts, [holes]) per layer; layer i is
|
|
named 'L{i}' at z = i * gap_mm. vias_mm: (x, y) through-barrels."""
|
|
nlayers = len(layers_mm)
|
|
return Problem(
|
|
board_path="synthetic",
|
|
net_name="TEST",
|
|
rho_ohm_m=rho,
|
|
plating_nm=int(plating_um * 1000),
|
|
layers=[
|
|
LayerFill(layer_name=f"L{i}", thickness_nm=int(t_um * 1000),
|
|
z_nm=int(i * gap_mm * NM), polygons=_polys(polys_mm))
|
|
for i, polys_mm in enumerate(layers_mm)
|
|
],
|
|
vias=[
|
|
ViaLink(x=int(x * NM), y=int(y * NM),
|
|
drill_nm=int(drill_mm * NM),
|
|
z_top_nm=-1, z_bot_nm=int((nlayers - 1) * gap_mm * NM) + 1)
|
|
for x, y in vias_mm
|
|
],
|
|
electrodes1=[Electrode(rect=rect_mm(rect1_mm), contact=contact1)],
|
|
electrodes2=[Electrode(rect=rect_mm(rect2_mm), contact=contact2)],
|
|
thickness_source="override",
|
|
)
|
|
|
|
|
|
def make_problem(polygons_mm, rect1_mm, rect2_mm, t_um=70.0,
|
|
rho=1.68e-8) -> Problem:
|
|
"""Single-layer problem (the v1 test surface)."""
|
|
p = make_multilayer([polygons_mm], rect1_mm, rect2_mm, t_um=t_um, rho=rho)
|
|
p.layers[0].layer_name = "F.Cu"
|
|
return p
|
|
|
|
|
|
def strip_problem(length=50.0, width=10.0, e_len=5.0, t_um=70.0):
|
|
"""Uniform strip with full-width electrodes at both ends."""
|
|
outline = [(0, 0), (length, 0), (length, width), (0, width)]
|
|
return make_problem(
|
|
[(outline, [])],
|
|
rect1_mm=(0, 0, e_len, width),
|
|
rect2_mm=(length - e_len, 0, length, width),
|
|
t_um=t_um,
|
|
)
|
|
|
|
|
|
def sigma_s(t_um=70.0, rho=1.68e-8) -> float:
|
|
return t_um * 1e-6 / rho
|