Averaging or smoothing ADC values - Page 1
Forum section: electronics / beginners

author: yashrk
author_rank: Frequent Contributor
timestamp: March 13, 2015, 04:32:05 pm
content: Hello Guys,I was using a PIC16F877A for reading adc value using MikroC from motor which gives me the idea of motor rpm. It gives voltages in 35v range so I used voltage divider for getting values between 0 to 5v but problem is that its very fluctuating i want to get a stable value, I know I should be doing averaging but i am not sure how to do it.

author: suicidaleggroll
author_rank: Super Contributor
timestamp: March 13, 2015, 04:51:25 pm
content: Put a big capacitor between the ADC input and ground (in parallel with the lower half of your voltage divider). You can use the resistor values from the voltage divider to calculate the RC time constant to determine how big the cap needs to be to give you adequate smoothing. You can also sample the ADC more rapidly and average the readings, provided the resistors you used in your divider aren't too big.What size resistors did you use in the divider anyway?

author: Seekonk
author_rank: Super Contributor
timestamp: March 13, 2015, 04:59:15 pm
content: Running average. This yields 10 times the raw data value.M = M - M/10M = M + rawdata

author: Bassman59
author_rank: Super Contributor
timestamp: March 13, 2015, 06:36:05 pm
content: Quote from: Seekonk on March 13, 2015, 04:59:15 pmThis.

author: janekm
author_rank: Unknown
timestamp: March 13, 2015, 07:19:08 pm
content: It is likely that what you are measuring from the motor is not a simple voltage representing the speed of the motor (could be a pulse per turn of the motor or many other things depending on the feedback design). Ideally you would hook it up to an oscilloscope to see what's going on. If you don't have access to one, try recording a set of readings from the ADC and graph them, it may help you to make more sense of what's happening.(or give us some more detail about the type of motor and what type of feedback mechanism is used).

author: macboy
author_rank: Super Contributor
timestamp: March 13, 2015, 07:54:03 pm
content: Quote from: Bassman59 on March 13, 2015, 06:36:05 pmSure, but don't use /10. Use /8 or /16 since that is easily accomplished with a bit shift.Anyway, the problem is likely noise related and I strongly agree with adding a capacitor to give filtering as suggested by others.

author: Alex Eisenhut
author_rank: Super Contributor
timestamp: March 13, 2015, 08:11:26 pm
content: What is this voltage divider you are using, and what equivalent resistance is it presenting the ADC input?The maximum impedance of a voltage source should be 2.5 k? per the datasheet.Also put in some overvoltage protection and transient suppressors, etc. Is this from an electric motor? In a car?

author: hamster_nz
author_rank: Super Contributor
timestamp: March 13, 2015, 09:45:43 pm
content: Hi,First off, you need to condition your ADC input with a low pass filter - an high frequency noise will get aliased to low frequency signals.The running average above "(x = x*0.9 + sample)" isn't that good a filter - the 3db is about 36% of the sample rate. So if you currently sample at 1000Hz, it is a single pole low pass with a -3db about 360Hz.A much better filter would be:Code:int low_pass_filter(int x) {static int samples;static int i = 0;static int total = 0;/* Update the moving average */total += x - samples;samples = x;/* Update the index */i = (i==7 ? 0 : i+1);return total/8}This (if I have coded correctly) gives a low pass filter with a far lower cutoff frequency - running at 1000kHz it brickwalls at 1/8th the sampling frequency, however some higher frequencies sneak through, at about -12db - if you put this through a second filter (with it's own static storage) can knock that down to -24db with little ill effects.So maybe sample at 3x the frequency, pass it through two moving average filters, and then decimate back to what you want. To put real numbers in, if you currently sample at 1kHz, you can sample at 3kHz, and a 8-sample moving average will give a break wall at 375Hz. At most the worst case noise will be reduced to about 6.25% of the original amplitude.And because you are sampling at a higher rate, the input signal only needs to be conditioned to 1.5kHz, not at 0.5 kHz required when sampling slower.

