succd: factor out ringbuffer, do not recalculate average on every request

This commit is contained in:
Serge Bazanski 2024-09-28 09:35:41 +02:00
parent 42c9ae2fa7
commit 4df00f0a63
3 changed files with 47 additions and 32 deletions

View file

@ -28,6 +28,8 @@ func main() {
d := daemon{}
d.daemonState.rpOn = true
d.daemonState.piraniVolts3.limit = 3
d.daemonState.piraniVolts100.limit = 100
d.aboveRough.threshold = float64(flagPressureThresholdRough)
d.aboveHigh.threshold = float64(flagPressureThresholdHigh)

View file

@ -66,6 +66,33 @@ func (t *thresholdOutput) process(value float64) {
}
}
// ringbufferInput accumulates analog data up to limit samples, and calculates
// an average.
type ringbufferInput struct {
data []float32
limit uint
avg float32
}
func (r *ringbufferInput) process(input float32) {
// TODO(q3k): use actual ringbuffer
// TODO(q3k): optimize average calculation
// TODO(q3k): precalculate value in mbar
r.data = append(r.data, input)
trim := len(r.data) - int(r.limit)
if trim > 0 {
r.data = r.data[trim:]
}
avg := float32(0.0)
for _, v := range r.data {
avg += v
}
if len(r.data) != 0 {
avg /= float32(len(r.data))
}
r.avg = avg
}
// process runs the pain acquisition and control loop of succd.
func (d *daemon) process(ctx context.Context) {
ticker := time.NewTicker(time.Millisecond * 100)
@ -96,12 +123,9 @@ func (d *daemon) processOnce(_ context.Context) error {
d.mu.Lock()
defer d.mu.Unlock()
// Process pirani ringbuffer.
d.adcPiraniVolts = append(d.adcPiraniVolts, v)
trim := len(d.adcPiraniVolts) - 100
if trim > 0 {
d.adcPiraniVolts = d.adcPiraniVolts[trim:]
}
// Process pirani ringbuffers.
d.piraniVolts3.process(v)
d.piraniVolts100.process(v)
d.pumpdown.process()
d.vent.process()

View file

@ -7,9 +7,9 @@ import "math"
type daemonState struct {
safety safetyStatus
// adcPiraniVolts is a moving window of read ADC values, used to calculate a
// moving average.
adcPiraniVolts []float32
piraniVolts100 ringbufferInput
piraniVolts3 ringbufferInput
rpOn bool
dpOn bool
@ -42,20 +42,18 @@ const (
piraniDetectionDisconnected = iota
)
func piraniVoltsToMbar(v float32) float32 {
// Per Pirani probe docs.
bar := math.Pow(10.0, float64(v)-8.5)
return float32(bar * 1000.0)
}
// piraniDetection guesses whether the pirani gauge is connected.
func (d *daemonState) piraniDetection() piraniDetection {
if len(d.adcPiraniVolts) < 3 {
if len(d.piraniVolts3.data) < int(d.piraniVolts3.limit) {
return piraniDetectionUnknown
}
volts := float32(0.0)
for _, v := range d.adcPiraniVolts[len(d.adcPiraniVolts)-3:] {
volts += v
}
volts /= 3.0
bar := math.Pow(10.0, float64(volts)-8.5)
mbar := float32(bar * 1000.0)
mbar := piraniVoltsToMbar(d.piraniVolts3.avg)
if mbar < 4e-6 {
return piraniDetectionDisconnected
}
@ -63,17 +61,8 @@ func (d *daemonState) piraniDetection() piraniDetection {
}
func (d *daemonState) pirani() (volts float32, mbar float32) {
volts = 0.0
for _, v := range d.adcPiraniVolts {
volts += v
}
if len(d.adcPiraniVolts) != 0 {
volts /= float32(len(d.adcPiraniVolts))
}
// Per Pirani probe docs.
bar := math.Pow(10.0, float64(volts)-8.5)
mbar = float32(bar * 1000.0)
volts = d.piraniVolts100.avg
mbar = piraniVoltsToMbar(volts)
return
}