Computing a moving average

Hi there,
I often and manually change the values of a data. In order to make the transitions less abrupt, I would like to have for a short time the average between the last value and the value just before.
If I choose the value 10 and the previous one was 8, I would like to have the value 9 for 0.5 s.
How could I do it?
Big thanks.

Hello,

It will be hard to help you with that little context.
Can you show us some code that you have and explain what is the purpose of it?

1 Like

I agree

Do you bring in new values into an array and dropping an old value?

float current=0; 
int timer = 0; 
....
....

if (millis()-timer > 500) {
    current = ( arr[9] + arr[10] ) / 2; 
    timer = millis(); 
}

Below is a Python Mode example that uses random numbers as data. You can adapt it for Java Mode, and step through an array of data instead, or use some other source, as needed.

The strategy for timing used here is to set a frameRate of 2 frames per second, and test the divisibility of frameCount by some modulus. If the result is 0, get a new value and display the average for one frame (0.5 seconds). During all other frames, display that new value instead of the average. You can change the modulus to change the timing.

# use random integers as data
old, new = floor(random(0, 101)), floor(random(0, 101))
def setup():
    size(240, 100)
    frameRate(2) # 2 frames per second; each frame displays for 0.5 seconds
    textSize(48)
    textAlign(LEFT, CENTER)
    fill(0)
    
def draw():
    global old, new
    background(255)
    if frameCount % 6 == 0: # can change modulus to adjust time of display of new value
        # get new value; display average of old and new values for one frame (0.5 seconds)
        old, new = new, floor(random(0, 101)) # use random integers as data
        text(float(old + new) / 2, 10, height / 2)
    else:
        # display new value whenever frameCount not evenly divisible by modulus
        text(float(new), 10, height / 2)

EDIT (March 30, 2021):

The above assumes that you consider frameCount to be a reliable measure of time. If not, you will obviously need to use another strategy.

The above also has new values becoming available at regular intervals. If, instead, they arrive at unpredictable times, you can maintain a rate of 60 frames per second. Whenever a new value arrives, save the frame number, let’s say, in a variable named eventFrameCount, and get the old and new values into the appropriate variables. During each frame, display the prescribed average if frameCount - eventFrameCount <= 30. Thereafter, display the most recent value during each frame until the next value arrives.

1 Like

What you describe is called easing not moving average these are very different things searching the Processing website for easing pulls up nay useful results.

1 Like

Below is an event-based application of the previous easing strategy.

  • An event is a mouse click within the display window.
  • A value is the x position where the mouse was clicked.
old, new = 0, 0
eventFrameCount = 0
def setup():
    size(256, 200)
    frameRate(60) # 30 frames are 0.5 seconds
    textSize(48)
    textAlign(LEFT, CENTER)
    fill(0)
    
def draw():
    global old, new, eventFrameCount
    background(255)
    # display average of old and new values for 30 frames (0.5 seconds of aging)
    if frameCount -  eventFrameCount <= 30:    # easing phase
        # event occurred; new value was fetched
        text((old + new) / 2, 40, height / 2)
    else:                                      # resting phase
        # display new value after 30 frames (0.5 seconds of aging)
        text(new, 40, height / 2)
        
def mouseClicked():
    # event occurred; fetch a new value 
    global old, new, eventFrameCount
    old, new = new, mouseX # use mouseX as new value
    eventFrameCount = frameCount

EDITED (2x on March 31, 2021) to refine one of the comments in the code, and add the following:

Yeah, here’s a Java Mode example that is worth considering. It eases the transition from old to new values by dividing it into chunks smaller than the one-half the difference that we get from the averaging strategy: Processing > Examples > Easing.

Hello.
Maybe be I should make an other post, but you’ll tell me.
I can have time elapsed between two tap of the key pad a or the keys a and b.
Now I would like to have the average between the two last time elapsed, but my program divide by 2 my last time elapsed, it doesn’t calculate the moving average whereas I worked with the program of demonstration.

Could you help me?

float average=0;
float averageTime = 0;
float sum = 0;
float[] storedValues;
int count = 0;

float current=0; 
int timerA = 0; 
int timerB  =0;



float TimeElapsed=0;

float[] timeElapsed;

void setup()
{
  storedValues = new float[2]; // do the avrage with 2 last datas
  
  timeElapsed = new float[2];
  
  frameRate(5);
  
}

void draw()
{
  calculateTime ();
 // float newValueFromStream = random(10.0);
  
  float newcalculateElapsedTime =  TimeElapsed;
  
 // AddNewValue(newValueFromStream);
  
  AddNewValue (newcalculateElapsedTime);
  
 
  
  if(count > 0)
  {
    averageTime  = sum / count;
   
  }
  
   println("count: " + count + " new value: " + newcalculateElapsedTime + " proper average: " + averageTime );
   timerB=timerA;
}



void AddNewValue(float val)
{
    if(count < storedValues.length)
  {
    //array is not full yet
    storedValues[count++] = val;
    
    sum += val; 
  }
  else
  {
    sum += val; 
    sum -= storedValues[0];
    
    //shift all of the values, drop the first one (oldest) 
    for(int i = 0; i < storedValues.length-1; i++)
    {
      storedValues[i] = storedValues[i+1] ;
    }
    //the add the new one
    storedValues[storedValues.length-1] = val;
  }
}

void keyPressed (){

if (key == 'a') {
  
  timerA= millis();
  
  
 
}
if (key == 'b') {
  
  timerB= millis();
 
}

}

void calculateTime (){

  TimeElapsed= abs ( timerA-timerB);
  
  print ("TimeElapsed : " ); print (TimeElapsed);
  
 } 
  

Blockquote

We need to make sure it is clear to us what events should cause a new value to be stored and what that new value should represent.

What new value should be stored when the a key is pressed? Should it be the time that has elapsed since either a or b was pressed?

What new value should be stored when the b key is pressed? Should it only be the time that has elapsed since a was pressed?

Hi javagar.

Let’s say for today, I would like to have have the time elapsed between the actual key a pressed and the key a pressed just before. This will be the actual time elapsed between two keys A pressed. We name the n for the actual key A and n-1 for the former key A

Then, I would like to compute the moving average between the actual time elapsed between two key A and the former time elapsed made with n-1 and n-2 keys A pressed.

I hope to be explicit. Thank you.

1 Like

Hello,

If I understood correctly, you want a moving average on the 3 last points.

For this, you will need to store the 3 data points somewhere. What you can do is used a simple fixed size array. Then every time you click on the ‘a’ key you store a new value but before you need to shift the last 2.

something like this:

long[] dataPoints= new long[3]; 

...

void keyPressed() {
  ...
  dataPoints[3] = dataPoints[2];
  dataPoints[2] = dataPoints[1];
  dataPoints[1] = elapsedTime;
  ...
}

Now your moving average will be sum(dataPoints(k)) / 3

1 Like

This sketch includes a simple class to calculate the moving average of a variable over a user specified number of values. The code should be self explanatory.

Note:

  • The average is calculated over the number of values available up to the maximum specified in the constructor (in this case 10)
  • The algorithm is of order O(1) which means the time to calculate the average is constant and not dependant on the number of values used to calculate the average.

In this case the variable is the elapsed time between the key ‘a’ being pressed) and the number of readings to average is 10

boolean ready = false;
int prev_time;

void setup() {
  size(200, 200);
}

void draw() {
  background(0);
}

void keyTyped() {
  if (key == 'a') {
    if (!ready) {
      ready = true;
      prev_time = millis();
    } else {
      int curr_time = millis();
      float average = avgTimer.nextValue(curr_time - prev_time);
      prev_time = curr_time;
      println("Avergae time between 'a' key presses = " + average + "ms");
    }
  }
}


MovingAverage avgTimer = new MovingAverage(10);

/**
 * Use  a circular array to store generation step impl. times
 * and calculate a moving average.
 * 
 * Specify the number of values to include in the moving average when
 * using the constructor. 
 * 
 * The implementation time is O(1) i.e. the same whatever the number 
 * of values used it takes the same amount of time to calculate the
 * moving average.
 * 
 * @author Peter Lager 2021
 */
