summaryrefslogtreecommitdiff
path: root/gr-digital
diff options
context:
space:
mode:
Diffstat (limited to 'gr-digital')
-rw-r--r--gr-digital/examples/Makefile.am6
-rw-r--r--gr-digital/examples/README153
-rwxr-xr-xgr-digital/examples/benchmark_rx.py2
-rwxr-xr-xgr-digital/examples/digital_bert_rx.py209
-rwxr-xr-xgr-digital/examples/digital_bert_tx.py135
-rwxr-xr-xgr-digital/examples/rx_voice.py31
-rwxr-xr-xgr-digital/examples/tunnel.py283
-rwxr-xr-xgr-digital/examples/tx_voice.py33
-rw-r--r--gr-digital/examples/uhd_interface.py6
-rw-r--r--gr-digital/python/Makefile.am1
-rw-r--r--gr-digital/python/d8psk.py372
-rw-r--r--gr-digital/python/dbpsk.py372
-rw-r--r--gr-digital/python/dqpsk.py376
-rw-r--r--gr-digital/python/generic_mod_demod.py2
-rw-r--r--gr-digital/python/gmsk.py18
-rw-r--r--gr-digital/python/modulation_utils.py81
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