20#include "../../editors/ControlEditor.h"
34ControlElementSolver::ControlElementSolver(
ControlEditor* controlEditor,
double timeStep,
double integrationError)
37 m_ownsCtrlContainer =
true;
38 m_ctrlContainer->FillContainer(controlEditor);
39 Initialize(controlEditor, timeStep, integrationError);
44 double integrationError,
47 m_ctrlContainer = ctrlContainer;
48 m_ownsCtrlContainer =
false;
49 Initialize(parent, timeStep, integrationError);
52ControlElementSolver::~ControlElementSolver()
54 if (m_inputToSolve)
delete[] m_inputToSolve;
55 if (m_ownsCtrlContainer && m_ctrlContainer)
delete m_ctrlContainer;
58void ControlElementSolver::Initialize(wxWindow* parent,
double timeStep,
double integrationError)
61 if (m_inputToSolve)
delete[] m_inputToSolve;
62 m_inputToSolve =
new double[3];
65 auto ioList = m_ctrlContainer->GetIOControlList();
66 if (ioList.size() < 2) {
68 m_failMessage = _(
"The control system must have at least one input and one output.");
70 bool haveInput, haveOutput;
71 haveInput = haveOutput =
false;
72 for (
auto it = ioList.begin(), itEnd = ioList.end(); it != itEnd; ++it) {
74 if (io->GetType() == Node::NodeType::NODE_OUT && !haveInput) {
78 else if (io->GetType() == Node::NodeType::NODE_IN) {
83 if (!fail && !haveInput) {
85 m_failMessage = _(
"There is no input in the control system.");
87 if (!fail && !haveOutput) {
89 m_failMessage = _(
"There is no output in the control system.");
94 m_failMessage = _(
"Input not connected.");
98 m_timeStep = timeStep;
99 m_integrationError = integrationError;
101 if (!InitializeValues(
true)) {
103 m_failMessage = _(
"It was not possible to initialize the control system.");
108 wxMessageDialog msgDialog(parent, m_failMessage, _(
"Error"), wxOK | wxCENTRE | wxICON_ERROR);
109 msgDialog.ShowModal();
116bool ControlElementSolver::InitializeValues(
bool startAllZero)
119 auto elementList = m_ctrlContainer->GetControlElementsList();
120 for (
auto it = elementList.begin(), itEnd = elementList.end(); it != itEnd; ++it) {
121 if (!(*it)->Initialize())
return false;
123 auto connectionLineList = m_ctrlContainer->GetConnectionLineList();
124 for (
auto it = connectionLineList.begin(), itEnd = connectionLineList.end(); it != itEnd; ++it) {
125 if (!(*it)->Initialize())
return false;
127 auto tfList = m_ctrlContainer->GetTFList();
128 for (
auto it = tfList.begin(), itEnd = tfList.end(); it != itEnd; ++it) {
129 (*it)->CalculateSpaceState(100, m_integrationError);
133 double origTimeStep = m_timeStep;
134 double minStep = m_timeStep / 10;
135 double maxStep = m_timeStep * 10;
137 double minError = 1e-7 * m_timeStep;
138 int maxIteration = 100 / m_timeStep;
140 double prevSol = 0.0;
141 double currentSol = 1.0;
143 double prevError = 1.0;
145 while (error > minError) {
146 prevSol = currentSol;
149 currentSol = GetLastSolution();
151 error = std::abs(prevSol - currentSol);
152 if (std::abs(error - prevError) < 1e-1) {
153 if (m_timeStep < maxStep) { m_timeStep *= 1.5; }
155 else if (std::abs(error - prevError) > 10) {
156 if (m_timeStep > minStep) { m_timeStep /= 1.5; }
158 if (numIt >= maxIteration) {
159 m_failMessage = _(
"It was not possible to initialize the control system.");
163 m_timeStep = origTimeStep;
170void ControlElementSolver::SolveNextStep()
173 auto elementList = m_ctrlContainer->GetControlElementsList();
174 for (
auto& element : elementList) {
175 element->SetSolved(
false);
177 auto connectionLineList = m_ctrlContainer->GetConnectionLineList();
178 for (
auto& cLine : connectionLineList) {
179 cLine->SetSolved(
false);
186 auto constantList = m_ctrlContainer->GetConstantList();
187 for (
auto it = constantList.begin(), itEnd = constantList.end(); it != itEnd; ++it) {
190 constant->SetSolved();
192 child->SetValue(constant->GetValue());
194 FillAllConnectedChildren(child);
199 auto mathExprList = m_ctrlContainer->GetMathExprList();
200 for (
auto it = mathExprList.begin(), itEnd = mathExprList.end(); it != itEnd; ++it) {
202 if (mathExpr->GetVariables().size() == 0) {
203 m_inputToSolve[0] = 0.0;
204 m_inputToSolve[1] = m_currentTime;
205 m_inputToSolve[2] = m_switchStatus;
206 mathExpr->Solve(m_inputToSolve, m_timeStep);
207 mathExpr->SetSolved();
209 child->SetValue(mathExpr->GetOutput());
211 FillAllConnectedChildren(child);
216 auto ioList = m_ctrlContainer->GetIOControlList();
217 for (
auto it = ioList.begin(), itEnd = ioList.end(); it != itEnd; ++it) {
223 bool inputType =
true;
225 switch (io->GetValue()) {
226 case IOControl::IN_TERMINAL_VOLTAGE: {
227 child->SetValue(m_terminalVoltage);
229 case IOControl::IN_VELOCITY: {
230 child->SetValue(m_velocity);
232 case IOControl::IN_ACTIVE_POWER: {
233 child->SetValue(m_activePower);
235 case IOControl::IN_REACTIVE_POWER: {
236 child->SetValue(m_reactivePower);
238 case IOControl::IN_INITIAL_TERMINAL_VOLTAGE: {
239 child->SetValue(m_initTerminalVoltage);
241 case IOControl::IN_INITIAL_MEC_POWER: {
242 child->SetValue(m_initMecPower);
244 case IOControl::IN_INITIAL_VELOCITY: {
245 child->SetValue(m_initVelocity);
247 case IOControl::IN_DELTA_VELOCITY: {
248 child->SetValue(m_deltaVelocity);
250 case IOControl::IN_DELTA_ACTIVE_POWER: {
251 child->SetValue(m_deltaPe);
253 case IOControl::IN_TEST: {
254 child->SetValue(io->GetTestValue());
258 io->SetSolved(
false);
263 FillAllConnectedChildren(child);
269 while (currentLine) {
270 currentLine = SolveNextElement(currentLine);
274 bool haveUnsolvedElement =
true;
275 while (haveUnsolvedElement) {
276 haveUnsolvedElement =
false;
278 for (
auto& cLine : connectionLineList) {
279 if (cLine->IsSolved()) {
280 auto parentList = cLine->GetParentList();
281 for (
auto itP = parentList.begin(), itPEnd = parentList.end(); itP != itPEnd; ++itP) {
283 if (!parent->IsSolved()) {
284 haveUnsolvedElement =
true;
286 currentLine = cLine.get();
287 while (currentLine) {
288 currentLine = SolveNextElement(currentLine);
295 if (haveUnsolvedElement)
break;
300 for (
auto it = ioList.begin(), itEnd = ioList.end(); it != itEnd; ++it) {
305 switch (io->GetValue()) {
306 case IOControl::OUT_MEC_POWER: {
307 m_mecPower = child->GetValue();
308 m_solutions.push_back(m_mecPower);
310 case IOControl::OUT_FIELD_VOLTAGE: {
311 m_fieldVoltage = child->GetValue();
312 m_solutions.push_back(m_fieldVoltage);
321void ControlElementSolver::FillAllConnectedChildren(
ConnectionLine* parent)
323 auto childList = parent->GetLineChildList();
324 for (
auto it = childList.begin(), itEnd = childList.end(); it != itEnd; ++it) {
326 child->SetValue(parent->GetValue());
328 FillAllConnectedChildren(child);
335 for (
auto it = parentList.begin(), itEnd = parentList.end(); it != itEnd; ++it) {
338 if (!element->IsSolved()) {
339 m_inputToSolve[0] = currentLine->GetValue();
340 if (!std::isfinite(m_inputToSolve[0])) {
341 m_inputToSolve[0] = 0.0;
343 m_failMessage = _(
"The control system solution is diverging. Try to reduce the time step.");
346 m_inputToSolve[1] = m_currentTime;
347 m_inputToSolve[2] = m_switchStatus;
348 if (!element->Solve(m_inputToSolve, m_timeStep)) {
351 wxString numerator, denominator;
352 tf->GetTFString(numerator, denominator);
353 m_failMessage = wxString::Format(_(
"Unable to compute the transfer function: (%s)/(%s)"), numerator, denominator);
357 element->SetSolved();
360 Node* outNode =
nullptr;
361 auto nodeList = element->GetNodeList();
362 for (
auto itN = nodeList.begin(), itNEnd = nodeList.end(); itN != itNEnd; ++itN) {
364 if (node->GetNodeType() == Node::NodeType::NODE_OUT) outNode = node;
366 if (!outNode)
return nullptr;
370 for (
auto itC = childList.begin(), itCEnd = childList.end(); itC != itCEnd; ++itC) {
372 if (!cLine->IsSolved()) {
374 auto lineNodeList = cLine->GetNodeList();
375 for (
auto itCN = lineNodeList.begin(), itCNEnd = lineNodeList.end(); itCN != itCNEnd; ++itCN) {
376 Node* childNode = *itCN;
377 if (childNode == outNode) {
379 if (cLine->GetType() != ConnectionLine::ConnectionLineType::ELEMENT_ELEMENT)
return nullptr;
382 cLine->SetValue(element->GetOutput());
384 FillAllConnectedChildren(cLine);
Connection between two control elements or other connection line and an element.
A control element that provides a constant value.
Class that can contain all control elements. Can identify (using RTTI) the elements from a generic li...
IOControl * m_inputControl
virtual std::vector< Element * > GetParentList() const
Get the parent list.
virtual std::vector< Element * > GetChildList() const
Get the Child list.
Provides the communication with the power element.
A generic math expression block that can perform math and conditional operations with the inputs.
Node of a control element. This class manages the user interaction with the connection and control el...
Calculates the time response by a frequency domain transfer function.