The dialog threshold field gets a unit selector: % of mean |J|
(default, as before) or absolute A/mm2. The absolute variant applies
at the solved operating point - |J| scales with the test current, so
it is meant to be used with the real operating current entered as the
test current (config comment, README and dialog say so).
Switching units swaps in the other unit config default
(TRIM_THRESHOLD_A_MM2 = 1.0 for absolute) but never clobbers a number
the user typed. Validation stays per unit: 0..100 for %, > 0 for
A/mm2. pipeline.run takes trim_pct/trim_abs (at most one), compute()
mirrors that, and the JSON records threshold_mode + threshold_value
next to the resolved threshold_a_per_mm2.
Suite on dev 3.13 and the Python 3.9 mac-stack venv: 151 passed each;
dialog wiring exercised offscreen (defaults, unit swap, validation).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
New EXPERIMENTAL dialog option (default off): after the solve, copper
whose |J| is below a threshold (default 10% of the mean |J| over all
solved copper cells - mean, not max, since contact-corner spikes would
dwarf a max-relative threshold) is vectorized into filled graphic
polygons on TRIM_LAYERS (User.5..User.8, configurable), one polygon
per region so Edit > Convert can turn one into a rule area by hand.
Areas are printed and the polygons saved to low_current_copper.json.
The mask -> polygon step is the 0.5 contour of the binary field via
contourpy (already in every venv as matplotlib dependency), padded so
regions touching the raster edge close, simplified with
Douglas-Peucker at 0.4 cells: staircase bevels collapse, one-cell-wide
strips survive. Specks under TRIM_MIN_AREA_MM2 are dropped.
Explicitly a suggestion, not a safe cut list (docstring, dialog and
README all say so): copper carries little current BECAUSE the rest
carries it, so removal redistributes |J| - the constant-density
optimizer that iterates this to convergence is future work.
board_io: the create/delete-with-status-surfaced helpers are now
generic (_create_items_checked / _remove_items_checked) and shared
between reference-image overlays and trim polygons.
Tested on the dev stack (3.13) and the Python 3.9 mac-stack venv, 148
passed each; contourpy 1.3.x has identical API on both.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
On OK the dialog closed and nothing appeared until the figures did,
which on a real board is minutes of looking like the plugin did
nothing. Put a small always-on-top window up for that stretch: the
stage now running, elapsed seconds, and Cancel.
Qt only repaints while the event loop runs and the solve owns the
thread, so the window pumps events itself - from inside the CG/AMG
iteration callback, which is where the time actually goes. That is
also where Cancel is noticed. The state is module-level because the
tick happens several frames deep in scipy/pyamg, and threading a
handle through those signatures for a progress bar is not worth it;
it stays inert until start(), so the standalone runner and the tests
are unaffected.
The window covers the figure work too, not just the solve: laying out
labels and writing four PNGs at full DPI is seconds on a real board -
10-15 of them on a large one - and closing before that left the same
silent gap one step later.
After a solve, the per-layer current-density maps can be pushed into
the open board as reference images on User.9..User.12 (stackup order,
top first) - visible right in the editor, toggled like any layer,
never plotted to gerbers. Dialog checkbox, default OFF; every push
replaces all reference images on those layers.
Rendering (fill_resistance/overlay.py, KiCad-free and tested headless):
one pixel per grid cell, opaque over copper with the log scale lifted
off the colormap's near-black bottom (dark canvas), transparent
elsewhere, one pixel of half-alpha edge bleed so the overlay reaches
the drawn outline instead of stopping half a cell short. Pushing lives
in board_io (ReferenceImage via the IPC API, KiCad >= 10.0.1; scale =
width / (pixels * 1 inch / 300 PPI), position = image center); kipy
0.7.1 swallows creation errors, so the per-item status is read from
the raw CreateItemsResponse. pipeline.run takes an optional overlay
callback; failures are reported, never fatal.
tools/kicad_overlay_test.py pushes a fiducial alignment pattern (KiCad
bbox readback verified placement to half a pixel); tools/
kicad_heatmap_overlay.py runs the whole thing headless against the
open board, filtering marker rectangles of other nets' analyses via
the exact copper test.
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>