Skip to content

Commit

Permalink
Add new nonlinear diode component
Browse files Browse the repository at this point in the history
+ add .h and .cpp for new nonlinear "Diode" class which uses and inherits from the new "MNANonlinearVariableCompInterface"

* modify "Components.h" to include .h of new diode model
* modify "dpsim/dpsim-models/CMakeLists.txt" to include .cpp of new diode model
* modify "EMTComponents.cpp" to make new diode model usable through pybind

Signed-off-by: Marvin Tollnitsch <marvin.tollnitsch@rwth-aachen.de>
  • Loading branch information
MarvinTollnitschRWTH committed Sep 16, 2024
1 parent 7faf993 commit 3c33e6d
Show file tree
Hide file tree
Showing 5 changed files with 274 additions and 13 deletions.
1 change: 1 addition & 0 deletions dpsim-models/include/dpsim-models/Components.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@
#endif
#include <dpsim-models/EMT/EMT_Ph1_Capacitor.h>
#include <dpsim-models/EMT/EMT_Ph1_CurrentSource.h>
#include <dpsim-models/EMT/EMT_Ph1_Diode.h>
#include <dpsim-models/EMT/EMT_Ph1_Inductor.h>
#include <dpsim-models/EMT/EMT_Ph1_Resistor.h>
#include <dpsim-models/EMT/EMT_Ph1_VoltageSource.h>
Expand Down
82 changes: 82 additions & 0 deletions dpsim-models/include/dpsim-models/EMT/EMT_Ph1_Diode.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/* Copyright 2017-2021 Institute for Automation of Complex Power Systems,
* EONERC, RWTH Aachen University
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*********************************************************************************/

#pragma once

#include <dpsim-models/MNASimPowerComp.h>
#include <dpsim-models/Solver/MNAInterface.h>
//#include <dpsim-models/Solver/MNAVariableCompInterface.h>
#include <dpsim-models/Solver/MNANonlinearVariableCompInterface.h>

