One of the kicad_skills usage guides for the
edaCLI — all six. Plain Markdown: read it directly, or hand it to whatever assistant you use.
ngspice runs inside the container (see the eda-environment guide), the same engine
KiCad’s built-in simulator uses, so results agree with what the user sees in
Eeschema.
# 1. write the deck (plain SPICE, any editor/tool)
# 2. cheap syntax check before burning a run
./bin/eda.sh sim lint sim/rc.cir
# 3. run it: writes raw + CSV + measurements + PNG plots
./bin/eda.sh sim run sim/rc.cir -o sim/out
sim run returns JSON: ok, errors (parsed from the ngspice log), and one
entry per analysis with csv, plot (PNG) and measurements. Read the PNG
with the Read tool when the shape of the response matters — the numbers alone
hide ringing, clipping and convergence artefacts.
* first line is ALWAYS the title - it is discarded
V1 in 0 DC 0 AC 1 SIN(0 1 1k) * AC 1 = 1 V stimulus for .ac
R1 in out 1k
C1 out 0 159.155n
.ac dec 200 10 100k * decade sweep, 200 points/decade
.tran 10u 5m
.end
0 is ground and must exist, otherwise ngspice reports a singular matrix.AC 1 so gains come out in dB directly..include/.lib paths are resolved relative to the deck; model files next to
the deck (*.lib, *.mod, *.sub) are copied into the work directory.dec (log) for AC.| Analysis | Measurements returned |
|---|---|
.ac |
max gain (dB) and its frequency, gain/phase at both ends, -3 dB corner(s), bandwidth, unity gain frequency, phase margin |
.tran |
min/max/peak-to-peak/mean/RMS/final, plus either step metrics (10-90 % rise time, overshoot %, 2 % settling time) or periodic metrics (amplitude, estimated frequency) depending on the waveform |
.dc |
min/max, endpoints, maximum slope (small-signal gain), monotonicity |
.op |
every node voltage and branch current |
THD needs the fundamental, so it is a separate call:
./bin/eda.sh sim measure sim/out/work/sim.raw --thd "v(out)" --fundamental 1000 --skip 1m
A nominal simulation is the one circuit you will never build. Vary the parts inside their tolerance and look at the spread of the number you actually care about:
./bin/eda.sh sim montecarlo sim/rc.cir -o sim/mc \
--vary R1=1% --vary C1=10% \
--metric ac.v(out).f_minus_3db_hz \
--trials 200
Returns statistics (mean, stdev, min/max, p05/median/p95, spread_pct),
nominal_metric for reference, a histogram.png and trials.csv. The metric
is a path into the usual measurements: <analysis>.<signal>.<key> — e.g.
ac.v(out).gain_db_max, tran.v(out).overshoot_pct, or op.v(out).
The same run also answers “so which component do I need to buy tighter?”.
sensitivity ranks every varied part, with sensitivity.png as the picture:
{"explained_pct": 99.7,
"parameters": [{"parameter": "C1", "contribution_pct": 99.3, "elasticity": -0.99},
{"parameter": "R1", "contribution_pct": 0.7, "elasticity": -0.96}]}
contribution_pct — that part’s share of the spread. Here the 10 % capacitor
is the whole problem and the 1 % resistor is irrelevant, so a tighter C is the
only change worth paying for.elasticity — how many percent the metric moves per percent of that part.
-0.99 says the corner frequency falls almost exactly in proportion, which is
what fc = 1/(2πRC) predicts.explained_pct — how much of the spread a straight line accounts for. Well
below 100 means the circuit does not respond linearly over that tolerance
band, and the per-part split is indicative rather than exact. Look at the
histogram before trusting the ranking.It costs no extra simulation — it is the trials you already ran, read column-wise. It needs at least three trials and more trials than varied parts.
--distribution normal (default) treats the tolerance as ±3σ, clipped to the
band — how reels of parts actually behave.--distribution uniform is the honest choice when you know nothing about the
distribution.--distribution worst samples only the two extremes, which finds the corners
fastest.--vary also accepts .param names, so anything parameterised in the deck
can be swept, not just R/C/L.--seed makes a run reproducible; quote the seed when you quote the result.Judge the result against the requirement, not against the nominal: “fc = 1000 Hz nominal, 5th–95th percentile 968–1035 Hz with 1 % parts, spec is ±5 % → passes with margin”.
./bin/eda.sh sim temperature sim/bias.cir -o sim/temp \
--temperatures -40 0 25 85 125 --metric op.v(out)
Runs the deck at each temperature (.temp) and reports the metric per point
plus drift_per_celsius. Only models with temperature coefficients will move —
ideal R and C do not, so a flat result means the models are ideal, not that the
circuit is stable.
./bin/eda.sh sim netlist hardware/amp.kicad_sch -o sim/amp.cir # kicad-cli export
./bin/eda.sh sim run sim/amp.cir -o sim/out
The export only produces a usable deck when the symbols carry Spice model
fields (Spice_Primitive, Spice_Model, .model/.subckt includes). For a
plain schematic it is usually faster and more honest to hand-write a deck for
the sub-circuit under investigation and say so in the report.
fc = 1/(2πRC), A = -Rf/Rin,
…). If simulation and theory disagree, the deck is usually wrong.singular matrix, timestep too small are reported in
errors; fix the circuit (add a DC path to ground, .options relaxation)
rather than ignoring them.value (analysis, conditions) and keep the generated PNG/CSV in the
repository next to the design when the result matters.