summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThales Lima Oliveira <thaleslima.ufu@gmail.com>2019-04-26 02:29:47 -0300
committerThales Lima Oliveira <thaleslima.ufu@gmail.com>2019-04-26 02:29:47 -0300
commita40d5a405d60b4e429f6f578dcfe3c33ab5ad81a (patch)
tree0f88240b49798ce5e3d9b96ca2951145a7978343
parent4dabf27f998db83e20bc0eca7e18672777f0bf5b (diff)
downloadPSP.git-a40d5a405d60b4e429f6f578dcfe3c33ab5ad81a.tar.gz
PSP.git-a40d5a405d60b4e429f6f578dcfe3c33ab5ad81a.tar.xz
PSP.git-a40d5a405d60b4e429f6f578dcfe3c33ab5ad81a.zip
Frequency response implemented
Need a form
-rw-r--r--Project/Bus.cpp30
-rw-r--r--Project/Bus.h4
-rw-r--r--Project/FileHanding.cpp23
-rw-r--r--Project/Load.cpp2
-rw-r--r--Project/Load.h2
-rw-r--r--Project/MainFrame.cpp13
-rw-r--r--Project/PowerElement.h17
-rw-r--r--Project/PowerQuality.cpp266
-rw-r--r--Project/PowerQuality.h14
-rw-r--r--Project/PropertiesData.h1
-rw-r--r--Project/PropertiesForm.wxcp663
-rw-r--r--Project/PropertiesFormBase.cpp60
-rw-r--r--Project/PropertiesFormBase.h104
-rw-r--r--Project/SimulationsSettingsForm.cpp2
-rw-r--r--Project/SyncGenerator.cpp2
-rw-r--r--Project/SyncGenerator.h2
-rw-r--r--Project/Text.cpp16
-rw-r--r--Project/Text.h3
-rw-r--r--Project/TextForm.cpp16
-rw-r--r--Project/Workspace.cpp52
-rw-r--r--Project/Workspace.h1
21 files changed, 773 insertions, 520 deletions
diff --git a/Project/Bus.cpp b/Project/Bus.cpp
index eecc06a..37eac3e 100644
--- a/Project/Bus.cpp
+++ b/Project/Bus.cpp
@@ -239,23 +239,31 @@ wxString Bus::GetTipText() const
}
tipText += _("\n\nSsc = ") + wxString::FromDouble(std::abs(m_electricalData.scPower), 5) + _(" p.u.");
+ tipText += _("\n\nTHD = ") + wxString::FromDouble(std::abs(m_electricalData.thd), 5) + wxT("\%");
return tipText;
}
-bool Bus::GetPlotData(ElementPlotData& plotData)
+bool Bus::GetPlotData(ElementPlotData& plotData, PlotStudy study)
{
- if(!m_electricalData.plotBus) return false;
- plotData.SetName(m_electricalData.name);
- plotData.SetCurveType(ElementPlotData::CT_BUS);
-
- std::vector<double> absVoltage, argVoltage;
- for(unsigned int i = 0; i < m_electricalData.stabVoltageVector.size(); ++i) {
- absVoltage.push_back(std::abs(m_electricalData.stabVoltageVector[i]));
- argVoltage.push_back(wxRadToDeg(std::arg(m_electricalData.stabVoltageVector[i])));
+ if(study == STABILITY) {
+ if(!m_electricalData.plotBus) return false;
+ plotData.SetName(m_electricalData.name);
+ plotData.SetCurveType(ElementPlotData::CT_BUS);
+
+ std::vector<double> absVoltage, argVoltage;
+ for(unsigned int i = 0; i < m_electricalData.stabVoltageVector.size(); ++i) {
+ absVoltage.push_back(std::abs(m_electricalData.stabVoltageVector[i]));
+ argVoltage.push_back(wxRadToDeg(std::arg(m_electricalData.stabVoltageVector[i])));
+ }
+ plotData.AddData(absVoltage, _("Voltage"));
+ plotData.AddData(argVoltage, _("Angle"));
+ } else if(FREQRESPONSE) {
+ //if(!m_electricalData.plotBus) return false;
+ plotData.SetName(m_electricalData.name);
+ plotData.SetCurveType(ElementPlotData::CT_BUS);
+ plotData.AddData(m_electricalData.absImpedanceVector, _("Impedance"));
}
- plotData.AddData(absVoltage, _("Voltage"));
- plotData.AddData(argVoltage, _("Angle"));
return true;
}
diff --git a/Project/Bus.h b/Project/Bus.h
index 2423be6..e2947ac 100644
--- a/Project/Bus.h
+++ b/Project/Bus.h
@@ -62,6 +62,8 @@ struct BusElectricalData {
std::vector<int> harmonicOrder;
std::vector< std::complex<double> > harmonicVoltage;
double thd = 0.0;
+
+ std::vector<double> absImpedanceVector;
};
/**
@@ -92,7 +94,7 @@ class Bus : public PowerElement
virtual BusElectricalData GetElectricalData() const { return m_electricalData; }
virtual void SetElectricalData(BusElectricalData electricalData) { m_electricalData = electricalData; }
virtual bool ShowForm(wxWindow* parent, Element* element);
- virtual bool GetPlotData(ElementPlotData& plotData);
+ virtual bool GetPlotData(ElementPlotData& plotData, PlotStudy study = STABILITY);
virtual rapidxml::xml_node<>* SaveElement(rapidxml::xml_document<>& doc, rapidxml::xml_node<>* elementListNode);
virtual bool OpenElement(rapidxml::xml_node<>* elementNode);
diff --git a/Project/FileHanding.cpp b/Project/FileHanding.cpp
index 7120063..f5facbf 100644
--- a/Project/FileHanding.cpp
+++ b/Project/FileHanding.cpp
@@ -232,7 +232,7 @@ void FileHanding::SaveProject(wxFileName path)
elementID++;
}
//}
-
+
//{ HarmCurrent
auto harmCurrentNode = XMLParser::AppendNode(doc, elementsNode, "HarmCurrentList");
auto harmCurrentList = allElements.GetHarmCurrentList();
@@ -492,19 +492,20 @@ bool FileHanding::OpenProject(wxFileName path)
transfomerNode = transfomerNode->next_sibling("Transfomer");
} //}
-
- //{ Transformer
+
+ //{ HarmCurrent
auto harmCurrentListNode = elementsNode->first_node("HarmCurrentList");
- if(!harmCurrentListNode) return false;
- auto harmCurrentNode = harmCurrentListNode->first_node("HarmCurrent");
- while(harmCurrentNode) {
- HarmCurrent* harmCurrent = new HarmCurrent();
+ if(harmCurrentListNode) {
+ auto harmCurrentNode = harmCurrentListNode->first_node("HarmCurrent");
+ while(harmCurrentNode) {
+ HarmCurrent* harmCurrent = new HarmCurrent();
- if(!harmCurrent->OpenElement(harmCurrentNode, parentList)) return false;
- elementList.push_back(harmCurrent);
- harmCurrentList.push_back(harmCurrent);
+ if(!harmCurrent->OpenElement(harmCurrentNode, parentList)) return false;
+ elementList.push_back(harmCurrent);
+ harmCurrentList.push_back(harmCurrent);
- harmCurrentNode = harmCurrentNode->next_sibling("HarmCurrent");
+ harmCurrentNode = harmCurrentNode->next_sibling("HarmCurrent");
+ }
} //}
m_workspace->SetElementList(elementList);
diff --git a/Project/Load.cpp b/Project/Load.cpp
index 64c5514..d9f1b2a 100644
--- a/Project/Load.cpp
+++ b/Project/Load.cpp
@@ -248,7 +248,7 @@ wxString Load::GetTipText() const
return tipText;
}
-bool Load::GetPlotData(ElementPlotData& plotData)
+bool Load::GetPlotData(ElementPlotData& plotData, PlotStudy study)
{
if(!m_electricalData.plotLoad) return false;
plotData.SetName(m_electricalData.name);
diff --git a/Project/Load.h b/Project/Load.h
index 342f377..4fa01ad 100644
--- a/Project/Load.h
+++ b/Project/Load.h
@@ -87,7 +87,7 @@ class Load : public Shunt
LoadElectricalData GetElectricalData() { return m_electricalData; }
LoadElectricalData GetPUElectricalData(double systemPowerBase);
void SetElectricalData(LoadElectricalData electricalData) { m_electricalData = electricalData; }
- virtual bool GetPlotData(ElementPlotData& plotData);
+ virtual bool GetPlotData(ElementPlotData& plotData, PlotStudy study = STABILITY);
virtual rapidxml::xml_node<>* SaveElement(rapidxml::xml_document<>& doc, rapidxml::xml_node<>* elementListNode);
virtual bool OpenElement(rapidxml::xml_node<>* elementNode, std::vector<Element*> parentList);
diff --git a/Project/MainFrame.cpp b/Project/MainFrame.cpp
index 3af0545..5e81c89 100644
--- a/Project/MainFrame.cpp
+++ b/Project/MainFrame.cpp
@@ -22,12 +22,12 @@
#include "DataReport.h"
#include "FileHanding.h"
#include "GeneralPropertiesForm.h"
+#include "HarmCurrent.h"
#include "ImportForm.h"
#include "IndMotor.h"
#include "Inductor.h"
#include "Line.h"
#include "Load.h"
-#include "HarmCurrent.h"
#include "MainFrame.h"
#include "PropertiesData.h"
#include "SimulationsSettingsForm.h"
@@ -153,8 +153,9 @@ void MainFrame::CreateAddElementsMenu()
_("Adds a shunt capacitor at the circuit"));
wxMenuItem* inductorElement = new wxMenuItem(m_addElementsMenu, ID_ADDMENU_INDUCTOR, _("&Inductor\tShift-I"),
_("Adds a shunt inductor at the circuit"));
- wxMenuItem* harmCurrentElement = new wxMenuItem(m_addElementsMenu, ID_ADDMENU_HARMCURRENT, _("&Harmonic current\tShift-H"),
- _("Adds a harmonic current source at the circuit"));
+ wxMenuItem* harmCurrentElement =
+ new wxMenuItem(m_addElementsMenu, ID_ADDMENU_HARMCURRENT, _("&Harmonic current\tShift-H"),
+ _("Adds a harmonic current source at the circuit"));
m_addElementsMenu->Append(busElement);
m_addElementsMenu->Append(lineElement);
@@ -446,8 +447,8 @@ void MainFrame::OnAddElementsClick(wxCommandEvent& event)
newElement = true;
} break;
case ID_ADDMENU_HARMCURRENT: {
- HarmCurrent* newHarmCurrent =
- new HarmCurrent(wxString::Format(_("Harmonic Current %d"), workspace->GetElementNumber(ID_INDUCTOR)));
+ HarmCurrent* newHarmCurrent = new HarmCurrent(
+ wxString::Format(_("Harmonic Current %d"), workspace->GetElementNumber(ID_INDUCTOR)));
workspace->IncrementElementNumber(ID_HARMCURRENT);
elementList.push_back(newHarmCurrent);
statusBarText = _("Insert Harmonic Current Source: Click on a buses, ESC to cancel.");
@@ -556,6 +557,8 @@ void MainFrame::OnSimulationSettingsClick(wxRibbonButtonBarEvent& event)
}
void MainFrame::OnFreqResponseClick(wxRibbonButtonBarEvent& event)
{
+ Workspace* workspace = static_cast<Workspace*>(m_auiNotebook->GetCurrentPage());
+ if(workspace) { workspace->RunFrequencyResponse(); }
}
void MainFrame::OnHarmDistortionsClick(wxRibbonButtonBarEvent& event)
{
diff --git a/Project/PowerElement.h b/Project/PowerElement.h
index d2b13e7..031834e 100644
--- a/Project/PowerElement.h
+++ b/Project/PowerElement.h
@@ -24,7 +24,7 @@
/**
* @enum ElectricalUnit
* @brief Electrical units.
-*/
+ */
enum ElectricalUnit {
UNIT_PU = 0, /**< Per unit (p.u.) */
UNIT_V, /**< Volt */
@@ -51,7 +51,7 @@ enum ElectricalUnit {
/**
* @enum FaultData
* @brief Information about fault (type and location).
-*/
+ */
enum FaultData {
FAULT_THREEPHASE = 0, /**< Three-phase fault */
FAULT_2LINE, /**< Line-to-line fault */
@@ -65,7 +65,7 @@ enum FaultData {
/**
* @enum SwitchingType
* @brief Type of switching.
-*/
+ */
enum SwitchingType {
SW_INSERT = 0, /**< Insert element */
SW_REMOVE /**< Remove element */
@@ -74,7 +74,7 @@ enum SwitchingType {
/**
* @enum PowerFlowDirection
* @brief Direction of power flow arrows.
-*/
+ */
enum PowerFlowDirection {
PF_NONE = 0, /**< No direction (no arrows printed) */
PF_TO_BUS, /**< Element to bus */
@@ -83,6 +83,11 @@ enum PowerFlowDirection {
PF_BUS2_TO_BUS1 /**< Second bus to first bus (branch elements) */
};
+enum PlotStudy {
+ STABILITY = 0, /**< Stability studies */
+ FREQRESPONSE /**< Frequency resonse (Harmonics) */
+};
+
/**
* @class SwitchingData
* @author Thales Lima Oliveira
@@ -195,7 +200,7 @@ class PowerElement : public Element
* @param plotData Plot data to be filled.
* @return true if the plot data was successfully filled, false otherwise.
*/
- virtual bool GetPlotData(ElementPlotData& plotData) { return false; }
+ virtual bool GetPlotData(ElementPlotData& plotData, PlotStudy study = STABILITY) { return false; }
/**
* @brief Check if the power element have dynamic event.
* @return true if the element have dynamic an event, false otherwise.
@@ -207,7 +212,7 @@ class PowerElement : public Element
*/
virtual void SetDynamicEvent(bool dynEvent = true) { m_dynEvent = dynEvent; }
virtual double GetValueFromUnit(double value, ElectricalUnit valueUnit);
-
+
virtual void SaveCADProperties(rapidxml::xml_document<>& doc, rapidxml::xml_node<>* elementNode);
virtual void SaveSwitchingData(rapidxml::xml_document<>& doc, rapidxml::xml_node<>* electricalNode);
virtual bool OpenElement(rapidxml::xml_node<>* elementNode, std::vector<Element*> parentList) { return true; }
diff --git a/Project/PowerQuality.cpp b/Project/PowerQuality.cpp
index 4efdc49..30969d9 100644
--- a/Project/PowerQuality.cpp
+++ b/Project/PowerQuality.cpp
@@ -23,133 +23,127 @@ void PowerQuality::CalculateHarmonicYbusList(double systemPowerBase)
// Fill all Ybuses
for(auto itYbus = m_harmYbusList.begin(), itYbusEnd = m_harmYbusList.end(); itYbus != itYbusEnd; ++itYbus) {
HarmonicYbus harmYBus = *itYbus;
- // Load
- for(auto it = m_loadList.begin(), itEnd = m_loadList.end(); it != itEnd; ++it) {
- Load* load = *it;
- if(load->IsOnline()) {
- int n = static_cast<Bus*>(load->GetParentList()[0])->GetElectricalData().number;
- LoadElectricalData data = load->GetPUElectricalData(systemPowerBase);
- wxMessageBox(wxString::Format("%f %f", data.activePower, data.reactivePower));
- std::complex<double> yLoad =
- std::complex<double>(data.activePower, -data.reactivePower / harmYBus.order);
- std::complex<double> v = static_cast<Bus*>(load->GetParentList()[0])->GetElectricalData().voltage;
- yLoad /= (std::abs(v) * std::abs(v));
- harmYBus.yBus[n][n] += yLoad;
- }
+ CalculateHarmonicYbus(harmYBus.yBus, systemPowerBase, harmYBus.order);
+ *itYbus = harmYBus;
+ }
+}
+
+void PowerQuality::CalculateHarmonicYbus(std::vector<std::vector<std::complex<double> > >& yBus,
+ double systemPowerBase,
+ double order)
+{
+ // Load
+ for(auto it = m_loadList.begin(), itEnd = m_loadList.end(); it != itEnd; ++it) {
+ Load* load = *it;
+ if(load->IsOnline()) {
+ int n = static_cast<Bus*>(load->GetParentList()[0])->GetElectricalData().number;
+ LoadElectricalData data = load->GetPUElectricalData(systemPowerBase);
+ std::complex<double> yLoad = std::complex<double>(data.activePower, -data.reactivePower / order);
+ std::complex<double> v = static_cast<Bus*>(load->GetParentList()[0])->GetElectricalData().voltage;
+ yLoad /= (std::abs(v) * std::abs(v));
+ yBus[n][n] += yLoad;
}
+ }
- // Capacitor
- for(auto it = m_capacitorList.begin(), itEnd = m_capacitorList.end(); it != itEnd; ++it) {
- Capacitor* capacitor = *it;
- if(capacitor->IsOnline()) {
- int n = static_cast<Bus*>(capacitor->GetParentList()[0])->GetElectricalData().number;
- CapacitorElectricalData data = capacitor->GetPUElectricalData(systemPowerBase);
- harmYBus.yBus[n][n] += std::complex<double>(0.0, data.reactivePower) * harmYBus.order;
- }
+ // Capacitor
+ for(auto it = m_capacitorList.begin(), itEnd = m_capacitorList.end(); it != itEnd; ++it) {
+ Capacitor* capacitor = *it;
+ if(capacitor->IsOnline()) {
+ int n = static_cast<Bus*>(capacitor->GetParentList()[0])->GetElectricalData().number;
+ CapacitorElectricalData data = capacitor->GetPUElectricalData(systemPowerBase);
+ yBus[n][n] += std::complex<double>(0.0, data.reactivePower) * order;
}
+ }
- // Inductor
- for(auto it = m_inductorList.begin(), itEnd = m_inductorList.end(); it != itEnd; ++it) {
- Inductor* inductor = *it;
- if(inductor->IsOnline()) {
- int n = static_cast<Bus*>(inductor->GetParentList()[0])->GetElectricalData().number;
- InductorElectricalData data = inductor->GetPUElectricalData(systemPowerBase);
- harmYBus.yBus[n][n] += std::complex<double>(0.0, -data.reactivePower) / harmYBus.order;
- }
+ // Inductor
+ for(auto it = m_inductorList.begin(), itEnd = m_inductorList.end(); it != itEnd; ++it) {
+ Inductor* inductor = *it;
+ if(inductor->IsOnline()) {
+ int n = static_cast<Bus*>(inductor->GetParentList()[0])->GetElectricalData().number;
+ InductorElectricalData data = inductor->GetPUElectricalData(systemPowerBase);
+ yBus[n][n] += std::complex<double>(0.0, -data.reactivePower) / order;
}
+ }
- // Power line
- for(auto it = m_lineList.begin(), itEnd = m_lineList.end(); it != itEnd; ++it) {
- Line* line = *it;
- if(line->IsOnline()) {
- LineElectricalData data = line->GetPUElectricalData(systemPowerBase);
+ // Power line
+ for(auto it = m_lineList.begin(), itEnd = m_lineList.end(); it != itEnd; ++it) {
+ Line* line = *it;
+ if(line->IsOnline()) {
+ LineElectricalData data = line->GetPUElectricalData(systemPowerBase);
- int n1 = static_cast<Bus*>(line->GetParentList()[0])->GetElectricalData().number;
- int n2 = static_cast<Bus*>(line->GetParentList()[1])->GetElectricalData().number;
+ int n1 = static_cast<Bus*>(line->GetParentList()[0])->GetElectricalData().number;
+ int n2 = static_cast<Bus*>(line->GetParentList()[1])->GetElectricalData().number;
- harmYBus.yBus[n1][n2] -=
- 1.0 / std::complex<double>(data.resistance, data.indReactance * harmYBus.order);
- harmYBus.yBus[n2][n1] -=
- 1.0 / std::complex<double>(data.resistance, data.indReactance * harmYBus.order);
+ yBus[n1][n2] -= 1.0 / std::complex<double>(data.resistance, data.indReactance * order);
+ yBus[n2][n1] -= 1.0 / std::complex<double>(data.resistance, data.indReactance * order);
- harmYBus.yBus[n1][n1] +=
- 1.0 / std::complex<double>(data.resistance, data.indReactance * harmYBus.order);
- harmYBus.yBus[n2][n2] +=
- 1.0 / std::complex<double>(data.resistance, data.indReactance * harmYBus.order);
+ yBus[n1][n1] += 1.0 / std::complex<double>(data.resistance, data.indReactance * order);
+ yBus[n2][n2] += 1.0 / std::complex<double>(data.resistance, data.indReactance * order);
- harmYBus.yBus[n1][n1] += std::complex<double>(0.0, (data.capSusceptance * harmYBus.order) / 2.0);
- harmYBus.yBus[n2][n2] += std::complex<double>(0.0, (data.capSusceptance * harmYBus.order) / 2.0);
- }
+ yBus[n1][n1] += std::complex<double>(0.0, (data.capSusceptance * order) / 2.0);
+ yBus[n2][n2] += std::complex<double>(0.0, (data.capSusceptance * order) / 2.0);
}
+ }
- // Transformer
- for(auto it = m_transformerList.begin(), itEnd = m_transformerList.end(); it != itEnd; ++it) {
- Transformer* transformer = *it;
+ // Transformer
+ for(auto it = m_transformerList.begin(), itEnd = m_transformerList.end(); it != itEnd; ++it) {
+ Transformer* transformer = *it;
- if(transformer->IsOnline()) {
- TransformerElectricalData data = transformer->GetPUElectricalData(systemPowerBase);
+ if(transformer->IsOnline()) {
+ TransformerElectricalData data = transformer->GetPUElectricalData(systemPowerBase);
- int n1 = static_cast<Bus*>(transformer->GetParentList()[0])->GetElectricalData().number;
- int n2 = static_cast<Bus*>(transformer->GetParentList()[1])->GetElectricalData().number;
+ int n1 = static_cast<Bus*>(transformer->GetParentList()[0])->GetElectricalData().number;
+ int n2 = static_cast<Bus*>(transformer->GetParentList()[1])->GetElectricalData().number;
- // If the transformer have nominal turns ratio (1.0) and no phase shifting, it will be modelled as
- // series impedance.
- if(data.turnsRatio == 1.0 && data.phaseShift == 0.0) {
- harmYBus.yBus[n1][n2] +=
- -1.0 / std::complex<double>(data.resistance, data.indReactance * harmYBus.order);
- harmYBus.yBus[n2][n1] +=
- -1.0 / std::complex<double>(data.resistance, data.indReactance * harmYBus.order);
+ // If the transformer have nominal turns ratio (1.0) and no phase shifting, it will be modelled as
+ // series impedance.
+ if(data.turnsRatio == 1.0 && data.phaseShift == 0.0) {
+ yBus[n1][n2] += -1.0 / std::complex<double>(data.resistance, data.indReactance * order);
+ yBus[n2][n1] += -1.0 / std::complex<double>(data.resistance, data.indReactance * order);
- harmYBus.yBus[n1][n1] +=
- 1.0 / std::complex<double>(data.resistance, data.indReactance * harmYBus.order);
- harmYBus.yBus[n2][n2] +=
- 1.0 / std::complex<double>(data.resistance, data.indReactance * harmYBus.order);
- }
- // If the transformer have no-nominal turn ratio and/or phase shifting, it will be modelled in a
- // different way (see references).
- //[Ref. 1: Elementos de analise de sistemas de potencia - Stevenson - pg. 232]
- //[Ref. 2:
- // http://www.ee.washington.edu/research/real/Library/Reports/Tap_Adjustments_in_AC_Load_Flows.pdf]
- // [Ref. 3: http://www.columbia.edu/~dano/courses/power/notes/power/andersson1.pdf]
- else {
- // Complex turns ratio
- double radPhaseShift = wxDegToRad(data.phaseShift);
- std::complex<double> a = std::complex<double>(data.turnsRatio * std::cos(radPhaseShift),
- -data.turnsRatio * std::sin(radPhaseShift));
-
- // Transformer admitance
- std::complex<double> y =
- 1.0 / std::complex<double>(data.resistance, data.indReactance * harmYBus.order);
-
- harmYBus.yBus[n1][n1] += y / (std::pow(std::abs(a), 2.0));
- harmYBus.yBus[n1][n2] += -(y / std::conj(a));
- harmYBus.yBus[n2][n1] += -(y / a);
- harmYBus.yBus[n2][n2] += y;
- }
+ yBus[n1][n1] += 1.0 / std::complex<double>(data.resistance, data.indReactance * order);
+ yBus[n2][n2] += 1.0 / std::complex<double>(data.resistance, data.indReactance * order);
}
- }
+ // If the transformer have no-nominal turn ratio and/or phase shifting, it will be modelled in a
+ // different way (see references).
+ //[Ref. 1: Elementos de analise de sistemas de potencia - Stevenson - pg. 232]
+ //[Ref. 2:
+ // http://www.ee.washington.edu/research/real/Library/Reports/Tap_Adjustments_in_AC_Load_Flows.pdf]
+ // [Ref. 3: http://www.columbia.edu/~dano/courses/power/notes/power/andersson1.pdf]
+ else {
+ // Complex turns ratio
+ double radPhaseShift = wxDegToRad(data.phaseShift);
+ std::complex<double> a = std::complex<double>(data.turnsRatio * std::cos(radPhaseShift),
+ -data.turnsRatio * std::sin(radPhaseShift));
+
+ // Transformer admitance
+ std::complex<double> y = 1.0 / std::complex<double>(data.resistance, data.indReactance * order);
- // Synchronous generator
- for(auto it = m_syncGeneratorList.begin(), itEnd = m_syncGeneratorList.end(); it != itEnd; ++it) {
- SyncGenerator* syncGenerator = *it;
- if(syncGenerator->IsOnline()) {
- int n = static_cast<Bus*>(syncGenerator->GetParentList()[0])->GetElectricalData().number;
- SyncGeneratorElectricalData data = syncGenerator->GetPUElectricalData(systemPowerBase);
- harmYBus.yBus[n][n] +=
- 1.0 / std::complex<double>(data.positiveResistance, data.positiveReactance * harmYBus.order);
+ yBus[n1][n1] += y / (std::pow(std::abs(a), 2.0));
+ yBus[n1][n2] += -(y / std::conj(a));
+ yBus[n2][n1] += -(y / a);
+ yBus[n2][n2] += y;
}
}
- // Synchronous motor
- for(auto it = m_syncMotorList.begin(), itEnd = m_syncMotorList.end(); it != itEnd; ++it) {
- SyncMotor* syncMotor = *it;
- if(syncMotor->IsOnline()) {
- int n = static_cast<Bus*>(syncMotor->GetParentList()[0])->GetElectricalData().number;
- SyncMotorElectricalData data = syncMotor->GetPUElectricalData(systemPowerBase);
- harmYBus.yBus[n][n] +=
- 1.0 / std::complex<double>(data.positiveResistance, data.positiveReactance * harmYBus.order);
- }
+ }
+
+ // Synchronous generator
+ for(auto it = m_syncGeneratorList.begin(), itEnd = m_syncGeneratorList.end(); it != itEnd; ++it) {
+ SyncGenerator* syncGenerator = *it;
+ if(syncGenerator->IsOnline()) {
+ int n = static_cast<Bus*>(syncGenerator->GetParentList()[0])->GetElectricalData().number;
+ SyncGeneratorElectricalData data = syncGenerator->GetPUElectricalData(systemPowerBase);
+ yBus[n][n] += 1.0 / std::complex<double>(data.positiveResistance, data.positiveReactance * order);
+ }
+ }
+ // Synchronous motor
+ for(auto it = m_syncMotorList.begin(), itEnd = m_syncMotorList.end(); it != itEnd; ++it) {
+ SyncMotor* syncMotor = *it;
+ if(syncMotor->IsOnline()) {
+ int n = static_cast<Bus*>(syncMotor->GetParentList()[0])->GetElectricalData().number;
+ SyncMotorElectricalData data = syncMotor->GetPUElectricalData(systemPowerBase);
+ yBus[n][n] += 1.0 / std::complex<double>(data.positiveResistance, data.positiveReactance * order);
}
- *itYbus = harmYBus;
}
}
@@ -207,7 +201,7 @@ bool PowerQuality::CalculateDistortions(double systemPowerBase)
for(unsigned int i = 0; i < m_harmYbusList.size(); ++i) {
vHarmList.push_back(GaussianElimination(m_harmYbusList[i].yBus, iHarmInjList[i]));
}
-
+
for(auto it = m_busList.begin(), itEnd = m_busList.end(); it != itEnd; ++it) {
Bus* bus = *it;
auto data = bus->GetElectricalData();
@@ -219,9 +213,10 @@ bool PowerQuality::CalculateDistortions(double systemPowerBase)
data.harmonicVoltage.push_back(vHarmList[i][data.number]);
data.harmonicOrder.push_back(static_cast<int>(harmOrders[i]));
}
- //distortion = std::sqrt(distortion) / std::abs(data.voltage);
+ // distortion = std::sqrt(distortion) / std::abs(data.voltage);
thd = std::sqrt(thd) * 100.0;
data.thd = thd;
+ bus->SetElectricalData(data);
}
return true;
@@ -256,3 +251,58 @@ std::vector<double> PowerQuality::GetHarmonicOrdersList()
}
return doubleHarmOrder;
}
+
+bool PowerQuality::CalculateFrequencyResponse(double systemFreq,
+ double initFreq,
+ double endFreq,
+ double stepFreq,
+ double systemPowerBase)
+{
+ // Clear all previous data
+ for(unsigned int i = 0; i < m_busList.size(); i++) {
+ auto data = m_busList[i]->GetElectricalData();
+ data.absImpedanceVector.clear();
+ data.absImpedanceVector.shrink_to_fit();
+ m_busList[i]->SetElectricalData(data);
+ }
+
+ // Create and fill with zeros the YBus
+ std::vector<std::vector<std::complex<double> > > yBus;
+ for(unsigned int i = 0; i < m_busList.size(); i++) {
+ std::vector<std::complex<double> > line;
+ for(unsigned int j = 0; j < m_busList.size(); j++) { line.push_back(std::complex<double>(0.0, 0.0)); }
+ yBus.push_back(line);
+ }
+ // Create and fill with zoros the injected current vector
+ std::vector<std::complex<double> > iInj;
+ for(unsigned int i = 0; i < m_busList.size(); i++) { iInj.push_back(std::complex<double>(10.0, 0.0)); }
+
+ if(initFreq < 1e-6) initFreq = stepFreq;
+ double currentFreq = initFreq;
+ while(currentFreq <= endFreq) {
+ m_frequencyList.push_back(currentFreq);
+
+ double order = currentFreq / systemFreq;
+
+ // Fill YBus with zeros
+ for(unsigned int i = 0; i < m_busList.size(); i++) {
+ for(unsigned int j = 0; j < m_busList.size(); j++) { yBus[i][j] = std::complex<double>(0.0, 0.0); }
+ }
+
+ CalculateHarmonicYbus(yBus, systemPowerBase, order);
+
+ for(unsigned int i = 0; i < m_busList.size(); i++) {
+ auto data = m_busList[i]->GetElectricalData();
+ iInj[data.number] = std::complex<double>(1.0, 0.0);
+
+ auto zh = GaussianElimination(yBus, iInj);
+
+ data.absImpedanceVector.push_back(std::abs(zh[data.number]));
+ m_busList[i]->SetElectricalData(data);
+ iInj[data.number] = std::complex<double>(0.0, 0.0);
+ }
+
+ currentFreq += stepFreq;
+ }
+ return false;
+}
diff --git a/Project/PowerQuality.h b/Project/PowerQuality.h
index ad47884..6c443e3 100644
--- a/Project/PowerQuality.h
+++ b/Project/PowerQuality.h
@@ -22,16 +22,26 @@ class PowerQuality : public ElectricCalculation
};
PowerQuality();
- PowerQuality(std::vector<Element*> elementList);
+ PowerQuality(std::vector<Element *> elementList);
~PowerQuality();
-
+
virtual void CalculateHarmonicYbusList(double systemPowerBase = 100e6);
+ virtual void CalculateHarmonicYbus(std::vector<std::vector<std::complex<double> > > &yBus,
+ double systemPowerBase,
+ double order);
virtual bool CalculateDistortions(double systemPowerBase = 100e6);
+ virtual bool CalculateFrequencyResponse(double systemFreq = 60.0,
+ double initFreq = 0.0,
+ double endFreq = 1500.0,
+ double stepFreq = 1.0,
+ double systemPowerBase = 100e6);
virtual std::vector<double> GetHarmonicOrdersList();
+ virtual std::vector<double> GetFrequencies() { return m_frequencyList; }
protected:
std::vector<HarmonicYbus> m_harmYbusList;
+ std::vector<double> m_frequencyList;
};
#endif // POWERQUALITY_H
diff --git a/Project/PropertiesData.h b/Project/PropertiesData.h
index 127eb59..926b90b 100644
--- a/Project/PropertiesData.h
+++ b/Project/PropertiesData.h
@@ -31,6 +31,7 @@ struct SimulationData {
ElectricalUnit basePowerUnit = UNIT_MVA;
bool faultAfterPowerFlow = false;
bool scPowerAfterPowerFlow = false;
+ bool harmDistortionAfterPowerFlow = false;
// Power flow
PowerFlowMethod powerFlowMethod = GAUSS_SEIDEL;
diff --git a/Project/PropertiesForm.wxcp b/Project/PropertiesForm.wxcp
index 3962cd0..f4f531a 100644
--- a/Project/PropertiesForm.wxcp
+++ b/Project/PropertiesForm.wxcp
@@ -1,7 +1,7 @@
{
"metadata": {
"m_generatedFilesDir": ".",
- "m_objCounter": 815,
+ "m_objCounter": 816,
"m_includeFiles": [],
"m_bitmapFunction": "wxCDAD0InitBitmapResources",
"m_bitmapsFile": "PropertiesFormBitmaps.cpp",
@@ -1531,6 +1531,299 @@
}]
}]
}, {
+ "m_type": 4401,
+ "proportion": 0,
+ "border": 5,
+ "gbSpan": "1,1",
+ "gbPosition": "0,0",
+ "m_styles": [],
+ "m_sizerFlags": ["wxEXPAND"],
+ "m_properties": [{
+ "type": "string",
+ "m_label": "Minimum Size:",
+ "m_value": "-1,-1"
+ }, {
+ "type": "string",
+ "m_label": "Name:",
+ "m_value": "boxSizerLvl3_2"
+ }, {
+ "type": "string",
+ "m_label": "Style:",
+ "m_value": ""
+ }, {
+ "type": "choice",
+ "m_label": "Orientation:",
+ "m_selection": 0,
+ "m_options": ["wxVERTICAL", "wxHORIZONTAL"]
+ }],
+ "m_events": [],
+ "m_children": [{
+ "m_type": 4405,
+ "proportion": 0,
+ "border": 5,
+ "gbSpan": "1,1",
+ "gbPosition": "0,0",
+ "m_styles": [],
+ "m_sizerFlags": ["wxLEFT", "wxRIGHT", "wxTOP", "wxALIGN_CENTER_VERTICAL"],
+ "m_properties": [{
+ "type": "winid",
+ "m_label": "ID:",
+ "m_winid": "wxID_ANY"
+ }, {
+ "type": "string",
+ "m_label": "Size:",
+ "m_value": "-1,-1"
+ }, {
+ "type": "string",
+ "m_label": "Minimum Size:",
+ "m_value": "-1,-1"
+ }, {
+ "type": "string",
+ "m_label": "Name:",
+ "m_value": "m_staticTextFreq"
+ }, {
+ "type": "multi-string",
+ "m_label": "Tooltip:",
+ "m_value": ""
+ }, {
+ "type": "colour",
+ "m_label": "Bg Colour:",
+ "colour": "<Default>"
+ }, {
+ "type": "colour",
+ "m_label": "Fg Colour:",
+ "colour": "<Default>"
+ }, {
+ "type": "font",
+ "m_label": "Font:",
+ "m_value": ""
+ }, {
+ "type": "bool",
+ "m_label": "Hidden",
+ "m_value": false
+ }, {
+ "type": "bool",
+ "m_label": "Disabled",
+ "m_value": false
+ }, {
+ "type": "bool",
+ "m_label": "Focused",
+ "m_value": false
+ }, {
+ "type": "string",
+ "m_label": "Class Name:",
+ "m_value": ""
+ }, {
+ "type": "string",
+ "m_label": "Include File:",
+ "m_value": ""
+ }, {
+ "type": "string",
+ "m_label": "Style:",
+ "m_value": ""
+ }, {
+ "type": "multi-string",
+ "m_label": "Label:",
+ "m_value": "System frequency"
+ }, {
+ "type": "string",
+ "m_label": "Wrap:",
+ "m_value": "-1"
+ }],
+ "m_events": [],
+ "m_children": []
+ }, {
+ "m_type": 4401,
+ "proportion": 0,
+ "border": 5,
+ "gbSpan": "1,1",
+ "gbPosition": "0,0",
+ "m_styles": [],
+ "m_sizerFlags": ["wxEXPAND"],
+ "m_properties": [{
+ "type": "string",
+ "m_label": "Minimum Size:",
+ "m_value": "-1,-1"
+ }, {
+ "type": "string",
+ "m_label": "Name:",
+ "m_value": "boxSizerLvl4_5"
+ }, {
+ "type": "string",
+ "m_label": "Style:",
+ "m_value": ""
+ }, {
+ "type": "choice",
+ "m_label": "Orientation:",
+ "m_selection": 1,
+ "m_options": ["wxVERTICAL", "wxHORIZONTAL"]
+ }],
+ "m_events": [],
+ "m_children": [{
+ "m_type": 4406,
+ "proportion": 1,
+ "border": 5,
+ "gbSpan": "1,1",
+ "gbPosition": "0,0",
+ "m_styles": [],
+ "m_sizerFlags": ["wxLEFT", "wxRIGHT", "wxBOTTOM", "wxALIGN_CENTER_VERTICAL"],
+ "m_properties": [{
+ "type": "winid",
+ "m_label": "ID:",
+ "m_winid": "wxID_ANY"
+ }, {
+ "type": "string",
+ "m_label": "Size:",
+ "m_value": "-1,-1"
+ }, {
+ "type": "string",
+ "m_label": "Minimum Size:",
+ "m_value": "-1,-1"
+ }, {
+ "type": "string",
+ "m_label": "Name:",
+ "m_value": "m_textCtrlFreq"
+ }, {
+ "type": "multi-string",
+ "m_label": "Tooltip:",
+ "m_value": ""
+ }, {
+ "type": "colour",
+ "m_label": "Bg Colour:",
+ "colour": "<Default>"
+ }, {
+ "type": "colour",
+ "m_label": "Fg Colour:",
+ "colour": "<Default>"
+ }, {
+ "type": "font",
+ "m_label": "Font:",
+ "m_value": ""
+ }, {
+ "type": "bool",
+ "m_label": "Hidden",
+ "m_value": false
+ }, {
+ "type": "bool",
+ "m_label": "Disabled",
+ "m_value": false
+ }, {
+ "type": "bool",
+ "m_label": "Focused",
+ "m_value": false
+ }, {
+ "type": "string",
+ "m_label": "Class Name:",
+ "m_value": ""
+ }, {
+ "type": "string",
+ "m_label": "Include File:",
+ "m_value": ""
+ }, {
+ "type": "string",
+ "m_label": "Style:",
+ "m_value": ""
+ }, {
+ "type": "string",
+ "m_label": "Value:",
+ "m_value": "60,0"
+ }, {
+ "type": "string",
+ "m_label": "Text Hint",
+ "m_value": ""
+ }, {
+ "type": "string",
+ "m_label": "Max Length:",
+ "m_value": "0"
+ }, {
+ "type": "bool",
+ "m_label": "Auto Complete Directories:",
+ "m_value": false
+ }, {
+ "type": "bool",
+ "m_label": "Auto Complete Files:",
+ "m_value": false
+ }],
+ "m_events": [],
+ "m_children": []
+ }, {
+ "m_type": 4405,
+ "proportion": 0,
+ "border": 5,
+ "gbSpan": "1,1",
+ "gbPosition": "0,0",
+ "m_styles": [],
+ "m_sizerFlags": ["wxLEFT", "wxRIGHT", "wxBOTTOM", "wxALIGN_CENTER_VERTICAL"],
+ "m_properties": [{
+ "type": "winid",
+ "m_label": "ID:",
+ "m_winid": "wxID_ANY"
+ }, {
+ "type": "string",
+ "m_label": "Size:",
+ "m_value": "-1,-1"
+ }, {
+ "type": "string",
+ "m_label": "Minimum Size:",
+ "m_value": "-1,-1"
+ }, {
+ "type": "string",
+ "m_label": "Name:",
+ "m_value": "m_staticTextFreqUnit"
+ }, {
+ "type": "multi-string",
+ "m_label": "Tooltip:",
+ "m_value": ""
+ }, {
+ "type": "colour",
+ "m_label": "Bg Colour:",
+ "colour": "<Default>"
+ }, {
+ "type": "colour",
+ "m_label": "Fg Colour:",
+ "colour": "<Default>"
+ }, {
+ "type": "font",
+ "m_label": "Font:",
+ "m_value": ""
+ }, {
+ "type": "bool",
+ "m_label": "Hidden",
+ "m_value": false
+ }, {
+ "type": "bool",
+ "m_label": "Disabled",
+ "m_value": false
+ }, {
+ "type": "bool",
+ "m_label": "Focused",
+ "m_value": false
+ }, {
+ "type": "string",
+ "m_label": "Class Name:",
+ "m_value": ""
+ }, {
+ "type": "string",
+ "m_label": "Include File:",
+ "m_value": ""
+ }, {
+ "type": "string",
+ "m_label": "Style:",
+ "m_value": ""
+ }, {
+ "type": "multi-string",
+ "m_label": "Label:",
+ "m_value": "Hz"
+ }, {
+ "type": "string",
+ "m_label": "Wrap:",
+ "m_value": "-1"
+ }],
+ "m_events": [],
+ "m_children": []
+ }]
+ }]
+ }, {
"m_type": 4449,
"proportion": 0,
"border": 5,
@@ -1711,6 +2004,81 @@
}],
"m_events": [],
"m_children": []
+ }, {
+ "m_type": 4415,
+ "proportion": 0,
+ "border": 5,
+ "gbSpan": "1,1",
+ "gbPosition": "0,0",
+ "m_styles": [],
+ "m_sizerFlags": ["wxALL", "wxLEFT", "wxRIGHT", "wxTOP", "wxBOTTOM"],
+ "m_properties": [{
+ "type": "winid",
+ "m_label": "ID:",
+ "m_winid": "wxID_ANY"
+ }, {
+ "type": "string",
+ "m_label": "Size:",
+ "m_value": "-1,-1"
+ }, {
+ "type": "string",
+ "m_label": "Minimum Size:",
+ "m_value": "-1,-1"
+ }, {
+ "type": "string",
+ "m_label": "Name:",
+ "m_value": "m_checkBoxTHDAfterPF"
+ }, {
+ "type": "multi-string",
+ "m_label": "Tooltip:",
+ "m_value": ""
+ }, {
+ "type": "colour",
+ "m_label": "Bg Colour:",
+ "colour": "<Default>"
+ }, {
+ "type": "colour",
+ "m_label": "Fg Colour:",
+ "colour": "<Default>"
+ }, {
+ "type": "font",
+ "m_label": "Font:",
+ "m_value": ""
+ }, {
+ "type": "bool",
+ "m_label": "Hidden",
+ "m_value": false
+ }, {
+ "type": "bool",
+ "m_label": "Disabled",
+ "m_value": false
+ }, {
+ "type": "bool",
+ "m_label": "Focused",
+ "m_value": false
+ }, {
+ "type": "string",
+ "m_label": "Class Name:",
+ "m_value": ""
+ }, {
+ "type": "string",
+ "m_label": "Include File:",
+ "m_value": ""
+ }, {
+ "type": "string",
+ "m_label": "Style:",
+ "m_value": ""
+ }, {
+ "type": "string",
+ "m_label": "Label:",
+ "m_value": "Calculate harmonic distortion after power flow"
+ }, {
+ "type": "bool",
+ "m_label": "Value:",
+ "m_value": true
+ }],
+ "m_events": [],
+ "m_children": []
}]
}]
}]
@@ -3660,299 +4028,6 @@
}, {
"type": "string",
"m_label": "Name:",
- "m_value": "boxSizerLvl3_5"
- }, {
- "type": "string",
- "m_label": "Style:",
- "m_value": ""
- }, {
- "type": "choice",
- "m_label": "Orientation:",
- "m_selection": 0,
- "m_options": ["wxVERTICAL", "wxHORIZONTAL"]
- }],
- "m_events": [],
- "m_children": [{
- "m_type": 4405,
- "proportion": 0,
- "border": 5,
- "gbSpan": "1,1",
- "gbPosition": "0,0",
- "m_styles": [],
- "m_sizerFlags": ["wxLEFT", "wxRIGHT", "wxTOP", "wxALIGN_CENTER_VERTICAL"],
- "m_properties": [{
- "type": "winid",
- "m_label": "ID:",
- "m_winid": "wxID_ANY"
- }, {
- "type": "string",
- "m_label": "Size:",
- "m_value": "-1,-1"
- }, {
- "type": "string",
- "m_label": "Minimum Size:",
- "m_value": "-1,-1"
- }, {
- "type": "string",
- "m_label": "Name:",
- "m_value": "m_staticTextFreq"
- }, {
- "type": "multi-string",
- "m_label": "Tooltip:",
- "m_value": ""
- }, {
- "type": "colour",
- "m_label": "Bg Colour:",
- "colour": "<Default>"
- }, {
- "type": "colour",
- "m_label": "Fg Colour:",
- "colour": "<Default>"
- }, {
- "type": "font",
- "m_label": "Font:",
- "m_value": ""
- }, {
- "type": "bool",
- "m_label": "Hidden",
- "m_value": false
- }, {
- "type": "bool",
- "m_label": "Disabled",
- "m_value": false
- }, {
- "type": "bool",
- "m_label": "Focused",
- "m_value": false
- }, {
- "type": "string",
- "m_label": "Class Name:",
- "m_value": ""
- }, {
- "type": "string",
- "m_label": "Include File:",
- "m_value": ""
- }, {
- "type": "string",
- "m_label": "Style:",
- "m_value": ""
- }, {
- "type": "multi-string",
- "m_label": "Label:",
- "m_value": "System frequency"
- }, {
- "type": "string",
- "m_label": "Wrap:",
- "m_value": "-1"
- }],
- "m_events": [],
- "m_children": []
- }, {
- "m_type": 4401,
- "proportion": 0,
- "border": 5,
- "gbSpan": "1,1",
- "gbPosition": "0,0",
- "m_styles": [],
- "m_sizerFlags": ["wxEXPAND"],
- "m_properties": [{
- "type": "string",
- "m_label": "Minimum Size:",
- "m_value": "-1,-1"
- }, {
- "type": "string",
- "m_label": "Name:",
- "m_value": "boxSizerLvl4_5"
- }, {
- "type": "string",
- "m_label": "Style:",
- "m_value": ""
- }, {
- "type": "choice",
- "m_label": "Orientation:",
- "m_selection": 1,
- "m_options": ["wxVERTICAL", "wxHORIZONTAL"]
- }],
- "m_events": [],
- "m_children": [{
- "m_type": 4406,
- "proportion": 1,
- "border": 5,
- "gbSpan": "1,1",
- "gbPosition": "0,0",
- "m_styles": [],
- "m_sizerFlags": ["wxLEFT", "wxRIGHT", "wxBOTTOM", "wxALIGN_CENTER_VERTICAL"],
- "m_properties": [{
- "type": "winid",
- "m_label": "ID:",
- "m_winid": "wxID_ANY"
- }, {
- "type": "string",
- "m_label": "Size:",
- "m_value": "-1,-1"
- }, {
- "type": "string",
- "m_label": "Minimum Size:",
- "m_value": "-1,-1"
- }, {
- "type": "string",
- "m_label": "Name:",
- "m_value": "m_textCtrlFreq"
- }, {
- "type": "multi-string",
- "m_label": "Tooltip:",
- "m_value": ""
- }, {
- "type": "colour",
- "m_label": "Bg Colour:",
- "colour": "<Default>"
- }, {
- "type": "colour",
- "m_label": "Fg Colour:",
- "colour": "<Default>"
- }, {
- "type": "font",
- "m_label": "Font:",
- "m_value": ""
- }, {
- "type": "bool",
- "m_label": "Hidden",
- "m_value": false
- }, {
- "type": "bool",
- "m_label": "Disabled",
- "m_value": false
- }, {
- "type": "bool",
- "m_label": "Focused",
- "m_value": false
- }, {
- "type": "string",
- "m_label": "Class Name:",
- "m_value": ""
- }, {
- "type": "string",
- "m_label": "Include File:",
- "m_value": ""
- }, {
- "type": "string",
- "m_label": "Style:",
- "m_value": ""
- }, {
- "type": "string",
- "m_label": "Value:",
- "m_value": "60,0"
- }, {
- "type": "string",
- "m_label": "Text Hint",
- "m_value": ""
- }, {
- "type": "string",
- "m_label": "Max Length:",
- "m_value": "0"
- }, {
- "type": "bool",
- "m_label": "Auto Complete Directories:",
- "m_value": false
- }, {
- "type": "bool",
- "m_label": "Auto Complete Files:",
- "m_value": false
- }],
- "m_events": [],
- "m_children": []
- }, {
- "m_type": 4405,
- "proportion": 0,
- "border": 5,
- "gbSpan": "1,1",
- "gbPosition": "0,0",
- "m_styles": [],
- "m_sizerFlags": ["wxLEFT", "wxRIGHT", "wxBOTTOM", "wxALIGN_CENTER_VERTICAL"],
- "m_properties": [{
- "type": "winid",
- "m_label": "ID:",
- "m_winid": "wxID_ANY"
- }, {
- "type": "string",
- "m_label": "Size:",
- "m_value": "-1,-1"
- }, {
- "type": "string",
- "m_label": "Minimum Size:",
- "m_value": "-1,-1"
- }, {
- "type": "string",
- "m_label": "Name:",
- "m_value": "m_staticTextFreqUnit"
- }, {
- "type": "multi-string",
- "m_label": "Tooltip:",
- "m_value": ""
- }, {
- "type": "colour",
- "m_label": "Bg Colour:",
- "colour": "<Default>"
- }, {
- "type": "colour",
- "m_label": "Fg Colour:",
- "colour": "<Default>"
- }, {
- "type": "font",
- "m_label": "Font:",
- "m_value": ""
- }, {
- "type": "bool",
- "m_label": "Hidden",
- "m_value": false
- }, {
- "type": "bool",
- "m_label": "Disabled",
- "m_value": false
- }, {
- "type": "bool",
- "m_label": "Focused",
- "m_value": false
- }, {
- "type": "string",
- "m_label": "Class Name:",
- "m_value": ""
- }, {
- "type": "string",
- "m_label": "Include File:",
- "m_value": ""
- }, {
- "type": "string",
- "m_label": "Style:",
- "m_value": ""
- }, {
- "type": "multi-string",
- "m_label": "Label:",
- "m_value": "Hz"
- }, {
- "type": "string",
- "m_label": "Wrap:",
- "m_value": "-1"
- }],
- "m_events": [],
- "m_children": []
- }]
- }]
- }, {
- "m_type": 4401,
- "proportion": 0,
- "border": 5,
- "gbSpan": "1,1",
- "gbPosition": "0,0",
- "m_styles": [],
- "m_sizerFlags": ["wxEXPAND"],
- "m_properties": [{
- "type": "string",
- "m_label": "Minimum Size:",
- "m_value": "-1,-1"
- }, {
- "type": "string",
- "m_label": "Name:",
"m_value": "boxSizerLvl3_8"
}, {
"type": "string",
diff --git a/Project/PropertiesFormBase.cpp b/Project/PropertiesFormBase.cpp
index 62f2c0d..e76b211 100644
--- a/Project/PropertiesFormBase.cpp
+++ b/Project/PropertiesFormBase.cpp
@@ -190,6 +190,33 @@ SimulationsSettingsFormBase::SimulationsSettingsFormBase(wxWindow* parent,
boxSizerLvl4_1->Add(m_choiceBasePower, 0, wxLEFT | wxRIGHT | wxBOTTOM, WXC_FROM_DIP(5));
+ wxBoxSizer* boxSizerLvl3_2 = new wxBoxSizer(wxVERTICAL);
+
+ boxSizerLvl2_1->Add(boxSizerLvl3_2, 0, wxEXPAND, WXC_FROM_DIP(5));
+
+ m_staticTextFreq = new wxStaticText(m_panelGeneral, wxID_ANY, _("System frequency"), wxDefaultPosition,
+ wxDLG_UNIT(m_panelGeneral, wxSize(-1, -1)), 0);
+
+ boxSizerLvl3_2->Add(m_staticTextFreq, 0, wxLEFT | wxRIGHT | wxTOP | wxALIGN_CENTER_VERTICAL, WXC_FROM_DIP(5));
+
+ wxBoxSizer* boxSizerLvl4_5 = new wxBoxSizer(wxHORIZONTAL);
+
+ boxSizerLvl3_2->Add(boxSizerLvl4_5, 0, wxEXPAND, WXC_FROM_DIP(5));
+
+ m_textCtrlFreq = new wxTextCtrl(m_panelGeneral, wxID_ANY, wxT("60,0"), wxDefaultPosition,
+ wxDLG_UNIT(m_panelGeneral, wxSize(-1, -1)), 0);
+#if wxVERSION_NUMBER >= 3000
+ m_textCtrlFreq->SetHint(wxT(""));
+#endif
+
+ boxSizerLvl4_5->Add(m_textCtrlFreq, 1, wxLEFT | wxRIGHT | wxBOTTOM | wxALIGN_CENTER_VERTICAL, WXC_FROM_DIP(5));
+
+ m_staticTextFreqUnit = new wxStaticText(m_panelGeneral, wxID_ANY, _("Hz"), wxDefaultPosition,
+ wxDLG_UNIT(m_panelGeneral, wxSize(-1, -1)), 0);
+
+ boxSizerLvl4_5->Add(m_staticTextFreqUnit, 0, wxLEFT | wxRIGHT | wxBOTTOM | wxALIGN_CENTER_VERTICAL,
+ WXC_FROM_DIP(5));
+
wxStaticBoxSizer* staticBoxSizerLvl3_2 =
new wxStaticBoxSizer(new wxStaticBox(m_panelGeneral, wxID_ANY, _("Continuous calculation")), wxVERTICAL);
@@ -208,6 +235,12 @@ SimulationsSettingsFormBase::SimulationsSettingsFormBase(wxWindow* parent,
staticBoxSizerLvl3_2->Add(m_checkBoxSCPowerAfterPF, 0, wxALL, WXC_FROM_DIP(5));
+ m_checkBoxTHDAfterPF = new wxCheckBox(m_panelGeneral, wxID_ANY, _("Calculate harmonic distortion after power flow"),
+ wxDefaultPosition, wxDLG_UNIT(m_panelGeneral, wxSize(-1, -1)), 0);
+ m_checkBoxTHDAfterPF->SetValue(true);
+
+ staticBoxSizerLvl3_2->Add(m_checkBoxTHDAfterPF, 0, wxALL, WXC_FROM_DIP(5));
+
m_panelPF =
new wxPanel(m_notebook, wxID_ANY, wxDefaultPosition, wxDLG_UNIT(m_notebook, wxSize(-1, -1)), wxTAB_TRAVERSAL);
m_notebook->AddPage(m_panelPF, _("Power flow"), false);
@@ -385,33 +418,6 @@ SimulationsSettingsFormBase::SimulationsSettingsFormBase(wxWindow* parent,
boxSizerLvl4_7->Add(m_staticTextSec_2, 0, wxLEFT | wxRIGHT | wxBOTTOM | wxALIGN_CENTER_VERTICAL, WXC_FROM_DIP(5));
- wxBoxSizer* boxSizerLvl3_5 = new wxBoxSizer(wxVERTICAL);
-
- gridSizerLvl_2_3->Add(boxSizerLvl3_5, 0, wxEXPAND, WXC_FROM_DIP(5));
-
- m_staticTextFreq = new wxStaticText(m_panelStability, wxID_ANY, _("System frequency"), wxDefaultPosition,
- wxDLG_UNIT(m_panelStability, wxSize(-1, -1)), 0);
-
- boxSizerLvl3_5->Add(m_staticTextFreq, 0, wxLEFT | wxRIGHT | wxTOP | wxALIGN_CENTER_VERTICAL, WXC_FROM_DIP(5));
-
- wxBoxSizer* boxSizerLvl4_5 = new wxBoxSizer(wxHORIZONTAL);
-
- boxSizerLvl3_5->Add(boxSizerLvl4_5, 0, wxEXPAND, WXC_FROM_DIP(5));
-
- m_textCtrlFreq = new wxTextCtrl(m_panelStability, wxID_ANY, wxT("60,0"), wxDefaultPosition,
- wxDLG_UNIT(m_panelStability, wxSize(-1, -1)), 0);
-#if wxVERSION_NUMBER >= 3000
- m_textCtrlFreq->SetHint(wxT(""));
-#endif
-
- boxSizerLvl4_5->Add(m_textCtrlFreq, 1, wxLEFT | wxRIGHT | wxBOTTOM | wxALIGN_CENTER_VERTICAL, WXC_FROM_DIP(5));
-
- m_staticTextFreqUnit = new wxStaticText(m_panelStability, wxID_ANY, _("Hz"), wxDefaultPosition,
- wxDLG_UNIT(m_panelStability, wxSize(-1, -1)), 0);
-
- boxSizerLvl4_5->Add(m_staticTextFreqUnit, 0, wxLEFT | wxRIGHT | wxBOTTOM | wxALIGN_CENTER_VERTICAL,
- WXC_FROM_DIP(5));
-
wxBoxSizer* boxSizerLvl3_8 = new wxBoxSizer(wxVERTICAL);
gridSizerLvl_2_3->Add(boxSizerLvl3_8, 0, wxEXPAND, WXC_FROM_DIP(5));
diff --git a/Project/PropertiesFormBase.h b/Project/PropertiesFormBase.h
index f0a579b..d7d4dce 100644
--- a/Project/PropertiesFormBase.h
+++ b/Project/PropertiesFormBase.h
@@ -7,32 +7,32 @@
#ifndef _PSP_PROJECT_PROPERTIESFORM_BASE_CLASSES_H
#define _PSP_PROJECT_PROPERTIESFORM_BASE_CLASSES_H
-#include <wx/settings.h>
-#include <wx/xrc/xmlres.h>
-#include <wx/xrc/xh_bmp.h>
+#include <wx/arrstr.h>
+#include <wx/artprov.h>
+#include <wx/button.h>
+#include <wx/checkbox.h>
+#include <wx/choice.h>
#include <wx/dialog.h>
+#include <wx/filepicker.h>
+#include <wx/grid.h>
+#include <wx/hyperlink.h>
#include <wx/iconbndl.h>
-#include <wx/artprov.h>
-#include <wx/sizer.h>
+#include <wx/imaglist.h>
#include <wx/notebook.h>
#include <wx/panel.h>
-#include <wx/imaglist.h>
+#include <wx/richtext/richtextctrl.h>
+#include <wx/settings.h>
+#include <wx/sizer.h>
+#include <wx/statbmp.h>
+#include <wx/statbox.h>
#include <wx/stattext.h>
-#include <wx/choice.h>
-#include <wx/arrstr.h>
-#include <wx/button.h>
#include <wx/textctrl.h>
-#include <wx/statbox.h>
-#include <wx/checkbox.h>
-#include <wx/statbmp.h>
-#include <wx/grid.h>
-#include <wx/richtext/richtextctrl.h>
-#include <wx/hyperlink.h>
-#include <wx/filepicker.h>
+#include <wx/xrc/xh_bmp.h>
+#include <wx/xrc/xmlres.h>
#if wxVERSION_NUMBER >= 2900
#include <wx/persist.h>
-#include <wx/persist/toplevel.h>
#include <wx/persist/bookctrl.h>
+#include <wx/persist/toplevel.h>
#include <wx/persist/treebook.h>
#endif
@@ -45,10 +45,9 @@
#define WXC_FROM_DIP(x) x
#endif
-
class GeneralPropertiesFormBase : public wxDialog
{
-protected:
+ protected:
wxNotebook* m_notebook;
wxPanel* m_panelGeneral;
wxStaticText* m_staticTextLanguage;
@@ -58,11 +57,11 @@ protected:
wxButton* m_buttonOK;
wxButton* m_buttonCancel;
-protected:
+ protected:
virtual void OnButtonOKClick(wxCommandEvent& event) { event.Skip(); }
virtual void OnButtonCancelClick(wxCommandEvent& event) { event.Skip(); }
-public:
+ public:
wxStaticText* GetStaticTextLanguage() { return m_staticTextLanguage; }
wxChoice* GetChoiceLanguage() { return m_choiceLanguage; }
wxStaticText* GetStaticTextTheme() { return m_staticTextTheme; }
@@ -71,21 +70,29 @@ public:
wxNotebook* GetNotebook() { return m_notebook; }
wxButton* GetButtonOK() { return m_buttonOK; }
wxButton* GetButtonCancel() { return m_buttonCancel; }
- GeneralPropertiesFormBase(wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("General settings"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize(-1,-1), long style = wxDEFAULT_DIALOG_STYLE);
+ GeneralPropertiesFormBase(wxWindow* parent,
+ wxWindowID id = wxID_ANY,
+ const wxString& title = _("General settings"),
+ const wxPoint& pos = wxDefaultPosition,
+ const wxSize& size = wxSize(-1, -1),
+ long style = wxDEFAULT_DIALOG_STYLE);
virtual ~GeneralPropertiesFormBase();
};
-
class SimulationsSettingsFormBase : public wxDialog
{
-protected:
+ protected:
wxNotebook* m_notebook;
wxPanel* m_panelGeneral;
wxStaticText* m_staticTextBasePower;
wxTextCtrl* m_textCtrlbasePower;
wxChoice* m_choiceBasePower;
+ wxStaticText* m_staticTextFreq;
+ wxTextCtrl* m_textCtrlFreq;
+ wxStaticText* m_staticTextFreqUnit;
wxCheckBox* m_checkBoxFaultAfterPF;
wxCheckBox* m_checkBoxSCPowerAfterPF;
+ wxCheckBox* m_checkBoxTHDAfterPF;
wxPanel* m_panelPF;
wxStaticText* m_staticTextPFMethod;
wxChoice* m_choicePFMethod;
@@ -105,9 +112,6 @@ protected:
wxStaticText* m_staticTextTSimTime;
wxTextCtrl* m_textCtrlSimTime;
wxStaticText* m_staticTextSec_2;
- wxStaticText* m_staticTextFreq;
- wxTextCtrl* m_textCtrlFreq;
- wxStaticText* m_staticTextFreqUnit;
wxStaticText* m_staticTextTStabTolerance;
wxTextCtrl* m_textCtrlStabTolerance;
wxStaticText* m_staticTextTStabMaxIterations;
@@ -148,18 +152,22 @@ protected:
wxButton* m_buttonOK;
wxButton* m_buttonCancel;
-protected:
+ protected:
virtual void OnPFMethodChoiceSelected(wxCommandEvent& event) { event.Skip(); }
virtual void OnCheckboxUseCompLoadClick(wxCommandEvent& event) { event.Skip(); }
virtual void OnButtonOKClick(wxCommandEvent& event) { event.Skip(); }
virtual void OnButtonCancelClick(wxCommandEvent& event) { event.Skip(); }
-public:
+ public:
wxStaticText* GetStaticTextBasePower() { return m_staticTextBasePower; }
wxTextCtrl* GetTextCtrlbasePower() { return m_textCtrlbasePower; }
wxChoice* GetChoiceBasePower() { return m_choiceBasePower; }
+ wxStaticText* GetStaticTextFreq() { return m_staticTextFreq; }
+ wxTextCtrl* GetTextCtrlFreq() { return m_textCtrlFreq; }
+ wxStaticText* GetStaticTextFreqUnit() { return m_staticTextFreqUnit; }
wxCheckBox* GetCheckBoxFaultAfterPF() { return m_checkBoxFaultAfterPF; }
wxCheckBox* GetCheckBoxSCPowerAfterPF() { return m_checkBoxSCPowerAfterPF; }
+ wxCheckBox* GetCheckBoxTHDAfterPF() { return m_checkBoxTHDAfterPF; }
wxPanel* GetPanelGeneral() { return m_panelGeneral; }
wxStaticText* GetStaticTextPFMethod() { return m_staticTextPFMethod; }
wxChoice* GetChoicePFMethod() { return m_choicePFMethod; }
@@ -179,9 +187,6 @@ public:
wxStaticText* GetStaticTextTSimTime() { return m_staticTextTSimTime; }
wxTextCtrl* GetTextCtrlSimTime() { return m_textCtrlSimTime; }
wxStaticText* GetStaticTextSec_2() { return m_staticTextSec_2; }
- wxStaticText* GetStaticTextFreq() { return m_staticTextFreq; }
- wxTextCtrl* GetTextCtrlFreq() { return m_textCtrlFreq; }
- wxStaticText* GetStaticTextFreqUnit() { return m_staticTextFreqUnit; }
wxStaticText* GetStaticTextTStabTolerance() { return m_staticTextTStabTolerance; }
wxTextCtrl* GetTextCtrlStabTolerance() { return m_textCtrlStabTolerance; }
wxStaticText* GetStaticTextTStabMaxIterations() { return m_staticTextTStabMaxIterations; }
@@ -223,14 +228,18 @@ public:
wxNotebook* GetNotebook() { return m_notebook; }
wxButton* GetButtonOK() { return m_buttonOK; }
wxButton* GetButtonCancel() { return m_buttonCancel; }
- SimulationsSettingsFormBase(wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Simulation settings"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize(-1,-1), long style = wxDEFAULT_DIALOG_STYLE);
+ SimulationsSettingsFormBase(wxWindow* parent,
+ wxWindowID id = wxID_ANY,
+ const wxString& title = _("Simulation settings"),
+ const wxPoint& pos = wxDefaultPosition,
+ const wxSize& size = wxSize(-1, -1),
+ long style = wxDEFAULT_DIALOG_STYLE);
virtual ~SimulationsSettingsFormBase();
};
-
class AboutFormBase : public wxDialog
{
-protected:
+ protected:
wxNotebook* m_notebook;
wxPanel* m_panelLogo;
wxStaticBitmap* m_staticBitmapLogo;
@@ -244,10 +253,10 @@ protected:
wxHyperlinkCtrl* m_hyperLinkPSP;
wxButton* m_buttonOK;
-protected:
+ protected:
virtual void OnOKButtonClick(wxCommandEvent& event) { event.Skip(); }
-public:
+ public:
wxStaticBitmap* GetStaticBitmapLogo() { return m_staticBitmapLogo; }
wxPanel* GetPanelLogo() { return m_panelLogo; }
wxGrid* GetGridCredits() { return m_gridCredits; }
@@ -260,14 +269,18 @@ public:
wxStaticText* GetStaticTextHome() { return m_staticTextHome; }
wxHyperlinkCtrl* GetHyperLinkPSP() { return m_hyperLinkPSP; }
wxButton* GetButtonOK() { return m_buttonOK; }
- AboutFormBase(wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("About PSP-UFU"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize(-1,-1), long style = wxDEFAULT_DIALOG_STYLE);
+ AboutFormBase(wxWindow* parent,
+ wxWindowID id = wxID_ANY,
+ const wxString& title = _("About PSP-UFU"),
+ const wxPoint& pos = wxDefaultPosition,
+ const wxSize& size = wxSize(-1, -1),
+ long style = wxDEFAULT_DIALOG_STYLE);
virtual ~AboutFormBase();
};
-
class ImportFormBase : public wxDialog
{
-protected:
+ protected:
wxNotebook* m_notebook;
wxPanel* m_panelCEPEL;
wxStaticText* m_staticTextBasePWFFile;
@@ -286,11 +299,11 @@ protected:
wxButton* m_buttonOK;
wxButton* m_buttonCancel;
-protected:
+ protected:
virtual void OnButtonOKClick(wxCommandEvent& event) { event.Skip(); }
virtual void OnButtonCancelClick(wxCommandEvent& event) { event.Skip(); }
-public:
+ public:
wxStaticText* GetStaticTextBasePWFFile() { return m_staticTextBasePWFFile; }
wxFilePickerCtrl* GetFilePickerANAREDEPWF() { return m_filePickerANAREDEPWF; }
wxStaticText* GetStaticTextBaseLSTFile() { return m_staticTextBaseLSTFile; }
@@ -308,7 +321,12 @@ public:
wxNotebook* GetNotebook() { return m_notebook; }
wxButton* GetButtonOK() { return m_buttonOK; }
wxButton* GetButtonCancel() { return m_buttonCancel; }
- ImportFormBase(wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Import files"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize(-1,-1), long style = wxDEFAULT_DIALOG_STYLE);
+ ImportFormBase(wxWindow* parent,
+ wxWindowID id = wxID_ANY,
+ const wxString& title = _("Import files"),
+ const wxPoint& pos = wxDefaultPosition,
+ const wxSize& size = wxSize(-1, -1),
+ long style = wxDEFAULT_DIALOG_STYLE);
virtual ~ImportFormBase();
};
diff --git a/Project/SimulationsSettingsForm.cpp b/Project/SimulationsSettingsForm.cpp
index b7878d5..2947638 100644
--- a/Project/SimulationsSettingsForm.cpp
+++ b/Project/SimulationsSettingsForm.cpp
@@ -41,6 +41,7 @@ SimulationsSettingsForm::SimulationsSettingsForm(wxWindow* parent, PropertiesDat
}
m_checkBoxFaultAfterPF->SetValue(data.faultAfterPowerFlow);
m_checkBoxSCPowerAfterPF->SetValue(data.scPowerAfterPowerFlow);
+ m_checkBoxTHDAfterPF->SetValue(data.harmDistortionAfterPowerFlow);
switch(data.powerFlowMethod) {
case GAUSS_SEIDEL: {
m_choicePFMethod->SetSelection(0);
@@ -107,6 +108,7 @@ bool SimulationsSettingsForm::ValidateData()
}
data.faultAfterPowerFlow = m_checkBoxFaultAfterPF->GetValue();
data.scPowerAfterPowerFlow = m_checkBoxSCPowerAfterPF->GetValue();
+ data.harmDistortionAfterPowerFlow = m_checkBoxTHDAfterPF->GetValue();
switch(m_choicePFMethod->GetSelection()) {
case 0: {
data.powerFlowMethod = GAUSS_SEIDEL;
diff --git a/Project/SyncGenerator.cpp b/Project/SyncGenerator.cpp
index c988a7e..78082d2 100644
--- a/Project/SyncGenerator.cpp
+++ b/Project/SyncGenerator.cpp
@@ -223,7 +223,7 @@ wxString SyncGenerator::GetTipText() const
return tipText;
}
-bool SyncGenerator::GetPlotData(ElementPlotData& plotData)
+bool SyncGenerator::GetPlotData(ElementPlotData& plotData, PlotStudy study)
{
if(!m_electricalData.plotSyncMachine) return false;
plotData.SetName(m_electricalData.name);
diff --git a/Project/SyncGenerator.h b/Project/SyncGenerator.h
index 70c4142..1a25a0e 100644
--- a/Project/SyncGenerator.h
+++ b/Project/SyncGenerator.h
@@ -156,7 +156,7 @@ class SyncGenerator : public Machines
virtual void SetElectricalData(SyncGeneratorElectricalData electricalData) { m_electricalData = electricalData; }
virtual void SetNominalVoltage(std::vector<double> nominalVoltage, std::vector<ElectricalUnit> nominalVoltageUnit);
virtual void SavePlotData();
- virtual bool GetPlotData(ElementPlotData& plotData);
+ virtual bool GetPlotData(ElementPlotData& plotData, PlotStudy study = STABILITY);
virtual rapidxml::xml_node<>* SaveElement(rapidxml::xml_document<>& doc, rapidxml::xml_node<>* elementListNode);
virtual bool OpenElement(rapidxml::xml_node<>* elementNode, std::vector<Element*> parentList);
diff --git a/Project/Text.cpp b/Project/Text.cpp
index 0697ac5..f73b425 100644
--- a/Project/Text.cpp
+++ b/Project/Text.cpp
@@ -270,6 +270,9 @@ void Text::UpdateText(double systemPowerBase)
break;
}
} break;
+ case DATA_PQ_THD: {
+ SetText("THD = " + wxString::FromDouble(data.thd, m_decimalPlaces) + "\%");
+ } break;
default:
break;
}
@@ -913,6 +916,19 @@ void Text::UpdateText(double systemPowerBase)
}
}
} break;
+ case TYPE_HARMCURRENT: {
+ HarmCurrent* harmCurrent = static_cast<HarmCurrent*>(m_element);
+ if(harmCurrent) {
+ auto data = harmCurrent->GetElectricalData();
+ switch(m_dataType) {
+ case DATA_NAME: {
+ SetText(data.name);
+ } break;
+ default:
+ break;
+ }
+ }
+ } break;
}
}
diff --git a/Project/Text.h b/Project/Text.h
index 56fc821..19e3876 100644
--- a/Project/Text.h
+++ b/Project/Text.h
@@ -64,7 +64,8 @@ enum DataType {
DATA_PF_ACTIVE,
DATA_PF_REACTIVE,
DATA_PF_LOSSES,
- DATA_PF_CURRENT
+ DATA_PF_CURRENT,
+ DATA_PQ_THD
};
/**
diff --git a/Project/TextForm.cpp b/Project/TextForm.cpp
index 993593c..30497fd 100644
--- a/Project/TextForm.cpp
+++ b/Project/TextForm.cpp
@@ -131,6 +131,9 @@ void TextForm::OnTypeChoiceSelected(wxCommandEvent& event)
case 5: {
m_text->SetDataType(DATA_SC_POWER);
} break;
+ case 6: {
+ m_text->SetDataType(DATA_PQ_THD);
+ } break;
}
} break;
case TYPE_SYNC_GENERATOR: {
@@ -203,7 +206,7 @@ void TextForm::OnTypeChoiceSelected(wxCommandEvent& event)
}
DataTypeChoice();
- if(m_text->GetDataType() == DATA_NAME) Preview();
+ if(m_text->GetDataType() == DATA_NAME || m_text->GetDataType() == DATA_PQ_THD) Preview();
}
bool TextForm::LoadChoices()
@@ -305,6 +308,9 @@ bool TextForm::LoadChoices()
break;
}
} break;
+ case DATA_PQ_THD: {
+ m_choiceTextType->SetSelection(6);
+ } break;
default:
break;
}
@@ -875,6 +881,7 @@ void TextForm::ElementNumberChoice()
arrayString.Add(_("Fault current"));
arrayString.Add(_("Fault voltage"));
arrayString.Add(_("Short-circuit power"));
+ arrayString.Add(_("Voltage THD"));
} break;
case TYPE_SYNC_GENERATOR: {
SyncGenerator* syncGenerator = m_allElements.GetSyncGeneratorList()[index];
@@ -966,7 +973,8 @@ void TextForm::DataTypeChoice()
wxArrayString arrayString;
switch(m_text->GetDataType()) {
- case DATA_NAME: {
+ case DATA_NAME:
+ case DATA_PQ_THD: {
m_choiceTextUnit->Enable(false);
return;
} break;
@@ -1191,7 +1199,9 @@ bool TextForm::ValidateData()
if(m_choiceElement->GetSelection() == -1) return false;
if(m_choiceName->GetSelection() == -1) return false;
if(m_choiceTextType->GetSelection() == -1) return false;
- if(m_text->GetDataType() != DATA_NAME && m_choiceTextUnit->GetSelection() == -1) return false;
+ if(m_text->GetDataType() != DATA_NAME && m_text->GetDataType() != DATA_PQ_THD &&
+ m_choiceTextUnit->GetSelection() == -1)
+ return false;
if(m_text->GetElementType() == TYPE_LINE || m_text->GetElementType() == TYPE_TRANSFORMER) {
if(m_text->GetDataType() != DATA_PF_LOSSES && m_text->GetDataType() != DATA_NAME) {
if(m_choiceTextFromBus->GetSelection() == -1) return false;
diff --git a/Project/Workspace.cpp b/Project/Workspace.cpp
index a17faae..6b8d197 100644
--- a/Project/Workspace.cpp
+++ b/Project/Workspace.cpp
@@ -1491,8 +1491,8 @@ void Workspace::OnMiddleDoubleClick(wxMouseEvent& event)
bool Workspace::RunStaticStudies()
{
- bool pfStatus, faultStatus, scStatus;
- pfStatus = faultStatus = scStatus = false;
+ bool pfStatus, faultStatus, scStatus, harmStatus;
+ pfStatus = faultStatus = scStatus = harmStatus = false;
pfStatus = RunPowerFlow();
@@ -1507,8 +1507,14 @@ bool Workspace::RunStaticStudies()
} else {
scStatus = true;
}
+
+ if(m_properties->GetSimulationPropertiesData().harmDistortionAfterPowerFlow) {
+ if(pfStatus) harmStatus = RunHarmonicDistortion();
+ } else {
+ harmStatus = true;
+ }
- if(pfStatus && faultStatus && scStatus) return true;
+ if(pfStatus && faultStatus && scStatus && harmStatus) return true;
return false;
}
@@ -1523,5 +1529,43 @@ bool Workspace::RunHarmonicDistortion()
basePower *= 1e3;
if(!RunPowerFlow()) return false;
PowerQuality pq(GetElementList());
- return pq.CalculateDistortions(basePower);
+ bool result = pq.CalculateDistortions(basePower);
+
+ UpdateTextElements();
+ Redraw();
+
+ return result;
+}
+
+bool Workspace::RunFrequencyResponse()
+{
+ auto simProp = m_properties->GetSimulationPropertiesData();
+ double basePower = simProp.basePower;
+ if(simProp.basePowerUnit == UNIT_MVA)
+ basePower *= 1e6;
+ else if(simProp.basePowerUnit == UNIT_kVA)
+ basePower *= 1e3;
+ PowerQuality pq(GetElementList());
+ bool result = pq.CalculateFrequencyResponse(simProp.stabilityFrequency, 0.0, 1500.0, 1.0, basePower);
+
+ wxMessageDialog msgDialog(
+ this,
+ wxString::Format(_("Calculations done.\nDo you wish to open the frequency response graphics?")),
+ _("Question"), wxYES_NO | wxCENTRE | wxICON_QUESTION);
+ if(msgDialog.ShowModal() == wxID_YES) {
+ std::vector<ElementPlotData> plotDataList;
+ for(auto it = m_elementList.begin(), itEnd = m_elementList.end(); it != itEnd; ++it) {
+ PowerElement* element = *it;
+ ElementPlotData plotData;
+ if(element->GetPlotData(plotData, FREQRESPONSE)) plotDataList.push_back(plotData);
+ }
+
+ ChartView* cView = new ChartView(this, plotDataList, pq.GetFrequencies());
+ cView->Show();
+ }
+
+ UpdateTextElements();
+ Redraw();
+
+ return result;
}
diff --git a/Project/Workspace.h b/Project/Workspace.h
index 38c5356..afcb1b3 100644
--- a/Project/Workspace.h
+++ b/Project/Workspace.h
@@ -149,6 +149,7 @@ class Workspace : public WorkspaceBase
bool RunStaticStudies();
bool RunStability();
bool RunHarmonicDistortion();
+ bool RunFrequencyResponse();
protected:
virtual void OnMiddleDoubleClick(wxMouseEvent& event);