# Create a rolling 3-second average using a queue but using elapsed time for averaging

Hey everyone, I’ve spent hours on this and I just can’t figure it out - from my research I’ve seen that a queue is the most efficient way of doing this but I can’t quite figure out how to modify my code to create a rolling 3-second average of my variable - power. I think I have too many elements in the queue as my averaging is really slow but I don’t know why I would need to restrict the number of elements in the window if I just gather as many as were there over the 3 second window.

``````private Queue<float> dataQueue = new Queue<float>();
private float currentSum = 0;

public float movingAverage = 0; // Store the calculated moving average

private float timeInterval = 3; // Time interval in seconds for calculating the moving average
private float elapsedTime = 0;

void Update()
{
{
elapsedTime += Time.deltaTime;
if (elapsedTime >= timeInterval)
{
CalculateMovingAverage();
elapsedTime = 0;
}
}
}

{
dataQueue.Enqueue(newValue);
currentSum += newValue;

// Remove outdated data from the queue
while (dataQueue.Count > 0 && Time.time - dataQueue.Peek() > timeInterval)
{
currentSum -= dataQueue.Dequeue();
}
}

public  void CalculateMovingAverage()
{
if (dataQueue.Count > 0)
{
movingAverage = currentSum / dataQueue.Count;
}
else
{
movingAverage = 0; // No data in the queue, set average to 0
}
}

public float GetAveragePower()
{
return movingAverage;
}
``````

So just to make sure i understood correct, what you want to do is - let’s say you have a health stat , you want to be able to have that stat monitored and always be able to get the average health during the last 3 seconds (for example) , right ?

Personally i would just use a good ol’ `List` and store the data as a pair of `<Stat,TimeStamp>` , here’s a code example of how i would do it

``````public class StatAverage
{
private struct DataTimestampPair
{
public float timestamp;
public float data;
}

private float avgTimer;
private List<DataTimestampPair> timeline;

public StatAverage(float avgTimer)
{
this.avgTimer = avgTimer;
timeline = new List<DataTimestampPair>();
}

// use this method to add entries to the timeline
// here , it is assumed that we will always add the entries in order , aka first -> last
public void Add(float data, float timestamp)
{
timeline.Add(new DataTimestampPair() { data = data, timestamp = timestamp });
}

public float GetAverage(float currentTimestamp)
{
int i = 0;

// since the timeline is assumed be ordered
// just iterate until you find an element that falls within the "avgTimer" duration
// this can be more efficient if you go from end -> start , but you get the idea
for (; i < timeline.Count; ++i)
{
// get the different between the entry and the current timestamp
float diff = currentTimestamp - timeline[i].timestamp;

// as soon as we encounter the first entry that falls within the "timer" interval , we stop
if (diff <= avgTimer)
break;
}

//  delete the "expired" entries
{
timeline.RemoveRange(0, i);
}

// here you iterate of entries that fall within the "avgTimer" duration

if (timeline.Count == 0)
return 0;

float sum = 0;
foreach (var entry in timeline)
{
sum += entry.data;
}

return sum / avgTimer;
}
}
``````

### NOTE:

The code above is supposed to be a “good enough” start to get things going, you can make it more precise/optimized if you need , one case where this can be inaccurate is a case like this

You can see in this example that the last two value fall within the green “timer” zone , but if we do a naive `( val1 + val2) / 2` , we miss that “rapid rise” that happened at the start of the range but wasn’t accounted for with “simple” avereging, ill leave that kind of polish to you

Your code looks mostly correct, but the issue was in how you’re adding data to the queue. You should be adding the actual data value (`newValue` ) to the queue, not the result of `(float)speedboi.GetPower()` . Ensure that `newValue` represents the power value you want to average.

``````using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class RollingAverage : MonoBehaviour
{
private Queue<float> dataQueue = new Queue<float>();
private float currentSum = 0;

public float movingAverage = 0; // Store the calculated moving average

private float timeInterval = 3; // Time interval in seconds for calculating the moving average
private float elapsedTime = 0;

void Update()
{
elapsedTime += Time.deltaTime;
if (elapsedTime >= timeInterval)
{
CalculateMovingAverage();
elapsedTime = 0;
}
}

{
dataQueue.Enqueue(newValue);
currentSum += newValue;

// Remove outdated data from the queue
while (dataQueue.Count > 0 && Time.time - dataQueue.Peek() > timeInterval)
{
currentSum -= dataQueue.Dequeue();
}
}

public void CalculateMovingAverage()
{
if (dataQueue.Count > 0)
{
movingAverage = currentSum / dataQueue.Count;
}
else
{
movingAverage = 0; // No data in the queue, set average to 0
}
}

public float GetAveragePower()
{
return movingAverage;
}
}
``````