Re: Looking for codes to average adc results

Started by Paul James E. February 20, 2004

Sorting and finding the middle number is the median, not the mean.
>
> --- Dave Mucha <> wrote:
>> --- In , "burt0072003" <burt007@i...> wrote:
>> > A 16bit word from externel adc and sample may be 10 times and
>> average
>> > it to get a stable value. Then display the final results on the
>> > character LCD. I know how to control the LCD, I have routines for
>> > that. Only need the code to average a 16 bit word 10 times. The
>> > results from external adc could be stored in 20 ram locations
>> > initialy. These are for pic 16fxx series.
>> > Thanks
>>
>> Op's I just re-read... you have a 16 bit value.
>>
>> Another way to look at the data would be to find the mean value.
>> This requires a SORT of the data and finding the middle number. That
>>
>> would allow you to use only 16 bit math with 16 bit numbers as you
>> are just comparing to see if one is higher than another.
>>
>> Since you are mostly ignoring numbers, a fast way to eleminate the
>> extreems would be to take 10% of each number and sum them. (Still 16
>>
>> bit) and average that number, then multiply by 10. That is a poor
>> average, but with that you can quickly lose the min and max values
>> prior to sorting.
>>
>>
>> I haven't run that process to it's simplicity, but one could take a
>> pass thru all the stored values to get the max and then delete that.
>> take another pass to get the MIN and delete that and just repeat
>> until the extreems have been deleted and you are left with the middle
>>
>> number.
>>
>> Since I'm rambling, one could take the lowest number and find the
>> differences between that and all the others and average those
>> differences and then add that back to the lowest number....
>>
>> Dave
>> (just lost the whole 'simple' thing)
>
> This will give you the median, not the mean.
>
> The answer is, set up a circular buffer of 8 or 16. Add all the
> numbers and save the total. On each sample, subtract the last buffer
> value from the total, replace it in the buffer with the new value, and
> add it to the total. Increment the pointer and shift the total by 3 or
> 4.
>
> Chad > =====
> My software has no bugs. Only undocumented features.
>
> __________________________________ > ------------------------ Yahoo! Groups Sponsor
> ---------------------~--> Buy Ink Cartridges or Refill Kits for your
> HP, Epson, Canon or Lexmark Printer at MyInks.com. Free s/h on orders
> $50 or more to the US & Canada.
> http://www.c1tracking.com/l.asp?cidU11
> http://us.click.yahoo.com/mOAaAA/3exGAA/qnsNAA/dN_tlB/TM
> ---------------------------------~->
>
> to unsubscribe, go to http://www.yahoogroups.com and follow the
> instructions Yahoo! Groups Links >
>


A 16bit word from externel adc and sample may be 10 times and average
it to get a stable value. Then display the final results on the
character LCD. I know how to control the LCD, I have routines for
that. Only need the code to average a 16 bit word 10 times. The
results from external adc could be stored in 20 ram locations
initialy. These are for pic 16fxx series.
Thanks



--- In , "burt0072003" <burt007@i...> wrote:
> A 16bit word from externel adc and sample may be 10 times and
average
> it to get a stable value. Then display the final results on the
> character LCD. I know how to control the LCD, I have routines for
> that. Only need the code to average a 16 bit word 10 times. The
> results from external adc could be stored in 20 ram locations
> initialy. These are for pic 16fxx series.
> Thanks


There are a few ways to handle averaging and retrieving data.

Personally, I preferr to scan the input each cycle. Others like to
get 10 readings at one shot and then average them. ( for loop )

Here is a clue to one way to average.

Assuming you can read your ADC into "RAW" RAW = external ADC value

MID = MID AVG
MID = MID + RAW
AVG = MID / 10 MID is just a holder for the interim calculations.

Initally, MID equals zero and the first read will do nothing unless
you had assigned values.

So, on the first pass, MID minus zero is zero.

Then it adds the RAW ADC input value.
Then divides by 10 to report the average.

Say, your ADC was reading 100

MID(0) = MID (0) - AVG(0) = zero
MID(0) - AVG(0) = zero
MID(0) + 100 = 100
AVG then equals 10 on the first loop

At the end of the first, MID = 100 and AVG = 10
end of second MID = 190, AVG = 19
end of thrid ; MID = 281, AVG = 28

it will take a hundred or so loops to get the average to equal the
input, and the average will lag behind the real value, but this
offers a very simple method using little RAM.

There ARE better ways and there ARE much more accurate and faster
ways, but this is really simple.

Dave
(likes simple)


--- In , "burt0072003" <burt007@i...> wrote:
> A 16bit word from externel adc and sample may be 10 times and
average
> it to get a stable value. Then display the final results on the
> character LCD. I know how to control the LCD, I have routines for
> that. Only need the code to average a 16 bit word 10 times. The
> results from external adc could be stored in 20 ram locations
> initialy. These are for pic 16fxx series.
> Thanks

