Skip to main content

Accelerated electrical, thermal, EMC, and coupled PCB analysis

CI License: MIT Python 3.11+

Status: beta. pcb-analysis is under active development. The public API, the JSON schemas and the defaults can change between minor releases (0.9.0 renamed the current-field contract), and the numerical results have been validated on a small set of boards so far. Please report problems and mismatches as GitHub issues.

Accelerated PEEC and matrix-free FEM solvers for electrical and thermal PCB analysis, radiated-emission evaluation for EMC, and PDN optimization.

The repository has three solver families: electrical, thermal and emc.

These solvers are designed to analyse PCBs faster, so that they can be embedded in an automated, LLM-driven PCB design workflow.

Features

  • electrical: 2.5D sheet PEEC for current density, voltage drop and skin effect on multilayer copper; matrix-free FEM for DC conduction and 2D frequency-domain Maxwell; 3D voxel PEEC (PyPEEC) for thick conductors; DICE delta scoring to rank many candidate edits without a full solve.
  • thermal: steady and transient heat conduction through the board stack, with convection, radiation and fixed-temperature boundaries.
  • emc: near-field scans, far-field patterns and CISPR 32 / FCC Part 15 margins computed from a solved current distribution.
  • multiphysics: electro-thermal fixed point with temperature-dependent copper, and emission of the cold or heated current.
  • geometry: reads a KiCad (or any mechanical) STEP export into the solvers' grids, keeping the plated via and through-hole barrels.
  • NumPy on the CPU everywhere; CUDA (CuPy) and OpenMP C++ kernels where they pay off.

Install

pip install pcb-analysis            # CPU only
pip install 'pcb-analysis[cuda]'    # adds CuPy for the CUDA paths

Requirements:

  • Python 3.11 or later. The base install includes OpenCASCADE (cadquery-ocp) and PyPEEC.
  • Optional: an NVIDIA driver with CUDA 13.x for [cuda]. Run nvidia-smi to check it.
  • kicad-cli (KiCad 8 or later) for the KiCad path below.

Each release is also attached to its GitHub release (wheel, sdist and SHA-256 checksums). To install one without PyPI:

pip install 'git+https://github.com/AFLOY/pcb-analysis.git@v0.9.0'

How to use: start from KiCad

KiCad is the recommended environment. Design the board there, export it as STEP with its copper, and let pcb-analysis read the copper back onto a grid.

1. Export the board with its copper. --include-tracks, --include-pads and --include-zones write the copper as solids. Vias and through-holes then come out as the plated barrels KiCad models, and pcb-analysis reads those barrels as they are, so do not add --fill-all-vias.

kicad-cli pcb export step --include-tracks --include-pads --include-zones \
  --include-inner-copper --no-extra-pad-thickness --no-components --force \
  --output power_module.step power_module.kicad_pcb

2. Solve it. The stackup comes from the .kicad_pcb. The body map sorts the solids into the board, one copper sheet per layer and the barrels. Two pads act as the input faces: 1 A enters at the input connector's VIN pin (J1 pad 3) and leaves at the MOSFET's source pad (Q1 pad 3). The API has no pad object: each pad's centre is read from the KiCad board (the pad properties, in mm), and the copper cells under it become the terminal's cells. current_field_problem_mapping collects the grid, copper, barrels and terminals into one current-field problem.

import numpy as np
from geometry.cad_import import (
    board_barrels, board_vias, kicad_step_body_map, layers_from_kicad_stackup,
    load_step, current_field_problem_mapping, rasterize_board, read_kicad_stackup, resolve_bodies,
)
from electrical.sheet_peec import solve_current_field_problem

board = "power_module.kicad_pcb"
layers, board_top_mm = layers_from_kicad_stackup(read_kicad_stackup(board))
body_map = kicad_step_body_map(layers, board_top_z_mm=board_top_mm)   # board, copper layers, barrels
resolved = resolve_bodies(load_step("power_module.step"), body_map)
raster = rasterize_board(resolved, body_map.board, pitch_mm=0.25, y_down=True)