author: MatthewEveritt
author_rank: Unknown
timestamp: March 13, 2015, 09:52:46 pm
content: Shouldn't it beCode:total -= samples - x;so x is added to the total?

author: hamster_nz
author_rank: Super Contributor
timestamp: March 13, 2015, 09:56:56 pm
content: Yeah. ... Brain fade :-) Opps. Fixed it..

author: T3sl4co1l
author_rank: Super Contributor
timestamp: March 13, 2015, 10:40:01 pm
content: The accumulate-and-divide method is a single pole IIR filter.I wouldn't call it a running average; that's usually used to mean a boxcar average, i.e., average the last N samples.The implementation is similarly simple:Y = Y + X - X[n-N]output = Y / NTypically, N is a power of 2, so shifts and aligned memory accesses provide easy optimizations.You will note this is equivalent to:Y = x + x[n-1] + x[n-2] + ... + x[n-N+1]But whereas a general FIR filter requires a multiply and accumulate (MAC) operation per tap, all but the first addition and final subtraction can be optimized out. The remaining cost is, you have to keep track of N samples of X, which means keeping an array. For small values of N (under 4 or 8, say), it's usually cheaper to assign them in a chain (i.e., X[n-4] <= X[n-3]; X[n-3] <= X[n-2]; etc.), but for larger values, the overhead of a circular buffer will be well worth it.Because a "boxcar" window has a sinc(f) frequency response, its filtering ability (aside from at lucky fractions of the sample frequency) is quite poor, and it can be easily beaten by a fairly modest MAC type filter -- while being only slightly harder to write, and to compute (on most MCUs today).The next easiest FIR filter to write is a 1-2-2-1 or 1-3-3-1 design (can be done with addition and subtraction alone), which is comparable to, I think, 6 or 8 taps "boxcar" style, but there aren't really any useful or lucky patterns beyond that.As for the analog side, the general scheme is to smooth the input sufficiently, so that the digital samples don't vary much from sample to sample -- thereby giving some confidence in the continuity of the data series, that you aren't missing information (aliasing!) between samples -- and following that with a complementary digital filter, so that when irregular samples do arrive, they are smoothed into a more realistic approximation of the band-limited signal.If you don't mind the response time, use a big huge R*C time constant. If time is more critical, but you're still feeling cheap, a 2-5 pole active filter (needs 1-2 op-amps) will give reasonable results to a bandwidth within 6-20x below the sample frequency (Fs). Or you can allow through much more analog noise, and filter it down that much more aggressively in the digital domain; the downside is, if the noise frequency happens to become synchronized with the sample frequency or a harmonic, you won't be able to tell if it's an aliasing error, or the true DC offset at work.Tim

author: HackedFridgeMagnet
author_rank: Super Contributor
timestamp: March 13, 2015, 11:20:40 pm
content: Here is a graphical representation of these two different filter types. (pinched from the webhttp://www.slideshare.net/op205/basics-of-digital-filters-presentation)

author: yashrk
author_rank: Frequent Contributor
timestamp: March 14, 2015, 10:01:53 pm
content: Its coming from a small dc motor which is driven by other lager motor which gives voltage according to its rpmI gaved a common ground to the motor and also added a 10uF capNow I will try the code mentionedAnything else should i change or add?

author: Psi
author_rank: Super Contributor
timestamp: March 14, 2015, 10:10:08 pm
content: uint32_t temp = ADCvalue + (AVG * 7); // one part new value, 7 part old valueAVG = (temp >> 3); //divide by 8

author: yashrk
author_rank: Frequent Contributor
timestamp: March 14, 2015, 10:14:07 pm
content: I am using a dc motor which gives atmost 35v out which i run it through a voltage divider from 10k and 1.2k which gives 4v out at 35vI added a 10uF cap (with out calculations) directly on the terminals of the motor now will try to add it to just the lower half n see if it works.