RAN MAC Scheduler — 5G/LTE L1/L2 downlink scheduler in C++

Published:

A compact, production-quality C++17 project that demonstrates three skills at once: modern C++, Radio Access Network (RAN) L1/L2 protocol knowledge, and a complete CI/CD pipeline.

🔗 Source code: github.com/nerostamas/Radio-Access-Network-RAN-MAC-Scheduler

Why this shows depth

This project is small on purpose — small enough to read in one sitting, yet correct enough to reproduce the exact throughput-vs-fairness trade-off described in the 3GPP literature. That combination is what demonstrates real skill rather than boilerplate.

On the C++ side, it is written the way shipped systems are: a layered architecture with a clean phy / mac / metrics boundary, an abstract Scheduler interface with polymorphic strategies behind a std::unique_ptr factory, RAII throughout with no raw new/delete, const-correct and [[nodiscard]] APIs, strong typing via purpose-built aliases (Cqi, Tti, Bits), and a deterministic, seedable RNG so every run is reproducible. It compiles cleanly under both GCC and Clang with -Wall -Wextra -Wpedantic and passes AddressSanitizer, UndefinedBehaviorSanitizer, clang-tidy, and cppcheck.

On the RAN side, the code is not a toy loop — it mirrors how a real gNB/eNB operates every millisecond: UEs report channel quality (CQI), the PHY performs link adaptation (CQI → MCS → transport block size) subject to the resource-block budget, the MAC scheduler grants the shared grid per TTI, and HARQ handles retransmission with soft-combining gain. The fact that Max C/I maximizes cell throughput while starving cell-edge UEs, and Proportional Fair recovers fairness at a modest throughput cost, falls directly out of the implementation — exactly as the theory predicts. Reproducing that behavior from first principles is the clearest evidence that the L1/L2 concepts are genuinely understood, not just named.

What it does

It simulates the air-interface boundary where throughput and fairness are decided: a base station (gNB/eNB) allocates a shared time–frequency resource-block grid among competing UEs, every Transmission Time Interval (TTI), with HARQ retransmissions for reliability.

  • L1 (PHY): channel quality (CQI) → modulation & coding scheme (MCS) → transport block size (TBS) per resource block, per TTI.
  • L2 (MAC): per-UE buffers, stop-and-wait HARQ, and three classic downlink schedulers.

RAN concepts modeled

ConceptLayer
Resource-Block grid & TTI loopL1 / L2
CQI → MCS → Transport Block SizeL1
Per-UE logical-channel buffersL2
Downlink scheduling (RR / Max-C·I / Proportional Fair)L2 (MAC)
HARQ stop-and-wait retransmissionL2 (MAC)
Throughput & Jain’s fairness KPIs—

Schedulers and the trade-off they reveal

Running the simulator (10 UEs, 50 RBs, 1000 TTIs, seed 42) reproduces the textbook throughput-vs-fairness behavior, which is what proves the model is faithful:

SchedulerCell throughputJain’s fairness
Round Robin17.4 Mbps0.83 (even, channel-agnostic)
Max C/I30.6 Mbps0.34 (cell-edge UEs starve)
Proportional Fair23.0 Mbps0.85 (best balance)

Engineering practices

  • C++17 with a clean phy / mac / metrics separation, -Wall -Wextra -Wpedantic, and zero build warnings.
  • CMake build with a reusable core library, a CLI (ran_sim), and an opt-in sanitizer / coverage build.
  • 24 GoogleTest unit tests driven by CTest, covering link adaptation, HARQ state transitions, KPI math, and end-to-end scheduler behavior (including determinism).
  • GitHub Actions CI/CD on every push and PR:
    1. clang-format style gate
    2. build matrix — GCC + Clang, Debug + Release
    3. GoogleTest via CTest
    4. AddressSanitizer + UndefinedBehaviorSanitizer test run
    5. static analysis — clang-tidy and cppcheck
    6. gcov/lcov coverage summary

Try it

git clone https://github.com/nerostamas/Radio-Access-Network-RAN-MAC-Scheduler
cd Radio-Access-Network-RAN-MAC-Scheduler
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -j
ctest --test-dir build --output-on-failure
./build/ran_sim --ues 10 --tti 1000 --rbs 50 --scheduler pf --seed 42
Direct Link