Transformer models

This page is the normative reference for how BMOPFTools models transformers: the supported subtypes, the conventions every subtype follows, the exported primitive admittance (Yprim), and the explicit list of approximations. The overriding design goal is consistency with OpenDSS: at a given setpoint the OPF constraints and the exported Yprim describe the same device, and both are built to match OpenDSS's own Yprim term-by-term wherever OpenDSS is unambiguous.

The companion Transformer primitive admittance spec page carries the full symbolic matrix derivations; this page is the model-level contract. For the workflow that produces these fields — turning short-circuit/open-circuit test data into a validated model — see the transformer test-data tutorial.

Supported subtypes

SubtypeShapeWindingsNotes
single_phasetwo-bus2 (per-phase YY)1/2/3-phase; line-to-neutral, line-to-line, or phase-to-ground winding pairs
center_taptwo-bus3 (split-phase)North-American 120/240; strict arity (2 HV, 3 LV)
wye_delta (Yd)two-bus2, 3-phasewye is winding 1 (from)
delta_wye (Dy)two-bus2, 3-phasedelta is winding 1 (from); backward-delta convention
single_phase_autotransformertwo-bus2, galvanically tiedstep voltage regulator; ANSI type A/B
open_delta_regulatortwo-bustwo L-L cores3-phase only; ABBC/BCAC/CABA
n_windingwinding-listany n, WYE and/or DELTAexact ZB leakage for any n; no tap optimisation

A subtype string outside this set is not silently dropped — the OPF builder and the Yprim export both emit a warning that the device contributes no constraints / is omitted from the export.

Conventions

These hold across every subtype unless a row below says otherwise.

AspectConvention
UnitsSI (volts, amperes, ohms, siemens); per-unit is an internal transform
Turns ratioN = (v_nom_from / v_nom_to) · tap, tap default 1.0
Current sign (Yprim)into the element (out of the bus); Y = Yᵀ, matches OpenDSS Yprim
Series leakagenominal winding bases for ordinary isolating transformers; see the subtype table below
Magnetising shuntacross winding 2 (the to-side coil), on winding 2's coil voltage base — the OpenDSS placement, verified against its Yprim. Inductive, so b_no_load < 0. See below.
Neutral groundingr/x_neutral_from/to (OpenDSS rneut/xneut) is an internal branch yₙ = 1/(Rₙ+jXₙ) from the winding neutral terminal to earth. A stand-alone transformer property — external groundings stay on buses/shunts and are never merged in.
Polarity / vector groupDy uses the backward-delta (k_prev) coil convention; n_winding DELTA windings use delta_roll = -1 for OpenDSS's standard delta
Lossless limitr = x = g = b = 0 is the well-posed ideal-transformer constraint, not a singularity (the Yprim export is the only path where Z=0 is singular — an ideal transformer has no admittance form)

Magnetising-shunt placement

For the ordinary isolating subtypes below, OpenDSS places the no-load (core-loss + magnetising) branch across winding 2, referred to winding 2's coil voltage — not winding 1, and not phase-to-ground. This was verified empirically by differencing OpenDSS's Yprim with and without %noloadloss/%imag (the shunt follows winding 2 when the winding order is flipped). BMOPFTools matches this in both the OPF and the Yprim export:

SubtypeWinding-2 coil the shunt spans
single_phasethe to coil (p_to − q_to)
wye_delta (Yd)a delta of Y₀/nφ branches across the LV delta coils
delta_wye (Dy)Y₀/nφ phase-to-neutral on the LV wye
center_tapthe entire Y₀ across LV leg 1 (t1 − tn), not split
n_windingwinding 2's coil (connection-aware), per-coil legacy value
single_phase_autotransformerlegacy shunt across the from winding
open_delta_regulatorlegacy shunt across each from-side regulator coil, per-regulator value

For new exchange data, use no_load_shunt = {winding, g, b}: g and b are per coil, in siemens on the selected physical winding's coil voltage base, including that winding's tap. Normalization creates ordinary connected bus shunts and retains transformer ownership in _meta["explicit_transformer_core_shunts"]. The transformer primitive alone excludes these materialized bus shunts; include them when comparing the whole terminal model. Current PowerIO imports use this explicit representation.

For compatibility, existing g_no_load/b_no_load values retain their subtype meaning: single_phase, Yd and Dy store a total divided equally over coils; center_tap stores the entire value on winding 2 (first secondary half-winding); n_winding stores a per-coil value on winding 2. Thus copying legacy numbers between subtypes is not a conversion. To express a legacy bank with m coils explicitly, divide its total by m; for n_winding, retain the value. Both forms on one transformer are rejected. These rules resolve the package compatibility choice in #279 without silently changing old data. Schema descriptions now match these runtime meanings. The legacy from_dss recovery also accounts for multi-coil wye-bank coil voltage and winding-2 taps; PMD export uses winding 2's voltage base. For one L-N or L-L coil, the nominal voltage is the coil voltage; two- and three-coil wye banks use V_LL/√3. Neutral selection respects declared case/bus roles and the PMD numeric "4" convention. Zero excitation requires no tap-dependent voltage base, so empty or unequal coil-tap arrays do not cause the legacy zero-shunt recovery to fail.

Fixed taps and stored ohms

