Skip to content
Snippets Groups Projects
Name Last commit Last update
Matlab
Python
gnuradio
gr-NOMA
.gitignore
readme.md

On the Performance of QPSK Modulation over Downlink NOMA: From error probability derivation to SDR-based validation

This repository is associated to the article available here.

Description

In this project, we study the performance of QPSK modulation in the context of multi-user downlink NOMA with a successive interference canceller (SIC) at the receiver side. We derive the analytical formula on its closed-form in the associated paper, and use the code in this repository to verify it, both through simulation and experimental validation. Numerical simulations are used to not only to corroborate the tightness of our theoretical expressions, but also to analyze the problem of power allocation in the two and three users cases. Finally, the code for an experimental validation testbed using NOMA with software defined radio is provided.

Table of content

  • GNURadio : GNURadio flowgraphs used in our experimental setup
  • gr-NOMA : Custom-made blocks, using C++, used in the flowgraphs
  • Matlab : Matlab code used to generate the channel parameters used in simulations
  • Python : Python scripts used for the simulations and optimization

GNURadio

These flowgraphs rely on the blocs defined in gr-NOMA, they must be installed first.

flowgraph_NOMA_2_users.grc

A flowgraph generating random symbols for 2 users, combining them using NOMA, and transmitting them through 2 antennas. They are then decoded, and the BER is computer for each user.

In this setup, the power allocated to each user can be chosen in live transmissions.

flowgraph_NOMA_3_users.grc

A flowgraph generating random symbols for 3 users, combining them using NOMA, and transmitting them through 2 antennas. They are then decoded, and the BER is computer for each user.

In this setup, the power allocated to each user can be chosen in live transmissions.

noise_generator.grc

This flowgraph generates random complex symbols, following a Gaussian repartition. These symbols are then sent at a given frequency, to generate random noise in our channel.

The noise's power can be modified during the transmission.

sync_test_flowgraph.grc

This simple flowgraph is used to test the phrase-shift correction for the blocs sync_frames_sender and sync_frames_receiver .

gr-NOMA

It is assumed that GNURadio is installed for the following steps. This repository should also be cloned or downloaded.

Installation

First, move to the right folder:

cd [...]/gr-NOMA

Then, create a build build folder (if it doesn't already exist) :

mkdir build
cd build

Then, compile the blocks:

cmake .. && make

And install them:

sudo make install

For linux, each time new blocks are installed, you must run this command:

sudo ldconfig

Blocs description

Note: The blocs' code is located in the gr-NOMA/lib subfolder.

BERCounter

Compute the Binary Error Rate for N users when provided the expected and decoded results.

  • in[0...N-1]: Reference values
  • in[N...2N-1]: Received values
  • out: BER

in[0] is compared to in[N], in[1] to in[N+1] and so one.

decode_cc

Decode N users NOMA symbol, expected input to use a QPSK constellation for each user.

  • in[0...N-1]: Each user's power (in decreasing order of magnitude)
  • in[N]: The complex symbol to decode
  • out[0...N-1]: Each user's decoded symbol
random_source_c

Generate a random complex number at a given frequency.

freq corresponds to samp_rate / sps, with sps the number of samples per symbol to output.

resampler_cc

Keeps only 1 symbol out of resamp_ratio, dephased starting at phase_shift * resamp_ratio.

Allows the user to extract only meaningful values from a given set. The resamp_ratio is typically sps (number of samples per symbol).

phase_shift helps choosing which value is kept. For example, if resamp_ratio = 32 and phase_shift = 0.5, then, out of 32 values, only the 16th value is kept (which probably corresponds to the max power).

signalMerger

Create a single symbol from multiple users' symbols using NOMA.

  • in[0...N-1]: Each user's power (in decreasing order of magnitude)
  • in[N...2N-1]: Each user's symbol to transmit
  • out[0...N-1]: The ponderated sum of the users' symbols

The output corresponds to in[0] * sqrt(in[N] / 2) + in[1] * sqrt(in[N+1] / 2) + ....

sync_frames_receiver

Block which automatically corrects the phase and amplitude of received symbols.

This should be at the receiving end of a sync_frame_sender bloc.

This block uses an initial burst of known symbols to compute the average phase and amplitude difference, and corrects it for all the following symbols.
It expects the initial known symbols (defined in the syncFrames vector of complex values) to be sent with a frequency of freq (where freq = sample_rate / sps).
No symbol is dropped by the block (it just prepends some symbols at the start).
Increasing procPerSymbol means that, for each known symbol, multiple values will be analyzed to compute the phase and amplitude difference. It is recommended to only increase this if the received symbols stay long enough at the optimal amplitude (i.e. the transition period is small).

Warning: The values in syncFrames MUST be != 0. Indeed, since this block is meant to be placed after an USRP source, it will initally be given noise by the antenna until the USRP source actually sends symbols. This means we have to find out which symbols are noise. This is done with a simple amplitude threshold on received values.

sync_frames_sender

Block which initially sends reference symbols and, coupled with a sync_frams_receiver, corrects the phase and amplitude of received symbols.

This should be at the sending end of a sync_frame_sender bloc.

This block sends an initial burst of known symbols, later used in sync_frames_receiver to compute the average phase and amplitude difference, and correct it for all the following symbols.
It sends the initial known symbols (defined in the syncFrames vector of complex values) with a frequency of freq (where freq = sample_rate / sps). After sending those symbols, it just acts as a passthrough block. No symbol is dropped by the block (it just prepends some symbols at the start).

Warning: The values in syncFrames MUST be != 0 (see sync_frames_receiver for details).

Matlab

In order to use this code, the parameters from BaseCodeMS.m must be modified, especially the values of N (the noise of the canal) and g (the attenuation for each user).

The power of the noise, N, must be simply converted in sigma (used in our algorithms), the standard deviation of the Gaussian noise.

Python

We assume that Python 3 and numpy are installed on the machine.

Script descriptions

Comparison_Experiment_Theory.py

Contains measured BER (Bit Error Rate) for 3 users, and compares them with theoretical results.

Comparison_Model_Theory.py

Contains several functions to compare the theoretical BER with a statistical BER calculated using the Monte Carlo method.

Find_Optimum.py

Contains the algorithm for searching for the optimum power distribution. A custom implementation is compared to an existing solution. It is based on scipy and uses the file Theorie_N_receptors.py.

Its behavior is detailed in our report, and explanations on the matrices used in the optimization are given at the beginning of the file.

Model_N_receivers.py

Contains functions to calculate an error rate by following the ideal channel model with the Monte-Carlo method.

Usage examples are given in Comparison_Model_Theorie.py and at the end of the file.

NOMA_Optimize.c

Contains an implementation of the proposed algorithm to find the optimum power distributions for N users. This file can be compiled using python3 setup.py --install, and then used as a standard module (see Time_Optimum.py for an example).

Theory_N_receivers.py

Contains functions to calculate the theoretical error rate using the formula developed in the report (and the pseudo code given therein).

Usage examples are given in Comparaison_Modele_Theorie.py and at the end of the file.

Time_Optimum.py

Contains the algorithm used to compare our proposed optimization method with the Basin-Hopping implementation in Scipy. It imports the contents of NOMA_Optimize.c as a module, which requires the command python3 setup.py --install to be run beforehand.

Appendixes

OFDMA

An implementation of OFDMA could be interesting, as seen in the following publication: https://www.researchgate.net/publication/322924686_OFDMA_Simulations_on_GNU_Radio. We were however unable to reproduce the flowgraph describe.