DPsim
Loading...
Searching...
No Matches
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
12using namespace CPS;
13using namespace CPS::DP::Ph1;
14using namespace CPS::Signal;
15
16DecouplingLine::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
48DecouplingLine::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
63void 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
88void 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
118Complex 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
125void 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
156void DecouplingLine::PreStep::execute(Real time, Int timeStepCount) {
157 mLine.step(time, timeStepCount);
158}
159
160void 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
172void DecouplingLine::PostStep::execute(Real time, Int timeStepCount) {
173 mLine.postStep();
174}
175
176Task::List DecouplingLine::getTasks() {
177 return Task::List(
178 {std::make_shared<PreStep>(*this), std::make_shared<PostStep>(*this)});
179}
180
181IdentifiedObject::List DecouplingLine::getLineComponents() {
182 return IdentifiedObject::List({mRes1, mRes2, mSrc1, mSrc2});
183}
Logger::Log mSLog
Component logger.