Imported Upstream version 3.2.2
[debian/gnuradio] / gnuradio-core / src / python / gnuradio / blks2impl / ofdm_sync_pn.py
1 #!/usr/bin/env python
2 #
3 # Copyright 2007,2008 Free Software Foundation, Inc.
4
5 # This file is part of GNU Radio
6
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)
10 # any later version.
11
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.
16
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.
21
22
23 import math
24 from numpy import fft
25 from gnuradio import gr
26
27 class ofdm_sync_pn(gr.hier_block2):
28     def __init__(self, fft_length, cp_length, logging=False):
29         """
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,
33         no. 12, 1997.
34         """
35         
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
39
40         self.input = gr.add_const_cc(0)
41
42         # PN Sync
43
44         # Create a delay line
45         self.delay = gr.delay(gr.sizeof_gr_complex, fft_length/2)
46
47         # Correlation from ML Sync
48         self.conjg = gr.conjugate_cc();
49         self.corr = gr.multiply_cc();
50
51         # Create a moving sum filter for the corr output
52         if 1:
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)
55         else:
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)
58
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)]
62
63         if 1:
64             self.inputmovingsum = gr.fir_filter_fff(1,movingsum2_taps)
65         else:
66             self.inputmovingsum = gr.fft_filter_fff(1,movingsum2_taps)
67
68         self.square = gr.multiply_ff()
69         self.normalize = gr.divide_ff()
70      
71         # Get magnitude (peaks) and angle (phase/freq error)
72         self.c2mag = gr.complex_to_mag_squared()
73         self.angle = gr.complex_to_arg()
74
75         self.sample_and_hold = gr.sample_and_hold_ff()
76
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)
81
82         self.connect(self, self.input)
83         
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))
93
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))
100
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)
105         
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))
109
110         # Set output signals
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))
115
116         if logging:
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"))
123