Is there a function in java to get moving average

Viewed 50428

I have a situation where I need to process 5000 samples from a device in every 0.5 sec.

Lets say the window size is 100, then there would be 50 points resulting from the moving average. I am trying with conventional method, i.e. with loops. But this is a very inefficient way to do it. Any suggestions ?

8 Answers

Here's a good implementation, using BigDecimal:

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.LinkedList;
import java.util.Queue;

public class MovingAverage {

    private final Queue<BigDecimal> window = new LinkedList<BigDecimal>();
    private final int period;
    private BigDecimal sum = BigDecimal.ZERO;

    public MovingAverage(int period) {
        assert period > 0 : "Period must be a positive integer";
        this.period = period;
    }

    public void add(BigDecimal num) {
        sum = sum.add(num);
        window.add(num);
        if (window.size() > period) {
            sum = sum.subtract(window.remove());
        }
    }

    public BigDecimal getAverage() {
        if (window.isEmpty()) return BigDecimal.ZERO; // technically the average is undefined
        BigDecimal divisor = BigDecimal.valueOf(window.size());
        return sum.divide(divisor, 2, RoundingMode.HALF_UP);
    }
}

Java 8 has added java.util.IntSummaryStatistics. There similar classes for Double and Long as well. Fairly straightforward to use:

IntSummaryStatistics stats = new IntSummaryStatistics();
stats.accept(1);
stats.accept(3);
stats.getAverage(); // Returns 2.0
static int[] myIntArray = new int[16];
public static double maf(double number)
{
    double avgnumber=0;
    for(int i=0; i<15; i++)
    {
        myIntArray[i] = myIntArray[i+1];
    }
    myIntArray[15]= (int) number;
    /* Doing Average */
    for(int  i=0; i<16; i++)
    {
        avgnumber=avgnumber+ myIntArray[i];
    }
    return avgnumber/16;

}

this algorithm can also be called as Moving Average Filter which is working well for me ... i implemented this algo in my graph project!

A solution without cumulative floating point errors.

/**
 * Voortschrijdend gemiddelde
 * @author Eelco de Lang
 */
public class MovingAverage
{
    private final double[] valuesWindow;
    private int fill;// = 0;

    public MovingAverage(int windowSize)
    {
        valuesWindow = new double[windowSize];
        assert windowSize > 0 : "Window size must be a positive integer";
    }

    public void add(long number)
    {
        add((double) number);
    }

    public void add(double number)
    {
        // Shift all values up 1 position
        System.arraycopy(valuesWindow, 0, valuesWindow, 1, valuesWindow.length - 1);
        valuesWindow[0] = number;
        if (fill < valuesWindow.length) {
            fill++;
        }
    }

    public double getAverage()
    {
        double result = 0;
        for (int i = 0; i < fill; i++) {
            result += valuesWindow[i];
        }
        if (fill == 0) {
            // Fine in most cases
            return 0;
        }
        else {
            return result / fill;
        }
    }
}
public class MovingAverageTest
{

    @Test
    public void test()
    {

        MovingAverage movingAverage = new MovingAverage(2);
        Assert.assertEquals(0, movingAverage.getAverage(), 0.00001);
        movingAverage.add(0.5);
        Assert.assertEquals(0.5, movingAverage.getAverage(), 0.00001);
        movingAverage.add(1.5);
        Assert.assertEquals(1.0, movingAverage.getAverage(), 0.00001);
        movingAverage.add(1.5);
        Assert.assertEquals(1.5, movingAverage.getAverage(), 0.00001);
    }

    @Test
    public void test2()
    {
        MovingAverage movingAverage = new MovingAverage(3);
        Assert.assertEquals(0, movingAverage.getAverage(), 0.00001);
        movingAverage.add(123);
        Assert.assertEquals(123, movingAverage.getAverage(), 0.00001);
        movingAverage.add(123);
        Assert.assertEquals(123, movingAverage.getAverage(), 0.00001);
        movingAverage.add(123);
        Assert.assertEquals(123, movingAverage.getAverage(), 0.00001);
        movingAverage.add(123);
        Assert.assertEquals(123, movingAverage.getAverage(), 0.00001);
        movingAverage.add(123);
        Assert.assertEquals(123, movingAverage.getAverage(), 0.00001);
    }
}
Related