Sample Code Ofdm
Sample Code Ofdm
Here I will provide all the code that I am developing. I will start in ascending
order, that is, from the first program written onwards. I hope that the
explanations will be sufficient. All the code will be in HTML format, just copy
and paste into the MATLAB editor and you will be good to go.
Version Short Description Date
0.10 Standard MCM communications system 09.10.04
0.11 * Incomplete * 09.11.04
0.12 Generic OFDM with Cyclic Prefixing 09.12.04
0.13 Added Channel equalization & AWGN noise effects 09.20.04
Other Necessary Functions
1. do_padding
Takes the serial input data and the user specified block size, then checks
the serial data if it can be completely divided into an integer number of
blocks. If not, it will add zeros to the end of the stream until an integer
number of blocks can be created.
Version 0.10 is basically a trial run to get back into the mode of things. This is
a simple MCM communications system. The code is pretty self-explanatory.
Results of running this script:
Fig. 1. Random input data samples
% 1. Generate data
M = 4;
no_of_data_points = 64;
input = randsrc(1,no_of_data_points, 0:M-1);
figure(1)
stem(input); grid on; xlabel('Data'); ylabel('Amplitude');title('Input')
% 2. Modulation
msg_tx = pskmod(input, M);
scatterplot(msg_tx);
% 3. Serial to Parallel
parallel_mod_data = reshape(msg_tx,8,8);
% 4. 64-point IFFT
ofdm_msg = ifft(parallel_mod_data);
% 5. Parallel to serial
ofdm_msg_tx = reshape(ofdm_msg, 1,64);
figure(3)
plot(real(ofdm_msg_tx)); grid on;title('Real part of OFDM signal')
figure(4)
plot(imag(ofdm_msg_tx)); grid on;title('Imaginary part of OFDM signal')
% ---------------------
% B: Receiver End
% ---------------------
% 1. Serial to Parallel
ofdm_msg_rx = reshape(ofdm_msg_tx, 8,8);
% 2. 64-point FFT
msg_rx = fft(ofdm_msg_rx);
% 3. Parallel to serial
msg_rx_ser = reshape(msg_rx, 1, 64);
% 4. Demodulation
msg_demod = pskdemod(msg_rx_ser, M);
figure(5)
stem(msg_demod); grid on;title('Output')
%
% OFDM System Version 0.11 - !!! InComplete !!!!
% Created on September 11, 2004 by Surujlal Dasrath
%
% ** New in Version 0.11 **
% 1. Add pilot symbols to the input data just before transmission
% 2. Implement cyclic prefix (CP), use 10% of symbol length. Divide the 64
% input data points into 8-bit streams, generate and append the CP based
% on each symbol
% 3. Include complex noise into transmitted signal
%
% Organization of Transmitter end of OFDM System
% a. Generate Data
% b. Modulate
% c. Serial to Parallel
% d. Cyclic Prefix (CP)
% e. Add Pilot points
% f. IFFT
% g. Parallel to Serial
% =======================================================================
%
% ---------------
% A: Definitions
% ---------------
M = 4; % use M=4 for QPSK modulation
no_of_data_points = 64; % have 64 data points
no_of_channels = no_of_data_points/8; % make each symbol block length 8
% 4. Append pilot symbols to the end of each data block. Now the new
% matrix will have an extra row. Each pilot will have unit amplitude
% and zero phase for future reference
% EX: If pilots were added to the above example, it will look like:
%
% parallel_data = 1 5
% 2 6
% 3 7
% 4 8
% -------
% 1 1
%
pilot_data = ones(1,8);
data_and_pilot = [parallel_mod_data;pilot_data]
% 5. Create cyclic prefix. Make its length 10% that of the parallel
% data stream. In this case, we have 8 parallel rows consisting of data
% points and one extra row with the pilot points
This is a more complete (well the first one anyway) OFDM system. It involves
all the necessary steps to generate an OFDM signal.
In this instance of the program, the user can specify how to do block processing
of the incoming signal. Here are the basic steps.
Transmitter End:
1. Define constants, such as block size, number of FFT/IFFT points, etc.
2. Call user written function 'do_padding'. This will take the length
(number) input data points and divide it by the block size. If the result is
an integer, then no padding is necessary. Otherwise, it will pad the data
stream with zeros so that there are an integer number of blocks.
Example: input = [1 2 3 4 5]; block_size = 4
after calling 'do_padding', input becomes [1 2 3 4 5 0 0 0]
3. Do modulation. In this case, I used the MATLAB function, 'pskmod' &
'pskdemod' pairs.
4. Do serial to parallel, i.e. reshape the serial 1 x N vector into a matrix
where the number of rows equal the block size. In this way, IFFT can
be performed columnwise and each column will represent one block of
data.
5. Do IFFT on each column of the data matrix.
6. Compute, generate and append the Cyclic Prefix to the data matrix in
4.
7. Reshape the matrix back to a 1 x N + cyclic prefix length vector for
transmission.
Receiver End:
Just do the opposite to all of the above!
Results of running this script:
Fig. 1. OFDM system without the effects of the channel or noise. Note that the red "x"
(received) perfectly matches up to the blue "o" (transmitted).
clear all
clc
close % closes any open figures
%
% OFDM System Version 0.12
% Created on September 12, 2004 by Surujlal Dasrath
%
% ** New in Version 0.12 **
% Transmitter
% 1. Function (do_padding) to do padding if the serial data cannot be
% segmented into an integer number of blocks
% 2. Create blocks of data points from the serial stream, in matrix
% form where after IFFT & Cyclic Prefixing (CP), each block
% will become an OFDM block
% 3. Add CP to exisiting blocks of data
% 4. Convert martix of blocks of data & CP into an OFDM signal for TX
%
% Receiver
% 5. On the RX end, add a multipath channel via "filer" command
% 6. Remove CP, do FFT & demodulate
% ---------------
% A: Definitions
% ---------------
M = 4; % QPSK signal constellation
no_of_data_points = 64; % have 128 data points
block_size = 8; % size of each ofdm block
cp_len = ceil(0.1*block_size); % length of cyclic prefix
no_of_ifft_points = block_size; % 128 points for the FFT/IFFT
no_of_fft_points = block_size;
% ---------------------------------------------
% B: % +++++ TRANSMITTER HEAD END +++++
% ---------------------------------------------
% 1. Generate 1 x 128 vector of random data points
data_source = randsrc(1, no_of_data_points, 0:M-1);
figure(1)
stem(data_source); grid on; xlabel('Data Points'); ylabel('Amplitude')
title('Transmitted Data "O"')
% --------------------------------
% C: % +++++ CHANNEL +++++
% --------------------------------
% Create a complex multipath channel
%+++channel = randn(1,block_size) + sqrt(-1)*randn(1,block_size);
% ------------------------------------------
% D: % +++++ RECEIVER TAIL END +++++
% ------------------------------------------
%
% 1. Generate random complex noise
%+++noise = randn(1,len_ofdm_data) + sqrt(-1)*randn(1,len_ofdm_data);
% 5. Remove CP
recvd_signal_matrix(1:cp_len,:)=[];
% 6. Perform FFT
for i=1:cols_ifft_data,
% FFT
fft_data_matrix(:,i) = fft(recvd_signal_matrix(:,i),no_of_fft_points);
end
figure(4)
stem(data_source)
hold on
stem(qpsk_demodulated_data,'rx');
grid on;xlabel('Data Points');ylabel('Amplitude');title('Received Data "X"')
I have further added a very simple Linear Equalizer to the code, where I
assume that the channel is perfectly known. Note that for equalization to work
here, the prefix length must be equal to or greater than the length of the
channel.
Afterwards, I added some AWGN noise to the received data. The figures
below shows some of the results.
See the code ofdm_013
Results of running this script:
Fig. 1. Superposition of TX (blue) & RX (red) data after channel effects and equalization
Fig. 2. Same data stream with 0 dB AWGN
Fig. 3. Notice that as the SNR increases the number of errors will decrease
clear all
clc
close % closes any open figures
%
% OFDM System Version 0.13
% Created on September 20, 2004 by Surujlal Dasrath
%
% ** New in Version 0.13 **
% 1. Added channel effects, i.e the channel is an FIR filter
% 2. Equalization after data passes through randomly generated channel
% 3. Implementation of AWGN noise after channel effects
% 3. Calculated Number of Errors and Bit Error Rate
% ---------------
% A: Definitions
% ---------------
M = 4; % QPSK signal constellation
no_of_data_points = 16; % have 128 data points
block_size = 8; % size of each ofdm block
cp_len = ceil(0.4*block_size); % length of cyclic prefix
no_of_ifft_points = block_size; % 128 points for the FFT/IFFT
no_of_fft_points = block_size;
% ---------------------------------------------
% B: % +++++ TRANSMITTER HEAD END +++++
% ---------------------------------------------
% 1. Generate 1 x 128 vector of random data points
data_source = randsrc(1, no_of_data_points, 0:M-1);
%figure(1)
%stem(data_source); grid on; xlabel('Data Points'); ylabel('Amplitude')
%title('Transmitted Data "O"')
% --------------------------------
% C: % +++++ CHANNEL +++++
% --------------------------------
% 1. Create a complex multipath channel
channel = randn(1,2) + sqrt(-1)*randn(1,2);
% ------------------------------------------
% D: % +++++ RECEIVER TAIL END +++++
% ------------------------------------------
%
% 3. Add Noise
awgn_noise = awgn(zeros(1,length(after_channel)),0);
noise_power = abs(awgn_noise);
% 5. Remove CP
recvd_signal_matrix(1:cp_len,:)=[];
% 6. Do Equalization
% Take FFT of the channel & pad it to fit each data block
[pad_chan bl] = do_padding(channel,block_size);
chan_fft = fft(pad_chan,block_size);
chan_fft = reshape(chan_fft,length(chan_fft),1);
[r_recvd_sig_mat c_recvd_sig_mat]=size(recvd_signal_matrix);
for i=1:r_recvd_sig_mat
recvd_signal_matrix(i,:)=recvd_signal_matrix(i,:)./chan_fft(i);
end
% 7. Perform FFT
for i=1:cols_ifft_data,
% FFT
fft_data_matrix(:,i) = fft(recvd_signal_matrix(:,i),no_of_fft_points);
end
% 8. Convert to serial stream
recvd_serial_data = reshape(fft_data_matrix, 1,(block_size*num_cols));
figure(4)
stem(data_source)
hold on
stem(qpsk_demodulated_data,'rx');
grid on;xlabel('Data Points');ylabel('Amplitude');
title('Received Data "x"- with Channel Effects')
% --------------------------------------------
% E: % +++++ CALCULATE BIT ERROR +++++
% --------------------------------------------
[no_of_errors ber]=biterr(data_source,qpsk_demodulated_data)
existing_blocks =
no_of_errors =
ber =
0.2813