LCOV - code coverage report
Current view: top level - Filter - DerivativeFilter.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 29 50 58.0 %
Date: 2026-09-09 11:02:08 Functions: 3 12 25.0 %

          Line data    Source code
       1             : /*
       2             :    This program is free software: you can redistribute it and/or modify
       3             :    it under the terms of the GNU General Public License as published by
       4             :    the Free Software Foundation, either version 3 of the License, or
       5             :    (at your option) any later version.
       6             : 
       7             :    This program is distributed in the hope that it will be useful,
       8             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
       9             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      10             :    GNU General Public License for more details.
      11             : 
      12             :    You should have received a copy of the GNU General Public License
      13             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      14             :  */
      15             : 
      16             : /// @file       Derivative.cpp
      17             : /// @brief      A class to implement a derivative (slope) filter
      18             : /// See http://www.holoborodko.com/pavel/numerical-methods/numerical-derivative/smooth-low-noise-differentiators/
      19             : //
      20             : #include <inttypes.h>
      21             : #include <AP_Math/AP_Math.h>
      22             : #include "Filter.h"
      23             : #include "DerivativeFilter.h"
      24             : 
      25             : 
      26             : template <class T,  uint8_t FILTER_SIZE>
      27    20748956 : void DerivativeFilter<T,FILTER_SIZE>::update(T sample, uint32_t timestamp)
      28             : {
      29    20748956 :     uint8_t i = FilterWithBuffer<T,FILTER_SIZE>::sample_index;
      30             :     uint8_t i1;
      31    20748956 :     if (i == 0) {
      32     2965199 :         i1 = FILTER_SIZE-1;
      33             :     } else {
      34    17783757 :         i1 = i-1;
      35             :     }
      36    20748956 :     if (_timestamps[i1] == timestamp) {
      37             :         // this is not a new timestamp - ignore
      38       73440 :         return;
      39             :     }
      40             : 
      41             :     // add timestamp before we apply to FilterWithBuffer
      42    20675516 :     _timestamps[i] = timestamp;
      43             : 
      44             :     // call parent's apply function to get the sample into the array
      45    20675516 :     FilterWithBuffer<T,FILTER_SIZE>::apply(sample);
      46             : 
      47    20675516 :     _new_data = true;
      48             : }
      49             : 
      50             : 
      51             : template <class T,  uint8_t FILTER_SIZE>
      52    44779706 : float DerivativeFilter<T,FILTER_SIZE>::slope(void)
      53             : {
      54    44779706 :     if (!_new_data) {
      55    23866916 :         return _last_slope;
      56             :     }
      57             : 
      58    20912790 :     float result = 0;
      59             : 
      60             :     // use f() to make the code match the maths a bit better. Note
      61             :     // that unlike an average filter, we care about the order of the elements
      62             : #define f(i) FilterWithBuffer<T,FILTER_SIZE>::samples[(((FilterWithBuffer<T,FILTER_SIZE>::sample_index-1)+i+1)+3*FILTER_SIZE/2) % FILTER_SIZE]
      63             : #define x(i) _timestamps[(((FilterWithBuffer<T,FILTER_SIZE>::sample_index-1)+i+1)+3*FILTER_SIZE/2) % FILTER_SIZE]
      64             : 
      65    20912790 :     if (_timestamps[FILTER_SIZE-1] == _timestamps[FILTER_SIZE-2]) {
      66             :         // we haven't filled the buffer yet - assume zero derivative
      67      282587 :         return 0;
      68             :     }
      69             : 
      70             :     // N in the paper is FILTER_SIZE
      71             :     switch (FILTER_SIZE) {
      72           0 :     case 5:
      73           0 :         result = 2*2*(f(1) - f(-1)) / (x(1) - x(-1))
      74           0 :                  + 4*1*(f(2) - f(-2)) / (x(2) - x(-2));
      75           0 :         result /= 8;
      76           0 :         break;
      77    20630203 :     case 7:
      78    20630203 :         result = 2*5*(f(1) - f(-1)) / (x(1) - x(-1))
      79    20630203 :                  + 4*4*(f(2) - f(-2)) / (x(2) - x(-2))
      80    20630203 :                  + 6*1*(f(3) - f(-3)) / (x(3) - x(-3));
      81    20630203 :         result /= 32;
      82    20630203 :         break;
      83           0 :     case 9:
      84           0 :         result = 2*14*(f(1) - f(-1)) / (x(1) - x(-1))
      85           0 :                  + 4*14*(f(2) - f(-2)) / (x(2) - x(-2))
      86           0 :                  + 6* 6*(f(3) - f(-3)) / (x(3) - x(-3))
      87           0 :                  + 8* 1*(f(4) - f(-4)) / (x(4) - x(-4));
      88           0 :         result /= 128;
      89           0 :         break;
      90           0 :     case 11:
      91           0 :         result =  2*42*(f(1) - f(-1)) / (x(1) - x(-1))
      92           0 :                  +  4*48*(f(2) - f(-2)) / (x(2) - x(-2))
      93           0 :                  +  6*27*(f(3) - f(-3)) / (x(3) - x(-3))
      94           0 :                  +  8* 8*(f(4) - f(-4)) / (x(4) - x(-4))
      95           0 :                  + 10* 1*(f(5) - f(-5)) / (x(5) - x(-5));
      96           0 :         result /= 512;
      97           0 :         break;
      98             :     default:
      99             :         result = 0;
     100             :         break;
     101             :     }
     102             : 
     103             :     // cope with numerical errors
     104    20630203 :     if (isnan(result) || isinf(result)) {
     105           0 :         result = 0;
     106             :     }
     107             : 
     108    20630203 :     _new_data = false;
     109    20630203 :     _last_slope = result;
     110             : 
     111    20630203 :     return result;
     112             : }
     113             : 
     114             : // reset - clear all samples
     115             : template <class T, uint8_t FILTER_SIZE>
     116        1285 : void DerivativeFilter<T,FILTER_SIZE>::reset(void)
     117             : {
     118             :     // call parent's apply function to get the sample into the array
     119        1285 :     FilterWithBuffer<T,FILTER_SIZE>::reset();
     120        1285 : }
     121             : 
     122             : // add new instances as needed here
     123             : template void DerivativeFilter<float,5>::update(float sample, uint32_t timestamp);
     124             : template float DerivativeFilter<float,5>::slope(void);
     125             : template void DerivativeFilter<float,5>::reset(void);
     126             : 
     127             : template void DerivativeFilter<float,7>::update(float sample, uint32_t timestamp);
     128             : template float DerivativeFilter<float,7>::slope(void);
     129             : template void DerivativeFilter<float,7>::reset(void);
     130             : 
     131             : template void DerivativeFilter<float,9>::update(float sample, uint32_t timestamp);
     132             : template float DerivativeFilter<float,9>::slope(void);
     133             : template void DerivativeFilter<float,9>::reset(void);
     134             : 
     135             : template void DerivativeFilter<float,11>::update(float sample, uint32_t timestamp);
     136             : template float DerivativeFilter<float,11>::slope(void);
     137             : template void DerivativeFilter<float,11>::reset(void);
     138             : 
     139             : 
     140             : 

Generated by: LCOV version 1.14