3 # Copyright 2007 Free Software Foundation, Inc.
5 # This file is part of GNU Radio
7 # GNU Radio is free software; you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 3, or (at your option)
12 # GNU Radio is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License
18 # along with GNU Radio; see the file COPYING. If not, write to
19 # the Free Software Foundation, Inc., 51 Franklin Street,
20 # Boston, MA 02110-1301, USA.
25 from gnuradio import gr
27 class ofdm_sync_pnac(gr.hier_block2):
28 def __init__(self, fft_length, cp_length, kstime, logging=False):
30 OFDM synchronization using PN Correlation and initial cross-correlation:
31 F. Tufvesson, O. Edfors, and M. Faulkner, "Time and Frequency Synchronization for OFDM using
32 PN-Sequency Preambles," IEEE Proc. VTC, 1999, pp. 2203-2207.
34 This implementation is meant to be a more robust version of the Schmidl and Cox receiver design.
35 By correlating against the preamble and using that as the input to the time-delayed correlation,
36 this circuit produces a very clean timing signal at the end of the preamble. The timing is
37 more accurate and does not have the problem associated with determining the timing from the
38 plateau structure in the Schmidl and Cox.
40 This implementation appears to require that the signal is received with a normalized power or signal
41 scalling factor to reduce ambiguities intorduced from partial correlation of the cyclic prefix and
42 the peak detection. A better peak detection block might fix this.
44 Also, the cross-correlation falls apart as the frequency offset gets larger and completely fails
45 when an integer offset is introduced. Another thing to look at.
48 gr.hier_block2.__init__(self, "ofdm_sync_pnac",
49 gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature
50 gr.io_signature2(2, 2, gr.sizeof_float, gr.sizeof_char)) # Output signature
53 self.input = gr.add_const_cc(0)
55 symbol_length = fft_length + cp_length
57 # PN Sync with cross-correlation input
59 # cross-correlate with the known symbol
60 kstime = [k.conjugate() for k in kstime[0:fft_length//2]]
62 self.crosscorr_filter = gr.fir_filter_ccc(1, kstime)
65 self.delay = gr.delay(gr.sizeof_gr_complex, fft_length/2)
67 # Correlation from ML Sync
68 self.conjg = gr.conjugate_cc();
69 self.corr = gr.multiply_cc();
71 # Create a moving sum filter for the input
72 self.mag = gr.complex_to_mag_squared()
73 movingsum_taps = (fft_length//1)*[1.0,]
74 self.power = gr.fir_filter_fff(1,movingsum_taps)
76 # Get magnitude (peaks) and angle (phase/freq error)
77 self.c2mag = gr.complex_to_mag_squared()
78 self.angle = gr.complex_to_arg()
79 self.compare = gr.sub_ff()
81 self.sample_and_hold = gr.sample_and_hold_ff()
83 #ML measurements input to sampler block and detect
84 self.threshold = gr.threshold_ff(0,0,0) # threshold detection might need to be tweaked
85 self.peaks = gr.float_to_char()
87 self.connect(self, self.input)
89 # Cross-correlate input signal with known preamble
90 self.connect(self.input, self.crosscorr_filter)
92 # use the output of the cross-correlation as input time-shifted correlation
93 self.connect(self.crosscorr_filter, self.delay)
94 self.connect(self.crosscorr_filter, (self.corr,0))
95 self.connect(self.delay, self.conjg)
96 self.connect(self.conjg, (self.corr,1))
97 self.connect(self.corr, self.c2mag)
98 self.connect(self.corr, self.angle)
99 self.connect(self.angle, (self.sample_and_hold,0))
101 # Get the power of the input signal to compare against the correlation
102 self.connect(self.crosscorr_filter, self.mag, self.power)
104 # Compare the power to the correlator output to determine timing peak
105 # When the peak occurs, it peaks above zero, so the thresholder detects this
106 self.connect(self.c2mag, (self.compare,0))
107 self.connect(self.power, (self.compare,1))
108 self.connect(self.compare, self.threshold)
109 self.connect(self.threshold, self.peaks, (self.sample_and_hold,1))
112 # Output 0: fine frequency correction value
113 # Output 1: timing signal
114 self.connect(self.sample_and_hold, (self,0))
115 self.connect(self.peaks, (self,1))
118 self.connect(self.compare, gr.file_sink(gr.sizeof_float, "ofdm_sync_pnac-compare_f.dat"))
119 self.connect(self.c2mag, gr.file_sink(gr.sizeof_float, "ofdm_sync_pnac-theta_f.dat"))
120 self.connect(self.power, gr.file_sink(gr.sizeof_float, "ofdm_sync_pnac-inputpower_f.dat"))
121 self.connect(self.angle, gr.file_sink(gr.sizeof_float, "ofdm_sync_pnac-epsilon_f.dat"))
122 self.connect(self.threshold, gr.file_sink(gr.sizeof_float, "ofdm_sync_pnac-threshold_f.dat"))
123 self.connect(self.peaks, gr.file_sink(gr.sizeof_char, "ofdm_sync_pnac-peaks_b.dat"))
124 self.connect(self.sample_and_hold, gr.file_sink(gr.sizeof_float, "ofdm_sync_pnac-sample_and_hold_f.dat"))
125 self.connect(self.input, gr.file_sink(gr.sizeof_gr_complex, "ofdm_sync_pnac-input_c.dat"))