FlightGear next
FGPID.cpp
Go to the documentation of this file.
1/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2
3 Module: FGPID.cpp
4 Author: Jon S. Berndt
5 Date started: 6/17/2006
6
7 ------------- Copyright (C) 2006 Jon S. Berndt (jon@jsbsim.org) -------------
8
9 This program is free software; you can redistribute it and/or modify it under
10 the terms of the GNU Lesser General Public License as published by the Free
11 Software Foundation; either version 2 of the License, or (at your option) any
12 later version.
13
14 This program is distributed in the hope that it will be useful, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
17 details.
18
19 You should have received a copy of the GNU Lesser General Public License along
20 with this program; if not, write to the Free Software Foundation, Inc., 59
21 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22
23 Further information about the GNU Lesser General Public License can also be
24 found on the world wide web at http://www.gnu.org.
25
26HISTORY
27--------------------------------------------------------------------------------
28Initial code 6/17/2006 JSB
29
30%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
31COMMENTS, REFERENCES, and NOTES
32%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
33
34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35INCLUDES
36%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
37
38#include "FGPID.h"
40
41using namespace std;
42
43namespace JSBSim {
44
45/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
46CLASS IMPLEMENTATION
47%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
48
50{
51 Element *el;
52
53 I_out_total = 0.0;
54 Input_prev = Input_prev2 = 0.0;
55 Trigger = nullptr;
56 ProcessVariableDot = nullptr;
57 IsStandard = false;
58 IntType = eNone; // No integrator initially defined.
59
60 CheckInputNodes(1, 1, element);
61
62 string pid_type = element->GetAttributeValue("type");
63
64 if (pid_type == "standard") IsStandard = true;
65
66 el = element->FindElement("kp");
67 if (el)
69 else
70 Kp = new FGRealValue(0.0);
71
72 el = element->FindElement("ki");
73 if (el) {
74 string integ_type = el->GetAttributeValue("type");
75 if (integ_type == "rect") { // Use rectangular integration
76 IntType = eRectEuler;
77 } else if (integ_type == "trap") { // Use trapezoidal integration
78 IntType = eTrapezoidal;
79 } else if (integ_type == "ab2") { // Use Adams Bashforth 2nd order integration
80 IntType = eAdamsBashforth2;
81 } else if (integ_type == "ab3") { // Use Adams Bashforth 3rd order integration
82 IntType = eAdamsBashforth3;
83 } else { // Use default Adams Bashforth 2nd order integration
84 IntType = eAdamsBashforth2;
85 }
86
88 }
89 else
90 Ki = new FGRealValue(0.0);
91
92
93 el = element->FindElement("kd");
94 if (el)
96 else
97 Kd = new FGRealValue(0.0);
98
99 el = element->FindElement("pvdot");
100 if (el)
101 ProcessVariableDot = new FGPropertyValue(el->GetDataLine(), PropertyManager);
102
103 el = element->FindElement("trigger");
104 if (el)
105 Trigger = new FGPropertyValue(el->GetDataLine(), PropertyManager);
106
107 bind(el);
108}
109
110//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
111
112void FGPID::bind(Element *el)
113{
115
116 string tmp;
117 if (Name.find("/") == string::npos) {
118 tmp = "fcs/" + PropertyManager->mkPropertyName(Name, true);
119 } else {
120 tmp = Name;
121 }
122 typedef double (FGPID::*PMF)(void) const;
123 PropertyManager->Tie(tmp+"/initial-integrator-value", this, (PMF)nullptr,
125
126 Debug(0);
127}
128
129//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
130
132{
133 delete Kp;
134 delete Ki;
135 delete Kd;
136 delete Trigger;
137 delete ProcessVariableDot;
138 Debug(1);
139}
140
141//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
142
144{
146
147 Input_prev = Input_prev2 = Output = I_out_total = 0.0;
148}
149
150//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
151
152bool FGPID::Run(void )
153{
154 double I_out_delta = 0.0;
155 double Dval = 0;
156
157 Input = InputNodes[0]->getDoubleValue();
158
159 if (ProcessVariableDot) {
160 Dval = ProcessVariableDot->getDoubleValue();
161 } else {
162 Dval = (Input - Input_prev)/dt;
163 }
164
165 // Do not continue to integrate the input to the integrator if a wind-up
166 // condition is sensed - that is, if the property pointed to by the trigger
167 // element is non-zero. Reset the integrator to 0.0 if the Trigger value
168 // is negative.
169
170 double test = 0.0;
171 if (Trigger) test = Trigger->getDoubleValue();
172
173 if (fabs(test) < 0.000001) {
174 switch(IntType) {
175 case eRectEuler:
176 I_out_delta = Input; // Normal rectangular integrator
177 break;
178 case eTrapezoidal:
179 I_out_delta = 0.5 * (Input + Input_prev); // Trapezoidal integrator
180 break;
181 case eAdamsBashforth2:
182 I_out_delta = 1.5*Input - 0.5*Input_prev; // 2nd order Adams Bashforth integrator
183 break;
184 case eAdamsBashforth3: // 3rd order Adams Bashforth integrator
185 I_out_delta = (23.0*Input - 16.0*Input_prev + 5.0*Input_prev2) / 12.0;
186 break;
187 case eNone:
188 // No integrator is defined or used.
189 I_out_delta = 0.0;
190 break;
191 }
192 }
193
194 if (test < 0.0) I_out_total = 0.0; // Reset integrator to 0.0
195
196 I_out_total += Ki->GetValue() * dt * I_out_delta;
197
198 if (IsStandard)
199 Output = Kp->GetValue() * (Input + I_out_total + Kd->GetValue()*Dval);
200 else
201 Output = Kp->GetValue()*Input + I_out_total + Kd->GetValue()*Dval;
202
203 Input_prev2 = test < 0.0 ? 0.0:Input_prev;
204 Input_prev = Input;
205
206 Clip();
207 SetOutput();
208
209 return true;
210}
211
212//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
213// The bitmasked value choices are as follows:
214// unset: In this case (the default) JSBSim would only print
215// out the normally expected messages, essentially echoing
216// the config files as they are read. If the environment
217// variable is not set, debug_lvl is set to 1 internally
218// 0: This requests JSBSim not to output any messages
219// whatsoever.
220// 1: This value explicity requests the normal JSBSim
221// startup messages
222// 2: This value asks for a message to be printed out when
223// a class is instantiated
224// 4: When this value is set, a message is displayed when a
225// FGModel object executes its Run() method
226// 8: When this value is set, various runtime state variables
227// are printed out periodically
228// 16: When set various parameters are sanity checked and
229// a message is printed out when they go out of bounds
230
231void FGPID::Debug(int from)
232{
233 if (debug_lvl <= 0) return;
234
235 if (debug_lvl & 1) { // Standard console startup message output
236 if (from == 0) { // Constructor
237 cout << " INPUT: " << InputNodes[0]->GetNameWithSign() << endl;
238
239 for (auto node: OutputNodes)
240 cout << " OUTPUT: " << node->getNameString() << endl;
241 }
242 }
243 if (debug_lvl & 2 ) { // Instantiation/Destruction notification
244 if (from == 0) cout << "Instantiated: FGPID" << endl;
245 if (from == 1) cout << "Destroyed: FGPID" << endl;
246 }
247 if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
248 }
249 if (debug_lvl & 8 ) { // Runtime state variables
250 }
251 if (debug_lvl & 16) { // Sanity checking
252 }
253 if (debug_lvl & 64) {
254 if (from == 0) { // Constructor
255 }
256 }
257}
258}
std::string GetDataLine(unsigned int i=0)
Gets a line of data belonging to an element.
std::string GetAttributeValue(const std::string &key)
Retrieves an attribute.
Element * FindElement(const std::string &el="")
Searches for a specified element.
FGFCSComponent(FGFCS *fcs, Element *el)
Constructor.
std::vector< FGPropertyValue_ptr > InputNodes
void CheckInputNodes(size_t MinNodes, size_t MaxNodes, Element *el)
virtual void ResetPastStates(void)
FGPropertyManager * PropertyManager
virtual void bind(Element *el)
virtual void SetOutput(void)
std::vector< FGPropertyNode_ptr > OutputNodes
static short debug_lvl
Definition FGJSBBase.h:190
void SetInitialOutput(double val)
Definition FGPID.h:138
void ResetPastStates(void) override
Definition FGPID.cpp:143
@ eAdamsBashforth3
Definition FGPID.h:136
@ eAdamsBashforth2
Definition FGPID.h:135
bool Run(void) override
Definition FGPID.cpp:152
FGPID(FGFCS *fcs, Element *element)
Definition FGPID.cpp:49
Represents a either a real value or a property value.
std::string mkPropertyName(std::string name, bool lowercase)
Property-ify a name replaces spaces with '-' and, optionally, makes name all lower case.
Represents a property value which can use late binding.
Represents a real value.
Definition FGRealValue.h:58
short debug_lvl