DPsim
Loading...
Searching...
No Matches
EMT_Ph3_RXLoad.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/EMT/EMT_Ph3_RXLoad.h>
10
11using namespace CPS;
12
13EMT::Ph3::RXLoad::RXLoad(String uid, String name, Logger::Level logLevel)
14 : CompositePowerComp<Real>(uid, name, true, true, Logger::Level::trace),
15 mActivePower(mAttributes->create<Matrix>("P")),
16 mReactivePower(mAttributes->create<Matrix>("Q")),
17 mNomVoltage(mAttributes->create<Real>("V_nom")),
18 mReactanceInSeries(false) {
19 mPhaseType = PhaseType::ABC;
20 setTerminalNumber(1);
21
22 SPDLOG_LOGGER_INFO(mSLog, "Create {} {}", this->type(), name);
23 **mIntfVoltage = Matrix::Zero(3, 1);
24 **mIntfCurrent = Matrix::Zero(3, 1);
25 mSLog->flush();
26}
27
28EMT::Ph3::RXLoad::RXLoad(String name, Logger::Level logLevel)
29 : RXLoad(name, name, logLevel) {}
30
31EMT::Ph3::RXLoad::RXLoad(String name, Matrix activePower, Matrix reactivePower,
32 Real volt, Logger::Level logLevel)
33 : RXLoad(name, logLevel) {
34 **mActivePower = activePower;
35 **mReactivePower = reactivePower;
36 mPower = MatrixComp::Zero(3, 3);
37 mPower << Complex((**mActivePower)(0, 0), (**mReactivePower)(0, 0)),
38 Complex((**mActivePower)(0, 1), (**mReactivePower)(0, 1)),
39 Complex((**mActivePower)(0, 2), (**mReactivePower)(0, 2)),
40 Complex((**mActivePower)(1, 0), (**mReactivePower)(1, 0)),
41 Complex((**mActivePower)(1, 1), (**mReactivePower)(1, 1)),
42 Complex((**mActivePower)(1, 2), (**mReactivePower)(1, 2)),
43 Complex((**mActivePower)(2, 0), (**mReactivePower)(2, 0)),
44 Complex((**mActivePower)(2, 1), (**mReactivePower)(2, 1)),
45 Complex((**mActivePower)(2, 2), (**mReactivePower)(2, 2));
46
47 **mNomVoltage = volt;
48 initPowerFromTerminal = false;
49}
50
51SimPowerComp<Real>::Ptr EMT::Ph3::RXLoad::clone(String name) {
52 auto copy = RXLoad::make(name, mLogLevel);
53 if (!initPowerFromTerminal)
54 copy->setParameters(**mActivePower, **mReactivePower, **mNomVoltage,
56 return copy;
57}
58
59void EMT::Ph3::RXLoad::setParameters(Matrix activePower, Matrix reactivePower,
60 Real volt, bool reactanceInSeries) {
61 **mActivePower = activePower;
62 **mReactivePower = reactivePower;
63 mReactanceInSeries = reactanceInSeries;
64
65 if (mReactanceInSeries) {
66 setVirtualNodeNumber(1);
67 }
68 // complex power
69 mPower = MatrixComp::Zero(3, 3);
70 mPower(0, 0) = {(**mActivePower)(0, 0), (**mReactivePower)(0, 0)};
71 mPower(1, 1) = {(**mActivePower)(1, 1), (**mReactivePower)(1, 1)};
72 mPower(2, 2) = {(**mActivePower)(2, 2), (**mReactivePower)(2, 2)};
73
74 **mNomVoltage = volt;
75
76 SPDLOG_LOGGER_INFO(mSLog,
77 "\nActive Power [W]: {}"
78 "\nReactive Power [VAr]: {}",
79 Logger::matrixToString(**mActivePower),
80 Logger::matrixToString(**mReactivePower));
81 SPDLOG_LOGGER_INFO(mSLog, "Nominal Voltage={} [V]", **mNomVoltage);
82
83 initPowerFromTerminal = false;
84}
85
88 return;
89 mSubCompCreated = true;
90
91 // Intentionally empty: which of R/L/C exist depends on the load power sign, known only in
92 // initializeParentFromNodesAndTerminals(), where the sub-components are created. Safe: any
93 // series-mode virtual node is already declared in setParameters().
94}
95
97 Real omega = 2. * PI * frequency;
98
99 if (initPowerFromTerminal) {
100 **mActivePower = Matrix::Zero(3, 3);
101 (**mActivePower)(0, 0) = mTerminals[0]->singleActivePower() / 3.;
102 (**mActivePower)(1, 1) = mTerminals[0]->singleActivePower() / 3.;
103 (**mActivePower)(2, 2) = mTerminals[0]->singleActivePower() / 3.;
104
105 **mReactivePower = Matrix::Zero(3, 3);
106 (**mReactivePower)(0, 0) = mTerminals[0]->singleReactivePower() / 3.;
107 (**mReactivePower)(1, 1) = mTerminals[0]->singleReactivePower() / 3.;
108 (**mReactivePower)(2, 2) = mTerminals[0]->singleReactivePower() / 3.;
109
110 // complex power
111 mPower = MatrixComp::Zero(3, 3);
112 mPower(0, 0) = {(**mActivePower)(0, 0), (**mReactivePower)(0, 0)};
113 mPower(1, 1) = {(**mActivePower)(1, 1), (**mReactivePower)(1, 1)};
114 mPower(2, 2) = {(**mActivePower)(2, 2), (**mReactivePower)(2, 2)};
115
116 **mNomVoltage = std::abs(mTerminals[0]->initialSingleVoltage());
117
118 SPDLOG_LOGGER_INFO(mSLog,
119 "\nActive Power [W]: {}"
120 "\nReactive Power [VAr]: {}",
121 Logger::matrixToString(**mActivePower),
122 Logger::matrixToString(**mReactivePower));
123 SPDLOG_LOGGER_INFO(mSLog, "Nominal Voltage={} [V]", **mNomVoltage);
124 }
125
126 // Compute derived impedance values and create+parametrize sub-components
127 // now that power and voltage are guaranteed to be known.
128 if ((**mActivePower)(0, 0) != 0) {
130 std::pow(**mNomVoltage / sqrt(3), 2) * (**mActivePower).inverse();
131 }
132 if ((**mReactivePower)(0, 0) != 0)
133 mReactance =
134 std::pow(**mNomVoltage / sqrt(3), 2) * (**mReactivePower).inverse();
135 else
136 mReactance = Matrix::Zero(3, 3);
137
138 if ((**mActivePower)(0, 0) != 0) {
140 std::make_shared<EMT::Ph3::Resistor>(**mName + "_res", mLogLevel);
141 mSubResistor->setParameters(mResistance);
142 if (mReactanceInSeries) {
143 mSubResistor->connect({mTerminals[0]->node(), mVirtualNodes[0]});
144 } else {
145 mSubResistor->connect({SimNode::GND, mTerminals[0]->node()});
146 }
147 addMNASubComponent(mSubResistor, MNA_SUBCOMP_TASK_ORDER::TASK_BEFORE_PARENT,
148 MNA_SUBCOMP_TASK_ORDER::TASK_BEFORE_PARENT, true);
149 }
150
151 if (mReactance(0, 0) > 0) {
152 mInductance = mReactance / omega;
153
155 std::make_shared<EMT::Ph3::Inductor>(**mName + "_ind", mLogLevel);
156 mSubInductor->setParameters(mInductance);
157 if (mReactanceInSeries) {
158 mSubInductor->connect({SimNode::GND, mVirtualNodes[0]});
159 } else {
160 mSubInductor->connect({SimNode::GND, mTerminals[0]->node()});
161 }
162 addMNASubComponent(mSubInductor, MNA_SUBCOMP_TASK_ORDER::TASK_BEFORE_PARENT,
163 MNA_SUBCOMP_TASK_ORDER::TASK_BEFORE_PARENT, true);
164 } else if (mReactance(0, 0) < 0) {
165 mCapacitance = -1. / omega * mReactance.inverse();
166
168 std::make_shared<EMT::Ph3::Capacitor>(**mName + "_cap", mLogLevel);
169 mSubCapacitor->setParameters(mCapacitance);
170 if (mReactanceInSeries) {
171 mSubCapacitor->connect({SimNode::GND, mVirtualNodes[0]});
172 } else {
173 mSubCapacitor->connect({SimNode::GND, mTerminals[0]->node()});
174 }
176 MNA_SUBCOMP_TASK_ORDER::TASK_BEFORE_PARENT,
177 MNA_SUBCOMP_TASK_ORDER::TASK_BEFORE_PARENT, true);
178 }
179
180 MatrixComp vInitABC = MatrixComp::Zero(3, 1);
181 vInitABC(0, 0) = RMS3PH_TO_PEAK1PH * mTerminals[0]->initialSingleVoltage();
182 vInitABC(1, 0) = vInitABC(0, 0) * SHIFT_TO_PHASE_B;
183 vInitABC(2, 0) = vInitABC(0, 0) * SHIFT_TO_PHASE_C;
184 **mIntfVoltage = vInitABC.real();
185
186 if ((**mActivePower)(0, 0) != 0) {
188 std::pow(**mNomVoltage / sqrt(3), 2) * (**mActivePower).inverse();
189 }
190
191 if ((**mReactivePower)(0, 0) != 0)
192 mReactance =
193 std::pow(**mNomVoltage / sqrt(3), 2) * (**mReactivePower).inverse();
194 else
195 mReactance = Matrix::Zero(1, 1);
196
197 if (mReactanceInSeries) {
198 MatrixComp impedance = MatrixComp::Zero(3, 3);
199 impedance << Complex(mResistance(0, 0), mReactance(0, 0)),
200 Complex(mResistance(0, 1), mReactance(0, 1)),
201 Complex(mResistance(0, 2), mReactance(0, 2)),
202 Complex(mResistance(1, 0), mReactance(1, 0)),
203 Complex(mResistance(1, 1), mReactance(1, 1)),
204 Complex(mResistance(1, 2), mReactance(1, 2)),
205 Complex(mResistance(2, 0), mReactance(2, 0)),
206 Complex(mResistance(2, 1), mReactance(2, 1)),
207 Complex(mResistance(2, 2), mReactance(2, 2));
208 **mIntfCurrent = (impedance.inverse() * vInitABC).real();
209
210 // Initialization of virtual node
211 // Initial voltage of phase B,C is set after A
212 MatrixComp vInitTerm0 = MatrixComp::Zero(3, 1);
213 vInitTerm0(0, 0) = initialSingleVoltage(0);
214 vInitTerm0(1, 0) = vInitTerm0(0, 0) * SHIFT_TO_PHASE_B;
215 vInitTerm0(2, 0) = vInitTerm0(0, 0) * SHIFT_TO_PHASE_C;
216 mVirtualNodes[0]->setInitialVoltage(vInitTerm0 +
218 }
219
220 if ((**mActivePower)(0, 0) != 0) {
221 mSubResistor->initializeFromNodesAndTerminals(frequency);
222 if (!mReactanceInSeries) {
223 **mIntfCurrent += mSubResistor->intfCurrent();
224 }
225 }
226
227 if (mReactance(0, 0) > 0) {
228 mSubInductor->initializeFromNodesAndTerminals(frequency);
229 if (!mReactanceInSeries) {
230 **mIntfCurrent += mSubInductor->intfCurrent();
231 }
232 } else if (mReactance(0, 0) < 0) {
233 mSubCapacitor->initializeFromNodesAndTerminals(frequency);
234 if (!mReactanceInSeries) {
235 **mIntfCurrent += mSubCapacitor->intfCurrent();
236 }
237 }
238
239 SPDLOG_LOGGER_INFO(
240 mSLog,
241 "\n--- Initialization from powerflow ---"
242 "\nVoltage across: {:s}"
243 "\nCurrent: {:s}"
244 "\nTerminal 0 voltage: {:s}"
245 "\nActive Power: {:s}"
246 "\nReactive Power: {:s}"
247 "\nResistance: {:s}"
248 "\nReactance: {:s}"
249 "\n--- Initialization from powerflow finished ---",
250 Logger::matrixToString(**mIntfVoltage),
251 Logger::matrixToString(**mIntfCurrent),
252 Logger::phasorToString(RMS3PH_TO_PEAK1PH * initialSingleVoltage(0)),
253 Logger::matrixToString(**mActivePower),
254 Logger::matrixToString(**mReactivePower),
255 Logger::matrixToString(mResistance), Logger::matrixToString(mReactance));
256 mSLog->flush();
257}
258
259void EMT::Ph3::RXLoad::mnaParentAddPreStepDependencies(
260 AttributeBase::List &prevStepDependencies,
261 AttributeBase::List &attributeDependencies,
262 AttributeBase::List &modifiedAttributes) {
263 modifiedAttributes.push_back(mRightVector);
264};
265
266void EMT::Ph3::RXLoad::mnaParentAddPostStepDependencies(
267 AttributeBase::List &prevStepDependencies,
268 AttributeBase::List &attributeDependencies,
269 AttributeBase::List &modifiedAttributes,
270 Attribute<Matrix>::Ptr &leftVector) {
271 attributeDependencies.push_back(leftVector);
272 modifiedAttributes.push_back(mIntfCurrent);
273 modifiedAttributes.push_back(mIntfVoltage);
274};
275
279
280void EMT::Ph3::RXLoad::mnaParentPostStep(Real time, Int timeStepCount,
281 Attribute<Matrix>::Ptr &leftVector) {
282 mnaCompUpdateVoltage(**leftVector);
283 mnaCompUpdateCurrent(**leftVector);
284}
285
286void EMT::Ph3::RXLoad::mnaCompUpdateVoltage(const Matrix &leftVector) {
287 **mIntfVoltage = Matrix::Zero(3, 1);
288 (**mIntfVoltage)(0, 0) =
289 Math::realFromVectorElement(leftVector, matrixNodeIndex(0, 0));
290 (**mIntfVoltage)(1, 0) =
291 Math::realFromVectorElement(leftVector, matrixNodeIndex(0, 1));
292 (**mIntfVoltage)(2, 0) =
293 Math::realFromVectorElement(leftVector, matrixNodeIndex(0, 2));
294}
295
296void EMT::Ph3::RXLoad::mnaCompUpdateCurrent(const Matrix &leftVector) {
297 if (mReactanceInSeries) {
298 **mIntfCurrent = mSubInductor->intfCurrent();
299 } else {
300 **mIntfCurrent = Matrix::Zero(3, 1);
301 for (auto &subc : mSubComponents) {
302 **mIntfCurrent += subc->intfCurrent();
303 }
304 }
305}
void addMNASubComponent(typename SimPowerComp< Real >::Ptr subc, MNA_SUBCOMP_TASK_ORDER preStepOrder, MNA_SUBCOMP_TASK_ORDER postStepOrder, Bool contributeToRightVector)
void mnaCompApplyRightSideVectorStamp(Matrix &rightVector) override
CompositePowerComp(String uid, String name, Bool hasPreStep, Bool hasPostStep, Logger::Level logLevel)
const Attribute< Matrix >::Ptr mActivePower
Active power [Watt].
Bool mReactanceInSeries
If set to true, the reactance is in series with the resistor. Otherwise it is parallel to the resisto...
RXLoad(String uid, String name, Logger::Level logLevel=Logger::Level::off)
Defines UID, name and logging level.
std::shared_ptr< EMT::Ph3::Resistor > mSubResistor
Internal resistance.
std::shared_ptr< EMT::Ph3::Inductor > mSubInductor
Internal inductor.
void createSubComponents() override
Constructs and registers MNA subcomponents; idempotent.
std::shared_ptr< EMT::Ph3::Capacitor > mSubCapacitor
Internal capacitor.
Matrix mResistance
Resistance [Ohm].
void initializeParentFromNodesAndTerminals(Real frequency) override
Derives values from power flow data and pushes them to subcomponents.
Matrix mReactance
Reactance [Ohm].
const Attribute< Real >::Ptr mNomVoltage
Nominal voltage [V].
SimPowerComp< Real >::Ptr clone(String name) override
Returns a modified copy of the component with the given suffix added to the name and without.
void mnaParentPreStep(Real time, Int timeStepCount) override
MNA pre and post step operations.
Matrix mCapacitance
Capacitance [F].
const Attribute< Matrix >::Ptr mReactivePower
Reactive power [VAr].
Matrix mInductance
Inductance [H].
const Attribute< String >::Ptr mName
Human readable name.
String uid()
Returns unique id.
String type()
Get component type (cross-platform)
AttributeList::Ptr mAttributes
Attribute List.
Attribute< Matrix >::Ptr mRightVector
const Attribute< MatrixVar< Real > >::Ptr mIntfCurrent
SimTerminal< Real >::List mTerminals
const Attribute< MatrixVar< Real > >::Ptr mIntfVoltage
SimNode< Real >::List mVirtualNodes
Logger::Level mLogLevel
Component logger control for internal variables.
Logger::Log mSLog
Component logger.