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