3 # Copyright 2005,2006,2007 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.
24 Transmit N simultaneous narrow band FM signals.
26 They will be centered at the frequency specified on the command line,
27 and will spaced at 25kHz steps from there.
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
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
45 from gnuradio.wxgui import stdgui2, fftsink2
46 #from gnuradio import tx_debug_gui
50 ########################################################
51 # instantiate one transmit chain for each call
53 class pipeline(gr.hier_block2):
54 def __init__(self, filename, lo_freq, audio_rate, if_rate):
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
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)
64 lo = gr.sig_source_c (if_rate, # sample rate
65 gr.GR_SIN_WAVE, # waveform type
69 mixer = gr.multiply_cc ()
71 self.connect (src, fmtx, (mixer, 0))
72 self.connect (lo, (mixer, 1))
73 self.connect (mixer, self)
75 class fm_tx_block(stdgui2.std_top_block):
76 def __init__(self, frame, panel, vbox, argv):
78 stdgui2.std_top_block.__init__ (self, frame, panel, vbox, argv)
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 ()
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)
99 if options.freq is None:
100 sys.stderr.write("fm_tx4: must specify frequency with -f FREQ\n")
104 # ----------------------------------------------------------------
105 # Set up constants and parameters
107 self.u = usrp.sink_c () # the USRP sink (consumes samples)
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
114 self.audio_rate = self.usrp_rate / self.sw_interp # 32 kS/s
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)
120 m = usrp.determine_tx_mux_value(self.u, options.tx_subdev_spec)
121 #print "mux = %#04x" % (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(),)
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]))
134 self.subdev.set_enable(True) # enable transmitter
138 # Instantiate N NBFM channels
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))
146 gain = gr.multiply_const_cc (4000.0 / options.nchannels)
149 self.connect (sum, gain)
150 self.connect (gain, self.u)
152 # plot an FFT to verify we are sending what we want
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)
162 # self.debugger = tx_debug_gui.tx_debug_gui(self.subdev)
163 # self.debugger.Show(True)
166 def set_freq(self, target_freq):
168 Set the center frequency we're interested in.
170 @param target_freq: frequency in Hz
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.
180 r = self.u.tune(self.subdev.which(), self.subdev, target_freq)
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
187 # Could use residual_freq in s/w freq translator
193 app = stdgui2.stdapp(fm_tx_block, "Multichannel FM Tx", nstatus=1)
196 if __name__ == '__main__':