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

xy

Vector of all variables (states then algebraics)

f

Differential equations (right-hand side of T x' = f)

g

Algebraic equations (right-hand side of 0 = g)

df

Jacobian df/dxy

dg

Jacobian dg/dxy

s

Service equations

# All variables in order
ss.GENCLS.syms.xy
\[\begin{split}\displaystyle \left[\begin{matrix}\delta\\\omega\\Id\\Iq\\vd\\vq\\tm\\te\\vf\\XadIfd\\Pe\\Qe\\psid\\psiq\\a\\v\end{matrix}\right]\end{split}\]

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
\[\begin{split}\displaystyle \left[\begin{matrix}2 \pi fn ue \left(\omega - 1\right)\\ue \left(- D \left(\omega - 1\right) - te + tm\right)\end{matrix}\right]\end{split}\]

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
\[\begin{split}\displaystyle \left[\begin{matrix}Id xq + psid - vf\\Iq xq + psiq\\- ue v \sin{\left(a - \delta \right)} - vd\\ue v \cos{\left(a - \delta \right)} - vq\\- tm + tm_{0}\\- te + ue \left(- Id psiq + Iq psid\right)\\ue vf_{0} - vf\\- XadIfd + ue vf_{0}\\- Pe + ue \left(Id vd + Iq vq\right)\\- Qe + ue \left(Id vq - Iq vd\right)\\- psid + ue \left(Iq ra + vq\right)\\psiq + ue \left(Id ra + vd\right)\\- ue \left(Id vd + Iq vq\right)\\- ue \left(Id vq - Iq vd\right)\end{matrix}\right]\end{split}\]

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
\[\begin{split}\displaystyle \left[\begin{array}{cccccccccccccccc}0 & 2 \pi fn ue & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\0 & - D ue & 0 & 0 & 0 & 0 & ue & - ue & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\end{array}\right]\end{split}\]
# Jacobian of algebraic equations (first 4 rows, first 6 columns)
ss.GENCLS.syms.dg[:4, :6]
\[\begin{split}\displaystyle \left[\begin{matrix}0 & 0 & xq & 0 & 0 & 0\\0 & 0 & 0 & xq & 0 & 0\\ue v \cos{\left(a - \delta \right)} & 0 & 0 & 0 & -1 & 0\\ue v \sin{\left(a - \delta \right)} & 0 & 0 & 0 & 0 & -1\end{matrix}\right]\end{split}\]

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#