1

I'm doing a 16QAM system (transmitter, channel and receiver), and BER and PER curves of the results. However, I'm having some problems with noise at the receiver. I'm running the system inside two loops: for all the Eb/No values and for all the packets and I sent 200 symbols and 1000 packets but this still happens. I would like to check whether the result from this code is correct or not:

clear all
clc
numPkts=1000;

N = 200; % number of symbols
M = 16;   % constellation size
k = log2(M); % bits per symbol
pv=4; %prefix length


% defining the real and imaginary PAM constellation
% for 16-QAM
alphaRe = [-(2*sqrt(M)/2-1):2:-1 1:2:2*sqrt(M)/2-1];
alphaIm = [-(2*sqrt(M)/2-1):2:-1 1:2:2*sqrt(M)/2-1];
k_16QAM = 1/sqrt(10);

Eb_N0_dB  = [0:15]; % multiple Es/N0 values
Es_N0_dB  = Eb_N0_dB + 10*log10(k);
erTot=zeros(1,length(Eb_N0_dB));

% Mapping for binary <--> Gray code conversion
ref = [0:k-1];
map = bitxor(ref,floor(ref/2));
[tt ind] = sort(map);                                

for ii = 1:length(Eb_N0_dB)
for pktX=1:numPkts    
% symbol generation
% ------------------
ipBit = rand(1,N*k,1)>0.5; % random 1's and 0's
ipBitReshape = reshape(ipBit,k,N).';
bin2DecMatrix = ones(N,1)*(2.^[(k/2-1):-1:0]) ; % conversion from binary to decimal
% real
ipBitRe =  ipBitReshape(:,[1:k/2]);
ipDecRe = sum(ipBitRe.*bin2DecMatrix,2);
ipGrayDecRe = bitxor(ipDecRe,floor(ipDecRe/2));
% imaginary
ipBitIm =  ipBitReshape(:,[k/2+1:k]);
ipDecIm = sum(ipBitIm.*bin2DecMatrix,2);
ipGrayDecIm = bitxor(ipDecIm,floor(ipDecIm/2)); 
% mapping the Gray coded symbols into constellation
modRe = alphaRe(ipGrayDecRe+1);
modIm = alphaIm(ipGrayDecIm+1);
% complex constellation
mod = modRe + j*modIm;
s1 = k_16QAM*mod; % normalization of transmit power to one 

s=[s1(length(s1)-pv+1:end) s1]; %add prefix


% noise
% -----
EsNo=10^(Es_N0_dB(ii)/10);
stanDevNoise=sqrt((1)/(2*EsNo));

n =stanDevNoise *[randn(1,length(s)) + j*randn(1,length(s))]; % white guassian noise, 0dB variance 



h=(1/sqrt(2))*(randn+j*randn);
y1= conv(s,h) + n; % additive white gaussian noise



%removes prefix
        y1(1:pv) = [];   

y=y1/h;
% demodulation
% ------------
y_re = real(y)/k_16QAM; % real part
y_im = imag(y)/k_16QAM; % imaginary part

% rounding to the nearest alphabet
ipHatRe = 2*floor(y_re/2)+1;
ipHatRe(find(ipHatRe>max(alphaRe))) = max(alphaRe);
ipHatRe(find(ipHatRe<min(alphaRe))) = min(alphaRe);
ipHatIm = 2*floor(y_im/2)+1;
ipHatIm(find(ipHatIm>max(alphaIm))) = max(alphaIm);
ipHatIm(find(ipHatIm<min(alphaIm))) = min(alphaIm);

% Constellation to Decimal conversion
ipDecHatRe = ind(floor((ipHatRe+4)/2+1))-1; % LUT based
ipDecHatIm = ind(floor((ipHatIm+4)/2+1))-1; % LUT based

% converting to binary string
ipBinHatRe = dec2bin(ipDecHatRe,k/2);
ipBinHatIm = dec2bin(ipDecHatIm,k/2);

