summaryrefslogtreecommitdiffstats
path: root/Project
diff options
context:
space:
mode:
Diffstat (limited to 'Project')
-rw-r--r--Project/ControlElementSolver.h2
-rw-r--r--Project/Electromechanical.cpp164
-rw-r--r--Project/Electromechanical.h6
-rw-r--r--Project/PowerElement.h29
-rw-r--r--Project/Project.mk2
-rw-r--r--Project/SyncGenerator.h36
-rw-r--r--Project/Workspace.cpp2
7 files changed, 205 insertions, 36 deletions
diff --git a/Project/ControlElementSolver.h b/Project/ControlElementSolver.h
index 9bc644c..26b8ec5 100644
--- a/Project/ControlElementSolver.h
+++ b/Project/ControlElementSolver.h
@@ -32,7 +32,7 @@ class ControlElementSolver
bool startAllZero = true,
double input = 0.0,
wxWindow* parent = NULL);
- ~ControlElementSolver() {}
+ virtual ~ControlElementSolver() {}
virtual bool InitializeValues(double input, bool startAllZero);
virtual void SolveNextStep(double input);
virtual std::vector<double> GetSolutions() { return m_solutions; }
diff --git a/Project/Electromechanical.cpp b/Project/Electromechanical.cpp
index 895a6f3..d2d9ae9 100644
--- a/Project/Electromechanical.cpp
+++ b/Project/Electromechanical.cpp
@@ -1,12 +1,37 @@
#include "Electromechanical.h"
+#include "ControlElementSolver.h"
-Electromechanical::Electromechanical(std::vector<Element*> elementList)
+Electromechanical::Electromechanical(wxWindow* parent, std::vector<Element*> elementList)
{
+ m_parent = parent;
GetElementsFromList(elementList);
SetEventTimeList();
}
Electromechanical::~Electromechanical() {}
+bool Electromechanical::RunStabilityCalculation()
+{
+ // Calculate the admittance matrix with the synchronous machines.
+ if(!GetYBus(m_yBus, m_powerSystemBase, POSITIVE_SEQ, false, true)) {
+ m_errorMsg = _("It was not possible to build the admittance matrix.");
+ return false;
+ }
+ InsertSyncMachinesOnYBus();
+
+ if(!InitializeDynamicElements()) return false;
+
+ // test
+ double simTime = 10.0;
+ double currentTime = 0.0;
+ while(currentTime <= simTime) {
+ if(HasEvent(currentTime)) {
+ SetEvent(currentTime);
+ }
+ currentTime += m_timeStep;
+ }
+ return true;
+}
+
void Electromechanical::SetEventTimeList()
{
// Fault
@@ -297,27 +322,6 @@ void Electromechanical::SetEvent(double currentTime)
}
}
-bool Electromechanical::RunStabilityCalculation()
-{
- // Calculate the admittance matrix with the synchronous machines.
- if(!GetYBus(m_yBus, m_powerSystemBase, POSITIVE_SEQ, false, true)) {
- m_errorMsg = _("It was not possible to build the admittance matrix.");
- return false;
- }
- InsertSyncMachinesOnYBus();
-
- // test
- double simTime = 10.0;
- double currentTime = 0.0;
- while(currentTime <= simTime) {
- if(HasEvent(currentTime)) {
- SetEvent(currentTime);
- }
- currentTime += m_timeStep;
- }
- return true;
-}
-
void Electromechanical::InsertSyncMachinesOnYBus()
{
for(auto it = m_syncGeneratorList.begin(), itEnd = m_syncGeneratorList.end(); it != itEnd; ++it) {
@@ -366,3 +370,119 @@ std::complex<double> Electromechanical::GetSyncMachineAdmittance(SyncGenerator*
double xdq = 0.5 * (xd + xq);
return std::complex<double>(ra, -xdq) / std::complex<double>(ra * ra + xd * xq, 0.0);
}
+
+bool Electromechanical::InitializeDynamicElements()
+{
+ // Synchronous generators
+ for(auto it = m_syncGeneratorList.begin(), itEnd = m_syncGeneratorList.end(); it != itEnd; ++it) {
+ SyncGenerator* syncGenerator = *it;
+ if(syncGenerator->IsOnline()) {
+ auto data = syncGenerator->GetPUElectricalData(m_powerSystemBase);
+ double k = 1.0; // Power base change factor.
+ if(data.useMachineBase) {
+ double oldBase = data.nominalPower * std::pow(1000.0f, data.nominalPowerUnit);
+ k = m_powerSystemBase / oldBase;
+ }
+ data.terminalVoltage = static_cast<Bus*>(syncGenerator->GetParentList()[0])->GetElectricalData().voltage;
+
+ std::complex<double> conjS(data.activePower, -data.reactivePower);
+ std::complex<double> conjV = std::conj(data.terminalVoltage);
+ std::complex<double> ia = conjS / conjV;
+
+ double xd = data.syncXd * k;
+ double xq = data.syncXq * k;
+ double ra = data.armResistance * k;
+
+ // Initialize state variables
+ std::complex<double> eq0 = data.terminalVoltage + std::complex<double>(ra, xq) * ia;
+ data.delta = std::arg(eq0);
+
+ double teta0 = std::arg(data.terminalVoltage);
+ double vd0, vq0;
+ ABCtoDQ0(data.terminalVoltage, data.delta - teta0, vd0, vq0);
+
+ double fi0 = std::arg(ia);
+ double id0, iq0;
+ ABCtoDQ0(ia, data.delta - fi0, id0, iq0);
+
+ data.initialFieldVoltage = std::abs(eq0) - (xd - xq) * id0;
+ data.pm = std::real((data.terminalVoltage * std::conj(ia)) + (std::abs(ia) * std::abs(ia) * ra));
+ data.speed = 2.0 * M_PI * 60.0;
+
+ switch(GetMachineModel(syncGenerator)) {
+ case SM_MODEL_1: {
+ data.tranEq = 0.0;
+ data.tranEd = 0.0;
+ data.subEq = 0.0;
+ data.subEd = 0.0;
+ } break;
+ case SM_MODEL_2: {
+ double tranXd = data.transXd * k;
+
+ data.tranEq = data.initialFieldVoltage + (xd - tranXd) * id0;
+ data.tranEd = 0.0;
+ data.subEd = 0.0;
+ data.subEq = 0.0;
+ } break;
+ case SM_MODEL_3: {
+ double tranXd = data.transXd * k;
+ double tranXq = data.transXq * k;
+
+ data.tranEq = data.initialFieldVoltage + (xd - tranXd) * id0;
+ data.tranEd = -(xq - tranXq) * iq0;
+ data.subEd = 0.0;
+ data.subEq = 0.0;
+ } break;
+ case SM_MODEL_4: {
+ double tranXd = data.transXd * k;
+ double subXd = data.subXd * k;
+ double subXq = data.subXq * k;
+
+ data.tranEq = data.initialFieldVoltage + (xd - tranXd) * id0;
+ data.tranEd = 0.0;
+ data.subEq = data.tranEq + (tranXd - subXd) * id0;
+ data.subEd = -(xq - subXq) * iq0;
+ } break;
+ case SM_MODEL_5: {
+ double tranXd = data.transXd * k;
+ double tranXq = data.transXq * k;
+ double subXd = data.subXd * k;
+ double subXq = data.subXq * k;
+
+ data.tranEq = data.initialFieldVoltage + (xd - tranXd) * id0;
+ data.tranEd = -(xq - tranXq) * iq0;
+ data.subEq = data.tranEq + (tranXd - subXd) * id0;
+ data.subEd = data.tranEd + (tranXq - subXq) * iq0;
+ } break;
+ default: {
+ break;
+ }
+ }
+
+ // Initialize controllers
+ if(data.useAVR) {
+ if(data.avrSolver) delete data.avrSolver;
+ data.avrSolver = new ControlElementSolver(data.avr, m_timeStep, 1e-3, false,
+ std::abs(data.terminalVoltage), m_parent);
+ if(!data.avrSolver->IsOK()) {
+ m_errorMsg = _("Error on initializate the AVR of \"") + data.name + _("\".");
+ syncGenerator->SetElectricalData(data);
+ return false;
+ }
+ }
+ if(data.useSpeedGovernor) {
+ if(data.speedGovSolver) delete data.speedGovSolver;
+ data.speedGovSolver =
+ new ControlElementSolver(data.speedGov, m_timeStep, 1e-3, false, data.speed, m_parent);
+ if(!data.speedGovSolver->IsOK()) {
+ m_errorMsg = _("Error on initializate the speed governor of \"") + data.name + _("\".");
+ syncGenerator->SetElectricalData(data);
+ return false;
+ }
+ }
+
+ syncGenerator->SetElectricalData(data);
+ }
+ }
+ return true;
+}
diff --git a/Project/Electromechanical.h b/Project/Electromechanical.h
index 172428f..1dadcce 100644
--- a/Project/Electromechanical.h
+++ b/Project/Electromechanical.h
@@ -3,10 +3,12 @@
#include "ElectricCalculation.h"
+class ControlElementSolver;
+
class Electromechanical : public ElectricCalculation
{
public:
- Electromechanical(std::vector<Element*> elementList);
+ Electromechanical(wxWindow* parent, std::vector<Element*> elementList);
~Electromechanical();
bool RunStabilityCalculation();
@@ -20,7 +22,9 @@ protected:
void InsertSyncMachinesOnYBus();
std::complex<double> GetSyncMachineAdmittance(SyncGenerator* generator);
+ bool InitializeDynamicElements();
+ wxWindow* m_parent = NULL;
wxString m_errorMsg = _("Unknown error");
std::vector<std::vector<std::complex<double> > > m_yBus;
diff --git a/Project/PowerElement.h b/Project/PowerElement.h
index 7399fe8..a5d65b1 100644
--- a/Project/PowerElement.h
+++ b/Project/PowerElement.h
@@ -78,6 +78,18 @@ struct SwitchingData {
};
/**
+ * @class IntegrationConstant
+ * @author Thales Lima Oliveira
+ * @date 24/05/2017
+ * @file PowerElement.h
+ * @brief Integration constants to calculate dynamic elements through trapezoidal integration method
+ */
+struct IntegrationConstant {
+ double c; /**< C value */
+ double m; /**< M value */
+};
+
+/**
* @class PowerElement
* @author Thales Lima Oliveira
* @date 18/01/2017
@@ -86,7 +98,7 @@ struct SwitchingData {
*/
class PowerElement : public Element
{
-public:
+ public:
/**
* @brief Constructor
*/
@@ -102,8 +114,9 @@ public:
* @param parentPoint Position of node on parent.
* @param secondPoint Next point in element.
*/
- virtual wxPoint2DDouble
- GetSwitchPoint(Element* parent, wxPoint2DDouble parentPoint, wxPoint2DDouble secondPoint) const;
+ virtual wxPoint2DDouble GetSwitchPoint(Element* parent,
+ wxPoint2DDouble parentPoint,
+ wxPoint2DDouble secondPoint) const;
/**
* @brief Check if switch contains position.
@@ -144,30 +157,26 @@ public:
* @param data Switching data.
*/
virtual void SetSwitchingData(SwitchingData data) { m_swData = data; }
-
/**
* @brief Returns the switching data of the element.
* @return Element switching data.
*/
virtual SwitchingData GetSwitchingData() { return m_swData; }
-
/**
* @brief Set the direction of the power flow.
* @param pfDirection Power flow direction.
*/
virtual void SetPowerFlowDirection(PowerFlowDirection pfDirection) { m_pfDirection = pfDirection; }
-
/**
* @brief Return the direction of the power flow.
* @return Power flow direction.
*/
virtual PowerFlowDirection GetPowerFlowDirection() const { return m_pfDirection; }
-
-protected:
+ protected:
SwitchingData m_swData;
std::vector<std::vector<wxPoint2DDouble> > m_powerFlowArrow;
PowerFlowDirection m_pfDirection = PF_NONE;
-
+
OpenGLColour m_busColour;
OpenGLColour m_onlineElementColour;
OpenGLColour m_offlineElementColour;
@@ -176,4 +185,4 @@ protected:
OpenGLColour m_powerFlowArrowColour;
};
-#endif // POWERELEMENT_H
+#endif // POWERELEMENT_H
diff --git a/Project/Project.mk b/Project/Project.mk
index 9f59536..f8cd070 100644
--- a/Project/Project.mk
+++ b/Project/Project.mk
@@ -13,7 +13,7 @@ CurrentFileName :=
CurrentFilePath :=
CurrentFileFullPath :=
User :=NDSE-69
-Date :=23/05/2017
+Date :=24/05/2017
CodeLitePath :="C:/Program Files/CodeLite"
LinkerName :=C:/TDM-GCC-64/bin/g++.exe
SharedObjectLinkerName :=C:/TDM-GCC-64/bin/g++.exe -shared -fPIC
diff --git a/Project/SyncGenerator.h b/Project/SyncGenerator.h
index 5fe078f..8cadddc 100644
--- a/Project/SyncGenerator.h
+++ b/Project/SyncGenerator.h
@@ -5,6 +5,7 @@
class SyncMachineForm;
class ControlElementContainer;
+class ControlElementSolver;
struct SyncGeneratorElectricalData {
// General
@@ -61,9 +62,44 @@ struct SyncGeneratorElectricalData {
double subTd0 = 0.0;
double subTq0 = 0.0;
+ // Machine state variables
+ std::complex<double> terminalVoltage;
+ std::vector<std::complex<double> > terminalVoltageVector;
+ std::complex<double> electricalPower;
+ std::vector<std::complex<double> > electricalPowerVector;
+ double pm;
+ std::vector<double> mechanicalPowerVector;
+ double speed;
+ std::vector<double> freqVector;
+ double fieldVoltage;
+ std::vector<double> fieldVoltageVector;
+ double delta;
+ std::vector<double> deltaVector;
+
+ double initialFieldVoltage;
+
+ // Internal machine variables
+ double tranEq;
+ double tranEd;
+ double subEq;
+ double subEd;
+ double pe;
+
+ // Integration constants
+ IntegrationConstant icSpeed;
+ IntegrationConstant icDelta;
+ IntegrationConstant icTranEq;
+ IntegrationConstant icTranEd;
+ IntegrationConstant icSubEq;
+ IntegrationConstant icSubEd;
+
// Control
ControlElementContainer* avr = NULL;
ControlElementContainer* speedGov = NULL;
+
+ // Control solvers
+ ControlElementSolver* avrSolver = NULL;
+ ControlElementSolver* speedGovSolver = NULL;
};
class SyncGenerator : public Machines
diff --git a/Project/Workspace.cpp b/Project/Workspace.cpp
index a45518f..9bd9afa 100644
--- a/Project/Workspace.cpp
+++ b/Project/Workspace.cpp
@@ -1397,7 +1397,7 @@ bool Workspace::RunStability()
// Run power flow before stability.
RunPowerFlow();
- Electromechanical stability(GetElementList());
+ Electromechanical stability(this, GetElementList());
bool result = stability.RunStabilityCalculation();
if(!result) {
wxMessageDialog msgDialog(this, stability.GetErrorMessage(), _("Error"), wxOK | wxCENTRE | wxICON_ERROR);