Imported Upstream version 3.2.2
[debian/gnuradio] / gnuradio-examples / python / usrp / fm_tx4.py
1 #!/usr/bin/env python
2 #
3 # Copyright 2005,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 """
24 Transmit N simultaneous narrow band FM signals.
25
26 They will be centered at the frequency specified on the command line,
27 and will spaced at 25kHz steps from there.
28
29 The program opens N files with names audio-N.dat where N is in [0,7].
30 These files should contain floating point audio samples in the range [-1,1]
31 sampled at 32kS/sec.  You can create files like this using
32 audio_to_file.py
33 """
34
35 from gnuradio import gr, eng_notation
36 from gnuradio import usrp
37 from gnuradio import audio
38 from gnuradio import blks2
39 from gnuradio.eng_option import eng_option
40 from optparse import OptionParser
41 from usrpm import usrp_dbid
42 import math
43 import sys
44
45 from gnuradio.wxgui import stdgui2, fftsink2
46 #from gnuradio import tx_debug_gui
47 import wx
48
49
50 ########################################################
51 # instantiate one transmit chain for each call
52
53 class pipeline(gr.hier_block2):
54     def __init__(self, filename, lo_freq, audio_rate, if_rate):
55
56         gr.hier_block2.__init__(self, "pipeline",
57                                 gr.io_signature(0, 0, 0),                    # Input signature
58                                 gr.io_signature(1, 1, gr.sizeof_gr_complex)) # Output signature
59
60         src = gr.file_source (gr.sizeof_float, filename, True)
61         fmtx = blks2.nbfm_tx (audio_rate, if_rate, max_dev=5e3, tau=75e-6)
62         
63         # Local oscillator
64         lo = gr.sig_source_c (if_rate,        # sample rate
65                               gr.GR_SIN_WAVE, # waveform type
66                               lo_freq,        #frequency
67                               1.0,            # amplitude
68                               0)              # DC Offset
69         mixer = gr.multiply_cc ()
70     
71         self.connect (src, fmtx, (mixer, 0))
72         self.connect (lo, (mixer, 1))
73         self.connect (mixer, self)
74
75 class fm_tx_block(stdgui2.std_top_block):
76     def __init__(self, frame, panel, vbox, argv):
77         MAX_CHANNELS = 7
78         stdgui2.std_top_block.__init__ (self, frame, panel, vbox, argv)
79
80         parser = OptionParser (option_class=eng_option)
81         parser.add_option("-T", "--tx-subdev-spec", type="subdev", default=None,
82                           help="select USRP Tx side A or B")
83         parser.add_option("-f", "--freq", type="eng_float", default=None,
84                            help="set Tx frequency to FREQ [required]", metavar="FREQ")
85         parser.add_option("-n", "--nchannels", type="int", default=4,
86                            help="number of Tx channels [1,4]")
87         #parser.add_option("","--debug", action="store_true", default=False,
88         #                  help="Launch Tx debugger")
89         (options, args) = parser.parse_args ()
90
91         if len(args) != 0:
92             parser.print_help()
93             sys.exit(1)
94
95         if options.nchannels < 1 or options.nchannels > MAX_CHANNELS:
96             sys.stderr.write ("fm_tx4: nchannels out of range.  Must be in [1,%d]\n" % MAX_CHANNELS)
97             sys.exit(1)
98         
99         if options.freq is None:
100             sys.stderr.write("fm_tx4: must specify frequency with -f FREQ\n")
101             parser.print_help()
102             sys.exit(1)
103
104         # ----------------------------------------------------------------
105         # Set up constants and parameters
106
107         self.u = usrp.sink_c ()       # the USRP sink (consumes samples)
108
109         self.dac_rate = self.u.dac_rate()                    # 128 MS/s
110         self.usrp_interp = 400
111         self.u.set_interp_rate(self.usrp_interp)
112         self.usrp_rate = self.dac_rate / self.usrp_interp    # 320 kS/s
113         self.sw_interp = 10
114         self.audio_rate = self.usrp_rate / self.sw_interp    # 32 kS/s
115
116         # determine the daughterboard subdevice we're using
117         if options.tx_subdev_spec is None:
118             options.tx_subdev_spec = usrp.pick_tx_subdevice(self.u)
119
120         m = usrp.determine_tx_mux_value(self.u, options.tx_subdev_spec)
121         #print "mux = %#04x" % (m,)
122         self.u.set_mux(m)
123         self.subdev = usrp.selected_subdev(self.u, options.tx_subdev_spec)
124         print "Using TX d'board %s" % (self.subdev.side_and_name(),)
125
126         self.subdev.set_gain(self.subdev.gain_range()[1])    # set max Tx gain
127         if not self.set_freq(options.freq):
128             freq_range = self.subdev.freq_range()
129             print "Failed to set frequency to %s.  Daughterboard supports %s to %s" % (
130                 eng_notation.num_to_str(options.freq),
131                 eng_notation.num_to_str(freq_range[0]),
132                 eng_notation.num_to_str(freq_range[1]))
133             raise SystemExit
134         self.subdev.set_enable(True)                         # enable transmitter
135
136         sum = gr.add_cc ()
137
138         # Instantiate N NBFM channels
139         step = 25e3
140         offset = (0 * step, 1 * step, -1 * step, 2 * step, -2 * step, 3 * step, -3 * step)
141         for i in range (options.nchannels):
142             t = pipeline("audio-%d.dat" % (i % 4), offset[i],
143                          self.audio_rate, self.usrp_rate)
144             self.connect(t, (sum, i))
145
146         gain = gr.multiply_const_cc (4000.0 / options.nchannels)
147
148         # connect it all
149         self.connect (sum, gain)
150         self.connect (gain, self.u)
151
152         # plot an FFT to verify we are sending what we want
153         if 1:
154             post_mod = fftsink2.fft_sink_c(panel, title="Post Modulation",
155                                            fft_size=512, sample_rate=self.usrp_rate,
156                                            y_per_div=20, ref_level=40)
157             self.connect (sum, post_mod)
158             vbox.Add (post_mod.win, 1, wx.EXPAND)
159             
160
161         #if options.debug:
162         #    self.debugger = tx_debug_gui.tx_debug_gui(self.subdev)
163         #    self.debugger.Show(True)
164
165
166     def set_freq(self, target_freq):
167         """
168         Set the center frequency we're interested in.
169
170         @param target_freq: frequency in Hz
171         @rypte: bool
172
173         Tuning is a two step process.  First we ask the front-end to
174         tune as close to the desired frequency as it can.  Then we use
175         the result of that operation and our target_frequency to
176         determine the value for the digital up converter.  Finally, we feed
177         any residual_freq to the s/w freq translater.
178         """
179
180         r = self.u.tune(self.subdev.which(), self.subdev, target_freq)
181         if r:
182             print "r.baseband_freq =", eng_notation.num_to_str(r.baseband_freq)
183             print "r.dxc_freq      =", eng_notation.num_to_str(r.dxc_freq)
184             print "r.residual_freq =", eng_notation.num_to_str(r.residual_freq)
185             print "r.inverted      =", r.inverted
186             
187             # Could use residual_freq in s/w freq translator
188             return True
189
190         return False
191
192 def main ():
193     app = stdgui2.stdapp(fm_tx_block, "Multichannel FM Tx", nstatus=1)
194     app.MainLoop ()
195
196 if __name__ == '__main__':
197     main ()