summaryrefslogtreecommitdiffstats
path: root/Project
diff options
context:
space:
mode:
Diffstat (limited to 'Project')
-rw-r--r--Project/ChartView.cpp2
-rw-r--r--Project/ChartView.h2
-rw-r--r--Project/ConnectionLine.h5
-rw-r--r--Project/ControlEditor.cpp106
-rw-r--r--Project/ControlEditor.h4
-rw-r--r--Project/ControlElement.cpp6
-rw-r--r--Project/ControlElement.h32
-rw-r--r--Project/ControlElementContainer.cpp5
-rw-r--r--Project/ControlElementSolver.cpp263
-rw-r--r--Project/ControlElementSolver.h49
-rw-r--r--Project/Exponential.cpp6
-rw-r--r--Project/Exponential.h2
-rw-r--r--Project/Gain.cpp6
-rw-r--r--Project/Gain.h2
-rw-r--r--Project/IOControl.h1
-rw-r--r--Project/Limiter.cpp9
-rw-r--r--Project/Limiter.h1
-rw-r--r--Project/Multiplier.cpp39
-rw-r--r--Project/Multiplier.h4
-rw-r--r--Project/Project.mk16
-rw-r--r--Project/Project.project2
-rw-r--r--Project/Project.txt2
-rw-r--r--Project/RateLimiter.cpp27
-rw-r--r--Project/RateLimiter.h2
-rw-r--r--Project/Sum.cpp44
-rw-r--r--Project/Sum.h3
-rw-r--r--Project/TransferFunction.cpp111
-rw-r--r--Project/TransferFunction.h31
28 files changed, 702 insertions, 80 deletions
diff --git a/Project/ChartView.cpp b/Project/ChartView.cpp
index 199060a..2f3f70d 100644
--- a/Project/ChartView.cpp
+++ b/Project/ChartView.cpp
@@ -45,6 +45,8 @@ ChartView::~ChartView() {}
void ChartView::SetMPWindow()
{
m_mpWindow = new mpWindow(this, wxID_ANY);
+
+ m_mpWindow->SetDoubleBuffered(true);
m_mpWindow->SetMargins(20, 10, 40, 60);
m_xaxis = new mpScaleX("", mpALIGN_BOTTOM, true);
diff --git a/Project/ChartView.h b/Project/ChartView.h
index b40a63d..741ffe2 100644
--- a/Project/ChartView.h
+++ b/Project/ChartView.h
@@ -54,7 +54,7 @@ class ChartView : public ChartViewBase
mpInfoCoords* m_coords = NULL;
mpInfoLegend* m_leg = NULL;
- bool m_hideGrid = false;
+ bool m_hideGrid = true;
bool m_showLeg = false;
bool m_showCoords = false;
bool m_darkTheme = false;
diff --git a/Project/ConnectionLine.h b/Project/ConnectionLine.h
index e9d238a..98e3098 100644
--- a/Project/ConnectionLine.h
+++ b/Project/ConnectionLine.h
@@ -29,6 +29,9 @@ class ConnectionLine : public ControlElement
virtual bool SetParentLine(ConnectionLine* parent);
virtual std::vector<ConnectionLine*> GetLineChildList() const;
+
+ virtual double GetValue() const { return m_value; }
+ virtual void SetValue(double value) { m_value = value; }
protected:
double m_lineOffset = 0.0;
@@ -38,6 +41,8 @@ class ConnectionLine : public ControlElement
ConnectionLineType m_type = ELEMENT_ELEMENT;
ConnectionLine* m_parentLine = NULL;
+
+ double m_value;
};
#endif // CONNECTIONLINE_H
diff --git a/Project/ControlEditor.cpp b/Project/ControlEditor.cpp
index 27c5662..12a9bd1 100644
--- a/Project/ControlEditor.cpp
+++ b/Project/ControlEditor.cpp
@@ -16,6 +16,8 @@
#include "Constant.h"
#include "Gain.h"
+#include "ControlElementSolver.h"
+
#include "ChartView.h"
#include "ElementPlotData.h"
@@ -617,35 +619,73 @@ void ControlEditor::OnKeyDown(wxKeyEvent& event)
{
RotateSelectedElements(event.GetModifiers() != wxMOD_SHIFT);
} break;
- case 'L':
- {
- //tests
+ case 'L': {
+ // tests
if(event.ControlDown() && event.ShiftDown()) {
- std::vector<double> time, sinC, cosC, tgC;
- for(int i=0; i<360; ++i) {
- time.push_back(i);
- sinC.push_back(std::sin(wxDegToRad(i)));
- cosC.push_back(std::cos(wxDegToRad(i)));
- tgC.push_back(std::tan(wxDegToRad(i)));
+ double timeStep = 1e-4;
+ double integrationError = 1e-5;
+ double simTime = 10.0;
+ double printStep = 1e-3;
+ double pdbStep = 1e-1;
+
+ double pulsePer = 5.0;
+
+ wxProgressDialog pbd(_("Test"), _("Initializing..."), 100, this,
+ wxPD_APP_MODAL | wxPD_AUTO_HIDE | wxPD_CAN_ABORT | wxPD_SMOOTH);
+ pbd.SetDoubleBuffered(true);
+ ControlElementSolver solver(this, timeStep, integrationError, false, 0.0);
+ if(solver.IsOK()) {
+ bool simStopped = false;
+ double currentTime = 0.0;
+ double printTime = 0.0;
+ double pulseTime = 0.0;
+ double pdbTime = 0.0;
+ std::vector<double> time;
+ std::vector<double> solution;
+ std::vector<double> inputV;
+ while(currentTime <= simTime) {
+ double input = 0.0;
+ if(pulseTime >= pulsePer * 2.0) pulseTime = 0.0;
+ if(pulseTime >= pulsePer) input = 1.0;
+
+ solver.SolveNextStep(input);
+ if(printTime >= printStep) {
+ time.push_back(currentTime);
+ solution.push_back(solver.GetLastSolution());
+ inputV.push_back(input);
+ printTime = 0.0;
+ }
+ if((pdbTime > pdbStep)) {
+ if(!pbd.Update((currentTime / simTime) * 100,
+ wxString::Format("Time = %.2fs", currentTime))) {
+ pbd.Update(100);
+ simStopped = true;
+ currentTime = simTime;
+ }
+ pbd.Refresh();
+ pbd.Update();
+ pdbTime = 0.0;
+ }
+ printTime += timeStep;
+ currentTime += timeStep;
+ pulseTime += timeStep;
+ pdbTime += timeStep;
+ }
+ if(!simStopped) {
+ std::vector<ElementPlotData> epdList;
+ ElementPlotData curve1Data(_("TESTES"), ElementPlotData::CT_BUS);
+ curve1Data.AddData(inputV, _("Entrada"));
+ curve1Data.AddData(solution, _("Saida"));
+ epdList.push_back(curve1Data);
+
+ ChartView* cView = new ChartView(this, epdList, time);
+ cView->Show();
+ }
+ } else {
+ wxMessageDialog msgDialog(this, _("It was not possible to solve the control system"),
+ _("Error"), wxOK | wxCENTRE | wxICON_ERROR);
+ msgDialog.ShowModal();
}
- std::vector<ElementPlotData> epdList;
-
- ElementPlotData curve1Data(_("Func. polinomiais 1"), ElementPlotData::CT_BUS);
- curve1Data.AddData(sinC, _("seno"));
- epdList.push_back(curve1Data);
-
- ElementPlotData curve2Data(_("Func. polinomiais 2"), ElementPlotData::CT_BUS);
- curve2Data.AddData(tgC, _("tangente"));
- epdList.push_back(curve2Data);
-
- ElementPlotData curve3Data(_("Func. polinomiais 3"), ElementPlotData::CT_SYNC_GENERATOR);
- curve3Data.AddData(sinC, _("seno"));
- curve3Data.AddData(cosC, _("cosseno"));
- curve3Data.AddData(tgC, _("tangente"));
- epdList.push_back(curve3Data);
-
- ChartView* cView = new ChartView(this, epdList, time);
- cView->Show();
}
}
}
@@ -771,21 +811,19 @@ void ControlEditor::OnImportClick(wxCommandEvent& event)
wxOK | wxCENTRE | wxICON_ERROR);
msgDialog.ShowModal();
}
-
- //Get the highest id number
+
+ // Get the highest id number
int majorElementID = 0;
for(auto it = m_elementList.begin(), itEnd = m_elementList.end(); it != itEnd; ++it) {
ControlElement* element = *it;
- if(element->GetID() > majorElementID)
- majorElementID = element->GetID();
+ if(element->GetID() > majorElementID) majorElementID = element->GetID();
}
for(auto it = m_connectionList.begin(), itEnd = m_connectionList.end(); it != itEnd; ++it) {
ConnectionLine* line = *it;
- if(line->GetID() > majorElementID)
- majorElementID = line->GetID();
+ if(line->GetID() > majorElementID) majorElementID = line->GetID();
}
m_lastElementID = ++majorElementID;
-
+
Redraw();
event.Skip();
}
diff --git a/Project/ControlEditor.h b/Project/ControlEditor.h
index 232ebd8..9de5a1f 100644
--- a/Project/ControlEditor.h
+++ b/Project/ControlEditor.h
@@ -9,6 +9,8 @@
#include <GL/gl.h>
#include <GL/glu.h>
+#include <wx/progdlg.h>
+
#include "IOControl.h"
class FileHanding;
@@ -25,6 +27,8 @@ class Exponential;
class Constant;
class Gain;
+class ControlElementSolver;
+
class ChartView;
class ElementDataObject;
diff --git a/Project/ControlElement.cpp b/Project/ControlElement.cpp
index fa99206..8df534a 100644
--- a/Project/ControlElement.cpp
+++ b/Project/ControlElement.cpp
@@ -121,3 +121,9 @@ void ControlElement::Move(wxPoint2DDouble position)
m_nodeList[i]->Move(position);
}
}
+
+bool ControlElement::Solve(double input, double timeStep)
+{
+ m_output = input;
+ return true;
+}
diff --git a/Project/ControlElement.h b/Project/ControlElement.h
index 1cf4e0b..1e60f97 100644
--- a/Project/ControlElement.h
+++ b/Project/ControlElement.h
@@ -5,7 +5,7 @@
class Node
{
-public:
+ public:
enum NodeType { NODE_IN = 0, NODE_OUT };
Node(wxPoint2DDouble position = wxPoint2DDouble(0, 0), NodeType nodeType = NODE_IN, double borderSize = 0.0);
@@ -13,39 +13,33 @@ public:
wxRect2DDouble GetRect() const { return m_rect; }
void SetRect(wxRect2DDouble rect) { m_rect = rect; }
-
wxPoint2DDouble GetPosition() const;
void SetPosition(wxPoint2DDouble position);
NodeType GetNodeType() const { return m_nodeType; }
void SetNodeType(NodeType nodeType) { m_nodeType = nodeType; }
-
double GetRadius() const { return m_radius; }
std::vector<wxPoint2DDouble> GetInTrianglePts() const { return m_triPts; }
-
double GetAngle() const { return m_angle; }
void SetAngle(double angle) { m_angle = angle; }
-
void Rotate(bool clockwise = true);
-
+
void RotateTriPt(double angle);
void StartMove(wxPoint2DDouble position);
void Move(wxPoint2DDouble position);
bool Contains(wxPoint2DDouble position) const;
-
+
bool IsConnected() const { return m_connected; }
void SetConnected(bool connected = true) { m_connected = connected; }
-
int GetID() const { return m_id; }
void SetID(int id) { m_id = id; }
-
-protected:
+ protected:
int m_id = -1;
-
+
wxRect2DDouble m_rect;
NodeType m_nodeType;
-
+
bool m_connected = false;
wxPoint2DDouble m_moveStartPt;
@@ -58,7 +52,7 @@ protected:
class ControlElement : public Element
{
-public:
+ public:
ControlElement(int id);
~ControlElement();
@@ -67,11 +61,17 @@ public:
void SetNodeList(std::vector<Node*> nodeList) { m_nodeList = nodeList; }
std::vector<Node*> GetNodeList() const { return m_nodeList; }
-
virtual void DrawNodes() const;
-protected:
+ virtual bool IsSolved() const { return m_solved; }
+ virtual void SetSolved(bool solved = true) { m_solved = solved; }
+ virtual bool Solve(double input, double timeStep);
+ virtual double GetOutput() const { return m_output; }
+ virtual void SetOutput(double output) { m_output = output; }
+ protected:
std::vector<Node*> m_nodeList;
+ bool m_solved = false;
+ double m_output = 0.0;
};
-#endif // CONTROLELEMENT_H
+#endif // CONTROLELEMENT_H
diff --git a/Project/ControlElementContainer.cpp b/Project/ControlElementContainer.cpp
index f5372a8..e461529 100644
--- a/Project/ControlElementContainer.cpp
+++ b/Project/ControlElementContainer.cpp
@@ -2,7 +2,7 @@
#include "ControlEditor.h"
#include "ControlElement.h"
-ControlElementContainer::ControlElementContainer() {}
+ControlElementContainer::ControlElementContainer() { ClearContainer(); }
ControlElementContainer::~ControlElementContainer() {}
void ControlElementContainer::FillContainer(ControlEditor* editor)
{
@@ -47,7 +47,8 @@ void ControlElementContainer::ClearContainer()
m_tfList.clear();
}
-void ControlElementContainer::FillContainer(std::vector<ControlElement*> controlElementList, std::vector<ConnectionLine*> connectionLineList)
+void ControlElementContainer::FillContainer(std::vector<ControlElement*> controlElementList,
+ std::vector<ConnectionLine*> connectionLineList)
{
m_ctrlElementsList = controlElementList;
m_cLineList = connectionLineList;
diff --git a/Project/ControlElementSolver.cpp b/Project/ControlElementSolver.cpp
new file mode 100644
index 0000000..e67cb9a
--- /dev/null
+++ b/Project/ControlElementSolver.cpp
@@ -0,0 +1,263 @@
+#include "ControlElementSolver.h"
+
+#include "ControlElementContainer.h"
+#include "ControlEditor.h"
+#include "ConnectionLine.h"
+#include "Constant.h"
+#include "Exponential.h"
+#include "Gain.h"
+#include "IOControl.h"
+#include "Limiter.h"
+#include "Multiplier.h"
+#include "RateLimiter.h"
+#include "Sum.h"
+#include "TransferFunction.h"
+
+ControlElementSolver::ControlElementSolver(ControlEditor* controlEditor,
+ double timeStep,
+ double integrationError,
+ bool startAllZero,
+ double input)
+{
+ m_ctrlContainer = new ControlElementContainer();
+ m_ctrlContainer->FillContainer(controlEditor);
+
+ // Check if the sistem have one input and one output
+ bool fail = false;
+ wxString failMessage = "";
+ auto ioList = m_ctrlContainer->GetIOControlList();
+ if(ioList.size() != 2) {
+ fail = true;
+ failMessage = _("The control system must have one input and one output.");
+ }
+ bool haveInput, haveOutput;
+ haveInput = haveOutput = false;
+ for(auto it = ioList.begin(), itEnd = ioList.end(); it != itEnd; ++it) {
+ IOControl* io = *it;
+ if(io->GetType() == Node::NODE_OUT) {
+ m_inputControl = io;
+ haveInput = true;
+ } else if(io->GetType() == Node::NODE_IN) {
+ m_outputControl = io;
+ haveOutput = true;
+ }
+ }
+ if(!fail && !haveInput) {
+ fail = true;
+ failMessage = _("There is no input in the control system.");
+ }
+ if(!fail && !haveOutput) {
+ fail = true;
+ failMessage = _("There is no output in the control system.");
+ }
+ if(!fail) {
+ if(m_inputControl->GetChildList().size() == 0) {
+ fail = true;
+ failMessage = _("Input not connected.");
+ }
+ }
+
+ m_timeStep = timeStep;
+ m_integrationError = integrationError;
+ if(!fail) {
+ if(!InitializeValues(input, startAllZero)) {
+ fail = true;
+ failMessage = _("It was not possible to initialize the control system.");
+ }
+ }
+
+ if(fail) {
+ wxMessageDialog msgDialog(controlEditor, failMessage, _("Error"), wxOK | wxCENTRE | wxICON_ERROR);
+ msgDialog.ShowModal();
+ } else {
+ m_isOK = true;
+ }
+}
+
+bool ControlElementSolver::InitializeValues(double input, bool startAllZero)
+{
+ // Reset Elements values
+ auto elementList = m_ctrlContainer->GetControlElementsList();
+ for(auto it = elementList.begin(), itEnd = elementList.end(); it != itEnd; ++it) {
+ ControlElement* element = *it;
+ element->SetSolved(false);
+ element->SetOutput(0.0);
+ }
+ auto tfList = m_ctrlContainer->GetTFList();
+ for(auto it = tfList.begin(), itEnd = tfList.end(); it != itEnd; ++it) {
+ TransferFunction* tf = *it;
+ tf->CalculateSpaceState(100, m_integrationError);
+ }
+ auto connectionLineList = m_ctrlContainer->GetConnectionLineList();
+ for(auto it = connectionLineList.begin(), itEnd = connectionLineList.end(); it != itEnd; ++it) {
+ ConnectionLine* cLine = *it;
+ cLine->SetSolved(false);
+ cLine->SetValue(0.0);
+ }
+
+ if(!startAllZero) {
+ double origTimeStep = m_timeStep;
+ double minStep = m_timeStep / 10;
+ double maxStep = m_timeStep * 10;
+ // Calculate the steady-state results according to the input.
+ double minError = 1e-7 * m_timeStep;
+ int maxIteration = 100 / m_timeStep;
+
+ double prevSol = 0.0;
+ double currentSol = 1.0;
+ double error = 1.0;
+ double prevError = 1.0;
+ int numIt = 0;
+ while(error > minError) {
+ prevSol = currentSol;
+ prevError = error;
+ SolveNextStep(input);
+ currentSol = GetLastSolution();
+ numIt++;
+ error = std::abs(prevSol - currentSol);
+ if(std::abs(error - prevError) < 1e-1) {
+ if(m_timeStep < maxStep) {
+ m_timeStep *= 1.5;
+ }
+ } else if(std::abs(error - prevError) > 10) {
+ if(m_timeStep > minStep) {
+ m_timeStep /= 1.5;
+ }
+ }
+ if(numIt >= maxIteration) return false;
+ }
+ m_timeStep = origTimeStep;
+ m_solutions.clear();
+ }
+
+ return true;
+}
+
+void ControlElementSolver::SolveNextStep(double input)
+{
+ // Set all elements as not solved
+ auto elementList = m_ctrlContainer->GetControlElementsList();
+ for(auto it = elementList.begin(), itEnd = elementList.end(); it != itEnd; ++it) {
+ ControlElement* element = *it;
+ element->SetSolved(false);
+ }
+ auto connectionLineList = m_ctrlContainer->GetConnectionLineList();
+ for(auto it = connectionLineList.begin(), itEnd = connectionLineList.end(); it != itEnd; ++it) {
+ ConnectionLine* cLine = *it;
+ cLine->SetSolved(false);
+ }
+
+ // Get first node and set input value on connected lines
+ ConnectionLine* firstConn = static_cast<ConnectionLine*>(m_inputControl->GetChildList()[0]);
+ m_inputControl->SetSolved();
+ firstConn->SetValue(input);
+ firstConn->SetSolved();
+ FillAllConnectedChildren(firstConn);
+
+ // Set value to the connected lines in constants
+ auto constantList = m_ctrlContainer->GetConstantList();
+ for(auto it = constantList.begin(), itEnd = constantList.end(); it != itEnd; ++it) {
+ Constant* constant = *it;
+ if(constant->GetChildList().size() == 1) {
+ constant->SetSolved();
+ ConnectionLine* child = static_cast<ConnectionLine*>(constant->GetChildList()[0]);
+ child->SetValue(constant->GetValue());
+ child->SetSolved();
+ FillAllConnectedChildren(child);
+ }
+ }
+
+ ConnectionLine* currentLine = firstConn;
+ while(currentLine) {
+ currentLine = SolveNextElement(currentLine);
+ }
+
+ bool haveUnsolvedElement = true;
+ while(haveUnsolvedElement) {
+ haveUnsolvedElement = false;
+ // Get the solved line connected with unsolved element (elements not connected in the main branch).
+ for(auto it = connectionLineList.begin(), itEnd = connectionLineList.end(); it != itEnd; ++it) {
+ ConnectionLine* cLine = *it;
+ if(cLine->IsSolved()) {
+ auto parentList = cLine->GetParentList();
+ for(auto itP = parentList.begin(), itPEnd = parentList.end(); itP != itPEnd; ++itP) {
+ ControlElement* parent = static_cast<ControlElement*>(*itP);
+ if(!parent->IsSolved()) {
+ haveUnsolvedElement = true;
+ // Solve secondary branch.
+ currentLine = cLine;
+ while(currentLine) {
+ currentLine = SolveNextElement(currentLine);
+ }
+ break;
+ }
+ }
+ }
+ if(haveUnsolvedElement) break;
+ }
+ }
+
+ // Set the control system step output.
+ if(m_outputControl->GetChildList().size() == 1) {
+ ConnectionLine* cLine = static_cast<ConnectionLine*>(m_outputControl->GetChildList()[0]);
+ m_solutions.push_back(cLine->GetValue());
+ } else
+ m_solutions.push_back(0.0);
+}
+
+void ControlElementSolver::FillAllConnectedChildren(ConnectionLine* parent)
+{
+ auto childList = parent->GetLineChildList();
+ for(auto it = childList.begin(), itEnd = childList.end(); it != itEnd; ++it) {
+ ConnectionLine* child = *it;
+ child->SetValue(parent->GetValue());
+ child->SetSolved();
+ FillAllConnectedChildren(child);
+ }
+}
+
+ConnectionLine* ControlElementSolver::SolveNextElement(ConnectionLine* currentLine)
+{
+ auto parentList = currentLine->GetParentList();
+ for(auto it = parentList.begin(), itEnd = parentList.end(); it != itEnd; ++it) {
+ ControlElement* element = static_cast<ControlElement*>(*it);
+ // Solve the unsolved parent.
+ if(!element->IsSolved()) {
+ if(!element->Solve(currentLine->GetValue(), m_timeStep)) return NULL;
+ element->SetSolved();
+
+ // Get the output node (must have one or will result NULL).
+ Node* outNode = NULL;
+ auto nodeList = element->GetNodeList();
+ for(auto itN = nodeList.begin(), itNEnd = nodeList.end(); itN != itNEnd; ++itN) {
+ Node* node = *itN;
+ if(node->GetNodeType() == Node::NODE_OUT) outNode = node;
+ }
+ if(!outNode) return NULL;
+
+ // Set connection line value associated with the output node.
+ auto childList = element->GetChildList();
+ for(auto itC = childList.begin(), itCEnd = childList.end(); itC != itCEnd; ++itC) {
+ ConnectionLine* cLine = static_cast<ConnectionLine*>(*itC);
+ if(!cLine->IsSolved()) { // Only check unsolved lines
+ // Check if the connection line have the output node on the list
+ auto lineNodeList = cLine->GetNodeList();
+ for(auto itCN = nodeList.begin(), itCNEnd = nodeList.end(); itCN != itCNEnd; ++itCN) {
+ Node* childNode = *itCN;
+ if(childNode == outNode) {
+ // Check if the line connect two elements, otherwise return NULL
+ if(cLine->GetType() != ConnectionLine::ELEMENT_ELEMENT) return NULL;
+
+ // Set the connection line value and return it.
+ cLine->SetValue(element->GetOutput());
+ cLine->SetSolved();
+ FillAllConnectedChildren(cLine);
+ return cLine;
+ }
+ }
+ }
+ }
+ }
+ }
+ return NULL;
+}
diff --git a/Project/ControlElementSolver.h b/Project/ControlElementSolver.h
new file mode 100644
index 0000000..6d0ad3f
--- /dev/null
+++ b/Project/ControlElementSolver.h
@@ -0,0 +1,49 @@
+#ifndef CONTROLELEMENTSOLVER_H
+#define CONTROLELEMENTSOLVER_H
+
+#include <stddef.h> // NULL definition
+#include <vector>
+
+class ControlElementContainer;
+class ControlEditor;
+class ConnectionLine;
+class Constant;
+class Exponential;
+class Gain;
+class IOControl;
+class Limiter;
+class Multiplier;
+class RateLimiter;
+class Sum;
+class TransferFunction;
+
+class ControlElementSolver
+{
+ public:
+ ControlElementSolver() {}
+ ControlElementSolver(ControlEditor* controlEditor,
+ double timeStep = 1e-3,
+ double integrationError = 1e-3,
+ bool startAllZero = false,
+ double input = 0.0);
+ ~ControlElementSolver() {}
+ virtual bool InitializeValues(double input, bool startAllZero);
+ virtual void SolveNextStep(double input);
+ virtual std::vector<double> GetSolutions() { return m_solutions; }
+ virtual double GetLastSolution() { return m_solutions[m_solutions.size() - 1]; }
+ virtual bool IsOK() const { return m_isOK; }
+ protected:
+ void FillAllConnectedChildren(ConnectionLine* parent);
+ ConnectionLine* SolveNextElement(ConnectionLine* currentLine);
+
+ ControlElementContainer* m_ctrlContainer = NULL;
+ double m_timeStep;
+ double m_integrationError;
+ std::vector<double> m_solutions;
+ bool m_isOK = false;
+
+ IOControl* m_inputControl = NULL;
+ IOControl* m_outputControl = NULL;
+};
+
+#endif // CONTROLELEMENTSOLVER_H
diff --git a/Project/Exponential.cpp b/Project/Exponential.cpp
index 7c4f1fe..e0daeef 100644
--- a/Project/Exponential.cpp
+++ b/Project/Exponential.cpp
@@ -111,3 +111,9 @@ void Exponential::SetValues(double aValue, double bValue)
m_aValue = aValue;
m_bValue = bValue;
}
+
+bool Exponential::Solve(double input, double timeStep)
+{
+ m_output = m_aValue * std::exp(m_bValue * input);
+ return true;
+}
diff --git a/Project/Exponential.h b/Project/Exponential.h
index 8260d66..e9e9511 100644
--- a/Project/Exponential.h
+++ b/Project/Exponential.h
@@ -22,6 +22,8 @@ public:
virtual void GetValues(double& aValue, double &bValue);
virtual void SetValues(double aValue, double bValue);
+ virtual bool Solve(double input, double timeStep);
+
protected:
double m_aValue = 0.001;
double m_bValue = 5.0;
diff --git a/Project/Gain.cpp b/Project/Gain.cpp
index faea89c..d2106d7 100644
--- a/Project/Gain.cpp
+++ b/Project/Gain.cpp
@@ -167,3 +167,9 @@ void Gain::Move(wxPoint2DDouble position)
SetPosition(m_movePos + position - m_moveStartPt);
UpdatePoints();
}
+
+bool Gain::Solve(double input, double timeStep)
+{
+ m_output = input * m_value;
+ return true;
+}
diff --git a/Project/Gain.h b/Project/Gain.h
index 8844372..bb9c3ce 100644
--- a/Project/Gain.h
+++ b/Project/Gain.h
@@ -24,6 +24,8 @@ class Gain : public ControlElement
virtual void SetValue(double value);
virtual double GetValue() const { return m_value; }
virtual void UpdatePoints();
+
+ virtual bool Solve(double input, double timeStep);
protected:
double m_value = 1.0;
diff --git a/Project/IOControl.h b/Project/IOControl.h
index 7b3f4d0..8a7666f 100644
--- a/Project/IOControl.h
+++ b/Project/IOControl.h
@@ -35,6 +35,7 @@ class IOControl : public ControlElement
virtual IOFlags GetValue() const { return m_value; }
virtual void SetValue(IOFlags value);
virtual int GetIOFlags() const { return m_ioFlags; }
+ virtual Node::NodeType GetType() { return m_ioNodeType; }
protected:
IOFlags m_value;
diff --git a/Project/Limiter.cpp b/Project/Limiter.cpp
index 2a0b707..cd76fba 100644
--- a/Project/Limiter.cpp
+++ b/Project/Limiter.cpp
@@ -87,3 +87,12 @@ void Limiter::UpdatePoints()
m_nodeList[1]->SetPosition(m_position + wxPoint2DDouble(0, -18));
}
}
+
+bool Limiter::Solve(double input, double timeStep)
+{
+ m_output = input;
+ if(m_output > m_upLimit) m_output = m_upLimit;
+ else if(m_output < m_lowLimit) m_output = m_lowLimit;
+
+ return true;
+}
diff --git a/Project/Limiter.h b/Project/Limiter.h
index 5f4e55b..1585a3c 100644
--- a/Project/Limiter.h
+++ b/Project/Limiter.h
@@ -16,6 +16,7 @@ public:
virtual bool Intersects(wxRect2DDouble rect) const { return m_rect.Intersects(rect); }
virtual bool ShowForm(wxWindow* parent, Element* element);
virtual void Rotate(bool clockwise = true);
+ virtual bool Solve(double input, double timeStep);
virtual void UpdatePoints();
diff --git a/Project/Multiplier.cpp b/Project/Multiplier.cpp
index ee644ed..e8708c9 100644
--- a/Project/Multiplier.cpp
+++ b/Project/Multiplier.cpp
@@ -1,12 +1,12 @@
#include "Multiplier.h"
+#include "ConnectionLine.h"
Multiplier::Multiplier(int id) : ControlElement(id)
{
m_width = m_height = 36.0;
Node* nodeIn1 = new Node(m_position + wxPoint2DDouble(-18, -9), Node::NODE_IN, m_borderSize);
nodeIn1->StartMove(m_position);
- Node* nodeIn2 =
- new Node(m_position + wxPoint2DDouble(-18, 9), Node::NODE_IN, m_borderSize);
+ Node* nodeIn2 = new Node(m_position + wxPoint2DDouble(-18, 9), Node::NODE_IN, m_borderSize);
nodeIn2->StartMove(m_position);
Node* nodeOut = new Node(m_position + wxPoint2DDouble(18, 0), Node::NODE_OUT, m_borderSize);
nodeOut->SetAngle(180.0);
@@ -17,7 +17,6 @@ Multiplier::Multiplier(int id) : ControlElement(id)
}
Multiplier::~Multiplier() {}
-
void Multiplier::Draw(wxPoint2DDouble translation, double scale) const
{
glLineWidth(1.0);
@@ -30,7 +29,7 @@ void Multiplier::Draw(wxPoint2DDouble translation, double scale) const
DrawRectangle(m_position, m_width, m_height);
glColor4d(0.0, 0.0, 0.0, 1.0);
DrawRectangle(m_position, m_width, m_height, GL_LINE_LOOP);
-
+
// Plot x.
glLineWidth(2.0);
std::vector<wxPoint2DDouble> xSymbol;
@@ -84,3 +83,35 @@ void Multiplier::UpdatePoints()
m_nodeList[2]->SetPosition(m_position + wxPoint2DDouble(0, -18));
}
}
+
+bool Multiplier::Solve(double input, double timeStep)
+{
+ std::vector<double> inputVector;
+ for(auto itN = m_nodeList.begin(), itNEnd = m_nodeList.end(); itN != itNEnd; ++itN) {
+ Node* node = *itN;
+ if(node->GetNodeType() != Node::NODE_OUT) {
+ if(!node->IsConnected()) {
+ inputVector.push_back(1.0);
+ } else {
+ for(auto itC = m_childList.begin(), itCEnd = m_childList.end(); itC != itCEnd; ++itC) {
+ ConnectionLine* cLine = static_cast<ConnectionLine*>(*itC);
+ auto nodeList = cLine->GetNodeList();
+ for(auto itCN = nodeList.begin(), itCNEnd = nodeList.end(); itCN != itCNEnd; ++itCN) {
+ Node* childNode = *itCN;
+ if(childNode == node) {
+ inputVector.push_back(cLine->GetValue());
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ m_output = 1.0;
+ for(unsigned int i = 0; i < inputVector.size(); ++i) {
+ m_output *= inputVector[i];
+ }
+
+ return true;
+}
diff --git a/Project/Multiplier.h b/Project/Multiplier.h
index 8a25b23..19fca71 100644
--- a/Project/Multiplier.h
+++ b/Project/Multiplier.h
@@ -3,6 +3,8 @@
#include "ControlElement.h"
+class ConnectionLine;
+
class Multiplier : public ControlElement
{
public:
@@ -16,6 +18,8 @@ class Multiplier : public ControlElement
virtual void Rotate(bool clockwise = true);
virtual void UpdatePoints();
+
+ virtual bool Solve(double input, double timeStep);
};
#endif // MULTIPLIER_H
diff --git a/Project/Project.mk b/Project/Project.mk
index c43d7d9..b9d2fb9 100644
--- a/Project/Project.mk
+++ b/Project/Project.mk
@@ -13,7 +13,7 @@ CurrentFileName :=
CurrentFilePath :=
CurrentFileFullPath :=
User :=NDSE-69
-Date :=03/05/2017
+Date :=13/05/2017
CodeLitePath :="C:/Program Files/CodeLite"
LinkerName :=C:/TDM-GCC-64/bin/g++.exe
SharedObjectLinkerName :=C:/TDM-GCC-64/bin/g++.exe -shared -fPIC
@@ -69,9 +69,9 @@ Objects0=$(IntermediateDirectory)/main.cpp$(ObjectSuffix) $(IntermediateDirector
$(IntermediateDirectory)/WorkspaceBase.cpp$(ObjectSuffix) $(IntermediateDirectory)/ElementForm.cpp$(ObjectSuffix) $(IntermediateDirectory)/ControlEditorBase.cpp$(ObjectSuffix) $(IntermediateDirectory)/ChartViewBase.cpp$(ObjectSuffix) $(IntermediateDirectory)/Bus.cpp$(ObjectSuffix) $(IntermediateDirectory)/Line.cpp$(ObjectSuffix) $(IntermediateDirectory)/Transformer.cpp$(ObjectSuffix) $(IntermediateDirectory)/Machines.cpp$(ObjectSuffix) $(IntermediateDirectory)/SyncGenerator.cpp$(ObjectSuffix) $(IntermediateDirectory)/IndMotor.cpp$(ObjectSuffix) \
$(IntermediateDirectory)/Branch.cpp$(ObjectSuffix) $(IntermediateDirectory)/SyncMotor.cpp$(ObjectSuffix) $(IntermediateDirectory)/Shunt.cpp$(ObjectSuffix) $(IntermediateDirectory)/Load.cpp$(ObjectSuffix) $(IntermediateDirectory)/Inductor.cpp$(ObjectSuffix) $(IntermediateDirectory)/Capacitor.cpp$(ObjectSuffix) $(IntermediateDirectory)/PowerElement.cpp$(ObjectSuffix) $(IntermediateDirectory)/ElectricCalculation.cpp$(ObjectSuffix) $(IntermediateDirectory)/PowerFlow.cpp$(ObjectSuffix) $(IntermediateDirectory)/Fault.cpp$(ObjectSuffix) \
$(IntermediateDirectory)/Text.cpp$(ObjectSuffix) $(IntermediateDirectory)/GraphicalElement.cpp$(ObjectSuffix) $(IntermediateDirectory)/ControlElement.cpp$(ObjectSuffix) $(IntermediateDirectory)/TransferFunction.cpp$(ObjectSuffix) $(IntermediateDirectory)/ConnectionLine.cpp$(ObjectSuffix) $(IntermediateDirectory)/Sum.cpp$(ObjectSuffix) $(IntermediateDirectory)/Multiplier.cpp$(ObjectSuffix) $(IntermediateDirectory)/Limiter.cpp$(ObjectSuffix) $(IntermediateDirectory)/RateLimiter.cpp$(ObjectSuffix) $(IntermediateDirectory)/Exponential.cpp$(ObjectSuffix) \
- $(IntermediateDirectory)/Constant.cpp$(ObjectSuffix) $(IntermediateDirectory)/Gain.cpp$(ObjectSuffix) $(IntermediateDirectory)/IOControl.cpp$(ObjectSuffix) $(IntermediateDirectory)/ControlElementContainer.cpp$(ObjectSuffix) $(IntermediateDirectory)/wxMathPlot_mathplot.cpp$(ObjectSuffix) $(IntermediateDirectory)/BusForm.cpp$(ObjectSuffix) $(IntermediateDirectory)/GeneratorStabForm.cpp$(ObjectSuffix) $(IntermediateDirectory)/LineForm.cpp$(ObjectSuffix) $(IntermediateDirectory)/SwitchingForm.cpp$(ObjectSuffix) $(IntermediateDirectory)/TransformerForm.cpp$(ObjectSuffix) \
- $(IntermediateDirectory)/LoadForm.cpp$(ObjectSuffix) $(IntermediateDirectory)/ReactiveShuntElementForm.cpp$(ObjectSuffix) $(IntermediateDirectory)/IndMotorForm.cpp$(ObjectSuffix) $(IntermediateDirectory)/SyncMachineForm.cpp$(ObjectSuffix) $(IntermediateDirectory)/TextForm.cpp$(ObjectSuffix) $(IntermediateDirectory)/TransferFunctionForm.cpp$(ObjectSuffix) $(IntermediateDirectory)/SumForm.cpp$(ObjectSuffix) $(IntermediateDirectory)/LimiterForm.cpp$(ObjectSuffix) $(IntermediateDirectory)/RateLimiterForm.cpp$(ObjectSuffix) $(IntermediateDirectory)/ExponentialForm.cpp$(ObjectSuffix) \
- $(IntermediateDirectory)/ConstantForm.cpp$(ObjectSuffix) $(IntermediateDirectory)/GainForm.cpp$(ObjectSuffix) $(IntermediateDirectory)/IOControlForm.cpp$(ObjectSuffix)
+ $(IntermediateDirectory)/Constant.cpp$(ObjectSuffix) $(IntermediateDirectory)/Gain.cpp$(ObjectSuffix) $(IntermediateDirectory)/IOControl.cpp$(ObjectSuffix) $(IntermediateDirectory)/ControlElementContainer.cpp$(ObjectSuffix) $(IntermediateDirectory)/ControlElementSolver.cpp$(ObjectSuffix) $(IntermediateDirectory)/wxMathPlot_mathplot.cpp$(ObjectSuffix) $(IntermediateDirectory)/BusForm.cpp$(ObjectSuffix) $(IntermediateDirectory)/GeneratorStabForm.cpp$(ObjectSuffix) $(IntermediateDirectory)/LineForm.cpp$(ObjectSuffix) $(IntermediateDirectory)/SwitchingForm.cpp$(ObjectSuffix) \
+ $(IntermediateDirectory)/TransformerForm.cpp$(ObjectSuffix) $(IntermediateDirectory)/LoadForm.cpp$(ObjectSuffix) $(IntermediateDirectory)/ReactiveShuntElementForm.cpp$(ObjectSuffix) $(IntermediateDirectory)/IndMotorForm.cpp$(ObjectSuffix) $(IntermediateDirectory)/SyncMachineForm.cpp$(ObjectSuffix) $(IntermediateDirectory)/TextForm.cpp$(ObjectSuffix) $(IntermediateDirectory)/TransferFunctionForm.cpp$(ObjectSuffix) $(IntermediateDirectory)/SumForm.cpp$(ObjectSuffix) $(IntermediateDirectory)/LimiterForm.cpp$(ObjectSuffix) $(IntermediateDirectory)/RateLimiterForm.cpp$(ObjectSuffix) \
+ $(IntermediateDirectory)/ExponentialForm.cpp$(ObjectSuffix) $(IntermediateDirectory)/ConstantForm.cpp$(ObjectSuffix) $(IntermediateDirectory)/GainForm.cpp$(ObjectSuffix) $(IntermediateDirectory)/IOControlForm.cpp$(ObjectSuffix)
@@ -528,6 +528,14 @@ $(IntermediateDirectory)/ControlElementContainer.cpp$(DependSuffix): ControlElem
$(IntermediateDirectory)/ControlElementContainer.cpp$(PreprocessSuffix): ControlElementContainer.cpp
$(CXX) $(CXXFLAGS) $(IncludePCH) $(IncludePath) $(PreprocessOnlySwitch) $(OutputSwitch) $(IntermediateDirectory)/ControlElementContainer.cpp$(PreprocessSuffix) ControlElementContainer.cpp
+$(IntermediateDirectory)/ControlElementSolver.cpp$(ObjectSuffix): ControlElementSolver.cpp $(IntermediateDirectory)/ControlElementSolver.cpp$(DependSuffix)
+ $(CXX) $(IncludePCH) $(SourceSwitch) "C:/Users/NDSE-69/Documents/GitHub/PSP/Project/ControlElementSolver.cpp" $(CXXFLAGS) $(ObjectSwitch)$(IntermediateDirectory)/ControlElementSolver.cpp$(ObjectSuffix) $(IncludePath)
+$(IntermediateDirectory)/ControlElementSolver.cpp$(DependSuffix): ControlElementSolver.cpp
+ @$(CXX) $(CXXFLAGS) $(IncludePCH) $(IncludePath) -MG -MP -MT$(IntermediateDirectory)/ControlElementSolver.cpp$(ObjectSuffix) -MF$(IntermediateDirectory)/ControlElementSolver.cpp$(DependSuffix) -MM ControlElementSolver.cpp
+
+$(IntermediateDirectory)/ControlElementSolver.cpp$(PreprocessSuffix): ControlElementSolver.cpp
+ $(CXX) $(CXXFLAGS) $(IncludePCH) $(IncludePath) $(PreprocessOnlySwitch) $(OutputSwitch) $(IntermediateDirectory)/ControlElementSolver.cpp$(PreprocessSuffix) ControlElementSolver.cpp
+
$(IntermediateDirectory)/wxMathPlot_mathplot.cpp$(ObjectSuffix): wxMathPlot/mathplot.cpp $(IntermediateDirectory)/wxMathPlot_mathplot.cpp$(DependSuffix)
$(CXX) $(IncludePCH) $(SourceSwitch) "C:/Users/NDSE-69/Documents/GitHub/PSP/Project/wxMathPlot/mathplot.cpp" $(CXXFLAGS) $(ObjectSwitch)$(IntermediateDirectory)/wxMathPlot_mathplot.cpp$(ObjectSuffix) $(IncludePath)
$(IntermediateDirectory)/wxMathPlot_mathplot.cpp$(DependSuffix): wxMathPlot/mathplot.cpp
diff --git a/Project/Project.project b/Project/Project.project
index 6671989..752ee00 100644
--- a/Project/Project.project
+++ b/Project/Project.project
@@ -49,6 +49,7 @@
<File Name="Gain.cpp"/>
<File Name="IOControl.cpp"/>
<File Name="ControlElementContainer.cpp"/>
+ <File Name="ControlElementSolver.cpp"/>
</VirtualDirectory>
<File Name="ElementPlotData.cpp"/>
</VirtualDirectory>
@@ -140,6 +141,7 @@
<File Name="Gain.h"/>
<File Name="IOControl.h"/>
<File Name="ControlElementContainer.h"/>
+ <File Name="ControlElementSolver.h"/>
</VirtualDirectory>
<File Name="ElementPlotData.h"/>
</VirtualDirectory>
diff --git a/Project/Project.txt b/Project/Project.txt
index fbf464d..65a2851 100644
--- a/Project/Project.txt
+++ b/Project/Project.txt
@@ -1 +1 @@
-./Release/main.cpp.o ./Release/win_resources.rc.o ./Release/ElementDataObject.cpp.o ./Release/Element.cpp.o ./Release/ElementPlotData.cpp.o ./Release/ArtMetro.cpp.o ./Release/wxGLString.cpp.o ./Release/MainFrame.cpp.o ./Release/Workspace.cpp.o ./Release/FileHanding.cpp.o ./Release/ControlEditor.cpp.o ./Release/Camera.cpp.o ./Release/ChartView.cpp.o ./Release/MainFrameBitmaps.cpp.o ./Release/WorkspaceBitmaps.cpp.o ./Release/BusFormBitmaps.cpp.o ./Release/ElementFormBitmaps.cpp.o ./Release/ControlEditorBitmaps.cpp.o ./Release/ChartViewBitmaps.cpp.o ./Release/MainFrameBase.cpp.o ./Release/WorkspaceBase.cpp.o ./Release/ElementForm.cpp.o ./Release/ControlEditorBase.cpp.o ./Release/ChartViewBase.cpp.o ./Release/Bus.cpp.o ./Release/Line.cpp.o ./Release/Transformer.cpp.o ./Release/Machines.cpp.o ./Release/SyncGenerator.cpp.o ./Release/IndMotor.cpp.o ./Release/Branch.cpp.o ./Release/SyncMotor.cpp.o ./Release/Shunt.cpp.o ./Release/Load.cpp.o ./Release/Inductor.cpp.o ./Release/Capacitor.cpp.o ./Release/PowerElement.cpp.o ./Release/ElectricCalculation.cpp.o ./Release/PowerFlow.cpp.o ./Release/Fault.cpp.o ./Release/Text.cpp.o ./Release/GraphicalElement.cpp.o ./Release/ControlElement.cpp.o ./Release/TransferFunction.cpp.o ./Release/ConnectionLine.cpp.o ./Release/Sum.cpp.o ./Release/Multiplier.cpp.o ./Release/Limiter.cpp.o ./Release/RateLimiter.cpp.o ./Release/Exponential.cpp.o ./Release/Constant.cpp.o ./Release/Gain.cpp.o ./Release/IOControl.cpp.o ./Release/ControlElementContainer.cpp.o ./Release/wxMathPlot_mathplot.cpp.o ./Release/BusForm.cpp.o ./Release/GeneratorStabForm.cpp.o ./Release/LineForm.cpp.o ./Release/SwitchingForm.cpp.o ./Release/TransformerForm.cpp.o ./Release/LoadForm.cpp.o ./Release/ReactiveShuntElementForm.cpp.o ./Release/IndMotorForm.cpp.o ./Release/SyncMachineForm.cpp.o ./Release/TextForm.cpp.o ./Release/TransferFunctionForm.cpp.o ./Release/SumForm.cpp.o ./Release/LimiterForm.cpp.o ./Release/RateLimiterForm.cpp.o ./Release/ExponentialForm.cpp.o ./Release/ConstantForm.cpp.o ./Release/GainForm.cpp.o ./Release/IOControlForm.cpp.o
+./Release/main.cpp.o ./Release/win_resources.rc.o ./Release/ElementDataObject.cpp.o ./Release/Element.cpp.o ./Release/ElementPlotData.cpp.o ./Release/ArtMetro.cpp.o ./Release/wxGLString.cpp.o ./Release/MainFrame.cpp.o ./Release/Workspace.cpp.o ./Release/FileHanding.cpp.o ./Release/ControlEditor.cpp.o ./Release/Camera.cpp.o ./Release/ChartView.cpp.o ./Release/MainFrameBitmaps.cpp.o ./Release/WorkspaceBitmaps.cpp.o ./Release/BusFormBitmaps.cpp.o ./Release/ElementFormBitmaps.cpp.o ./Release/ControlEditorBitmaps.cpp.o ./Release/ChartViewBitmaps.cpp.o ./Release/MainFrameBase.cpp.o ./Release/WorkspaceBase.cpp.o ./Release/ElementForm.cpp.o ./Release/ControlEditorBase.cpp.o ./Release/ChartViewBase.cpp.o ./Release/Bus.cpp.o ./Release/Line.cpp.o ./Release/Transformer.cpp.o ./Release/Machines.cpp.o ./Release/SyncGenerator.cpp.o ./Release/IndMotor.cpp.o ./Release/Branch.cpp.o ./Release/SyncMotor.cpp.o ./Release/Shunt.cpp.o ./Release/Load.cpp.o ./Release/Inductor.cpp.o ./Release/Capacitor.cpp.o ./Release/PowerElement.cpp.o ./Release/ElectricCalculation.cpp.o ./Release/PowerFlow.cpp.o ./Release/Fault.cpp.o ./Release/Text.cpp.o ./Release/GraphicalElement.cpp.o ./Release/ControlElement.cpp.o ./Release/TransferFunction.cpp.o ./Release/ConnectionLine.cpp.o ./Release/Sum.cpp.o ./Release/Multiplier.cpp.o ./Release/Limiter.cpp.o ./Release/RateLimiter.cpp.o ./Release/Exponential.cpp.o ./Release/Constant.cpp.o ./Release/Gain.cpp.o ./Release/IOControl.cpp.o ./Release/ControlElementContainer.cpp.o ./Release/ControlElementSolver.cpp.o ./Release/wxMathPlot_mathplot.cpp.o ./Release/BusForm.cpp.o ./Release/GeneratorStabForm.cpp.o ./Release/LineForm.cpp.o ./Release/SwitchingForm.cpp.o ./Release/TransformerForm.cpp.o ./Release/LoadForm.cpp.o ./Release/ReactiveShuntElementForm.cpp.o ./Release/IndMotorForm.cpp.o ./Release/SyncMachineForm.cpp.o ./Release/TextForm.cpp.o ./Release/TransferFunctionForm.cpp.o ./Release/SumForm.cpp.o ./Release/LimiterForm.cpp.o ./Release/RateLimiterForm.cpp.o ./Release/ExponentialForm.cpp.o ./Release/ConstantForm.cpp.o ./Release/GainForm.cpp.o ./Release/IOControlForm.cpp.o
diff --git a/Project/RateLimiter.cpp b/Project/RateLimiter.cpp
index 5da0578..42bede1 100644
--- a/Project/RateLimiter.cpp
+++ b/Project/RateLimiter.cpp
@@ -13,10 +13,7 @@ RateLimiter::RateLimiter(int id) : ControlElement(id)
m_nodeList.push_back(nodeOut);
}
-RateLimiter::~RateLimiter()
-{
-}
-
+RateLimiter::~RateLimiter() {}
void RateLimiter::Draw(wxPoint2DDouble translation, double scale) const
{
glLineWidth(1.0);
@@ -37,7 +34,7 @@ void RateLimiter::Draw(wxPoint2DDouble translation, double scale) const
axis.push_back(m_position + wxPoint2DDouble(0, -13));
axis.push_back(m_position + wxPoint2DDouble(0, 13));
DrawLine(axis, GL_LINES);
-
+
glLineWidth(2.0);
std::vector<wxPoint2DDouble> limSymbol;
limSymbol.push_back(m_position + wxPoint2DDouble(10, -10));
@@ -95,3 +92,23 @@ void RateLimiter::UpdatePoints()
m_nodeList[1]->SetPosition(m_position + wxPoint2DDouble(0, -18));
}
}
+
+bool RateLimiter::Solve(double input, double timeStep)
+{
+ double rate = (input - m_output) / timeStep;
+
+ bool reachLimit = false;
+ if(rate > m_upLimit) {
+ rate = m_upLimit;
+ reachLimit = true;
+ } else if(rate < m_lowLimit) {
+ rate = m_lowLimit;
+ reachLimit = true;
+ }
+
+ if(reachLimit)
+ m_output += rate * timeStep;
+ else
+ m_output = input;
+ return true;
+}
diff --git a/Project/RateLimiter.h b/Project/RateLimiter.h
index d17642b..b1e669c 100644
--- a/Project/RateLimiter.h
+++ b/Project/RateLimiter.h
@@ -24,6 +24,8 @@ class RateLimiter : public ControlElement
void SetUpLimit(double upLimit) { m_upLimit = upLimit; }
void SetLowLimit(double lowLimit) { m_lowLimit = lowLimit; }
+ virtual bool Solve(double input, double timeStep);
+
protected:
double m_upLimit = 5.0;
double m_lowLimit = -5.0;
diff --git a/Project/Sum.cpp b/Project/Sum.cpp
index 606b367..b7a4f8a 100644
--- a/Project/Sum.cpp
+++ b/Project/Sum.cpp
@@ -1,8 +1,8 @@
#include "Sum.h"
#include "SumForm.h"
+#include "ConnectionLine.h"
-Sum::Sum(int id)
- : ControlElement(id)
+Sum::Sum(int id) : ControlElement(id)
{
m_width = m_height = 36.0;
Node* nodeIn1 = new Node(m_position + wxPoint2DDouble(-m_width / 2, 9 - m_height / 2), Node::NODE_IN, m_borderSize);
@@ -23,7 +23,6 @@ Sum::Sum(int id)
}
Sum::~Sum() {}
-
void Sum::Draw(wxPoint2DDouble translation, double scale) const
{
glLineWidth(1.0);
@@ -133,12 +132,13 @@ void Sum::UpdatePoints()
else if(m_angle == 270.0)
m_nodeList[m_nodeList.size() - 1]->SetPosition(m_position + wxPoint2DDouble(0, -m_height / 2));
- SetPosition(m_position); // Update rect.
+ SetPosition(m_position); // Update rect.
}
void Sum::AddInNode()
{
Node* newNode = new Node(wxPoint2DDouble(0, 0), Node::NODE_IN, m_borderSize);
+ newNode->SetAngle(m_angle);
m_nodeList.insert(m_nodeList.end() - 1, newNode);
}
@@ -181,3 +181,39 @@ void Sum::Rotate(bool clockwise)
node->Rotate(clockwise);
}
}
+
+bool Sum::Solve(double input, double timeStep)
+{
+ std::vector<double> inputVector;
+ for(auto itN = m_nodeList.begin(), itNEnd = m_nodeList.end(); itN != itNEnd; ++itN) {
+ Node* node = *itN;
+ if(node->GetNodeType() != Node::NODE_OUT) {
+ if(!node->IsConnected()) {
+ inputVector.push_back(0.0);
+ } else {
+ for(auto itC = m_childList.begin(), itCEnd = m_childList.end(); itC != itCEnd; ++itC) {
+ ConnectionLine* cLine = static_cast<ConnectionLine*>(*itC);
+ auto nodeList = cLine->GetNodeList();
+ for(auto itCN = nodeList.begin(), itCNEnd = nodeList.end(); itCN != itCNEnd; ++itCN) {
+ Node* childNode = *itCN;
+ if(childNode == node) {
+ inputVector.push_back(cLine->GetValue());
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if(m_signalList.size() != inputVector.size()) return false;
+
+ m_output = 0.0;
+ for(unsigned int i = 0; i < m_signalList.size(); ++i) {
+ if(m_signalList[i] == SIGNAL_POSITIVE)
+ m_output += inputVector[i];
+ else if(m_signalList[i] == SIGNAL_NEGATIVE)
+ m_output -= inputVector[i];
+ }
+ return true;
+}
diff --git a/Project/Sum.h b/Project/Sum.h
index a99067e..f3ab4c6 100644
--- a/Project/Sum.h
+++ b/Project/Sum.h
@@ -4,6 +4,7 @@
#include "ControlElement.h"
class SumForm;
+class ConnectionLine;
class Sum : public ControlElement
{
@@ -21,6 +22,8 @@ public:
virtual std::vector<Signal> GetSignalList() const { return m_signalList; }
virtual void SetSignalList(std::vector<Signal> signalList) { m_signalList = signalList; }
+ virtual bool Solve(double input, double timeStep);
+
virtual void UpdatePoints();
void AddInNode();
void RemoveInNode();
diff --git a/Project/TransferFunction.cpp b/Project/TransferFunction.cpp
index 9c8ffea..ebb59fb 100644
--- a/Project/TransferFunction.cpp
+++ b/Project/TransferFunction.cpp
@@ -32,7 +32,6 @@ TransferFunction::TransferFunction(int id) : ControlElement(id)
}
TransferFunction::~TransferFunction() {}
-
void TransferFunction::Draw(wxPoint2DDouble translation, double scale) const
{
glLineWidth(1.0);
@@ -88,7 +87,7 @@ void TransferFunction::SetText(wxString numerator, wxString denominator)
m_width = nWidth > dWidth ? nWidth : dWidth;
m_height = m_glStringNum->getheight() + m_glStringDen->getheight() + 2 * m_borderSize;
- SetPosition(m_position); // Update rect properly.
+ SetPosition(m_position); // Update rect properly.
}
wxString TransferFunction::GetSuperscriptNumber(int number)
@@ -248,3 +247,111 @@ void TransferFunction::Rotate(bool clockwise)
node->Rotate(clockwise);
}
}
+
+void TransferFunction::CalculateSpaceState(int maxIteration, double error)
+{
+ m_maxIteration = maxIteration;
+ m_error = error;
+
+ int order = static_cast<int>(m_denominator.size());
+ std::vector<double> denominator = m_denominator;
+ std::vector<double> numerator;
+
+ int k = order;
+ for(int i = 0; i < order; i++) {
+ int numIndex = i - (order - static_cast<int>(m_numerator.size()));
+ if(numIndex < 0)
+ numerator.push_back(0.0);
+ else
+ numerator.push_back(m_numerator[numIndex]);
+ k--;
+ }
+
+ SpaceState ss;
+ for(int i = 0; i < (order - 1); i++) {
+ std::vector<double> lineA;
+ for(int j = 0; j < (order - 1); j++) {
+ if(j == i + 1)
+ lineA.push_back(1.0);
+ else
+ lineA.push_back(0.0);
+ }
+ ss.A.push_back(lineA);
+ ss.B.push_back(0.0);
+ ss.C.push_back(0.0);
+ }
+ for(int i = 0; i < order - 1; i++) {
+ ss.A[order - 2][i] = -(denominator[order - 1 - i] / denominator[0]);
+ ss.C[i] = (numerator[order - 1 - i] - denominator[order - 1 - i] * numerator[0]) / denominator[0];
+ }
+ ss.B[order - 2] = 1.0;
+ ss.D = numerator[0];
+
+ m_ss = ss;
+
+ // Reset state
+ m_x.clear();
+ m_dx.clear();
+
+ for(unsigned int i = 0; i < m_denominator.size(); ++i) {
+ m_x.push_back(0.0);
+ m_dx.push_back(0.0);
+ }
+}
+
+bool TransferFunction::Solve(double input, double timeStep)
+{
+ int order = static_cast<int>(m_ss.A.size());
+
+ std::vector<double> x;
+ std::vector<double> oldx;
+ std::vector<double> dx;
+ std::vector<double> olddx;
+ for(int i = 0; i < order; i++) {
+ x.push_back(m_x[i]);
+ oldx.push_back(m_x[i]);
+
+ dx.push_back(m_dx[i]);
+ olddx.push_back(m_dx[i]);
+ }
+
+ bool exit = false;
+ int iter = 0;
+ while(!exit) {
+ double xError = 0.0;
+ double dxError = 0.0;
+ for(int i = 0; i < order; i++) {
+ // Trapezoidal method
+ x[i] = m_x[i] + 0.5 * timeStep * (m_dx[i] + dx[i]);
+
+ if(std::abs(x[i] - oldx[i]) > xError) xError = std::abs(x[i] - oldx[i]);
+
+ oldx[i] = x[i];
+ }
+ for(int i = 0; i < order; i++) {
+ // x' = Ax + Bu
+ dx[i] = 0.0;
+ for(int j = 0; j < order; j++) dx[i] += m_ss.A[i][j] * x[j];
+ dx[i] += m_ss.B[i] * input;
+
+ if(std::abs(dx[i] - olddx[i]) > dxError) dxError = std::abs(dx[i] - olddx[i]);
+
+ olddx[i] = dx[i];
+ }
+ if(std::max(xError, dxError) < m_error) exit = true;
+
+ iter++;
+ if(iter >= m_maxIteration) return false;
+ }
+
+ m_output = 0.0;
+ for(int i = 0; i < order; i++) {
+ m_output += m_ss.C[i] * x[i];
+ m_x[i] = x[i];
+ m_dx[i] = dx[i];
+ }
+
+ m_output += m_ss.D * input;
+
+ return true;
+}
diff --git a/Project/TransferFunction.h b/Project/TransferFunction.h
index 45681ce..19bd04e 100644
--- a/Project/TransferFunction.h
+++ b/Project/TransferFunction.h
@@ -10,7 +10,14 @@ class TransferFunctionForm;
class TransferFunction : public ControlElement
{
-public:
+ public:
+ struct SpaceState {
+ std::vector<std::vector<double> > A;
+ std::vector<double> B;
+ std::vector<double> C;
+ double D;
+ };
+
TransferFunction(int id);
~TransferFunction();
@@ -19,25 +26,35 @@ public:
virtual bool Intersects(wxRect2DDouble rect) const { return m_rect.Intersects(rect); }
virtual bool ShowForm(wxWindow* parent, Element* element);
virtual void Rotate(bool clockwise = true);
-
+
virtual std::vector<double> GetNumerator() const { return m_numerator; }
virtual std::vector<double> GetDenominator() const { return m_denominator; }
virtual void SetNumerator(std::vector<double> numerator) { m_numerator = numerator; }
virtual void SetDenominator(std::vector<double> denominator) { m_denominator = denominator; }
virtual void UpdateTFText();
-
-protected:
+ virtual SpaceState GetSpaceState() { return m_ss; }
+ virtual void CalculateSpaceState(int maxIteration = 100, double error = 1e-3);
+ virtual bool Solve(double input, double timeStep);
+
+ protected:
virtual void SetText(wxString numerator, wxString denominator);
virtual wxString GetSuperscriptNumber(int number);
virtual void GetTFString(wxString& numerator, wxString& denominator);
-
+
wchar_t m_supNumber[10];
-
+
wxGLString* m_glStringNum = NULL;
wxGLString* m_glStringDen = NULL;
int m_fontSize = 10;
+
std::vector<double> m_numerator;
std::vector<double> m_denominator;
+ SpaceState m_ss;
+
+ std::vector<double> m_x;
+ std::vector<double> m_dx;
+ double m_error = 1e-3;
+ int m_maxIteration = 100;
};
-#endif // TRANSFERFUNCTION_H
+#endif // TRANSFERFUNCTION_H