1 /******************************************************************************* 2 * Copyright 2011 See AUTHORS file. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 ******************************************************************************/ 16 17 package com.badlogic.gdx.math; 18 19 /** A simple class keeping track of the mean of a stream of values within a certain window. the WindowedMean will only return a 20 * value in case enough data has been sampled. After enough data has been sampled the oldest sample will be replaced by the newest 21 * in case a new sample is added. 22 * 23 * @author badlogicgames (at) gmail.com */ 24 public final class WindowedMean { 25 float values[]; 26 int added_values = 0; 27 int last_value; 28 float mean = 0; 29 boolean dirty = true; 30 31 /** constructor, window_size specifies the number of samples we will continuously get the mean and variance from. the class will 32 * only return meaning full values if at least window_size values have been added. 33 * 34 * @param window_size size of the sample window */ 35 public WindowedMean (int window_size) { 36 values = new float[window_size]; 37 } 38 39 /** @return whether the value returned will be meaningful */ 40 public boolean hasEnoughData () { 41 return added_values >= values.length; 42 } 43 44 /** clears this WindowedMean. The class will only return meaningful values after enough data has been added again. */ 45 public void clear () { 46 added_values = 0; 47 last_value = 0; 48 for (int i = 0; i < values.length; i++) 49 values[i] = 0; 50 dirty = true; 51 } 52 53 /** adds a new sample to this mean. In case the window is full the oldest value will be replaced by this new value. 54 * 55 * @param value The value to add */ 56 public void addValue (float value) { 57 if (added_values < values.length) 58 added_values++; 59 values[last_value++] = value; 60 if (last_value > values.length - 1) last_value = 0; 61 dirty = true; 62 } 63 64 /** returns the mean of the samples added to this instance. Only returns meaningful results when at least window_size samples 65 * as specified in the constructor have been added. 66 * @return the mean */ 67 public float getMean () { 68 if (hasEnoughData()) { 69 if (dirty == true) { 70 float mean = 0; 71 for (int i = 0; i < values.length; i++) 72 mean += values[i]; 73 74 this.mean = mean / values.length; 75 dirty = false; 76 } 77 return this.mean; 78 } else 79 return 0; 80 } 81 82 /** @return the oldest value in the window */ 83 public float getOldest () { 84 return last_value == values.length - 1 ? values[0] : values[last_value + 1]; 85 } 86 87 /** @return the value last added */ 88 public float getLatest () { 89 return values[last_value - 1 == -1 ? values.length - 1 : last_value - 1]; 90 } 91 92 /** @return The standard deviation */ 93 public float standardDeviation () { 94 if (!hasEnoughData()) return 0; 95 96 float mean = getMean(); 97 float sum = 0; 98 for (int i = 0; i < values.length; i++) { 99 sum += (values[i] - mean) * (values[i] - mean); 100 } 101 102 return (float)Math.sqrt(sum / values.length); 103 } 104 105 public int getWindowSize () { 106 return values.length; 107 } 108 } 109