Is there a function in java to get moving average

后端 未结 7 1788
囚心锁ツ
囚心锁ツ 2020-12-14 16:14

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 fro

相关标签:
7条回答
  • 2020-12-14 16:50

    Here's one way.

    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());
        }
    }
    
    0 讨论(0)
  • 2020-12-14 16:52

    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);
        }
    }
    
    0 讨论(0)
  • 2020-12-14 16:52

    As far as I know, there is no such function (class) in Java. But you can make one by yourself. Here is a simple example (SMA-Simple Moving Average):

    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;
        }
    }
    
    0 讨论(0)
  • 2020-12-14 16:57

    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
    
    0 讨论(0)
  • 2020-12-14 16:59
    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!

    0 讨论(0)
  • 2020-12-14 17:05

    You can do that in O(1): keep a queue of the last 50 entries. When you add an entry and the queue is shorter 50 elements, just update the total and the count. If it is longer than 50 elements, update the total and the count as well. Pseudocode:

    add(double x) {
        total += x;
        addToQueue(x);
        if (queueSize > 50) {
            total -= removeLastFromQueue();
        } else {
            count++;
        }
    }
    double getAverage() {
        return total / count;
    }
    
    0 讨论(0)
提交回复
热议问题