Introduction
Orthogonal Frequency Division Multiple Access allows multiple users share the same symbol with different subcarriers. The subcarrier group forma a subchannel. In OFDMA, unique subchannels are assigned to different users.
OFDMA is used in various wireless technologies
- Mobile WiMAX (IEEE 802.16e),
- WLAN (WiFi-6 IEEE 802.11ax)
- 4G LTE
- 5G NR
Let us consider 192 data subcarriers which are divided into 8 subchannels. Now Each subchannel carries total 24 data subcarriers. We are now allocating one unique subchannel to two users.
In this simulation OFDMA python code, user1 is allocated subchannel number2 and user2 is allocated subchannel number5.
At the receiver part, We will pass sub channel number assigned to user1 to retrieve the transmitted data at the receiver side.
We have excluded guard sub carrier and pilot sub carrier from this simulation. So blocks such as scrambler, FEC encoder, interleaver is not present in this OFDMA simulation
Python Script – OFDMA
# Following script is OFDMA simulation python code
# Library files
import random
import numpy as np
import matplotlib.pyplot as plt
from scipy.fftpack import fft, ifft, ifftshift
# Define parameters for OFDMA System simulation
dataCarriers = 192 # Number of data sub carriers in a symbol
DataSC_per_subchannel = 24
Nsubchl = 8 # Each subchannel carry 24 data subcarriers
mu = 2 # bits per symbol for QPSK modulation type (mu = 4 for 16QAM, mu = 6 for 64QAM)
payloadBits_per_OFDM = dataCarriers * mu # number of payload bits per OFDM symbol 192*2 = 384 bits
payloadBits_per_SC = DataSC_per_subchannel * mu # number of payload bits per OFDM symbol 192*2 = 384 bits
len1 = payloadBits_per_SC # length of input data
mode = 2 # Modulation Order for QPSK
mapping_table = {
0: 0.7071 + 0.7071j,
1: - 0.7071 + 0.7071j,
2: 0.7071 - 0.7071j,
3: - 0.7071 - 0.7071j}
# Conversion of 192 data subcarriers to 8 Subchannels
list = [i for i in range(1, 193)]
SCarray = np.reshape(list, (8, 24))
print(list)
# USer # 1 Mapping
# Step-1 : Sub channel allocation
SCnum = 2 # Range of sub channel assignment is 0 to 7
print(SCarray[SCnum, :])
# Step 2 : Binary data generation for 1 sub channel
# i.e. 24 data sub carriers i.e. 48 bits
input_data = ""
for i in range(len1):
temp1 = str(random.randint(0, 1))
input_data += temp1
print(input_data)
# Step-3: Converting binary vector into group of 2 bits (as per QPSK) and
# map the same as per mapping table
s1 = input_data
s2_user1 = []
chunks = [s1[i:i+mode] for i in range(0, len(s1), mode)]
for piece in chunks:
temp = int(piece, 2)
s2_user1.append(temp)
print(s2_user1)
Q = np.zeros((24,), dtype=complex)
j = 0
for val in s2_user1:
Q[j] = mapping_table[val]
j += 1
print(Q)
dummy1 = [0 for element in range(256)]
i = 0
for val1 in SCarray[SCnum, :]:
dummy1[val1] = Q[i]
i += 1
print('complex value inserted:', dummy1)
# USer # 1 Mapping
# Step-1 : Sub channel allocation
SCnum = 5 # Range of sub channel assignment is 0 to 7
print(SCarray[SCnum, :])
# Step 2 : Binary data generation for 1 sub channel
# i.e. 24 data sub carriers i.e. 48 bits
input_data = ""
for i in range(len1):
temp1 = str(random.randint(0, 1))
input_data += temp1
print(input_data)
# Step-3: Converting binary vector into group of 2 bits (as per QPSK) and
# map the same as per mapping table
s1 = input_data
s2_user2 = []
chunks = [s1[i:i+mode] for i in range(0, len(s1), mode)]
for piece in chunks:
temp = int(piece, 2)
s2_user2.append(temp)
print(s2_user2)
Q1 = np.zeros((24,), dtype=complex)
j = 0
for val in s2_user2:
Q1[j] = mapping_table[val]
j += 1
print(Q)
dummy2 = [0 for element in range(256)]
i = 0
for val1 in SCarray[SCnum, :]:
dummy2[val1] = Q1[i]
i += 1
print('complex value inserted:', dummy2)
# Summing data of both users
dummy = np.zeros((256,), dtype=complex)
for i in range(1, 256):
dummy[i] = dummy1[i] + dummy2[i]
# Time domain conversion before feeding data to DAC
N = 256
OFDM_sym = ifft(dummy, N)
# Receiver part (User # 1 decoding)
SCnum = 2 # This is 2 for user#1 and 5 for user#2
OFDM_sym_r = fft(OFDM_sym, N)
Q_r = np.zeros((24,), dtype=complex)
i = 0
for val1 in SCarray[SCnum, :]:
Q_r[i] = OFDM_sym_r[val1]
i += 1
# Plots for User # 1
figure, axis = plt.subplots(2, 2)
# For Built in convolution
axis[0, 0].plot(Q.real, Q.imag, 'bo')
axis[0, 0].set_title("User #1 : Tx Constellation Diagram")
axis[0, 1].plot(OFDM_sym)
axis[0, 1].set_title("Time domain IFFT diagram")
axis[1, 0].plot(OFDM_sym_r)
axis[1, 0].set_title("Frequency domain FFT diagram")
axis[1, 1].plot(Q_r.real, Q_r.imag, 'ro')
axis[1, 1].set_title("User #1 : Rx const. diagram")
plt.tight_layout()
plt.show()
Output Plots OFDMA