Commit a7621c94 authored by Markus Mirz's avatar Markus Mirz
Browse files

add sst model and fix powerflow

parent 2b04fccf
......@@ -31,6 +31,7 @@
#include <cps/SP/SP_Ph1_PiLine.h>
#include <cps/SP/SP_Ph1_Shunt.h>
#include <cps/SP/SP_Ph1_Transformer.h>
#include <cps/SP/SP_Ph1_SolidStateTransformer.h>
#include <cps/SP/SP_Ph1_Load.h>
#include <cps/SP/SP_Ph1_SynchronGenerator.h>
#include <cps/SP/SP_Ph1_PQNode.h>
......
......@@ -23,9 +23,6 @@
#include <cps/PowerComponent.h>
#include <cps/Solver/PFSolverInterfaceBus.h>
#include <cps/SP/SP_Ph1_PVNode.h>
#include <cps/SP/SP_Ph1_PQNode.h>
#include <cps/SP/SP_Ph1_VDNode.h>
#include <cps/Solver/MNAInterface.h>
#include <cps/Solver/DAEInterface.h>
......
/**
* @file
* @author Junjie Zhang <junjie.zhang@eonerc.rwth-aachen.de>
* @copyright 2017-2019, Institute for Automation of Complex Power Systems, EONERC
*
* CPowerSystems
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/
#pragma once
#include <cps/PowerComponent.h>
#include <cps/Solver/MNAInterface.h>
#include <cps/SP/SP_Ph1_Load.h>
namespace CPS {
namespace SP { namespace Ph1 {
/* \brief Ideal solid state transformer
* Modelled as two loads at each side.
* Demands Pref, Q1 from side 1, and generate Pref, Q2 to side 2.
* Depends on the actual condition, values can be negative
*/
class SolidStateTransformer :
public PowerComponent<Complex>,
public SharedFactory<SolidStateTransformer>,
public MNAInterface{
private:
///
std::shared_ptr<SP::Ph1::Load> mSubLoadSide1;
///
std::shared_ptr<SP::Ph1::Load> mSubLoadSide2;
/// Rated Apparent Power [VA]
Real mRatedPower = 0;
/// Power [watt]
Real mPref = std::numeric_limits<double>::infinity();
/// Active power at secondary side [watt]
Real mP2 = std::numeric_limits<double>::infinity();
/// Reactive power at primary side [var]
Real mQ1ref;
/// Reactive power at secondary side [var]
Real mQ2ref;
/// Nominal voltage of primary side [V]
Real mNominalVoltageEnd1;
/// Nominal voltage of secondary side [V]
Real mNominalVoltageEnd2;
// Per Unit values
/// Active power at primary side [p.u.]
Real mPref_perUnit;
/// Active power at secondary side [p.u.]
Real mP2_perUnit;
/// Reactive power at primary side [p.u.]
Real mQ1ref_perUnit;
/// Reactive power at secondary side [p.u.]
Real mQ2ref_perUnit;
public:
///
SolidStateTransformer(String uid, String name, Logger::Level logLevel = Logger::Level::off);
///
SolidStateTransformer(String name, Logger::Level logLevel = Logger::Level::off)
:SolidStateTransformer(name, name, logLevel) {};
///
PowerComponent<Complex>::Ptr clone(String name);
// #### Power Flow Section ####
/// Initializes component
void initializeFromPowerflow(Real frequency);
///
void setParameters(Real nomV1, Real nomV2, Real Pref, Real Q1ref, Real Q2ref);
///
void calculatePerUnitParameters(Real baseApparentPower, Real baseOmega);
///
Complex getNodalInjection(CPS::TopologicalNode::Ptr node);
// // #### MNA Section ####
// /// Initializes internal variables of the component
// void mnaInitialize(Real omega, Real timeStep, Attribute<Matrix>::Ptr leftVector);
// /// Stamps system matrix
// void mnaApplySystemMatrixStamp(Matrix& systemMatrix);
// /// Updates internal current variable of the component
// void mnaUpdateCurrent(const Matrix& leftVector);
// /// Updates internal voltage variable of the component
// void mnaUpdateVoltage(const Matrix& leftVector);
};
}
}
}
\ No newline at end of file
......@@ -98,6 +98,7 @@ list(APPEND SOURCES
SP/SP_Ph1_PiLine.cpp
SP/SP_Ph1_Load.cpp
SP/SP_Ph1_Transformer.cpp
SP/SP_Ph1_SolidStateTransformer.cpp
SP/SP_Ph1_Shunt.cpp
SP/SP_Ph1_SynchronGenerator.cpp
SP/SP_Ph1_PQNode.cpp
......
......@@ -56,13 +56,13 @@ void SP::Ph1::PiLine::setParameters(Real resistance, Real inductance, Real capac
mSeriesInd = inductance;
mSLog->info("Resistance={} [Ohm] Inductance={} [H]", mSeriesRes, mNominalOmega*mSeriesInd);
if(capacitance >= 0){
if(capacitance > 0){
mParallelCap = capacitance;
}else{
mParallelCap = 1e-12;
mSLog->warn("Zero value for Capacitance, setting default value of C={} [F]", mParallelCap);
}
if(conductance >= 0){
if(conductance > 0){
mParallelCond = conductance;
}else{
if (mBehaviour == Behaviour::Initialization)
......
/**
* @file
* @author Junjie Zhang <junjie.zhang@eonerc.rwth-aachen.de>
* @copyright 2017-2019, Institute for Automation of Complex Power Systems, EONERC
*
* CPowerSystems
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/
#include <cps/SP/SP_Ph1_SolidStateTransformer.h>
using namespace CPS;
SP::Ph1::SolidStateTransformer::SolidStateTransformer(String uid, String name, Logger::Level logLevel)
: PowerComponent<Complex>(uid, name, logLevel) {
mSLog->info("Create {} of type {}", mName, this->type());
mSLog->flush();
mIntfVoltage = MatrixComp::Zero(1, 1);
mIntfCurrent = MatrixComp::Zero(1, 1);
setTerminalNumber(2);
addAttribute<Real>("P_ref", &mPref, Flags::read | Flags::write);
addAttribute<Real>("Q1_ref", &mQ1ref, Flags::read | Flags::write);
addAttribute<Real>("Q2_ref", &mQ2ref, Flags::read | Flags::write);
};
PowerComponent<Complex>::Ptr SP::Ph1::SolidStateTransformer::clone(String name) {
// everything set by initializeFromPowerflow
return SolidStateTransformer::make(name, mLogLevel);
}
void SP::Ph1::SolidStateTransformer::setParameters(Real nomV1, Real nomV2, Real Pref, Real Q1ref, Real Q2ref){
mNominalVoltageEnd1 = nomV1;
mNominalVoltageEnd2 = nomV2;
mPref = Pref;
mQ1ref = Q1ref;
mQ2ref = Q2ref;
mP2 = -1 * std::sqrt(Pref * Pref + Q1ref * Q1ref - Q2ref * Q2ref);
}
void SP::Ph1::SolidStateTransformer::initializeFromPowerflow(Real frequency){
checkForUnconnectedTerminals();
if(std::isinf(mP2)){
std::stringstream ss;
ss << "SST >>" << this->name() << ": infinite or nan values. Or initialized before setting parameters.";
throw std::invalid_argument(ss.str());
}
if ((mPref * mP2) > 0){
throw std::invalid_argument("power at primary and secondary sides should be opposite");
}
mSubLoadSide1 = Load::make(mName + "_subLoad1", mLogLevel);
mSubLoadSide1->setParameters(mPref, mQ1ref, mNominalVoltageEnd1);
mSubLoadSide2 = Load::make(mName + "_subLoad2", mLogLevel);
mSubLoadSide2->setParameters(mP2, mQ2ref, mNominalVoltageEnd2);
mSubLoadSide1->connect({mTerminals[0]->node()});
mSubLoadSide2->connect({mTerminals[1]->node()});
mSLog->info(
"\n--- Initialization from powerflow ---"
"\nTerminal 0 power flow: {:s} VA"
"\nTerminal 1 power flow: {:s} VA"
"\n--- Initialization from powerflow finished ---",
Logger::complexToString(Complex(mPref,mQ1ref)),
Logger::complexToString(Complex(mP2,mQ2ref)));
}
void SP::Ph1::SolidStateTransformer::calculatePerUnitParameters(Real baseApparentPower, Real baseOmega) {
mPref_perUnit = mPref / baseApparentPower;
mP2_perUnit = mP2 / baseApparentPower;
mQ1ref_perUnit = mQ1ref / baseApparentPower;
mQ2ref_perUnit = mQ2ref / baseApparentPower;
mSubLoadSide1->calculatePerUnitParameters(baseApparentPower, baseOmega);
mSubLoadSide2->calculatePerUnitParameters(baseApparentPower, baseOmega);
mSLog->info(
"\n#### Calculate Per Unit Parameters for {}"
"\nTerminal 0 power flow: {:s} p.u."
"\nTerminal 1 power flow: {:s} p.u."
"\n#### Calculate Per Unit Parameters finished ---",
mName,
Logger::complexToString(Complex(mPref_perUnit, mQ1ref_perUnit)),
Logger::complexToString(Complex(mP2_perUnit, mQ2ref_perUnit)));
}
Complex SP::Ph1::SolidStateTransformer::getNodalInjection(CPS::TopologicalNode::Ptr node) {
if (node->name() == mTerminals[0]->node()->name())
{
mSLog->info(
"\n#### get nodal injection for primary side"
"\nreturned {:s} p.u.",
Logger::complexToString(Complex(mPref_perUnit, mQ1ref_perUnit)));
return Complex(mPref_perUnit, mQ1ref_perUnit);
}
else if (node->name() == mTerminals[1]->node()->name())
{
mSLog->info(
"\n#### get nodal injection for secondary side"
"\nreturned {:s} p.u.",
Logger::complexToString(Complex(mP2_perUnit, mQ2ref_perUnit)));
return Complex(mP2_perUnit, mQ2ref_perUnit);
}
else{
throw std::invalid_argument("Failed to process nodal power injection of Solid State Transformer"
+ this->name());
}
}
\ No newline at end of file
......@@ -122,12 +122,17 @@ void SP::Ph1::Transformer::calculatePerUnitParameters(Real baseApparentPower, Re
// set snubber resistance
if (mBehaviour == Behaviour::Initialization) {
Real snubberResistance = 1e6;
Real snubberResistance = 1e3;
mSubSnubResistor = std::make_shared<SP::Ph1::Resistor>(mUID + "_snub_res", mName + "_snub_res", mLogLevel);
mSubSnubResistor->setParameters(snubberResistance);
mSubSnubResistor->connect({ node(1), SP::Node::GND });
mSubSnubResistor->initializeFromPowerflow(mBaseOmega);
}
if (mSubSnubResistor) {
mSubSnubResistor->setBaseVoltage(mBaseVoltage);
mSubSnubResistor->calculatePerUnitParameters(baseApparentPower);
}
mSLog->info("Leakage Impedance Per Unit={} [Ohm] ", mLeakagePerUnit);
}
......@@ -160,9 +165,6 @@ void SP::Ph1::Transformer::pfApplyAdmittanceMatrixStamp(SparseMatrixCompRow & Y)
Y.coeffRef(this->simNode(1), this->simNode(1)) += mY_element.coeff(1, 1);
Y.coeffRef(this->simNode(1), this->simNode(0)) += mY_element.coeff(1, 0);
if(mSubSnubResistor)
mSubSnubResistor->pfApplyAdmittanceMatrixStamp(Y);
mSLog->info("#### Y matrix stamping: {}", mY_element);
}
......
......@@ -72,6 +72,8 @@ namespace DPsim {
CPS::SystemTopology mSystem;
/// Vector of transformer components
std::vector<std::shared_ptr<CPS::SP::Ph1::Transformer>> mTransformers;
/// Vector of solid state transformer components
std::vector<std::shared_ptr<CPS::SP::Ph1::SolidStateTransformer>> mSolidStateTransformers;
/// Vector of synchronous generator components
std::vector<std::shared_ptr<CPS::SP::Ph1::SynchronGenerator>> mSynchronGenerators;
/// Vector of load components
......
......@@ -49,6 +49,9 @@ void PFSolver::initialize(){
mExternalGrids.push_back(extnet);
else if (std::shared_ptr<CPS::SP::Ph1::Shunt> shunt = std::dynamic_pointer_cast<CPS::SP::Ph1::Shunt>(comp))
mShunts.push_back(shunt);
else if(std::shared_ptr<CPS::SP::Ph1::SolidStateTransformer> sst = std::dynamic_pointer_cast<CPS::SP::Ph1::SolidStateTransformer>(comp)){
mSolidStateTransformers.push_back(sst);
}
}
setBaseApparentPower();
......@@ -93,6 +96,9 @@ void PFSolver::initializeComponents(){
for(auto gen : mSynchronGenerators) {
gen->calculatePerUnitParameters(mBaseApparentPower, mSystem.mSystemOmega);
}
for(auto sst : mSolidStateTransformers){
sst->calculatePerUnitParameters(mBaseApparentPower, mSystem.mSystemOmega);
}
}
......@@ -147,6 +153,10 @@ void PFSolver::determinePFBusType() {
if (extnet->mPowerflowBusType == CPS::PowerflowBusType::VD) {
connectedVD = true;
}
else if (extnet->mPowerflowBusType == CPS::PowerflowBusType::PV) {
connectedPV = true;
}
}
}
......
......@@ -53,6 +53,11 @@ void PFSolverPowerPolar::generateInitialSolution(Real time, bool keep_last_solut
sol_P(pq->simNode()) -= load->attribute<CPS::Real>("P_pu")->get();
sol_Q(pq->simNode()) -= load->attribute<CPS::Real>("Q_pu")->get();
}
else if(std::shared_ptr<CPS::SP::Ph1::SolidStateTransformer> sst =
std::dynamic_pointer_cast<CPS::SP::Ph1::SolidStateTransformer>(comp)){
sol_P(pq->simNode()) -= sst->getNodalInjection(pq).real();
sol_Q(pq->simNode()) -= sst->getNodalInjection(pq).imag();
}
sol_S_complex(pq->simNode()) = CPS::Complex(sol_P[pq->simNode()], sol_Q[pq->simNode()]);
}
}
......@@ -70,6 +75,11 @@ void PFSolverPowerPolar::generateInitialSolution(Real time, bool keep_last_solut
else if (std::shared_ptr<CPS::SP::Ph1::Load> load = std::dynamic_pointer_cast<CPS::SP::Ph1::Load>(comp)) {
sol_P(pv->simNode()) -= load->attribute<CPS::Real>("P_pu")->get();
}
else if (std::shared_ptr<CPS::SP::Ph1::externalGridInjection> extnet =
std::dynamic_pointer_cast<CPS::SP::Ph1::externalGridInjection>(comp)) {
sol_P(pv->simNode()) += extnet->attribute<CPS::Real>("p_inj")->get() / mBaseApparentPower;
sol_V(pv->simNode()) = extnet->attribute<CPS::Real>("V_set_pu")->get();
}
sol_S_complex(pv->simNode()) = CPS::Complex(sol_P[pv->simNode()], sol_Q[pv->simNode()]);
sol_V_complex(pv->simNode()) = CPS::Complex(sol_V[pv->simNode()], sol_D[pv->simNode()]);
}
......@@ -369,8 +379,12 @@ void PFSolverPowerPolar::calculatePAndQAtSlackBus() {
S = sol_Vcx(k) * conj(I);
sol_P(k) = S.real();
sol_Q(k) = S.imag();
for(auto extnet : mExternalGrids)
extnet->updatePowerInjection(S*mBaseApparentPower);
for(auto extnet : mExternalGrids){
if(extnet->mPowerflowBusType==CPS::PowerflowBusType::VD){
extnet->updatePowerInjection(S*mBaseApparentPower);
break;
}
}
}
}
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment