]> git.mxchange.org Git - flightgear.git/blob - src/Autopilot/digitalfilter.cxx
MapWidget: make use of the new POI system and display cities on the map.
[flightgear.git] / src / Autopilot / digitalfilter.cxx
1 // digitalfilter.cxx - a selection of digital filters
2 //
3 // Written by Torsten Dreyer
4 // Based heavily on work created by Curtis Olson, started January 2004.
5 //
6 // Copyright (C) 2004  Curtis L. Olson  - http://www.flightgear.org/~curt
7 // Copyright (C) 2010  Torsten Dreyer - Torsten (at) t3r (dot) de
8 //
9 // This program is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU General Public License as
11 // published by the Free Software Foundation; either version 2 of the
12 // License, or (at your option) any later version.
13 //
14 // This program is distributed in the hope that it will be useful, but
15 // WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 // General Public License for more details.
18 //
19 // You should have received a copy of the GNU General Public License
20 // along with this program; if not, write to the Free Software
21 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
22 //
23
24 #include "digitalfilter.hxx"
25 #include "functor.hxx"
26 #include <deque>
27
28 using std::map;
29 using std::string;
30 using std::endl;
31 using std::cout;
32
33 namespace FGXMLAutopilot {
34
35 /**
36  *
37  *
38  */
39 class DigitalFilterImplementation : public SGReferenced {
40 protected:
41   virtual bool configure( const std::string & nodeName, SGPropertyNode_ptr configNode) = 0;
42 public:
43   virtual ~DigitalFilterImplementation() {}
44   DigitalFilterImplementation();
45   virtual void   initialize( double initvalue ) {}
46   virtual double compute( double dt, double input ) = 0;
47   bool configure( SGPropertyNode_ptr configNode );
48
49   void setDigitalFilter( DigitalFilter * digitalFilter ) { _digitalFilter = digitalFilter; }
50
51 protected:
52   DigitalFilter * _digitalFilter;
53 };
54
55 /* --------------------------------------------------------------------------------- */
56 /* --------------------------------------------------------------------------------- */
57 class GainFilterImplementation : public DigitalFilterImplementation {
58 protected:
59   InputValueList _gainInput;
60   bool configure( const std::string & nodeName, SGPropertyNode_ptr configNode );
61 public:
62   GainFilterImplementation() : _gainInput(1.0) {}
63   double compute(  double dt, double input );
64 };
65
66 class ReciprocalFilterImplementation : public GainFilterImplementation {
67 public:
68   double compute(  double dt, double input );
69 };
70
71 class DerivativeFilterImplementation : public GainFilterImplementation {
72   InputValueList _TfInput;
73   double _input_1;
74   bool configure( const std::string & nodeName, SGPropertyNode_ptr configNode );
75 public:
76   DerivativeFilterImplementation();
77   double compute(  double dt, double input );
78   virtual void initialize( double initvalue );
79 };
80
81 class ExponentialFilterImplementation : public GainFilterImplementation {
82 protected:
83   InputValueList _TfInput;
84   bool configure( const std::string & nodeName, SGPropertyNode_ptr configNode );
85   bool _isSecondOrder;
86   double output_1, output_2;
87 public:
88   ExponentialFilterImplementation();
89   double compute(  double dt, double input );
90   virtual void initialize( double initvalue );
91 };
92
93 class MovingAverageFilterImplementation : public DigitalFilterImplementation {
94 protected:
95   InputValueList _samplesInput;
96   double _output_1;
97   std::deque <double> _inputQueue;
98   bool configure( const std::string & nodeName, SGPropertyNode_ptr configNode );
99 public:
100   MovingAverageFilterImplementation();
101   double compute(  double dt, double input );
102   virtual void initialize( double initvalue );
103 };
104
105 class NoiseSpikeFilterImplementation : public DigitalFilterImplementation {
106 protected:
107   double _output_1;
108   InputValueList _rateOfChangeInput;
109   bool configure( const std::string & nodeName, SGPropertyNode_ptr configNode );
110 public:
111   NoiseSpikeFilterImplementation();
112   double compute(  double dt, double input );
113   virtual void initialize( double initvalue );
114 };
115
116 /* --------------------------------------------------------------------------------- */
117 /* --------------------------------------------------------------------------------- */
118
119 } // namespace FGXMLAutopilot
120
121 using namespace FGXMLAutopilot;
122
123 /* --------------------------------------------------------------------------------- */
124 /* --------------------------------------------------------------------------------- */
125 DigitalFilterImplementation::DigitalFilterImplementation() :
126   _digitalFilter(NULL)
127 {
128 }
129
130 bool DigitalFilterImplementation::configure( SGPropertyNode_ptr configNode )
131 {
132   for (int i = 0; i < configNode->nChildren(); ++i ) {
133     SGPropertyNode_ptr prop;
134
135     SGPropertyNode_ptr child = configNode->getChild(i);
136     string cname(child->getName());
137
138     if( configure( cname, child ) )
139       continue;
140
141   } // for configNode->nChildren()
142
143   return true;
144 }
145
146 /* --------------------------------------------------------------------------------- */
147 /* --------------------------------------------------------------------------------- */
148
149 double GainFilterImplementation::compute(  double dt, double input )
150 {
151   return _gainInput.get_value() * input;
152 }
153
154 bool GainFilterImplementation::configure( const std::string & nodeName, SGPropertyNode_ptr configNode )
155 {
156   if (nodeName == "gain" ) {
157     _gainInput.push_back( new InputValue( configNode, 1 ) );
158     return true;
159   }
160
161   return false;
162 }
163
164 /* --------------------------------------------------------------------------------- */
165 /* --------------------------------------------------------------------------------- */
166
167 double ReciprocalFilterImplementation::compute(  double dt, double input )
168 {
169   if( input >= -SGLimitsd::min() && input <= SGLimitsd::min() )
170     return SGLimitsd::max();
171
172   return _gainInput.get_value() / input;
173
174 }
175
176 /* --------------------------------------------------------------------------------- */
177 /* --------------------------------------------------------------------------------- */
178
179 DerivativeFilterImplementation::DerivativeFilterImplementation() :
180   _input_1(0.0)
181 {
182 }
183
184 void DerivativeFilterImplementation::initialize( double initvalue )
185 {
186   _input_1 = initvalue;
187 }
188
189
190 bool DerivativeFilterImplementation::configure( const std::string & nodeName, SGPropertyNode_ptr configNode )
191 {
192   if( GainFilterImplementation::configure( nodeName, configNode ) )
193     return true;
194
195   if (nodeName == "filter-time" ) {
196     _TfInput.push_back( new InputValue( configNode, 1 ) );
197     return true;
198   }
199
200   return false;
201 }
202
203 double DerivativeFilterImplementation::compute(  double dt, double input )
204 {
205   double output = (input - _input_1) * _TfInput.get_value() * _gainInput.get_value() / dt;
206   _input_1 = input;
207   return output;
208
209 }
210
211 /* --------------------------------------------------------------------------------- */
212 /* --------------------------------------------------------------------------------- */
213
214 MovingAverageFilterImplementation::MovingAverageFilterImplementation() :
215   _output_1(0.0)
216 {
217 }
218
219 void MovingAverageFilterImplementation::initialize( double initvalue )
220 {
221   _output_1 = initvalue;
222 }
223
224 double MovingAverageFilterImplementation::compute(  double dt, double input )
225 {
226   std::deque<double>::size_type samples = _samplesInput.get_value();
227   _inputQueue.resize(samples+1, 0.0);
228
229   double output_0 = _output_1 + (input - _inputQueue.back()) / samples;
230
231   _output_1 = output_0;
232   _inputQueue.push_front(input);
233   return output_0;
234 }
235
236 bool MovingAverageFilterImplementation::configure( const std::string & nodeName, SGPropertyNode_ptr configNode )
237 {
238   if (nodeName == "samples" ) {
239     _samplesInput.push_back( new InputValue( configNode, 1 ) );
240     return true;
241   }
242
243   return false;
244 }
245
246 /* --------------------------------------------------------------------------------- */
247 /* --------------------------------------------------------------------------------- */
248
249 NoiseSpikeFilterImplementation::NoiseSpikeFilterImplementation() :
250   _output_1(0.0)
251 {
252 }
253
254 void NoiseSpikeFilterImplementation::initialize( double initvalue )
255 {
256   _output_1 = initvalue;
257 }
258
259 double NoiseSpikeFilterImplementation::compute(  double dt, double input )
260 {
261   double delta = input - _output_1;
262   if( fabs(delta) <= SGLimitsd::min() ) return input; // trivial
263
264   double maxChange = _rateOfChangeInput.get_value() * dt;
265   const PeriodicalValue * periodical = _digitalFilter->getPeriodicalValue();
266   if( periodical ) delta = periodical->normalizeSymmetric( delta );
267
268   if( fabs(delta) <= maxChange )
269     return (_output_1 = input);
270   else
271     return (_output_1 = _output_1 + copysign( maxChange, delta ));
272 }
273
274 bool NoiseSpikeFilterImplementation::configure( const std::string & nodeName, SGPropertyNode_ptr configNode )
275 {
276   if (nodeName == "max-rate-of-change" ) {
277     _rateOfChangeInput.push_back( new InputValue( configNode, 1 ) );
278     return true;
279   }
280
281   return false;
282 }
283
284 /* --------------------------------------------------------------------------------- */
285 /* --------------------------------------------------------------------------------- */
286
287 ExponentialFilterImplementation::ExponentialFilterImplementation()
288   : _isSecondOrder(false),
289     output_1(0.0),
290     output_2(0.0)
291 {
292 }
293
294 void ExponentialFilterImplementation::initialize( double initvalue )
295 {
296   output_1 = output_2 = initvalue;
297 }
298
299 double ExponentialFilterImplementation::compute(  double dt, double input )
300 {
301   input = GainFilterImplementation::compute( dt, input );
302   double tf = _TfInput.get_value();
303
304   double output_0;
305
306   // avoid negative filter times 
307   // and div by zero if -tf == dt
308
309   double alpha = tf > 0.0 ? 1 / ((tf/dt) + 1) : 1.0;
310  
311   if(_isSecondOrder) {
312     output_0 = alpha * alpha * input + 
313                2 * (1 - alpha) * output_1 -
314               (1 - alpha) * (1 - alpha) * output_2;
315   } else {
316     output_0 = alpha * input + (1 - alpha) * output_1;
317   }
318   output_2 = output_1;
319   return (output_1 = output_0);
320 }
321
322 bool ExponentialFilterImplementation::configure( const std::string & nodeName, SGPropertyNode_ptr configNode )
323 {
324   if( GainFilterImplementation::configure( nodeName, configNode ) )
325     return true;
326
327   if (nodeName == "filter-time" ) {
328     _TfInput.push_back( new InputValue( configNode, 1 ) );
329     return true;
330   }
331
332   if (nodeName == "type" ) {
333     string type(configNode->getStringValue());
334     _isSecondOrder = type == "double-exponential";
335   }
336
337   return false;
338 }
339
340 /* --------------------------------------------------------------------------------- */
341 /* Digital Filter Component Implementation                                           */
342 /* --------------------------------------------------------------------------------- */
343
344 DigitalFilter::DigitalFilter() :
345     AnalogComponent(),
346     _initializeTo(INITIALIZE_INPUT)
347 {
348 }
349
350 DigitalFilter::~DigitalFilter()
351 {
352 }
353
354
355 static map<string,FunctorBase<DigitalFilterImplementation> *> componentForge;
356
357 bool DigitalFilter::configure(const string& nodeName, SGPropertyNode_ptr configNode)
358 {
359   if( componentForge.empty() ) {
360     componentForge["gain"] = new CreateAndConfigureFunctor<GainFilterImplementation,DigitalFilterImplementation>();
361     componentForge["exponential"] = new CreateAndConfigureFunctor<ExponentialFilterImplementation,DigitalFilterImplementation>();
362     componentForge["double-exponential"] = new CreateAndConfigureFunctor<ExponentialFilterImplementation,DigitalFilterImplementation>();
363     componentForge["moving-average"] = new CreateAndConfigureFunctor<MovingAverageFilterImplementation,DigitalFilterImplementation>();
364     componentForge["noise-spike"] = new CreateAndConfigureFunctor<NoiseSpikeFilterImplementation,DigitalFilterImplementation>();
365     componentForge["reciprocal"] = new CreateAndConfigureFunctor<ReciprocalFilterImplementation,DigitalFilterImplementation>();
366     componentForge["derivative"] = new CreateAndConfigureFunctor<DerivativeFilterImplementation,DigitalFilterImplementation>();
367   }
368
369   SG_LOG( SG_AUTOPILOT, SG_BULK, "DigitalFilter::configure(" << nodeName << ")" << endl );
370   if( AnalogComponent::configure( nodeName, configNode ) )
371     return true;
372
373   if (nodeName == "type" ) {
374     string type( configNode->getStringValue() );
375     if( componentForge.count(type) == 0 ) {
376       SG_LOG( SG_AUTOPILOT, SG_BULK, "unhandled filter type <" << type << ">" << endl );
377       return true;
378     }
379     _implementation = (*componentForge[type])( configNode->getParent() );
380     _implementation->setDigitalFilter( this );
381     return true;
382   }
383
384   if( nodeName == "initialize-to" ) {
385     string s( configNode->getStringValue() );
386     if( s == "input" ) {
387       _initializeTo = INITIALIZE_INPUT;
388     } else if( s == "output" ) {
389       _initializeTo = INITIALIZE_OUTPUT;
390     } else if( s == "none" ) {
391       _initializeTo = INITIALIZE_NONE;
392     } else {
393       SG_LOG( SG_AUTOPILOT, SG_WARN, "unhandled initialize-to value '" << s << "' ignored" );
394     }
395     return true;
396   }
397
398   SG_LOG( SG_AUTOPILOT, SG_BULK, "DigitalFilter::configure(" << nodeName << ") [unhandled]" << endl );
399   return false; // not handled by us, let the base class try
400 }
401
402 void DigitalFilter::update( bool firstTime, double dt)
403 {
404   if( _implementation == NULL ) return;
405
406   if( firstTime ) {
407     switch( _initializeTo ) {
408
409       case INITIALIZE_INPUT:
410         SG_LOG(SG_AUTOPILOT,SG_DEBUG, "First time initialization of " << get_name() << " to " << _valueInput.get_value() );
411         _implementation->initialize( _valueInput.get_value() );
412         break;
413
414       case INITIALIZE_OUTPUT:
415         SG_LOG(SG_AUTOPILOT,SG_DEBUG, "First time initialization of " << get_name() << " to " << get_output_value() );
416         _implementation->initialize( get_output_value() );
417         break;
418
419       default:
420         SG_LOG(SG_AUTOPILOT,SG_DEBUG, "First time initialization of " << get_name() << " to (uninitialized)" );
421         break;
422     }
423   }
424
425   double input = _valueInput.get_value() - _referenceInput.get_value();
426   double output = _implementation->compute( dt, input );
427
428   set_output_value( output );
429
430   if(_debug) {
431     cout << "input:" << input
432          << "\toutput:" << output << endl;
433   }
434 }