Initialization from a Power Flow
The rule
Every device is initialized backwards: from its terminal voltage and power, choose the states that make its derivatives zero, and latch whatever internal reference that implies.
A classical machine latches its internal EMF magnitude and its mechanical power. A transient
machine additionally derives the field voltage its flux state requires. An exciter latches V_ref
so that its output is exactly that field voltage. A governor latches P_ref likewise.
Nothing reads a setpoint from the input file. A file's stated V_ref and its stated power flow
are two independent claims, and they will not agree to machine precision. Deriving the setpoint from
the operating point makes them agree by construction.
The invariant, and the gate that checks it
After the build, at t = 0:
- every device's derivative vector is zero, and
- the network residual
Y V − I_inj(x, V)is zero,
both to machine precision, not merely to a solver tolerance. That is not an aspiration; it falls
out algebraically. Each machine's Norton current is E·y with E = V + z·I for the very
I = conj(S/V) the power flow produced, so the network residual at its bus reduces to the
power-flow equation that was already satisfied. Each remaining injection becomes an admittance
y = −conj(R)/|V|², which reproduces R exactly at the voltage it was derived at.
So the builder checks both and refuses a system that fails either. Which gives the single most useful check in the whole module:
Run with no disturbance at all. The trajectory must be a flat line.
If initialization is consistent, every derivative is zero at t = 0 and stays zero. If a sign is
flipped, a per-unit base missed, a Norton stamp inconsistent with the impedance its own model
initialized against, or a residual assembled wrongly, the state drifts immediately and visibly.
Nearly every mistake in this module is caught by that one check, and it is run for every model and
every combination of controls.
What the check cannot see
A wrong device/load split. If a caller declares that a machine makes half of what it really makes, the result is self-consistent: the machine initializes to an equilibrium at the power it was told, and the remainder is absorbed into the bus's admittance, so both residuals are still exactly zero.
What comes out is a different machine — smaller output, smaller internal EMF, smaller rotor angle — swinging against a network that makes up the difference from something inert. The trajectory is plausible and the answer is wrong.
This is why the equilibrium gate is a code-correctness check and not an input-validation one,
and why the file format removes the need to state the split at all: a device may give its own p
and q, and if it does not, it takes what its bus's solved injection has left. One device omitting
it at a bus is unambiguous; two is refused by name rather than split by a guess.
Deriving the rotor angle
For any machine with a q axis, the rotor angle comes from the steady-state reference
\[ E_q = V + (r_a + j x_q),I, \qquad \delta = \arg E_q \]
That is not a convenience. Choosing δ this way forces the d-axis component of E_q to zero,
which reduces the stator relation for e'_d to exactly (x_q − x'_q)·i_q — the expression
ė'_d = 0 demands. The same construction works for the subtransient machine, because at steady
state a machine looks like x_q behind its terminal on the q axis whatever damper windings it
carries.
Two identities check the result exactly, and both are asserted to 1e-12:
- The machine reproduces its own terminal current.
injection(x₀, V₀) − y_norton·V₀must equalconj(S/V). A transposed sine and cosine, aqaxis defined the other way round, or a sign slip in the stator solve all survive a plausibility reading; none survives this. - A machine with no subtransient saliency cancels its own Norton stamp, so
∂I/∂Vis exactly zero.
Against Dynawo, gridoxide's δ₀ on Kundur's Example 13.2 agrees to 6e-5 rad — two implementations
deriving the same rotor angle from the same terminal condition by independent routes.
What loads become
Constant admittance, derived at the solved voltage, unless a ZipLoad device says otherwise. This
is exact at t = 0 by construction, and it is a real modelling choice with real consequences: a
constant-impedance load sheds power as the square of the voltage, so it is optimistic about
voltage recovery compared with a constant-power one. See The Model Library.