Hi guys

Can someone share a simple, basic digital low pass filter in C, it will be good if it can be run in a 8bit AVR. But anything will do.

Thanks a lot.

NOTE:

I have not done any DSP, so please keep it as simple as possible, thank a lot.

Author

Message

Hi guys

Can someone share a simple, basic digital low pass filter in C, it will be good if it can be run in a 8bit AVR. But anything will do.

Thanks a lot.

NOTE:

I have not done any DSP, so please keep it as simple as possible, thank a lot.

Output = (input * coeff) + (Output * (1-coeff))

Is the standard first order IIR filter.

You can see that it basically adds in some of the new with some of the old. Eg if the coeff is 0.25, it gets 25% of the input and adds 75% of the current value thus limiting the rate of change of the output. You can see that the coeff is between 0 and 1. To implement this in a microcontroller you might scale the equation to work with integers rather than floating point and might choose a coeff with a binary weight so that the multiplies become shifts. As for calculating the corner frequency etc, Google should assist.

There are severel threads about different filter types (IIR, FIR), initialization, impulse resonse, calculation / memory demands etc.

Easy? Try this:

uint16_t lowpass(uint16_t input) { static uint16_t lst; uint16_t new = (lst * 4 + input) / 5; lst = new; return new; }

You need to watch out for the limited range for the input. (I leave it to you to check this out.)

In all digital filters, you need to be aware of where the different values come from. For example, in Kartman's example, the Output term is the filter output at the time of the new sample which is the result of the previous input sample.

Also, you need to be aware that virtually all digital filters assume that samples are evenly spaced in time.

When doing the computation for each sample, you also need to be aware of potential internal overflow cases since you sometimes have differences between two larger numbers. The output will look like it is in bounds of the number capacity, but, internally, there are steps that can overflow the number capacity. So, take that into consideration when choosing variable types. Kartman's example is not subject to this (as written) since both coefficients are less than 1.

Jim

// // 'a' has the current rpm, now we filter it to slow down the jitters // if the coeff == 0 then there will be no filter action // if the coeff == 255 then the output will stay at the last input value // in between values will work between these two extremes! ie: increasing // the value increases the filter action (slows the response). // coeff = read_modbus_reg(MB_RPM_FILTER); coeff &=0x00ff; // coeff must be between 0 and 255 rpm_filter = ((rpm_filter * (256-coeff)) + (((unsigned long)a<<8) * coeff))>>8; write_modbus_reg(MB_CURR_RPM,(rpm_filter>>8));

Here's an example of the equation I posted. For integer calculation, the values are scaled by 256 (2^8). The code was to smooth out the reading of a tachometer and the code was run every 50ms (20Hz). The coefficient was adjusted to give the 'best' visual response to the user.

Skotti's example is the same equation, just re-arranged. In his example the coeff is 0.2 (1/5) as he gets 4 times the previous and 1 of the new.

Sampling a microphone?

Note that as a general rule you need to sample at a rate greater than twice the highest frequency component of the input signal.

If you were sampling audio up to 20 kHz, you would need to sample at a rate greater than 40 K Samples/Second.

If you were sampling a continuous sin wave of 10 kHz and you wanted to then feed it back out a DAC, (reconstruct the original signal), you would have to sample at > 20 kS/Sec.

If you were to sample at exactly 20 kS/Sec you could have your samples hit at each zero crossing of the signal, and the output would be 0 V, a flat line.

If you were making a poor-man's O'scope, and displaying the input signal on a small Graphics LCD, for example, sampling at significantly higher than twice the input signal gives a nicer looking waveform. Would you rather look at a sin wave made up of 3 dots per period, or a 100 dots / period?

An extension of this concept is that one generally puts a physical, real world, RC, LPF in the analog input signal chain before the ADC. One wants to remove any high frequency components which are outside of one's bandwidth of interest, before the signal is sampled. If there are any high freq components in the signal that have a frequency greater than or equal to 1/2 the sampling frequency they will alias down into the lower frequency portion of the signal. i.e. A high freq component will appear as a low freq component, distorting your signal, (adding "noise" to the signal).

So, add a filter to the input of your ADC. Then sample at greater than twice the cutoff frequency of the input filter, or higher.

There is lots of good info out there, but it can be a little intimidating when one looks at the math underlying the principles.