% converting binary string to number
ipBinHatRe = ipBinHatRe.';
ipBinHatRe = ipBinHatRe(1:end).';
ipBinHatRe = reshape(str2num(ipBinHatRe).',k/2,N).' ;

ipBinHatIm = ipBinHatIm.';
ipBinHatIm = ipBinHatIm(1:end).';
ipBinHatIm = reshape(str2num(ipBinHatIm).',k/2,N).' ;

% counting errors for real and imaginary
nBitErr(pktX) = size(find([ipBitRe- ipBinHatRe]),1) + size(find([ipBitIm - ipBinHatIm]),1) ;

end
erTot(ii)=erTot(ii)+sum(nBitErr); %total errors in all packets

simBer(ii)=(erTot(ii)/(N*k*numPkts)); %bit error rate

totPktErRate(ii)=(erTot(ii)/(numPkts)); 
end

theoryBer = (1/k)*3/2*erfc(sqrt(k*0.1*(10.^(Eb_N0_dB/10))));

close all; figure
semilogy(Eb_N0_dB,theoryBer,'bs-','LineWidth',2);
hold on
semilogy(Eb_N0_dB,simBer,'mx-','LineWidth',2);
axis([0 15 10^-5 1])
grid on
legend('theory', 'simulation');
xlabel('Eb/No, dB')
ylabel('Bit Error Rate')
title('Bit error probability curve for 16-QAM modulation')

Thanks!

SleuthEye
  • 14,379
  • 2
  • 32
  • 61
Natiya
  • 463
  • 2
  • 9
  • 25
  • You should be more specific, and post (part of) your code. From what you say, my guess is that the number of packets or symbols is insufficient for large Eb/N0 values, because there the BER is low – Luis Mendo Jun 21 '14 at 12:45
  • oh, thank you. I think my BER is ok: it's around 10^-6 but there is a discontinuity around the Eb/No=20 dB. My maximum value for Eb/No is 30 dB. – Natiya Jun 22 '14 at 21:09

1 Answers1

2

The code provided makes the following assumptions:

  • 16-QAM modulation using Gray-coding bit mapping
  • a flat slow/block Rayleigh fading channel model.
  • coherent decoding under perfect channel state information estimation

Due to it's similarity with the Additive-White-Gaussian-Noise (AWGN) channel, a logical first step in understanding and calibrating the system performance under the assumptions stated above is to evaluate its performance without fading (i.e. substituting the channel model with an AWGN channel by setting h=1 in the provided code).

AWGN channel

You may want to verify the calibration of Symbol-Error-Rate (SER) performance as this can have a large impact on the (BER) performance, and SER curves are readily available for coherent decoding of uncoded 16-QAM constellation (see e.g dsplog, these lecture slides, this book, etc.) Those references also include the following approximation to the SER of 16-QAM:

1.5*erfc(sqrt(EsN0/10))

where EsN0 = 10.^(0.1*EsN0_dB).

Note that results may be equivalently provided in terms of either Es/N0 (the average energy per symbol) or Eb/N0 (the average energy per bit). For a k-bits signal constellation (constellation size of 2k), the relationship between Es/N0 and Eb/N0 is given as

Es/N0 = k*Eb/N0

Thus for 16-QAM, Es/N0 = 4Eb/N0 (or Es/N0dB = Eb/N0dB + 6dB).

For a Gray coded scheme, a BER approximation for sufficiently high Eb/N0 can then be obtained from the fact that a symbol error translates into 1 bit in error (out of the k-bits in the symbol) most of the time, thus BER ~ SER/k (or again for 16-QAM: BER ~ SER/4).

Es/N0 (dB)   Eb/N0 (dB)   SER      BER approx
15           9            1.8e-2   4.5e-3
16           10           7.0e-3   1.8e-3
18           12           5.5e-4   1.4e-4
20           14           1.2e-5   3.0e-6
25           19           2.7e-15  6.7e-16

As a side note, the confidence interval of simulation results using 2,000,000 symbols at SERs below approximately 10-5 can start to be quite significant. As an illustration, the following graph shows the SER of 16-QAM in blue, with the expected 95% confidence interval of a 2,000,000 symbols simulation in red: enter image description here

Rayleigh block fading channel

Once performance calibration has been established for the AWGN channel, we can get back to the Rayleigh block fading channel used in the posted code.

Assuming perfect channel state information estimation at the receiver and if there were no noise, it is possible to scale the received signal back exactly onto the original transmitted symbols using the transformation:

y = y1/h;

When noise is present, this transformation unfortunately also scales the noise. Fortunately, the noise remains white and Gaussian such that the basic derivation of AWGN channel equations can be reused with some work. Over independent packets, the statistical distribution of the scaling abs(h) follows a Rayleigh distribution (with parameter sigma2=1/2). Thus to get the average effect of this scaling on SER, it is possible to compute the weighted sum (where the weight is the probability density function of the Rayleigh distribution) of the effects over the range of possible scaling values using the integral: enter image description here

This can be done numerically with MATLAB using:

function SER = AwgnSer(EsN0)
  SER = 1.5*erfc(sqrt(0.1*EsN0));
end
function f = WeightedAwgnSer(x)
  weight = 2*x.*exp(-x.*conj(x));
  f = weight*AwgnSer(EsN0*x.*conj(x));
end
function SER = BlockRayleighFadingSer(EsN0)
  for ii=1:length(EsN0)
    SER(ii) = quad(inline('WeightedAwgnSer(EsN0(ii),s)','s'), 0, inf);
  end
end

A similar derivation can be obtained for the BER:

function BER = AwgnBer(EsN0)
  x = sqrt(0.1*EsN0);
  q1 = 0.5*erfc(x);
  q3 = 0.5*erfc(3*x);
  q5 = 0.5*erfc(5*x);
  BER = (12*q1+8*q3-4*q5 - q1*(q1+q3-2*q5)+(q3-q5)*q5)/16;
end
function f = WeightedAwgnBer(x)
  weight = 2*x.*exp(-x.*conj(x));
  f = weight*AwgnBer(EsN0*x.*conj(x));
end
function SER = BlockRayleighFadingBer(EsN0)
  for ii=1:length(EsN0)
    SER(ii) = quad(inline('WeightedAwgnBer(EsN0(ii),s)','s'), 0, inf);
  end
end

Note that I've use an exact formula for the BER since the weighted average tends to be affected by low signal-to-noise ratio where the approximation is not very good. It does not make a huge difference on the curve (~0.3dB at Eb/N0=10dB) but it is not something I want to worry about when calibrating performance curves.

This yields the following performance curves: enter image description here

Other considerations

Decoding performance can be affected by a number of other factors which are beyond the scope of this answer. The following thus only briefly touches on a few common ones and links to external references which may be used for additional information.

The decoder in the posted code uses explicit knowledge of the fading effect (as evidenced from the line y=y1/h;). It is generally not the case, and fading must first be estimated. The estimation of the channel effect at the receiver is beyond the scope of this answer, but generally imperfect estimation result in some performance loss. Performance curves of perfect knowledge are often used as a practical benchmark against which to compare performance under imperfect channel estimation.

Channel coding is often done to improve system performance. Common benchmarks used for coded modulation over the AWGN channel are:

  • Shannon's channel capacity
  • Union upper bound (eg. these lectures notes), and multiple other bounds found in research literature
  • Uncoded modulation performance (which we derived here)

Similarly for coded modulation over flat block Rayleigh fading channel, the following benchmarks are commonly used:

  • Outage probability (see section 5.4.1 of this book)
  • Uncoded modulation performance (which we derived here)
SleuthEye
  • 14,379
  • 2
  • 32
  • 61
  • thanks a lot for this explanaition, it's really helpful. In my program, I'm also sending packets, and using cyclic prefix so I set an additional calibration considering this: EsNodB=EbNodB+10*log10(k)- 10*log10(sqrt(N/(N+pv))); and simBer(EbNoX)=3/2*(erTot(EbNoX)/(N*k*numPkts*(N/(N+pv)))); where N is the number of symbols, k is the number of bit per symbol, pv is the length of the cyclic prefix and numPkts, the number of packets. also: EbNoX=1:length(EbNodB). Is this correct? – Natiya Jun 28 '14 at 20:13
  • Probably more like EsNodB=EbNodb+10*log10(k*N/(N+pv)), as you are sending k*N bits for each N+pv symbols (Assuming N does not already include the cyclic prefix, otherwise it would be +10*log10(k*(N-pv)/N)). Also, your _measured_ BER need not be readjusted (the efficiency of the scheme is already accounted for in the other factor), so you'd have erTot(EbNoX)/(N*k*numPkts). – SleuthEye Jun 29 '14 at 03:11
  • oh, I see. thanks!! I tried that out, and as I set: EsNodB=EbNodb+10*log10(k*N/(N+pv)); (as you said), erTot=zeros(1,length(EbNodB)); it works by doing this: erTot(EbNoX)=erTot(EbNoX)+sum(nBitErr); and I plot semilogy(EbNodB,simBer), where simBer(EbNoX)=3/2*(erTot(EbNoX)/(N*k*numPkts*(N/(N+pv)))); is that correct? because it's the only thing that I'm not sure. many thanks!! – Natiya Jun 29 '14 at 14:33
  • also, I would like to ask this: I'm plotting in the same figure 3 BER functions (for BPSK, QPSK and 16QAM schemes). I've been calculating, and I'm sending 280000 bits for BPSK and QPSK and 800000 for 16QAM. Should I send the same number of bits in the three cases in order to make a better a better comparison? thanks a lot in advance!! :-) – Natiya Jun 29 '14 at 14:37
  • Your measured BER is erTot(EbNoX)/(N*k*numPkts). I don't see why you'd add 3/2 and N/(N+pv) factors to simBer. – SleuthEye Jul 01 '14 at 02:52
  • also, since you are plotting rates, you do not need to match the number of bits sent for it to be a fair comparison. What is important is that you send enough data to ensure the estimated rates are estimated to sufficient accuracy. – SleuthEye Jul 01 '14 at 02:53
  • ok! thanks!! I added it because I have an offset when comparing the curve with the theoretical BER, but I found that it could be because of my white noise's calibration. I'm not sure than the standard deviation for 16QAM is stanDevNoise=sqrt(seqLen*S/(2*EbNo)); where seqLen is the length of the spreading sequence. I openned a new question for this, but if you could help me, please, I will delete that one :-( – Natiya Jul 01 '14 at 07:01
  • I don't think `seqLen` belongs there. Note sure what `S` is in your equation, but I'd assume it's a scaling factor to obtain an average symbol energy S, such that you transmit {-3,-1,+1,+3}*sqrt(S/10) in each dimension. In that case, I'd expect stanDevNoise = sqrt(N0/2) = sqrt(S/(2*EsNo)) = sqrt(S/(2*EbNo*(k*N/(N+pv)))). – SleuthEye Jul 02 '14 at 18:03
  • Thanks for that clarification. Unfortunatly the offset is a bit bigger now. So trying to find my possible mistakes, I've been checking this: S=1/sqrt(10); I think is correct for 16QAM, and also I have: EbNodB=0:2:20; EsNodB=EbNodB+10*log10(k*N/(N+pv)); (this was already checked, you helped me) and my for-loop start is: for EbNoX=1:length(EbNodB) EbNo=10^(EbNodB(EbNoX)/10); %convert from dB to linear scale EsNo=10^(EsNodB(EbNoX)/10); is that correct? thanks a lot for all your help, this is driving me crazy – Natiya Jul 03 '14 at 07:56
  • What exactly is `S`? If it is the desired average symbol energy then see above. If on the other hand you transmit {-3,-1,+1,+3}*S where S=1/sqrt(10) then you get unit average symbol energy. In that case, stanDevNoise = sqrt(N0/2) = sqrt(1/(2*EsNo)). The rest of what you indicated seems fine. – SleuthEye Jul 03 '14 at 12:17
  • S is the normalized energy per symbol, so it should be stanDevNoise = sqrt(N0/2) = sqrt(S/(2*EsNo)) , where EsNo=10^(EsNodB(EbNoX)/10); However, the offset problem is only solved by doing stanDevNoise=sqrt(seqLen*(S)/(EbNo)); where EbNo=10^(EbNodB(EbNoX)/10); The point is that I cannot justify this, so probably the calibration error is in another place :-( anyway, you helped me a lot! Now I understand everything better! thanks! :D – Natiya Jul 03 '14 at 21:37
  • I found this information: http://www.mathworks.es/es/help/comm/ug/awgn-channel.html could that be the reason why my system works better if I set stanDevNoise =sqrt(S/(EsNo)) ? – Natiya Jul 04 '14 at 21:49
  • Depending on how you apply stanDevNoise could potentially explain a factor of sqrt(2), eg. stanDevNoise^2=E[|n|^2] where n is complex vs. stanDevNoise^2=E[nx^2]=E[ny^2] where n=nx+j*ny. Perhaps you could update your question with a snippet of code illustrating how you generate your symbols and add noise, so we can look it over. – SleuthEye Jul 05 '14 at 11:29
  • I did it... That's the code that works properly. However, I'm trying to implement a rake receiver, so if I do (Rxchips*h(I(n))')/(abs(h(I(n))))^2; at the receiver, it's when I'm having problems with noise (I know this because I isolated the problem). So I thought to perform channel precoding, by dividing my transmitted signal by h...but it's tricky. If you see something wrong there, please help me! thanks a lot!! :-) – Natiya Jul 05 '14 at 14:27
  • another alternative that I'm considering is filtering the noise (with the smooth function) at the beginning of the transmitter...is this a good option or it doesn't make any sense? – Natiya Jul 05 '14 at 17:05
  • The noise is part of your channel model, not something the transmitter has control over, so filtering the noise there is not going to be representative. – SleuthEye Jul 05 '14 at 23:45
  • That said, the code you provided seems to correspond to a Rayleigh fading channel. Performance curves are not the same as for the AWGN channel which I provided. – SleuthEye Jul 05 '14 at 23:54
  • I know, but the point is that when I set numPaths=0, then h=1, my curve should be the same as AWGN, and it's not :-( – Natiya Jul 06 '14 at 19:30
  • Also, I was wondering why when I set in that code h=1 (AWGN channel), the BER result is correct for the noise standard deviation equal to 1/sqrt (2) but not with the other formula depending on the bit or symbol energy that we talked before, please help me. Thanks! ☺ – Natiya Jul 07 '14 at 18:03
  • Setting h=1 in the posted code (Not sure about `numPaths` which does not appear) does match AWGN performance. Note that the curve I provided is for SER, not BER (I did however provide a few BER points in table format). I imagine that's what you meant by "That's the code that works properly". Note that in general you'll get better answers including the code that doesn't work (along with what you've tried). – SleuthEye Jul 08 '14 at 02:27
  • For the noise standard deviation in the posted code, it is initially set to 1/sqrt(2) then multiplied by 10^(-Es_N0_dB(ii)/20)=1/sqrt(Es_N0), so effective standard deviation is actually 1/sqrt(2Es_N0). This does correspond to what we talked (note that S=1 since the transmitted symbols are normalized). – SleuthEye Jul 08 '14 at 02:28
  • Thank you :-) I uploaded the code that I would like to check. I think is correct, but the BER result is quite bad. It's a 16QAM system with cyclic prefix and a single path Rayleigh channel plus AWGN channel. The results show the theoretical BER for AWGN 16QAM and my computed BER. Thanks!!! :D – Natiya Jul 09 '14 at 08:15
  • As I indicated before, this isn't the AWGN channel (and so theoretical curve is quite different). At first glance, results look fine for Rayleigh channel (or more specifically flat slow block fading Rayleigh channel, which includes AWGN). I'll update my answer with more details... – SleuthEye Jul 10 '14 at 02:45
  • I would like to verify that the result from that code is correct. But I don't know how. Also, I have the code for a multipath channel plus AWGN, detecting the first path in the receiver and my BER result is a constant line. I really don't know how to check whether that code is correct or not. Should I add it to my question too? I think it's a easier case than the one that is already there, but with more than one path. – Natiya Jul 10 '14 at 10:59
  • Thanks for your explaination. I updated my code, with a Rayleigh channel and DSSS. At the receiver, I'm detecting the first path. Please, ignore the theoretical BER which corresponds to 16QAM in AWGN. My simulated BER and PER (packet error rate) results are a straight line. Is this behavour normal? Also, I'm trying another model with an exponentially decay channel. Do you know any source that I can check to see whether the BER is correct or not? Thank you very much!! – Natiya Jul 14 '14 at 22:12
  • Exploring all the possible communication channels and strategies that can be used at the receiver is beyond the scope of this answer. Also note that different channels could make good additional questions (although theoretical aspects may be better directed at another forum as SO is mostly programming oriented), but constantly changing the question does not help future readers. – SleuthEye Jul 15 '14 at 00:57
  • Yes, you are right. Thank you very much for all your help. I think also my problem was to divide the big problem into small pieces, and that's why I didn't know how to ask my question clearly at the beginning. Thanks!! :) – Natiya Jul 15 '14 at 09:51
  • by the way, your code above gives me this error: Error in inline expression ==> WeightedAwgnBer(EsN0(ii),s) Undefined function or variable 'ii' – Natiya Jul 15 '14 at 11:06
  • I've tested with octave (Matlab clone), and AFAIK this syntax should also work with Matlab. By the way, you did include the `for ii=...` loop? It's required if EsN0 is a vector, since I don't think `quad` handles vectors (otherwise if EsN0 is a scalar you can drop the `ii` from the inline expression). Otherwise, if this is a difference between the two (and not just a typo), you could try the anonymous function syntax: `for ii=1:length(EsN0) BER(ii)=quad(@(s) WeightedAwgnBer(EsN0(ii),s), 0, inf); end` – SleuthEye Jul 16 '14 at 00:48
  • oh, that's ok, thanks! :) and did you derivate this coefficients (12*q1+8*q3-4*q5 - q1*(q1+q3-2*q5)+(q3-q5)*q5)/16 from the wikipedia's formulas? Because I would like to plot the case in which the amplitudes of the Rayleigh channel follow an exponential decay, but I don't find any source. Could I do it by using the Rayleigh distribution as starting point? – Natiya Jul 16 '14 at 07:23
  • I obtained the coefficients by considering the number of bits in error and the corresponding probability over all 256 (transmitted,decoded) pairs (actually only 48 terms when taking advantage of symmetry) for the AWGN channel. The first 12*q1/16 term is essentially your more familiar (1/k)*3/2*erfc(... – SleuthEye Jul 16 '14 at 12:09
  • Performance for Rayleigh channel is generally obtained by realizing that given the channel parameters and a receiver performing linear operations, the decision statistics are still governed by Gaussian (although scaled) noise distribution. As such performance can be obtained by integrating over the range of channel parameter values. – SleuthEye Jul 16 '14 at 12:14
  • This is where `weight = 2*x*exp(-x^2)` and later `quad` comes in for a single path Rayleigh block fading channel. – SleuthEye Jul 16 '14 at 12:20
  • A graduate level textbook such as http://www.amazon.com/Digital-Communications-Edition-John-Proakis/dp/0072957166 would covers such channel performance aspect (including maximum ratio combining and RAKE receiver performance) in far more details than could be done here given the space and format constraints. – SleuthEye Jul 16 '14 at 12:29
  • oh, wow! I found the book in my university's library, I'm having a look at it, and it's great! thanks!! :D – Natiya Jul 16 '14 at 14:10