1. 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.
    Dismiss Notice

ADC Moving Average

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

  1. stewart_bakeruk

    stewart_bakeruk New 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.
    Please, nothing too mathematical !

    Thanks

    Stewart
     
  2. ronsimpson

    ronsimpson Well-Known Member Most 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.
    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.
     
  3. ericgibbs

    ericgibbs Well-Known Member Most 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
     
  4. dave

    Dave New Member

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


     
  5. stewart_bakeruk

    stewart_bakeruk New 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
    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]
     
  6. ericgibbs

    ericgibbs Well-Known Member Most 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
  7. Ian Rogers

    Ian Rogers Super Moderator Most Helpful Member

    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. ronsimpson

    ronsimpson Well-Known Member Most Helpful Member

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

    stewart_bakeruk New 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. ronsimpson

    ronsimpson Well-Known Member Most 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_bakeruk

    stewart_bakeruk New 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. ronsimpson

    ronsimpson Well-Known Member Most 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. languer

    languer Active 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. ronsimpson

    ronsimpson Well-Known Member Most 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_bakeruk

    stewart_bakeruk New 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
     

Share This Page