DPsim
DP_Ph1_Inductor.cpp
1 /* Copyright 2017-2021 Institute for Automation of Complex Power Systems,
2  * EONERC, RWTH Aachen University
3  *
4  * This Source Code Form is subject to the terms of the Mozilla Public
5  * License, v. 2.0. If a copy of the MPL was not distributed with this
6  * file, You can obtain one at https://mozilla.org/MPL/2.0/.
7  *********************************************************************************/
8 
9 #include <dpsim-models/DP/DP_Ph1_Inductor.h>
10 
11 using namespace CPS;
12 
13 DP::Ph1::Inductor::Inductor(String uid, String name, Logger::Level logLevel)
14  : MNASimPowerComp<Complex>(uid, name, true, true, logLevel),
15  Base::Ph1::Inductor(mAttributes) {
16  mEquivCurrent = {0, 0};
17  **mIntfVoltage = MatrixComp::Zero(1, 1);
18  **mIntfCurrent = MatrixComp::Zero(1, 1);
19  setTerminalNumber(2);
20 }
21 
23  auto copy = Inductor::make(name, mLogLevel);
24  copy->setParameters(**mInductance);
25  return copy;
26 }
27 
28 void DP::Ph1::Inductor::initialize(Matrix frequencies) {
30 
31  mEquivCurrent = MatrixComp::Zero(mNumFreqs, 1);
32  mEquivCond = MatrixComp::Zero(mNumFreqs, 1);
33  mPrevCurrFac = MatrixComp::Zero(mNumFreqs, 1);
34 }
35 
37 
38  Real omega = 2. * PI * frequency;
39  Complex impedance = {0, omega * **mInductance};
40  (**mIntfVoltage)(0, 0) = initialSingleVoltage(1) - initialSingleVoltage(0);
41  (**mIntfCurrent)(0, 0) = (**mIntfVoltage)(0, 0) / impedance;
42 
43  SPDLOG_LOGGER_INFO(mSLog,
44  "\nInductance [H]: {:s}"
45  "\nImpedance [Ohm]: {:s}",
46  Logger::realToString(**mInductance),
47  Logger::complexToString(impedance));
48  SPDLOG_LOGGER_INFO(mSLog,
49  "\n--- Initialization from powerflow ---"
50  "\nVoltage across: {:s}"
51  "\nCurrent: {:s}"
52  "\nTerminal 0 voltage: {:s}"
53  "\nTerminal 1 voltage: {:s}"
54  "\n--- Initialization from powerflow finished ---",
55  Logger::phasorToString((**mIntfVoltage)(0, 0)),
56  Logger::phasorToString((**mIntfCurrent)(0, 0)),
57  Logger::phasorToString(initialSingleVoltage(0)),
58  Logger::phasorToString(initialSingleVoltage(1)));
59 }
60 
61 // #### MNA functions ####
62 
63 void DP::Ph1::Inductor::initVars(Real timeStep) {
64  for (UInt freq = 0; freq < mNumFreqs; freq++) {
65  Real a = timeStep / (2. * **mInductance);
66  Real b = timeStep * 2. * PI * mFrequencies(freq, 0) / 2.;
67 
68  Real equivCondReal = a / (1. + b * b);
69  Real equivCondImag = -a * b / (1. + b * b);
70  mEquivCond(freq, 0) = {equivCondReal, equivCondImag};
71  Real preCurrFracReal = (1. - b * b) / (1. + b * b);
72  Real preCurrFracImag = (-2. * b) / (1. + b * b);
73  mPrevCurrFac(freq, 0) = {preCurrFracReal, preCurrFracImag};
74 
75  // In steady-state, these variables should not change
76  mEquivCurrent(freq, 0) = mEquivCond(freq, 0) * (**mIntfVoltage)(0, freq) +
77  mPrevCurrFac(freq, 0) * (**mIntfCurrent)(0, freq);
78  (**mIntfCurrent)(0, freq) =
79  mEquivCond(freq, 0) * (**mIntfVoltage)(0, freq) +
80  mEquivCurrent(freq, 0);
81  }
82 }
83 
84 void DP::Ph1::Inductor::mnaCompInitialize(Real omega, Real timeStep,
85  Attribute<Matrix>::Ptr leftVector) {
86  updateMatrixNodeIndices();
87  initVars(timeStep);
88 
89  SPDLOG_LOGGER_INFO(mSLog,
90  "\n--- MNA initialization ---"
91  "\nInitial voltage {:s}"
92  "\nInitial current {:s}"
93  "\nEquiv. current {:s}"
94  "\n--- MNA initialization finished ---",
95  Logger::phasorToString((**mIntfVoltage)(0, 0)),
96  Logger::phasorToString((**mIntfCurrent)(0, 0)),
97  Logger::complexToString(mEquivCurrent(0, 0)));
98 }
99 
100 void DP::Ph1::Inductor::mnaCompInitializeHarm(
101  Real omega, Real timeStep,
102  std::vector<Attribute<Matrix>::Ptr> leftVectors) {
103  updateMatrixNodeIndices();
104 
105  initVars(timeStep);
106 
107  mMnaTasks.push_back(std::make_shared<MnaPreStepHarm>(*this));
108  mMnaTasks.push_back(std::make_shared<MnaPostStepHarm>(*this, leftVectors));
109  **mRightVector = Matrix::Zero(leftVectors[0]->get().rows(), mNumFreqs);
110 }
111 
113  SparseMatrixRow &systemMatrix) {
114  for (UInt freq = 0; freq < mNumFreqs; freq++) {
115  MNAStampUtils::stampAdmittance(
116  mEquivCond(freq, 0), systemMatrix, matrixNodeIndex(0),
117  matrixNodeIndex(1), terminalNotGrounded(0), terminalNotGrounded(1),
118  mSLog, mNumFreqs, freq);
119  }
120 }
121 
122 void DP::Ph1::Inductor::mnaCompApplySystemMatrixStampHarm(
123  SparseMatrixRow &systemMatrix, Int freqIdx) {
124  MNAStampUtils::stampAdmittance(mEquivCond(freqIdx, 0), systemMatrix,
125  matrixNodeIndex(0), matrixNodeIndex(1),
126  terminalNotGrounded(0), terminalNotGrounded(1),
127  mSLog);
128 }
129 
131  for (UInt freq = 0; freq < mNumFreqs; freq++) {
132  // Calculate equivalent current source for next time step
133  mEquivCurrent(freq, 0) = mEquivCond(freq, 0) * (**mIntfVoltage)(0, freq) +
134  mPrevCurrFac(freq, 0) * (**mIntfCurrent)(0, freq);
135 
136  if (terminalNotGrounded(0))
137  Math::setVectorElement(rightVector, matrixNodeIndex(0),
138  mEquivCurrent(freq, 0), mNumFreqs, freq);
139  if (terminalNotGrounded(1))
140  Math::setVectorElement(rightVector, matrixNodeIndex(1),
141  -mEquivCurrent(freq, 0), mNumFreqs, freq);
142 
143  SPDLOG_LOGGER_DEBUG(mSLog, "MNA EquivCurrent {:s}",
144  Logger::complexToString(mEquivCurrent(freq, 0)));
145  if (terminalNotGrounded(0))
146  SPDLOG_LOGGER_DEBUG(mSLog, "Add {:s} to source vector at {:d}",
147  Logger::complexToString(mEquivCurrent(freq, 0)),
148  matrixNodeIndex(0));
149  if (terminalNotGrounded(1))
150  SPDLOG_LOGGER_DEBUG(mSLog, "Add {:s} to source vector at {:d}",
151  Logger::complexToString(-mEquivCurrent(freq, 0)),
152  matrixNodeIndex(1));
153  }
154 }
155 
156 void DP::Ph1::Inductor::mnaCompApplyRightSideVectorStampHarm(
157  Matrix &rightVector) {
158  for (UInt freq = 0; freq < mNumFreqs; freq++) {
159  // Calculate equivalent current source for next time step
160  mEquivCurrent(freq, 0) = mEquivCond(freq, 0) * (**mIntfVoltage)(0, freq) +
161  mPrevCurrFac(freq, 0) * (**mIntfCurrent)(0, freq);
162 
163  if (terminalNotGrounded(0))
164  Math::setVectorElement(rightVector, matrixNodeIndex(0),
165  mEquivCurrent(freq, 0), 1, 0, freq);
166  if (terminalNotGrounded(1))
167  Math::setVectorElement(rightVector, matrixNodeIndex(1),
168  -mEquivCurrent(freq, 0), 1, 0, freq);
169  }
170 }
171 
173  AttributeBase::List &prevStepDependencies,
174  AttributeBase::List &attributeDependencies,
175  AttributeBase::List &modifiedAttributes) {
176  // actually depends on L, but then we'd have to modify the system matrix anyway
177  prevStepDependencies.push_back(mIntfVoltage);
178  prevStepDependencies.push_back(mIntfCurrent);
179  modifiedAttributes.push_back(mRightVector);
180 }
181 
182 void DP::Ph1::Inductor::mnaCompPreStep(Real time, Int timeStepCount) {
183  this->mnaApplyRightSideVectorStamp(**this->mRightVector);
184 }
185 
187  AttributeBase::List &prevStepDependencies,
188  AttributeBase::List &attributeDependencies,
189  AttributeBase::List &modifiedAttributes,
190  Attribute<Matrix>::Ptr &leftVector) {
191  attributeDependencies.push_back(leftVector);
192  modifiedAttributes.push_back(mIntfVoltage);
193  modifiedAttributes.push_back(mIntfCurrent);
194 }
195 
196 void DP::Ph1::Inductor::mnaCompPostStep(Real time, Int timeStepCount,
197  Attribute<Matrix>::Ptr &leftVector) {
198  this->mnaUpdateVoltage(**leftVector);
199  this->mnaUpdateCurrent(**leftVector);
200 }
201 
202 void DP::Ph1::Inductor::MnaPreStepHarm::execute(Real time, Int timeStepCount) {
203  mInductor.mnaCompApplyRightSideVectorStampHarm(**mInductor.mRightVector);
204 }
205 
206 void DP::Ph1::Inductor::MnaPostStepHarm::execute(Real time, Int timeStepCount) {
207  for (UInt freq = 0; freq < mInductor.mNumFreqs; freq++)
208  mInductor.mnaCompUpdateVoltageHarm(**mLeftVectors[freq], freq);
209  mInductor.mnaCompUpdateCurrentHarm();
210 }
211 
212 void DP::Ph1::Inductor::mnaCompUpdateVoltage(const Matrix &leftVector) {
213  // v1 - v0
214  for (UInt freq = 0; freq < mNumFreqs; freq++) {
215  (**mIntfVoltage)(0, freq) = 0;
216  if (terminalNotGrounded(1))
217  (**mIntfVoltage)(0, freq) = Math::complexFromVectorElement(
218  leftVector, matrixNodeIndex(1), mNumFreqs, freq);
219  if (terminalNotGrounded(0))
220  (**mIntfVoltage)(0, freq) =
221  (**mIntfVoltage)(0, freq) -
222  Math::complexFromVectorElement(leftVector, matrixNodeIndex(0),
223  mNumFreqs, freq);
224 
225  SPDLOG_LOGGER_DEBUG(mSLog, "Voltage {:s}",
226  Logger::phasorToString((**mIntfVoltage)(0, freq)));
227  }
228 }
229 
230 void DP::Ph1::Inductor::mnaCompUpdateVoltageHarm(const Matrix &leftVector,
231  Int freqIdx) {
232  // v1 - v0
233  (**mIntfVoltage)(0, freqIdx) = 0;
234  if (terminalNotGrounded(1))
235  (**mIntfVoltage)(0, freqIdx) =
236  Math::complexFromVectorElement(leftVector, matrixNodeIndex(1));
237  if (terminalNotGrounded(0))
238  (**mIntfVoltage)(0, freqIdx) =
239  (**mIntfVoltage)(0, freqIdx) -
240  Math::complexFromVectorElement(leftVector, matrixNodeIndex(0));
241 
242  SPDLOG_LOGGER_DEBUG(mSLog, "Voltage {:s}",
243  Logger::phasorToString((**mIntfVoltage)(0, freqIdx)));
244 }
245 
246 void DP::Ph1::Inductor::mnaCompUpdateCurrent(const Matrix &leftVector) {
247  for (UInt freq = 0; freq < mNumFreqs; freq++) {
248  (**mIntfCurrent)(0, freq) =
249  mEquivCond(freq, 0) * (**mIntfVoltage)(0, freq) +
250  mEquivCurrent(freq, 0);
251  SPDLOG_LOGGER_DEBUG(mSLog, "Current {:s}",
252  Logger::phasorToString((**mIntfCurrent)(0, freq)));
253  }
254 }
255 
256 void DP::Ph1::Inductor::mnaCompUpdateCurrentHarm() {
257  for (UInt freq = 0; freq < mNumFreqs; freq++) {
258  (**mIntfCurrent)(0, freq) =
259  mEquivCond(freq, 0) * (**mIntfVoltage)(0, freq) +
260  mEquivCurrent(freq, 0);
261  SPDLOG_LOGGER_DEBUG(mSLog, "Current {:s}",
262  Logger::phasorToString((**mIntfCurrent)(0, freq)));
263  }
264 }
265 
266 // #### Tear Methods ####
267 void DP::Ph1::Inductor::mnaTearInitialize(Real omega, Real timeStep) {
268  initVars(timeStep);
269 }
270 
271 void DP::Ph1::Inductor::mnaTearApplyMatrixStamp(SparseMatrixRow &tearMatrix) {
272  Math::addToMatrixElement(tearMatrix, mTearIdx, mTearIdx,
273  1. / mEquivCond(0, 0));
274 }
275 
276 void DP::Ph1::Inductor::mnaTearApplyVoltageStamp(Matrix &voltageVector) {
277  mEquivCurrent(0, 0) = mEquivCond(0, 0) * (**mIntfVoltage)(0, 0) +
278  mPrevCurrFac(0, 0) * (**mIntfCurrent)(0, 0);
279  Math::addToVectorElement(voltageVector, mTearIdx,
280  mEquivCurrent(0, 0) / mEquivCond(0, 0));
281 }
282 
283 void DP::Ph1::Inductor::mnaTearPostStep(Complex voltage, Complex current) {
284  (**mIntfVoltage)(0, 0) = voltage;
285  (**mIntfCurrent)(0, 0) = mEquivCond(0, 0) * voltage + mEquivCurrent(0, 0);
286 }
void mnaCompUpdateCurrent(const Matrix &leftVector) override
Update interface current from MNA system results.
void mnaCompAddPostStepDependencies(AttributeBase::List &prevStepDependencies, AttributeBase::List &attributeDependencies, AttributeBase::List &modifiedAttributes, Attribute< Matrix >::Ptr &leftVector) override
Add MNA post step dependencies.
SimPowerComp< Complex >::Ptr clone(String name) override
Return new instance with the same parameters.
MatrixComp mEquivCurrent
DC equivalent current source for harmonics [A].
void mnaCompAddPreStepDependencies(AttributeBase::List &prevStepDependencies, AttributeBase::List &attributeDependencies, AttributeBase::List &modifiedAttributes) override
Add MNA pre step dependencies.
void mnaCompInitialize(Real omega, Real timeStep, Attribute< Matrix >::Ptr leftVector) override
Initializes MNA specific variables.
void mnaCompUpdateVoltage(const Matrix &leftVector) override
Update interface voltage from MNA system results.
void mnaCompPostStep(Real time, Int timeStepCount, Attribute< Matrix >::Ptr &leftVector) override
MNA post step operations.
void mnaCompApplyRightSideVectorStamp(Matrix &rightVector) override
Stamps right side (source) vector.
void initializeFromNodesAndTerminals(Real frequency) override
Initializes states from power flow data.
void initialize(Matrix frequencies) override
Initializes state variables considering the number of frequencies.
void mnaCompPreStep(Real time, Int timeStepCount) override
MNA pre step operations.
void mnaCompApplySystemMatrixStamp(SparseMatrixRow &systemMatrix) override
Stamps system matrix.
Inductor(String uid, String name, Logger::Level logLevel=Logger::Level::off)
Defines UID, name and log level.
Base class for all MNA components that are transmitting power.
Base class for all components that are transmitting power.
Definition: SimPowerComp.h:17
virtual void initialize(Matrix frequencies)
Initialize components with correct network frequencies.
const Attribute< MatrixVar< Complex > >::Ptr mIntfCurrent
Current through component.
Definition: SimPowerComp.h:47
const Attribute< MatrixVar< Complex > >::Ptr mIntfVoltage
Voltage between terminals.
Definition: SimPowerComp.h:45