Power System Platform  2026w11a-beta
Loading...
Searching...
No Matches
SyncMotor.cpp
1/*
2 * Copyright (C) 2017 Thales Lima Oliveira <thales@ufu.br>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 */
17
18#include "../../forms/SyncMachineForm.h"
19#include <memory>
20#include "../controlElement/ControlElementContainer.h"
21#include "SyncMotor.h"
22
23SyncMotor::SyncMotor() : Machines()
24{
25 m_elementType = TYPE_SYNC_MOTOR;
26}
27
28SyncMotor::SyncMotor(wxString name) : Machines()
29{
30 m_elementType = TYPE_SYNC_MOTOR;
31 m_electricalData.name = name;
32}
33
34SyncMotor::~SyncMotor()
35{
36 if (m_electricalData.avr) delete m_electricalData.avr;
37 if (m_electricalData.speedGov) delete m_electricalData.speedGov;
38 if (m_electricalData.avrSolver) delete m_electricalData.avrSolver;
39 if (m_electricalData.speedGovSolver) delete m_electricalData.speedGovSolver;
40}
41
42//void SyncMotor::DrawSymbol() const { DrawArc(m_position, 12, 30, 330, 10, GL_LINE_STRIP); }
43void SyncMotor::DrawDCSymbol(wxGraphicsContext* gc) const
44{
45 DrawDCArc(m_position, 12, 30, 330, 10, gc);
46}
47
48void SyncMotor::DrawDCSymbol(wxDC& dc) const
49{
50 DrawDCArc(m_position, 12, 30, 330, dc);
51}
52
53bool SyncMotor::GetContextMenu(wxMenu& menu)
54{
55 menu.Append(ID_EDIT_ELEMENT, _("Edit Synchronous Condenser"));
56
57 wxMenu* textMenu = new wxMenu();
58
59 textMenu->Append(ID_TXT_NAME, _("Name"));
60 textMenu->Append(ID_TXT_ACTIVE_POWER, _("Active power"));
61 textMenu->Append(ID_TXT_REACTIVE_POWER, _("Reactive power"));
62 textMenu->SetClientData(menu.GetClientData());
63 menu.AppendSubMenu(textMenu, _("Add text"));
64
65 GeneralMenuItens(menu);
66
67 return true;
68}
69
70bool SyncMotor::ShowForm(wxWindow* parent, Element* element, wxWindow* workspace)
71{
72 SyncMachineForm syncMotorForm(parent, this);
73 syncMotorForm.SetTitle(_("Synchronous Condenser"));
74 syncMotorForm.CenterOnParent();
75 if (syncMotorForm.ShowModal() == wxID_OK) {
76 return true;
77 }
78 return false;
79}
80
81SyncMotorElectricalData SyncMotor::GetPUElectricalData(double systemPowerBase)
82{
83 SyncMotorElectricalData data = m_electricalData;
84 double machineBasePower = 1.0;
85 if (data.useMachineBase) { machineBasePower = GetValueFromUnit(data.nominalPower, data.nominalPowerUnit); }
86
87 // Active power
88 double activePower = GetValueFromUnit(data.activePower, data.activePowerUnit);
89 if (!m_online) activePower = 0.0;
90 if (data.activePowerUnit == ElectricalUnit::UNIT_PU) {
91 if (data.useMachineBase) data.activePower = (activePower * machineBasePower) / systemPowerBase;
92 }
93 else {
94 data.activePower = activePower / systemPowerBase;
95 }
96 data.activePowerUnit = ElectricalUnit::UNIT_PU;
97
98 // Reactive power
99 double reactivePower = GetValueFromUnit(data.reactivePower, data.reactivePowerUnit);
100 if (!m_online) reactivePower = 0.0;
101 if (data.reactivePowerUnit == ElectricalUnit::UNIT_PU) {
102 if (data.useMachineBase) data.reactivePower = (reactivePower * machineBasePower) / systemPowerBase;
103 }
104 else {
105 data.reactivePower = reactivePower / systemPowerBase;
106 }
107 data.reactivePowerUnit = ElectricalUnit::UNIT_PU;
108
109 // Max reactive power
110 double maxReactive = GetValueFromUnit(data.maxReactive, data.maxReactiveUnit);
111 if (data.maxReactiveUnit == ElectricalUnit::UNIT_PU) {
112 if (data.useMachineBase) data.maxReactive = (maxReactive * machineBasePower) / systemPowerBase;
113 }
114 else {
115 data.maxReactive = maxReactive / systemPowerBase;
116 }
117 data.maxReactiveUnit = ElectricalUnit::UNIT_PU;
118
119 // Min reactive power
120 double minReactive = GetValueFromUnit(data.minReactive, data.minReactiveUnit);
121 if (data.minReactiveUnit == ElectricalUnit::UNIT_PU) {
122 if (data.useMachineBase) data.minReactive = (minReactive * machineBasePower) / systemPowerBase;
123 }
124 else {
125 data.minReactive = minReactive / systemPowerBase;
126 }
127 data.minReactiveUnit = ElectricalUnit::UNIT_PU;
128
129 double baseVoltage = GetValueFromUnit(data.nominalVoltage, data.nominalVoltageUnit);
130 double systemBaseImpedance = (baseVoltage * baseVoltage) / systemPowerBase;
131 double machineBaseImpedance = (baseVoltage * baseVoltage) / machineBasePower;
132
133 // Fault data
134 if (data.useMachineBase) {
135 data.positiveResistance = (data.positiveResistance * machineBaseImpedance) / systemBaseImpedance;
136 data.positiveReactance = (data.positiveReactance * machineBaseImpedance) / systemBaseImpedance;
137 data.negativeResistance = (data.negativeResistance * machineBaseImpedance) / systemBaseImpedance;
138 data.negativeReactance = (data.negativeReactance * machineBaseImpedance) / systemBaseImpedance;
139 data.zeroResistance = (data.zeroResistance * machineBaseImpedance) / systemBaseImpedance;
140 data.zeroReactance = (data.zeroReactance * machineBaseImpedance) / systemBaseImpedance;
141 data.groundResistance = (data.groundResistance * machineBaseImpedance) / systemBaseImpedance;
142 data.groundReactance = (data.groundReactance * machineBaseImpedance) / systemBaseImpedance;
143 }
144
145 if (!m_online) {
146 data.faultCurrent[0] = std::complex<double>(0, 0);
147 data.faultCurrent[1] = std::complex<double>(0, 0);
148 data.faultCurrent[2] = std::complex<double>(0, 0);
149 }
150
151 return data;
152}
153
154void SyncMotor::SetNominalVoltage(std::vector<double> nominalVoltage, std::vector<ElectricalUnit> nominalVoltageUnit)
155{
156 if (nominalVoltage.size() > 0) {
157 m_electricalData.nominalVoltage = nominalVoltage[0];
158 m_electricalData.nominalVoltageUnit = nominalVoltageUnit[0];
159 }
160}
161
163{
164 auto copy = new SyncMotor(*this);
165
166 auto data = copy->GetElectricalData();
167 data.avrSolver = nullptr;
168 data.speedGovSolver = nullptr;
169
170 if (m_electricalData.avr) {
171 std::vector<std::shared_ptr<ConnectionLine>> cLineList;
172 std::vector<std::shared_ptr<ControlElement>> elementList;
173
174 m_electricalData.avr->GetContainerCopy(elementList, cLineList);
175
176 auto avrCopy = new ControlElementContainer();
177 avrCopy->FillContainer(elementList, cLineList);
178
179 data.avr = avrCopy;
180 }
181 else {
182 data.avr = nullptr;
183 }
184
185 if (m_electricalData.speedGov) {
186 std::vector<std::shared_ptr<ConnectionLine>> cLineList;
187 std::vector<std::shared_ptr<ControlElement>> elementList;
188
189 m_electricalData.speedGov->GetContainerCopy(elementList, cLineList);
190
191 auto speedGovCopy = new ControlElementContainer();
192 speedGovCopy->FillContainer(elementList, cLineList);
193
194 data.speedGov = speedGovCopy;
195 }
196 else {
197 data.speedGov = nullptr;
198 }
199
200 copy->SetElectricalData(data);
201
202 return copy;
203}
204
205wxString SyncMotor::GetTipText() const
206{
207 wxString tipText = m_electricalData.name;
208 tipText += "\n";
209 double activePower = m_electricalData.activePower;
210 if (!m_online) activePower = 0.0;
211 tipText += _("\nP = ") + wxString::FromDouble(activePower, 5);
212 switch (m_electricalData.activePowerUnit) {
214 tipText += _(" p.u.");
215 } break;
217 tipText += _(" W");
218 } break;
220 tipText += _(" kW");
221 } break;
223 tipText += _(" MW");
224 } break;
225 default:
226 break;
227 }
228 double reactivePower = m_electricalData.reactivePower;
229 if (!m_online) reactivePower = 0.0;
230 tipText += _("\nQ = ") + wxString::FromDouble(reactivePower, 5);
231 switch (m_electricalData.reactivePowerUnit) {
233 tipText += _(" p.u.");
234 } break;
236 tipText += _(" var");
237 } break;
239 tipText += _(" kvar");
240 } break;
242 tipText += _(" Mvar");
243 } break;
244 default:
245 break;
246 }
247
248 return tipText;
249}
250
251rapidxml::xml_node<>* SyncMotor::SaveElement(rapidxml::xml_document<>& doc, rapidxml::xml_node<>* elementListNode)
252{
253 auto elementNode = XMLParser::AppendNode(doc, elementListNode, "SyncMotor");
254 XMLParser::SetNodeAttribute(doc, elementNode, "ID", m_elementID);
255
256 SaveCADProperties(doc, elementNode);
257
258 auto electricalProp = XMLParser::AppendNode(doc, elementNode, "ElectricalProperties");
259 auto isOnline = XMLParser::AppendNode(doc, electricalProp, "IsOnline");
260 XMLParser::SetNodeValue(doc, isOnline, m_online);
261 auto name = XMLParser::AppendNode(doc, electricalProp, "Name");
262 XMLParser::SetNodeValue(doc, name, m_electricalData.name);
263 auto nominalPower = XMLParser::AppendNode(doc, electricalProp, "NominalPower");
264 XMLParser::SetNodeValue(doc, nominalPower, m_electricalData.nominalPower);
265 XMLParser::SetNodeAttribute(doc, nominalPower, "UnitID", static_cast<int>(m_electricalData.nominalPowerUnit));
266 auto activePower = XMLParser::AppendNode(doc, electricalProp, "ActivePower");
267 XMLParser::SetNodeValue(doc, activePower, m_electricalData.activePower);
268 XMLParser::SetNodeAttribute(doc, activePower, "UnitID", static_cast<int>(m_electricalData.activePowerUnit));
269 auto reactivePower = XMLParser::AppendNode(doc, electricalProp, "ReactivePower");
270 XMLParser::SetNodeValue(doc, reactivePower, m_electricalData.reactivePower);
271 XMLParser::SetNodeAttribute(doc, reactivePower, "UnitID", static_cast<int>(m_electricalData.reactivePowerUnit));
272 auto haveMaxReactive = XMLParser::AppendNode(doc, electricalProp, "HaveMaxReactive");
273 XMLParser::SetNodeValue(doc, haveMaxReactive, m_electricalData.haveMaxReactive);
274 auto maxReactive = XMLParser::AppendNode(doc, electricalProp, "MaxReactive");
275 XMLParser::SetNodeValue(doc, maxReactive, m_electricalData.maxReactive);
276 XMLParser::SetNodeAttribute(doc, maxReactive, "UnitID", static_cast<int>(m_electricalData.maxReactiveUnit));
277 auto haveMinReactive = XMLParser::AppendNode(doc, electricalProp, "HaveMinReactive");
278 XMLParser::SetNodeValue(doc, haveMinReactive, m_electricalData.haveMinReactive);
279 auto minReactive = XMLParser::AppendNode(doc, electricalProp, "MinReactive");
280 XMLParser::SetNodeValue(doc, minReactive, m_electricalData.minReactive);
281 XMLParser::SetNodeAttribute(doc, minReactive, "UnitID", static_cast<int>(m_electricalData.minReactiveUnit));
282 auto useMachineBase = XMLParser::AppendNode(doc, electricalProp, "UseMachineBase");
283 XMLParser::SetNodeValue(doc, useMachineBase, m_electricalData.useMachineBase);
284
285 auto fault = XMLParser::AppendNode(doc, electricalProp, "Fault");
286 auto positiveResistance = XMLParser::AppendNode(doc, fault, "PositiveResistance");
287 XMLParser::SetNodeValue(doc, positiveResistance, m_electricalData.positiveResistance);
288 auto positiveReactance = XMLParser::AppendNode(doc, fault, "PositiveReactance");
289 XMLParser::SetNodeValue(doc, positiveReactance, m_electricalData.positiveReactance);
290 auto negativeResistance = XMLParser::AppendNode(doc, fault, "NegativeResistance");
291 XMLParser::SetNodeValue(doc, negativeResistance, m_electricalData.negativeResistance);
292 auto negativeReactance = XMLParser::AppendNode(doc, fault, "NegativeReactance");
293 XMLParser::SetNodeValue(doc, negativeReactance, m_electricalData.negativeReactance);
294 auto zeroResistance = XMLParser::AppendNode(doc, fault, "ZeroResistance");
295 XMLParser::SetNodeValue(doc, zeroResistance, m_electricalData.zeroResistance);
296 auto zeroReactance = XMLParser::AppendNode(doc, fault, "ZeroReactance");
297 XMLParser::SetNodeValue(doc, zeroReactance, m_electricalData.zeroReactance);
298 auto groundResistance = XMLParser::AppendNode(doc, fault, "GroundResistance");
299 XMLParser::SetNodeValue(doc, groundResistance, m_electricalData.groundResistance);
300 auto groundReactance = XMLParser::AppendNode(doc, fault, "GroundReactance");
301 XMLParser::SetNodeValue(doc, groundReactance, m_electricalData.groundReactance);
302 auto groundNeutral = XMLParser::AppendNode(doc, fault, "GroundNeutral");
303 XMLParser::SetNodeValue(doc, groundNeutral, m_electricalData.groundNeutral);
304
305 return elementNode;
306}
307
308bool SyncMotor::OpenElement(rapidxml::xml_node<>* elementNode, std::vector<Element*> parentList)
309{
310 if (!OpenCADProperties(elementNode, parentList)) return false;
311
312 auto electricalProp = elementNode->first_node("ElectricalProperties");
313 if (!electricalProp) return false;
314
315 SetOnline(XMLParser::GetNodeValueInt(electricalProp, "IsOnline"));
316 m_electricalData.name = electricalProp->first_node("Name")->value();
317 m_electricalData.nominalPower = XMLParser::GetNodeValueDouble(electricalProp, "NominalPower");
318 m_electricalData.nominalPowerUnit =
319 static_cast<ElectricalUnit>(XMLParser::GetAttributeValueInt(electricalProp, "NominalPower", "UnitID"));
320 m_electricalData.activePower = XMLParser::GetNodeValueDouble(electricalProp, "ActivePower");
321 m_electricalData.activePowerUnit =
322 static_cast<ElectricalUnit>(XMLParser::GetAttributeValueInt(electricalProp, "ActivePower", "UnitID"));
323 m_electricalData.reactivePower = XMLParser::GetNodeValueDouble(electricalProp, "ReactivePower");
324 m_electricalData.reactivePowerUnit =
325 static_cast<ElectricalUnit>(XMLParser::GetAttributeValueInt(electricalProp, "ReactivePower", "UnitID"));
326 m_electricalData.haveMaxReactive = XMLParser::GetNodeValueInt(electricalProp, "HaveMaxReactive");
327 m_electricalData.maxReactive = XMLParser::GetNodeValueDouble(electricalProp, "MaxReactive");
328 m_electricalData.maxReactiveUnit =
329 static_cast<ElectricalUnit>(XMLParser::GetAttributeValueInt(electricalProp, "MaxReactive", "UnitID"));
330 m_electricalData.haveMinReactive = XMLParser::GetNodeValueInt(electricalProp, "HaveMinReactive");
331 m_electricalData.minReactive = XMLParser::GetNodeValueDouble(electricalProp, "MinReactive");
332 m_electricalData.minReactiveUnit =
333 static_cast<ElectricalUnit>(XMLParser::GetAttributeValueInt(electricalProp, "MinReactive", "UnitID"));
334 m_electricalData.useMachineBase = XMLParser::GetNodeValueInt(electricalProp, "UseMachineBase");
335
336 auto fault = electricalProp->first_node("Fault");
337 if (!fault) return false;
338 m_electricalData.positiveResistance = XMLParser::GetNodeValueDouble(fault, "PositiveResistance");
339 m_electricalData.positiveReactance = XMLParser::GetNodeValueDouble(fault, "PositiveReactance");
340 m_electricalData.negativeResistance = XMLParser::GetNodeValueDouble(fault, "NegativeResistance");
341 m_electricalData.negativeReactance = XMLParser::GetNodeValueDouble(fault, "NegativeReactance");
342 m_electricalData.zeroResistance = XMLParser::GetNodeValueDouble(fault, "ZeroResistance");
343 m_electricalData.zeroReactance = XMLParser::GetNodeValueDouble(fault, "ZeroReactance");
344 m_electricalData.groundResistance = XMLParser::GetNodeValueDouble(fault, "GroundResistance");
345 m_electricalData.groundReactance = XMLParser::GetNodeValueDouble(fault, "GroundReactance");
346 m_electricalData.groundNeutral = XMLParser::GetNodeValueInt(fault, "GroundNeutral");
347
348 m_inserted = true;
349
350 return true;
351}
@ ID_EDIT_ELEMENT
Definition Element.h:75
ElectricalUnit
Electrical units.
Class that can contain all control elements. Can identify (using RTTI) the elements from a generic li...
Base class of all elements of the program. This class is responsible for manage graphical and his dat...
Definition Element.h:112
virtual void GeneralMenuItens(wxMenu &menu)
Insert general itens to context menu.
Definition Element.cpp:388
bool SetOnline(bool online=true)
Set if the element is online or offline.
Definition Element.cpp:378
Abstract class for rotary machines power elements.
Definition Machines.h:34
Form to edit the synchronous machine power data.
Synchronous motor (synchronous compensator) power element.
Definition SyncMotor.h:135
virtual Element * GetCopy()
Get a the element copy.
virtual void SetNominalVoltage(std::vector< double > nominalVoltage, std::vector< ElectricalUnit > nominalVoltageUnit)
Set nominal voltage of the element.
virtual wxString GetTipText() const
Get the tip text.
virtual bool GetContextMenu(wxMenu &menu)
Get the element contex menu.
Definition SyncMotor.cpp:53
virtual bool ShowForm(wxWindow *parent, Element *element, wxWindow *workspace=nullptr)
Show element data form.
Definition SyncMotor.cpp:70