DPsim
Loading...
Searching...
No Matches
DP_Ph1_Transformer.cpp
Go to the documentation of this file.
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
10
11using namespace CPS;
12
14 Logger::Level logLevel,
15 Bool withResistiveLosses)
17 CompositePowerComp<Complex>(uid, name, true, true, logLevel) {
18 if (withResistiveLosses)
20 else
22
24
25 SPDLOG_LOGGER_INFO(mSLog, "Create {} {}", this->type(), name);
26 **mIntfVoltage = MatrixComp::Zero(1, 1);
27 **mIntfCurrent = MatrixComp::Zero(1, 1);
28}
29
32 auto copy = Transformer::make(name, mLogLevel);
34 std::abs(**mRatio), std::arg(**mRatio), **mResistance,
35 **mInductance);
36 return copy;
37}
38
40 Real nomVoltageSecondary,
41 Real ratioAbs, Real ratioPhase,
42 Real resistance, Real inductance) {
43
44 Base::Ph1::Transformer::setParameters(nomVoltagePrimary, nomVoltageSecondary,
45 ratioAbs, ratioPhase, resistance,
46 inductance);
47
48 SPDLOG_LOGGER_INFO(
49 mSLog, "Nominal Voltage Primary={} [V] Nominal Voltage Secondary={} [V]",
51 SPDLOG_LOGGER_INFO(
52 mSLog,
53 "Resistance={} [Ohm] Inductance={} [Ohm] (referred to primary side)",
55 SPDLOG_LOGGER_INFO(mSLog, "Tap Ratio={} [ ] Phase Shift={} [deg]",
56 std::abs(**mRatio), std::arg(**mRatio));
57 SPDLOG_LOGGER_INFO(mSLog, "Rated Power ={} [W]", **mRatedPower);
58
59 mParametersSet = true;
60}
61
63 Real nomVoltageSecondary,
64 Real ratedPower, Real ratioAbs,
65 Real ratioPhase, Real resistance,
66 Real inductance) {
67
68 **mRatedPower = ratedPower;
69 SPDLOG_LOGGER_INFO(mSLog, "Rated Power ={} [W]", **mRatedPower);
70
71 DP::Ph1::Transformer::setParameters(nomVoltagePrimary, nomVoltageSecondary,
72 ratioAbs, ratioPhase, resistance,
73 inductance);
74}
75
76void DP::Ph1::Transformer::resolveWindingRoles() {
77 switch (mReferenceWinding) {
79 mReferenceTerminal = 0;
80 break;
82 mReferenceTerminal = 1;
83 break;
85 SPDLOG_LOGGER_ERROR(mSLog,
86 "Transformer {}: three-winding transformers are "
87 "not implemented",
88 this->name());
91 mReferenceTerminal =
92 (mNominalVoltagePrimary >= mNominalVoltageSecondary) ? 0 : 1;
93 break;
94 }
95
96 mRatioFromReference = (mReferenceTerminal == 0) ? **mRatio : 1. / **mRatio;
97 mOrientationSign = (mReferenceTerminal == 0) ? 1. : -1.;
98
99 if (mReferenceWinding == WindingReference::Auto &&
100 std::abs(mNominalVoltagePrimary - mNominalVoltageSecondary) <=
101 DOUBLE_EPSILON * mNominalVoltagePrimary)
102 SPDLOG_LOGGER_WARN(mSLog,
103 "Transformer {}: both windings are nominally {} [V], so "
104 "the reference winding cannot be resolved from the "
105 "nominal voltages; winding 1 assumed. Pass an explicit "
106 "WindingReference to remove the ambiguity.",
107 this->name(), mNominalVoltagePrimary);
108
109 SPDLOG_LOGGER_INFO(
110 mSLog,
111 "Impedance referred to winding {} ({} [V]) {}, remaining "
112 "winding at terminal {} ({} [V]), ratio = {}",
113 mReferenceTerminal + 1, nominalVoltageAt(mReferenceTerminal),
114 mReferenceWinding == WindingReference::Auto
115 ? "(resolved from the nominal voltages)"
116 : "(set explicitly)",
117 nonReferenceTerminal(), nominalVoltageAt(nonReferenceTerminal()),
118 Logger::complexToString(mRatioFromReference));
119}
120
122 if (mSubCompCreated)
123 return;
124 mSubCompCreated = true;
125
126 resolveWindingRoles();
127
128 auto midpoint = mVirtualNodes[2];
129
130 mSubInductor =
131 std::make_shared<DP::Ph1::Inductor>(**mName + "_ind", mLogLevel);
132 mSubInductor->setParameters(**mInductance / 2.);
135
136 mSubInductor2 =
137 std::make_shared<DP::Ph1::Inductor>(**mName + "_ind2", mLogLevel);
138 mSubInductor2->setParameters(**mInductance / 2.);
141
142 if (mNumVirtualNodes == 5) {
143 mSubResistor =
144 std::make_shared<DP::Ph1::Resistor>(**mName + "_res", mLogLevel);
145 mSubResistor->setParameters(**mResistance / 2.);
146 mSubResistor->connect({node(mReferenceTerminal), mVirtualNodes[3]});
147 mSubInductor->connect({mVirtualNodes[3], midpoint});
150
151 mSubResistor2 =
152 std::make_shared<DP::Ph1::Resistor>(**mName + "_res2", mLogLevel);
153 mSubResistor2->setParameters(**mResistance / 2.);
154 mSubResistor2->connect({midpoint, mVirtualNodes[4]});
155 mSubInductor2->connect({mVirtualNodes[4], mVirtualNodes[0]});
156 addMNASubComponent(mSubResistor2,
159 } else {
160 mSubInductor->connect({node(mReferenceTerminal), midpoint});
161 mSubInductor2->connect({midpoint, mVirtualNodes[0]});
162 }
163
164 if (**mRatedPower <= 0) {
165 SPDLOG_LOGGER_WARN(mSLog,
166 "Transformer {}: rated power is {} [VA], so the "
167 "magnetizing branch cannot be sized and is omitted",
168 this->name(), **mRatedPower);
169 return;
170 }
171
172 if (mNoLoadCurrent <= mNoLoadLoss) {
173 SPDLOG_LOGGER_ERROR(mSLog,
174 "Transformer {}: no-load current {} must exceed the "
175 "no-load loss {}; the magnetizing branch has no "
176 "reactive part otherwise",
177 this->name(), mNoLoadCurrent, mNoLoadLoss);
179 }
180
181 mMagnetizingResistance = std::pow(nominalVoltageAt(mReferenceTerminal), 2) /
182 (mNoLoadLoss * **mRatedPower);
183 mSubMagnetizingResistor =
184 std::make_shared<DP::Ph1::Resistor>(**mName + "_mag_res", mLogLevel);
185 mSubMagnetizingResistor->setParameters(mMagnetizingResistance);
186 mSubMagnetizingResistor->connect({midpoint, DP::SimNode::GND});
187 SPDLOG_LOGGER_INFO(mSLog,
188 "Magnetizing resistance = {} [Ohm] at the T midpoint",
189 Logger::realToString(mMagnetizingResistance));
190 addMNASubComponent(mSubMagnetizingResistor,
193
194 mSubMagnetizingInductor =
195 std::make_shared<DP::Ph1::Inductor>(**mName + "_mag_ind", mLogLevel);
196 mSubMagnetizingInductor->connect({midpoint, DP::SimNode::GND});
197 addMNASubComponent(mSubMagnetizingInductor,
200}
201
203 Real frequency) {
204 Real omega = 2. * PI * frequency;
205 if (mSubMagnetizingInductor) {
206 Real magnetizingSusceptance =
207 std::sqrt(std::pow(mNoLoadCurrent, 2) - std::pow(mNoLoadLoss, 2)) *
208 **mRatedPower / std::pow(nominalVoltageAt(mReferenceTerminal), 2);
209 mMagnetizingInductance = 1. / (omega * magnetizingSusceptance);
210 mSubMagnetizingInductor->setParameters(mMagnetizingInductance);
211 SPDLOG_LOGGER_INFO(mSLog, "Magnetizing inductance = {} [H]",
212 Logger::realToString(mMagnetizingInductance));
213 }
214
215 // Set initial voltage of virtual node in between
216 mVirtualNodes[0]->setInitialVoltage(
217 initialSingleVoltage(nonReferenceTerminal()) * mRatioFromReference);
218
219 Complex halfImpedance =
220 Complex(**mResistance / 2., omega * **mInductance / 2.);
221 Complex magnetizingAdmittance = Complex(0, 0);
222 if (mSubMagnetizingInductor)
223 magnetizingAdmittance = 1. / mMagnetizingResistance +
224 1. / Complex(0, omega * mMagnetizingInductance);
225
226 Complex referenceVoltage = initialSingleVoltage(mReferenceTerminal);
227 Complex midpointVoltage =
228 (referenceVoltage + mVirtualNodes[0]->initialSingleVoltage()) /
229 (2. + halfImpedance * magnetizingAdmittance);
230 mVirtualNodes[2]->setInitialVoltage(midpointVoltage);
231
232 if (mNumVirtualNodes == 5) {
233 Complex referenceCurrent =
234 (referenceVoltage - midpointVoltage) / halfImpedance;
235 Complex nonReferenceCurrent =
236 (midpointVoltage - mVirtualNodes[0]->initialSingleVoltage()) /
237 halfImpedance;
238 mVirtualNodes[3]->setInitialVoltage(referenceVoltage -
239 referenceCurrent * **mResistance / 2.);
240 mVirtualNodes[4]->setInitialVoltage(
241 midpointVoltage - nonReferenceCurrent * **mResistance / 2.);
242 }
243
244 // Static calculations from load flow data
245 Complex impedance = {**mResistance, omega * **mInductance};
246 SPDLOG_LOGGER_INFO(mSLog, "Reactance={} [Ohm] (referred to primary side)",
247 omega * **mInductance);
248 Complex impedanceVoltage =
249 mOrientationSign * (mVirtualNodes[0]->initialSingleVoltage() -
250 initialSingleVoltage(mReferenceTerminal));
251 (**mIntfVoltage)(0, 0) = initialSingleVoltage(1) - initialSingleVoltage(0);
252 (**mIntfCurrent)(0, 0) = impedanceVoltage / impedance;
253
254 SPDLOG_LOGGER_INFO(
255 mSLog,
256 "\n--- Initialization from powerflow ---"
257 "\nVoltage across: {:s}"
258 "\nCurrent: {:s}"
259 "\nTerminal 0 voltage: {:s}"
260 "\nTerminal 1 voltage: {:s}"
261 "\nVirtual Node 1 voltage: {:s}"
262 "\n--- Initialization from powerflow finished ---",
268}
269
271 Real omega, Real timeStep, Attribute<Matrix>::Ptr leftVector) {
272 SPDLOG_LOGGER_INFO(
273 mSLog,
274 "\nTerminal 0 connected to {:s} = sim node {:d}"
275 "\nTerminal 1 connected to {:s} = sim node {:d}",
278}
279
281 SparseMatrixRow &systemMatrix) {
282 // Ideal transformer equations
283 if (terminalNotGrounded(mReferenceTerminal)) {
286 Complex(-1.0, 0));
289 Complex(1.0, 0));
290 }
291 if (terminalNotGrounded(nonReferenceTerminal())) {
293 systemMatrix, matrixNodeIndex(nonReferenceTerminal()),
294 mVirtualNodes[1]->matrixNodeIndex(), std::conj(mRatioFromReference));
296 matrixNodeIndex(nonReferenceTerminal()),
297 -mRatioFromReference);
298 }
299
300 // Add subcomps to system matrix
301 for (auto subcomp : mSubComponents)
302 if (auto mnasubcomp = std::dynamic_pointer_cast<MNAInterface>(subcomp))
303 mnasubcomp->mnaApplySystemMatrixStamp(systemMatrix);
304
305 if (terminalNotGrounded(mReferenceTerminal)) {
306 SPDLOG_LOGGER_INFO(mSLog, "Add {:s} to system at ({:d},{:d})",
310 SPDLOG_LOGGER_INFO(mSLog, "Add {:s} to system at ({:d},{:d})",
314 }
315 if (terminalNotGrounded(nonReferenceTerminal())) {
316 SPDLOG_LOGGER_INFO(mSLog, "Add {:s} to system at ({:d},{:d})",
317 Logger::complexToString(mRatioFromReference),
318 matrixNodeIndex(nonReferenceTerminal()),
320 SPDLOG_LOGGER_INFO(mSLog, "Add {:s} to system at ({:d},{:d})",
321 Logger::complexToString(-mRatioFromReference),
323 matrixNodeIndex(nonReferenceTerminal()));
324 }
325}
326
328 AttributeBase::List &prevStepDependencies,
329 AttributeBase::List &attributeDependencies,
330 AttributeBase::List &modifiedAttributes) {
331 prevStepDependencies.push_back(mIntfCurrent);
332 prevStepDependencies.push_back(mIntfVoltage);
333 modifiedAttributes.push_back(mRightVector);
334}
335
339
341 AttributeBase::List &prevStepDependencies,
342 AttributeBase::List &attributeDependencies,
343 AttributeBase::List &modifiedAttributes,
344 Attribute<Matrix>::Ptr &leftVector) {
345 attributeDependencies.push_back(leftVector);
346 modifiedAttributes.push_back(mIntfVoltage);
347 modifiedAttributes.push_back(mIntfCurrent);
348}
349
351 Real time, Int timeStepCount, Attribute<Matrix>::Ptr &leftVector) {
352 this->mnaUpdateVoltage(**leftVector);
353 this->mnaUpdateCurrent(**leftVector);
354}
355
357 (**mIntfCurrent)(0, 0) = mOrientationSign * mSubInductor->intfCurrent()(0, 0);
358}
359
361 // v1 - v0
362 (**mIntfVoltage)(0, 0) = 0;
363 if (terminalNotGrounded(1))
364 (**mIntfVoltage)(0, 0) =
366 if (terminalNotGrounded(0))
367 (**mIntfVoltage)(0, 0) =
368 (**mIntfVoltage)(0, 0) -
370
371 SPDLOG_LOGGER_DEBUG(mSLog, "Voltage {:s}",
373}
std::vector< Ptr > List
Definition Attribute.h:123
AttributePointer< Attribute< T > > Ptr
Definition Attribute.h:249
const Attribute< Real >::Ptr mRatedPower
Rated Apparent Power [VA].
const Attribute< Real >::Ptr mInductance
Inductance [H].
void setParameters(Real nomVoltagePrimary, Real nomVoltageSecondary, Real ratioAbs, Real ratioPhase, Real resistance, Real inductance)
Real mNominalVoltageSecondary
Nominal voltage of secondary side.
const Attribute< Real >::Ptr mResistance
Resistance [Ohm].
Real mNominalVoltagePrimary
Nominal voltage of primary side.
Real nominalVoltageAt(UInt terminal) const
Nominal voltage of the winding at the given terminal.
const Attribute< Complex >::Ptr mRatio
Complex transformer ratio.
void addMNASubComponent(typename SimPowerComp< Complex >::Ptr subc, MNA_SUBCOMP_TASK_ORDER preStepOrder, MNA_SUBCOMP_TASK_ORDER postStepOrder, Bool contributeToRightVector)
CompositePowerComp(String uid, String name, Bool hasPreStep, Bool hasPostStep, Logger::Level logLevel)
Transformer(String uid, String name, Logger::Level logLevel=Logger::Level::off, Bool withResistiveLosses=false)
Defines UID, name and logging level.
void setParameters(Real nomVoltagePrimary, Real nomVoltageSecondary, Real ratioAbs, Real ratioPhase, Real resistance, Real inductance)
Defines component parameters.
void createSubComponents() override
Constructs and registers MNA subcomponents (incl. terminal swap); idempotent.
void mnaCompApplySystemMatrixStamp(SparseMatrixRow &systemMatrix) override
Stamps system matrix.
void mnaParentPreStep(Real time, Int timeStepCount) override
MNA pre step operations.
void mnaParentInitialize(Real omega, Real timeStep, Attribute< Matrix >::Ptr leftVector) override
Initializes internal variables of the component.
void initializeParentFromNodesAndTerminals(Real frequency) override
Initializes component from power flow data.
void mnaParentAddPostStepDependencies(AttributeBase::List &prevStepDependencies, AttributeBase::List &attributeDependencies, AttributeBase::List &modifiedAttributes, Attribute< Matrix >::Ptr &leftVector) override
Add MNA post step dependencies.
void mnaCompUpdateVoltage(const Matrix &leftVector) override
Updates internal voltage variable of the component.
SimPowerComp< Complex >::Ptr clone(String name) override
DEPRECATED: Delete method.
void mnaCompUpdateCurrent(const Matrix &leftVector) override
Updates internal current variable of the component.
void mnaParentAddPreStepDependencies(AttributeBase::List &prevStepDependencies, AttributeBase::List &attributeDependencies, AttributeBase::List &modifiedAttributes) override
Add MNA pre step dependencies.
void mnaParentPostStep(Real time, Int timeStepCount, Attribute< Matrix >::Ptr &leftVector) override
MNA post step operations.
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.
spdlog::level::level_enum Level
Definition Logger.h:33
static String complexToString(const Complex &num)
Definition Logger.cpp:63
static String realToString(const Real &num)
Definition Logger.cpp:69
static String phasorToString(const Complex &num)
Definition Logger.cpp:57
void mnaUpdateCurrent(const Matrix &leftVector) final
void mnaUpdateVoltage(const Matrix &leftVector) final
Attribute< Matrix >::Ptr mRightVector
void mnaApplyRightSideVectorStamp(Matrix &rightVector) final
static Complex complexFromVectorElement(const Matrix &mat, Matrix::Index row, Int maxFreq=1, Int freqIdx=0)
Definition MathUtils.cpp:94
static void setMatrixElement(SparseMatrixRow &mat, Matrix::Index row, Matrix::Index column, Complex value, Int maxFreq=1, Int freqIdx=0)
UInt matrixNodeIndex(UInt nodeIndex)
const Attribute< MatrixVar< Complex > >::Ptr mIntfCurrent
SimTerminal< Complex >::List mTerminals
SimNode< Complex >::Ptr node(UInt index)
const Attribute< MatrixVar< Complex > >::Ptr mIntfVoltage
std::shared_ptr< SimPowerComp< VarType > > Ptr
SimNode< Complex >::List mVirtualNodes
std::vector< std::shared_ptr< SimPowerComp< Complex > > > mSubComponents
Bool terminalNotGrounded(UInt index)
Complex initialSingleVoltage(UInt index)
Logger::Level mLogLevel
Component logger control for internal variables.
UInt mNumVirtualNodes
Determines the number of virtual or internal Nodes.
bool mParametersSet
Flag indicating that parameters are set via setParameters() function.
Logger::Log mSLog
Component logger.
static std::shared_ptr< Transformer > make(Args &&...args)
Definition PtrFactory.h:19
#define PI
Definition Definitions.h:43
#define DOUBLE_EPSILON
Definition Definitions.h:14
Eigen::Matrix< Real, Eigen::Dynamic, Eigen::Dynamic, Eigen::ColMajor > Matrix
Dense matrix for real numbers.
Definition Definitions.h:79
std::string String
Definition Definitions.h:63
double Real
Definition Definitions.h:60
int Int
Definition Definitions.h:59
std::complex< Real > Complex
Definition Definitions.h:61
bool Bool
Definition Definitions.h:62
Eigen::SparseMatrix< Real, Eigen::RowMajor > SparseMatrixRow
Sparse matrix for real numbers (row major).
Definition Definitions.h:72