486 if (x.rows() != mStateSize || x.cols() != 1)
487 throw std::invalid_argument(
488 "SSN_GFM state vector has an invalid dimension.");
490 if (u.rows() != mInputSize || u.cols() != 1)
491 throw std::invalid_argument(
492 "SSN_GFM input vector has an invalid dimension.");
494 const Real pFiltered = x(PFiltered, 0);
495 const Real omega = x(Omega, 0);
496 const Real theta = x(Theta, 0);
497 const Real delayVoltageD = x(DelayVoltageD, 0);
498 const Real delayVoltageQ = x(DelayVoltageQ, 0);
500 const Matrix vcAbc = x.block(VcA, 0, 3, 1);
501 const Matrix ifAbc = x.block(IfA, 0, 3, 1);
503 const Matrix parkTransform = getParkTransformMatrix(theta);
504 const Matrix inverseParkTransform = getInverseParkTransformMatrix(theta);
506 const Matrix tD = parkTransform.row(0);
507 const Matrix tQ = parkTransform.row(1);
508 const Matrix sD = inverseParkTransform.col(0);
509 const Matrix sQ = inverseParkTransform.col(1);
511 const Matrix iGridAbc = (vcAbc - u) / mRc;
513 const Real vcD = (tD * vcAbc)(0, 0);
514 const Real vcQ = (tQ * vcAbc)(0, 0);
515 const Real ifD = (tD * ifAbc)(0, 0);
516 const Real ifQ = (tQ * ifAbc)(0, 0);
517 const Real iGridD = (tD * iGridAbc)(0, 0);
518 const Real iGridQ = (tQ * iGridAbc)(0, 0);
520 Matrix dVcDByX = Matrix::Zero(1, mStateSize);
521 Matrix dVcQByX = Matrix::Zero(1, mStateSize);
522 Matrix dIfDByX = Matrix::Zero(1, mStateSize);
523 Matrix dIfQByX = Matrix::Zero(1, mStateSize);
524 Matrix dIGridDByX = Matrix::Zero(1, mStateSize);
525 Matrix dIGridQByX = Matrix::Zero(1, mStateSize);
527 dVcDByX(0, Theta) = vcQ;
528 dVcDByX.block(0, VcA, 1, 3) = tD;
529 dVcQByX(0, Theta) = -vcD;
530 dVcQByX.block(0, VcA, 1, 3) = tQ;
532 dIfDByX(0, Theta) = ifQ;
533 dIfDByX.block(0, IfA, 1, 3) = tD;
534 dIfQByX(0, Theta) = -ifD;
535 dIfQByX.block(0, IfA, 1, 3) = tQ;
537 dIGridDByX(0, Theta) = iGridQ;
538 dIGridDByX.block(0, VcA, 1, 3) = tD / mRc;
539 dIGridQByX(0, Theta) = -iGridD;
540 dIGridQByX.block(0, VcA, 1, 3) = tQ / mRc;
542 const Matrix dIGridDByU = -tD / mRc;
543 const Matrix dIGridQByU = -tQ / mRc;
545 Matrix dPByX = 1.5 * (iGridD * dVcDByX + vcD * dIGridDByX + iGridQ * dVcQByX +
547 const Matrix dPByU = 1.5 * (vcD * dIGridDByU + vcQ * dIGridQByU);
549 Matrix dQByX = 1.5 * (iGridD * dVcQByX + vcQ * dIGridDByX - iGridQ * dVcDByX -
551 const Matrix dQByU = 1.5 * (vcQ * dIGridDByU - vcD * dIGridQByU);
553 dPByX(0, Theta) = 0.0;
554 dQByX(0, Theta) = 0.0;
556 const Real pccVoltageMagnitude = std::sqrt(vcD * vcD + vcQ * vcQ);
557 Matrix dPccVoltageMagnitudeByX = Matrix::Zero(1, mStateSize);
559 if (pccVoltageMagnitude > 1e-12) {
560 dPccVoltageMagnitudeByX =
561 (vcD * dVcDByX + vcQ * dVcQByX) / pccVoltageMagnitude;
562 dPccVoltageMagnitudeByX(0, Theta) = 0.0;
565 Matrix unitOmega = Matrix::Zero(1, mStateSize);
566 Matrix unitVoltageMagnitude = Matrix::Zero(1, mStateSize);
567 Matrix unitVoltageIntegratorD = Matrix::Zero(1, mStateSize);
568 Matrix unitVoltageIntegratorQ = Matrix::Zero(1, mStateSize);
569 Matrix unitCurrentIntegratorD = Matrix::Zero(1, mStateSize);
570 Matrix unitCurrentIntegratorQ = Matrix::Zero(1, mStateSize);
572 unitOmega(0, Omega) = 1.0;
573 unitVoltageMagnitude(0, VoltageMagnitude) = 1.0;
574 unitVoltageIntegratorD(0, VoltageIntegratorD) = 1.0;
575 unitVoltageIntegratorQ(0, VoltageIntegratorQ) = 1.0;
576 unitCurrentIntegratorD(0, CurrentIntegratorD) = 1.0;
577 unitCurrentIntegratorQ(0, CurrentIntegratorQ) = 1.0;
579 const Matrix dVoltageErrorDByX = unitVoltageMagnitude -
580 mVirtualResistance * dIfDByX +
581 mVirtualReactance * dIfQByX - dVcDByX;
582 const Matrix dVoltageErrorQByX =
583 -mVirtualResistance * dIfQByX - mVirtualReactance * dIfDByX - dVcQByX;
585 const Matrix dCurrentReferenceDByX =
586 mGridCurrentFeedforward * dIGridDByX -
587 mCf * (vcQ * unitOmega + omega * dVcQByX) +
588 mKpVoltage * dVoltageErrorDByX + mKiVoltage * unitVoltageIntegratorD;
589 const Matrix dCurrentReferenceDByU = mGridCurrentFeedforward * dIGridDByU;
591 const Matrix dCurrentReferenceQByX =
592 mGridCurrentFeedforward * dIGridQByX +
593 mCf * (vcD * unitOmega + omega * dVcDByX) +
594 mKpVoltage * dVoltageErrorQByX + mKiVoltage * unitVoltageIntegratorQ;
595 const Matrix dCurrentReferenceQByU = mGridCurrentFeedforward * dIGridQByU;
597 const Matrix dCurrentErrorDByX = dCurrentReferenceDByX - dIfDByX;
598 const Matrix dCurrentErrorQByX = dCurrentReferenceQByX - dIfQByX;
599 const Matrix dCurrentErrorDByU = dCurrentReferenceDByU;
600 const Matrix dCurrentErrorQByU = dCurrentReferenceQByU;
602 const Matrix dCapacitorCurrentDByX = dIfDByX - dIGridDByX;
603 const Matrix dCapacitorCurrentQByX = dIfQByX - dIGridQByX;
604 const Matrix dCapacitorCurrentDByU = -dIGridDByU;
605 const Matrix dCapacitorCurrentQByU = -dIGridQByU;
607 const Matrix dConverterVoltageReferenceDByX =
608 dVcDByX - mLf * (ifQ * unitOmega + omega * dIfQByX) +
609 mKpCurrent * dCurrentErrorDByX + mKiCurrent * unitCurrentIntegratorD -
610 mActiveDampingGain * dCapacitorCurrentDByX;
611 const Matrix dConverterVoltageReferenceDByU =
612 mKpCurrent * dCurrentErrorDByU -
613 mActiveDampingGain * dCapacitorCurrentDByU;
615 const Matrix dConverterVoltageReferenceQByX =
616 dVcQByX + mLf * (ifD * unitOmega + omega * dIfDByX) +
617 mKpCurrent * dCurrentErrorQByX + mKiCurrent * unitCurrentIntegratorQ -
618 mActiveDampingGain * dCapacitorCurrentQByX;
619 const Matrix dConverterVoltageReferenceQByU =
620 mKpCurrent * dCurrentErrorQByU -
621 mActiveDampingGain * dCapacitorCurrentQByU;
623 A.setZero(mStateSize, mStateSize);
624 B.setZero(mStateSize, mInputSize);
625 C.setZero(mOutputSize, mStateSize);
626 D.setZero(mOutputSize, mInputSize);
628 A.row(PFiltered) = mPowerFilterCutoff * dPByX;
629 A(PFiltered, PFiltered) -= mPowerFilterCutoff;
630 B.row(PFiltered) = mPowerFilterCutoff * dPByU;
632 A.row(QFiltered) = mPowerFilterCutoff * dQByX;
633 A(QFiltered, QFiltered) -= mPowerFilterCutoff;
634 B.row(QFiltered) = mPowerFilterCutoff * dQByU;
636 const Real omegaDenominator = regularizedOmega(omega);
637 const Real omegaDenominatorDerivative =
638 std::abs(omega) >= std::abs(omegaDenominator) ? 1.0 : 0.0;
640 A(Omega, PFiltered) = -1.0 / (mVirtualInertia * omegaDenominator);
641 A(Omega, Omega) = (-(mPRef - pFiltered) * omegaDenominatorDerivative /
642 (omegaDenominator * omegaDenominator) -
643 mDampingCoefficient) /
646 A(Theta, Omega) = 1.0;
648 if (mReactiveDroopCutoff > 0.0) {
649 A(VoltageMagnitude, QFiltered) =
650 -mReactiveDroopCutoff * mReactivePowerDroop;
651 A(VoltageMagnitude, VoltageMagnitude) = -mReactiveDroopCutoff;
653 A(VoltageMagnitude, QFiltered) = -mReactiveIntegralGain;
654 A.row(VoltageMagnitude) -= mVoltageDroopGain * dPccVoltageMagnitudeByX;
657 A.row(VoltageIntegratorD) = dVoltageErrorDByX;
658 A.row(VoltageIntegratorQ) = dVoltageErrorQByX;
660 A.row(CurrentIntegratorD) = dCurrentErrorDByX;
661 B.row(CurrentIntegratorD) = dCurrentErrorDByU;
662 A.row(CurrentIntegratorQ) = dCurrentErrorQByX;
663 B.row(CurrentIntegratorQ) = dCurrentErrorQByU;
665 A.row(DelayVoltageD) = mDelayBandwidth * dConverterVoltageReferenceDByX;
666 A(DelayVoltageD, DelayVoltageD) -= mDelayBandwidth;
667 B.row(DelayVoltageD) = mDelayBandwidth * dConverterVoltageReferenceDByU;
669 A.row(DelayVoltageQ) = mDelayBandwidth * dConverterVoltageReferenceQByX;
670 A(DelayVoltageQ, DelayVoltageQ) -= mDelayBandwidth;
671 B.row(DelayVoltageQ) = mDelayBandwidth * dConverterVoltageReferenceQByU;
673 const Matrix identity = Matrix::Identity(3, 3);
675 A.block(VcA, VcA, 3, 3) = -identity / (mCf * mRc);
676 A.block(VcA, IfA, 3, 3) = identity / mCf;
677 B.block(VcA, 0, 3, 3) = identity / (mCf * mRc);
679 A.block(IfA, VcA, 3, 3) = -identity / mLf;
680 A.block(IfA, IfA, 3, 3) = -mRf * identity / mLf;
681 A.block(IfA, Theta, 3, 1) = (sQ * delayVoltageD - sD * delayVoltageQ) / mLf;
682 A.block(IfA, DelayVoltageD, 3, 1) = sD / mLf;
683 A.block(IfA, DelayVoltageQ, 3, 1) = sQ / mLf;
685 C.block(0, VcA, 3, 3) = -identity / mRc;
694 A.setZero(mStateSize, mStateSize);
695 B.setZero(mStateSize, mInputSize);
696 C.setZero(mOutputSize, mStateSize);
697 D.setZero(mOutputSize, mInputSize);
699 Matrix fPlus = Matrix::Zero(mStateSize, 1);
700 Matrix fMinus = Matrix::Zero(mStateSize, 1);
702 Matrix gPlus = Matrix::Zero(mOutputSize, 1);
703 Matrix gMinus = Matrix::Zero(mOutputSize, 1);
706 for (
Int column = 0; column < mStateSize; ++column) {
708 mJacobianAbsoluteStep +
709 mJacobianRelativeStep * std::max(1.0, std::abs(x(column, 0)));
714 xPlus(column, 0) += step;
715 xMinus(column, 0) -= step;
717 evaluateStateDerivative(xPlus, u, fPlus);
718 evaluateStateDerivative(xMinus, u, fMinus);
720 evaluateOutput(xPlus, u, gPlus);
721 evaluateOutput(xMinus, u, gMinus);
723 A.col(column) = (fPlus - fMinus) / (2.0 * step);
724 C.col(column) = (gPlus - gMinus) / (2.0 * step);
728 for (
Int column = 0; column < mInputSize; ++column) {
730 mJacobianAbsoluteStep +
731 mJacobianRelativeStep * std::max(1.0, std::abs(u(column, 0)));
736 uPlus(column, 0) += step;
737 uMinus(column, 0) -= step;
739 evaluateStateDerivative(x, uPlus, fPlus);
740 evaluateStateDerivative(x, uMinus, fMinus);
742 evaluateOutput(x, uPlus, gPlus);
743 evaluateOutput(x, uMinus, gMinus);
745 B.col(column) = (fPlus - fMinus) / (2.0 * step);
746 D.col(column) = (gPlus - gMinus) / (2.0 * step);
837 throw std::logic_error(
"setParameters() must be called before "
838 "initializeFromNodesAndTerminals().");
840 const Real omegaInitialization = 2.0 *
PI * frequency;
841 const Complex imaginaryUnit(0.0, 1.0);
843 const Complex powerReference(mPRef, mQRef);
851 MatrixComp iInjectionPhasor = MatrixComp::Zero(3, 1);
860 const Complex vcA = vcPhasor(0, 0);
863 iInjectionPhasor.setZero();
871 const Complex currentA = std::conj(powerReference / (1.5 * vcA));
878 const MatrixComp nextVcPhasor = uPhasor + mRc * nextInjectionCurrent;
880 iInjectionPhasor = nextInjectionCurrent;
883 vcPhasor = nextVcPhasor;
887 vcPhasor = nextVcPhasor;
894 iInjectionPhasor + imaginaryUnit * omegaInitialization * mCf * vcPhasor;
900 vcPhasor + (mRf + imaginaryUnit * omegaInitialization * mLf) * ifPhasor;
902 const Matrix vcAbc0 = vcPhasor.real();
903 const Matrix ifAbc0 = ifPhasor.real();
904 const Matrix iGridAbc0 = iInjectionPhasor.real();
905 const Matrix converterVoltageAbc0 = converterVoltagePhasor.real();
911 const Complex virtualImpedance(mVirtualResistance, mVirtualReactance);
912 const MatrixComp emfPhasor = vcPhasor + virtualImpedance * ifPhasor;
913 const Real theta0 = std::arg(emfPhasor(0, 0));
915 const Matrix parkTransform = getParkTransformMatrix(theta0);
917 const Matrix vcDq0 = parkTransform * vcAbc0;
918 const Matrix ifDq0 = parkTransform * ifAbc0;
919 const Matrix iGridDq0 = parkTransform * iGridAbc0;
920 const Matrix converterVoltageDq0 = parkTransform * converterVoltageAbc0;
922 const Real vcD0 = vcDq0(0, 0);
923 const Real vcQ0 = vcDq0(1, 0);
925 const Real ifD0 = ifDq0(0, 0);
926 const Real ifQ0 = ifDq0(1, 0);
928 const Real iGridD0 = iGridDq0(0, 0);
929 const Real iGridQ0 = iGridDq0(1, 0);
931 const Real pInitial = 1.5 * (vcD0 * iGridD0 + vcQ0 * iGridQ0);
933 const Real qInitial = 1.5 * (vcQ0 * iGridD0 - vcD0 * iGridQ0);
935 const Real iCapD0 = ifD0 - iGridD0;
936 const Real iCapQ0 = ifQ0 - iGridQ0;
938 Matrix x0 = Matrix::Zero(mStateSize, 1);
940 x0(PFiltered, 0) = pInitial;
941 x0(QFiltered, 0) = qInitial;
943 x0(Omega, 0) = omegaInitialization;
944 x0(Theta, 0) = theta0;
947 x0(VoltageMagnitude, 0) = std::abs(emfPhasor(0, 0));
951 mVoltageSetpoint = x0(VoltageMagnitude, 0);
955 const Real voltageReferenceD0 =
956 x0(VoltageMagnitude, 0) -
957 (mVirtualResistance * ifD0 - mVirtualReactance * ifQ0);
958 const Real voltageReferenceQ0 =
959 -(mVirtualResistance * ifQ0 + mVirtualReactance * ifD0);
960 const Real voltageErrorD0 = voltageReferenceD0 - vcD0;
961 const Real voltageErrorQ0 = voltageReferenceQ0 - vcQ0;
971 x0(VoltageIntegratorD, 0) =
972 (ifD0 - mGridCurrentFeedforward * iGridD0 +
973 omegaInitialization * mCf * vcQ0 - mKpVoltage * voltageErrorD0) /
982 x0(VoltageIntegratorQ, 0) =
983 (ifQ0 - mGridCurrentFeedforward * iGridQ0 -
984 omegaInitialization * mCf * vcD0 - mKpVoltage * voltageErrorQ0) /
994 x0(CurrentIntegratorD, 0) =
995 (converterVoltageDq0(0, 0) - vcD0 + omegaInitialization * mLf * ifQ0 +
996 mActiveDampingGain * iCapD0) /
1004 x0(CurrentIntegratorQ, 0) =
1005 (converterVoltageDq0(1, 0) - vcQ0 - omegaInitialization * mLf * ifD0 +
1006 mActiveDampingGain * iCapQ0) /
1010 x0(DelayVoltageD, 0) = converterVoltageDq0(0, 0);
1011 x0(DelayVoltageQ, 0) = converterVoltageDq0(1, 0);
1013 x0.block(VcA, 0, 3, 1) = vcAbc0;
1014 x0.block(IfA, 0, 3, 1) = ifAbc0;
1044 Matrix stateDerivative = Matrix::Zero(mStateSize, 1);
1048 const Matrix nonlinearOutput = [&]() {
1049 Matrix output = Matrix::Zero(mOutputSize, 1);
1058 "\n--- SSN GFM initialization ---"
1059 "\nInput voltage u: {:s}"
1060 "\nInterface current y: {:s}"
1062 "\nState derivative norm: {:.6e}"
1063 "\nNonlinear output: {:s}"
1064 "\nSSN output: {:s}"
1065 "\nOutput mismatch norm: {:.6e}"
1067 "\nHistory-vector norm: {:.6e}"
1068 "\nP/Q initial: [{:.6e}, {:.6e}]"
1069 "\nVc dq: [{:.6e}, {:.6e}]"
1070 "\nIGrid dq: [{:.6e}, {:.6e}]"
1071 "\nIf dq: [{:.6e}, {:.6e}]"
1072 "\nConverter voltage dq: [{:.6e}, {:.6e}]"
1073 "\n--- SSN GFM initialization finished ---",
1078 mW.norm(),
mYHist.norm(), pInitial, qInitial, vcD0, vcQ0, iGridD0,
1079 iGridQ0, ifD0, ifQ0, converterVoltageDq0(0, 0),
1080 converterVoltageDq0(1, 0));