This example extends the Examine 16-QAM Using MATLAB example to perform pulse shaping and matched 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 matching filters. The example displays a portion of the random data in a stem plot, displays the transmitted and received signals in constellation diagrams, and computes the bit error rate (BER).
Define simulation parameters for a 16-QAM modulation scheme with raised cosine filtering, and an AWGN channel.
M = 16; % Modulation order k = log2(M); % Number of bits per symbol numBits = 3e5; % Number of bits to process sps = 4; % Number of samples per symbol (oversampling factor)
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')
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
Reshape the input vector into a matrix of 4-bit binary data. Then, use the bi2de
function to convert the data into integer symbols.
dataInMatrix = reshape(dataIn,length(dataIn)/k,k); % Reshape data into binary 4-tuples dataSymbolsIn = bi2de(dataInMatrix); % Convert to integers
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 de2bi
function.
dataOutMatrix = de2bi(dataSymbolsOut,k);
dataOut = dataOutMatrix(:); % Return data in column vector
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.83e-03, based on 550 errors.
To visualize the filter effects in an eye diagram, reduce the 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 matched 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 as a matched pair of filters.
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);
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);
Displaying the eye diagram of the signal after the matched 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);
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,'g.'); hold on; scatterplot(rxFiltSignal(1:5e3),1,0,'kx',scatplot); title('Received Signal, Before and After Filtering'); legend('Before Filtering','After Filtering'); axis([-5 5 -5 5]); % Set axis ranges hold off;