Declared linear circuits with ngspice
schemaxis.ngspice/1 generates inspectable netlists and runs ngspice 47 in
isolated batch processes with startup files disabled. It supports ideal resistor
and capacitor networks with one grounded ideal voltage source, uncoupled ideal
inductors in AC sweeps, and a bounded first-order RC transient. The host has no
ngspice or numerical-library dependency.
The bridge and two-stage RC ladder examples also exercise multiple unknown nodes.
This is a circuit simulation provider; it does not import KiCad boards/schematics,
load vendor models, accept arbitrary netlists or control physical hardware.
The official release page, control-language tutorial and native documentation define the upstream CLI and analysis commands. Ngspice has BSD-style licensing; see its source distribution for notices.
Shared document authoring#
Start from the divider, RC frequency response or RC step response. For inductive circuits use the RL low-pass, series RLC resonance or parallel LC band-pass. This route uses a document, not a node graph. Shared source and JSON-pointer property edits, history, undo and revision checks remain available.
Every input declares version, operation and circuit. The circuit contains:
source: the driven node, defaultin; the ideal source's other terminal is ground node0. Other names use lowercase ASCII letters, digits and underscores, start with a letter, and have at most 32 characters.resistors: 1–64{name, a, b, resistance}objects, resistance in ohms, range 0.001–1e9.aandbare distinct node names.capacitors: 0–64{name, a, b, capacitance}objects, capacitance in farads, range 1e-12–1. Component names must be unique.inductors: AC only, 0–64{name, a, b, inductance}objects, inductance in henries, range 1e-9–1000. No coupling, winding resistance, core or saturation model. Names are unique across all component types. Omit this field for DC/RC transient documents; those operations reject it, including an empty array.probes: selected non-ground voltage nodes, default["out"]. At most sixteen non-ground nodes are allowed; AC selects at most fifteen probes to keep its four columns per probe within the shared numeric-table limit. Every node must have a resistor/inductor path to ground or the source for the DC operating point; capacitive-only references are rejected. Ideal-inductor loops and inductive shorts across the source are rejected because they lack a unique DC operating point. Floating/ill-conditioned networks fail.
Operation fields are at the document root:
dcSweep:startandstopin source volts (default 0 and 5, range ±1000),points(2–512, default 101). Capacitors are open at DC.acSweep: positivestart/stopin Hz (range 0.001–1e9, defaults 1/10000),points(3–512) and nonzeroamplitudein volts (default 1, range ±1000). Frequencies are linearly spaced, including endpoints. Phasors use exp(+jωt). Inductor admittance is 1/(jωL). Every requested frequency is checked before native execution, including singular undamped resonances inside the sweep.rcStep: exactly one resistor between source and response node and one capacitor between response and ground.amplitudeis the step in volts; capacitor voltage starts at zero.stopis seconds (1e-9–1e6) and must be 0.01–20 RC time constants.pointsselects uniform output times. General transient networks are rejected.
Sweeps require stop > start. The qualified ngspice 47 linear AC command returns
only one sample when requested with two points, so the host explicitly requires
at least three AC points and verifies exact sample counts. Native transient integration uses a maximum internal
step no greater than RC/1000 before uniform resampling. Point counts bound published
results; the RC duration bound also caps integration work. Use a fresh output
directory and configure ngspice or pass --ngspice /absolute/ngspice.
Publications and independent verification#
results.csv, kindtable: source volts, frequency Hz or time seconds followed by selected voltages. AC supplies real/imaginary volts, magnitude volts and principal phase in degrees. Phase wrapping at ±180° is a representation choice.circuit-summary.json, kindtext: topology, output columns, first/last sample, maximum independent voltage error, RC time constant and declared limits.circuit.cir, kindtext: the deterministic generated simulation netlist.
Named sampled performance requirements#
An optional root requirements array declares 1–32 named performance checks.
Each selects a published probe, quantity, sample axis, inclusive two-value
window, and at least one inclusive minimum or maximum. Names are unique
lowercase identifiers. The explicit quantity and axis names carry their units:
| Analysis | Quantity | Sample axis | Interpretation |
|---|---|---|---|
| DC sweep | voltage_V |
sourceVoltage_V |
Signed probe voltage in volts versus signed source voltage. |
| AC sweep | magnitude_V |
frequency_Hz |
Absolute probe phasor magnitude in volts versus frequency in Hz. |
| AC sweep | gainMagnitude |
frequency_Hz |
Dimensionless abs(Vprobe)/abs(Vsource) in V/V; a negative source does not invert this magnitude. |
| RC step | voltage_V |
time_s |
Signed probe voltage in volts versus time in seconds. |
For example, the RC filter requirement
checks the measured gain at three declared frequencies between cutoff and twice
cutoff. The ideal response 1/(1+jωRC) has gain 1/sqrt(2) at cutoff and
1/sqrt(5) at twice cutoff, so this requirement passes the nominal circuit:
"requirements": [{
"name": "filter_gain", "probe": "out", "quantity": "gainMagnitude",
"axis": "frequency_Hz", "window": [159.15494309189532, 318.30988618379064],
"minimum": 0.44, "maximum": 0.72
}]
A window must lie inside the declared analysis interval and contain a declared
sample. Equal endpoints select a single sample. Endpoint comparisons allow eight
floating-point representable steps at the largest absolute interval/window
coordinate; the summary records this endpointTolerance in the axis units.
Selection uses the declared sample coordinates, avoiding native accumulation
roundoff; both declared and native coordinates are retained for the worst sample.
This endpoint allowance never relaxes voltage or gain bounds. Performance bounds
apply directly to measured native values, independently of the existing solver
correctness tolerances. Use meaningful bounds with room for numerical precision.
Magnitude/gain bounds must be nonnegative; voltage bounds preserve polarity.
Phase requirements are not supported, avoiding wrapping and zero-magnitude angle
ambiguities. There are no arbitrary requirement expressions or native scripts.
circuit-summary.json retains performance.accepted, each requirement's observed
minimum/maximum, checked sample count and bound checks. A lower-bound check uses
the smallest signed voltage (not its absolute value); an upper bound uses the
largest. Signed margin is observed-minus-minimum or maximum-minus-observed, so
a negative margin identifies a violation. Every bound reports its worst sample
index and operating coordinate. An unmet requirement suggests inspecting that
condition and revising components, excitation or the stated bound.
Solver correctness is verified first through native raw readback and independent
equations. A physically verified ideal circuit that misses its stated performance
requirements fails with PERFORMANCE_NOT_MET, retaining the native files, CSV,
summary and explained checks. It is not a successful workflow publication and
cannot be resumed as a success. Invalid names, axes, probes, windows and
contradictory bounds fail during planning as INVALID_REQUIREMENT (typed violations
use INVALID_ARGUMENT). Native computation failures retain their existing faults.
Offline verification reconstructs performance from authored requirements and
checked native voltages, so refreshing publication hashes cannot hide forged
assessments.
The divider requirement and
settling requirement supply
DC and RC examples. Doubling the filter capacitor reduces its sampled gain below
the stated minimum; doubling the step resistor delays reaching 4.7 V in the
selected window. The capacitance study
uses the existing $analytic finite-values mechanism to compare 0.98, 1 and 2 µF.
The last visit is deliberately unmet and retains its evidence; this is not an
automatic tolerance optimiser. Smaller component changes are not independently
modelled uncertainties unless authored as separate visits.
These assessments cover only the finite declared samples and component values. They do not prove behaviour between frequencies/times, exact crossing/settling times, continuous-band extrema or every value within a manufacturing-tolerance range. Narrow resonances can lie between samples. Add justified sample locations or separate parameter visits; the adaptor does not invent continuous-envelope or physical-device guarantees.
PYTHONPATH=src python3 tools/qualify_ngspice_performance.py \
--executable /absolute/ngspice --output-directory new-performance-acceptance
Keep the summary and netlist with CSV. There is no schematic layout, PCB geometry, automatic component-tolerance model, parasitic model, nonlinear behaviour or general device-current publication. The editable ngspice → Calc workflow checks numeric workbook readback. Reuse on unchanged workflow resume remains subject to ordinary artifact and authored-plan verification. The RLC → Calc workflow preserves frequency, real/imaginary voltage, magnitude and phase in an editable workbook.
Analytic inductive examples#
The RL example has series L=1 H and shunt R=1000 Ω. Its resistor voltage is
H=1/(1+jωL/R), giving (1-j)/2 at 159.15494309189532 Hz and (1-2j)/5
at twice that frequency. Reversing an uncoupled inductor's terminals does not
change node voltages; reversing source amplitude reverses the voltage phasors.
The series RLC example uses R=1000 Ω, L=1 H and C=1 µF, with output across C.
Writing x=ω/1000, its transfer function is H=1/(1-x²+jx). At resonance
x=1, the output is -j V for a 1 V source; at x=2 it is (-3-2j)/13 V.
Doubling L gives H=1/(1-2x²+jx), so at the original resonance it becomes
(-1-j)/2 V. Splitting L into series 0.25 H and 0.75 H coils preserves the
response while exercising an additional internal node.
The parallel example drives a parallel 1 H / 1 µF tank through 1000 Ω. Its
transfer function is H=1/(1+j(x-1/x)): the response leads below resonance,
equals unity at resonance, and lags above it. These closed-form functions supply
the reviewed acceptance literals independently of both native and host solvers.
Phase at exactly zero magnitude is undefined; do not interpret it as a physical
angle. No inductor DC sweep, RLC transient, transformer or general device-current
claim is made.
Verification and recovery#
A separate host solver builds complex nodal equations and uses partial-pivot elimination to verify every native node voltage for DC/AC, including unselected nodes. RC transient voltage is checked against V(1−exp(−t/RC)). All sample coordinates and CSV phasor conversions are checked. A host ASCII raw parser independently reads saved native values; a second ngspice process also reloads them. Digests, exact netlists, runtime identity, authored/plan agreement and summary values are checked on every offline verification.
Sample-coordinate roundoff uses the full sweep interval, including sweeps ending at zero. DC/AC voltage tolerance is 1e-9 V + 1e-7 times expected magnitude. RC allows 2e-6 times max(|amplitude|, 1) V for integration and interpolation error. These are numerical checks on an ideal model, not a claim about physical circuit performance. A successful simulator exit or existing raw file alone never establishes success.
FLOATING_CIRCUIT requires a resistor/inductor reference path; ILL_CONDITIONED_CIRCUIT
requires damping or better-bounded component ratios. INVALID_SWEEP requires valid increasing
endpoints. UNSUPPORTED_CIRCUIT needs the documented RC topology or removal of an
ideal-inductor/source loop. Native failures, timeouts and cancellation retain stage logs and partial evidence. Correct the
input and run a fresh attempt; do not loosen verification to accept disagreement.
PYTHONPATH=src python3 -m schemaxis run examples/schemaxis/ngspice-rc-frequency.json \
--ngspice /absolute/ngspice --output-directory new-frequency-response
PYTHONPATH=src python3 tools/qualify_ngspice.py \
--config /path/to/private-config.json --output-directory new-acceptance