Dynamic Models

Below is the list of all dynamic models used in the system. The corresponding classes are located in the ./devices directory. The following documentation describes the mathematical equations and the python implementation. Detailed instructions on how to create user-defined models aro not yet available.

Metaclass

All devices are derived from

class pydynamicestimator.devices.device.DeviceRect[source]

Dynamic or static device modeled in rectangular coordinates. Used as a parent class for all devices modeled in rectangular coordinates.

properties

Flags for method calls (e.g., ‘gcall’, ‘fcall’).

Type:

dict[str, bool]

xf

Final state results for simulation/estimation.

Type:

dict[str, np.ndarray]

xinit

Initial state values for all devices of the instance.

Type:

dict[State, list[float]]

xmin

Minimum limited state value.

Type:

list[float]

xmax

Maximum limited state value.

Type:

list[float]

_params

Device parameters, such as rated voltage, power, and frequency and internal parameters.

Type:

dict[str, float]

_data

Additional data which will be used in a list, one entry for each device of this object instance.

Type:

dict[str, str]

bus

Buses where the device is connected. Each device has an entry in the list.

Type:

list[Optional[str]]

states

State variables.

Type:

list[States]

units

Units of state variables.

Type:

list[States]

ns

Total number of states in the model.

Type:

float

_states_noise

Noise for each state variable.

Type:

dict[States, float]

_states_init_error

Initial error for each state variable.

Type:

dict[States, float]

vre

Order of the real voltage value for each device in the overall DAE model.

Type:

list[float]

vim

Order of the real voltage value for each device in the overall DAE model.

Type:

list[float]

_algebs

Algebraic variables (‘vre’, ‘vim’).

Type:

list[str]

_descr

Descriptions for key parameters.

Type:

dict[str, str]

The method for generating the differential and algebraic equations in each model is:

pydynamicestimator.devices.device.DeviceRect.fgcall(self, dae)

A method that executes the differential and algebraic equations of the model and adds them to the appropriate places in the Dae class

Parameters:

dae (Dae) – an instance of a class Dae

Returns:

None

Return type:

None

Synchronous Generator Transient Model

The Synchronous Generator Transient Model provides a two-axis dynamic approximation of a synchronous generator. It is based on the formulation provided in [1].

Python Implementation

class pydynamicestimator.devices.synchronous.SynchronousTransient(avr=None, governor=None, pss=None, shaft=None)[source]

Transient two-axis SG with TGOV1 governor and IEEEDC1A AVR

Rotor Dynamics

\[\begin{split}\dot{\delta} &= 2 \pi f_n \Delta \omega \\ \Delta \dot{\omega} &= \frac{1}{2 H} \left( P_m - E_d I_d - E_q I_q + (X_q' - X_d') I_d I_q - D \Delta \omega - f (\Delta \omega + 1) \right)\end{split}\]

Electromagnetic Equations

\[\begin{split}\dot{E}_q &= \frac{1}{T_{d'}} \left( -E_q + E_f + (X_d - X_d') I_d \right)\\ \dot{E}_d &= \frac{1}{T_{q'}} \left( -E_d - (X_q - X_q') I_q \right)\end{split}\]

Excitation System Equations

\[\begin{split} \dot{E}_{\textup{fd}} &= \frac{1}{T_{E}} \left( -K_{E,i}E_{\textup{fd},i} + V_{R,i}\right)\\ \dot{R}_{f} &= \frac{1}{T_{F} } \left(- R_{f} + \frac{K_{F}}{T_{F}}E_{\textup{fd}} \right)\\ \dot{V}_{R} &= \frac{1}{T_{A}} \left(-V_{R} + K_{A}R_{f} - \frac{K_{A}K_{F}}{T_{F}}E_{\textup{fd}} + K_{A}(v_{\textup{ref}} - v_i) \right)\end{split}\]

Turbine-Governor System Equations

