diff options
Diffstat (limited to 'gr-digital/examples/narrowband')
-rw-r--r-- | gr-digital/examples/narrowband/README | 153 | ||||
-rwxr-xr-x | gr-digital/examples/narrowband/benchmark_rx.py | 6 | ||||
-rwxr-xr-x | gr-digital/examples/narrowband/benchmark_tx.py | 6 | ||||
-rwxr-xr-x | gr-digital/examples/narrowband/digital_bert_rx.py | 2 | ||||
-rwxr-xr-x | gr-digital/examples/narrowband/digital_bert_tx.py | 2 | ||||
-rwxr-xr-x | gr-digital/examples/narrowband/rx_voice.py | 2 | ||||
-rwxr-xr-x | gr-digital/examples/narrowband/tunnel.py | 8 | ||||
-rw-r--r-- | gr-digital/examples/narrowband/uhd_interface.py | 38 |
8 files changed, 191 insertions, 26 deletions
diff --git a/gr-digital/examples/narrowband/README b/gr-digital/examples/narrowband/README new file mode 100644 index 000000000..1c50ad69b --- /dev/null +++ b/gr-digital/examples/narrowband/README @@ -0,0 +1,153 @@ +Quick overview of what's here: + +* benchmark_tx.py: generates packets of the size you +specify and sends them across the air using the USRP. Known to work +well using the USRP with the RFX transceiver daughterboards. +You can specify the bitrate to use with the -r <bitrate> command line +parameter. The default is 500k. Some machines will do 1M or more. +You can select the modulation to use with the -m <modulation> command +line argument. The legal values for <modulation> are gmsk, dbpsk and dqpsk. + +* benchmark_rx.py: the receiver half of benchmark_tx.py. +Command line arguments are pretty much the same as rx. Works well +with a USRP and RFX transceiver daughterboards. Will also work +with TVRX daugherboard, but you'll need to fiddle with the gain. See +below. Prints a summary of each packet received and keeps a running +total of packets received, and how many of them were error free. +There are two levels of error reporting going on. If the access code +(PN code) and header of a packet were properly detected, then you'll +get an output line. If the CRC32 of the payload was correct you get +"ok = True", else "ok = False". The "pktno" is extracted from the +received packet. If there are skipped numbers, you're missing some +packets. Be sure you've got a suitable antenna connected to the TX/RX +port on each board. For the RFX-400, "70 cm" / 420 MHz antennas for ham +handi-talkies work great. These are available at ham radio supplies, +etc. The boards need to be at least 3m apart. You can also try +experimenting with the rx gain (-g <gain> command line option). + +Generally speaking, I start the rx first on one machine, and then fire +up the tx on the other machine. The tx also supports a discontinous +transmission mode where it sends bursts of 5 packets and then waits 1 +second. This is useful for ensuring that all the receiver control +loops lock up fast enough. + +* tunnel.py: This program provides a framework for building your own +MACs. It creates a "TAP" interface in the kernel, typically gr0, +and sends and receives ethernet frames through it. See +/usr/src/linux/Documentation/networking/tuntap.txt and/or Google for +"universal tun tap". The Linux 2.6 kernel includes the tun module, you +don't have to build it. You may have to "modprobe tun" if it's not +loaded by default. If /dev/net/tun doesn't exist, try "modprobe tun". + +To run this program you'll need to be root or running with the +appropriate capability to open the tun interface. You'll need to fire +up two copies on different machines. Once each is running you'll need +to ifconfig the gr0 interface to set the IP address. + +This will allow two machines to talk, but anything beyond the two +machines depends on your networking setup. Left as an exercise... + +On machine A: + + $ su + # ./tunnel.py --freq 423.0M --bitrate 500k + # # in another window on A, also as root... + # ifconfig gr0 192.168.200.1 + + +On machine B: + + $ su + # ./tunnel.py --freq 423.0M --bitrate 500k + # # in another window on B, also as root... + # ifconfig gr0 192.168.200.2 + +Now, on machine A you shold be able to ping machine B: + + $ ping 192.168.200.2 + +and you should see some output for each packet in the +tunnel.py window if you used the -v option. + +Likewise, on machine B: + + $ ping 192.168.200.1 + +This now uses a carrier sense MAC, so you should be able to ssh +between the machines, web browse, etc. + +* run_length.py: This program takes a single argument '-f FILE' and +outputs the number of runs of similar bits within the file. It is +useful as a diagnostic tool when experimenting with line coding or +whitening algorithms. + + + +********************************************************************** +********************************************************************** + + +BERT testing example scripts + +benchmark_tx.py + +This sets up a BPSK transmitter that is modulated with a pseudorandom +sequence of bits. The PN code is generated by sending an all 1s +sequence through a 7-bit scrambler. The transmitter performs the BPSK +modulation, then passes the complex baseband waveform through a +root-raised-cosine filter and onto the USRP. + +The --sps parameter controls how many baseband samples per symbol +are created and passed through the RRC filter, prior to going to the +USRP over the USB for interpolation to the final DAC rate. + +The baseband bit rate is controlled by -r or --rate. This value, when +multiplied by the --sps parameter, must result in valid interpolation +rate for the USRP. For example, if the baseband rate is 250k bits/sec, +and the samples per symbol is 4, then the final rate is 1M samples/sec, +which results in an interpolation rate of 128. The valid interpolation +rates for the USRP are multiples of 4 between 16 and 512. + +Finally, the RRC excess bandwidth may be specified by --excess-bw. +(See ./benchmark_tx.py -h for additional parameters.) + + +benchmark_rx.py + +This sets up a BPSK receiver to demodulate the received waveform. It +accepts a similar set of parameters as the transmitter, except that one +specifies the USRP decimation rate desired. The resulting sample stream +rate must be an integral number of baseband symbols. For example, the +parameters corresponding to the above transmitter would be to use a +decimation rate of 8 (32 sps), 16 (16 sps), 32 (8 sps), 64, (4 sps), or +128 (2 sps). The lower the USRP decimation, the more CPU is required to +demodulate the signal, so not all valid decimation rates will work. + +The baseband signal from the USRP is first passed through an AGC to +establish an average power of 1.0. It is then passed through a matched +filter (another RRC), a Costas phase-locked loop, and a Mueller and +Muller bit timing recovery loop. The resulting constellation has an SNR +estimation probe attached, and is then sliced into a bit stream. + +The recovered bits are then passed through a 7-bit descrambler. If +there are no channel errors, the all 1s sequence is recovered. In the +event of a channel error, there will be a 0 in the bit stream for each +feedback tap in the descrambler. In this case, the CCSDS descrambler is +using 3 feedback taps. + +Finally, the signal is passed into a bit density measurement probe. The +channel BER is measured by dividing the 0s density by three. This +measurement is inaccurate at high BER rates (>10%) as the error 0s +begin to overlap. + +The benchmark script will, once per second, output the Costas loop +frequency offset, the recovered timing error, the estimated SNR, and the +average BER. + +NOTE: The particular SNR estimator used is inaccurate below about 7dB, +and will report erroneously high values even for random noise. + +There are a variety of Costas and M&M loop parameters one can adjust. +See ./benchmark_rx.py -h for the full set. + + diff --git a/gr-digital/examples/narrowband/benchmark_rx.py b/gr-digital/examples/narrowband/benchmark_rx.py index 65aac3638..32c3222ae 100755 --- a/gr-digital/examples/narrowband/benchmark_rx.py +++ b/gr-digital/examples/narrowband/benchmark_rx.py @@ -44,7 +44,11 @@ class my_top_block(gr.top_block): gr.top_block.__init__(self) if(options.rx_freq is not None): - self.source = uhd_receiver(options.address, options.bitrate, + # Work-around to get the modulation's bits_per_symbol + args = demodulator.extract_kwargs_from_options(options) + symbol_rate = options.bitrate / demodulator(**args).bits_per_symbol() + + self.source = uhd_receiver(options.args, symbol_rate, options.samples_per_symbol, options.rx_freq, options.rx_gain, options.antenna, options.verbose) diff --git a/gr-digital/examples/narrowband/benchmark_tx.py b/gr-digital/examples/narrowband/benchmark_tx.py index 1fd881981..25ed355da 100755 --- a/gr-digital/examples/narrowband/benchmark_tx.py +++ b/gr-digital/examples/narrowband/benchmark_tx.py @@ -43,7 +43,11 @@ class my_top_block(gr.top_block): gr.top_block.__init__(self) if(options.tx_freq is not None): - self.sink = uhd_transmitter(options.address, options.bitrate, + # Work-around to get the modulation's bits_per_symbol + args = modulator.extract_kwargs_from_options(options) + symbol_rate = options.bitrate / modulator(**args).bits_per_symbol() + + self.sink = uhd_transmitter(options.args, symbol_rate, options.samples_per_symbol, options.tx_freq, options.tx_gain, options.antenna, options.verbose) diff --git a/gr-digital/examples/narrowband/digital_bert_rx.py b/gr-digital/examples/narrowband/digital_bert_rx.py index 9878f55e1..28331310d 100755 --- a/gr-digital/examples/narrowband/digital_bert_rx.py +++ b/gr-digital/examples/narrowband/digital_bert_rx.py @@ -113,7 +113,7 @@ class rx_psk_block(gr.top_block): self._demodulator = self._demodulator_class(**demod_kwargs) if(options.rx_freq is not None): - self._source = uhd_receiver(options.address, options.bitrate, + self._source = uhd_receiver(options.args, options.bitrate, options.samples_per_symbol, options.rx_freq, options.rx_gain, options.antenna, options.verbose) diff --git a/gr-digital/examples/narrowband/digital_bert_tx.py b/gr-digital/examples/narrowband/digital_bert_tx.py index 96cb338fe..46f4f9097 100755 --- a/gr-digital/examples/narrowband/digital_bert_tx.py +++ b/gr-digital/examples/narrowband/digital_bert_tx.py @@ -67,7 +67,7 @@ class tx_psk_block(gr.top_block): self._modulator = self._modulator_class(**mod_kwargs) if(options.tx_freq is not None): - self._sink = uhd_transmitter(options.address, options.bitrate, + self._sink = uhd_transmitter(options.args, options.bitrate, options.samples_per_symbol, options.tx_freq, options.tx_gain, options.antenna, options.verbose) diff --git a/gr-digital/examples/narrowband/rx_voice.py b/gr-digital/examples/narrowband/rx_voice.py index 42d7b893b..100caff8e 100755 --- a/gr-digital/examples/narrowband/rx_voice.py +++ b/gr-digital/examples/narrowband/rx_voice.py @@ -66,7 +66,7 @@ class my_top_block(gr.top_block): self.audio_tx = audio_tx(options.audio_output) if(options.rx_freq is not None): - self.source = uhd_receiver(options.address, options.bitrate, + self.source = uhd_receiver(options.args, options.bitrate, options.samples_per_symbol, options.rx_freq, options.rx_gain, options.antenna, options.verbose) diff --git a/gr-digital/examples/narrowband/tunnel.py b/gr-digital/examples/narrowband/tunnel.py index 7f40bb1c3..7414a7227 100755 --- a/gr-digital/examples/narrowband/tunnel.py +++ b/gr-digital/examples/narrowband/tunnel.py @@ -92,12 +92,16 @@ class my_top_block(gr.top_block): gr.top_block.__init__(self) - self.source = uhd_receiver(options.address, options.bitrate, + # Get the modulation's bits_per_symbol + args = mod_class.extract_kwargs_from_options(options) + symbol_rate = options.bitrate / mod_class(**args).bits_per_symbol() + + self.source = uhd_receiver(options.args, symbol_rate, options.samples_per_symbol, options.rx_freq, options.rx_gain, options.antenna, options.verbose) - self.sink = uhd_transmitter(options.address, options.bitrate, + self.sink = uhd_transmitter(options.args, symbol_rate, options.samples_per_symbol, options.tx_freq, options.tx_gain, options.antenna, options.verbose) diff --git a/gr-digital/examples/narrowband/uhd_interface.py b/gr-digital/examples/narrowband/uhd_interface.py index 8420f3eec..a0be516ec 100644 --- a/gr-digital/examples/narrowband/uhd_interface.py +++ b/gr-digital/examples/narrowband/uhd_interface.py @@ -42,36 +42,36 @@ def add_freq_option(parser): metavar="FREQ") class uhd_interface: - def __init__(self, istx, address, bitrate, sps, freq=None, + def __init__(self, istx, args, sym_rate, sps, freq=None, gain=None, antenna=None): if(istx): - self.u = uhd.usrp_sink(device_addr=address, + self.u = uhd.usrp_sink(device_addr=args, io_type=uhd.io_type.COMPLEX_FLOAT32, num_channels=1) else: - self.u = uhd.usrp_source(device_addr=address, + self.u = uhd.usrp_source(device_addr=args, io_type=uhd.io_type.COMPLEX_FLOAT32, num_channels=1) - self._addr = address + self._args = args self._ant = antenna self._gain = self.set_gain(gain) self._freq = self.set_freq(freq) - self._rate, self._sps = self.set_sample_rate(bitrate, sps) + self._rate, self._sps = self.set_sample_rate(sym_rate, sps) if(antenna): self.u.set_antenna(antenna, 0) - def set_sample_rate(self, bitrate, req_sps): + def set_sample_rate(self, sym_rate, req_sps): start_sps = req_sps while(True): - asked_samp_rate = bitrate * req_sps + asked_samp_rate = sym_rate * req_sps self.u.set_samp_rate(asked_samp_rate) actual_samp_rate = self.u.get_samp_rate() - sps = actual_samp_rate/bitrate + sps = actual_samp_rate/sym_rate if(sps < 2): req_sps +=1 else: @@ -79,7 +79,7 @@ class uhd_interface: break if(sps != req_sps): - print "\nBit Rate: %f" % (bitrate) + print "\nSymbol Rate: %f" % (sym_rate) print "Requested sps: %f" % (start_sps) print "Given sample rate: %f" % (actual_samp_rate) print "Actual sps for rate: %f" % (actual_sps) @@ -124,14 +124,14 @@ class uhd_interface: #-------------------------------------------------------------------# class uhd_transmitter(uhd_interface, gr.hier_block2): - def __init__(self, address, bitrate, sps, freq=None, gain=None, + def __init__(self, args, sym_rate, sps, freq=None, gain=None, antenna=None, verbose=False): gr.hier_block2.__init__(self, "uhd_transmitter", gr.io_signature(1,1,gr.sizeof_gr_complex), gr.io_signature(0,0,0)) # Set up the UHD interface as a transmitter - uhd_interface.__init__(self, True, address, bitrate, sps, + uhd_interface.__init__(self, True, args, sym_rate, sps, freq, gain, antenna) self.connect(self, self.u) @@ -141,8 +141,8 @@ class uhd_transmitter(uhd_interface, gr.hier_block2): def add_options(parser): add_freq_option(parser) - parser.add_option("-a", "--address", type="string", default="addr=192.168.10.2", - help="Address of UHD device, [default=%default]") + parser.add_option("-a", "--args", type="string", default="", + help="UHD device address args [default=%default]") parser.add_option("-A", "--antenna", type="string", default=None, help="select Rx Antenna where appropriate") parser.add_option("", "--tx-freq", type="eng_float", default=None, @@ -160,7 +160,7 @@ class uhd_transmitter(uhd_interface, gr.hier_block2): Prints information about the UHD transmitter """ print "\nUHD Transmitter:" - print "Address: %s" % (self._addr) + print "Args: %s" % (self._args) print "Freq: %sHz" % (eng_notation.num_to_str(self._freq)) print "Gain: %f dB" % (self._gain) print "Sample Rate: %ssps" % (eng_notation.num_to_str(self._rate)) @@ -174,14 +174,14 @@ class uhd_transmitter(uhd_interface, gr.hier_block2): class uhd_receiver(uhd_interface, gr.hier_block2): - def __init__(self, address, bitrate, sps, freq=None, gain=None, + def __init__(self, args, sym_rate, sps, freq=None, gain=None, antenna=None, verbose=False): gr.hier_block2.__init__(self, "uhd_receiver", gr.io_signature(0,0,0), gr.io_signature(1,1,gr.sizeof_gr_complex)) # Set up the UHD interface as a receiver - uhd_interface.__init__(self, False, address, bitrate, sps, + uhd_interface.__init__(self, False, args, sym_rate, sps, freq, gain, antenna) self.connect(self.u, self) @@ -191,8 +191,8 @@ class uhd_receiver(uhd_interface, gr.hier_block2): def add_options(parser): add_freq_option(parser) - parser.add_option("-a", "--address", type="string", default="addr=192.168.10.2", - help="Address of UHD device, [default=%default]") + parser.add_option("-a", "--args", type="string", default="", + help="UHD device address args [default=%default]") parser.add_option("-A", "--antenna", type="string", default=None, help="select Rx Antenna where appropriate") parser.add_option("", "--rx-freq", type="eng_float", default=None, @@ -211,7 +211,7 @@ class uhd_receiver(uhd_interface, gr.hier_block2): Prints information about the UHD transmitter """ print "\nUHD Receiver:" - print "Address: %s" % (self._addr) + print "UHD Args: %s" % (self._args) print "Freq: %sHz" % (eng_notation.num_to_str(self._freq)) print "Gain: %f dB" % (self._gain) print "Sample Rate: %ssps" % (eng_notation.num_to_str(self._rate)) |