14. Inspecting Model Equations#
One of the key features of ANDES is its symbolic-numeric hybrid framework, which allows you to inspect the mathematical equations that define each model. This capability is invaluable for understanding model behavior, debugging simulations, and verifying that models are implemented correctly.
Every model in ANDES is defined symbolically using SymPy, and the framework automatically generates numerical code for efficient simulation. This tutorial shows how to access and examine the symbolic equations, variables, and services that comprise each model.
14.1. Setup#
%matplotlib inline
import andes
andes.config_logger(30) # Reduce logging verbosity
14.2. Listing Available Models#
To see all models supported by ANDES, create an empty System object and call supported_models(). Models are organized into groups based on their function in the power system.
ss = andes.System()
print(ss.supported_models())
Supported Groups and Models
Group | Models
-------------------+----------------------------------------------------------
ACLine | Line
ACNode | Bus
ACShort | Jumper
Calculation | ACE, ACEc, COI
Collection | Area
DCLink | Ground, R, L, C, RCp, RCs, RLs, RLCs, RLCp
DCTopology | Node
DG | PVD1, ESD1, EV1, EV2
DGProtection | DGPRCT1, DGPRCTExt
DataSeries | TimeSeries
DynLoad | ZIP, FLoad
DynShaft | SHAFT5
Exciter | EXDC2, IEEEX1, ESDC1A, ESDC2A, EXST1, ESST3A, SEXS,
| IEEET1, EXAC1, EXAC2, EXAC4, ESST4B, AC8B, IEEET3,
| ESAC1A, ESST1A, ESAC5A
FreqMeasurement | BusFreq, BusROCOF, FreqDiv
Information | Summary
Interface | Fortescue
Motor | Motor3, Motor5
OutputSelect | Output
PLL | PLL1, PLL2
PSS | IEEEST, ST2CUT
PhasorMeasurement | PMU
RenAerodynamics | WTARA1, WTARV1
RenExciter | REECA1, REECA1E, REECA1G, REECB1
RenGen | REGCA1, REGCP1, REGCV1, REGCV2, REGF1, REGF2, REGF3
RenGovernor | WTDTA1, WTDS
RenPitch | WTPTA1
RenPlant | REPCA1
RenTorque | WTTQA1
StaticACDC | VSCShunt
StaticGen | PV, Slack
StaticLoad | PQ
StaticShunt | Shunt, ShuntTD, ShuntSw
SynGen | GENCLS, GENROU, PLBVFU1
TimedEvent | Toggle, Fault, Alter
TurbineGov | TG2, TGOV1, TGOV1DB, TGOV1N, TGOV1NDB, IEEEG1, IEESGO,
| GAST, HYGOV, HYGOVDB, HYGOV4
VoltComp | IEEEVC
14.3. Preparing Model Equations#
Before inspecting a model's symbolic equations, you need to call prepare() on that model. This triggers the symbolic processing that generates the equations and Jacobian matrices. For a single model, this is fast; preparing all models takes longer but is still manageable.
# Prepare equations for the GENCLS model (classical generator)
ss.GENCLS.prepare()
14.4. Model Documentation#
Each model provides comprehensive documentation through the doc() method. This returns a formatted string containing:
Model description and group membership
Parameter definitions with units and defaults
Variable definitions (states and algebraics)
Initialization equations
Differential and algebraic equations
Service definitions
Configuration options
print(ss.GENCLS.doc())
Model <GENCLS> in Group <SynGen>
Classical generator model.
Parameters
Name | Description | Default | Unit | Properties
--------+--------------------------+---------+------+-------------------------
idx | unique device idx | | |
u | connection status | 1 | bool |
name | device name | | |
bus | interface bus id | | | mandatory
gen | static generator index | | | mandatory
coi | center of inertia index | | |
coi2 | center of inertia index | | |
Sn | Power rating | 100 | MVA |
Vn | AC voltage rating | 110 | |
fn | rated frequency | 60 | |
D | Damping coefficient | 0 | | power
M | machine start up time | 6 | | non_zero,non_negative,po
| (2H) | | | wer
ra | armature resistance | 0 | | z
xl | leakage reactance | 0 | | z
xd1 | d-axis transient | 0.302 | | z
| reactance | | |
kp | active power feedback | 0 | |
| gain | | |
kw | speed feedback gain | 0 | |
S10 | first saturation factor | 0 | |
S12 | second saturation factor | 1 | |
gammap | P ratio of linked static | 1 | |
| gen | | |
gammaq | Q ratio of linked static | 1 | |
| gen | | |
ue | effective online status | 0 | |
subidx | Generator idx in plant; | 0 | |
| only used by PSS/E data | | |
Variables
Name | Type | Description | Unit | Properties
--------+----------+-----------------------------------+----------+-----------
delta | State | rotor angle | rad | v_str
omega | State | rotor speed | pu (Hz) | v_str
Id | Algeb | d-axis current | | v_str
Iq | Algeb | q-axis current | | v_str
vd | Algeb | d-axis voltage | | v_str
vq | Algeb | q-axis voltage | | v_str
tm | Algeb | mechanical torque | | v_str
te | Algeb | electric torque | | v_str
vf | Algeb | excitation voltage | pu | v_str
XadIfd | Algeb | d-axis armature excitation | p.u (kV) | v_str
| | current | |
Pe | Algeb | active power injection | | v_str
Qe | Algeb | reactive power injection | | v_str
psid | Algeb | d-axis flux | | v_str
psiq | Algeb | q-axis flux | | v_str
a | ExtAlgeb | Bus voltage phase angle | |
v | ExtAlgeb | Bus voltage magnitude | |
Initialization Equations
Name | Type | Initial Value
--------+----------+----------------------------
delta | State | delta0
omega | State | u
Id | Algeb | u * Id0
Iq | Algeb | u * Iq0
vd | Algeb | u * vd0
vq | Algeb | u * vq0
tm | Algeb | tm0
te | Algeb | u * tm0
vf | Algeb | u * vf0
XadIfd | Algeb | u * vf0
Pe | Algeb | u * (vd0 * Id0 + vq0 * Iq0)
Qe | Algeb | u * (vq0 * Id0 - vd0 * Iq0)
psid | Algeb | u * psid0
psiq | Algeb | u * psiq0
a | ExtAlgeb |
v | ExtAlgeb |
Differential Equations
Name | Type | RHS of Equation "T x' = f(x, y)" | T (LHS)
-------+-------+----------------------------------+--------
delta | State | ue * (2 * pi * fn) * (omega - 1) |
omega | State | ue * (tm - te - D * (omega - 1)) | M
Algebraic Equations
Name | Type | RHS of Equation "0 = g(x, y)"
--------+----------+----------------------------------
Id | Algeb | + xq * Id - vf+ psid
Iq | Algeb | + xq * Iq+ psiq
vd | Algeb | ue * v * sin(delta - a) - vd
vq | Algeb | ue * v * cos(delta - a) - vq
tm | Algeb | tm0 - tm
te | Algeb | ue * (psid * Iq - psiq * Id) - te
vf | Algeb | ue * vf0 - vf
XadIfd | Algeb | ue * vf0 - XadIfd
Pe | Algeb | ue * (vd * Id + vq * Iq) - Pe
Qe | Algeb | ue * (vq * Id - vd * Iq) - Qe
psid | Algeb | ue * (ra*Iq + vq) - psid
psiq | Algeb | ue * (ra*Id + vd) + psiq
a | ExtAlgeb | -ue * (vd * Id + vq * Iq)
v | ExtAlgeb | -ue * (vq * Id - vd * Iq)
Services
Name | Equation | Type
---------+------------------------------------------------------+-------------
p0 | p0s * gammap | ConstService
q0 | q0s * gammaq | ConstService
_V | v * exp(1j * a) | ConstService
_S | p0 - 1j * q0 | ConstService
_I | _S / conj(_V) | ConstService
_E | _V + _I * (ra + 1j * xq) | ConstService
_deltac | log(_E / abs(_E)) | ConstService
delta0 | u * im(_deltac) | ConstService
vdq | u * (_V * exp(1j * 0.5 * pi - _deltac)) | ConstService
Idq | u * (_I * exp(1j * 0.5 * pi - _deltac)) | ConstService
Id0 | re(Idq) | ConstService
Iq0 | im(Idq) | ConstService
vd0 | re(vdq) | ConstService
vq0 | im(vdq) | ConstService
tm0 | u * ((vq0 + ra * Iq0) * Iq0 + (vd0 + ra * Id0) * | ConstService
| Id0) |
psid0 | u * (ra * Iq0) + vq0 | ConstService
psiq0 | -u * (ra * Id0) - vd0 | ConstService
vf0 | (vq0 + ra * Iq0) + xq * Id0 | ConstService
Setpoints
Name | Target | Info
------+--------+-----
pref | tm0 |
vref | vf0 |
Config Fields in [GENCLS]
Option | Value | Info | Acceptable values
--------------+-------+------------------------------------+------------------
allow_adjust | 1 | allow adjusting upper or lower | (0, 1)
| | limits |
adjust_lower | 0 | adjust lower limit | (0, 1)
adjust_upper | 1 | adjust upper limit | (0, 1)
vf_lower | 1 | lower limit for vf warning |
vf_upper | 5 | upper limit for vf warning |
The documentation shows that GENCLS (classical generator) has two state variables (delta for rotor angle and omega for rotor speed) and several algebraic variables for currents, voltages, and power outputs. The differential equations implement the swing equation that governs generator dynamics.
14.5. Accessing Variables#
Model variables are stored in ordered dictionaries accessible through states and algebs attributes. This lets you enumerate all variables programmatically.
# State (differential) variables
print("State variables:")
for name, var in ss.GENCLS.states.items():
print(f" {name}: {var}")
State variables:
delta: State: GENCLS.delta, []
omega: State: GENCLS.omega, []
# Algebraic variables
print("Algebraic variables:")
for name, var in ss.GENCLS.algebs.items():
print(f" {name}: {var}")
Algebraic variables:
Id: Algeb: GENCLS.Id, []
Iq: Algeb: GENCLS.Iq, []
vd: Algeb: GENCLS.vd, []
vq: Algeb: GENCLS.vq, []
tm: Algeb: GENCLS.tm, []
te: Algeb: GENCLS.te, []
vf: Algeb: GENCLS.vf, []
XadIfd: Algeb: GENCLS.XadIfd, []
Pe: Algeb: GENCLS.Pe, []
Qe: Algeb: GENCLS.Qe, []
psid: Algeb: GENCLS.psid, []
psiq: Algeb: GENCLS.psiq, []
14.6. Symbolic Equations#
The symbolic equations are stored in Model.syms. This object contains SymPy expressions that can be displayed, manipulated, and analyzed. The main attributes are:
Attribute |
Contents |
|---|---|
|
Vector of all variables (states then algebraics) |
|
Differential equations (right-hand side of T x' = f) |
|
Algebraic equations (right-hand side of 0 = g) |
|
Jacobian df/dxy |
|
Jacobian dg/dxy |
|
Service equations |
# All variables in order
ss.GENCLS.syms.xy
14.6.1. Differential Equations#
The differential equations define how state variables evolve over time. For generators, these typically include the swing equation relating rotor angle and speed to mechanical and electrical torque.
ss.GENCLS.syms.f
The first equation is the rotor angle dynamics: d(delta)/dt = 2*pi*fn*(omega - 1), where omega is in per-unit of nominal frequency. The second equation is the swing equation: M*d(omega)/dt = tm - te - D*(omega - 1), relating acceleration to the imbalance between mechanical torque tm and electrical torque te, with damping D.
14.6.2. Algebraic Equations#
Algebraic equations define relationships that must hold at every instant (they have no time derivative). These typically include current-voltage relationships, power calculations, and interface equations.
ss.GENCLS.syms.g
14.6.3. Jacobian Matrices#
The Jacobian matrices contain partial derivatives of the equations with respect to variables. These are essential for Newton-Raphson iteration in power flow and implicit integration in time-domain simulation.
# Jacobian of differential equations
ss.GENCLS.syms.df
# Jacobian of algebraic equations (first 4 rows, first 6 columns)
ss.GENCLS.syms.dg[:4, :6]
14.7. Services#
Services are intermediate calculations that are computed once (at initialization) and reused throughout the simulation. They often represent derived quantities like initial values or converted parameters.
# List all services
print("Services:")
for name, svc in ss.GENCLS.services.items():
print(f" {name}")
Services:
p0
q0
_V
_S
_I
_E
_deltac
delta0
vdq
Idq
Id0
Iq0
vd0
vq0
tm0
psid0
psiq0
vf0
# Service equations
ss.GENCLS.syms.s
[gammap*p0s,
gammaq*q0s,
v*exp(I*a),
p0 - I*q0,
_S/conj(_V),
_I*(ra + I*xq) + _V,
log(_E/Abs(_E)),
u*im(_deltac),
_V*u*exp(-_deltac + 0.5*I*pi),
_I*u*exp(-_deltac + 0.5*I*pi),
re(Idq),
im(Idq),
re(vdq),
im(vdq),
u*(Id0*(Id0*ra + vd0) + Iq0*(Iq0*ra + vq0)),
Iq0*ra*u + vq0,
-Id0*ra*u - vd0,
Id0*xq + Iq0*ra + vq0]
14.8. Practical Applications#
Understanding model equations is useful for:
Verification: Confirming that a model implements the expected physics
Debugging: Identifying why a simulation produces unexpected results
Extension: Understanding the structure before adding new features
Documentation: Generating mathematical descriptions for papers or reports
Teaching: Demonstrating power system dynamics concepts
14.9. See Also#
Hybrid Symbolic-Numeric Framework - Overview of the symbolic-numeric framework
Variables - Detailed variable type documentation
Creating Models - Creating new models