summaryrefslogtreecommitdiff
path: root/gr-uhd
diff options
context:
space:
mode:
Diffstat (limited to 'gr-uhd')
-rw-r--r--gr-uhd/examples/Makefile.am2
-rwxr-xr-xgr-uhd/examples/fm_tx_2_daughterboards.py203
-rwxr-xr-xgr-uhd/examples/usrp_spectrum_sense.py243
3 files changed, 448 insertions, 0 deletions
diff --git a/gr-uhd/examples/Makefile.am b/gr-uhd/examples/Makefile.am
index 8fe0c9221..b10b48928 100644
--- a/gr-uhd/examples/Makefile.am
+++ b/gr-uhd/examples/Makefile.am
@@ -27,10 +27,12 @@ ourdatadir = $(exampledir)/uhd
dist_ourdata_SCRIPTS = \
fm_tx4.py \
+ fm_tx_2_daughterboards.py \
max_power.py \
usrp_am_mw_rcv.py \
usrp_nbfm_ptt.py \
usrp_nbfm_rcv.py \
+ usrp_spectrum_sense.py \
usrp_tv_rcv_nogui.py \
usrp_tv_rcv.py \
usrp_wfm_rcv2_nogui.py \
diff --git a/gr-uhd/examples/fm_tx_2_daughterboards.py b/gr-uhd/examples/fm_tx_2_daughterboards.py
new file mode 100755
index 000000000..36d237616
--- /dev/null
+++ b/gr-uhd/examples/fm_tx_2_daughterboards.py
@@ -0,0 +1,203 @@
+#!/usr/bin/env python
+#
+# Copyright 2005-2007,2011 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+"""
+Transmit 2 signals, one out each daughterboard.
+
+Outputs SSB (USB) signals on side A and side B at frequencies
+specified on command line.
+
+Side A is 600 Hz tone.
+Side B is 350 + 440 Hz tones.
+"""
+
+from gnuradio import gr, uhd, blks2
+from gnuradio.eng_notation import num_to_str, str_to_num
+from gnuradio.eng_option import eng_option
+from optparse import OptionParser
+import math
+import sys
+
+
+class example_signal_0(gr.hier_block2):
+ """
+ Sinusoid at 600 Hz.
+ """
+ def __init__(self, sample_rate):
+ gr.hier_block2.__init__(self, "example_signal_0",
+ gr.io_signature(0, 0, 0), # Input signature
+ gr.io_signature(1, 1, gr.sizeof_gr_complex)) # Output signature
+
+ src = gr.sig_source_c (sample_rate, # sample rate
+ gr.GR_SIN_WAVE, # waveform type
+ 600, # frequency
+ 1.0, # amplitude
+ 0) # DC Offset
+
+ self.connect(src, self)
+
+
+class example_signal_1(gr.hier_block2):
+ """
+ North American dial tone (350 + 440 Hz).
+ """
+ def __init__(self, sample_rate):
+ gr.hier_block2.__init__(self, "example_signal_1",
+ gr.io_signature(0, 0, 0), # Input signature
+ gr.io_signature(1, 1, gr.sizeof_gr_complex)) # Output signature
+
+ src0 = gr.sig_source_c (sample_rate, # sample rate
+ gr.GR_SIN_WAVE, # waveform type
+ 350, # frequency
+ 1.0, # amplitude
+ 0) # DC Offset
+
+ src1 = gr.sig_source_c (sample_rate, # sample rate
+ gr.GR_SIN_WAVE, # waveform type
+ 440, # frequency
+ 1.0, # amplitude
+ 0) # DC Offset
+ sum = gr.add_cc()
+ self.connect(src0, (sum, 0))
+ self.connect(src1, (sum, 1))
+ self.connect(sum, self)
+
+class my_top_block(gr.top_block):
+
+ def __init__(self):
+ gr.top_block.__init__(self)
+
+ usage="%prog: [options] tx-freq0 tx-freq1"
+ parser = OptionParser (option_class=eng_option, usage=usage)
+ parser.add_option("-a", "--address", type="string",
+ default="addr=192.168.10.2",
+ help="Address of UHD device, [default=%default]")
+ parser.add_option("-A", "--antenna", type="string", default=None,
+ help="select Rx Antenna where appropriate")
+ parser.add_option("-s", "--samp-rate", type="eng_float", default=320e3,
+ help="set sample rate [default=%default]")
+ parser.add_option("-g", "--gain", type="eng_float", default=None,
+ help="set gain in dB (default is midpoint)")
+ (options, args) = parser.parse_args ()
+
+ if len(args) != 2:
+ parser.print_help()
+ raise SystemExit
+ else:
+ freq0 = str_to_num(args[0])
+ freq1 = str_to_num(args[1])
+
+ # ----------------------------------------------------------------
+ # Set up USRP to transmit on both daughterboards
+
+ d = uhd.device_find(uhd.device_addr(options.address))
+ uhd_type = d[0].get('type')
+
+ self.u = uhd.usrp_sink(device_addr=options.address,
+ io_type=uhd.io_type.COMPLEX_FLOAT32,
+ num_channels=2)
+
+ # Set up USRP system based on type
+ if(uhd_type == "usrp"):
+ self.u.set_subdev_spec("A:0 B:0")
+ tr0 = uhd.tune_request(freq0)
+ tr1 = uhd.tune_request(freq1)
+
+ else:
+ if abs(freq0 - freq1) > 5.5e6:
+ sys.stderr.write("\nError: When not using two separate d'boards, frequencies must bewithin 5.5MHz of each other.\n")
+ raise SystemExit
+
+ self.u.set_subdev_spec("A:0 A:0")
+
+ mid_freq = (freq0 + freq1)/2.0
+ tr0 = uhd.tune_request(freq0, rf_freq=mid_freq,
+ rf_freq_policy=uhd.tune_request.POLICY_MANUAL)
+
+ tr1 = uhd.tune_request(freq1, rf_freq=mid_freq,
+ rf_freq_policy=uhd.tune_request.POLICY_MANUAL)
+
+ # Use the tune requests to tune each channel
+ self.set_freq(tr0, 0)
+ self.set_freq(tr1, 1)
+
+ self.usrp_rate = options.samp_rate
+
+ self.u.set_samp_rate(self.usrp_rate)
+ dev_rate = self.u.get_samp_rate()
+
+ # ----------------------------------------------------------------
+ # build two signal sources, interleave them, amplify and
+ # connect them to usrp
+
+ sig0 = example_signal_0(self.usrp_rate)
+ sig1 = example_signal_1(self.usrp_rate)
+
+ intl = gr.interleave(gr.sizeof_gr_complex)
+ self.connect(sig0, (intl, 0))
+ self.connect(sig1, (intl, 1))
+
+ # Correct for any difference in requested and actual rates
+ rrate = self.usrp_rate / dev_rate
+ resamp = blks2.pfb_arb_resampler_ccf(rrate)
+
+ # and wire them up
+ self.connect(intl, resamp, self.u)
+
+ if options.gain is None:
+ # if no gain was specified, use the mid-point in dB
+ g = self.u.get_gain_range()
+ options.gain = float(g.start()+g.stop())/2.0
+
+ self.set_gain(options.gain, 0)
+ self.set_gain(options.gain, 1)
+
+ def set_freq(self, target_freq, chan):
+ """
+ Set the center frequency we're interested in.
+
+ @param side: 0 = side A, 1 = side B
+ @param target_freq: frequency in Hz
+ @rtype: bool
+ """
+
+ print "Tuning channel %s to %sHz" % \
+ (chan, num_to_str(target_freq))
+
+ r = self.u.set_center_freq(target_freq, chan)
+
+ if r:
+ return True
+
+ else:
+ print " Set Frequency Failed!"
+
+ return False
+
+ def set_gain(self, gain, chan):
+ self.u.set_gain(gain, chan)
+
+if __name__ == '__main__':
+ try:
+ my_top_block().run()
+ except KeyboardInterrupt:
+ pass
diff --git a/gr-uhd/examples/usrp_spectrum_sense.py b/gr-uhd/examples/usrp_spectrum_sense.py
new file mode 100755
index 000000000..e89745b3b
--- /dev/null
+++ b/gr-uhd/examples/usrp_spectrum_sense.py
@@ -0,0 +1,243 @@
+#!/usr/bin/env python
+#
+# Copyright 2005,2007,2011 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+from gnuradio import gr, eng_notation, window
+from gnuradio import audio
+from gnuradio import uhd
+from gnuradio.eng_option import eng_option
+from optparse import OptionParser
+import sys
+import math
+import struct
+
+sys.stderr.write("Warning: this is known to have issues on some machines+Python version combinations to seg fault due to the callback in bin_statitics. If you figure out why, we'd love to hear about it!\n")
+
+class tune(gr.feval_dd):
+ """
+ This class allows C++ code to callback into python.
+ """
+ def __init__(self, tb):
+ gr.feval_dd.__init__(self)
+ self.tb = tb
+
+ def eval(self, ignore):
+ """
+ This method is called from gr.bin_statistics_f when it wants
+ to change the center frequency. This method tunes the front
+ end to the new center frequency, and returns the new frequency
+ as its result.
+ """
+
+ try:
+ # We use this try block so that if something goes wrong
+ # from here down, at least we'll have a prayer of knowing
+ # what went wrong. Without this, you get a very
+ # mysterious:
+ #
+ # terminate called after throwing an instance of
+ # 'Swig::DirectorMethodException' Aborted
+ #
+ # message on stderr. Not exactly helpful ;)
+
+ new_freq = self.tb.set_next_freq()
+ return new_freq
+
+ except Exception, e:
+ print "tune: Exception: ", e
+
+
+class parse_msg(object):
+ def __init__(self, msg):
+ self.center_freq = msg.arg1()
+ self.vlen = int(msg.arg2())
+ assert(msg.length() == self.vlen * gr.sizeof_float)
+
+ # FIXME consider using NumPy array
+ t = msg.to_string()
+ self.raw_data = t
+ self.data = struct.unpack('%df' % (self.vlen,), t)
+
+
+class my_top_block(gr.top_block):
+
+ def __init__(self):
+ gr.top_block.__init__(self)
+
+ usage = "usage: %prog [options] min_freq max_freq"
+ parser = OptionParser(option_class=eng_option, usage=usage)
+ parser.add_option("-a", "--address", type="string",
+ default="addr=192.168.10.2",
+ help="Address of UHD device, [default=%default]")
+ parser.add_option("-A", "--antenna", type="string", default=None,
+ help="select Rx Antenna where appropriate")
+ parser.add_option("-s", "--samp-rate", type="eng_float", default=1e6,
+ help="set sample rate [default=%default]")
+ parser.add_option("-g", "--gain", type="eng_float", default=None,
+ help="set gain in dB (default is midpoint)")
+ parser.add_option("", "--tune-delay", type="eng_float",
+ default=1e-3, metavar="SECS",
+ help="time to delay (in seconds) after changing frequency [default=%default]")
+ parser.add_option("", "--dwell-delay", type="eng_float",
+ default=10e-3, metavar="SECS",
+ help="time to dwell (in seconds) at a given frequncy [default=%default]")
+ parser.add_option("-F", "--fft-size", type="int", default=256,
+ help="specify number of FFT bins [default=%default]")
+ parser.add_option("", "--real-time", action="store_true", default=False,
+ help="Attempt to enable real-time scheduling")
+
+ (options, args) = parser.parse_args()
+ if len(args) != 2:
+ parser.print_help()
+ sys.exit(1)
+
+ self.min_freq = eng_notation.str_to_num(args[0])
+ self.max_freq = eng_notation.str_to_num(args[1])
+
+ if self.min_freq > self.max_freq:
+ # swap them
+ self.min_freq, self.max_freq = self.max_freq, self.min_freq
+
+ self.fft_size = options.fft_size
+
+ if not options.real_time:
+ realtime = False
+ else:
+ # Attempt to enable realtime scheduling
+ r = gr.enable_realtime_scheduling()
+ if r == gr.RT_OK:
+ realtime = True
+ else:
+ realtime = False
+ print "Note: failed to enable realtime scheduling"
+
+ # build graph
+ self.u = uhd.usrp_source(device_addr=options.address,
+ io_type=uhd.io_type.COMPLEX_FLOAT32,
+ num_channels=1)
+
+ usrp_rate = options.samp_rate
+ self.u.set_samp_rate(usrp_rate)
+ dev_rate = self.u.get_samp_rate()
+
+ s2v = gr.stream_to_vector(gr.sizeof_gr_complex, self.fft_size)
+
+ mywindow = window.blackmanharris(self.fft_size)
+ fft = gr.fft_vcc(self.fft_size, True, mywindow)
+ power = 0
+ for tap in mywindow:
+ power += tap*tap
+
+ c2mag = gr.complex_to_mag_squared(self.fft_size)
+
+ # FIXME the log10 primitive is dog slow
+ log = gr.nlog10_ff(10, self.fft_size,
+ -20*math.log10(self.fft_size)-10*math.log10(power/self.fft_size))
+
+ # Set the freq_step to 75% of the actual data throughput.
+ # This allows us to discard the bins on both ends of the spectrum.
+
+ self.freq_step = 0.75 * usrp_rate
+ self.min_center_freq = self.min_freq + self.freq_step/2
+ nsteps = math.ceil((self.max_freq - self.min_freq) / self.freq_step)
+ self.max_center_freq = self.min_center_freq + (nsteps * self.freq_step)
+
+ self.next_freq = self.min_center_freq
+
+ tune_delay = max(0, int(round(options.tune_delay * usrp_rate / self.fft_size))) # in fft_frames
+ dwell_delay = max(1, int(round(options.dwell_delay * usrp_rate / self.fft_size))) # in fft_frames
+
+ self.msgq = gr.msg_queue(16)
+ self._tune_callback = tune(self) # hang on to this to keep it from being GC'd
+ stats = gr.bin_statistics_f(self.fft_size, self.msgq,
+ self._tune_callback, tune_delay,
+ dwell_delay)
+
+ # FIXME leave out the log10 until we speed it up
+ #self.connect(self.u, s2v, fft, c2mag, log, stats)
+ self.connect(self.u, s2v, fft, c2mag, stats)
+
+ if options.gain is None:
+ # if no gain was specified, use the mid-point in dB
+ g = self.u.get_gain_range()
+ options.gain = float(g.start()+g.stop())/2.0
+
+ self.set_gain(options.gain)
+ print "gain =", options.gain
+
+
+ def set_next_freq(self):
+ target_freq = self.next_freq
+ self.next_freq = self.next_freq + self.freq_step
+ if self.next_freq >= self.max_center_freq:
+ self.next_freq = self.min_center_freq
+
+ if not self.set_freq(target_freq):
+ print "Failed to set frequency to", target_freq
+ sys.exit(1)
+
+ return target_freq
+
+
+ def set_freq(self, target_freq):
+ """
+ Set the center frequency we're interested in.
+
+ @param target_freq: frequency in Hz
+ @rypte: bool
+ """
+ r = self.u.set_center_freq(target_freq)
+ if r:
+ return True
+
+ return False
+
+ def set_gain(self, gain):
+ self.u.set_gain(gain)
+
+
+def main_loop(tb):
+ while 1:
+
+ # Get the next message sent from the C++ code (blocking call).
+ # It contains the center frequency and the mag squared of the fft
+ m = parse_msg(tb.msgq.delete_head())
+
+ # Print center freq so we know that something is happening...
+ print m.center_freq
+
+ # FIXME do something useful with the data...
+
+ # m.data are the mag_squared of the fft output (they are in the
+ # standard order. I.e., bin 0 == DC.)
+ # You'll probably want to do the equivalent of "fftshift" on them
+ # m.raw_data is a string that contains the binary floats.
+ # You could write this as binary to a file.
+
+
+if __name__ == '__main__':
+ tb = my_top_block()
+ try:
+ tb.start()
+ main_loop(tb)
+
+ except KeyboardInterrupt:
+ pass