Commit e6940243 authored by Renaud Gonce's avatar Renaud Gonce

Add new file

parents
%% Simulates GFSK communication and plots the performance in terms of BER
%
% For the CFO correction, the samples are processed "one by one" to match
% the real behavior of the radio.
%
%% Transmission
%%% Transmission/modulation parameters
f_c = 2.45e09; % Carrier frequency
r_symb = 1e06; % Symbol rate
Ts = 1/r_symb; % Symbol period
m = 0.5; % Modulation index
BTb = 0.5; % Bandwidth - Symbol perdiod product
N_symb = 1e06; % Number of symbols used for the simulation
reso = 8; % Resolution factor (number of samples by symbol period at TX)
dfppm = 30; % CFO expressed in ppm wrt the carrier frequency
%%% For BER vs Eb/N0 plot and noise variance (N0) generation
Nsnr = 16; % Number of different values for the plot
Eb_N0_dB = linspace(0,Nsnr-1,Nsnr);
Eb_N0 = 10.^(Eb_N0_dB/10);
Eb = 1;
N0 = Eb./Eb_N0;
%%% Generation of the preamble + noise before packet parameter
preamble = [1;-1;1;-1;1;-1;1;-1];
Lpreamble = length(preamble);
Lnoisestart = 92; % Length of the noise portion preceding the packet
N_symb = N_symb-Lpreamble-Lnoisestart;
%%% Generation of the sequence of symbols (I)
M = 2;
N_bits_by_symb = log2(M);
I = pammod(N_symb,M); % "pammod" is a function I wrote for the PAM modulation
I(1) = 1; % Because the first bit of the Access Address is always the opposite of the last one of the preamble.
I = [preamble;I];
LI = length(I);
%%% Gaussian pulse-shape filter (g) generation
N_Ts = 3; % Number of symbol periods for the filter support
time = -N_Ts/2*Ts : Ts/reso : N_Ts/2*Ts; % Filter support
Tb = Ts/N_bits_by_symb; % Here, we will always have Tb=Ts since M=2
K = sqrt(log(2)); % Parameter for the filter amplitude, set to a value giving a unitary amplitude
g = g_GMSK(time,K,Tb,BTb); % Filter generation, using my function "g_GMSK"
Lg = length(g);
%%% Convolution (convo) between the symbol sequence and the Gaussian filter
Iup = upsample(I, reso);
convIupg = conv(Iup,g);
tmin = (reso*(LI-1)+Lg+1)/2 - (reso*LI)/2;
tmax = (reso*(LI-1)+Lg+1)/2 + (reso*LI)/2;
convo = convIupg(tmin:tmax);
Lconvo = length(convo);
%%% Integration (integ) of the convolution
integ = zeros(Lconvo-1,1);
incr = zeros(Lconvo-1,1);
integ(1) = (convo(1)+convo(2))/2 * (Ts/reso);
for i = 2:Lconvo-1
incr(i) = (convo(i)+convo(i+1))/2 * (Ts/reso);
integ(i) = integ(i-1) + incr(i);
end
% In practice the values in ak are tabled (they can be precomputed).
% They are used for the CFO correction.
integ2 = integ(1+reso:end) - integ(1:end-reso);
a = integ2 * pi*m/Tb;
ak = a(reso:reso+2*reso-1);
%%% Phase (phi) generation
phi = pi*m/Tb * integ;
Lphi = length(phi);
%%% Transmitted signal (s) generation
s = exp(1j*phi);
Ls = length(s);
%% Reception
OSF = 8; % Oversampling factor (number of samples by symbol period at RX)
BERcorr = zeros(Nsnr,1);
BER = zeros(Nsnr,1);
df_hat = zeros(Nsnr,1);
ind_trig = zeros(Nsnr,1);
SFindi = zeros(Nsnr,1);
% Loop for each different value of the noise variance
% Since the non-idealities mitigations are sized for a SNR value of 13 or
% 14 dB, the loop should only take those values.
% for i = 1:Nsnr
SNR = 13;
for i = SNR+1
%%% AWGN (n) generation
N = N0(i)*OSF;
n = awgn(Lnoisestart*OSF+Ls, 1, N);
%%% Received signal (r) generation
r = [zeros(Lnoisestart*OSF, 1) ; s] + n;
Lr = length(r);
%%% CFO
df = dfppm/1e06 * f_c;
time = (1/(r_symb*OSF) : 1/(r_symb*OSF) : (Lr)/(r_symb*OSF))';
rcfo = exp(1j*2*pi*df*time).*r;
%%% Filtering of the received CFO'ed signal
fcut = 0.6e06;
Nper = 8;
[h0] = LPF('Hamming', fcut, OSF, Nper);
Lh0 = length(h0);
rconvh00 = conv(rcfo,h0);
rconvh0 = rconvh00(1+Nper/2*OSF:end-Nper/2*OSF);
rcfof = rconvh0;
%%% Preamble detection
% Hermitian product
OSR = OSF;
Hprod = rcfof(1+OSR:end).*conj(rcfof(1:end-OSR));
% IIR filter
IIRb = 1;
IIRa = zeros(OSR+1,1);
IIRa(1) = 1;
IIRa(OSR+1) = 0.875;
IIRHprod = filter(IIRb,IIRa,Hprod);
absIIRHprod = abs(IIRHprod);
LabsIIRHprod = length(absIIRHprod);
% Search for preamble
if (SNR == 13)
thresh = 37.5;
elseif (SNR == 14)
thresh = 32.5;
end
p = 1;
booly = false;
while(booly == false)
if (absIIRHprod(p) > thresh)
booly = true;
elseif (p >= LabsIIRHprod)
booly = true;
fprintf('Error, after 1000 iterations, there is still no value that has reached the threshold!');
else
p = p+1;
end
end
ind_trig(i) = p; % This is the index that triggered the detection.
%%% Symbol timing recovery
Noffset = 5; % We need to wait for 5 periods after the
% preamble detection in order to target the
% max of the 6th preamble period.
offset = Noffset*OSF;
maxxtemp = absIIRHprod(ind_trig(i)+offset);
indtemp = ind_trig(i)+offset;
kk = 1;
while (kk < 1*OSF)
if (absIIRHprod(ind_trig(i)+offset+kk) > maxxtemp)
maxxtemp = absIIRHprod(ind_trig(i)+offset+kk);
indtemp = ind_trig(i)+offset+kk;
end
kk = kk+1;
end
SFindi(i) = indtemp;
%%% CFO correction
df_hat_temp1 = 0;
Nperiod = 6;
b = 1;
counter = 1;
symbr = zeros(Nperiod*OSF,1);
symbrold = zeros(Nperiod*OSF,1);
dfh = zeros(Nperiod*OSF,1);
dfh1 = zeros(Nperiod*OSF,1);
demodsymbrrold = zeros(Nperiod*OSF,1);
dk = zeros(Nperiod*OSF,1);
akind = zeros(Nperiod*OSF,1);
hermi_unnorm = zeros(Nperiod*OSF, 1);
hermi = zeros(Nperiod*OSF, 1);
while(b <= Nperiod*OSF)
% The first sample used for the CFO correction is the one 1
% period after the preamble detection.
symbr(b) = rcfof(b+ind_trig(i)+OSF-1);
symbrold(b) = rcfof(b+ind_trig(i)+OSF-1-OSF);
hermi_unnorm(b) = symbr(b)*conj(symbrold(b));
hermi(b) = hermi_unnorm(b)/abs(hermi_unnorm(b));
dk(b) = imag(hermi(b));
% Simulates the index used to fetch the tabled values from the
% LUTs.
akind(b) = mod(b,2*OSF);
if (akind(b) == 0)
akind(b) = 2*OSF;
end
sinak = sin(ak(akind(b)));
cosak = cos(ak(akind(b)));
dfh1(b) = (dk(b)-sinak)/cosak /(2*pi*Tb); % CFO estimate
df_hat_temp1 = df_hat_temp1+dfh1(b);
dfh(b) = df_hat_temp1/counter; % Averaging of the estimate
counter = counter + 1;
b = b+1;
end
df_hat(i) = dfh(end); % Final CFO estimate.
rcorr = exp(-1j*2*pi*df_hat(i)*time((Lnoisestart+Lpreamble)*OSF+1 : end)).*rcfo((Lnoisestart+Lpreamble)*OSF+1 : end);
% Filtering of the corrected signal
rcorrconvh0 = conv(rcorr,h0);
rcorrconvh0 = rcorrconvh0(1+Nper/2*OSF:end-Nper/2*OSF);
rcorrf = rcorrconvh0;
Lrcorrf = length(rcorrf);
%%% Filtering of the received signal (to simulate the case without CFO)
rconvh0 = conv(r,h0);
rconvh0 = rconvh0(1+Nper/2*OSF:end-Nper/2*OSF);
rf = rconvh0;
Lrf = length(rf);
%%% Demodulation
% Index for the decimation prior to the demodulation
indidown = mod(SFindi(i)+2,OSF);
if (indidown == 0)
indidown = OSF;
end
rcorrfdown = downsample(rcorrf(indidown:end),OSF/2);
Lrcorrfdown = length(rcorrfdown);
if (mod(Lrcorrfdown,2)==0)
demodcorr = imag(rcorrfdown(2:2:end).*conj(rcorrfdown(1:2:end-1)));
else
demodcorr = imag(rcorrfdown(2:2:end-1).*conj(rcorrfdown(1:2:end-2)));
end
Ldemodcorr = length(demodcorr);
rfdown = downsample(rf(indidown:end),OSF/2);
Lrfdown = length(rfdown);
if (mod(Lrfdown,2)==0)
demod = imag(rfdown(2:2:end).*conj(rfdown(1:2:end-1)));
else
demod = imag(rfdown(2:2:end-1).*conj(rfdown(1:2:end-2)));
end
demod = demod(1+Lpreamble+Lnoisestart:end);
Ldemod = length(demod);
%%% Decision
Icorr_hat = sign(demodcorr);
BERcorr(i) = sum(I(1+Lpreamble:Lpreamble+Ldemodcorr)~=Icorr_hat)/N_symb;
I_hat = sign(demod);
BER(i) = sum(I(1+Lpreamble:Lpreamble+Ldemodcorr)~=I_hat)/N_symb;
end
% BER vs Eb/N0 plot
figure;
semilogy(Eb_N0_dB,BERcorr,'xg','LineWidth',1.5,'MarkerSize',8);
hold on;
semilogy(Eb_N0_dB,BER,'xk','LineWidth',1.5,'MarkerSize',8);
axis([0 Nsnr 10/N_symb 1]);
grid;
legend('After CFO correction', 'Without CFO');
title( strcat('BER -- CFO = ', num2str(df)) );
xlabel('E_{b}/N_{0} [dB]');
ylabel('BER');
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment