GithubHelp home page GithubHelp logo

filters's Introduction

Filters

A Realtime Digital Signal Processing (DSP) Library for Arduino.

The Filters library implements several useful digital filters for real-time signal processing in microcontrollers. These filters are easy-to-use, programmable versions of common analog signal processing filters, such as single-pole (RC) lowpass and highpass filters. The library also includes two-pole lowpass filters (Bessel and Butterworth), as well other "filters" to calculate running statistics, or return the time derivative of a signal.

A common usage of the Filters library is to use a lowpass filter (or cascaded set of lowpass filters) to smooth out values read continuously from an analog input pin. The filter output values can be read as needed, and are always valid. This is a simple way to implement the standard oversample, filter, downsample patten common with in analog-to-digital conversion (ADC).

The filters use floating point precision, and should be updated with new input values frequently and continuously (in a loop) for accuracy., but do not need to be updated at fixed intervals (updates can be asynchronous). That is, Filters can be updated with new input values at essentially any rate, as long as they are the updated much more frequently the filter cut-off frequency.

In addition to standard analog-like (recursive) filters, the library also includes additional filters useful for statistics and signal processing. The Derivative filter returns the current time derivative (dx/dt) of the signal. The RunningStatistics keeps track of the running mean() as well standard deviation sigma() of a signal, over some user-defined time window.

Filters can also be cascaded, and the output of one filter can be used as the input of another filter.

Installation (Ardunio, Energia, etc.)

Make sure you have the Arduino environment installed on your system.

To install the Filters library, simply download (or clone) the Filters folder (this repository) into the Arduino libraries directory. The libraries directory resides in the default save location for Arduino sketches. On a Mac, this is Documents > Arduino > libraries. The Filters should be added there.

You can then use the filters in your sketches by adding

#include <Filters.h>

Using the Filters

There are some examples in examples directory.

The standard pattern for using a filter is:

  • Declare a filter, and set any properties.

  • Update the filter value continuously in a loop, by calling .input( newValue ) on the filter. Updates should happen frequently, for numerical stability and accuracy, but do not have to occur at fixed time intervals.

  • To retrieve the value of the filter, call .output() on the filter. The output is valid at any time, and contains the most up-to-date filtered values.

Filter Types

The Filters library contains four different filter classes. Please see the .h files for the various filters, for a full list of functions.


The one pole filter functions like an analog RC filter, with a corner specified by fc. The filter is initialized to zero, but the initial value can be specified (useful for avoid jumps at startup, if the signal contains an offset).

// constructor for one pole filter
FilterOnePole( FILTER_TYPE ft=LOWPASS, float fc=1.0, float initialValue=0 );

The FILTER_TYPE can be LOWPASS or HIGHPASS, which function like the traditional analog RC highpass and lowpass circuits. The INTEGRATOR and DIFFERENTIATOR filter types are experimental.


The two pole filter functions like an analog RCL lowpass filter. The filter values are specified by the frequency0, the natural undampened frequency of the filter, and the qualityFactor. In practice, It is often more useful to create a two pole filter with the default values, and then set the filter values by calling setAsFilter on the newly created filter:

// constructor for two pole filter
FilterTwoPole( float frequency0 = 1, float qualityFactor = 1, float xInit = 0);

// member function for specifying filter type and value
void setAsFilter( OSCILLATOR_TYPE ft, float frequency3db, float initialValue=0 );

The OSCILLATOR_TYPE can be LOWPASS_BESSEL or LOWPASS_BUTTERWORTH, which have slightly different phase frequency responses. The corner frequency (cutoff frequency) is specified by the frequency3db parameter.


The derivative "filter" has the standard filter interface, but returns the latest time derivative dx/dt of the signal.

// constructor for derivative filter
FilterDerivative()

The running statistics "filter" keeps a running value calculated for the mean() and sigma() (standard deviation) of a signal, over some specified running window. This can be useful, for instance, too see if the value on a sensor is constant, or noisy/changing.

// constructor for running statistics filter
RunningStatistics();
  
// member function to specify the window time
void setWindowSecs( float windowSecs );

Update (2021)

This code was released as an opensource project in 2015, and I have not been attending to it. It appears that the code has become useful to the community, and gets a fair number of downloads / forks / etc.

First, I wanted to express a sincere Thank You to GitHub, Arduino, and the opensource community, for keeping up interest in the project, and for the contributions. I'll be updating the project with additional documentation and examples in the future, to extend the usefulness of the project.

The planned future work includes:

  • Adding the code to the Arduino Library, to make it more widely available, and easier to install
  • Adding additional user information (specifics on the various filters, and how to use).
  • Adding additional examples
  • Addressing any pending Issues on GitHub

