Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

ADC Moving Average

Status
Not open for further replies.
Hi,
I am working on a project using Oshon Basic where simple averaging of an ADC voltage is not good enough.

I would appreciate any pointers/code samples on how to program a Moving Average in Basic.
Please, nothing too mathematical !

Thanks

Stewart
 
Why not simple averaging? I want to know more.

I have seen programs where they store the last 100 samples and average all 100. With each new sample they write the new sample over the oldest data. I do not like this because many micro computers I use do not have 100 RAM locations.

I use a formula that acts just like a RC filter on the ADC input pin. Google RC time constant.
Sample=ADC input
Average=the average
64=is how slow the filter is. Can be any number but a binary number like 2,4,8,16,32,...256 is faster because you shift not divide.

Average=Average-(Average-Sample)/64

With each sample you look to see how fare the sample is from the average. (Average-Sample)
Then divide down that difference to a small number. /64
Now subtract that small number from the average.
 
Hi,
I am working on a project using Oshon Basic where simple averaging of an ADC voltage is not good enough.

I would appreciate any pointers/code samples on how to program a Moving Average in Basic.
Please, nothing too mathematical !

Thanks

Stewart

hi Stewart,
If you post your code and say how many samples you want in your ring buffer and data rates I could help with Oshonsoft
 
Hi Eric and Ron,
I have posted my code (the simple bit of it), but it is probably better if I describe what I am trying to fix.

The project uses LED's to show on a map the direction that a beam aerial (antenna) is pointing.
The direction information comes from a potentiometer coupled to the motor that rotates the beam.

The rotator moves the full 360 degrees plus an overrun of 90 degrees giving a total range of 450 degrees.
The voltage from the potentiometer is linear and goes from 0 to +4.5V which represents 450 degrees.

The LED's on the map display are positioned at 5 degree intervals, so there are 360/5 = 72 fitted.
However to cover 450 degrees the LED pattern needs to move 450/5 = 90 steps.

At present the ADC is read and an average of 4 readings is taken, the averaged value is then divided
by 2 to bring it closer to the scaling needed. Fine adjustment is made with a small pot on the ADC input.

The problem is that under certain conditions noise/uncertainty etc will cause the LED pattern to dither
between steps giving the effect of more than one LED on.

Adding simple averaging does not help, although increasing the ADC sample window time does.

It is not possible to keep adding averaging as the operation of the design relies upon POV (persistance
of vision) for beam patterns and LED brightness.

I feel that the moving average is a route worth exploring.

Cheers
Stewart



[CODE
Proc adc () 'read ADC and calculate an average reading
' Rotator feedback range 0 to 4.5V (0 to 450 deg)
' 450 deg = 90 steps of 5 deg
' 4.5v input gives raw ADC value of 230
' No FP so divide by 2 gives 115 and use input trim pot for fine adjustment

adc_temp = 0
For i=0 To 3 'take 4 ADC readings
Adcin 0, raw_adc 'get ADC reading from Ch 0
adc_temp = adc_temp + raw_adc
Next i

adc_value =ShiftRight(adc_temp,2)'shift right 2 places to divide by 4

adc_value = adc_value/2 'No FP so get as close to 90 FSD as possible
'
End Proc
[/CODE]
 
hi Stewart,
Got that OK, will post some OSH Basic fragments for a 4 byte ring buffer.

EDIT:
Run this program, I have used a LCD to show the results.

As I dont know all the details of your project I have to make some guesses as to what the data rates might be, etc.

How and when you call the adc will effect the average, it you post the full code it would be more helpful.
 
Last edited:
I made a small averaging ADC read for a turbo c program on a vortex PC... simple 15 integer (word) array using bubble sort...
Fill the array..
Bubble sort the array.... This will help http://www.codecodex.com/wiki/Bubble_sort#Blitz_BASIC
Select the 7th or 8th elements for the average.

You can increase/ decrease the element size to suit.
 
The problem is really two problems.
1. Averaging. Talked about above.
2. Display. I see you have a LED every 5 degrees. What do you do if the average gives you a number of 2.5 and you have 0 and 5 (no 2.5)?

A. You could turn on both 0 and 5 to indicate 2.5.
B. For a reading of 4 you cold turn LED-5 on bright and LED-0 on dim. (using PWM).
C. You could slow down this process. If you are fast the LEDs will blink. If you choose a slower speed and modulate the brightness of the LEDs your eye will not see flicker.
D. you could speed up the process and let your eye do the averaging. (no average in software) If you can measure the angle and turn on the LED 1000 time a second and LED-5 is on most of the readings but LED-0 is on 10% of the time your eye will see a bright 5 and a dim 0.
E. In the case above where the angle is 2.5 you can build in hysteresis. If LED-0 is on then LED-5 will not light with numbers of 1,2,3, or 4 but will light at 5. Now that LED-5 is on, LED-0 will not light with a 4,3,2 or 1.
 
The problem is really two problems.
1. Averaging. Talked about above.
2. Display. I see you have a LED every 5 degrees. What do you do if the average gives you a number of 2.5 and you have 0 and 5 (no 2.5)?

A. You could turn on both 0 and 5 to indicate 2.5.
B. For a reading of 4 you cold turn LED-5 on bright and LED-0 on dim. (using PWM).
C. You could slow down this process. If you are fast the LEDs will blink. If you choose a slower speed and modulate the brightness of the LEDs your eye will not see flicker.
D. you could speed up the process and let your eye do the averaging. (no average in software) If you can measure the angle and turn on the LED 1000 time a second and LED-5 is on most of the readings but LED-0 is on 10% of the time your eye will see a bright 5 and a dim 0.
E. In the case above where the angle is 2.5 you can build in hysteresis. If LED-0 is on then LED-5 will not light with numbers of 1,2,3, or 4 but will light at 5. Now that LED-5 is on, LED-0 will not light with a 4,3,2 or 1.

Ron, you have got to the core of the problem.

I think that what I really want to do is implement (E).
The action should snap between adjacent LEDS and not involve more than one on at any time whether dimmed or not.

There must be a simple way of implementing this, but all I can think of at present is a look up table.

Cheers
Stewart
 
Angle is 0 to 450 (0 to 360)

If angle(old) is > angle(new)+4 then angle(old)=angle(new)
If angle(old) is < angle(new)-4 then angle(old)=angle(new)
'do nothing if the above is not true, because angle(old) is with in +/-4 of angle(new)

You might have to limit the range to 4 to 450 because this might not work at 0.
 
Many thanks to all for your suggestions. Using a combination of averaging and hysteresis I have now reduced (but not totally removed) the
instability. I had thought that noise pickup on the ADC input might be contributing to the dithering, however using a battery and a pot gives
exactly the same problem. So I will revisit the main code and see if that is where it is happening.

Cheers
Stewart
 
Check you power supply. The VCC should be clean and stable.
You can also try a RC filter on the analog input. 0.1uf and 1k
 
Another possible source of instability is the ADC itself. You want to make sure the series source resistance is not too high (check the datasheet) so it does not impact the RC charge-time of the internal ADC. Also you want to make sure the shunt source resistance is not too low (again check the datasheet) so it does not discharge the internal cap too fast. Finally, part of the proper operation of the ADC has to do with the ADC_CLOCK and ADC_SAMPLEUS. There allowable ranges are found (guess where?) on the datasheet.
 
All up and running in fine form.
Correcting a stupid coding error plus adding some filtering on the rotator supply completely cured the problem.

Many thanks to all those who gave their help...

Cheers
Stewart
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top