ngspice simulation tutorial and template skill. Provides nine standard simulation examples: (1) Transient — RC charging voltage and current; (2) DC — NMOS Id-Vds family curves; (3) AC — RC low-pass filter frequency response; (4) Noise — RC filter output noise spectral density and kT/C; (5) Transient — sample-and-hold switch comparison; (6) Transient — kT/C noise time-domain statistical measurement; (7) DC — NMOS current mirror output characteristics; (8) AC — common-source amplifier frequency response; (9) DC — transmission gate on-resistance. Built-in PTM 180/45/22nm models included.
Important — do not modify skill files during normal use. All new scripts, netlists, simulation outputs, and plots should go into the user's project working directory (outside
.claude/). Do not modify the skill'sassets/folder orSKILL.md. Only edit skill-internal files when the user explicitly asks to improve or extend the skill itself.
Dependencies: system-installed ngspice, Python 3 with numpy ≥ 1.20, matplotlib ≥ 3.3, scipy ≥ 1.7 (NumPy 1.x and 2.x both supported).
If ngspice is not found when a script starts, check_ngspice() will print a brief
error and exit. Full platform-specific install instructions — including a portable
Windows install that requires no PATH change, Chinese-network pip mirror fallbacks,
and python-dateutil/six troubleshooting — are in:
references/installation.md
assets/
├── ngspice_common.py — shared utilities: path constants, runner, parsers, template renderer
├── models/
│ ├── ptm180.lib — PTM 180nm BSIM3v3
│ ├── ptm45hp.lib — PTM 45nm HP BSIM4
│ └── ptm22hp.lib — PTM 22nm HP BSIM4
├── netlist/
│ ├── tran_rc_charging.cir.tmpl — Transient: RC charging voltage and current
│ ├── dc_nmos_iv.cir.tmpl — DC: NMOS Id-Vds family curves
│ ├── ac_rc_filter.cir.tmpl — AC: RC low-pass frequency response
│ ├── noise_rc_filter.cir.tmpl — Noise: RC output noise spectral density
│ ├── tran_sample_hold_nmos.cir.tmpl — Transient: 180nm NMOS sample-and-hold
│ ├── tran_sample_hold_ideal.cir.tmpl — Transient: ideal switch sample-and-hold
│ ├── tran_ktc_noise.cir.tmpl — Transient: kT/C noise time-domain statistics
│ ├── dc_current_mirror.cir.tmpl — DC: NMOS current mirror
│ ├── ac_cs_amp.cir.tmpl — AC: common-source amplifier frequency response
│ └── dc_tgate_ron.cir.tmpl — DC: transmission gate on-resistance
├── simulate_tran_rc_charging.py — RC charging simulation engine
├── plot_tran_rc_charging.py — RC charging plotting
├── run_tran_rc_charging.py — RC charging entry point
├── simulate_dc_nmos_iv.py — DC family-curve simulation engine
├── plot_dc_nmos_iv.py — DC family-curve plotting
├── run_dc_nmos_iv.py — DC family-curve entry point
├── simulate_ac_rc_filter.py — AC + noise simulation engine
├── plot_ac_rc_filter.py — AC + noise plotting
├── run_ac_rc_filter.py — AC + noise entry point
├── simulate_tran_sample_hold.py — sample-and-hold simulation engine
├── plot_tran_sample_hold.py — sample-and-hold plotting
├── run_tran_sample_hold.py — sample-and-hold entry point
├── simulate_tran_ktc_noise.py — kT/C noise simulation engine
├── plot_tran_ktc_noise.py — kT/C noise plotting
├── run_tran_ktc_noise.py — kT/C noise entry point
├── simulate_dc_current_mirror.py — current mirror simulation engine
├── plot_dc_current_mirror.py — current mirror plotting
├── run_dc_current_mirror.py — current mirror entry point
├── simulate_ac_cs_amp.py — common-source amplifier simulation engine
├── plot_ac_cs_amp.py — common-source amplifier plotting
├── run_ac_cs_amp.py — common-source amplifier entry point
├── simulate_dc_tgate_ron.py — transmission gate Ron simulation engine
├── plot_dc_tgate_ron.py — transmission gate Ron plotting
├── run_dc_tgate_ron.py — transmission gate Ron entry point
├── logs/ — simulation logs (auto-created)
└── plots/ — output figures (auto-created)
Naming convention: netlist templates are prefixed by simulation type (dc_, ac_, noise_, tran_); Python files follow the same naming (e.g. run_dc_nmos_iv.py).
assets/ to the project directory.python run_tran_rc_charging.py # RC charging (simplest — good for verifying ngspice install)
python run_dc_nmos_iv.py # DC family curves
python run_ac_rc_filter.py # AC + noise
python run_tran_sample_hold.py # sample-and-hold
python run_tran_ktc_noise.py # kT/C noise statistics
python run_dc_current_mirror.py # current mirror
python run_ac_cs_amp.py # common-source amplifier
python run_dc_tgate_ron.py # transmission gate Ron
On Windows, set PYTHONUTF8=1 to avoid GBK encoding errors.
All paths resolve automatically via Path(__file__).resolve().parent — no configuration needed.
Circuit: R + C to ground, 1V DC step input, initial Vcap = 0.
Configurations:
| Config | R | C | τ = RC |
|---|---|---|---|
| 1 | 1 kΩ | 1 pF | 1 ns |
| 2 | 10 kΩ | 1 pF | 10 ns |
Simulation: .tran to 10τ (slow config), UIC + IC=0.
Output: plots/tran_rc_charging.png (top panel: voltage; bottom panel: current).
Sanity checks:
Files: tran_rc_charging.cir.tmpl → simulate_tran_rc_charging.py → plot_tran_rc_charging.py → run_tran_rc_charging.py
Circuit: PTM 180nm NMOS, W=10µm, L=0.18µm.
Simulation: .dc Vds 0 1.8 0.01, Vgs = {0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8} V.
Output: plots/nmos_dc_iv.png.
Sanity checks:
Files: dc_nmos_iv.cir.tmpl → simulate_dc_nmos_iv.py → plot_dc_nmos_iv.py → run_dc_nmos_iv.py
Circuit: R + C to ground, AC source amplitude 1V.
Configurations:
| Config | R | C | fc = 1/(2πRC) |
|---|---|---|---|
| 1 | 1 kΩ | 1 pF | 159.2 MHz |
| 2 | 10 kΩ | 1 pF | 15.92 MHz |
Simulation: .ac dec 100 1Meg 10G.
Output: plots/rc_ac_bw.png (top panel: gain).
Sanity checks:
Circuit: same as AC example (R + C to ground).
Simulation: .noise v(out) Vin dec 100 1Meg 10G.
Output: plots/rc_ac_bw.png (bottom panel: noise spectral density).
Sanity checks:
AC and noise share a single entry script
run_ac_rc_filter.py(same circuit, natural teaching flow).
Circuit: NMOS switch (180nm, W=4µm) + Csamp=1pF, 10MHz sinusoidal input, 100MHz clock.
Simulation: .tran 0.1n 250n.
Output: plots/sample_hold_compare.png.
Model comparison:
| Model | Ron | Characteristics |
|---|---|---|
| 180nm NMOS | ~400 Ω | real parasitics |
| Ideal switch SPICE subckt | 50 Ω | no parasitics |
Sanity checks:
Files: tran_sample_hold_nmos/ideal.cir.tmpl → simulate_tran_sample_hold.py → plot_tran_sample_hold.py → run_tran_sample_hold.py
Circuit: noisy R (400Ω, equivalent switch Ron) + Csamp; DC input 0.9V. A trnoise voltage source injects thermal noise into the resistor.
Principle: Resistor thermal noise density 4kTR, bandwidth-limited by RC, gives capacitor noise variance = kT/C. Sample v(out) every 5τ over a long transient to obtain 10000 independent samples.
Configurations:
| Csamp | τ = RC | √(kT/C) theoretical |
|---|---|---|
| 1 pF | 0.4 ns | 64.3 µVrms |
| 100 fF | 0.04 ns | 203.5 µVrms |
Output: plots/tran_ktc_noise_hist.png (noise trace + histogram + fitted Gaussian + statistics summary).
Sanity checks:
Files: tran_ktc_noise.cir.tmpl → simulate_tran_ktc_noise.py → plot_tran_ktc_noise.py → run_tran_ktc_noise.py
Circuit: PTM 180nm NMOS 1:1 current mirror; M1 diode-connected (reference), M2 output.
Parameters: W=10µm, L=0.5µm (longer channel for better matching), Iref=100µA.
Simulation: .dc Vout 0 1.8 0.01.
Output: plots/dc_current_mirror.png (Iout vs Vout + mirror ratio).
Sanity checks:
Files: dc_current_mirror.cir.tmpl → simulate_dc_current_mirror.py → plot_dc_current_mirror.py → run_dc_current_mirror.py
Circuit: PTM 180nm NMOS common-source amplifier with resistive load and load capacitance.
Parameters: W=10µm, L=0.18µm, Vgs=0.6V, Rd=2kΩ, CL=1pF, VDD=1.8V.
Simulation: .ac dec 100 1k 100G.
Output: plots/ac_cs_amp_bode.png (gain Bode plot + phase).
Sanity checks:
Files: ac_cs_amp.cir.tmpl → simulate_ac_cs_amp.py → plot_ac_cs_amp.py → run_ac_cs_amp.py
Circuit: NMOS + PMOS complementary transmission gate, W/L=100, fully on (clk=VDD, clkb=0).
Method: Apply 10mV across the gate, sweep Vpass; Ron = 10mV / I.
Technology node comparison:
| Node | VDD | L | W | Model |
|---|---|---|---|---|
| 180nm | 1.8V | 0.18µm | 18µm | PTM BSIM3v3 |
| 45nm HP | 1.0V | 45nm | 4.5µm | PTM BSIM4 |
| 22nm HP | 0.8V | 22nm | 2.2µm | PTM BSIM4 |
Output: plots/dc_tgate_ron.png (Ron vs Vpass, log scale, 3 curves).
Sanity checks:
Files: dc_tgate_ron.cir.tmpl → simulate_dc_tgate_ron.py → plot_dc_tgate_ron.py → run_dc_tgate_ron.py
| Function / Constant | Purpose |
|---|---|
BASE_DIR, NETLIST_DIR, MODEL_DIR, LOG_DIR, PLOT_DIR | Path constants via Path(__file__).resolve().parent |
strip_ansi(text) | Remove ANSI colour codes |
find_ngspice() | Prefer ngspice_con, fall back to ngspice |
run_ngspice(netlist, log, timeout) | Batch-mode execution: -b, stdin=DEVNULL, Windows CREATE_NO_WINDOW |
parse_print_table(log_path) | Parse .print table output → ndarray |
parse_wrdata(data_path) | Parse wrdata two-column output → ndarray |
spath(p) | str(p).replace('\\', '/') for netlist paths |
render_template(tmpl_name, **kw) | Read .cir.tmpl and fill placeholders with str.format(**kw) |
dc_, ac_, noise_, tran_str.format() placeholders: {R}, {model_path}{...} inside SPICE comment lines — they are parsed as format placeholders and raise KeyErrorspath() to forward slashes (Windows compatibility)tempfile.NamedTemporaryFile(suffix='.cir') before executionplt.show(); always use fig.savefig(path, dpi=150, bbox_inches='tight')plots/$V_{DS}$, $I_D$)See references/conventions.md for full details:
See references/installation.md for installation details:
six/dateutil, pip mirror fallbacks