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
FGFilter.cpp
1/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2
3 Module: FGFilter.cpp
4 Author: Jon S. Berndt
5 Date started: 11/2000
6
7 ------------- Copyright (C) 2000 -------------
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
26FUNCTIONAL DESCRIPTION
27--------------------------------------------------------------------------------
28
29HISTORY
30--------------------------------------------------------------------------------
31
32%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
33COMMENTS, REFERENCES, and NOTES
34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35
36%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
37INCLUDES
38%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
39
40#include "FGFilter.h"
41#include "models/FGFCS.h"
42#include "math/FGParameterValue.h"
43#include "input_output/FGLog.h"
44
45using namespace std;
46
47namespace JSBSim {
48
49/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
50CLASS IMPLEMENTATION
51%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
52
53FGFilter::FGFilter(FGFCS* fcs, Element* element)
54 : FGFCSComponent(fcs, element), DynamicFilter(false), Initialize(true)
55{
56 C[1] = C[2] = C[3] = C[4] = C[5] = C[6] = nullptr;
57
58 CheckInputNodes(1, 1, element);
59
60 auto PropertyManager = fcs->GetPropertyManager();
61 for (int i=1; i<7; i++)
62 ReadFilterCoefficients(element, i, PropertyManager);
63
64 if (Type == "LAG_FILTER") FilterType = eLag ;
65 else if (Type == "LEAD_LAG_FILTER") FilterType = eLeadLag ;
66 else if (Type == "SECOND_ORDER_FILTER") FilterType = eOrder2 ;
67 else if (Type == "WASHOUT_FILTER") FilterType = eWashout ;
68 else FilterType = eUnknown ;
69
70 CalculateDynamicFilters();
71
72 bind(element, PropertyManager.get());
73
74 Debug(0);
75}
76
77//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
78
79FGFilter::~FGFilter()
80{
81 Debug(1);
82}
83
84//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
85
86void FGFilter::ResetPastStates(void)
87{
88 FGFCSComponent::ResetPastStates();
89
90 Input = 0.0; Initialize = true;
91}
92
93//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
94
95void FGFilter::ReadFilterCoefficients(Element* element, int index,
96 std::shared_ptr<FGPropertyManager> PropertyManager)
97{
98 // index is known to be 1-7.
99 // A stringstream would be overkill, but also trying to avoid sprintf
100 string coefficient = "c0";
101 coefficient[1] += index;
102
103 if ( element->FindElement(coefficient) ) {
104 C[index] = new FGParameterValue(element->FindElement(coefficient),
105 PropertyManager);
106 DynamicFilter |= !C[index]->IsConstant();
107 }
108}
109
110//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
111
112void FGFilter::CalculateDynamicFilters(void)
113{
114 double denom;
115
116 switch (FilterType) {
117 case eLag:
118 denom = 2.0 + dt*C[1];
119 ca = dt*C[1] / denom;
120 cb = (2.0 - dt*C[1]) / denom;
121
122 break;
123 case eLeadLag:
124 denom = 2.0*C[3] + dt*C[4];
125 ca = (2.0*C[1] + dt*C[2]) / denom;
126 cb = (dt*C[2] - 2.0*C[1]) / denom;
127 cc = (2.0*C[3] - dt*C[4]) / denom;
128 break;
129 case eOrder2:
130 denom = 4.0*C[4] + 2.0*C[5]*dt + C[6]*dt*dt;
131 ca = (4.0*C[1] + 2.0*C[2]*dt + C[3]*dt*dt) / denom;
132 cb = (2.0*C[3]*dt*dt - 8.0*C[1]) / denom;
133 cc = (4.0*C[1] - 2.0*C[2]*dt + C[3]*dt*dt) / denom;
134 cd = (2.0*C[6]*dt*dt - 8.0*C[4]) / denom;
135 ce = (4.0*C[4] - 2.0*C[5]*dt + C[6]*dt*dt) / denom;
136 break;
137 case eWashout:
138 denom = 2.0 + dt*C[1];
139 ca = 2.0 / denom;
140 cb = (2.0 - dt*C[1]) / denom;
141 break;
142 case eUnknown:
143 {
144 FGLogging log(LogLevel::ERROR);
145 log << "Unknown filter type\n";
146 }
147 break;
148 }
149
150}
151
152//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
153
154bool FGFilter::Run(void)
155{
156 if (Initialize) {
157
158 PreviousOutput2 = PreviousInput2 = PreviousOutput1 = PreviousInput1 = Output = Input;
159 Initialize = false;
160
161 } else {
162
163 Input = InputNodes[0]->getDoubleValue();
164
165 if (DynamicFilter) CalculateDynamicFilters();
166
167 switch (FilterType) {
168 case eLag:
169 Output = (Input + PreviousInput1) * ca + PreviousOutput1 * cb;
170 break;
171 case eLeadLag:
172 Output = Input * ca + PreviousInput1 * cb + PreviousOutput1 * cc;
173 break;
174 case eOrder2:
175 Output = Input * ca + PreviousInput1 * cb + PreviousInput2 * cc
176 - PreviousOutput1 * cd - PreviousOutput2 * ce;
177 break;
178 case eWashout:
179 Output = Input * ca - PreviousInput1 * ca + PreviousOutput1 * cb;
180 break;
181 case eUnknown:
182 break;
183 }
184
185 }
186
187 PreviousOutput2 = PreviousOutput1;
188 PreviousOutput1 = Output;
189 PreviousInput2 = PreviousInput1;
190 PreviousInput1 = Input;
191
192 Clip();
193 SetOutput();
194
195 return true;
196}
197
198//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
199// The bitmasked value choices are as follows:
200// unset: In this case (the default) JSBSim would only print
201// out the normally expected messages, essentially echoing
202// the config files as they are read. If the environment
203// variable is not set, debug_lvl is set to 1 internally
204// 0: This requests JSBSim not to output any messages
205// whatsoever.
206// 1: This value explicitly requests the normal JSBSim
207// startup messages
208// 2: This value asks for a message to be printed out when
209// a class is instantiated
210// 4: When this value is set, a message is displayed when a
211// FGModel object executes its Run() method
212// 8: When this value is set, various runtime state variables
213// are printed out periodically
214// 16: When set various parameters are sanity checked and
215// a message is printed out when they go out of bounds
216
217void FGFilter::Debug(int from)
218{
219 if (debug_lvl <= 0) return;
220
221 if (debug_lvl & 1) { // Standard console startup message output
222 if (from == 0) { // Constructor
223 FGLogging log(LogLevel::DEBUG);
224 log << " INPUT: " << InputNodes[0]->GetName() << fixed << "\n";
225
226 for (int i=1; i < 7; i++) {
227 if (!C[i]) break;
228
229 log << " C[" << i << "]";
230 if (!C[i]->IsConstant()) log << " is the value of property";
231 log << ": "<< C[i]->GetName() << "\n";
232 }
233
234 for (auto node: OutputNodes)
235 log << " OUTPUT: " << node->getNameString() << "\n";
236 }
237 }
238 if (debug_lvl & 2 ) { // Instantiation/Destruction notification
239 FGLogging log(LogLevel::DEBUG);
240 if (from == 0) log << "Instantiated: FGFilter\n";
241 if (from == 1) log << "Destroyed: FGFilter\n";
242 }
243 if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
244 }
245 if (debug_lvl & 8 ) { // Runtime state variables
246 }
247 if (debug_lvl & 16) { // Sanity checking
248 }
249 if (debug_lvl & 64) {
250 if (from == 0) { // Constructor
251 }
252 }
253}
254}
Main namespace for the JSBSim Flight Dynamics Model.
Definition FGFDMExec.cpp:71