JSBSim Flight Dynamics Model 1.2.4 (07 Feb 2026)
An Open Source Flight Dynamics and Control Software Library in C++
Loading...
Searching...
No Matches
FGPID.cpp
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"
39#include "models/FGFCS.h"
40#include "math/FGParameterValue.h"
41
42using namespace std;
43
44namespace JSBSim {
45
46/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
47CLASS IMPLEMENTATION
48%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
49
50FGPID::FGPID(FGFCS* fcs, Element* element) : FGFCSComponent(fcs, element)
51{
52 Element *el;
53
54 I_out_total = 0.0;
55 Input_prev = Input_prev2 = 0.0;
56 Trigger = nullptr;
57 ProcessVariableDot = nullptr;
58 IsStandard = false;
59 IntType = eNone; // No integrator initially defined.
60
61 CheckInputNodes(1, 1, element);
62
63 auto PropertyManager = fcs->GetPropertyManager();
64 string pid_type = element->GetAttributeValue("type");
65
66 if (pid_type == "standard") IsStandard = true;
67
68 el = element->FindElement("kp");
69 if (el)
70 Kp = new FGParameterValue(el, PropertyManager);
71 else
72 Kp = new FGRealValue(0.0);
73
74 el = element->FindElement("ki");
75 if (el) {
76 string integ_type = el->GetAttributeValue("type");
77 if (integ_type == "rect") { // Use rectangular integration
78 IntType = eRectEuler;
79 } else if (integ_type == "trap") { // Use trapezoidal integration
80 IntType = eTrapezoidal;
81 } else if (integ_type == "ab2") { // Use Adams Bashforth 2nd order integration
82 IntType = eAdamsBashforth2;
83 } else if (integ_type == "ab3") { // Use Adams Bashforth 3rd order integration
84 IntType = eAdamsBashforth3;
85 } else { // Use default Adams Bashforth 2nd order integration
86 IntType = eAdamsBashforth2;
87 }
88
89 Ki = new FGParameterValue(el, PropertyManager);
90 }
91 else
92 Ki = new FGRealValue(0.0);
93
94
95 el = element->FindElement("kd");
96 if (el)
97 Kd = new FGParameterValue(el, PropertyManager);
98 else
99 Kd = new FGRealValue(0.0);
100
101 el = element->FindElement("pvdot");
102 if (el)
103 ProcessVariableDot = new FGPropertyValue(el->GetDataLine(), PropertyManager, el);
104
105 el = element->FindElement("trigger");
106 if (el)
107 Trigger = new FGPropertyValue(el->GetDataLine(), PropertyManager, el);
108
109 bind(el, PropertyManager.get());
110}
111
112//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
113
114void FGPID::bind(Element *el, FGPropertyManager* PropertyManager)
115{
116 FGFCSComponent::bind(el, PropertyManager);
117
118 string tmp;
119 if (Name.find("/") == string::npos) {
120 tmp = "fcs/" + PropertyManager->mkPropertyName(Name, true);
121 } else {
122 tmp = Name;
123 }
124 PropertyManager->Tie<FGPID, double>(tmp+"/initial-integrator-value", this,
125 nullptr, &FGPID::SetInitialOutput);
126
127 Debug(0);
128}
129
130//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
131
132FGPID::~FGPID()
133{
134 delete Kp;
135 delete Ki;
136 delete Kd;
137 delete Trigger;
138 delete ProcessVariableDot;
139 Debug(1);
140}
141
142//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
143
144void FGPID::ResetPastStates(void)
145{
146 FGFCSComponent::ResetPastStates();
147
148 Input_prev = Input_prev2 = Output = I_out_total = 0.0;
149}
150
151//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
152
153bool FGPID::Run(void )
154{
155 double I_out_delta = 0.0;
156 double Dval = 0;
157
158 Input = InputNodes[0]->getDoubleValue();
159
160 if (ProcessVariableDot) {
161 Dval = ProcessVariableDot->getDoubleValue();
162 } else {
163 Dval = (Input - Input_prev)/dt;
164 }
165
166 // Do not continue to integrate the input to the integrator if a wind-up
167 // condition is sensed - that is, if the property pointed to by the trigger
168 // element is non-zero. Reset the integrator to 0.0 if the Trigger value
169 // is negative.
170
171 double test = 0.0;
172 if (Trigger) test = Trigger->getDoubleValue();
173
174 if (fabs(test) < 0.000001) {
175 switch(IntType) {
176 case eRectEuler:
177 I_out_delta = Input; // Normal rectangular integrator
178 break;
179 case eTrapezoidal:
180 I_out_delta = 0.5 * (Input + Input_prev); // Trapezoidal integrator
181 break;
182 case eAdamsBashforth2:
183 I_out_delta = 1.5*Input - 0.5*Input_prev; // 2nd order Adams Bashforth integrator
184 break;
185 case eAdamsBashforth3: // 3rd order Adams Bashforth integrator
186 I_out_delta = (23.0*Input - 16.0*Input_prev + 5.0*Input_prev2) / 12.0;
187 break;
188 case eNone:
189 // No integrator is defined or used.
190 I_out_delta = 0.0;
191 break;
192 }
193 }
194
195 if (test < 0.0) I_out_total = 0.0; // Reset integrator to 0.0
196
197 I_out_total += Ki->GetValue() * dt * I_out_delta;
198
199 if (IsStandard)
200 Output = Kp->GetValue() * (Input + I_out_total + Kd->GetValue()*Dval);
201 else
202 Output = Kp->GetValue()*Input + I_out_total + Kd->GetValue()*Dval;
203
204 Input_prev2 = test < 0.0 ? 0.0:Input_prev;
205 Input_prev = Input;
206
207 Clip();
208 SetOutput();
209
210 return true;
211}
212
213//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
214// The bitmasked value choices are as follows:
215// unset: In this case (the default) JSBSim would only print
216// out the normally expected messages, essentially echoing
217// the config files as they are read. If the environment
218// variable is not set, debug_lvl is set to 1 internally
219// 0: This requests JSBSim not to output any messages
220// whatsoever.
221// 1: This value explicity requests the normal JSBSim
222// startup messages
223// 2: This value asks for a message to be printed out when
224// a class is instantiated
225// 4: When this value is set, a message is displayed when a
226// FGModel object executes its Run() method
227// 8: When this value is set, various runtime state variables
228// are printed out periodically
229// 16: When set various parameters are sanity checked and
230// a message is printed out when they go out of bounds
231
232void FGPID::Debug(int from)
233{
234 if (debug_lvl <= 0) return;
235
236 if (debug_lvl & 1) { // Standard console startup message output
237 if (from == 0) { // Constructor
238 cout << " INPUT: " << InputNodes[0]->GetNameWithSign() << endl;
239
240 for (auto node: OutputNodes)
241 cout << " OUTPUT: " << node->getNameString() << endl;
242 }
243 }
244 if (debug_lvl & 2 ) { // Instantiation/Destruction notification
245 if (from == 0) cout << "Instantiated: FGPID" << endl;
246 if (from == 1) cout << "Destroyed: FGPID" << endl;
247 }
248 if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
249 }
250 if (debug_lvl & 8 ) { // Runtime state variables
251 }
252 if (debug_lvl & 16) { // Sanity checking
253 }
254 if (debug_lvl & 64) {
255 if (from == 0) { // Constructor
256 }
257 }
258}
259}