diff options
Diffstat (limited to 'gr-uhd')
-rw-r--r-- | gr-uhd/examples/Makefile.am | 2 | ||||
-rwxr-xr-x | gr-uhd/examples/fm_tx_2_daughterboards.py | 203 | ||||
-rwxr-xr-x | gr-uhd/examples/usrp_spectrum_sense.py | 243 |
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 |