DPsim
DecouplingLine.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/Definitions.h"
10 #include <dpsim-models/Signal/DecouplingLine.h>
11 
12 using namespace CPS;
13 using namespace CPS::DP::Ph1;
14 using namespace CPS::Signal;
15 
16 DecouplingLine::DecouplingLine(String name, SimNode<Complex>::Ptr node1,
17  SimNode<Complex>::Ptr node2, Real resistance,
18  Real inductance, Real capacitance,
19  Logger::Level logLevel)
20  : SimSignalComp(name, name, logLevel), mResistance(resistance),
21  mInductance(inductance), mCapacitance(capacitance), mNode1(node1),
22  mNode2(node2), mStates(mAttributes->create<Matrix>("states")),
23  mSrcCur1Ref(mAttributes->create<Complex>("i_src1")),
24  mSrcCur2Ref(mAttributes->create<Complex>("i_src2")) {
25 
26  mSurgeImpedance = sqrt(inductance / capacitance);
27  mDelay = sqrt(inductance * capacitance);
28  SPDLOG_LOGGER_INFO(mSLog, "surge impedance: {}", mSurgeImpedance);
29  SPDLOG_LOGGER_INFO(mSLog, "delay: {}", mDelay);
30 
31  mRes1 = Resistor::make(name + "_r1", logLevel);
32  mRes1->setParameters(mSurgeImpedance + resistance / 4);
33  mRes1->connect({node1, SimNode<Complex>::GND});
34  mRes2 = Resistor::make(name + "_r2", logLevel);
35  mRes2->setParameters(mSurgeImpedance + resistance / 4);
36  mRes2->connect({node2, SimNode<Complex>::GND});
37 
38  mSrc1 = CurrentSource::make(name + "_i1", logLevel);
39  mSrc1->setParameters(0);
40  mSrc1->connect({node1, SimNode<Complex>::GND});
41  mSrcCur1 = mSrc1->mCurrentRef;
42  mSrc2 = CurrentSource::make(name + "_i2", logLevel);
43  mSrc2->setParameters(0);
44  mSrc2->connect({node2, SimNode<Complex>::GND});
45  mSrcCur2 = mSrc2->mCurrentRef;
46 }
47 
48 DecouplingLine::DecouplingLine(String name, Logger::Level logLevel)
49  : SimSignalComp(name, name, logLevel),
50  mStates(mAttributes->create<Matrix>("states")),
51  mSrcCur1Ref(mAttributes->create<Complex>("i_src1")),
52  mSrcCur2Ref(mAttributes->create<Complex>("i_src2")) {
53 
54  mRes1 = Resistor::make(name + "_r1", logLevel);
55  mRes2 = Resistor::make(name + "_r2", logLevel);
56  mSrc1 = CurrentSource::make(name + "_i1", logLevel);
57  mSrc2 = CurrentSource::make(name + "_i2", logLevel);
58 
59  mSrcCur1 = mSrc1->mCurrentRef;
60  mSrcCur2 = mSrc2->mCurrentRef;
61 }
62 
63 void DecouplingLine::setParameters(SimNode<Complex>::Ptr node1,
64  SimNode<Complex>::Ptr node2, Real resistance,
65  Real inductance, Real capacitance) {
66 
67  mResistance = resistance;
68  mInductance = inductance;
69  mCapacitance = capacitance;
70  mNode1 = node1;
71  mNode2 = node2;
72 
73  mSurgeImpedance = sqrt(inductance / capacitance);
74  mDelay = sqrt(inductance * capacitance);
75  SPDLOG_LOGGER_INFO(mSLog, "surge impedance: {}", mSurgeImpedance);
76  SPDLOG_LOGGER_INFO(mSLog, "delay: {}", mDelay);
77 
78  mRes1->setParameters(mSurgeImpedance + resistance / 4);
79  mRes1->connect({node1, SimNode<Complex>::GND});
80  mRes2->setParameters(mSurgeImpedance + resistance / 4);
81  mRes2->connect({node2, SimNode<Complex>::GND});
82  mSrc1->setParameters(0);
83  mSrc1->connect({node1, SimNode<Complex>::GND});
84  mSrc2->setParameters(0);
85  mSrc2->connect({node2, SimNode<Complex>::GND});
86 }
87 
88 void DecouplingLine::initialize(Real omega, Real timeStep) {
89  if (mDelay < timeStep)
90  throw SystemError("Timestep too large for decoupling");
91 
92  if (mNode1 == nullptr || mNode2 == nullptr)
93  throw SystemError("nodes not initialized!");
94 
95  mBufSize = static_cast<UInt>(ceil(mDelay / timeStep));
96  mAlpha = 1 - (mBufSize - mDelay / timeStep);
97  SPDLOG_LOGGER_INFO(mSLog, "bufsize {} alpha {}", mBufSize, mAlpha);
98 
99  Complex volt1 = mNode1->initialSingleVoltage();
100  Complex volt2 = mNode2->initialSingleVoltage();
101  // TODO different initialization for lumped resistance?
102  Complex initAdmittance = 1. / Complex(mResistance, omega * mInductance) +
103  Complex(0, omega * mCapacitance / 2);
104  Complex cur1 = volt1 * initAdmittance -
105  volt2 / Complex(mResistance, omega * mInductance);
106  Complex cur2 = volt2 * initAdmittance -
107  volt1 / Complex(mResistance, omega * mInductance);
108  SPDLOG_LOGGER_INFO(mSLog, "initial voltages: v_k {} v_m {}", volt1, volt2);
109  SPDLOG_LOGGER_INFO(mSLog, "initial currents: i_km {} i_mk {}", cur1, cur2);
110 
111  // Resize ring buffers and initialize
112  mVolt1.resize(mBufSize, volt1);
113  mVolt2.resize(mBufSize, volt2);
114  mCur1.resize(mBufSize, cur1);
115  mCur2.resize(mBufSize, cur2);
116 }
117 
118 Complex DecouplingLine::interpolate(std::vector<Complex> &data) {
119  // linear interpolation of the nearest values
120  Complex c1 = data[mBufIdx];
121  Complex c2 = mBufIdx == mBufSize - 1 ? data[0] : data[mBufIdx + 1];
122  return mAlpha * c1 + (1 - mAlpha) * c2;
123 }
124 
125 void DecouplingLine::step(Real time, Int timeStepCount) {
126  Complex volt1 = interpolate(mVolt1);
127  Complex volt2 = interpolate(mVolt2);
128  Complex cur1 = interpolate(mCur1);
129  Complex cur2 = interpolate(mCur2);
130 
131  if (timeStepCount == 0) {
132  // bit of a hack for proper initialization
133  **mSrcCur1Ref = cur1 - volt1 / (mSurgeImpedance + mResistance / 4);
134  **mSrcCur2Ref = cur2 - volt2 / (mSurgeImpedance + mResistance / 4);
135  } else {
136  // Update currents
137  Real denom = (mSurgeImpedance + mResistance / 4) *
138  (mSurgeImpedance + mResistance / 4);
139  **mSrcCur1Ref = -mSurgeImpedance / denom *
140  (volt2 + (mSurgeImpedance - mResistance / 4) * cur2) -
141  mResistance / 4 / denom *
142  (volt1 + (mSurgeImpedance - mResistance / 4) * cur1);
143  **mSrcCur2Ref = -mSurgeImpedance / denom *
144  (volt1 + (mSurgeImpedance - mResistance / 4) * cur1) -
145  mResistance / 4 / denom *
146  (volt2 + (mSurgeImpedance - mResistance / 4) * cur2);
147  **mSrcCur1Ref = **mSrcCur1Ref * Complex(cos(-2. * PI * 50 * mDelay),
148  sin(-2. * PI * 50 * mDelay));
149  **mSrcCur2Ref = **mSrcCur2Ref * Complex(cos(-2. * PI * 50 * mDelay),
150  sin(-2. * PI * 50 * mDelay));
151  }
152  mSrcCur1->set(**mSrcCur1Ref);
153  mSrcCur2->set(**mSrcCur2Ref);
154 }
155 
156 void DecouplingLine::PreStep::execute(Real time, Int timeStepCount) {
157  mLine.step(time, timeStepCount);
158 }
159 
160 void DecouplingLine::postStep() {
161  // Update ringbuffers with new values
162  mVolt1[mBufIdx] = -mRes1->intfVoltage()(0, 0);
163  mVolt2[mBufIdx] = -mRes2->intfVoltage()(0, 0);
164  mCur1[mBufIdx] = -mRes1->intfCurrent()(0, 0) + mSrcCur1->get();
165  mCur2[mBufIdx] = -mRes2->intfCurrent()(0, 0) + mSrcCur2->get();
166 
167  mBufIdx++;
168  if (mBufIdx == mBufSize)
169  mBufIdx = 0;
170 }
171 
172 void DecouplingLine::PostStep::execute(Real time, Int timeStepCount) {
173  mLine.postStep();
174 }
175 
176 Task::List DecouplingLine::getTasks() {
177  return Task::List(
178  {std::make_shared<PreStep>(*this), std::make_shared<PostStep>(*this)});
179 }
180 
181 IdentifiedObject::List DecouplingLine::getLineComponents() {
182  return IdentifiedObject::List({mRes1, mRes2, mSrc1, mSrc2});
183 }
virtual void set(T value)=0
virtual T & get()=0
Logger::Log mSLog
Component logger.