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

Merge branch 'powerflow-development' into 'master'

Powerflow development

See merge request acs/public/simulation/dpsim!136
parents 7c60d93b f282acae
......@@ -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>
namespace CPS {
......@@ -33,29 +30,49 @@ namespace CPS {
namespace SP {
namespace Ph1 {
class SynchronGenerator : public PowerComponent<Complex>,
public SharedFactory<SynchronGenerator>, public PFSolverInterfaceBus {
class SynchronGenerator :
public PowerComponent<Complex>,
public SharedFactory<SynchronGenerator>,
public PFSolverInterfaceBus {
private:
Real mRatedU;
Real mRatedS;
/// Rate apparent power [VA]
Real mRatedApparentPower;
/// Rated voltage [V]
Real mRatedVoltage;
public:
using PowerComponent<Complex>::PowerComponent;
/// Active power set point of the machine [W]
Real mSetPointActivePower;
/// Voltage set point of the machine [V]
Real mSetPointVoltage;
/// Maximum reactive power [VAr]
Real mMaximumReactivePower;
/// Defines UID, name, component parameters and logging level
SynchronGenerator(String uid, String name,
PowerflowBusType powerflowBusType,
Logger::Level logLevel = Logger::Level::off);
/// Base apparent power[VA]
Real mBaseApparentPower;
/// Base omega [1/s]
Real mBaseOmega;
/// Base voltage [V]
Real mBaseVoltage;
/// Active power set point of the machine [pu]
Real mSetPointActivePowerPerUnit;
/// Voltage set point of the machine [pu]
Real mSetPointVoltagePerUnit;
SynchronGenerator(String uid, String name, Real power,
Real voltageSetPoint,PowerflowBusType powerflowBusType,
Logger::Level logLevel = Logger::Level::off);
SynchronGenerator(String uid, String name, Real power, Real maxQ, Real voltageSetPoint,
Real ratedU, Real ratedS, PowerflowBusType powerflowBusType,
Logger::Level logLevel = Logger::Level::off);
public:
/// Defines UID, name and logging level
SynchronGenerator(String uid, String name, Logger::Level logLevel = Logger::Level::off);
/// Defines name and logging level
SynchronGenerator(String name, Logger::Level logLevel = Logger::Level::off)
: SynchronGenerator(name, name, logLevel) { }
/// Setter for synchronous generator parameters
void setParameters(Real ratedApparentPower, Real ratedVoltage, Real setPointActivePower, Real setPointVoltage, Real maximumReactivePower, PowerflowBusType powerflowBusType);
// #### Powerflow section ####
/// Set base voltage
void setBaseVoltage(Real baseVoltage);
/// Initializes component from power flow data
void calculatePerUnitParameters(Real baseApparentPower, Real baseOmega);
/// Modify powerflow bus type
void modifyPowerFlowBusType(PowerflowBusType powerflowBusType) override;
};
......
......@@ -314,6 +314,19 @@ Component::Ptr Reader::mapEnergyConsumer(EnergyConsumer* consumer) {
}
else if (mDomain == Domain::SP) {
auto load = std::make_shared<SP::Ph1::Load>(consumer->mRID, consumer->name, mComponentLogLevel);
// TODO: Use EnergyConsumer.P and EnergyConsumer.Q if available, overwrite if existent SvPowerFlow data
/*
Real p = 0;
Real q = 0;
if (consumer->p.value){
p = unitValue(consumer->p.value,UnitMultiplier::M);
}
if (consumer->q.value){
q = unitValue(consumer->q.value,UnitMultiplier::M);
}*/
// P and Q values will be set according to SvPowerFlow data
load->setParameters(0, 0, 0);
load->modifyPowerFlowBusType(PowerflowBusType::PQ); // for powerflow solver set as PQ component as default
return load;
......@@ -551,28 +564,39 @@ Component::Ptr Reader::mapSynchronousMachine(SynchronousMachine* machine) {
for (auto syncGen : genUnit->RotatingMachine)
{
if (syncGen->mRID == machine->mRID){
// Check whether relevant input data are set, otherwise set default values
Real setPointActivePower = 0;
Real setPointVoltage = 0;
Real maximumReactivePower = 1e12;
try{
mSLog->info(" InitialP={}", (float)genUnit->initialP.value);
//mSLog->info("InitialP {}", genUnit->initialP.value);
setPointActivePower = unitValue(genUnit->initialP.value, UnitMultiplier::M);
mSLog->info(" setPointActivePower={}", setPointActivePower);
}catch(ReadingUninitializedField* e){
genUnit->initialP.value = 0 ;
std::cerr << "Uninitalized InitialP for GeneratingUnit " << genUnit->name << ".Setting default value of " << genUnit->initialP.value << std::endl;
std::cerr << "Uninitalized setPointActivePower for GeneratingUnit " << machine->name << ". Using default value of " << setPointActivePower << std::endl;
}
if (machine->RegulatingControl) {
setPointVoltage = unitValue(machine->RegulatingControl->targetValue.value, UnitMultiplier::k);
mSLog->info(" setPointVoltage={}", setPointVoltage);
} else {
std::cerr << "Uninitalized setPointVoltage for GeneratingUnit " << machine->name << ". Using default value of " << setPointVoltage << std::endl;
}
try{
mSLog->info(" maxQ={}", (float)machine->maxQ.value);
maximumReactivePower = unitValue(machine->maxQ.value, UnitMultiplier::M);
mSLog->info(" maximumReactivePower={}", maximumReactivePower);
}catch(ReadingUninitializedField* e){
machine->maxQ.value = 1e12;
std::cerr << "Uninitalized maxQ for GeneratingUnit " << genUnit->name << ".Setting default value of " << machine->maxQ.value << std::endl;
std::cerr << "Uninitalized maximumReactivePower for GeneratingUnit " << machine->name << ". Using default value of " << maximumReactivePower << std::endl;
}
return std::make_shared<SP::Ph1::SynchronGenerator>
(machine->mRID, machine->name, unitValue(genUnit->initialP.value, UnitMultiplier::M),
unitValue(machine->maxQ.value, UnitMultiplier::M),
unitValue(machine->RegulatingControl->targetValue.value, UnitMultiplier::k),
auto gen = std::make_shared<SP::Ph1::SynchronGenerator>(machine->mRID, machine->name, mComponentLogLevel);
gen->setParameters(unitValue(machine->ratedS.value, UnitMultiplier::M),
unitValue(machine->ratedU.value, UnitMultiplier::k),
unitValue(machine->ratedS.value, UnitMultiplier::M),
PowerflowBusType::PV, mComponentLogLevel);
setPointActivePower,
setPointVoltage,
maximumReactivePower,
PowerflowBusType::PV);
gen->setBaseVoltage(unitValue(machine->ratedU.value, UnitMultiplier::k));
return gen;
}
}
......@@ -580,7 +604,7 @@ Component::Ptr Reader::mapSynchronousMachine(SynchronousMachine* machine) {
}
mSLog->info("no corresponding initial power for {}", machine->name);
return std::make_shared<SP::Ph1::SynchronGenerator>(machine->mRID, machine->name,PowerflowBusType::PV, mComponentLogLevel);
return std::make_shared<SP::Ph1::SynchronGenerator>(machine->mRID, machine->name, mComponentLogLevel);
}
else {
return std::make_shared<DP::Ph1::SynchronGeneratorIdeal>(machine->mRID, machine->name, mComponentLogLevel);
......
......@@ -23,56 +23,62 @@
using namespace CPS;
SP::Ph1::SynchronGenerator::SynchronGenerator(String uid, String name,
PowerflowBusType powerflowBusType,
Logger::Level logLevel) : PowerComponent<Complex>(uid, name, logLevel) {
SP::Ph1::SynchronGenerator::SynchronGenerator(String uid, String name, Logger::Level logLevel)
: PowerComponent<Complex>(uid, name, logLevel) {
mSLog->info("Create {} of type {}", name, this->type());
mSLog->flush();
setTerminalNumber(1);
mPowerflowBusType = powerflowBusType;
mSLog->info("Create {} of type {}", name, this->type());
addAttribute<Real>("P_set", &mSetPointActivePower, Flags::read | Flags::write);
addAttribute<Real>("V_set", &mSetPointVoltage, Flags::read | Flags::write);
addAttribute<Real>("P_set_pu", &mSetPointActivePowerPerUnit, Flags::read | Flags::write);
addAttribute<Real>("V_set_pu", &mSetPointVoltagePerUnit, Flags::read | Flags::write);
};
SP::Ph1::SynchronGenerator::SynchronGenerator(String uid, String name, Real power, Real maxQ,
Real vSetPoint, Real ratedU, Real ratedS, PowerflowBusType powerflowBusType, Logger::Level logLevel)
: SynchronGenerator(uid, name, powerflowBusType, logLevel){
mRatedS = ratedS;
mRatedU = ratedU;
void SP::Ph1::SynchronGenerator::setParameters(Real ratedApparentPower, Real ratedVoltage, Real setPointActivePower, Real setPointVoltage, Real maximumReactivePower, PowerflowBusType powerflowBusType) {
mRatedApparentPower = ratedApparentPower;
mRatedVoltage = ratedVoltage;
mSetPointActivePower = setPointActivePower;
mSetPointVoltage = setPointVoltage;
mMaximumReactivePower = maximumReactivePower;
mPowerflowBusType = powerflowBusType;
switch (powerflowBusType)
{
case CPS::PowerflowBusType::PV:
mSLog->info("Create PVNode as member of {}.", name);
mPV = std::make_shared<PVNode>(uid, name, power, vSetPoint, maxQ, ratedU, ratedS, logLevel);
mSLog->info("Power={} [W] Voltage={} [pu]", power, vSetPoint / ratedU);
break;
case CPS::PowerflowBusType::PQ:
mSLog->info("Setting Synchronous Generator as PQNode is currently not supported.");
break;
case CPS::PowerflowBusType::VD:
mSLog->info("Create VDNode as member of {}.", name);
mVD = std::make_shared<VDNode>(uid, name, vSetPoint / ratedU, logLevel);
mSLog->info("Power={} [W] Voltage={} [pu]", power, vSetPoint);
break;
default:
throw std::invalid_argument(" Invalid power flow bus type ");
break;
}
};
mSLog->info("Rated Apparent Power={} [VA] Rated Voltage={} [V]", mRatedApparentPower, mRatedVoltage);
mSLog->info("Active Power Set Point={} [W] Voltage Set Point={} [V]", mSetPointActivePower, mSetPointVoltage);
mSLog->info("Maximum Reactive Power={} [VAr]", mMaximumReactivePower);
mSLog->flush();
}
// #### Powerflow section ####
void SP::Ph1::SynchronGenerator::setBaseVoltage(Real baseVoltage) {
mBaseVoltage = baseVoltage;
}
void SP::Ph1::SynchronGenerator::modifyPowerFlowBusType(PowerflowBusType powerflowBusType) {
void SP::Ph1::SynchronGenerator::calculatePerUnitParameters(Real baseApparentPower, Real baseOmega) {
mSLog->info("#### Calculate Per Unit Parameters for {}", mName);
mBaseApparentPower = baseApparentPower;
mBaseOmega = baseOmega;
mSLog->info("Base Power={} [VA] Base Omega={} [1/s]", mBaseApparentPower, mBaseOmega);
mPowerflowBusType = powerflowBusType;
mSetPointActivePowerPerUnit = mSetPointActivePower/mBaseApparentPower;
mSetPointVoltagePerUnit = mSetPointVoltage/mBaseVoltage;
mSLog->info("Active Power Set Point={} [pu] Voltage Set Point={} [pu]", mSetPointActivePowerPerUnit, mSetPointVoltagePerUnit);
mSLog->flush();
}
void SP::Ph1::SynchronGenerator::modifyPowerFlowBusType(PowerflowBusType powerflowBusType) {
switch (powerflowBusType)
{
case CPS::PowerflowBusType::PV:
mPowerflowBusType = powerflowBusType;
break;
case CPS::PowerflowBusType::PQ:
mSLog->info(" Setting Synchronous Generator as PQNode is currently not supported.");
throw std::invalid_argument("Setting Synchronous Generator as PQNode is currently not supported.");
break;
case CPS::PowerflowBusType::VD:
mVD = std::make_shared<VDNode>(mUID, mName, mPV->attribute<Real>("V_set_pu")->get(), mLogLevel);
mPowerflowBusType = powerflowBusType;
break;
case CPS::PowerflowBusType::None:
break;
......@@ -80,7 +86,6 @@ void SP::Ph1::SynchronGenerator::modifyPowerFlowBusType(PowerflowBusType powerfl
throw std::invalid_argument(" Invalid power flow bus type ");
break;
}
}
Subproject commit 732a79cc615c5b539fba5156008a1232c358c419
Subproject commit 96a84a5454aa60735229945dfa994d365838a988
......@@ -90,6 +90,9 @@ void PFSolver::initializeComponents(){
for(auto load : mLoads) {
load->calculatePerUnitParameters(mBaseApparentPower, mSystem.mSystemOmega);
}
for(auto gen : mSynchronGenerators) {
gen->calculatePerUnitParameters(mBaseApparentPower, mSystem.mSystemOmega);
}
}
......@@ -97,8 +100,8 @@ void PFSolver::setBaseApparentPower() {
Real maxPower = 0.;
if (!mSynchronGenerators.empty()) {
for (auto gen : mSynchronGenerators)
if (std::abs(gen->mPV->attribute<Real>("P_set")->get()) > maxPower)
maxPower = std::abs(gen->mPV->attribute<Real>("P_set")->get());
if (std::abs(gen->attribute<Real>("P_set")->get()) > maxPower)
maxPower = std::abs(gen->attribute<Real>("P_set")->get());
}
else if (!mTransformers.empty()) {
for (auto trafo : mTransformers)
......@@ -164,10 +167,21 @@ void PFSolver::determinePFBusType() {
else if (connectedPV && connectedPQ && !connectedVD) {
mPVBusIndices.push_back(node->simNode());
mPVBuses.push_back(node);
mSLog->info("Note: node with uuid {} set as PV bus. Both PV and PQ type components were connected.", node->attribute<String>("uid")->get());
} // only VD type component connected -> set as VD bus
else if (!connectedPV && !connectedPQ && connectedVD) {
mVDBusIndices.push_back(node->simNode());
mVDBuses.push_back(node);
} // VD and PV type component connect -> set as VD bus
else if (connectedPV && !connectedPQ && connectedVD) {
mVDBusIndices.push_back(node->simNode());
mVDBuses.push_back(node);
mSLog->info("Note: node with uuid {} set as VD bus. Both VD and PV type components were connected.", node->attribute<String>("uid")->get());
} // VD, PV and PQ type component connect -> set as VD bus
else if (connectedPV && connectedPQ && connectedVD) {
mVDBusIndices.push_back(node->simNode());
mVDBuses.push_back(node);
mSLog->info("Note: node with uuid {} set as VD bus. VD, PV and PQ type components were connected.", node->attribute<String>("uid")->get());
}
else {
std::stringstream ss;
......
......@@ -31,6 +31,17 @@ void PFSolverPowerPolar::generateInitialSolution(Real time, bool keep_last_solut
resize_sol(mSystem.mNodes.size());
resize_complex_sol(mSystem.mNodes.size());
// update all components for the new time
for (auto comp : mSystem.mComponents) {
if (std::shared_ptr<CPS::SP::Ph1::Load> load = std::dynamic_pointer_cast<CPS::SP::Ph1::Load>(comp)) {
if (load->use_profile) {
load->updatePQ(time);
load->calculatePerUnitParameters(mBaseApparentPower, mSystem.mSystemOmega);
}
}
}
// set initial solution for the new time
for (auto pq : mPQBuses) {
if (!keep_last_solution) {
sol_V(pq->simNode()) = 1.0;
......@@ -39,15 +50,10 @@ void PFSolverPowerPolar::generateInitialSolution(Real time, bool keep_last_solut
}
for (auto comp : mSystem.mComponentsAtNode[pq]) {
if (std::shared_ptr<CPS::SP::Ph1::Load> load = std::dynamic_pointer_cast<CPS::SP::Ph1::Load>(comp)) {
if (load->use_profile) {
load->updatePQ(time);
load->calculatePerUnitParameters(mBaseApparentPower, mSystem.mSystemOmega);
}
sol_P(pq->simNode()) -= load->attribute<CPS::Real>("P_pu")->get();
sol_Q(pq->simNode()) -= load->attribute<CPS::Real>("Q_pu")->get();
sol_S_complex(pq->simNode()) = CPS::Complex(sol_P[pq->simNode()], sol_Q[pq->simNode()]);
}
sol_S_complex(pq->simNode()) = CPS::Complex(sol_P[pq->simNode()], sol_Q[pq->simNode()]);
}
}
......@@ -58,8 +64,8 @@ void PFSolverPowerPolar::generateInitialSolution(Real time, bool keep_last_solut
}
for (auto comp : mSystem.mComponentsAtNode[pv]) {
if (std::shared_ptr<CPS::SP::Ph1::SynchronGenerator> gen = std::dynamic_pointer_cast<CPS::SP::Ph1::SynchronGenerator>(comp)) {
sol_P(pv->simNode()) += gen->mPV->attribute<CPS::Real>("P_set")->get() / mBaseApparentPower;
sol_V(pv->simNode()) = gen->mPV->attribute<CPS::Real>("V_set_pu")->get();
sol_P(pv->simNode()) += gen->attribute<CPS::Real>("P_set_pu")->get();
sol_V(pv->simNode()) = gen->attribute<CPS::Real>("V_set_pu")->get();
}
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();
......@@ -87,7 +93,7 @@ void PFSolverPowerPolar::generateInitialSolution(Real time, bool keep_last_solut
for (auto gen : mSynchronGenerators)
{
if (gen->node(0)->simNode() == vd->simNode())
sol_V(vd->simNode()) = gen->mVD->attribute<CPS::Real>("V_set_pu")->get();
sol_V(vd->simNode()) = gen->attribute<CPS::Real>("V_set_pu")->get();
}
}
......
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