Cognitive Radio Spectrum Occupancy Classification (5G NR / LTE / Noise)
ML-based spectrum sensing prototype for cognitive radio. Uses MATLAB (5G/LTE/Communications Toolboxes) to generate composite wideband RF captures with signals placed at known frequency sub-bands, then PyTorch (ResNet18 transfer learning) to classify each sub-band independently as NR / LTE / Noise — producing a per-frequency occupancy map.
Outcome
Given a wideband spectrogram, the model outputs which frequency sub-bands are occupied (and by what signal type — NR or LTE) versus free (Noise) — the core decision a cognitive radio needs before opportunistically transmitting on an unused band.
Example output:
Sub-band 1: Noise (free)
Sub-band 2: NR (OCCUPIED)
Sub-band 3: NR (OCCUPIED)
Sub-band 4: Noise (free)
Sub-band 5: LTE (OCCUPIED)
Sub-band 6: Noise (free)
Repo structure
.
├── matlab/
│ └── generate_subband_dataset.m # composite signal generation + sub-band spectrogram crops
├── python/
│ ├── train_classifier.py # ResNet18 transfer learning + evaluation
│ ├── classify_capture.py # inference: prints per-sub-band occupancy map
│ └── requirements.txt
├── subband_dataset/ # generated crops (gitignored — see below)
│ ├── NR/
│ ├── LTE/
│ └── Noise/
├── results/ # confusion matrix, per-SNR accuracy, sample occupancy maps
├── .gitignore
└── README.md
Requirements
MATLAB side: 5G Toolbox, LTE Toolbox, Communications Toolbox, Signal Processing Toolbox (desktop or MATLAB Online).
Python side:
pip install -r python/requirements.txt
How to run
- Open
matlab/generate_subband_dataset.min MATLAB, run it — populatessubband_dataset/with labeled sub-band crops across a range of SNRs. - Set up a Python venv and install requirements (see above).
- Run
python python/train_classifier.py— trains the model, prints classification report, confusion matrix, and per-SNR accuracy. - Run
python python/classify_capture.pyon a new capture's sub-band crops to get an occupancy map.
Results
(fill in after training — overall accuracy, per-class precision/recall, per-SNR accuracy table, sample occupancy maps)
Design notes / trade-offs
- Sub-band boundaries are fixed (currently 6 equal frequency slices), not pixel-level — a signal straddling two sub-bands can get an ambiguous label. Full semantic segmentation (DeepLab/U-Net) would resolve this at the cost of needing pixel-level masks and a heavier model.
- Time resolution isn't addressed — occupancy is reported per capture window, not per time-slice within it. A natural extension.
- Dataset is generated synthetically and not committed to the repo — ground truth comes for free from the MATLAB generation step, since signal placement is known at generation time.
Next steps
- Add WLAN/WiFi as a 4th class for a more realistic coexistence scenario.
- Add a time axis (slice both frequency and time) for finer-grained occupancy maps.
- Test on real SDR-captured spectrograms to measure the sim-to-real gap.
Log in or sign up for Devpost to join the conversation.