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),
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",
45std::vector<EMT::SSNComp::LocalAbcStateBlock>
48 {{
static_cast<UInt>(VcA),
static_cast<UInt>(VcB),
static_cast<UInt>(VcC)},
50 {{
static_cast<UInt>(IfA),
static_cast<UInt>(IfB),
static_cast<UInt>(IfC)},
60 throw std::invalid_argument(
"Filter inductance lf must be positive.");
63 throw std::invalid_argument(
"Filter capacitance cf must be positive.");
66 throw std::invalid_argument(
"Filter resistance rf must be non-negative.");
69 throw std::invalid_argument(
"Coupling resistance rc must be positive.");
72 throw std::invalid_argument(
73 "Nominal angular frequency omegaN must be positive.");
75 if (omegaCutoff < 0.0)
76 throw std::invalid_argument(
77 "Power-filter cutoff frequency omegaCutoff must be non-negative.");
80 throw std::invalid_argument(
"PLL integral gain kiPLL must be non-zero.");
82 if (kiPowerCtrl == 0.0)
83 throw std::invalid_argument(
84 "Power-control integral gain kiPowerCtrl must be non-zero.");
86 if (kiCurrCtrl == 0.0)
87 throw std::invalid_argument(
88 "Current-control integral gain kiCurrCtrl must be non-zero.");
99 mOmegaCutoff = omegaCutoff;
102 mKpPowerCtrl = kpPowerCtrl;
103 mKiPowerCtrl = kiPowerCtrl;
104 mKpCurrCtrl = kpCurrCtrl;
105 mKiCurrCtrl = kiCurrCtrl;
107 const Matrix x0 = Matrix::Zero(mStateSize, 1);
108 const Matrix u0 = Matrix::Zero(3, 1);
116 buildStateSpaceModel(x0, u0, aMatrix, bMatrix, cMatrix, dMatrix, eVector,
123Matrix EMT::Ph3::AvVoltSourceInverterStateSpace::getParkTransformMatrix(
126 const Real k = std::sqrt(2.0 / 3.0);
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);
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);
138Matrix EMT::Ph3::AvVoltSourceInverterStateSpace::getInverseParkTransformMatrix(
141 const Real k = std::sqrt(2.0 / 3.0);
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);
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;
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);
165 **mPInst = **mVcD * **mIrcD + **mVcQ * **mIrcQ;
166 **mQInst = -**mVcD * **mIrcQ + **mVcQ * **mIrcD;
168 **mOmegaPLL = mOmegaN + mKpPLL * **mVcQ + mKiPLL * x(PhiPLL, 0);
174 throw std::logic_error(
"setParameters() must be called before "
175 "initializeFromNodesAndTerminals().");
182 const Real omega = 2.0 *
PI * frequency;
184 const Complex powerRef(mPRef, mQRef);
189 MatrixComp iInjPhasor = MatrixComp::Zero(3, 1);
192 const Complex vcA = vcPhasor(0, 0);
195 iInjPhasor.setZero();
199 const Complex iA = std::conj(powerRef / (1.5 * vcA));
204 const MatrixComp vcNext = uPhasor + mRc * iNext;
216 const MatrixComp ifPhasor = j * omega * mCf * vcPhasor + iInjPhasor;
217 const MatrixComp vRefPhasor = vcPhasor + (mRf + j * omega * mLf) * ifPhasor;
219 const Matrix vcAbc0 = vcPhasor.real();
220 const Matrix ifAbc0 = ifPhasor.real();
221 const Matrix iInjAbc0 = iInjPhasor.real();
222 const Matrix vRefAbc0 = vRefPhasor.real();
224 const Real theta0 = std::arg(vcPhasor(0, 0));
225 const Matrix parkTransform = getParkTransformMatrix(theta0);
227 const Matrix vcDq = parkTransform * vcAbc0;
228 const Matrix iDq = parkTransform * iInjAbc0;
229 const Matrix vRefDq = parkTransform * vRefAbc0;
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);
236 const Real pInit = vcD * ircD + vcQ * ircQ;
237 const Real qInit = -vcD * ircQ + vcQ * ircD;
239 Matrix x0 = Matrix::Zero(mStateSize, 1);
241 x0(ThetaPLL, 0) = theta0;
242 x0(PhiPLL, 0) = (omega - mOmegaN) / mKiPLL;
243 x0(PFiltered, 0) = pInit;
244 x0(QFiltered, 0) = qInit;
246 x0(PhiD, 0) = (ircD + mKpPowerCtrl * (pInit - mPRef)) / mKiPowerCtrl;
247 x0(PhiQ, 0) = (ircQ - mKpPowerCtrl * (qInit - mQRef)) / mKiPowerCtrl;
250 -mKpPowerCtrl * pInit + mKiPowerCtrl * x0(PhiD, 0) + mKpPowerCtrl * mPRef;
252 mKpPowerCtrl * qInit + mKiPowerCtrl * x0(PhiQ, 0) - mKpPowerCtrl * mQRef;
254 x0(GammaD, 0) = (vRefDq(0, 0) + mKpCurrCtrl * (ircD - iRefD)) / mKiCurrCtrl;
255 x0(GammaQ, 0) = (vRefDq(1, 0) + mKpCurrCtrl * (ircQ - iRefQ)) / mKiCurrCtrl;
257 x0.block(VcA, 0, 3, 1) = vcAbc0;
258 x0.block(IfA, 0, 3, 1) = ifAbc0;
267 SPDLOG_LOGGER_INFO(
mSLog,
268 "\n--- Inverter SSN phasor/dq initialization ---"
272 "\nP/Q init: [{:.6e}, {:.6e}]"
273 "\nVc dq: [{:.6e}, {:.6e}]"
274 "\nIinj dq: [{:.6e}, {:.6e}]"
275 "\n--- Initialization finished ---",
282void EMT::Ph3::AvVoltSourceInverterStateSpace::buildStateSpaceModel(
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);
297 const Matrix identity3 = Matrix::Identity(3, 3);
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);
306 const Matrix dTdTheta = tQ;
307 const Matrix dTqTheta = -tD;
308 const Matrix dSdTheta = sQ;
309 const Matrix dSqTheta = -sD;
319 const Real vq0 = (tQ * vcAbc0)(0, 0);
320 const Real aThetaPLL = (dTqTheta * vcAbc0)(0, 0);
322 const Real bVq = vq0 - aThetaPLL * theta0 - (aVPLL * vcAbc0)(0, 0);
335 const Matrix iInjAbc0 = (vcAbc0 - u) / mRc;
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);
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;
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);
354 const Real bIrcD = ircD0 - dIrcDByTheta * theta0 -
355 (dIrcDByVc * vcAbc0)(0, 0) - (dIrcDByU * u)(0, 0);
357 const Real bIrcQ = ircQ0 - dIrcQByTheta * theta0 -
358 (dIrcQByVc * vcAbc0)(0, 0) - (dIrcQByU * u)(0, 0);
369 const Real p0 = vcD0 * ircD0 + vcQ0 * ircQ0;
370 const Real dPByTheta = ircD0 * dVcDByTheta + vcD0 * dIrcDByTheta +
371 ircQ0 * dVcQByTheta + vcQ0 * dIrcQByTheta;
373 ircD0 * dVcDByVc + vcD0 * dIrcDByVc + ircQ0 * dVcQByVc + vcQ0 * dIrcQByVc;
374 const Matrix dPByU = vcD0 * dIrcDByU + vcQ0 * dIrcQByU;
376 p0 - dPByTheta * theta0 - (dPByVc * vcAbc0)(0, 0) - (dPByU * u)(0, 0);
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;
385 q0 - dQByTheta * theta0 - (dQByVc * vcAbc0)(0, 0) - (dQByU * u)(0, 0);
397 -mKpPowerCtrl * pFiltered0 + mKiPowerCtrl * phiD0 + mKpPowerCtrl * mPRef;
399 mKpPowerCtrl * qFiltered0 + mKiPowerCtrl * phiQ0 - mKpPowerCtrl * mQRef;
413 -mKpCurrCtrl * ircD0 + mKiCurrCtrl * gammaD0 + mKpCurrCtrl * iRefD0;
415 -mKpCurrCtrl * ircQ0 + mKiCurrCtrl * gammaQ0 + mKpCurrCtrl * iRefQ0;
417 const Matrix vRefAbc0 = sD * vRefD0 + sQ * vRefQ0;
419 const Real dVRefDByTheta = -mKpCurrCtrl * dIrcDByTheta;
420 const Matrix dVRefDByVc = -mKpCurrCtrl * dIrcDByVc;
421 const Matrix dVRefDByU = -mKpCurrCtrl * dIrcDByU;
423 const Real dVRefQByTheta = -mKpCurrCtrl * dIrcQByTheta;
424 const Matrix dVRefQByVc = -mKpCurrCtrl * dIrcQByVc;
425 const Matrix dVRefQByU = -mKpCurrCtrl * dIrcQByU;
427 Matrix dVRefAbcByX = Matrix::Zero(3, mStateSize);
428 Matrix dVRefAbcByU = Matrix::Zero(3, 3);
430 dVRefAbcByX.col(ThetaPLL) = dSdTheta * vRefD0 + dSqTheta * vRefQ0 +
431 sD * dVRefDByTheta + sQ * dVRefQByTheta;
433 dVRefAbcByX.col(PFiltered) += sD * (-mKpCurrCtrl * mKpPowerCtrl);
434 dVRefAbcByX.col(PhiD) += sD * (mKpCurrCtrl * mKiPowerCtrl);
435 dVRefAbcByX.col(GammaD) += sD * mKiCurrCtrl;
437 dVRefAbcByX.col(QFiltered) += sQ * (mKpCurrCtrl * mKpPowerCtrl);
438 dVRefAbcByX.col(PhiQ) += sQ * (mKpCurrCtrl * mKiPowerCtrl);
439 dVRefAbcByX.col(GammaQ) += sQ * mKiCurrCtrl;
441 dVRefAbcByX.block(0, VcA, 3, 3) += sD * dVRefDByVc + sQ * dVRefQByVc;
443 dVRefAbcByU = sD * dVRefDByU + sQ * dVRefQByU;
445 const Matrix vRefAbcOffset = vRefAbc0 - dVRefAbcByX * x - dVRefAbcByU * u;
453 A.setZero(mStateSize, mStateSize);
454 B.setZero(mStateSize, 3);
455 C.setZero(3, mStateSize);
457 E.setZero(mStateSize, 1);
463 A(ThetaPLL, ThetaPLL) = mKpPLL * aThetaPLL;
464 A(ThetaPLL, PhiPLL) = mKiPLL;
465 A.block(ThetaPLL, VcA, 1, 3) = mKpPLL * aVPLL;
467 A(PhiPLL, ThetaPLL) = aThetaPLL;
468 A.block(PhiPLL, VcA, 1, 3) = aVPLL;
470 E(ThetaPLL, 0) = mOmegaN + mKpPLL * bVq;
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;
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;
491 A(PhiD, PFiltered) = -1.0;
494 A(PhiQ, QFiltered) = 1.0;
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;
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;
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;
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;
535 C.block(0, VcA, 3, 3) = -1.0 / mRc * identity3;
536 D = 1.0 / mRc * identity3;
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
Bool updateComponentParameters() 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)
MatrixComp buildInitialInputFromNodes(Real frequency) override final
const Attribute< Matrix >::Ptr mX
void setStateOffset(const Matrix &E)
void setParameters(const Matrix &A, const Matrix &B, const Matrix &C, const Matrix &D)
static constexpr Real mInitializationTolerance
void setOutputOffset(const Matrix &F)
static constexpr Int mInitializationMaxIterations
String uid()
Returns unique id.
AttributeList::Ptr mAttributes
Attribute List.
spdlog::level::level_enum Level
static String matrixToString(const Matrix &mat)
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.
Eigen::Matrix< Real, Eigen::Dynamic, Eigen::Dynamic, Eigen::ColMajor > Matrix
Dense matrix for real numbers.
std::complex< Real > Complex
Eigen::Matrix< Complex, Eigen::Dynamic, Eigen::Dynamic, Eigen::ColMajor > MatrixComp
Dense matrix for complex numbers.