9 #include <dpsim-models/SP/SP_Ph1_Transformer.h>
15 Logger::Level logLevel,
16 Bool withResistiveLosses)
19 mBaseVoltage(mAttributes->create<Real>(
"base_Voltage")),
20 mCurrent(mAttributes->create<MatrixComp>(
"current_vector")),
21 mActivePowerBranch(mAttributes->create<Matrix>(
"p_branch_vector")),
22 mReactivePowerBranch(mAttributes->create<Matrix>(
"q_branch_vector")),
23 mActivePowerInjection(mAttributes->create<Real>(
"p_inj")),
24 mReactivePowerInjection(mAttributes->create<Real>(
"q_inj")) {
25 if (withResistiveLosses)
26 setVirtualNodeNumber(3);
28 setVirtualNodeNumber(2);
30 SPDLOG_LOGGER_INFO(
mSLog,
"Create {} {}", this->
type(), name);
41 Real nomVoltageEnd2, Real ratioAbs,
42 Real ratioPhase, Real resistance,
46 Base::Ph1::Transformer::setParameters(nomVoltageEnd1, nomVoltageEnd2,
47 ratioAbs, ratioPhase, resistance,
51 mSLog,
"Nominal Voltage End 1={} [V] Nominal Voltage End 2={} [V]",
52 **mNominalVoltageEnd1, **mNominalVoltageEnd2);
54 mSLog,
"Resistance={} [Ohm] Inductance={} [H] (referred to primary side)",
55 **mResistance, **mInductance);
56 SPDLOG_LOGGER_INFO(mSLog,
"Tap Ratio={} [/] Phase Shift={} [deg]",
57 std::abs(**mRatio), std::arg(**mRatio));
58 SPDLOG_LOGGER_INFO(mSLog,
"Rated Power ={} [W]", **mRatedPower);
60 mRatioAbs = std::abs(**mRatio);
61 mRatioPhase = std::arg(**mRatio);
63 mParametersSet =
true;
67 Real nomVoltageEnd2, Real ratedPower,
68 Real ratioAbs, Real ratioPhase,
69 Real resistance, Real inductance) {
71 **mRatedPower = ratedPower;
72 SPDLOG_LOGGER_INFO(mSLog,
"Rated Power ={} [W]", **mRatedPower);
75 ratioPhase, resistance, inductance);
80 auto copy = Transformer::make(name, mLogLevel);
81 copy->setParameters(**mNominalVoltageEnd1, **mNominalVoltageEnd2,
82 **mRatedPower, std::abs(**mRatio), std::arg(**mRatio),
83 **mResistance, **mInductance);
88 mNominalOmega = 2. * PI * frequency;
89 mReactance = mNominalOmega * **mInductance;
90 SPDLOG_LOGGER_INFO(mSLog,
"Reactance={} [Ohm] (referred to primary side)",
96 if (Math::abs(**mRatio) < 1.) {
97 **mRatio = 1. / **mRatio;
98 mRatioAbs = std::abs(**mRatio);
99 mRatioPhase = std::arg(**mRatio);
100 std::shared_ptr<SimTerminal<Complex>> tmp = mTerminals[0];
101 mTerminals[0] = mTerminals[1];
103 Real tmpVolt = **mNominalVoltageEnd1;
104 **mNominalVoltageEnd1 = **mNominalVoltageEnd2;
105 **mNominalVoltageEnd2 = tmpVolt;
106 SPDLOG_LOGGER_INFO(mSLog,
"Switching terminals to have first terminal at "
107 "higher voltage side. Updated parameters: ");
109 mSLog,
"Nominal Voltage End 1 = {} [V] Nominal Voltage End 2 = {} [V]",
110 **mNominalVoltageEnd1, **mNominalVoltageEnd2);
111 SPDLOG_LOGGER_INFO(mSLog,
"Tap Ratio = {} [ ] Phase Shift = {} [deg]",
112 mRatioAbs, mRatioPhase);
116 mVirtualNodes[0]->setInitialVoltage(initialSingleVoltage(1) * **mRatio);
119 Complex impedance = {**mResistance, mReactance};
120 (**mIntfVoltage)(0, 0) =
121 mVirtualNodes[0]->initialSingleVoltage() - initialSingleVoltage(0);
122 (**mIntfCurrent)(0, 0) = (**mIntfVoltage)(0, 0) / impedance;
125 mSubInductor = std::make_shared<SP::Ph1::Inductor>(
126 **mUID +
"_ind", **mName +
"_ind", Logger::Level::off);
127 mSubInductor->setParameters(**mInductance);
128 addMNASubComponent(mSubInductor, MNA_SUBCOMP_TASK_ORDER::TASK_BEFORE_PARENT,
129 MNA_SUBCOMP_TASK_ORDER::TASK_BEFORE_PARENT,
true);
131 if (mNumVirtualNodes == 3) {
132 mVirtualNodes[2]->setInitialVoltage(initialSingleVoltage(0));
133 mSubResistor = std::make_shared<SP::Ph1::Resistor>(
134 **mUID +
"_res", **mName +
"_res", Logger::Level::off);
135 mSubResistor->setParameters(**mResistance);
136 mSubResistor->connect({node(0), mVirtualNodes[2]});
137 mSubInductor->connect({mVirtualNodes[2], mVirtualNodes[0]});
138 addMNASubComponent(mSubResistor, MNA_SUBCOMP_TASK_ORDER::TASK_BEFORE_PARENT,
139 MNA_SUBCOMP_TASK_ORDER::TASK_BEFORE_PARENT,
true);
141 mSubInductor->connect({node(0), mVirtualNodes[0]});
145 if (mBehaviour == TopologicalPowerComp::Behaviour::Initialization ||
146 mBehaviour == TopologicalPowerComp::Behaviour::MNASimulation) {
148 Real pSnub = P_SNUB_TRANSFORMER * **mRatedPower;
149 Real qSnub = Q_SNUB_TRANSFORMER * **mRatedPower;
152 mSnubberResistance1 = std::pow(std::abs(**mNominalVoltageEnd1), 2) / pSnub;
154 std::make_shared<SP::Ph1::Resistor>(**mName +
"_snub_res1", mLogLevel);
155 mSubSnubResistor1->setParameters(mSnubberResistance1);
156 mSubSnubResistor1->connect({node(0), SP::SimNode::GND});
159 "Snubber Resistance 1 (connected to higher voltage side {}) = {} [Ohm]",
160 node(0)->name(), Logger::realToString(mSnubberResistance1));
161 mSubSnubResistor1->setBaseVoltage(**mNominalVoltageEnd1);
162 addMNASubComponent(mSubSnubResistor1,
163 MNA_SUBCOMP_TASK_ORDER::TASK_BEFORE_PARENT,
164 MNA_SUBCOMP_TASK_ORDER::TASK_BEFORE_PARENT,
true);
167 mSnubberResistance2 = std::pow(std::abs(**mNominalVoltageEnd2), 2) / pSnub;
169 std::make_shared<SP::Ph1::Resistor>(**mName +
"_snub_res2", mLogLevel);
170 mSubSnubResistor2->setParameters(mSnubberResistance2);
171 mSubSnubResistor2->connect({node(1), SP::SimNode::GND});
174 "Snubber Resistance 2 (connected to lower voltage side {}) = {} [Ohm]",
175 node(1)->name(), Logger::realToString(mSnubberResistance2));
176 mSubSnubResistor2->setBaseVoltage(**mNominalVoltageEnd2);
177 addMNASubComponent(mSubSnubResistor2,
178 MNA_SUBCOMP_TASK_ORDER::TASK_BEFORE_PARENT,
179 MNA_SUBCOMP_TASK_ORDER::TASK_BEFORE_PARENT,
true);
191 mSnubberCapacitance2 =
192 qSnub / std::pow(std::abs(**mNominalVoltageEnd2), 2) / mNominalOmega;
194 std::make_shared<SP::Ph1::Capacitor>(**mName +
"_snub_cap2", mLogLevel);
195 mSubSnubCapacitor2->setParameters(mSnubberCapacitance2);
196 mSubSnubCapacitor2->connect({node(1), SP::SimNode::GND});
199 "Snubber Capacitance 2 (connected to lower voltage side {}) = {} [F]",
200 node(1)->name(), Logger::realToString(mSnubberCapacitance2));
201 mSubSnubCapacitor2->setBaseVoltage(**mNominalVoltageEnd2);
202 addMNASubComponent(mSubSnubCapacitor2,
203 MNA_SUBCOMP_TASK_ORDER::TASK_BEFORE_PARENT,
204 MNA_SUBCOMP_TASK_ORDER::TASK_BEFORE_PARENT,
true);
208 SPDLOG_LOGGER_INFO(mSLog,
"Electrical subcomponents: ");
209 for (
auto subcomp : mSubComponents) {
210 SPDLOG_LOGGER_INFO(mSLog,
"- {}", subcomp->name());
211 subcomp->initialize(mFrequencies);
212 subcomp->initializeFromNodesAndTerminals(frequency);
217 "\n--- Initialization from powerflow ---"
218 "\nVoltage across: {:s}"
220 "\nTerminal 0 voltage: {:s}"
221 "\nTerminal 1 voltage: {:s}"
222 "\nVirtual Node 1 voltage: {:s}"
223 "\n--- Initialization from powerflow finished ---",
224 Logger::phasorToString((**mIntfVoltage)(0, 0)),
225 Logger::phasorToString((**mIntfCurrent)(0, 0)),
226 Logger::phasorToString(initialSingleVoltage(0)),
227 Logger::phasorToString(initialSingleVoltage(1)),
228 Logger::phasorToString(mVirtualNodes[0]->initialSingleVoltage()));
236 **mBaseVoltage = baseVoltage;
241 SPDLOG_LOGGER_INFO(mSLog,
"#### Calculate Per Unit Parameters for {}",
243 mBaseApparentPower = baseApparentPower;
244 mBaseOmega = baseOmega;
245 SPDLOG_LOGGER_INFO(mSLog,
"Base Power={} [VA] Base Omega={} [1/s]",
246 baseApparentPower, baseOmega);
248 mBaseImpedance = **mBaseVoltage * **mBaseVoltage / mBaseApparentPower;
249 mBaseAdmittance = 1.0 / mBaseImpedance;
250 mBaseCurrent = baseApparentPower /
253 SPDLOG_LOGGER_INFO(mSLog,
"Base Voltage={} [V] Base Impedance={} [Ohm]",
254 **mBaseVoltage, mBaseImpedance);
256 mResistancePerUnit = **mResistance / mBaseImpedance;
257 mReactancePerUnit = mReactance / mBaseImpedance;
258 SPDLOG_LOGGER_INFO(mSLog,
"Resistance={} [pu] Reactance={} [pu]",
259 mResistancePerUnit, mReactancePerUnit);
261 mBaseInductance = mBaseImpedance / mBaseOmega;
262 mInductancePerUnit = **mInductance / mBaseInductance;
264 mLeakagePerUnit = Complex(mResistancePerUnit, 1. * mInductancePerUnit);
265 SPDLOG_LOGGER_INFO(mSLog,
"Leakage Impedance={} [pu] ", mLeakagePerUnit);
267 mRatioAbsPerUnit = mRatioAbs / **mNominalVoltageEnd1 * **mNominalVoltageEnd2;
268 SPDLOG_LOGGER_INFO(mSLog,
"Tap Ratio={} [pu]", mRatioAbsPerUnit);
271 if (mSubSnubResistor1)
272 mSubSnubResistor1->calculatePerUnitParameters(mBaseApparentPower);
273 if (mSubSnubResistor2)
274 mSubSnubResistor2->calculatePerUnitParameters(mBaseApparentPower);
275 if (mSubSnubCapacitor1)
276 mSubSnubCapacitor1->calculatePerUnitParameters(mBaseApparentPower);
277 if (mSubSnubCapacitor2)
278 mSubSnubCapacitor2->calculatePerUnitParameters(mBaseApparentPower);
282 SparseMatrixCompRow &Y) {
284 mY_element = MatrixComp(2, 2);
285 Complex y = Complex(1, 0) / mLeakagePerUnit;
287 mY_element(0, 0) = y;
288 mY_element(0, 1) = -y * mRatioAbsPerUnit;
289 mY_element(1, 0) = -y * mRatioAbsPerUnit;
290 mY_element(1, 1) = y * std::pow(mRatioAbsPerUnit, 2);
293 for (
int i = 0; i < 2; i++)
294 for (
int j = 0; j < 2; j++)
295 if (std::isinf(mY_element.coeff(i, j).real()) ||
296 std::isinf(mY_element.coeff(i, j).imag())) {
297 std::cout << mY_element << std::endl;
298 std::cout <<
"Zl:" << mLeakage << std::endl;
299 std::cout <<
"tap:" << mRatioAbsPerUnit << std::endl;
300 std::stringstream ss;
301 ss <<
"Transformer>>" << this->name()
302 <<
": infinite or nan values in the element Y at: " << i <<
"," << j;
303 throw std::invalid_argument(ss.str());
307 Y.coeffRef(this->matrixNodeIndex(0), this->matrixNodeIndex(0)) +=
308 mY_element.coeff(0, 0);
309 Y.coeffRef(this->matrixNodeIndex(0), this->matrixNodeIndex(1)) +=
310 mY_element.coeff(0, 1);
311 Y.coeffRef(this->matrixNodeIndex(1), this->matrixNodeIndex(1)) +=
312 mY_element.coeff(1, 1);
313 Y.coeffRef(this->matrixNodeIndex(1), this->matrixNodeIndex(0)) +=
314 mY_element.coeff(1, 0);
316 SPDLOG_LOGGER_INFO(mSLog,
"#### Y matrix stamping: {}", mY_element);
318 if (mSubSnubResistor1)
319 mSubSnubResistor1->pfApplyAdmittanceMatrixStamp(Y);
320 if (mSubSnubResistor2)
321 mSubSnubResistor2->pfApplyAdmittanceMatrixStamp(Y);
322 if (mSubSnubCapacitor1)
323 mSubSnubCapacitor1->pfApplyAdmittanceMatrixStamp(Y);
324 if (mSubSnubCapacitor2)
325 mSubSnubCapacitor2->pfApplyAdmittanceMatrixStamp(Y);
329 VectorComp &powerflow) {
330 **mCurrent = current * mBaseCurrent;
331 **mActivePowerBranch = powerflow.real() * mBaseApparentPower;
332 **mReactivePowerBranch = powerflow.imag() * mBaseApparentPower;
336 **mActivePowerInjection = std::real(powerInjection) * mBaseApparentPower;
337 **mReactivePowerInjection = std::imag(powerInjection) * mBaseApparentPower;
348 "\nTerminal 0 connected to {:s} = sim node {:d}"
349 "\nTerminal 1 connected to {:s} = sim node {:d}",
350 mTerminals[0]->node()->name(), mTerminals[0]->node()->matrixNodeIndex(),
351 mTerminals[1]->node()->name(), mTerminals[1]->node()->matrixNodeIndex());
355 SparseMatrixRow &systemMatrix) {
357 if (terminalNotGrounded(0)) {
358 Math::setMatrixElement(systemMatrix, mVirtualNodes[0]->matrixNodeIndex(),
359 mVirtualNodes[1]->matrixNodeIndex(),
361 Math::setMatrixElement(systemMatrix, mVirtualNodes[1]->matrixNodeIndex(),
362 mVirtualNodes[0]->matrixNodeIndex(),
365 if (terminalNotGrounded(1)) {
366 Math::setMatrixElement(systemMatrix, matrixNodeIndex(1),
367 mVirtualNodes[1]->matrixNodeIndex(), **mRatio);
368 Math::setMatrixElement(systemMatrix, mVirtualNodes[1]->matrixNodeIndex(),
369 matrixNodeIndex(1), -**mRatio);
373 for (
auto subcomp : mSubComponents)
374 if (
auto mnasubcomp = std::dynamic_pointer_cast<MNAInterface>(subcomp))
375 mnasubcomp->mnaApplySystemMatrixStamp(systemMatrix);
377 if (terminalNotGrounded(0)) {
378 SPDLOG_LOGGER_INFO(mSLog,
"Add {:s} to system at ({:d},{:d})",
379 Logger::complexToString(Complex(-1.0, 0)),
380 mVirtualNodes[0]->matrixNodeIndex(),
381 mVirtualNodes[1]->matrixNodeIndex());
382 SPDLOG_LOGGER_INFO(mSLog,
"Add {:s} to system at ({:d},{:d})",
383 Logger::complexToString(Complex(1.0, 0)),
384 mVirtualNodes[1]->matrixNodeIndex(),
385 mVirtualNodes[0]->matrixNodeIndex());
387 if (terminalNotGrounded(1)) {
388 SPDLOG_LOGGER_INFO(mSLog,
"Add {:s} to system at ({:d},{:d})",
389 Logger::complexToString(**mRatio), matrixNodeIndex(1),
390 mVirtualNodes[1]->matrixNodeIndex());
391 SPDLOG_LOGGER_INFO(mSLog,
"Add {:s} to system at ({:d},{:d})",
392 Logger::complexToString(-**mRatio),
393 mVirtualNodes[1]->matrixNodeIndex(), matrixNodeIndex(1));
398 AttributeBase::List &prevStepDependencies,
399 AttributeBase::List &attributeDependencies,
400 AttributeBase::List &modifiedAttributes) {
401 prevStepDependencies.push_back(mIntfCurrent);
402 prevStepDependencies.push_back(mIntfVoltage);
403 modifiedAttributes.push_back(mRightVector);
407 mnaCompApplyRightSideVectorStamp(**mRightVector);
411 AttributeBase::List &prevStepDependencies,
412 AttributeBase::List &attributeDependencies,
413 AttributeBase::List &modifiedAttributes,
415 attributeDependencies.push_back(leftVector);
416 modifiedAttributes.push_back(mIntfVoltage);
417 modifiedAttributes.push_back(mIntfCurrent);
422 this->mnaUpdateVoltage(**leftVector);
423 this->mnaUpdateCurrent(**leftVector);
427 (**mIntfCurrent)(0, 0) = mSubInductor->intfCurrent()(0, 0);
428 SPDLOG_LOGGER_DEBUG(mSLog,
"Current {:s}",
429 Logger::phasorToString((**mIntfCurrent)(0, 0)));
434 (**mIntfVoltage)(0, 0) = 0;
435 (**mIntfVoltage)(0, 0) =
436 Math::complexFromVectorElement(leftVector, matrixNodeIndex(1));
437 (**mIntfVoltage)(0, 0) = (**mIntfVoltage)(0, 0) -
438 Math::complexFromVectorElement(
439 leftVector, mVirtualNodes[0]->matrixNodeIndex());
440 SPDLOG_LOGGER_DEBUG(mSLog,
"Voltage {:s}",
441 Logger::phasorToString((**mIntfVoltage)(0, 0)));
Base class for composite power components.
String type()
Get component type (cross-platform)
Base class for all components that are transmitting power.
const Attribute< MatrixVar< Complex > >::Ptr mIntfCurrent
Current through component.
const Attribute< MatrixVar< Complex > >::Ptr mIntfVoltage
Voltage between terminals.
Logger::Log mSLog
Component logger.