DPsim
Loading...
Searching...
No Matches
EMT_DC_PiLine.cpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2026 Institute for Automation of Complex Power Systems, EONERC, RWTH Aachen University
2// SPDX-License-Identifier: MPL-2.0
3
5
6using namespace CPS;
7
9 : CompositePowerComp<Real>(uid, name, true, true, logLevel),
10 mSeriesResistance(mAttributes->create<Real>("R_series")),
11 mSeriesInductance(mAttributes->create<Real>("L_series")),
12 mParallelCapacitance(mAttributes->create<Real>("C_parallel", 0.0)),
13 mParallelConductance(mAttributes->create<Real>("G_parallel", 0.0)),
14 mInitialCurrent(mAttributes->create<Real>("i_init", 0.0)) {
18 **mIntfVoltage = Matrix::Zero(1, 1);
19 **mIntfCurrent = Matrix::Zero(1, 1);
20}
21
29
31 Real seriesInductance,
32 Real parallelCapacitance,
33 Real parallelConductance,
34 Real initialCurrent) {
35 const Real epsilon = std::numeric_limits<Real>::epsilon();
36 if (!Math::isFinite(seriesResistance) || seriesResistance <= DOUBLE_EPSILON)
37 throw std::invalid_argument(
38 "DC pi-line series resistance must be finite and positive.");
39 if (!Math::isFinite(seriesInductance) || seriesInductance <= DOUBLE_EPSILON)
40 throw std::invalid_argument(
41 "DC pi-line series inductance must be finite and positive.");
42 if (!Math::isFinite(parallelCapacitance) || parallelCapacitance < 0.0 ||
43 (parallelCapacitance > 0.0 &&
44 parallelCapacitance / 2.0 <= DOUBLE_EPSILON))
45 throw std::invalid_argument(
46 "DC pi-line shunt capacitance must be zero or safely positive.");
47 if (!Math::isFinite(parallelConductance) || parallelConductance < 0.0 ||
48 (parallelConductance > 0.0 && parallelConductance <= DOUBLE_EPSILON))
49 throw std::invalid_argument(
50 "DC pi-line shunt conductance must be zero or safely positive.");
51 if (!Math::isFinite(initialCurrent))
52 throw std::invalid_argument("DC pi-line initial current must be finite.");
53
54 **mSeriesResistance = seriesResistance;
55 **mSeriesInductance = seriesInductance;
56 **mParallelCapacitance = parallelCapacitance;
57 **mParallelConductance = parallelConductance;
58 **mInitialCurrent = initialCurrent;
59 mParametersSet = true;
60}
61
62void EMT::DC::PiLine::validateDCTerminals() const {
63 for (UInt terminalIdx = 0; terminalIdx < 2; ++terminalIdx) {
64 const auto terminalNode = const_cast<PiLine *>(this)->node(terminalIdx);
65 if (!terminalNode->isGround() && terminalNode->phaseType() != PhaseType::DC)
66 throw std::invalid_argument(
67 "DC pi-line requires DC nodes or ground at both terminals.");
68 }
69}
70
73 return;
74 if (!mParametersSet)
75 throw std::logic_error(
76 "setParameters() must be called before pi-line construction.");
77 validateDCTerminals();
78 mSubCompCreated = true;
79
80 mSeriesResistor = Resistor::make(**mName + "_series_R", mLogLevel);
81 mSeriesResistor->setParameters(**mSeriesResistance);
82 mSeriesResistor->connect({mTerminals[0]->node(), mVirtualNodes[0]});
83 addMNASubComponent(mSeriesResistor,
86
87 mSeriesInductor = Inductor::make(**mName + "_series_L", mLogLevel);
88 mSeriesInductor->setParameters(**mSeriesInductance, **mInitialCurrent);
89 mSeriesInductor->connect({mVirtualNodes[0], mTerminals[1]->node()});
90 addMNASubComponent(mSeriesInductor,
93
94 if (**mParallelConductance > 0.0) {
95 const Real halfShuntResistance = 2.0 / **mParallelConductance;
96 if (!Math::isFinite(halfShuntResistance))
97 throw std::invalid_argument("DC pi-line shunt resistance is non-finite.");
98
99 mShuntResistor0 = Resistor::make(**mName + "_shunt_R0", mLogLevel);
100 mShuntResistor0->setParameters(halfShuntResistance);
101 mShuntResistor0->connect({EMT::SimNode::GND, mTerminals[0]->node()});
102 addMNASubComponent(mShuntResistor0,
105
106 mShuntResistor1 = Resistor::make(**mName + "_shunt_R1", mLogLevel);
107 mShuntResistor1->setParameters(halfShuntResistance);
108 mShuntResistor1->connect({EMT::SimNode::GND, mTerminals[1]->node()});
109 addMNASubComponent(mShuntResistor1,
112 }
113
114 if (**mParallelCapacitance > 0.0) {
115 const Real halfCapacitance = **mParallelCapacitance / 2.0;
116 mShuntCapacitor0 = Capacitor::make(**mName + "_shunt_C0", mLogLevel);
117 mShuntCapacitor0->setParameters(halfCapacitance);
118 mShuntCapacitor0->connect({EMT::SimNode::GND, mTerminals[0]->node()});
119 addMNASubComponent(mShuntCapacitor0,
122
123 mShuntCapacitor1 = Capacitor::make(**mName + "_shunt_C1", mLogLevel);
124 mShuntCapacitor1->setParameters(halfCapacitance);
125 mShuntCapacitor1->connect({EMT::SimNode::GND, mTerminals[1]->node()});
126 addMNASubComponent(mShuntCapacitor1,
129 }
130}
131
133 validateDCTerminals();
134 const Complex voltage0 = initialSingleVoltage(0);
135 const Complex voltage1 = initialSingleVoltage(1);
136 if (!Math::isFinite(voltage0) || !Math::isFinite(voltage1) ||
137 std::abs(voltage0.imag()) > std::numeric_limits<Real>::epsilon() ||
138 std::abs(voltage1.imag()) > std::numeric_limits<Real>::epsilon())
139 throw std::invalid_argument(
140 "DC pi-line initial node voltages must be finite real values.");
141
142 (**mIntfVoltage)(0, 0) = voltage1.real() - voltage0.real();
143 (**mIntfCurrent)(0, 0) = **mInitialCurrent;
144
145 const Real virtualVoltage =
146 voltage0.real() + **mSeriesResistance * **mInitialCurrent;
147 mVirtualNodes[0]->setInitialVoltage(Complex(virtualVoltage, 0.0));
148}
149
151 (**mIntfVoltage)(0, 0) = 0.0;
152 if (terminalNotGrounded(1))
153 (**mIntfVoltage)(0, 0) =
155 if (terminalNotGrounded(0))
156 (**mIntfVoltage)(0, 0) -=
158 if (!Math::isFinite((**mIntfVoltage)(0, 0)))
159 throw std::runtime_error(
160 "DC pi-line voltage update produced a non-finite value.");
161}
162
164 **mIntfCurrent = mSeriesInductor->intfCurrent();
165 if (!(**mIntfCurrent).allFinite())
166 throw std::runtime_error(
167 "DC pi-line current update produced a non-finite value.");
168}
169
173
175 Attribute<Matrix>::Ptr &leftVector) {
176 mnaCompUpdateVoltage(**leftVector);
177 mnaCompUpdateCurrent(**leftVector);
178}
179
182 AttributeBase::List &modifiedAttributes) {
183 modifiedAttributes.push_back(mRightVector);
184}
185
187 AttributeBase::List &, AttributeBase::List &attributeDependencies,
188 AttributeBase::List &modifiedAttributes,
189 Attribute<Matrix>::Ptr &leftVector) {
190 attributeDependencies.push_back(leftVector);
191 modifiedAttributes.push_back(mIntfVoltage);
192 modifiedAttributes.push_back(mIntfCurrent);
193}
std::vector< Ptr > List
Definition Attribute.h:123
AttributePointer< Attribute< T > > Ptr
Definition Attribute.h:250
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< Real >::Ptr mSeriesResistance
Series resistance [ohm].
void initializeParentFromNodesAndTerminals(Real frequency) override final
void mnaParentAddPreStepDependencies(AttributeBase::List &prevStepDependencies, AttributeBase::List &attributeDependencies, AttributeBase::List &modifiedAttributes) override final
const Attribute< Real >::Ptr mInitialCurrent
Initial series current from terminal 1 to terminal 0 [A].
void mnaCompUpdateVoltage(const Matrix &leftVector) override final
void mnaParentPostStep(Real time, Int timeStepCount, Attribute< Matrix >::Ptr &leftVector) override final
const Attribute< Real >::Ptr mParallelCapacitance
Total terminal-to-ground shunt capacitance [F].
const Attribute< Real >::Ptr mSeriesInductance
Series inductance [H].
void createSubComponents() override final
Constructs and registers MNA subcomponents; called before collectVirtualNodes so virtual nodes exist ...
void mnaParentPreStep(Real time, Int timeStepCount) override final
void setParameters(Real seriesResistance, Real seriesInductance, Real parallelCapacitance=0.0, Real parallelConductance=0.0, Real initialCurrent=0.0)
void mnaCompUpdateCurrent(const Matrix &leftVector) override final
const Attribute< Real >::Ptr mParallelConductance
Total terminal-to-ground shunt conductance [S].
SimPowerComp< Real >::Ptr clone(String name) override final
Returns a modified copy of the component with the given suffix added to the name and without.
void mnaParentAddPostStepDependencies(AttributeBase::List &prevStepDependencies, AttributeBase::List &attributeDependencies, AttributeBase::List &modifiedAttributes, Attribute< Matrix >::Ptr &leftVector) override final
PiLine(String uid, String name, Logger::Level logLevel=Logger::Level::off)
const Attribute< String >::Ptr mName
Human readable name.
String uid()
Returns unique id.
AttributeList::Ptr mAttributes
Attribute List.
spdlog::level::level_enum Level
Definition Logger.h:33
Attribute< Matrix >::Ptr mRightVector
static Real realFromVectorElement(const Matrix &mat, Matrix::Index row)
static bool isFinite(Real value)
Definition MathUtils.cpp:63
static Ptr GND
Definition SimNode.h:35
UInt matrixNodeIndex(UInt nodeIndex)
const Attribute< MatrixVar< Real > >::Ptr mIntfCurrent
SimTerminal< Real >::List mTerminals
void setVirtualNodeNumber(UInt num)
const Attribute< MatrixVar< Real > >::Ptr mIntfVoltage
std::shared_ptr< SimPowerComp< VarType > > Ptr
SimNode< Real >::List mVirtualNodes
Bool terminalNotGrounded(UInt index)
Complex initialSingleVoltage(UInt index)
void setTerminalNumber(UInt num)
Logger::Level mLogLevel
Component logger control for internal variables.
bool mParametersSet
Flag indicating that parameters are set via setParameters() function.
static std::shared_ptr< PiLine > make(Args &&...args)
Definition PtrFactory.h:19
#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:81
std::string String
Definition Definitions.h:65
double Real
Definition Definitions.h:62
int Int
Definition Definitions.h:61
std::complex< Real > Complex
Definition Definitions.h:63
unsigned int UInt
Definition Definitions.h:60