succd: Add hysteresis feature to thresholdOutput blocks

Add a hysteresis value that can be optionally configured for
thresholdOutput blocks.  This will hopefully help to prevent jumping
outputs from feedback that is caused by the thresholdOutput itself.
This commit is contained in:
Rahix 2024-10-04 22:33:22 +02:00
parent ed8adad611
commit 8645718748
2 changed files with 29 additions and 5 deletions

View file

@ -30,13 +30,20 @@ type thresholdOutput struct {
debounce time.Time
// threshold is the setpoint of the block.
threshold float64
// hysteresis around the process setpoint (min/max is threshold +- hysteresis)
hysteresis float64
}
func (t *thresholdOutput) process(value float64) {
if time.Now().Before(t.debounce) {
return
}
new := value > t.threshold
new := t.output
if t.output {
new = value > (t.threshold - t.hysteresis)
} else {
new = value > (t.threshold + t.hysteresis)
}
if new != t.output {
t.output = new
t.debounce = time.Now().Add(time.Second * 5)

View file

@ -26,20 +26,37 @@ func TestMomentaryOutput(t *testing.T) {
func TestThresholdOutput(t *testing.T) {
to := thresholdOutput{
threshold: 1,
threshold: 1,
hysteresis: 0.2,
}
to.process(0)
to.process(0.7)
if to.output {
t.Fatalf("output shouldn't have triggered")
}
to.process(2)
to.process(1)
if to.output {
t.Fatalf("output shouldn't have triggered")
}
to.process(1.3)
if !to.output {
t.Fatalf("output should have triggered")
}
to.process(0)
to.process(1)
if !to.output {
t.Fatalf("output should have triggered")
}
to.process(0.7)
if !to.output {
t.Fatalf("output should have triggered (in debounce)")
}
// let debounce timeout pass
time.Sleep(time.Second * 6)
to.process(0.7)
if to.output {
t.Fatalf("output shouldn't have triggered")
}
}
func TestRingbufferInput(t *testing.T) {