Published and maintained by SDP8.org β the official platform for reproducible wireless sensing.
If you use SDP in your research, please cite:
@ARTICLE{11652923,
author={Zhang, Di and Huang, Jiawei and Cui, Yuanhao and Cao, Xiaowen and Han, Tony Xiao and Jing, Xiaojun},
journal={IEEE Transactions on Mobile Computing},
title={SDP: A Unified Protocol and Benchmarking Framework for Reproducible Wi-Fi Sensing},
year={2026},
volume={},
number={},
pages={1-14},
keywords={Wireless fidelity;Modeling;Frequency;Protocols;Training;Streams;Accuracy;Measurement;Tensors;Antennas;Benchmark;canonical representation;channel state information (CSI);integrated sensing and communications (ISAC);reproducibility;wireless sensing},
doi={10.1109/TMC.2026.3723025}}- Modular algorithm pipeline -- freely compose preprocessing steps with
AlgorithmStepandexecute_algorithm_steps() - Pluggable readers -- bring your own file-format reader via
register_reader()andpipeline(..., reader=)(CLI--reader) - Per-dataset pipeline presets --
widar,gait,xrf55,elderAL,ztevia--algorithm-preset - Compatibility & stability fixes -- clearer errors when an algorithm doesn't support a dataset, checkpoint always saved, Python 3.9 fix, XRF55 subset split fix
SDP is a protocol-level abstraction and unified benchmark for reproducible wireless sensing.
β οΈ SDP is not a new neural network, but a standardized protocol that unifies CSI representations for fair comparison.
| Capability | WSDP | SenseFi (2023) | CSIKit |
|---|---|---|---|
| Built-in Models | 19 (MLPβMamba/GNN) | 11 (MLPβViT) | β |
| Preprocessing Algorithms | 26+ (Wavelet, STC, etc.) | β | Basic |
| Datasets | 5 | 4 | β |
| Pluggable Architecture | β Registry | β | β |
| Protocol Abstraction | β Unique | β | β |
| Training Pipeline | β | β | β |
| CLI | β Full | Basic | β |
Verified from official GitHub repos on 2026-03-17.
| Category | Models | Use Case |
|---|---|---|
| Baseline | MLP, CNN1D, CNN2D, LSTM | Quick experiments, comparisons |
| Mainstream | ResNet1D, ResNet2D, BiLSTM+Attn, EfficientNet | Production use |
| SOTA | ViT, Mamba, GNN, CSIModel | Cutting-edge research |
| Specialized | THAT, CSITime, PA_CSI | Task-specific architectures |
| Lightweight | WiFlexFormer, AttentionGRU | Efficient deployment |
| Cross-Domain | EI, FewSense | Domain adaptation & few-shot |
from wsdp.models import create_model, list_models
model = create_model("ResNet1D", num_classes=10, input_shape=(20, 30, 3))
β οΈ Baseline Model Architecture NoteBaseline models (MLP, CNN1D, CNN2D, LSTM) use a Spatial Encoder (Conv2d-based) to compress the
(F, A)antenna dimension before temporal processing. This prevents parameter explosion from direct(T, F, A)flattening. SeeCHANGELOG.mdfor details.
| Category | Algorithms | Count |
|---|---|---|
| Denoising | Wavelet, Butterworth, Savitzky-Golay, Bandpass, Hampel | 5 |
| Phase Calibration | Linear, Polynomial, STC, Robust | 4 |
| Amplitude | Z-Score, Min-Max, IQR Outlier, AGC Compensation | 4 |
| Interpolation | Linear, Cubic, Nearest, Anti-alias Decimate | 4 |
| Features | Doppler, Entropy, CSI Ratio, Tensor, Conjugate Multiply, PCA Fusion | 6 |
| Detection | Variance, Change Point | 2 |
| Composition | Pipeline presets, YAML config | - |
from wsdp.algorithms import denoise, calibrate, normalize
denoised = denoise(csi, method='butterworth', order=5, cutoff=0.3)
calibrated = calibrate(csi, method='stc')See Model Guide and Algorithm Guide.
Wireless sensing research often suffers from:
- β Hardware-specific CSI formats
- β Inconsistent preprocessing pipelines
- β Unstable training results
- β Large performance variance across random seeds
Result: Models cannot be fairly compared.
SDP solves this at the protocol level, not the model level:
| Feature | Raw CSI | Other Tools | SDP |
|---|---|---|---|
| Standardized Format | β Hardware-specific | β Unified CSIFrame | |
| Multi-Dataset Support | β Manual parsing | β 5 datasets built-in | |
| Preprocessing | β DIY | β Wavelet + Phase Calib | |
| Reproducibility | β Random | β 5-seed standard | |
| Deep Learning | β From scratch | β CNN+Transformer | |
| CLI Interface | β None | β Full CLI support |
SDP projects raw CSI into a fixed canonical frequency grid (K=30), ensuring cross-hardware comparability.
| Metric | Result |
|---|---|
| Accuracy | SOTA on 5 datasets |
| Reproducibility | 5-seed evaluation standard |
| Stability | Low variance across runs |
Figure 1: Accuracy comparison across datasets
pip install wsdpVerify installation:
wsdp --versionπ Required: Create a free account at SDP8.org β your account credentials are needed for dataset downloads.
π VPN is recommended for downloading datasets.
Option A: From CLI (Recommended for testing)
All datasets hosted on SDP8.org:
# elderAL = smallest dataset, fastest for testing
# Use your SDP8.org email/password:
wsdp download elderAL ./data --email you@example.com --password yourpassword
# Or use a JWT token (from SDP8.org dashboard):
wsdp download elderAL ./data --token YOUR_JWT_TOKEN
# Download larger datasets:
# wsdp download widar ./data
# wsdp download gait ./data
# wsdp download xrf55 ./data
# wsdp download zte ./data --email you@example.com --password yourpassword
# β οΈ zte requires applying for access on the SDP platform firstOption B: From SDP8.org Web Interface
Log in at sdp8.org and download datasets manually.
Required Dataset Structure:
data/
βββ elderAL/ # Dataset name
β βββ action0_static_new/ # Activity folder
β β βββ user0_position1_activity0/ # Sample folder
β β β βββ sample1.csv
β β β βββ ...
β β βββ ...
β βββ action1_walk_new/
β βββ ...
βββ widar/
β
βββ gait/
β
βββ xrf55/
β βββ WIFI/
β βββ sample.npy
βββ zte/
π Python API (Recommended for research):
Create train.py:
from wsdp import pipeline
# Minimal call - uses default hyperparameters
pipeline("./data/elderAL", "./output", "elderAL")
# Or with custom hyperparameters
pipeline(
input_path="./data/elderAL",
output_folder="./output",
dataset="elderAL",
learning_rate=1e-3,
num_epochs=50,
batch_size=64,
)Run:
python train.pyπ» CLI (Quick & Simple):
# Basic training
wsdp run ./data/elderAL ./output elderAL
# With hyperparameter override
wsdp run ./data/elderAL ./output elderAL --lr 0.001 --epochs 50 --batch-size 64
# With hyperparameter config file (YAML, top-level key = dataset name)
wsdp run ./data/elderAL ./output elderAL --config my_config.yaml
# Swap the model: a registered model name, or your own .py file
wsdp run ./data/elderAL ./output elderAL --model THAT
wsdp run ./data/elderAL ./output elderAL -m custom_model.py
# Custom preprocessing: algorithm config (YAML/JSON) or a preset
wsdp run ./data/elderAL ./output elderAL --algorithm-config my_algorithms.yaml
wsdp run ./data/elderAL ./output elderAL --algorithm-preset high_qualityπ What You Get:
After training, check ./output/ (one set of files per random seed, 5 seeds by default):
output/
βββ best_checkpoint_<seed>.pth # Best model checkpoint for each seed
βββ training_history_<seed>.csv # Per-epoch loss & accuracy for each seed
βββ cm_rs_<seed>.png # Confusion matrix for each seed
Mean and variance of Top-1 accuracy across seeds are printed to the console at the end.
β If you see these files, SDP is working correctly!
| Dataset | Format | Subcarriers | Complex | Scenarios | Size |
|---|---|---|---|---|---|
| Widar | .dat (bfee) | 30 | β | Gesture recognition | ~2GB |
| Gait | .dat (bfee, Intel IWL5300) | 30 | β | Gait recognition | ~1GB |
| XRF55 | .npy | 30 | β | Human activity | ~3GB |
| ElderAL | .csv | varies | β | Elderly activity | ~500MB |
| ZTE | .csv | 512 | β | CSI with I/Q | ~4GB |
More datasets coming soon!
Step 1: Create custom_model.py:
import torch
import torch.nn as nn
class YourCustomModel(nn.Module):
def __init__(self, num_classes=6):
super().__init__()
# Your architecture here
# Input shape: (Batch, Timestamp, Frequency, Antenna)
def forward(self, x):
# Your forward pass
return output
# Required: expose model class
model = YourCustomModelStep 2: Run with your model:
wsdp run ./data/elderAL ./output elderAL -m custom_model.pyLabels and split groups are parsed from filenames, so name your files after
one of the built-in dataset conventions (e.g. XRF55 user_action_trial) and pass
that dataset name. If your files use a custom format, register a reader for it:
from wsdp import pipeline
from wsdp.readers import BaseReader, register_reader
class MyReader(BaseReader):
def sniff(self, file_path): return file_path.endswith(".myfmt")
def read_file(self, file_path): ... # parse the file into CSIData
register_reader("my_format", MyReader)
# Filenames follow the XRF55 convention -> dataset="xrf55" + custom reader for the format
pipeline("./data/my_dataset", "./output", "xrf55", reader="my_format")End-to-end example: examples/scripts/custom_reader_algorithm.py.
Want to go deeper? Here's where to modify:
| Directory | Purpose | What to Modify |
|---|---|---|
models/ |
Architectures | Define or compare model architectures |
algorithms/ |
Signal Processing | Denoising, calibration, etc. |
datasets/ |
Dataset Wrappers | Add new dataset loaders |
readers/ |
File Readers | Add new format parsers |
structure/ |
Data Structures | Modify CSIFrame format |
processors/ |
Protocol Logic | Adjust canonical projection |
WSDP features a Registry Pattern that makes algorithms pluggable:
from wsdp.algorithms import denoise, calibrate, register_algorithm
# Unified API β switch methods with one parameter
denoised = denoise(csi, method='butterworth', order=5)
calibrated = calibrate(csi, method='stc')
# Register your own algorithm
def my_denoise(csi, **kwargs):
return my_custom_filter(csi)
register_algorithm('denoise', 'my_method', my_denoise)
result = denoise(csi, method='my_method') # Works like built-in!You can try this in examples/getting_started.ipynb or just in your custom pipeline!
Configuration file support:
# examples/configs/algorithms_config.yaml
denoise:
method: butterworth
params:
order: 5
cutoff: 0.3
calibrate:
method: stc
normalize:
method: z-scorefrom wsdp.algorithms import load_config, execute_pipeline
config = load_config('examples/configs/algorithms_config.yaml')
processed = execute_pipeline(csi, config)Or:
pipeline(
"./data/elderAL",
"./output",
"elderAL",
algorithm_config_file='./examples/configs/algorithms_config.yaml',
)Pipeline presets:
from wsdp.algorithms import apply_preset, execute_pipeline
# Choose a preset for your use case
steps = apply_preset('high_quality') # or 'fast', 'robust', etc.
processed = execute_pipeline(csi, steps)Modular pipeline (compose or skip steps freely):
from wsdp.algorithms import AlgorithmStep
from wsdp.processors import ModularProcessor
steps = [
AlgorithmStep(category="denoise", method="wavelet", params={"level": 2}),
AlgorithmStep(category="normalize", method="z-score"), # calibration skipped
]
data, labels, groups = ModularProcessor(steps).process(csi_data_list, dataset="xrf55")Config-file form: examples/configs/modular_pipeline.yaml.
| Category | Algorithm | Key Function | Reference |
|---|---|---|---|
| Denoising | Wavelet | wavelet_denoise_csi() |
Donoho & Johnstone, 1994 |
| Butterworth | butterworth_denoise() |
Butterworth, 1930 | |
| Savitzky-Golay | savgol_denoise() |
Savitzky & Golay, 1964 | |
| Bandpass | bandpass_filter() |
Standard DSP | |
| Hampel | hampel_filter() |
Hampel, 1974 | |
| Phase Calibration | Linear | phase_calibration() |
Halperin et al., 2010 |
| Polynomial | polynomial_calibration() |
Extension of linear | |
| STC | stc_calibration() |
Xie et al., IEEE TWC 2019 | |
| Robust | robust_phase_sanitization() |
Wang et al., ICPADS 2012 | |
| Normalization | Z-Score | normalize_amplitude() |
Standard statistical |
| Min-Max | normalize_amplitude() |
Standard statistical | |
| AGC Compensation | agc_compensate() |
AGC gain correction | |
| Interpolation | Linear/Cubic/Nearest | interpolate_grid() |
de Boor, 1978 |
| Anti-alias Decimate | decimate() |
Anti-alias downsampling | |
| Features | Doppler | doppler_spectrum() |
Ali et al., MobiCom 2015 |
| Entropy | entropy_features() |
Shannon, 1948 | |
| CSI Ratio | csi_ratio() |
Halperin et al., 2011 | |
| Tensor Decomposition | tensor_decomposition() |
Kolda & Bader, SIAM 2009 | |
| Conjugate Multiply | conjugate_multiply() |
Antenna pair correlation | |
| PCA Fusion | pca_fusion() |
Dimensionality reduction | |
| Detection | Activity | detect_activity() |
Zhou et al., 2013 |
| Change Point | change_point_detection() |
Adams & MacKay, 2007 |
Built-in Presets:
| Preset | Denoise | Calibrate | Use Case |
|---|---|---|---|
high_quality |
Butterworth (order=5) | STC | Maximum accuracy |
fast |
Savitzky-Golay | Linear | Speed-optimized |
robust |
Wavelet | Robust | Noisy environments |
gesture_recognition |
Butterworth (order=4) | STC | Gesture tasks |
activity_detection |
Savitzky-Golay | Polynomial | HAR tasks |
localization |
Wavelet | Robust | Localization tasks |
Per-dataset presets (
widar,gait,xrf55,elderAL,zte) are also available; they currently mirror the legacy default chain (linear calibration
- wavelet denoise).
Raw CSI
β
[Deterministic Sanitization]
- Phase calibration
- Wavelet denoising
β
[Canonical Tensor Construction]
- K=30 frequency grid
- Standardized shape
β
[Deep Learning Model]
β
Prediction
After sanitization, SDP constructs a Canonical CSI Tensor:
Where:
-
$A$ = Number of antennas -
$K$ = 30 (fixed frequency grid) -
$T$ = Time samples
This ensures cross-hardware comparability.
Raw CSI contains hardware distortions:
- Phase offsets
- Sampling time offsets
- Noise fluctuations
SDP enforces deterministic calibration and denoising, guaranteeing:
- β Same raw CSI β Same cleaned tensor
- β Reproducibility is enforced, not optional
| # | Resource | What You'll Learn |
|---|---|---|
| 1 | Quickstart Notebook | 5-min intro β registry exploration & processor customization |
| 2 | Getting Started Notebook | Algorithm deep-dive β phase calibration & denoising with step-by-step visualizations |
| 3 | Full Tutorial Notebook |
End-to-end workflow β install β preprocess β train β evaluate β CLI |
| Resource | Description |
|---|---|
| Installation | Setup & environment configuration |
| Quickstart Guide | First steps with WSDP |
| Algorithm Guide | How to choose and chain preprocessing algorithms |
| Python API | Programmatic usage in detail |
| CLI Reference | Command-line interface usage |
| Configuration | YAML config files & pipeline presets |
| Resource | Description |
|---|---|
| Full Documentation Site | Complete MkDocs documentation |
| API Reference | All public APIs |
| Dataset Overview | Format details & download guide for all 5 datasets |
| Model Guide | All 19 models with architecture details |
| Leaderboard | Benchmark comparison across models & datasets |
| Changelog | Version history |
| Contributing | Development guide & PR process |
- v0.1 - Initial protocol design
- v0.2 - 5 datasets support, CLI tool
- v0.3 - More datasets (WiFi-HAR, CSI-HAR, etc.)
- v0.4 - 19 models, 26+ algorithms, leaderboard, CI/CD, scientific bug fixes
- v0.5 - PyPI official release, online demo platform
- v1.0 - Full protocol standardization
Want a specific dataset? Open an issue and let us know!
We welcome contributions! See CONTRIBUTING.md for:
- Development setup
- Coding guidelines
- Pull request process
MIT License - see LICENSE file.
Made with β€οΈ by the WSDP Team

