mirror of
https://github.com/ruvnet/RuView
synced 2026-08-04 19:31:42 +00:00
feat(train): TrainingConfig subcarrier-layout presets + real MmFiDataset loader test (#537)
Closes the remaining doable items from the 2026-05-11 training-pipeline audit: #6 (CSI format default = 56-sc / 1 NIC) + #7 (multi-band 168-sc mesh not in config): new `TrainingConfig::for_subcarriers(native, target)` plus named presets `mmfi()` (114→56), `ht40_192()` (≈192-sc ESP32 HT40 → 56) and `multiband_168()` (168-sc ADR-078 multi-band mesh → 56). Non-MM-Fi CSI shapes are now first-class instead of requiring manual `native_subcarriers` / `num_subcarriers` overrides; the field docs list the supported source counts and the multi-NIC mapping (a 2–3-node mesh currently rides on `n_rx` until a dedicated node dimension lands). Model input width stays `num_subcarriers`; the presets only vary the resampling input. #4 (proof.rs uses synthetic data): reframed — a deterministic proof *must* use a reproducible source, so `verify-training` correctly stays on `SyntheticCsiDataset`. The real gap was that nothing exercised the on-disk `MmFiDataset` path. New `tests/test_real_loader.rs` writes synthetic CSI to `.npy` files in the `MmFiDataset::discover` layout, loads it back, and checks the resulting `CsiSample` — covering the no-interp case, the subcarrier-interpolation branch, and the empty-root case. Adds `ndarray` / `ndarray-npy` as dev-deps for the fixture writing. cargo check + cargo test -p wifi-densepose-train --no-default-features: clean, all existing tests green, 3 new loader tests + the updated config doctest pass. Purely additive — no model-shape change, no tch-module change.
This commit is contained in:
@@ -15,6 +15,15 @@
|
||||
//!
|
||||
//! assert_eq!(cfg.num_subcarriers, 56);
|
||||
//! assert_eq!(cfg.num_keypoints, 17);
|
||||
//!
|
||||
//! // Adapt for a non-MM-Fi source — e.g. an ESP32 HT40 capture (~192 raw
|
||||
//! // subcarriers) or the ADR-078 multi-band mesh (168). The model still sees
|
||||
//! // `num_subcarriers`; the loader resamples the native count down to it.
|
||||
//! let ht40 = TrainingConfig::ht40_192();
|
||||
//! assert_eq!(ht40.native_subcarriers, 192);
|
||||
//! assert!(ht40.needs_subcarrier_interp());
|
||||
//! let mesh = TrainingConfig::for_subcarriers(168, 56);
|
||||
//! assert_eq!(mesh.native_subcarriers, 168);
|
||||
//! ```
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
@@ -36,16 +45,26 @@ pub struct TrainingConfig {
|
||||
// -----------------------------------------------------------------------
|
||||
// Data / Signal
|
||||
// -----------------------------------------------------------------------
|
||||
/// Number of subcarriers after interpolation (system target).
|
||||
/// Number of subcarriers after interpolation (the *model's* input width).
|
||||
///
|
||||
/// The model always sees this many subcarriers regardless of the raw
|
||||
/// hardware output. Default: **56**.
|
||||
/// hardware output; [`crate::subcarrier::interpolate_subcarriers`] resamples
|
||||
/// `native_subcarriers` → `num_subcarriers` when they differ. Default: **56**.
|
||||
pub num_subcarriers: usize,
|
||||
|
||||
/// Number of subcarriers in the raw dataset before interpolation.
|
||||
/// Number of subcarriers in the *raw* dataset, before interpolation.
|
||||
///
|
||||
/// MM-Fi provides 114 subcarriers; set this to 56 when the dataset
|
||||
/// already matches the target count. Default: **114**.
|
||||
/// Common sources: MM-Fi = 114, ESP32 HT20 = 56, ESP32 HT40 ≈ 192 (or 114),
|
||||
/// multi-band mesh = 168 (ADR-078). When it equals [`Self::num_subcarriers`]
|
||||
/// no interpolation happens ([`Self::needs_subcarrier_interp`]). For the
|
||||
/// non-MM-Fi shapes prefer the preset constructors
|
||||
/// ([`Self::for_subcarriers`], [`Self::ht40_192`], [`Self::multiband_168`])
|
||||
/// over overriding both fields by hand. Default: **114**.
|
||||
///
|
||||
/// **Multi-NIC note:** a 2–3-node CSI mesh currently maps onto the existing
|
||||
/// `[T, n_tx, n_rx, n_sc]` layout by treating the nodes' receive chains as
|
||||
/// extra `n_rx` (i.e. `num_antennas_rx = nodes × per_node_rx`); a dedicated
|
||||
/// node dimension is a separate dataset-loader change.
|
||||
pub native_subcarriers: usize,
|
||||
|
||||
/// Number of transmit antennas. Default: **3**.
|
||||
@@ -238,6 +257,43 @@ impl TrainingConfig {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Build a config for a dataset whose raw CSI has `native` subcarriers,
|
||||
/// resampling to `target` (the model's input width) before training.
|
||||
///
|
||||
/// All other fields take their [`Default`] values. Prefer this over
|
||||
/// overriding `native_subcarriers` / `num_subcarriers` directly so the
|
||||
/// relationship between the dataset's shape and the model's is explicit.
|
||||
#[must_use]
|
||||
pub fn for_subcarriers(native: usize, target: usize) -> Self {
|
||||
Self {
|
||||
native_subcarriers: native,
|
||||
num_subcarriers: target,
|
||||
..Self::default()
|
||||
}
|
||||
}
|
||||
|
||||
/// Preset for the MM-Fi dataset (114 raw subcarriers → 56). Identical to
|
||||
/// [`Self::default()`]; provided as a named counterpart to the other
|
||||
/// presets.
|
||||
#[must_use]
|
||||
pub fn mmfi() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
/// Preset for ESP32 HT40 captures (≈192 raw subcarriers → 56). Use
|
||||
/// [`Self::for_subcarriers`] if your capture reports a different native
|
||||
/// count (some HT40 firmwares yield 114).
|
||||
#[must_use]
|
||||
pub fn ht40_192() -> Self {
|
||||
Self::for_subcarriers(192, 56)
|
||||
}
|
||||
|
||||
/// Preset for the ADR-078 multi-band mesh (168 raw subcarriers → 56).
|
||||
#[must_use]
|
||||
pub fn multiband_168() -> Self {
|
||||
Self::for_subcarriers(168, 56)
|
||||
}
|
||||
|
||||
/// Returns `true` when the native dataset subcarrier count differs from the
|
||||
/// model's target count and interpolation is therefore required.
|
||||
pub fn needs_subcarrier_interp(&self) -> bool {
|
||||
|
||||
Reference in New Issue
Block a user