\[\begin{split}\dot{p}_{\textup{m}} &= \frac{1}{T_{ch}} \left( p_{\textup{sv}}- p_{\textup{m}} \right)\\ \dot{p}_{sv} &= \frac{1}{T_{sv}} \left( - \frac{\Delta \omega}{R_d} - p_{\textup{sv}} + p_{\textup{ref}} \right)\end{split}\]

Synchronous Generator Subtransient Model

The Synchronous Generator Subransient Model provides a dynamic approximation of a synchronous generator based on Anderson-Fauad’s model. It is based on the formulation provided in [1].

Python Implementation

class pydynamicestimator.devices.synchronous.SynchronousSubtransient(avr=None, governor=None, pss=None, shaft=None)[source]
Subtransient Anderson Fouad SG with TGOV1 governor and IEEEDC1A AVR

The subtransient behavior of the synchronous generator is described by the following differential equations:

Rotor Dynamics

\[\begin{split}\dot{\delta} &= 2 \pi f_n \Delta \omega \\ \Delta \dot{\omega} &= \frac{1}{2 H} \Big( P_m - E_{d}^{\prime\prime} I_d - E_{q}^{\prime\prime} I_q + (X_q^{\prime\prime} - X_d^{\prime\prime}) I_d I_q - D \Delta \omega - f (\Delta \omega + 1) \Big) \\\end{split}\]

Electromagnetic Equations

\[\begin{split}\dot{E}_q^{\prime} &= \frac{1}{T_{d}^{\prime}} \Big( -E_q + E_f + (X_d - X_d^{\prime}) I_d \Big) \\ \dot{E}_d^{\prime} &= \frac{1}{T_{q}^{\prime}} \Big( -E_d - (X_q - X_q^{\prime}) I_q \Big) \\ \dot{E}_{q}^{\prime\prime} &= \frac{1}{T_{d}^{\prime\prime}} \Big( E_q - E_{q}^{\prime\prime} + (X_d^{\prime} - X_d^{\prime\prime}) I_d \Big) \\ \dot{E}_{d}^{\prime\prime} &= \frac{1}{T_{q}^{\prime\prime}} \Big( E_d - E_{d}^{\prime\prime} - (X_q^{\prime} - X_q^{\prime\prime}) I_q \Big) \\\end{split}\]

Excitation System Equations

\[\begin{split} \dot{E}_{\textup{fd}} &= \frac{1}{T_{E}} \left( -K_{E,i}E_{\textup{fd},i} + V_{R,i}\right)\\ \dot{R}_{f} &= \frac{1}{T_{F} } \left(- R_{f} + \frac{K_{F}}{T_{F}}E_{\textup{fd}} \right)\\ \dot{V}_{R} &= \frac{1}{T_{A}} \left(-V_{R} + K_{A}R_{f} - \frac{K_{A}K_{F}}{T_{F}}E_{\textup{fd}} + K_{A}(v_{\textup{ref}} - v_i) \right)\end{split}\]

Turbine-Governor System Equations

\[\begin{split}\dot{p}_{\textup{m}} &= \frac{1}{T_{ch}} \left( p_{\textup{sv}}- p_{\textup{m}} \right)\\ \dot{p}_{sv} &= \frac{1}{T_{sv}} \left( - \frac{\Delta \omega}{R_d} - p_{\textup{sv}} + p_{\textup{ref}} \right)\end{split}\]

Synchronous Generator Subtransient Model (with Stator Dynamics)

The Synchronous Generator Subtransient Model with Stator Dynamics provides a dynamic approximation of a synchronous generator, including stator dynamics, based on the formulation by Sauer and Pai. It extends the standard subtransient model by incorporating additional stator field dynamics, as described in [3].

Python Implementation

class pydynamicestimator.devices.synchronous.SynchronousSubtransientSP(avr=None, governor=None, pss=None, shaft=None)[source]
Subtransient Sauer and Pai SG model with stator dynamics

with TGOV1 governor and IEEEDC1A AVR

