# Unwanted ringing in low-pass Butterworth filter.

#### jasonc

##### New member
I am reading some noisy data from external sensors and trying to smooth it out. I know very little about discrete filters. When looking at my data in my plotting program (kst), I applied a low-pass filter and it looked great so I tried to implement a similar filter in my own software. In the plotter program, it was described as a "zero phase low-pass filter with a butterworth amplitude response", I set order to 4 and cutoff frequency to 0.005 (as a fraction of the sample rate - my sample rate is 189 Hz so this works out to about 1Hz - my noise is roughly 6Hz).

I searched around the internet for Butterworth filter calculators and found Butterworth / Bessel / Chebyshev Filters. I entered the following parameters:

• Type: Butterworth
• Order: 4
• Sample Rate: 189
• Corner Frequency: 1

It generated the following coefficients and function (C++):

Code:
[COLOR=#000080]#define [/COLOR]GAIN [COLOR=#000080]1.367579855e+07[/COLOR]

[COLOR=#808000]float [/COLOR][COLOR=#800080]LowPass[/COLOR][COLOR=#000000]::[/COLOR]next [COLOR=#000000]([/COLOR][COLOR=#808000]float [/COLOR][COLOR=#000000]value[/COLOR][COLOR=#000000]) [/COLOR][COLOR=#000000]{[/COLOR]

[COLOR=#800000]  xv[/COLOR][COLOR=#000000][[/COLOR][COLOR=#000080]0[/COLOR][COLOR=#000000]] [/COLOR][COLOR=#000000]= [/COLOR][COLOR=#800000]xv[/COLOR][COLOR=#000000][[/COLOR][COLOR=#000080]1[/COLOR][COLOR=#000000]];[/COLOR]
[COLOR=#800000]  xv[/COLOR][COLOR=#000000][[/COLOR][COLOR=#000080]1[/COLOR][COLOR=#000000]] [/COLOR][COLOR=#000000]= [/COLOR][COLOR=#800000]xv[/COLOR][COLOR=#000000][[/COLOR][COLOR=#000080]2[/COLOR][COLOR=#000000]];[/COLOR]
[COLOR=#800000]  xv[/COLOR][COLOR=#000000][[/COLOR][COLOR=#000080]2[/COLOR][COLOR=#000000]] [/COLOR][COLOR=#000000]= [/COLOR][COLOR=#800000]xv[/COLOR][COLOR=#000000][[/COLOR][COLOR=#000080]3[/COLOR][COLOR=#000000]];[/COLOR]
[COLOR=#800000]  xv[/COLOR][COLOR=#000000][[/COLOR][COLOR=#000080]3[/COLOR][COLOR=#000000]] [/COLOR][COLOR=#000000]= [/COLOR][COLOR=#800000]xv[/COLOR][COLOR=#000000][[/COLOR][COLOR=#000080]4[/COLOR][COLOR=#000000]];[/COLOR]
[COLOR=#800000]  xv[/COLOR][COLOR=#000000][[/COLOR][COLOR=#000080]4[/COLOR][COLOR=#000000]] [/COLOR][COLOR=#000000]= [/COLOR][COLOR=#000000]value[/COLOR][COLOR=#000000]/[/COLOR]GAIN[COLOR=#000000];[/COLOR]

[COLOR=#800000]  yv[/COLOR][COLOR=#000000][[/COLOR][COLOR=#000080]0[/COLOR][COLOR=#000000]] [/COLOR][COLOR=#000000]= [/COLOR][COLOR=#800000]yv[/COLOR][COLOR=#000000][[/COLOR][COLOR=#000080]1[/COLOR][COLOR=#000000]];[/COLOR]
[COLOR=#800000]  yv[/COLOR][COLOR=#000000][[/COLOR][COLOR=#000080]1[/COLOR][COLOR=#000000]] [/COLOR][COLOR=#000000]= [/COLOR][COLOR=#800000]yv[/COLOR][COLOR=#000000][[/COLOR][COLOR=#000080]2[/COLOR][COLOR=#000000]];[/COLOR]
[COLOR=#800000]  yv[/COLOR][COLOR=#000000][[/COLOR][COLOR=#000080]2[/COLOR][COLOR=#000000]] [/COLOR][COLOR=#000000]= [/COLOR][COLOR=#800000]yv[/COLOR][COLOR=#000000][[/COLOR][COLOR=#000080]3[/COLOR][COLOR=#000000]];[/COLOR]
[COLOR=#800000]  yv[/COLOR][COLOR=#000000][[/COLOR][COLOR=#000080]3[/COLOR][COLOR=#000000]] [/COLOR][COLOR=#000000]= [/COLOR][COLOR=#800000]yv[/COLOR][COLOR=#000000][[/COLOR][COLOR=#000080]4[/COLOR][COLOR=#000000]];[/COLOR]
[COLOR=#800000]  yv[/COLOR][COLOR=#000000][[/COLOR][COLOR=#000080]4[/COLOR][COLOR=#000000]] [/COLOR][COLOR=#000000]= [/COLOR][COLOR=#000000]([/COLOR][COLOR=#800000]xv[/COLOR][COLOR=#000000][[/COLOR][COLOR=#000080]0[/COLOR][COLOR=#000000]] [/COLOR][COLOR=#000000]+ [/COLOR][COLOR=#800000]xv[/COLOR][COLOR=#000000][[/COLOR][COLOR=#000080]4[/COLOR][COLOR=#000000]]) [/COLOR][COLOR=#000000]+ [/COLOR][COLOR=#000080]4 [/COLOR][COLOR=#000000]* [/COLOR][COLOR=#000000]([/COLOR][COLOR=#800000]xv[/COLOR][COLOR=#000000][[/COLOR][COLOR=#000080]1[/COLOR][COLOR=#000000]] [/COLOR][COLOR=#000000]+ [/COLOR][COLOR=#800000]xv[/COLOR][COLOR=#000000][[/COLOR][COLOR=#000080]3[/COLOR][COLOR=#000000]]) [/COLOR][COLOR=#000000]+ [/COLOR][COLOR=#000080]6 [/COLOR][COLOR=#000000]* [/COLOR][COLOR=#800000]xv[/COLOR][COLOR=#000000][[/COLOR][COLOR=#000080]2[/COLOR][COLOR=#000000]][/COLOR]
[COLOR=#000000]         + [/COLOR][COLOR=#000000]([/COLOR][COLOR=#000000]-[/COLOR][COLOR=#000080]0.9167904003[/COLOR][COLOR=#000000]*[/COLOR][COLOR=#800000]yv[/COLOR][COLOR=#000000][[/COLOR][COLOR=#000080]0[/COLOR][COLOR=#000000]]) [/COLOR][COLOR=#000000]+ [/COLOR][COLOR=#000000]([/COLOR][COLOR=#000080]3.7468029782[/COLOR][COLOR=#000000]*[/COLOR][COLOR=#800000]yv[/COLOR][COLOR=#000000][[/COLOR][COLOR=#000080]1[/COLOR][COLOR=#000000]])[/COLOR]
[COLOR=#000000]         + [/COLOR][COLOR=#000000]([/COLOR][COLOR=#000000]-[/COLOR][COLOR=#000080]5.7431439716[/COLOR][COLOR=#000000]*[/COLOR][COLOR=#800000]yv[/COLOR][COLOR=#000000][[/COLOR][COLOR=#000080]2[/COLOR][COLOR=#000000]]) [/COLOR][COLOR=#000000]+ [/COLOR][COLOR=#000000]([/COLOR][COLOR=#000080]3.9131302238[/COLOR][COLOR=#000000]*[/COLOR][COLOR=#800000]yv[/COLOR][COLOR=#000000][[/COLOR][COLOR=#000080]3[/COLOR][COLOR=#000000]]);[/COLOR]

[COLOR=#808000]  return [/COLOR][COLOR=#800000]yv[/COLOR][COLOR=#000000][[/COLOR][COLOR=#000080]4[/COLOR][COLOR=#000000]];[/COLOR]

[COLOR=#000000]}[/COLOR]

Where xv and yv are both float[5] arrays initially filled with 0's. The results are not ideal. There is a ringing at approximately 0.91 Hz. Here is what it looks like:

The block in the center is the original data with the filter turned off. The left and right portions are the filtered data. The filtered lines should be relatively flat, but instead there is a ~0.91Hz sine-shaped ringing. The ringing is constant amplitude, it does not seem to depend on the data and it does not diminish over time (at least as far as I can tell). Is something wrong with my filter design/implementation? Is Butterworth not the best type of filter to use here? Why does the plotter's built-in filter (not shown above) work so well when mine doesn't?

Thanks!
J

Last edited:

#### jasonc

##### New member
I figured it out. Seems it was just a precision problem. I switched to doubles instead of floats and the results are much smoother.

#### chisigma

##### Well-known member
... I entered the following parameters:

• Type: Butterworth
• Order: 4
• Sample Rate: 189
• Corner Frequency: 1

...the results are not ideal. There is a ringing at approximately 0.91 Hz. Here is what it looks like:

The block in the center is the original data with the filter turned off. The left and right portions are the filtered data. The filtered lines should be relatively flat, but instead there is a ~0.91Hz sine-shaped ringing. The ringing is constant amplitude, it does not seem to depend on the data and it does not diminish over time (at least as far as I can tell). Is something wrong with my filter design/implementation? Is Butterworth not the best type of filter to use here? Why does the plotter's built-in filter (not shown above) work so well when mine doesn't?...

It seems You have set as corner frequency 1 Hz and the ringing has a frequency about .91 Hz that is inside the pass band of the filter...

Kind regards

$\chi$ $\sigma$

#### Jameson

Staff member
I figured it out. Seems it was just a precision problem. I switched to doubles instead of floats and the results are much smoother.
Welcome to MHB and thanks for posting this! Even if you figured it out this problem can help others in the future.

#### Ackbach

##### Indicium Physicus
Staff member
Usually, the best techniques for smoothing out data is in hardware. If you examine the entire DAQ chain from transducer to computer, the closer to the transducer you get rid of the noise, the better.

You might try the following:

1. Making $\pm$ pairs of wires go through the same holes in metal boxes, not separate holes. This is especially good for any power wires, shielded or not.
2. Shielding signal wires. The shield should be grounded on one end only.
3. Twisting wires can help some, though this is probably easier on signal wires than power wires.
4. Separating DC from AC wires physically.
5. Sometimes a simple RC filter can do wonders. You say your noise is in the 6Hz range. Have you slapped an oscilloscope on your signals to make sure of this? In what frequency range is your desired signal?

#### jasonc

##### New member

The fundamental problem here is that I'm a software guy, not a hardware guy. I have only basic working knowledge of electronics and I had to get this working quick and dirty.

I have a device that has four PWMed outputs that normally drive LEDs but I am using the outputs to control software instead, so I have to filter the PWM output. I'm reading the outputs with an Arduino and I can only sample the four lines at 189 Hz. I do not know what the PWM frequency is, and I unfortunately don't own a scope. The PWMing and aliasing are the sources of the "noise" more so than line or other hardware noise.

With little knowledge of hardware, I just went for a software filter instead. I do a 380-sample running average (~2 seconds, which is fine because the sensor values change very slowly), then I apply the Butterworth filter to that to smooth it out. Eyeballing the sampled values shows a roughly 6 Hz variation in the running average (corresponding to heavy aliasing artifacts from the PWM sampling). On the post-ADC side, it all looks like this:

(Higher res: http://img442.imageshack.us/img442/2426/sensorr.png)

The PWM signal is in the background, the running average is the middle-colored one, and the filtered signal (after fixing my precision problem) is the darkest (with some latency, which I also don't care about - although I don't pretend to understand why the low pass filter added a full 0.5 second offset).

That said, I still have a few undesired digital filter artifacts, and I'd prefer a hardware solution so that I don't have to reimplement the filtering if I use this device in other pieces of software.

So based on your advice, I'm going to get my project working with my current software filter, then revisit it and try and do it in hardware. I'll be starting here: http://www.proaxis.com/~wagnerj/PWMfil/PWM Filters.pdf and I'll see how far I get. I have a friend with a scope and as soon as I have access to it I'll check it out.

Thanks again!
J

Last edited:

#### Ackbach

##### Indicium Physicus
Staff member
Well, I could be wrong, but I don't think you can fix aliasing in software. The problem with aliasing is in your DAQ rate - once the data is in your computer, the damage is done. I think you're simply going to have to slap a scope on your data, and see exactly what you've got. Find out what frequency range your signal is in, and then get your sampling rate to be at least 10 times that (realistically; the Nyquist frequency is a minimal sampling frequency. You really need to be a lot better than Nyquist to get decent data). You also need to know exactly what the frequency range is for your noise. Once you know that, you can apply a precisely-tuned hardware filter that gets rid of your noise nicely.

Is this for a school project, or for work?

#### jasonc

##### New member
It's for a personal project. The signals that I'm dealing with here come from the red, green, blue, and white LED channels of a hacked prototype board from one of these: http://www.mind-lamp.com/.

The software filtered results actually don't look half bad, they match what I see on the on-board LEDs quite closely, but I'm definitely going to go back later and try and improve it with a hardware filter like you say, also it will be a good electronics learning project for me. The software filter only really works because of the huge running average window, which I can get away with because I know the sensor changes slowly - but it sounds like a hardware filter would give me smooth results with a much faster response time (I hope) and would definitely be more ideal. Still, I'm happy that I was just able to figure out how to use a relay to control power to the sensor board...

Thanks again!
J

P.S. Here is four channels of data over 10 minutes (the values hold for a while, then transition, hold, transition, etc.), averaged, filtered, with range and gamma correction, could certainly be smoother, but not too bad, right?

Last edited:

#### Ackbach

##### Indicium Physicus
Staff member
A running average filter can do some things, but it is limited. I've had limited success with it. I'm glad you've got good enough data for now. I'd definitely recommend the hardware filter, and taking the steps I've given above. That should help a lot more.

Cheers.

#### CaptainBlack

##### Well-known member
Use the filter design tool here now look at the impulse and step response on the output page, you will see that you have a near 1-s lag which is a consequence of using an essentially analog design method of specified order and ripple charateristics.

(in digital filtering we often prefer linear phase as it is distortion free, at the cost pf a pure time delay which is not really a disadvantage)

Using proper digital design methods for a FIR filter you can get the delay down to half the number of signal taps used (in samples), but either the number of signal taps or the in band and out of band ripple will rise.

CB

Last edited:

#### chisigma

##### Well-known member
... using proper digital design methods for a FIR filter you can get the delay down to half the number of signal taps used (in samples), but either the number of signal taps or the in band and out of band ripple will rise...

CB
A FIR [Finite Impulse Response] digital filter has pulse response in z domain ...

$\displaystyle H(z)= \sum_{k=0}^{K-1} h_{k}\ z^{-k}$ (1)

... so that is an 'only zeroes' transfer function. K is the number of coefficients $h_{k}$. In time domain if we indicate with $x_{n}$ the iuput sequence and with $y_{n}$ the output sequence is ...

$\displaystyle y_{n}= \sum_{k=0}^{K-1} h_{k}\ x_{n-k}$ (2)

A FIR filter has linear phase only if for all k is $h_{k}=h_{K-1-k}$ [simmetrical pulse response] or $h_{k}=-h_{K-1-k}$ [antisimmetrical pulse response]. In both cases the time delay [in sample times T] is $\displaystyle \tau= \frac{K-1}{2}\ T$...

Kind regards

$\chi$ $\sigma$

#### jasonc

##### New member
A running average filter can do some things, but it is limited. I've had limited success with it. I'm glad you've got good enough data for now. I'd definitely recommend the hardware filter, and taking the steps I've given above. That should help a lot more.
I spent a ton of time learning about electronics and filter design in the last few days, and switched over to an active 2nd-order hardware filter, and IT'S AMAZING. The response time is SO much better. My hardware filter isn't quite perfect (not bad for my first electronics project but definitely has mistakes), so I still am doing a small amount of software filtering on the signal (a 75-sample raised cosine 1Hz low pass), but don't need the running average filter any more, and the measured values are much more stable and transitions are very crisp, and there's no more Butterworth overshoot on hard transitions.

Awesome, thanks again guys!

J