Categorygithub.com/flaviostutz/signalutils
repositorypackage
1.12.2
Repository: https://github.com/flaviostutz/signalutils.git
Documentation: pkg.go.dev

# README

signalutils

Build Status

Event/Signal processing utilities lib for Golang. Online moving averager, linear regression, timed value, worker frequency control in Golang etc

See API documentation at https://pkg.go.dev/github.com/flaviostutz/signalutils?tab=doc

Usage

package main
import (
	"fmt"
	"github.com/flaviostutz/signalutils"
)

func main() {
	fmt.Printf("Moving Average\n")
	ma := signalutils.NewMovingAverage(5)
	ma.AddSample(0.00)
	ma.AddSample(99999.00)
	fmt.Printf("Average is %f\n", ma.Average())
	ma.AddSample(1000.00)
	ma.AddSample(2000.00)
	fmt.Printf("Average is %f\n", ma.Average())
	ma.AddSample(3000.00)
	ma.AddSample(4000.00)
	fmt.Printf("Average is %f\n", ma.Average())
	ma.AddSample(5000.00)
	ma.AddSample(6000.00)
	fmt.Printf("Average is %f\n", ma.Average())
}

Results

Moving Average
Average is 49999.500000
Average is 25749.750000
Average is 21999.800000
Average is 4000.000000

Utilities

  • MovingAverage - add values to an array with a fixed max size and query for the average of values in this fixed size array
	ma := NewMovingAverageTimeWindow(1*time.Second, 10)
	ma.AddSample(1000)
	ma.AddSample(2000)
	ma.AddSample(3000)
	ma.AddSample(4000)
	ma.AddSample(3000)
	ma.AddSample(2000)
	ma.AddSample(3000)
	ma.AddSample(2000)
	assert.Equal(t, 1000.0, ma.Average())
	time.Sleep(100 * time.Millisecond)
	ma.AddSample(3000)
	assert.Equal(t, 2000.0, ma.Average())
	ma.AddSample(2000)
	assert.Equal(t, 2000.0, ma.Average())
  • SchmittTrigger - set current values and track current up/down state based on schmitt trigger algorithm
	st, _ := NewSchmittTrigger(10, 20, false)
	assert.False(t, st.IsUpperRange())
	st.SetCurrentValue(11)
	assert.False(t, st.IsUpperRange())
	st.SetCurrentValue(15)
	assert.False(t, st.IsUpperRange())

	st.SetCurrentValue(21)
	assert.True(t, st.IsUpperRange())
	st.SetCurrentValue(25)
	assert.True(t, st.IsUpperRange())
	st.SetCurrentValue(18)
	assert.True(t, st.IsUpperRange())
  • DynamicSchmittTrigger - set current values and track current up/down state based on schmitt trigger algorithm. Trigger points are set dynamically set in a timelly manner.

  • StateTracker - set state identifications and if state has lots of successive repetitions, perform a state transition. Useful to filter out noises from state changes.

	st := NewStateTracker("state1", 3, onChange, 0, nil, true)
	st.SetTransientState("state2")
	st.SetTransientState("state2")
	assert.Equal(t, "state1", st.CurrentState.Name)
	st.SetTransientState("state2")
	assert.Equal(t, "state2", notifiedNewState.Name)
	st.SetTransientState("state3")
	assert.Equal(t, "state2", st.CurrentState.Name)
	st.SetTransientState("state3")
	st.SetTransientState("state2")
	st.SetTransientState("state3")
	st.SetTransientState("state3")
	assert.Equal(t, "state2", st.CurrentState.Name)
  • Timeseries - time/value array with max time span for keeping size at control. If you try to get values between time points, interpolation will occur.
	ts := NewTimeseries(1000 * time.Millisecond)

	ts.AddSample(-100)
	time.Sleep(500 * time.Millisecond)
	ts.AddSample(-1000)

	nv, ok := ts.GetValue(time.Now().Add(-250 * time.Millisecond))
	assert.True(t, ok)
	assert.InDeltaf(t, float64(-555), nv.Value, float64(20), "")
  • TimeseriesCounterRate - add counter values to a timeseries and query for rate at any time range. Something that ressembles "rate(metric_name[1m])" on Prometheus queries, for example.
	ts := NewTimeseriesCounterRate(1 * time.Second)

	_, ok := ts.Rate(1 * time.Second)
	assert.False(t, ok)

	ts.Inc(100000) //100000
	time.Sleep(300 * time.Millisecond)
	ts.Inc(100000) //200000
	time.Sleep(300 * time.Millisecond)
	ts.Inc(200000) //400000
	time.Sleep(300 * time.Millisecond)
	ts.Inc(100000) //500000
	time.Sleep(300 * time.Millisecond)

	_, ok = ts.Rate(2 * time.Second)
	assert.False(t, ok)
  • Worker - useful for workloads that works on a "while true" loop. It launches a Go routine with a function, limits the loop frequency, measures actual frequency and alerts if frequency is outside desired limits.
	w := StartWorker("test1", func() error {
		//do some real work here
		time.Sleep(15 * time.Millisecond)
		return nil
	}, 5, true)
	time.Sleep(200 * time.Millisecond)
	assert.True(t, w.active)
	time.Sleep(2000 * time.Millisecond)
	assert.InDeltaf(t, 5, w.CurrentFreq, 2, "")
	assert.InDeltaf(t, 15, w.CurrentStepTime.Milliseconds(), 5, "")
	w.Stop()
	time.Sleep(300 * time.Millisecond)
	assert.False(t, w.active)