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

  1. Open matlab/generate_subband_dataset.m in MATLAB, run it — populates subband_dataset/ with labeled sub-band crops across a range of SNRs.
  2. Set up a Python venv and install requirements (see above).
  3. Run python python/train_classifier.py — trains the model, prints classification report, confusion matrix, and per-SNR accuracy.
  4. Run python python/classify_capture.py on 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.

Built With

Share this project:

Updates