Main Content

Use Pulse Shaping on 16-QAM Signal

This example extends the Examine 16-QAM Using MATLAB example to perform pulse shaping and raised cosine filtering by using a pair of square-root raised cosine (RRC) filters. The rcosdesign function creates the filters. BER performance can be improved by adding forward error correction (FEC) to the communication link. To add FEC to the communications link with pulse shape filtering example, see the Use Forward Error Correction on 16-QAM Signal example.

This example shows how to process a binary data stream by using a communications link that consists of a baseband modulator, channel, demodulator, and pulse shaping and raised cosine filtering. The example computes the bit error rate (BER), displays filter effects in eye diagrams, and displays the transmitted and received signals in a constellation diagram.

Establish Simulation Framework

Define simulation parameters for a 16-QAM modulation scheme with raised cosine filtering, and an AWGN channel.

M = 16;            % Modulation order
k = log2(M);       % Bits per symbol
numBits = k*7.5e4; % Bits to process
sps = 4;           % Samples per symbol (oversampling factor)

Create RRC Filter

Set the RRC filter parameters.

filtlen = 10;      % Filter length in symbols
rolloff = 0.25;    % Filter rolloff factor

Use the rcosdesign function to create an RRC filter.

rrcFilter = rcosdesign(rolloff,filtlen,sps);

Use the FVTool to display the RRC filter impulse response.

fvtool(rrcFilter,'Analysis','Impulse')

{"String":"Figure Figure 1: Impulse Response contains an axes object. The axes object with title Impulse Response contains an object of type stem.","Tex":"Impulse Response","LaTex":[]}

Compute System BER

Use the randi function to generate random binary data. Set the rng function to its default state, or any static seed value, so that the example produces repeatable results.

rng default;                     % Use default random number generator
dataIn = randi([0 1],numBits,1); % Generate vector of binary data

Use the bit2int function to convert k-tuple binary words into integer symbols.

dataSymbolsIn = bit2int(dataIn,k);

Apply 16-QAM modulation using the qammod function.

dataMod = qammod(dataSymbolsIn,M);

Use the upfirdn function to upsample the signal by the oversampling factor and apply the RRC filter. The upfirdn function pads the upsampled signal with zeros at the end to flush the filter. Then, the function applies the filter.

txFiltSignal = upfirdn(dataMod,rrcFilter,sps,1);

Using the number of bits per symbol (k) and the number of samples per symbol (sps), convert the ratio of energy per bit to noise power spectral density (EbNo) to an SNR value for use by the awgn function.

EbNo = 10;
snr = EbNo + 10*log10(k) - 10*log10(sps);

Pass the filtered signal through an AWGN channel.

rxSignal = awgn(txFiltSignal,snr,'measured');

Use the upfirdn function on the received signal to downsample and filter the signal. Downsample by using the same oversampling factor applied for upsampling the transmitted signal. Filter by using the same RRC filter applied to the transmitted signal.

Each filtering operation delays the signal by half of the filter length in symbols, filtlen/2. So, the total delay from transmit and receive filtering equals the filter length, filtlen. For the BER computation, the transmitted and received signals must be the same size and you must account for the delay between the transmitted and received signal. Remove the first filtlen symbols in the decimated signal to account for the cumulative delay of the transmit and receive filtering operations. Remove the last filtlen symbols in the decimated signal to ensure the number of samples in the demodulator output matches the number of samples in the modulator input.

rxFiltSignal = ...
    upfirdn(rxSignal,rrcFilter,1,sps);       % Downsample and filter
rxFiltSignal = ...
    rxFiltSignal(filtlen + 1:end - filtlen); % Account for delay

Use the qamdemod function to demodulate the received filtered signal.

dataSymbolsOut = qamdemod(rxFiltSignal,M);

Convert the recovered integer symbols into binary data by using the int2bit function.

dataOut = int2bit(dataSymbolsOut,k);

Determine the number of errors and the associated BER by using the biterr function.

[numErrors,ber] = biterr(dataIn,dataOut);
fprintf('\nFor an EbNo setting of %3.1f dB, the bit error rate is %5.2e, based on %d errors.\n', ...
    EbNo,ber,numErrors)
For an EbNo setting of 10.0 dB, the bit error rate is 1.79e-03, based on 538 errors.

Visualize Filter Effects

To visualize the filter effects in an eye diagram, reduce the Eb/N0 setting and regenerate the received data. Visualizing a high SNR signal with no other multipath effects, you can use eye diagrams to highlight the intersymbol interference (ISI) reduction at the output for the pair of pulse shaping RRC filters. The RRC filter does not have zero-ISI until it is paired with the second RRC filter to form in cascade a raised cosine filter.

EbNo = 20;
snr = EbNo + 10*log10(k) - 10*log10(sps);
rxSignal = awgn(txFiltSignal,snr,'measured');
rxFiltSignal = ...
    upfirdn(rxSignal,rrcFilter,1,sps);         % Downsample and filter
rxFiltSignal = ...
    rxFiltSignal(filtlen + 1:end - filtlen);   % Account for delay

Create an eye diagram for a portion of the filtered noiseless signal to visualize the effect of the pulse shaping. The transmitted signal has RRC filtering and shows ISI as a narrowing of the eye-opening.

eyediagram(txFiltSignal(1:2000),sps*2);

{"String":"Figure Eye Diagram contains 2 axes objects. Axes object 1 with title Eye Diagram for In-Phase Signal contains an object of type line. This object represents In-phase. Axes object 2 with title Eye Diagram for Quadrature Signal contains an object of type line. This object represents Quadrature.","Tex":["Eye Diagram for In-Phase Signal","Eye Diagram for Quadrature Signal"],"LaTex":[]}

Displaying the eye diagram of the signal after the channel noise shows the signal with RRC filtering and noise. The noise level causes further narrowing of the eye diagram eye-opening.

eyediagram(rxSignal(1:2000),sps*2);

{"String":"Figure Eye Diagram contains 2 axes objects. Axes object 1 with title Eye Diagram for In-Phase Signal contains an object of type line. This object represents In-phase. Axes object 2 with title Eye Diagram for Quadrature Signal contains an object of type line. This object represents Quadrature.","Tex":["Eye Diagram for In-Phase Signal","Eye Diagram for Quadrature Signal"],"LaTex":[]}

Displaying the eye diagram of the signal after the receive filtering is applied shows the signal with raised cosine filtering. The wider eye diagram eye-openings, the signal has less ISI with raised cosine filtering as compared to the signal with RRC filtering.

eyediagram(rxFiltSignal(1:2000),2);

{"String":"Figure Eye Diagram contains 2 axes objects. Axes object 1 with title Eye Diagram for In-Phase Signal contains an object of type line. This object represents In-phase. Axes object 2 with title Eye Diagram for Quadrature Signal contains an object of type line. This object represents Quadrature.","Tex":["Eye Diagram for In-Phase Signal","Eye Diagram for Quadrature Signal"],"LaTex":[]}

Create a constellation diagram of the received signal before and after filtering. Scale the received signal by the square root of the number of samples per symbol to normalize the transmit and receive power levels.

scatplot = scatterplot(sqrt(sps)*...
    rxSignal(1:sps*5e3),...
    sps,0);
hold on;
scatterplot(rxFiltSignal(1:5e3),1,0,'bx',scatplot);
title('Received Signal, Before and After Filtering');
legend('Before Filtering','After Filtering');
axis([-5 5 -5 5]); % Set axis ranges
hold off;

Figure Scatter Plot contains an axes object. The axes object with title Received Signal, Before and After Filtering contains 2 objects of type line. These objects represent Before Filtering, After Filtering.

Related Topics