OFDM Transmitter simulation Python | WiMAX 256 point FFT

This page covers OFDM Transmitter simulation as per WiMAX 256 point FFT. It includes binary generator, QPSK modulation (mapping), OFDM symbol formation and various plots.

Introduction : OFDM is a multicarrier transmission scheme used in WiMAX and WLAN standards. It has been introduced in IEE 802.11a Physical layer specifications and later introduced in IEEE 802.16-2004 Physical layer. Its variant OFDMA is widely used in 4G LTE system and later versions of the cellular standards.

wimax physical layer Block diagram for transmitter part

As shown in the figure-1, WiMAX Physical layer consists transmitter and receiver. Transmitter modules which include Scrambler, EFC encoder, interleaver, data modulation, IFFT, CP insertion etc. Receiver consists of reverse functionalities of transmitter modules. In addition receiver has time offset/frequency offset correction and channel equalization modules. Refer WiMAX OFDM Physical layer >> and WLAN OFDM PHY >> for more information.

OFDM Transmitter simulation in python

In this python simulation we will be simulating OFDM transmitter modules viz. binary generator, QPSK modulation, symbol formation, IFFT and CP insertion modules. The code simulates data with size equals one OFDM symbol i.e. 384 bits which can be occupied on 192 data carriers carrying QPSK complex symbols. The symbol accommodates eight pilots in each OFDM symbols. The same code can be changed to frame consisting of multiple OFDM symbols. It can be changed to other modulation schemes by changing value of "mu" to 4 and 6 as per 16QAM and 64QAM modulation types respectively.

OFDM Python code

# Python Library import
import random
import numpy as np
import matplotlib.pyplot as plt
from scipy.fftpack import fft, ifft, ifftshift

# Step1 : WiMaX OFDM 256 Parameters configuration for simulation
dataCarriers = 192 # Number of data sub carriers in a symbol
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
input_data = ""
len1 = payloadBits_per_OFDM # length of input data
pilot = [1, -1, 1, -1, -1, -1, 1, 1] # 8 Nos. pilot sub carriers
pilot_pop = [41, 66, 91, 116, 142, 167, 192, 217] # Positions of pilot sub carriers in OFDM symbol
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}

# Step 2 : Binary data generation for 1 symbol data carriers i.e. 384 bits
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 = []
chunks = [s1[i:i+mode] for i in range(0, len(s1), mode)]
for piece in chunks:
  temp = int(piece, 2)
  s2.append(temp)
print(s2)
Q = np.zeros((192,), dtype=complex)
j = 0
for val in s2:
  Q[j] = mapping_table[val]
  j += 1
print(Q)

# Step 4 : Arranging data sub carriers as per WiMAX OFDM symbol format
list1 = [i for i in range(29, 41)]
list2 = [i for i in range(42, 66)]
list3 = [i for i in range(67, 91)]
list4 = [i for i in range(92, 116)]
list5 = [i for i in range(117, 129)]
list6 = [i for i in range(130, 142)]
list7 = [i for i in range(143, 167)]
list8 = [i for i in range(168, 192)]
list9 = [i for i in range(193, 217)]
list10 = [i for i in range(218, 230)]
list = list1 + list2 + list3 + list4 + list5 + list6 + list7 + list8 + list9 + list10
# print(list)
dummy = [0 for element in range(256)]
print('all zeros:', dummy)

# Step 5 : Modulation values (to data sub carriers) and pilot values (to pilot sub carriers) insertion
i = 0
for val1 in list:
  dummy[val1] = Q[i]
  i += 1
print('complex value inserted:', dummy)
i = 0
for val2 in pilot_pop:
  dummy[val2] = pilot[i]
  i += 1
print('pilot values inserted:', dummy)

# Step 6 : Inverse fourier transform for size 256 for entire symbol
N =256
OFDM_sym = ifft(dummy, N)
CP =16 # Cyclic prefix of 16 samples
CP_samples = OFDM_sym[N-CP:] # extraction of CP samples from symbol
OFDM_sym_cp = np.append([CP_samples], [OFDM_sym]) # Concatenate CP and Symbol
x = ifftshift(OFDM_sym_cp)

# Initialise the subplot function
figure, axis = plt.subplots(2, 2)
# For Built in convolution
axis[0,0].plot(Q.real, Q.imag, 'bo')
axis[0,0].set_title("QPSK Constellation Diagram")
# For Our own function
axis[0,1].plot(dummy, 'ro')
axis[0,1].set_title("# Sub-carriers: Data(192),Pilot(8),Null(55),DC(1)")
axis[1, 0].plot(OFDM_sym)
axis[1, 0].set_title("1 symbol OFDM power (After IFFT) vs time")
Xfft = fft(OFDM_sym, 256)
axis[1, 1].plot(abs(Xfft))
axis[1, 1].set_title("OFDM absolute value (After FFT) vs frequency")
plt.show()

Output plots

Following are the output plots of OFDM python script as mentioned above. The plots include QPSK constellation diagram, subcarriers (data, pilots, guard, DC) with their values, symbol vs time after IFFT and symbol vs samples after FFT.

OFDM Transmitter python script output plots

Other useful DSP codes in Python

Useful Links to MATLAB codes

RF and Wireless tutorials