Temporal Smoothing Techniques for CSI Phase Trajectories in WiFi‑DensePose

WiFi‑DensePose employs three distinct temporal smoothing mechanisms—moving‑average filtering, Butterworth low‑pass filtering, and exponential moving‑average (EMA) on detection confidence—to stabilize noisy CSI phase trajectories before pose estimation.

The ruvnet/wifi-densepose repository processes raw Channel State Information (CSI) through a dedicated sanitization pipeline that applies these temporal smoothing techniques for CSI phase trajectories to suppress high‑frequency jitter while preserving essential motion cues. Understanding these filtering stages is critical for configuring the trade‑off between noise reduction and motion fidelity in dense pose reconstruction systems.

Moving‑Average Smoothing for Phase Trajectories

The first smoothing layer operates inside PhaseSanitizer within v1/src/core/phase_sanitizer.py. The smooth_phase method delegates to _apply_moving_average, which implements a symmetric sliding window mean.

Implementation Details

The method accepts a configurable smoothing_window parameter. If the supplied window size is even, the implementation automatically increments it to the next odd integer, ensuring a symmetric neighborhood around each sample. This prevents phase shifts that would otherwise distort the temporal alignment of the CSI data.

from v1.src.core.phase_sanitizer import PhaseSanitizer

config = {
    'unwrapping_method': 'numpy',
    'outlier_threshold': 3.0,
    'smoothing_window': 5,          # Must be odd; auto-corrected if even

    'enable_smoothing': True,
    'enable_noise_filtering': True,
    'noise_threshold': 0.05         # Butterworth cutoff (fraction of Nyquist)

}
sanitizer = PhaseSanitizer(config)

raw_phase = ...                     # np.ndarray shape (antennas, samples)

clean_phase = sanitizer.sanitize_phase(raw_phase)

Butterworth Low‑Pass Filtering

Following the moving‑average stage, the pipeline applies a 4th‑order Butterworth low‑pass filter via the filter_noise method, which calls _apply_low_pass_filter. This stage targets residual high‑frequency artifacts that survive the initial averaging.

Zero‑Phase Filtering

The cutoff frequency is proportional to the noise_threshold parameter, expressed as a fraction of the Nyquist rate. The implementation uses scipy.signal.filtfilt to apply the filter forward and backward, eliminating group delay and ensuring zero phase distortion. This preserves the temporal alignment of phase trajectories critical for accurate time‑of‑flight calculations.

Exponential Moving Average for Detection Confidence

Beyond the phase trajectory itself, WiFi‑DensePose stabilizes binary human‑presence decisions using an exponential moving‑average (EMA) implemented in v1/src/core/csi_processor.py. The CSIProcessor._apply_temporal_smoothing method smooths scalar confidence scores across successive CSI frames.

EMA Formula and Configuration

The smoothing follows the recurrence relation:

smoothed = α · previous + (1 − α) · raw

Here, α corresponds to the configurable smoothing_factor (typically near 0.9). This technique prevents rapid oscillations between detection states when noise temporarily perturbs the signal energy.

from v1.src.core.csi_processor import CSIProcessor

proc_cfg = {
    'sampling_rate': 1000,
    'window_size': 256,
    'overlap': 0.5,
    'noise_threshold': 0.1,
    'smoothing_factor': 0.9       # EMA coefficient α

}
processor = CSIProcessor(proc_cfg)

csi_data = ...                    # CSIData instance

result = await processor.process_csi_data(csi_data)

print(f"Human detected: {result.human_detected}, confidence (smoothed): {result.confidence}")

Configuration and Implementation Examples

All three temporal smoothing techniques for CSI phase trajectories expose hyperparameters through the configuration dictionaries passed to PhaseSanitizer and CSIProcessor. When tuning these values:

  • Increase smoothing_window to aggressively suppress jitter, but expect increased latency and potential smearing of rapid motion.
  • Decrease noise_threshold to raise the Butterworth cutoff and preserve high‑frequency motion details.
  • Adjust smoothing_factor closer to 1.0 for stronger confidence stabilization, or closer to 0.0 for faster reaction to appearance/disappearance events.

Summary

  • Moving‑average smoothing in v1/src/core/phase_sanitizer.py applies a symmetric sliding window mean with automatic odd‑window correction via _apply_moving_average.
  • Butterworth low‑pass filtering uses a 4th‑order design with scipy.signal.filtfilt for zero‑phase distortion, configured by noise_threshold.
  • Exponential moving‑average in v1/src/core/csi_processor.py stabilizes detection confidence scores using _apply_temporal_smoothing with configurable coefficient α.
  • These stages execute sequentially within sanitize_phase() and process_csi_data() to yield temporally coherent phase trajectories suitable for dense pose estimation.

Frequently Asked Questions

What is the default window size for moving‑average smoothing in WiFi‑DensePose?

The default configuration typically sets smoothing_window to 5 samples, though the implementation accepts any positive integer. If you supply an even number, the _apply_moving_average method automatically increments it to the nearest odd integer to maintain symmetry.

Why does the Butterworth filter use filtfilt instead of lfilter?

The _apply_low_pass_filter method uses scipy.signal.filtfilt to process the signal both forward and backward. This zero‑phase filtering technique cancels out the group delay inherent in causal IIR filters, ensuring that peaks and troughs in the CSI phase trajectory remain temporally aligned with the original raw data.

How does the EMA smoothing factor affect human detection latency?

A high smoothing_factor (e.g., 0.95) makes the EMA in _apply_temporal_smoothing heavily weight historical confidence values, reducing false‑positive flicker but introducing lag when a human actually enters the scene. Conversely, a low factor (e.g., 0.5) makes the system responsive but more susceptible to noise‑induced state changes.

Can I disable temporal smoothing if I need raw phase data?

Yes. Setting enable_smoothing to False in the PhaseSanitizer configuration skips the moving‑average stage, and setting enable_noise_filtering to False bypasses the Butterworth filter. However, the EMA in CSIProcessor is typically always active unless you modify the source code to skip the _apply_temporal_smoothing call.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →