diff options
Diffstat (limited to 'gr-digital')
-rw-r--r-- | gr-digital/examples/Makefile.am | 6 | ||||
-rw-r--r-- | gr-digital/examples/README | 153 | ||||
-rwxr-xr-x | gr-digital/examples/benchmark_rx.py | 2 | ||||
-rwxr-xr-x | gr-digital/examples/digital_bert_rx.py | 209 | ||||
-rwxr-xr-x | gr-digital/examples/digital_bert_tx.py | 135 | ||||
-rwxr-xr-x | gr-digital/examples/rx_voice.py | 31 | ||||
-rwxr-xr-x | gr-digital/examples/tunnel.py | 283 | ||||
-rwxr-xr-x | gr-digital/examples/tx_voice.py | 33 | ||||
-rw-r--r-- | gr-digital/examples/uhd_interface.py | 6 | ||||
-rw-r--r-- | gr-digital/python/Makefile.am | 1 | ||||
-rw-r--r-- | gr-digital/python/d8psk.py | 372 | ||||
-rw-r--r-- | gr-digital/python/dbpsk.py | 372 | ||||
-rw-r--r-- | gr-digital/python/dqpsk.py | 376 | ||||
-rw-r--r-- | gr-digital/python/generic_mod_demod.py | 2 | ||||
-rw-r--r-- | gr-digital/python/gmsk.py | 18 | ||||
-rw-r--r-- | gr-digital/python/modulation_utils.py | 81 |
16 files changed, 848 insertions, 1232 deletions
diff --git a/gr-digital/examples/Makefile.am b/gr-digital/examples/Makefile.am index 4f745f3a9..dc8aba6ca 100644 --- a/gr-digital/examples/Makefile.am +++ b/gr-digital/examples/Makefile.am @@ -37,6 +37,8 @@ dist_ourdata_SCRIPTS = \ tx_voice.py \ rx_voice.py \ run_length.py \ - gen_whitener.py - + gen_whitener.py \ + digital_bert_rx.py \ + digital_bert_tx.py \ + tunnel.py diff --git a/gr-digital/examples/README b/gr-digital/examples/README new file mode 100644 index 000000000..1c50ad69b --- /dev/null +++ b/gr-digital/examples/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/benchmark_rx.py b/gr-digital/examples/benchmark_rx.py index 7eb4fb9b4..c586cc8fe 100755 --- a/gr-digital/examples/benchmark_rx.py +++ b/gr-digital/examples/benchmark_rx.py @@ -44,7 +44,7 @@ class my_top_block(gr.top_block): def __init__(self, demodulator, rx_callback, options): gr.top_block.__init__(self) - if(options.tx_freq is not None): + if(options.rx_freq is not None): self.source = uhd_receiver(options.address, options.bitrate, options.samples_per_symbol, options.rx_freq, options.rx_gain, diff --git a/gr-digital/examples/digital_bert_rx.py b/gr-digital/examples/digital_bert_rx.py new file mode 100755 index 000000000..9ee1f5ee8 --- /dev/null +++ b/gr-digital/examples/digital_bert_rx.py @@ -0,0 +1,209 @@ +#!/usr/bin/env python +# +# Copyright 2008,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 +from optparse import OptionParser +from gnuradio.eng_option import eng_option +import gnuradio.gr.gr_threading as _threading +import sys, time, math + +from gnuradio import digital + +# from current dir +from uhd_interface import uhd_receiver + +n2s = eng_notation.num_to_str + +class status_thread(_threading.Thread): + def __init__(self, tb): + _threading.Thread.__init__(self) + self.setDaemon(1) + self.tb = tb + self.done = False + self.start() + + def run(self): + while not self.done: + print "Freq. Offset: {0:5.0f} Hz Timing Offset: {1:10.1f} ppm Estimated SNR: {2:4.1f} dB BER: {3:g}".format( + tb.frequency_offset(), tb.timing_offset()*1e6, tb.snr(), tb.ber()) + try: + time.sleep(1.0) + except KeyboardInterrupt: + self.done = True + + + +class bert_receiver(gr.hier_block2): + def __init__(self, bitrate, + constellation, samples_per_symbol, + differential, excess_bw, gray_coded, + freq_bw, timing_bw, phase_bw, + verbose, log): + + gr.hier_block2.__init__(self, "bert_receive", + gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature + gr.io_signature(0, 0, 0)) # Output signature + + self._bitrate = bitrate + + self._demod = digital.generic_demod(constellation, samples_per_symbol, + differential, excess_bw, gray_coded, + freq_bw, timing_bw, phase_bw, + verbose, log) + + self._symbol_rate = self._bitrate * self._demod.bits_per_symbol() + self._sample_rate = self._symbol_rate * samples_per_symbol + + # Add an SNR probe on the demodulated constellation + self._snr_probe = gr.probe_mpsk_snr_c(10.0/self._symbol_rate) + self.connect(self._demod.time_recov, self._snr_probe) + + # Descramble BERT sequence. A channel error will create 3 incorrect bits + self._descrambler = gr.descrambler_bb(0x8A, 0x7F, 7) # CCSDS 7-bit descrambler + + # Measure BER by the density of 0s in the stream + self._ber = gr.probe_density_b(1.0/self._symbol_rate) + + self.connect(self, self._demod, self._descrambler, self._ber) + + def frequency_offset(self): + return self._demod.freq_recov.get_frequency()*self._sample_rate/(2*math.pi) + + def timing_offset(self): + return self._demod.time_recov.get_clock_rate() + + def snr(self): + return self._snr_probe.snr() + + def ber(self): + return (1.0-self._ber.density())/3.0 + + + +class rx_psk_block(gr.top_block): + def __init__(self, demod, options): + + gr.top_block.__init__(self, "rx_mpsk") + + self._demodulator_class = demod + + # Get demod_kwargs + demod_kwargs = self._demodulator_class.extract_kwargs_from_options(options) + + # demodulator + self._demodulator = self._demodulator_class(**demod_kwargs) + + if(options.rx_freq is not None): + self._source = uhd_receiver(options.address, options.bitrate, + options.samples_per_symbol, + options.rx_freq, options.rx_gain, + options.antenna, options.verbose) + options.samples_per_symbol = self._source._sps + + elif(options.from_file is not None): + self._source = gr.file_source(gr.sizeof_gr_complex, options.from_file) + else: + self._source = gr.null_source(gr.sizeof_gr_complex) + + # Create the BERT receiver + self._receiver = bert_receiver(options.bitrate, + self._demodulator._constellation, + options.samples_per_symbol, + options.differential, + options.excess_bw, + gray_coded=True, + freq_bw=options.freq_bw, + timing_bw=options.timing_bw, + phase_bw=options.phase_bw, + verbose=options.verbose, + log=options.log) + + self.connect(self._source, self._receiver) + + def snr(self): + return self._receiver.snr() + + def mag(self): + return self._receiver.signal_mean() + + def var(self): + return self._receiver.noise_variance() + + def ber(self): + return self._receiver.ber() + + def frequency_offset(self): + return self._receiver.frequency_offset() + + def timing_offset(self): + return self._receiver.timing_offset() + + +def get_options(demods): + parser = OptionParser(option_class=eng_option, conflict_handler="resolve") + parser.add_option("","--from-file", default=None, + help="input file of samples to demod") + parser.add_option("-m", "--modulation", type="choice", choices=demods.keys(), + default='psk', + help="Select modulation from: %s [default=%%default]" + % (', '.join(demods.keys()),)) + parser.add_option("-r", "--bitrate", type="eng_float", default=250e3, + help="Select modulation bit rate (default=%default)") + parser.add_option("-S", "--samples-per-symbol", type="float", default=2, + help="set samples/symbol [default=%default]") + if not parser.has_option("--verbose"): + parser.add_option("-v", "--verbose", action="store_true", default=False) + if not parser.has_option("--log"): + parser.add_option("", "--log", action="store_true", default=False, + help="Log all parts of flow graph to files (CAUTION: lots of data)") + + uhd_receiver.add_options(parser) + + demods = digital.modulation_utils2.type_1_demods() + for mod in demods.values(): + mod.add_options(parser) + + (options, args) = parser.parse_args() + if len(args) != 0: + parser.print_help() + sys.exit(1) + + return (options, args) + + +if __name__ == "__main__": + demods = digital.modulation_utils2.type_1_demods() + + (options, args) = get_options(demods) + + demod = demods[options.modulation] + tb = rx_psk_block(demod, options) + + print "\n*** SNR estimator is inaccurate below about 7dB" + print "*** BER estimator is inaccurate above about 10%\n" + updater = status_thread(tb) + + try: + tb.run() + except KeyboardInterrupt: + updater.done = True + updater = None diff --git a/gr-digital/examples/digital_bert_tx.py b/gr-digital/examples/digital_bert_tx.py new file mode 100755 index 000000000..6b544c7f7 --- /dev/null +++ b/gr-digital/examples/digital_bert_tx.py @@ -0,0 +1,135 @@ +#!/usr/bin/env python +# +# Copyright 2008,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 +from gnuradio.eng_option import eng_option +from optparse import OptionParser +import sys + +from gnuradio import digital + +# from current dir +from uhd_interface import uhd_transmitter + +n2s = eng_notation.num_to_str + +class bert_transmit(gr.hier_block2): + def __init__(self, constellation, samples_per_symbol, + differential, excess_bw, gray_coded, + verbose, log): + + gr.hier_block2.__init__(self, "bert_transmit", + gr.io_signature(0, 0, 0), # Output signature + gr.io_signature(1, 1, gr.sizeof_gr_complex)) # Input signature + + # Create BERT data bit stream + self._bits = gr.vector_source_b([1,], True) # Infinite stream of ones + self._scrambler = gr.scrambler_bb(0x8A, 0x7F, 7) # CCSDS 7-bit scrambler + + self._mod = digital.generic_mod(constellation, samples_per_symbol, + differential, excess_bw, gray_coded, + verbose, log) + + self._pack = gr.unpacked_to_packed_bb(self._mod.bits_per_symbol(), gr.GR_MSB_FIRST) + + self.connect(self._bits, self._scrambler, self._pack, self._mod, self) + + +class tx_psk_block(gr.top_block): + def __init__(self, mod, options): + gr.top_block.__init__(self, "tx_mpsk") + + self._modulator_class = mod + + # Get mod_kwargs + mod_kwargs = self._modulator_class.extract_kwargs_from_options(options) + + # transmitter + self._modulator = self._modulator_class(**mod_kwargs) + + if(options.tx_freq is not None): + self._sink = uhd_transmitter(options.address, options.bitrate, + options.samples_per_symbol, + options.tx_freq, options.tx_gain, + options.antenna, options.verbose) + options.samples_per_symbol = self._sink._sps + + elif(options.to_file is not None): + self._sink = gr.file_sink(gr.sizeof_gr_complex, options.to_file) + else: + self._sink = gr.null_sink(gr.sizeof_gr_complex) + + + self._transmitter = bert_transmit(self._modulator._constellation, + options.samples_per_symbol, + options.differential, + options.excess_bw, + gray_coded=True, + verbose=options.verbose, + log=options.log) + + self.connect(self._transmitter, self._sink) + + +def get_options(mods): + parser = OptionParser(option_class=eng_option, conflict_handler="resolve") + parser.add_option("-m", "--modulation", type="choice", choices=mods.keys(), + default='psk', + help="Select modulation from: %s [default=%%default]" + % (', '.join(mods.keys()),)) + parser.add_option("", "--amplitude", type="eng_float", default=0.2, + help="set Tx amplitude (0-1) (default=%default)") + parser.add_option("-r", "--bitrate", type="eng_float", default=250e3, + help="Select modulation bit rate (default=%default)") + parser.add_option("-S", "--samples-per-symbol", type="float", default=2, + help="set samples/symbol [default=%default]") + parser.add_option("","--to-file", default=None, + help="Output file for modulated samples") + if not parser.has_option("--verbose"): + parser.add_option("-v", "--verbose", action="store_true", default=False) + if not parser.has_option("--log"): + parser.add_option("", "--log", action="store_true", default=False) + + uhd_transmitter.add_options(parser) + + for mod in mods.values(): + mod.add_options(parser) + + (options, args) = parser.parse_args() + if len(args) != 0: + parser.print_help() + sys.exit(1) + + return (options, args) + +if __name__ == "__main__": + mods = digital.modulation_utils2.type_1_mods() + + (options, args) = get_options(mods) + + mod = mods[options.modulation] + tb = tx_psk_block(mod, options) + + try: + tb.run() + except KeyboardInterrupt: + pass diff --git a/gr-digital/examples/rx_voice.py b/gr-digital/examples/rx_voice.py index d29d64ed6..b58704e16 100755 --- a/gr-digital/examples/rx_voice.py +++ b/gr-digital/examples/rx_voice.py @@ -20,17 +20,13 @@ # Boston, MA 02110-1301, USA. # -from gnuradio import gr -from gnuradio import uhd -from gnuradio import audio +from gnuradio import gr, blks2, audio, uhd from gnuradio import eng_notation from gnuradio.eng_option import eng_option from optparse import OptionParser -from gnuradio.vocoder import gsm_full_rate - -# From gr-digital from gnuradio import digital +from gnuradio import vocoder import random import struct @@ -38,6 +34,7 @@ import sys # from current dir from receive_path import receive_path +from uhd_interface import uhd_receiver #import os #print os.getpid() @@ -50,9 +47,9 @@ class audio_tx(gr.hier_block2): gr.io_signature(0, 0, 0), # Input signature gr.io_signature(0, 0, 0)) # Output signature - sample_rate = 8000 + self.sample_rate = sample_rate = 8000 self.packet_src = gr.message_source(33) - voice_decoder = gsm_full_rate.decode_ps() + voice_decoder = vocoder.gsm_fr_decode_ps() s2f = gr.short_to_float () sink_scale = gr.multiply_const_ff(1.0/32767.) audio_sink = audio.sink(sample_rate, audio_output_dev) @@ -68,10 +65,25 @@ class my_top_block(gr.top_block): self.rxpath = receive_path(demod_class, rx_callback, options) self.audio_tx = audio_tx(options.audio_output) - if(options.from_file is not None): + if(options.rx_freq is not None): + self.source = uhd_receiver(options.address, options.bitrate, + options.samples_per_symbol, + options.rx_freq, options.rx_gain, + options.antenna, options.verbose) + options.samples_per_symbol = self.source._sps + + audio_rate = self.audio_tx.sample_rate + usrp_rate = self.source.get_sample_rate() + rrate = audio_rate / usrp_rate + self.resampler = blks2.pfb_arb_resampler_ccf(rrate) + + self.connect(self.source, self.resampler, self.rxpath) + + elif(options.from_file is not None): self.thr = gr.throttle(gr.sizeof_gr_complex, options.bitrate) self.source = gr.file_source(gr.sizeof_gr_complex, options.from_file) self.connect(self.source, self.thr, self.rxpath) + else: self.thr = gr.throttle(gr.sizeof_gr_complex, 1e6) self.source = gr.null_source(gr.sizeof_gr_complex) @@ -117,6 +129,7 @@ def main(): parser.add_option("","--from-file", default=None, help="input file of samples to demod") receive_path.add_options(parser, expert_grp) + uhd_receiver.add_options(parser) for mod in demods.values(): mod.add_options(expert_grp) diff --git a/gr-digital/examples/tunnel.py b/gr-digital/examples/tunnel.py new file mode 100755 index 000000000..d25594df5 --- /dev/null +++ b/gr-digital/examples/tunnel.py @@ -0,0 +1,283 @@ +#!/usr/bin/env python +# +# Copyright 2005,2006,2009,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. +# + + +# //////////////////////////////////////////////////////////////////// +# +# This code sets up up a virtual ethernet interface (typically +# gr0), and relays packets between the interface and the GNU Radio +# PHY+MAC +# +# What this means in plain language, is that if you've got a couple +# of USRPs on different machines, and if you run this code on those +# machines, you can talk between them using normal TCP/IP +# networking. +# +# //////////////////////////////////////////////////////////////////// + + +from gnuradio import gr, digital, uhd +from gnuradio import eng_notation +from gnuradio.eng_option import eng_option +from optparse import OptionParser + +# from current dir +from receive_path import receive_path +from transmit_path import transmit_path +from uhd_interface import uhd_transmitter +from uhd_interface import uhd_receiver + +import os, sys +import random, time, struct + +#print os.getpid() +#raw_input('Attach and press enter') + +# //////////////////////////////////////////////////////////////////// +# +# Use the Universal TUN/TAP device driver to move packets to/from +# kernel +# +# See /usr/src/linux/Documentation/networking/tuntap.txt +# +# //////////////////////////////////////////////////////////////////// + +# Linux specific... +# TUNSETIFF ifr flags from <linux/tun_if.h> + +IFF_TUN = 0x0001 # tunnel IP packets +IFF_TAP = 0x0002 # tunnel ethernet frames +IFF_NO_PI = 0x1000 # don't pass extra packet info +IFF_ONE_QUEUE = 0x2000 # beats me ;) + +def open_tun_interface(tun_device_filename): + from fcntl import ioctl + + mode = IFF_TAP | IFF_NO_PI + TUNSETIFF = 0x400454ca + + tun = os.open(tun_device_filename, os.O_RDWR) + ifs = ioctl(tun, TUNSETIFF, struct.pack("16sH", "gr%d", mode)) + ifname = ifs[:16].strip("\x00") + return (tun, ifname) + + +# //////////////////////////////////////////////////////////////////// +# the flow graph +# //////////////////////////////////////////////////////////////////// + +class my_top_block(gr.top_block): + + def __init__(self, mod_class, demod_class, + rx_callback, options): + + gr.top_block.__init__(self) + + self.source = uhd_receiver(options.address, options.bitrate, + options.samples_per_symbol, + options.rx_freq, options.rx_gain, + options.antenna, options.verbose) + + self.sink = uhd_transmitter(options.address, options.bitrate, + options.samples_per_symbol, + options.tx_freq, options.tx_gain, + options.antenna, options.verbose) + + options.samples_per_symbol = self.source._sps + + self.txpath = transmit_path(mod_class, options) + self.rxpath = receive_path(demod_class, rx_callback, options) + self.connect(self.txpath, self.sink) + self.connect(self.source, self.rxpath) + + def send_pkt(self, payload='', eof=False): + return self.txpath.send_pkt(payload, eof) + + def carrier_sensed(self): + """ + Return True if the receive path thinks there's carrier + """ + return self.rxpath.carrier_sensed() + + +# //////////////////////////////////////////////////////////////////// +# Carrier Sense MAC +# //////////////////////////////////////////////////////////////////// + +class cs_mac(object): + """ + Prototype carrier sense MAC + + Reads packets from the TUN/TAP interface, and sends them to the + PHY. Receives packets from the PHY via phy_rx_callback, and sends + them into the TUN/TAP interface. + + Of course, we're not restricted to getting packets via TUN/TAP, + this is just an example. + """ + + def __init__(self, tun_fd, verbose=False): + self.tun_fd = tun_fd # file descriptor for TUN/TAP interface + self.verbose = verbose + self.tb = None # top block (access to PHY) + + def set_top_block(self, tb): + self.tb = tb + + def phy_rx_callback(self, ok, payload): + """ + Invoked by thread associated with PHY to pass received packet up. + + @param ok: bool indicating whether payload CRC was OK + @param payload: contents of the packet (string) + """ + if self.verbose: + print "Rx: ok = %r len(payload) = %4d" % (ok, len(payload)) + if ok: + os.write(self.tun_fd, payload) + + def main_loop(self): + """ + Main loop for MAC. + Only returns if we get an error reading from TUN. + + FIXME: may want to check for EINTR and EAGAIN and reissue read + """ + min_delay = 0.001 # seconds + + while 1: + payload = os.read(self.tun_fd, 10*1024) + if not payload: + self.tb.send_pkt(eof=True) + break + + if self.verbose: + print "Tx: len(payload) = %4d" % (len(payload),) + + delay = min_delay + while self.tb.carrier_sensed(): + sys.stderr.write('B') + time.sleep(delay) + if delay < 0.050: + delay = delay * 2 # exponential back-off + + self.tb.send_pkt(payload) + + +# ///////////////////////////////////////////////////////////////////////////// +# main +# ///////////////////////////////////////////////////////////////////////////// + +def main(): + + mods = digital.modulation_utils2.type_1_mods() + demods = digital.modulation_utils2.type_1_demods() + + parser = OptionParser (option_class=eng_option, conflict_handler="resolve") + expert_grp = parser.add_option_group("Expert") + parser.add_option("-m", "--modulation", type="choice", choices=mods.keys(), + default='gmsk', + help="Select modulation from: %s [default=%%default]" + % (', '.join(mods.keys()),)) + + parser.add_option("-s", "--size", type="eng_float", default=1500, + help="set packet size [default=%default]") + parser.add_option("-v","--verbose", action="store_true", default=False) + expert_grp.add_option("-c", "--carrier-threshold", type="eng_float", default=30, + help="set carrier detect threshold (dB) [default=%default]") + expert_grp.add_option("","--tun-device-filename", default="/dev/net/tun", + help="path to tun device file [default=%default]") + + transmit_path.add_options(parser, expert_grp) + receive_path.add_options(parser, expert_grp) + uhd_receiver.add_options(parser) + uhd_transmitter.add_options(parser) + + for mod in mods.values(): + mod.add_options(expert_grp) + + for demod in demods.values(): + demod.add_options(expert_grp) + + (options, args) = parser.parse_args () + if len(args) != 0: + parser.print_help(sys.stderr) + sys.exit(1) + + # open the TUN/TAP interface + (tun_fd, tun_ifname) = open_tun_interface(options.tun_device_filename) + + # 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" + + # instantiate the MAC + mac = cs_mac(tun_fd, verbose=True) + + # build the graph (PHY) + tb = my_top_block(mods[options.modulation], + demods[options.modulation], + mac.phy_rx_callback, + options) + + mac.set_top_block(tb) # give the MAC a handle for the PHY + + if tb.txpath.bitrate() != tb.rxpath.bitrate(): + print "WARNING: Transmit bitrate = %sb/sec, Receive bitrate = %sb/sec" % ( + eng_notation.num_to_str(tb.txpath.bitrate()), + eng_notation.num_to_str(tb.rxpath.bitrate())) + + print "modulation: %s" % (options.modulation,) + print "freq: %s" % (eng_notation.num_to_str(options.tx_freq)) + print "bitrate: %sb/sec" % (eng_notation.num_to_str(tb.txpath.bitrate()),) + print "samples/symbol: %3d" % (tb.txpath.samples_per_symbol(),) + + tb.rxpath.set_carrier_threshold(options.carrier_threshold) + print "Carrier sense threshold:", options.carrier_threshold, "dB" + + print + print "Allocated virtual ethernet interface: %s" % (tun_ifname,) + print "You must now use ifconfig to set its IP address. E.g.," + print + print " $ sudo ifconfig %s 192.168.200.1" % (tun_ifname,) + print + print "Be sure to use a different address in the same subnet for each machine." + print + + + tb.start() # Start executing the flow graph (runs in separate threads) + + mac.main_loop() # don't expect this to return... + + tb.stop() # but if it does, tell flow graph to stop. + tb.wait() # wait for it to finish + + +if __name__ == '__main__': + try: + main() + except KeyboardInterrupt: + pass diff --git a/gr-digital/examples/tx_voice.py b/gr-digital/examples/tx_voice.py index f4f2c3a86..eabb5e3c3 100755 --- a/gr-digital/examples/tx_voice.py +++ b/gr-digital/examples/tx_voice.py @@ -20,17 +20,13 @@ # Boston, MA 02110-1301, USA. # -from gnuradio import gr -from gnuradio import uhd -from gnuradio import audio +from gnuradio import gr, blks2, audio, uhd from gnuradio import eng_notation from gnuradio.eng_option import eng_option from optparse import OptionParser -from gnuradio.vocoder import gsm_full_rate - -# From gr-digital from gnuradio import digital +from gnuradio import vocoder import random import time @@ -39,6 +35,7 @@ import sys # from current dir from transmit_path import transmit_path +from uhd_interface import uhd_transmitter #import os #print os.getpid() @@ -50,11 +47,11 @@ class audio_rx(gr.hier_block2): gr.hier_block2.__init__(self, "audio_rx", gr.io_signature(0, 0, 0), # Input signature gr.io_signature(0, 0, 0)) # Output signature - sample_rate = 8000 + self.sample_rate = sample_rate = 8000 src = audio.source(sample_rate, audio_input_dev) src_scale = gr.multiply_const_ff(32767) f2s = gr.float_to_short() - voice_coder = gsm_full_rate.encode_sp() + voice_coder = vocoder.gsm_fr_encode_sp() self.packets_from_encoder = gr.msg_queue() packet_sink = gr.message_sink(33, self.packets_from_encoder, False) self.connect(src, src_scale, f2s, voice_coder, packet_sink) @@ -70,13 +67,27 @@ class my_top_block(gr.top_block): self.txpath = transmit_path(modulator_class, options) self.audio_rx = audio_rx(options.audio_input) - if(options.to_file is not None): + if(options.tx_freq is not None): + self.sink = uhd_transmitter(options.address, options.bitrate, + options.samples_per_symbol, + options.tx_freq, options.tx_gain, + options.antenna, options.verbose) + options.samples_per_symbol = self.sink._sps + audio_rate = self.audio_rx.sample_rate + usrp_rate = self.sink.get_sample_rate() + rrate = usrp_rate / audio_rate + + elif(options.to_file is not None): self.sink = gr.file_sink(gr.sizeof_gr_complex, options.to_file) + rrate = 1 else: self.sink = gr.null_sink(gr.sizeof_gr_complex) + rrate = 1 + self.resampler = blks2.pfb_arb_resampler_ccf(rrate) + self.connect(self.audio_rx) - self.connect(self.txpath, self.sink) + self.connect(self.txpath, self.resampler, self.sink) # ///////////////////////////////////////////////////////////////////////////// @@ -106,7 +117,9 @@ def main(): help="pcm input device name. E.g., hw:0,0 or /dev/dsp") parser.add_option("","--to-file", default=None, help="Output file for modulated samples") + transmit_path.add_options(parser, expert_grp) + uhd_transmitter.add_options(parser) for mod in mods.values(): mod.add_options(expert_grp) diff --git a/gr-digital/examples/uhd_interface.py b/gr-digital/examples/uhd_interface.py index 3e2162ba3..8420f3eec 100644 --- a/gr-digital/examples/uhd_interface.py +++ b/gr-digital/examples/uhd_interface.py @@ -90,6 +90,9 @@ class uhd_interface: return (actual_samp_rate, actual_sps) + def get_sample_rate(self): + return self.u.get_samp_rate() + def set_gain(self, gain=None): if gain is None: # if no gain was specified, use the mid-point in dB @@ -197,7 +200,8 @@ class uhd_receiver(uhd_interface, gr.hier_block2): metavar="FREQ") parser.add_option("", "--rx-gain", type="eng_float", default=None, help="set receive gain in dB (default is midpoint)") - parser.add_option("-v", "--verbose", action="store_true", default=False) + if not parser.has_option("--verbose"): + parser.add_option("-v", "--verbose", action="store_true", default=False) # Make a static method to call before instantiation add_options = staticmethod(add_options) diff --git a/gr-digital/python/Makefile.am b/gr-digital/python/Makefile.am index a33e4963d..cd98fe2d4 100644 --- a/gr-digital/python/Makefile.am +++ b/gr-digital/python/Makefile.am @@ -53,7 +53,6 @@ digital_PYTHON = \ crc.py \ generic_mod_demod.py \ gmsk.py \ - modulation_utils.py \ modulation_utils2.py \ packet_utils.py \ pkt.py \ diff --git a/gr-digital/python/d8psk.py b/gr-digital/python/d8psk.py deleted file mode 100644 index 46290faed..000000000 --- a/gr-digital/python/d8psk.py +++ /dev/null @@ -1,372 +0,0 @@ -# -# Copyright 2005,2006,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. -# - -# See gnuradio-examples/python/digital for examples - -""" -differential 8PSK modulation and demodulation. -""" - -from gnuradio import gr, modulation_utils2 -from math import pi, sqrt -import digital_swig, psk -import cmath -from pprint import pprint - -# default values (used in __init__ and add_options) -_def_samples_per_symbol = 3 -_def_excess_bw = 0.35 -_def_gray_code = True -_def_verbose = False -_def_log = False - -_def_freq_alpha = 0.010 -_def_phase_damping = 0.4 -_def_phase_natfreq = 0.25 -_def_timing_alpha = 0.100 -_def_timing_beta = 0.010 -_def_timing_max_dev = 1.5 - -# ///////////////////////////////////////////////////////////////////////////// -# D8PSK modulator -# ///////////////////////////////////////////////////////////////////////////// - -class d8psk_mod(gr.hier_block2): - - def __init__(self, - samples_per_symbol=_def_samples_per_symbol, - excess_bw=_def_excess_bw, - gray_code=_def_gray_code, - verbose=_def_verbose, - log=_def_log): - """ - Hierarchical block for RRC-filtered differential 8PSK modulation. - - The input is a byte stream (unsigned char) and the - output is the complex modulated signal at baseband. - - @param samples_per_symbol: samples per symbol >= 2 - @type samples_per_symbol: integer - @param excess_bw: Root-raised cosine filter excess bandwidth - @type excess_bw: float - @param gray_code: Tell modulator to Gray code the bits - @type gray_code: bool - @param verbose: Print information about modulator? - @type verbose: bool - @param log: Log modulation data to files? - @type log: bool - """ - - gr.hier_block2.__init__(self, "d8psk_mod", - gr.io_signature(1, 1, gr.sizeof_char), # Input signature - gr.io_signature(1, 1, gr.sizeof_gr_complex)) # Output signature - - self._samples_per_symbol = samples_per_symbol - self._excess_bw = excess_bw - self._gray_code = gray_code - - if not isinstance(samples_per_symbol, int) or samples_per_symbol < 2: - raise TypeError, ("sbp must be an integer >= 2, is %d" % samples_per_symbol) - - arity = pow(2,self.bits_per_symbol()) - - # turn bytes into k-bit vectors - self.bytes2chunks = \ - gr.packed_to_unpacked_bb(self.bits_per_symbol(), gr.GR_MSB_FIRST) - - if self._gray_code: - self.symbol_mapper = gr.map_bb(psk.binary_to_gray[arity]) - else: - self.symbol_mapper = gr.map_bb(psk.binary_to_ungray[arity]) - - self.diffenc = gr.diff_encoder_bb(arity) - - rot = 1 - rotated_const = map(lambda pt: pt * rot, psk.constellation[arity]) - self.chunks2symbols = gr.chunks_to_symbols_bc(rotated_const) - - # pulse shaping filter - nfilts = 32 - ntaps = 11 * int(nfilts * self._samples_per_symbol) # make nfilts filters of ntaps each - self.rrc_taps = gr.firdes.root_raised_cosine( - nfilts, # gain - nfilts, # sampling rate based on 32 filters in resampler - 1.0, # symbol rate - self._excess_bw, # excess bandwidth (roll-off factor) - ntaps) - self.rrc_filter = gr.pfb_arb_resampler_ccf(self._samples_per_symbol, self.rrc_taps) - - if verbose: - self._print_verbage() - - if log: - self._setup_logging() - - # Connect & Initialize base class - self.connect(self, self.bytes2chunks, self.symbol_mapper, self.diffenc, - self.chunks2symbols, self.rrc_filter, self) - - def samples_per_symbol(self): - return self._samples_per_symbol - - def bits_per_symbol(self=None): # staticmethod that's also callable on an instance - return 3 - bits_per_symbol = staticmethod(bits_per_symbol) # make it a static method. RTFM - - def _print_verbage(self): - print "\nModulator:" - print "bits per symbol: %d" % self.bits_per_symbol() - print "Gray code: %s" % self._gray_code - print "RRC roll-off factor: %f" % self._excess_bw - - def _setup_logging(self): - print "Modulation logging turned on." - self.connect(self.bytes2chunks, - gr.file_sink(gr.sizeof_char, "tx_bytes2chunks.dat")) - self.connect(self.symbol_mapper, - gr.file_sink(gr.sizeof_char, "tx_graycoder.dat")) - self.connect(self.diffenc, - gr.file_sink(gr.sizeof_char, "tx_diffenc.dat")) - self.connect(self.chunks2symbols, - gr.file_sink(gr.sizeof_gr_complex, "tx_chunks2symbols.dat")) - self.connect(self.rrc_filter, - gr.file_sink(gr.sizeof_gr_complex, "tx_rrc_filter.dat")) - - def add_options(parser): - """ - Adds 8PSK modulation-specific options to the standard parser - """ - parser.add_option("", "--excess-bw", type="float", default=_def_excess_bw, - help="set RRC excess bandwith factor [default=%default] (PSK)") - parser.add_option("", "--no-gray-code", dest="gray_code", - action="store_false", default=_def_gray_code, - help="disable gray coding on modulated bits (PSK)") - add_options=staticmethod(add_options) - - - def extract_kwargs_from_options(options): - """ - Given command line options, create dictionary suitable for passing to __init__ - """ - return modulation_utils2.extract_kwargs_from_options(d8psk_mod.__init__, - ('self',), options) - extract_kwargs_from_options=staticmethod(extract_kwargs_from_options) - - -# ///////////////////////////////////////////////////////////////////////////// -# D8PSK demodulator -# -# Differentially coherent detection of differentially encoded 8psk -# ///////////////////////////////////////////////////////////////////////////// - -class d8psk_demod(gr.hier_block2): - - def __init__(self, - samples_per_symbol=_def_samples_per_symbol, - excess_bw=_def_excess_bw, - freq_alpha=_def_freq_alpha, - phase_damping=_def_phase_damping, - phase_natfreq=_def_phase_natfreq, - timing_alpha=_def_timing_alpha, - timing_max_dev=_def_timing_max_dev, - gray_code=_def_gray_code, - verbose=_def_verbose, - log=_def_log, - sync_out=False): - """ - Hierarchical block for RRC-filtered DQPSK demodulation - - The input is the complex modulated signal at baseband. - The output is a stream of bits packed 1 bit per byte (LSB) - - @param samples_per_symbol: samples per symbol >= 2 - @type samples_per_symbol: float - @param excess_bw: Root-raised cosine filter excess bandwidth - @type excess_bw: float - @param freq_alpha: loop filter gain for frequency recovery - @type freq_alpha: float - @param phase_damping: loop filter damping factor for phase/fine frequency recovery - @type phase_damping: float - @param phase_natfreq: loop filter natural frequency for phase/fine frequency recovery - @type phase_natfreq: float - @param timing_alpha: timing loop alpha gain - @type timing_alpha: float - @param timing_max: timing loop maximum rate deviations - @type timing_max: float - @param gray_code: Tell modulator to Gray code the bits - @type gray_code: bool - @param verbose: Print information about modulator? - @type verbose: bool - @param debug: Print modualtion data to files? - @type debug: bool - """ - if sync_out: io_sig_out = gr.io_signaturev(2, 2, (gr.sizeof_char, gr.sizeof_gr_complex)) - else: io_sig_out = gr.io_signature(1, 1, gr.sizeof_char) - - gr.hier_block2.__init__(self, "d8psk_demod", - gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature - io_sig_out) # Output signature - - self._samples_per_symbol = samples_per_symbol - self._excess_bw = excess_bw - self._freq_alpha = freq_alpha - self._freq_beta = 0.25*self._freq_alpha**2 - self._phase_damping = phase_damping - self._phase_natfreq = phase_natfreq - self._timing_alpha = timing_alpha - self._timing_beta = _def_timing_beta - self._timing_max_dev=timing_max_dev - self._gray_code = gray_code - - if samples_per_symbol < 2: - raise TypeError, "sbp must be >= 2, is %d" % samples_per_symbol - - arity = pow(2,self.bits_per_symbol()) - - # Automatic gain control - self.agc = gr.agc2_cc(0.6e-1, 1e-3, 1, 1, 100) - #self.agc = gr.feedforward_agc_cc(16, 2.0) - - # Frequency correction - self.freq_recov = gr.fll_band_edge_cc(self._samples_per_symbol, self._excess_bw, - 11*int(self._samples_per_symbol), - self._freq_alpha, self._freq_beta) - - # symbol timing recovery with RRC data filter - nfilts = 32 - ntaps = 11 * int(samples_per_symbol*nfilts) - taps = gr.firdes.root_raised_cosine(1.41*nfilts, nfilts, - 1.0/float(self._samples_per_symbol), - self._excess_bw, ntaps) - self.time_recov = gr.pfb_clock_sync_ccf(self._samples_per_symbol, - self._timing_alpha, - taps, nfilts, nfilts/2, self._timing_max_dev) - self.time_recov.set_beta(self._timing_beta) - - # Perform phase / fine frequency correction - self.phase_recov = digital_swig.costas_loop_cc(self._phase_damping, - self._phase_natfreq, - arity) - - # Perform Differential decoding on the constellation - self.diffdec = gr.diff_phasor_cc() - - # find closest constellation point - rot = cmath.exp(1j*cmath.pi/8.0) - rotated_const = map(lambda pt: pt * rot, psk.constellation[arity]) - self.slicer = gr.constellation_decoder_cb(rotated_const, range(arity)) - - if self._gray_code: - self.symbol_mapper = gr.map_bb(psk.gray_to_binary[arity]) - else: - self.symbol_mapper = gr.map_bb(psk.ungray_to_binary[arity]) - - # unpack the k bit vector into a stream of bits - self.unpack = gr.unpack_k_bits_bb(self.bits_per_symbol()) - - if verbose: - self._print_verbage() - - if log: - self._setup_logging() - - # Connect - self.connect(self, self.agc, - self.freq_recov, self.time_recov, self.phase_recov, - self.diffdec, self.slicer, self.symbol_mapper, self.unpack, self) - if sync_out: self.connect(self.phase_recov, (self, 1)) - - def samples_per_symbol(self): - return self._samples_per_symbol - - def bits_per_symbol(self=None): # staticmethod that's also callable on an instance - return 3 - bits_per_symbol = staticmethod(bits_per_symbol) # make it a static method. RTFM - - def _print_verbage(self): - print "\nDemodulator:" - print "bits per symbol: %d" % self.bits_per_symbol() - print "Gray code: %s" % self._gray_code - print "RRC roll-off factor: %.2f" % self._excess_bw - print "FLL gain: %.2f" % self._freq_alpha - print "Timing alpha gain: %.2f" % self._timing_alpha - print "Timing beta gain: %.2f" % self._timing_beta - print "Timing max dev: %.2f" % self._timing_max_dev - print "Phase damping fact: %.2e" % self._phase_damping - print "Phase natural freq: %.2e" % self._phase_natfreq - - - def _setup_logging(self): - print "Modulation logging turned on." - self.connect(self.agc, - gr.file_sink(gr.sizeof_gr_complex, "rx_agc.dat")) - self.connect(self.freq_recov, - gr.file_sink(gr.sizeof_gr_complex, "rx_freq_recov.dat")) - self.connect(self.time_recov, - gr.file_sink(gr.sizeof_gr_complex, "rx_time_recov.dat")) - self.connect(self.phase_recov, - gr.file_sink(gr.sizeof_gr_complex, "rx_phase_recov.dat")) - self.connect(self.diffdec, - gr.file_sink(gr.sizeof_gr_complex, "rx_diffdec.dat")) - self.connect(self.slicer, - gr.file_sink(gr.sizeof_char, "rx_slicer.dat")) - self.connect(self.symbol_mapper, - gr.file_sink(gr.sizeof_char, "rx_gray_decoder.dat")) - self.connect(self.unpack, - gr.file_sink(gr.sizeof_char, "rx_unpack.dat")) - - def add_options(parser): - """ - Adds D8PSK demodulation-specific options to the standard parser - """ - parser.add_option("", "--excess-bw", type="float", default=_def_excess_bw, - help="set RRC excess bandwith factor [default=%default] (PSK)") - parser.add_option("", "--no-gray-code", dest="gray_code", - action="store_false", default=_def_gray_code, - help="disable gray coding on modulated bits (PSK)") - parser.add_option("", "--freq-alpha", type="float", default=_def_freq_alpha, - help="set frequency lock loop alpha gain value [default=%default] (PSK)") - parser.add_option("", "--phase-natfreq", type="float", default=_def_phase_natfreq, - help="set natural frequency of phase tracking loop [default=%default] (PSK)") - parser.add_option("", "--phase-damping", type="float", default=_def_phase_damping, - help="set damping factor of phase tracking loop [default=%default] (PSK)") - parser.add_option("", "--timing-alpha", type="float", default=_def_timing_alpha, - help="set timing symbol sync loop gain alpha value [default=%default] (GMSK/PSK)") - parser.add_option("", "--timing-beta", type="float", default=_def_timing_beta, - help="set timing symbol sync loop gain beta value [default=%default] (GMSK/PSK)") - parser.add_option("", "--timing-max-dev", type="float", default=_def_timing_max_dev, - help="set timing symbol sync loop maximum deviation [default=%default] (GMSK/PSK)") - add_options=staticmethod(add_options) - - def extract_kwargs_from_options(options): - """ - Given command line options, create dictionary suitable for passing to __init__ - """ - return modulation_utils2.extract_kwargs_from_options( - d8psk_demod.__init__, ('self',), options) - extract_kwargs_from_options=staticmethod(extract_kwargs_from_options) - - -# -# Add these to the mod/demod registry -# -modulation_utils2.add_type_1_mod('d8psk', d8psk_mod) -modulation_utils2.add_type_1_demod('d8psk', d8psk_demod) diff --git a/gr-digital/python/dbpsk.py b/gr-digital/python/dbpsk.py deleted file mode 100644 index 9e065263f..000000000 --- a/gr-digital/python/dbpsk.py +++ /dev/null @@ -1,372 +0,0 @@ -# -# Copyright 2009,2010,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. -# - -# See gnuradio-examples/python/digital for examples - -""" -differential BPSK modulation and demodulation. -""" - -from gnuradio import gr, modulation_utils2 -from math import pi, sqrt, ceil -import digital_swig, psk -import cmath -from pprint import pprint - -# default values (used in __init__ and add_options) -_def_samples_per_symbol = 2 -_def_excess_bw = 0.35 -_def_gray_code = True -_def_verbose = False -_def_log = False - -_def_freq_alpha = 0.010 -_def_phase_damping = 0.4 -_def_phase_natfreq = 0.25 -_def_timing_alpha = 0.100 -_def_timing_beta = 0.010 -_def_timing_max_dev = 1.5 - - -# ///////////////////////////////////////////////////////////////////////////// -# DBPSK modulator -# ///////////////////////////////////////////////////////////////////////////// - -class dbpsk_mod(gr.hier_block2): - - def __init__(self, - samples_per_symbol=_def_samples_per_symbol, - excess_bw=_def_excess_bw, - gray_code=_def_gray_code, - verbose=_def_verbose, - log=_def_log): - """ - Hierarchical block for RRC-filtered differential BPSK modulation. - - The input is a byte stream (unsigned char) and the - output is the complex modulated signal at baseband. - - @param samples_per_symbol: samples per symbol >= 2 - @type samples_per_symbol: integer - @param excess_bw: Root-raised cosine filter excess bandwidth - @type excess_bw: float - @param gray_code: Tell modulator to Gray code the bits - @type gray_code: bool - @param verbose: Print information about modulator? - @type verbose: bool - @param log: Log modulation data to files? - @type log: bool - """ - - gr.hier_block2.__init__(self, "dbpsk_mod", - gr.io_signature(1, 1, gr.sizeof_char), # Input signature - gr.io_signature(1, 1, gr.sizeof_gr_complex)) # Output signature - - self._samples_per_symbol = samples_per_symbol - self._excess_bw = excess_bw - self._gray_code = gray_code - - if self._samples_per_symbol < 2: - raise TypeError, ("sbp must be an integer >= 2, is %d" % self._samples_per_symbol) - - arity = pow(2,self.bits_per_symbol()) - - # turn bytes into k-bit vectors - self.bytes2chunks = \ - gr.packed_to_unpacked_bb(self.bits_per_symbol(), gr.GR_MSB_FIRST) - - if self._gray_code: - self.symbol_mapper = gr.map_bb(psk.binary_to_gray[arity]) - else: - self.symbol_mapper = gr.map_bb(psk.binary_to_ungray[arity]) - - self.diffenc = gr.diff_encoder_bb(arity) - - - self.chunks2symbols = gr.chunks_to_symbols_bc(psk.constellation[arity]) - - # pulse shaping filter - nfilts = 32 - ntaps = nfilts * 11 * int(self._samples_per_symbol) # make nfilts filters of ntaps each - self.rrc_taps = gr.firdes.root_raised_cosine( - nfilts, # gain - nfilts, # sampling rate based on 32 filters in resampler - 1.0, # symbol rate - self._excess_bw, # excess bandwidth (roll-off factor) - ntaps) - self.rrc_filter = gr.pfb_arb_resampler_ccf(self._samples_per_symbol, self.rrc_taps) - - # Connect - self.connect(self, self.bytes2chunks, self.symbol_mapper, self.diffenc, - self.chunks2symbols, self.rrc_filter, self) - - if verbose: - self._print_verbage() - - if log: - self._setup_logging() - - - def samples_per_symbol(self): - return self._samples_per_symbol - - def bits_per_symbol(self=None): # static method that's also callable on an instance - return 1 - bits_per_symbol = staticmethod(bits_per_symbol) # make it a static method. RTFM - - def add_options(parser): - """ - Adds DBPSK modulation-specific options to the standard parser - """ - parser.add_option("", "--excess-bw", type="float", default=_def_excess_bw, - help="set RRC excess bandwith factor [default=%default]") - parser.add_option("", "--no-gray-code", dest="gray_code", - action="store_false", default=True, - help="disable gray coding on modulated bits (PSK)") - add_options=staticmethod(add_options) - - def extract_kwargs_from_options(options): - """ - Given command line options, create dictionary suitable for passing to __init__ - """ - return modulation_utils2.extract_kwargs_from_options(dbpsk_mod.__init__, - ('self',), options) - extract_kwargs_from_options=staticmethod(extract_kwargs_from_options) - - - def _print_verbage(self): - print "\nModulator:" - print "bits per symbol: %d" % self.bits_per_symbol() - print "Gray code: %s" % self._gray_code - print "RRC roll-off factor: %.2f" % self._excess_bw - - def _setup_logging(self): - print "Modulation logging turned on." - self.connect(self.bytes2chunks, - gr.file_sink(gr.sizeof_char, "tx_bytes2chunks.dat")) - self.connect(self.symbol_mapper, - gr.file_sink(gr.sizeof_char, "tx_graycoder.dat")) - self.connect(self.diffenc, - gr.file_sink(gr.sizeof_char, "tx_diffenc.dat")) - self.connect(self.chunks2symbols, - gr.file_sink(gr.sizeof_gr_complex, "tx_chunks2symbols.dat")) - self.connect(self.rrc_filter, - gr.file_sink(gr.sizeof_gr_complex, "tx_rrc_filter.dat")) - - -# ///////////////////////////////////////////////////////////////////////////// -# DBPSK demodulator -# -# Differentially coherent detection of differentially encoded BPSK -# ///////////////////////////////////////////////////////////////////////////// - -class dbpsk_demod(gr.hier_block2): - - def __init__(self, - samples_per_symbol=_def_samples_per_symbol, - excess_bw=_def_excess_bw, - freq_alpha=_def_freq_alpha, - phase_damping=_def_phase_damping, - phase_natfreq=_def_phase_natfreq, - timing_alpha=_def_timing_alpha, - timing_max_dev=_def_timing_max_dev, - gray_code=_def_gray_code, - verbose=_def_verbose, - log=_def_log, - sync_out=False): - """ - Hierarchical block for RRC-filtered differential BPSK demodulation - - The input is the complex modulated signal at baseband. - The output is a stream of bits packed 1 bit per byte (LSB) - - @param samples_per_symbol: samples per symbol >= 2 - @type samples_per_symbol: float - @param excess_bw: Root-raised cosine filter excess bandwidth - @type excess_bw: float - @param freq_alpha: loop filter gain for frequency recovery - @type freq_alpha: float - @param phase_damping: loop filter damping factor for phase/fine frequency recovery - @type phase_damping: float - @param phase_natfreq: loop filter natural frequency for phase/fine frequency recovery - @type phase_natfreq: float - @param timing_alpha: loop alpha gain for timing recovery - @type timing_alpha: float - @param timing_max: timing loop maximum rate deviations - @type timing_max: float - @param gray_code: Tell modulator to Gray code the bits - @type gray_code: bool - @param verbose: Print information about modulator? - @type verbose: bool - @param log: Print modualtion data to files? - @type log: bool - @param sync_out: Output a sync signal on :1? - @type sync_out: bool - """ - if sync_out: io_sig_out = gr.io_signaturev(2, 2, (gr.sizeof_char, gr.sizeof_gr_complex)) - else: io_sig_out = gr.io_signature(1, 1, gr.sizeof_char) - - gr.hier_block2.__init__(self, "dbpsk_demod", - gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature - io_sig_out) # Output signature - - self._samples_per_symbol = samples_per_symbol - self._excess_bw = excess_bw - self._freq_alpha = freq_alpha - self._freq_beta = 0.10*self._freq_alpha - self._phase_damping = phase_damping - self._phase_natfreq = phase_natfreq - self._timing_alpha = timing_alpha - self._timing_beta = _def_timing_beta - self._timing_max_dev=timing_max_dev - self._gray_code = gray_code - - if samples_per_symbol < 2: - raise TypeError, "samples_per_symbol must be >= 2, is %r" % (samples_per_symbol,) - - arity = pow(2,self.bits_per_symbol()) - - # Automatic gain control - self.agc = gr.agc2_cc(0.6e-1, 1e-3, 1, 1, 100) - #self.agc = gr.feedforward_agc_cc(16, 1.0) - - # Frequency correction - self.freq_recov = gr.fll_band_edge_cc(self._samples_per_symbol, self._excess_bw, - 11*int(self._samples_per_symbol), - self._freq_alpha, self._freq_beta) - - # symbol timing recovery with RRC data filter - nfilts = 32 - ntaps = 11 * int(self._samples_per_symbol*nfilts) - taps = gr.firdes.root_raised_cosine(nfilts, nfilts, - 1.0/float(self._samples_per_symbol), - self._excess_bw, ntaps) - self.time_recov = gr.pfb_clock_sync_ccf(self._samples_per_symbol, - self._timing_alpha, - taps, nfilts, nfilts/2, self._timing_max_dev) - self.time_recov.set_beta(self._timing_beta) - - # Perform phase / fine frequency correction - self.phase_recov = digital_swig.costas_loop_cc(self._phase_damping, - self._phase_natfreq, - arity) - - # Do differential decoding based on phase change of symbols - self.diffdec = gr.diff_phasor_cc() - - # find closest constellation point - const = digital_swig.constellation_bpsk() - self.slicer = digital_swig.constellation_decoder_cb(const.base()) - - if self._gray_code: - self.symbol_mapper = gr.map_bb(psk.gray_to_binary[arity]) - else: - self.symbol_mapper = gr.map_bb(psk.ungray_to_binary[arity]) - - # unpack the k bit vector into a stream of bits - self.unpack = gr.unpack_k_bits_bb(self.bits_per_symbol()) - - if verbose: - self._print_verbage() - - if log: - self._setup_logging() - - # Connect - self.connect(self, self.agc, - self.freq_recov, self.time_recov, self.phase_recov, - self.diffdec, self.slicer, self.symbol_mapper, self.unpack, self) - if sync_out: self.connect(self.phase_recov, (self, 1)) - - def samples_per_symbol(self): - return self._samples_per_symbol - - def bits_per_symbol(self=None): # staticmethod that's also callable on an instance - return 1 - bits_per_symbol = staticmethod(bits_per_symbol) # make it a static method. RTFM - - def _print_verbage(self): - print "\nDemodulator:" - print "bits per symbol: %d" % self.bits_per_symbol() - print "Gray code: %s" % self._gray_code - print "RRC roll-off factor: %.2f" % self._excess_bw - print "FLL gain: %.2e" % self._freq_alpha - print "Timing alpha gain: %.2e" % self._timing_alpha - print "Timing beta gain: %.2e" % self._timing_beta - print "Timing max dev: %.2f" % self._timing_max_dev - print "Phase damping fact: %.2e" % self._phase_damping - print "Phase natural freq: %.2e" % self._phase_natfreq - - def _setup_logging(self): - print "Modulation logging turned on." - self.connect(self.agc, - gr.file_sink(gr.sizeof_gr_complex, "rx_agc.dat")) - self.connect(self.freq_recov, - gr.file_sink(gr.sizeof_gr_complex, "rx_freq_recov.dat")) - self.connect(self.time_recov, - gr.file_sink(gr.sizeof_gr_complex, "rx_time_recov.dat")) - self.connect(self.phase_recov, - gr.file_sink(gr.sizeof_gr_complex, "rx_phase_recov.dat")) - self.connect(self.diffdec, - gr.file_sink(gr.sizeof_gr_complex, "rx_diffdec.dat")) - self.connect(self.slicer, - gr.file_sink(gr.sizeof_char, "rx_slicer.dat")) - self.connect(self.symbol_mapper, - gr.file_sink(gr.sizeof_char, "rx_symbol_mapper.dat")) - self.connect(self.unpack, - gr.file_sink(gr.sizeof_char, "rx_unpack.dat")) - - def add_options(parser): - """ - Adds DBPSK demodulation-specific options to the standard parser - """ - parser.add_option("", "--excess-bw", type="float", default=_def_excess_bw, - help="set RRC excess bandwith factor [default=%default] (PSK)") - parser.add_option("", "--no-gray-code", dest="gray_code", - action="store_false", default=_def_gray_code, - help="disable gray coding on modulated bits (PSK)") - parser.add_option("", "--freq-alpha", type="float", default=_def_freq_alpha, - help="set frequency lock loop alpha gain value [default=%default] (PSK)") - parser.add_option("", "--phase-natfreq", type="float", default=_def_phase_natfreq, - help="set natural frequency of phase tracking loop [default=%default] (PSK)") - parser.add_option("", "--phase-damping", type="float", default=_def_phase_damping, - help="set damping factor of phase tracking loop [default=%default] (PSK)") - parser.add_option("", "--timing-alpha", type="float", default=_def_timing_alpha, - help="set timing symbol sync loop gain alpha value [default=%default] (GMSK/PSK)") - parser.add_option("", "--timing-beta", type="float", default=_def_timing_beta, - help="set timing symbol sync loop gain beta value [default=%default] (GMSK/PSK)") - parser.add_option("", "--timing-max-dev", type="float", default=_def_timing_max_dev, - help="set timing symbol sync loop maximum deviation [default=%default] (GMSK/PSK)") - add_options=staticmethod(add_options) - - def extract_kwargs_from_options(options): - """ - Given command line options, create dictionary suitable for passing to __init__ - """ - return modulation_utils2.extract_kwargs_from_options( - dbpsk_demod.__init__, ('self',), options) - extract_kwargs_from_options=staticmethod(extract_kwargs_from_options) - -# -# Add these to the mod/demod registry -# -modulation_utils2.add_type_1_mod('dbpsk', dbpsk_mod) -modulation_utils2.add_type_1_demod('dbpsk', dbpsk_demod) diff --git a/gr-digital/python/dqpsk.py b/gr-digital/python/dqpsk.py deleted file mode 100644 index 5e17d24bc..000000000 --- a/gr-digital/python/dqpsk.py +++ /dev/null @@ -1,376 +0,0 @@ -# -# Copyright 2009,2010,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. -# - -# See gnuradio-examples/python/digital for examples - -""" -differential QPSK modulation and demodulation. -""" - -from gnuradio import gr, modulation_utils2 -from math import pi, sqrt -import digital_swig, psk -import cmath -from pprint import pprint - -# default values (used in __init__ and add_options) -_def_samples_per_symbol = 2 -_def_excess_bw = 0.35 -_def_gray_code = True -_def_verbose = False -_def_log = False - -_def_freq_alpha = 0.010 -_def_phase_damping = 0.4 -_def_phase_natfreq = 0.25 -_def_timing_alpha = 0.100 -_def_timing_beta = 0.010 -_def_timing_max_dev = 1.5 - - -# ///////////////////////////////////////////////////////////////////////////// -# DQPSK modulator -# ///////////////////////////////////////////////////////////////////////////// - -class dqpsk_mod(gr.hier_block2): - - def __init__(self, - samples_per_symbol=_def_samples_per_symbol, - excess_bw=_def_excess_bw, - gray_code=_def_gray_code, - verbose=_def_verbose, - log=_def_log): - """ - Hierarchical block for RRC-filtered QPSK modulation. - - The input is a byte stream (unsigned char) and the - output is the complex modulated signal at baseband. - - @param samples_per_symbol: samples per symbol >= 2 - @type samples_per_symbol: integer - @param excess_bw: Root-raised cosine filter excess bandwidth - @type excess_bw: float - @param gray_code: Tell modulator to Gray code the bits - @type gray_code: bool - @param verbose: Print information about modulator? - @type verbose: bool - @param debug: Print modualtion data to files? - @type debug: bool - """ - - gr.hier_block2.__init__(self, "dqpsk_mod", - gr.io_signature(1, 1, gr.sizeof_char), # Input signature - gr.io_signature(1, 1, gr.sizeof_gr_complex)) # Output signature - - self._samples_per_symbol = samples_per_symbol - self._excess_bw = excess_bw - self._gray_code = gray_code - - if samples_per_symbol < 2: - raise TypeError, ("sbp must be >= 2, is %f" % samples_per_symbol) - - arity = pow(2,self.bits_per_symbol()) - - # turn bytes into k-bit vectors - self.bytes2chunks = \ - gr.packed_to_unpacked_bb(self.bits_per_symbol(), gr.GR_MSB_FIRST) - - if self._gray_code: - self.symbol_mapper = gr.map_bb(psk.binary_to_gray[arity]) - else: - self.symbol_mapper = gr.map_bb(psk.binary_to_ungray[arity]) - - self.diffenc = gr.diff_encoder_bb(arity) - - rot = .707 + .707j - rotated_const = map(lambda pt: pt * rot, psk.constellation[arity]) - self.chunks2symbols = gr.chunks_to_symbols_bc(rotated_const) - - # pulse shaping filter - nfilts = 32 - ntaps = 11 * int(nfilts * self._samples_per_symbol) # make nfilts filters of ntaps each - self.rrc_taps = gr.firdes.root_raised_cosine( - nfilts, # gain - nfilts, # sampling rate based on 32 filters in resampler - 1.0, # symbol rate - self._excess_bw, # excess bandwidth (roll-off factor) - ntaps) - self.rrc_filter = gr.pfb_arb_resampler_ccf(self._samples_per_symbol, self.rrc_taps) - - if verbose: - self._print_verbage() - - if log: - self._setup_logging() - - # Connect & Initialize base class - self.connect(self, self.bytes2chunks, self.symbol_mapper, self.diffenc, - self.chunks2symbols, self.rrc_filter, self) - - def samples_per_symbol(self): - return self._samples_per_symbol - - def bits_per_symbol(self=None): # staticmethod that's also callable on an instance - return 2 - bits_per_symbol = staticmethod(bits_per_symbol) # make it a static method. RTFM - - def _print_verbage(self): - print "\nModulator:" - print "bits per symbol: %d" % self.bits_per_symbol() - print "Gray code: %s" % self._gray_code - print "RRC roll-off factor: %f" % self._excess_bw - - def _setup_logging(self): - print "Modulation logging turned on." - self.connect(self.bytes2chunks, - gr.file_sink(gr.sizeof_char, "tx_bytes2chunks.dat")) - self.connect(self.symbol_mapper, - gr.file_sink(gr.sizeof_char, "tx_graycoder.dat")) - self.connect(self.diffenc, - gr.file_sink(gr.sizeof_char, "tx_diffenc.dat")) - self.connect(self.chunks2symbols, - gr.file_sink(gr.sizeof_gr_complex, "tx_chunks2symbols.dat")) - self.connect(self.rrc_filter, - gr.file_sink(gr.sizeof_gr_complex, "tx_rrc_filter.dat")) - - def add_options(parser): - """ - Adds QPSK modulation-specific options to the standard parser - """ - parser.add_option("", "--excess-bw", type="float", default=_def_excess_bw, - help="set RRC excess bandwith factor [default=%default] (PSK)") - parser.add_option("", "--no-gray-code", dest="gray_code", - action="store_false", default=_def_gray_code, - help="disable gray coding on modulated bits (PSK)") - add_options=staticmethod(add_options) - - - def extract_kwargs_from_options(options): - """ - Given command line options, create dictionary suitable for passing to __init__ - """ - return modulation_utils2.extract_kwargs_from_options(dqpsk_mod.__init__, - ('self',), options) - extract_kwargs_from_options=staticmethod(extract_kwargs_from_options) - - -# ///////////////////////////////////////////////////////////////////////////// -# DQPSK demodulator -# -# Differentially coherent detection of differentially encoded qpsk -# ///////////////////////////////////////////////////////////////////////////// - -class dqpsk_demod(gr.hier_block2): - - def __init__(self, - samples_per_symbol=_def_samples_per_symbol, - excess_bw=_def_excess_bw, - freq_alpha=_def_freq_alpha, - phase_damping=_def_phase_damping, - phase_natfreq=_def_phase_natfreq, - timing_alpha=_def_timing_alpha, - timing_max_dev=_def_timing_max_dev, - gray_code=_def_gray_code, - verbose=_def_verbose, - log=_def_log, - sync_out=False): - """ - Hierarchical block for RRC-filtered DQPSK demodulation - - The input is the complex modulated signal at baseband. - The output is a stream of bits packed 1 bit per byte (LSB) - - @param samples_per_symbol: samples per symbol >= 2 - @type samples_per_symbol: float - @param excess_bw: Root-raised cosine filter excess bandwidth - @type excess_bw: float - @param freq_alpha: loop filter gain for frequency recovery - @type freq_alpha: float - @param phase_damping: loop filter damping factor for phase/fine frequency recovery - @type phase_damping: float - @param phase_natfreq: loop filter natural frequency for phase/fine frequency recovery - @type phase_natfreq: float - @param timing_alpha: timing loop alpha gain - @type timing_alpha: float - @param timing_max: timing loop maximum rate deviations - @type timing_max: float - @param gray_code: Tell modulator to Gray code the bits - @type gray_code: bool - @param verbose: Print information about modulator? - @type verbose: bool - @param log: Print modualtion data to files? - @type log: bool - @param sync_out: Output a sync signal on :1? - @type sync_out: bool - """ - if sync_out: io_sig_out = gr.io_signaturev(2, 2, (gr.sizeof_char, gr.sizeof_gr_complex)) - else: io_sig_out = gr.io_signature(1, 1, gr.sizeof_char) - - gr.hier_block2.__init__(self, "dqpsk_demod", - gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature - io_sig_out) # Output signature - - self._samples_per_symbol = samples_per_symbol - self._excess_bw = excess_bw - self._freq_alpha = freq_alpha - self._freq_beta = 0.25*self._freq_alpha**2 - self._phase_damping = phase_damping - self._phase_natfreq = phase_natfreq - self._timing_alpha = timing_alpha - self._timing_beta = _def_timing_beta - self._timing_max_dev=timing_max_dev - self._gray_code = gray_code - - if samples_per_symbol < 2: - raise TypeError, "sbp must be >= 2, is %d" % samples_per_symbol - - arity = pow(2,self.bits_per_symbol()) - - # Automatic gain control - self.agc = gr.agc2_cc(0.6e-1, 1e-3, 1, 1, 100) - #self.agc = gr.feedforward_agc_cc(16, 2.0) - - # Frequency correction - self.freq_recov = gr.fll_band_edge_cc(self._samples_per_symbol, self._excess_bw, - 11*int(self._samples_per_symbol), - self._freq_alpha, self._freq_beta) - - - # symbol timing recovery with RRC data filter - nfilts = 32 - ntaps = 11 * int(samples_per_symbol*nfilts) - taps = gr.firdes.root_raised_cosine(nfilts, nfilts, - 1.0/float(self._samples_per_symbol), - self._excess_bw, ntaps) - self.time_recov = gr.pfb_clock_sync_ccf(self._samples_per_symbol, - self._timing_alpha, - taps, nfilts, nfilts/2, self._timing_max_dev) - self.time_recov.set_beta(self._timing_beta) - - - # Perform phase / fine frequency correction - self.phase_recov = digital_swig.costas_loop_cc(self._phase_damping, - self._phase_natfreq, - arity) - - # Perform Differential decoding on the constellation - self.diffdec = gr.diff_phasor_cc() - - # find closest constellation point - rot = 1 - rotated_const = map(lambda pt: pt * rot, psk.constellation[arity]) - self.slicer = gr.constellation_decoder_cb(rotated_const, range(arity)) - - if self._gray_code: - self.symbol_mapper = gr.map_bb(psk.gray_to_binary[arity]) - else: - self.symbol_mapper = gr.map_bb(psk.ungray_to_binary[arity]) - - # unpack the k bit vector into a stream of bits - self.unpack = gr.unpack_k_bits_bb(self.bits_per_symbol()) - - if verbose: - self._print_verbage() - - if log: - self._setup_logging() - - # Connect - self.connect(self, self.agc, - self.freq_recov, self.time_recov, self.phase_recov, - self.diffdec, self.slicer, self.symbol_mapper, self.unpack, self) - if sync_out: self.connect(self.phase_recov, (self, 1)) - - def samples_per_symbol(self): - return self._samples_per_symbol - - def bits_per_symbol(self=None): # staticmethod that's also callable on an instance - return 2 - bits_per_symbol = staticmethod(bits_per_symbol) # make it a static method. RTFM - - def _print_verbage(self): - print "\nDemodulator:" - print "bits per symbol: %d" % self.bits_per_symbol() - print "Gray code: %s" % self._gray_code - print "RRC roll-off factor: %.2f" % self._excess_bw - print "FLL gain: %.2f" % self._freq_alpha - print "Timing alpha gain: %.2f" % self._timing_alpha - print "Timing beta gain: %.2f" % self._timing_beta - print "Timing max dev: %.2f" % self._timing_max_dev - print "Phase damping fact: %.2e" % self._phase_damping - print "Phase natural freq: %.2e" % self._phase_natfreq - - def _setup_logging(self): - print "Modulation logging turned on." - self.connect(self.agc, - gr.file_sink(gr.sizeof_gr_complex, "rx_agc.dat")) - self.connect(self.freq_recov, - gr.file_sink(gr.sizeof_gr_complex, "rx_freq_recov.dat")) - self.connect(self.time_recov, - gr.file_sink(gr.sizeof_gr_complex, "rx_time_recov.dat")) - self.connect(self.phase_recov, - gr.file_sink(gr.sizeof_gr_complex, "rx_phase_recov.dat")) - self.connect(self.diffdec, - gr.file_sink(gr.sizeof_gr_complex, "rx_diffdec.dat")) - self.connect(self.slicer, - gr.file_sink(gr.sizeof_char, "rx_slicer.dat")) - self.connect(self.symbol_mapper, - gr.file_sink(gr.sizeof_char, "rx_gray_decoder.dat")) - self.connect(self.unpack, - gr.file_sink(gr.sizeof_char, "rx_unpack.dat")) - - def add_options(parser): - """ - Adds DQPSK demodulation-specific options to the standard parser - """ - parser.add_option("", "--excess-bw", type="float", default=_def_excess_bw, - help="set RRC excess bandwith factor [default=%default] (PSK)") - parser.add_option("", "--no-gray-code", dest="gray_code", - action="store_false", default=_def_gray_code, - help="disable gray coding on modulated bits (PSK)") - parser.add_option("", "--freq-alpha", type="float", default=_def_freq_alpha, - help="set frequency lock loop alpha gain value [default=%default] (PSK)") - parser.add_option("", "--phase-natfreq", type="float", default=_def_phase_natfreq, - help="set natural frequency of phase tracking loop [default=%default] (PSK)") - parser.add_option("", "--phase-damping", type="float", default=_def_phase_damping, - help="set damping factor of phase tracking loop [default=%default] (PSK)") - parser.add_option("", "--timing-alpha", type="float", default=_def_timing_alpha, - help="set timing symbol sync loop gain alpha value [default=%default] (GMSK/PSK)") - parser.add_option("", "--timing-beta", type="float", default=_def_timing_beta, - help="set timing symbol sync loop gain beta value [default=%default] (GMSK/PSK)") - parser.add_option("", "--timing-max-dev", type="float", default=_def_timing_max_dev, - help="set timing symbol sync loop maximum deviation [default=%default] (GMSK/PSK)") - add_options=staticmethod(add_options) - - def extract_kwargs_from_options(options): - """ - Given command line options, create dictionary suitable for passing to __init__ - """ - return modulation_utils2.extract_kwargs_from_options( - dqpsk_demod.__init__, ('self',), options) - extract_kwargs_from_options=staticmethod(extract_kwargs_from_options) - - -# -# Add these to the mod/demod registry -# -modulation_utils2.add_type_1_mod('dqpsk', dqpsk_mod) -modulation_utils2.add_type_1_demod('dqpsk', dqpsk_demod) diff --git a/gr-digital/python/generic_mod_demod.py b/gr-digital/python/generic_mod_demod.py index dc69fc0b5..dec96e455 100644 --- a/gr-digital/python/generic_mod_demod.py +++ b/gr-digital/python/generic_mod_demod.py @@ -76,8 +76,8 @@ def add_common_options(parser): class generic_mod(gr.hier_block2): def __init__(self, constellation, - differential=_def_differential, samples_per_symbol=_def_samples_per_symbol, + differential=_def_differential, excess_bw=_def_excess_bw, gray_coded=True, verbose=_def_verbose, diff --git a/gr-digital/python/gmsk.py b/gr-digital/python/gmsk.py index ba122821e..c7a50f422 100644 --- a/gr-digital/python/gmsk.py +++ b/gr-digital/python/gmsk.py @@ -78,8 +78,10 @@ class gmsk_mod(gr.hier_block2): self._samples_per_symbol = samples_per_symbol self._bt = bt - if not isinstance(samples_per_symbol, int) or samples_per_symbol < 2: - raise TypeError, ("samples_per_symbol must be an integer >= 2, is %r" % \ + self._differential = False # make consistant with other modulators + + if samples_per_symbol < 2: + raise TypeError, ("samples_per_symbol must >= 2, is %r" % \ (samples_per_symbol,)) ntaps = 4 * samples_per_symbol # up to 3 bits in filter at once @@ -94,12 +96,12 @@ class gmsk_mod(gr.hier_block2): 1, # gain samples_per_symbol, # symbol_rate bt, # bandwidth * symbol time - ntaps # number of taps + int(ntaps) # number of taps ) - self.sqwave = (1,) * samples_per_symbol # rectangular window + self.sqwave = (1,) * int(samples_per_symbol) # rectangular window self.taps = numpy.convolve(numpy.array(self.gaussian_taps),numpy.array(self.sqwave)) - self.gaussian_filter = gr.interp_fir_filter_fff(samples_per_symbol, self.taps) + self.gaussian_filter = gr.pfb_arb_resampler_fff(samples_per_symbol, self.taps) # FM modulation self.fmmod = gr.frequency_modulator_fc(sensitivity) @@ -192,6 +194,8 @@ class gmsk_demod(gr.hier_block2): self._bt = bt self._timing_bw = timing_bw self._timing_max_dev= _def_timing_max_dev + + self._differential = False # make consistant with other modulators if samples_per_symbol < 2: raise TypeError, "samples_per_symbol >= 2, is %f" % samples_per_symbol @@ -234,7 +238,7 @@ class gmsk_demod(gr.hier_block2): def _print_verbage(self): print "bits per symbol: %d" % self.bits_per_symbol() - print "Bandwidth-Time Prod: %f" % self._bw + print "Bandwidth-Time Prod: %f" % self._bt print "Timing bandwidth: %.2e" % self._timing_bw @@ -253,6 +257,8 @@ class gmsk_demod(gr.hier_block2): """ parser.add_option("", "--timing-bw", type="float", default=_def_timing_bw, help="set timing symbol sync loop gain lock-in bandwidth [default=%default]") + parser.add_option("", "--bt", type="float", default=_def_bt, + help="set bandwidth-time product [default=%default] (GMSK)") add_options=staticmethod(add_options) def extract_kwargs_from_options(options): diff --git a/gr-digital/python/modulation_utils.py b/gr-digital/python/modulation_utils.py deleted file mode 100644 index 71ba77389..000000000 --- a/gr-digital/python/modulation_utils.py +++ /dev/null @@ -1,81 +0,0 @@ -# -# Copyright 2006 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 this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -# - -""" -Miscellaneous utilities for managing mods and demods, as well as other items -useful in dealing with generalized handling of different modulations and demods. -""" - -import inspect - - -# Type 1 modulators accept a stream of bytes on their input and produce complex baseband output -_type_1_modulators = {} - -def type_1_mods(): - return _type_1_modulators - -def add_type_1_mod(name, mod_class): - _type_1_modulators[name] = mod_class - - -# Type 1 demodulators accept complex baseband input and produce a stream of bits, packed -# 1 bit / byte as their output. Their output is completely unambiguous. There is no need -# to resolve phase or polarity ambiguities. -_type_1_demodulators = {} - -def type_1_demods(): - return _type_1_demodulators - -def add_type_1_demod(name, demod_class): - _type_1_demodulators[name] = demod_class - - -def extract_kwargs_from_options(function, excluded_args, options): - """ - Given a function, a list of excluded arguments and the result of - parsing command line options, create a dictionary of key word - arguments suitable for passing to the function. The dictionary - will be populated with key/value pairs where the keys are those - that are common to the function's argument list (minus the - excluded_args) and the attributes in options. The values are the - corresponding values from options unless that value is None. - In that case, the corresponding dictionary entry is not populated. - - (This allows different modulations that have the same parameter - names, but different default values to coexist. The downside is - that --help in the option parser will list the default as None, - but in that case the default provided in the __init__ argument - list will be used since there is no kwargs entry.) - - @param function: the function whose parameter list will be examined - @param excluded_args: function arguments that are NOT to be added to the dictionary - @type excluded_args: sequence of strings - @param options: result of command argument parsing - @type options: optparse.Values - """ - # Try this in C++ ;) - args, varargs, varkw, defaults = inspect.getargspec(function) - d = {} - for kw in [a for a in args if a not in excluded_args]: - if hasattr(options, kw): - if getattr(options, kw) is not None: - d[kw] = getattr(options, kw) - return d |