Skip to content

Commit 0b4ab46

Browse files
authored
Use system base for governor-machine power signals (#438)
1 parent b5cc7a3 commit 0b4ab46

19 files changed

Lines changed: 722 additions & 48 deletions

File tree

GridKit/Model/PhasorDynamics/Governor/Tgov1/README.md

Lines changed: 32 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Figure 1: Governor TGOV1 model. Figure courtesy of [PowerWorld](https://www.powe
1212

1313
Symbol | Units | Description | Typical Value | Note
1414
------------|--------|-----------------------------------|---------------| ------
15+
$T_{\mathrm{rate}}$ | [MW] | Turbine rating | 100.0 |
1516
$R$ | [p.u.] | Droop Constant | 0.05 |
1617
$T_1$ | [sec] | Valve Time Delay | 0.5 |
1718
$T_2$ | [sec] | Turbine Numerator Time Constant | 2.5 |
@@ -50,53 +51,60 @@ $P_{ref}$ | [p.u.] | Reference Power | Either a constant
5051

5152
## Model Equations
5253

53-
### Differential Equations
54-
The TGOV1 differential equations, as derived from the model diagram. Define the pre-limit derivative of $P_v$
55-
54+
For readability, define:
5655
```math
57-
f = \dfrac{1}{T_1}\left[-P_v + \dfrac{1}{R}(P_{ref} - \omega)\right]
56+
f = -P_v + \dfrac{1}{R}(P_{ref} - \omega)
5857
```
5958

60-
so that $\dot P_v$ can be written in piecewise form compactly.
59+
### Differential Equations
60+
The TGOV1 differential equations, as derived from the model diagram.
61+
6162
```math
6263
\begin{aligned}
63-
\dot P_{tx} &= P_v - \dfrac{1}{T_3}(P_{tx}+T_2P_v) \\
64-
\dot P_v &=
65-
\begin{cases}
66-
f
67-
& \text{if } (P_v^{\min} < P_v < P_v^{\max}) & \lor \\
68-
& \quad (P_v \leq P_v^{\min} \land f>0) & \lor \\
69-
& \quad(P_v \geq P_v^{\max} \land f<0) \\
70-
0
71-
& \text{else}
72-
\end{cases}
64+
0 &= -T_3 \dot P_{tx} - P_{tx} + (T_3 - T_2)P_v \\
65+
0 &= -T_1 \dot P_v
66+
+ \text{antiwindup}(
67+
P_v,
68+
f,
69+
P_v^{\min},
70+
P_v^{\max}
71+
)
7372
\end{aligned}
7473
```
7574

75+
CommonMath defines the [Anti-Windup](../../../../CommonMath.md#anti-windup-indicator)
76+
target and smooth approximation.
77+
7678
### Algebraic Equations
7779
The algebraic equation dictating the mechnical power output.
7880
```math
7981
\begin{aligned}
80-
P_m &= \dfrac{1}{T_3}(P_{tx}+T_2P_v) - D_t \omega \\
82+
0 &= -\dfrac{S_{\mathrm{sys}}}{T_{\mathrm{rate}}} P_m
83+
+ \dfrac{1}{T_3}(P_{tx}+T_2P_v) - D_t \omega \\
8184
\end{aligned}
8285
```
8386

84-
In simulation the piecewise form above is replaced with a smooth approximation where $\phi$ is GridKit's smooth anti-windup indicator. See [CommonMath: Anti-Windup Indicator](../../../../CommonMath.md#antiwindup) for its definition, behavior, and design rationale.
85-
8687
## Initialization
87-
At steady state we assume that $P_v$ is at or within its limits. This implies the initial conditions are a function of $P_m$ which is equal to the electric torque.
88+
At steady state we assume that $P_v$ is at or within its limits. This implies the initial conditions are a function of the initial mechanical power converted to the TGOV1 component base.
8889
```math
8990
\begin{aligned}
90-
P_{tx} &= (T_3-T_2) P_m\\
91-
P_v &= P_m\\
92-
\dot P_{tx} &=0\\
93-
\dot P_v &=0\\
91+
P^{\mathrm{tgov1}}_{m,0}
92+
&= \dfrac{S_{\mathrm{sys}}}{T_{\mathrm{rate}}}P_{m,0} \\
93+
P_{tx,0}
94+
&= (T_3 - T_2)P^{\mathrm{tgov1}}_{m,0} \\
95+
P_{v,0}
96+
&= P^{\mathrm{tgov1}}_{m,0} \\
97+
\dot P_{tx,0}
98+
&= 0 \\
99+
\dot P_{v,0}
100+
&= 0
94101
\end{aligned}
95102
```
96103

97104
And if the reference power is a constant parameter, we can determine the value by solving the steady state equations.
98105
```math
99106
\begin{aligned}
100-
P_{ref} &= R P_m\\
107+
P_{ref,0}
108+
&= R P^{\mathrm{tgov1}}_{m,0}
101109
\end{aligned}
102110
```

GridKit/Model/PhasorDynamics/Governor/Tgov1/Tgov1.hpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ namespace GridKit
7474
using Component<scalar_type, index_type>::J_rows_buffer_;
7575
using Component<scalar_type, index_type>::J_cols_buffer_;
7676
using Component<scalar_type, index_type>::J_vals_buffer_;
77+
using Component<scalar_type, index_type>::va_system_base_;
7778
using Component<scalar_type, index_type>::variable_indices_;
7879
using Component<scalar_type, index_type>::residual_indices_;
7980

@@ -115,6 +116,7 @@ namespace GridKit
115116

116117
private:
117118
// Input parameters
119+
RealT Trate_{0};
118120
RealT R_{0};
119121
RealT Pvmin_{0};
120122
RealT Pvmax_{0};
@@ -123,14 +125,20 @@ namespace GridKit
123125
RealT T3_{0};
124126
RealT Dt_{0};
125127

128+
// Derived parameters
129+
RealT va_component_base_{0};
130+
126131
// Input States (which can be parameters)
127132
ScalarT pref_{0};
128133

129134
/// Component signal extension
130135
ComponentSignals<ScalarT, IdxT, Tgov1InternalVariables, Tgov1ExternalVariables> signals_;
131136

132137
// Parameter initialization function
133-
void initializeParameters(const ModelDataT& data);
138+
void initializeParameters(const ModelDataT& data);
139+
void setDerivedParams();
140+
ScalarT toComponentBase(ScalarT value) const;
141+
ScalarT toSystemBase(ScalarT value) const;
134142

135143
/* Local copies of signal variables */
136144
std::vector<ScalarT> ws_;

GridKit/Model/PhasorDynamics/Governor/Tgov1/Tgov1Data.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ namespace GridKit
2222
*/
2323
enum class Tgov1Parameters
2424
{
25+
Trate, ///< Turbine-rating power base
2526
R, ///< Droop Constant
2627
T1, ///< Valve Time Delay
2728
T2, ///< Turbine Numerator Time Constant

GridKit/Model/PhasorDynamics/Governor/Tgov1/Tgov1Impl.hpp

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,10 @@ namespace GridKit
3232
*/
3333
template <typename scalar_type, typename index_type>
3434
Tgov1<scalar_type, index_type>::Tgov1()
35+
: Trate_(100.0)
3536
{
3637
size_ = 3;
38+
setDerivedParams();
3739
}
3840

3941
/**
@@ -44,7 +46,8 @@ namespace GridKit
4446
*/
4547
template <typename scalar_type, typename index_type>
4648
Tgov1<scalar_type, index_type>::Tgov1(SignalT* pmech, SignalT* omega)
47-
: R_(0.05),
49+
: Trate_(100.0),
50+
R_(0.05),
4851
Pvmin_(0),
4952
Pvmax_(1),
5053
T1_(HALF<RealT>),
@@ -57,6 +60,7 @@ namespace GridKit
5760

5861
// 3 internal variables
5962
size_ = 3;
63+
setDerivedParams();
6064
}
6165

6266
/**
@@ -69,6 +73,7 @@ namespace GridKit
6973
{
7074
initializeParameters(data);
7175
size_ = 3;
76+
setDerivedParams();
7277
}
7378

7479
/**
@@ -82,6 +87,11 @@ namespace GridKit
8287
template <typename scalar_type, typename index_type>
8388
void Tgov1<scalar_type, index_type>::initializeParameters(const ModelDataT& data)
8489
{
90+
if (data.parameters.contains(ModelDataT::Parameters::Trate))
91+
{
92+
Trate_ = std::get<RealT>(data.parameters.at(ModelDataT::Parameters::Trate));
93+
}
94+
8595
if (data.parameters.contains(ModelDataT::Parameters::R))
8696
{
8797
R_ = std::get<RealT>(data.parameters.at(ModelDataT::Parameters::R));
@@ -118,6 +128,26 @@ namespace GridKit
118128
}
119129
}
120130

131+
template <typename scalar_type, typename index_type>
132+
void Tgov1<scalar_type, index_type>::setDerivedParams()
133+
{
134+
va_component_base_ = Trate_ * static_cast<RealT>(1.0e6);
135+
}
136+
137+
// System base -> component base when reading signals.
138+
template <typename scalar_type, typename index_type>
139+
scalar_type Tgov1<scalar_type, index_type>::toComponentBase(scalar_type value) const
140+
{
141+
return value * va_system_base_ / va_component_base_;
142+
}
143+
144+
// Governor base -> system base for signals output.
145+
template <typename scalar_type, typename index_type>
146+
scalar_type Tgov1<scalar_type, index_type>::toSystemBase(scalar_type value) const
147+
{
148+
return value / toComponentBase(static_cast<scalar_type>(ONE<RealT>));
149+
}
150+
121151
/**
122152
* @brief Set the component ID
123153
*/
@@ -200,7 +230,8 @@ namespace GridKit
200230
// Initial mechanical = initial electric torque
201231
if (signals_.template isAssigned<Tgov1InternalVariables::PM>())
202232
{
203-
p0 = y_[2]; ///<- generator needs to be initialized first
233+
// System base -> governor base for governor initialization.
234+
p0 = toComponentBase(y_[2]); ///<- generator needs to be initialized first
204235
}
205236

206237
// Input Variables (Parameter for now)
@@ -209,7 +240,7 @@ namespace GridKit
209240
// Internal States
210241
y_[0] = (T3_ - T2_) * p0; // y0 - Ptx (Turbine Power )
211242
y_[1] = p0; // y1 - Pv (Valve Position)
212-
y_[2] = p0; // y2 - Pm (Mech Power)
243+
y_[2] = toSystemBase(p0); // y2 - Pm (Mech Power, System Base)
213244

214245
// D.V. Derivative
215246
yp_[0] = 0.0; // Ptx
@@ -276,15 +307,16 @@ namespace GridKit
276307
// Set signal variable aliases
277308
ScalarT omega = ws[0];
278309

279-
// The 'pre-limit' derivative of Pv
280-
ScalarT func = (-pv + (pref_ - omega) / R_) / T1_;
310+
// The 'pre-limit' target of Pv
311+
ScalarT func = -pv + (pref_ - omega) / R_;
281312

282313
// Internal Differential Equations
283-
f[0] = -ptx_dot + pv - (ptx + T2_ * pv) / T3_;
284-
f[1] = -pv_dot + Math::antiwindup(pv, func, Pvmin_, Pvmax_);
314+
f[0] = -T3_ * ptx_dot - ptx + (T3_ - T2_) * pv;
315+
f[1] = -T1_ * pv_dot + Math::antiwindup(pv, func, Pvmin_, Pvmax_);
285316

286317
// Internal Algebraic Equations
287-
f[2] = -pmech + (ptx + T2_ * pv) / T3_ - (Dt_ * omega);
318+
// Convert pmech to component base from its system base value
319+
f[2] = -toComponentBase(pmech) + (ptx + T2_ * pv) / T3_ - (Dt_ * omega);
288320

289321
return 0;
290322
}

GridKit/Model/PhasorDynamics/INPUT_FORMAT.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ are specified:
144144
`Genrou` | 6th order machine model | `bus`, `pmech`\*, `speed`\*, `efd`\* | `p0`, `q0`, `H`, `D`, `Ra`, `Tdop`, `Tdopp`, `Tqop`, `Tqopp`, `Xd`, `Xdp`, `Xdpp`, `Xq`, `Xqp`, `Xqpp`, `Xl`, `S10`, `S12`, `mva` | `ir`, `ii`, `p`, `q`, `delta`, `omega`, `speed`
145145
`Gensal` | 5th order salient-pole machine model | `bus`, `pmech`\*, `speed`\*, `efd`\* | `p0`, `q0`, `H`, `D`, `Ra`, `Tdop`, `Tdopp`, `Tqopp`, `Xd`, `Xdp`, `Xdpp`, `Xq`, `Xl`, `S10`, `S12`, `mva` | `ir`, `ii`, `p`, `q`, `delta`, `omega`, `speed`, `Eqp`, `psidp`, `psiqpp`, `psidpp`, `vd`, `vq`, `te`, `id`, `iq`
146146
`GenClassical` | the classical machine model | `bus`, `pmech`\*, `speed`\*, `efd`\* | `p0`, `q0`, `H`, `D`, `Ra`, `Xdp`, `mva` | `ir`, `ii`, `p`, `q`, `delta`, `omega`
147-
`Tgov1 ` | the TGOV1 governor model | `pmech`, `speed` | `R`, `T1`, `T2`, `T3`, `Pvmax`, `Pvmin`, `Dt` | `none`
147+
`Tgov1 ` | the TGOV1 governor model | `pmech`, `speed` | `Trate`, `R`, `T1`, `T2`, `T3`, `Pvmax`, `Pvmin`, `Dt` | `none`
148148
`Ieeet1` | the IEEET1 exciter model | `bus`, `speed`, `efd`, `vs`\* | `Tr`, `Ka`, `Ta`, `Ke`, `Te`, `Kf`, `Tf`, `Vrmin`, `Vrmax`, `E1`, `E2`, `Se1`, `Se2`, `Ispdlim` | `efd`, `ksat`
149149
`SexsPti` | the SEXS-PTI simplified exciter model | `bus`, `efd`, `vs`\* | `Ta`, `Tb`, `Te`, `K`, `Efdmax`, `Efdmin` | `efd`
150150
`Ieeest` | the IEEEST stabilizer model | `input`, `output` | `A1`, `A2`, `A3`, `A4`, `A5`, `A6`, `T1`, `T2`, `T3`, `T4`, `T5`, `T6`, `Ks`, `Lsmin`, `Lsmax`, `Vcl`, `Vcu`, `Tdelay` | `vss`
@@ -184,7 +184,7 @@ side for off-nominal transformer branches.
184184
"devices": [
185185
{ "class": "Branch", "ports": {"bus1":1, "bus2":2}, "id": "BR1", "params": {"R":0.0, "X":0.1, "G":0.0, "B":0.0} },
186186
{ "class": "Genrou", "ports": {"bus":1, "speed": 1, "pmech":2, "efd":3}, "id": "DV1", "params": {"p0":1.0, "q0":0.05013, "H":3.0, "D":0.0, "Ra":0.0, "Tdop":7.0, "Tdopp":0.04, "Tqopp":0.05, "Tqop":0.75, "Xd":2.1, "Xdp":0.2, "Xdpp":0.18, "Xq":0.5, "Xqp": 0.0, "Xqpp":0.18, "Xl":0.15, "S10":0.0, "S12":0.0}, "mon": ["delta", "omega"] },
187-
{ "class": "Tgov1", "ports": {"bus":1, "speed": 1, "pmech":2}, "id": "DV2", "params": {"R":0.05, "T1":0.5,"T2":2.5, "T3":7.5, "Pvmax":0, "Pvmin":1, "Dt":0}},
187+
{ "class": "Tgov1", "ports": {"bus":1, "speed": 1, "pmech":2}, "id": "DV2", "params": {"Trate":100.0, "R":0.05, "T1":0.5,"T2":2.5, "T3":7.5, "Pvmax":0, "Pvmin":1, "Dt":0}},
188188
{ "class": "Ieeet1", "ports": {"bus":1, "speed": 1, "efd":3}, "id": "DV3", "params": {"Tr":0.001, "Ka":50.0, "Ta":0.04, "Ke":-0.06, "Te":0.6, "Kf":0.09, "Tf":1.46, "Vrmin":-1, "Vrmax":1, "E1":2.8, "E2":3.373, "Se1":0.04, "Se2":0.33, "Ispdlim":0}},
189189
{ "class": "BusFault", "ports": {"bus":1}, "id": "EVT1", "params": {"state0": false, "R":0.0, "X":1e-3} }
190190
]

GridKit/Model/PhasorDynamics/SynchronousMachine/GENROUwS/GenrouImpl.hpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -277,12 +277,14 @@ namespace GridKit
277277
return monitor_.get();
278278
}
279279

280+
// System base -> machine base when reading system values.
280281
template <typename scalar_type, typename index_type>
281282
Genrou<scalar_type, index_type>::ScalarT Genrou<scalar_type, index_type>::toMachineBase(ScalarT value) const
282283
{
283284
return value * va_system_base_ / va_machine_base_;
284285
}
285286

287+
// Machine base -> system base for network and signal output.
286288
template <typename scalar_type, typename index_type>
287289
Genrou<scalar_type, index_type>::ScalarT Genrou<scalar_type, index_type>::toSystemBase(ScalarT value) const
288290
{
@@ -293,6 +295,7 @@ namespace GridKit
293295
void Genrou<scalar_type, index_type>::initializeMonitor()
294296
{
295297
using Variable = typename ModelDataT::MonitorableVariables;
298+
// Convert monitored terminal values to system base.
296299
monitor_->set(Variable::ir, [this]
297300
{ return toSystemBase(y_[15]); });
298301
monitor_->set(Variable::ii, [this]
@@ -491,10 +494,11 @@ namespace GridKit
491494
+ G_ * (vd * -std::cos(delta) + vq * std::sin(delta));
492495

493496
ScalarT Te = y_[12];
494-
pmech_set_ = Te;
497+
// Convert Te to system base for governor PM signal.
498+
pmech_set_ = toSystemBase(Te);
495499
if (signals_.template isAttached<GenrouExternalVariables::PM>())
496500
{
497-
signals_.template writeExternalVariable<GenrouExternalVariables::PM>(Te);
501+
signals_.template writeExternalVariable<GenrouExternalVariables::PM>(pmech_set_);
498502
}
499503

500504
efd_set_ = Eqp + Xd1_ * (id + Xd3_ * (Eqp - psidp - Xd2_ * id)) + psidpp * ksat;
@@ -589,7 +593,7 @@ namespace GridKit
589593
ScalarT vi = wb[1];
590594

591595
// Set signal variable aliases
592-
ScalarT pmech = ws[0];
596+
ScalarT pmech = toMachineBase(ws[0]);
593597
ScalarT efd = ws[1];
594598

595599
/* 6 Genrou differential equations */
@@ -637,6 +641,7 @@ namespace GridKit
637641
ScalarT vr = wb[0];
638642
ScalarT vi = wb[1];
639643

644+
// Convert current injection to system base for the network.
640645
h[0] = toSystemBase(inr - vr * G_ + vi * B_);
641646
h[1] = toSystemBase(ini - vr * B_ - vi * G_);
642647

GridKit/Model/PhasorDynamics/SynchronousMachine/GENSALwS/GensalImpl.hpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -128,12 +128,14 @@ namespace GridKit
128128
return monitor_.get();
129129
}
130130

131+
// System base -> machine base when reading system values.
131132
template <typename scalar_type, typename index_type>
132133
scalar_type Gensal<scalar_type, index_type>::toMachineBase(ScalarT value) const
133134
{
134135
return value * va_system_base_ / va_machine_base_;
135136
}
136137

138+
// Machine base -> system base for network and signal output.
137139
template <typename scalar_type, typename index_type>
138140
scalar_type Gensal<scalar_type, index_type>::toSystemBase(ScalarT value) const
139141
{
@@ -144,6 +146,7 @@ namespace GridKit
144146
void Gensal<scalar_type, index_type>::initializeMonitor()
145147
{
146148
using Variable = typename ModelDataT::MonitorableVariables;
149+
// Convert monitored terminal values to system base.
147150
monitor_->set(Variable::ir, [this]
148151
{ return toSystemBase(y_[12]); });
149152
monitor_->set(Variable::ii, [this]
@@ -314,10 +317,11 @@ namespace GridKit
314317
y_[15] = B_ * (vd * std::sin(delta) + vq * std::cos(delta))
315318
+ G_ * (vd * -std::cos(delta) + vq * std::sin(delta));
316319

317-
pmech_set_ = Te;
320+
// Convert Te to system base for governor PM signal.
321+
pmech_set_ = toSystemBase(Te);
318322
if (signals_.template isAttached<GensalExternalVariables::PM>())
319323
{
320-
signals_.template writeExternalVariable<GensalExternalVariables::PM>(Te);
324+
signals_.template writeExternalVariable<GensalExternalVariables::PM>(pmech_set_);
321325
}
322326

323327
efd_set_ = Eqp + Xd1_ * (id + Xd3_ * (Eqp - psidp - Xd2_ * id)) + ksat;
@@ -408,7 +412,7 @@ namespace GridKit
408412
ScalarT vi = wb[1];
409413

410414
// Set signal variable aliases
411-
ScalarT pmech = ws[0];
415+
ScalarT pmech = toMachineBase(ws[0]);
412416
ScalarT efd = ws[1];
413417

414418
/* 5 Gensal differential equations */
@@ -453,6 +457,7 @@ namespace GridKit
453457
ScalarT vr = wb[0];
454458
ScalarT vi = wb[1];
455459

460+
// Convert current injection to system base for the network.
456461
h[0] = toSystemBase(inr - vr * G_ + vi * B_);
457462
h[1] = toSystemBase(ini - vr * B_ - vi * G_);
458463

0 commit comments

Comments
 (0)