feat(server): accuracy sprint 001 — Kalman tracker, multi-node fusion, eigenvalue counting#341
Draft
taylorjdawson wants to merge 3 commits intoruvnet:mainfrom
Draft
feat(server): accuracy sprint 001 — Kalman tracker, multi-node fusion, eigenvalue counting#341taylorjdawson wants to merge 3 commits intoruvnet:mainfrom
taylorjdawson wants to merge 3 commits intoruvnet:mainfrom
Conversation
Complements ruvnet#326 (per-node state pipeline) with additional features: - Dynamic adaptive classifier: discover activity classes from training data filenames instead of hardcoded array. Users add classes via filename convention (train_<class>_<desc>.jsonl), no code changes. - Per-node UI cards: SensingTab shows individual node status with color-coded markers, RSSI, variance, and classification per node. - Colored node markers in 3D gaussian splat view (8-color palette). - Per-node RSSI history tracking in sensing service. - XSS fix: UI uses createElement/textContent instead of innerHTML. - RSSI sign fix: ensure dBm values are always negative. - GET /api/v1/nodes endpoint for per-node health monitoring. - node_features field in WebSocket SensingUpdate messages. - Firmware watchdog fix: yield after every frame to prevent IDLE1 starvation. Addresses ruvnet#237, ruvnet#276, ruvnet#282 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…, eigenvalue counting Wire three existing signal-crate components into the live sensing path: Step 1 — Kalman Tracker (tracker_bridge.rs): - PoseTracker from wifi-densepose-signal wired into all 5 mutable derive_pose_from_sensing call sites - Stable TrackId-based person IDs replace ephemeral 0-based indices - Greedy Mahalanobis assignment with proper lifecycle transitions (Tentative → Active → Lost → Terminated) - Kalman-smoothed keypoint positions reduce frame-to-frame jitter Step 2 — Multi-Node Fusion (multistatic_bridge.rs): - MultistaticFuser replaces naive .sum() aggregation at both ESP32 paths - Attention-weighted CSI fusion across nodes with cosine-similarity weights - Fallback uses max (not sum) to avoid double-counting overlapping coverage - Node positions configurable via --node-positions CLI arg - Single-node passthrough preserved (min_nodes=1) Step 3 — Eigenvalue Person Counting (field_model.rs upgrade): - Full covariance matrix accumulation (replaces diagonal variance approx) - True eigendecomposition via ndarray-linalg Eigh (Marcenko-Pastur threshold) - estimate_occupancy() for runtime eigenvalue-based counting - Calibration API: POST /calibration/start|stop, GET /calibration/status - Graceful fallback to score_to_person_count when uncalibrated New files: tracker_bridge.rs, multistatic_bridge.rs, field_bridge.rs Modified: sensing-server main.rs, Cargo.toml; signal field_model.rs, Cargo.toml Refs: .swarm/plans/accuracy-sprint-001.md Co-Authored-By: claude-flow <ruv@ruv.net>
6 tasks
Critical fixes: - C1: FieldModel created with n_links=1 (single_link_config) so feed_calibration/extract_perturbation no longer get DimensionMismatch - C2: variance_explained now uses centered covariance trace (E[x²]-E[x]²) matching mode_energies normalization - C3: MP ratio uses total_obs = frames * links for consistent threshold between calibration and runtime - C4: Noise estimator filters to positive eigenvalues only, preventing collapse to ~0 on rank-deficient matrices (p > n) - C5: ESP32 paths gate total_persons on presence — empty room reports 0 High fixes: - H1: Bounding box computed from observed keypoints only (confidence > 0), preventing collapse from centroid-filled unobserved slots - H2: fuse_or_fallback returns Option<usize> instead of sentinel 0, eliminating type ambiguity between "fusion succeeded" and "zero people" - H3: Monotonic epoch-relative timestamps replace wall-clock/Instant mixing, preventing spurious TimestampMismatch on NTP steps - H5: ndarray-linalg gated behind "eigenvalue" feature flag (default=on), diagonal fallback used with --no-default-features Moderate fixes: - M1: calibration_start guards against replacing Fresh calibration - M2: parse_node_positions logs warning for malformed entries Co-Authored-By: claude-flow <ruv@ruv.net>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Wire three existing signal-crate components into the live sensing path to replace heuristic person counting with physics-grounded approaches:
tracker_bridge.rs): Stable person IDs viaPoseTrackerwith greedy Mahalanobis assignment, proper lifecycle transitions (Tentative→Active→Lost→Terminated), and Kalman-smoothed keypoints — eliminates frame-to-frame jitter and ephemeral 0-based IDsmultistatic_bridge.rs):MultistaticFuserreplaces naive.sum()of per-node person counts with attention-weighted CSI fusion — two nodes seeing one person now reports 1 (not 2). Fallback usesmaxto avoid double-counting overlapping coveragefield_model.rsupgrade): Full covariance matrix +ndarray-linalgeigendecomposition with Marcenko-Pastur noise threshold replaces diagonal variance approximation.estimate_occupancy()for runtime counting, calibration API (/calibration/start|stop|status)Changes
New files
sensing-server/src/tracker_bridge.rssensing-server/src/multistatic_bridge.rssensing-server/src/field_bridge.rsModified files
sensing-server/Cargo.tomlwifi-densepose-signaldependencysensing-server/src/main.rssignal/Cargo.tomlndarray-linalgdependencysignal/src/ruvsense/field_model.rsestimate_occupancy(),baseline_eigenvalue_countKey design decisions
ndarray-linalgovernalgebra— signal crate already usesndarray, workspace dep existsTest plan
cargo test -p wifi-densepose-signal --no-default-features— existing 49+ tests pass (16 tracker + 15 multistatic + 18+4 field_model)cargo test -p wifi-densepose-sensing-server— existing server tests + new bridge tests passcargo test --workspace --no-default-features— full 1031+ test suite greenPOST /calibration/start, wait,POST /calibration/stop— verify baseline eigenvalue count reportedRefs:
.swarm/plans/accuracy-sprint-001.md🤖 Generated with claude-flow