The model includes the following equations for rotor dynamics, stator dynamics, and the excitation system:

Rotor Dynamics

\[\begin{split}\dot{\delta} &= 2 \pi f_n \Delta \omega \\ \Delta \dot{\omega} &= \frac{1}{2 H} \Big( P_m - (\psi_d I_q - \psi_q I_d) - D \Delta \omega - f (\Delta \omega + 1) \Big)\end{split}\]

Electromagnetic Equations

The stator dynamics include the following equations for the flux linkages in the d and q axes:

\[\begin{split}\dot{E}_d' &= \frac{1}{T_q'} \Big( -E_d' + (X_q - X_q') (i_q - g_{q2} \Psi_{q2} - (1 - g_{q1}) i_q - g_{q2} E_d') \Big) \\ \dot{E}_q' &= \frac{1}{T_d'} \Big( -E_q' - (X_d - X_d') (i_d - g_{d2} \Psi_{d2} - (1 - g_{d1}) i_d + g_{d2} E_q') + E_f \Big)\\ \dot{\Psi}_{d2} &= \frac{1}{T_{d2}} \Big( -\Psi_{d2} + E_q' - (X_d' - X_l) i_d \Big) \\ \dot{\Psi}_{q2} &= \frac{1}{T_{q2}} \Big( -\Psi_{q2} - E_d' - (X_q' - X_l) i_q \Big)\end{split}\]

Flux Linkage Dynamics

The following equations describe the stator flux linkage dynamics in the d and q axes:

\[\begin{split}\dot{\Psi}_d &= 2 \pi f_n (R_s i_d + (1 + \Delta \omega) \Psi_q + v_d) \\ \dot{\Psi}_q &= 2 \pi f_n (R_s i_q - (1 + \Delta \omega) \Psi_d + v_q)\end{split}\]

Algebraic Equations

The following algebraic equations govern the system:

\[\begin{split}i_d &= \frac{1}{x_d''} \Big( -\psi_d + g_{d1} e_q' + (1 - g_{d1}) \psi_{d2} \Big)\\ i_q &= \frac{1}{x_q''} \Big( -\psi_q - g_{q1} e_d' + (1 - g_{q1}) \psi_{q2} \Big)\\ g_{d1} &= \frac{x_d'' - x_l}{x_d' - x_l}\\ g_{q1} &= \frac{x_q'' - x_l}{x_q' - x_l}\\ g_{d2} &= \frac{1 - g_{d1}}{x_d' - x_l}\\ g_{q2} &= \frac{1 - g_{q1}}{x_q' - x_l}\end{split}\]

Synchronous Generator Subtransient Model (without Stator Dynamics)

The Synchronous Generator Subtransient Model without Stator Dynamics provides a dynamic approximation of a synchronous generator, based on the formulation by Sauer and Pai. The stator dynamics are neglected making the model 6th order [3].

Python Implementation

class pydynamicestimator.devices.synchronous.SynchronousSubtransientSP6(avr=None, governor=None, pss=None, shaft=None)[source]
Subtransient Sauer and Pai SG 6th order model with neglected stator dynamics

(stator modeled with algebraic equations) and included TGOV1 governor and IEEEDC1A AVR

The model includes the following equations:

Rotor Dynamics

\[\begin{split}\dot{\delta} &= 2 \pi f_n \Delta \omega \\ \Delta \dot{\omega} &= \frac{1}{2 H} \Big( P_m - (\psi_d I_q - \psi_q I_d) - D \Delta \omega - f (\Delta \omega + 1) \Big)\end{split}\]

Electromagnetic Equations

The stator dynamics include the following equations for the flux linkages in the d and q axes:

