FlightGear next
digitalfilter.cxx
Go to the documentation of this file.
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// Washout/high-pass filter, lead-lag filter and integrator added.
10// low-pass and lag aliases added to Exponential filter,
11// rate-limit added. A J Teeder 2013
12//
13// This program is free software; you can redistribute it and/or
14// modify it under the terms of the GNU General Public License as
15// published by the Free Software Foundation; either version 2 of the
16// License, or (at your option) any later version.
17//
18// This program is distributed in the hope that it will be useful, but
19// WITHOUT ANY WARRANTY; without even the implied warranty of
20// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21// General Public License for more details.
22//
23// You should have received a copy of the GNU General Public License
24// along with this program; if not, write to the Free Software
25// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26//
27
28#include "digitalfilter.hxx"
29#include <GUI/Highlight.hxx>
30#include <Main/globals.hxx>
31
32#include <deque>
33#include <algorithm>
34
35#include <simgear/misc/strutils.hxx>
36
37namespace FGXMLAutopilot
38{
39
45 public SGReferenced
46{
47 public:
50 virtual void initialize( double initvalue ) {}
51 virtual double compute( double dt, double input ) = 0;
52 virtual bool configure( SGPropertyNode& cfg_node,
53 const std::string& cfg_name,
54 SGPropertyNode& prop_root ) = 0;
55
56 void setDigitalFilter( DigitalFilter * digitalFilter ) { _digitalFilter = digitalFilter; }
57 virtual void collectDependentProperties(std::set<const SGPropertyNode*>& props) const = 0;
58 protected:
60};
61
62/* --------------------------------------------------------------------------------- */
63/* --------------------------------------------------------------------------------- */
65protected:
66 simgear::ValueList _gainInput;
67 bool configure(SGPropertyNode& cfg_node,
68 const std::string& cfg_name,
69 SGPropertyNode& prop_root);
70public:
72 double compute( double dt, double input );
73 virtual void collectDependentProperties(std::set<const SGPropertyNode*>& props) const
74 {
75 _gainInput.collectDependentProperties(props);
76 }
77};
78
80public:
81 double compute( double dt, double input );
82};
83
85 simgear::ValueList _TfInput;
86 double _input_1;
87 bool configure( SGPropertyNode& cfg_node,
88 const std::string& cfg_name,
89 SGPropertyNode& prop_root );
90public:
92 double compute( double dt, double input );
93 virtual void initialize( double initvalue );
94 virtual void collectDependentProperties(std::set<const SGPropertyNode*>& props) const
95 {
97 _TfInput.collectDependentProperties(props);
98 }
99};
100
102protected:
103 simgear::ValueList _TfInput;
104 bool configure(SGPropertyNode& cfg_node,
105 const std::string& cfg_name,
106 SGPropertyNode& prop_root);
109public:
111 double compute( double dt, double input );
112 virtual void initialize( double initvalue );
113 virtual void collectDependentProperties(std::set<const SGPropertyNode*>& props) const
114 {
116 _TfInput.collectDependentProperties(props);
117 }
118};
119
121protected:
122 simgear::ValueList _samplesInput;
123 double _output_1;
124 std::deque<double> _inputQueue;
125 bool configure(SGPropertyNode& cfg_node,
126 const std::string& cfg_name,
127 SGPropertyNode& prop_root);
128public:
130 double compute( double dt, double input );
131 virtual void initialize( double initvalue );
132 virtual void collectDependentProperties(std::set<const SGPropertyNode*>& props) const
133 {
134 _samplesInput.collectDependentProperties(props);
135 }
136};
137
139protected:
140 double _output_1;
141 simgear::ValueList _rateOfChangeInput;
142 bool configure( SGPropertyNode& cfg_node,
143 const std::string& cfg_name,
144 SGPropertyNode& prop_root );
145public:
147 double compute( double dt, double input );
148 virtual void initialize( double initvalue );
149 virtual void collectDependentProperties(std::set<const SGPropertyNode*>& props) const
150 {
151 _rateOfChangeInput.collectDependentProperties(props);
152 }
153};
154
156protected:
157 double _output_1;
158 simgear::ValueList _rateOfChangeMax;
159 simgear::ValueList _rateOfChangeMin;
160 bool configure( SGPropertyNode& cfg_node,
161 const std::string& cfg_name,
162 SGPropertyNode& prop_root );
163public:
165 double compute( double dt, double input );
166 virtual void initialize( double initvalue );
167 virtual void collectDependentProperties(std::set<const SGPropertyNode*>& props) const
168 {
169 _rateOfChangeMax.collectDependentProperties(props);
170 _rateOfChangeMin.collectDependentProperties(props);
171 }
172};
173
175protected:
176 simgear::ValueList _TfInput;
177 simgear::ValueList _minInput;
178 simgear::ValueList _maxInput;
179 double _input_1;
180 double _output_1;
181 bool configure(SGPropertyNode& cfg_node,
182 const std::string& cfg_name,
183 SGPropertyNode& prop_root);
184public:
186 double compute( double dt, double input );
187 virtual void initialize( double initvalue );
188 virtual void collectDependentProperties(std::set<const SGPropertyNode*>& props) const
189 {
191 _TfInput.collectDependentProperties(props);
192 _minInput.collectDependentProperties(props);
193 _maxInput.collectDependentProperties(props);
194 }
195};
196
197// integrates x" + ax' + bx + c = 0
199protected:
200 simgear::ValueList _aInput;
201 simgear::ValueList _bInput;
202 simgear::ValueList _cInput;
203 double _x2;
204 double _x1;
205 double _x0;
206 bool configure(SGPropertyNode& cfg_node,
207 const std::string& cfg_name,
208 SGPropertyNode& prop_root);
209public:
211 double compute( double dt, double input );
212 virtual void initialize( double initvalue );
213 virtual void collectDependentProperties(std::set<const SGPropertyNode*>& props) const
214 {
216 _aInput.collectDependentProperties(props);
217 _bInput.collectDependentProperties(props);
218 _cInput.collectDependentProperties(props);
219 }
220};
221
223protected:
224 simgear::ValueList _TfInput;
225 double _input_1;
226 double _output_1;
227 bool configure(SGPropertyNode& cfg_node,
228 const std::string& cfg_name,
229 SGPropertyNode& prop_root);
230public:
232 double compute( double dt, double input );
233 virtual void initialize( double initvalue );
234 virtual void collectDependentProperties(std::set<const SGPropertyNode*>& props) const
235 {
237 _TfInput.collectDependentProperties(props);
238 }
239};
241protected:
242 simgear::ValueList _TfaInput;
243 simgear::ValueList _TfbInput;
244 double _input_1;
245 double _output_1;
246 bool configure(SGPropertyNode& cfg_node,
247 const std::string& cfg_name,
248 SGPropertyNode& prop_root);
249public:
251 double compute( double dt, double input );
252 virtual void initialize( double initvalue );
253 virtual void collectDependentProperties(std::set<const SGPropertyNode*>& props) const
254 {
256 _TfaInput.collectDependentProperties(props);
257 _TfbInput.collectDependentProperties(props);
258 }
259};
260
262{
263protected:
264 simgear::ValueList _amplitude;
265
266 std::vector<double> _discreteValues;
267 bool _absoluteVal = false;
268 size_t _numDiscreteValues = 1024;
269
270 bool configure(SGPropertyNode& cfg_node,
271 const std::string& cfg_name,
272 SGPropertyNode& prop_root) override;
273
274public:
276 double compute(double dt, double input) override;
277 void initialize(double initvalue) override;
278 virtual void collectDependentProperties(std::set<const SGPropertyNode*>& props) const
279 {
280 _amplitude.collectDependentProperties(props);
281 }
282};
283
284/* --------------------------------------------------------------------------------- */
285/* --------------------------------------------------------------------------------- */
286
287} // namespace FGXMLAutopilot
288
289using namespace FGXMLAutopilot;
290
291//------------------------------------------------------------------------------
297
298//------------------------------------------------------------------------------
299double GainFilterImplementation::compute( double dt, double input )
300{
301 return _gainInput.get_value() * input;
302}
303
304bool GainFilterImplementation::configure( SGPropertyNode& cfg_node,
305 const std::string& cfg_name,
306 SGPropertyNode& prop_root )
307{
308 if (cfg_name == "gain" ) {
309 _gainInput.push_back(new simgear::Value(prop_root, cfg_node, 1));
310 return true;
311 }
312
313 return false;
314}
315
316/* --------------------------------------------------------------------------------- */
317/* --------------------------------------------------------------------------------- */
318
319double ReciprocalFilterImplementation::compute( double dt, double input )
320{
321 if( input >= -SGLimitsd::min() && input <= SGLimitsd::min() )
322 return SGLimitsd::max();
323
324 return _gainInput.get_value() / input;
325
326}
327
328/* --------------------------------------------------------------------------------- */
329/* --------------------------------------------------------------------------------- */
330
335
337{
338 _input_1 = initvalue;
339}
340
341//------------------------------------------------------------------------------
342bool DerivativeFilterImplementation::configure( SGPropertyNode& cfg_node,
343 const std::string& cfg_name,
344 SGPropertyNode& prop_root )
345{
346 if( GainFilterImplementation::configure(cfg_node, cfg_name, prop_root) )
347 return true;
348
349 if (cfg_name == "filter-time" ) {
350 _TfInput.push_back(new simgear::Value(prop_root, cfg_node, 1));
351 return true;
352 }
353
354 return false;
355}
356
357double DerivativeFilterImplementation::compute( double dt, double input )
358{
359 double output = (input - _input_1) * _TfInput.get_value() * _gainInput.get_value() / dt;
360 _input_1 = input;
361 return output;
362
363}
364
365/* --------------------------------------------------------------------------------- */
366/* --------------------------------------------------------------------------------- */
367
372
374{
375 _output_1 = initvalue;
376}
377
378double MovingAverageFilterImplementation::compute( double dt, double input )
379{
380 typedef std::deque<double>::size_type size_type;
381 size_type samples = _samplesInput.get_value();
382
383 if (_inputQueue.size() != samples) {
384 // For constant size filters, this code executed once.
385 bool shrunk = _inputQueue.size() > samples;
386 _inputQueue.resize(samples, _output_1);
387 if (shrunk) {
388 _output_1 = 0.0;
389 for (size_type ii = 0; ii < samples; ii++)
390 _output_1 += _inputQueue[ii];
391 _output_1 /= samples;
392 }
393 }
394
395 double output_0 = _output_1 + (input - _inputQueue.back()) / samples;
396
397 _output_1 = output_0;
398 _inputQueue.pop_back();
399 _inputQueue.push_front(input);
400 return output_0;
401}
402
403bool MovingAverageFilterImplementation::configure( SGPropertyNode& cfg_node,
404 const std::string& cfg_name,
405 SGPropertyNode& prop_root )
406{
407 if (cfg_name == "samples" ) {
408 _samplesInput.push_back(new simgear::Value(prop_root, cfg_node, 1));
409 return true;
410 }
411
412 return false;
413}
414
415/* --------------------------------------------------------------------------------- */
416/* --------------------------------------------------------------------------------- */
417
422
424{
425 _output_1 = initvalue;
426}
427
428double NoiseSpikeFilterImplementation::compute( double dt, double input )
429{
430 double delta = input - _output_1;
431 if( fabs(delta) <= SGLimitsd::min() ) return input; // trivial
432
433 double maxChange = _rateOfChangeInput.get_value() * dt;
434 const auto periodical = _digitalFilter->getPeriodicalValue();
435 if( periodical ) delta = periodical->normalizeSymmetric( delta );
436
437 if( fabs(delta) <= maxChange )
438 return (_output_1 = input);
439 else
440 return (_output_1 = _output_1 + copysign( maxChange, delta ));
441}
442
443//------------------------------------------------------------------------------
444bool NoiseSpikeFilterImplementation::configure( SGPropertyNode& cfg_node,
445 const std::string& cfg_name,
446 SGPropertyNode& prop_root )
447{
448 if (cfg_name == "max-rate-of-change" ) {
449 _rateOfChangeInput.push_back(new simgear::Value(prop_root, cfg_node, 1));
450 return true;
451 }
452
453 return false;
454}
455
456/* --------------------------------------------------------------------------------- */
457
462
464{
465 _output_1 = initvalue;
466}
467
468double RateLimitFilterImplementation::compute( double dt, double input )
469{
470 double delta = input - _output_1;
471 double output;
472
473 if( fabs(delta) <= SGLimitsd::min() ) return input; // trivial
474
475 double maxChange = _rateOfChangeMax.get_value() * dt;
476 double minChange = _rateOfChangeMin.get_value() * dt;
477// const PeriodicalValue * periodical = _digitalFilter->getPeriodicalValue();
478// if( periodical ) delta = periodical->normalizeSymmetric( delta );
479
480 output = input;
481 if(delta >= maxChange ) output = _output_1 + maxChange;
482 if(delta <= minChange ) output = _output_1 + minChange;
483 _output_1 = output;
484
485 return (output);
486}
487
488bool RateLimitFilterImplementation::configure( SGPropertyNode& cfg_node,
489 const std::string& cfg_name,
490 SGPropertyNode& prop_root )
491{
492// std::cout << "RateLimitFilterImplementation " << cfg_name << std::endl;
493 if (cfg_name == "max-rate-of-change" ) {
494 _rateOfChangeMax.push_back(new simgear::Value(prop_root, cfg_node, 1));
495 return true;
496 }
497 if (cfg_name == "min-rate-of-change" ) {
498 _rateOfChangeMin.push_back(new simgear::Value(prop_root, cfg_node, 1));
499 return true;
500 }
501
502 return false;
503}
504
505/* --------------------------------------------------------------------------------- */
506/* --------------------------------------------------------------------------------- */
507
514
516{
517 _output_1 = _output_2 = initvalue;
518}
519
520double ExponentialFilterImplementation::compute( double dt, double input )
521{
522 input = GainFilterImplementation::compute( dt, input );
523 double tf = _TfInput.get_value();
524
525 double output_0;
526
527 // avoid negative filter times
528 // and div by zero if -tf == dt
529
530 double alpha = tf > 0.0 ? 1 / ((tf/dt) + 1) : 1.0;
531
532 if(_isSecondOrder) {
533 output_0 = alpha * alpha * input +
534 2 * (1 - alpha) * _output_1 -
535 (1 - alpha) * (1 - alpha) * _output_2;
536 } else {
537 output_0 = alpha * input + (1 - alpha) * _output_1;
538 }
540 return (_output_1 = output_0);
541}
542
543//------------------------------------------------------------------------------
544bool ExponentialFilterImplementation::configure( SGPropertyNode& cfg_node,
545 const std::string& cfg_name,
546 SGPropertyNode& prop_root )
547{
548 if( GainFilterImplementation::configure(cfg_node, cfg_name, prop_root) )
549 return true;
550
551 if (cfg_name == "filter-time" ) {
552 _TfInput.push_back(new simgear::Value(prop_root, cfg_node, 1));
553 return true;
554 }
555
556 if (cfg_name == "type" ) {
557 std::string type = simgear::strutils::strip(cfg_node.getStringValue());
558 _isSecondOrder = type == "double-exponential";
559 }
560
561 return false;
562}
563
564/* --------------------------------------------------------------------------------- */
565
571
573{
574 _input_1 = _output_1 = initvalue;
575}
576
577//------------------------------------------------------------------------------
578bool IntegratorFilterImplementation::configure( SGPropertyNode& cfg_node,
579 const std::string& cfg_name,
580 SGPropertyNode& prop_root )
581{
582 if( GainFilterImplementation::configure(cfg_node, cfg_name, prop_root) )
583 return true;
584
585 if (cfg_name == "u_min" ) {
586 _minInput.push_back(new simgear::Value(prop_root, cfg_node, 1));
587 return true;
588 }
589 if (cfg_name == "u_max" ) {
590 _maxInput.push_back(new simgear::Value(prop_root, cfg_node, 1));
591 return true;
592 }
593 return false;
594}
595
596double IntegratorFilterImplementation::compute( double dt, double input )
597{
598 double output = _output_1 + input * _gainInput.get_value() * dt;
599 double u_min = _minInput.get_value();
600 double u_max = _maxInput.get_value();
601 if (output >= u_max) output = u_max; // clamping inside "::compute" prevents integrator wind-up
602 if (output <= u_min) output = u_min;
603 _input_1 = input;
604 _output_1 = output;
605 return output;
606
607}
608
609/* --------------------------------------------------------------------------------- */
614
616{
617 _x2 = _x1 = _x0 = initvalue;
618}
619
621 const std::string& cfg_name,
622 SGPropertyNode& prop_root )
623{
624 if( GainFilterImplementation::configure(cfg_node, cfg_name, prop_root) )
625 return true;
626
627 if (cfg_name == "a" ) {
628 _aInput.push_back(new simgear::Value(prop_root, cfg_node, 1));
629 return true;
630 }
631 if (cfg_name == "b" ) {
632 _bInput.push_back(new simgear::Value(prop_root, cfg_node, 1));
633 return true;
634 }
635 if (cfg_name == "c" ) {
636 _cInput.push_back(new simgear::Value(prop_root, cfg_node, 1));
637 return true;
638 }
639 return false;
640}
641
642double DampedOscillationFilterImplementation::compute( double dt, double input )
643{
644 if (fabs(input) > 1e-15) {
645 double dz = dt * input;
646 _x0 = _x1 - dz;
647 _x2 = _x1 + dz;
648 } else {
649 double a = _aInput.get_value();
650 double b = _bInput.get_value();
651 double c = _cInput.get_value();
652 _x0 = (_x1 * (2. + dt * (a - b * dt)) - _x2 - c * dt * dt) / (1. + a * dt);
653 _x2 = _x1;
654 _x1 = _x0;
655 }
656 return _x0;
657}
658
659/* --------------------------------------------------------------------------------- */
660
667
669{
670 _input_1 = initvalue;
671 _output_1 = initvalue;
672}
673
674//double HighPassFilterImplementation::compute( double dt, double input )
675//{
676// input = GainFilterImplementation::compute( dt, input );
677// double tf = _TfInput.get_value();
678//
679// double output;
680//
681// // avoid negative filter times
682// // and div by zero if -tf == dt
683//
684// double alpha = tf > 0.0 ? 1 / ((tf/dt) + 1) : 1.0;
685// output = (1 - alpha) * (input - _input_1 + _output_1);
686// _input_1 = input;
687// _output_1 = output;
688// return output;
689//}
690
691double HighPassFilterImplementation::compute(double dt, double input)
692{
693 if (SGMiscd::isNaN(input))
694 SG_LOG(SG_AUTOPILOT, SG_ALERT, "High pass filter output is NaN.");
695
696 input = GainFilterImplementation::compute(dt, input);
697 double tf = _TfInput.get_value();
698
699 double output;
700
701 // avoid negative filter times
702 // and div by zero if -tf == dt
703
704
705 double alpha = tf > 0.0 ? 1 / ((tf / dt) + 1) : 1.0;
706 output = (1 - alpha) * (input - _input_1 + _output_1);
707 _input_1 = input;
708
709 // Catch NaN before it causes damage
710
711 if (output != output) {
712 SG_LOG(SG_AUTOPILOT, SG_ALERT, "High pass filter output is NaN.");
713 output = 0.0;
714 }
715 _output_1 = output;
716 return output;
717}
718//------------------------------------------------------------------------------
719bool HighPassFilterImplementation::configure( SGPropertyNode& cfg_node,
720 const std::string& cfg_name,
721 SGPropertyNode& prop_root )
722{
723 if( GainFilterImplementation::configure(cfg_node, cfg_name, prop_root) )
724 return true;
725
726 if (cfg_name == "filter-time" ) {
727 _TfInput.push_back(new simgear::Value(prop_root, cfg_node, 1));
728 return true;
729 }
730
731 return false;
732}
733
734/* --------------------------------------------------------------------------------- */
735
742
744{
745 _input_1 = initvalue;
746 _output_1 = initvalue;
747}
748
749double LeadLagFilterImplementation::compute( double dt, double input )
750{
751 input = GainFilterImplementation::compute( dt, input );
752 double tfa = _TfaInput.get_value();
753 double tfb = _TfbInput.get_value();
754
755 double output;
756
757 // avoid negative filter times
758 // and div by zero if -tf == dt
759
760 double alpha = tfa > 0.0 ? 1 / ((tfa/dt) + 1) : 1.0;
761 double beta = tfb > 0.0 ? 1 / ((tfb/dt) + 1) : 1.0;
762 output = (1 - beta) * (input / (1 - alpha) - _input_1 + _output_1);
763 _input_1 = input;
764 _output_1 = output;
765 return output;
766}
767
768//------------------------------------------------------------------------------
769bool LeadLagFilterImplementation::configure( SGPropertyNode& cfg_node,
770 const std::string& cfg_name,
771 SGPropertyNode& prop_root )
772{
773 if( GainFilterImplementation::configure(cfg_node, cfg_name, prop_root) )
774 return true;
775
776 if (cfg_name == "filter-time-a" ) {
777 _TfaInput.push_back(new simgear::Value(prop_root, cfg_node, 1));
778 return true;
779 }
780 if (cfg_name == "filter-time-b" ) {
781 _TfbInput.push_back(new simgear::Value(prop_root, cfg_node, 1));
782 return true;
783 }
784 return false;
785}
786
787
788/* --------------------------------------------------------------------------------- */
789
794
796{
797 // allocate the array one bigger so we don't need to worry about
798 // wrapping.bound checking the discrete +1 lookup
800 std::generate(_discreteValues.begin(), _discreteValues.end(), []() {
801 return (sg_random() * 2.0) - 1.0;
802 });
803}
804
805static double lerp(double a, double b, double t)
806{
807 return (a * (1.0 - t)) + (b * t);
808}
809
810double CoherentNoiseFilterImplementation::compute(double dt, double input)
811{
812 const double a = _amplitude.get_value();
813
814 const double t = input * _numDiscreteValues;
815 const int i = static_cast<int>(floor(t)) % _numDiscreteValues;
816 const auto v0 = _discreteValues.at(i);
817 const auto v1 = _discreteValues.at(i + 1);
818
819 const auto weight = t - floor(t);
820 const double output = lerp(v0, v1, weight);
821
822 return _absoluteVal ? fabs(output) * a : output * a;
823}
824
825//------------------------------------------------------------------------------
827 const std::string& cfg_name,
828 SGPropertyNode& prop_root)
829{
830 if (cfg_name == "discrete-resolution") {
831 _numDiscreteValues = cfg_node.getIntValue();
832 return true;
833 }
834
835 if (cfg_name == "amplitude") {
836 _amplitude.push_back(new simgear::Value(prop_root, cfg_node, 1.0));
837 return true;
838 }
839
840 if (cfg_name == "absolute") {
841 _absoluteVal = cfg_node.getBoolValue();
842 return true;
843 }
844 return false;
845}
846
847/* -------------------------------------------------------------------------- */
848/* Digital Filter Component Implementation */
849/* -------------------------------------------------------------------------- */
850
853 _initializeTo(INITIALIZE_INPUT)
854{
855}
856
860
861//------------------------------------------------------------------------------
862template<class DigitalFilterType>
864{
865 return new DigitalFilterType();
866}
867
868typedef std::map<std::string, DigitalFilterImplementation*(*)()>
871
872//------------------------------------------------------------------------------
873bool DigitalFilter::configure( SGPropertyNode& prop_root,
874 SGPropertyNode& cfg )
875{
876 if( componentForge.empty() )
877 {
891 }
892
893 const auto type = simgear::strutils::strip(cfg.getStringValue("type"));
894 DigitalFilterMap::iterator component_factory = componentForge.find(type);
895 if( component_factory == componentForge.end() )
896 {
897 SG_LOG(SG_AUTOPILOT, SG_WARN, "unhandled filter type '" << type << "'");
898 return false;
899 }
900
901 _implementation = (*component_factory->second)();
902 _implementation->setDigitalFilter( this );
903
904 for( int i = 0; i < cfg.nChildren(); ++i )
905 {
906 SGPropertyNode_ptr child = cfg.getChild(i);
907 std::string cname(child->getNameString());
908 bool ok = false;
909 if (!ok) ok = _implementation->configure(*child, cname, prop_root);
910 if (!ok) ok = configure(*child, cname, prop_root);
911 if (!ok) ok = (cname == "type");
912 if (!ok) ok = (cname == "params"); // 'params' is usually used to specify parameters in PropertList files.
913 if (!ok) {
914 SG_LOG
915 (
916 SG_AUTOPILOT,
917 SG_ALERT,
918 "DigitalFilter: unknown config node: " << cname
919 );
920 }
921 }
922
923 /* Send information about associations between our input and output
924 properties to Highlight. */
925 std::set<const SGPropertyNode*> inputs;
926 _implementation->collectDependentProperties(inputs);
928
929 auto highlight = globals->get_subsystem<Highlight>();
930 if (highlight) {
931 for (auto in: inputs) {
932 for (auto& out: _output_list) {
933 highlight->addPropertyProperty(
934 in->getPath(true /*simplify*/),
935 out->getPath(true /*simplify*/)
936 );
937 }
938 }
939 }
940
941 return true;
942}
943
944//------------------------------------------------------------------------------
945bool DigitalFilter::configure( SGPropertyNode& cfg_node,
946 const std::string& cfg_name,
947 SGPropertyNode& prop_root )
948{
949 if( cfg_name == "initialize-to" )
950 {
951 const auto s = simgear::strutils::strip(cfg_node.getStringValue());
952 if( s == "input" )
953 _initializeTo = INITIALIZE_INPUT;
954 else if( s == "output" )
955 _initializeTo = INITIALIZE_OUTPUT;
956 else if( s == "none" )
957 _initializeTo = INITIALIZE_NONE;
958 else
959 SG_LOG
960 (
961 SG_AUTOPILOT,
962 SG_WARN, "DigitalFilter: initialize-to (" << s << ") ignored"
963 );
964
965 return true;
966 }
967
968 return AnalogComponent::configure(cfg_node, cfg_name, prop_root);
969}
970
971//------------------------------------------------------------------------------
972void DigitalFilter::update( bool firstTime, double dt)
973{
974 if( _implementation == NULL ) return;
975
976 if( firstTime ) {
977 switch( _initializeTo ) {
978
979 case INITIALIZE_INPUT:
980 SG_LOG(SG_AUTOPILOT,SG_DEBUG, "First time initialization of " << subsystemId() << " to " << _valueInput.get_value() );
981 _implementation->initialize( _valueInput.get_value() );
982 break;
983
984 case INITIALIZE_OUTPUT:
985 SG_LOG(SG_AUTOPILOT,SG_DEBUG, "First time initialization of " << subsystemId() << " to " << get_output_value() );
986 _implementation->initialize( get_output_value() );
987 break;
988
989 default:
990 SG_LOG(SG_AUTOPILOT,SG_DEBUG, "First time initialization of " << subsystemId() << " to (uninitialized)" );
991 break;
992 }
993 }
994
995 double input = _valueInput.get_value() - _referenceInput.get_value();
996 if (SGMiscd::isNaN(input))
997 input = _valueInput.get_value() - _referenceInput.get_value();
998 double output = _implementation->compute( dt, input );
999
1000 set_output_value( output );
1001
1002 if(_debug) {
1003 std::cout << subsystemId() << ": input=" << input
1004 << "\toutput=" << output << std::endl;
1005 }
1006}
1007
1008
1009// Register the subsystem.
1010SGSubsystemMgr::Registrant<DigitalFilter> registrantDigitalFilter;
#define i(x)
static ComponentForge componentForge
simgear::ValueList _valueInput
the value input
bool configure(SGPropertyNode &cfg_node, const std::string &cfg_name, SGPropertyNode &prop_root) override
This method configures this analog component from a property node.
AnalogComponent()
A constructor for an analog component.
simgear::ValueList _referenceInput
the reference input
void collectDependentProperties(std::set< const SGPropertyNode * > &props) const
Add to <props> all properties that are used by this component.
double get_output_value() const
return the current double value of the output property
double compute(double dt, double input) override
bool configure(SGPropertyNode &cfg_node, const std::string &cfg_name, SGPropertyNode &prop_root) override
virtual void collectDependentProperties(std::set< const SGPropertyNode * > &props) const
bool _debug
debug flag, true if this component should generate some useful output on every iteration
Definition component.hxx:66
bool configure(SGPropertyNode &cfg_node, const std::string &cfg_name, SGPropertyNode &prop_root)
virtual void collectDependentProperties(std::set< const SGPropertyNode * > &props) const
virtual void collectDependentProperties(std::set< const SGPropertyNode * > &props) const
virtual void collectDependentProperties(std::set< const SGPropertyNode * > &props) const =0
virtual double compute(double dt, double input)=0
void setDigitalFilter(DigitalFilter *digitalFilter)
virtual bool configure(SGPropertyNode &cfg_node, const std::string &cfg_name, SGPropertyNode &prop_root)=0
virtual void initialize(double initvalue)
brief@ DigitalFilter - a selection of digital filters
bool configure(SGPropertyNode &cfg_node, const std::string &cfg_name, SGPropertyNode &prop_root) override
This method configures this analog component from a property node.
void update(bool firstTime, double dt) override
pure virtual function to be implemented by the derived classes.
virtual void collectDependentProperties(std::set< const SGPropertyNode * > &props) const
bool configure(SGPropertyNode &cfg_node, const std::string &cfg_name, SGPropertyNode &prop_root)
virtual void collectDependentProperties(std::set< const SGPropertyNode * > &props) const
double compute(double dt, double input)
bool configure(SGPropertyNode &cfg_node, const std::string &cfg_name, SGPropertyNode &prop_root)
double compute(double dt, double input)
bool configure(SGPropertyNode &cfg_node, const std::string &cfg_name, SGPropertyNode &prop_root)
virtual void initialize(double initvalue)
virtual void collectDependentProperties(std::set< const SGPropertyNode * > &props) const
bool configure(SGPropertyNode &cfg_node, const std::string &cfg_name, SGPropertyNode &prop_root)
virtual void collectDependentProperties(std::set< const SGPropertyNode * > &props) const
bool configure(SGPropertyNode &cfg_node, const std::string &cfg_name, SGPropertyNode &prop_root)
virtual void collectDependentProperties(std::set< const SGPropertyNode * > &props) const
virtual void initialize(double initvalue)
double compute(double dt, double input)
bool configure(SGPropertyNode &cfg_node, const std::string &cfg_name, SGPropertyNode &prop_root)
virtual void collectDependentProperties(std::set< const SGPropertyNode * > &props) const
bool configure(SGPropertyNode &cfg_node, const std::string &cfg_name, SGPropertyNode &prop_root)
virtual void collectDependentProperties(std::set< const SGPropertyNode * > &props) const
double compute(double dt, double input)
virtual void collectDependentProperties(std::set< const SGPropertyNode * > &props) const
bool configure(SGPropertyNode &cfg_node, const std::string &cfg_name, SGPropertyNode &prop_root)
virtual void initialize(double initvalue)
SGSubsystemMgr::Registrant< DigitalFilter > registrantDigitalFilter
static double lerp(double a, double b, double t)
std::map< std::string, DigitalFilterImplementation *(*)()> DigitalFilterMap
DigitalFilterImplementation * digitalFilterFactory()
FGGlobals * globals
Definition globals.cxx:142