Merging ofdm2 branch -r7047:7321 into trunk. This updates the OFDM code to hier_block...
[debian/gnuradio] / gnuradio-core / src / python / gnuradio / blks2impl / ofdm_receiver.py
1 #!/usr/bin/env python
2 #
3 # Copyright 2006, 2007 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 from gnuradio.blks2impl.ofdm_sync_ml import ofdm_sync_ml
27 from gnuradio.blks2impl.ofdm_sync_pn import ofdm_sync_pn
28 from gnuradio.blks2impl.ofdm_sync_pnac import ofdm_sync_pnac
29 from gnuradio.blks2impl.ofdm_sync_fixed import ofdm_sync_fixed
30
31 class ofdm_receiver(gr.hier_block2):
32     """
33     Performs receiver synchronization on OFDM symbols.
34
35     The receiver performs channel filtering as well as symbol, frequency, and phase synchronization.
36     The synchronization routines are available in three flavors: preamble correlator (Schmidl and Cox),
37     modifid preamble correlator with autocorrelation (not yet working), and cyclic prefix correlator
38     (Van de Beeks).
39     """
40
41     def __init__(self, fft_length, cp_length, occupied_tones, snr, ks, logging=False):
42         """
43         Hierarchical block for receiving OFDM symbols.
44
45         The input is the complex modulated signal at baseband.
46         Synchronized packets are sent back to the demodulator.
47
48         @param fft_length: total number of subcarriers
49         @type  fft_length: int
50         @param cp_length: length of cyclic prefix as specified in subcarriers (<= fft_length)
51         @type  cp_length: int
52         @param occupied_tones: number of subcarriers used for data
53         @type  occupied_tones: int
54         @param snr: estimated signal to noise ratio used to guide cyclic prefix synchronizer
55         @type  snr: float
56         @param ks: known symbols used as preambles to each packet
57         @type  ks: list of lists
58         @param logging: turn file logging on or off
59         @type  logging: bool
60         """
61
62         gr.hier_block2.__init__(self, "ofdm_receiver",
63                                 gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature
64                                 gr.io_signature2(2, 2, gr.sizeof_gr_complex*occupied_tones, gr.sizeof_char)) # Output signature
65
66         bw = (float(occupied_tones) / float(fft_length)) / 2.0
67         tb = bw*0.08
68         chan_coeffs = gr.firdes.low_pass (1.0,                     # gain
69                                           1.0,                     # sampling rate
70                                           bw+tb,                   # midpoint of trans. band
71                                           tb,                      # width of trans. band
72                                           gr.firdes.WIN_HAMMING)   # filter type
73         self.chan_filt = gr.fft_filter_ccc(1, chan_coeffs)
74         
75         win = [1 for i in range(fft_length)]
76
77         zeros_on_left = int(math.ceil((fft_length - occupied_tones)/2.0))
78         zeros_on_right = fft_length - occupied_tones - zeros_on_left
79         ks0 = zeros_on_left*[0.0,]
80         ks0.extend(ks[0])
81         ks0.extend(zeros_on_right*[0.0,])
82         
83         ks0time = fft.ifft(ks0)
84         # ADD SCALING FACTOR
85         ks0time = ks0time.tolist()
86         
87         SYNC = "pn"
88         if SYNC == "ml":
89             self.ofdm_sync = ofdm_sync_ml(fft_length, cp_length, snr, logging)
90         elif SYNC == "pn":
91             self.ofdm_sync = ofdm_sync_pn(fft_length, cp_length, logging)
92         elif SYNC == "pnac":
93             self.ofdm_sync = ofdm_sync_pnac(fft_length, cp_length, ks0time)
94         elif SYNC == "fixed":
95             self.ofdm_sync = ofdm_sync_fixed(fft_length, cp_length, logging)
96                         
97         self.fft_demod = gr.fft_vcc(fft_length, True, win, True)
98         self.ofdm_frame_acq = gr.ofdm_frame_acquisition(occupied_tones, fft_length,
99                                                         cp_length, ks[0])
100
101         self.connect(self, self.chan_filt)
102         self.connect(self.chan_filt, self.ofdm_sync, self.fft_demod, (self.ofdm_frame_acq,0))
103         self.connect((self.ofdm_sync,1), (self.ofdm_frame_acq,1))
104         self.connect((self.ofdm_frame_acq,0), (self,0))
105         self.connect((self.ofdm_frame_acq,1), (self,1))
106
107         if logging:
108             self.connect(self.chan_filt, gr.file_sink(gr.sizeof_gr_complex, "chan_filt_c.dat"))
109             self.connect(self.fft_demod, gr.file_sink(gr.sizeof_gr_complex*fft_length, "fft_out_c.dat"))
110             self.connect(self.ofdm_frame_acq,
111                          gr.file_sink(gr.sizeof_gr_complex*occupied_tones, "ofdm_frame_acq_c.dat"))
112             self.connect((self.ofdm_frame_acq,1), gr.file_sink(1, "found_corr_b.dat"))