\[\begin{split}\dot{E}_d' &= \frac{1}{T_q'} \Big( -E_d' + (X_q - X_q') (i_q - g_{q2} \Psi_{q2} - (1 - g_{q1}) i_q - g_{q2} E_d') \Big) \\ \dot{E}_q' &= \frac{1}{T_d'} \Big( -E_q' - (X_d - X_d') (i_d - g_{d2} \Psi_{d2} - (1 - g_{d1}) i_d + g_{d2} E_q') + E_f \Big)\\ \dot{\Psi}_{d2} &= \frac{1}{T_{d2}} \Big( -\Psi_{d2} + E_q' - (X_d' - X_l) i_d \Big) \\ \dot{\Psi}_{q2} &= \frac{1}{T_{q2}} \Big( -\Psi_{q2} - E_d' - (X_q' - X_l) i_q \Big)\end{split}\]

Flux Linkage Dynamics

The following equations describe the stator flux linkage dynamics in the d and q axes:

Algebraic Equations

The following algebraic equations govern the system:

\[\begin{split}0 &=-i_d +\frac{1}{x_d''} \Big( -\psi_d + g_{d1} e_q' + (1 - g_{d1}) \psi_{d2} \Big)\\ 0&=-i_q +\frac{1}{x_q''} \Big( -\psi_q - g_{q1} e_d' + (1 - g_{q1}) \psi_{q2} \Big)\\ 0&= R_s i_d + (1 + \Delta \omega) \Psi_q + v_d \\ 0&= R_s i_q - (1 + \Delta \omega) \Psi_d + v_q \\ g_{d1} &= \frac{x_d'' - x_l}{x_d' - x_l}\\ g_{q1} &= \frac{x_q'' - x_l}{x_q' - x_l}\\ g_{d2} &= \frac{1 - g_{d1}}{x_d' - x_l}\\ g_{q2} &= \frac{1 - g_{q1}}{x_q' - x_l}\end{split}\]

Converter Metaclass

This is the parent class for all inverter models. It introduces all necessary parameters and also stores the model initialization details with a custom script.

class pydynamicestimator.devices.inverter.Inverter(filter=None, pll=None, angle=None, voltage=None, inner=None)[source]

Metaclass for inverters

current_ref(dae)[source]

Inner current references (ifd_ref, ifq_ref), host-mediated: published by the inner strategy and read back by its own current loop. A symbolic intermediate today; when the current limiter (b1) lands it will resolve to a saturated var_sym algebraic (i* = sat(iref)), with no consumer change – this accessor is that interception seam.

Parameters:

dae (Dae)

fgcall(dae)[source]

Orchestrate the pluggable converter strategies into the DAE residual.

The host owns only the cross-cutting glue: the reference-frame frequency, the Park transforms into the converter frame, the power measurement, and the power-measurement filters. Everything else is delegated, in signal-flow order: PLL -> angle source (omega_c, delta_c) -> voltage control (Vcd) -> inner control (Vsw) -> filter (LCL). Each strategy reads host params/states by attribute and writes its own equations; the host threads the symbolic intermediates (omega_c, Vcd, Vsw) between them.

Return type:

None

Parameters:

dae (Dae)

finit_anchor_residuals(dae)[source]

Extra steady-state anchor residuals (each an n-vector that must equal 0) a device declares to keep its initialization Newton system square.

The generic finit() pins each device’s state ODEs (f = 0) plus two quantities through the bus-current balance (g[vre]/g[vim]), so the square-system invariant is n_setpoints == 2 (the SG: Pref + Vref). A device with more setpoints returns n_setpoints - 2 anchor residuals to balance them. Empty by default -> existing devices are unaffected.

Example – the inverter has 3 setpoints (Pref/Qref/Vref) but the bus equations pin only 2; it returns one anchor (Qref = Qc) here. See docs/inverter_modernization_design.md §7.

Return type:

list

Parameters:

dae (Dae)

pll_frequency(dae)[source]

Synchronizing frequency from the PLL, host-mediated (the PSS-style coupling): the PLL’s omega_pll when a PLL strategy is present, else the nominal omega_net (no PLL => no estimate). A consumer reads this accessor and never references the PLL strategy directly.

Return type:

SX

Parameters:

dae (Dae)

switching_voltage(dae)[source]

Switching voltage (Vswd, Vswq) in the network frame, host-mediated: published by the inner strategy and read by the filter. A symbolic intermediate, not a DAE variable (byte-identical).

Parameters:

dae (Dae)

static to_external(d_int, q_int, delta)[source]

Park-rotate (d, q) from the converter (internal) frame back to the network (external) frame defined by angle delta.

static to_internal(d_ext, q_ext, delta)[source]

Park-rotate (d, q) from the network (external) frame into the converter (internal) frame defined by angle delta.

var_sym(dae, name)[source]

Resolve a registered variable name to its symbol wherever it lives: dae.y for a device-private algebraic, dae.x for a differential state. Lets the converter equations read a coupling quantity (a filter state, the frame angle, …) without knowing whether a given realization made it a state or an algebraic – e.g. the dynamic LCL filter (states) vs a future quasi-static LCL_static (algebraics). Mirrors Synchronous.var_sym; today every inverter variable is a state, so this resolves to dae.x.

Return type:

SX

Parameters:
  • dae (Dae)

  • name (str)

voltage_command(dae)[source]

Voltage-magnitude reference Vcd, host-mediated: published on the host by the voltage strategy’s fgcall and read here by the inner controller. A symbolic intermediate, not a DAE variable (byte-identical).

Return type:

SX

Parameters:

dae (Dae)

Grid-Following Converter

The Grid-Following Converter Model provides a dynamic representation of a grid-following inverter. It captures the small-signal stability behavior in low-inertia power systems, as described in [2].

Python Implementation

class pydynamicestimator.devices.inverter.GridFollowing(filter=None, angle=None, voltage=None, inner=None, pll=None)[source]
Grid-Following Inverter (with Droop)

Based on the grid-following inverter model in https://doi.org/10.1109/TPWRS.2021.3061434

The dynamic behavior of the grid-following converter is described by the following differential equations:

Converter Voltage Dynamics

\[\dot{v}_{fd_{ext}} = \frac{\omega_{b}}{c_{f}}(i_{fd_{ext}} - i_{td_{ext}}) + \omega_{net}\omega_{b}v_{fq_{ext}}\]
\[\dot{v}_{fq_{ext}} = \frac{\omega_{b}}{c_{f}}(i_{fq_{ext}} - i_{tq_{ext}}) - \omega_{net}\omega_{b}v_{fd_{ext}}\]

Converter Current Dynamics

\[\dot{i}_{fd_{ext}} = \frac{\omega_{b}}{l_{f}}(v_{swd} - v_{fd_{ext}}) - \frac{\omega_{b}r_{f}}{l_{f}}i_{fd_{ext}} + \omega_{net}\omega_{b}i_{fq_{ext}}\]
\[\dot{i}_{fq_{ext}} = \frac{\omega_{b}}{l_{f}}(v_{swq} - v_{fq_{ext}}) - \frac{\omega_{b}r_{f}}{l_{f}}i_{fq_{ext}} - \omega_{net}\omega_{b}i_{fd_{ext}}\]

Grid-Side Current Dynamics

\[\dot{i}_{td_{ext}} = \frac{\omega_b}{l_t}(v_{fd_{ext}} - v_{n_{re}}) - \frac{\omega_b r_t}{l_t}i_{td_{ext}} + \omega_{net} \omega_b i_{tq_{ext}}\]
\[\dot{i}_{tq_{ext}} = \frac{\omega_b}{l_t}(v_{fq_{ext}} - v_{n_{im}}) - \frac{\omega_b r_t}{l_t}i_{tq_{ext}} - \omega_{net} \omega_b i_{td_{ext}}\]

Phase-Locked Loop (PLL) Dynamics

\[\dot{\epsilon} = v_{fq_{pll}}\]
\[\delta\dot{\theta}_{pll} = \omega_{b}\delta\omega_{pll}\]