Op's I just re-read... you have a 16 bit value.

Another way to look at the data would be to find the mean value.
This requires a SORT of the data and finding the middle number. That
would allow you to use only 16 bit math with 16 bit numbers as you
are just comparing to see if one is higher than another.

Since you are mostly ignoring numbers, a fast way to eleminate the
extreems would be to take 10% of each number and sum them. (Still 16
bit) and average that number, then multiply by 10. That is a poor
average, but with that you can quickly lose the min and max values
prior to sorting. I haven't run that process to it's simplicity, but one could take a
pass thru all the stored values to get the max and then delete that.
take another pass to get the MIN and delete that and just repeat
until the extreems have been deleted and you are left with the middle
number.

Since I'm rambling, one could take the lowest number and find the
differences between that and all the others and average those
differences and then add that back to the lowest number....

Dave
(just lost the whole 'simple' thing)



Dave Mucha wrote:
> --- In , "burt0072003" <burt007@i...> wrote:
> > A 16bit word from externel adc and sample may be 10 times and
> average
> > it to get a stable value. Then display the final results on the
> > character LCD. I know how to control the LCD, I have routines for
> > that. Only need the code to average a 16 bit word 10 times. The
> > results from external adc could be stored in 20 ram locations
> > initialy. These are for pic 16fxx series.
> > Thanks > There are a few ways to handle averaging and retrieving data.
>
> Personally, I preferr to scan the input each cycle. Others like to
> get 10 readings at one shot and then average them. ( for loop )
>
> Here is a clue to one way to average.
>
> Assuming you can read your ADC into "RAW" > RAW = external ADC value
>
> MID = MID - AVG
> MID = MID + RAW
> AVG = MID / 10
>
> MID is just a holder for the interim calculations.
>
> Initally, MID equals zero and the first read will do nothing unless
> you had assigned values.
>
> So, on the first pass, MID minus zero is zero.
>
> Then it adds the RAW ADC input value.
> Then divides by 10 to report the average.
>
> Say, your ADC was reading 100
>
> MID(0) = MID (0) - AVG(0) = zero
> MID(0) - AVG(0) = zero
> MID(0) + 100 = 100
> AVG then equals 10 on the first loop
>
> At the end of the first, MID = 100 and AVG = 10
> end of second MID = 190, AVG = 19
> end of thrid ; MID = 281, AVG = 28
>
> it will take a hundred or so loops to get the average to equal the
> input, and the average will lag behind the real value, but this
> offers a very simple method using little RAM.
>
> There ARE better ways and there ARE much more accurate and faster
> ways, but this is really simple.
>
> Dave
> (likes simple)


Instead how about
MID = AVG * 10
MID = MID - AVG
MID = MID + RAW
AVG = MID / 10

which is the same as
AVG = ((AVG * 10 - AVG) + RAW) / 10

which is the same as
AVG = ((AVG * 9) + RAW) / 10

If you substitute 8 in place of 10 your division becomes much simpler
(simply shift right 3 places)

e.g.
AVG = ((AVG * 7) + RAW) >> 3

or 16 in place of 10 (shift right 4 places)

AVG = ((AVG * 15) + RAW) >> 4

If you keep a seperate total you will not need to multiply

AVG_ACC = AVG_ACC - AVG + RAW
AVG = AVG_ACC >> 4

Regards
Sergio Masci

http://www.xcprod.com/titan/XCSB - optimising structured PIC BASIC compiler




--- Dave Mucha <> wrote:
> --- In , "burt0072003" <burt007@i...> wrote:
> > A 16bit word from externel adc and sample may be 10 times and
> average
> > it to get a stable value. Then display the final results on the
> > character LCD. I know how to control the LCD, I have routines for
> > that. Only need the code to average a 16 bit word 10 times. The
> > results from external adc could be stored in 20 ram locations
> > initialy. These are for pic 16fxx series.
> > Thanks
>
> Op's I just re-read... you have a 16 bit value.
>
> Another way to look at the data would be to find the mean value.
> This requires a SORT of the data and finding the middle number. That
>
> would allow you to use only 16 bit math with 16 bit numbers as you
> are just comparing to see if one is higher than another.
>
> Since you are mostly ignoring numbers, a fast way to eleminate the
> extreems would be to take 10% of each number and sum them. (Still 16
>
> bit) and average that number, then multiply by 10. That is a poor
> average, but with that you can quickly lose the min and max values
> prior to sorting. > I haven't run that process to it's simplicity, but one could take a
> pass thru all the stored values to get the max and then delete that.
> take another pass to get the MIN and delete that and just repeat
> until the extreems have been deleted and you are left with the middle
>
> number.
>
> Since I'm rambling, one could take the lowest number and find the
> differences between that and all the others and average those
> differences and then add that back to the lowest number....
>
> Dave
> (just lost the whole 'simple' thing)

