7#include <dpsim-models/DP/DP_Ph1_AvVoltSourceInverterStateSpace.h>
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")) {
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) {
38 throw std::invalid_argument(
"Filter inductance lf must be positive.");
41 throw std::invalid_argument(
"Filter capacitance cf must be positive.");
44 throw std::invalid_argument(
"Filter resistance rf must be non-negative.");
47 throw std::invalid_argument(
"Coupling resistance rc must be positive.");
50 throw std::invalid_argument(
51 "Nominal angular frequency omegaN must be positive.");
53 if (omegaCutoff < 0.0)
54 throw std::invalid_argument(
55 "Power-filter cutoff frequency omegaCutoff must be non-negative.");
58 throw std::invalid_argument(
"PLL integral gain kiPLL must be non-zero.");
60 if (kiPowerCtrl == 0.0)
61 throw std::invalid_argument(
62 "Power-control integral gain kiPowerCtrl must be non-zero.");
64 if (kiCurrCtrl == 0.0)
65 throw std::invalid_argument(
66 "Current-control integral gain kiCurrCtrl must be non-zero.");
77 mOmegaCutoff = omegaCutoff;
80 mKpPowerCtrl = kpPowerCtrl;
81 mKiPowerCtrl = kiPowerCtrl;
82 mKpCurrCtrl = kpCurrCtrl;
83 mKiCurrCtrl = kiCurrCtrl;
85 const Matrix x0 = Matrix::Zero(12, 1);
86 const Matrix u0 = Matrix::Zero(2, 1);
88 Matrix aMatrix, bMatrix, cMatrix, dMatrix, eVector, fVector;
89 buildStateSpaceModel(x0, u0, aMatrix, bMatrix, cMatrix, dMatrix, eVector,
92 MixedVTypeVariableSSNComp::setParameters(aMatrix, bMatrix, cMatrix, dMatrix,
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 {
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);
112 const Real uRe = u(0, 0);
113 const Real uIm = u(1, 0);
115 const Real cosPsi = std::cos(psi);
116 const Real sinPsi = std::sin(psi);
119 const Real vcD = vcRe * cosPsi + vcIm * sinPsi;
120 const Real vcQ = vcIm * cosPsi - vcRe * sinPsi;
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;
128 const Real dVcQByPsi = -vcIm * sinPsi - vcRe * cosPsi;
129 const Real dVcQByVcRe = -sinPsi;
130 const Real dVcQByVcIm = cosPsi;
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;
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;
146 const Real pInst = vcD * ircD + vcQ * ircQ;
147 const Real qInst = -vcD * ircQ + vcQ * ircD;
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;
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;
161 -mKpPowerCtrl * pF + mKiPowerCtrl * phiD + mKpPowerCtrl * mPRef;
163 mKpPowerCtrl * qF + mKiPowerCtrl * phiQ - mKpPowerCtrl * mQRef;
166 -mKpCurrCtrl * ircD + mKiCurrCtrl * gammaD + mKpCurrCtrl * iRefD;
168 -mKpCurrCtrl * ircQ + mKiCurrCtrl * gammaQ + mKpCurrCtrl * 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;
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;
190 const Real vRefEnvRe = vRefD * cosPsi - vRefQ * sinPsi;
191 const Real vRefEnvIm = vRefD * sinPsi + vRefQ * cosPsi;
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;
198 auto dVRefEnvRe = [&](Real dD, Real dQ) {
return dD * cosPsi - dQ * sinPsi; };
199 auto dVRefEnvIm = [&](Real dD, Real dQ) {
return dD * sinPsi + dQ * cosPsi; };
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);
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);
224 Matrix f = Matrix::Zero(12, 1);
225 f(Psi, 0) = mKpPLL * vcQ + mKiPLL * x(PhiPLL, 0);
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;
239 A = Matrix::Zero(12, 12);
240 B = Matrix::Zero(12, 2);
242 A(Psi, Psi) = mKpPLL * dVcQByPsi;
243 A(Psi, PhiPLL) = mKiPLL;
244 A(Psi, VcRe) = mKpPLL * dVcQByVcRe;
245 A(Psi, VcIm) = mKpPLL * dVcQByVcIm;
247 A(PhiPLL, Psi) = dVcQByPsi;
248 A(PhiPLL, VcRe) = dVcQByVcRe;
249 A(PhiPLL, VcIm) = dVcQByVcIm;
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;
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;
263 A(PhiD, PFiltered) = -1.0;
264 A(PhiQ, QFiltered) = 1.0;
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;
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;
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);
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);
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;
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;
321 E = f - A * x - B * u;
324 C = Matrix::Zero(2, 12);
325 C(0, VcRe) = -1.0 / mRc;
326 C(1, VcIm) = -1.0 / mRc;
328 D = Matrix::Zero(2, 2);
332 F = Matrix::Zero(2, 1);
340 buildStateSpaceModel(**
mX, packComplex((**inputAttribute())(0, 0)),
mA, mB,
350 const Matrix &u)
const {
351 const Matrix &x = **
mX;
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;
361 **mVcD = vcRe * cosPsi + vcIm * sinPsi;
362 **mVcQ = vcIm * cosPsi - vcRe * sinPsi;
363 **mIrcD = ircRe * cosPsi + ircIm * sinPsi;
364 **mIrcQ = ircIm * cosPsi - ircRe * sinPsi;
366 **mPInst = **mVcD * **mIrcD + **mVcQ * **mIrcQ;
367 **mQInst = -**mVcD * **mIrcQ + **mVcQ * **mIrcD;
369 **mOmegaPLL = mOmegaN + mKpPLL * **mVcQ + mKiPLL * x(PhiPLL, 0);
375 throw std::logic_error(
"setParameters() must be called before "
376 "initializeFromNodesAndTerminals().");
380 const Real omega = 2.0 * PI * frequency;
381 const Complex powerRef(mPRef, mQRef);
384 const Complex U = uInit(0, 0);
387 Complex irc(0.0, 0.0);
389 for (Int iter = 0; iter < mInitializationMaxIterations; ++iter) {
390 if (std::abs(vc) < mInitializationTolerance) {
391 irc = Complex(0.0, 0.0);
395 const Complex iNext = std::conj(powerRef / vc);
396 const Complex vcNext = U + mRc * iNext;
400 if (std::abs(vcNext - vc) < mInitializationTolerance) {
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;
413 const Real psi0 = std::arg(vc);
414 const Complex rot0 = std::exp(-j * psi0);
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();
423 const Real pInit = vcD * ircD + vcQ * ircQ;
424 const Real qInit = -vcD * ircQ + vcQ * ircD;
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;
431 -mKpPowerCtrl * pInit + mKiPowerCtrl * phiD0 + mKpPowerCtrl * mPRef;
433 mKpPowerCtrl * qInit + mKiPowerCtrl * phiQ0 - mKpPowerCtrl * mQRef;
435 const Complex vRefDQ = vRef * rot0;
437 (vRefDQ.real() + mKpCurrCtrl * (ircD - iRefD0)) / mKiCurrCtrl;
439 (vRefDQ.imag() + mKpCurrCtrl * (ircQ - iRefQ0)) / mKiCurrCtrl;
441 Matrix x0 = Matrix::Zero(
stateSize(), 1);
443 x0(PhiPLL, 0) = phiPLL0;
444 x0(PFiltered, 0) = pInit;
445 x0(QFiltered, 0) = qInit;
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();
457 (**mIntfCurrent)(0, 0) = (U - vc) / mRc;
462 SPDLOG_LOGGER_INFO(
mSLog,
463 "\n--- Inverter SSN mixed real+complex initialization ---"
467 "\nP/Q init: [{:.6e}, {:.6e}]"
468 "\nVc dq: [{:.6e}, {:.6e}]"
469 "\nIinj dq: [{:.6e}, {:.6e}]"
470 "\n--- Initialization finished ---",
473 Logger::matrixToString(**
mX), pInit, qInit, vcD, vcQ, ircD,
void updateLogAttributes(const Matrix &u) const override final
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.