Initial import: KiCad zone resistance plugin
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>
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
"""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
|
||||
Reference in New Issue
Block a user