Add sensor weight

This commit is contained in:
Søren Rasmussen 2022-03-11 20:46:18 +01:00
parent e5d5b6ca2f
commit 2d4dfa73d6
7 changed files with 61 additions and 26 deletions

View file

@ -55,7 +55,7 @@ func persistData(ctx context.Context, wg *sync.WaitGroup, chState <-chan control
break
}
err := datlog("%v TEMP %v %v", t.Time.Unix(), t.Sensor, t.MilliDegrees)
err := datlog("%v TEMP %v %v", t.Time.Unix(), t.Sensor, t.Degrees)
if err != nil {
hub.CaptureException(err)
log.Printf("Error persisting temperature reading: %v", err)

View file

@ -56,7 +56,7 @@ func mainLoop(ctx context.Context, wg *sync.WaitGroup, js nats.JetStream, config
wg.Add(3)
go persistData(ctx, wg, chDbState, chDbTemp, config)
go ctrl.Run(ctx, wg)
go temperature.PollSensors(ctx, wg, 1*time.Second)
go temperature.PollSensors(ctx, wg, 1*time.Second, config.Sensors.Weight)
for {
select {

View file

@ -89,18 +89,18 @@ func (p *ChamberController) Run(ctx context.Context, wg *sync.WaitGroup) {
func (p *ChamberController) setTemperature(t temperature.TemperatureReading) {
switch t.Sensor {
case p.config.Sensor.Ambient:
p.ambientTemperature = t.Degrees()
case p.config.Sensors.Ambient:
p.ambientTemperature = t.Degrees
case p.config.Sensor.Chamber:
p.chamberTemperature = t.Degrees()
case p.config.Sensors.Chamber:
p.chamberTemperature = t.Degrees
case p.config.Sensor.Wort:
p.wortTemperature = t.Degrees()
case p.config.Sensors.Wort:
p.wortTemperature = t.Degrees
default:
log.Printf("Unknown sensor: sensor=%v temp=%v", t.Sensor, t.MilliDegrees)
p.hub.CaptureMessage(fmt.Sprintf("Unknown sensor: sensor=%v temp=%v", t.Sensor, t.MilliDegrees))
log.Printf("Unknown sensor: sensor=%v temp=%v", t.Sensor, t.Degrees)
p.hub.CaptureMessage(fmt.Sprintf("Unknown sensor: sensor=%v temp=%v", t.Sensor, t.Degrees))
}
}

View file

@ -16,10 +16,11 @@ type ControllerConfig struct {
DataPath string `mapstructure:"data_path"`
Sensor struct {
Sensors struct {
Wort string `mapstructure:"wort"`
Chamber string `mapstructure:"chamber"`
Ambient string `mapstructure:"ambient"`
Weight float64 `mapstructure:"weight"`
} `mapstructure:"sensors"`
FermentationTemperature float64 `mapstructure:"fermentation_temp"`

View file

@ -36,16 +36,18 @@ var (
sensors []string
accErrTrigger int
accErrSensor map[string]int
filters map[string]*EWMAFilter
)
func Initialize() {
sensors = make([]string, 0)
filters = make(map[string]*EWMAFilter)
C = make(chan TemperatureReading, 30)
ConfigUpdates = make(chan []string, 1)
accErrSensor = make(map[string]int)
}
func PollSensors(ctx context.Context, wg *sync.WaitGroup, readingInterval time.Duration) {
func PollSensors(ctx context.Context, wg *sync.WaitGroup, readingInterval time.Duration, filterWeight float64) {
hub := sentry.CurrentHub().Clone()
defer hub.Flush(10 * time.Second)
defer wg.Done()
@ -95,6 +97,13 @@ func PollSensors(ctx context.Context, wg *sync.WaitGroup, readingInterval time.D
case c := <-ConfigUpdates:
sensors = c
for k := range filters {
delete(filters, k)
}
for _, x := range sensors {
filters[x] = NewEWMAFilter(filterWeight)
}
case <-ctx.Done():
close(C)
return
@ -115,16 +124,17 @@ func readSensors(hub *sentry.Hub) {
}
accErrSensor[sensor] = 0
tw := filters[sensor].Update(float64(t) / 1000)
r := TemperatureReading{
Time: time.Now(),
Sensor: sensor,
MilliDegrees: t,
Degrees: tw,
}
metrics.TemperatureSensorReadingDegreesCelcius.
WithLabelValues(sensor).
Set(r.Degrees())
Set(tw)
C <- r

28
pkg/temperature/filter.go Normal file
View file

@ -0,0 +1,28 @@
package temperature
// EWMAFilter is an exponentially weighted moving average filter
// See https://hackaday.com/2019/09/06/sensor-filters-for-coders/
type EWMAFilter struct {
weight float64
prevTemp float64
isInitialized bool
}
func NewEWMAFilter(weight float64) *EWMAFilter {
return &EWMAFilter{
weight: weight,
}
}
func (p *EWMAFilter) Update(input float64) float64 {
if !p.isInitialized {
p.prevTemp = input
p.isInitialized = true
return input
}
ewmf := (1-p.weight)*p.prevTemp + p.weight*input
p.prevTemp = ewmf
return ewmf
}

View file

@ -5,9 +5,5 @@ import "time"
type TemperatureReading struct {
Sensor string `json:"sensor"`
Time time.Time `json:"time"`
MilliDegrees int64 `json:"milli_degrees"`
}
func (t *TemperatureReading) Degrees() float64 {
return float64(t.MilliDegrees) / 1000.0
Degrees float64 `json:"degrees"`
}