diff options
Diffstat (limited to 'Project')
-rw-r--r-- | Project/ControlElementSolver.h | 2 | ||||
-rw-r--r-- | Project/Electromechanical.cpp | 164 | ||||
-rw-r--r-- | Project/Electromechanical.h | 6 | ||||
-rw-r--r-- | Project/PowerElement.h | 29 | ||||
-rw-r--r-- | Project/Project.mk | 2 | ||||
-rw-r--r-- | Project/SyncGenerator.h | 36 | ||||
-rw-r--r-- | Project/Workspace.cpp | 2 |
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); |