diff --git a/speedtest/data_manager.go b/speedtest/data_manager.go index fac4a34..5d80720 100644 --- a/speedtest/data_manager.go +++ b/speedtest/data_manager.go @@ -248,7 +248,7 @@ func (td *TestDirection) rateCapture() chan bool { ticker := time.NewTicker(td.manager.rateCaptureFrequency) var prevTotalDataVolume int64 = 0 stopCapture := make(chan bool) - td.welford = internal.NewWelford(int(5 * time.Second / td.manager.rateCaptureFrequency)) + td.welford = internal.NewWelford(5*time.Second, td.manager.rateCaptureFrequency) sTime := time.Now() go func(t *time.Ticker) { defer t.Stop() @@ -263,7 +263,7 @@ func (td *TestDirection) rateCapture() chan bool { } // anyway we update the measuring instrument globalAvg := (float64(td.totalDataVolume)) / float64(time.Since(sTime).Milliseconds()) * 1000 - if td.welford.Update(globalAvg) { + if td.welford.Update(globalAvg, float64(deltaDataVolume)) { go td.closeFunc() } // reports the current rate at the given rate diff --git a/speedtest/internal/welford.go b/speedtest/internal/welford.go index ffeaf49..c2c3dcd 100644 --- a/speedtest/internal/welford.go +++ b/speedtest/internal/welford.go @@ -3,36 +3,49 @@ package internal import ( "fmt" "math" + "time" ) // Welford Fast standard deviation calculation with moving window // ref Welford, B. P. (1962). Note on a Method for Calculating Corrected Sums of Squares and Products. Technometrics, 4(3), 419–420. https://doi.org/10.1080/00401706.1962.10490022 type Welford struct { n int // data size + cap int // queue capacity + vector []float64 // data set mean float64 // mean sum float64 // sum - vector []float64 // data set eraseIndex int // the value will be erased next time - cap int currentStdDev float64 consecutiveStableIterations int consecutiveStableIterationsThreshold int cv float64 ewmaMean float64 + steps int + minSteps int + beta float64 + scale float64 + movingVector []float64 // data set + movingAvg float64 } -// NewWelford recommended windowSize = moving time window / sampling frequency -func NewWelford(windowSize int) *Welford { +// NewWelford recommended windowSize = cycle / sampling frequency +func NewWelford(cycle, frequency time.Duration) *Welford { + windowSize := int(cycle / frequency) return &Welford{ vector: make([]float64, windowSize), + movingVector: make([]float64, windowSize), cap: windowSize, - consecutiveStableIterationsThreshold: 10, + consecutiveStableIterationsThreshold: windowSize / 3, // 33% + minSteps: windowSize * 2, // set minimum steps with 2x windowSize. + beta: 2 / (float64(windowSize) + 1), // ewma beta ratio + scale: float64(time.Second / frequency), } } // Update Enter the given value into the measuring system. // return bool stability evaluation -func (w *Welford) Update(value float64) bool { +func (w *Welford) Update(globalAvg, value float64) bool { + value = value * w.scale if w.n == w.cap { delta := w.vector[w.eraseIndex] - w.mean w.mean -= delta / float64(w.n-1) @@ -41,37 +54,37 @@ func (w *Welford) Update(value float64) bool { if w.sum < 0 { w.sum = 0 } - w.vector[w.eraseIndex] = value + w.vector[w.eraseIndex] = globalAvg + w.movingAvg -= w.movingVector[w.eraseIndex] + w.movingVector[w.eraseIndex] = value + w.movingAvg += value w.eraseIndex++ if w.eraseIndex == w.cap { w.eraseIndex = 0 } } else { - w.vector[w.n] = value + w.vector[w.n] = globalAvg + w.movingVector[w.n] = value + w.movingAvg += value w.n++ } - delta := value - w.mean + delta := globalAvg - w.mean w.mean += delta / float64(w.n) - w.sum += delta * (value - w.mean) + w.sum += delta * (globalAvg - w.mean) w.currentStdDev = math.Sqrt(w.Variance()) // update C.V - if w.mean == 0 { - w.cv = 1 - } else { + if w.mean != 0 { w.cv = w.currentStdDev / w.mean - if w.cv > 1 { - w.cv = 1 - } } - // ewma beta ratio - // TODO: w.cv needs normalization - beta := w.cv*0.381 + 0.618 - w.ewmaMean = w.mean*beta + w.ewmaMean*(1-beta) + w.ewmaMean = value*w.beta + w.ewmaMean*(1-w.beta) // acc consecutiveStableIterations - if w.cap/2 < w.n && w.cv < 0.03 { + if w.n == w.cap && w.cv < 0.03 { w.consecutiveStableIterations++ + } else if w.consecutiveStableIterations > 0 { + w.consecutiveStableIterations-- } - return w.consecutiveStableIterations >= w.consecutiveStableIterationsThreshold + w.steps++ + return w.consecutiveStableIterations >= w.consecutiveStableIterationsThreshold && w.steps > w.minSteps } func (w *Welford) Mean() float64 { @@ -94,7 +107,7 @@ func (w *Welford) StandardDeviation() float64 { } func (w *Welford) EWMA() float64 { - return w.ewmaMean + return w.ewmaMean*0.5 + w.movingAvg/float64(w.n)*0.5 } func (w *Welford) String() string { diff --git a/speedtest/internal/welford_test.go b/speedtest/internal/welford_test.go index 415fd30..d8ecbc7 100644 --- a/speedtest/internal/welford_test.go +++ b/speedtest/internal/welford_test.go @@ -8,25 +8,24 @@ import ( ) func BenchmarkWOM(b *testing.B) { - w := NewWelford(10) + w := NewWelford(time.Second*5, time.Millisecond*50) rd := rand.New(rand.NewSource(0)) var arr []float64 for i := 0; i < 100; i++ { arr = append(arr, rd.Float64()) } for i := 0; i < b.N; i++ { - w.Update(arr[i%100]) + w.Update(arr[i%100], arr[i%100]) } } func TestWOM(t *testing.T) { - //data := []float64{0, 6.91552, 18.721692307692308, 23.04116556291391, 28.059485148514852, 31.118470119521916, 34.21727152317881, 35.15127065527066, 36.74378054862843, 38.05981374722838, 39.122272, 38.76271506352087, 39.60149084858569, 40.23165538461539, 40.72287589158345, 41.3182940397351, 41.36879800498754, 41.848093896713614, 42.29560044395117, 42.45441684210526, 42.27466666666667, 42.67902476190476, 42.68457142857143, 42.80731190269331, 42.75244, 42.6367104, 42.65657801691007, 42.68948038490007, 42.81048394004282, 42.64527084769124, 42.802427145708585, 42.92410838709678, 43.15598501872659, 43.32482909090909, 43.46838800705467, 43.5166464877213, 43.523846751804555, 43.73983171521036, 43.870409258285115, 43.84913230769231, 43.72752023988006, 43.85322926829268, 43.964127436994765, 44.027410506741056, 43.99742169768498, 44.093007552199026, 44.241321164710996, 44.287108464483204, 44.079746772178254, 44.180878367346935, 44.1128768, 44.17403607843137, 44.0556123076923, 44.20335873255375, 44.19607703703704, 44.2603155216285, 44.202986438258385, 44.2371857042747, 44.17902344827586, 44.31277559322034, 44.30876912840985, 44.378359108781126, 44.3999845410628, 44.37440913415794, 44.4760624609619, 44.471889264841586, 44.454861296184134, 44.37803098927294, 44.37345251396648, 44.47449043478261, 44.43488914285714, 44.50349070422535, 44.45223882254929, 44.433060821917806, 44.46777081081081, 44.4554752, 44.43440842105263, 44.55939356178609, 44.59433376057421, 44.633178734177214, 44.5508462884279, 44.58072493827161, 44.67904608632041, 44.662959537572256, 44.66403237324446, 44.59772449459332, 44.53588837209303, 44.586143382352944, 44.66949738933031, 44.66949618320611, 44.69251965356429, 44.628363956043955, 44.63443946968051, 44.607556129032254, 44.66488851063829, 44.66553062513155, 44.72077, 44.75405813234384, 44.821391020408164, 44.88321874368814, 44.9364192, 44.94112373787369, 44.958842352941176, 44.97548797517455, 44.94797846153846, 44.9455939047619, 44.910117647058826, 44.88617040358744, 44.86545696835092, 44.86558503026968, 44.90363345454546, 44.87501062871554, 44.93104802713802, 44.93590804597701, 44.90068409051044, 44.87467130434782, 44.891225650749874, 44.9156841025641, 44.92164610169491, 44.89092118971601, 44.9027482086319, 44.86017701453105, 44.87692428711898, 44.8651103526735, 44.8483070967742, 44.79754023356263, 44.787605776860815, 44.7891175822446, 44.778797499999996, 44.778773283743995, 44.79586406274028, 44.77517923664122, 44.62143350499849, 44.48119933904161, 44.38141850746269, 44.425831753554505, 44.390321423320096, 44.31049810218978, 44.124642318840586, 44.01107798561151, 44.02091885714285, 44.02881950942861, 44.019682253521125, 44.071147412587415, 44.08087753401833, 44.09411310344827, 44.12980821917809, 44.07751870493811, 44.09083445854713, 44.09876506104924, 44.08840634582056, 44.13032264900663, 44.09793658729115, 44.106114509803916, 44.06832567199065, 44.096165139981935, 44.116, 44.10581480066234, 44.09257851448817, 44.075851106639846, 44.074916, 44.091910073282826, 44.09682567901235, 44.07930895705522, 44.053896892138944, 44.06240019391589, 44.06116150788872, 44.1180531736527, 44.15990285714285, 44.134685126020585, 44.18049829431832, 44.158170252572496, 44.21358883720931, 44.16577849710982, 44.1291108045977, 44.16022671694664, 44.1493200045439, 44.1491597740113, 44.15741842696629, 44.177169162011175, 44.21226797022553, 44.166602585349686, 44.17985497692815, 44.168419672131144, 44.19028366481904, 44.173513455095645, 44.162090322580646, 44.123481608212145, 44.155531914893615, 44.18765714285714, 44.224294736842104, 44.21350366492147, 44.168821324448146, 44.168, 44.17472356215214, 44.187647999999996, 44.18084571428571, 44.18716962744899, 44.19440137359862, 44.1429404079992, 44.15704} - data := []float64{0, 1550.14016, 1102.92032, 759.1852799999999, 601.88672, 502.06617600000004, 435.71381333333335, 385.54944, 348.24736, 316.40547555555554, 289.261344, 267.38202181818184, 252.83786666666668, 245.42818461538462, 245.35842285714287, 235.63543466666667, 227.58704000000003, 220.20446117647057, 213.48643555555554, 207.48786526315791, 201.919424, 197.19868952380952, 192.2912581818182, 188.60752695652172, 185.09968, 181.7553664, 178.6282953846154, 175.99228444444446, 173.34433142857142, 170.91121655172415, 168.496128, 166.37638193548386, 163.99491999999998, 161.9206012121212, 160.24624, 158.76464457142856, 157.2420711111111, 155.45751351351353, 154.00374736842107, 152.63651282051282, 151.112704, 149.88837463414634, 149.02825142857142, 147.3117618604651, 144.63512, 145.58946844444446, 144.72223304347824, 143.76531744680852, 143.01374, 142.06400653061226, 141.0796992, 140.27383843137252, 139.51694153846157, 138.54825660377358, 138.22770370370372, 137.21800727272725, 136.98238857142854, 135.9439045614035, 135.45676137931034, 135.40977898305084, 134.70067622540847, 134.12748048540504, 133.63318709677418, 133.16014222222222, 132.703765, 132.20392861538463, 131.7192387878788, 131.27342328358208, 130.71865882352944, 130.23932753623188, 129.99216914285716, 129.28652169014086, 129.16500888888888, 128.67712438356165, 128.25776864864866, 127.85582506666665, 127.45831157894739, 127.03613922077922, 126.90191179487178, 126.59213772151901, 126.425936, 126.0965688888889, 125.77238634146343, 125.49601735357918, 125.1707276190476, 124.89910964705884, 124.60520186046512, 124.29531218390805, 124.02556363636364, 123.47192808988764, 123.56910222222223, 123.33042637362638, 123.09693913043478, 122.809328172043, 122.58635234042553, 122.41840168421052, 122.15547666666666, 121.92927999999999, 121.73630367346938, 121.48462222222223, 121.29761599999999, 121.06910415841584, 120.87151686274511, 120.68683805825242, 120.51469538461538, 120.2012220952381, 120.15477433962265, 119.2894474766355, 119.77253037037036, 119.57481394495413, 119.31698327272728, 119.10490234234233, 118.99255142857143, 118.76022088495574, 118.8147452631579, 118.6306587826087, 118.51604413793103, 118.38956854700855, 118.1484366101695, 117.98398924369748, 117.95854933333334, 117.80418115702479, 117.68285901639344, 117.32433170731707, 117.36720000000001, 117.21502720000001, 117.10605714285714, 117.01992566929134, 116.88315749999998, 116.77652093023256, 116.65271384615386, 116.51296488549619, 116.39656969696969, 116.29855518796992, 116.18375402985075, 116.00662992592594, 115.96002117647059, 115.85702540145985, 115.77244985507247, 115.67459145200748, 115.48589942857143, 115.44551716312057, 115.35635154929577, 115.21038993006992, 115.11760666666666, 115.01394537931034, 114.97817863013698, 114.80941278911564, 114.72184648648648, 114.64405261744967, 114.55408426666666, 114.41580291390729, 114.3308, 114.27059869281045, 114.18505260423433, 114.14871122580645, 113.99949128205128, 113.94442191082803, 113.83386734177216, 113.59835371069182, 113.515388, 113.6068849689441, 113.52565728395062, 113.47399852760736, 113.35184, 113.3104446060606, 113.19637204819277, 113.12842730538924, 113.09605333333333, 113.08127621301774, 112.81183811764706, 112.9294203508772, 112.81810418604651, 112.69997317919075, 112.63358712643677, 112.5452672, 112.50175090909092, 112.52005423728812, 112.43650516853933, 112.34864983240223, 112.20527644444445, 112.20484950276244, 112.19415912087912, 112.13252546448088, 112.04997913043476, 112.02885535135137, 111.93645075268819, 111.89874994652408, 111.80677787234042, 111.73926264550266, 111.75360336842105, 111.62827225130889, 111.64060833333332, 111.58019481865286, 111.51077113402062, 111.32106666666667, 111.43125714285713, 111.37313757741902, 111.2588913131313, 111.27499738693469, 111.22497689768976} - size := 5 * time.Second / (time.Millisecond * 50) - w := NewWelford(int(size)) + data := []float64{0, 6.91552, 18.721692307692308, 23.04116556291391, 28.059485148514852, 31.118470119521916, 34.21727152317881, 35.15127065527066, 36.74378054862843, 38.05981374722838, 39.122272, 38.76271506352087, 39.60149084858569, 40.23165538461539, 40.72287589158345, 41.3182940397351, 41.36879800498754, 41.848093896713614, 42.29560044395117, 42.45441684210526, 42.27466666666667, 42.67902476190476, 42.68457142857143, 42.80731190269331, 42.75244, 42.6367104, 42.65657801691007, 42.68948038490007, 42.81048394004282, 42.64527084769124, 42.802427145708585, 42.92410838709678, 43.15598501872659, 43.32482909090909, 43.46838800705467, 43.5166464877213, 43.523846751804555, 43.73983171521036, 43.870409258285115, 43.84913230769231, 43.72752023988006, 43.85322926829268, 43.964127436994765, 44.027410506741056, 43.99742169768498, 44.093007552199026, 44.241321164710996, 44.287108464483204, 44.079746772178254, 44.180878367346935, 44.1128768, 44.17403607843137, 44.0556123076923, 44.20335873255375, 44.19607703703704, 44.2603155216285, 44.202986438258385, 44.2371857042747, 44.17902344827586, 44.31277559322034, 44.30876912840985, 44.378359108781126, 44.3999845410628, 44.37440913415794, 44.4760624609619, 44.471889264841586, 44.454861296184134, 44.37803098927294, 44.37345251396648, 44.47449043478261, 44.43488914285714, 44.50349070422535, 44.45223882254929, 44.433060821917806, 44.46777081081081, 44.4554752, 44.43440842105263, 44.55939356178609, 44.59433376057421, 44.633178734177214, 44.5508462884279, 44.58072493827161, 44.67904608632041, 44.662959537572256, 44.66403237324446, 44.59772449459332, 44.53588837209303, 44.586143382352944, 44.66949738933031, 44.66949618320611, 44.69251965356429, 44.628363956043955, 44.63443946968051, 44.607556129032254, 44.66488851063829, 44.66553062513155, 44.72077, 44.75405813234384, 44.821391020408164, 44.88321874368814, 44.9364192, 44.94112373787369, 44.958842352941176, 44.97548797517455, 44.94797846153846, 44.9455939047619, 44.910117647058826, 44.88617040358744, 44.86545696835092, 44.86558503026968, 44.90363345454546, 44.87501062871554, 44.93104802713802, 44.93590804597701, 44.90068409051044, 44.87467130434782, 44.891225650749874, 44.9156841025641, 44.92164610169491, 44.89092118971601, 44.9027482086319, 44.86017701453105, 44.87692428711898, 44.8651103526735, 44.8483070967742, 44.79754023356263, 44.787605776860815, 44.7891175822446, 44.778797499999996, 44.778773283743995, 44.79586406274028, 44.77517923664122, 44.62143350499849, 44.48119933904161, 44.38141850746269, 44.425831753554505, 44.390321423320096, 44.31049810218978, 44.124642318840586, 44.01107798561151, 44.02091885714285, 44.02881950942861, 44.019682253521125, 44.071147412587415, 44.08087753401833, 44.09411310344827, 44.12980821917809, 44.07751870493811, 44.09083445854713, 44.09876506104924, 44.08840634582056, 44.13032264900663, 44.09793658729115, 44.106114509803916, 44.06832567199065, 44.096165139981935, 44.116, 44.10581480066234, 44.09257851448817, 44.075851106639846, 44.074916, 44.091910073282826, 44.09682567901235, 44.07930895705522, 44.053896892138944, 44.06240019391589, 44.06116150788872, 44.1180531736527, 44.15990285714285, 44.134685126020585, 44.18049829431832, 44.158170252572496, 44.21358883720931, 44.16577849710982, 44.1291108045977, 44.16022671694664, 44.1493200045439, 44.1491597740113, 44.15741842696629, 44.177169162011175, 44.21226797022553, 44.166602585349686, 44.17985497692815, 44.168419672131144, 44.19028366481904, 44.173513455095645, 44.162090322580646, 44.123481608212145, 44.155531914893615, 44.18765714285714, 44.224294736842104, 44.21350366492147, 44.168821324448146, 44.168, 44.17472356215214, 44.187647999999996, 44.18084571428571, 44.18716962744899, 44.19440137359862, 44.1429404079992, 44.15704} + // data := []float64{0, 1550.14016, 1102.92032, 759.1852799999999, 601.88672, 502.06617600000004, 435.71381333333335, 385.54944, 348.24736, 316.40547555555554, 289.261344, 267.38202181818184, 252.83786666666668, 245.42818461538462, 245.35842285714287, 235.63543466666667, 227.58704000000003, 220.20446117647057, 213.48643555555554, 207.48786526315791, 201.919424, 197.19868952380952, 192.2912581818182, 188.60752695652172, 185.09968, 181.7553664, 178.6282953846154, 175.99228444444446, 173.34433142857142, 170.91121655172415, 168.496128, 166.37638193548386, 163.99491999999998, 161.9206012121212, 160.24624, 158.76464457142856, 157.2420711111111, 155.45751351351353, 154.00374736842107, 152.63651282051282, 151.112704, 149.88837463414634, 149.02825142857142, 147.3117618604651, 144.63512, 145.58946844444446, 144.72223304347824, 143.76531744680852, 143.01374, 142.06400653061226, 141.0796992, 140.27383843137252, 139.51694153846157, 138.54825660377358, 138.22770370370372, 137.21800727272725, 136.98238857142854, 135.9439045614035, 135.45676137931034, 135.40977898305084, 134.70067622540847, 134.12748048540504, 133.63318709677418, 133.16014222222222, 132.703765, 132.20392861538463, 131.7192387878788, 131.27342328358208, 130.71865882352944, 130.23932753623188, 129.99216914285716, 129.28652169014086, 129.16500888888888, 128.67712438356165, 128.25776864864866, 127.85582506666665, 127.45831157894739, 127.03613922077922, 126.90191179487178, 126.59213772151901, 126.425936, 126.0965688888889, 125.77238634146343, 125.49601735357918, 125.1707276190476, 124.89910964705884, 124.60520186046512, 124.29531218390805, 124.02556363636364, 123.47192808988764, 123.56910222222223, 123.33042637362638, 123.09693913043478, 122.809328172043, 122.58635234042553, 122.41840168421052, 122.15547666666666, 121.92927999999999, 121.73630367346938, 121.48462222222223, 121.29761599999999, 121.06910415841584, 120.87151686274511, 120.68683805825242, 120.51469538461538, 120.2012220952381, 120.15477433962265, 119.2894474766355, 119.77253037037036, 119.57481394495413, 119.31698327272728, 119.10490234234233, 118.99255142857143, 118.76022088495574, 118.8147452631579, 118.6306587826087, 118.51604413793103, 118.38956854700855, 118.1484366101695, 117.98398924369748, 117.95854933333334, 117.80418115702479, 117.68285901639344, 117.32433170731707, 117.36720000000001, 117.21502720000001, 117.10605714285714, 117.01992566929134, 116.88315749999998, 116.77652093023256, 116.65271384615386, 116.51296488549619, 116.39656969696969, 116.29855518796992, 116.18375402985075, 116.00662992592594, 115.96002117647059, 115.85702540145985, 115.77244985507247, 115.67459145200748, 115.48589942857143, 115.44551716312057, 115.35635154929577, 115.21038993006992, 115.11760666666666, 115.01394537931034, 114.97817863013698, 114.80941278911564, 114.72184648648648, 114.64405261744967, 114.55408426666666, 114.41580291390729, 114.3308, 114.27059869281045, 114.18505260423433, 114.14871122580645, 113.99949128205128, 113.94442191082803, 113.83386734177216, 113.59835371069182, 113.515388, 113.6068849689441, 113.52565728395062, 113.47399852760736, 113.35184, 113.3104446060606, 113.19637204819277, 113.12842730538924, 113.09605333333333, 113.08127621301774, 112.81183811764706, 112.9294203508772, 112.81810418604651, 112.69997317919075, 112.63358712643677, 112.5452672, 112.50175090909092, 112.52005423728812, 112.43650516853933, 112.34864983240223, 112.20527644444445, 112.20484950276244, 112.19415912087912, 112.13252546448088, 112.04997913043476, 112.02885535135137, 111.93645075268819, 111.89874994652408, 111.80677787234042, 111.73926264550266, 111.75360336842105, 111.62827225130889, 111.64060833333332, 111.58019481865286, 111.51077113402062, 111.32106666666667, 111.43125714285713, 111.37313757741902, 111.2588913131313, 111.27499738693469, 111.22497689768976} + w := NewWelford(time.Second*5, time.Millisecond*50) ok := false for i, x := range data { - if w.Update(x) { + if w.Update(x, x) { ok = true break }