How Human Movement Affects Wi-Fi CSI Signals: A Technical Analysis of the wifi-densepose Repository

When humans move through a Wi-Fi environment, they alter multipath propagation paths, causing measurable variations in Channel State Information (CSI) amplitude, phase, and frequency-domain characteristics that the wifi-densepose pipeline detects through statistical feature extraction and temporal analysis.

Human movement detection through walls and obstacles using commodity Wi-Fi hardware relies on capturing subtle changes in Channel State Information (CSI). The open-source wifi-densepose repository (ruvnet/wifi-densepose) implements a complete pipeline that demonstrates how human movement affects Wi-Fi CSI signals by processing raw IQ samples into motion confidence scores and spatial features.

The Physics of Movement in Wi-Fi Channels

Wi-Fi CSI captures the complex-valued channel response for every sub-carrier, antenna pair, and transmit-receive combination. When a person moves, their body blocks, reflects, and scatters radio frequency signals, dynamically altering the multipath propagation environment. These physical changes manifest as amplitude attenuation, phase shifts, and Doppler frequency shifts across the CSI stream, creating a unique signature that distinguishes human motion from static environmental noise.

CSI Processing Pipeline Architecture

The wifi-densepose codebase processes these signal variations through a modular pipeline defined in v1/src/core/csi_processor.py. Raw bytes from ESP32 or router hardware flow through phase sanitization, noise removal, and feature extraction stages to produce a human detection confidence score.

The pipeline executes these sequential operations:

  1. Raw extraction (csi_extractor.py): Captures byte streams from Wi-Fi hardware.
  2. Phase sanitization (phase_sanitizer.py): Unwraps phase discontinuities via sanitize_phase and removes outliers.
  3. Pre-processing (CSIProcessor._remove_noise, _apply_windowing, _normalize_amplitude): Conditions the signal for analysis.
  4. Feature extraction (_extract_amplitude_features, _extract_phase_features, _extract_correlation_features, _extract_doppler_features): Computes statistical descriptors.
  5. Motion analysis (_analyze_motion_patterns): Derives a composite motion score from variance and correlation deviation.
  6. Confidence calculation (_calculate_detection_confidence, _apply_temporal_smoothing): Produces the final detection result.

How Movement Manifests in CSI Features

Amplitude Variance Across Sub-Carriers

Human bodies block specific propagation paths, causing time-varying attenuation in certain sub-carriers. The _extract_amplitude_features method in v1/src/core/csi_processor.py quantifies this effect by computing amplitude_variance = np.var(csi_data.amplitude, axis=0), capturing the temporal instability introduced by moving scatterers.

Phase Differences Between Adjacent Sub-Carriers

As a person moves, changing path lengths introduce phase shifts that differ across the frequency spectrum. The pipeline calculates this via np.diff(csi_data.phase, axis=1) in _extract_phase_features, averaging the differential phase response to detect motion-induced path length variations.

Antenna Correlation Degradation

Static environments maintain stable spatial correlation between multiple antennas. Human movement disrupts this correlation by introducing independent scattering at different antenna elements. The _extract_correlation_features method computes np.corrcoef(csi_data.amplitude) to measure this spatial decorrelation.

Doppler Frequency Shifts

Relative motion between the human body and Wi-Fi transceivers creates Doppler-shifted reflections visible in the power spectral density. The _extract_doppler_features method computes these frequency-domain characteristics using FFT-based PSD analysis, providing a placeholder Doppler vector for motion frequency analysis.

Motion Pattern Analysis and Detection Confidence

The system synthesizes these indicators into a motion-score within _analyze_motion_patterns. This weighted combination of amplitude variance and correlation deviation feeds into _calculate_detection_confidence, which applies _apply_temporal_smoothing to reduce false positives. When the confidence exceeds the configurable human_detection_threshold (default 0.8), the pipeline returns a HumanDetectionResult with human_detected=True.

Implementing the Detection Pipeline

The following example demonstrates the complete workflow from raw hardware bytes to human presence detection:

from src.hardware.csi_extractor import CSIExtractor
from src.core.phase_sanitizer import PhaseSanitizer
from src.core.csi_processor import CSIProcessor

# 1️⃣  Extract raw CSI (mocked in tests)

extractor = CSIExtractor(
    config={'hardware_type': 'esp32', 'sampling_rate': 100, 'buffer_size': 256,
            'timeout': 1.0}, logger=None
)
raw_csi = extractor._read_raw_data()                     # → bytes from ESP32

# 2️⃣  Parse into structured CSIData

csi_data = extractor.parser.parse(raw_csi)

# 3️⃣  Sanitize phase

phase_sanitizer = PhaseSanitizer(
    config={'unwrapping_method': 'numpy', 'outlier_threshold': 3.0,
            'smoothing_window': 5}, logger=None
)
csi_data.phase = phase_sanitizer.sanitize_phase(csi_data.phase)

# 4️⃣  Process and detect human presence

processor = CSIProcessor(
    config={'sampling_rate': 100, 'window_size': 256, 'overlap': 0.5,
            'noise_threshold': -80, 'human_detection_threshold': 0.8},
    logger=None
)
result = await processor.process_csi_data(csi_data)

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

After processing, inspect the specific features that indicate movement:

features = processor.extract_features(csi_data)
print("Amplitude variance per sub‑carrier:", features.amplitude_variance[:5])
print("Mean phase difference:", features.phase_difference)
print("Correlation matrix shape:", features.correlation_matrix.shape)
print("Doppler placeholder vector:", features.doppler_shift[:3])

Adjust detection sensitivity by modifying the processor configuration:

processor.human_detection_threshold = 0.6   # more sensitive

processor.smoothing_factor = 0.7          # smoother confidence curve

Critical Source Files

Summary

  • Human movement alters Wi-Fi multipath propagation, creating detectable variations in CSI amplitude, phase, and correlation structures.
  • The wifi-densepose pipeline processes these changes through PhaseSanitizer for signal conditioning and CSIProcessor for statistical feature extraction.
  • Key detection features include amplitude variance, differential phase, antenna correlation matrices, and Doppler characteristics.
  • The system calculates a composite motion-score combining variance and correlation deviation, applying temporal smoothing to generate a confidence score.
  • Detection triggers when confidence exceeds the human_detection_threshold (default 0.8), as implemented in v1/src/core/csi_processor.py.

Frequently Asked Questions

What specific CSI features indicate human movement?

Human movement primarily affects amplitude variance across sub-carriers, phase differences between adjacent frequencies, and spatial correlation between antenna streams. The wifi-densepose code extracts these via np.var() for amplitude instability, np.diff() for phase gradients, and np.corrcoef() for antenna decorrelation in v1/src/core/csi_processor.py.

How does the repository handle noisy phase data?

The PhaseSanitizer class in v1/src/core/phase_sanitizer.py applies phase unwrapping via unwrap_phase to resolve discontinuities, outlier removal via remove_outliers using a configurable threshold (default 3.0), and optional smoothing windows to eliminate high-frequency noise introduced by rapid motion.

What is the default detection threshold for human presence?

The CSIProcessor uses a default human_detection_threshold of 0.8, configurable during initialization or runtime. Values closer to 0.6 increase sensitivity for small movements but may introduce false positives, while higher values reduce false alarms at the cost of missing subtle motions.

Can this system distinguish between multiple moving people?

The current implementation in v1/src/core/csi_processor.py calculates a single composite motion score without spatial localization of multiple scatterers. While the correlation features and Doppler analysis theoretically contain information about multiple moving objects, the repository's _analyze_motion_patterns method aggregates these into a binary detection decision rather than individual tracking.

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 →