package decor
import (
"sort"
"github.com/VividCortex/ewma"
)
// MovingAverage is the interface that computes a moving average over a time-
// series stream of numbers. The average may be over a window or exponentially
// decaying.
type MovingAverage interface {
Add(float64)
Value() float64
Set(float64)
}
type median struct {
window [3]float64
dst []float64
}
type sortable []float64
func (s sortable) Len() int { return len(s) }
func (s sortable) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s sortable) Less(i, j int) bool { return s[i] < s[j] }
func (s *median) Add(v float64) {
s.window[0], s.window[1] = s.window[1], s.window[2]
s.window[2] = v
}
func (s *median) Value() float64 {
copy(s.dst, s.window[:])
sort.Sort(sortable(s.dst))
return s.dst[1]
}
func (s *median) Set(value float64) {
for i, _ := range s.window {
s.window[i] = value
}
}
// NewMedian is fixed last 3 samples median MovingAverage.
func NewMedian() MovingAverage {
return &median{
dst: make([]float64, 3),
}
}
type medianEwma struct {
MovingAverage
median MovingAverage
}
func (s medianEwma) Add(v float64) {
s.median.Add(v)
s.MovingAverage.Add(s.median.Value())
}
// NewMedianEwma is ewma based MovingAverage, which gets its values from median MovingAverage.
func NewMedianEwma(age ...float64) MovingAverage {
return medianEwma{
MovingAverage: ewma.NewMovingAverage(age...),
median: NewMedian(),
}
}