Discussion in 'Oshonsoft' started by stewart_bakeruk, Feb 5, 2012.

1. ### stewart_bakerukNew Member

Joined:
Aug 24, 2010
Messages:
31
Likes:
0
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.

Thanks

Stewart

2. ### ronsimpsonWell-Known MemberMost Helpful Member

Joined:
Apr 17, 2007
Messages:
7,254
Likes:
961
Location:
Loveland, CO USA
ONLINE
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.
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.

3. ### ericgibbsWell-Known MemberMost Helpful Member

Joined:
Jan 4, 2007
Messages:
21,187
Likes:
644
Location:
Ex Yorks' Hants UK
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

Joined:
Jan 12, 1997
Messages:
-
Likes:
0

5. ### stewart_bakerukNew Member

Joined:
Aug 24, 2010
Messages:
31
Likes:
0

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
' 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

Next i

adc_value = adc_value/2 'No FP so get as close to 90 FSD as possible
'
End Proc
[/CODE]

6. ### ericgibbsWell-Known MemberMost Helpful Member

Joined:
Jan 4, 2007
Messages:
21,187
Likes:
644
Location:
Ex Yorks' Hants UK
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: Feb 5, 2012

Joined:
Mar 28, 2011
Messages:
9,164
Likes:
910
Location:
Rochdale UK
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.

8. ### ronsimpsonWell-Known MemberMost Helpful Member

Joined:
Apr 17, 2007
Messages:
7,254
Likes:
961
Location:
Loveland, CO USA
ONLINE
The problem is really two problems.
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.

9. ### stewart_bakerukNew Member

Joined:
Aug 24, 2010
Messages:
31
Likes:
0
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

10. ### ronsimpsonWell-Known MemberMost Helpful Member

Joined:
Apr 17, 2007
Messages:
7,254
Likes:
961
Location:
Loveland, CO USA
ONLINE
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.

11. ### stewart_bakerukNew Member

Joined:
Aug 24, 2010
Messages:
31
Likes:
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

12. ### ronsimpsonWell-Known MemberMost Helpful Member

Joined:
Apr 17, 2007
Messages:
7,254
Likes:
961
Location:
Loveland, CO USA
ONLINE
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

13. ### languerActive Member

Joined:
Oct 26, 2010
Messages:
193
Likes:
25
Location:
Arizona
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.

14. ### ronsimpsonWell-Known MemberMost Helpful Member

Joined:
Apr 17, 2007
Messages:
7,254
Likes:
961
Location:
Loveland, CO USA
ONLINE
As Languer said, try using a slower ADC_CLOCK.

15. ### stewart_bakerukNew Member

Joined:
Aug 24, 2010
Messages:
31
Likes:
0
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