DPsim
Loading...
Searching...
No Matches
DP_Ph1_AvVoltSourceInverterStateSpace.cpp
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
7#include <dpsim-models/DP/DP_Ph1_AvVoltSourceInverterStateSpace.h>
8
9using namespace CPS;
10
11DP::Ph1::AvVoltSourceInverterStateSpace::AvVoltSourceInverterStateSpace(
12 String uid, String name, Logger::Level logLevel)
13 : MixedVTypeVariableSSNComp(uid, name, 8, 2, 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 **mVcD = 0.0;
25 **mVcQ = 0.0;
26 **mIrcD = 0.0;
27 **mIrcQ = 0.0;
28 **mPInst = 0.0;
29 **mQInst = 0.0;
30 **mOmegaPLL = 0.0;
31}
32
33void DP::Ph1::AvVoltSourceInverterStateSpace::setParameters(
34 Real lf, Real cf, Real rf, Real rc, Real omegaN, Real kpPLL, Real kiPLL,
35 Real omegaCutoff, Real pRef, Real qRef, Real kpPowerCtrl, Real kiPowerCtrl,
36 Real kpCurrCtrl, Real kiCurrCtrl) {
37 if (lf <= 0.0)
38 throw std::invalid_argument("Filter inductance lf must be positive.");
39
40 if (cf <= 0.0)
41 throw std::invalid_argument("Filter capacitance cf must be positive.");
42
43 if (rf < 0.0)
44 throw std::invalid_argument("Filter resistance rf must be non-negative.");
45
46 if (rc <= 0.0)
47 throw std::invalid_argument("Coupling resistance rc must be positive.");
48
49 if (omegaN <= 0.0)
50 throw std::invalid_argument(
51 "Nominal angular frequency omegaN must be positive.");
52
53 if (omegaCutoff < 0.0)
54 throw std::invalid_argument(
55 "Power-filter cutoff frequency omegaCutoff must be non-negative.");
56
57 if (kiPLL == 0.0)
58 throw std::invalid_argument("PLL integral gain kiPLL must be non-zero.");
59
60 if (kiPowerCtrl == 0.0)
61 throw std::invalid_argument(
62 "Power-control integral gain kiPowerCtrl must be non-zero.");
63
64 if (kiCurrCtrl == 0.0)
65 throw std::invalid_argument(
66 "Current-control integral gain kiCurrCtrl must be non-zero.");
67
68 mLf = lf;
69 mCf = cf;
70 mRf = rf;
71 mRc = rc;
72
73 mOmegaN = omegaN;
74 mKpPLL = kpPLL;
75 mKiPLL = kiPLL;
76
77 mOmegaCutoff = omegaCutoff;
78 mPRef = pRef;
79 mQRef = qRef;
80 mKpPowerCtrl = kpPowerCtrl;
81 mKiPowerCtrl = kiPowerCtrl;
82 mKpCurrCtrl = kpCurrCtrl;
83 mKiCurrCtrl = kiCurrCtrl;
84
85 const Matrix x0 = Matrix::Zero(12, 1);
86 const Matrix u0 = Matrix::Zero(2, 1);
87
88 Matrix aMatrix, bMatrix, cMatrix, dMatrix, eVector, fVector;
89 buildStateSpaceModel(x0, u0, aMatrix, bMatrix, cMatrix, dMatrix, eVector,
90 fVector);
91
92 MixedVTypeVariableSSNComp::setParameters(aMatrix, bMatrix, cMatrix, dMatrix,
93 eVector, fVector);
94}
95
96void DP::Ph1::AvVoltSourceInverterStateSpace::buildStateSpaceModel(
97 const Matrix &x, const Matrix &u, Matrix &A, Matrix &B, Matrix &C,
98 Matrix &D, Matrix &E, Matrix &F) const {
99 // 1) Unpack the operating point. psi := theta0 - thetaN (never a state itself).
100 const Real psi = x(Psi, 0);
101 const Real pF = x(PFiltered, 0);
102 const Real qF = x(QFiltered, 0);
103 const Real phiD = x(PhiD, 0);
104 const Real phiQ = x(PhiQ, 0);
105 const Real gammaD = x(GammaD, 0);
106 const Real gammaQ = x(GammaQ, 0);
107 const Real vcRe = x(VcRe, 0);
108 const Real vcIm = x(VcIm, 0);
109 const Real ifRe = x(IfRe, 0);
110 const Real ifIm = x(IfIm, 0);
111
112 const Real uRe = u(0, 0);
113 const Real uIm = u(1, 0);
114
115 const Real cosPsi = std::cos(psi);
116 const Real sinPsi = std::sin(psi);
117
118 // 2) dq measurements: Vc*e^{-j*psi} and Irc*e^{-j*psi}, Irc = (Vc-U)/Rc.
119 const Real vcD = vcRe * cosPsi + vcIm * sinPsi;
120 const Real vcQ = vcIm * cosPsi - vcRe * sinPsi;
121
122 const Real ircRe = (vcRe - uRe) / mRc;
123 const Real ircIm = (vcIm - uIm) / mRc;
124 const Real ircD = ircRe * cosPsi + ircIm * sinPsi;
125 const Real ircQ = ircIm * cosPsi - ircRe * sinPsi;
126
127 // Jacobian of vcQ (only vq feeds the PLL rows).
128 const Real dVcQByPsi = -vcIm * sinPsi - vcRe * cosPsi;
129 const Real dVcQByVcRe = -sinPsi;
130 const Real dVcQByVcIm = cosPsi;
131
132 // Jacobian of ircD, ircQ.
133 const Real dIrcDByPsi = -ircRe * sinPsi + ircIm * cosPsi;
134 const Real dIrcDByVcRe = cosPsi / mRc;
135 const Real dIrcDByVcIm = sinPsi / mRc;
136 const Real dIrcDByURe = -cosPsi / mRc;
137 const Real dIrcDByUIm = -sinPsi / mRc;
138
139 const Real dIrcQByPsi = -ircIm * sinPsi - ircRe * cosPsi;
140 const Real dIrcQByVcRe = -sinPsi / mRc;
141 const Real dIrcQByVcIm = cosPsi / mRc;
142 const Real dIrcQByURe = sinPsi / mRc;
143 const Real dIrcQByUIm = -cosPsi / mRc;
144
145 // 3) Power: P+jQ = (1/Rc)*Vc*conj(Vc-U), evaluated as the dot product below.
146 const Real pInst = vcD * ircD + vcQ * ircQ;
147 const Real qInst = -vcD * ircQ + vcQ * ircD;
148
149 const Real dPByVcRe = (2.0 / mRc) * vcRe - (1.0 / mRc) * uRe;
150 const Real dPByVcIm = (2.0 / mRc) * vcIm - (1.0 / mRc) * uIm;
151 const Real dPByURe = -(1.0 / mRc) * vcRe;
152 const Real dPByUIm = -(1.0 / mRc) * vcIm;
153
154 const Real dQByVcRe = (1.0 / mRc) * uIm;
155 const Real dQByVcIm = -(1.0 / mRc) * uRe;
156 const Real dQByURe = -(1.0 / mRc) * vcIm;
157 const Real dQByUIm = (1.0 / mRc) * vcRe;
158
159 // 4) Outer power control and inner current control (dq).
160 const Real iRefD =
161 -mKpPowerCtrl * pF + mKiPowerCtrl * phiD + mKpPowerCtrl * mPRef;
162 const Real iRefQ =
163 mKpPowerCtrl * qF + mKiPowerCtrl * phiQ - mKpPowerCtrl * mQRef;
164
165 const Real vRefD =
166 -mKpCurrCtrl * ircD + mKiCurrCtrl * gammaD + mKpCurrCtrl * iRefD;
167 const Real vRefQ =
168 -mKpCurrCtrl * ircQ + mKiCurrCtrl * gammaQ + mKpCurrCtrl * iRefQ;
169
170 // d(vRefD)/d{...}, d(vRefQ)/d{...} via the chain rule through ircD/ircQ, iRefD/iRefQ.
171 const Real dVRefDByPsi = -mKpCurrCtrl * dIrcDByPsi;
172 const Real dVRefDByVcRe = -mKpCurrCtrl * dIrcDByVcRe;
173 const Real dVRefDByVcIm = -mKpCurrCtrl * dIrcDByVcIm;
174 const Real dVRefDByURe = -mKpCurrCtrl * dIrcDByURe;
175 const Real dVRefDByUIm = -mKpCurrCtrl * dIrcDByUIm;
176 const Real dVRefDByPF = -mKpCurrCtrl * mKpPowerCtrl;
177 const Real dVRefDByPhiD = mKpCurrCtrl * mKiPowerCtrl;
178 const Real dVRefDByGammaD = mKiCurrCtrl;
179
180 const Real dVRefQByPsi = -mKpCurrCtrl * dIrcQByPsi;
181 const Real dVRefQByVcRe = -mKpCurrCtrl * dIrcQByVcRe;
182 const Real dVRefQByVcIm = -mKpCurrCtrl * dIrcQByVcIm;
183 const Real dVRefQByURe = -mKpCurrCtrl * dIrcQByURe;
184 const Real dVRefQByUIm = -mKpCurrCtrl * dIrcQByUIm;
185 const Real dVRefQByQF = mKpCurrCtrl * mKpPowerCtrl;
186 const Real dVRefQByPhiQ = mKpCurrCtrl * mKiPowerCtrl;
187 const Real dVRefQByGammaQ = mKiCurrCtrl;
188
189 // 5) Bridge-voltage reference: VRefEnv = (vRefD+j*vRefQ)*e^{j*psi}; psi's partial needs the product rule, every other variable only enters implicitly.
190 const Real vRefEnvRe = vRefD * cosPsi - vRefQ * sinPsi;
191 const Real vRefEnvIm = vRefD * sinPsi + vRefQ * cosPsi;
192
193 const Real dVRefEnvReByPsi = dVRefDByPsi * cosPsi - vRefD * sinPsi -
194 dVRefQByPsi * sinPsi - vRefQ * cosPsi;
195 const Real dVRefEnvImByPsi = dVRefDByPsi * sinPsi + vRefD * cosPsi +
196 dVRefQByPsi * cosPsi - vRefQ * sinPsi;
197
198 auto dVRefEnvRe = [&](Real dD, Real dQ) { return dD * cosPsi - dQ * sinPsi; };
199 auto dVRefEnvIm = [&](Real dD, Real dQ) { return dD * sinPsi + dQ * cosPsi; };
200
201 const Real dVRefEnvReByPF = dVRefEnvRe(dVRefDByPF, 0.0);
202 const Real dVRefEnvReByQF = dVRefEnvRe(0.0, dVRefQByQF);
203 const Real dVRefEnvReByPhiD = dVRefEnvRe(dVRefDByPhiD, 0.0);
204 const Real dVRefEnvReByPhiQ = dVRefEnvRe(0.0, dVRefQByPhiQ);
205 const Real dVRefEnvReByGammaD = dVRefEnvRe(dVRefDByGammaD, 0.0);
206 const Real dVRefEnvReByGammaQ = dVRefEnvRe(0.0, dVRefQByGammaQ);
207 const Real dVRefEnvReByVcRe = dVRefEnvRe(dVRefDByVcRe, dVRefQByVcRe);
208 const Real dVRefEnvReByVcIm = dVRefEnvRe(dVRefDByVcIm, dVRefQByVcIm);
209 const Real dVRefEnvReByURe = dVRefEnvRe(dVRefDByURe, dVRefQByURe);
210 const Real dVRefEnvReByUIm = dVRefEnvRe(dVRefDByUIm, dVRefQByUIm);
211
212 const Real dVRefEnvImByPF = dVRefEnvIm(dVRefDByPF, 0.0);
213 const Real dVRefEnvImByQF = dVRefEnvIm(0.0, dVRefQByQF);
214 const Real dVRefEnvImByPhiD = dVRefEnvIm(dVRefDByPhiD, 0.0);
215 const Real dVRefEnvImByPhiQ = dVRefEnvIm(0.0, dVRefQByPhiQ);
216 const Real dVRefEnvImByGammaD = dVRefEnvIm(dVRefDByGammaD, 0.0);
217 const Real dVRefEnvImByGammaQ = dVRefEnvIm(0.0, dVRefQByGammaQ);
218 const Real dVRefEnvImByVcRe = dVRefEnvIm(dVRefDByVcRe, dVRefQByVcRe);
219 const Real dVRefEnvImByVcIm = dVRefEnvIm(dVRefDByVcIm, dVRefQByVcIm);
220 const Real dVRefEnvImByURe = dVRefEnvIm(dVRefDByURe, dVRefQByURe);
221 const Real dVRefEnvImByUIm = dVRefEnvIm(dVRefDByUIm, dVRefQByUIm);
222
223 // 6) RHS f(x,u) (x_dot = f(x,u)).
224 Matrix f = Matrix::Zero(12, 1);
225 f(Psi, 0) = mKpPLL * vcQ + mKiPLL * x(PhiPLL, 0);
226 f(PhiPLL, 0) = vcQ;
227 f(PFiltered, 0) = mOmegaCutoff * (pInst - pF);
228 f(QFiltered, 0) = mOmegaCutoff * (qInst - qF);
229 f(PhiD, 0) = mPRef - pF;
230 f(PhiQ, 0) = qF - mQRef;
231 f(GammaD, 0) = iRefD - ircD;
232 f(GammaQ, 0) = iRefQ - ircQ;
233 f(VcRe, 0) = ifRe / mCf + (uRe - vcRe) / (mCf * mRc) + mOmegaN * vcIm;
234 f(VcIm, 0) = ifIm / mCf + (uIm - vcIm) / (mCf * mRc) - mOmegaN * vcRe;
235 f(IfRe, 0) = (vRefEnvRe - vcRe - mRf * ifRe) / mLf + mOmegaN * ifIm;
236 f(IfIm, 0) = (vRefEnvIm - vcIm - mRf * ifIm) / mLf - mOmegaN * ifRe;
237
238 // 7) Analytic Jacobian A = df/dx, B = df/du.
239 A = Matrix::Zero(12, 12);
240 B = Matrix::Zero(12, 2);
241
242 A(Psi, Psi) = mKpPLL * dVcQByPsi;
243 A(Psi, PhiPLL) = mKiPLL;
244 A(Psi, VcRe) = mKpPLL * dVcQByVcRe;
245 A(Psi, VcIm) = mKpPLL * dVcQByVcIm;
246
247 A(PhiPLL, Psi) = dVcQByPsi;
248 A(PhiPLL, VcRe) = dVcQByVcRe;
249 A(PhiPLL, VcIm) = dVcQByVcIm;
250
251 A(PFiltered, PFiltered) = -mOmegaCutoff;
252 A(PFiltered, VcRe) = mOmegaCutoff * dPByVcRe;
253 A(PFiltered, VcIm) = mOmegaCutoff * dPByVcIm;
254 B(PFiltered, 0) = mOmegaCutoff * dPByURe;
255 B(PFiltered, 1) = mOmegaCutoff * dPByUIm;
256
257 A(QFiltered, QFiltered) = -mOmegaCutoff;
258 A(QFiltered, VcRe) = mOmegaCutoff * dQByVcRe;
259 A(QFiltered, VcIm) = mOmegaCutoff * dQByVcIm;
260 B(QFiltered, 0) = mOmegaCutoff * dQByURe;
261 B(QFiltered, 1) = mOmegaCutoff * dQByUIm;
262
263 A(PhiD, PFiltered) = -1.0;
264 A(PhiQ, QFiltered) = 1.0;
265
266 A(GammaD, PFiltered) = -mKpPowerCtrl;
267 A(GammaD, PhiD) = mKiPowerCtrl;
268 A(GammaD, Psi) = -dIrcDByPsi;
269 A(GammaD, VcRe) = -dIrcDByVcRe;
270 A(GammaD, VcIm) = -dIrcDByVcIm;
271 B(GammaD, 0) = -dIrcDByURe;
272 B(GammaD, 1) = -dIrcDByUIm;
273
274 A(GammaQ, QFiltered) = mKpPowerCtrl;
275 A(GammaQ, PhiQ) = mKiPowerCtrl;
276 A(GammaQ, Psi) = -dIrcQByPsi;
277 A(GammaQ, VcRe) = -dIrcQByVcRe;
278 A(GammaQ, VcIm) = -dIrcQByVcIm;
279 B(GammaQ, 0) = -dIrcQByURe;
280 B(GammaQ, 1) = -dIrcQByUIm;
281
282 A(VcRe, VcRe) = -1.0 / (mCf * mRc);
283 A(VcRe, VcIm) = mOmegaN;
284 A(VcRe, IfRe) = 1.0 / mCf;
285 B(VcRe, 0) = 1.0 / (mCf * mRc);
286
287 A(VcIm, VcRe) = -mOmegaN;
288 A(VcIm, VcIm) = -1.0 / (mCf * mRc);
289 A(VcIm, IfIm) = 1.0 / mCf;
290 B(VcIm, 1) = 1.0 / (mCf * mRc);
291
292 A(IfRe, Psi) = dVRefEnvReByPsi / mLf;
293 A(IfRe, PFiltered) = dVRefEnvReByPF / mLf;
294 A(IfRe, QFiltered) = dVRefEnvReByQF / mLf;
295 A(IfRe, PhiD) = dVRefEnvReByPhiD / mLf;
296 A(IfRe, PhiQ) = dVRefEnvReByPhiQ / mLf;
297 A(IfRe, GammaD) = dVRefEnvReByGammaD / mLf;
298 A(IfRe, GammaQ) = dVRefEnvReByGammaQ / mLf;
299 A(IfRe, VcRe) = dVRefEnvReByVcRe / mLf - 1.0 / mLf;
300 A(IfRe, VcIm) = dVRefEnvReByVcIm / mLf;
301 A(IfRe, IfRe) = -mRf / mLf;
302 A(IfRe, IfIm) = mOmegaN;
303 B(IfRe, 0) = dVRefEnvReByURe / mLf;
304 B(IfRe, 1) = dVRefEnvReByUIm / mLf;
305
306 A(IfIm, Psi) = dVRefEnvImByPsi / mLf;
307 A(IfIm, PFiltered) = dVRefEnvImByPF / mLf;
308 A(IfIm, QFiltered) = dVRefEnvImByQF / mLf;
309 A(IfIm, PhiD) = dVRefEnvImByPhiD / mLf;
310 A(IfIm, PhiQ) = dVRefEnvImByPhiQ / mLf;
311 A(IfIm, GammaD) = dVRefEnvImByGammaD / mLf;
312 A(IfIm, GammaQ) = dVRefEnvImByGammaQ / mLf;
313 A(IfIm, VcRe) = dVRefEnvImByVcRe / mLf;
314 A(IfIm, VcIm) = dVRefEnvImByVcIm / mLf - 1.0 / mLf;
315 A(IfIm, IfRe) = -mOmegaN;
316 A(IfIm, IfIm) = -mRf / mLf;
317 B(IfIm, 0) = dVRefEnvImByURe / mLf;
318 B(IfIm, 1) = dVRefEnvImByUIm / mLf;
319
320 // 8) Offset E = f(x,u) - A*x - B*u.
321 E = f - A * x - B * u;
322
323 // 9) SSN output: y = (u - Vc)/Rc (exact, no relinearization needed).
324 C = Matrix::Zero(2, 12);
325 C(0, VcRe) = -1.0 / mRc;
326 C(1, VcIm) = -1.0 / mRc;
327
328 D = Matrix::Zero(2, 2);
329 D(0, 0) = 1.0 / mRc;
330 D(1, 1) = 1.0 / mRc;
331
332 F = Matrix::Zero(2, 1);
333}
334
336 Matrix E;
337 Matrix F;
338
339 // Relinearized every step (mirrors EMT); change-check intentionally skipped.
340 buildStateSpaceModel(**mX, packComplex((**inputAttribute())(0, 0)), mA, mB,
341 mC, mD, E, F);
342
343 setStateOffset(E);
344 setOutputOffset(F);
345
346 return true;
347}
348
350 const Matrix &u) const {
351 const Matrix &x = **mX;
352
353 const Real psi = x(Psi, 0);
354 const Real cosPsi = std::cos(psi);
355 const Real sinPsi = std::sin(psi);
356 const Real vcRe = x(VcRe, 0);
357 const Real vcIm = x(VcIm, 0);
358 const Real ircRe = (vcRe - u(0, 0)) / mRc;
359 const Real ircIm = (vcIm - u(1, 0)) / mRc;
360
361 **mVcD = vcRe * cosPsi + vcIm * sinPsi;
362 **mVcQ = vcIm * cosPsi - vcRe * sinPsi;
363 **mIrcD = ircRe * cosPsi + ircIm * sinPsi;
364 **mIrcQ = ircIm * cosPsi - ircRe * sinPsi;
365
366 **mPInst = **mVcD * **mIrcD + **mVcQ * **mIrcQ;
367 **mQInst = -**mVcD * **mIrcQ + **mVcQ * **mIrcD;
368
369 **mOmegaPLL = mOmegaN + mKpPLL * **mVcQ + mKiPLL * x(PhiPLL, 0);
370}
371
373 Real frequency) {
374 if (!mParametersSet)
375 throw std::logic_error("setParameters() must be called before "
376 "initializeFromNodesAndTerminals().");
377
378 // Initialized algebraically (mixed state), mirroring EMT::Ph3::AvVoltSourceInverterStateSpace.
379
380 const Real omega = 2.0 * PI * frequency;
381 const Complex powerRef(mPRef, mQRef);
382
383 const MatrixComp uInit = buildInitialInputFromNodes(frequency);
384 const Complex U = uInit(0, 0);
385
386 Complex vc = U;
387 Complex irc(0.0, 0.0);
388
389 for (Int iter = 0; iter < mInitializationMaxIterations; ++iter) {
390 if (std::abs(vc) < mInitializationTolerance) {
391 irc = Complex(0.0, 0.0);
392 break;
393 }
394
395 const Complex iNext = std::conj(powerRef / vc);
396 const Complex vcNext = U + mRc * iNext;
397
398 irc = iNext;
399
400 if (std::abs(vcNext - vc) < mInitializationTolerance) {
401 vc = vcNext;
402 break;
403 }
404
405 vc = vcNext;
406 }
407
408 const Complex j(0.0, 1.0);
409 const Complex ifCurrent = j * omega * mCf * vc + irc;
410 const Complex vRef = vc + (mRf + j * omega * mLf) * ifCurrent;
411
412 // thetaN(0) = 0, so psi0 = theta0 exactly.
413 const Real psi0 = std::arg(vc);
414 const Complex rot0 = std::exp(-j * psi0);
415
416 const Complex vcDQ = vc * rot0;
417 const Real vcD = vcDQ.real();
418 const Real vcQ = vcDQ.imag();
419 const Complex ircDQ = irc * rot0;
420 const Real ircD = ircDQ.real();
421 const Real ircQ = ircDQ.imag();
422
423 const Real pInit = vcD * ircD + vcQ * ircQ;
424 const Real qInit = -vcD * ircQ + vcQ * ircD;
425
426 const Real phiPLL0 = (omega - mOmegaN) / mKiPLL;
427 const Real phiD0 = (ircD + mKpPowerCtrl * (pInit - mPRef)) / mKiPowerCtrl;
428 const Real phiQ0 = (ircQ - mKpPowerCtrl * (qInit - mQRef)) / mKiPowerCtrl;
429
430 const Real iRefD0 =
431 -mKpPowerCtrl * pInit + mKiPowerCtrl * phiD0 + mKpPowerCtrl * mPRef;
432 const Real iRefQ0 =
433 mKpPowerCtrl * qInit + mKiPowerCtrl * phiQ0 - mKpPowerCtrl * mQRef;
434
435 const Complex vRefDQ = vRef * rot0;
436 const Real gammaD0 =
437 (vRefDQ.real() + mKpCurrCtrl * (ircD - iRefD0)) / mKiCurrCtrl;
438 const Real gammaQ0 =
439 (vRefDQ.imag() + mKpCurrCtrl * (ircQ - iRefQ0)) / mKiCurrCtrl;
440
441 Matrix x0 = Matrix::Zero(stateSize(), 1);
442 x0(Psi, 0) = psi0;
443 x0(PhiPLL, 0) = phiPLL0;
444 x0(PFiltered, 0) = pInit;
445 x0(QFiltered, 0) = qInit;
446 x0(PhiD, 0) = phiD0;
447 x0(PhiQ, 0) = phiQ0;
448 x0(GammaD, 0) = gammaD0;
449 x0(GammaQ, 0) = gammaQ0;
450 x0(VcRe, 0) = vc.real();
451 x0(VcIm, 0) = vc.imag();
452 x0(IfRe, 0) = ifCurrent.real();
453 x0(IfIm, 0) = ifCurrent.imag();
454
455 **mX = x0;
456 **mIntfVoltage = uInit;
457 (**mIntfCurrent)(0, 0) = (U - vc) / mRc;
458
460 updateLogAttributes(packComplex(U));
461
462 SPDLOG_LOGGER_INFO(mSLog,
463 "\n--- Inverter SSN mixed real+complex initialization ---"
464 "\nInput u: {:s}"
465 "\nOutput y: {:s}"
466 "\nState x: {:s}"
467 "\nP/Q init: [{:.6e}, {:.6e}]"
468 "\nVc dq: [{:.6e}, {:.6e}]"
469 "\nIinj dq: [{:.6e}, {:.6e}]"
470 "\n--- Initialization finished ---",
471 Logger::matrixCompToString(**mIntfVoltage),
472 Logger::matrixCompToString(**mIntfCurrent),
473 Logger::matrixToString(**mX), pInit, qInit, vcD, vcQ, ircD,
474 ircQ);
475}
Bool updateComponentParameters() override final
Rebuild A/B/C/D/E/F from the current state/input; returns true if the stamp changed.
void initializeFromNodesAndTerminals(Real frequency) override
Initializes Component variables according to power flow data stored in Nodes.
virtual MatrixComp buildInitialInputFromNodes(Real frequency)
Default: v = v_terminal1 - v_terminal0.
Matrix mA
Continuous-time real model over the packed state and packed [Re,Im] input/output.
Int stateSize() const
Total packed real state size: realStateCount + 2*complexStateCount.
const Attribute< Matrix >::Ptr mX
Packed real state: [realStates..., Re(cplxState0), Im(cplxState0), ...].
const Attribute< MatrixVar< Complex > >::Ptr mIntfCurrent
const Attribute< MatrixVar< Complex > >::Ptr mIntfVoltage
bool mParametersSet
Flag indicating that parameters are set via setParameters() function.
Logger::Log mSLog
Component logger.