DPsim
DP_Ph1_Inverter.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 <cmath>
10 #include <dpsim-models/DP/DP_Ph1_Inverter.h>
11 #include <dpsim-models/MathUtils.h>
12 
13 using namespace CPS;
14 using namespace std;
15 
16 DP::Ph1::Inverter::Inverter(String uid, String name, Logger::Level logLevel)
17  : MNASimPowerComp<Complex>(uid, name, true, true, logLevel) {
18  setTerminalNumber(1);
19  setVirtualNodeNumber(1);
20  **mIntfVoltage = MatrixComp::Zero(1, 1);
21  **mIntfCurrent = MatrixComp::Zero(1, 1);
22 }
23 
24 void DP::Ph1::Inverter::setParameters(const std::vector<Int> &carrierHarms,
25  const std::vector<Int> &modulHarms,
26  Real inputVoltage, Real ratio,
27  Real phase) {
28  mCarHarms = carrierHarms;
29  mModHarms = modulHarms;
30  mVin = inputVoltage;
31  mModIdx = ratio;
32  mPhaseMod = phase;
33 
34  mParametersSet = true;
35 }
36 
38 
39 void DP::Ph1::Inverter::generateFrequencies() {
40  for (Int m = 2; m <= mMaxCarrierHarm; m = m + 2) {
41  mCarHarms.push_back(m);
42  SPDLOG_LOGGER_INFO(mSLog, "Add carrier harmonic {0}", m);
43  }
44  for (Int n = -mMaxModulHarm; n <= mMaxModulHarm; n = n + 2) {
45  mModHarms.push_back(n);
46  SPDLOG_LOGGER_INFO(mSLog, "Add modulation harmonic {0}", n);
47  }
48 }
49 
50 void DP::Ph1::Inverter::initialize(Matrix frequencies) {
52 
53  SPDLOG_LOGGER_INFO(mSLog, "\n--- Initialization ---");
54 
55  // Check that both lists have the same length
56  mCarHarNum = static_cast<UInt>(mCarHarms.size());
57  mModHarNum = static_cast<UInt>(mModHarms.size());
58  if (mCarHarNum != mModHarNum) {
59  throw std::invalid_argument(
60  "Number of carrier and modulation harmonics must be equal.");
61  }
62  mHarNum = mCarHarNum;
63 
64  mPhasorMags = Matrix::Zero(mHarNum, 1);
65  mPhasorPhases = Matrix::Zero(mHarNum, 1);
66  mPhasorFreqs = Matrix::Zero(mHarNum, 1);
67 
68  for (UInt h = 0; h < mHarNum; h++) {
69  mPhasorFreqs(h, 0) = mCarHarms[h] * mFreqCar + mModHarms[h] * mFreqMod;
70  mPhasorPhases(h, 0) = mCarHarms[h] * mPhaseCar + mModHarms[h] * mPhaseMod;
71  }
72 
73  // Precompute factorials
74  for (Int f = 0; f <= mMaxBesselSumIdx; f++) {
75  mFactorials.push_back(factorial(f));
76  }
77 
78  for (UInt h = 0; h < mHarNum; h++) {
79  for (Int f = 0; f <= mMaxBesselSumIdx; f++)
80  mMultInvFactorials[f + mModHarms[h]] = multInvFactorial(f + mModHarms[h]);
81  }
82 
83  SPDLOG_LOGGER_INFO(mSLog,
84  "\nFrequencies: \n{}"
85  "\nPhases: \n{}"
86  "\n--- End of initialization ---",
87  mPhasorFreqs, mPhasorPhases);
88 }
89 
90 void DP::Ph1::Inverter::calculatePhasors() {
91  // Compute fundamental content of grid frequency
92  mVfund = mModIdx * mVin;
93  (**mIntfVoltage)(0, 0) = Complex(0, mVfund * -1);
94 
95  // Compute sideband harmonics for even multiplies of carrier frequency m
96  // and odd reference signal multiplies n
97  for (UInt h = 0; h < mHarNum; h++) {
98  Real Jn = besselFirstKind_n_opt(mModHarms[h], mMaxBesselSumIdx,
99  mCarHarms[h] * mModIdx * PI / 2.);
100  //mPhasorMags(h, 0) = (4.*mVin/PI) * (Jn/mCarHarms[h]) * cos(mCarHarms[h] * PI/2.);
101  //(**mIntfVoltage)(0, h+1) = mPhasorMags(h, 0) * -1i;
102  (**mIntfVoltage)(0, h + 1) =
103  Complex(0, -1 * (4. * mVin / PI) * (Jn / mCarHarms[h]) *
104  cos(mCarHarms[h] * PI / 2.));
105  }
106 
107  SPDLOG_LOGGER_DEBUG(mSLog,
108  "\n--- Phasor calculation ---"
109  "\n{}"
110  "\n{}"
111  "\n--- Phasor calculation end ---",
112  mPhasorMags, **mIntfVoltage);
113 }
114 
115 // #### MNA functions ####
116 
117 void DP::Ph1::Inverter::mnaCompInitialize(Real omega, Real timeStep,
118  Attribute<Matrix>::Ptr leftVector) {
119  updateMatrixNodeIndices();
120  calculatePhasors();
121 }
122 
123 void DP::Ph1::Inverter::mnaCompInitializeHarm(
124  Real omega, Real timeStep,
125  std::vector<Attribute<Matrix>::Ptr> leftVectors) {
126  updateMatrixNodeIndices();
127 
128  mMnaTasks.push_back(std::make_shared<MnaPreStepHarm>(*this));
129  mMnaTasks.push_back(std::make_shared<MnaPostStepHarm>(*this, leftVectors));
130  **mRightVector = Matrix::Zero(leftVectors[0]->get().rows(), mNumFreqs);
131 
132  calculatePhasors();
133 }
134 
136  SparseMatrixRow &systemMatrix) {
137  SPDLOG_LOGGER_INFO(mSLog, "--- Stamping into system matrix ---");
138 
139  for (UInt freq = 0; freq < mNumFreqs; freq++) {
140  SPDLOG_LOGGER_INFO(mSLog, "Stamp frequency {:d}", freq);
141  if (terminalNotGrounded(0)) {
142  Math::setMatrixElement(systemMatrix, mVirtualNodes[0]->matrixNodeIndex(),
143  matrixNodeIndex(0), Complex(1, 0), mNumFreqs,
144  freq);
145  Math::setMatrixElement(systemMatrix, matrixNodeIndex(0),
146  mVirtualNodes[0]->matrixNodeIndex(), Complex(1, 0),
147  mNumFreqs, freq);
148  }
149 
150  if (terminalNotGrounded(0)) {
151  SPDLOG_LOGGER_INFO(mSLog, "Add {:f} to system at ({:d},{:d})", 1.,
152  mVirtualNodes[0]->matrixNodeIndex(),
153  matrixNodeIndex(0));
154  SPDLOG_LOGGER_INFO(mSLog, "Add {:f} to system at ({:d},{:d})", 1.,
155  matrixNodeIndex(0),
156  mVirtualNodes[0]->matrixNodeIndex());
157  }
158  }
159  SPDLOG_LOGGER_INFO(mSLog, "--- Stamping into system matrix end ---");
160 }
161 
162 void DP::Ph1::Inverter::mnaCompApplySystemMatrixStampHarm(
163  SparseMatrixRow &systemMatrix, Int freqIdx) {
164  SPDLOG_LOGGER_INFO(mSLog, "Stamp frequency {:d}", freqIdx);
165  if (terminalNotGrounded(0)) {
166  Math::setMatrixElement(systemMatrix, mVirtualNodes[0]->matrixNodeIndex(),
167  matrixNodeIndex(0), Complex(1, 0));
168  Math::setMatrixElement(systemMatrix, matrixNodeIndex(0),
169  mVirtualNodes[0]->matrixNodeIndex(), Complex(1, 0));
170  }
171 
172  if (terminalNotGrounded(0)) {
173  SPDLOG_LOGGER_INFO(mSLog, "Add {:f} to system at ({:d},{:d})", 1.,
174  mVirtualNodes[0]->matrixNodeIndex(), matrixNodeIndex(0));
175  SPDLOG_LOGGER_INFO(mSLog, "Add {:f} to system at ({:d},{:d})", 1.,
176  matrixNodeIndex(0), mVirtualNodes[0]->matrixNodeIndex());
177  }
178 }
179 
181  SPDLOG_LOGGER_DEBUG(mSLog, "Stamp harmonics into source vector");
182  for (UInt freq = 0; freq < mNumFreqs; freq++) {
183  if (terminalNotGrounded(0)) {
184  Math::setVectorElement(rightVector, mVirtualNodes[0]->matrixNodeIndex(),
185  (**mIntfVoltage)(0, freq), mNumFreqs, freq);
186 
187  SPDLOG_LOGGER_DEBUG(mSLog,
188  "Add {:s} to source vector at {:d}, harmonic {:d}",
189  Logger::complexToString((**mIntfVoltage)(0, freq)),
190  mVirtualNodes[0]->matrixNodeIndex(), freq);
191  }
192  }
193 }
194 
195 void DP::Ph1::Inverter::mnaCompApplyRightSideVectorStampHarm(
196  Matrix &rightVector) {
197  SPDLOG_LOGGER_DEBUG(mSLog, "Stamp harmonics into source vector");
198  for (UInt freq = 0; freq < mNumFreqs; freq++) {
199  if (terminalNotGrounded(0)) {
200  Math::setVectorElement(rightVector, mVirtualNodes[0]->matrixNodeIndex(),
201  (**mIntfVoltage)(0, freq), 1, 0, freq);
202  }
203  }
204 }
205 
206 void DP::Ph1::Inverter::mnaCompApplyRightSideVectorStampHarm(
207  Matrix &rightVector, Int freq) {
208  Math::setVectorElement(rightVector, mVirtualNodes[0]->matrixNodeIndex(),
209  (**mIntfVoltage)(0, freq));
210 }
211 
213  AttributeBase::List &prevStepDependencies,
214  AttributeBase::List &attributeDependencies,
215  AttributeBase::List &modifiedAttributes) {
216  modifiedAttributes.push_back(mRightVector);
217  modifiedAttributes.push_back(mIntfVoltage);
218 }
219 
220 void DP::Ph1::Inverter::mnaCompPreStep(Real time, Int timeStepCount) {
221  calculatePhasors();
222  mnaCompApplyRightSideVectorStamp(**mRightVector);
223 }
224 
225 void DP::Ph1::Inverter::MnaPreStepHarm::execute(Real time, Int timeStepCount) {
226  mInverter.calculatePhasors();
227  mInverter.mnaCompApplyRightSideVectorStampHarm(**mInverter.mRightVector);
228 }
229 
231  AttributeBase::List &prevStepDependencies,
232  AttributeBase::List &attributeDependencies,
233  AttributeBase::List &modifiedAttributes,
234  Attribute<Matrix>::Ptr &leftVector) {
235  attributeDependencies.push_back(leftVector);
236  modifiedAttributes.push_back(mIntfCurrent);
237 }
238 
239 void DP::Ph1::Inverter::mnaCompPostStep(Real time, Int timeStepCount,
240  Attribute<Matrix>::Ptr &leftVector) {}
241 
242 void DP::Ph1::Inverter::MnaPostStepHarm::execute(Real time, Int timeStepCount) {
243 
244 }
245 
246 // #### Math functions ####
247 
249 Real DP::Ph1::Inverter::besselFirstKind_n(Int n, Int k_max, Real x) const {
250  Real Jn = 0;
251  for (Int k = 0; k <= k_max; ++k) {
252  Real Jn_k = pow(-1, k) / (double)factorial(k) * multInvFactorial(k + n) *
253  pow(x / 2., 2. * k + n);
254  Jn = Jn + Jn_k;
255  }
256  return Jn;
257 }
258 
260 Real DP::Ph1::Inverter::besselFirstKind_n_opt(Int n, Int k_max, Real x) {
261  Real Jn = 0;
262  for (Int k = 0; k <= k_max; ++k) {
263  Real Jn_k = pow(-1, k) / mFactorials[k] * mMultInvFactorials[k + n] *
264  pow(x / 2., 2. * k + n);
265  Jn = Jn + Jn_k;
266  }
267  return Jn;
268 }
269 
270 long long DP::Ph1::Inverter::factorial(Int n) const {
271  return (n == 1 || n == 0) ? 1 : factorial(n - 1) * n;
272 }
273 
274 Real DP::Ph1::Inverter::multInvFactorial(Int n) const {
275  if (n < 0)
276  return 0;
277  else
278  return 1. / (double)factorial(n);
279 }
280 
281 Real DP::Ph1::Inverter::multInvIntGamma(Real n) const {
282  if (n <= 0)
283  return 0;
284  else
285  return 1. / std::tgamma(n);
286 }
void mnaCompAddPreStepDependencies(AttributeBase::List &prevStepDependencies, AttributeBase::List &attributeDependencies, AttributeBase::List &modifiedAttributes) override
Add MNA pre step dependencies.
void mnaCompApplySystemMatrixStamp(SparseMatrixRow &systemMatrix) override
Stamps system matrix.
void initialize(Matrix frequencies) override
Initialize components with correct network frequencies.
Real besselFirstKind_n(Int n, Int k_max, Real x) const
Bessel function.
Real besselFirstKind_n_opt(Int n, Int k_max, Real x)
Bessel function using look up tables for factorials.
Inverter(String name, String uid, Logger::Level logLevel=Logger::Level::off)
Defines UID, name and logging level.
void mnaCompApplyRightSideVectorStamp(Matrix &rightVector) override
Stamps right side (source) vector.
void initializeFromNodesAndTerminals(Real frequency) override
Initializes Component variables according to power flow data stored in Nodes.
void mnaCompInitialize(Real omega, Real timeStep, Attribute< Matrix >::Ptr leftVector) override
Initializes internal variables of the component.
void mnaCompAddPostStepDependencies(AttributeBase::List &prevStepDependencies, AttributeBase::List &attributeDependencies, AttributeBase::List &modifiedAttributes, Attribute< Matrix >::Ptr &leftVector) override
Add MNA post step dependencies.
Base class for all MNA components that are transmitting power.
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