pydynamicestimator.devices.inverter_angle

Inverter angle-source strategies (what makes a converter forming vs following).

The angle source produces the converter frequency omega_c and integrates the converter-frame angle delta_c – it fuses the synchronous machine’s governor and shaft roles (there is no separable mechanical-power intermediate in an inverter), so the active-power droop and the power-measurement state Pc_tilde live here. It is the mandatory axis: a grid-forming converter sets its own frequency from the droop off nominal (DroopAngle, exposing host.omega_c); a grid-following converter rides on a PLL’s frequency (PLLAngle, reading host.pll_frequency). Future variants: VSM (swing ODE), dVOC, matching control.

See docs/inverter_modernization_design.md §4.1. NOTE (Phase 2 boundary): the angle source owns the Pc_tilde state and the droop, but the first-order power-measurement filter equation d Pc_tilde/dt = omega_f (Pc - Pc_tilde) is written by the host, because Pc is computed from the shared Park-transform loop in Inverter.fgcall. A later cleanup can move power computation behind a host accessor and the filter equation into the strategy.

Attributes

ANGLE_REGISTRY

Classes

AngleSource

Abstract base class for inverter angle-source strategies (pluggable).

_PowerDroopAngle

Shared declarations for the power-droop angle family (Pc_tilde +

DroopAngle

Grid-forming droop: the converter sets its own frequency from the

PLLAngle

Grid-following: the converter frequency rides on the PLL's synchronizing

Module Contents

class pydynamicestimator.devices.inverter_angle.AngleSource[source]

Bases: abc.ABC

Abstract base class for inverter angle-source strategies (pluggable).

Must own delta_c (and, for the droop family, Pc_tilde) and expose the converter frequency: fgcall() returns the omega_c vector consumed by the host’s inner control ladder and writes dae.f[delta_c]. The strategy reads host params/states/setpoints by attribute (host.Kp, host.Pref, dae.x[host.Pc_tilde]) and, for the following variant, the synchronizing frequency via host.pll_frequency(dae).

abstract states() List[str][source]
Return type:

List[str]

algebs() List[str][source]
Return type:

List[str]

algebs_units() Dict[str, str][source]
Return type:

Dict[str, str]

algebs_noise() Dict[str, float][source]
Return type:

Dict[str, float]

algebs_x0() Dict[str, float][source]
Return type:

Dict[str, float]

abstract units() List[str][source]
Return type:

List[str]

abstract params() Dict[str, float][source]
Return type:

Dict[str, float]

abstract states_noise() Dict[str, float][source]
Return type:

Dict[str, float]

abstract states_init_error() Dict[str, float][source]
Return type:

Dict[str, float]

abstract x0() Dict[str, float][source]
Return type:

Dict[str, float]

abstract descriptions() Dict[str, str][source]
Return type:

Dict[str, str]

abstract setpoints() Dict[str, float][source]
Return type:

Dict[str, float]

abstract fgcall(host, dae: pydynamicestimator.system.Dae, omega_ref_vec, omega_b)[source]

Return the omega_c vector and write dae.f[delta_c] (the angle dynamics). Grid-forming variants also set host.omega_c; grid-following variants leave it unset and read host.pll_frequency(dae) instead.

Parameters:

dae (pydynamicestimator.system.Dae)

steady_frequency(host, dae: pydynamicestimator.system.Dae) numpy.ndarray[source]

The converter frequency at steady state, fed to the inner-control init’s decoupling terms. Nominal for ANY synchronizing source: delta_c steady forces omega_c = omega_ref = omega_net, independent of the angle law.

Parameters:

dae (pydynamicestimator.system.Dae)

Return type:

numpy.ndarray

abstract finit_sequential(host, dae: pydynamicestimator.system.Dae, Pc: numpy.ndarray, delta_c: numpy.ndarray) Dict[str, numpy.ndarray][source]

Resolve the angle source’s states/setpoints from the (frame-invariant) active power Pc and the inner-controller’s frame angle delta_c. The base raises so a new angle source declares its own.

Parameters:
Return type:

Dict[str, numpy.ndarray]

class pydynamicestimator.devices.inverter_angle._PowerDroopAngle[source]

Bases: AngleSource

Shared declarations for the power-droop angle family (Pc_tilde + delta_c states, Kp droop gain, Pref setpoint). Concrete subclasses differ only in the frequency anchor inside fgcall().

states() List[str][source]
Return type:

List[str]

units() List[str][source]
Return type:

List[str]

params() Dict[str, float][source]
Return type:

Dict[str, float]

states_noise() Dict[str, float][source]
Return type:

Dict[str, float]

states_init_error() Dict[str, float][source]
Return type:

Dict[str, float]

x0() Dict[str, float][source]
Return type:

Dict[str, float]

setpoints() Dict[str, float][source]
Return type:

Dict[str, float]

descriptions() Dict[str, str][source]
Return type:

Dict[str, str]

finit_sequential(host, dae: pydynamicestimator.system.Dae, Pc: numpy.ndarray, delta_c: numpy.ndarray) Dict[str, numpy.ndarray][source]

Resolve the angle source’s states/setpoints from the (frame-invariant) active power Pc and the inner-controller’s frame angle delta_c. The base raises so a new angle source declares its own.

Parameters:
Return type:

Dict[str, numpy.ndarray]

class pydynamicestimator.devices.inverter_angle.DroopAngle[source]

Bases: _PowerDroopAngle

Grid-forming droop: the converter sets its own frequency from the active-power droop off nominal, omega_c = omega_net + Kp (Pref - Pc_tilde), and exposes it as host.omega_c (read by the COI / single reference-frame machinery in system.py). Byte-identical to the previous GridForming angle.

fgcall(host, dae: pydynamicestimator.system.Dae, omega_ref_vec, omega_b)[source]

Return the omega_c vector and write dae.f[delta_c] (the angle dynamics). Grid-forming variants also set host.omega_c; grid-following variants leave it unset and read host.pll_frequency(dae) instead.

Parameters:

dae (pydynamicestimator.system.Dae)

class pydynamicestimator.devices.inverter_angle.PLLAngle[source]

Bases: _PowerDroopAngle

Grid-following: the converter frequency rides on the PLL’s synchronizing frequency (read host-mediated via host.pll_frequency) plus the active-power droop, omega_c = omega_pll + Kp (Pref - Pc_tilde). Pairs with a PLL strategy (which owns omega_pll and the PLL states). Byte-identical to the previous GridFollowing angle.

fgcall(host, dae: pydynamicestimator.system.Dae, omega_ref_vec, omega_b)[source]

Return the omega_c vector and write dae.f[delta_c] (the angle dynamics). Grid-forming variants also set host.omega_c; grid-following variants leave it unset and read host.pll_frequency(dae) instead.

Parameters:

dae (pydynamicestimator.system.Dae)

pydynamicestimator.devices.inverter_angle.ANGLE_REGISTRY: Dict[str, type]