# rcm_ml: learned radio-map models on RadioMapSeer

Question: does feeding a cheap physics map into the U-Net (the "hybrid") beat a
pure-geometry U-Net (RadioUNet-style), in accuracy and in data efficiency?

## Full run on the Mac (Apple GPU, native Python, not Docker: Docker has no MPS)

```bash
cd ~/projects/radio-coverage
python3 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt torch gdown

# 1. dataset (3.26 GB zip, RadioMapSeer, CC BY 4.0)
mkdir -p data/rms && gdown 1_EHrS-Sp25nzmbJKbwnNVzbSR57jb6_8 -O data/rms.zip
cd data/rms && unzip -q ../rms.zip 'png/buildings_complete/*' 'png/antennas/*' 'gain/DPM/*' 'gain/IRT2/*' 'antenna/*' dataset.csv && cd ../..

# 2. cache (all 80 Tx per training map = 40k samples; ~30 min on 8 cores)
RMS_ROOT=data/rms python -m rcm_ml.prepare --out data/rms_cache --tx-train 80 --tx-eval 80 --workers 8

# 3. baselines + models at full resolution (RadioUNet protocol: 50 epochs, Adam)
python -m rcm_ml.eval_baselines data/rms_cache runs/baselines.json
for v in geom feats hybrid; do
  python -m rcm_ml.train --cache data/rms_cache --variant $v --size 256 --epochs 50 --lr 1e-4 --batch 15 --base 32 --device mps --threads 8
done
# data efficiency
for m in 50 150; do for v in geom hybrid; do
  python -m rcm_ml.train --cache data/rms_cache --variant $v --size 256 --epochs 50 --maps $m --device mps
done; done
```

Results land in `runs/<variant>_<target>_s<size>_m<maps>/test.json`.

## Files
- `data.py`: decoding (PL_dB = −147 + 99.16·gray), split, straight-line physics features (numba)
- `baseline.py`: B0 log-distance, B1 multi-wall (fitted by least squares)
- `models.py`: U-Net; `residual=True` adds the B1 channel to the output
- `train.py`: variants `geom` / `feats` / `hybrid`, wall-clock or epoch budget
- `eval_baselines.py`: analytic baselines on the test split
