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