gitlab.com/SkynetLabs/skyd@v1.6.9/skymodules/renter/expmovingavg.go (about) 1 package renter 2 3 // expMovingAvg is a function to track the exponential moving average of a 4 // series of datapoints. 5 type expMovingAvg struct { 6 decay float64 7 8 // weightedSpan tracks the total decayed amount of data we've received, and 9 // the weighted sum tracks the total decayed value of all the data we've 10 // received. 11 weightedSpan float64 12 weightedSum float64 13 } 14 15 // newExpMovingAvg returns an expMovingAvg that's ready to receive data and 16 // compute averages. 17 func newExpMovingAvg(decay float64) *expMovingAvg { 18 return &expMovingAvg{ 19 decay: decay, 20 } 21 } 22 23 // addDataPoint adds a single data point to the average, decaying the existing 24 // data by the chosen decay of the average. 25 func (ema *expMovingAvg) addDataPoint(data float64) { 26 ema.weightedSpan *= ema.decay 27 ema.weightedSpan += 1 28 ema.weightedSum *= ema.decay 29 ema.weightedSum += data 30 } 31 32 // average returns the average of all the data that's been added to the 33 // expMovingAvg. 34 func (ema *expMovingAvg) average() float64 { 35 return ema.weightedSum / ema.weightedSpan 36 } 37 38 // expMovingAvgHotStart is a helper to compute the next exponential moving 39 // average given the last value and a new point of measurement. The function is 40 // fully stateless, but also has a 'hot start', which means that the first data 41 // point sets the average at full strength. If the first datapoint is an outlier 42 // datapoint, it can significantly disrupt the average until many more 43 // datapoints have come in. 44 // 45 // https://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average 46 func expMovingAvgHotStart(oldEMA, newValue, decay float64) float64 { 47 if decay < 0 || decay > 1 { 48 panic("decay has to be a value in range 0 <= x <= 1") 49 } 50 if oldEMA == 0 { 51 // This is the hot start. If there is no EMA yet, we take the first 52 // datapoint as the true average. If you don't do this, when you start 53 // off at first you will have an average that is completely incorrect, 54 // because your first datapoint might be '80' but at a decay of 0.9 your 55 // average after that datapoint will be 8. 56 return newValue 57 } 58 return newValue*(1-decay) + decay*oldEMA 59 }