Files
kicad-zone-resistance/README.md
T
janik 4e39f598a5 Add GPL-3.0 license, PCM packaging, and cross-platform deploy
- LICENSE.txt (GPL-3.0-or-later), declared in the new PCM v2
  metadata.json (validated against the official schema)
- tools/build_package.py builds the registry-layout addon zip in dist/
  plus the submission metadata copy with sha256/sizes and a release
  download_url derived from the Gitea homepage
- tools/deploy.py: symlink/copy deploy for Linux, macOS and Windows
- 64 px resources/icon.png for the PCM listing
- README: Linux setup/dev commands, packaging and license sections

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-15 14:55:24 +07:00

8.5 KiB
Raw Blame History

Fill Resistance — KiCad 10 plugin

Computes the DC resistance of copper zone fills between two contacts, single- or multi-layer: the chosen net's fills on the selected copper layers are solved as coupled finite-difference sheets linked by the net's via and through-hole-pad barrels (18 µm plating, configurable). Shows per-layer rasterized maps, potential, current density, and power density, reports per-via currents (via ampacity!) and total dissipation at a selectable test current. PNGs + a text summary are saved per run.

Uses the KiCad IPC API (kicad-python / kipy), not the deprecated SWIG API. Requires KiCad 10.0.1+.

Setup (one-time)

  1. Enable the API server: KiCad → Preferences → Plugins → check Enable KiCad API.
  2. Check the interpreter path on the same page: should point at the KiCad 10 Python, e.g. C:\Program Files\KiCad\10.0\bin\pythonw.exe on Windows or /usr/bin/python3 on Linux (after a 9→10 upgrade it can point at KiCad 9).
  3. Deploy (dev checkout; end users install the PCM zip instead, see Packaging):
    powershell -ExecutionPolicy Bypass -File deploy.ps1        # junction (dev)
    powershell -ExecutionPolicy Bypass -File deploy.ps1 -Mode Copy
    
    Linux / macOS (also works on Windows with developer mode):
    python3 tools/deploy.py            # symlink (dev)
    python3 tools/deploy.py --copy
    
  4. Restart KiCad; first load builds the plugin venv (numpy, scipy, matplotlib, PySide6 — takes minutes; the Ω button appears when done). If stuck: Preferences → Plugins → Recreate Plugin Environment.

