AI-assisted electronic circuit design for Raspberry Pi and other embedded projects — analog and digital — powered by a headless ngspice engine driven from a small Python harness.
Documentation:
HOW-TO.mdis the full guide, written for both humans and AI agents (the agent section covers the netlist conventions and verification steps to follow).
circuit-lab/
harness/
run_circuit.py # ngspice driver: netlist -> parsed results (op/data) + plots
circuits/
analog/ # R/C/L, dividers, MOSFET switches, LED, op-amp, level shifter
digital/ # behavioral + (where used) XSPICE digital logic
README.md
- Linux. ngspice 47 is a self-contained, no-sudo install under
~/.local(built headless:--with-x=no --enable-xspice), so it needs no X11 and no root.~/.local/binmust be onPATH. - Python 3 + optional
matplotlibfor--plot.
# list example circuits
python3 harness/run_circuit.py list
# run a circuit and print its operating point / data tables
python3 harness/run_circuit.py run circuits/analog/voltage_divider.cir
# run with parameter substitutes
python3 harness/run_circuit.py run circuits/analog/rc_lowpass.cir --set R1=4700
# sweep a parameter (runs ngspice once per value)
python3 harness/run_circuit.py run circuits/analog/rc_lowpass.cir --sweep R1=4700,10000,22000
# render a plot of the first data CSV
python3 harness/run_circuit.py run circuits/analog/rc_lowpass.cir --plot /tmp/rc.png
# scaffold a new circuit
python3 harness/run_circuit.py new circuits/analog/my_circuitThe harness reads results two ways:
- Operating-point / printed scalars — any
v(node) = valuelines in the log (fromprint v(x)afterop,dc, ortran) are reported asv(node) = value. - Data tables — every
*.csvwritten bywrdatain the netlist's.controlblock. ngspice'swrdatais finicky: pass ONE vector per call (a single-vectorwrdatayields a clean 2-column CSV[abscissa, value]). Passing several vectors to one call interleaves the abscissa and is unusable. So a typical.controlblock is:
.control
tran 0.01m 8m # or: dc VIN 0 5 0.5 | ac dec 10 1 1meg
wrdata v_in.csv v(in) # one signal per file
wrdata v_out.csv v(out)
.endc
.end
wrdata writes relative to the ngspice working directory, which the harness
owns; your netlist should use plain relative filenames.
- Write a
.cirnetlist. Use the.controlblock for the analysis and onewrdataper signal you care about. - Reuse these building blocks:
- Analog: R/C/L, V/I sources (DC
V in 0 5,PULSE(v1 v2 td tr tf pw per)), diodesD ... <model>, MOSFETsM <d g s b> <model>, and a portable behavioral op-amp subcircuit (seeopamp_noninv.cir). - Digital: behavioral logic via
Bsources, e.g. an inverterB1 out 0 V = 3.3*(V(in)<1.65), a NAND... V = 3.3*((V(a)<1.65)|(V(b)<1.65)). XSPICE digital primitives (a1 ...) are also available when the exact gate model is wanted.
- Analog: R/C/L, V/I sources (DC
op ; print v(x)can return stale/zero values if the engine isn't fully initialised; preferdc,tran, oracpluswrdatafor guaranteed data.- The earlier "Arch package extracted to
~/.local" shortcut is not used here: that binary hardcodes/usr/lib/ngspicecode models and returns all-zero simulations when it can't find them. The harness uses the self-built headless ngspice 47 instead. - Sweeps use the source name (
dc VIN 0 5 1), not the node (dc v(in)...).