private class MovingAverage {
  private float[] data;
  private float total = 0, average = 0;
  private int idx = 0, n = 0;

  /**
   * For a moving average we must have at least remember the last 
   * two values.
   * @param size the size of the underlying array
   */
  public MovingAverage(int size) {
    data = new float[Math.max(2, size)];
  }

  // Include the next value in the moving average
  public float nextValue(float value) {
    total -= data[idx];
    data[idx] = value;
    total += value;
    idx = ++idx % data.length;
    if (n < data.length) n++;
    average = total / (float)n;
    return average;
  }

  public void reset() {
    for (int i = 0; i < data.length; i++)
      data[i] = 0;
    ;
    total = n = 0;
  }

  public float average() {
    return average;
  }
}
1 Like

Thanks quark!
It works so perfectly!

But now I have a problem that I couldn’t guess before.
Sometimes I stop my program (with noloop) and restart it (with loop.)
I would like as soon as the program restarts with the key ‘:’ and as soon as letter a is triggered, the program calculates the time elapsed between this last key ‘a’ pressed, with the old key ‘a’ pressed: the one triggered before I stopped the program with the key ‘:’
Best regards!

I tried this but it doesn’t work

boolean ready = false;
int startStop; 
int lastMillis;
boolean running;

float LastRecordedAverage;

int curr_time, prev_time;



float average;

void setup() {
  size(400, 400);
}

void draw() {
  background(0);
}

void keyTyped() {
  if (key == 'a') {
    if (!ready) {
      ready = true;
      prev_time = millis();
    } else {
      int curr_time = millis();
      average = avgTimer.nextValue(curr_time - prev_time);
      prev_time = curr_time;
      println("Avergae time between 'a' key presses = " + average + "ms");
      
      LastRecordedAverage=average;
    }
  }
}


void  keyPressed () {
 
  if ((key == '!') ) {  print ("STOP MOVEMENT AND TIMER: ");
           startStop= 0; println ( startStop ); // 0= STOP
 
        
         
           running = false;
        
           noLoop(); 
        
          
           print ("LastRecordeadAverge: "); print (  LastRecordedAverage ) ;
    }
            
     
           else if (key == ':') { // 0= start
    
           startStop= 1;  print ("START MOVEMENT AND TIMER: "); println (startStop );
    
           running = true; // TRIG the TIMER
           
        //   int m = millis(); // useless
        //   lastMillis = m;
       
           loop();
           
    if (key == 'a') {
    if (!ready) {
      ready = true;
      prev_time = millis();
    } else {
      int curr_time = millis();
      average = avgTimer.nextValue(curr_time - prev_time);
      prev_time = curr_time;
      println("Avergae time between 'a' key presses = " + average + "ms");
      
      LastRecordedAverage=average;
    }
  }
         
           
             }       
 }
MovingAverage avgTimer = new MovingAverage(2);

/**
 * Use  a circular array to store generation step impl. times
 * and calculate a moving average.
 * 
 * Specify the number of values to include in the moving average when
 * using the constructor. 
 * 
 * The implementation time is O(1) i.e. the same whatever the number 
 * of values used it takes the same amount of time to calculate the
 * moving average.
 * 
 * @author Peter Lager 2021
 */
private class MovingAverage {
  private float[] data;
  private float total = 0, average = 0;
  private int idx = 0, n = 0;

  /**
   * For a moving average we must have at least remember the last 
   * two values.
   * @param size the size of the underlying array
   */
  public MovingAverage(int size) {
    data = new float[Math.max(2, size)];
  }

  // Include the next value in the moving average
  public float nextValue(float value) {
    total -= data[idx];
    data[idx] = value;
    total += value;
    idx = ++idx % data.length;
    if (n < data.length) n++;
    average = total / (float)n;
    return average;
  }

  public void reset() {
    for (int i = 0; i < data.length; i++)
      data[i] = 0;
    ;
    total = n = 0;
  }

  public float average() {
    return average;
  }
}

It would help if I understood what you use the average time between ‘a’ key presses is used for and why you need a moving average.

Hello,

