3 # Copyright 2007,2008 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_pn(gr.hier_block2):
28 def __init__(self, fft_length, cp_length, logging=False):
30 OFDM synchronization using PN Correlation:
31 T. M. Schmidl and D. C. Cox, "Robust Frequency and Timing
32 Synchonization for OFDM," IEEE Trans. Communications, vol. 45,
36 gr.hier_block2.__init__(self, "ofdm_sync_pn",
37 gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature
38 gr.io_signature2(2, 2, gr.sizeof_float, gr.sizeof_char)) # Output signature
40 self.input = gr.add_const_cc(0)
45 self.delay = gr.delay(gr.sizeof_gr_complex, fft_length/2)
47 # Correlation from ML Sync
48 self.conjg = gr.conjugate_cc();
49 self.corr = gr.multiply_cc();
51 # Create a moving sum filter for the corr output
53 moving_sum_taps = [1.0 for i in range(fft_length//2)]
54 self.moving_sum_filter = gr.fir_filter_ccf(1,moving_sum_taps)
56 moving_sum_taps = [complex(1.0,0.0) for i in range(fft_length//2)]
57 self.moving_sum_filter = gr.fft_filter_ccc(1,moving_sum_taps)
59 # Create a moving sum filter for the input
60 self.inputmag2 = gr.complex_to_mag_squared()
61 movingsum2_taps = [1.0 for i in range(fft_length//2)]
64 self.inputmovingsum = gr.fir_filter_fff(1,movingsum2_taps)
66 self.inputmovingsum = gr.fft_filter_fff(1,movingsum2_taps)
68 self.square = gr.multiply_ff()
69 self.normalize = gr.divide_ff()
71 # Get magnitude (peaks) and angle (phase/freq error)
72 self.c2mag = gr.complex_to_mag_squared()
73 self.angle = gr.complex_to_arg()
75 self.sample_and_hold = gr.sample_and_hold_ff()
77 #ML measurements input to sampler block and detect
78 self.sub1 = gr.add_const_ff(-1)
79 self.pk_detect = gr.peak_detector_fb(0.20, 0.20, 30, 0.001)
80 #self.pk_detect = gr.peak_detector2_fb(9)
82 self.connect(self, self.input)
84 # Calculate the frequency offset from the correlation of the preamble
85 self.connect(self.input, self.delay)
86 self.connect(self.input, (self.corr,0))
87 self.connect(self.delay, self.conjg)
88 self.connect(self.conjg, (self.corr,1))
89 self.connect(self.corr, self.moving_sum_filter)
90 self.connect(self.moving_sum_filter, self.c2mag)
91 self.connect(self.moving_sum_filter, self.angle)
92 self.connect(self.angle, (self.sample_and_hold,0))
94 # Get the power of the input signal to normalize the output of the correlation
95 self.connect(self.input, self.inputmag2, self.inputmovingsum)
96 self.connect(self.inputmovingsum, (self.square,0))
97 self.connect(self.inputmovingsum, (self.square,1))
98 self.connect(self.square, (self.normalize,1))
99 self.connect(self.c2mag, (self.normalize,0))
101 # Create a moving sum filter for the corr output
102 matched_filter_taps = [1.0/cp_length for i in range(cp_length)]
103 self.matched_filter = gr.fir_filter_fff(1,matched_filter_taps)
104 self.connect(self.normalize, self.matched_filter)
106 self.connect(self.matched_filter, self.sub1, self.pk_detect)
107 #self.connect(self.matched_filter, self.pk_detect)
108 self.connect(self.pk_detect, (self.sample_and_hold,1))
111 # Output 0: fine frequency correction value
112 # Output 1: timing signal
113 self.connect(self.sample_and_hold, (self,0))
114 self.connect(self.pk_detect, (self,1))
117 self.connect(self.matched_filter, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-mf_f.dat"))
118 self.connect(self.normalize, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-theta_f.dat"))
119 self.connect(self.angle, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-epsilon_f.dat"))
120 self.connect(self.pk_detect, gr.file_sink(gr.sizeof_char, "ofdm_sync_pn-peaks_b.dat"))
121 self.connect(self.sample_and_hold, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-sample_and_hold_f.dat"))
122 self.connect(self.input, gr.file_sink(gr.sizeof_gr_complex, "ofdm_sync_pn-input_c.dat"))