def pad_cells(layer, x_mm, y_mm, half_width_mm=0.5):
    """Copper cells of `layer` around a pad centre given in KiCad coordinates."""
    row, col = raster.cell_of(x_mm * 1e-3, -y_mm * 1e-3)   # the STEP export negates KiCad's y
    k = [spec.name for spec in raster.layers].index(layer)
    r = int(np.ceil(half_width_mm / raster.pitch_mm))
    rows, cols = raster.shape
    return [{"layer": layer, "x": c, "y": y}
            for y in range(max(row - r, 0), min(row + r + 1, rows))
            for c in range(max(col - r, 0), min(col + r + 1, cols)) if raster.occupancy[k, y, c] > 0]

terminals = [
    {"name": "VIN", "pad": "J1.3", "current_a": 1.0, "cells": pad_cells("F.Cu", 129.0, 97.58)},
    {"name": "SRC", "pad": "Q1.3", "current_a": -1.0, "cells": pad_cells("F.Cu", 149.26, 95.675)},
]
problem = current_field_problem_mapping(raster, terminals=terminals, frequency_hz=0.0,
                                    vias=board_vias(resolved, raster), barrels=board_barrels(resolved, raster))
result = solve_current_field_problem(problem)             # DC sheet PEEC on the CPU
print(f"voltage span {result.metrics['voltage_span_v'] * 1e3:.3f} mV, "
      f"peak current density {result.metrics['max_current_density_a_per_mm2']:.2f} A/mm2")

On the example board (two layers, a 139 × 139 grid) this takes a few seconds on a desktop CPU.

Next steps

Each package README continues from the same export, one step at a time:

Package What you get
electrical terminals and current cases, DC and AC sheet PEEC, the matrix-free FEM
thermal board thermal mesh, heat sources, convection, temperature rise
emc radiated field and limit margin from the solved current
multiphysics electro-thermal coupling and emission of the heated board
geometry body maps, rasterising, plated barrels, the current-field problem

Documentation

The methods, their limits and the measurements behind each design decision:

Release and migration notes are in CHANGELOG.md.

Development

pip install -e '.[test]'              # from a clone; CPU only, as CI runs it
python -m pytest tests/
pip install -e '.[native]'            # optional C++ kernels (pybind11, OpenMP)
cmake -S . -B build/native -DCMAKE_BUILD_TYPE=Release
cmake --build build/native

Tests that need the C++ kernels are skipped until they are built. CMakeLists.txt lists the native targets; -DPCB_NATIVE_OPENMP=OFF drops OpenMP and -DPCB_NATIVE_MARCH=x86-64-v3 (for example) replaces -march=native. The scripts in experiments/ regenerate the numbers quoted in docs/; run them from the repository root.

License

MIT

Release files for pcb-analysis 0.9.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pcb-analysis 0.9.1
File Size Uploaded
pcb_analysis-0.9.1.tar.gz 316.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for pcb-analysis 0.9.1
File Interpreter ABI Platform
pcb_analysis-0.9.1-py3-none-any.whl Python 3 none any Details

Total release size: 604.0 kB

Release files / pcb_analysis-0.9.1.tar.gz

Download URL pcb_analysis-0.9.1.tar.gz
Size 316.9 kB
Tags Source
SHA-256 checksum
How to use checksums
97bd0363e216d7766bd84e615d25ff47189462547179d0f2f412f3cac1dc62a7
BLAKE2b-256 checksum
How to use checksums
43c755e768138442648658366ddef4744bd1c4726670057900431061f205bf7c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 25, 2026.

Transparency log

Release files / pcb_analysis-0.9.1-py3-none-any.whl

Download URL pcb_analysis-0.9.1-py3-none-any.whl
Size 287.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
67f0192889e8372894df5c0715fb82f0c4ce9d67bdd55728f80259cef876682f
BLAKE2b-256 checksum
How to use checksums
4e1202a30db5519d7cbc260dd3c9e659cd7b0c093a46e3346da94e47ac5cfa77
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 25, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.9.1 This release

2 release files

0.9.0

2 release files

0.8.2

2 release files

0.8.1

2 release files

0.8.0

2 release files

0.7.0

2 release files

0.6.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page