SubtypeStored impedance/baseFixed-tap treatment
single_phaseeach winding's nominal ohms; nominal coil voltages define the ratioprimary ohms scale by tap²; secondary-referred equivalent is constant
center_tapnominal HV ohms and nominal ohms per secondary half-winding; v_nom_to is per legprimary star arm scales by tap²; both secondary arms retain their nominal ohms
Yd / Dynominal bus-base ohms (V_LL²/S); delta coil impedance is three times its bus-base valuethe wye-referred equivalent scales by tap² for Yd and is constant for Dy
Yd / Dy combined fieldsalready wye-referred, for both hand-authored JSON and PowerIOnormalize onto the wye winding, then apply the same rule as split fields
n_windingr_winding on each nominal coil base; x_sc on winding 1's coil baseonly nominal winding taps are supported; non-unity winding taps are rejected
single_phase_autotransformer / open_delta_regulatorsupplied series ohms on the declared side, with regulator connection and type defining n_effregulator equations use Z_from + n_eff² Z_to; the ordinary transformer tap² correction does not apply

The ordinary subtype conventions are tested against independent OpenDSS primitives at taps 0.95, 1.0, and 1.06 with nonzero leakage and excitation, using both hand-authored dictionaries and imported DSS. The center-tap primary referral was corrected in #393; stored data continue to use nominal ohms. The same referral is used by its zero-arm and variable-ratio equations, with current coupling substituted to retain quadratic constraints. Fixed-tap tests do not certify control-law behavior or resolve unequal-kVA n-winding import (#356).

Primitive admittance export

transformer_yprim(xfmr, subtype) / export_yprim(net) return the SI Yprim block over the device's (bus, terminal) nodes. It includes the series leakage, the winding-2 magnetising shunt, and the rneut/xneut grounding branch. Two caveats for consumers:

  • Regulators (single_phase_autotransformer, open_delta_regulator): the shared-bushing / shared-phase galvanic tie is an OPF topological constraint, not part of the device primitive (the exported block is the Yan et al. (2018) "unspecified neutral" matrix). The exported Yprim alone leaves the regulated side's return floating.
  • Ideal transformers (Z = 0): no admittance form exists; the export returns a singular (shunt-only) block with a warning. The OPF still enforces the exact ratio.

OPF ↔ Yprim consistency

The OPF builders and the Yprim export are independent implementations. Their agreement at a given setpoint is a guarded invariant: the test suite reconstructs the element current I = Yₚ·V from a solved power flow and checks it node-by-node against the solved OPF winding-current variables, for single_phase, center_tap, wye_delta, and delta_wye, including off-nominal fixed taps. See Validating the OPF.

Approximations

Everything below is a deliberate, bounded approximation — listed here so nothing is hidden.

AreaStatus
n_winding tapNo tap optimisation — the ratio is held at nominal. Tap fields on an n_winding transformer or its windings raise ArgumentError at native OPF build. Model a regulated winding with a two-bus subtype instead.
4+ winding importfrom_dss imports the validated n_winding cases emitted by PowerIO v0.9. Unsupported winding sets refuse loudly, not built wrong.
Discrete tapsOptimised taps are continuous; there is no discrete-step (numtaps) model.
Per-winding ratingsA two-bus transformer carries one s_rating (winding-1 base). Distinct per-winding kVA is retained only on n_winding (per-winding s_max).

Nameplate rating (s_rating) as a loading cap

s_rating plays two roles, and they must not be conflated:

  1. Per-unit impedance base (always). The short-circuit reactances are expressed on winding 1's kVA base — the OpenDSS convention (%XHL/%XHT/ %XLT are all on the winding-1 base, not the highest-powered winding). The OPF matches this: the leakage is per-unitised by z_base(winding-1 bus) and s_rating. This base never changes, so OpenDSS round-trips stay exact.
  2. Apparent-power loading cap (always enforced). The nameplate is enforced as a per-winding coil apparent-power limit P² + Q² ≤ (s_rating / n_\text{ph})² (the coil voltage is phase-to-neutral for a wye winding, line-to-line for a delta winding, so it is never ≈ 0 — no neutral degeneracy), alongside the per-winding i_max_from/i_max_to current cones when present. Because s_rating is a required field, every transformer is power-limited; to solve without the limit (e.g. a determined power flow compared against limit-free OpenDSS), remove s_rating from the network dict before calling the OPF. Keep in mind the primary coil carries load plus copper losses, so at exactly-rated delivery the from-side cap binds slightly below the secondary nameplate throughput (by the loss margin). See current vs. apparent-power limits.

For n_winding transformers, add an optional per-winding s_max (the winding's own kVA) inside each winding entry; it is enforced when present. The per-unit impedance base still keys off winding 1's s_rating, so introducing per-winding ratings never re-bases the leakage.

Not approximations (common misconceptions): the Dy/Yd leakage under tap is exact (it matches OpenDSS's tap² winding-1 self-impedance scaling — the short-circuit impedance referred to the tapped side goes as tap², the non-tapped side is held at nominal; verified against OpenDSS's short-circuit Yprim, applied identically in the OPF and the Yprim export); the magnetising susceptance (%imag) is retained; zero-loss transformers are exact; the n_winding ZB leakage is exact for any winding count.

Grounding: the stand-alone contract

A transformer's model never absorbs an external grounding. Concretely:

  • A grounded-wye star point earthed through OpenDSS rneut/xneut is modeled by the transformer's own r/x_neutral_* fields (an internal branch to earth).
  • An OpenDSS earth node (.0) on a winding is routed to the bus neutral, and the bus's grounding (perfect, or an impedance shunt) does the earthing.
  • External grounding reactors import as first-class shunt elements.

So the exported Yprim for a transformer is a function of the transformer's own data only — no bus grounding data leaks into it, and there is no Kron reduction of external nodes inside the builder.