# How to Implement Cross-Environment Domain Generalization with MERIDIAN for Zero-Shot Deployment in RuView

> Implement MERIDIAN for zero-shot domain generalization in RuView. Eliminate accuracy loss when deploying between environments with CSI normalization, FiLM conditioning, and adversarial domain factorization.

- Repository: [rUv/RuView](https://github.com/ruvnet/RuView)
- Tags: how-to-guide
- Published: 2026-03-08

---

**MERIDIAN (ADR-027) enables zero-shot cross-environment deployment in RuView by combining hardware-agnostic CSI normalization, geometry-aware FiLM conditioning, and adversarial domain factorization to eliminate the 40-70% accuracy loss typically seen when moving between rooms.**

Cross-environment domain generalization with MERIDIAN allows a single WiFi-DensePose model trained in one room to deploy immediately in any new environment without retraining. This article explains how to implement MERIDIAN in the RuView repository using its Rust-based training and inference pipeline.

## Understanding the MERIDIAN Architecture

MERIDIAN sits between the CSI encoder and the pose regression heads in `wifi-densepose-rs`. It consists of four tightly coupled modules that together enable zero-shot generalization.

### Hardware Normalization Layer

The `HardwareNormalizer` in [`crates/wifi-densepose-signal/src/hardware_norm.rs`](https://github.com/ruvnet/RuView/blob/main/crates/wifi-densepose-signal/src/hardware_norm.rs) resamples raw CSI from any supported chipset to a canonical 56-subcarrier grid. It Z-score normalizes amplitudes and sanitizes phase, ensuring that ESP32-S3, Intel 5300, and Atheros NICs produce identical input distributions.

```rust
use wifi_densepose_signal::hardware_norm::{
    HardwareNormalizer, HardwareType,
};

let normalizer = HardwareNormalizer::new();
let raw_amp: Vec<f64> = /* from ESP32 */;
let raw_phase: Vec<f64> = /* from ESP32 */;
let frame = normalizer
    .normalize(&raw_amp, &raw_phase, HardwareType::Esp32S3)
    .expect("normalisation failed");

```

### Geometry Encoding and FiLM Conditioning

The `GeometryEncoder` in [`crates/wifi-densepose-train/src/geometry.rs`](https://github.com/ruvnet/RuView/blob/main/crates/wifi-densepose-train/src/geometry.rs) converts physical AP positions into a 64-dimensional conditioning vector using Fourier positional encoding and DeepSets permutation-invariant pooling. This vector drives Feature-wise Linear Modulation (FiLM) layers that condition the pose features on room geometry.

```rust
use wifi_densepose_train::geometry::GeometryEncoder;

let ap_positions = vec![
    [0.0_f32, 0.0, 2.5],
    [3.5, 0.0, 2.5],
    [1.75, 4.0, 2.5],
];
let geom_enc = GeometryEncoder::new();
let g_vec = geom_enc.encode(&ap_positions);

// FiLM modulation
let gamma = linear_gamma(&g_vec);
let beta = linear_beta(&g_vec);
let h_pose_conditioned: Vec<_> = gamma.iter()
    .zip(h_pose.iter())
    .zip(beta.iter())
    .map(|((g, h), b)| g * h + b)
    .collect();

```

### Domain Factorization with Gradient Reversal

The `DomainFactorizer` in [`crates/wifi-densepose-train/src/domain.rs`](https://github.com/ruvnet/RuView/blob/main/crates/wifi-densepose-train/src/domain.rs) splits features into pose-relevant (`h_pose`) and environment-specific (`h_env`) components. A `GradientReversalLayer` (GRL) forces `h_pose` to become invariant to the `DomainClassifier`'s predictions, while the classifier tries to predict the source environment from `h_pose`.

## Training with Adversarial Domain Generalization

During training (Phases 2-6), MERIDIAN adds adversarial and contrastive losses to the standard pose regression. The total loss function implemented in [`domain.rs`](https://github.com/ruvnet/RuView/blob/main/domain.rs) is:

```

L_total = L_pose
        + λ_c·L_contrastive
        + λ_adv·L_domain
        + λ_env·L_env_recon

```

The adversarial weight follows the schedule `λ(p) = 2/(1+exp(-10p)) - 1` implemented in `AdversarialSchedule`.

```rust
use wifi_densepose_train::domain::{
    DomainFactorizer, GradientReversalLayer,
    DomainClassifier, AdversarialSchedule,
};

let factorizer = DomainFactorizer::new(17, 64);
let classifier = DomainClassifier::new(17, 64, n_domains);
let schedule = AdversarialSchedule::new(max_epochs);

// Inside training loop
let (h_pose, h_env) = factorizer.factorize(&body_part_features);
let lambda = schedule.lambda(epoch);
let grl = GradientReversalLayer::new(lambda);
let domain_logits = classifier.classify(&grl.forward(&h_pose));
let l_domain = cross_entropy(&domain_logits, &domain_labels);

```

## Zero-Shot Deployment Workflow

To deploy a MERIDIAN-trained model in a new room without retraining:

1. **Measure AP positions** in the target room (meters from origin).
2. **Package the model** with MERIDIAN segments (`GEOM`, `DOMAIN`, `HWSTATS`) in an RVF container.
3. **Run inference** with geometry flags; the model conditions on the supplied layout automatically.

This eliminates the 40-70% accuracy degradation seen in naive WiFi-DensePose when moving between rooms.

## Optional Few-Shot Rapid Adaptation

If 10 seconds of calibration data are available, `RapidAdaptation` in [`crates/wifi-densepose-train/src/rapid_adapt.rs`](https://github.com/ruvnet/RuView/blob/main/crates/wifi-densepose-train/src/rapid_adapt.rs) builds a LoRA adapter using contrastive loss and entropy minimization—no pose labels required.

```rust
use wifi_densepose_train::rapid_adapt::RapidAdaptation;

let calibration_batch = collect_csi_batch(200); // ~10s @ 20Hz
let adapter = RapidAdaptation::default()
    .fit(&calibration_batch, &model)
    .expect("adaptation failed");

rvf_container.add_segment("DOMAIN", adapter.serialize());

```

## Summary

- **MERIDIAN** implements cross-environment domain generalization through four modules: `HardwareNormalizer`, `GeometryEncoder`, `DomainFactorizer`, and `DomainClassifier`.
- **Zero-shot deployment** requires only AP position coordinates; the model adapts via FiLM conditioning without retraining.
- **Adversarial training** in [`domain.rs`](https://github.com/ruvnet/RuView/blob/main/domain.rs) uses a Gradient Reversal Layer to enforce domain-invariant pose features.
- **Few-shot adaptation** via `RapidAdaptation` enables 10-second calibration with LoRA adapters when zero-shot accuracy needs refinement.
- **Source files** are located in [`crates/wifi-densepose-signal/src/hardware_norm.rs`](https://github.com/ruvnet/RuView/blob/main/crates/wifi-densepose-signal/src/hardware_norm.rs), [`crates/wifi-densepose-train/src/geometry.rs`](https://github.com/ruvnet/RuView/blob/main/crates/wifi-densepose-train/src/geometry.rs), [`crates/wifi-densepose-train/src/domain.rs`](https://github.com/ruvnet/RuView/blob/main/crates/wifi-densepose-train/src/domain.rs), and [`crates/wifi-densepose-train/src/rapid_adapt.rs`](https://github.com/ruvnet/RuView/blob/main/crates/wifi-densepose-train/src/rapid_adapt.rs).

## Frequently Asked Questions

### What hardware platforms does MERIDIAN support?

MERIDIAN supports ESP32-S3, Intel 5300, and Atheros chipsets through the `HardwareNormalizer` in [`hardware_norm.rs`](https://github.com/ruvnet/RuView/blob/main/hardware_norm.rs). It resamples raw CSI from any of these platforms to a canonical 56-subcarrier grid with Z-score normalized amplitudes and sanitized phase, ensuring consistent input distributions across hardware variants.

### How does MERIDIAN handle different room geometries?

The `GeometryEncoder` in [`geometry.rs`](https://github.com/ruvnet/RuView/blob/main/geometry.rs) encodes physical AP positions into a 64-dimensional vector using Fourier positional encoding and DeepSets permutation-invariant pooling. This vector drives FiLM layers that condition the pose features on the specific room layout, allowing the model to adapt to new geometries without parameter updates.

### What is the computational overhead of MERIDIAN?

MERIDIAN adds approximately 12,000 parameters to the base WiFi-DensePose model (totaling roughly 67,000 parameters), keeping it well within ESP32 and WebAssembly deployment budgets. The environment path (`h_env`) is discarded during inference, so only the pose-encoder path executes at runtime.

### Can MERIDIAN adapt to new environments without labeled data?

Yes. The `RapidAdaptation` module in [`rapid_adapt.rs`](https://github.com/ruvnet/RuView/blob/main/rapid_adapt.rs) supports few-shot adaptation using only 10 seconds of unlabeled CSI data. It builds a LoRA adapter using contrastive loss and entropy minimization, requiring no ground-truth pose labels. The resulting adapter is stored in the RVF container's `DOMAIN` segment for persistent reuse.