Power System Platform  2026w11a-beta
Loading...
Searching...
No Matches
IndMotor.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 "IndMotor.h"
19#include "../../forms/IndMotorForm.h"
20
21IndMotor::IndMotor() : Machines()
22{
23 m_elementType = TYPE_IND_MOTOR;
24}
25
26IndMotor::IndMotor(wxString name) : Machines()
27{
28 m_elementType = TYPE_IND_MOTOR;
29 m_electricalData.name = name;
30}
31
32IndMotor::~IndMotor() {}
33
34//void IndMotor::DrawSymbol() const
35//{
36// std::vector<wxPoint2DDouble> mPts;
37// mPts.push_back(wxPoint2DDouble(-10, 13) + m_position);
38// mPts.push_back(wxPoint2DDouble(-10, -13) + m_position);
39// mPts.push_back(wxPoint2DDouble(0, 2) + m_position);
40// mPts.push_back(wxPoint2DDouble(10, -13) + m_position);
41// mPts.push_back(wxPoint2DDouble(10, 13) + m_position);
42// DrawLine(mPts);
43//}
44
45void IndMotor::DrawDCSymbol(wxGraphicsContext* gc) const
46{
47 std::vector<wxPoint2DDouble> mPts;
48 mPts.push_back(wxPoint2DDouble(-10, 13) + m_position);
49 mPts.push_back(wxPoint2DDouble(-10, -13) + m_position);
50 mPts.push_back(wxPoint2DDouble(0, 2) + m_position);
51 mPts.push_back(wxPoint2DDouble(10, -13) + m_position);
52 mPts.push_back(wxPoint2DDouble(10, 13) + m_position);
53 gc->StrokeLines(mPts.size(), &mPts[0]);
54}
55
56void IndMotor::DrawDCSymbol(wxDC& dc) const
57{
58 wxPoint mPts[5];
59 wxPoint pos = wxPoint((int)m_position.m_x, (int)m_position.m_y);
60 mPts[0] = wxPoint(-10, 13) + pos;
61 mPts[1] = wxPoint(-10, -13) + pos;
62 mPts[2] = wxPoint(0, 2) + pos;
63 mPts[3] = wxPoint(10, -13) + pos;
64 mPts[4] = wxPoint(10, 13) + pos;
65 dc.DrawLines(5, mPts);
66}
67
68bool IndMotor::GetContextMenu(wxMenu& menu)
69{
70 menu.Append(ID_EDIT_ELEMENT, _("Edit induction motor"));
71
72 wxMenu* textMenu = new wxMenu();
73
74 textMenu->Append(ID_TXT_NAME, _("Name"));
75 textMenu->Append(ID_TXT_ACTIVE_POWER, _("Active power"));
76 textMenu->Append(ID_TXT_REACTIVE_POWER, _("Reactive power"));
77 textMenu->SetClientData(menu.GetClientData());
78 menu.AppendSubMenu(textMenu, _("Add text"));
79
80 GeneralMenuItens(menu);
81 return true;
82}
83
84bool IndMotor::ShowForm(wxWindow* parent, Element* element, wxWindow* workspace)
85{
86 IndMotorForm indMotorForm(parent, this);
87 indMotorForm.CentreOnParent();
88 if (indMotorForm.ShowModal() == wxID_OK) {
89 return true;
90 }
91 return false;
92}
93
94IndMotorElectricalData IndMotor::GetPUElectricalData(double systemPowerBase)
95{
96 //IndMotorElectricalData data
98 data.name = m_electricalData.name;
99 data.activePower = m_electricalData.activePower;
100 data.activePowerUnit = m_electricalData.activePowerUnit;
101 data.reactivePower = m_electricalData.reactivePower;
102 data.reactivePowerUnit = m_electricalData.reactivePowerUnit;
103
104
105 switch (data.activePowerUnit) {
107 data.activePower = data.activePower / systemPowerBase;
108 data.activePowerUnit = ElectricalUnit::UNIT_PU;
109 } break;
111 data.activePower = (data.activePower * 1e3) / systemPowerBase;
112 data.activePowerUnit = ElectricalUnit::UNIT_PU;
113 } break;
115 data.activePower = (data.activePower * 1e6) / systemPowerBase;
116 data.activePowerUnit = ElectricalUnit::UNIT_PU;
117 } break;
118 default:
119 break;
120 }
121 switch (data.reactivePowerUnit) {
123 data.reactivePower = data.reactivePower / systemPowerBase;
124 data.reactivePowerUnit = ElectricalUnit::UNIT_PU;
125 } break;
127 data.reactivePower = (data.reactivePower * 1e3) / systemPowerBase;
128 data.reactivePowerUnit = ElectricalUnit::UNIT_PU;
129 } break;
131 data.reactivePower = (data.reactivePower * 1e6) / systemPowerBase;
132 data.reactivePowerUnit = ElectricalUnit::UNIT_PU;
133 } break;
134 default:
135 break;
136 }
137
138 return data;
139}
140
142{
143 IndMotor* copy = new IndMotor();
144 *copy = *this;
145 return copy;
146}
147
148wxString IndMotor::GetTipText() const
149{
150 wxString tipText = m_electricalData.name;
151 tipText += "\n";
152 double activePower = m_electricalData.activePower;
153 if (!m_online) activePower = 0.0;
154 tipText += _("\nP = ") + wxString::FromDouble(activePower, 5);
155 switch (m_electricalData.activePowerUnit) {
157 tipText += _(" p.u.");
158 } break;
160 tipText += _(" W");
161 } break;
163 tipText += _(" kW");
164 } break;
166 tipText += _(" MW");
167 } break;
168 default:
169 break;
170 }
171 double reactivePower = m_electricalData.reactivePower;
172 if (!m_online) reactivePower = 0.0;
173 tipText += _("\nQ = ") + wxString::FromDouble(reactivePower, 5);
174 switch (m_electricalData.reactivePowerUnit) {
176 tipText += _(" p.u.");
177 } break;
179 tipText += _(" var");
180 } break;
182 tipText += _(" kvar");
183 } break;
185 tipText += _(" Mvar");
186 } break;
187 default:
188 break;
189 }
190
191 return tipText;
192}
193
194rapidxml::xml_node<>* IndMotor::SaveElement(rapidxml::xml_document<>& doc, rapidxml::xml_node<>* elementListNode)
195{
196 auto elementNode = XMLParser::AppendNode(doc, elementListNode, "IndMotor");
197 XMLParser::SetNodeAttribute(doc, elementNode, "ID", m_elementID);
198
199 SaveCADProperties(doc, elementNode);
200
201 // Element properties
202 // General
203 auto electricalProp = XMLParser::AppendNode(doc, elementNode, "ElectricalProperties");
204 auto isOnline = XMLParser::AppendNode(doc, electricalProp, "IsOnline");
205 XMLParser::SetNodeValue(doc, isOnline, m_online);
206 auto name = XMLParser::AppendNode(doc, electricalProp, "Name");
207 XMLParser::SetNodeValue(doc, name, m_electricalData.name);
208 auto ratedPower = XMLParser::AppendNode(doc, electricalProp, "RatedPower");
209 XMLParser::SetNodeValue(doc, ratedPower, m_electricalData.ratedPower);
210 XMLParser::SetNodeAttribute(doc, ratedPower, "UnitID", static_cast<int>(m_electricalData.activePowerUnit));
211 auto activePower = XMLParser::AppendNode(doc, electricalProp, "ActivePower");
212 XMLParser::SetNodeValue(doc, activePower, m_electricalData.activePower);
213 XMLParser::SetNodeAttribute(doc, activePower, "UnitID", static_cast<int>(m_electricalData.activePowerUnit));
214 auto reactivePower = XMLParser::AppendNode(doc, electricalProp, "ReactivePower");
215 XMLParser::SetNodeValue(doc, reactivePower, m_electricalData.reactivePower);
216 XMLParser::SetNodeAttribute(doc, reactivePower, "UnitID", static_cast<int>(m_electricalData.reactivePowerUnit));
217 auto useMachineBase = XMLParser::AppendNode(doc, electricalProp, "UseMachineBase");
218 XMLParser::SetNodeValue(doc, useMachineBase, m_electricalData.useMachinePowerAsBase);
219
220 // Stability
221 auto stability = XMLParser::AppendNode(doc, electricalProp, "Stability");
222 auto plotMotor = XMLParser::AppendNode(doc, stability, "PlotIndMachine");
223 XMLParser::SetNodeValue(doc, plotMotor, m_electricalData.plotIndMachine);
224 auto inertia = XMLParser::AppendNode(doc, stability, "Inertia");
225 XMLParser::SetNodeValue(doc, inertia, m_electricalData.inertia);
226 auto r1 = XMLParser::AppendNode(doc, stability, "StatorResistence");
227 XMLParser::SetNodeValue(doc, r1, m_electricalData.r1);
228 auto x1 = XMLParser::AppendNode(doc, stability, "StatorReactance");
229 XMLParser::SetNodeValue(doc, x1, m_electricalData.x1);
230 auto r2 = XMLParser::AppendNode(doc, stability, "RotorResistence");
231 XMLParser::SetNodeValue(doc, r2, m_electricalData.r2);
232 auto x2 = XMLParser::AppendNode(doc, stability, "RotorReactance");
233 XMLParser::SetNodeValue(doc, x2, m_electricalData.x2);
234 auto xm = XMLParser::AppendNode(doc, stability, "MagnetizingReactance");
235 XMLParser::SetNodeValue(doc, xm, m_electricalData.xm);
236 auto useCageFactor = XMLParser::AppendNode(doc, stability, "UseCageFactor");
237 XMLParser::SetNodeValue(doc, useCageFactor, m_electricalData.useKf);
238 auto cageFactor = XMLParser::AppendNode(doc, stability, "CageFactor");
239 XMLParser::SetNodeValue(doc, cageFactor, m_electricalData.kf);
240 auto loadChar = XMLParser::AppendNode(doc, stability, "LoadCharacteristic");
241 auto aw = XMLParser::AppendNode(doc, loadChar, "Constant");
242 XMLParser::SetNodeValue(doc, aw, m_electricalData.aw);
243 auto bw = XMLParser::AppendNode(doc, loadChar, "Linear");
244 XMLParser::SetNodeValue(doc, bw, m_electricalData.bw);
245 auto cw = XMLParser::AppendNode(doc, loadChar, "Quadratic");
246 XMLParser::SetNodeValue(doc, cw, m_electricalData.cw);
247
248 SaveSwitchingData(doc, electricalProp);
249
250 return elementNode;
251}
252
253bool IndMotor::OpenElement(rapidxml::xml_node<>* elementNode, std::vector<Element*> parentList)
254{
255 if (!OpenCADProperties(elementNode, parentList)) return false;
256
257 auto electricalProp = elementNode->first_node("ElectricalProperties");
258 if (!electricalProp) return false;
259
260 // Element properties
261 SetOnline(XMLParser::GetNodeValueInt(electricalProp, "IsOnline"));
262 m_electricalData.name = electricalProp->first_node("Name")->value();
263 m_electricalData.ratedPower = XMLParser::GetNodeValueDouble(electricalProp, "RatedPower");
264 m_electricalData.ratedPowerUnit =
265 static_cast<ElectricalUnit>(XMLParser::GetAttributeValueInt(electricalProp, "RatedPower", "UnitID"));
266 m_electricalData.activePower = XMLParser::GetNodeValueDouble(electricalProp, "ActivePower");
267 m_electricalData.activePowerUnit =
268 static_cast<ElectricalUnit>(XMLParser::GetAttributeValueInt(electricalProp, "ActivePower", "UnitID"));
269 m_electricalData.reactivePower = XMLParser::GetNodeValueDouble(electricalProp, "ReactivePower");
270 m_electricalData.reactivePowerUnit =
271 static_cast<ElectricalUnit>(XMLParser::GetAttributeValueInt(electricalProp, "ReactivePower", "UnitID"));
272 m_electricalData.useMachinePowerAsBase = XMLParser::GetNodeValueInt(electricalProp, "UseMachineBase");
273
274 // Stability
275 auto stability = electricalProp->first_node("Stability");
276 m_electricalData.plotIndMachine = XMLParser::GetNodeValueInt(stability, "PlotIndMachine");
277 m_electricalData.inertia = XMLParser::GetNodeValueDouble(stability, "Inertia");
278 m_electricalData.r1 = XMLParser::GetNodeValueDouble(stability, "StatorResistence");
279 m_electricalData.x1 = XMLParser::GetNodeValueDouble(stability, "StatorReactance");
280 m_electricalData.r2 = XMLParser::GetNodeValueDouble(stability, "RotorResistence");
281 m_electricalData.x2 = XMLParser::GetNodeValueDouble(stability, "RotorReactance");
282 m_electricalData.xm = XMLParser::GetNodeValueDouble(stability, "MagnetizingReactance");
283 m_electricalData.useKf = XMLParser::GetNodeValueInt(stability, "UseCageFactor");
284 m_electricalData.kf = XMLParser::GetNodeValueDouble(stability, "CageFactor");
285 auto loadChar = stability->first_node("LoadCharacteristic");
286 m_electricalData.aw = XMLParser::GetNodeValueDouble(loadChar, "Constant");
287 m_electricalData.bw = XMLParser::GetNodeValueDouble(loadChar, "Linear");
288 m_electricalData.cw = XMLParser::GetNodeValueDouble(loadChar, "Quadratic");
289
290 if (!OpenSwitchingData(electricalProp)) return false;
291 if (m_swData.swTime.size() != 0) SetDynamicEvent(true);
292
293 m_inserted = true;
294
295 return true;
296}
297
299{
300 if (!m_electricalData.plotIndMachine) return false;
301 plotData.SetName(m_electricalData.name);
302 plotData.SetCurveType(ElementPlotData::CurveType::CT_IND_MOTOR);
303
304 plotData.AddData(m_electricalData.terminalVoltageVector, _("Terminal voltage"));
305 plotData.AddData(m_electricalData.activePowerVector, _("Active power"));
306 plotData.AddData(m_electricalData.reactivePowerVector, _("Reactive power"));
307 plotData.AddData(m_electricalData.currentVector, _("Current"));
308 plotData.AddData(m_electricalData.electricalTorqueVector, _("Electrical torque"));
309 plotData.AddData(m_electricalData.mechanicalTorqueVector, _("Mechanical torque"));
310 plotData.AddData(m_electricalData.velocityVector, _("Speed"));
311 plotData.AddData(m_electricalData.slipVector, _("Slip"));
312 return true;
313}
314
315void IndMotor::InitPowerFlowMotor(double systemPowerBase, int busNumber)
316{
317 double k = 1.0; // Power base change factor.
318 if (m_electricalData.useMachinePowerAsBase) {
319 double oldBase = GetValueFromUnit(m_electricalData.ratedPower, m_electricalData.ratedPowerUnit);
320 k = systemPowerBase / oldBase;
321 }
322 // Calculate the induction machine transient constants at the machine base
323 m_electricalData.r1t = m_electricalData.r1 * k;
324 m_electricalData.r2t = m_electricalData.r2 * k;
325 m_electricalData.x1t = m_electricalData.x1 * k;
326 m_electricalData.x2t = m_electricalData.x2 * k;
327 m_electricalData.xmt = m_electricalData.xm * k;
328
329 m_electricalData.xt = m_electricalData.x1t +
330 (m_electricalData.x2t * m_electricalData.xmt) / (m_electricalData.x2t + m_electricalData.xmt);
331 m_electricalData.x0 = m_electricalData.x1t + m_electricalData.xmt;
332
333 double r1 = m_electricalData.r1t;
334 double r2 = m_electricalData.r2t;
335 if (m_electricalData.useKf) r2 *= (1.0 + m_electricalData.kf * m_electricalData.r2t);
336 double x1 = m_electricalData.x1t;
337 double x2 = m_electricalData.x2t;
338 double xm = m_electricalData.xmt;
339 m_electricalData.k1 = x2 + xm;
340 m_electricalData.k2 = -x1 * m_electricalData.k1 - x2 * xm;
341 m_electricalData.k3 = xm + x1;
342 m_electricalData.k4 = r1 * m_electricalData.k1;
343
344 auto puData = GetPUElectricalData(systemPowerBase);
345 m_electricalData.p0 = puData.activePower;
346 m_electricalData.busNum = busNumber;
347}
348
349bool IndMotor::CalculateReactivePower(double voltage)
350{
351 double a = m_electricalData.p0 *
352 (m_electricalData.r1t * m_electricalData.r1t + m_electricalData.k3 * m_electricalData.k3) -
353 voltage * voltage * m_electricalData.r1t;
354 double b = 2.0 * m_electricalData.p0 *
355 (m_electricalData.r1t * m_electricalData.k2 + m_electricalData.k3 * m_electricalData.k4) -
356 voltage * voltage * (m_electricalData.k2 + m_electricalData.k1 * m_electricalData.k3);
357 double c =
358 m_electricalData.p0 * (m_electricalData.k2 * m_electricalData.k2 + m_electricalData.k4 * m_electricalData.k4) -
359 voltage * voltage * m_electricalData.k1 * m_electricalData.k4;
360 double d = (b * b - 4.0 * a * c);
361 if (d < 0.0) return false;
362 double r2_s = (-b + std::sqrt(d)) / (2.0 * a);
363
364 double qa = m_electricalData.k1 * (r2_s * m_electricalData.r1t - m_electricalData.x1t * m_electricalData.k1 -
365 m_electricalData.x2t * m_electricalData.xmt);
366 double qb =
367 r2_s * (r2_s * (m_electricalData.xmt + m_electricalData.x1t) + m_electricalData.r1t * m_electricalData.k1);
368 double qc = r2_s * m_electricalData.r1t - m_electricalData.x1t * m_electricalData.k1 -
369 m_electricalData.x2t * m_electricalData.xmt;
370 double qd = r2_s * (m_electricalData.xmt + m_electricalData.x1t) + m_electricalData.r1t * m_electricalData.k1;
371 m_electricalData.qValue = (-voltage * voltage * (qa - qb)) / (qc * qc + qd * qd);
372
373 return true;
374}
@ ID_EDIT_ELEMENT
Definition Element.h:75
ElectricalUnit
Electrical units.
PlotStudy
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
Form to edit the induction motor power data.
Induction motor power element.
Definition IndMotor.h:119
virtual bool GetContextMenu(wxMenu &menu)
Get the element contex menu.
Definition IndMotor.cpp:68
virtual bool ShowForm(wxWindow *parent, Element *element, wxWindow *workspace=nullptr)
Show element data form.
Definition IndMotor.cpp:84
virtual Element * GetCopy()
Get a the element copy.
Definition IndMotor.cpp:141
virtual bool GetPlotData(ElementPlotData &plotData, PlotStudy study=PlotStudy::STABILITY)
Fill the plot data.
Definition IndMotor.cpp:298
virtual wxString GetTipText() const
Get the tip text.
Definition IndMotor.cpp:148
Abstract class for rotary machines power elements.
Definition Machines.h:34
virtual void SetDynamicEvent(bool dynEvent=true)
Set if the power element have dynamic event.
std::vector< double > swTime