I have some understanding problems with OFDM. I think I have understood most of the theoretical concept. At the moment, I am trying to write some Python code to simulate the transmitter part. This is just to see what the signal looks like in the time and frequency domain.

As an example, I want to build a transmitter with the following properties:

  • Number of subcarriers: 4
  • Modulation of each subcarrier is QPSK
  • All subcarriers are used and I don’t want to append a CP.

My goal is to create one symbol in the time domain. First, I have to generate data. Let’s say I have the following symbols at the input of my IFFT:

[1.+1.j 1.-1.j 1.+1.j 1.+1.j]

At the output I have another four complex values:

[ 2.+1.j -1.+0.j 0.+1.j 1.+0.j]

What am I supposed to do with these four values? Somehow I have to generate a complex baseband signal x(t) from this. If I split this into a real and imaginary part, I have four values for each part. How can I generate a waveform from this?


1 Answer 1


This existing answer should help further detail the explanation and code provided below.

The complex baseband signal is simply the IFFT; recreating the time domain waveform from the baseband values. So each bin in the FFT represents the complex value for the individual frequency "sub-carrier" represented by that FFT bin.

For each FFT frame of N sub-carriers, load in the N complex values for each of the N QPSK symbols within that FFT frame, which will have a time duration corresponding to the time interval for the resulting Inverse FFT. Then on the next frame, load all the next symbols (based on the data desired to be transmitted) and append the resulting Inverse FFT for that next frame at the end of the previous etc (assuming as the OP has stated that we are ignoring the additional Cyclic Prefix).

Below is a simple Python example of this that I had previously done to confirm the carrier offset computations I provided for this other post, in this case using $N=8$. The four symbols labeled "0", "1", "2", "3", correspond to the possible combinations for two bits of data, depending on how a binary data pattern is mapped to those symbols (see Gray-coding for QPSK at this link). Thus the sequence [0, 1, 2, 0, 2, 3, 0, 1] corresponds to some 16 bit sequence of binary data. The result tx is the 8 time domain samples resulting from the parallel transmission of the 8 closely spaced individual QPSK waveforms. Note how each of the symbols is thus sampled at 8 samples/symbol.

# map ofdm symbols to QPSK constellation

# here is an example short sequence 
# where 0 is Q1, 1 Q2, 2 Q3 and 3 Q4

symmap = {0: 1 + 1j,
        1 : 1 - 1j,
        3 : -1 - 1j,
        2 : -1 + 1j}

tx_symb = [0, 1, 2, 0, 2, 3, 0, 1]

# inverse FFT for tx sequence

txfft = [symmap[i] for i in tx_symb]

tx = fft.ifft(txfft)

# recovering rx in the receiver

rx1 = fft.fft(tx)

I hope the following additional graphics clear up any residual confusion:

Freq vs Time

Above we see the processing of three successive OFDM symbols in time (where an "OFDM Symbol" corresponds to a complete FFT frame). Each OFDM symbol contains 4 sub-carriers each with QPSK modulation, with the red dots indicating possible locations for any given transmission. For the first sub-carrier I have specifically indicated that we are transmitting "S1" for first sub-carrier in the first OFDM symbol, then "S2" for this same sub-carrier in the next OFDM symbol, then "S3" for this same sub-carrier in the third OFDM symbol. The time duration for "S1", "S2" and "S3" is the time duration of the FFT frame. Given with the FFT that we have the same number of samples in time and in frequency, then the four samples in the FFT correspond to four samples in time, and the duration will be given by the sampling rate for those samples. If for example we wanted a QPSK symbol duration to be 1 ms, then that means we have to have a sampling rate of 4 samples per ms or 4 KHz: We need to load the FFT at this rate in order to keep up with a transmitted output consistent with a 1 ms QPSK symbol duration.

This is further detailed in the plot below showing the resulting IFFT outputs and the first sub-carrier's contribution to the resulting IFFT (which would be the sum of all the modulated sub-carriers in the time domain).


  • $\begingroup$ Ok. Thanks for your replie. I understood, that the output of the IFFT represent the samples of the time domain. And I know, that when I feed this samples back to a FFT, I get back what I fed into the IFFT. What I do not understand is, how I have to handle the symblos that come out of the IFFT to send them over a channel. I do not have an information of the symbol length. $\endgroup$ May 21, 2023 at 12:50
  • $\begingroup$ As an example. For a BPSK simulation I made with python, I do it the following way in the transmitter. I have a series of bits. Each bit is mapped to a 1 or a -1. I use this numbers to feed them into a pulseshaping filter. And now I have a symbol, I can send over a channel. I know how many samples per symbol I used and I know the samplerate of my system. So I can tell how long a symbol in time domain will be. I don‘t understand how to do this with the samples after the IFFT. $\endgroup$ May 21, 2023 at 12:51
  • $\begingroup$ The number of samples $N$ is the samples $0$ to $N-1$ in the frequency domain where $0$ is "DC" and $N$ is the sampling rate $f_s$. This corresponds to $N$ samples in the time domain with $n=0$ to $n=N-1$ where each sample has a duration $T$ given by $1/f_s$. Thus your symbol duration is $NT = N/f_s$. Does that make sense? The whole FFT frame is the duration of one BPSK symbol. This also makes sense that you don't change that symbol until the next FFT. $\endgroup$ May 21, 2023 at 12:56
  • 1
    $\begingroup$ Thank you very much. You have helped me to make a little progress. My simulation is now working and behaving as I expected. $\endgroup$ May 22, 2023 at 15:59
  • $\begingroup$ I am so happy to hear that. Thanks for letting me know. $\endgroup$ May 22, 2023 at 16:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.