Transformer Control (Complex Tap, Outer Loop)

Concept

Sparlectra models transformer regulation within the existing branch PI model using a complex tap t = τ * exp(jφ) and without auxiliary nodes.

  • τ → voltage control
  • φ → active power flow control (PST behavior)

A combined transformer (“Schrägregler”) is represented by enabling both controls on one device.


Equations

With series admittance y, total shunt y_sh, and from-side tap t:

\[\begin{aligned} Y_{ff} &= \frac{y + 0.5\,y_{sh}}{\lvert t \rvert^2} \\ Y_{ft} &= -\frac{y}{\overline{t}} \\ Y_{tf} &= -\frac{y}{t} \\ Y_{tt} &= y + 0.5\,y_{sh} \end{aligned}\]

This matches the Sparlectra sign and conjugation convention.


Numerical Method

Transformer control is implemented as an outer loop around the power flow:

  1. Solve PF with current taps
  2. Evaluate control error
  3. Update tap(s) (continuous or discrete)
  4. Re-run PF
  5. Stop on convergence, limits, or iteration cap

No augmentation of the Newton system is performed.


Controller Resolution

Controllers are collected centrally via _tap_controllers(net) from PowerTransformerWinding.controls.

They are:

  • deduplicated by identity
  • used consistently for execution and reporting
  • evaluated to determine if outer-loop control is required

Design Rationale

Tap control is intentionally kept outside the Newton solver:

  • no extension of Jacobian/state vector
  • simpler solver backends
  • centralized control logic (deadbands, limits, discrete steps)
  • deterministic post-processing between iterations

Taps are treated as supervisory control updates, not algebraic unknowns.


API

addPowerTransformerControl!(net;
  trafo = "1",
  mode = :voltage,
  target_bus = "B5",
  target_vm_pu = 1.01,
  control_ratio = true,
  control_phase = false,
  is_discrete = true)

Generic control framework integration

Transformer tap/phase control is implemented as an AbstractOuterController. Controllers are collected by collect_outer_controllers(net). When at least one controller is present, run_acpflow calls run_control! for outer-loop orchestration.

Advanced direct use:

result = run_control!(
  net;
  pf_config = powerflow_config(),
  control_config = control_config(),
)

result.status
result.trace
latest_control_result(net)

Preferred high-level solve path:

Result inspection

run_acpflow(net = net; show_results = false)

result = latest_control_result(net)

println(result.status)
println(result.outer_iterations)
println(result.powerflow_solves)
println(result.controllers)
println(result.trace)

result.status is the outer control-loop terminal state. It is separate from numerical PF success/failure. result.trace is machine-readable and does not require parsing console output.

addPowerTransformerControl!(net;
  trafo = "1",
  mode = :branch_active_power,
  target_branch = ("B1", "B2"),
  p_target_mw = 250.0,
  control_ratio = false,
  control_phase = true,
  is_discrete = true)
addPowerTransformerControl!(net;
  trafo = "1",
  mode = :voltage_and_branch_active_power,
  target_bus = "B5",
  target_vm_pu = 1.01,
  target_branch = ("B1", "B2"),
  p_target_mw = 250.0,
  control_ratio = true,
  control_phase = true,
  is_discrete = true)

Discrete Tap Behavior

  • ratio: tap_ratio_new = clamp(tap_ratio ± tap_step, tap_min, tap_max)

  • phase: phase_shift_deg_new = clamp(phase_shift_deg ± phase_step_deg, phase_min_deg, phase_max_deg)


Limits / Scope

  • No auxiliary transformer nodes
  • No coupling of tap variables into NR
  • No coordinated multi-transformer control

Remote Voltage Control (Current vs. Complete)

Current capability

Sparlectra already supports basic remote voltage control:

  • measurement: target_bus
  • actuator: one transformer tap
  • objective: target_vm_pu ± deadband

This corresponds to a single-controller remote regulation.


What is missing for full remote voltage control

A complete implementation (as used in real grid control systems or CGMES-based models) typically requires:

  • multiple transformers controlling the same remote bus

  • coordination between controllers, e.g.:

    • participation factors / weighting
    • priority rules
  • limit handling with redistribution (when one transformer hits tap limits)

  • anti-hunting / stabilization mechanisms

  • deterministic group convergence logic


Key gap in Sparlectra

Currently:

  • controllers operate independently
  • no grouping or coordination exists
  • no shared control objective across multiple transformers

Implication

Sparlectra implements:

single-actuator remote control

but not yet:

coordinated multi-actuator remote voltage control


Example: Inline Controller Definition

ctrl = PowerTransformerControl(
  trafo = "",
  mode = :voltage,
  target_bus = "B5",
  target_vm_pu = 1.01,
  control_ratio = true,
  control_phase = false,
)

addPIModelTrafo!(
  net = net,
  fromBus = "B1",
  toBus = "B2",
  r_pu = 0.01,
  x_pu = 0.08,
  b_pu = 0.0,
  ratio = 1.0,
  shift_deg = 0.0,
  status = 1,
  controls = [ctrl],
)

Examples

See:

  • examples/tap_control_demo_grid.jl
    • Two-file configuration model:
      • examples/configuration.yaml (or SPARLECTRA_CONFIGURATION_YAML) for central solver/output/control-framework settings.
      • examples/tap_control_demo_grid.yaml for demo-specific transformer setpoints and tap parameters.
    • Demonstrates all three control types in one lightweight network: OLTC voltage control, PST active-power control, and Schrägregler combined voltage + active-power control.
    • Controller definitions are created programmatically by the example.
    • Central control.controllers: [] remains reserved/future.
    • Optional classic output: SPARLECTRA_TAP_DEMO_CLASSIC=1 julia --project=. examples/tap_control_demo_grid.jl
    • Optional raw result dump: SPARLECTRA_TAP_DEMO_RAW=1 julia --project=. examples/tap_control_demo_grid.jl
    • Default output is compact and summarizes controller status, taps/phases, and trace size.
    • Structured results are inspected via latest_control_result(net) (controller rows and trace rows).

for runnable setups.