feat(collector): add collector service

This commit is contained in:
2025-12-26 18:04:17 +03:00
parent a7e5670d7c
commit cfec8d0ff6
8 changed files with 569 additions and 40 deletions

View File

@@ -0,0 +1,114 @@
#!/usr/bin/env python3
"""
FR-2.2: Audio Data Validation
Validates audio metrics against expected ranges
"""
from typing import NamedTuple
class ValidationResult(NamedTuple):
"""Validation result"""
valid: bool
error: str = ""
class AudioValidator:
"""
Validates audio metrics against hardware constraints and realistic ranges.
"""
# Hardware constraints (from FR spec)
RMS_MIN_DB = -40.0 # Noise floor
RMS_MAX_DB = 80.0 # Clipping threshold
FREQ_MIN_HZ = 100 # Below = unreliable (FFT bin size ~43Hz)
FREQ_MAX_HZ = 8000 # Nyquist @ 22.05kHz with safety margin
# Extended ranges for detection (not storage)
FREQ_MIN_EXTENDED_HZ = 20
FREQ_MAX_EXTENDED_HZ = 11000
@staticmethod
def validate_rms(rms_db: float) -> ValidationResult:
"""
Validate RMS value.
Args:
rms_db: RMS in dB
Returns:
ValidationResult with valid flag and error message
"""
if not isinstance(rms_db, (int, float)):
return ValidationResult(False, "RMS must be numeric")
if rms_db < AudioValidator.RMS_MIN_DB:
return ValidationResult(
False, f"RMS {rms_db:.1f}dB below minimum {AudioValidator.RMS_MIN_DB}dB"
)
if rms_db > AudioValidator.RMS_MAX_DB:
return ValidationResult(
False,
f"RMS {rms_db:.1f}dB exceeds maximum {AudioValidator.RMS_MAX_DB}dB",
)
return ValidationResult(True)
@staticmethod
def validate_frequency(freq_hz: int, strict: bool = True) -> ValidationResult:
"""
Validate frequency value.
Args:
freq_hz: Frequency in Hz
strict: If True, use tight range (100-8000Hz), else extended (20-11000Hz)
Returns:
ValidationResult with valid flag and error message
"""
if not isinstance(freq_hz, int):
return ValidationResult(False, "Frequency must be integer")
if strict:
min_hz = AudioValidator.FREQ_MIN_HZ
max_hz = AudioValidator.FREQ_MAX_HZ
else:
min_hz = AudioValidator.FREQ_MIN_EXTENDED_HZ
max_hz = AudioValidator.FREQ_MAX_EXTENDED_HZ
if freq_hz < min_hz:
return ValidationResult(
False, f"Frequency {freq_hz}Hz below minimum {min_hz}Hz"
)
if freq_hz > max_hz:
return ValidationResult(
False, f"Frequency {freq_hz}Hz exceeds maximum {max_hz}Hz"
)
return ValidationResult(True)
@staticmethod
def validate_packet(rms_db: float, freq_hz: int) -> ValidationResult:
"""
Validate complete audio packet.
Args:
rms_db: RMS in dB
freq_hz: Frequency in Hz
Returns:
ValidationResult with valid flag and error message
"""
rms_result = AudioValidator.validate_rms(rms_db)
if not rms_result.valid:
return rms_result
freq_result = AudioValidator.validate_frequency(freq_hz, strict=True)
if not freq_result.valid:
return freq_result
return ValidationResult(True)