Wiki Shannon-Nyquist Sampling Theorem and Wiki Nyquist Frequency might be of interest, and contain a number of associated links.

JC

Kartman and skotti:

Thank you for giving me an basic introduction, that what I need.

ka7ehk, Kartman and DocJC:

Thanks again, for giving me some practical advice, those extra info is really useful and saving making a few mistakes a long the way.

DocJC:

Thanks for your links, I will properly need to look around the topics you linked in, as I am not good at getting the info out of wiki. (I should improve my English :)

So if I want to filter the data from a digital accelerometer, should I do this:

Quote:

//take 10 sample at fix interval and put them in data[10]

//run it thought a filter one by one

//take the last of the 10 as output

Note: my device with the accelerometer is stationary

Take each sample and put it through the filter at constant rate.

Your digital filter might use data for the current value, V(n); the preceding value, V(n-1); the value before that one, V(n-2); and the one before that, V(n-3).

Initially all values are 0.

The present value depends upon the present input and the recent preceding values.

Every time you take a new sample you feed it through the filter equation and out comes the filtered value.

You can certainly store the incoming values in a small array, but you process the data each time you take a new reading.

You could take several readings, average them, and take that as the reading you feed into the filter algorithm. That is conceptually easy to understand as two different, sequential, data processing blocks. It may not be necessary, but is doable.

If you were to take several samples and average them to get the sample value you feed into the digital filter then use 8 samples, not 10, for the average.

You can then rotate the data instead of doing a classic divide and it is faster. (Rotate one place = divide by 2, rotate two places = divide by 4...)

If you do a classic data averaging before sending the data to the IIR or FIR filter algorithm you can probably get away with a lower order filter, as you have already removed some of the noise from the signal.

JC

Initially all values are 0.

The present value depends upon the present input and the recent preceding values.

Every time you take a new sample you feed it through the filter equation and out comes the filtered value.

You can certainly store the incoming values in a small array, but you process the data each time you take a new reading.

You could take several readings, average them, and take that as the reading you feed into the filter algorithm. That is conceptually easy to understand as two different, sequential, data processing blocks. It may not be necessary, but is doable.

If you were to take several samples and average them to get the sample value you feed into the digital filter then use 8 samples, not 10, for the average.

You can then rotate the data instead of doing a classic divide and it is faster. (Rotate one place = divide by 2, rotate two places = divide by 4...)

If you do a classic data averaging before sending the data to the IIR or FIR filter algorithm you can probably get away with a lower order filter, as you have already removed some of the noise from the signal.

JC

Hi DocJC

Thank you for taking the time to explain it, I surely understand it better now. I think your suggestion of averaging it before feeding it to the filter should be good enough for my application.

And thank you for showing me I should take 8 samples instead of 10, this is a good tips :)

I know I can divide something by 2 by right shift 1 bit etc, but I never thought of using this to speed up my code.

Thanks a lot.

Initially all values are 0.

The present value depends upon the present input and the recent preceding values.

Every time you take a new sample you feed it through the filter equation and out comes the filtered value.

You can certainly store the incoming values in a small array, but you process the data each time you take a new reading.

You could take several readings, average them, and take that as the reading you feed into the filter algorithm. That is conceptually easy to understand as two different, sequential, data processing blocks. It may not be necessary, but is doable.

If you were to take several samples and average them to get the sample value you feed into the digital filter then use 8 samples, not 10, for the average.

You can then rotate the data instead of doing a classic divide and it is faster. (Rotate one place = divide by 2, rotate two places = divide by 4...)

If you do a classic data averaging before sending the data to the IIR or FIR filter algorithm you can probably get away with a lower order filter, as you have already removed some of the noise from the signal.

JC

Hi DocJC

Thank you for taking the time to explain it, I surely understand it better now. I think your suggestion of averaging it before feeding it to the filter should be good enough for my application.

And thank you for showing me I should take 8 samples instead of 10, this is a good tips :)

I know I can divide something by 2 by right shift 1 bit etc, but I never thought of using this to speed up my code.

Thanks a lot.

I am from The Island of Hobbit, but I was born in PRC, if you have to know.

Wu,

I thought that the Hobbit movies were filmed on the south island.

Cheers,

Ross

I am not sure actually, but I think you are right. I am more interested in electronic than movies :)

Thanks!

As far as I know, the electronics industry in the Island of Hobbit is pretty limited, it's a country there are more sheep than human :shock: