Replay Tabs:
- Add stability detection and threshold classification features with corresponding tests
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
"""Classify sensor values into three bands around (target, margin)
|
||||
|
||||
Auto mode derives target=mean, margin=1
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
import math
|
||||
from dataclasses import dataclass
|
||||
|
||||
BAND_IN = "in_range"
|
||||
BAND_HIGH = "high"
|
||||
BAND_LOW = "low"
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ThresholdConfig:
|
||||
set_point: float = 149.0 # process target: used as band TARGET when auto=False
|
||||
margin: float = 1.0 # used as band MARGIN when auto=False
|
||||
auto: bool = True # auto=True: target=frame mean, margin=frame 1σ
|
||||
|
||||
def resolve_bounds(values: list[float], cfg: ThresholdConfig) -> tuple[float, float]:
|
||||
if not cfg.auto:
|
||||
return cfg.set_point, cfg.margin
|
||||
clean = [v for v in values if not math.isnan(v)]
|
||||
if not clean:
|
||||
return cfg.set_point, cfg.margin
|
||||
mean = sum(clean) / len(clean)
|
||||
variance = sum((v - mean) ** 2 for v in clean) / len(clean)
|
||||
return mean, math.sqrt(variance)
|
||||
|
||||
def classify(value: float, target: float, margin: float) -> str:
|
||||
if math.isnan(value):
|
||||
return BAND_IN
|
||||
if value > target + margin:
|
||||
return BAND_HIGH
|
||||
if value < target - margin:
|
||||
return BAND_LOW
|
||||
return BAND_IN
|
||||
|
||||
def classify_all(values: list[float], cfg: ThresholdConfig) -> list[str]:
|
||||
target, margin = resolve_bounds(values, cfg)
|
||||
return [classify(v, target, margin)for v in values ]
|
||||
Reference in New Issue
Block a user