Math Problem
Archiver
Posts: 46,084
Hello Group:
I have a math problem. I need calculate the average of
100 values, I have already it storage in the StampMem
the range of this numbers is from 0 to 4095. This
memory bank is actualized every 500 ms so I have to
calculate this average evry time that this numbers are
changed.
Thanks.
ALBERTO.
=====
Alberto Zamora Estrada.
Phone: (506) 220-6736.
Cell: (506) 374-3846.
Fax: (506) 220-8684
Investigaci
I have a math problem. I need calculate the average of
100 values, I have already it storage in the StampMem
the range of this numbers is from 0 to 4095. This
memory bank is actualized every 500 ms so I have to
calculate this average evry time that this numbers are
changed.
Thanks.
ALBERTO.
=====
Alberto Zamora Estrada.
Phone: (506) 220-6736.
Cell: (506) 374-3846.
Fax: (506) 220-8684
Investigaci
Comments
]
You are reading an ADC. After your shiftin command write:
newresult = newresult + result
When you have finished reading the ADC write:
newresult = newresult/100
This assumes you are using a for/next loop to get 100 reading and that the
program assigns the value of ADC readout to "result". Each time the program
cycles through the loop "newresult" will be incremented by the value of
"result" or whatever you variable is. At the very beginning of your program
write:
newresult = 0
Sid
save program memory in any language. I've compared this in doing digital
filtering with PICs.
Dennis
On Fri, 9 Nov 2001, [noparse][[/noparse]iso-8859-1] Alberto Zamora wrote:
> Hello Group:
>
> I have a math problem. I need calculate the average of
> 100 values, I have already it storage in the StampMem
> the range of this numbers is from 0 to 4095. This
> memory bank is actualized every 500 ms so I have to
> calculate this average evry time that this numbers are
> changed.
>
> Thanks.
>
> ALBERTO.
>
> =====
> Alberto Zamora Estrada.
> Phone: (506) 220-6736.
> Cell: (506) 374-3846.
> Fax: (506) 220-8684
> Investigaci
the memory is FIFO so if I want get the average of the
all history should I do:
average=(average*100+result)/101
the next will be:
average=(average*101+result)/102
I only need get the average of the 100 values that
there are in the memory in every moment.
--- Newzed@a... escribi
>Hi alberto,
>
>Regarding the FIFO,
>
> >The problem is that the program to storage the data to
> >the memory is FIFO so if I want get the average of the
> >all history should I do:
> >
> >average=(average*100+result)/101
> >
> >the next will be:
> >
> >average=(average*101+result)/102
>
>If you cannot rewrite your storage code to reflect a LILO structure
>the following could be used without tracking N0
>
>Instead of summarizing 100 results you could use the following:
>(N? are reading results)
>
>Avg = ( ((N0+N1+..N9)/10) + ((N10+N11+..N19)/10) + ..
>((N90+N91+..N99)/10) )/10
>No overflow can occur this way.
>
>Once you got an average value:
>AvgNew = ( (Avg*10) - (Avg/10) + (N100/10) )/10
>in which N100 is the new reading
>
>This way the latest reading always takes part for 1/100 of the average
>value.
>If your readings do not fluctuate too much the error may be acceptable.
>
>Regards peter
Another approach, very similar to yours Peter, would be to create a
sort of "running average" everytime you read N...
i.e.
Avg = (N + Avg) / 2
^
Previous Avg value
Again Alberto as Peter pointed out you should compare this method
to a true average and determine if your error is acceptable or not.
In a former life we used this exact method I mention above over
hundreds of samples and saw no significant difference using this
method compared to totaling all samples and dividing by the total
number of samples with conventional averaging.
Beau Schwabe IC Mask Designer
National Semiconductor Wired Communications Division
500 Pinnacle Court, Suite 525 Mail Stop GA1 Norcross, GA 30071
If you have a fifo with 100 entries, and you are putting in a new entry, then,
average = (average * 100 - oldest_value + newest_value) / 100
The newest value then replaces the oldest value in the memory.
The above calculation as written will not work on the Stamp, because
(1) the Stamp does not do fractions and (2) the number 409500 is
greater than one word in number of bits.
The best solution I think is to use a double precision accumulator
that can hold values up to 16 million.
acc0 var word ' low word of accumulator
acc1 var word ' high word of accumulator
As Dennis suggested, it is easiest if the number of samples can be a
power of 2, like 64 or 128. But it is not too much more work to do
100.
At the outset, can you fill up all of the cells in memory with a
single starting value?
accumulate: ' subtract oldest value x, add newest value y
acc0 = acc0 - x
acc1 = acc1 - (acc0 max x - acc0 max 1)
acc0 = acc0 + y
acc1 = acc0 max y - y max 1 + acc1
quotient:
' calculate accumulator/100, were acc=acc1:acc0, two words
' quotient q0, one word
q0=acc1//100
q0=(q0*655)+(q0**23593)+(acc0/100)
I think that is right (I got if off my web page), but I don't have
time to recheck it right now.
-- best regards
Tracy Allen
electronically monitored ecosystems
http://www.emesystems.com
mailto:tracy@e...
>The problem is that the program to storage the data to
>the memory is FIFO so if I want get the average of the
>all history should I do:
>
>average=(average*100+result)/101
>
>the next will be:
>
>average=(average*101+result)/102
>
>I only need get the average of the 100 values that
>there are in the memory in every moment.
>
>
> --- Newzed@a... escribi
>Hi Beau,
>
>The formula you gave
>
>Avg = (N + Avg) / 2
>
> ^
> Previous Avg value
>
>Will let the new reading take part for 50/100 in the new average.
>This will lead to greater fluctuations in avg but would progress faster to
>an end value if the readings are constantly progressing upwards or downwards
>(like measuring a triangle waveform).
>
>Regards peter
This method was used for measuring pressure in a "foot-sensor" in efforts
to develop a 'smart' unit that would accommodate or learn a specific way in
which a person walked. So in this case yes, the waveform was somewhat
triangular in nature.
Beau Schwabe Mask Designer IV - ATL
National Semiconductor Wired Communications Division
500 Pinnacle Court, Suite 525 Mail Stop GA1 Norcross, GA 30071
counted, then divide the variable by the counter to get the average.
Original Message
> I have a math problem. I need calculate the average of
> 100 values, I have already it storage in the StampMem
> the range of this numbers is from 0 to 4095. This
> memory bank is actualized every 500 ms so I have to
> calculate this average evry time that this numbers are
> changed.
Instead of summarizing 100 results you could use the following:
(N? are reading results)
Avg = ( ((N0+N1+..N9)/10) + ((N10+N11+..N19)/10) + ..
((N90+N91+..N99)/10) )/10
No overflow can occur this way.
Once you got an average value:
AvgNew = ( (Avg*10) - (N0/10) + (N100/10) )/10
in which N100 is the new reading
You must keep track of the N0 value!
The next reading the current N1 becomes N0 and so on.
Or use 24bit integer math. I am sure Tracy has some routines for that.
Regards peter
Oorspronkelijk bericht
Van: Alberto Zamora [noparse]/noparse]mailto:[url=http://forums.parallaxinc.com/group/basicstamps/post?postID=WvpA9cHgCASl5QMF7NhsSK2ouDdNQ4q_hBKk6fvbXsvMcyXZaOAwoPP7SM7mVUIUArod4vSR14aHKm8]azestrada@y...[/url
Verzonden: vrijdag 9 november 2001 12:39
Aan: basicstamps@yahoogroups.com
Onderwerp: Re: [noparse][[/noparse]basicstamps] Math Problem
The problem is that the program to storage the data to
the memory is FIFO so if I want get the average of the
all history should I do:
average=(average*100+result)/101
the next will be:
average=(average*101+result)/102
I only need get the average of the 100 values that
there are in the memory in every moment.
--- Newzed@a... escribi
following. A running "box car" average has a transfer function with a low
frequency passband. At higher frequencies, it has "side lobes" that can
effectively filter out line voltage ripple (60 Hz, US, or 50 Hz Europe,
Asia), provided that the number of samples averaged, and sampling frequency,
are adjusted so that the ripple frequency is close to the frequency of one
of the deep notches. I use this technique with high input impedance
biological electrodes, and it works well in effectively eliminating any
ripple, with no additional circuitry.
Dennis
Original Message
From: "peter verkaik" <peterverkaik@b...>
To: <basicstamps@yahoogroups.com>
Sent: Saturday, November 10, 2001 12:25 AM
Subject: RE: [noparse][[/noparse]basicstamps] Math Problem
> Hi alberto,
> Tracy wrote:
> >As Dennis suggested, it is easiest if the number of samples can be a
> >power of 2, like 64 or 128. But it is not too much more work to do
> >100.
>
> If the averaging is intended to average an existing ripple on a DC value
> it would be best to use a number of samples that fits a whole number
> of ripple cycles. That way the fluctuations in avg should be minimized.
> So if you have 35 samples per second on a DC voltage with a 120Hz ripple,
> you have 120/35=24/7 ripple cycles per sample or 24 ripple cycles per 7
> samples,
> then you should use a multiple of 7 samples to average, i.e 98 instead of
> 100.
>
> Regards peter
>
>
>
>
> To UNSUBSCRIBE, just send mail to:
> basicstamps-unsubscribe@yahoogroups.com
> from the same email address that you subscribed. Text in the Subject and
Body of the message will be ignored.
>
>
> Your use of Yahoo! Groups is subject to http://docs.yahoo.com/info/terms/
>
>
>
Regarding the FIFO,
>The problem is that the program to storage the data to
>the memory is FIFO so if I want get the average of the
>all history should I do:
>
>average=(average*100+result)/101
>
>the next will be:
>
>average=(average*101+result)/102
If you cannot rewrite your storage code to reflect a LILO structure
the following could be used without tracking N0
Instead of summarizing 100 results you could use the following:
(N? are reading results)
Avg = ( ((N0+N1+..N9)/10) + ((N10+N11+..N19)/10) + ..
((N90+N91+..N99)/10) )/10
No overflow can occur this way.
Once you got an average value:
AvgNew = ( (Avg*10) - (Avg/10) + (N100/10) )/10
in which N100 is the new reading
This way the latest reading always takes part for 1/100 of the average
value.
If your readings do not fluctuate too much the error may be acceptable.
Regards peter
The formula you gave
Avg = (N + Avg) / 2
^
Previous Avg value
Will let the new reading take part for 50/100 in the new average.
This will lead to greater fluctuations in avg but would progress faster to
an end value if the readings are constantly progressing upwards or downwards
(like measuring a triangle waveform).
Regards peter
Tracy wrote:
>As Dennis suggested, it is easiest if the number of samples can be a
>power of 2, like 64 or 128. But it is not too much more work to do
>100.
If the averaging is intended to average an existing ripple on a DC value
it would be best to use a number of samples that fits a whole number
of ripple cycles. That way the fluctuations in avg should be minimized.
So if you have 35 samples per second on a DC voltage with a 120Hz ripple,
you have 120/35=24/7 ripple cycles per sample or 24 ripple cycles per 7
samples,
then you should use a multiple of 7 samples to average, i.e 98 instead of
100.
Regards peter
I think that you have a problem making 100 reads if the individual read
values are greater than 655 since that would be a value greater than the
maximum 16 bits of NEWRESULT. Alberto indicated that he was doing 12 bit
conversions (max value 4096).
Mike
At 02:54 PM 11/9/2001 -0500, you wrote:
>You are reading an ADC. After your shiftin command write:
>newresult = newresult + result
>
>When you have finished reading the ADC write:
>
>newresult = newresult/100
>
>This assumes you are using a for/next loop to get 100 reading and that the
>program assigns the value of ADC readout to "result". Each time the program
>cycles through the loop "newresult" will be incremented by the value of
>"result" or whatever you variable is. At the very beginning of your program
>write:
>
>newresult = 0
>
>Sid
_________________________________
Mike Walsh
walsh@i...
[noparse][[/noparse]Non-text portions of this message have been removed]
> >Avg = (N + Avg) / 2
> >
> > ^
> > Previous Avg value
This is a discrete-time low-pass (smoothing) filter. The filter step
response is (1/2)^k, which reaches 1/e between the 1st and the 2nd
step (1/ln 2=1.44. Filters with longer time constants add up n parts
of the old value with 1 part of the new value. For example,
avg = (avg * 15 + new_value)/16
This has a longer time constant, (15/16)^k, and the response to a
step input reaches 1/e between the 15th and 16th sample time.
On the stamp or on any integer processor, it is not a good idea to
implement the filters exactly as written above. It has annoying
hysteresis. Consider what happens in a by-2 filter, when the current
average value happens to be 10, and the new value takes a jump up to
11. Nothing happens! because in integer math, {(10+11)/2=10}. The
input has to take a jump to 12 before the filter output jumps to 11
{(10+12)/2=11)}. But if the current value happens to be 10 and then
goes down to 9, the output of the filter immediately drops to 9.
{(10+9)/2=9}. The upshot of this asymmetry is that the filter always
tends to underestimate.
The situation is much worse with slower filters. For example, with a
by 4 filter, the input value can jump by 3 without affecting the
output:
10+10+10+10/4=10
11+10+10+10/4=10 ' integer math
12+10+10+10/4=10
13+10+10+10/4=10
14+10+10+10/4=11
but it only has to fall by one for the output to drop immediately:
10+10+10+10/4=10
9+10+10+10/4=9
In practice, that is worthless.
To be useful, the filter has to keep track of fractional parts. On
the Stamp or PIC that means making the accumulator a multiple of the
input value. If the data comes from a 12 bit converter, the best
resolution comes with 16 fractional parts:
The by-2 filter should be initialized at a multiple:
avg = first_value * 16
and the subsequent filtering as:
avg = avg/2 + (new_value * 8)
For example, with an first value of 10:
avg = 160 ' initial value
loop:
gosub getnewvalue 'not shown
avg = avg/2 + (new_value*8)
debug dec avg, tab,dec avg*/160, cr
goto loop
The */160 in the debug statement converts to decimal. When the input
jumps from 10 to 11, here is the sequence of average values with
fractional parts:
160 10.0
168 10.5
172 10.7
174 10.8
175 10.9
175 10.9 ...
or when it drops from 10 to 9:
160 10.0
152 9.5
148 9.2
146 9.1
145 9.0
144 9.0
144 9.0 ...
There are still funny numerical effects that happen in slower
filters, that complicate the algorithm.
-- regards,
Tracy Allen
electronically monitored ecosystems
mailto:tracy@e...
http://www.emesystems.com
> >>Peter wrote:
> >Hi Beau,
> >
> >The formula you gave
> >
> >Avg = (N + Avg) / 2
> >
> > ^
> > Previous Avg value
> >
> >Will let the new reading take part for 50/100 in the new average.
> >This will lead to greater fluctuations in avg but would progress faster to
> >an end value if the readings are constantly progressing upwards or downwards
> >(like measuring a triangle waveform).
> >
> >Regards peter
>
>This method was used for measuring pressure in a "foot-sensor" in efforts
>to develop a 'smart' unit that would accommodate or learn a specific way in
>which a person walked. So in this case yes, the waveform was somewhat
>triangular in nature.
>
>
>Beau Schwabe Mask Designer IV - ATL
>National Semiconductor Wired Communications Division
>500 Pinnacle Court, Suite 525 Mail Stop GA1 Norcross, GA 30071
>
Tracy, thanks for the elaborate explanation.
I checked my formula and it does indeed get stuck at 99 for a 100 input
due to a loss of fractions.
So alberto, here is little adjusted formula
which keeps the ones also
Avg = ( ((N0+N1+..N9)/10) + ((N10+N11+..N19)/10) + ..
((N90+N91+..N99)/10) )/10
No overflow can occur this way.
Once you got an average value: (assuming N0 will be equal to average)
Avgx10 = Avgx10 - (Avgx10/100) + (N100/10)
Avg = (Avgx10+5)/10
in which N100 is the new reading and the 5 is to adjust for rounding errors
This way the latest reading always takes part for 1/100 of the average
value.
If Avgx10=990 and N100=100 then the next Avgx10 will be 991
992,993 till 1000
For Avgx10 is 995..1000 Avg becomes 100
which is indeed the end value for input 100
regards peter
I wasn't in my office so I couldn't check my e-mail
until now, I'll read all the message and look for a
solution to my problem with all your help.
Thanks.
Alberto
--- Tracy Allen <tracy@e...> escribi
If you really thing that is easiest a sample number of
128 I don't see any problems I can change my code to
storage 128 samples.
Please tell me how the code in this case.
Alberto.
--- Tracy Allen <tracy@e...> escribi
>If you really thing that is easiest a sample number of
>128 I don't see any problems I can change my code to
>storage 128 samples.
>Please tell me how the code in this case.
>Alberto.
Hi Alberto,
The easy part is that division by 128 is a simple shift of the bits:
acc1 var byte ' high byte of 24 bit accumulator
acc0 var word ' low word of 24 bit accumulator
result var word
' example acc1:acc0 = 445229, or $6CB2D, or %0110 1100 1011 0010 1101
acc0=52013 ' $CB2D, %1100 1011 0010 1101
acc1=6 ' $6, %0110
' double precision divide by 128 (result fits one word)
result = (acc0>>7)+(acc1<<9)
debug dec result, hex result, bin result,cr
' 3478, $D96, %110110010110
' double precision divide by 100 (result fits one word)
result=(acc1*655)+(acc1**23593)+(acc0/100)
debug dec result, hex result, bin result,cr
' 4452 $1164 %1000101100100
So, you see, either formula will fit on one line.
Your FIFO is implemented in RAM, with pointers, right? For each new
entry you put in, you have to pull the oldest entry out. At each
step the accumulation is found by subtracting the OLD value and
adding the NEW:
acc0 = acc0 - OLD ' subtract oldest entry
acc1 = acc1 - (acc0 max OLD - acc0 max 1) ' high word - borrow
acc0 = acc0 + NEW ' add in newest entry
acc1 = acc1 + (acc0 max NEW - NEW max 1) ' high word + carry
The expressions in parentheses are tricks for the Stamp to get the
borrow and the carry for double precision math.
Then divide the accumulation by 100 (or by 128) to get the resulting
average at each step. (If you need to round off, add 50 before the
divide by 100, or 64 before the divide by 128.)
-- regards,
Tracy Allen
electronically monitored ecosystems
mailto:tracy@e...
http://www.emesystems.com
I undestood, but a important things is that I a
precision minimun of 2 decimals.
Thanks.
Alberto
--- Tracy Allen <tracy@e...> escribi
>I undestood, but a important things is that I a
>precision minimun of 2 decimals.
>Thanks.
>Alberto
Hi Alberto,
You have 12 bits from the A/D converter going in to a double
precision accumulator, and the computation of the average at the
output will also be 12 bits. If you can justify more precision, then
divide the accumulator by 10 instead of 100, and the result will have
one more digit that you can display in tenths, (as 3456.7, por
ejemplo).
Could you give a numerical example of what you are trying to get out of it?
-- regards,
Tracy Allen
electronically monitored ecosystems
mailto:tracy@e...
http://www.emesystems.com
all that, I have to apply a this value a formula that
we had already talked.
Thanks.
Alberto
--- Tracy Allen <tracy@e...> escribi
Can you please explain to me how I would go about performing the following
math problem on a Basic Stamp BS2:
1200 / .03227 = 37186.24 <
this is what i get from my
calculator
Thanks in advance.
Rod
First, let me point out the page at
http://www.al-williams.com/pak1bas.htm which doesn't use your exact
numbers and formula, but it would probably answer your question. You can
also find simple examples for the PAK-I, II, and/or IX at
http://www.al-williams.com/doclib.htm -- remember that PAK-I code will
run on a PAK-II or IX.
Now, to your specific question:
The flip way to answer is to use FConvert to convert the numbers to hex
and then do the division. However, most likely one of the numbers is
from a sensor reading or something so you can't run FConvert on it (this
is the PC program we provide on the PAK disk and you can download it
from our site as well).
I'm going to assume 1200 is coming in from somewhere as an integer and
.03227 is a constant you need. I'm also going to assume you are using
our sample program (which is not actually necessary, but makes things
easier). So you will replace the code between the comments that look
something like:
' Begin Test code; replace with your code
And
' End Test code
The first step is to run FConvert and plug the number .03227 in. It will
tell you that the hex equivalent is: 7A042D8C.
Now your program could look something like this (assuming 1200 is in
variable Z):
Fpx=Z ' 1200 in your example
Gosub floadint ' this does what Fconvert does, but in real time not on
the PC
Fpxhigh=$7A04
Fpxlow=$2D8C
Gosub floady ' now X=1200 and Y=.03227
Gosub Fdiv
Now, you probably want to do something with the result. That's a problem
since the Stamp doesn't really "get" 37186.24.
You can print the answer using something like:
Fpx=5 ' 5 digits
Gosub fdump
You can also use the digit command to pick it out digit by digit. You
can use Fint to get the 24 bit integer answer (and discard the top 8
bits since the Stamp can't really handle 24 bits well).
Another option is to keep the number in the PAK (maybe in a temp
register). For example, suppose you wanted to do something when the
answer exceeded 30000. Instead of reading it back to the Stamp as an
integer, consider this. With the result in X, you could use Fconvert to
find the value for 30000 (8D6A6000).
Then you'd load Y with 30000:
Fpxhigh=$8D6A
Fpxlow=$6000
Gosub FloadY
Now, do a subtraction:
Gosub Fsub
And you could use FGetDigit to learn the sign of the answer. If it is
positive, the answer is >30000. If it is - it is less. You can also
detect 0 (which would be equal). Let's assume we just want greater than:
Fpx=0 ' get sign
Gosub FGetDigit
If Fdigit="+" then UhOh
' answer was <=30000
You can find a reference of all these calls at
http://www.al-williams.com/paklib.htm
The raw commands behind them are documented in the PAK manuals.
Hope that helps. BTW, if you need support, feel free to open a ticket at
http://www.al-williams.com/faqs (click on Submit A FAQ).
Regards,
Al Williams
AWC
*Basic Stamp FAQ: http://www.wd5gnr.com/stampfaq.htm
>
Original Message
> From: Rod [noparse]/noparse]mailto:[url=http://forums.parallaxinc.com/group/basicstamps/post?postID=DKKx8ofMVOue9M0-keDNHT4yaqSfY1XgWgZDtPjxHFh0feePPlxkjCvp6vDj17cnfnocCr7WFR-iQA]rsilvera@s...[/url
> Sent: Monday, September 02, 2002 6:02 AM
> To: basicstamps@yahoogroups.com
> Subject: [noparse][[/noparse]basicstamps] Re:Math problem
>
>
>
>
> Dear Al Williams,
>
>
>
> Can you please explain to me how I would go about performing
> the following math problem on a Basic Stamp BS2:
>
>
>
> 1200 / .03227 = 37186.24 <
this is what i
> get from my
> calculator
>
>
>
>
>
>
>
> Thanks in advance.
>
>
>
> Rod
>
>
>
>
> To UNSUBSCRIBE, just send mail to:
> basicstamps-unsubscribe@yahoogroups.com
> from the same email address that you subscribed. Text in the
> Subject and Body of the message will be ignored.
>
>
> Your use of Yahoo! Groups is subject to
> http://docs.yahoo.com/info/terms/
>
>