/*******************************************************************************
* Copyright 2011 See AUTHORS file.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package com.badlogic.gdx.math;
/**
* A simple class keeping track of the mean of a stream of values within a
* certain window. the WindowedMean will only return a value in case enough data
* has been sampled. After enough data has been sampled the oldest sample will
* be replaced by the newest in case a new sample is added.
*
* @author badlogicgames@gmail.com
*/
public final class WindowedMean {
float values[];
int added_values = 0;
int last_value;
float mean = 0;
boolean dirty = true;
/**
* constructor, window_size specifies the number of samples we will
* continuously get the mean and variance from. the class will only return
* meaning full values if at least window_size values have been added.
*
* @param window_size
* size of the sample window
*/
public WindowedMean(int window_size) {
values = new float[window_size];
}
/**
* @return whether the value returned will be meaningful
*/
public boolean hasEnoughData() {
return added_values >= values.length;
}
/**
* clears this WindowedMean. The class will only return meaningful values
* after enough data has been added again.
*/
public void clear() {
added_values = 0;
last_value = 0;
for (int i = 0; i < values.length; i++)
values[i] = 0;
dirty = true;
}
/**
* adds a new sample to this mean. In case the window is full the oldest
* value will be replaced by this new value.
*
* @param value
* The value to add
*/
public void addValue(float value) {
if (added_values < values.length)
added_values++;
values[last_value++] = value;
if (last_value > values.length - 1)
last_value = 0;
dirty = true;
}
/**
* returns the mean of the samples added to this instance. Only returns
* meaningful results when at least window_size samples as specified in the
* constructor have been added.
*
* @return the mean
*/
public float getMean() {
if (hasEnoughData()) {
if (dirty == true) {
float mean = 0;
for (int i = 0; i < values.length; i++)
mean += values[i];
this.mean = mean / values.length;
dirty = false;
}
return this.mean;
} else
return 0;
}
/**
* @return the oldest value in the window
*/
public float getOldest() {
return last_value == values.length - 1 ? values[0] : values[last_value + 1];
}
/**
* @return the value last added
*/
public float getLatest() {
return values[last_value - 1 == -1 ? values.length - 1 : last_value - 1];
}
/**
* @return The standard deviation
*/
public float standardDeviation() {
if (!hasEnoughData())
return 0;
float mean = getMean();
float sum = 0;
for (int i = 0; i < values.length; i++) {
sum += (values[i] - mean) * (values[i] - mean);
}
return (float) Math.sqrt(sum / values.length);
}
public int getWindowSize() {
return values.length;
}
}