20#include "../../editors/ControlEditor.h"
34ControlElementSolver::ControlElementSolver(
ControlEditor* controlEditor,
double timeStep,
double integrationError)
37 m_ctrlContainer->FillContainer(controlEditor);
38 Initialize(controlEditor, timeStep, integrationError);
43 double integrationError,
46 m_ctrlContainer = ctrlContainer;
47 Initialize(parent, timeStep, integrationError);
50ControlElementSolver::~ControlElementSolver()
52 if (m_inputToSolve)
delete[] m_inputToSolve;
56void ControlElementSolver::Initialize(wxWindow* parent,
double timeStep,
double integrationError)
59 if (m_inputToSolve)
delete[] m_inputToSolve;
60 m_inputToSolve =
new double[3];
63 auto ioList = m_ctrlContainer->GetIOControlList();
64 if (ioList.size() < 2) {
66 m_failMessage = _(
"The control system must have at least one input and one output.");
68 bool haveInput, haveOutput;
69 haveInput = haveOutput =
false;
70 for (
auto it = ioList.begin(), itEnd = ioList.end(); it != itEnd; ++it) {
72 if (io->GetType() == Node::NodeType::NODE_OUT && !haveInput) {
76 else if (io->GetType() == Node::NodeType::NODE_IN) {
81 if (!fail && !haveInput) {
83 m_failMessage = _(
"There is no input in the control system.");
85 if (!fail && !haveOutput) {
87 m_failMessage = _(
"There is no output in the control system.");
92 m_failMessage = _(
"Input not connected.");
96 m_timeStep = timeStep;
97 m_integrationError = integrationError;
99 if (!InitializeValues(
true)) {
101 m_failMessage = _(
"It was not possible to initialize the control system.");
106 wxMessageDialog msgDialog(parent, m_failMessage, _(
"Error"), wxOK | wxCENTRE | wxICON_ERROR);
107 msgDialog.ShowModal();
114bool ControlElementSolver::InitializeValues(
bool startAllZero)
117 auto elementList = m_ctrlContainer->GetControlElementsList();
118 for (
auto it = elementList.begin(), itEnd = elementList.end(); it != itEnd; ++it) {
119 if (!(*it)->Initialize())
return false;
121 auto connectionLineList = m_ctrlContainer->GetConnectionLineList();
122 for (
auto it = connectionLineList.begin(), itEnd = connectionLineList.end(); it != itEnd; ++it) {
123 if (!(*it)->Initialize())
return false;
125 auto tfList = m_ctrlContainer->GetTFList();
126 for (
auto it = tfList.begin(), itEnd = tfList.end(); it != itEnd; ++it) {
127 (*it)->CalculateSpaceState(100, m_integrationError);
131 double origTimeStep = m_timeStep;
132 double minStep = m_timeStep / 10;
133 double maxStep = m_timeStep * 10;
135 double minError = 1e-7 * m_timeStep;
136 int maxIteration = 100 / m_timeStep;
138 double prevSol = 0.0;
139 double currentSol = 1.0;
141 double prevError = 1.0;
143 while (error > minError) {
144 prevSol = currentSol;
147 currentSol = GetLastSolution();
149 error = std::abs(prevSol - currentSol);
150 if (std::abs(error - prevError) < 1e-1) {
151 if (m_timeStep < maxStep) { m_timeStep *= 1.5; }
153 else if (std::abs(error - prevError) > 10) {
154 if (m_timeStep > minStep) { m_timeStep /= 1.5; }
156 if (numIt >= maxIteration) {
157 m_failMessage = _(
"It was not possible to initialize the control system.");
161 m_timeStep = origTimeStep;
168void ControlElementSolver::SolveNextStep()
171 auto elementList = m_ctrlContainer->GetControlElementsList();
172 for (
auto& element : elementList) {
173 element->SetSolved(
false);
175 auto connectionLineList = m_ctrlContainer->GetConnectionLineList();
176 for (
auto& cLine : connectionLineList) {
177 cLine->SetSolved(
false);
184 auto constantList = m_ctrlContainer->GetConstantList();
185 for (
auto it = constantList.begin(), itEnd = constantList.end(); it != itEnd; ++it) {
188 constant->SetSolved();
190 child->SetValue(constant->GetValue());
192 FillAllConnectedChildren(child);
197 auto mathExprList = m_ctrlContainer->GetMathExprList();
198 for (
auto it = mathExprList.begin(), itEnd = mathExprList.end(); it != itEnd; ++it) {
200 if (mathExpr->GetVariables().size() == 0) {
201 m_inputToSolve[0] = 0.0;
202 m_inputToSolve[1] = m_currentTime;
203 m_inputToSolve[2] = m_switchStatus;
204 mathExpr->Solve(m_inputToSolve, m_timeStep);
205 mathExpr->SetSolved();
207 child->SetValue(mathExpr->GetOutput());
209 FillAllConnectedChildren(child);
214 auto ioList = m_ctrlContainer->GetIOControlList();
215 for (
auto it = ioList.begin(), itEnd = ioList.end(); it != itEnd; ++it) {
221 bool inputType =
true;
223 switch (io->GetValue()) {
224 case IOControl::IN_TERMINAL_VOLTAGE: {
225 child->SetValue(m_terminalVoltage);
227 case IOControl::IN_VELOCITY: {
228 child->SetValue(m_velocity);
230 case IOControl::IN_ACTIVE_POWER: {
231 child->SetValue(m_activePower);
233 case IOControl::IN_REACTIVE_POWER: {
234 child->SetValue(m_reactivePower);
236 case IOControl::IN_INITIAL_TERMINAL_VOLTAGE: {
237 child->SetValue(m_initTerminalVoltage);
239 case IOControl::IN_INITIAL_MEC_POWER: {
240 child->SetValue(m_initMecPower);
242 case IOControl::IN_INITIAL_VELOCITY: {
243 child->SetValue(m_initVelocity);
245 case IOControl::IN_DELTA_VELOCITY: {
246 child->SetValue(m_deltaVelocity);
248 case IOControl::IN_DELTA_ACTIVE_POWER: {
249 child->SetValue(m_deltaPe);
251 case IOControl::IN_TEST: {
252 child->SetValue(io->GetTestValue());
256 io->SetSolved(
false);
261 FillAllConnectedChildren(child);
267 while (currentLine) {
268 currentLine = SolveNextElement(currentLine);
272 bool haveUnsolvedElement =
true;
273 while (haveUnsolvedElement) {
274 haveUnsolvedElement =
false;
276 for (
auto& cLine : connectionLineList) {
277 if (cLine->IsSolved()) {
278 auto parentList = cLine->GetParentList();
279 for (
auto itP = parentList.begin(), itPEnd = parentList.end(); itP != itPEnd; ++itP) {
281 if (!parent->IsSolved()) {
282 haveUnsolvedElement =
true;
284 currentLine = cLine.get();
285 while (currentLine) {
286 currentLine = SolveNextElement(currentLine);
293 if (haveUnsolvedElement)
break;
298 for (
auto it = ioList.begin(), itEnd = ioList.end(); it != itEnd; ++it) {
303 switch (io->GetValue()) {
304 case IOControl::OUT_MEC_POWER: {
305 m_mecPower = child->GetValue();
306 m_solutions.push_back(m_mecPower);
308 case IOControl::OUT_FIELD_VOLTAGE: {
309 m_fieldVoltage = child->GetValue();
310 m_solutions.push_back(m_fieldVoltage);
319void ControlElementSolver::FillAllConnectedChildren(
ConnectionLine* parent)
321 auto childList = parent->GetLineChildList();
322 for (
auto it = childList.begin(), itEnd = childList.end(); it != itEnd; ++it) {
324 child->SetValue(parent->GetValue());
326 FillAllConnectedChildren(child);
333 for (
auto it = parentList.begin(), itEnd = parentList.end(); it != itEnd; ++it) {
336 if (!element->IsSolved()) {
337 m_inputToSolve[0] = currentLine->GetValue();
338 if (!std::isfinite(m_inputToSolve[0])) {
339 m_inputToSolve[0] = 0.0;
341 m_failMessage = _(
"The control system solution is diverging. Try to reduce the time step.");
344 m_inputToSolve[1] = m_currentTime;
345 m_inputToSolve[2] = m_switchStatus;
346 if (!element->Solve(m_inputToSolve, m_timeStep)) {
349 wxString numerator, denominator;
350 tf->GetTFString(numerator, denominator);
351 m_failMessage = wxString::Format(_(
"Unable to compute the transfer function: (%s)/(%s)"), numerator, denominator);
355 element->SetSolved();
358 Node* outNode =
nullptr;
359 auto nodeList = element->GetNodeList();
360 for (
auto itN = nodeList.begin(), itNEnd = nodeList.end(); itN != itNEnd; ++itN) {
362 if (node->GetNodeType() == Node::NodeType::NODE_OUT) outNode = node;
364 if (!outNode)
return nullptr;
368 for (
auto itC = childList.begin(), itCEnd = childList.end(); itC != itCEnd; ++itC) {
370 if (!cLine->IsSolved()) {
372 auto lineNodeList = cLine->GetNodeList();
373 for (
auto itCN = lineNodeList.begin(), itCNEnd = lineNodeList.end(); itCN != itCNEnd; ++itCN) {
374 Node* childNode = *itCN;
375 if (childNode == outNode) {
377 if (cLine->GetType() != ConnectionLine::ConnectionLineType::ELEMENT_ELEMENT)
return nullptr;
380 cLine->SetValue(element->GetOutput());
382 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.