summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--stabilizer/rev3.go124
-rw-r--r--stabilizer/stabilizer.go6
2 files changed, 130 insertions, 0 deletions
diff --git a/stabilizer/rev3.go b/stabilizer/rev3.go
new file mode 100644
index 0000000..e81fc76
--- /dev/null
+++ b/stabilizer/rev3.go
@@ -0,0 +1,124 @@
+package stabilizer
+
+import (
+ "fmt"
+ "sync"
+
+ "github.com/network-quality/goresponsiveness/debug"
+ "github.com/network-quality/goresponsiveness/ms"
+ "github.com/network-quality/goresponsiveness/rpm"
+ "github.com/network-quality/goresponsiveness/utilities"
+)
+
+type DataPointStabilizer struct {
+ instantaneousMeasurements *ms.MathematicalSeries[float64]
+ movingAverages *ms.MathematicalSeries[float64]
+ stabilityStandardDeviation float64
+ m sync.Mutex
+ dbgLevel debug.DebugLevel
+ dbgConfig *debug.DebugWithPrefix
+}
+
+type ProbeStabilizer DataPointStabilizer
+type ThroughputStabilizer DataPointStabilizer
+
+// Stabilizer parameters:
+// 1. I: The number of previous instantaneous measurements to consider when generating
+// the so-called instantaneous moving averages.
+// 2. K: The number of instantaneous moving averages to consider when determining stability.
+// 3: S: The standard deviation cutoff used to determine stability among the K preceding
+// moving averages of a measurement.
+
+func NewProbeStabilizer(i int, k int, s float64, debugLevel debug.DebugLevel, debug *debug.DebugWithPrefix) ProbeStabilizer {
+ return ProbeStabilizer{instantaneousMeasurements: ms.NewMathematicalSeries[float64](i),
+ movingAverages: ms.NewMathematicalSeries[float64](k),
+ stabilityStandardDeviation: s,
+ dbgConfig: debug,
+ dbgLevel: debugLevel}
+}
+
+func (r3 *ProbeStabilizer) AddMeasurement(measurement rpm.ProbeDataPoint) {
+ r3.m.Lock()
+ defer r3.m.Unlock()
+ // Add this instantaneous measurement to the mix of the I previous instantaneous measurements.
+ r3.instantaneousMeasurements.AddElement(measurement.Duration.Seconds())
+ // Calculate the moving average of the I previous instantaneous measurements and add it to
+ // the mix of K previous moving averages.
+ r3.movingAverages.AddElement(r3.instantaneousMeasurements.CalculateAverage())
+
+ if debug.IsDebug(r3.dbgLevel) {
+ fmt.Printf(
+ "%s: MA: %f ns (previous %d intervals).\n",
+ r3.dbgConfig.String(),
+ r3.movingAverages.CalculateAverage(),
+ r3.movingAverages.Size(),
+ )
+ }
+}
+
+func (r3 *ProbeStabilizer) IsStable() bool {
+ // calculate whether the standard deviation of the K previous moving averages falls below S.
+ islt, stddev := r3.movingAverages.StandardDeviationLessThan(r3.stabilityStandardDeviation)
+
+ if debug.IsDebug(r3.dbgLevel) {
+ fmt.Printf(
+ "%s: Standard Deviation: %f s; Is Normally Distributed? %v).\n",
+ r3.dbgConfig.String(),
+ stddev,
+ r3.movingAverages.IsNormallyDistributed(),
+ )
+ fmt.Printf("%s: Values: ", r3.dbgConfig.String())
+ for _, v := range r3.movingAverages.Values() {
+ fmt.Printf("%v, ", v)
+ }
+ fmt.Printf("\n")
+ }
+ return islt
+}
+
+func NewThroughputStabilizer(i int, k int, s float64, debugLevel debug.DebugLevel, debug *debug.DebugWithPrefix) ThroughputStabilizer {
+ return ThroughputStabilizer{instantaneousMeasurements: ms.NewMathematicalSeries[float64](i),
+ movingAverages: ms.NewMathematicalSeries[float64](k),
+ stabilityStandardDeviation: s,
+ dbgConfig: debug,
+ dbgLevel: debugLevel}
+}
+
+func (r3 *ThroughputStabilizer) AddMeasurement(measurement rpm.ThroughputDataPoint) {
+ r3.m.Lock()
+ defer r3.m.Unlock()
+ // Add this instantaneous measurement to the mix of the I previous instantaneous measurements.
+ r3.instantaneousMeasurements.AddElement(utilities.ToMbps(measurement.Throughput))
+ // Calculate the moving average of the I previous instantaneous measurements and add it to
+ // the mix of K previous moving averages.
+ r3.movingAverages.AddElement(r3.instantaneousMeasurements.CalculateAverage())
+
+ if debug.IsDebug(r3.dbgLevel) {
+ fmt.Printf(
+ "%s: MA: %f Mbps (previous %d intervals).\n",
+ r3.dbgConfig.String(),
+ r3.movingAverages.CalculateAverage(),
+ r3.movingAverages.Size(),
+ )
+ }
+}
+
+func (r3 *ThroughputStabilizer) IsStable() bool {
+ // calculate whether the standard deviation of the K previous moving averages falls below S.
+ islt, stddev := r3.movingAverages.StandardDeviationLessThan(r3.stabilityStandardDeviation)
+
+ if debug.IsDebug(r3.dbgLevel) {
+ fmt.Printf(
+ "%s: Standard Deviation: %f Mbps; Is Normally Distributed? %v).\n",
+ r3.dbgConfig.String(),
+ stddev,
+ r3.movingAverages.IsNormallyDistributed(),
+ )
+ fmt.Printf("%s: Values: ", r3.dbgConfig.String())
+ for _, v := range r3.movingAverages.Values() {
+ fmt.Printf("%v, ", v)
+ }
+ fmt.Printf("\n")
+ }
+ return islt
+}
diff --git a/stabilizer/stabilizer.go b/stabilizer/stabilizer.go
new file mode 100644
index 0000000..d85cedc
--- /dev/null
+++ b/stabilizer/stabilizer.go
@@ -0,0 +1,6 @@
+package stabilizer
+
+type Stabilizer[T any] interface {
+ AddMeasurement(T)
+ IsStable() bool
+}