Power System Platform  2026w10a-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)
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 = m_electricalData;
97
98 switch (data.activePowerUnit) {
100 data.activePower = data.activePower / systemPowerBase;
101 data.activePowerUnit = ElectricalUnit::UNIT_PU;
102 } break;
104 data.activePower = (data.activePower * 1e3) / systemPowerBase;
105 data.activePowerUnit = ElectricalUnit::UNIT_PU;
106 } break;
108 data.activePower = (data.activePower * 1e6) / systemPowerBase;
109 data.activePowerUnit = ElectricalUnit::UNIT_PU;
110 } break;
111 default:
112 break;
113 }
114 switch (data.reactivePowerUnit) {
116 data.reactivePower = data.reactivePower / systemPowerBase;
117 data.reactivePowerUnit = ElectricalUnit::UNIT_PU;
118 } break;
120 data.reactivePower = (data.reactivePower * 1e3) / systemPowerBase;
121 data.reactivePowerUnit = ElectricalUnit::UNIT_PU;
122 } break;
124 data.reactivePower = (data.reactivePower * 1e6) / systemPowerBase;
125 data.reactivePowerUnit = ElectricalUnit::UNIT_PU;
126 } break;
127 default:
128 break;
129 }
130
131 return data;
132}
133
135{
136 IndMotor* copy = new IndMotor();
137 *copy = *this;
138 return copy;
139}
140
141wxString IndMotor::GetTipText() const
142{
143 wxString tipText = m_electricalData.name;
144 tipText += "\n";
145 double activePower = m_electricalData.activePower;
146 if (!m_online) activePower = 0.0;
147 tipText += _("\nP = ") + wxString::FromDouble(activePower, 5);
148 switch (m_electricalData.activePowerUnit) {
150 tipText += _(" p.u.");
151 } break;
153 tipText += _(" W");
154 } break;
156 tipText += _(" kW");
157 } break;
159 tipText += _(" MW");
160 } break;
161 default:
162 break;
163 }
164 double reactivePower = m_electricalData.reactivePower;
165 if (!m_online) reactivePower = 0.0;
166 tipText += _("\nQ = ") + wxString::FromDouble(reactivePower, 5);
167 switch (m_electricalData.reactivePowerUnit) {
169 tipText += _(" p.u.");
170 } break;
172 tipText += _(" var");
173 } break;
175 tipText += _(" kvar");
176 } break;
178 tipText += _(" Mvar");
179 } break;
180 default:
181 break;
182 }
183
184 return tipText;
185}
186
187rapidxml::xml_node<>* IndMotor::SaveElement(rapidxml::xml_document<>& doc, rapidxml::xml_node<>* elementListNode)
188{
189 auto elementNode = XMLParser::AppendNode(doc, elementListNode, "IndMotor");
190 XMLParser::SetNodeAttribute(doc, elementNode, "ID", m_elementID);
191
192 SaveCADProperties(doc, elementNode);
193
194 // Element properties
195 // General
196 auto electricalProp = XMLParser::AppendNode(doc, elementNode, "ElectricalProperties");
197 auto isOnline = XMLParser::AppendNode(doc, electricalProp, "IsOnline");
198 XMLParser::SetNodeValue(doc, isOnline, m_online);
199 auto name = XMLParser::AppendNode(doc, electricalProp, "Name");
200 XMLParser::SetNodeValue(doc, name, m_electricalData.name);
201 auto ratedPower = XMLParser::AppendNode(doc, electricalProp, "RatedPower");
202 XMLParser::SetNodeValue(doc, ratedPower, m_electricalData.ratedPower);
203 XMLParser::SetNodeAttribute(doc, ratedPower, "UnitID", static_cast<int>(m_electricalData.activePowerUnit));
204 auto activePower = XMLParser::AppendNode(doc, electricalProp, "ActivePower");
205 XMLParser::SetNodeValue(doc, activePower, m_electricalData.activePower);
206 XMLParser::SetNodeAttribute(doc, activePower, "UnitID", static_cast<int>(m_electricalData.activePowerUnit));
207 auto reactivePower = XMLParser::AppendNode(doc, electricalProp, "ReactivePower");
208 XMLParser::SetNodeValue(doc, reactivePower, m_electricalData.reactivePower);
209 XMLParser::SetNodeAttribute(doc, reactivePower, "UnitID", static_cast<int>(m_electricalData.reactivePowerUnit));
210 auto useMachineBase = XMLParser::AppendNode(doc, electricalProp, "UseMachineBase");
211 XMLParser::SetNodeValue(doc, useMachineBase, m_electricalData.useMachinePowerAsBase);
212
213 // Stability
214 auto stability = XMLParser::AppendNode(doc, electricalProp, "Stability");
215 auto plotMotor = XMLParser::AppendNode(doc, stability, "PlotIndMachine");
216 XMLParser::SetNodeValue(doc, plotMotor, m_electricalData.plotIndMachine);
217 auto inertia = XMLParser::AppendNode(doc, stability, "Inertia");
218 XMLParser::SetNodeValue(doc, inertia, m_electricalData.inertia);
219 auto r1 = XMLParser::AppendNode(doc, stability, "StatorResistence");
220 XMLParser::SetNodeValue(doc, r1, m_electricalData.r1);
221 auto x1 = XMLParser::AppendNode(doc, stability, "StatorReactance");
222 XMLParser::SetNodeValue(doc, x1, m_electricalData.x1);
223 auto r2 = XMLParser::AppendNode(doc, stability, "RotorResistence");
224 XMLParser::SetNodeValue(doc, r2, m_electricalData.r2);
225 auto x2 = XMLParser::AppendNode(doc, stability, "RotorReactance");
226 XMLParser::SetNodeValue(doc, x2, m_electricalData.x2);
227 auto xm = XMLParser::AppendNode(doc, stability, "MagnetizingReactance");
228 XMLParser::SetNodeValue(doc, xm, m_electricalData.xm);
229 auto useCageFactor = XMLParser::AppendNode(doc, stability, "UseCageFactor");
230 XMLParser::SetNodeValue(doc, useCageFactor, m_electricalData.useKf);
231 auto cageFactor = XMLParser::AppendNode(doc, stability, "CageFactor");
232 XMLParser::SetNodeValue(doc, cageFactor, m_electricalData.kf);
233 auto loadChar = XMLParser::AppendNode(doc, stability, "LoadCharacteristic");
234 auto aw = XMLParser::AppendNode(doc, loadChar, "Constant");
235 XMLParser::SetNodeValue(doc, aw, m_electricalData.aw);
236 auto bw = XMLParser::AppendNode(doc, loadChar, "Linear");
237 XMLParser::SetNodeValue(doc, bw, m_electricalData.bw);
238 auto cw = XMLParser::AppendNode(doc, loadChar, "Quadratic");
239 XMLParser::SetNodeValue(doc, cw, m_electricalData.cw);
240
241 SaveSwitchingData(doc, electricalProp);
242
243 return elementNode;
244}
245
246bool IndMotor::OpenElement(rapidxml::xml_node<>* elementNode, std::vector<Element*> parentList)
247{
248 if (!OpenCADProperties(elementNode, parentList)) return false;
249
250 auto electricalProp = elementNode->first_node("ElectricalProperties");
251 if (!electricalProp) return false;
252
253 // Element properties
254 SetOnline(XMLParser::GetNodeValueInt(electricalProp, "IsOnline"));
255 m_electricalData.name = electricalProp->first_node("Name")->value();
256 m_electricalData.ratedPower = XMLParser::GetNodeValueDouble(electricalProp, "RatedPower");
257 m_electricalData.ratedPowerUnit =
258 static_cast<ElectricalUnit>(XMLParser::GetAttributeValueInt(electricalProp, "RatedPower", "UnitID"));
259 m_electricalData.activePower = XMLParser::GetNodeValueDouble(electricalProp, "ActivePower");
260 m_electricalData.activePowerUnit =
261 static_cast<ElectricalUnit>(XMLParser::GetAttributeValueInt(electricalProp, "ActivePower", "UnitID"));
262 m_electricalData.reactivePower = XMLParser::GetNodeValueDouble(electricalProp, "ReactivePower");
263 m_electricalData.reactivePowerUnit =
264 static_cast<ElectricalUnit>(XMLParser::GetAttributeValueInt(electricalProp, "ReactivePower", "UnitID"));
265 m_electricalData.useMachinePowerAsBase = XMLParser::GetNodeValueInt(electricalProp, "UseMachineBase");
266
267 // Stability
268 auto stability = electricalProp->first_node("Stability");
269 m_electricalData.plotIndMachine = XMLParser::GetNodeValueInt(stability, "PlotIndMachine");
270 m_electricalData.inertia = XMLParser::GetNodeValueDouble(stability, "Inertia");
271 m_electricalData.r1 = XMLParser::GetNodeValueDouble(stability, "StatorResistence");
272 m_electricalData.x1 = XMLParser::GetNodeValueDouble(stability, "StatorReactance");
273 m_electricalData.r2 = XMLParser::GetNodeValueDouble(stability, "RotorResistence");
274 m_electricalData.x2 = XMLParser::GetNodeValueDouble(stability, "RotorReactance");
275 m_electricalData.xm = XMLParser::GetNodeValueDouble(stability, "MagnetizingReactance");
276 m_electricalData.useKf = XMLParser::GetNodeValueInt(stability, "UseCageFactor");
277 m_electricalData.kf = XMLParser::GetNodeValueDouble(stability, "CageFactor");
278 auto loadChar = stability->first_node("LoadCharacteristic");
279 m_electricalData.aw = XMLParser::GetNodeValueDouble(loadChar, "Constant");
280 m_electricalData.bw = XMLParser::GetNodeValueDouble(loadChar, "Linear");
281 m_electricalData.cw = XMLParser::GetNodeValueDouble(loadChar, "Quadratic");
282
283 if (!OpenSwitchingData(electricalProp)) return false;
284 if (m_swData.swTime.size() != 0) SetDynamicEvent(true);
285
286 m_inserted = true;
287
288 return true;
289}
290
292{
293 if (!m_electricalData.plotIndMachine) return false;
294 plotData.SetName(m_electricalData.name);
295 plotData.SetCurveType(ElementPlotData::CurveType::CT_IND_MOTOR);
296
297 plotData.AddData(m_electricalData.terminalVoltageVector, _("Terminal voltage"));
298 plotData.AddData(m_electricalData.activePowerVector, _("Active power"));
299 plotData.AddData(m_electricalData.reactivePowerVector, _("Reactive power"));
300 plotData.AddData(m_electricalData.currentVector, _("Current"));
301 plotData.AddData(m_electricalData.electricalTorqueVector, _("Electrical torque"));
302 plotData.AddData(m_electricalData.mechanicalTorqueVector, _("Mechanical torque"));
303 plotData.AddData(m_electricalData.velocityVector, _("Speed"));
304 plotData.AddData(m_electricalData.slipVector, _("Slip"));
305 return true;
306}
307
308void IndMotor::InitPowerFlowMotor(double systemPowerBase, int busNumber)
309{
310 double k = 1.0; // Power base change factor.
311 if (m_electricalData.useMachinePowerAsBase) {
312 double oldBase = GetValueFromUnit(m_electricalData.ratedPower, m_electricalData.ratedPowerUnit);
313 k = systemPowerBase / oldBase;
314 }
315 // Calculate the induction machine transient constants at the machine base
316 m_electricalData.r1t = m_electricalData.r1 * k;
317 m_electricalData.r2t = m_electricalData.r2 * k;
318 m_electricalData.x1t = m_electricalData.x1 * k;
319 m_electricalData.x2t = m_electricalData.x2 * k;
320 m_electricalData.xmt = m_electricalData.xm * k;
321
322 m_electricalData.xt = m_electricalData.x1t +
323 (m_electricalData.x2t * m_electricalData.xmt) / (m_electricalData.x2t + m_electricalData.xmt);
324 m_electricalData.x0 = m_electricalData.x1t + m_electricalData.xmt;
325
326 double r1 = m_electricalData.r1t;
327 double r2 = m_electricalData.r2t;
328 if (m_electricalData.useKf) r2 *= (1.0 + m_electricalData.kf * m_electricalData.r2t);
329 double x1 = m_electricalData.x1t;
330 double x2 = m_electricalData.x2t;
331 double xm = m_electricalData.xmt;
332 m_electricalData.k1 = x2 + xm;
333 m_electricalData.k2 = -x1 * m_electricalData.k1 - x2 * xm;
334 m_electricalData.k3 = xm + x1;
335 m_electricalData.k4 = r1 * m_electricalData.k1;
336
337 auto puData = GetPUElectricalData(systemPowerBase);
338 m_electricalData.p0 = puData.activePower;
339 m_electricalData.busNum = busNumber;
340}
341
342bool IndMotor::CalculateReactivePower(double voltage)
343{
344 double a = m_electricalData.p0 *
345 (m_electricalData.r1t * m_electricalData.r1t + m_electricalData.k3 * m_electricalData.k3) -
346 voltage * voltage * m_electricalData.r1t;
347 double b = 2.0 * m_electricalData.p0 *
348 (m_electricalData.r1t * m_electricalData.k2 + m_electricalData.k3 * m_electricalData.k4) -
349 voltage * voltage * (m_electricalData.k2 + m_electricalData.k1 * m_electricalData.k3);
350 double c =
351 m_electricalData.p0 * (m_electricalData.k2 * m_electricalData.k2 + m_electricalData.k4 * m_electricalData.k4) -
352 voltage * voltage * m_electricalData.k1 * m_electricalData.k4;
353 double d = (b * b - 4.0 * a * c);
354 if (d < 0.0) return false;
355 double r2_s = (-b + std::sqrt(d)) / (2.0 * a);
356
357 double qa = m_electricalData.k1 * (r2_s * m_electricalData.r1t - m_electricalData.x1t * m_electricalData.k1 -
358 m_electricalData.x2t * m_electricalData.xmt);
359 double qb =
360 r2_s * (r2_s * (m_electricalData.xmt + m_electricalData.x1t) + m_electricalData.r1t * m_electricalData.k1);
361 double qc = r2_s * m_electricalData.r1t - m_electricalData.x1t * m_electricalData.k1 -
362 m_electricalData.x2t * m_electricalData.xmt;
363 double qd = r2_s * (m_electricalData.xmt + m_electricalData.x1t) + m_electricalData.r1t * m_electricalData.k1;
364 m_electricalData.qValue = (-voltage * voltage * (qa - qb)) / (qc * qc + qd * qd);
365
366 return true;
367}
@ 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:457
bool SetOnline(bool online=true)
Set if the element is online or offline.
Definition Element.cpp:447
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 Element * GetCopy()
Get a the element copy.
Definition IndMotor.cpp:134
virtual bool GetPlotData(ElementPlotData &plotData, PlotStudy study=PlotStudy::STABILITY)
Fill the plot data.
Definition IndMotor.cpp:291
virtual bool ShowForm(wxWindow *parent, Element *element)
Show element data form.
Definition IndMotor.cpp:84
virtual wxString GetTipText() const
Get the tip text.
Definition IndMotor.cpp:141
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