DPsim
Loading...
Searching...
No Matches
Base_SynchronGenerator.cpp
1/* Copyright 2017-2021 Institute for Automation of Complex Power Systems,
2 * EONERC, RWTH Aachen University
3 *
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
7 *********************************************************************************/
8
9#include <dpsim-models/Base/Base_SynchronGenerator.h>
10#include <dpsim-models/Signal/ExciterDC1Simp.h>
11
12using namespace CPS;
13
14void Base::SynchronGenerator::setBaseParameters(Real nomPower, Real nomVolt,
15 Real nomFreq) {
16 mNomPower = nomPower;
17 mNomVolt = nomVolt;
18 mNomFreq = nomFreq;
19 mNomOmega = nomFreq * 2 * PI;
20
21 // Set base stator values
22 mBase_V_RMS = mNomVolt / sqrt(3);
23 mBase_V = mBase_V_RMS * sqrt(2);
25 mBase_I = mBase_I_RMS * sqrt(2);
27
31
34}
35
36void Base::SynchronGenerator::setBaseParameters(Real nomPower, Real nomVolt,
37 Real nomFreq,
38 Real nomFieldCur) {
39 mNomFieldCur = nomFieldCur;
40 Base::SynchronGenerator::setBaseParameters(nomPower, nomVolt, nomFreq);
41}
42
44 Real nomPower, Real nomVolt, Real nomFreq, Real nomFieldCur, Int poleNumber,
45 Real Rs, Real Ll, Real Lmd, Real Lmq, Real Rfd, Real Llfd, Real Rkd,
46 Real Llkd, Real Rkq1, Real Llkq1, Real Rkq2, Real Llkq2, Real inertia) {
47 mParameterType = ParameterType::perUnit;
48 mNumericalMethod = NumericalMethod::Trapezoidal;
49
50 setBaseParameters(nomPower, nomVolt, nomFreq, nomFieldCur);
51 setAndApplyFundamentalPerUnitParameters(poleNumber, Rs, Ll, Lmd, Lmq, Rfd,
52 Llfd, Rkd, Llkd, Rkq1, Llkq1, Rkq2,
53 Llkq2, inertia);
54}
55
57 Real nomPower, Real nomVolt, Real nomFreq, Int poleNumber, Real nomFieldCur,
58 Real Rs, Real Ld, Real Lq, Real Ld_t, Real Lq_t, Real Ld_s, Real Lq_s,
59 Real Ll, Real Td0_t, Real Tq0_t, Real Td0_s, Real Tq0_s, Real inertia) {
60 mParameterType = ParameterType::perUnit;
61 mNumericalMethod = NumericalMethod::Trapezoidal;
62
63 setBaseParameters(nomPower, nomVolt, nomFreq, nomFieldCur);
64 setOperationalPerUnitParameters(poleNumber, inertia, Rs, Ld, Lq, Ll, Ld_t,
65 Lq_t, Ld_s, Lq_s, Td0_t, Tq0_t, Td0_s, Tq0_s);
66 calculateFundamentalFromOperationalParameters();
67}
68
69void Base::SynchronGenerator::setOperationalPerUnitParameters(
70 Int poleNumber, Real inertia, Real Rs, Real Ld, Real Lq, Real Ll, Real Ld_t,
71 Real Lq_t, Real Ld_s, Real Lq_s, Real Td0_t, Real Tq0_t, Real Td0_s,
72 Real Tq0_s) {
73 mPoleNumber = poleNumber;
74 **mInertia = inertia;
75
76 **mRs = Rs;
77 **mLl = Ll;
78 **mLd = Ld;
79 **mLq = Lq;
80
81 **mLd_t = Ld_t;
82 **mLq_t = Lq_t;
83 **mLd_s = Ld_s;
84 **mLq_s = Lq_s;
85 **mTd0_t = Td0_t;
86 **mTq0_t = Tq0_t;
87 **mTd0_s = Td0_s;
88 **mTq0_s = Tq0_s;
89}
90
91void Base::SynchronGenerator::setAndApplyFundamentalPerUnitParameters(
92 Int poleNumber, Real Rs, Real Ll, Real Lmd, Real Lmq, Real Rfd, Real Llfd,
93 Real Rkd, Real Llkd, Real Rkq1, Real Llkq1, Real Rkq2, Real Llkq2,
94 Real inertia) {
95 Base::SynchronGenerator::setFundamentalPerUnitParameters(
96 poleNumber, Rs, Ll, Lmd, Lmq, Rfd, Llfd, Rkd, Llkd, Rkq1, Llkq1, Rkq2,
97 Llkq2, inertia);
98
99 Base::SynchronGenerator::applyFundamentalPerUnitParameters();
100}
101
102void Base::SynchronGenerator::setFundamentalPerUnitParameters(
103 Int poleNumber, Real Rs, Real Ll, Real Lmd, Real Lmq, Real Rfd, Real Llfd,
104 Real Rkd, Real Llkd, Real Rkq1, Real Llkq1, Real Rkq2, Real Llkq2,
105 Real inertia) {
106 // PoleNumber otherwise not set but currently not used in SynchronGeneratorDQ
107 mPoleNumber = poleNumber;
108 **mInertia = inertia;
109
110 **mRs = Rs;
111 **mLl = Ll;
112 mLmd = Lmd;
113 mLmq = Lmq;
114
115 mRfd = Rfd;
116 mLlfd = Llfd;
117 mRkd = Rkd;
118 mLlkd = Llkd;
119 mRkq1 = Rkq1;
120 mLlkq1 = Llkq1;
121 mRkq2 = Rkq2;
122 mLlkq2 = Llkq2;
123}
124
125void Base::SynchronGenerator::applyFundamentalPerUnitParameters() {
126 // derive further parameters
127 **mLd = **mLl + mLmd;
128 **mLq = **mLl + mLmq;
129 mLfd = mLlfd + mLmd;
130 mLkd = mLlkd + mLmd;
131 mLkq1 = mLlkq1 + mLmq;
132 mLkq2 = mLlkq2 + mLmq;
133
134 // base rotor values
135 mBase_ifd = mLmd * mNomFieldCur;
136 mBase_vfd = mNomPower / mBase_ifd;
137 mBase_Zfd = mBase_vfd / mBase_ifd;
138 mBase_Lfd = mBase_Zfd / mBase_OmElec;
139
140 // derive number of damping windings
141 if (mRkq2 == 0 && mLlkq2 == 0)
142 mNumDampingWindings = 1;
143 else
144 mNumDampingWindings = 2;
145
146 if (mNumDampingWindings == 1) {
147 mVsr = Matrix::Zero(6, 1);
148 mIsr = Matrix::Zero(6, 1);
149 mPsisr = Matrix::Zero(6, 1);
150 mInductanceMat = Matrix::Zero(6, 6);
151 mResistanceMat = Matrix::Zero(6, 6);
152
153 // Determinant of Lq(inductance matrix of q axis)
154 // Real detLq = -(mLl + mLmq)*(mLlkq1 + mLmq) + mLmq*mLmq;
155 // Determinant of Ld (inductance matrix of d axis)
156 // Real detLd = (mLmd + mLl)*(-mLlfd*mLlkd - mLlfd*mLmd - mLmd*mLlkd) +
157 // mLmd*mLmd*(mLlfd + mLlkd);
158
159 mInductanceMat << **mLd, mLmd, mLmd, 0, 0, 0, mLmd, mLfd, mLmd, 0, 0, 0,
160 mLmd, mLmd, mLkd, 0, 0, 0, 0, 0, 0, **mLq, mLmq, 0, 0, 0, 0, mLmq,
161 mLkq1, 0, 0, 0, 0, 0, 0, **mLl;
162
163 mResistanceMat << **mRs, 0, 0, 0, 0, 0, 0, mRfd, 0, 0, 0, 0, 0, 0, mRkd, 0,
164 0, 0, 0, 0, 0, **mRs, 0, 0, 0, 0, 0, 0, mRkq1, 0, 0, 0, 0, 0, 0, **mRs;
165
166 // Compute inverse Inductance Matrix:
167 mInvInductanceMat = mInductanceMat.inverse();
168 } else {
169 mVsr = Matrix::Zero(7, 1);
170 mIsr = Matrix::Zero(7, 1);
171 mPsisr = Matrix::Zero(7, 1);
172 mInductanceMat = Matrix::Zero(7, 7);
173 mResistanceMat = Matrix::Zero(7, 7);
174
175 // Determinant of Lq(inductance matrix of q axis)
176 // Real detLq = -mLmq*mLlkq2*(mLlkq1 + mLl) - mLl*mLlkq1*(mLlkq2 + mLmq);
177 // Determinant of Ld (inductance matrix of d axis)
178 // Real detLd = (mLmd + mLl)*(-mLlfd*mLlkd - mLlfd*mLmd - mLmd*mLlkd) +
179 // mLmd*mLmd*(mLlfd + mLlkd);
180
181 mInductanceMat << **mLd, mLmd, mLmd, 0, 0, 0, 0, mLmd, mLfd, mLmd, 0, 0, 0,
182 0, mLmd, mLmd, mLkd, 0, 0, 0, 0, 0, 0, 0, **mLq, mLmq, mLmq, 0, 0, 0, 0,
183 mLmq, mLkq1, mLmq, 0, 0, 0, 0, mLmq, mLmq, mLkq2, 0, 0, 0, 0, 0, 0, 0,
184 **mLl;
185
186 mResistanceMat << **mRs, 0, 0, 0, 0, 0, 0, 0, mRfd, 0, 0, 0, 0, 0, 0, 0,
187 mRkd, 0, 0, 0, 0, 0, 0, 0, **mRs, 0, 0, 0, 0, 0, 0, 0, mRkq1, 0, 0, 0,
188 0, 0, 0, 0, mRkq2, 0, 0, 0, 0, 0, 0, 0, **mRs;
189
190 // Compute inverse Inductance Matrix:
191 mInvInductanceMat = mInductanceMat.inverse();
192 }
193}
194
195void Base::SynchronGenerator::calculateFundamentalFromOperationalParameters() {
196 mLmd = **mLd - **mLl;
197 mLmq = **mLq - **mLl;
198
199 mLlfd = mLmd * (**mLd_t - **mLl) / (mLmd - **mLd_t + **mLl);
200 mLlkq1 = mLmq * (**mLq_t - **mLl) / (mLmq - **mLq_t + **mLl);
201
202 mLlkd = mLmd * mLlfd * (**mLd_s - **mLl) /
203 (mLlfd * mLmd - (mLmd + mLlfd) * (**mLd_s - **mLl));
204 mLlkq2 = mLmq * mLlkq1 * (**mLq_s - **mLl) /
205 (mLlkq1 * mLmq - (mLmq + mLlkq1) * (**mLq_s - **mLl));
206
207 mRfd = (mLmd + mLlfd) / (**mTd0_t * mNomOmega);
208 mRkd = (1 / (**mTd0_s * mNomOmega)) * (mLlkd + mLmd * mLlfd / (mLmd + mLlfd));
209 mRkq1 = (mLmq + mLlkq1) / (**mTq0_t * mNomOmega);
210 mRkq2 =
211 (1 / (**mTq0_s * mNomOmega)) * (mLlkq2 + mLmq * mLlkq1 / (mLmq + mLlkq1));
212
213 Base::SynchronGenerator::applyFundamentalPerUnitParameters();
214}
215
216void Base::SynchronGenerator::setInitialValues(Real initActivePower,
217 Real initReactivePower,
218 Real initTerminalVolt,
219 Real initVoltAngle,
220 Real initMechPower) {
221 mInitElecPower = Complex(initActivePower, initReactivePower);
222 mInitTerminalVoltage = initTerminalVolt;
223 mInitVoltAngle = initVoltAngle;
224 mInitMechPower = initMechPower;
225 mInitialValuesSet = true;
226}
227
229 // Power in per unit
230 Real init_P = mInitElecPower.real() / mNomPower;
231 Real init_Q = mInitElecPower.imag() / mNomPower;
232 Real init_S_abs = sqrt(pow(init_P, 2.) + pow(init_Q, 2.));
233 // Complex init_S = mInitElecPower;
234 // Terminal voltage in pu
235 Real init_vt_abs = mInitTerminalVoltage / mBase_V;
236 // Complex init_vt = Complex(mInitTerminalVoltage*cos(mInitVoltAngle),
237 // mInitTerminalVoltage*sin(mInitVoltAngle));
238 Real init_it_abs = init_S_abs / init_vt_abs;
239 // Complex init_it = std::conj( init_S / init_vt );
240 // Power factor
241 Real init_pf = acos(init_P / init_S_abs);
242 // Load angle
243 Real init_delta = atan(((mLmq + **mLl) * init_it_abs * cos(init_pf) -
244 **mRs * init_it_abs * sin(init_pf)) /
245 (init_vt_abs + **mRs * init_it_abs * cos(init_pf) +
246 (mLmq + **mLl) * init_it_abs * sin(init_pf)));
247 // Real init_delta_deg = init_delta / PI * 180;
248
249 // Electrical torque
250 // Real init_Te = init_P + **mRs * pow(init_it, 2.);
251
252 // dq stator voltages and currents
253 Real init_vd = init_vt_abs * sin(init_delta);
254 Real init_vq = init_vt_abs * cos(init_delta);
255 Real init_id = init_it_abs * sin(init_delta + init_pf);
256 Real init_iq = init_it_abs * cos(init_delta + init_pf);
257
258 // Rotor voltage and current
259 Real init_ifd = (init_vq + **mRs * init_iq + (mLmd + **mLl) * init_id) / mLmd;
260 Real init_vfd = mRfd * init_ifd;
261
262 // Flux linkages
263 Real init_psid = init_vq + **mRs * init_iq;
264 Real init_psiq = -init_vd - **mRs * init_id;
265 Real init_psifd = mLfd * init_ifd - mLmd * init_id;
266 Real init_psikd = mLmd * (init_ifd - init_id);
267 Real init_psiq1 = -mLmq * init_iq;
268 Real init_psiq2 = -mLmq * init_iq;
269
270 // Initialize mechanical variables
271 **mOmMech = 1;
272 **mMechPower = mInitMechPower / mNomPower;
273 **mMechTorque = **mMechPower / 1;
274 mThetaMech = mInitVoltAngle + init_delta - PI / 2.;
275 **mDelta = init_delta;
276
277 if (mNumDampingWindings == 2) {
278 mVsr << init_vd, init_vfd, 0, init_vq, 0, 0, 0;
279 mIsr << -init_id, init_ifd, 0, -init_iq, 0, 0, 0;
280 mPsisr << init_psid, init_psifd, init_psikd, init_psiq, init_psiq1,
281 init_psiq2, 0;
282 } else {
283 mVsr << init_vd, init_vfd, 0, init_vq, 0, 0;
284 mIsr << -init_id, init_ifd, 0, -init_iq, 0, 0;
285 mPsisr << init_psid, init_psifd, init_psikd, init_psiq, init_psiq1, 0;
286 }
287
288 if (mNumDampingWindings == 2) {
289 mVsr << init_vd, init_vfd, 0, init_vq, 0, 0, 0;
290 mIsr << -init_id, init_ifd, 0, -init_iq, 0, 0, 0;
291 mPsisr << init_psid, init_psifd, init_psikd, init_psiq, init_psiq1,
292 init_psiq2, 0;
293 } else {
294 mVsr << init_vd, init_vfd, 0, init_vq, 0, 0;
295 mIsr << -init_id, init_ifd, 0, -init_iq, 0, 0;
296 mPsisr << init_psid, init_psifd, init_psikd, init_psiq, init_psiq1, 0;
297 }
298
299 **mElecTorque = (mPsisr(3, 0) * mIsr(0, 0) - mPsisr(0, 0) * mIsr(3, 0));
300
301 // Initialize controllers
302 if (mHasExciter) {
303 // Note: field voltage scaled by Lmd/Rfd to transform from synchronous generator pu system
304 // to the exciter pu system
305 mExciter->initializeStates(init_vt_abs, (mLmd / mRfd) * init_vfd);
306 }
308 mGovernor->initializeStates(**mMechTorque);
309 mTurbine->initializeStates(**mMechTorque);
310 }
311}
312
313void Base::SynchronGenerator::calcStateSpaceMatrixDQ() {
314 if (mNumDampingWindings == 2) {
315 mLad = 1. / (1. / mLmd + 1. / **mLl + 1. / mLlfd + 1. / mLlkd);
316 mLaq = 1. / (1. / mLmq + 1. / **mLl + 1. / mLlkq1 + 1. / mLlkq2);
317
318 mPsisr = Matrix::Zero(7, 1);
319
320 mOmegaFluxMat = Matrix::Zero(7, 7);
321 mOmegaFluxMat << 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
322 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
323 0, 0, 0, 0, 0;
324
325 mFluxStateSpaceMat =
326 Matrix::Zero(7, 7); // order of lambdas: ds; fd; kd; qs; kq1; kq2; 0s
327 mFluxStateSpaceMat << **mRs / **mLl * mLad / **mLl - **mRs / **mLl,
328 **mRs / **mLl * mLad / mLlfd, **mRs / **mLl * mLad / mLlkd, 0, 0, 0, 0,
329 mRfd / mLlfd * mLad / **mLl, mRfd / mLlfd * mLad / mLlfd - mRfd / mLlfd,
330 mRfd / mLlfd * mLad / mLlkd, 0, 0, 0, 0, mRkd / mLlkd * mLad / **mLl,
331 mRkd / mLlkd * mLad / mLlfd, mRkd / mLlkd * mLad / mLlkd - mRkd / mLlkd,
332 0, 0, 0, 0, 0, 0, 0, **mRs / **mLl * mLaq / **mLl - **mRs / **mLl,
333 **mRs / **mLl * mLaq / mLlkq1, **mRs / **mLl * mLaq / mLlkq2, 0, 0, 0,
334 0, mRkq1 / mLlkq1 * mLaq / **mLl,
335 mRkq1 / mLlkq1 * mLaq / mLlkq1 - mRkq1 / mLlkq1,
336 mRkq1 / mLlkq1 * mLaq / mLlkq2, 0, 0, 0, 0,
337 mRkq2 / mLlkq2 * mLaq / **mLl, mRkq2 / mLlkq2 * mLaq / mLlkq1,
338 mRkq2 / mLlkq2 * mLaq / mLlkq2 - mRkq2 / mLlkq2, 0, 0, 0, 0, 0, 0, 0,
339 -**mRs / **mLl;
340
341 mFluxToCurrentMat =
342 Matrix::Zero(7, 7); // need for electric torque id, iq ->1st and 4th row
343 mFluxToCurrentMat << 1. / **mLl - mLad / **mLl / **mLl,
344 -mLad / mLlfd / **mLl, -mLad / mLlkd / **mLl, 0, 0, 0, 0,
345 -mLad / **mLl / mLlfd, 1. / mLlfd - mLad / mLlfd / mLlfd,
346 -mLad / mLlkd / mLlfd, 0, 0, 0, 0, -mLad / **mLl / mLlkd,
347 -mLad / mLlfd / mLlkd, 1. / mLlkd - mLad / mLlkd / mLlkd, 0, 0, 0, 0, 0,
348 0, 0, 1. / **mLl - mLaq / **mLl / **mLl, -mLaq / mLlkq1 / **mLl,
349 -mLaq / mLlkq2 / **mLl, 0, 0, 0, 0, -mLaq / **mLl / mLlkq1,
350 1. / mLlkq1 - mLaq / mLlkq1 / mLlkq1, -mLaq / mLlkq2 / mLlkq1, 0, 0, 0,
351 0, -mLaq / **mLl / mLlkq2, -mLaq / mLlkq1 / mLlkq2,
352 1. / mLlkq2 - mLaq / mLlkq2 / mLlkq2, 0, 0, 0, 0, 0, 0, 0, 1. / **mLl;
353 } else {
354 mLad = 1. / (1. / mLmd + 1. / **mLl + 1. / mLlfd + 1. / mLlkd);
355 mLaq = 1. / (1. / mLmq + 1. / **mLl + 1. / mLlkq1);
356
357 mPsisr = Matrix::Zero(6, 1);
358
359 mOmegaFluxMat = Matrix::Zero(6, 6);
360 mOmegaFluxMat << 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1,
361 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
362
363 mFluxStateSpaceMat = Matrix::Zero(6, 6);
364 mFluxStateSpaceMat << // same order as above; only without kq2
365 **mRs / **mLl * mLad / **mLl - **mRs / **mLl,
366 **mRs / **mLl * mLad / mLlfd, **mRs / **mLl * mLad / mLlkd, 0, 0, 0,
367 mRfd / mLlfd * mLad / **mLl, mRfd / mLlfd * mLad / mLlfd - mRfd / mLlfd,
368 mRfd / mLlfd * mLad / mLlkd, 0, 0, 0, mRkd / mLlkd * mLad / **mLl,
369 mRkd / mLlkd * mLad / mLlfd, mRkd / mLlkd * mLad / mLlkd - mRkd / mLlkd,
370 0, 0, 0, 0, 0, 0, **mRs / **mLl * mLaq / **mLl - **mRs / **mLl,
371 **mRs / **mLl * mLaq / mLlkq1, 0, 0, 0, 0,
372 mRkq1 / mLlkq1 * mLaq / **mLl,
373 mRkq1 / mLlkq1 * mLaq / mLlkq1 - mRkq1 / mLlkq1, 0, 0, 0, 0, 0, 0,
374 -**mRs / **mLl;
375
376 mFluxToCurrentMat = Matrix::Zero(6, 6);
377 mFluxToCurrentMat << 1. / **mLl - mLad / **mLl / **mLl,
378 -mLad / mLlfd / **mLl, -mLad / mLlkd / **mLl, 0, 0, 0,
379 -mLad / **mLl / mLlfd, 1. / mLlfd - mLad / mLlfd / mLlfd,
380 -mLad / mLlkd / mLlfd, 0, 0, 0, -mLad / **mLl / mLlkd,
381 -mLad / mLlfd / mLlkd, 1. / mLlkd - mLad / mLlkd / mLlkd, 0, 0, 0, 0, 0,
382 0, 1. / **mLl - mLaq / **mLl / **mLl, -mLaq / mLlkq1 / **mLl, 0, 0, 0,
383 0, -mLaq / **mLl / mLlkq1, 1. / mLlkq1 - mLaq / mLlkq1 / mLlkq1, 0, 0,
384 0, 0, 0, 0, 1. / **mLl;
385 }
386}
387
388Real Base::SynchronGenerator::calcHfromJ(Real J, Real omegaNominal,
389 Int polePairNumber) {
390 return J * 0.5 * omegaNominal * omegaNominal / polePairNumber;
391}
392
393void CPS::Base::SynchronGenerator::addExciter(Real Ta, Real Ka, Real Te,
394 Real Ke, Real Tf, Real Kf,
395 Real Tr) {
396 // CLI-only logger
397 auto log = CPS::Logger::get("SynchronGenerator",
398 CPS::Logger::Level::off, // file level
399 CPS::Logger::Level::info); // CLI level
400
401 SPDLOG_LOGGER_WARN(
402 log, "Deprecated API addExciter(Ta,Ka,Te,Ke,Tf,Kf,Tr) called. "
403 "This overload will be removed in the future. "
404 "Please create an ExciterDC1Simp and parameters explicitly.");
405
406 auto params = std::make_shared<CPS::Signal::ExciterDC1SimpParameters>();
407 params->Ta = Ta;
408 params->Ka = Ka;
409 params->Tef = Te;
410 params->Kef = Ke;
411 params->Tf = Tf;
412 params->Kf = Kf;
413 params->Tr = Tr;
414
415 // Apply legacy amplifier limits for the deprecated path
416 params->MaxVa = 1.0;
417 params->MinVa = -0.9;
418
419 // No saturation by default
420 params->Aef = 0.0;
421 params->Bef = 0.0;
422
423 mExciter = std::make_shared<CPS::Signal::ExciterDC1Simp>(
424 "Exciter", CPS::Logger::Level::info);
425 mExciter->setParameters(params);
426 mHasExciter = true;
427
428 SPDLOG_LOGGER_INFO(
429 log,
430 "Attached ExciterDC1Simp (Ka={:.3g}, Ta={:.3g}, Kef={:.3g}, Tef={:.3g}, "
431 "Kf={:.3g}, Tf={:.3g}, Tr={:.3g}, MaxVa={:.3g}, MinVa={:.3g})",
432 params->Ka, params->Ta, params->Kef, params->Tef, params->Kf, params->Tf,
433 params->Tr, params->MaxVa, params->MinVa);
434}
435
436void Base::SynchronGenerator::addGovernor(Real Ta, Real Tb, Real Tc, Real Fa,
437 Real Fb, Real Fc, Real K, Real Tsr,
438 Real Tsm, Real Tm_init, Real PmRef) {
439 auto log = CPS::Logger::get("SynchronGenerator", CPS::Logger::Level::off,
440 CPS::Logger::Level::info);
441 SPDLOG_LOGGER_WARN(
442 log, "addGovernor(Ta, Tb, ...) uses the legacy TurbineGovernor "
443 "model; prefer addGovernor(shared_ptr<TurbineGovernorType1>)");
444 mTurbineGovernor = Signal::TurbineGovernor::make("TurbineGovernor",
445 CPS::Logger::Level::info);
446 mTurbineGovernor->setParameters(Ta, Tb, Tc, Fa, Fb, Fc, K, Tsr, Tsm);
447 mTurbineGovernor->initialize(PmRef, Tm_init);
448 mHasTurbineGovernor = true;
449}
450
451void Base::SynchronGenerator::addGovernor(
452 std::shared_ptr<Signal::TurbineGovernorType1> turbineGovernor) {
453 auto log = CPS::Logger::get("SynchronGenerator", CPS::Logger::Level::off,
454 CPS::Logger::Level::info);
455 if (!turbineGovernor) {
456 SPDLOG_LOGGER_ERROR(log,
457 "addGovernor called with null TurbineGovernorType1");
458 return;
459 }
460 mTurbineGovernorType1 = turbineGovernor;
462}
463
464void Base::SynchronGenerator::addGovernor(Real T3, Real T4, Real T5, Real Tc,
465 Real Ts, Real R, Real Tmin, Real Tmax,
466 Real OmRef, Real TmRef) {
467 auto log = CPS::Logger::get("SynchronGenerator", CPS::Logger::Level::off,
468 CPS::Logger::Level::info);
469 SPDLOG_LOGGER_WARN(log,
470 "Scalar addGovernor(T3, T4, ...) is deprecated; create a "
471 "TurbineGovernorType1 and use "
472 "addGovernor(shared_ptr<TurbineGovernorType1>) instead");
473 auto gov = Signal::TurbineGovernorType1::make("TurbineGovernorType1",
474 CPS::Logger::Level::info);
475 gov->setParameters(T3, T4, T5, Tc, Ts, R, Tmin, Tmax, OmRef);
476 gov->initializeStates(TmRef);
477 addGovernor(gov);
478}
479
481 std::shared_ptr<Base::Governor> governor,
482 std::shared_ptr<Base::GovernorParameters> govParams,
483 std::shared_ptr<Base::Turbine> turbine,
484 std::shared_ptr<Base::TurbineParameters> turbineParams) {
485 auto log = CPS::Logger::get("SynchronGenerator", CPS::Logger::Level::off,
486 CPS::Logger::Level::info);
487 if (!governor) {
488 SPDLOG_LOGGER_ERROR(log, "addGovernorAndTurbine called with null governor");
489 return;
490 }
491 if (!turbine) {
492 SPDLOG_LOGGER_ERROR(log, "addGovernorAndTurbine called with null turbine");
493 return;
494 }
495 governor->setParameters(govParams);
496 turbine->setParameters(turbineParams);
497 mGovernor = governor;
498 mTurbine = turbine;
500}
501
503 std::shared_ptr<Base::Governor> governor,
504 std::shared_ptr<Base::Turbine> turbine) {
505 auto log = CPS::Logger::get("SynchronGenerator", CPS::Logger::Level::off,
506 CPS::Logger::Level::info);
507 if (!governor) {
508 SPDLOG_LOGGER_ERROR(log, "addGovernorAndTurbine called with null governor");
509 return;
510 }
511 if (!turbine) {
512 SPDLOG_LOGGER_ERROR(log, "addGovernorAndTurbine called with null turbine");
513 return;
514 }
515 mGovernor = governor;
516 mTurbine = turbine;
518}
519
521 std::shared_ptr<Base::PSS> pss,
522 std::shared_ptr<Base::PSSParameters> parameters) {
523 auto log = CPS::Logger::get("SynchronGenerator", CPS::Logger::Level::off,
524 CPS::Logger::Level::info);
525 if (!mHasExciter) {
526 SPDLOG_LOGGER_ERROR(
527 log, "Cannot attach PSS: no exciter present. Attach an exciter first.");
529 }
530 if (!pss) {
531 SPDLOG_LOGGER_ERROR(log,
532 "addPSS called with null PSS on SynchronGenerator");
533 return;
534 }
535 mPSS = pss;
536 mPSS->setParameters(parameters);
537 mHasPSS = true;
538}
539
540void Base::SynchronGenerator::addPSS(std::shared_ptr<Base::PSS> pss) {
541 auto log = CPS::Logger::get("SynchronGenerator", CPS::Logger::Level::off,
542 CPS::Logger::Level::info);
543 if (!mHasExciter) {
544 SPDLOG_LOGGER_ERROR(
545 log, "Cannot attach PSS: no exciter present. Attach an exciter first.");
547 }
548 if (!pss) {
549 SPDLOG_LOGGER_ERROR(log,
550 "addPSS called with null PSS on SynchronGenerator");
551 return;
552 }
553 mPSS = pss;
554 mHasPSS = true;
555}
Matrix mIsr
Vector of stator and rotor currents.
Real mNomFreq
nominal frequency fn [Hz]
Bool mHasTurbineGovernorType1
Determines if TurbineGovernorType1 is activated.
Real mLmd
d-axis mutual inductance Lmd [H]
Real mBase_I
base stator current peak
Bool mHasExciter
Determines if Exciter is activated.
const Attribute< Real >::Ptr mMechTorque
mechanical torque
Real mLmq
q-axis mutual inductance Lmq [H]
std::shared_ptr< Base::Exciter > mExciter
Signal component modelling voltage regulator and exciter.
void addGovernorAndTurbine(std::shared_ptr< Base::Governor > governor, std::shared_ptr< Base::GovernorParameters > govParams, std::shared_ptr< Base::Turbine > turbine, std::shared_ptr< Base::TurbineParameters > turbineParams)
Add a modular governor + turbine pair (new API for SteamTurbineGovernor / SteamTurbine)
Real mBase_I_RMS
base stator current RMS
std::shared_ptr< Base::Turbine > mTurbine
Modular turbine (SteamTurbine / HydroTurbine)
void addPSS(std::shared_ptr< Base::PSS > pss, std::shared_ptr< Base::PSSParameters > parameters)
Attach a PSS (initialised separately) to this generator.
const Attribute< Real >::Ptr mMechPower
mechanical Power Pm [W]
Real mNomVolt
nominal voltage Vn [V] (phase-to-phase RMS)
Matrix mVsr
Vector of stator and rotor voltages.
Matrix mPsisr
Vector of stator and rotor fluxes.
Real mBase_L
base stator inductance
Real mBase_Z
base stator impedance
const Attribute< Real >::Ptr mRs
stator resistance Rs [Ohm]
Bool mHasGovernorAndTurbine
Determines if modular Governor + Turbine pair is activated.
std::shared_ptr< Base::PSS > mPSS
Power system stabilizer.
void addExciter(std::shared_ptr< Base::Exciter > exciter, std::shared_ptr< Base::ExciterParameters > params)
Add voltage regulator and exciter.
std::shared_ptr< Base::Governor > mGovernor
Modular governor (SteamTurbineGovernor / HydroTurbineGovernor)
void setBaseAndFundamentalPerUnitParameters(Real nomPower, Real nomVolt, Real nomFreq, Real nomFieldCur, Int poleNumber, Real Rs, Real Ll, Real Lmd, Real Lmq, Real Rfd, Real Llfd, Real Rkd, Real Llkd, Real Rkq1, Real Llkq1, Real Rkq2, Real Llkq2, Real inertia)
Initializes the base and fundamental machine parameters in per unit.
Real mRfd
field resistance Rfd [Ohm]
Real mNomOmega
nominal angular frequency wn [Hz]
Real mBase_OmElec
base electrical angular frequency
const Attribute< Real >::Ptr mLl
leakage inductance Ll [H]
Real mBase_OmMech
base mechanical angular frequency
const Attribute< Real >::Ptr mDelta
rotor angle delta
Real mLfd
field inductance Lfd [H]
Bool mHasPSS
Determines if PSS is activated.
Int mNumDampingWindings
Number of damping windings in q.
Real mBase_V
base stator voltage (phase-to-ground peak)
Real mNomPower
nominal power Pn [VA]
void setBaseAndOperationalPerUnitParameters(Real nomPower, Real nomVolt, Real nomFreq, Int poleNumber, Real nomFieldCur, Real Rs, Real Ld, Real Lq, Real Ld_t, Real Lq_t, Real Ld_s, Real Lq_s, Real Ll, Real Td0_t, Real Tq0_t, Real Td0_s, Real Tq0_s, Real inertia)
const Attribute< Real >::Ptr mOmMech
rotor speed omega_r
std::shared_ptr< Signal::TurbineGovernorType1 > mTurbineGovernorType1
Signal component modelling governor control and steam turbine (TurbineGovernorType1)
const Attribute< Real >::Ptr mElecTorque
electrical torque
Real mBase_V_RMS
base stator voltage (phase-to-ground RMS)