DPsim
DP_Ph1_ResIndSeries.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_ResIndSeries.h>
10 
11 using namespace CPS;
12 
13 DP::Ph1::ResIndSeries::ResIndSeries(String uid, String name,
14  Logger::Level logLevel)
15  : MNASimPowerComp<Complex>(uid, name, true, true, logLevel),
16  mInductance(mAttributes->create<Real>("L")),
18  mResistance(mAttributes->create<Real>("R")) {
19  mEquivCurrent = {0, 0};
20  **mIntfVoltage = MatrixComp::Zero(1, 1);
21  **mIntfCurrent = MatrixComp::Zero(1, 1);
22  setTerminalNumber(2);
23 }
24 
27  auto copy = ResIndSeries::make(name, mLogLevel);
28  copy->setParameters(**mResistance, **mInductance);
29  return copy;
30 }
31 
32 void DP::Ph1::ResIndSeries::setParameters(Real resistance, Real inductance) {
33  **mResistance = resistance;
34  **mInductance = inductance;
35 }
36 
37 void DP::Ph1::ResIndSeries::initialize(Matrix frequencies) {
39 
40  mEquivCurrent = MatrixComp::Zero(mNumFreqs, 1);
41  mEquivCond = MatrixComp::Zero(mNumFreqs, 1);
42  mPrevCurrFac = MatrixComp::Zero(mNumFreqs, 1);
43 }
44 
46 
47  Real omega = 2. * PI * frequency;
48  Complex impedance = {0, omega * **mInductance};
49  (**mIntfVoltage)(0, 0) = initialSingleVoltage(1) - initialSingleVoltage(0);
50  (**mIntfCurrent)(0, 0) = (**mIntfVoltage)(0, 0) / impedance;
51 
52  SPDLOG_LOGGER_INFO(mSLog,
53  "\n--- Initialization from powerflow ---"
54  "\nVoltage across: {:s}"
55  "\nCurrent: {:s}"
56  "\nTerminal 0 voltage: {:s}"
57  "\nTerminal 1 voltage: {:s}"
58  "\n--- Initialization from powerflow finished ---",
59  Logger::phasorToString((**mIntfVoltage)(0, 0)),
60  Logger::phasorToString((**mIntfCurrent)(0, 0)),
61  Logger::phasorToString(initialSingleVoltage(0)),
62  Logger::phasorToString(initialSingleVoltage(1)));
63 }
64 
65 // #### MNA functions ####
66 
67 void DP::Ph1::ResIndSeries::initVars(Real timeStep) {
68  for (Int freq = 0; freq < mNumFreqs; freq++) {
69  Real a = timeStep / (2. * **mInductance);
70  Real b = timeStep * 2. * PI * mFrequencies(freq, 0) / 2.;
71 
72  Real equivCondReal = a / (1. + b * b);
73  Real equivCondImag = -a * b / (1. + b * b);
74  mEquivCond(freq, 0) = {equivCondReal, equivCondImag};
75  Real preCurrFracReal = (1. - b * b) / (1. + b * b);
76  Real preCurrFracImag = (-2. * b) / (1. + b * b);
77  mPrevCurrFac(freq, 0) = {preCurrFracReal, preCurrFracImag};
78 
79  // TODO: check if this is correct or if it should be only computed before the step
80  mEquivCurrent(freq, 0) = mEquivCond(freq, 0) * (**mIntfVoltage)(0, freq) +
81  mPrevCurrFac(freq, 0) * (**mIntfCurrent)(0, freq);
82  (**mIntfCurrent)(0, freq) =
83  mEquivCond(freq, 0) * (**mIntfVoltage)(0, freq) +
84  mEquivCurrent(freq, 0);
85  }
86 }
87 
89  Real omega, Real timeStep, Attribute<Matrix>::Ptr leftVector) {
90  updateMatrixNodeIndices();
91  initVars(timeStep);
92 
93  SPDLOG_LOGGER_INFO(mSLog,
94  "\n--- MNA initialization ---"
95  "\nInitial voltage {:s}"
96  "\nInitial current {:s}"
97  "\nEquiv. current {:s}"
98  "\n--- MNA initialization finished ---",
99  Logger::phasorToString((**mIntfVoltage)(0, 0)),
100  Logger::phasorToString((**mIntfCurrent)(0, 0)),
101  Logger::complexToString(mEquivCurrent(0, 0)));
102 }
103 
104 void DP::Ph1::ResIndSeries::mnaCompInitializeHarm(
105  Real omega, Real timeStep,
106  std::vector<Attribute<Matrix>::Ptr> leftVectors) {
107  updateMatrixNodeIndices();
108 
109  initVars(timeStep);
110 
111  mMnaTasks.push_back(std::make_shared<MnaPreStepHarm>(*this));
112  mMnaTasks.push_back(std::make_shared<MnaPostStepHarm>(*this, leftVectors));
113  **mRightVector = Matrix::Zero(leftVectors[0]->get().rows(), mNumFreqs);
114 }
115 
117  SparseMatrixRow &systemMatrix) {
118  for (Int freq = 0; freq < mNumFreqs; freq++) {
119  if (terminalNotGrounded(0))
120  Math::addToMatrixElement(systemMatrix, matrixNodeIndex(0),
121  matrixNodeIndex(0), mEquivCond(freq, 0),
122  mNumFreqs, freq);
123  if (terminalNotGrounded(1))
124  Math::addToMatrixElement(systemMatrix, matrixNodeIndex(1),
125  matrixNodeIndex(1), mEquivCond(freq, 0),
126  mNumFreqs, freq);
127  if (terminalNotGrounded(0) && terminalNotGrounded(1)) {
128  Math::addToMatrixElement(systemMatrix, matrixNodeIndex(0),
129  matrixNodeIndex(1), -mEquivCond(freq, 0),
130  mNumFreqs, freq);
131  Math::addToMatrixElement(systemMatrix, matrixNodeIndex(1),
132  matrixNodeIndex(0), -mEquivCond(freq, 0),
133  mNumFreqs, freq);
134  }
135 
136  SPDLOG_LOGGER_INFO(mSLog, "-- Stamp frequency {:d} ---", freq);
137  if (terminalNotGrounded(0))
138  SPDLOG_LOGGER_INFO(mSLog, "Add {:s} to system at ({:d},{:d})",
139  Logger::complexToString(mEquivCond(freq, 0)),
140  matrixNodeIndex(0), matrixNodeIndex(0));
141  if (terminalNotGrounded(1))
142  SPDLOG_LOGGER_INFO(mSLog, "Add {:s} to system at ({:d},{:d})",
143  Logger::complexToString(mEquivCond(freq, 0)),
144  matrixNodeIndex(1), matrixNodeIndex(1));
145  if (terminalNotGrounded(0) && terminalNotGrounded(1)) {
146  SPDLOG_LOGGER_INFO(mSLog, "Add {:s} to system at ({:d},{:d})",
147  Logger::complexToString(-mEquivCond(freq, 0)),
148  matrixNodeIndex(0), matrixNodeIndex(1));
149  SPDLOG_LOGGER_INFO(mSLog, "Add {:s} to system at ({:d},{:d})",
150  Logger::complexToString(-mEquivCond(freq, 0)),
151  matrixNodeIndex(1), matrixNodeIndex(0));
152  }
153  }
154 }
155 
156 void DP::Ph1::ResIndSeries::mnaCompApplySystemMatrixStampHarm(
157  SparseMatrixRow &systemMatrix, Int freqIdx) {
158  if (terminalNotGrounded(0))
159  Math::addToMatrixElement(systemMatrix, matrixNodeIndex(0),
160  matrixNodeIndex(0), mEquivCond(freqIdx, 0));
161  if (terminalNotGrounded(1))
162  Math::addToMatrixElement(systemMatrix, matrixNodeIndex(1),
163  matrixNodeIndex(1), mEquivCond(freqIdx, 0));
164  if (terminalNotGrounded(0) && terminalNotGrounded(1)) {
165  Math::addToMatrixElement(systemMatrix, matrixNodeIndex(0),
166  matrixNodeIndex(1), -mEquivCond(freqIdx, 0));
167  Math::addToMatrixElement(systemMatrix, matrixNodeIndex(1),
168  matrixNodeIndex(0), -mEquivCond(freqIdx, 0));
169  }
170 
171  SPDLOG_LOGGER_INFO(mSLog, "-- Stamp frequency {:d} ---", freqIdx);
172  if (terminalNotGrounded(0))
173  SPDLOG_LOGGER_INFO(mSLog, "Add {:f}+j{:f} to system at ({:d},{:d})",
174  mEquivCond(freqIdx, 0).real(),
175  mEquivCond(freqIdx, 0).imag(), matrixNodeIndex(0),
176  matrixNodeIndex(0));
177  if (terminalNotGrounded(1))
178  SPDLOG_LOGGER_INFO(mSLog, "Add {:f}+j{:f} to system at ({:d},{:d})",
179  mEquivCond(freqIdx, 0).real(),
180  mEquivCond(freqIdx, 0).imag(), matrixNodeIndex(1),
181  matrixNodeIndex(1));
182  if (terminalNotGrounded(0) && terminalNotGrounded(1)) {
183  SPDLOG_LOGGER_INFO(mSLog, "Add {:f}+j{:f} to system at ({:d},{:d})",
184  -mEquivCond(freqIdx, 0).real(),
185  -mEquivCond(freqIdx, 0).imag(), matrixNodeIndex(0),
186  matrixNodeIndex(1));
187  SPDLOG_LOGGER_INFO(mSLog, "Add {:f}+j{:f} to system at ({:d},{:d})",
188  -mEquivCond(freqIdx, 0).real(),
189  -mEquivCond(freqIdx, 0).imag(), matrixNodeIndex(1),
190  matrixNodeIndex(0));
191  }
192 }
193 
195  Matrix &rightVector) {
196  for (Int freq = 0; freq < mNumFreqs; freq++) {
197  // Calculate equivalent current source for next time step
198  mEquivCurrent(freq, 0) = mEquivCond(freq, 0) * (**mIntfVoltage)(0, freq) +
199  mPrevCurrFac(freq, 0) * (**mIntfCurrent)(0, freq);
200 
201  if (terminalNotGrounded(0))
202  Math::setVectorElement(rightVector, matrixNodeIndex(0),
203  mEquivCurrent(freq, 0), mNumFreqs, freq);
204  if (terminalNotGrounded(1))
205  Math::setVectorElement(rightVector, matrixNodeIndex(1),
206  -mEquivCurrent(freq, 0), mNumFreqs, freq);
207 
208  SPDLOG_LOGGER_DEBUG(mSLog, "MNA EquivCurrent {:s}",
209  Logger::complexToString(mEquivCurrent(freq, 0)));
210  if (terminalNotGrounded(0))
211  SPDLOG_LOGGER_DEBUG(mSLog, "Add {:s} to source vector at {:d}",
212  Logger::complexToString(mEquivCurrent(freq, 0)),
213  matrixNodeIndex(0));
214  if (terminalNotGrounded(1))
215  SPDLOG_LOGGER_DEBUG(mSLog, "Add {:s} to source vector at {:d}",
216  Logger::complexToString(-mEquivCurrent(freq, 0)),
217  matrixNodeIndex(1));
218  }
219 }
220 
221 void DP::Ph1::ResIndSeries::mnaCompApplyRightSideVectorStampHarm(
222  Matrix &rightVector) {
223  for (Int freq = 0; freq < mNumFreqs; freq++) {
224  // Calculate equivalent current source for next time step
225  mEquivCurrent(freq, 0) = mEquivCond(freq, 0) * (**mIntfVoltage)(0, freq) +
226  mPrevCurrFac(freq, 0) * (**mIntfCurrent)(0, freq);
227 
228  if (terminalNotGrounded(0))
229  Math::setVectorElement(rightVector, matrixNodeIndex(0),
230  mEquivCurrent(freq, 0), 1, 0, freq);
231  if (terminalNotGrounded(1))
232  Math::setVectorElement(rightVector, matrixNodeIndex(1),
233  -mEquivCurrent(freq, 0), 1, 0, freq);
234  }
235 }
236 
237 void mnaCompAddPreStepDependencies(AttributeBase::List &prevStepDependencies,
238  AttributeBase::List &attributeDependencies,
239  AttributeBase::List &modifiedAttributes) {
240  // actually depends on L, but then we'd have to modify the system matrix anyway
241  modifiedAttributes.push_back(mRightVector);
242  prevStepDependencies.push_back(mIntfVoltage);
243  prevStepDependencies.push_back(mIntfCurrent);
244 }
245 
246 void DP::Ph1::ResIndSeries::mnaCompPreStep(Real time, Int timeStepCount) {
247  mResIndSeries.mnaCompApplyRightSideVectorStamp(**mRightVector);
248 }
249 
250 void DP::Ph1::ResIndSeries::MnaPreStepHarm::execute(Real time,
251  Int timeStepCount) {
252  mResIndSeries.mnaCompApplyRightSideVectorStampHarm(
253  **mResIndSeries.mRightVector);
254 }
255 
256 void mnaCompAddPostStepDependencies(AttributeBase::List &prevStepDependencies,
257  AttributeBase::List &attributeDependencies,
258  AttributeBase::List &modifiedAttributes,
259  Attribute<Matrix>::Ptr &leftVector) {
260  attributeDependencies.push_back(leftVector);
261  modifiedAttributes.push_back(mIntfVoltage);
262  modifiedAttributes.push_back(mIntfCurrent);
263 }
264 
265 void DP::Ph1::ResIndSeries::mnaCompPostStep(
266  Real time, Int timeStepCount, Attribute<Matrix>::Ptr &leftVector) {
267  mnaCompUpdateVoltage(**leftVector);
268  mnaCompUpdateCurrent(**leftVector);
269 }
270 
271 void DP::Ph1::ResIndSeries::MnaPostStepHarm::execute(Real time,
272  Int timeStepCount) {
273  for (Int freq = 0; freq < mResIndSeries.mNumFreqs; freq++)
274  mResIndSeries.mnaCompUpdateVoltageHarm(**mLeftVectors[freq], freq);
275  mResIndSeries.mnaCompUpdateCurrentHarm();
276 }
277 
278 void DP::Ph1::ResIndSeries::mnaCompUpdateVoltage(const Matrix &leftVector) {
279  // v1 - v0
280  for (Int freq = 0; freq < mNumFreqs; freq++) {
281  (**mIntfVoltage)(0, freq) = 0;
282  if (terminalNotGrounded(1))
283  (**mIntfVoltage)(0, freq) = Math::complexFromVectorElement(
284  leftVector, matrixNodeIndex(1), mNumFreqs, freq);
285  if (terminalNotGrounded(0))
286  (**mIntfVoltage)(0, freq) =
287  (**mIntfVoltage)(0, freq) -
288  Math::complexFromVectorElement(leftVector, matrixNodeIndex(0),
289  mNumFreqs, freq);
290 
291  SPDLOG_LOGGER_DEBUG(mSLog, "Voltage {:s}",
292  Logger::phasorToString((**mIntfVoltage)(0, freq)));
293  }
294 }
295 
296 void DP::Ph1::ResIndSeries::mnaCompUpdateVoltageHarm(const Matrix &leftVector,
297  Int freqIdx) {
298  // v1 - v0
299  (**mIntfVoltage)(0, freqIdx) = 0;
300  if (terminalNotGrounded(1))
301  (**mIntfVoltage)(0, freqIdx) =
302  Math::complexFromVectorElement(leftVector, matrixNodeIndex(1));
303  if (terminalNotGrounded(0))
304  (**mIntfVoltage)(0, freqIdx) =
305  (**mIntfVoltage)(0, freqIdx) -
306  Math::complexFromVectorElement(leftVector, matrixNodeIndex(0));
307 
308  SPDLOG_LOGGER_DEBUG(mSLog, "Voltage {:s}",
309  Logger::phasorToString((**mIntfVoltage)(0, freqIdx)));
310 }
311 
312 void DP::Ph1::ResIndSeries::mnaCompUpdateCurrent(const Matrix &leftVector) {
313  for (Int freq = 0; freq < mNumFreqs; freq++) {
314  (**mIntfCurrent)(0, freq) =
315  mEquivCond(freq, 0) * (**mIntfVoltage)(0, freq) +
316  mEquivCurrent(freq, 0);
317  SPDLOG_LOGGER_DEBUG(mSLog, "Current {:s}",
318  Logger::phasorToString((**mIntfCurrent)(0, freq)));
319  }
320 }
321 
322 void DP::Ph1::ResIndSeries::mnaCompUpdateCurrentHarm() {
323  for (Int freq = 0; freq < mNumFreqs; freq++) {
324  (**mIntfCurrent)(0, freq) =
325  mEquivCond(freq, 0) * (**mIntfVoltage)(0, freq) +
326  mEquivCurrent(freq, 0);
327  SPDLOG_LOGGER_DEBUG(mSLog, "Current {:s}",
328  Logger::phasorToString((**mIntfCurrent)(0, freq)));
329  }
330 }
331 
332 // #### Tear Methods ####
333 void DP::Ph1::ResIndSeries::mnaTearInitialize(Real omega, Real timeStep) {
334  initVars(timeStep);
335 }
336 
337 void DP::Ph1::ResIndSeries::mnaTearApplyMatrixStamp(
338  SparseMatrixRow &tearMatrix) {
339  Math::addToMatrixElement(tearMatrix, mTearIdx, mTearIdx,
340  1. / mEquivCond(0, 0));
341 }
342 
343 void DP::Ph1::ResIndSeries::mnaTearApplyVoltageStamp(Matrix &voltageVector) {
344  mEquivCurrent(0, 0) = mEquivCond(0, 0) * (**mIntfVoltage)(0, 0) +
345  mPrevCurrFac(0, 0) * (**mIntfCurrent)(0, 0);
346  Math::addToVectorElement(voltageVector, mTearIdx,
347  mEquivCurrent(0, 0) / mEquivCond(0, 0));
348 }
349 
350 void DP::Ph1::ResIndSeries::mnaTearPostStep(Complex voltage, Complex current) {
351  (**mIntfVoltage)(0, 0) = voltage;
352  (**mIntfCurrent)(0, 0) = mEquivCond(0, 0) * voltage + mEquivCurrent(0, 0);
353 }
void initialize(Matrix frequencies)
Initializes state variables considering the number of frequencies.
void mnaCompInitialize(Real omega, Real timeStep, Attribute< Matrix >::Ptr leftVector)
Initializes MNA specific variables.
void mnaCompApplyRightSideVectorStamp(Matrix &rightVector)
Stamps right side (source) vector.
void mnaCompApplySystemMatrixStamp(SparseMatrixRow &systemMatrix)
Stamps system matrix.
void initializeFromNodesAndTerminals(Real frequency)
Initializes states from power flow data.
MatrixComp mEquivCurrent
DC equivalent current source for harmonics [A].
void mnaCompUpdateVoltage(const Matrix &leftVector)
Update interface voltage from MNA system results.
void setParameters(Real resistance, Real inductance)
Sets model specific parameters.
ResIndSeries(String uid, String name, Logger::Level logLevel=Logger::Level::off)
Defines UID, name and log level.
SimPowerComp< Complex >::Ptr clone(String name)
Return new instance with the same parameters.
void mnaCompUpdateCurrent()
Update interface current from MNA system results.
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