Computing stuff tied to the physical world

Digital filter design

In Software on Oct 15, 2011 at 00:01

In the moving averages post a few days ago, I just picked whatever seemed reasonable for filtering – i.e. running a moving average of order 31 over 531 samples, sampling at roughly 7,000 samples/second (which is what the free-running ADC does with my clock choice). And indeed, it looks like it will work quite well.

The nice thing about moving averages done this way, is that the calculations are trivial: just add the new value in and omit the oldest one. All it takes is an N-stage sample memory, i.e. 31-int array in this case.

But diving a bit deeper into FIR filters, which includes such a moving average as simplest case, it’s clear that I was sampling more than needed. I really don’t need 531 samples to measure the peak-to-peak level of the underlying 50 Hz signal, I just need to measure for the duration of a few 50 Hz cycles (about 3 in the above case).

As it turns out, once you dive in there are many ways to improve things, and lots of online guides and tools.

There’s a lot more to FIR filter design, and there’s an amazing design technique by Parks and McClellan which lets you basically specify what cutoff frequency you want, and what attenuation you you want above a second (higher) frequency. Then I found this site with an easy to use on-line tool for visualizing it and doing all the calculations:

That’s attenuation on the Y axis vs frequency on the X axis. The gray lines are what I specified as requirement:

And this is the C code it generated for me:

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

sampling frequency: 1000 Hz
fixed point precision: 16 bits

* 0 Hz - 50 Hz
gain = 1
desired ripple = 5 dB
actual ripple = n/a
* 100 Hz - 500 Hz
gain = 0
desired attenuation = -50 dB
actual attenuation = n/a
*/

#define FILTER_LENGTH 31

int filter[FILTER_LENGTH] = {
-226,
-328,
-486,
-608,
-628,
-474,
-81,
595,
1565,
2793,
4194,
5646,
7000,
8103,
8825,
9076,
8825,
8103,
7000,
5646,
4194,
2793,
1565,
595,
-81,
-474,
-628,
-608,
-486,
-328,
-226
};
``````

There’s a drawback in that this is no longer a moving average. Now each output of the filter is defined by applying these integer coefficients to each of the past 31 samples. So there’s more computation involved – a quick test tells me that each sample would take 100..200 µs extra (on an ATmega @ 16 MHz).

But the nice part of this is that it might support a lower-power implementation. Instead of running the ADC 531 times @ 7 KHz (with an unknown filter response), I could run the ADC 100 times, clocked on the 1 ms timer interrupt (and sleeping in between), and apply this modified FIR filter to extract a similar peak-to-peak results.

Why low power? Well, running this on batteries is probably not practical, but I might consider running this setup off a very low-power transformer-less supply. After all, the goal of these experiments is to create a simple low-cost sensor, which can then be used for all the major energy consumers in the house. I’m trying to reduce power consumption, not add yet more to it from all these extra AC current sensors!

Note that maybe none of this will be needed – a simple RC filter before the ADC pin, plus an order 7..31 moving average may well be more than sufficient after all.

But it’s good to know that this option is available if needed. And it’s pretty amazing to see how easily such DSP tasks can be solved, even for someone who has never done any digital signal processing before!

1. What kind of transformerless supply do you have in mind? I have used this one: http://www.brighthub.com/engineering/electrical/articles/77929.aspx# in the past, but was told that such a supply is not very efficient, but never measured it actually.

I know that existing power metering devices take upto 0.5W, which is not that much, but I guess the power supply does take the most of this…