4#include <Eigen/Eigenvalues>
6#include <dpsim/StateSpaceModalAnalysis.h>
14Matrix parkTransformDQ0(Real theta) {
15 Matrix transform(3, 3);
17 const Real k = std::sqrt(2.0 / 3.0);
18 const Real k0 = 1.0 / std::sqrt(3.0);
20 transform.row(0) << k * std::cos(theta), k * std::cos(theta - 2.0 * PI / 3.0),
21 k * std::cos(theta + 2.0 * PI / 3.0);
23 transform.row(1) << -k * std::sin(theta),
24 -k * std::sin(theta - 2.0 * PI / 3.0),
25 -k * std::sin(theta + 2.0 * PI / 3.0);
27 transform.row(2) << k0, k0, k0;
34StateSpaceModalAnalysis::StateSpaceModalAnalysis(
36 : mExtractor(extractor) {}
39 if (!mExtractor.isInitialized())
40 throw std::logic_error(
"StateSpaceModalAnalysis requires an initialized "
41 "MNAStateSpaceExtractor.");
43 const Matrix Ad = buildDiscreteStateMatrixInAnalysisFrame();
46 mDiscreteEigenvalues.resize(0);
47 mContinuousEigenvalues.resize(0);
51 Eigen::EigenSolver<Matrix> eigenSolver(Ad,
false);
53 if (eigenSolver.info() != Eigen::Success)
54 throw std::runtime_error(
55 "StateSpaceModalAnalysis: eigenvalue computation failed.");
57 mDiscreteEigenvalues = eigenSolver.eigenvalues();
59 mContinuousEigenvalues.resize(mDiscreteEigenvalues.rows());
61 for (Eigen::Index idx = 0; idx < mDiscreteEigenvalues.rows(); ++idx)
62 mContinuousEigenvalues(idx) =
63 mapDiscreteToContinuous(mDiscreteEigenvalues(idx));
67StateSpaceModalAnalysis::buildDiscreteStateMatrixInAnalysisFrame()
const {
68 const Matrix &nativeAd = mExtractor.getDiscreteStateMatrix();
70 if (mAnalysisFrame == StateSpaceAnalysisFrame::Native)
73 if (mAnalysisFrame == StateSpaceAnalysisFrame::GlobalDQ0) {
74 if (!mExtractor.hasExtractionTime()) {
75 throw std::logic_error(
76 "GlobalDQ0 modal analysis requires a valid extraction timestamp.");
79 if (mGlobalOmega <= 0.0) {
80 throw std::logic_error(
81 "GlobalDQ0 modal analysis requires a positive frame angular speed.");
84 const Real time = mExtractor.getLastExtractionTime();
85 const Real timeStep = mExtractor.getTimeStep();
87 const Real thetaNow = mGlobalTheta0 + mGlobalOmega * time;
88 const Real thetaNext = thetaNow + mGlobalOmega * timeStep;
90 const Matrix transformNow = buildGlobalDq0Transformation(thetaNow);
91 const Matrix transformNext = buildGlobalDq0Transformation(thetaNext);
98 return transformNext * nativeAd * transformNow.transpose();
101 throw std::logic_error(
"Unsupported state-space analysis frame.");
104Matrix StateSpaceModalAnalysis::buildGlobalDq0Transformation(Real theta)
const {
105 const UInt stateCount = mExtractor.getStateCount();
107 Matrix transform = Matrix::Identity(stateCount, stateCount);
109 const Matrix park = parkTransformDQ0(theta);
111 for (
const auto &abcBlock : mExtractor.getMetadata().abcStateIndexTriples) {
112 for (UInt row = 0; row < 3; ++row) {
113 for (UInt col = 0; col < 3; ++col) {
114 transform(abcBlock[row], abcBlock[col]) = park(row, col);
123StateSpaceModalAnalysis::mapDiscreteToContinuous(
const CPS::Complex &z)
const {
124 const CPS::Complex one(1.0, 0.0);
125 const CPS::Complex denominator = z + one;
127 if (std::abs(denominator) <= DOUBLE_EPSILON)
128 return CPS::Complex(std::numeric_limits<Real>::infinity(), 0.0);
130 return (2.0 / mExtractor.getTimeStep()) * (z - one) / denominator;
void update()
Update modal quantities from the current extracted state matrix.