Merged r4518:5130 from developer branch n4hy/ofdm into trunk, passes distcheck.
[debian/gnuradio] / gnuradio-examples / python / ofdm / ofdm.py
1 #!/usr/bin/env python
2 #
3 # Copyright 2004,2005,2006 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 2, 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 from gnuradio import gr
24 from optparse import OptionParser
25 from ofdm_receiver import ofdm_receiver
26
27 class ofdm_mod(gr.hier_block):
28     def __init__(self, fg, options):
29         self.fg = fg
30         self._occupied_tones = options.occupied_tones
31         self._fft_length = options.fft_length
32         self._cp_length = options.cp_length
33         self._mtu = options.mtu
34
35         symbol_length = self._fft_length + self._cp_length
36
37         if self._fft_length < self._occupied_tones:
38             sys.stderr.write("occupied tones must be less than FFT length\n")
39             raise SystemExit
40         if self._fft_length < self._cp_length:
41             sys.stderr.write("cyclic prefix length  must be less than FFT length\n")
42             raise SystemExit
43
44         win = [] #[1 for i in range(self._fft_length)]
45
46         # hard-coded known symbol
47         #ks = self._occupied_tones*[1,]
48         ks1 = known_symbols_200_1
49         ks2 = known_symbols_200_2
50         
51         self.ofdm = gr.ofdm_bpsk_mapper(self._mtu, self._occupied_tones, self._fft_length, ks1, ks2)
52         self.ifft = gr.fft_vcc(self._fft_length, False, win, True)
53         self.cp_adder = gr.ofdm_cyclic_prefixer(self._fft_length, symbol_length)
54         
55         if options.verbose:
56             self._print_verbage()
57
58         self.fg.connect(self.ofdm, self.ifft, self.cp_adder)
59         gr.hier_block.__init__(self, self.fg, self.ofdm, self.cp_adder)
60
61     def samples_per_symbol(self):
62         return 2
63
64     def mtu(self):
65         return self._mtu
66
67     def bits_per_symbol(self=None):   # staticmethod that's also callable on an instance
68         return 1
69     bits_per_symbol = staticmethod(bits_per_symbol)      # make it a static method.  RTFM
70
71     def add_options(normal, expert):
72         """
73         Adds OFDM-specific options to the Options Parser
74         """
75         expert.add_option("", "--mtu", type="int", default=1500,
76                           help="set maximum transmit unit [default=%default]")
77         expert.add_option("", "--fft-length", type="intx", default=512,
78                           help="set the number of FFT bins [default=%default]")
79         expert.add_option("", "--occupied-tones", type="intx", default=200,
80                           help="set the number of occupied FFT bins [default=%default]")
81         expert.add_option("", "--cp-length", type="intx", default=128,
82                           help="set the number of bits in the cyclic prefix [default=%default]")
83     # Make a static method to call before instantiation
84     add_options = staticmethod(add_options)
85
86     def _print_verbage(self):
87         """
88         Prints information about the OFDM modulator
89         """
90         print "\nOFDM Modulator:"
91         print "FFT length:      %3d"   % (self._fft_length)
92         print "Occupied Tones:  %3d"   % (self._occupied_tones)
93         print "CP length:       %3d"   % (self._cp_length)
94
95
96 class ofdm_demod(gr.hier_block):
97     def __init__(self, fg, options):
98         self.fg = fg
99         self._occupied_tones = options.occupied_tones
100         self._fft_length = options.fft_length
101         self._cp_length = options.cp_length
102         self._snr = options.snr
103
104         symbol_length = self._fft_length + self._cp_length
105
106         win = [1 for i in range(self._fft_length)]
107
108         # hard-coded known symbol
109         ks1 = known_symbols_200_1
110         ks2 = known_symbols_200_2
111
112         # ML Sync
113         self.ofdm_sync = ofdm_receiver(self.fg, self._fft_length, symbol_length, self._snr)
114
115         # OFDM Demod
116         self.fft_demod = gr.fft_vcc(self._fft_length, True, win, True)
117         self.ofdm_corr  = gr.ofdm_correlator(self._occupied_tones, self._fft_length,
118                                              self._cp_length, ks1, ks2)
119         self.ofdm_demod = gr.ofdm_bpsk_demapper(self._occupied_tones)
120
121
122         if options.verbose:
123             self._print_verbage()
124
125         self.fg.connect(self.ofdm_sync, self.fft_demod, self.ofdm_corr, self.ofdm_demod)
126         gr.hier_block.__init__(self, self.fg, self.ofdm_sync, self.ofdm_demod)
127         
128     def bits_per_symbol(self=None):   # staticmethod that's also callable on an instance
129         return 1
130     bits_per_symbol = staticmethod(bits_per_symbol)      # make it a static method.  RTFM
131
132     def add_options(normal, expert):
133         """
134         Adds OFDM-specific options to the Options Parser
135         """
136         expert.add_option("", "--fft-length", type="intx", default=512,
137                           help="set the number of FFT bins [default=%default]")
138         expert.add_option("", "--occupied-tones", type="intx", default=200,
139                           help="set the number of occupied FFT bins [default=%default]")
140         expert.add_option("", "--cp-length", type="intx", default=128,
141                           help="set the number of bits in the cyclic prefix [default=%default]")
142     # Make a static method to call before instantiation
143     add_options = staticmethod(add_options)
144
145     def _print_verbage(self):
146         """
147         Prints information about the OFDM demodulator
148         """
149         print "\nOFDM Demodulator:"
150         print "FFT length:      %3d"   % (self._fft_length)
151         print "Occupied Tones:  %3d"   % (self._occupied_tones)
152         print "CP length:       %3d"   % (self._cp_length)
153
154
155 # generated in python using:
156 # import random
157 # pn = [2.0*random.randint(0,1)-1.0 for i in range(self._occupied_tones)]
158
159 known_symbols_200_1 = [1.0, 1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0, 1.0, -1.0, 1.0, -1.0, -1.0, 1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, -1.0, -1.0, 1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, -1.0, 1.0, -1.0, 1.0, -1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, -1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 1.0, -1.0]
160         
161 known_symbols_200_2 = [-1.0, -1.0, -1.0, 1.0, 1.0, 1.0, -1.0, -1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, -1.0, 1.0, -1.0, 1.0, -1.0, 1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, -1.0, 1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, -1.0, 1.0, 1.0, 1.0, -1.0, 1.0, -1.0, 1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0, 1.0, -1.0, 1.0, -1.0, 1.0, -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, -1.0, -1.0, 1.0, -1.0, 1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, -1.0, 1.0, 1.0, 1.0]