Skip to content

v0.3.0 — ic= initial conditions, --out-every, a real silent-wrong-answer fix

Choose a tag to compare

@Elvis-codeur Elvis-codeur released this 14 Sep 06:37
· 40 commits to main since this release

Third checkpoint release — 6 commits since v0.2.0, one real silent-wrong-answer bug closed and
two new capabilities. See README.md for the architecture rationale and
book/dev-guide/src/design-decisions.md/docs/journal/ for the reasoning behind each of these.

Highlights

  • Fixed a real silent-wrong-answer bug: kind=sig2phys converters have no terminals and
    stamp nothing into the MNA system — they're named values consumed by reference (a source's
    own value field, a switch's gate=/ctrl=), never a circuit node. Because block names and
    circuit node names are separate namespaces, wiring a converter's name onto an element line
    (R1 VDRV 0 1k) built a perfectly ordinary undriven node — KCL solved it fine to 0, so the
    run silently reported V(VDRV) = 0 right next to the block's own correct, non-zero output
    column, in both --mode dc and --mode transient. DaeError::Sig2PhysUsedAsCircuitNode
    (reject_sig2phys_wired_into_circuit) now catches this before any system is built, in both
    modes, naming the converter, the offending element, and the node token as written.
  • ic= initial conditions are now honored end to end: general-mna v0.1.0 gained real
    ic= support on C/L (see its own release notes); this release is the seam that actually
    uses it — resolve_initial_state centralizes the decision across all four transient entry
    points (simulate_transient, simulate_transient_with_ideal_switches, the closed-loop runner,
    the streamed block-graph runner), so a run given no explicit x_initial now starts from
    whatever ic= the netlist declares instead of always from rest, falling back to rest only when
    the netlist declares none. An explicit x_initial from the caller still always wins.
  • --out-every N decimates CSV/raw output without coarsening the timestep: every step is
    still taken and the solution is bit-identical, only 1-in-N resolved points are written — for a
    case like verifying zero-voltage switching, where the integration step has to resolve a sub-
    picosecond hard-discharge time but a multi-microsecond commutation window doesn't need every
    point written to disk. kind=measure still sees every point regardless of --out-every (only
    the file, not the measurement, is thinned — decimating a measurement's own input would change
    its answer, not just its size). Tested by asserting kept rows are byte-for-byte the full run's
    rows at those indices, not just that the output shrank.

Fixed since v0.2.0: the two v0.2.0-era doc pages (resolve_initial_state's own doc comment,
DaeError::InitialCondition) that described the old solved-operating-point ic= semantics —
now backwards, since general-mna moved to a true assignment — were corrected alongside the
seam that consumes it.