Progress and updates will be posted to this site, and this is the main repository for the Filters code.

filters's People

Contributors

jonhub avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

filters's Issues

Filters - output

I'm not sure if I am setting it up correctly but if I set a low pass filter frequency at 100 (Hz). The 100 Hz should be the cutoff frequency correct? Now if I use the output function of my filter and print the value... should I be seeing a value of zero if my input frequency is over 100 Hz?

Undefined behavior on timer rollover

The method FilterOnePole::input(float) starts with these statements:

long time = micros();
ElapsedUS = float(time - LastUS);   // cast to float here, for math

When micros() reaches 231, which happens roughly 35.8 minutes after the program starts, time becomes a large negative number, and the subtraction time - LastUS overflows.

In C and C++, arithmetic overflow of signed integral types is undefined behavior. This means the program is incorrect, and anything can happen, including (but not limited to) the subtraction giving the expected result. Just for illustration, here is a recent example of the kind of surprises you can get with integer overflows.

The same bug is present in FilterTwoPole.cpp and in FilterDerivative.cpp.

The fix is very simple: all variables holding timestamps (LastUS, LastTimeUS, thisUS, time and now) should be declared unsigned long. This is the type returned by micros(), and it is not a coincidence that it is the right type for timing calculations. Unlike signed integers, the arithmetics on unsigned integers are specified by the C and C++ standards to be done modulo MAX(type)+1. This guarantees that the subtraction will yield the correct result even across a micros() rollover.

Library for C language

Hello,

I know this is targeted for Arduino users, however, if using esp-idf then C language is required. Is it possible to convert to C language for your library?

Thank you.

Filters are unsuitable for fixed-rate sampling

These filters assume the sampling rate is the rate of the user program calling their input() methods. This is fine if the user just calls filter.input(analogRead(PIN)) in his loop. However, if he manages to have a fixed sampling rate (maybe by using external hardware) and his calls to input() are not quite periodic, then the filters will assume wrong timings. I have witnessed one user being bitten by this issue.

A related issue is the poor performance. I have benchmarked FilterOnePole::input(float) at about 245 µs average time per sample on a 16 MHz AVR-based Arduino. I suspect a significant fraction of this time is spent in computing ampFactor as

ampFactor = exp( -1.0 / TauSamps );

given that both the floating-point division and the exponential are very CPU-intensive on 8-bit FPU-less micros.

Computing this for every sample is reasonable if the sampling rate is not constant. However, when using a fixed sampling rate, this computation only needs to be performed once, at initialization. I implemented a constant-rate low pass filter similar to FilterOnePole in LOWPASS mode and it takes only 27.8 µs per sample, i.e. it is 8.8 times faster than FilterOnePole.

I suggest putting a note somewhere, maybe in a README file, warning the users that this library is only suited for cases where the sampling rate cannot be kept constant, and that dealing with this uneven sampling comes at a high cost in terms of processing time.

The default view is running

I want the display to run without having to write 4V, 1000V then the final display. I want a final view that is legible

// wire i2c
#include <Wire.h> 
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27,16,2);

#include <Filters.h>

float testFrequency = 50; // signal frequency (Hz)
float windowLength = 40.0/testFrequency; // how long to average the signal, for statistist

int Sensor = 0;                 

float intercept = -0.04; // adjust untuk kalibrasi
float slope = 0.0964; // adjust untuk kalibrasi
float current_Volts;

unsigned long previousMillis1 = 0;
const long interval1 = 1000;

void setup() {
  Wire.begin();
  Serial.begin(9600);
  
  lcd.init();
  lcd.backlight();
}

void loop() {
  RunningStatistics inputStats;               
  inputStats.setWindowSecs( windowLength );
   
  while( true ) {   
    Sensor = analogRead(A0); // read the analog in value:
    inputStats.input(Sensor); // log to Stats function
        
   if(millis() - previousMillis1 >= interval1) {
      previousMillis1 = millis();
        current_Volts = inputStats.sigma()* slope + intercept; //Calibartions for offset and amplitude
        current_Volts = current_Volts*(49.3231); //Further calibrations for the amplitude     
          lcd.clear();
          lcd.setCursor(0,0);
          lcd.print("VOLTAGE");
          lcd.setCursor(0,1);
          lcd.print(current_Volts);
          lcd.print("V");
    }
    break;
  }
}

compilation error

Arduino\libraries\Filters-master\FilterTwoPole.cpp: In member function 'void FilterTwoPole::test()':

C:\Users\Shubh\Documents\Arduino\libraries\Filters-master\FilterTwoPole.cpp:198:33: error: 'analogWrite' was not declared in this scope

 analogWrite(10,osc.output() ); // hardcoded the dial pin

                             ^

exit status 1

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.