Shop OBEX P1 Docs P2 Docs Learn Events
Calculating a moving average — Parallax Forums

Calculating a moving average

brucehbruceh Posts: 5
edited 2008-05-12 14:58 in BASIC Stamp
I am using the BS2 to drive a robotic servo using a potentiometer as an input (pretty much using techniques documented by Parallax). Everything works fine except that kids are the source of rotation for the potentiometer. Their imput is jerky, causing the servo to be subjected to rapid acceleration and quick reversals. This is terrorizing the gear train connected to the servo and is causing the spline on the·servo shaft to loosen.

My fix for this would be to calculate a moving average of the last x pot readings and use·this as the input to the servo pulse generation routine. This would create a damping or·shock absorber effect.·(The application doesn't require absolute accurate tracking.)

It seems to me that an array of the previous x readings would be a starting point for the summation, however, I don't see·a way to shift the readings placing the newest reading in the array and sending the oldest reading to the bit bucket each time through the loop.

Anyone solved this problem?

Comments

  • Mike GreenMike Green Posts: 23,101
    edited 2008-05-08 19:29
    You shouldn't need too many readings to smooth out this movement. Maybe 4 or 5 readings will be enough. In that case, just using simple variables would work, say avg1, avg2, avg3, avg4. The newest is avg1 and the oldest is avg4. To shift the values, just do "avg4 = avg3", "avg3 = avg2", "avg2 = avg1", then get the newest value "avg1 = ???".
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2008-05-08 19:38
    Assuming that NewReading is less than 8192, you could also use a running average, computed as follows:

    AvgReading = AvgReading * 7 + NewReading >> 3
    
    
    


    This should give you adequate smoothing. If not, multiply by 15 and shift by 4 instead. In that case NewReading would have to be less than 4096.

    -Phil
  • brucehbruceh Posts: 5
    edited 2008-05-08 22:14
    Thanks guys, I'll try both of these methods.
  • Tracy AllenTracy Allen Posts: 6,666
    edited 2008-05-08 23:10
    Another way to do the low-pass filter takes advantage of the ** operator:

    ' enter with x = new reading, less than 8192.
    IF firstLoop THEN   ' initialize the accumulator
      accum = x * 8   ' accumulator operates at 8 * x.
    ELSE
      accum = accum ** 57345 + x   '   57345 = 65536 * 7/8 + 1
    ENDIF
      x = accum / 8  ' this is the filter output
    



    --Running the accumulator at 8 times the data input allows it to track small changes smoothly.

    --Most filters or averaging schemes do require initialization in order to fill up the pipeline and produce "good" values right away.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Tracy Allen
    www.emesystems.com
  • Chris SavageChris Savage Parallax Engineering Posts: 14,406
    edited 2008-05-12 14:58
    I’ve done like Phil and used a running average, although for simplicity I usually just use a simple add then divide by two scheme. You still have to observe max limits for the variable based on the sum of the max possible values.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Chris Savage
    Parallax Tech Support
Sign In or Register to comment.