Commit 9be81892 authored by Jan Dinkelbach's avatar Jan Dinkelbach Committed by Markus Mirz
Browse files

new implementation of emt3ph controlled voltage source (wip)

parent 6be87a46
......@@ -36,6 +36,7 @@ set(CIRCUIT_SOURCES
#Circuits/EMT_ResVS_RL_Switch.cpp
Circuits/EMT_VSI.cpp
Circuits/EMT_PiLine.cpp
Circuits/EMT_VS_Controlled.cpp
# EMT examples with PF initialization
Circuits/EMT_Slack_PiLine_PQLoad_with_PF_Init.cpp
......
/* Copyright 2017-2020 Institute for Automation of Complex Power Systems,
* EONERC, RWTH Aachen University
* DPsim
*
* 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 <DPsim.h>
using namespace DPsim;
using namespace CPS;
using namespace CPS::CIM;
void vsEMT3ph() {
Real timeStep = 0.00005;
Real finalTime = 0.1;
String simName = "EMT_VoltageSource";
Logger::setLogDir("logs/"+simName);
// Nodes
auto n1 = SimNode<Real>::make("n1", PhaseType::ABC);
// Components
auto vs = EMT::Ph3::VoltageSource::make("vs1", Logger::Level::debug);
vs->setParameters(Reader::singlePhaseVariableToThreePhase(CPS::Math::polar(100000, 0)), 50);
auto res = EMT::Ph3::Resistor::make("R1");
res->setParameters(Reader::singlePhaseParameterToThreePhase(100));
// Topology
vs->connect({ SimNode<Real>::GND, n1 });
res->connect({n1, SimNode<Real>::GND});
auto sys = SystemTopology(50,
SystemNodeList{n1},
SystemComponentList{vs, res});
// Logging
auto logger = DataLogger::make(simName);
logger->addAttribute("v", vs->attribute("v_intf"));
logger->addAttribute("i", vs->attribute("i_intf"));
// Simulation
Simulation sim(simName);
sim.setSystem(sys);
sim.setTimeStep(timeStep);
sim.setFinalTime(finalTime);
sim.setDomain(Domain::EMT);
sim.addLogger(logger);
sim.run();
}
void vsControlledEMT3ph() {
Real timeStep = 0.00005;
Real finalTime = 0.1;
String simName = "EMT_VoltageSource_Controlled";
Logger::setLogDir("logs/"+simName);
// Nodes
auto n1 = SimNode<Real>::make("n1", PhaseType::ABC);
// Components
auto vs = EMT::Ph3::ControlledVoltageSource::make("vs1", Logger::Level::debug);
auto res = EMT::Ph3::Resistor::make("R1");
res->setParameters(Reader::singlePhaseParameterToThreePhase(100));
// Topology
vs->connect({ SimNode<Real>::GND, n1 });
res->connect({n1, SimNode<Real>::GND});
auto sys = SystemTopology(50,
SystemNodeList{n1},
SystemComponentList{vs, res});
// Logging
auto logger = DataLogger::make(simName);
logger->addAttribute("v", vs->attribute("v_intf"));
logger->addAttribute("i", vs->attribute("i_intf"));
// Simulation
Simulation sim(simName);
sim.setSystem(sys);
sim.setTimeStep(timeStep);
sim.setFinalTime(finalTime);
sim.setDomain(Domain::EMT);
sim.addLogger(logger);
sim.run();
}
int main(int argc, char* argv[]) {
vsEMT3ph();
vsControlledEMT3ph();
}
%% Cell type:markdown id: tags:
# Comparison of VS and VS controlled
%% Cell type:code id: tags:
``` python
%%bash
TOP=${TOP:-$(git rev-parse --show-toplevel)}
PATH=${TOP}/build/Examples/Cxx
EMT_VS_Controlled
```
%% Cell type:code id: tags:
``` python
from villas.dataprocessing.readtools import *
from villas.dataprocessing.timeseries import *
from villas.dataprocessing.timeseries import TimeSeries as ts
import matplotlib.pyplot as plt
import numpy as np
import re
#%matplotlib widget
```
%% Cell type:markdown id: tags:
## Voltage Source
%% Cell type:code id: tags:
``` python
model_name = 'EMT_VoltageSource'
path_EMT = 'logs/' + model_name + '/'
dpsim_result_file_EMT = path_EMT + model_name + '.csv'
ts_dpsim_EMT = read_timeseries_csv(dpsim_result_file_EMT)
```
%% Cell type:markdown id: tags:
### Plot voltages
%% Cell type:code id: tags:
``` python
plt.figure()
var_names = ['v_0', 'v_1', 'v_2']
for var_name in var_names:
plt.plot(ts_dpsim_EMT[var_name].time, np.sqrt(3/2)*ts_dpsim_EMT[var_name].values, label=var_name)
plt.legend()
plt.show()
```
%% Cell type:markdown id: tags:
### Plot currents
%% Cell type:code id: tags:
``` python
plt.figure()
var_names = ['i_0', 'i_1', 'i_2']
for var_name in var_names:
plt.plot(ts_dpsim_EMT[var_name].time, np.sqrt(3/2)*ts_dpsim_EMT[var_name].values, label=var_name)
plt.legend()
plt.show()
```
%% Cell type:markdown id: tags:
## Voltage Source Controlled
%% Cell type:code id: tags:
``` python
model_name = 'EMT_VoltageSource_Controlled'
path_EMT = 'logs/' + model_name + '/'
dpsim_result_file_EMT = path_EMT + model_name + '.csv'
ts_dpsim_EMT_ctrl = read_timeseries_csv(dpsim_result_file_EMT)
```
%% Cell type:markdown id: tags:
### Plot voltages
%% Cell type:code id: tags:
``` python
plt.figure()
var_names = ['v_0', 'v_1', 'v_2']
for var_name in var_names:
plt.plot(ts_dpsim_EMT_ctrl[var_name].time, np.sqrt(3/2)*ts_dpsim_EMT_ctrl[var_name].values, label=var_name)
plt.legend()
plt.show()
```
%% Cell type:markdown id: tags:
### Plot currents
%% Cell type:code id: tags:
``` python
plt.figure()
var_names = ['i_0', 'i_1', 'i_2']
for var_name in var_names:
plt.plot(ts_dpsim_EMT_ctrl[var_name].time, np.sqrt(3/2)*ts_dpsim_EMT_ctrl[var_name].values, label=var_name)
plt.legend()
plt.show()
```
%% Cell type:markdown id: tags:
## Comparison VS vs. VS controlled
%% Cell type:code id: tags:
``` python
errors_emt = []
for name in ['v_0', 'v_1', 'v_2', 'i_0', 'i_1', 'i_2']:
errors_emt.append(np.absolute(ts_dpsim_EMT[name].values - ts_dpsim_EMT_ctrl[name].values).max())
print(name + ': ' + str(errors_emt[-1]))
assert np.max(errors_emt) < 1e-3
```
%% Cell type:code id: tags:
``` python
```
......@@ -10,17 +10,26 @@
#include <cps/SimPowerComp.h>
#include <cps/Solver/MNAInterface.h>
#include <cps/EMT/EMT_Ph3_VoltageSource.h>
namespace CPS {
namespace EMT {
namespace Ph3 {
/// \brief Controlled voltage source
///
/// This model enables to control an ideal voltage source with a signal reference.
class ControlledVoltageSource :
public MNAInterface,
public SimPowerComp<Real>,
public SharedFactory<ControlledVoltageSource> {
protected:
void updateVoltage(Real time);
// ### Electrical Subcomponents ###
/// Voltage source
std::shared_ptr<EMT::Ph3::VoltageSource> mSubVoltageSource;
// #### solver ####
/// Vector to collect subcomponent right vector stamps
std::vector<const Matrix*> mRightVectorStamps;
public:
/// Defines UID, name and logging level
ControlledVoltageSource(String uid, String name, Logger::Level logLevel = Logger::Level::off);
......@@ -28,12 +37,13 @@ namespace CPS {
ControlledVoltageSource(String name, Logger::Level logLevel = Logger::Level::off)
: ControlledVoltageSource(name, name, logLevel) { }
void setParameters(const Matrix& voltageRefABC);
SimPowerComp<Real>::Ptr clone(String name);
void updateSignalReference(Real time, Int timeStepCount);
// #### General ####
/// Initializes component from power flow data
void initializeFromNodesAndTerminals(Real frequency) { }
void initializeFromNodesAndTerminals(Real frequency);
// #### MNA section ####
/// Initializes internal variables of the component
......@@ -44,6 +54,8 @@ namespace CPS {
void mnaApplyRightSideVectorStamp(Matrix& rightVector);
/// Returns current through the component
void mnaUpdateCurrent(const Matrix& leftVector);
/// Updates voltage across component
void mnaUpdateVoltage(const Matrix& leftVector);
/// MNA pre step operations
void mnaPreStep(Real time, Int timeStepCount);
/// MNA post step operations
......
......@@ -7,6 +7,7 @@
*********************************************************************************/
#include <cps/EMT/EMT_Ph3_ControlledVoltageSource.h>
#include <cps/CIM/Reader.h>
using namespace CPS;
......@@ -14,83 +15,120 @@ using namespace CPS;
EMT::Ph3::ControlledVoltageSource::ControlledVoltageSource(String uid, String name, Logger::Level logLevel)
: SimPowerComp<Real>(uid, name, logLevel) {
mPhaseType = PhaseType::ABC;
setVirtualNodeNumber(1);
setVirtualNodeNumber(0);
setTerminalNumber(2);
mIntfVoltage = Matrix::Zero(3, 1);
mIntfCurrent = Matrix::Zero(3, 1);
}
mSLog->info("Create {} {}", this->type(), name);
mSubVoltageSource = std::make_shared<EMT::Ph3::VoltageSource>(mName + "_vs", mLogLevel);
mSubComponents.push_back(mSubVoltageSource);
mSLog->info("Electrical subcomponents: ");
for (auto subcomp: mSubComponents)
mSLog->info("- {}", subcomp->name());
void EMT::Ph3::ControlledVoltageSource::setParameters(const Matrix& voltageRefABC) {
mIntfVoltage = voltageRefABC;
mSLog->info("Reference voltage: {:s}", Logger::matrixToString(mIntfVoltage));
mParametersSet = true;
addAttribute<MatrixComp>("V_ref", Flags::read | Flags::write); // rms-value, phase-to-phase
addAttribute<Real>("f_src", Flags::read | Flags::write);
}
SimPowerComp<Real>::Ptr EMT::Ph3::ControlledVoltageSource::clone(String name) {
auto copy = ControlledVoltageSource::make(name, mLogLevel);
copy->setParameters(attribute<Matrix>("v_intf")->get());
return copy;
}
void EMT::Ph3::ControlledVoltageSource::initializeFromNodesAndTerminals(Real frequency) {
// Connect electrical subcomponents
mSubVoltageSource->connect({ node(0), node(1) });
// Initialize electrical subcomponents
mSubVoltageSource->initialize(mFrequencies);
// mSubVoltageSource->initializeFromNodesAndTerminals(frequency);
}
// #### MNA functions ####
void EMT::Ph3::ControlledVoltageSource::mnaInitialize(Real omega, Real timeStep, Attribute<Matrix>::Ptr leftVector) {
MNAInterface::mnaInitialize(omega, timeStep);
updateMatrixNodeIndices();
// initialize electrical subcomponents
mSubVoltageSource->mnaInitialize(omega, timeStep, leftVector);
// collect right side vectors of subcomponents
mRightVectorStamps.push_back(&mSubVoltageSource->attribute<Matrix>("right_vector")->get());
// collect tasks
mMnaTasks.push_back(std::make_shared<MnaPreStep>(*this));
mMnaTasks.push_back(std::make_shared<MnaPostStep>(*this, leftVector));
mRightVector = Matrix::Zero(leftVector->get().rows(), 1);
}
void EMT::Ph3::ControlledVoltageSource::mnaApplySystemMatrixStamp(Matrix& systemMatrix) {
if (terminalNotGrounded(0)) {
Math::addToMatrixElement(systemMatrix, matrixNodeIndex(0, 0), mVirtualNodes[0]->matrixNodeIndex(PhaseType::A), -1);
Math::addToMatrixElement(systemMatrix, mVirtualNodes[0]->matrixNodeIndex(PhaseType::A), matrixNodeIndex(0, 0), -1);
Math::addToMatrixElement(systemMatrix, matrixNodeIndex(0, 1), mVirtualNodes[0]->matrixNodeIndex(PhaseType::B), -1);
Math::addToMatrixElement(systemMatrix, mVirtualNodes[0]->matrixNodeIndex(PhaseType::B), matrixNodeIndex(0, 1), -1);
Math::addToMatrixElement(systemMatrix, matrixNodeIndex(0, 2), mVirtualNodes[0]->matrixNodeIndex(PhaseType::C), -1);
Math::addToMatrixElement(systemMatrix, mVirtualNodes[0]->matrixNodeIndex(PhaseType::C), matrixNodeIndex(0, 2), -1);
}
if (terminalNotGrounded(1)) {
Math::addToMatrixElement(systemMatrix, matrixNodeIndex(1, 0), mVirtualNodes[0]->matrixNodeIndex(PhaseType::A), 1);
Math::addToMatrixElement(systemMatrix, mVirtualNodes[0]->matrixNodeIndex(PhaseType::A), matrixNodeIndex(1, 0), 1);
Math::addToMatrixElement(systemMatrix, matrixNodeIndex(1, 1), mVirtualNodes[0]->matrixNodeIndex(PhaseType::B), 1);
Math::addToMatrixElement(systemMatrix, mVirtualNodes[0]->matrixNodeIndex(PhaseType::B), matrixNodeIndex(1, 1), 1);
Math::addToMatrixElement(systemMatrix, matrixNodeIndex(1, 2), mVirtualNodes[0]->matrixNodeIndex(PhaseType::C), 1);
Math::addToMatrixElement(systemMatrix, mVirtualNodes[0]->matrixNodeIndex(PhaseType::C), matrixNodeIndex(1, 2), 1);
}
mSubVoltageSource->mnaApplySystemMatrixStamp(systemMatrix);
}
void EMT::Ph3::ControlledVoltageSource::mnaApplyRightSideVectorStamp(Matrix& rightVector) {
Math::setVectorElement(rightVector, mVirtualNodes[0]->matrixNodeIndex(PhaseType::A), mIntfVoltage(0, 0));
Math::setVectorElement(rightVector, mVirtualNodes[0]->matrixNodeIndex(PhaseType::B), mIntfVoltage(1, 0));
Math::setVectorElement(rightVector, mVirtualNodes[0]->matrixNodeIndex(PhaseType::C), mIntfVoltage(2, 0));
rightVector.setZero();
for (auto stamp : mRightVectorStamps)
rightVector += *stamp;
mSLog->debug("Right Side Vector: {:s}",
Logger::matrixToString(rightVector));
}
void EMT::Ph3::ControlledVoltageSource::mnaAddPreStepDependencies(AttributeBase::List &prevStepDependencies, AttributeBase::List &attributeDependencies, AttributeBase::List &modifiedAttributes) {
attributeDependencies.push_back(attribute("v_intf"));
mSubVoltageSource->mnaAddPreStepDependencies(prevStepDependencies, attributeDependencies, modifiedAttributes);
// add pre-step dependencies of component itself
prevStepDependencies.push_back(attribute("i_intf"));
prevStepDependencies.push_back(attribute("v_intf"));
modifiedAttributes.push_back(attribute("right_vector"));
}
void EMT::Ph3::ControlledVoltageSource::updateSignalReference(Real time, Int timeStepCount) {
MatrixComp vref = MatrixComp::Zero(3,1);
// TODO: currently support only hard-coded sinusoid
// later signal components can be used here
MatrixComp vrefcos = CIM::Reader::singlePhaseVariableToThreePhase(CPS::Math::polar(100000, 0));
Real fref = 50;
vref(0, 0) = Math::abs(vrefcos(0, 0)) * cos(time * 2. * PI * fref + Math::phase(vrefcos(0, 0)));
vref(1, 0) = Math::abs(vrefcos(1, 0)) * cos(time * 2. * PI * fref + Math::phase(vrefcos(1, 0)));
vref(2, 0) = Math::abs(vrefcos(2, 0)) * cos(time * 2. * PI * fref + Math::phase(vrefcos(2, 0)));
mSubVoltageSource->attribute<MatrixComp>("V_ref")->set(vref);
}
void EMT::Ph3::ControlledVoltageSource::mnaPreStep(Real time, Int timeStepCount) {
updateSignalReference(time, timeStepCount);
// pre-step of subcomponents
mSubVoltageSource->mnaPreStep(time, timeStepCount);
// pre-step of component itself
mnaApplyRightSideVectorStamp(mRightVector);
}
void EMT::Ph3::ControlledVoltageSource::mnaAddPostStepDependencies(AttributeBase::List &prevStepDependencies, AttributeBase::List &attributeDependencies, AttributeBase::List &modifiedAttributes, Attribute<Matrix>::Ptr &leftVector) {
// add post-step dependencies of subcomponents
mSubVoltageSource->mnaAddPostStepDependencies(prevStepDependencies, attributeDependencies, modifiedAttributes, leftVector);
// add post-step dependencies of component itself
attributeDependencies.push_back(leftVector);
modifiedAttributes.push_back(attribute("v_intf"));
modifiedAttributes.push_back(attribute("i_intf"));
};
void EMT::Ph3::ControlledVoltageSource::mnaPostStep(Real time, Int timeStepCount, Attribute<Matrix>::Ptr &leftVector) {
// post-step of subcomponents
mSubVoltageSource->mnaPostStep(time, timeStepCount, leftVector);
// post-step of component itself
mnaUpdateCurrent(*leftVector);
mnaUpdateVoltage(*leftVector);
}
void EMT::Ph3::ControlledVoltageSource::mnaUpdateVoltage(const Matrix& leftVector) {
mIntfVoltage = mSubVoltageSource->attribute<Matrix>("v_intf")->get();
}
void EMT::Ph3::ControlledVoltageSource::mnaUpdateCurrent(const Matrix& leftVector) {
mIntfCurrent(0, 0) = Math::realFromVectorElement(leftVector, mVirtualNodes[0]->matrixNodeIndex(PhaseType::A));
mIntfCurrent(1, 0) = Math::realFromVectorElement(leftVector, mVirtualNodes[0]->matrixNodeIndex(PhaseType::B));
mIntfCurrent(2, 0) = Math::realFromVectorElement(leftVector, mVirtualNodes[0]->matrixNodeIndex(PhaseType::C));
mIntfCurrent = mSubVoltageSource->attribute<Matrix>("i_intf")->get();
}
Markdown is supported
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