17 Bool withResistiveLosses)
26 if (withResistiveLosses)
31 SPDLOG_LOGGER_INFO(
mSLog,
"Create {} {}", this->
type(), name);
42 Real nomVoltageSecondary,
48 ratioAbs, ratioPhase, resistance,
52 mSLog,
"Nominal Voltage Primary={} [V] Nominal Voltage Secondary={} [V]",
55 mSLog,
"Resistance={} [Ohm] Inductance={} [H] (referred to primary side)",
57 SPDLOG_LOGGER_INFO(
mSLog,
"Tap Ratio={} [/] Phase Shift={} [deg]",
61 mRatioAbs = std::abs(**
mRatio);
62 mRatioPhase = std::arg(**
mRatio);
68 Real nomVoltageSecondary,
76 SPDLOG_LOGGER_ERROR(
mSLog,
"Rated power {} [VA] is negative; must be >= 0",
85 ratioAbs, ratioPhase, resistance,
98void SP::Ph1::Transformer::resolveWindingRoles() {
99 switch (mReferenceWinding) {
101 mReferenceTerminal = 0;
104 mReferenceTerminal = 1;
107 SPDLOG_LOGGER_ERROR(mSLog,
108 "Transformer {}: three-winding transformers are "
114 (mNominalVoltagePrimary >= mNominalVoltageSecondary) ? 0 : 1;
117 mRatioFromReference = (mReferenceTerminal == 0) ? **mRatio : 1. / **mRatio;
118 mOrientationSign = (mReferenceTerminal == 0) ? 1. : -1.;
120 if ((mReferenceTerminal == 0) != (
Math::abs(**mRatio) >= 1.) &&
124 "Nominal voltages put the higher-voltage winding at terminal {} ({} "
125 "[V] against {} [V]) but the turns ratio {} points the other way; "
126 "check the argument order of setParameters()",
127 mReferenceTerminal, nominalVoltageAt(mReferenceTerminal),
128 nominalVoltageAt(nonReferenceTerminal()),
137 resolveWindingRoles();
141 mSubInductor = std::make_shared<SP::Ph1::Inductor>(
142 **
mUID +
"_ind", **
mName +
"_ind", Logger::Level::off);
147 mSubInductor2 = std::make_shared<SP::Ph1::Inductor>(
148 **
mUID +
"_ind2", **
mName +
"_ind2", Logger::Level::off);
154 mSubResistor = std::make_shared<SP::Ph1::Resistor>(
155 **
mUID +
"_res", **
mName +
"_res", Logger::Level::off);
162 mSubResistor2 = std::make_shared<SP::Ph1::Resistor>(
163 **
mUID +
"_res2", **
mName +
"_res2", Logger::Level::off);
171 mSubInductor->connect({
node(mReferenceTerminal), midpoint});
175 bool magnetizingEnabled =
178 if (!magnetizingEnabled)
182 SPDLOG_LOGGER_WARN(
mSLog,
183 "Transformer {}: rated power is {} [VA], so the "
184 "magnetizing branch cannot be sized and is omitted",
189 if (mNoLoadCurrent <= mNoLoadLoss) {
190 SPDLOG_LOGGER_ERROR(
mSLog,
191 "Transformer {}: no-load current {} must exceed the "
193 this->
name(), mNoLoadCurrent, mNoLoadLoss);
197 mSubMagnetizingResistor = std::make_shared<SP::Ph1::Resistor>(
198 **
mUID +
"_mag_res", **
mName +
"_mag_res", Logger::Level::off);
204 mSubMagnetizingInductor = std::make_shared<SP::Ph1::Inductor>(
205 **
mUID +
"_mag_ind", **
mName +
"_mag_ind", Logger::Level::off);
214 mNominalOmega = 2. *
PI * frequency;
216 SPDLOG_LOGGER_INFO(
mSLog,
"Reactance={} [Ohm] (referred to primary side)",
219 if (mSubMagnetizingResistor) {
220 mMagnetizingResistance = std::pow(
nominalVoltageAt(mReferenceTerminal), 2) /
222 mSubMagnetizingResistor->setParameters(mMagnetizingResistance);
223 mSubMagnetizingResistor->setBaseVoltage(
226 Real magnetizingSusceptance =
227 std::sqrt(std::pow(mNoLoadCurrent, 2) - std::pow(mNoLoadLoss, 2)) *
229 mMagnetizingInductance = 1. / (mNominalOmega * magnetizingSusceptance);
230 mSubMagnetizingInductor->setParameters(mMagnetizingInductance);
232 SPDLOG_LOGGER_INFO(
mSLog,
233 "Magnetizing resistance = {} [Ohm], inductance = {} [H]",
245 mOrientationSign * (
mVirtualNodes[0]->initialSingleVoltage() -
248 (**mIntfCurrent)(0, 0) = impedanceVoltage / impedance;
256 "\n--- Initialization from powerflow ---"
257 "\nVoltage across: {:s}"
259 "\nTerminal 0 voltage: {:s}"
260 "\nTerminal 1 voltage: {:s}"
261 "\nVirtual Node 1 voltage: {:s}"
262 "\n--- Initialization from powerflow finished ---",
288 SPDLOG_LOGGER_INFO(
mSLog,
"#### Calculate Per Unit Parameters for {}",
290 mBaseApparentPower = baseApparentPower;
291 mBaseOmega = baseOmega;
292 SPDLOG_LOGGER_INFO(
mSLog,
"Base Power={} [VA] Base Omega={} [1/s]",
293 baseApparentPower, baseOmega);
295 resolveWindingRoles();
299 SPDLOG_LOGGER_INFO(
mSLog,
300 "Transformer {}: no base voltage was set, using the "
301 "reference winding {} [V]",
302 this->
name(), referenceVoltage);
304 }
else if (std::abs(**
mBaseVoltage - referenceVoltage) >
306 SPDLOG_LOGGER_WARN(
mSLog,
307 "Transformer {}: base voltage {} [V] does not match the "
308 "reference winding {} [V]; the impedances are referred "
309 "to the reference winding, so that is used as the base",
315 mBaseAdmittance = 1.0 / mBaseImpedance;
316 mBaseCurrent = baseApparentPower /
319 SPDLOG_LOGGER_INFO(
mSLog,
"Base Voltage={} [V] Base Impedance={} [Ohm]",
322 mResistancePerUnit = **
mResistance / mBaseImpedance;
323 mReactancePerUnit = mReactance / mBaseImpedance;
324 SPDLOG_LOGGER_INFO(
mSLog,
"Resistance={} [pu] Reactance={} [pu]",
325 mResistancePerUnit, mReactancePerUnit);
327 mBaseInductance = mBaseImpedance / mBaseOmega;
328 mInductancePerUnit = **
mInductance / mBaseInductance;
330 mLeakagePerUnit =
Complex(mResistancePerUnit, 1. * mInductancePerUnit);
331 SPDLOG_LOGGER_INFO(
mSLog,
"Leakage Impedance={} [pu] ", mLeakagePerUnit);
335 mRatioPerUnit = mRatioFromReference /
339 SPDLOG_LOGGER_INFO(
mSLog,
"Tap Ratio={} [pu]", mRatioAbsPerUnit);
342 bool magnetizingEnabled =
345 if (magnetizingEnabled && **
mRatedPower > 0 && mNoLoadCurrent > mNoLoadLoss)
346 mMagnetizingPerUnit =
347 Complex(mNoLoadLoss, -std::sqrt(std::pow(mNoLoadCurrent, 2) -
348 std::pow(mNoLoadLoss, 2))) *
352 mMagnetizingPerUnit =
Complex(0, 0);
359 Complex halfLeakage = mLeakagePerUnit / 2.;
361 mLeakagePerUnit + halfLeakage * halfLeakage * mMagnetizingPerUnit;
362 Complex yShunted = (1. + halfLeakage * mMagnetizingPerUnit) / determinant;
363 Complex ySeries = 1. / determinant;
365 mY_element(0, 0) = yShunted;
366 mY_element(0, 1) = -ySeries * mRatioPerUnit;
367 mY_element(1, 0) = -ySeries * std::conj(mRatioPerUnit);
368 mY_element(1, 1) = yShunted * std::norm(mRatioPerUnit);
371 for (
int i = 0; i < 2; i++)
372 for (
int j = 0; j < 2; j++)
376 "Transformer {}: non-finite per-unit admittance {} "
377 "in element Y({},{}) (leakage {}, tap {})",
386 mY_element.coeff(0, 0);
389 mY_element.coeff(0, 1);
392 mY_element.coeff(1, 1);
395 mY_element.coeff(1, 0);
397 SPDLOG_LOGGER_INFO(
mSLog,
"#### Y matrix stamping: {}", mY_element);
402 **
mCurrent = current * mBaseCurrent;
420 "\nTerminal 0 connected to {:s} = sim node {:d}"
421 "\nTerminal 1 connected to {:s} = sim node {:d}",
443 -mRatioFromReference);
448 if (
auto mnasubcomp = std::dynamic_pointer_cast<MNAInterface>(subcomp))
449 mnasubcomp->mnaApplySystemMatrixStamp(systemMatrix);
452 SPDLOG_LOGGER_INFO(
mSLog,
"Add {:s} to system at ({:d},{:d})",
456 SPDLOG_LOGGER_INFO(
mSLog,
"Add {:s} to system at ({:d},{:d})",
462 SPDLOG_LOGGER_INFO(
mSLog,
"Add {:s} to system at ({:d},{:d})",
465 SPDLOG_LOGGER_INFO(
mSLog,
"Add {:s} to system at ({:d},{:d})",
489 attributeDependencies.push_back(leftVector);
501 (**mIntfCurrent)(0, 0) = mOrientationSign * mSubInductor->intfCurrent()(0, 0);
502 SPDLOG_LOGGER_DEBUG(
mSLog,
"Current {:s}",
508 (**mIntfVoltage)(0, 0) = 0;
510 (**mIntfVoltage)(0, 0) =
513 (**mIntfVoltage)(0, 0) =
517 SPDLOG_LOGGER_DEBUG(
mSLog,
"Voltage {:s}",
AttributePointer< Attribute< T > > Ptr
void addMNASubComponent(typename SimPowerComp< Complex >::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< String >::Ptr mName
Human readable name.
String uid()
Returns unique id.
String type()
Get component type (cross-platform)
const Attribute< String >::Ptr mUID
Unique identifier.
AttributeList::Ptr mAttributes
Attribute List.
spdlog::level::level_enum Level
static String complexToString(const Complex &num)
static String realToString(const Real &num)
static String phasorToString(const Complex &num)
void mnaUpdateCurrent(const Matrix &leftVector) final
void mnaUpdateVoltage(const Matrix &leftVector) final
Attribute< Matrix >::Ptr mRightVector
static Complex complexFromVectorElement(const Matrix &mat, Matrix::Index row, Int maxFreq=1, Int freqIdx=0)
static void setMatrixElement(SparseMatrixRow &mat, Matrix::Index row, Matrix::Index column, Complex value, Int maxFreq=1, Int freqIdx=0)
static bool isFinite(Real value)
static Real abs(Complex value)
UInt matrixNodeIndex(UInt nodeIndex)
const Attribute< MatrixVar< Complex > >::Ptr mIntfCurrent
SimTerminal< Complex >::List mTerminals
SimNode< Complex >::Ptr node(UInt index)
void setVirtualNodeNumber(UInt num)
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)
void setTerminalNumber(UInt num)
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)
Eigen::Matrix< Real, Eigen::Dynamic, Eigen::Dynamic, Eigen::ColMajor > Matrix
Dense matrix for real numbers.
Eigen::SparseMatrix< Complex, Eigen::RowMajor > SparseMatrixCompRow
Sparse matrix for complex numbers (row major).
Eigen::Matrix< Complex, Eigen::Dynamic, 1 > VectorComp
Dense vector for complex numbers.
std::complex< Real > Complex
Eigen::Matrix< Complex, Eigen::Dynamic, Eigen::Dynamic, Eigen::ColMajor > MatrixComp
Dense matrix for complex numbers.
Eigen::SparseMatrix< Real, Eigen::RowMajor > SparseMatrixRow
Sparse matrix for real numbers (row major).