Power and Frequency Dynamics

\[\dot{\tilde{p}}_{c} = \omega_{f}(p_{c} - \tilde{p}_{c})\]
\[\delta\dot{\theta}_{c} = \omega_{b}\delta\omega_{c}\]
\[\dot{\tilde{q}}_{c} = \omega_{f}(q_{c} - \tilde{q}_{c})\]

Control Dynamics

\[\dot{\xi}_{d} = v_{fd^{*}} - v_{fd_{int}}\]
\[\dot{\xi}_{q} = v_{fq^{*}} - v_{fq_{int}}\]
\[\dot{\gamma}_{d} = i_{fd^{*}} - i_{fd_{int}}\]
\[\dot{\gamma}_{q} = i_{fq^{*}} - i_{fq_{int}}\]

Grid-Forming Converter

The Grid-Forming Converter Model provides a dynamic representation of a grid-forming inverter. It captures the small-signal stability behavior in low-inertia power systems, as described in [2].

Python Implementation

class pydynamicestimator.devices.inverter.GridForming(filter=None, angle=None, voltage=None, inner=None, pll=None)[source]
Grid-Forming Inverter (Droop-Based)

Based on the grid-forming inverter model in https://doi.org/10.1109/TPWRS.2021.3061434 The dynamic behavior of the grid-forming converter is described by the following differential equations:

Converter Voltage Dynamics

\[\dot{v}_{fd_{ext}} = \frac{\omega_{b}}{c_{f}}(i_{fd_{ext}} - i_{td_{ext}}) + \omega_{net}\omega_{b}v_{fq_{ext}}\]
\[\dot{v}_{fq_{ext}} = \frac{\omega_{b}}{c_{f}}(i_{fq_{ext}} - i_{tq_{ext}}) - \omega_{net}\omega_{b}v_{fd_{ext}}\]

Converter Current Dynamics

\[\dot{i}_{fd_{ext}} = \frac{\omega_{b}}{l_{f}}(v_{swd} - v_{fd_{ext}}) - \frac{\omega_{b}r_{f}}{l_{f}}i_{fd_{ext}} + \omega_{net}\omega_{b}i_{fq_{ext}}\]
\[\dot{i}_{fq_{ext}} = \frac{\omega_{b}}{l_{f}}(v_{swq} - v_{fq_{ext}}) - \frac{\omega_{b}r_{f}}{l_{f}}i_{fq_{ext}} - \omega_{net}\omega_{b}i_{fd_{ext}}\]

Grid-Side Current Dynamics

\[\dot{i}_{td_{ext}} = \frac{\omega_b}{l_t}(v_{fd_{ext}} - v_{n_{re}}) - \frac{\omega_b r_t}{l_t}i_{td_{ext}} + \omega_{net} \omega_b i_{tq_{ext}}\]
\[\dot{i}_{tq_{ext}} = \frac{\omega_b}{l_t}(v_{fq_{ext}} - v_{n_{im}}) - \frac{\omega_b r_t}{l_t}i_{tq_{ext}} - \omega_{net} \omega_b i_{td_{ext}}\]

Power and Frequency Dynamics

\[\dot{\tilde{p}}_{c} = \omega_{f}(p_{c} - \tilde{p}_{c})\]
\[\delta\dot{\theta}_{c} = \omega_{b}\delta\omega_{c}\]
\[\dot{\tilde{q}}_{c} = \omega_{f}(q_{c} - \tilde{q}_{c})\]

Control Dynamics

\[\dot{\xi}_{d} = v_{fd^{*}} - v_{fd_{int}}\]
\[\dot{\xi}_{q} = v_{fq^{*}} - v_{fq_{int}}\]
\[\dot{\gamma}_{d} = i_{fd^{*}} - i_{fd_{int}}\]
\[\dot{\gamma}_{q} = i_{fq^{*}} - i_{fq_{int}}\]

References