.save / .tran / .solver
Directives appear at the top level, outside any module, and start with a .. They configure the simulation as a whole — how long it runs, what gets recorded, and how the equations are integrated.
.tran — transient analysis
| start | Start time (currently always 0) |
| stop | End time |
| step / min_step | Timestep on fixed solvers, minimum step size on adaptive solvers (dt) |
| max_step | Max step size on adaptive solvers; not compulsory on fixed solvers |
.save — signal logging
.save(signal1, signal2, ...) lists what ends up as columns in simulation_output.csv. Signals are referenced by their fully-qualified mangled name, using dot notation to reach into module instances.
Each argument resolves in one of three ways:
- If the name matches an MNA node, it's read from the circuit solution vector.
- If it matches a named circuit element that owns a branch row, its current is logged — see below.
- Otherwise it's read from the logic values map (a VM signal).
Logging branch currents
A .save() argument may name a circuit element, in which case the current through it is logged rather than a voltage. Two spellings mean exactly the same thing:
Either way the CSV column is headed I(main.vsense), so a current column is never confusable with a voltage column. Element names and net names are guaranteed disjoint by the compiler, so the bare form is unambiguous.
Only elements that own an MNA branch row can be logged this way — voltage_source, L, VCVS and CCVS. Naming a resistor is a compile error that points you at the ammeter idiom rather than silently logging zeros.
Column order: node voltages and logic signals come first, in the order written; every branch-current column is appended after them.
.zcd — zero-crossing detection
Enables zero-crossing detection for circuits whose logic outputs switch discretely — comparators, PWM generators, digital controllers. When active, the solver probes one step ahead at each timestep before committing. If any logic variable jumps by more than 1.0 between the current state and the probe, a discontinuity is declared and the crossing time is isolated by bisection down to 1 ps. The timestep is then shortened to land exactly on the event boundary, which stops the integrator stepping across a discontinuity and introducing phase error or false transients.
- Bisection tolerance: 10⁻¹² s (1 picosecond).
- Performance: the check is skipped entirely when
.zcdis absent — analog-only circuits pay nothing. - When to use: any circuit where a logic block produces a step output — a PWM comparator, a relay model, a digital PI controller whose output saturates.
.op — DC operating point
Instructs the VM to solve for the DC operating point before the transient begins. Without it, capacitors start uncharged and voltage sources snap to their values in a single linear solve — the circuit charges from zero initial conditions, which can mean a long startup transient before steady state.
With .op, the solver uses source stepping: supply voltages and driven sources are scaled from 5 % to 100 % in twelve alpha steps. At each level, up to 500 Newton-Raphson iterations run with a 0.05 V per-iteration damping limit. The converged solution at α = 1.0 is committed as the initial condition, so the waveform begins at the settled operating point.
When to use: any circuit with a well-defined DC bias point — amplifiers, filters, motor drives. Omit it only when the startup transient itself is what you're simulating.
.solver — solver type
Same arguments as SPICE. Implicit solvers treat the circuit as a differential-algebraic system and solve G·x = b at each timepoint, enforcing Kirchhoff's laws and voltage-source constraints simultaneously. They're unconditionally stable for linear circuits; nonlinear devices need an inner Newton-Raphson loop.
Every implicit solver here uses Modified Newton: the Jacobian is reused across multiple inner iterations rather than recomputed every time. Reuse policy differs — some recompute once per timestep unconditionally, others carry a Jacobian across many timesteps and refresh it only once a convergence failure proves it stale.
Damping also differs by solver, but all use diagonally-scaled trust-region damping: each variable's proposed step is measured against its own current magnitude rather than one global voltage budget, so the same solver behaves correctly on a millivolt junction and a kilovolt bus inside one circuit.
Available solvers
| Solver | Description | Simulink | SPICE |
| euler_fixed | Backward Euler, fixed timestep, first-order, no tunable parameters. A single implicit solve per step with no error control. Use as a debugging baseline, or when you need a known-simple, always-converges reference trace. | ode1 | — |
| euler_adaptive | Backward Euler with Modified Newton-Raphson, trust-region damping, and convergence-driven adaptive timestepping. Expands dt by 1.5× when the inner loop converges quickly, contracts by 0.5× on failure. General-purpose first-order solver. | ode15s (1st order) | — |
| gauss_siedel | Backward Euler with fixed-point under-relaxation (ω = 0.05). No Jacobian is formed at all, making it structurally immune to every Jacobian-related failure mode the others share. Converges slowly but predictably — useful as a diagnostic cross-check, since a difference in outcome isolates the problem to the Newton machinery rather than the circuit. Not recommended for general use. | — | — |
| trapezoidal | Variable-step Crank-Nicolson with Modified Newton-Raphson and trust-region damping. A-stable. Falls back to Backward Euler for one step after a ZCD event or a rejected step, to suppress numerical ringing before resuming 2nd-order accuracy. | ode23t | Trap |
| trapezoidal_fixed | The fixed-step counterpart to trapezoidal: same 2nd-order formula and Newton loop, no adaptive step control at all. A foundation-testing tool — it isolates whether a convergence failure comes from the core Newton/Jacobian mechanics or from the adaptive layer on top. |
ode23t | Trap |
| bdf2 | 2nd-order Backward Differentiation Formula (Gear's method) with Modified Newton-Raphson, trust-region damping and adaptive timestepping. L-stable — actively damps spurious oscillations after switching events. Uses a Backward Euler primer on startup and after any step rejection. | ode15s | Gear |
| ndf2 | Shampine & Reichelt's order-2 Numerical Differentiation Formula — the real algorithm underlying ode15s. Adds a κ-weighted correction to plain BDF2, improving accuracy within the same A-stable order-2 regime. (Per the Dahlquist second barrier, no linear multistep method of order 3+ can be A-stable, so it deliberately stops at 2.) Starts at order 1 and promotes once enough step history exists. |
ode15s | Gear (NDF) |