namespace CPS {
namespace EMT {
namespace Ph1 {
/// EMT Diode
class Diode : public MNASimPowerComp<Real>,
public SharedFactory<Diode>,
public MNANonlinearVariableCompInterface {
protected:
///TODO: mI_S and mV_T as const CPS::Attribute<Real>::Ptr, also change in
// pybind EMTComponents
Real mI_S = 0.000001;
Real mV_T = 0.027;
Matrix Jacobian = Matrix::Zero(1, 1);
Real itVoltage = 0.;
Real itCurrent = 0.;

public:
/// Defines UID, name, component parameters and logging level
Diode(String uid, String name, Logger::Level logLevel = Logger::Level::off);
/// Defines name, component parameters and logging level
Diode(String name, Logger::Level logLevel = Logger::Level::off)
: Diode(name, name, logLevel) {}

// #### General ####
///
SimPowerComp<Real>::Ptr clone(String name) override;
/// Initializes component from power flow data
void initializeFromNodesAndTerminals(Real frequency) override;

void setParameters(Real, Real);

// #### MNA section ####
/// Initializes internal variables of the component
void mnaCompInitialize(Real omega, Real timeStep,
Attribute<Matrix>::Ptr leftSideVector) override;
/// Stamps system matrix
void mnaCompApplySystemMatrixStamp(SparseMatrixRow &systemMatrix) override;
/// Stamps right side (source) vector
void mnaCompApplyRightSideVectorStamp(Matrix &rightVector) override {
} //No right side vector stamps
/// Update interface voltage from MNA system result
void mnaCompUpdateVoltage(const Matrix &leftVector) override;
/// Update interface current from MNA system result
void mnaCompUpdateCurrent(const Matrix &leftVector) override;
/// MNA pre and post step operations
void mnaCompPreStep(Real time,
Int timeStepCount) override; //No right side vector stamps
void mnaCompPostStep(Real time, Int timeStepCount,
Attribute<Matrix>::Ptr &leftVector) override;
/// add MNA pre and post step dependencies
void
mnaCompAddPostStepDependencies(AttributeBase::List &prevStepDependencies,
AttributeBase::List &attributeDependencies,
AttributeBase::List &modifiedAttributes,
Attribute<Matrix>::Ptr &leftVector) override;

virtual void iterationUpdate(const Matrix &leftVector) override;

virtual bool hasParameterChanged() override { return true; }

void calculateNonlinearFunctionResult() override;

void updateJacobian();
};
} // namespace Ph1
} // namespace EMT
} // namespace CPS
1 change: 1 addition & 0 deletions dpsim-models/src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ list(APPEND MODELS_SOURCES
EMT/EMT_Ph1_VoltageSourceRamp.cpp
EMT/EMT_Ph1_VoltageSourceNorton.cpp
EMT/EMT_Ph1_Switch.cpp
EMT/EMT_Ph1_Diode.cpp

EMT/EMT_Ph3_CurrentSource.cpp
EMT/EMT_Ph3_VoltageSource.cpp
Expand Down
166 changes: 166 additions & 0 deletions dpsim-models/src/EMT/EMT_Ph1_Diode.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
/* Copyright 2017-2021 Institute for Automation of Complex Power Systems,
* EONERC, RWTH Aachen University
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
******************************************************************************/

#include <dpsim-models/EMT/EMT_Ph1_Diode.h>

using namespace CPS;

EMT::Ph1::Diode::Diode(String uid, String name, Logger::Level logLevel)
: MNASimPowerComp<Real>(uid, name, false, false, logLevel) {
mPhaseType = PhaseType::Single;
setTerminalNumber(2);
**mIntfVoltage = Matrix::Zero(1, 1);
**mIntfCurrent = Matrix::Zero(1, 1);
}

void EMT::Ph1::Diode::setParameters(Real I_S, Real V_T) {
mI_S = I_S;
mV_T = V_T;
}

SimPowerComp<Real>::Ptr EMT::Ph1::Diode::clone(String name) {
auto copy = Diode::make(name, mLogLevel);
copy->setParameters(mI_S, mV_T);
return copy;
}

void EMT::Ph1::Diode::initializeFromNodesAndTerminals(Real frequency) {

// IntfVoltage initialization for each phase
MatrixComp vInitABC = Matrix::Zero(1, 1);
vInitABC(0, 0) = RMS3PH_TO_PEAK1PH * initialSingleVoltage(1) -
RMS3PH_TO_PEAK1PH * initialSingleVoltage(0);
(**mIntfVoltage)(0, 0) = vInitABC(0, 0).real();

///FIXME: Initialization should include solving the system once to obtain
// the actual values solving the
// system for the 0th time step. As of now abnormal current
// values for the 0th time step are to be expected.

(**mIntfCurrent)(0, 0) = mI_S * (expf((**mIntfVoltage)(0, 0) / mV_T) - 1.);

SPDLOG_LOGGER_INFO(mSLog,
"\n--- Initialization from powerflow ---"
"\nVoltage across: {:f}"
"\nCurrent: {:f}"
"\nTerminal 0 voltage: {:f}"
"\nTerminal 1 voltage: {:f}"
"\n--- Initialization from powerflow finished ---",
(**mIntfVoltage)(0, 0), (**mIntfCurrent)(0, 0),
initialSingleVoltage(0).real(),
initialSingleVoltage(1).real());
}

void EMT::Ph1::Diode::mnaCompInitialize(Real omega, Real timeStep,
Attribute<Matrix>::Ptr leftVector) {

updateMatrixNodeIndices();

**mRightVector = Matrix::Zero(leftVector->get().rows(), 1);
**mNonlinearFunctionStamp = Matrix::Zero(leftVector->get().rows(), 1);
calculateNonlinearFunctionResult();
updateJacobian();

mMnaTasks.push_back(std::make_shared<MnaPostStep>(*this, leftVector));
}

void EMT::Ph1::Diode::mnaCompApplySystemMatrixStamp(
SparseMatrixRow &systemMatrix) {
// Set diagonal entries
if (terminalNotGrounded(0)) {
// set upper left block, 3x3 entries
Math::addToMatrixElement(systemMatrix, matrixNodeIndex(0, 0),
matrixNodeIndex(0, 0), Jacobian(0, 0));
}
if (terminalNotGrounded(1)) {
// set buttom right block, 3x3 entries
Math::addToMatrixElement(systemMatrix, matrixNodeIndex(1, 0),
matrixNodeIndex(1, 0), Jacobian(0, 0));
}
// Set off diagonal blocks, 2x3x3 entries
if (terminalNotGrounded(0) && terminalNotGrounded(1)) {
Math::addToMatrixElement(systemMatrix, matrixNodeIndex(0, 0),
matrixNodeIndex(1, 0), -Jacobian(0, 0));

Math::addToMatrixElement(systemMatrix, matrixNodeIndex(1, 0),
matrixNodeIndex(0, 0), -Jacobian(0, 0));
}
}

void EMT::Ph1::Diode::mnaCompAddPostStepDependencies(
AttributeBase::List &prevStepDependencies,
AttributeBase::List &attributeDependencies,
AttributeBase::List &modifiedAttributes,
Attribute<Matrix>::Ptr &leftVector) {
attributeDependencies.push_back(leftVector);
modifiedAttributes.push_back(attribute("v_intf"));
modifiedAttributes.push_back(attribute("i_intf"));
}

void EMT::Ph1::Diode::mnaCompPreStep(Real time, Int timeStepCount) {
mnaCompApplyRightSideVectorStamp(**mRightVector);
}

void EMT::Ph1::Diode::mnaCompPostStep(Real time, Int timeStepCount,
Attribute<Matrix>::Ptr &leftVector) {
mnaUpdateVoltage(**leftVector);
mnaUpdateCurrent(**leftVector);
}

void EMT::Ph1::Diode::mnaCompUpdateVoltage(const Matrix &leftVector) {
// v1 - v0
**mIntfVoltage = Matrix::Zero(3, 1);
if (terminalNotGrounded(1)) {
(**mIntfVoltage)(0, 0) =
Math::realFromVectorElement(leftVector, matrixNodeIndex(1, 0));
}
if (terminalNotGrounded(0)) {
(**mIntfVoltage)(0, 0) =
(**mIntfVoltage)(0, 0) -
Math::realFromVectorElement(leftVector, matrixNodeIndex(0, 0));
}
}

void EMT::Ph1::Diode::mnaCompUpdateCurrent(const Matrix &leftVector) {
(**mIntfCurrent)(0, 0) = mI_S * (expf((**mIntfVoltage)(0, 0) / mV_T) - 1.);
}

void EMT::Ph1::Diode::iterationUpdate(const Matrix &leftVector) {
//Update phase voltages
if (terminalNotGrounded(1)) {
(**mIntfVoltage)(0, 0) =
Math::realFromVectorElement(leftVector, matrixNodeIndex(1, 0));
}
if (terminalNotGrounded(0)) {
(**mIntfVoltage)(0, 0) =
(**mIntfVoltage)(0, 0) -
Math::realFromVectorElement(leftVector, matrixNodeIndex(0, 0));
}

calculateNonlinearFunctionResult();

updateJacobian();
}

void EMT::Ph1::Diode::calculateNonlinearFunctionResult() {

(**mIntfCurrent)(0, 0) = mI_S * (expf((**mIntfVoltage)(0, 0) / mV_T) - 1.);

if (terminalNotGrounded(1)) {
Math::setVectorElement(**mNonlinearFunctionStamp, matrixNodeIndex(1, 0),
(**mIntfCurrent)(0, 0));
}
if (terminalNotGrounded(0)) {
Math::setVectorElement(**mNonlinearFunctionStamp, matrixNodeIndex(0, 0),
-(**mIntfCurrent)(0, 0));
}
}

void EMT::Ph1::Diode::updateJacobian() {
Jacobian(0, 0) = (mI_S / mV_T) * expf((**mIntfVoltage)(0, 0) / mV_T);
}
37 changes: 24 additions & 13 deletions dpsim/src/pybind/EMTComponents.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,13 +102,27 @@ void addEMTPh1Components(py::module_ mEMTPh1) {
.def("connect", &CPS::EMT::Ph1::Inductor::connect)
.def_property("L", createAttributeGetter<CPS::Real>("L"),
createAttributeSetter<CPS::Real>("L"));

py::class_<CPS::EMT::Ph1::Switch, std::shared_ptr<CPS::EMT::Ph1::Switch>, CPS::SimPowerComp<CPS::Real>, CPS::Base::Ph1::Switch>(mEMTPh1, "Switch", py::multiple_inheritance())
.def(py::init<std::string, CPS::Logger::Level>(), "name"_a, "loglevel"_a = CPS::Logger::Level::off)
.def("set_parameters", &CPS::EMT::Ph1::Switch::setParameters, "open_resistance"_a, "closed_resistance"_a, "closed"_a = false) // cppcheck-suppress assignBoolToPointer

py::class_<CPS::EMT::Ph1::Switch, std::shared_ptr<CPS::EMT::Ph1::Switch>,
CPS::SimPowerComp<CPS::Real>, CPS::Base::Ph1::Switch>(
mEMTPh1, "Switch", py::multiple_inheritance())
.def(py::init<std::string, CPS::Logger::Level>(), "name"_a,
"loglevel"_a = CPS::Logger::Level::off)
.def("set_parameters", &CPS::EMT::Ph1::Switch::setParameters,
"open_resistance"_a, "closed_resistance"_a,
"closed"_a = false) // cppcheck-suppress assignBoolToPointer
.def("open", &CPS::EMT::Ph1::Switch::open)
.def("close", &CPS::EMT::Ph1::Switch::close)
.def("connect", &CPS::EMT::Ph1::Switch::connect);
.def("connect", &CPS::EMT::Ph1::Switch::connect);

py::class_<CPS::EMT::Ph1::Diode, std::shared_ptr<CPS::EMT::Ph1::Diode>,
CPS::SimPowerComp<CPS::Real>>(mEMTPh1, "Diode",
py::multiple_inheritance())
.def(py::init<std::string>())
.def(py::init<std::string, CPS::Logger::Level>())
.def("set_parameters", &CPS::EMT::Ph1::Diode::setParameters, "I_S"_a,
"V_T"_a)
.def("connect", &CPS::EMT::Ph1::Diode::connect);
}

void addEMTPh3Components(py::module_ mEMTPh3) {
Expand All @@ -128,15 +142,13 @@ void addEMTPh3Components(py::module_ mEMTPh3) {
.def_property("f_src", createAttributeGetter<CPS::Real>("f_src"),
createAttributeSetter<CPS::Real>("f_src"));


py::class_<CPS::EMT::Ph3::Resistor, std::shared_ptr<CPS::EMT::Ph3::Resistor>,
CPS::SimPowerComp<CPS::Real>>(mEMTPh3, "Resistor",
py::multiple_inheritance())
.def(py::init<std::string>())
.def(py::init<std::string, CPS::Logger::Level>())
.def("set_parameters", &CPS::EMT::Ph3::Resistor::setParameters, "R"_a)
.def("connect", &CPS::EMT::Ph3::Resistor::connect);


py::class_<CPS::EMT::Ph3::Capacitor,
std::shared_ptr<CPS::EMT::Ph3::Capacitor>,
Expand Down Expand Up @@ -194,7 +206,7 @@ void addEMTPh3Components(py::module_ mEMTPh3) {
"loglevel"_a = CPS::Logger::Level::off)
.def("set_parameters", &CPS::EMT::Ph3::Switch::setParameters,
"open_resistance"_a, "closed_resistance"_a,
// cppcheck-suppress assignBoolToPointer
// cppcheck-suppress assignBoolToPointer
"closed"_a = false)
.def("open", &CPS::EMT::Ph3::Switch::openSwitch)
.def("close", &CPS::EMT::Ph3::Switch::closeSwitch)
Expand Down Expand Up @@ -369,7 +381,7 @@ void addEMTPh3Components(py::module_ mEMTPh3) {
"loglevel"_a = CPS::Logger::Level::off)
.def(py::init<std::string, std::string, CPS::Logger::Level, CPS::Bool>(),
"uid"_a, "name"_a, "loglevel"_a = CPS::Logger::Level::off,
// cppcheck-suppress assignBoolToPointer
// cppcheck-suppress assignBoolToPointer
"with_trafo"_a = false)
.def("set_parameters",
&CPS::EMT::Ph3::AvVoltageSourceInverterDQ::setParameters,
Expand Down Expand Up @@ -402,9 +414,8 @@ void addEMTPh3Components(py::module_ mEMTPh3) {
"loglevel"_a = CPS::Logger::Level::off)
.def(py::init<std::string, std::string, CPS::Logger::Level, CPS::Bool>(),
"uid"_a, "name"_a, "loglevel"_a = CPS::Logger::Level::off,
// cppcheck-suppress assignBoolToPointer
"with_resistive_losses"_a =
false)
// cppcheck-suppress assignBoolToPointer
"with_resistive_losses"_a = false)
.def("set_parameters", &CPS::EMT::Ph3::Transformer::setParameters,
"nom_voltage_end_1"_a, "nom_voltage_end_2"_a, "rated_power"_a,
"ratio_abs"_a, "ratio_phase"_a, "resistance"_a, "inductance"_a)
Expand All @@ -428,7 +439,7 @@ void addEMTPh3Components(py::module_ mEMTPh3) {
"loglevel"_a = CPS::Logger::Level::off)
.def("set_parameters", &CPS::EMT::Ph3::SeriesSwitch::setParameters,
"open_resistance"_a, "closed_resistance"_a,
// cppcheck-suppress assignBoolToPointer
// cppcheck-suppress assignBoolToPointer
"closed"_a = false)
.def("open", &CPS::EMT::Ph3::SeriesSwitch::open)
.def("close", &CPS::EMT::Ph3::SeriesSwitch::close)
Expand Down

0 comments on commit 3c33e6d

Please sign in to comment.