How Multi-Person Tracking Works with Hungarian-Lite Assignment in RuView
RuView tracks up to four people in real time using a greedy "Hungarian-lite" algorithm that matches Wi-Fi CSI variance signatures to persistent slots, delivering sub-5 ms latency on ESP-32-S3 edge devices.
RuView's Wi-Fi-based sensing pipeline relies on multi-person tracking with Hungarian-lite assignment to maintain identity stability across frames without the computational overhead of classical optimization algorithms. Implemented in the sig_mincut_person_match.rs module, this approach uses greedy minimum-cost matching on compact 8-dimensional feature vectors, enabling deterministic tracking on memory-constrained WASM-edge environments.
Understanding the Hungarian-Lite Assignment Strategy
The classical Hungarian algorithm solves the assignment problem in O(N³) time, guaranteeing globally optimal matching between detections and tracks. Hungarian-lite replaces this with a greedy O(N²) approach that repeatedly selects the lowest-cost available pair without backtracking.
In sig_mincut_person_match.rs, the greedy_assign function implements this by iterating through the cost matrix to find the minimum Euclidean distance between a detected person and an active slot, marking both as assigned, and continuing until all detections are matched or distances exceed MAX_MATCH_DISTANCE. While potentially suboptimal for large N, this method is deterministic, requires no dynamic memory allocation, and executes in under 5 ms on ESP-32-S3 microcontrollers—critical for RuView's real-time requirements where MAX_PERSONS is capped at 4.
Core Components of the PersonMatcher
Feature Extraction and Signature Vectors
Each detected person is represented by a compact feature vector consisting of the top-8 variance values from their CSI sub-carriers. In sig_mincut_person_match.rs, the constant FEAT_DIM is set to 8:
const FEAT_DIM: usize = 8;
These variance patterns serve as unique fingerprints for each individual's movement and position relative to the Wi-Fi antennas, enabling the tracker to distinguish between multiple people even when they cross paths or move erratically.
Cost Matrix Construction
The algorithm builds a cost matrix using Euclidean (L₂) distances between newly extracted feature vectors and the stored signatures of active slots. The implementation calculates this via l2_distance(¤t[d], &self.slots[s].signature) for each detection-slot pair.
This distance metric quantifies the similarity between a current observation and a tracked identity, where values below MAX_MATCH_DISTANCE (5.0) indicate valid matches and higher values trigger the creation of new tracks or slot recycling.
Slot Management and EMA Updates
RuView maintains exactly four person slots (MAX_PERSONS = 4), each storing a signature, frame counter, and stability metrics. When a match occurs, the slot's signature updates using an exponential moving average (EMA) with SIG_ALPHA = 0.15:
slot.signature[f] = SIG_ALPHA * current_features[p][f] + (1.0 - SIG_ALPHA) * slot.signature[f];
This smoothing prevents sudden jumps caused by temporary occlusion or noise. Slots time out after ABSENT_TIMEOUT = 100 consecutive empty frames, releasing resources for new detections.
Implementation in sig_mincut_person_match.rs
The tracking logic resides in rust-port/wifi-densepose-rs/crates/wifi-densepose-wasm-edge/src/sig_mincut_person_match.rs. Key operational constants include:
const MAX_PERSONS: usize = 4;– Hard limit on concurrent tracksconst FEAT_DIM: usize = 8;– Feature vector dimensionalityconst MAX_MATCH_DISTANCE: f32 = 5.0;– Rejection threshold for spurious matchesconst ABSENT_TIMEOUT: u16 = 100;– Frames before slot releaseconst SIG_ALPHA: f32 = 0.15;– EMA smoothing factor
The PersonMatcher::process_frame method drives the pipeline, emitting structured events including EVENT_PERSON_ID_ASSIGNED, EVENT_PERSON_ID_SWAP, and EVENT_MATCH_CONFIDENCE that downstream applications consume for real-time analytics.
Practical Code Examples
Basic Frame Processing
Initialize the matcher and process CSI frames to obtain person IDs:
use wifi_densepose_wasm_edge::sig_mincut_person_match::PersonMatcher;
// Create the matcher with 4-person capacity
let mut matcher = PersonMatcher::new();
// Simulated CSI data (32 subcarriers)
let amplitudes = [1.0_f32; 32];
let variances = [0.2_f32; 32];
let n_persons = 2; // Two detections this frame
// Process frame and retrieve events
let events = matcher.process_frame(&litudes, &variances, n_persons);
for (event_type, value) in events {
match event_type {
EVENT_PERSON_ID_ASSIGNED => println!("New ID: {:.2}", value),
EVENT_PERSON_ID_SWAP => println!("Swap detected: {:.2}", value),
EVENT_MATCH_CONFIDENCE => println!("Confidence: {:.2}", value),
_ => {}
}
}
Accessing Stable Signatures
Check if a tracked person has stabilized and retrieve their current signature:
let slot_idx = 0;
if matcher.is_person_stable(slot_idx) {
if let Some(sig) = matcher.person_signature(slot_idx) {
println!("Stable signature for slot {}: {:?}", slot_idx, sig);
// Returns array of 8 f32 values (FEAT_DIM)
}
}
Integration with Full Pose Tracking
For applications requiring 17-keypoint pose estimation, combine the CSI-based matcher with the Kalman-based PoseTracker:
// Obtain IDs from CSI matching first
let csi_ids = matcher.active_persons();
// PoseTracker uses full Hungarian algorithm for keypoint associations
let mut pose_tracker = PoseTracker::new();
let detections: Vec<PoseDetection> = // ... from DensePose model
// Process with full tracking
pose_tracker.predict_all(&detections, &csi_ids);
The PoseTracker in pose_tracker.rs implements the classical O(N³) Hungarian algorithm for up to 10 persons, suitable for higher-level pose data where computational constraints are less severe than the ESP-32-S3 target environment.
Performance Characteristics and Hardware Constraints
The Hungarian-lite design specifically targets WASM-edge environments and microcontrollers like the ESP-32-S3. By avoiding the O(N³) complexity of the full Hungarian algorithm and limiting MAX_PERSONS to 4, the implementation achieves:
- Deterministic latency: Consistently under 5 ms per frame on ESP-32-S3
- Memory efficiency: Fixed-size arrays eliminate heap allocations during tracking
- Power efficiency: Reduced CPU cycles extend battery life in portable deployments
When tracking requirements exceed four people or involve complex pose keypoints, the system falls back to the full PoseTracker implementation in pose_tracker.rs, which trades computational overhead for assignment optimality.
Summary
- RuView implements multi-person tracking with Hungarian-lite assignment in
sig_mincut_person_match.rsto enable real-time Wi-Fi sensing on constrained edge devices. - The algorithm uses greedy minimum-cost matching on a 4×N cost matrix of Euclidean distances between 8-dimensional CSI variance signatures, avoiding the O(N³) complexity of classical methods.
- Exponential moving averages with α=0.15 smooth signature updates, while hard thresholds (
MAX_MATCH_DISTANCE = 5.0) and timeout counters (ABSENT_TIMEOUT = 100) filter spurious matches and release stale tracks. - The implementation emits structured events (
EVENT_PERSON_ID_ASSIGNED,EVENT_PERSON_ID_SWAP,EVENT_MATCH_CONFIDENCE) for downstream integration and achieves sub-5 ms latency on ESP-32-S3 hardware.
Frequently Asked Questions
What is the difference between Hungarian-lite and the full Hungarian algorithm?
The full Hungarian algorithm solves the assignment problem in O(N³) time, guaranteeing globally optimal matching between detections and tracks. Hungarian-lite uses a greedy O(N²) approach that repeatedly selects the lowest-cost available pair without backtracking. While potentially suboptimal for large N, this method is deterministic, requires no dynamic memory allocation, and executes in under 5 ms on ESP-32-S3 microcontrollers—critical for RuView's real-time requirements where MAX_PERSONS is capped at 4.
Why does RuView limit tracking to four people?
RuView constrains simultaneous tracking to four people (MAX_PERSONS = 4) to maintain real-time performance on ESP-32-S3 and other edge devices. This limit ensures the greedy assignment algorithm operates on a small, fixed-size cost matrix (maximum 4×4), eliminating dynamic memory allocation and keeping computational latency below 5 ms per frame. For scenarios requiring more than four people, RuView provides the separate PoseTracker in pose_tracker.rs, which supports up to 10 persons using the full Hungarian algorithm but requires significantly more computational resources.
How does the exponential moving average prevent ID switches?
The exponential moving average (EMA) with SIG_ALPHA = 0.15 smooths the signature updates for each tracked slot, preventing sudden jumps caused by temporary occlusion, noise, or brief signature similarities between people. By blending only 15% of the new observation with 85% of the historical signature, the tracker maintains stable identity representations even when individuals cross paths or move erratically. This temporal consistency, combined with the MAX_MATCH_DISTANCE threshold of 5.0, significantly reduces the likelihood of identity swaps compared to frame-to-frame nearest-neighbor matching without smoothing.
Can I use the full pose tracker instead of the CSI-based matcher?
Yes, RuView provides the PoseTracker in pose_tracker.rs as an alternative for applications requiring full 17-keypoint pose estimation or tracking more than four people. While the CSI-based PersonMatcher uses Hungarian-lite assignment on variance signatures for edge efficiency, PoseTracker implements the classical O(N³) Hungarian algorithm on Kalman-filtered keypoint states, supporting up to 10 persons. You can integrate both trackers by first obtaining person IDs from the CSI matcher, then passing them to PoseTracker for pose trajectory maintenance, though this requires significantly more computational resources and is typically deployed on less constrained hardware than the ESP-32-S3 target environment.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →