ELT-43007 DIGITAL COMMUNICATIONS Matlab Exercise #1 Baseband equivalent digital transmission in AWGN channel: Transmitter and receiver structures - QAM signals, symbol detection and symbol error probability calculations 1 SYSTEM MODEL AND GENERATION OF QAM SYMBOLS 1.1 SYSTEM MODEL In this exercise, we create a baseband equivalent QAM transmission system including a transmitter (TX), a receiver (RX), and a simple AWGN (Additive White Gaussian Noise) channel model. We consider the TX and RX structures to be similar to the ones shown in Fig. 1. Here, both the TX and RX structure are based on complex calculations, but the same structures can also be implemented by using only real-valued signals (i.e., I/Q-modulation with separate I and Q branches). As transmit and receive filters we use the Root-Raised-Cosine (RRC) filters. Together (in TX and RX) these filters fulfill the Nyquist criterion (i.e. no inter-symbol-interference (ISI)). Notice that a single RRC does not do this unlike with the conventional raised-cosine filter. Complex symbols k Transmitter Transmit filter gt () Complex baseband signal a st () Noise r(t) Receive filter f(t) qt () Receiver Sampler q(k) Decicion Detected symbols aˆk Figure 1: Baseband equivalent system structure with AWGN channel. 1.2 CONSIDERED SYSTEM PARAMETERS First let s define the general system parameters as follows: SNR = 0:1:20; % Signal-to-noise ratio vector [db] T = 1/10e6; % Symbol time interval [s] r = 4; % Oversampling factor (r samples per pulse) N_symbols_per_pulse = 40; % Duration of TX/RX filter in symbols alpha = 0.20; % Roll-off factor (excess bandwidth) Based on above we can define sampling frequency and sampling time interval as Fs = r/t; % Sampling frequency Ts = 1/Fs; % Sampling time interval
1.3 GENERATION OF QAM SYMBOLS First we define the number of symbols to be transmitted. N_symbols = 10000; % Number of symbols Then generate the symbols o Create a 16-QAM constellation (help bsxfun) o Scale the constellation so that the expected average power of transmitted symbols equals to one o Generate the specified number (N_symbols) of random symbols o Plot the transmitted symbols in complex plane (a constellation) % Alphabet size M = 16; % Number of symbols in the QAM alphabet (e.g. 16 means 16-QAM). % Valid alphabet sizes are 4, 16, 64, 256, 1024,... % (i.e. the possible values are given by the vector 2.^(2:2:N), for any N) % Here qam_axis presents the symbol values in real/imaginary axis. % So, generally for different alphabet/constellation sizes (): qam_axis = -sqrt(m)+1:2:sqrt(m)-1; % For example, the above results in % qam_axis = [-1 1]; % for QPSK % qam_axis = [-3-1 1 3]; % for 16-QAM % qam_axis = [-7-5 -3-1 1 3 5 7]; % for 64-QAM % generation of a complex constellation: alphabet = bsxfun(@plus,qam_axis',1j*qam_axis); %help bsxfun % equivalent to alphabet = repmat(qam_axis', 1, sqrt(alphabet_size)) +... % repmat(1j*qam_axis, sqrt(alphabet_size), 1); alphabet = alphabet(:).'; % alphabet symbols as a row vector % Scaling the constellation, so that the mean power of a transmitted symbol % is one (e.g., with QPSK this is 1/sqrt(2), and for 16-QAM 1/sqrt(10)) alphabet_scaling_factor = 1/sqrt(mean(abs(alphabet).^2)); alphabet = alphabet*alphabet_scaling_factor; % Random vector of symbol indices (i.e., numbers between 1...alphabet_size) symbol_ind = randi(length(alphabet),1,n_symbols); symbols = alphabet(symbol_ind); % Symbols to be transmitted % Plot the symbols figure plot(symbols,'ro', 'MarkerFaceColor','r') title('transmitted symbols') 2 TRANSMITTER STRUCTURE By following the TX structure in Fig. 1, we generate a continuous time QAM signal based on the abovedefined system parameters. Implement the transit filter: Root-Raised-Cosine (RRC) and plot the pulse shape % Filter generation gt = rcosdesign(alpha,n_symbols_per_pulse,r,'sqrt');
% Plot the pulse shape of the transmit/receive filter figure plot(-n_symbols_per_pulse*r/2*ts:ts:n_symbols_per_pulse*r/2*ts,gt,'b') stem(- N_symbols_per_pulse*r/2*Ts:T:N_symbols_per_pulse*r/2*Ts,gt(1:r:end),'ro') xlabel('time [s]') title('transmit/receive RRC filter (pulse shape)') legend('pulse shape','ideal symbol-sampling locations') Filter the transmitted symbol sequence. Remember to upsample the symbol sequence rate to match with sampling rate of the filter/pulse: % Zero vector initilized for up-sampled symbol sequence symbols_upsampled = zeros(size(1:r*n_symbols)); % symbol insertion symbols_upsampled(1:r: r*n_symbols) = symbols; % now the up-sampled sequence looks like {a1 0 0... a2 0 0... a3 0 0...} st = filter(gt,1,symbols_upsampled); % Transmitter filtering st = st(1+(length(gt)-1)/2:end); % Filter delay correction Plot the transmit signal s(t) in time and frequency domain figure % zoom manually to see the signal better plot(abs(st)) xlabel('time [s]') ylabel('amplitude (of a complex signal)') title('signal s(t) in time domain') NFFT = 2^14; %FFT size f = -Fs/2:1/(NFFT*Ts):Fs/2-1/(NFFT*Ts); %frequency vector % Plot the transmit signal in frequency domain subplot(2,2,1); plot(f/1e6, fftshift(abs(fft(st, NFFT)))); ylabel('amplitude ') title('tx signal s(t)') ylim([0 500]); 3 CHANNEL MODEL Here we consider a simple AWGN channel model. We create white random noise, scale it with the proper scaling factor to obtain the desired SNR (after receive filtering), and then add it on top of the transmitted signal s(t). Generate the noise vector % Complex white Gaussian random noise n = (1/sqrt(2))*(randn(size(st)) + 1j*randn(size(st))); P_s = var(st); P_n = var(n); % Signal power % Noise power % Defining noise scaling factor based on the desired SNR: noise_scaling_factor = sqrt(p_s/p_n./10.^(snr./10)*(r/(1+alpha)));
Add noise on top of the signal s(t). Remember that the variable SNR is now a vector. % Initialization for RX signal matrix, where each row represents the % received signal with a specific SNR value rt = zeros(length(snr), length(st)); % Received signal with different SNR values for ii = 1:1:length(SNR) rt(ii,:) = st + noise_scaling_factor(ii)*n; end Plot the amplitude spectrum of the noise and noisy bandpass signal % Plot the amplitude response of the noise with the SNR corresponding % to the last value in the SNR vector (just as an example) subplot(2,2,2) plot(f/1e6, fftshift(abs(fft(noise_scaling_factor(end)*n, NFFT)))); title(['noise (corresponding to SNR = ', num2str(snr(end)), ' db)']) ylim([0 500]); % Received signal with the noise when the SNR is equal to the last value of % the SNR vector subplot(2,2,3) plot(f/1e6, fftshift(abs(fft(rt(end,:), NFFT)))); title(['rx signal r(t) (SNR = ', num2str(snr(end)), ' db)']) ylim([0 500]); Based on the figures, could you tell why we used r/(1+alpha) when scaling the noise? Think when the noise is added to the signal and how the receive filter affects that. 4 RECEIVER STRUCTURE Typically, due to many unknown/uncertain parameters, most of the complexity in a communications system is found on the RX side. Now, by following the RX structure in Fig. 1, we estimate the transmitted symbols from the received noisy bandpass QAM signal. 4.1 SIGNAL FILTERING AND SAMPLING Filter the received signal r(t) with the receive filter (RRC similar to TX) and sample the resulting continuous time signal q(t) in order to obtain the discrete time signal sequence q(k). % Creating the receive filter (it is the same as in the transmitter) ft = gt; % Plotting the amplitude response of the receive filter subplot(2,2,4) plot(f/1e6, fftshift(abs(fft(ft, NFFT)))); title('rx filter f(t)') % Initialization for the received symbol matrix, where each row represents % the symbols with a specific SNR value
qk = zeros(length(snr), N_symbols - N_symbols_per_pulse); % Note that due to filtering transitions, we loose some of the last % symbols of the symbol sequence. In practice we would simply continue % taking a few samples after the sequence to try to get all the symbols. % However, filter transitions in the beginning and in end are always % creating non-idealities to the transmission (the same is also happening % in frequency domain: e.g. compare data in the middle and in the edge of % the used band). % Filtering and sampling for ii = 1:1:length(SNR) qt = filter(ft,1,rt(ii,:)); % Receiver filtering qt = qt(1+(length(ft)-1)/2:end); % Filter delay correction end % Sampling the filtered signal. Remember that we used oversampling in % the TX. qk(ii,:) = qt(1:r:end); Plot the samples in a complex plane (constellation) with a few different SNR values % Plot a few examples of the noisy samples and compare them with the % original symbol alphabet figure(5) subplot(3,1,1) plot(qk(1,:),'b*') plot(alphabet,'ro', 'MarkerFaceColor','r') hold off legend('received samples', 'Original symbols') title(['received samples with SNR = ', num2str(snr(1)), ' db']) figure(5) subplot(3,1,2) mid_ind = ceil(length(snr)/2); % index for the entry in the middle plot(qk(mid_ind,:),'b*') plot(alphabet,'ro', 'MarkerFaceColor','r') hold off legend('received samples ', 'Original symbols') title(['received samples with SNR = ', num2str(snr(mid_ind)), ' db']) figure(5) subplot(3,1,3) plot(qk(end, :),'b*') plot(alphabet,'ro', 'MarkerFaceColor','r') hold off legend('received samples ', 'Original symbols') title(['received samples with SNR = ', num2str(snr(end)), ' db'])
Based on the constellation figures, what you say about the received samples with different SNRs? (Note the scaling differences between the figures.) Intuitively, what is the easiest case to perform the symbol detection? 4.2 OBTAINING SYMBOL DECISIONS AND CALCULATING THE SYMBOL ERROR RATE (SER) The final step is to make the symbol decisions. This is done based on the minimum distance principle, where the symbol estimate is defined as that symbol of the alphabet, which minimizes the distance to the symbol sample. Calculate the Euclidian distance between each symbol sample and each alphabet symbol. Then find the indices of the alphabet symbols, which have the minimum distance to the symbol samples, and finally find out which symbols were received incorrectly and define the observed Symbol Error Rate (SER). Remember again that we used multiple SNR values and each row of the signal samples q(k) represents the received signal with different SNRs. % Initialization SER = zeros(1,length(snr)); for ii = 1:1:length(SNR) alphabet_error_matrix = abs(bsxfun(@minus,alphabet.',qk(ii,:))); % Now, rows represent the alphabet symbol indices and columns represent % the received symbol indices (e.g. the Euclidian distance between the % 5th received symbol and the 3rd symbol in the alphabet is given as % "alphabet_error_matrix(3,5)" % Searching for the indeces corresponding to the minimum distances [~,estimated_symbol_ind] = min(alphabet_error_matrix); % Finding out which symbols were estimated incorrecly: symbol_errors =... estimated_symbol_ind ~= symbol_ind(1:length(estimated_symbol_ind)); % Symbol error rate (0 means 0% of errors, 1 means 100% of errors) SER(1,ii) = mean(symbol_errors); end Calculate the theoretical symbol error probability (see p. 153 from the lecture slides) and compare that with the simulated results % Find out the minimum distance between two constellation points d = min(abs(alphabet(1)-alphabet(2:end))); % Sigma values. Note that we need to first divide the original power of the % noise by two in order to get the parameter used in the equations. % Variable noise_scaling_factor was used for amplitudes so we need to % square it for getting the corresponding power scaling factor. sigma = sqrt(0.5 * P_n * noise_scaling_factor.^2); % Theoretical symbol error probability P_sym_error = (4*qfunc(d./(2*sigma)) - 4*qfunc(d./(2*sigma)).^2) *... ((M-4-4*(sqrt(M)-2))/M) +... (2*qfunc(d./(2*sigma))- qfunc(d./(2*sigma)).^2) * (4/M) +...
(3*qfunc(d./(2*sigma)) - 2*qfunc(d./(2*sigma)).^2) * (4*(sqrt(M)-2)/M); % Note that we could calculate this for 16-QAM directly as in p. 151: % P_sym_error_16QAM = 3*qfunc(d./(2*sigma)) - 2.25*qfunc(d./(2*sigma)).^2; % but now the probability is given in a more generic form and thus is % applicable to all M-QAM alphabets. % Compare the simulated and theoretical results. % You can also check lecture slides p. 161 for more examples. figure semilogy(snr, SER, 'LineWidth', 3); ; semilogy(snr, P_sym_error, 'r--', 'LineWidth', 2); title('symbol error rate') xlabel('snr [db]') ylabel('ser') legend('simulated SER','Theoretical symbol error probability'); Do the simulated results match with the theoretical ones? Where you can see differences and why there?