DPsim
Loading...
Searching...
No Matches
EMT_SSNComp.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 <dpsim-models/EMT/EMT_SSNComp.h>
5
6using namespace CPS;
7
8EMT::SSNComp::SSNComp(String uid, String name, Int inputSize, Int outputSize,
9 Logger::Level logLevel)
10 : MNASimPowerComp<Real>(uid, name, true, true, logLevel), mTimeStep(0.0),
11 mW(Matrix::Zero(outputSize, inputSize)),
12 mYHist(Matrix::Zero(outputSize, 1)), mInputSize(inputSize),
13 mOutputSize(outputSize), mX(mAttributes->create<Matrix>("x")) {
14 mParametersSet = false;
15}
16
18 return static_cast<UInt>(mA.rows());
19}
20
21std::vector<std::array<UInt, 3>>
23 // Default: no abc-frame state metadata. Derived components should override
24 // this only for states known to form physical abc triples.
25 return {};
26}
27
28const Matrix &EMT::SSNComp::getDiscreteA() const { return mdA; }
29
30const Matrix &EMT::SSNComp::getDiscreteB() const { return mdB; }
31
32const Matrix &EMT::SSNComp::getC() const { return mC; }
33
34void EMT::SSNComp::setParameters(const Matrix &A, const Matrix &B,
35 const Matrix &C, const Matrix &D) {
36 mParametersSet = false;
37
38 if (A.rows() != A.cols())
39 throw std::invalid_argument("A must be square.");
40
41 if (B.rows() != A.rows() || B.cols() != mInputSize)
42 throw std::invalid_argument("B has invalid dimensions.");
43
44 if (C.rows() != mOutputSize || C.cols() != A.rows())
45 throw std::invalid_argument("C has invalid dimensions.");
46
47 if (D.rows() != mOutputSize || D.cols() != mInputSize)
48 throw std::invalid_argument("D has invalid dimensions.");
49
50 mA = A;
51 mB = B;
52 mC = C;
53 mD = D;
54
55 **mX = Matrix::Zero(mA.rows(), 1);
56
57 mdA = Matrix::Zero(mA.rows(), mA.cols());
58 mdB = Matrix::Zero(mB.rows(), mB.cols());
59
60 mW = Matrix::Zero(mOutputSize, mInputSize);
61 mYHist = Matrix::Zero(mOutputSize, 1);
62
63 mParametersSet = true;
64}
65
66Matrix EMT::SSNComp::calculateHistoryVector() const {
67 return mC * (mdA * (**mX) + mdB * (**inputAttribute()));
68}
69
70MatrixComp
71EMT::SSNComp::calculateSteadyStateStateFromInput(const MatrixComp &u,
72 Real frequency) const {
73 const Real omega = 2.0 * PI * frequency;
74 MatrixComp h =
75 Complex(0.0, omega) * MatrixComp::Identity(mA.rows(), mA.cols()) -
76 mA.cast<Complex>();
77
78 return h.inverse() * mB.cast<Complex>() * u;
79}
80
81MatrixComp
82EMT::SSNComp::calculateSteadyStateOutputFromInput(const MatrixComp &x,
83 const MatrixComp &u) const {
84 return mC.cast<Complex>() * x + mD.cast<Complex>() * u;
85}
86
87void EMT::SSNComp::updateState(const Matrix &uOld, const Matrix &uNew) {
88 **mX = mdA * (**mX) + mdB * (uNew + uOld);
89}
90
91void EMT::SSNComp::updateLogAttributes(const Matrix &) const {
92 // the default implementation does nothing.
93}
94
95void EMT::SSNComp::recomputeDiscreteModel() {
96 Math::calculateStateSpaceTrapezoidalMatrices(mA, mB, mTimeStep, mdA, mdB);
97 mW = mC * mdB + mD;
98}
99
101 // For linear components, the default implementation does nothing.
102}
103
104void EMT::SSNComp::mnaCompInitialize(Real, Real timeStep,
105 Attribute<Matrix>::Ptr) {
106 if (!mParametersSet)
107 throw std::logic_error(
108 "setParameters() must be called before initialization.");
109
110 mTimeStep = timeStep;
111 updateMatrixNodeIndices();
112
113 recomputeDiscreteModel();
114 mYHist = calculateHistoryVector();
115}
116
117void EMT::SSNComp::mnaCompAddPreStepDependencies(
118 AttributeBase::List &prevStepDependencies,
119 AttributeBase::List &attributeDependencies,
120 AttributeBase::List &modifiedAttributes) {
121 modifiedAttributes.push_back(mRightVector);
122 prevStepDependencies.push_back(mX);
123 prevStepDependencies.push_back(inputAttribute());
124}
125
126void EMT::SSNComp::mnaCompPreStep(Real time, Int timeStepCount) {
127 updateStateSpaceModel();
128 mYHist = calculateHistoryVector();
129 mnaCompApplyRightSideVectorStamp(**mRightVector);
130}
131
132void EMT::SSNComp::mnaCompAddPostStepDependencies(
133 AttributeBase::List &prevStepDependencies,
134 AttributeBase::List &attributeDependencies,
135 AttributeBase::List &modifiedAttributes,
136 Attribute<Matrix>::Ptr &leftVector) {
137 attributeDependencies.push_back(leftVector);
138 modifiedAttributes.push_back(inputAttribute());
139 modifiedAttributes.push_back(outputAttribute());
140 modifiedAttributes.push_back(mX);
141}
virtual void updateLogAttributes(const Matrix &u) const
Update derived attributes used for logging/inspection.
const Matrix & getDiscreteA() const
Get discrete state transition matrix used by the trapezoidal SSN model.
const Matrix & getDiscreteB() const
Get discrete input matrix used by the trapezoidal SSN model.
virtual std::vector< std::array< UInt, 3 > > getLocalAbcStateIndexTriples() const
const Matrix & getC() const
Get continuous-time output matrix of the SSN model.
virtual void updateStateSpaceModel()
Hook for variable/time-varying SSN components.
UInt getStateCount() const
Get number of internal state variables of the SSN model.
Base class for all MNA components that are transmitting power.
static void calculateStateSpaceTrapezoidalMatrices(const Matrix &A, const Matrix &B, const Matrix &C, const Real &dt, Matrix &Ad, Matrix &Bd, Matrix &Cd)
Calculate the discretized state space matrices Ad, Bd, Cd using trapezoidal rule.