- THT pad copper is now part of the conductor: the exact pad outline
(incl. oblong/custom shapes) is fetched from KiCad once per pad and
stamped onto every included layer (the outer shape stands in for
inner rings). Annular rings bridge antipads, and joints land on real
copper instead of only pour coverage.
- The internal lead conductor is modeled in every solder-filled hole:
a cylinder of drill - THT_LEAD_CLEARANCE_MM (0.25 fab rule) with
THT_LEAD_RHO_OHM_M (copper default; config for brass/steel leads),
in parallel with the solder annulus and the plating.
- Drill mouths of THT pads: populated pads keep conducting mouth
copper (stands in for the solder plug - conservative, the plug is
worth ~200 um of copper equivalent); DNP pad holes are cut open on
every layer like uncapped via mouths.
- Oblong pads: the coat uses the exact pad shape; the lead cone tapers
within the inscribed circle (new pad_min_nm on ViaLink/Electrode) so
the long axis is not overstated sideways.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The pad face is wetted where the joint is: the protrusion side,
opposite the component (already read from the owning footprint). The
component-side pad face stays bare - contact_solder_buildups and
tht_joint_buildups no longer coat both outer layers.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
No size-threshold guessing: whether a hole is a via or a THT pad
already comes from KiCad (board.get_vias vs drilled board.get_pads).
Every populated THT pad of the net now carries the complete joint the
contacts got: solder-filled barrel, average-thickness coat over a
pad-diameter disc on the outer layers, and the protruding-lead cone on
the side opposite its owning footprint. The footprint side and the
Do-not-populate flag are read from KiCad (footprint pads store absolute
positions, so owner lookup is an exact (x, y, number) map); DNP pads
stay plating-only with no joint. Contact pads are deduplicated by
barrel center so their cone/coat is never applied twice.
Barrels are now gathered in single-layer runs too: via rings and drill
mouths perforate a lone plane, THT joints stiffen it locally.
ViaLink gains solder_filled + protrusion_side (legacy dumps load with
the old every-THT-pad-filled semantics).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The clipped lead of a soldered THT contact protrudes
THT_LEAD_PROTRUSION_MM (1.5 mm default, 0 disables) out of the hole on
the side opposite the component, and a solder cone wraps it: full
protrusion height at the drill wall, tapering linearly to zero at the
pad edge. Painted as per-cell extra conduction-equivalent copper via
stack.thick_scale - the tall solder column at the wall pulls the joint
vicinity to lead potential (equivalent to extending the barrel wall
vertically), the taper carries the radial spreading. DC-exact additive
conductance; at f > 0 the factor multiplies the skin-corrected sheet
conductance like the via mouths (documented approximation).
The protrusion side is looked up from the owning footprint (pads store
absolute positions; component on F.Cu -> lead tents on B.Cu), with a
logged B.Cu fallback. Dump schema gains protrusion_side and
tht_protrusion_nm (defaults keep older v6 dumps loading).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Selected vias and through-hole pads inject at the drill-wall ring on
every spanned layer (both contact models), not the whole pad face,
so the pad/pour spreading resistance is part of the result. Vias are
now selectable as contacts.
- Soldered THT joints: the hole is modeled solder-filled (core in
parallel with the plating, also for stitching THT barrels) and the
pad face carries an average-thickness solder coat over the modeled
copper (SOLDER_THICKNESS_UM).
- Vias with drills above a configurable threshold (dialog field,
default CAP_MAX_DRILL_MM = 0.5) keep open mouths even with capping
selected - the fab caps only small vias.
- Geometry dump schema v6: electrode barrel fields, cap_max_drill_nm.
- Verified against R = rho/(pi t)*acosh(d/2a) for two circular contacts
on a sheet (+2.6% at h = 0.15 mm, a = 1 mm; uniform model above the
equipotential one as required by the contact bracket).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- adaptive: skip layers with zero quadtree leaves in the connectivity
restriction and mesh-boundary loops (IndexError on boards where a
selected layer has no copper)
- board_io: accept ZT_TEARDROP zones as conducting copper (KiCad types
teardrop fills ZT_TEARDROP, never ZT_COPPER, so they were dropped)
- geometry: copper_bbox uses the exact stroke bbox (centerline extrema
+ half width) instead of a 100 um chord tessellation that could
undershoot arc/cap extrema past the raster guard margin
- solver/adaptive: reference |J| to the conduction-equivalent thickness
sigma*rho in every branch (the uniform branch used geometric t, so AC
plots changed scale ~rs_ratio depending on unrelated per-cell maps)
- solver/adaptive/raster: chain cells no longer show phantom sheet-face
currents; store dl per chain link and overlay the true 1D density
|dV|/(rho*dl) (exact at any frequency: AC scaling of link conductance
and cross-section cancels)
- test_quadtree: compare edge lists pair-for-pair (the independent
column sort destroyed endpoint association)
Each via now contributes its ring/pad copper (full-thickness disc of
the pad diameter on every spanned layer) and its drill mouth: with
"vias filled + capped" (dialog checkbox, default on, VIAS_CAPPED) the
mouth carries a CAP_PLATING_UM (15 um) thin copper cap on the outer
layers and is an open hole on inner layers; unchecked, mouths are open
everywhere. Mouth coverage is area-weighted per cell (4x4
supersampling) through a per-cell thickness map feeding the existing
harmonic-mean face machinery, so sub-cell mouths perturb the sheet by
their true covered fraction instead of whole cells. Fully swallowed
cells leave the mask; the barrel then attaches through the ring via the
existing pad-footprint search. THT-pad copper and drills stay outside
the model. Ring discs paint before 1D trace chains (chains see them as
regular copper), mouths after wide tracks (drills go through trace
copper). standalone gains --uncapped.
Tests: cap==foil identity against the feature-off reference, strict
R(solid) < R(cap) < R(hole) ordering, ring bridging a fill gap that a
ringless barrel cannot cross, gentle sub-cell perturbation at coarse
grids, and JSON roundtrip of the new fields.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Tracks are now first-class Problem objects (TrackSeg: centerline +
width, dump schema v5), so the wide/narrow decision replays at raster
time: traces at least TRACK_1D_FACTOR (3) cells wide rasterize from
their outline as before; narrower ones mark the cells their centerline
crosses as copper and connect them with explicit conductance links
carrying the trace's TRUE arc length per link - no staircase inflation
for diagonals or arcs, and no discretization error in the trace R, at
any grid size. Links across cells already joined by pour faces are
skipped (union, not sum); chain-only cells get no sheet faces (their
copper is narrower than a cell). Electrodes, via barrels, connectivity
restriction and the skin-effect scaling all work on chain cells
unchanged.
This removes the need to shrink the cell size for thin traces: a 0.2 mm
bridge at 500 um cells now matches its finely-rasterized ground truth
within a few percent (tested), including diagonal and arc traces.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Straight tracks become capsule outline polygons (rectangle +
semicircular caps), arc tracks annular bands with end caps, both
tessellated to the same sagitta tolerance as zone-fill arcs; they merge
into the per-layer copper next to the fills, so rasterization, via
stitching, the solver and the plots handle them unchanged. Trace-only
layers and trace-only nets now qualify as candidates. Dialog checkbox
(on by default, INCLUDE_TRACKS) toggles them per run.
Hole-less polygons (every track outline) now paint the layer mask
directly instead of allocating a full-frame temporary each.
Tests: exact N-cell chain on a rasterized capsule, analytic annular-
sector convergence for an arc trace, capsule/arc-band outline geometry
invariants, collinear-arc degradation, and fill+trace union solve.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Refuse the uniform contact model when the fills form multiple
disconnected copper groups that each touch both terminals: the
prescribed injection split is ill-posed and the grounded system was
singular, silently returning garbage (e.g. negative gigaohms).
connected_restrict now reports the component count; a power-balance
backstop (SolverError) catches any other inconsistent solve.
- Connect via/pad barrels to the nearest fill copper within the pad
footprint (+1 cell) instead of only the exact center cell, so
thermal-relief spokes still stitch layers; barrels that reach fill on
fewer than two layers are warned about. ViaLink gains pad_nm
(extracted from the padstack, JSON-roundtripped).
- Validate dialog input on OK (layers, current > 0, cell > 0, parseable
frequency, extra Cu >= 0) with an inline error instead of silently
substituting defaults; parse_frequency raises on garbage; pipeline
rejects i_test <= 0; choose_cell_size rejects non-positive overrides.
- Warn when a contact part is dropped by the connectivity restriction;
floor instead of truncate in cell_of; correct the uniform-model
summary line; drop an unused variable; refresh plugin.json wording.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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>