Usage

  1. Mark the current-injection terminals. Each terminal may have multiple parts (all merged into one externally-bonded contact):
    • V+ rectangles on User.1, V rectangles on User.2 (marker layers, configurable via ELECTRODE_POS_LAYER / ELECTRODE_NEG_LAYER), any number per side, axis-aligned;
    • pads (real copper shape; through-hole pad contacts all layers, SMD pad its own layer) — selected pads fill a side that has no rectangles;
    • legacy: exactly 2 selected contacts with no marker rectangles still works; empty selection scans the whole board's marker layers.
  2. Select the contacts, click the Fill Resistance Ω button.
  3. In the dialog, pick the net (defaults to the selected pad's net), check the layers to include, set each contact's layer scope ("All selected layers" = bolted-lug/through contact), the test current, and optionally a grid cell size. Multiple layers are coupled through the net's via/pad barrels automatically.
  4. Read R / voltage drop / total power in the figure titles and status bar. Outputs land in <board dir>\fill_res_results\<timestamp>\: per-layer 1_raster_map / 2_potential / 3_current_density / 4_power_density PNGs, summary.txt (incl. the busiest vias with per-via current and dissipation, and the current through each injection area — computed flux with the equipotential model, prescribed area share with the uniform model), geometry_dump.json.

Model & limits

  • Sheet model per layer: R□ = ρ/t, ρ = 1.68e-8 Ωm (20 °C), t from the board's physical stackup. Layer z-positions from the stackup drive the barrel lengths.
  • Via/pad barrels: thin-wall annulus, R = ρ·L/(π·d·t_plating), VIA_PLATING_UM = 18 in fill_resistance/config.py. Vias are always plated; capped vs uncapped does not change the layer-to-layer DC path (the ≥5 µm cap sits over the hole mouth in parallel with the annular-ring contact, not in series). Per layer a barrel attaches to the fill cell under it, or to the nearest copper cell within the pad footprint plus one grid cell — fills joined by thermal-relief spokes still connect; wider antipads do not, and the barrel bridges the layers above/below with the full barrel length. Barrels that reach fill on fewer than two layers carry no current and are reported.
  • Tracks and pad copper (other than the selected contacts) are not part of the conductor model — zone fills + barrels only.
  • Solder buildup on mask openings (dialog checkbox, off by default; INCLUDE_MASK_BUILDUP): zones drawn on F.Mask/B.Mask are treated as mask openings that collect SOLDER_THICKNESS_UM (50 µm) of solder on the exposed pour, plus an optional user-defined added copper thickness (dialog field, e.g. a soldered busbar/wire). The sheet conductance there becomes t_Cu/ρ_Cu + t_solder/ρ_solder + t_extra/ρ_Cu (SAC305 ρ = 1.32e-7 Ωm: 50 µm solder ≈ 6.4 µm copper); interface faces use harmonic-mean conductances. Buildup areas render tin-gray on the raster map; |J| in them is referenced to the conductance-equivalent copper thickness.
  • Contact models (dialog / CONTACT_MODEL): default uniform injection — a conductor pressed on top feeds the current orthogonally with uniform surface density, so |J| ramps across the contact area (R = ΔV̄/I from area-averaged terminal potentials); or equipotential — ideal bonded lug (Dirichlet). The two bracket a real contact: R_equipotential ≤ R_real ≤ R_uniform. If the selected fills form several disconnected copper groups that each touch both terminals (e.g. planes joined only through the bolted lugs), only the equipotential model is well-defined; the uniform model stops with an error instead of prescribing an arbitrary split.
  • Fields are reported at the dialog's test current; power scales with I².
  • Skin effect (f > 0): per-layer effective sheet resistance from the exact 1D foil-diffusion solution Zs = τρ·coth(τt), τ = (1+j)/δ (SKIN_SIDES = 1 in config: plane facing a return plane; 2 = isolated foil), and the analogous correction for the 18 µm barrel wall. Enter one frequency per run (e.g. a switching harmonic, with its RMS amplitude as the test current) — suffixes k/M accepted. Caveat: only through-thickness crowding is modeled. Lateral (proximity-effect) redistribution needs a magneto-quasistatic solver and is not captured — since the resistance-driven distribution is the minimum-dissipation one, AC results are a rigorous lower bound. Rule of thumb for 70 µm foil: skin is negligible below ~300 kHz (δ = 173 µm at 142 kHz), ~+11 % at 1 MHz.
  • 5-point FDM per layer on an auto-sized shared grid (~2 M cells total across layers by default). Direct sparse solve up to 2.5 M unknowns, Jacobi-CG above. Discretization error typically ≲ 2 % at defaults — halve the cell size and compare to judge convergence.

Offline / development

Every run writes geometry_dump.json; re-solve without KiCad:

.venv\Scripts\python.exe -m fill_resistance.standalone dump.json `
    [--current 40] [--cell-um 50] [--layers F.Cu,In1.Cu] [--no-show] `
    [--out DIR] [--force-iterative]

Dev environment, tests, headless extraction (Windows shown; on Linux/macOS use .venv/bin/python):

uv venv --python 3.11 .venv
uv pip install --python .venv\Scripts\python.exe kicad-python numpy scipy matplotlib pytest
.venv\Scripts\python.exe -m pytest tests -q          # incl. exact analytic cases
.venv\Scripts\python.exe tools\api_probe.py          # IPC API probe vs live KiCad
.venv\Scripts\python.exe -m fill_resistance.board_io dump.json [NET]  # extract only

Packaging / publishing

python tools/build_package.py builds the PCM addon zip in dist/ (installable right away via Plugin and Content Manager → Install from File) plus dist/metadata-registry.json with the SHA-256 and sizes filled in. To publish: upload the zip to a release, set download_url (and the homepage resource in metadata.json), then submit the registry copy as packages/th.co.b4l.fill-resistance/metadata.json in a merge request to https://gitlab.com/kicad/addons/metadata. Icons are regenerated with python tools/gen_icons.py.

License

GPL-3.0-or-later — see LICENSE.txt.

Troubleshooting

  • No toolbar button: venv still building (wait), or build failed → Recreate Plugin Environment; check the interpreter path (setup 2).
  • "Could not connect to KiCad's IPC API": API server not enabled, or KiCad not running (no headless mode in KiCad 10).
  • "KiCad is busy": a modal dialog is open in KiCad — close it, rerun.
  • Windows don't appear: they may open behind KiCad (raised best-effort); PNGs are always saved regardless.
  • Result seems too low/high: remember the model is fills + barrels only, with ideal contacts; measure electrode-to-electrode.