DPsim
Loading...
Searching...
No Matches
EMT_Ph3_AvVoltSourceInverterStateSpace.cpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2026 Institute for Automation of Complex Power Systems, EONERC, RWTH Aachen University
2// SPDX-License-Identifier: MPL-2.0
3
4#include <cmath>
5#include <stdexcept>
6
8
9using namespace CPS;
10
13 : TwoTerminalVTypeVariableSSNComp(uid, name, logLevel), mLf(0.0), mCf(0.0),
14 mRf(0.0), mRc(0.0), mOmegaN(0.0), mKpPLL(0.0), mKiPLL(0.0),
15 mOmegaCutoff(0.0), mPRef(0.0), mQRef(0.0), mKpPowerCtrl(0.0),
16 mKiPowerCtrl(0.0), mKpCurrCtrl(0.0), mKiCurrCtrl(0.0),
17 mVcD(mAttributes->create<Real>("vc_d")),
18 mVcQ(mAttributes->create<Real>("vc_q")),
19 mIrcD(mAttributes->create<Real>("irc_d")),
20 mIrcQ(mAttributes->create<Real>("irc_q")),
21 mPInst(mAttributes->create<Real>("p_inst")),
22 mQInst(mAttributes->create<Real>("q_inst")),
23 mOmegaPLL(mAttributes->create<Real>("omega_pll")) {
24 **mIntfVoltage = Matrix::Zero(3, 1);
25 **mIntfCurrent = Matrix::Zero(3, 1);
26
27 **mVcD = 0.0;
28 **mVcQ = 0.0;
29 **mIrcD = 0.0;
30 **mIrcQ = 0.0;
31 **mPInst = 0.0;
32 **mQInst = 0.0;
33 **mOmegaPLL = 0.0;
34}
35
36std::vector<String>
38 return {
39 "theta_pll", "phi_pll", "p_filtered", "q_filtered", "phi_d",
40 "phi_q", "gamma_d", "gamma_q", "vc_a", "vc_b",
41 "vc_c", "if_a", "if_b", "if_c",
42 };
43}
44
45std::vector<EMT::SSNComp::LocalAbcStateBlock>
47 return {
48 {{static_cast<UInt>(VcA), static_cast<UInt>(VcB), static_cast<UInt>(VcC)},
49 "vc"},
50 {{static_cast<UInt>(IfA), static_cast<UInt>(IfB), static_cast<UInt>(IfC)},
51 "if"},
52 };
53}
54
56 Real lf, Real cf, Real rf, Real rc, Real omegaN, Real kpPLL, Real kiPLL,
57 Real omegaCutoff, Real pRef, Real qRef, Real kpPowerCtrl, Real kiPowerCtrl,
58 Real kpCurrCtrl, Real kiCurrCtrl) {
59 if (lf <= 0.0)
60 throw std::invalid_argument("Filter inductance lf must be positive.");
61
62 if (cf <= 0.0)
63 throw std::invalid_argument("Filter capacitance cf must be positive.");
64
65 if (rf < 0.0)
66 throw std::invalid_argument("Filter resistance rf must be non-negative.");
67
68 if (rc <= 0.0)
69 throw std::invalid_argument("Coupling resistance rc must be positive.");
70
71 if (omegaN <= 0.0)
72 throw std::invalid_argument(
73 "Nominal angular frequency omegaN must be positive.");
74
75 if (omegaCutoff < 0.0)
76 throw std::invalid_argument(
77 "Power-filter cutoff frequency omegaCutoff must be non-negative.");
78
79 if (kiPLL == 0.0)
80 throw std::invalid_argument("PLL integral gain kiPLL must be non-zero.");
81
82 if (kiPowerCtrl == 0.0)
83 throw std::invalid_argument(
84 "Power-control integral gain kiPowerCtrl must be non-zero.");
85
86 if (kiCurrCtrl == 0.0)
87 throw std::invalid_argument(
88 "Current-control integral gain kiCurrCtrl must be non-zero.");
89
90 mLf = lf;
91 mCf = cf;
92 mRf = rf;
93 mRc = rc;
94
95 mOmegaN = omegaN;
96 mKpPLL = kpPLL;
97 mKiPLL = kiPLL;
98
99 mOmegaCutoff = omegaCutoff;
100 mPRef = pRef;
101 mQRef = qRef;
102 mKpPowerCtrl = kpPowerCtrl;
103 mKiPowerCtrl = kiPowerCtrl;
104 mKpCurrCtrl = kpCurrCtrl;
105 mKiCurrCtrl = kiCurrCtrl;
106
107 const Matrix x0 = Matrix::Zero(mStateSize, 1);
108 const Matrix u0 = Matrix::Zero(3, 1);
109
110 Matrix aMatrix;
111 Matrix bMatrix;
112 Matrix cMatrix;
113 Matrix dMatrix;
114 Matrix eVector;
115 Matrix fVector;
116 buildStateSpaceModel(x0, u0, aMatrix, bMatrix, cMatrix, dMatrix, eVector,
117 fVector);
118
119 VTypeVariableSSNComp::setParameters(aMatrix, bMatrix, cMatrix, dMatrix,
120 eVector, fVector);
121}
122
123Matrix EMT::Ph3::AvVoltSourceInverterStateSpace::getParkTransformMatrix(
124 Real theta) const {
125 Matrix transform(2, 3);
126 const Real k = std::sqrt(2.0 / 3.0);
127
128 transform.row(0) << k * std::cos(theta), k * std::cos(theta - 2.0 * PI / 3.0),
129 k * std::cos(theta + 2.0 * PI / 3.0);
130
131 transform.row(1) << -k * std::sin(theta),
132 -k * std::sin(theta - 2.0 * PI / 3.0),
133 -k * std::sin(theta + 2.0 * PI / 3.0);
134
135 return transform;
136}
137
138Matrix EMT::Ph3::AvVoltSourceInverterStateSpace::getInverseParkTransformMatrix(
139 Real theta) const {
140 Matrix transform(3, 2);
141 const Real k = std::sqrt(2.0 / 3.0);
142
143 transform << k * std::cos(theta), -k * std::sin(theta),
144 k * std::cos(theta - 2.0 * PI / 3.0),
145 -k * std::sin(theta - 2.0 * PI / 3.0),
146 k * std::cos(theta + 2.0 * PI / 3.0),
147 -k * std::sin(theta + 2.0 * PI / 3.0);
148
149 return transform;
150}
151
153 const Matrix &u) const {
154 const Matrix &x = **mX;
155
156 const Matrix parkTransform = getParkTransformMatrix(x(ThetaPLL, 0));
157 const Matrix vcAbc = x.block(VcA, 0, 3, 1);
158 const Matrix iGridAbc = (vcAbc - u) / mRc;
159
160 **mVcD = (parkTransform.row(0) * vcAbc)(0, 0);
161 **mVcQ = (parkTransform.row(1) * vcAbc)(0, 0);
162 **mIrcD = (parkTransform.row(0) * iGridAbc)(0, 0);
163 **mIrcQ = (parkTransform.row(1) * iGridAbc)(0, 0);
164
165 **mPInst = **mVcD * **mIrcD + **mVcQ * **mIrcQ;
166 **mQInst = -**mVcD * **mIrcQ + **mVcQ * **mIrcD;
167
168 **mOmegaPLL = mOmegaN + mKpPLL * **mVcQ + mKiPLL * x(PhiPLL, 0);
169}
170
172 Real frequency) {
173 if (!mParametersSet)
174 throw std::logic_error("setParameters() must be called before "
175 "initializeFromNodesAndTerminals().");
176
177 // The generic SSN phasor initialization is not used because this component
178 // mixes EMT abc electrical states with dq-frame controller states. The filter
179 // states are initialized from balanced phasors; the controller states are
180 // initialized algebraically from the corresponding dq operating point.
181
182 const Real omega = 2.0 * PI * frequency;
183 const Complex j(0.0, 1.0);
184 const Complex powerRef(mPRef, mQRef);
185
186 const MatrixComp uPhasor = buildInitialInputFromNodes(frequency);
187
188 MatrixComp vcPhasor = uPhasor;
189 MatrixComp iInjPhasor = MatrixComp::Zero(3, 1);
190
191 for (Int iter = 0; iter < mInitializationMaxIterations; ++iter) {
192 const Complex vcA = vcPhasor(0, 0);
193
194 if (std::abs(vcA) < mInitializationTolerance) {
195 iInjPhasor.setZero();
196 break;
197 }
198
199 const Complex iA = std::conj(powerRef / (1.5 * vcA));
200
201 MatrixComp iNext(3, 1);
202 iNext << iA, iA * SHIFT_TO_PHASE_B, iA * SHIFT_TO_PHASE_C;
203
204 const MatrixComp vcNext = uPhasor + mRc * iNext;
205
206 iInjPhasor = iNext;
207
208 if ((vcNext - vcPhasor).norm() < mInitializationTolerance) {
209 vcPhasor = vcNext;
210 break;
211 }
212
213 vcPhasor = vcNext;
214 }
215
216 const MatrixComp ifPhasor = j * omega * mCf * vcPhasor + iInjPhasor;
217 const MatrixComp vRefPhasor = vcPhasor + (mRf + j * omega * mLf) * ifPhasor;
218
219 const Matrix vcAbc0 = vcPhasor.real();
220 const Matrix ifAbc0 = ifPhasor.real();
221 const Matrix iInjAbc0 = iInjPhasor.real();
222 const Matrix vRefAbc0 = vRefPhasor.real();
223
224 const Real theta0 = std::arg(vcPhasor(0, 0));
225 const Matrix parkTransform = getParkTransformMatrix(theta0);
226
227 const Matrix vcDq = parkTransform * vcAbc0;
228 const Matrix iDq = parkTransform * iInjAbc0;
229 const Matrix vRefDq = parkTransform * vRefAbc0;
230
231 const Real vcD = vcDq(0, 0);
232 const Real vcQ = vcDq(1, 0);
233 const Real ircD = iDq(0, 0);
234 const Real ircQ = iDq(1, 0);
235
236 const Real pInit = vcD * ircD + vcQ * ircQ;
237 const Real qInit = -vcD * ircQ + vcQ * ircD;
238
239 Matrix x0 = Matrix::Zero(mStateSize, 1);
240
241 x0(ThetaPLL, 0) = theta0;
242 x0(PhiPLL, 0) = (omega - mOmegaN) / mKiPLL;
243 x0(PFiltered, 0) = pInit;
244 x0(QFiltered, 0) = qInit;
245
246 x0(PhiD, 0) = (ircD + mKpPowerCtrl * (pInit - mPRef)) / mKiPowerCtrl;
247 x0(PhiQ, 0) = (ircQ - mKpPowerCtrl * (qInit - mQRef)) / mKiPowerCtrl;
248
249 const Real iRefD =
250 -mKpPowerCtrl * pInit + mKiPowerCtrl * x0(PhiD, 0) + mKpPowerCtrl * mPRef;
251 const Real iRefQ =
252 mKpPowerCtrl * qInit + mKiPowerCtrl * x0(PhiQ, 0) - mKpPowerCtrl * mQRef;
253
254 x0(GammaD, 0) = (vRefDq(0, 0) + mKpCurrCtrl * (ircD - iRefD)) / mKiCurrCtrl;
255 x0(GammaQ, 0) = (vRefDq(1, 0) + mKpCurrCtrl * (ircQ - iRefQ)) / mKiCurrCtrl;
256
257 x0.block(VcA, 0, 3, 1) = vcAbc0;
258 x0.block(IfA, 0, 3, 1) = ifAbc0;
259
260 **mX = x0;
261 **mIntfVoltage = uPhasor.real();
262 **mIntfCurrent = ((uPhasor - vcPhasor) / mRc).real();
263
266
267 SPDLOG_LOGGER_INFO(mSLog,
268 "\n--- Inverter SSN phasor/dq initialization ---"
269 "\nInput u: {:s}"
270 "\nOutput y: {:s}"
271 "\nState x: {:s}"
272 "\nP/Q init: [{:.6e}, {:.6e}]"
273 "\nVc dq: [{:.6e}, {:.6e}]"
274 "\nIinj dq: [{:.6e}, {:.6e}]"
275 "\n--- Initialization finished ---",
278 Logger::matrixToString(**mX), pInit, qInit, vcD, vcQ, ircD,
279 ircQ);
280}
281
282void EMT::Ph3::AvVoltSourceInverterStateSpace::buildStateSpaceModel(
283 const Matrix &x, const Matrix &u, Matrix &A, Matrix &B, Matrix &C,
284 Matrix &D, Matrix &E, Matrix &F) const {
285 // -------------------------------------------------------------------------
286 // 1) Operating point and Park transformation
287 // -------------------------------------------------------------------------
288 const Real theta0 = x(ThetaPLL, 0);
289 const Real pFiltered0 = x(PFiltered, 0);
290 const Real qFiltered0 = x(QFiltered, 0);
291 const Real phiD0 = x(PhiD, 0);
292 const Real phiQ0 = x(PhiQ, 0);
293 const Real gammaD0 = x(GammaD, 0);
294 const Real gammaQ0 = x(GammaQ, 0);
295 const Matrix vcAbc0 = x.block(VcA, 0, 3, 1);
296
297 const Matrix identity3 = Matrix::Identity(3, 3);
298
299 const Matrix parkTransform = getParkTransformMatrix(theta0);
300 const Matrix tD = parkTransform.row(0);
301 const Matrix tQ = parkTransform.row(1);
302 const Matrix inverseParkTransform = getInverseParkTransformMatrix(theta0);
303 const Matrix sD = inverseParkTransform.col(0);
304 const Matrix sQ = inverseParkTransform.col(1);
305
306 const Matrix dTdTheta = tQ;
307 const Matrix dTqTheta = -tD;
308 const Matrix dSdTheta = sQ;
309 const Matrix dSqTheta = -sD;
310
311 // -------------------------------------------------------------------------
312 // 2) PLL measurement equation
313 //
314 // vq(theta, Vc) ≈ aThetaPLL * theta + aVPLL * Vc + bVq
315 //
316 // theta_dot = omegaN + KpPLL * vq + KiPLL * phiPLL
317 // phiPLL_dot = vq
318 // -------------------------------------------------------------------------
319 const Real vq0 = (tQ * vcAbc0)(0, 0);
320 const Real aThetaPLL = (dTqTheta * vcAbc0)(0, 0);
321 const Matrix aVPLL = tQ;
322 const Real bVq = vq0 - aThetaPLL * theta0 - (aVPLL * vcAbc0)(0, 0);
323
324 // -------------------------------------------------------------------------
325 // 3) Grid-current measurement in dq
326 //
327 // i_rc = (Vc - u) / Rc
328 // i_dq = T(theta) * i_rc
329 //
330 // The controller uses positive current as inverter injection into the grid.
331 // The SSN output uses the opposite sign:
332 //
333 // y = (u - Vc) / Rc
334 // -------------------------------------------------------------------------
335 const Matrix iInjAbc0 = (vcAbc0 - u) / mRc;
336
337 const Real vcD0 = (tD * vcAbc0)(0, 0);
338 const Real vcQ0 = (tQ * vcAbc0)(0, 0);
339 const Real ircD0 = (tD * iInjAbc0)(0, 0);
340 const Real ircQ0 = (tQ * iInjAbc0)(0, 0);
341
342 const Matrix dVcDByVc = tD;
343 const Matrix dVcQByVc = tQ;
344 const Matrix dIrcDByVc = tD / mRc;
345 const Matrix dIrcQByVc = tQ / mRc;
346 const Matrix dIrcDByU = -tD / mRc;
347 const Matrix dIrcQByU = -tQ / mRc;
348
349 const Real dVcDByTheta = (dTdTheta * vcAbc0)(0, 0);
350 const Real dVcQByTheta = (dTqTheta * vcAbc0)(0, 0);
351 const Real dIrcDByTheta = (dTdTheta * iInjAbc0)(0, 0);
352 const Real dIrcQByTheta = (dTqTheta * iInjAbc0)(0, 0);
353
354 const Real bIrcD = ircD0 - dIrcDByTheta * theta0 -
355 (dIrcDByVc * vcAbc0)(0, 0) - (dIrcDByU * u)(0, 0);
356
357 const Real bIrcQ = ircQ0 - dIrcQByTheta * theta0 -
358 (dIrcQByVc * vcAbc0)(0, 0) - (dIrcQByU * u)(0, 0);
359
360 // -------------------------------------------------------------------------
361 // 4) Power measurement and power-filter states
362 //
363 // p = vc_d * irc_d + vc_q * irc_q
364 // q = -vc_d * irc_q + vc_q * irc_d
365 //
366 // P_dot = omegaCutoff * (p - P)
367 // Q_dot = omegaCutoff * (q - Q)
368 // -------------------------------------------------------------------------
369 const Real p0 = vcD0 * ircD0 + vcQ0 * ircQ0;
370 const Real dPByTheta = ircD0 * dVcDByTheta + vcD0 * dIrcDByTheta +
371 ircQ0 * dVcQByTheta + vcQ0 * dIrcQByTheta;
372 const Matrix dPByVc =
373 ircD0 * dVcDByVc + vcD0 * dIrcDByVc + ircQ0 * dVcQByVc + vcQ0 * dIrcQByVc;
374 const Matrix dPByU = vcD0 * dIrcDByU + vcQ0 * dIrcQByU;
375 const Real bP =
376 p0 - dPByTheta * theta0 - (dPByVc * vcAbc0)(0, 0) - (dPByU * u)(0, 0);
377
378 const Real q0 = -vcD0 * ircQ0 + vcQ0 * ircD0;
379 const Real dQByTheta = -ircQ0 * dVcDByTheta - vcD0 * dIrcQByTheta +
380 ircD0 * dVcQByTheta + vcQ0 * dIrcDByTheta;
381 const Matrix dQByVc = -ircQ0 * dVcDByVc - vcD0 * dIrcQByVc +
382 ircD0 * dVcQByVc + vcQ0 * dIrcDByVc;
383 const Matrix dQByU = -vcD0 * dIrcQByU + vcQ0 * dIrcDByU;
384 const Real bQ =
385 q0 - dQByTheta * theta0 - (dQByVc * vcAbc0)(0, 0) - (dQByU * u)(0, 0);
386
387 // -------------------------------------------------------------------------
388 // 5) Outer power control
389 //
390 // phi_d_dot = Pref - P
391 // phi_q_dot = Q - Qref
392 //
393 // iRef_d = KpP * (Pref - P) + KiP * phi_d
394 // iRef_q = KpP * (Q - Qref) + KiP * phi_q
395 // -------------------------------------------------------------------------
396 const Real iRefD0 =
397 -mKpPowerCtrl * pFiltered0 + mKiPowerCtrl * phiD0 + mKpPowerCtrl * mPRef;
398 const Real iRefQ0 =
399 mKpPowerCtrl * qFiltered0 + mKiPowerCtrl * phiQ0 - mKpPowerCtrl * mQRef;
400
401 // -------------------------------------------------------------------------
402 // 6) Inner current control and bridge-voltage reference
403 //
404 // gamma_d_dot = iRef_d - irc_d
405 // gamma_q_dot = iRef_q - irc_q
406 //
407 // vRef_d = KpI * (iRef_d - irc_d) + KiI * gamma_d
408 // vRef_q = KpI * (iRef_q - irc_q) + KiI * gamma_q
409 //
410 // vRef_abc = T_inv(theta) * [vRef_d, vRef_q]
411 // -------------------------------------------------------------------------
412 const Real vRefD0 =
413 -mKpCurrCtrl * ircD0 + mKiCurrCtrl * gammaD0 + mKpCurrCtrl * iRefD0;
414 const Real vRefQ0 =
415 -mKpCurrCtrl * ircQ0 + mKiCurrCtrl * gammaQ0 + mKpCurrCtrl * iRefQ0;
416
417 const Matrix vRefAbc0 = sD * vRefD0 + sQ * vRefQ0;
418
419 const Real dVRefDByTheta = -mKpCurrCtrl * dIrcDByTheta;
420 const Matrix dVRefDByVc = -mKpCurrCtrl * dIrcDByVc;
421 const Matrix dVRefDByU = -mKpCurrCtrl * dIrcDByU;
422
423 const Real dVRefQByTheta = -mKpCurrCtrl * dIrcQByTheta;
424 const Matrix dVRefQByVc = -mKpCurrCtrl * dIrcQByVc;
425 const Matrix dVRefQByU = -mKpCurrCtrl * dIrcQByU;
426
427 Matrix dVRefAbcByX = Matrix::Zero(3, mStateSize);
428 Matrix dVRefAbcByU = Matrix::Zero(3, 3);
429
430 dVRefAbcByX.col(ThetaPLL) = dSdTheta * vRefD0 + dSqTheta * vRefQ0 +
431 sD * dVRefDByTheta + sQ * dVRefQByTheta;
432
433 dVRefAbcByX.col(PFiltered) += sD * (-mKpCurrCtrl * mKpPowerCtrl);
434 dVRefAbcByX.col(PhiD) += sD * (mKpCurrCtrl * mKiPowerCtrl);
435 dVRefAbcByX.col(GammaD) += sD * mKiCurrCtrl;
436
437 dVRefAbcByX.col(QFiltered) += sQ * (mKpCurrCtrl * mKpPowerCtrl);
438 dVRefAbcByX.col(PhiQ) += sQ * (mKpCurrCtrl * mKiPowerCtrl);
439 dVRefAbcByX.col(GammaQ) += sQ * mKiCurrCtrl;
440
441 dVRefAbcByX.block(0, VcA, 3, 3) += sD * dVRefDByVc + sQ * dVRefQByVc;
442
443 dVRefAbcByU = sD * dVRefDByU + sQ * dVRefQByU;
444
445 const Matrix vRefAbcOffset = vRefAbc0 - dVRefAbcByX * x - dVRefAbcByU * u;
446
447 // -------------------------------------------------------------------------
448 // 7) Initialize affine state-space matrices
449 //
450 // x_dot ≈ A * x + B * u + E
451 // y ≈ C * x + D * u + F
452 // -------------------------------------------------------------------------
453 A.setZero(mStateSize, mStateSize);
454 B.setZero(mStateSize, 3);
455 C.setZero(3, mStateSize);
456 D.setZero(3, 3);
457 E.setZero(mStateSize, 1);
458 F.setZero(3, 1);
459
460 // -------------------------------------------------------------------------
461 // 8) Stamp PLL rows
462 // -------------------------------------------------------------------------
463 A(ThetaPLL, ThetaPLL) = mKpPLL * aThetaPLL;
464 A(ThetaPLL, PhiPLL) = mKiPLL;
465 A.block(ThetaPLL, VcA, 1, 3) = mKpPLL * aVPLL;
466
467 A(PhiPLL, ThetaPLL) = aThetaPLL;
468 A.block(PhiPLL, VcA, 1, 3) = aVPLL;
469
470 E(ThetaPLL, 0) = mOmegaN + mKpPLL * bVq;
471 E(PhiPLL, 0) = bVq;
472
473 // -------------------------------------------------------------------------
474 // 9) Stamp power-filter rows
475 // -------------------------------------------------------------------------
476 A(PFiltered, ThetaPLL) = mOmegaCutoff * dPByTheta;
477 A(PFiltered, PFiltered) = -mOmegaCutoff;
478 A.block(PFiltered, VcA, 1, 3) = mOmegaCutoff * dPByVc;
479 B.block(PFiltered, 0, 1, 3) = mOmegaCutoff * dPByU;
480 E(PFiltered, 0) = mOmegaCutoff * bP;
481
482 A(QFiltered, ThetaPLL) = mOmegaCutoff * dQByTheta;
483 A(QFiltered, QFiltered) = -mOmegaCutoff;
484 A.block(QFiltered, VcA, 1, 3) = mOmegaCutoff * dQByVc;
485 B.block(QFiltered, 0, 1, 3) = mOmegaCutoff * dQByU;
486 E(QFiltered, 0) = mOmegaCutoff * bQ;
487
488 // -------------------------------------------------------------------------
489 // 10) Stamp outer-loop integrator rows
490 // -------------------------------------------------------------------------
491 A(PhiD, PFiltered) = -1.0;
492 E(PhiD, 0) = mPRef;
493
494 A(PhiQ, QFiltered) = 1.0;
495 E(PhiQ, 0) = -mQRef;
496
497 // -------------------------------------------------------------------------
498 // 11) Stamp current-loop integrator rows
499 // -------------------------------------------------------------------------
500 A(GammaD, PFiltered) = -mKpPowerCtrl;
501 A(GammaD, PhiD) = mKiPowerCtrl;
502 A(GammaD, ThetaPLL) = -dIrcDByTheta;
503 A.block(GammaD, VcA, 1, 3) = -dIrcDByVc;
504 B.block(GammaD, 0, 1, 3) = -dIrcDByU;
505 E(GammaD, 0) = mKpPowerCtrl * mPRef - bIrcD;
506
507 A(GammaQ, QFiltered) = mKpPowerCtrl;
508 A(GammaQ, PhiQ) = mKiPowerCtrl;
509 A(GammaQ, ThetaPLL) = -dIrcQByTheta;
510 A.block(GammaQ, VcA, 1, 3) = -dIrcQByVc;
511 B.block(GammaQ, 0, 1, 3) = -dIrcQByU;
512 E(GammaQ, 0) = -mKpPowerCtrl * mQRef - bIrcQ;
513
514 // -------------------------------------------------------------------------
515 // 12) Stamp electrical filter plant
516 //
517 // Vc_dot = If / Cf + (u - Vc) / (Cf * Rc)
518 // If_dot = (vRef_abc - Vc - Rf * If) / Lf
519 // -------------------------------------------------------------------------
520 A.block(VcA, VcA, 3, 3) = -1.0 / (mCf * mRc) * identity3;
521 A.block(VcA, IfA, 3, 3) = 1.0 / mCf * identity3;
522 B.block(VcA, 0, 3, 3) = 1.0 / (mCf * mRc) * identity3;
523
524 A.block(IfA, 0, 3, mStateSize) = (1.0 / mLf) * dVRefAbcByX;
525 A.block(IfA, VcA, 3, 3) += -1.0 / mLf * identity3;
526 A.block(IfA, IfA, 3, 3) += -mRf / mLf * identity3;
527 B.block(IfA, 0, 3, 3) = (1.0 / mLf) * dVRefAbcByU;
528 E.block(IfA, 0, 3, 1) = (1.0 / mLf) * vRefAbcOffset;
529
530 // -------------------------------------------------------------------------
531 // 13) Stamp SSN output
532 //
533 // y = (u - Vc) / Rc
534 // -------------------------------------------------------------------------
535 C.block(0, VcA, 3, 3) = -1.0 / mRc * identity3;
536 D = 1.0 / mRc * identity3;
537}
538
540 Matrix E;
541 Matrix F;
542
543 // The local linearized SSN model is time-varying because the network abc
544 // states are coupled with dq-frame control through the Park transformation.
545 // Therefore the stamp is recomputed every step and the change check is
546 // intentionally skipped.
547 buildStateSpaceModel(**mX, **mIntfVoltage, mA, mB, mC, mD, E, F);
548
551
552 return true;
553}
void setParameters(Real lf, Real cf, Real rf, Real rc, Real omegaN, Real kpPLL, Real kiPLL, Real omegaCutoff, Real pRef, Real qRef, Real kpPowerCtrl, Real kiPowerCtrl, Real kpCurrCtrl, Real kiCurrCtrl)
std::vector< SSNComp::LocalAbcStateBlock > getLocalAbcStateBlocks() const override final
std::vector< String > getLocalStateNames() const override final
AvVoltSourceInverterStateSpace(String uid, String name, Logger::Level logLevel=Logger::Level::off)
void initializeFromNodesAndTerminals(Real frequency) override final
Initializes Component variables according to power flow data stored in Nodes.
void updateLogAttributes(const Matrix &u) const override final
Update derived attributes used for logging/inspection.
TwoTerminalVTypeVariableSSNComp(String uid, String name, Logger::Level logLevel=Logger::Level::off)
const Attribute< Matrix >::Ptr mX
Definition EMT_SSNComp.h:43
void setParameters(const Matrix &A, const Matrix &B, const Matrix &C, const Matrix &D)
static constexpr Real mInitializationTolerance
static constexpr Int mInitializationMaxIterations
String uid()
Returns unique id.
AttributeList::Ptr mAttributes
Attribute List.
spdlog::level::level_enum Level
Definition Logger.h:33
static String matrixToString(const Matrix &mat)
Definition Logger.cpp:31
const Attribute< MatrixVar< Real > >::Ptr mIntfCurrent
const Attribute< MatrixVar< Real > >::Ptr mIntfVoltage
bool mParametersSet
Flag indicating that parameters are set via setParameters() function.
Logger::Log mSLog
Component logger.
#define PI
Definition Definitions.h:43
#define SHIFT_TO_PHASE_C
Definition Definitions.h:47
#define SHIFT_TO_PHASE_B
Definition Definitions.h:46
Eigen::Matrix< Real, Eigen::Dynamic, Eigen::Dynamic, Eigen::ColMajor > Matrix
Dense matrix for real numbers.
Definition Definitions.h:81
std::string String
Definition Definitions.h:65
double Real
Definition Definitions.h:62
int Int
Definition Definitions.h:61
std::complex< Real > Complex
Definition Definitions.h:63
Eigen::Matrix< Complex, Eigen::Dynamic, Eigen::Dynamic, Eigen::ColMajor > MatrixComp
Dense matrix for complex numbers.
Definition Definitions.h:84
bool Bool
Definition Definitions.h:64
unsigned int UInt
Definition Definitions.h:60