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:
parent
051a4bec94
commit
0757ec58a8
|
@ -30,13 +30,20 @@ type thresholdOutput struct {
|
||||||
debounce time.Time
|
debounce time.Time
|
||||||
// threshold is the setpoint of the block.
|
// threshold is the setpoint of the block.
|
||||||
threshold float64
|
threshold float64
|
||||||
|
// hysteresis around the process setpoint (min/max is threshold +- hysteresis)
|
||||||
|
hysteresis float64
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *thresholdOutput) process(value float64) {
|
func (t *thresholdOutput) process(value float64) {
|
||||||
if time.Now().Before(t.debounce) {
|
if time.Now().Before(t.debounce) {
|
||||||
return
|
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 {
|
if new != t.output {
|
||||||
t.output = new
|
t.output = new
|
||||||
t.debounce = time.Now().Add(time.Second * 5)
|
t.debounce = time.Now().Add(time.Second * 5)
|
||||||
|
|
|
@ -27,19 +27,36 @@ func TestMomentaryOutput(t *testing.T) {
|
||||||
func TestThresholdOutput(t *testing.T) {
|
func TestThresholdOutput(t *testing.T) {
|
||||||
to := thresholdOutput{
|
to := thresholdOutput{
|
||||||
threshold: 1,
|
threshold: 1,
|
||||||
|
hysteresis: 0.2,
|
||||||
}
|
}
|
||||||
to.process(0)
|
to.process(0.7)
|
||||||
if to.output {
|
if to.output {
|
||||||
t.Fatalf("output shouldn't have triggered")
|
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 {
|
if !to.output {
|
||||||
t.Fatalf("output should have triggered")
|
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 {
|
if !to.output {
|
||||||
t.Fatalf("output should have triggered (in debounce)")
|
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) {
|
func TestRingbufferInput(t *testing.T) {
|
||||||
|
|
Loading…
Reference in a new issue