1
$\begingroup$

I want to filter sensor signals for a data acquisition application on an ATmega microcontroller. The interesting parts of the signal are in the range 0-5Hz, and I'd like to leave these mostly unchanged, but strongly attenuate 50Hz power line hum and anything above that.

The signal will later be evaluated in the time domain, especially the time and amplitude of large peaks (typically lasting well over a second), and the area under those peaks.

Since the signal is generated by a different device with its own power supply, I expect to see some power supply hum as well as general noise.

In order to minimize hardware components I plan to use a simple RC filter (-3dB at 18Hz) for antialiasing, combined with a fairly high sample rate (> 1kHz), and then apply digital filtering. The signal will then be sent on to a PC at a much lower sampling rate (probably <10Hz). However, I'm not very experienced with filtering, so I'm a bit overwhelmed with the choices available.

Given the fast sampling rate and very limited CPU power, filters that require many floating point operations would at best be a good deal of work to implement. I played around with filter design tools a bit and looked at the properties of Butterworth and Bessel filters or just chaining several first-order filters in a row (since they can be implemented very efficiently), and finally found an interesting section about the humble "moving average" filter on dspguide.com.

After playing around in Octave a bit, it seems to me that by chaining four moving average filters, two with 1/50s and two with 1/60s window, would give me

  • around 0.5dB attenuation at 5Hz, the outer limit of what might still be interesting signal
  • over 100dB attenuation at both 50Hz and 60Hz, even if the frequency is 1% off
  • over 80dB attenuation for anything above 100Hz
  • linear phase shift in the signal band, for a fixed delay of <40ms

This looks very promising, but since I only started playing with all of this very recently, I'm not completely sure my results are valid. Is this a good filter for my task, or would you recommend something else?

There might also still be noise left in the range of 5Hz to 50Hz which would cause aliasing when the signal is sampled at 10Hz by the PC. Then again, I don't expect to see much noise in that range and don't want to needlessly distort the signal. Should I just send the latest sample, or perhaps take the average of all samples between two "PC sample points"? What would you recommend?

Edit to address Oscar's questions:

I don't think there will be much signal above 5Hz and the SNR should be pretty good without any filtering already, but I'll try recording some examples soon. Different environments and different source equipment for the signal could also look quite different, though.

At the moment, a different device that we use for the same purpose samples the input at only 2Hz without extra filtering after the A/D, but the A/D module in that device seems to filter quite a bit already. Trying to get the requirements, I got the "at most 5Hz" figure from a colleague (though I'm not even sure if he meant samplerate or nyquist frequency), so I adjusted the sample rate up in order to remain consistent.

I'll probably have to handle four channels sampled at 12 bits, and the filtering is the only CPU-intensive task the controller has to perform. The number of cycles per sample is a tradeoff against sample rate (ammount of aliasing) and code maintainability (perform calculations while communicating with the ADC?), but I think 400 cycles would be a pretty good result.

I can't push the full sample rate to the PC, but 100-200sps per channel should be ok.

$\endgroup$
  • $\begingroup$ Will you have any signal left above 5 Hz? In that case you would need to filter that out to be able to downsample to 10 Hz. Considering the limited computational power of the ATmega, why did you chose 10 Hz for the incoming samples to the PC? If you can increase that, it will save you quite a bit of computations in the Atmega. How many cycles can you afford per incoming sample? What type of SNR do you expect for the input signal? How many bits will you sample with? You should probably go for a fixed-point implementation anyway. $\endgroup$ – Oscar Jul 11 '14 at 13:31
  • $\begingroup$ Added the answers to your questions. $\endgroup$ – Medo42 Jul 11 '14 at 15:06
1
$\begingroup$

Is this a good filter for my task, or would you recommend something else?

It might be given that you do not need to get rid of any other noise/signal in that band. The advantage will be the lack of multiplications and therefore most likely fewer cycles in your implementation.

Should I just send the latest sample, or perhaps take the average of all samples between two "PC sample points"?

Taking the average is just like using another moving average filter, so this may or may not be a good idea. It is easily analyzed in a similar way. Given that your signal is "good enough" to downsample, filtering again will, while removing a bit of noise, primarily mess up with the passband.

It is worth noting though that it may be worthwhile to use a so called polyphase decomposition. You do not really want to spend time computing intermediate samples which are not transferred to the PC anyway. Hence, you do in fact have quite a bit more cycles per sample. The straightforward way to go about this to use an (or several) FIR filter. In the case of several compute the convolution of all. Only apply the filter such that it computes exactly the output you want. If you go with this approach you might just as well design a single FIR filter using general multipliers (since the convolution of the moving average filters will have general coefficients anyway).

Assuming you have the signal package for Octave (and that the call is identical to Matlab), you can try something like:

fs=1000
fn = fs/2 % To simplify things
delta = 3 % range in Hz around the power line frequencies, should be less than 5...
eps = 1e-7 % Some small number....
N = 50 % Filter order
W = 10 % How much more you'd like to attenuate the power compared to generic noise

h = firpm(N, [0 5 (50-delta) (50+delta) (50+delta+eps) (60-delta-eps)  (60-delta)  (60+delta) (60+delta+eps) fn]/fn,[1 1 0 0 0 0 0 0 0 0], [1 W 1 W 1])

The lesser you pick delta, the more likely that you will get a notch exactly where you want it...

$\endgroup$
  • $\begingroup$ You do not really want to spend time computing intermediate samples which are not transferred to the PC anyway. Ooooh, now I feel a bit silly because I didn't realize this myself :) $\endgroup$ – Medo42 Jul 11 '14 at 17:02
  • $\begingroup$ I'm not sure if I'll actually end up using this approach, but it is a good recommendation, so have an accept. One remark though, Octave's signal package apparently doesn't implement firpm yet. $\endgroup$ – Medo42 Jul 21 '14 at 10:31
  • $\begingroup$ Actually I'm using the decimating FIR filter idea now, because it appears to have only advantages in my situation. I tried both that and a two-stage moving average, and the FIR takes less RAM, is more general, has shorter code and is actually faster. My current kernel is like a two-stage moving average to get rid of 50Hz and 60Hz, except that a moving average that targets 60Hz would need a length of 16.67 samples - so I profit from the added generality :) $\endgroup$ – Medo42 Jul 23 '14 at 9:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.