mirror of
https://github.com/ruvnet/RuView
synced 2026-08-07 20:01:43 +00:00
8504638187
Operator-initiated calibration that records 30 s of stationary CSI,
emits a per-subcarrier baseline (amplitude mean+variance via Welford,
phase via circular sin/cos sums with von Mises dispersion), and gates
downstream stages on a deviation z-score. Plugs into multistatic
coherence gating, motion/presence detection, and the new ADR-134 CIR
estimator as a reference-subtracted input.
API surface (under wifi_densepose_signal):
CalibrationConfig::{ht20, ht40, he20, he40}
CalibrationRecorder { record(), finalize(), frames_recorded() }
BaselineCalibration {
subcarriers: Vec<SubcarrierBaseline>,
deviation(&CsiFrame), subtract_in_place(&mut CsiFrame),
to_bytes(), from_bytes()
}
CalibrationDeviationScore { amplitude_z_median, amplitude_z_max,
phase_drift_median, motion_flagged }
CalibrationError { SubcarrierMismatch, TierMismatch,
InsufficientFrames, VersionMismatch, TruncatedBuffer }
Binary baseline format: magic 0xCA1B_0001 + u8 version=1 + u8 tier +
captured_at_unix_s (i64) + frame_count (u64) + num_subcarriers (u32) +
[SubcarrierBaseline; N] as 16 bytes each (amp_mean, amp_variance,
phase_mean, phase_dispersion as f32 LE). Hand-written serialisation so
the format is stable across Rust toolchain versions without serde drift.
CLI: new `wifi-densepose calibrate` subcommand binds a UDP listener
(0xC511_0001 frames), streams them through CalibrationRecorder, prints
a real-time z-score banner per ADR-135 §risk 1 (operator-may-be-moving),
aborts on sustained high deviation, and writes the binary baseline to
disk. Local UDP packet parser duplicated from sensing-server (per ADR
discussion — avoids cross-crate API churn).
Witness: cross-platform-deterministic SHA-256 over the per-subcarrier
quantised baseline profile (u16 LE at 1e-2/1e-4/1e-3, no sort) using
the lesson learnt from the CIR PR #837 libm-jitter fix. Hash:
d6bce07ecb1648e6936561df44bf4a3bfc17bb0ba5f692646b2301d105b52f67
CI guard: new "ADR-135 calibration witness proof (determinism guard)"
step under the Rust Workspace Tests job, adjacent to the existing
ADR-134 CIR guard. Regressions are unambiguously attributable.
Hardware-in-loop validation: full 600-frame capture exercised via the
new scripts/synth-csi-udp.py emitter targeting 127.0.0.1:5005. The CLI
binary received 600 frames at 20 Hz, z_med stable at ~0.7, motion
correctly NOT flagged, finalised baseline written to baseline.bin (860
bytes) with correct magic + version + timestamp in the header. Live
ESP32 capture from COM9 is operator follow-up — requires provisioning
the firmware's UDP target IP to match the host running the CLI.
Test results (cargo test -p wifi-densepose-signal --no-default-features):
lib: 382 pass / 0 fail / 1 ignored
calibration_synthetic: 17 pass / 0 fail
calibration_drift: 5 pass / 0 fail
calibration_roundtrip: 10 pass / 0 fail
cir_*: 9 pass + 6 documented P2 ignores
doctest: 10 pass
Bench: 20 Criterion combinations registered
(recorder_record / recorder_finalize / deviation / record_600 /
to_bytes across HT20/HT40/HE20/HE40 tiers).
Witness: bash scripts/verify-calibration-proof.sh → VERDICT: PASS
Co-Authored-By: claude-flow <ruv@ruv.net>
129 lines
3.9 KiB
Rust
129 lines
3.9 KiB
Rust
//! WiFi-DensePose Signal Processing Library
|
|
//!
|
|
//! This crate provides signal processing capabilities for WiFi-based human pose estimation,
|
|
//! including CSI (Channel State Information) processing, phase sanitization, feature extraction,
|
|
//! and motion detection.
|
|
//!
|
|
//! # Features
|
|
//!
|
|
//! - **CSI Processing**: Preprocessing, noise removal, windowing, and normalization
|
|
//! - **Phase Sanitization**: Phase unwrapping, outlier removal, and smoothing
|
|
//! - **Feature Extraction**: Amplitude, phase, correlation, Doppler, and PSD features
|
|
//! - **Motion Detection**: Human presence detection with confidence scoring
|
|
//!
|
|
//! # Example
|
|
//!
|
|
//! ```rust,no_run
|
|
//! use wifi_densepose_signal::{
|
|
//! CsiProcessor, CsiProcessorConfig,
|
|
//! PhaseSanitizer, PhaseSanitizerConfig,
|
|
//! MotionDetector,
|
|
//! };
|
|
//!
|
|
//! // Configure CSI processor
|
|
//! let config = CsiProcessorConfig::builder()
|
|
//! .sampling_rate(1000.0)
|
|
//! .window_size(256)
|
|
//! .overlap(0.5)
|
|
//! .noise_threshold(-30.0)
|
|
//! .build();
|
|
//!
|
|
//! let processor = CsiProcessor::new(config);
|
|
//! ```
|
|
|
|
pub mod bvp;
|
|
pub mod csi_processor;
|
|
pub mod csi_ratio;
|
|
pub mod features;
|
|
pub mod fresnel;
|
|
pub mod hampel;
|
|
pub mod hardware_norm;
|
|
pub mod motion;
|
|
pub mod phase_sanitizer;
|
|
pub mod ruvsense;
|
|
pub mod spectrogram;
|
|
pub mod subcarrier_selection;
|
|
|
|
// Re-export main types for convenience
|
|
pub use csi_processor::{
|
|
CsiData, CsiDataBuilder, CsiPreprocessor, CsiProcessor, CsiProcessorConfig,
|
|
CsiProcessorConfigBuilder, CsiProcessorError,
|
|
};
|
|
pub use features::{
|
|
AmplitudeFeatures, CorrelationFeatures, CsiFeatures, DopplerFeatures, FeatureExtractor,
|
|
FeatureExtractorConfig, PhaseFeatures, PowerSpectralDensity,
|
|
};
|
|
pub use hardware_norm::{
|
|
AmplitudeStats, CanonicalCsiFrame, HardwareNormError, HardwareNormalizer, HardwareType,
|
|
};
|
|
pub use motion::{
|
|
HumanDetectionResult, MotionAnalysis, MotionDetector, MotionDetectorConfig, MotionScore,
|
|
};
|
|
pub use phase_sanitizer::{
|
|
PhaseSanitizationError, PhaseSanitizer, PhaseSanitizerConfig, UnwrappingMethod,
|
|
};
|
|
|
|
// ADR-134: CIR top-level re-exports
|
|
pub use ruvsense::cir;
|
|
pub use ruvsense::cir::{Cir, CirConfig, CirError, CirEstimator};
|
|
|
|
// ADR-135: Baseline calibration top-level re-exports
|
|
pub use ruvsense::calibration;
|
|
pub use ruvsense::calibration::{
|
|
BaselineCalibration, CalibrationConfig, CalibrationDeviationScore, CalibrationError,
|
|
CalibrationRecorder, PhyTier, SubcarrierBaseline,
|
|
};
|
|
|
|
/// Library version
|
|
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
|
|
|
|
/// Common result type for signal processing operations
|
|
pub type Result<T> = std::result::Result<T, SignalError>;
|
|
|
|
/// Unified error type for signal processing operations
|
|
#[derive(Debug, thiserror::Error)]
|
|
pub enum SignalError {
|
|
/// CSI processing error
|
|
#[error("CSI processing error: {0}")]
|
|
CsiProcessing(#[from] CsiProcessorError),
|
|
|
|
/// Phase sanitization error
|
|
#[error("Phase sanitization error: {0}")]
|
|
PhaseSanitization(#[from] PhaseSanitizationError),
|
|
|
|
/// Feature extraction error
|
|
#[error("Feature extraction error: {0}")]
|
|
FeatureExtraction(String),
|
|
|
|
/// Motion detection error
|
|
#[error("Motion detection error: {0}")]
|
|
MotionDetection(String),
|
|
|
|
/// Invalid configuration
|
|
#[error("Invalid configuration: {0}")]
|
|
InvalidConfig(String),
|
|
|
|
/// Data validation error
|
|
#[error("Data validation error: {0}")]
|
|
DataValidation(String),
|
|
}
|
|
|
|
/// Prelude module for convenient imports
|
|
pub mod prelude {
|
|
pub use crate::csi_processor::{CsiData, CsiProcessor, CsiProcessorConfig};
|
|
pub use crate::features::{CsiFeatures, FeatureExtractor};
|
|
pub use crate::motion::{HumanDetectionResult, MotionDetector};
|
|
pub use crate::phase_sanitizer::{PhaseSanitizer, PhaseSanitizerConfig};
|
|
pub use crate::{Result, SignalError};
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn test_version() {
|
|
assert!(VERSION.contains('.'), "VERSION should be a semver string");
|
|
}
|
|
}
|