Predictive CSI for 5G Link Adaptation
Closing the blind spot between channel reports. A 5G base station decides how fast to transmit to each user from the channel-quality (CQI) report the user sends back. Those reports arrive only periodically, and between them the scheduler holds the last value constant. In a moving network the channel has usually changed, so the transmission is matched to a channel that no longer exists. This feature predicts the next report, per user, and feeds that forecast into the scheduler's rate decision.
Architecture in brief
The predictor sits alongside the scheduler's existing link-adaptation logic and is driven entirely by data the base station already has. There is no new interface to the user, no additional signalling, and no change to the radio standard, only the channel-quality value fed into rate selection changes.
Per-user prediction. Each connected user keeps a short rolling window of its most recent channel reports. When a new report arrives, the model forecasts the user's next value from that window. The forecast is cached and used for the following scheduling decisions, until the next real report refreshes it.
Two prediction engines, one interface. The same forecast can be produced by a lightweight linear predictor or by a compact neural predictor. Both plug into the same interface and are selected by configuration, so a deployment can choose the trade-off that suits its conditions.
Runs inside the base station. Both models are compiled directly into the DU and execute as plain arithmetic, there is no external machine-learning runtime, no inference server, and no added latency on the scheduling path. Models can also be updated live, without restarting the base station.
Safe by construction. Whenever there is no confident forecast, early after a user connects, or when the input history is incomplete, the scheduler falls straight back to today's behaviour. The feature can never do worse than the current baseline.
Designed for mobility. The value of prediction grows precisely with how fast the channel changes. For a stationary user the last report is already a good estimate and there is little to gain. For a moving user, or when reports are spaced further apart, the last report goes stale quickly, and that is exactly the blind spot this feature fills.
What this brings
- Better link adaptation. The scheduler transmits based on where the channel is heading, not where it last was, so the modulation and coding it chooses fits the real channel more often.
- More efficient use of the same spectrum. Fewer over-optimistic transmissions that fail, and fewer over-cautious ones that leave capacity on the table, without any change to bandwidth, power, or hardware.
- Strongest where it is needed most. The benefit scales with mobility and with the spacing of channel reports, targeting exactly the conditions where the conventional approach struggles.
- Per-user, at cell scale. Every connected user gets its own forecast, so the improvement applies across a realistic multi-user cell rather than a single ideal link.
- Zero deployment risk to adopt. It ships disabled, rolls out in reviewable stages, and always falls back to the current behaviour, so it can be evaluated safely before it ever influences a live transmission.
- No standards impact. Fully within 3GPP: no new procedure, no message to the user device, no reconfiguration. It is an internal scheduler improvement.
Deployment and running guide
The feature rolls out in stages. Each stage is enabled independently in the DU configuration, so it can be validated before the next is turned on.
Clone the OCUDU-RAN repository and check out the dev branch, then build it (the predictor is compiled directly into the DU):
git clone https://github.com/TOSSI-Foundation/OCUDU-RAN
cd OCUDU-RAN
git checkout dev
./build.sh
Stage 1, Collect channel data
Enable dataset logging while inference stays off. Every channel report is recorded as one row, the recent history and the value that followed, building the examples the predictor learns from.
csi_ml:
inference:
enabled: false
dataset_logging:
enabled: true
output_dir: ml/datasets
scenario: collect_run
Run the base station with real users and move them through the conditions you want to cover (stationary, walking, driving), tagging each run with a distinct scenario. Each run produces a dataset file under output_dir.
Stage 2, Train the predictors
Train both models offline from the captured data. The linear model needs only numpy; the neural model additionally needs PyTorch.
# Linear predictor
python3 ml/training/train_export_csi_wiener.py ml/datasets/*.csv \
--model-out ml/models/csi_wiener_seed.model \
--inc-out lib/scheduler/support/csi_ml_wiener_model.inc
# Neural predictor
python3 ml/training/train_export_csi_gru.py ml/datasets/*.csv \
--model-out ml/models/csi_gru_seed.model \
--inc-out lib/scheduler/support/csi_ml_gru_model.inc
Each command produces a runtime model file (for live loading) and a compiled-in seed (baked into the binary on the next build). Both print a held-out comparison against the baseline so you can confirm the model is sound before deploying it.
Stage 3, Run in shadow mode
Turn inference on but keep actuation off. The base station now computes and logs a prediction for every report without changing any scheduling decision, zero risk, and it lets you confirm the live predictions match the offline evaluation.
csi_ml:
inference:
enabled: true
model_type: gru # 'gru' or 'wiener'
gru_model_path: ml/models/csi_gru_seed.model
apply_to_mcs: false # shadow: logged, not applied
dataset_logging:
enabled: true
output_dir: ml/datasets
scenario: shadow_run
Stage 4, Promote to live
Once shadow results look right, enable actuation. The scheduler now sources channel quality from the prediction, still falling back to the baseline whenever no confident forecast is available.
csi_ml:
inference:
enabled: true
model_type: gru
gru_model_path: ml/models/csi_gru_seed.model
apply_to_mcs: true # live: prediction drives rate selection
Running the stack
Launch the core and base station together:
./run_stack.sh configs/csi_ml_example.yaml
On startup the active CSI-ML settings are printed, so every run is self-documenting, you can see at a glance which model is live and whether it is shadowing or actuating.
Updating a model without downtime
Point the model path at a new file and replace it in place; the base station detects the change and swaps the model atomically, with no restart and no interruption to service.
Results
Benchmarking was performed on mobile user equipment in a controlled environment, comparing the predictive scheduler against the conventional hold-last-report baseline under matched conditions. To separate a genuine improvement from run-to-run variation, the baseline was measured repeatedly to establish a noise floor, and the predictive configuration was evaluated against it on identical traffic and radio conditions.
The evaluation looks at two layers:
- Prediction quality, how closely the forecast tracks the channel quality the user actually reports next, compared with holding the last report.
- Delivered performance, the downlink throughput and error rate the user experiences with the predictor driving rate selection, against the same baseline.
Notes
- The feature is disabled by default and has no effect until explicitly enabled.
- It changes only the channel-quality value fed into the existing, standard rate-selection logic; the modulation and coding tables, the radio interface, and all signalling are untouched.
- Prediction helps in proportion to how fast the channel changes. In near-static conditions the baseline is already close to optimal, and the feature is designed to match it there, not regress it.