Eb_No_linear = db2pow(Eb_No);
error_awgn = zeros(length(Eb_No), N_iterations);
error_rayleigh_awgn = zeros(length(Eb_No), N_iterations);
BER_awgn = zeros(size(Eb_No));
BER_rayleigh_awgn = zeros(size(Eb_No));
BER_theoretical_awgn = qfunc(sqrt(2 * Eb_No_linear));
BER_theoretical_fading = 0.5 * (1 - sqrt(Eb_No_linear ./ (1 + Eb_No_linear)));
Es_No = Eb_No(n) + 10*log10(Im);
total_bit_errors_awgn = 0;
total_bit_errors_rayleigh = 0;
data = randi([0 1], Nb, 1);
data_symbols = bi2de(reshape(data, Im, []).', 'left-msb');
x = pskmod(data_symbols, M, pi/M, 'gray');
h = 1/sqrt(2) * (randn(N, 1) + 1i * randn(N, 1));
y = awgn(x, Es_No, "measured");
yf = awgn(xf, Es_No, "measured");
y_est = pskdemod(y, M, pi/M, 'gray');
yf_est = pskdemod(yf_equalized, M, pi/M, 'gray');
y_est_bits = de2bi(y_est, Im, 'left-msb').';
yf_est_bits = de2bi(yf_est, Im, 'left-msb').';
y_est_bits = y_est_bits(:);
yf_est_bits = yf_est_bits(:);
total_bit_errors_awgn = total_bit_errors_awgn + nnz(data ~= y_est_bits);
total_bit_errors_rayleigh = total_bit_errors_rayleigh + nnz(data ~= yf_est_bits);
BER_awgn(n) = total_bit_errors_awgn / (Nb * N_iterations);
BER_rayleigh_awgn(n) = total_bit_errors_rayleigh / (Nb * N_iterations);
semilogy(Eb_No, BER_theoretical_awgn, 'r-', 'LineWidth', 1.5); hold on;
semilogy(Eb_No, BER_awgn, 'r-o', 'LineWidth', 1);
semilogy(Eb_No, BER_theoretical_fading, 'b-', 'LineWidth', 1.5);
semilogy(Eb_No, BER_rayleigh_awgn, 'b-o', 'LineWidth', 1);
title('QPSK BER curves for AWGN and Rayleigh');
legend('AWGN_{theory}', 'AWGN_{simulation}', 'Rayleigh_{theory}', 'Rayleigh_{simulation}', 'location', 'best');