This will give you the median, not the mean.

The answer is, set up a circular buffer of 8 or 16. Add all the
numbers and save the total. On each sample, subtract the last buffer
value from the total, replace it in the buffer with the new value, and
add it to the total. Increment the pointer and shift the total by 3 or
4.

Chad =====
My software has no bugs. Only undocumented features.

__________________________________




--- In , Chad Russel <chadrussel@y...> wrote:

> The answer is, set up a circular buffer of 8 or 16. Add all the
> numbers and save the total. On each sample, subtract the last
buffer
> value from the total, replace it in the buffer with the new value,
and
> add it to the total. Increment the pointer and shift the total by
3 or
> 4.

Don't forget to add 4 (if you have 8 values) or 8 (if you have 16
values) before dividing in order to properly round the result. If
you don't your result will always be truncated.

For example, if you had the set {2,2,2,2,2,2,2,1} the sum is 15 and
if you do the shift (15 >> 3) you get 1. However, if you add half
the divisor to the sum before dividing you would get 15 + 4 = 19 and
after dividing (19 >> 3) you get the proper result of 2.

The worst part about this is you must use 24 bit math since you have
16 bit values. But that is not terribly difficult to deal with.

--Scott




----- Original Message -----
From: "Paul James E." <>
To: <>
Cc: <>
Sent: Friday, February 20, 2004 6:24 AM
Subject: Re: [piclist] Re: Looking for codes to average adc results >
> Sorting and finding the middle number is the median, not the mean.

The median can sometimes be more 'meaningful' than the mean; it depends on
how the data are distributed. It is another type of average.

Leon
--
Leon Heller, G1HSM
Email:
My low-cost Philips LPC210x ARM development system:
http://webspace.webring.com/people/jl/leon_heller//lpc2104.html





----- Original Message -----
From: Scott Lee <>
To: <>
Sent: Friday, February 20, 2004 6:13 PM
Subject: [piclist] Re: Looking for codes to average adc results > --- In , Chad Russel <chadrussel@y...> wrote:
>
> > The answer is, set up a circular buffer of 8 or 16. Add all the
> > numbers and save the total. On each sample, subtract the last
> buffer
> > value from the total, replace it in the buffer with the new value,
> and
> > add it to the total. Increment the pointer and shift the total by
> 3 or
> > 4.
>
> Don't forget to add 4 (if you have 8 values) or 8 (if you have 16
> values) before dividing in order to properly round the result. If
> you don't your result will always be truncated.
>
> For example, if you had the set {2,2,2,2,2,2,2,1} the sum is 15 and
> if you do the shift (15 >> 3) you get 1. However, if you add half
> the divisor to the sum before dividing you would get 15 + 4 = 19 and
> after dividing (19 >> 3) you get the proper result of 2.
>
> The worst part about this is you must use 24 bit math since you have
> 16 bit values. But that is not terribly difficult to deal with.
>
> --Scott

Hi Scott,

Actually if it's a 10 bit ADC reading the calculation will fit in a 16 bit
int (10+3, only 3 bits needed for all possible carries since only 7 adds
present with bit 9 possibly set to 1). Regards
Sergio Masci

http://www.xcprod.com/titan/XCSB - optimising structured PIC BASIC compiler



--- In , "sergio masci" <smypl@x> wrote:
>
> ----- Original Message -----
> From: Scott Lee <midl_man@y...>
> To: <>
> Sent: Friday, February 20, 2004 6:13 PM
> Subject: [piclist] Re: Looking for codes to average adc results > > --- In , Chad Russel <chadrussel@y...>
wrote:
> >
> > > The answer is, set up a circular buffer of 8 or 16. Add all
the
> > > numbers and save the total. On each sample, subtract the last
> > buffer
> > > value from the total, replace it in the buffer with the new
value,
> > and
> > > add it to the total. Increment the pointer and shift the total
by
> > 3 or
> > > 4.
> >
> > Don't forget to add 4 (if you have 8 values) or 8 (if you have 16
> > values) before dividing in order to properly round the result. If
> > you don't your result will always be truncated.
> >
> > For example, if you had the set {2,2,2,2,2,2,2,1} the sum is 15
and
> > if you do the shift (15 >> 3) you get 1. However, if you add half
> > the divisor to the sum before dividing you would get 15 + 4 = 19
and
> > after dividing (19 >> 3) you get the proper result of 2.
> >
> > The worst part about this is you must use 24 bit math since you
have
> > 16 bit values. But that is not terribly difficult to deal with.
> >
> > --Scott
>
> Hi Scott,
>
> Actually if it's a 10 bit ADC reading the calculation will fit in a
16 bit
> int (10+3, only 3 bits needed for all possible carries since only 7
adds
> present with bit 9 possibly set to 1).

That would be correct if using the internal DAC but he already stated
he is using an external DAC and getting 16 bit data.