soldermaskdocs

Simulation

spice.simulate(netlist) runs after the parts are resolved and before anything is placed. It is the dynamic version of the ERC's Ohm's-law rules: instead of computing what a resistor should pass from the declared rail, it switches the declared rails on from zero in ngspice, with every part it has a model for in the deck, and reads what the nets settle to. The traces go to the scope as sim.json beside the version's board.json; the findings go on the board as gaps and notes, and the command line prints them under sim.

It is report only. repair.passes() is the bar and does not read it. The models are a behavioural regulator, a table of generic diodes and a high-gain amplifier, not the parts, and a bar that moved on them would fail boards for the model's sake. What it is for is the sentence beside the result: +3V3 settles at 3.285 V (declared 3.3 V); D1 1.42 mA.

The engine

ngspice, which is what KiCad simulates with. Found in either of two forms:

  • ngspice on PATH (brew install ngspice), run in batch mode with -b -r;
  • failing that, the shared library KiCad ships (KiCad.app/Contents/Frameworks/libngspice.0.dylib on macOS, libngspice.so.0 on Linux), driven through ctypes — ngSpice_Init, ngSpice_Circ, ngSpice_Command("run"), then write for the raw file.

Either way it runs in a child process under a ten-second timeout, because a deck ngspice cannot solve can take the process down and a simulation that fails must cost a note and never the build. soldermask setup prints which was found; SOLDERMASK_NGSPICE points at a program or a library, and SOLDERMASK_SIM=off (or --no-sim on the command line) skips the stage, which the board then says.

No engine is a note — not simulated: ngspice not found — and no file. The scope's tab says there is no simulation; it never shows a flat line.

What is in the deck

Ground is node 0 (two ground nets are one node, and said). Every other net is a node; the stimulus is the design's own.

KindIn the deck asFrom
resistor, capacitor, inductorR, C, Lthe value, or the first value in the catalogue description when the design left it blank
LEDa diode whose Vf at 20 mA is the colour's (electrical.LED_VF)the anode/cathode the resolver found on the ordered part, or pin 1 as anode
diodea generic silicon or Schottky diodethe description
transistorgeneric NPN/PNP (β 150) or NMOS/PMOS (Vth 1.8 V)pins named B/C/E or G/D/S; the polarity from the description
switcha closed contact (0.1 Ω) when on two nets, and said—
connectornothing: its pins are nodes—
crystalnothing—
IC or module, linear regulatorone behavioural source, out = min(in − dropout, Vout), 50 mΩ outVout from the part number (AMS1117-3.3, XC6206P332, HT7550, L7805, …), else the catalogue description, else the rail's declaration — and the assumption says which; dropout from the description (1.1V@(800mA)) or the family. An ADJ/FB pin makes it ADJ + 1.25 V with the divider in the deck
buck / boostthe same source, an ideal converter with no rippleas above, dropout 0.3 V / none
op-amp / comparatorevery unit with +, − and OUT as mid + half·tanh(10⁴·(V₊−V₋)/half), 100 Ω outthe supply pins named V+/VCC and V−/VEE/GND; a comparator is the same with a note that its open collector needs the pull-up the design gives it
anything elsenothing: pins open, the part named in unmodelled—

A part on fewer than two nets is not in the circuit and is not counted as unmodelled — the resolver already reported the dropped connections, and this stage does not say it twice.

Stimulus. Every power net with a declared voltage_v that no modelled part drives gets a source ramping from 0 to that voltage in 100 µs. Every power net with a declared current_a gets a load of V/I to ground. A rail a modelled regulator drives gets no source: it is the rail the check is about. A power net that declares no voltage gets nothing, and the assumption says so; a design with no declared rail is refused rather than run, because a circuit with nothing switched on settles at zero everywhere and would report that as a result.

Duration. Five time constants of the slowest RC in view — each capacitor's farads against the parallel resistance on its net — bounded to 1–10 ms, and the trace resampled onto 2,001 uniform points. .option rshunt=1e9 gives every open pin a path to ground so an unmodelled part's node is not a singular matrix.

What it reports

  • A rail a modelled part drives, against its declaration. Within 5 % is a note (+3V3 settles at 3.285 V (declared 3.3 V)); further is a gap. A 5 V part on a rail declared 3.3 V is said in the assumptions before the run.
  • LED current. Past 30 mA is a gap; under 50 µA is a gap (conducts nothing — check its polarity) unless something with no model is on the LED's path — a GPIO of the MCU, through its series resistor — in which case it is not simulated, said as such, and not a gap. Under 1 mA is a note: dim for an indicator.
  • The parts without a model, one gap line naming them: their pins are open, so the traces show the rails without whatever they do.
  • What was assumed, in sim.json and printed by the command line: where each regulator's numbers came from, which switches were closed, which power nets got no source.
  • The deck itself rides in sim.json as deck, so a person can run it through ngspice by hand.

What it does not do

No layout parasitics — there is no layout yet, and the copper's resistance, the plane's inductance and the coupling between tracks are not in a deck built from a netlist. Nothing an MCU, a radio or a sensor does: those are unmodelled, their rails are still traced and still loaded with the current the design declared for them. No temperature. No switching ripple on a converter. No current limit on a regulator macro, and its input draws nothing, so an input rail shows the load the design declared on it rather than the load behind the regulator. No 555, no charger IC, no logic — a macro library is a list that grows by the part, and every part not on it is named.

Measured on the boards already built (11 Sep 2026)

tools/sim_survey.py runs the stage over every version under projects/, read-only. Of 41 versions (31 distinct designs): 16 simulate; 25 are refused with a reason — 24 because no net declares a voltage (designs from before voltage_v existed in the schema) and one because it has no ground net. Of the 16: 11 have a rail a modelled regulator drives, checked against its declaration, and all 11 settle within 5 %; all 16 have an LED current; 213 of 229 parts are in the deck, the 16 without a model being 11 ICs and 5 modules (the ESP32-C3 and -S3 modules, the MCP73831 charger, the SHT40 sensor, the MAX3485 transceiver). Median 0.12 s a board, 0.8 s at most.

Two false findings were caught by that survey before this shipped, and are what the not simulated and absent cases above exist for: an LED on an MCU's GPIO read as not lit — check its polarity on seven versions, and a tactile switch the resolver had already dropped for its pad names was counted again here as a part without a model on six.

On this page