DPsim
Loading...
Searching...
No Matches
DecouplingLineEMT_Ph3.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/MathUtils.h"
10#include <Eigen/src/Core/Array.h>
11#include <dpsim-models/Signal/DecouplingLineEMT_Ph3.h>
12
13using namespace CPS;
14using namespace CPS::EMT::Ph3;
15using namespace CPS::Signal;
16
17DecouplingLineEMT_Ph3::DecouplingLineEMT_Ph3(String name,
18 Logger::Level logLevel)
19 : SimSignalComp(name, name, logLevel),
20 mStates(mAttributes->create<Matrix>("states")),
21 mSrcCur1Ref(mAttributes->create<Matrix>("i_src1", Matrix::Zero(3, 1))),
22 mSrcCur2Ref(mAttributes->create<Matrix>("i_src2", Matrix::Zero(3, 1))) {
23
24 mRes1 = EMT::Ph3::Resistor::make(name + "_r1", logLevel);
25 mRes2 = EMT::Ph3::Resistor::make(name + "_r2", logLevel);
26 mSrc1 = ControlledCurrentSource::make(name + "_i1", logLevel);
27 mSrc2 = ControlledCurrentSource::make(name + "_i2", logLevel);
28}
29
30void DecouplingLineEMT_Ph3::setParameters(SimNode<Real>::Ptr node1,
31 SimNode<Real>::Ptr node2,
32 Matrix resistance, Matrix inductance,
33 Matrix capacitance) {
34
35 mResistance = resistance;
36 mInductance = inductance;
37 mCapacitance = capacitance;
38 mNode1 = node1;
39 mNode2 = node2;
40
41 mSurgeImpedance = (inductance * capacitance.inverse()).array().sqrt();
42 mDelay = (inductance.array() * capacitance.array()).sqrt().maxCoeff();
43 SPDLOG_LOGGER_INFO(mSLog, "surge impedance: {}", mSurgeImpedance);
44 SPDLOG_LOGGER_INFO(mSLog, "delay: {}", mDelay);
45
46 mRes1->setParameters(Math::singlePhaseParameterToThreePhase(
47 mSurgeImpedance(0, 0) + mResistance(0, 0) / 4));
48 mRes1->connect({SimNode<Real>::GND, node1});
49 mRes2->setParameters(Math::singlePhaseParameterToThreePhase(
50 mSurgeImpedance(0, 0) + mResistance(0, 0) / 4));
51 /*Notice that, as opposed to the DecouplingLine Ph1, this resistor is connected from GND to node2,
52 since currently the Ph3 resistor has the opposite sign convention for voltage and current, compared to the Ph1 countepart.*/
53 mRes2->connect({SimNode<Real>::GND, node2});
54 mSrc1->setParameters(Matrix::Zero(3, 1));
55 mSrc1->connect({node1, SimNode<Real>::GND});
56 mSrc2->setParameters(Matrix::Zero(3, 1));
57 mSrc2->connect({node2, SimNode<Real>::GND});
58
59 mSrcCur1 = mSrc1->mCurrentRef;
60 mSrcCur2 = mSrc2->mCurrentRef;
61}
62
63void DecouplingLineEMT_Ph3::initialize(Real omega, Real timeStep) {
64 if (mDelay < timeStep)
65 throw SystemError("Timestep too large for decoupling");
66
67 mBufSize = static_cast<UInt>(ceil(mDelay / timeStep));
68 mAlpha = 1 - (mBufSize - mDelay / timeStep);
69 SPDLOG_LOGGER_INFO(mSLog, "bufsize {} alpha {}", mBufSize, mAlpha);
70
71 // Initialization based on static PI-line model
72 MatrixComp volt1 = -mNode1->initialVoltage();
73 MatrixComp volt2 = -mNode2->initialVoltage();
74
75 MatrixComp initAdmittance =
76 (mResistance + Complex(0, omega) * mInductance).inverse() +
77 Complex(0, omega) * mCapacitance / 2;
78 MatrixComp cur1 =
79 initAdmittance * volt1 -
80 (mResistance + Complex(0, omega) * mInductance).inverse() * volt2;
81 MatrixComp cur2 =
82 initAdmittance * volt2 -
83 (mResistance + Complex(0, omega) * mInductance).inverse() * volt1;
84
85 SPDLOG_LOGGER_INFO(mSLog, "initial voltages: v_k {} v_m {}", volt1, volt2);
86 SPDLOG_LOGGER_INFO(mSLog, "initial currents: i_km {} i_mk {}", cur1, cur2);
87
88 // Resize ring buffers and initialize
89 mVolt1 = volt1.real().transpose().replicate(mBufSize, 1);
90 mVolt2 = volt2.real().transpose().replicate(mBufSize, 1);
91 mCur1 = cur1.real().transpose().replicate(mBufSize, 1);
92 mCur2 = cur2.real().transpose().replicate(mBufSize, 1);
93}
94
95Matrix DecouplingLineEMT_Ph3::interpolate(Matrix &data) {
96 // linear interpolation of the nearest values
97 Matrix c1 = data.row(mBufIdx);
98 Matrix c2 = mBufIdx == mBufSize - 1 ? data.row(0) : data.row(mBufIdx + 1);
99 return (mAlpha * c1 + (1 - mAlpha) * c2).transpose();
100}
101
102void DecouplingLineEMT_Ph3::step(Real time, Int timeStepCount) {
103 Matrix volt1 = interpolate(mVolt1);
104 Matrix volt2 = interpolate(mVolt2);
105 Matrix cur1 = interpolate(mCur1);
106 Matrix cur2 = interpolate(mCur2);
107 Matrix denom = (mSurgeImpedance + (mResistance / 4)) *
108 (mSurgeImpedance + (mResistance / 4));
109
110 if (timeStepCount == 0) {
111 // initialization
112 **mSrcCur1Ref =
113 cur1 - (mSurgeImpedance + mResistance / 4).inverse() * volt1;
114 **mSrcCur2Ref =
115 cur2 - (mSurgeImpedance + mResistance / 4).inverse() * volt2;
116 } else {
117 // Update currents
118 **mSrcCur1Ref = -mSurgeImpedance * denom.inverse() *
119 (volt2 + (mSurgeImpedance - mResistance / 4) * cur2) -
120 mResistance / 4 * denom.inverse() *
121 (volt1 + (mSurgeImpedance - mResistance / 4) * cur1);
122 **mSrcCur2Ref = -mSurgeImpedance * denom.inverse() *
123 (volt1 + (mSurgeImpedance - mResistance / 4) * cur1) -
124 mResistance / 4 * denom.inverse() *
125 (volt2 + (mSurgeImpedance - mResistance / 4) * cur2);
126 }
127 mSrcCur1->set(**mSrcCur1Ref);
128 mSrcCur2->set(**mSrcCur2Ref);
129}
130
131void DecouplingLineEMT_Ph3::PreStep::execute(Real time, Int timeStepCount) {
132 mLine.step(time, timeStepCount);
133}
134
135void DecouplingLineEMT_Ph3::postStep() {
136 // Update ringbuffers with new values
137 mVolt1.row(mBufIdx) = -mRes1->intfVoltage().transpose();
138 mVolt2.row(mBufIdx) = -mRes2->intfVoltage().transpose();
139 mCur1.row(mBufIdx) =
140 -mRes1->intfCurrent().transpose() + mSrcCur1->get().real().transpose();
141 mCur2.row(mBufIdx) =
142 -mRes2->intfCurrent().transpose() + mSrcCur2->get().real().transpose();
143
144 mBufIdx++;
145 if (mBufIdx == mBufSize)
146 mBufIdx = 0;
147}
148
149void DecouplingLineEMT_Ph3::PostStep::execute(Real time, Int timeStepCount) {
150 mLine.postStep();
151}
152
153Task::List DecouplingLineEMT_Ph3::getTasks() {
154 return Task::List(
155 {std::make_shared<PreStep>(*this), std::make_shared<PostStep>(*this)});
156}
157
158IdentifiedObject::List DecouplingLineEMT_Ph3::getLineComponents() {
159 return IdentifiedObject::List({mRes1, mRes2, mSrc1, mSrc2});
160}
static Matrix singlePhaseParameterToThreePhase(Real parameter)
To convert single phase parameters to symmetrical three phase ones.
Logger::Log mSLog
Component logger.