I try to adjust the tempo of music with a kind of metronome that doesn’t hit the beat consistently. In addition, I allow myself to stop and restart the metronome whenever I want with the noLoop () AND Loop () functions.
In our example, the tempo is given from the time elapsed between 2 beats (between 2 ‘a’ keys pressed) and continuously calculated by the moving average.

Let’s imagine that the time elapsed between 2 beats, so the tempo is 100. Then I stop this metronome far from the central position, I change its speed and I put it at 110.
Then I release him. Then when the metronome returns to its central position, it gives me a new pulse.
I would like to have the time elapsed between the pulsation given before I stop the program and the the pulsation given after restarting the program.

Would you like a drawing maybe?

OK I think I get the idea consider the following series of events

Time (ms)        Event
...
1000          'a' key pressed for first time
1015          'a' key pressed : 15ms stored in moving average calculator (MAC)
1033          'a' key pressed : 17ms stored in moving average calculator (MAC)
1046          Sketch paused to change metronome
2150          Sketch resumed 
2160          'a' key pressed : ?????

If you look at the events shown here the the gap between the 3rd and 4th ‘a’ key press is 1127ms (i.e. 2160 - 1033) but the sketch was paused for 1104ms (2150 - 1046)

Am I right in assuming that you want to use the time between ‘a’ presses ignoring time paused i.e. 23ms (1127 - 1104) in the moving average?

:grinning: :star_struck:

It is exactly that!

Great, hopefully will get back very soon with a solution.

Problem solved below is the sketch. To test it hit the ‘a’ key about once per second and the average time will be ~1000ms. When ready type the ‘;’ key soon after one of the ‘a’ presses. Now wait at least 10 seconds and then hit the "’;’ key to restart the sketch and immediately followed by the ‘a’ key. The average should still be about 1000ms.

boolean ready = false;

int pause_start_time, sketch_pause_interval = 0;
int prev_time;

void setup() {
  size(400, 200);
  textSize(20);
}

void draw() {
  background(0);
  fill(255);
  text("Moving average = ", 10, 40, 380, 40);
  text("" + avgTimer.average(), 10, 80, 380, 40);
}

void keyTyped() {
  // Toggle between sketch paused - running
  if (key == ';' || key == ':') {
    if (isLooping()) {
      pause_start_time = millis();
      noLoop();
      println("Paused at " + pause_start_time);
    } else {
      sketch_pause_interval = millis() - pause_start_time;
      println("Paused at " + millis() + " for " + sketch_pause_interval + "ms");
      loop();
    }
  }
  // Only consider 'a' keys when the sketch is not paused
  if (key == 'a' && isLooping()) {
    if (!ready) {
      ready = true;
      prev_time = millis();
    } else {
      int curr_time = millis();
      avgTimer.nextValue(curr_time - prev_time - sketch_pause_interval);
      sketch_pause_interval = 0;
      println("'a' key pressed at " + curr_time);
      prev_time = curr_time;
    }
  }
}


MovingAverage avgTimer = new MovingAverage(2);

/**
 * Use  a circular array to store generation step impl. times
 * and calculate a moving average.
 * 
 * Specify the number of values to include in the moving average when
 * using the constructor. 
 * 
 * The implementation time is O(1) i.e. the same whatever the number 
 * of values used it takes the same amount of time to calculate the
 * moving average.
 * 
 * @author Peter Lager 2021
 */
private class MovingAverage {
  private float[] data;
  private float total = 0, average = 0;
  private int idx = 0, n = 0;

  /**
   * For a moving average we must have at least remember the last 
   * two values.
   * @param size the size of the underlying array
   */
  public MovingAverage(int size) {
    data = new float[Math.max(2, size)];
  }

  // Include the next value in the moving average
  public float nextValue(float value) {
    total -= data[idx];
    data[idx] = value;
    total += value;
    idx = ++idx % data.length;
    if (n < data.length) n++;
    average = total / (float)n;
    return average;
  }

  public void reset() {
    for (int i = 0; i < data.length; i++)
      data[i] = 0;
    total = n = 0;
  }

  public float average() {
    return average;
  }
}
1 Like

Thank you so much , super Mister! It’s exactly what I wanted. Bravo, felicitation. Benjamin