Digital low pass filter

Hi all,

I'm revisiting a project of mine, the PCBs are done already - so i'm limited to software only.

I'm filtering the output of some accelerometers with a simple first order RC filter, with my cut off frequency at 100Hz, and being first order I've only got 20dB/decade of gain in the stopband. The ADC sampling frequency is 600Hz, so no aliasing issues there.

However, I'd like really to have more like 40dB/decade, therefore adding a software 1st order low pass filter will give me total 40dB/decade of roll off.

I don't want to move my -3dB point to less than 100Hz.

Cheers!

EDIT - I'm using this tool (http://www-users.cs.york.ac.uk/~fisher/mkfilter/trad.html) but when I test it in Excel with some generic data, it doesn't filter per se - just reduces the amplitude, even if the input is within the passband. Clearly something fundamental I'm missing.

Additionally, the above clearly uses floating point math - whereas I'd like to stay integer... there must be a way to do this.

http://www.schwietering.com/jayduino/filtuino/ might be what you are looking for?

This works, and you get the source code with coefs as well..
http://t-filter.appspot.com/fir/index.html

Hmm - thanks for the links, seems like I need to do some more reading, IIRs vs FIRs etc... :~

Your code (10secs of work :wink: ):
SampleFilter.c

#include "SampleFilter.h"

static int filter_taps[SAMPLEFILTER_TAP_NUM] = {
  -145,
  -420,
  18,
  1564,
  1645,
  -2243,
  -4962,
  3135,
  20181,
  29406,
  20181,
  3135,
  -4962,
  -2243,
  1645,
  1564,
  18,
  -420,
  -145
};

void SampleFilter_init(SampleFilter* f) {
  int i;
  for(i = 0; i < SAMPLEFILTER_TAP_NUM; ++i)
    f->history[i] = 0;
  f->last_index = 0;
}

void SampleFilter_put(SampleFilter* f, int input) {
  f->history[f->last_index++] = input;
  if(f->last_index == SAMPLEFILTER_TAP_NUM)
    f->last_index = 0;
}

int SampleFilter_get(SampleFilter* f) {
  long long acc = 0;
  int index = f->last_index, i;
  for(i = 0; i < SAMPLEFILTER_TAP_NUM; ++i) {
    index = index != 0 ? index-1 : SAMPLEFILTER_TAP_NUM-1;
    acc += (long long)f->history[index] * filter_taps[i];
  };
  return acc >> 16;
}

SampleFilter.h:

#ifndef SAMPLEFILTER_H_
#define SAMPLEFILTER_H_
/*

FIR filter designed with
 http://t-filter.appspot.com

sampling frequency: 600 Hz

fixed point precision: 16 bits

* 0 Hz - 100 Hz
  gain = 1
  desired ripple = 1 dB
  actual ripple = n/a

* 200 Hz - 300 Hz
  gain = 0
  desired attenuation = -80 dB
  actual attenuation = n/a

*/

#define SAMPLEFILTER_TAP_NUM 19

typedef struct {
  int history[SAMPLEFILTER_TAP_NUM];
  unsigned int last_index;
} SampleFilter;

void SampleFilter_init(SampleFilter* f);
void SampleFilter_put(SampleFilter* f, int input);
int SampleFilter_get(SampleFilter* f);

#endif

I got as far as generating what you have in that example using my required numbers before - but I don't understand the long list of taps?

I also don't understand if I need an IIR or FIR filter etc - these are all things I need to look up...

If you are interested in phase linearity go for a FIR, or perhaps a Bessel filter in IIR.

If you just want fastest transition from pass to stop band and don't care about
phase distortion, IIR chebyshev or elliptic is the way to go.

Yes, phase linearity is something that's important. So, the filter designed here - http://t-filter.appspot.com/fir/index.html

Is that a butterworth filter?

but I don't understand the long list of taps?

The list of taps is not long, iit is quite short, I worked with 300 on arduino, but the propagation delay is long with many taps (the "sharper" filter and more attenuation in stop band, the more taps you will need).
That is a digital filter you are looking for. You may use FIR or IIR - there are differences where to use which. But for a quick start to check the feasibility of the solution try with the above code, it is 100hz pass-band with 80db stop-band attenuation @ your 600Hz sampling rate. You may study how it behaves (you may use 16bit or 32bit int or floating point taps and calculations, the latter is most precise one, less noise, you may make it sharper with more stop band att - with much more taps however).
I cannot find the source with my code yet, but it works like:

#include "SampleFilter.c"
setup() {
...
SampleFilter My100Hz;
SampleFilter_init(My100Hz);
}
void() {
...
your loop:
int data = your_accel_data();
// put your new data into the filter
SampleFilter_put(My100Hz, data);
// get the filtered data out of the FIR filter
data_filtered =  SampleFilter_get(My100Hz);
...

or something like that :).

Thanks Pito,

I've got an analog discovery, which has a built in programmable function generator so I'll test some up tomorrow with some frequency sweeps and see what happens.

Are the 'taps', what is commonly referred to by most sources as the filter coefficients?

"Tap" means a tap which provides a delayed input to the multiplication operation in the filter model (see its block diagram). A coefficient is related to a tap ("tap weight"). See the pictures in: