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