SANE

Symbolic Analog Network Engine, symbolic and numeric circuit analysis.

SANE extracts the differential-algebraic system F(x, x', t) = 0 from a circuit and analyzes it symbolically and numerically: DC operating point, transient, small-signal AC, poles/zeros, noise, harmonic balance, and exact first- and second-order parameter sensitivities for each of those, all by automatic differentiation of one hash-consed symbolic DAG.

import numpy as np
import sane

model = sane.Circuit.parse("""
    V1 in 0 5
    R1 in out 1k
    C1 out 0 1u
""").extract()

op   = model.operating_point()          # DC bias, labeled by node
ss   = model.small_signal("V1", "out")  # linearize at the bias
ss.poles()                              # [-1000.+0.j], the RC pole
traj = model.transient(np.linspace(0, 5e-3, 200))
sens = op.sensitivity("out")            # exact dy/dp, one adjoint solve
sens.ranked()                           # parameters by relative sensitivity

Results are labeled by node and parameter name, not positional vectors. A result object keeps its solved state, so derived analyses need no re-solve, and parameters read and write hierarchically: model.X1.R2 = 1e3.

Frontends and devices

SANE

The SPICE frontend parses .param expressions, .subckt hierarchy, .model cards, and the standard source waveforms (SIN, PULSE, EXP, PWL). Devices cover the classic set: diodes, MOSFETs, BJTs (Gummel-Poon), JFETs, MESFETs, controlled sources and switches, behavioral sources, and transmission lines. The web app at sane.milanrother.com runs the full engine in the browser.

Symbolic graph

Compact models are the differentiator: a native Verilog-A frontend lowers BSIM4, PSP, HICUM, VBIC, and EKV onto the same DAG, with no OSDI binary and no generated code. Every parameter stays exposed to the autodiff, even in harmonic balance. Temperature is a first-class symbolic global, so .temp sweeps are physical and d(metric)/dT is exact. Noise sources (thermal, shot, flicker, Verilog-A noise) are summed in one registry.

The engine

Rust core: hash-consed symbolic DAG, autodiff, threaded sparse LU (via RSLAB ), optional Cranelift JIT. Python binding via PyO3, or embed the whole engine in Rust with no Python at all.

Validation

Every claim is checked against independent references on real circuits: more than sixty decks spanning RC networks, textbook transistor stages, the uA741, production SKY130 AnalogGym operational amplifiers, and IBM power grids past 100k nodes. DC operating points agree with ngspice within a millivolt across the corpus, harmonic balance is checked against Xyce, and the symbolic transfer functions against Lcapy. Cold DC solves run in 0.015 to 2.5 ms at the raw engine call.

History

SANE is the return to my RFIC EDA roots. It builds on work I did together with Ralf Sommer, the inventor of Analog Insydes, on reviving that tool from December 2024 on. In June 2026 I picked the ideas up again on my own stack, with SSA-style compute graphs at the core of the engine. The first two months produced the SPICE parser, the symbolic DAG engine, the full set of analyses, and the Verilog-A frontend. The web app at sane.milanrother.com is public; the core engine is in early access.