I'm implementing Schmidl and Cox in Matlab and attempting to recover the data being transmitted. However, I have a problem even with 0 carrier frequency offset, 0 carrier phase shift, and my channel vector just being [1], sometimes my timing estimation will be +/- 2 symbols off (due to noise I've injected) and my data will be 'spinning'. The schmidl & cox paper is below. I can't tell what I'm doing wrong and how to fix the issue if my timing is a couple symbols off. My intuition tells me I should be able to make a full recovery if the timing is within the guard band (cyclic prefix)
http://140.117.160.140/course/pdfdownload/94_2/%E6...
close all
clear all
%parameters for sim
%carrier frequency offset
cfo = 0.00;
%phase offset
cpo = 0;
%channel
chan = [1]
%fft length
N=64;
%cyclic prefix length
cycPre = 16;
%symbol length
symLen = N + cycPre;
%create the schmidl-cox preamble
sw1 = [zeros(1,6), 2*randi([0,1],1,26)-1, 0, 2*randi([0,1],1,26)-1, zeros(1,5)];
sw1(find(sw1==-1)) = -sqrt(2);
sw1(find(sw1==1)) = sqrt(2);
%zero out out frequencies 33 = DC [odds on even]
sw1(2:2:end) = 0;
pre1 = ifft(sw1,N);
syncword1= [pre1(49:64) pre1];
%create second preamble
sw2 = [zeros(1,6), 2*randi([0,1],1,26)-1, 0, 2*randi([0,1],1,26)-1, zeros(1,5)];
pre2 = ifft(sw2,N);
syncword2 = [pre2(49:64) pre2];
%create the data to send
inputiFFT = [zeros(1,6), 2*randi([0,1],1,26)-1, 0, 2*randi([0,1],1,26)-1, zeros(1,5)];
outputiFFT = ifft((inputiFFT),N);
%cyclic prefix
outputiFFT_with_CP = [outputiFFT(49:64) outputiFFT];
%construct the signal in the middle of 2000 points
tx = 20*[syncword1 syncword2 outputiFFT_with_CP];
sig = 0.0001*(randn(1,160)+1j*randn(1,160));
txall = [sig tx sig]
noise =0.01*(randn(1,length(txall))+1j*randn(1,length(txall)));
IQ = filter(chan,1,txall) + noise;
nn = [0:length(IQ)-1];
w = 2*pi*cfo
ejwn = exp(1i*(w*nn + cpo));
IQ= (IQ/20).*ejwn;
L = N/2-1;
M = N/2;
%schmidl and cox P, R, and M
for j = 1:length(IQ)-2*M
P(j) = sum(conj(IQ(j:j+L)).*(IQ(j+(L+1):j+2*(L+1)-1)));
R(j) = sum(abs(IQ(j+(L+1):j+2*(L+1)-1)).^2);
end
M = (abs(P).^2)./(R.^2);
%find start via schmidl and cox method
sync = 0;
strt = cycPre + 1;
cntr = 0;
for j = 1:length(M)-1
if(M(j) > .96 & M(j) < 1.5)
if(M(j-1) > .96 )
cntr = cntr + 1;
end
if(cntr == cycPre)
sync = j;
cntr=0
end
else
cntr =0 ;
end
end
%actual start for testing
%sync = 177
%eq (39) , (40),
phi = angle(P(sync));
CFO = phi/(N*pi);
%check if phi > pi
flag_cfo = 0;
if(phi > pi)
flag_cfo = 1;
end
%sanity check
realstart= 161+symLen*2+16;
actual_data = fft(txall(realstart:realstart+63),64);
bins = [0:63];
%calculate start
start = sync+(N)+symLen+cycPre;
%fft sync word 1
x1k = fft(IQ(sync:sync+N-1),N);
%fft sync word 2
x2k = fft(IQ(sync+N+cycPre:sync+N+cycPre+N-1),N);
%the data that is spun
data_corrected = fft(IQ(start:start+63),64);
%correct preamble 1 & 2
x1ks = fft(IQ(sync:sync+N-1).*exp(-1j*2*pi*bins*CFO),N);
x2ks = fft(IQ(sync+(N)+cycPre:sync+(N)+cycPre+N-1).*exp(-1j*2*pi*bins*CFO),N);
%vk
vkt = sqrt(2) * x2ks./x1ks;
vk = vkt(2:2:end);
%find B(g) to maximize eq(41)
denom = 2*(sum(abs(x2ks(1:2:end).^2))).^2
for k = 1:32
x1t = circshift(x1ks(2:2:end), [1 2*k]);
x2t = circshift(x2ks(2:2:end), [1 2*k]);
B2(k) = abs(sum(conj(x1t).*conj(vk).*x2t)).^2/denom;
end
%find index for max B
[~, g0] = max(B2);
if(abs(CFO) > 3e-5)
%if phi is greater than pi then we need an integer shift too
if( flag_cfo == 0 )
printOverPi = 1
delF = 2*g0/N
data_spin1 = IQ(start:start+63).*exp(-1j*2*pi*bins*CFO);
data_spin2 = data_spin1.*exp(-1j*2*pi*delF);
data_corrected2 = fft(data_spin2, N);
%else just correct the CFO
else
data_spin1 = IQ(start:start+63).*exp(-1j*2*pi*bins*CFO);
data_corrected2 = fft(data_spin1, N);
end
else
data_corrected2 = fft(IQ(start:start+63), N);
end
figure
plot(M(1:300))
hold on
plot(sync, M(sync), 'rx')
hold off
axis([1 length(M) 0 2])
title('M timing metric eq (8) in schmidl & cox paper')
figure
subplot(411)
plot(real(inputiFFT), imag(inputiFFT),'x');
title('input to FFT')
subplot(412)
plot(real(actual_data)*1/20, imag(actual_data)*1/20,'x')
title('sanity check actual data')
axis([-1 1 -1 1])
subplot(413)
plot(real(data_corrected), imag(data_corrected),'x')
title('data uncorrected')
subplot(414)
plot(real(data_corrected2), imag(data_corrected2),'x')
title('corrected data')
if(abs(CFO)>3e-5)
figure
subplot(311)
plot(real(data_spin1), imag(data_spin1),'x')
title('sanity check actual data')
subplot(312)
plot(real(data_spin2), imag(data_spin2),'x')
title('sanity check actual data')
axis([-1 1 -1 1])
subplot(313)
plot(real(data_corrected2), imag(data_corrected2),'x')
title('corrected data')
end
data_corrected(find(real(data_corrected)>.1)) = 1;
data_corrected(find(real(data_corrected)<-.1)) = -1;
data_corrected(find(abs(data_corrected)~=1)) = 0;
figure
plot(real(inputiFFT))
hold on
plot(real(data_corrected),'color','r')
hold off
title('input to fft, uncorrected data overlayed')
data_corrected2(find(real(data_corrected2)>.1)) = 1;
data_corrected2(find(real(data_corrected2)<-.1)) = -1;
data_corrected2(find(abs(data_corrected2)~=1)) = 0;
figure
plot(real(inputiFFT))
hold on
plot(real(data_corrected2),'color','r')
hold off
title('input to fft, corrected data overlayed')
Hi spetcavich,
The time synchronizers are not perfect and Cox's is not the best of them. The detection of the start of frame (SOF) has a certain uncertainty (for example +/- 2 samples) and you must work with it. This is not a problem because there is a cyclic prefix but you must include a channel equalizer to resolved it.
When the detector error is +1 sample, you are taking N-1 samples from the current OFDM symbol and a sample from the next OFDM symbol. This is solved using a fixed correction of the TSA output, for example -3 samples, so that you can ensure that you are always taking samples of the same OFDM symbol.
When the detector error is -1 sample, you are taking a sample of the cyclic prefix of the current OFDM symbol and N-1 samples of the current OFDM symbol, which is not wrong.
In both cases you must correct the phase change with an equalizer.
Take a look at this article where some TSAs for OFDM are compared: "A Novel Timing Estimation Method for OFDM Systems". And this one designed for WLAN: "Low Complexity Time Synchronization Algorithm for OFDM Systems with Repetitive Preambles"
Regards,
Julián