java中是否有一个函数可以获得移动平均值

时间:2010-09-25 10:23:40

标签: java

我有一种情况需要每隔0.5秒从设备处理5000个样本。

假设窗口大小为100,那么移动平均线将产生50个点。我正在尝试使用传统方法,即使用循环。但这是一种非常低效的方法。有什么建议吗?

7 个答案:

答案 0 :(得分:24)

查看Apache Maths库。这有方法可以准确地做你想要的。有关详细信息,请参阅DescriptiveStatisticsMean

答案 1 :(得分:20)

这是一种方式。

public class Rolling {

    private int size;
    private double total = 0d;
    private int index = 0;
    private double samples[];

    public Rolling(int size) {
        this.size = size;
        samples = new double[size];
        for (int i = 0; i < size; i++) samples[i] = 0d;
    }

    public void add(double x) {
        total -= samples[index];
        samples[index] = x;
        total += x;
        if (++index == size) index = 0; // cheaper than modulus
    }

    public double getAverage() {
        return total / size;
    }   
}

public class RollingTest extends TestCase {

    private final static int SIZE = 5;
    private static final double FULL_SUM = 12.5d;

    private Rolling r;

    public void setUp() {
        r = new Rolling(SIZE);
    }

    public void testInitial() {
        assertEquals(0d, r.getAverage());
    }

    public void testOne() {
        r.add(3.5d);
        assertEquals(3.5d / SIZE, r.getAverage());
    }

    public void testFillBuffer() {
        fillBufferAndTest();
    }

    public void testForceOverWrite() {
        fillBufferAndTest();

        double newVal = SIZE + .5d;
        r.add(newVal);
        // get the 'full sum' from fillBufferAndTest(), add the value we just added,
        // and subtract off the value we anticipate overwriting.
        assertEquals((FULL_SUM + newVal - .5d) / SIZE, r.getAverage());
    }

    public void testManyValues() {
        for (int i = 0; i < 1003; i++) r.add((double) i);
        fillBufferAndTest();
    }


    private void fillBufferAndTest() {
        // Don't write a zero value so we don't confuse an initialized
        // buffer element with a data element.
        for (int i = 0; i < SIZE; i++) r.add(i + .5d);
        assertEquals(FULL_SUM / SIZE, r.getAverage());
    }
}

答案 2 :(得分:8)

您可以在O(1)中执行此操作:保留最近50个条目的队列。添加条目并且队列短50个元素时,只需更新总计和计数。如果它超过50个元素,也要更新总数和计数。伪代码:

add(double x) {
    total += x;
    addToQueue(x);
    if (queueSize > 50) {
        total -= removeLastFromQueue();
    } else {
        count++;
    }
}
double getAverage() {
    return total / count;
}

答案 3 :(得分:5)

据我所知,Java中没有这样的函数(类)。但你可以自己做一个。这是一个简单的例子(SMA-简单移动平均线):

public class MovingAverage {
    private int [] window;
    private int n, insert;
    private long sum;

    public MovingAverage(int size) {
        window = new int[size];
        insert = 0;
        sum = 0;
    }

    public double next(int val) {
        if (n < window.length)  n++;
        sum -= window[insert];
        sum += val;
        window[insert] = val;
        insert = (insert + 1) % window.length;
        return (double)sum / n;
    }
}

答案 4 :(得分:4)

这是一个很好的实现,使用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);
    }
}

答案 5 :(得分:2)

Java 8已添加java.util.IntSummaryStatisticsDoubleLong也有类似的类。相当简单易用:

IntSummaryStatistics stats = new IntSummaryStatistics();
stats.accept(1);
stats.accept(3);
stats.getAverage(); // Returns 2.0

答案 6 :(得分: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;

}

这个算法也可以称为移动平均滤波器,对我来说效果很好......我在我的图形项目中实现了这个算法!