commit-gnuradio
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Commit-gnuradio] gnuradio-examples/python/gmsk2 benchmark_gmsk_t...


From: Thomas W. Rondeau
Subject: [Commit-gnuradio] gnuradio-examples/python/gmsk2 benchmark_gmsk_t...
Date: Wed, 28 Jun 2006 18:15:24 +0000

CVSROOT:        /sources/gnuradio
Module name:    gnuradio-examples
Changes by:     Thomas W. Rondeau <trondeau1122>        06/06/28 18:15:24

Modified files:
        python/gmsk2   : benchmark_gmsk_tx.py benchmark_mpsk_rx.py 
                         benchmark_mpsk_tx.py receive_path.py 
                         transmit_path.py 
Added files:
        python/gmsk2   : bpsk.py dbpsk.py dqpsk.py pkt.py qpsk.py 

Log message:
        working m-psk; seperate files for bpsk, dbpsk, qpsk (not working at MAC 
level), and dqpsk

CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/gnuradio-examples/python/gmsk2/benchmark_gmsk_tx.py?cvsroot=gnuradio&r1=1.17&r2=1.18
http://cvs.savannah.gnu.org/viewcvs/gnuradio-examples/python/gmsk2/benchmark_mpsk_rx.py?cvsroot=gnuradio&r1=1.1&r2=1.2
http://cvs.savannah.gnu.org/viewcvs/gnuradio-examples/python/gmsk2/benchmark_mpsk_tx.py?cvsroot=gnuradio&r1=1.3&r2=1.4
http://cvs.savannah.gnu.org/viewcvs/gnuradio-examples/python/gmsk2/receive_path.py?cvsroot=gnuradio&r1=1.12&r2=1.13
http://cvs.savannah.gnu.org/viewcvs/gnuradio-examples/python/gmsk2/transmit_path.py?cvsroot=gnuradio&r1=1.9&r2=1.10
http://cvs.savannah.gnu.org/viewcvs/gnuradio-examples/python/gmsk2/bpsk.py?cvsroot=gnuradio&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnuradio-examples/python/gmsk2/dbpsk.py?cvsroot=gnuradio&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnuradio-examples/python/gmsk2/dqpsk.py?cvsroot=gnuradio&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnuradio-examples/python/gmsk2/pkt.py?cvsroot=gnuradio&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnuradio-examples/python/gmsk2/qpsk.py?cvsroot=gnuradio&rev=1.1

Patches:
Index: benchmark_gmsk_tx.py
===================================================================
RCS file: 
/sources/gnuradio/gnuradio-examples/python/gmsk2/benchmark_gmsk_tx.py,v
retrieving revision 1.17
retrieving revision 1.18
diff -u -b -r1.17 -r1.18
--- benchmark_gmsk_tx.py        21 Jun 2006 00:55:01 -0000      1.17
+++ benchmark_gmsk_tx.py        28 Jun 2006 18:15:23 -0000      1.18
@@ -46,7 +46,8 @@
                  bitrate, interp_rate, spb, bt, options):
         gr.flow_graph.__init__(self)
         self.txpath = transmit_path(self, mod_class, tx_subdev_spec,
-                                    bitrate, interp_rate, spb, bt, options)
+                                    bitrate, interp_rate, spb, gain, m_arity,
+                                    options, mod_kwargs)
 
 
 # /////////////////////////////////////////////////////////////////////////////
@@ -65,15 +66,20 @@
     parser.add_option("-T", "--tx-subdev-spec", type="subdev", default=None,
                       help="select USRP Tx side A or B")
     parser.add_option("-f", "--freq", type="eng_float", default=423.1e6,
-                       help="set Tx and Rx frequency to FREQ 
[default=%default]", metavar="FREQ")
+                      help="set Tx and Rx frequency to FREQ 
[default=%default]",
+                      metavar="FREQ")
     parser.add_option("-r", "--bitrate", type="eng_float", default=None,
                       help="specify bitrate.  spb and interp will be derived.")
-    parser.add_option("-S", "--spb", type="int", default=None, help="set 
samples/baud [default=%default]")
+    parser.add_option("-S", "--spb", type="int", default=None,
+                      help="set samples/baud [default=%default]")
     parser.add_option("-i", "--interp", type="intx", default=None,
                       help="set fpga interpolation rate to INTERP 
[default=%default]")
     parser.add_option("-s", "--size", type="eng_float", default=1500,
                       help="set packet size [default=%default]")
-    parser.add_option("", "--bt", type="float", default=0.3, help="set 
bandwidth-time product [default=%default]")
+    parser.add_option("", "--bt", type="float", default=0.3,
+                      help="set bandwidth-time product [default=%default]")
+    parser.add_option("-g", "--gain", type="eng_float", default=100.0,
+                      help="transmitter gain [default=%default]")
     parser.add_option("-M", "--megabytes", type="eng_float", default=1.0,
                       help="set megabytes to transmit [default=%default]")
     parser.add_option("","--discontinuous", action="store_true", default=False,

Index: benchmark_mpsk_rx.py
===================================================================
RCS file: 
/sources/gnuradio/gnuradio-examples/python/gmsk2/benchmark_mpsk_rx.py,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -b -r1.1 -r1.2
--- benchmark_mpsk_rx.py        31 May 2006 03:11:32 -0000      1.1
+++ benchmark_mpsk_rx.py        28 Jun 2006 18:15:23 -0000      1.2
@@ -30,7 +30,11 @@
 import struct
 
 # from current dir
-from mpsk_receive_path import mpsk_receive_path
+from bpsk import bpsk_demod
+from dbpsk import dbpsk_demod
+from dqpsk import dqpsk_demod
+from receive_path import receive_path
+import fusb_options
 
 #import os
 #print os.getpid()
@@ -39,11 +43,13 @@
 
 class my_graph(gr.flow_graph):
 
-    def __init__(self, rx_subdev_spec, bitrate, decim_rate, spb,
-                 arity, excess_bw, rx_callback, log):
+    def __init__(self, demod_class, rx_subdev_spec,
+                 bitrate, decim_rate, spb, arity,
+                 rx_callback, options, demod_kwargs):
         gr.flow_graph.__init__(self)
-        self.rxpath = mpsk_receive_path(self, rx_subdev_spec, bitrate, 
decim_rate,
-                                        spb, arity, excess_bw, rx_callback, 
log)
+        self.rxpath = receive_path(self, demod_class, rx_subdev_spec,
+                                   bitrate, decim_rate, spb, arity,
+                                   rx_callback, options, demod_kwargs)
 
 # /////////////////////////////////////////////////////////////////////////////
 #                                   main
@@ -71,20 +77,23 @@
     parser.add_option("-R", "--rx-subdev-spec", type="subdev", default=None,
                       help="select USRP Rx side A or B")
     parser.add_option("-f", "--freq", type="eng_float", default=423.1e6,
-                       help="set Rx frequency to FREQ [default=%default]", 
metavar="FREQ")
+                      help="set Rx frequency to FREQ [default=%default]",
+                      metavar="FREQ")
     parser.add_option("-r", "--bitrate", type="eng_float", default=None,
                       help="specify bitrate.  spb and interp will be derived.")
-    parser.add_option("-S", "--spb", type="int", default=None, help="set 
samples/baud [default=%default]")
+    parser.add_option("-S", "--spb", type="int", default=None,
+                      help="set samples/baud [default=%default]")
     parser.add_option("-d", "--decim", type="intx", default=None,
                       help="set fpga decim rate to DECIM [default=%default]")
-    parser.add_option("", "--m-arity", type=int, default=4,
-                      help="PSK arity [default=%default]")
+    parser.add_option("-m", "--modulation", type="string", default='dbpsk',
+                      help="modulation type (bpsk, dbpsk, dqpsk) 
[default=%default]")
     parser.add_option("", "--excess-bw", type="float", default=0.3,
                       help="set RRC excess bandwith factor [default=%default]")
     parser.add_option("-g", "--gain", type="eng_float", default=27,
                       help="set rx gain")
     parser.add_option("","--log", action="store_true", default=False,
                       help="enable diagnostic logging")
+    fusb_options.add_options(parser)
     (options, args) = parser.parse_args ()
 
     if len(args) != 0:
@@ -94,19 +103,44 @@
     if options.freq < 1e6:
         options.freq *= 1e6
 
+    demod_kwargs = {
+            'excess_bw' : options.excess_bw,
+            }
+
+    #FIXME: Needs to be worked in to overall structure; this will be fixed
+    #       once static class definitions for modulations are defined
+    if(options.modulation=='bpsk'):
+        modulation=bpsk_demod
+        m_arity=2
+    elif(options.modulation=='dbpsk'):
+        modulation=dbpsk_demod
+        m_arity=2
+    else:
+        modulation=dqpsk_demod
+        m_arity=4
+
     # build the graph
-    fg = my_graph(options.rx_subdev_spec, options.bitrate,
-                  options.decim, options.spb, options.m_arity, 
-                  options.excess_bw, rx_callback, options.log)
+    fg = my_graph(modulation,
+                  options.rx_subdev_spec, options.bitrate,
+                  options.decim, options.spb, m_arity,
+                  rx_callback, options, demod_kwargs)
 
     print "bitrate: %sb/sec" % (eng_notation.num_to_str(fg.rxpath.bitrate()),)
     print "spb:     %3d" % (fg.rxpath.spb(),)
     print "decim:   %3d" % (fg.rxpath.decim(),)
 
-    fg.rxpath.set_freq(options.freq)
+    ok = fg.rxpath.set_freq(options.freq)
+    if not ok:
+        print "Failed to set Rx frequency to %s" % 
(eng_notation.num_to_str(options.freq),)
+        raise SystemExit
+    
     fg.rxpath.set_gain(options.gain)
     print "Rx gain_range: ", fg.rxpath.subdev.gain_range(), " using", 
fg.rxpath.gain
 
+    r = gr.enable_realtime_scheduling()
+    if r != gr.RT_OK:
+        print "Warning: Failed to enable realtime scheduling."
+
     fg.start()        # start flow graph
     fg.wait()         # wait for it to finish
 

Index: benchmark_mpsk_tx.py
===================================================================
RCS file: 
/sources/gnuradio/gnuradio-examples/python/gmsk2/benchmark_mpsk_tx.py,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -b -r1.3 -r1.4
--- benchmark_mpsk_tx.py        6 Jun 2006 05:01:22 -0000       1.3
+++ benchmark_mpsk_tx.py        28 Jun 2006 18:15:23 -0000      1.4
@@ -26,13 +26,14 @@
 from gnuradio.eng_option import eng_option
 from optparse import OptionParser
 
-import random
-import time
-import struct
-import sys
+import random, time, struct, sys
 
 # from current dir
-from mpsk_transmit_path import mpsk_transmit_path
+from bpsk  import bpsk_mod
+from dbpsk import dbpsk_mod
+from dqpsk import dqpsk_mod
+from transmit_path import transmit_path
+import fusb_options
 
 #import os
 #print os.getpid()
@@ -41,11 +42,13 @@
 
 class my_graph(gr.flow_graph):
 
-    def __init__(self, tx_subdev_spec, bitrate, interp_rate, spb,
-                 arity, excess_bw):
+    def __init__(self, mod_class, tx_subdev_spec,
+                 bitrate, interp_rate, spb, gain,
+                 options, mod_kwargs):
         gr.flow_graph.__init__(self)
-        self.txpath = mpsk_transmit_path(self, tx_subdev_spec, bitrate,
-                                         interp_rate, spb, arity, excess_bw)
+        self.txpath = transmit_path(self, mod_class, tx_subdev_spec,
+                                    bitrate, interp_rate, spb, gain,
+                                    options, mod_kwargs)
 
 
 # /////////////////////////////////////////////////////////////////////////////
@@ -64,22 +67,27 @@
     parser.add_option("-T", "--tx-subdev-spec", type="subdev", default=None,
                       help="select USRP Tx side A or B")
     parser.add_option("-f", "--freq", type="eng_float", default=423.1e6,
-                       help="set Tx and Rx frequency to FREQ 
[default=%default]", metavar="FREQ")
+                      help="set Tx and Rx frequency to FREQ 
[default=%default]",
+                      metavar="FREQ")
     parser.add_option("-r", "--bitrate", type="eng_float", default=None,
                       help="specify bitrate.  spb and interp will be derived.")
-    parser.add_option("-S", "--spb", type="int", default=None, help="set 
samples/baud [default=%default]")
+    parser.add_option("-S", "--spb", type="int", default=None,
+                      help="set samples/baud [default=%default]")
     parser.add_option("-i", "--interp", type="intx", default=None,
                       help="set fpga interpolation rate to INTERP 
[default=%default]")
     parser.add_option("-s", "--size", type="eng_float", default=1500,
                       help="set packet size [default=%default]")
-    parser.add_option("", "--m-arity", type=int, default=4,
-                      help="PSK arity [default=%default]")
+    parser.add_option("-m", "--modulation", type="string", default='dbpsk',
+                      help="modulation type (bpsk, dbpsk, dqpsk) 
[default=%default]")
     parser.add_option("", "--excess-bw", type="float", default=0.3,
                       help="set RRC excess bandwith factor [default=%default]")
+    parser.add_option("-g", "--gain", type="eng_float", default=100.0,
+                      help="transmitter gain [default=%default]")
     parser.add_option("-M", "--megabytes", type="eng_float", default=1.0,
                       help="set megabytes to transmit [default=%default]")
     parser.add_option("","--discontinuous", action="store_true", default=False,
                       help="enable discontinous transmission (bursts of 5 
packets)")
+    fusb_options.add_options(parser)
     (options, args) = parser.parse_args ()
 
     if len(args) != 0:
@@ -91,15 +99,36 @@
 
     pkt_size = int(options.size)
 
+    mod_kwargs = {
+        'excess_bw' : options.excess_bw,
+        }
+
+    #FIXME: rework when static class defintions are ready for the modulation 
types
+    if(options.modulation=='bpsk'):
+        modulation=bpsk_mod
+    elif( options.modulation=='dbpsk'):
+        modulation=dbpsk_mod
+    else:
+        modulation=dqpsk_mod
+
     # build the graph
-    fg = my_graph(options.tx_subdev_spec, options.bitrate, options.interp,
-                  options.spb, options.m_arity, options.excess_bw)
+    fg = my_graph(modulation,
+                  options.tx_subdev_spec, options.bitrate, options.interp,
+                  options.spb, options.gain,
+                  options, mod_kwargs)
 
     print "bitrate: %sb/sec" % (eng_notation.num_to_str(fg.txpath.bitrate()),)
     print "spb:     %3d" % (fg.txpath.spb(),)
     print "interp:  %3d" % (fg.txpath.interp(),)
 
-    fg.txpath.set_freq(options.freq)
+    ok = fg.txpath.set_freq(options.freq)
+    if not ok:
+        print "Failed to set Tx frequency to %s" % 
(eng_notation.num_to_str(options.freq),)
+        raise SystemExit
+
+    r = gr.enable_realtime_scheduling()
+    if r != gr.RT_OK:
+        print "Warning: failed to enable realtime scheduling"
 
     fg.start()                       # start flow graph
 

Index: receive_path.py
===================================================================
RCS file: /sources/gnuradio/gnuradio-examples/python/gmsk2/receive_path.py,v
retrieving revision 1.12
retrieving revision 1.13
diff -u -b -r1.12 -r1.13
--- receive_path.py     21 Jun 2006 00:55:01 -0000      1.12
+++ receive_path.py     28 Jun 2006 18:15:23 -0000      1.13
@@ -24,6 +24,7 @@
 from gnuradio import usrp
 
 # from current dir
+from pkt import demod_pkts
 from pick_bitrate import pick_rx_bitrate
 
 # /////////////////////////////////////////////////////////////////////////////
@@ -32,12 +33,8 @@
 
 class receive_path(gr.hier_block):
     def __init__(self, fg, demod_class, rx_subdev_spec,
-                 bitrate, decim, spb, rx_callback, options):
-
-        # FIXME add this as a parameter
-        demod_kwargs = {
-            'gain_mu' : 0.03,     # default
-            }
+                 bitrate, decim, spb, m_arity,
+                 rx_callback, options, demod_kwargs):
 
         self.u = usrp.source_c (fusb_block_size=options.fusb_block_size,
                                 fusb_nblocks=options.fusb_nblocks)

Index: transmit_path.py
===================================================================
RCS file: /sources/gnuradio/gnuradio-examples/python/gmsk2/transmit_path.py,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -b -r1.9 -r1.10
--- transmit_path.py    21 Jun 2006 00:55:01 -0000      1.9
+++ transmit_path.py    28 Jun 2006 18:15:23 -0000      1.10
@@ -31,19 +31,17 @@
 
 class transmit_path(gr.hier_block):
     def __init__(self, fg, mod_class, tx_subdev_spec,
-                 bitrate, interp, spb, bt, options):
+                 bitrate, interp, spb, gain,
+                 options, mod_kwargs):
 
-        # FIXME add this as a parameter, and move bt arg into dict
-        mod_kwargs = {
-            'bt' : bt
-            }
-
-        self.normal_gain = 8000
+        self.normal_gain = gain
 
         self.u = usrp.sink_c (fusb_block_size=options.fusb_block_size,
                               fusb_nblocks=options.fusb_nblocks)
         dac_rate = self.u.dac_rate();
 
+        print mod_class
+        print mod_class.bits_per_baud()
         (self._bitrate, self._spb, self._interp) = \
             pick_tx_bitrate(bitrate, mod_class.bits_per_baud(), spb, interp, 
dac_rate)
 

Index: bpsk.py
===================================================================
RCS file: bpsk.py
diff -N bpsk.py
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ bpsk.py     28 Jun 2006 18:15:23 -0000      1.1
@@ -0,0 +1,256 @@
+#
+# Copyright 2005,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 2, 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., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+# 
+
+# See gnuradio-examples/python/gmsk2 for examples
+
+"""
+BPSK modulation and demodulation.
+"""
+
+from gnuradio import gr, gru
+from math import pi, sqrt
+import cmath
+import Numeric
+from pprint import pprint
+
+_use_gray_code = True
+
+def make_constellation(m):
+    return [cmath.exp(i * 2 * pi / m * 1j) for i in range(m)]
+        
+# Common definition of constellations for Tx and Rx
+constellation = {
+    2 : make_constellation(2),           # BPSK
+    4 : make_constellation(4),           # QPSK
+    8 : make_constellation(8)            # 8PSK
+    }
+
+if 0:
+    print "const(2) ="
+    pprint(constellation[2])
+    print "const(4) ="
+    pprint(constellation[4])
+    print "const(8) ="
+    pprint(constellation[8])
+
+
+if _use_gray_code:
+    # -----------------------
+    # Do Gray code
+    # -----------------------
+    # binary to gray coding
+    binary_to_gray = {
+        2 : (0, 1),
+        4 : (0, 1, 3, 2),
+        8 : (0, 1, 3, 2, 7, 6, 4, 5)
+        }
+    
+    # gray to binary
+    gray_to_binary = {
+        2 : (0, 1),
+        4 : (0, 1, 3, 2),
+        8 : (0, 1, 3, 2, 6, 7, 5, 4)
+        }
+else:
+    # -----------------------
+    # Don't Gray code
+    # -----------------------
+    # identity mapping
+    binary_to_gray = {
+        2 : (0, 1),
+        4 : (0, 1, 2, 3),
+        8 : (0, 1, 2, 3, 4, 5, 6, 7)
+        }
+    
+    # identity mapping
+    gray_to_binary = {
+        2 : (0, 1),
+        4 : (0, 1, 2, 3),
+        8 : (0, 1, 2, 3, 4, 5, 6, 7)
+        }
+
+
+# /////////////////////////////////////////////////////////////////////////////
+#            mPSK mod/demod with steams of bytes as data i/o
+# /////////////////////////////////////////////////////////////////////////////
+
+
+class bpsk_mod(gr.hier_block):
+
+    def __init__(self, fg, spb, excess_bw):
+        """
+       Hierarchical block for RRC-filtered BPSK modulation.
+
+       The input is a byte stream (unsigned char) and the
+       output is the complex modulated signal at baseband.
+
+       @param fg: flow graph
+       @type fg: flow graph
+       @param spb: samples per baud >= 2
+       @type spb: integer
+       @param excess_bw: Root-raised cosine filter excess bandwidth
+       @type excess_bw: float
+       """
+        if not isinstance(spb, int) or spb < 2:
+            raise TypeError, "sbp must be an integer >= 2"
+        self.spb = spb
+
+       ntaps = 11 * spb
+
+        bits_per_symbol = self.bits_per_baud()
+        arity = pow(2,bits_per_symbol)
+        print "bits_per_symbol =", bits_per_symbol
+        
+        # turn bytes into k-bit vectors
+        self.bytes2chunks = \
+          gr.packed_to_unpacked_bb(bits_per_symbol, gr.GR_MSB_FIRST)
+
+        self.chunks2symbols = gr.chunks_to_symbols_bc(constellation[arity])
+
+        # pulse shaping filter
+       self.rrc_taps = gr.firdes.root_raised_cosine(
+               spb,            # gain  (spb since we're interpolating by spb)
+               spb,            # sampling rate
+               1.0,            # symbol rate
+               excess_bw,      # excess bandwidth (roll-off factor)
+                ntaps)
+
+       self.rrc_filter = gr.interp_fir_filter_ccf(spb, self.rrc_taps)
+
+       # Connect
+        fg.connect(self.bytes2chunks, self.chunks2symbols, self.rrc_filter)
+
+        if 1:
+            fg.connect(self.rrc_filter,
+                       gr.file_sink(gr.sizeof_gr_complex, "rrc.dat"))
+            
+       # Initialize base class
+       gr.hier_block.__init__(self, fg, self.bytes2chunks, self.rrc_filter)
+
+    def samples_per_baud(self):
+        return self.spb
+
+    def bits_per_baud(self=None):   # staticmethod that's also callable on an 
instance
+        return 1
+    bits_per_baud = staticmethod(bits_per_baud)      # make it a static 
method.  RTFM
+
+
+class bpsk_demod__coherent_detection_of_psk(gr.hier_block):
+    def __init__(self, fg, spb, excess_bw, costas_alpha=0.005, gain_mu=0.05):
+        """
+       Hierarchical block for RRC-filtered 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 fg: flow graph
+       @type fg: flow graph
+       @param spb: samples per baud >= 2
+       @type spb: float
+       @param excess_bw: Root-raised cosine filter excess bandwidth
+       @type excess_bw: float
+        @param costas_alpha: loop filter gain
+        @type costas_alphas: float
+        @param gain_mu:
+        @type gain_mu: float
+       """
+        if spb < 2:
+            raise TypeError, "sbp must be >= 2"
+        self.spb = spb
+
+        bits_per_symbol = self.bits_per_baud()
+        arity = pow(2,bits_per_symbol)
+        print "bits_per_symbol =", bits_per_symbol
+
+        # Automatic gain control
+        self.preamp = gr.multiply_const_cc(10e-5)
+        self.agc = gr.agc_cc(1e-3, 1, 1)
+        
+        # Costas loop (carrier tracking)
+        # FIXME: need to decide how to handle this more generally; do we pull 
it from higher layer?
+        costas_order = 2
+        costas_alpha *= 15   # 2nd order loop needs more gain
+        beta = .25 * costas_alpha * costas_alpha
+        self.costas_loop = gr.costas_loop_cc(costas_alpha, beta, 0.05, -0.05, 
costas_order)
+
+        # RRC data filter
+        ntaps = 11 * spb
+        self.rrc_taps = gr.firdes.root_raised_cosine(
+            1.0,                # gain 
+            spb,                # sampling rate
+            1.0,                # symbol rate
+            excess_bw,          # excess bandwidth (roll-off factor)
+            ntaps)
+
+        self.rrc_filter=gr.fir_filter_ccf(1, self.rrc_taps)
+
+        # symbol clock recovery
+        omega = spb
+        gain_omega = .25 * gain_mu * gain_mu
+        omega_rel_limit = 0.5
+        mu = 0.05
+        gain_mu = 0.1
+        self.clock_recovery=gr.clock_recovery_mm_cc(omega, gain_omega,
+                                                    mu, gain_mu, 
omega_rel_limit)
+
+        # find closest constellation point
+        #rot = .707 + .707j
+        rot = 1
+        rotated_const = map(lambda pt: pt * rot, constellation[arity])
+        print "rotated_const =", rotated_const
+
+        self.slicer = gr.constellation_decoder_cb(rotated_const, range(arity))
+        self.gray_decoder = gr.map_bb(gray_to_binary[arity])
+        
+        # unpack the k bit vector into a stream of bits
+        self.unpack = gr.unpack_k_bits_bb(bits_per_symbol)
+
+        fg.connect(self.preamp, self.agc, self.costas_loop, self.rrc_filter, 
self.clock_recovery,
+                   self.slicer, self.gray_decoder, self.unpack)
+        
+        # Debug sinks
+        if 1:
+            fg.connect(self.agc,
+                       gr.file_sink(gr.sizeof_gr_complex, "agc.dat"))
+            fg.connect(self.costas_loop,
+                       gr.file_sink(gr.sizeof_gr_complex, "costas_loop.dat"))
+            fg.connect(self.rrc_filter,
+                       gr.file_sink(gr.sizeof_gr_complex, "rrc.dat"))
+            fg.connect(self.clock_recovery,
+                       gr.file_sink(gr.sizeof_gr_complex, 
"clock_recovery.dat"))
+            fg.connect(self.slicer,
+                       gr.file_sink(gr.sizeof_char, "slicer.dat"))
+            fg.connect(self.unpack,
+                       gr.file_sink(gr.sizeof_char, "unpack.dat"))
+
+        # Initialize base class
+        gr.hier_block.__init__(self, fg, self.preamp, self.unpack)
+
+    def samples_per_baud(self):
+        return self.spb
+
+    def bits_per_baud(self=None):   # staticmethod that's also callable on an 
instance
+        return 1
+    bits_per_baud = staticmethod(bits_per_baud)      # make it a static 
method.  RTFM
+
+
+bpsk_demod = bpsk_demod__coherent_detection_of_psk
+

Index: dbpsk.py
===================================================================
RCS file: dbpsk.py
diff -N dbpsk.py
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ dbpsk.py    28 Jun 2006 18:15:23 -0000      1.1
@@ -0,0 +1,282 @@
+#
+# Copyright 2005,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 2, 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., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+# 
+
+# See gnuradio-examples/python/gmsk2 for examples
+
+"""
+differential BPSK modulation and demodulation.
+"""
+
+from gnuradio import gr, gru
+from math import pi, sqrt
+import cmath
+import Numeric
+from pprint import pprint
+
+_use_gray_code = True
+
+def make_constellation(m):
+    return [cmath.exp(i * 2 * pi / m * 1j) for i in range(m)]
+        
+# Common definition of constellations for Tx and Rx
+constellation = {
+    2 : make_constellation(2),           # BPSK
+    4 : make_constellation(4),           # QPSK
+    8 : make_constellation(8)            # 8PSK
+    }
+
+if 0:
+    print "const(2) ="
+    pprint(constellation[2])
+    print "const(4) ="
+    pprint(constellation[4])
+    print "const(8) ="
+    pprint(constellation[8])
+
+
+if _use_gray_code:
+    # -----------------------
+    # Do Gray code
+    # -----------------------
+    # binary to gray coding
+    binary_to_gray = {
+        2 : (0, 1),
+        4 : (0, 1, 3, 2),
+        8 : (0, 1, 3, 2, 7, 6, 4, 5)
+        }
+    
+    # gray to binary
+    gray_to_binary = {
+        2 : (0, 1),
+        4 : (0, 1, 3, 2),
+        8 : (0, 1, 3, 2, 6, 7, 5, 4)
+        }
+else:
+    # -----------------------
+    # Don't Gray code
+    # -----------------------
+    # identity mapping
+    binary_to_gray = {
+        2 : (0, 1),
+        4 : (0, 1, 2, 3),
+        8 : (0, 1, 2, 3, 4, 5, 6, 7)
+        }
+    
+    # identity mapping
+    gray_to_binary = {
+        2 : (0, 1),
+        4 : (0, 1, 2, 3),
+        8 : (0, 1, 2, 3, 4, 5, 6, 7)
+        }
+
+
+# /////////////////////////////////////////////////////////////////////////////
+#            BPSK mod/demod with steams of bytes as data i/o
+# /////////////////////////////////////////////////////////////////////////////
+
+
+class dbpsk_mod(gr.hier_block):
+
+    def __init__(self, fg, spb, excess_bw):
+        """
+       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 fg: flow graph
+       @type fg: flow graph
+       @param spb: samples per baud >= 2
+       @type spb: integer
+       @param excess_bw: Root-raised cosine filter excess bandwidth
+       @type excess_bw: float
+       """
+        if not isinstance(spb, int) or spb < 2:
+            raise TypeError, "sbp must be an integer >= 2"
+        self.spb = spb
+
+       ntaps = 11 * spb
+
+        bits_per_symbol = self.bits_per_baud()
+        arity = pow(2,bits_per_symbol)
+        self.bits_per_symbol = bits_per_symbol
+        print "bits_per_symbol =", bits_per_symbol
+        
+        # turn bytes into k-bit vectors
+        self.bytes2chunks = \
+          gr.packed_to_unpacked_bb(bits_per_symbol, gr.GR_MSB_FIRST)
+
+        if True:
+            self.gray_coder = gr.map_bb(binary_to_gray[arity])
+        else:
+            self.gray_coder = None
+
+        self.diffenc = gr.diff_encoder_bb(arity)
+        
+        self.chunks2symbols = gr.chunks_to_symbols_bc(constellation[arity])
+
+        # pulse shaping filter
+       self.rrc_taps = gr.firdes.root_raised_cosine(
+               spb,            # gain  (spb since we're interpolating by spb)
+               spb,            # sampling rate
+               1.0,            # symbol rate
+               excess_bw,      # excess bandwidth (roll-off factor)
+                ntaps)
+
+       self.rrc_filter = gr.interp_fir_filter_ccf(spb, self.rrc_taps)
+
+       # Connect
+        if self.gray_coder:
+            fg.connect(self.bytes2chunks, self.gray_coder)
+            t = self.gray_coder
+        else:
+            t = self.bytes2chunks
+
+        fg.connect(t, self.diffenc, self.chunks2symbols, self.rrc_filter)
+        
+        if 1:
+            fg.connect(self.gray_coder,
+                       gr.file_sink(gr.sizeof_char, "graycoder.dat"))
+            fg.connect(self.diffenc,
+                       gr.file_sink(gr.sizeof_char, "diffenc.dat"))
+            
+       # Initialize base class
+       gr.hier_block.__init__(self, fg, self.bytes2chunks, self.rrc_filter)
+
+    def samples_per_baud(self):
+        return self.spb
+
+    def bits_per_baud(self=None):   # staticmethod that's also callable on an 
instance
+        return 1
+    bits_per_baud = staticmethod(bits_per_baud)      # make it a static 
method.  RTFM
+
+
+
+class 
dbpsk_demod__coherent_detection_of_differentially_encoded_psk(gr.hier_block):
+    def __init__(self, fg, spb, excess_bw, costas_alpha=0.005, gain_mu=0.05):
+        """
+       Hierarchical block for RRC-filtered 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 fg: flow graph
+       @type fg: flow graph
+       @param spb: samples per baud >= 2
+       @type spb: float
+       @param excess_bw: Root-raised cosine filter excess bandwidth
+       @type excess_bw: float
+        @param costas_alpha: loop filter gain
+        @type costas_alphas: float
+        @param gain_mu:
+        @type gain_mu: float
+       """
+        if spb < 2:
+            raise TypeError, "sbp must be >= 2"
+        self.spb = spb
+
+        bits_per_symbol = self.bits_per_baud()
+        arity = pow(2,bits_per_symbol)
+        print "bits_per_symbol =", bits_per_symbol
+
+        # Automatic gain control
+        self.preamp = gr.multiply_const_cc(10e-5)
+        self.agc = gr.agc_cc(1e-3, 1, 1)
+        
+        # Costas loop (carrier tracking)
+        # FIXME: need to decide how to handle this more generally; do we pull 
it from higher layer?
+        costas_order = 2
+        costas_alpha *= 15   # 2nd order loop needs more gain
+        beta = .25 * costas_alpha * costas_alpha
+        self.costas_loop = gr.costas_loop_cc(costas_alpha, beta, 0.05, -0.05, 
costas_order)
+
+        # RRC data filter
+        ntaps = 11 * spb
+        self.rrc_taps = gr.firdes.root_raised_cosine(
+            1.0,                # gain 
+            spb,                # sampling rate
+            1.0,                # symbol rate
+            excess_bw,          # excess bandwidth (roll-off factor)
+            ntaps)
+
+        self.rrc_filter=gr.fir_filter_ccf(1, self.rrc_taps)
+
+        # symbol clock recovery
+        omega = spb
+        gain_omega = .25 * gain_mu * gain_mu
+        omega_rel_limit = 0.5
+        mu = 0.05
+        gain_mu = 0.1
+        self.clock_recovery=gr.clock_recovery_mm_cc(omega, gain_omega,
+                                                    mu, gain_mu, 
omega_rel_limit)
+
+        # find closest constellation point
+        #rot = .707 + .707j
+        rot = 1
+        rotated_const = map(lambda pt: pt * rot, constellation[arity])
+        print "rotated_const =", rotated_const
+
+        self.diffdec = gr.diff_phasor_cc()
+        #self.diffdec = gr.diff_decoder_bb(arity)
+
+        self.slicer = gr.constellation_decoder_cb(rotated_const, range(arity))
+        self.gray_decoder = gr.map_bb(gray_to_binary[arity])
+        
+        # unpack the k bit vector into a stream of bits
+        self.unpack = gr.unpack_k_bits_bb(bits_per_symbol)
+
+        fg.connect(self.preamp, self.agc, self.costas_loop, self.rrc_filter, 
self.clock_recovery,
+                   self.diffdec, self.slicer, self.gray_decoder, self.unpack)
+        #fg.connect(self.preamp, self.agc, self.costas_loop, self.rrc_filter, 
self.clock_recovery,
+        #           self.slicer, self.diffdec, self.gray_decoder, self.unpack)
+        
+        # Debug sinks
+        if 1:
+            fg.connect(self.agc,
+                       gr.file_sink(gr.sizeof_gr_complex, "agc.dat"))
+            fg.connect(self.costas_loop,
+                       gr.file_sink(gr.sizeof_gr_complex, "costas_loop.dat"))
+            fg.connect(self.rrc_filter,
+                       gr.file_sink(gr.sizeof_gr_complex, "rrc.dat"))
+            fg.connect(self.clock_recovery,
+                       gr.file_sink(gr.sizeof_gr_complex, 
"clock_recovery.dat"))
+            fg.connect(self.slicer,
+                       gr.file_sink(gr.sizeof_char, "slicer.dat"))
+            fg.connect(self.diffdec,
+                       gr.file_sink(gr.sizeof_gr_complex, "diffdec.dat"))
+            #fg.connect(self.diffdec,
+            #          gr.file_sink(gr.sizeof_char, "diffdec.dat"))
+            fg.connect(self.unpack,
+                       gr.file_sink(gr.sizeof_char, "unpack.dat"))
+
+        # Initialize base class
+        gr.hier_block.__init__(self, fg, self.preamp, self.unpack)
+
+    def samples_per_baud(self):
+        return self.spb
+
+    def bits_per_baud(self=None):   # staticmethod that's also callable on an 
instance
+        return 1
+    bits_per_baud = staticmethod(bits_per_baud)      # make it a static 
method.  RTFM
+
+
+dbpsk_demod = dbpsk_demod__coherent_detection_of_differentially_encoded_psk
+

Index: dqpsk.py
===================================================================
RCS file: dqpsk.py
diff -N dqpsk.py
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ dqpsk.py    28 Jun 2006 18:15:23 -0000      1.1
@@ -0,0 +1,280 @@
+#
+# Copyright 2005,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 2, 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., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+# 
+
+# See gnuradio-examples/python/gmsk2 for examples
+
+"""
+differential QPSK modulation and demodulation.
+"""
+
+from gnuradio import gr, gru
+from math import pi, sqrt
+import cmath
+import Numeric
+from pprint import pprint
+
+_use_gray_code = True
+
+def make_constellation(m):
+    return [cmath.exp(i * 2 * pi / m * 1j) for i in range(m)]
+        
+# Common definition of constellations for Tx and Rx
+constellation = {
+    2 : make_constellation(2),           # BPSK
+    4 : make_constellation(4),           # QPSK
+    8 : make_constellation(8)            # 8PSK
+    }
+
+if 0:
+    print "const(2) ="
+    pprint(constellation[2])
+    print "const(4) ="
+    pprint(constellation[4])
+    print "const(8) ="
+    pprint(constellation[8])
+
+
+if _use_gray_code:
+    # -----------------------
+    # Do Gray code
+    # -----------------------
+    # binary to gray coding
+    binary_to_gray = {
+        2 : (0, 1),
+        4 : (0, 1, 3, 2),
+        8 : (0, 1, 3, 2, 7, 6, 4, 5)
+        }
+    
+    # gray to binary
+    gray_to_binary = {
+        2 : (0, 1),
+        4 : (0, 1, 3, 2),
+        8 : (0, 1, 3, 2, 6, 7, 5, 4)
+        }
+else:
+    # -----------------------
+    # Don't Gray code
+    # -----------------------
+    # identity mapping
+    binary_to_gray = {
+        2 : (0, 1),
+        4 : (0, 1, 2, 3),
+        8 : (0, 1, 2, 3, 4, 5, 6, 7)
+        }
+    
+    # identity mapping
+    gray_to_binary = {
+        2 : (0, 1),
+        4 : (0, 1, 2, 3),
+        8 : (0, 1, 2, 3, 4, 5, 6, 7)
+        }
+
+
+# /////////////////////////////////////////////////////////////////////////////
+#            QPSK mod/demod with steams of bytes as data i/o
+# /////////////////////////////////////////////////////////////////////////////
+
+
+class dqpsk_mod(gr.hier_block):
+
+    def __init__(self, fg, spb, excess_bw):
+        """
+       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 fg: flow graph
+       @type fg: flow graph
+       @param spb: samples per baud >= 2
+       @type spb: integer
+       @param excess_bw: Root-raised cosine filter excess bandwidth
+       @type excess_bw: float
+       """
+        if not isinstance(spb, int) or spb < 2:
+            raise TypeError, "sbp must be an integer >= 2"
+        self.spb = spb
+
+       ntaps = 11 * spb
+
+        bits_per_symbol = self.bits_per_baud()
+        arity = pow(2,bits_per_symbol)
+        print "bits_per_symbol =", bits_per_symbol
+        
+        # turn bytes into k-bit vectors
+        self.bytes2chunks = \
+          gr.packed_to_unpacked_bb(bits_per_symbol, gr.GR_MSB_FIRST)
+
+        if True:
+            self.gray_coder = gr.map_bb(binary_to_gray[arity])
+        else:
+            self.gray_coder = None
+
+        self.diffenc = gr.diff_encoder_bb(arity)
+        
+        self.chunks2symbols = gr.chunks_to_symbols_bc(constellation[arity])
+
+        # pulse shaping filter
+       self.rrc_taps = gr.firdes.root_raised_cosine(
+               spb,            # gain  (spb since we're interpolating by spb)
+               spb,            # sampling rate
+               1.0,            # symbol rate
+               excess_bw,      # excess bandwidth (roll-off factor)
+                ntaps)
+
+       self.rrc_filter = gr.interp_fir_filter_ccf(spb, self.rrc_taps)
+
+       # Connect
+        if self.gray_coder:
+            fg.connect(self.bytes2chunks, self.gray_coder)
+            t = self.gray_coder
+        else:
+            t = self.bytes2chunks
+
+        fg.connect(t, self.diffenc, self.chunks2symbols, self.rrc_filter)
+        
+        if 1:
+            fg.connect(self.gray_coder,
+                       gr.file_sink(gr.sizeof_char, "graycoder.dat"))
+            fg.connect(self.diffenc,
+                       gr.file_sink(gr.sizeof_char, "diffenc.dat"))
+            
+       # Initialize base class
+       gr.hier_block.__init__(self, fg, self.bytes2chunks, self.rrc_filter)
+
+    def samples_per_baud(self):
+        return self.spb
+
+    def bits_per_baud(self=None):   # staticmethod that's also callable on an 
instance
+        return 1
+    bits_per_baud = staticmethod(bits_per_baud)      # make it a static 
method.  RTFM
+
+
+
+class 
dqpsk_demod__coherent_detection_of_differentially_encoded_psk(gr.hier_block):
+    def __init__(self, fg, spb, excess_bw, costas_alpha=0.005, gain_mu=0.05):
+        """
+       Hierarchical block for RRC-filtered QPSK demodulation
+
+       The input is the complex modulated signal at baseband.
+       The output is a stream of bits packed 1 bit per byte (LSB)
+
+       @param fg: flow graph
+       @type fg: flow graph
+       @param spb: samples per baud >= 2
+       @type spb: float
+       @param excess_bw: Root-raised cosine filter excess bandwidth
+       @type excess_bw: float
+        @param costas_alpha: loop filter gain
+        @type costas_alphas: float
+        @param gain_mu:
+        @type gain_mu: float
+       """
+        if spb < 2:
+            raise TypeError, "sbp must be >= 2"
+        self.spb = spb
+
+        bits_per_symbol = self.bits_per_baud()
+        arity = pow(2,bits_per_symbol)
+        print "bits_per_symbol =", bits_per_symbol
+
+        # Automatic gain control
+        self.preamp = gr.multiply_const_cc(10e-5)
+        self.agc = gr.agc_cc(1e-3, 1, 1)
+        
+        # Costas loop (carrier tracking)
+        # FIXME: need to decide how to handle this more generally; do we pull 
it from higher layer?
+        costas_order = 4
+        beta = .25 * costas_alpha * costas_alpha
+        self.costas_loop = gr.costas_loop_cc(costas_alpha, beta, 0.05, -0.05, 
costas_order)
+
+        # RRC data filter
+        ntaps = 11 * spb
+        self.rrc_taps = gr.firdes.root_raised_cosine(
+            1.0,                # gain 
+            spb,                # sampling rate
+            1.0,                # symbol rate
+            excess_bw,          # excess bandwidth (roll-off factor)
+            ntaps)
+
+        self.rrc_filter=gr.fir_filter_ccf(1, self.rrc_taps)
+
+        # symbol clock recovery
+        omega = spb
+        gain_omega = .25 * gain_mu * gain_mu
+        omega_rel_limit = 0.5
+        mu = 0.05
+        gain_mu = 0.1
+        self.clock_recovery=gr.clock_recovery_mm_cc(omega, gain_omega,
+                                                    mu, gain_mu, 
omega_rel_limit)
+
+        # find closest constellation point
+        #rot = .707 + .707j
+        rot = 1
+        rotated_const = map(lambda pt: pt * rot, constellation[arity])
+        print "rotated_const =", rotated_const
+
+        self.diffdec = gr.diff_phasor_cc()
+        #self.diffdec = gr.diff_decoder_bb(arity)
+
+        self.slicer = gr.constellation_decoder_cb(rotated_const, range(arity))
+        self.gray_decoder = gr.map_bb(gray_to_binary[arity])
+        
+        # unpack the k bit vector into a stream of bits
+        self.unpack = gr.unpack_k_bits_bb(bits_per_symbol)
+
+        fg.connect(self.preamp, self.agc, self.costas_loop, self.rrc_filter, 
self.clock_recovery,
+                   self.diffdec, self.slicer, self.gray_decoder, self.unpack)
+        #fg.connect(self.preamp, self.agc, self.costas_loop, self.rrc_filter, 
self.clock_recovery,
+        #           self.slicer, self.diffdec, self.gray_decoder, self.unpack)
+        
+        # Debug sinks
+        if 1:
+            fg.connect(self.agc,
+                       gr.file_sink(gr.sizeof_gr_complex, "agc.dat"))
+            fg.connect(self.costas_loop,
+                       gr.file_sink(gr.sizeof_gr_complex, "costas_loop.dat"))
+            fg.connect(self.rrc_filter,
+                       gr.file_sink(gr.sizeof_gr_complex, "rrc.dat"))
+            fg.connect(self.clock_recovery,
+                       gr.file_sink(gr.sizeof_gr_complex, 
"clock_recovery.dat"))
+            fg.connect(self.slicer,
+                       gr.file_sink(gr.sizeof_char, "slicer.dat"))
+            fg.connect(self.diffdec,
+                       gr.file_sink(gr.sizeof_gr_complex, "diffdec.dat"))
+            #fg.connect(self.diffdec,
+            #          gr.file_sink(gr.sizeof_char, "diffdec.dat"))
+            fg.connect(self.unpack,
+                       gr.file_sink(gr.sizeof_char, "unpack.dat"))
+
+        # Initialize base class
+        gr.hier_block.__init__(self, fg, self.preamp, self.unpack)
+
+    def samples_per_baud(self):
+        return self.spb
+
+    def bits_per_baud(self=None):   # staticmethod that's also callable on an 
instance
+        return 1
+    bits_per_baud = staticmethod(bits_per_baud)      # make it a static 
method.  RTFM
+
+
+dqpsk_demod = dqpsk_demod__coherent_detection_of_differentially_encoded_psk
+

Index: pkt.py
===================================================================
RCS file: pkt.py
diff -N pkt.py
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ pkt.py      28 Jun 2006 18:15:23 -0000      1.1
@@ -0,0 +1,156 @@
+#
+# Copyright 2005,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 2, 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., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+# 
+
+from math import pi
+import Numeric
+
+from gnuradio import gr, packet_utils
+import gnuradio.gr.gr_threading as _threading
+
+
+# /////////////////////////////////////////////////////////////////////////////
+#                   mod/demod with packets as i/o
+# /////////////////////////////////////////////////////////////////////////////
+
+class mod_pkts(gr.hier_block):
+    """
+    Wrap an arbitrary digital modulator in our packet handling framework.
+
+    Send packets by calling send_pkt
+    """
+    def __init__(self, fg, modulator, access_code=None, msgq_limit=2, 
pad_for_usrp=True):
+        """
+       Hierarchical block for sending packets
+
+        Packets to be sent are enqueued by calling send_pkt.
+        The output is the complex modulated signal at baseband.
+
+       @param fg: flow graph
+       @type fg: flow graph
+        @param modulator: instance of modulator class (gr_block or hier_block)
+        @type modulator: complex baseband out
+        @param access_code: AKA sync vector
+        @type access_code: string of 1's and 0's between 1 and 64 long
+        @param msgq_limit: maximum number of messages in message queue
+        @type msgq_limit: int
+        @param pad_for_usrp: If true, packets are padded such that they end up 
a multiple of 128 samples
+
+        See gmsk_mod for remaining parameters
+        """
+        self._modulator = modulator
+        self._pad_for_usrp = pad_for_usrp
+
+        if access_code is None:
+            access_code = packet_utils.default_access_code
+        if not packet_utils.is_1_0_string(access_code):
+            raise ValueError, "Invalid access_code %r. Must be string of 1's 
and 0's" % (access_code,)
+        self._access_code = access_code
+
+        # accepts messages from the outside world
+        self._pkt_input = gr.message_source(gr.sizeof_char, msgq_limit)
+        fg.connect(self._pkt_input, self._modulator)
+        gr.hier_block.__init__(self, fg, None, self._modulator)
+
+    def send_pkt(self, payload='', eof=False):
+        """
+        Send the payload.
+
+        @param payload: data to send
+        @type payload: string
+        """
+        if eof:
+            msg = gr.message(1) # tell self._pkt_input we're not sending any 
more packets
+        else:
+            # print "original_payload =", string_to_hex_list(payload)
+            pkt = packet_utils.make_packet(payload,
+                                           self._modulator.samples_per_baud(),
+                                           self._modulator.bits_per_baud(),
+                                           self._access_code,
+                                           self._pad_for_usrp)
+            #print "pkt =", string_to_hex_list(pkt)
+            msg = gr.message_from_string(pkt)
+        self._pkt_input.msgq().insert_tail(msg)
+
+
+
+class demod_pkts(gr.hier_block):
+    """
+    Wrap an arbitrary digital demodulator in our packet handling framework.
+
+    The input is complex baseband.  When packets are demodulated, they are 
passed to the
+    app via the callback.
+    """
+
+    def __init__(self, fg, demodulator, access_code=None, callback=None, 
threshold=-1):
+        """
+       Hierarchical block for demodulating and deframing packets.
+
+       The input is the complex modulated signal at baseband.
+        Demodulated packets are sent to the handler.
+
+       @param fg: flow graph
+       @type fg: flow graph
+        @param demodulator: instance of demodulator class (gr_block or 
hier_block)
+        @type demodulator: complex baseband in
+        @param access_code: AKA sync vector
+        @type access_code: string of 1's and 0's
+        @param callback:  function of two args: ok, payload
+        @type callback: ok: bool; payload: string
+        @param threshold: detect access_code with up to threshold bits wrong 
(-1 -> use default)
+        @type threshold: int
+       """
+
+        self._demodulator = demodulator
+        if access_code is None:
+            access_code = packet_utils.default_access_code
+        if not packet_utils.is_1_0_string(access_code):
+            raise ValueError, "Invalid access_code %r. Must be string of 1's 
and 0's" % (access_code,)
+        self._access_code = access_code
+
+        if threshold == -1:
+            threshold = 12              # FIXME raise exception
+
+        self._rcvd_pktq = gr.msg_queue()          # holds packets from the PHY
+        self.correlator = gr.correlate_access_code_bb(access_code, threshold)
+
+        self.framer_sink = gr.framer_sink_1(self._rcvd_pktq)
+        fg.connect(self._demodulator, self.correlator, self.framer_sink)
+        
+        gr.hier_block.__init__(self, fg, self._demodulator, None)
+        self._watcher = _queue_watcher_thread(self._rcvd_pktq, callback)
+
+
+class _queue_watcher_thread(_threading.Thread):
+    def __init__(self, rcvd_pktq, callback):
+        _threading.Thread.__init__(self)
+        self.setDaemon(1)
+        self.rcvd_pktq = rcvd_pktq
+        self.callback = callback
+        self.keep_running = True
+        self.start()
+
+
+    def run(self):
+        while self.keep_running:
+            msg = self.rcvd_pktq.delete_head()
+            ok, payload = packet_utils.unmake_packet(msg.to_string())
+            if self.callback:
+                self.callback(ok, payload)

Index: qpsk.py
===================================================================
RCS file: qpsk.py
diff -N qpsk.py
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ qpsk.py     28 Jun 2006 18:15:23 -0000      1.1
@@ -0,0 +1,418 @@
+#
+# Copyright 2005,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 2, 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., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+# 
+
+# See gnuradio-examples/python/gmsk2 for examples
+
+"""
+PSK and differential PSK modulation and demodulation.
+"""
+
+from gnuradio import gr, gru
+from math import pi, sqrt
+import cmath
+import Numeric
+from pprint import pprint
+
+_use_gray_code = True
+
+def make_constellation(m):
+    return [cmath.exp(i * 2 * pi / m * 1j) for i in range(m)]
+        
+# Common definition of constellations for Tx and Rx
+constellation = {
+    2 : make_constellation(2),           # BPSK
+    4 : make_constellation(4),           # QPSK
+    8 : make_constellation(8)            # 8PSK
+    }
+
+if 0:
+    print "const(2) ="
+    pprint(constellation[2])
+    print "const(4) ="
+    pprint(constellation[4])
+    print "const(8) ="
+    pprint(constellation[8])
+
+
+if _use_gray_code:
+    # -----------------------
+    # Do Gray code
+    # -----------------------
+    # binary to gray coding
+    binary_to_gray = {
+        2 : (0, 1),
+        4 : (0, 1, 3, 2),
+        8 : (0, 1, 3, 2, 7, 6, 4, 5)
+        }
+    
+    # gray to binary
+    gray_to_binary = {
+        2 : (0, 1),
+        4 : (0, 1, 3, 2),
+        8 : (0, 1, 3, 2, 6, 7, 5, 4)
+        }
+else:
+    # -----------------------
+    # Don't Gray code
+    # -----------------------
+    # identity mapping
+    binary_to_gray = {
+        2 : (0, 1),
+        4 : (0, 1, 2, 3),
+        8 : (0, 1, 2, 3, 4, 5, 6, 7)
+        }
+    
+    # identity mapping
+    gray_to_binary = {
+        2 : (0, 1),
+        4 : (0, 1, 2, 3),
+        8 : (0, 1, 2, 3, 4, 5, 6, 7)
+        }
+
+
+# /////////////////////////////////////////////////////////////////////////////
+#            mPSK mod/demod with steams of bytes as data i/o
+# /////////////////////////////////////////////////////////////////////////////
+
+
+class mpsk_mod(gr.hier_block):
+
+    def __init__(self, fg, spb, arity, excess_bw, diff=False):
+        """
+       Hierarchical block for RRC-filtered PSK modulation.
+
+       The input is a byte stream (unsigned char) and the
+       output is the complex modulated signal at baseband.
+
+       @param fg: flow graph
+       @type fg: flow graph
+       @param spb: samples per baud >= 2
+       @type spb: integer
+       @param excess_bw: Root-raised cosine filter excess bandwidth
+       @type excess_bw: float
+        @param arity: whick PSK: 2, 4, 8
+        @type arity: int in {2, 4, 8}
+        @param diff: differential PSK if true
+        @type diff: bool
+       """
+        if not isinstance(spb, int) or spb < 2:
+            raise TypeError, "sbp must be an integer >= 2"
+        self.spb = spb
+
+        if not arity in (2, 4):
+            raise ValueError, "n must be 2, 4, or 8"
+
+       ntaps = 11 * spb
+
+        bits_per_symbol = int(gru.log2(arity))
+        self.bits_per_symbol = bits_per_symbol
+        print "bits_per_symbol =", bits_per_symbol
+        
+        # turn bytes into k-bit vectors
+        self.bytes2chunks = \
+          gr.packed_to_unpacked_bb(bits_per_symbol, gr.GR_MSB_FIRST)
+
+        if True or arity > 2:
+            self.gray_coder = gr.map_bb(binary_to_gray[arity])
+        else:
+            self.gray_coder = None
+
+        if diff:
+            self.diffenc = gr.diff_encoder_bb(arity)
+        else:
+            self.diffenc = None
+
+        self.chunks2symbols = gr.chunks_to_symbols_bc(constellation[arity])
+
+        # pulse shaping filter
+       self.rrc_taps = gr.firdes.root_raised_cosine(
+               spb,            # gain  (spb since we're interpolating by spb)
+               spb,            # sampling rate
+               1.0,            # symbol rate
+               excess_bw,      # excess bandwidth (roll-off factor)
+                ntaps)
+
+       self.rrc_filter = gr.interp_fir_filter_ccf(spb, self.rrc_taps)
+
+       # Connect
+        if self.gray_coder:
+            fg.connect(self.bytes2chunks, self.gray_coder)
+            t = self.gray_coder
+        else:
+            t = self.bytes2chunks
+
+        if diff:
+            fg.connect(t, self.diffenc, self.chunks2symbols, self.rrc_filter)
+        else:
+            fg.connect(t, self.chunks2symbols, self.rrc_filter)
+
+        if 1:
+            fg.connect(self.gray_coder,
+                       gr.file_sink(gr.sizeof_char, "graycoder.dat"))
+            if diff:
+                fg.connect(self.diffenc,
+                           gr.file_sink(gr.sizeof_char, "diffenc.dat"))
+            
+       # Initialize base class
+       gr.hier_block.__init__(self, fg, self.bytes2chunks, self.rrc_filter)
+
+    def samples_per_baud(self):
+        return self.spb
+
+    def bits_per_baud(self):
+        return self.bits_per_symbol
+
+
+class 
mpsk_demod__coherent_detection_of_differentially_encoded_psk(gr.hier_block):
+    def __init__(self, fg, spb, arity, excess_bw, diff=False, 
costas_alpha=0.005, gain_mu=0.05):
+        """
+       Hierarchical block for RRC-filtered PSK demodulation
+
+       The input is the complex modulated signal at baseband.
+       The output is a stream of bits packed 1 bit per byte (LSB)
+
+       @param fg: flow graph
+       @type fg: flow graph
+       @param spb: samples per baud >= 2
+       @type spb: float
+       @param excess_bw: Root-raised cosine filter excess bandwidth
+       @type excess_bw: float
+        @param arity: whick PSK: 2, 4, 8
+        @type arity: int in {2, 4, 8}
+        @param diff: differential PSK if true
+        @type diff: bool
+        @param costas_alpha: loop filter gain
+        @type costas_alphas: float
+        @param gain_mu:
+        @type gain_mu: float
+       """
+        if spb < 2:
+            raise TypeError, "sbp must be >= 2"
+        self.spb = spb
+
+        if not arity in (2, 4):
+            raise ValueError, "n must be 2 or 4"
+
+        if not diff and arity==4:
+            raise NotImplementedError, "non-differential QPSK not supported 
yet"
+
+        bits_per_symbol = int(gru.log2(arity))
+        print "bits_per_symbol =", bits_per_symbol
+
+        # Automatic gain control
+        self.agc = gr.agc_cc(1e-3, 1, 1)
+        
+        # Costas loop (carrier tracking)
+        # FIXME: need to decide how to handle this more generally; do we pull 
it from higher layer?
+        if arity == 2:
+            costas_order = 2
+            costas_alpha *= 15   # 2nd order loop needs more gain
+        else:
+            costas_order = 4
+        beta = .25 * costas_alpha * costas_alpha
+        self.costas_loop = gr.costas_loop_cc(costas_alpha, beta, 0.05, -0.05, 
costas_order)
+
+        # RRC data filter
+        ntaps = 11 * spb
+        self.rrc_taps = gr.firdes.root_raised_cosine(
+            1.0,                # gain 
+            spb,                # sampling rate
+            1.0,                # symbol rate
+            excess_bw,          # excess bandwidth (roll-off factor)
+            ntaps)
+
+        self.rrc_filter=gr.fir_filter_ccf(1, self.rrc_taps)
+
+        # symbol clock recovery
+        omega = spb
+        gain_omega = .25 * gain_mu * gain_mu
+        omega_rel_limit = 0.5
+        mu = 0.05
+        gain_mu = 0.1
+        self.clock_recovery=gr.clock_recovery_mm_cc(omega, gain_omega,
+                                                    mu, gain_mu, 
omega_rel_limit)
+
+        # find closest constellation point
+        #rot = .707 + .707j
+        rot = 1
+        rotated_const = map(lambda pt: pt * rot, constellation[arity])
+        print "rotated_const =", rotated_const
+
+        if(diff):
+            self.diffdec = gr.diff_phasor_cc()
+            #self.diffdec = gr.diff_decoder_bb(arity)
+
+        self.slicer = gr.constellation_decoder_cb(rotated_const, range(arity))
+        self.gray_decoder = gr.map_bb(gray_to_binary[arity])
+        
+        # unpack the k bit vector into a stream of bits
+        self.unpack = gr.unpack_k_bits_bb(bits_per_symbol)
+
+        if(diff):
+            fg.connect(self.agc, self.costas_loop, self.rrc_filter, 
self.clock_recovery,
+                       self.diffdec, self.slicer, self.gray_decoder, 
self.unpack)
+        else:
+            fg.connect(self.agc, self.costas_loop, self.rrc_filter, 
self.clock_recovery,
+                       self.slicer, self.gray_decoder, self.unpack)
+
+        #fg.connect(self.agc, self.costas_loop, self.rrc_filter, 
self.clock_recovery,
+        #           self.slicer, self.diffdec, self.gray_decoder, self.unpack)
+        
+        # Debug sinks
+        if 1:
+            fg.connect(self.agc,
+                       gr.file_sink(gr.sizeof_gr_complex, "agc.dat"))
+            fg.connect(self.costas_loop,
+                       gr.file_sink(gr.sizeof_gr_complex, "costas_loop.dat"))
+            fg.connect(self.rrc_filter,
+                       gr.file_sink(gr.sizeof_gr_complex, "rrc.dat"))
+            fg.connect(self.clock_recovery,
+                       gr.file_sink(gr.sizeof_gr_complex, 
"clock_recovery.dat"))
+            fg.connect(self.slicer,
+                       gr.file_sink(gr.sizeof_char, "slicer.dat"))
+            if(diff):
+                fg.connect(self.diffdec,
+                           gr.file_sink(gr.sizeof_gr_complex, "diffdec.dat"))
+                #fg.connect(self.diffdec,
+                #          gr.file_sink(gr.sizeof_char, "diffdec.dat"))
+            fg.connect(self.unpack,
+                       gr.file_sink(gr.sizeof_char, "unpack.dat"))
+
+        # Initialize base class
+        gr.hier_block.__init__(self, fg, self.agc, self.unpack)
+
+    def samples_per_baud(self):
+        return self.spb
+
+    def bits_per_baud(self):
+        return self.bits_per_symbol
+
+
+#########################################################################
+
+class 
mpsk_demod__coherent_detection_of_nondifferentially_encoded_psk(gr.hier_block):
+    def __init__(self, fg, spb, arity, excess_bw, diff=False, 
costas_alpha=0.005, gain_mu=0.05):
+        """
+       Hierarchical block for RRC-filtered PSK demodulation
+
+       The input is the complex modulated signal at baseband.
+       The output is a stream of bits packed 1 bit per byte (LSB)
+
+       @param fg: flow graph
+       @type fg: flow graph
+       @param spb: samples per baud >= 2
+       @type spb: float
+       @param excess_bw: Root-raised cosine filter excess bandwidth
+       @type excess_bw: float
+        @param arity: whick PSK: 2, 4, 8
+        @type arity: int in {2, 4, 8}
+        @param diff: differential PSK if true
+        @type diff: bool
+        @param costas_alpha: loop filter gain
+        @type costas_alphas: float
+        @param gain_mu:
+        @type gain_mu: float
+       """
+        if spb < 2:
+            raise TypeError, "sbp must be >= 2"
+        self.spb = spb
+
+        if not arity in (2, 4):
+            raise ValueError, "n must be 2 or 4"
+
+        bits_per_symbol = int(gru.log2(arity))
+        print "bits_per_symbol =", bits_per_symbol
+
+        # Automatic gain control
+        self.agc = gr.agc_cc(1e-3, 1, 1)
+        
+        # Costas loop (carrier tracking)
+        # FIXME: need to decide how to handle this more generally; do we pull 
it from higher layer?
+        if arity == 2:
+            costas_order = 2
+            costas_alpha *= 15   # 2nd order loop needs more gain
+        else:
+            costas_order = 4
+        beta = .25 * costas_alpha * costas_alpha
+        self.costas_loop = gr.costas_loop_cc(costas_alpha, beta, 0.05, -0.05, 
costas_order)
+
+        # RRC data filter
+        ntaps = 11 * spb
+        self.rrc_taps = gr.firdes.root_raised_cosine(
+            1.0,                # gain 
+            spb,                # sampling rate
+            1.0,                # symbol rate
+            excess_bw,          # excess bandwidth (roll-off factor)
+            ntaps)
+
+        self.rrc_filter=gr.fir_filter_ccf(1, self.rrc_taps)
+
+        # symbol clock recovery
+        omega = spb
+        gain_omega = .25 * gain_mu * gain_mu
+        omega_rel_limit = 0.5
+        mu = 0.05
+        gain_mu = 0.1
+        self.clock_recovery=gr.clock_recovery_mm_cc(omega, gain_omega,
+                                                    mu, gain_mu, 
omega_rel_limit)
+
+        # find closest constellation point
+        #rot = .707 + .707j
+        rot = 1
+        rotated_const = map(lambda pt: pt * rot, constellation[arity])
+        print "rotated_const =", rotated_const
+
+        self.slicer = gr.constellation_decoder_cb(rotated_const, range(arity))
+        self.gray_decoder = gr.map_bb(gray_to_binary[arity])
+        
+        # unpack the k bit vector into a stream of bits
+        self.unpack = gr.unpack_k_bits_bb(bits_per_symbol)
+
+        fg.connect(self.agc, self.costas_loop, self.rrc_filter, 
self.clock_recovery,
+                   self.slicer, self.gray_decoder, self.unpack)
+        
+        # Debug sinks
+        if 1:
+            fg.connect(self.agc,
+                       gr.file_sink(gr.sizeof_gr_complex, "agc.dat"))
+            fg.connect(self.costas_loop,
+                       gr.file_sink(gr.sizeof_gr_complex, "costas_loop.dat"))
+            fg.connect(self.rrc_filter,
+                       gr.file_sink(gr.sizeof_gr_complex, "rrc.dat"))
+            fg.connect(self.clock_recovery,
+                       gr.file_sink(gr.sizeof_gr_complex, 
"clock_recovery.dat"))
+            fg.connect(self.slicer,
+                       gr.file_sink(gr.sizeof_char, "slicer.dat"))
+            fg.connect(self.unpack,
+                       gr.file_sink(gr.sizeof_char, "unpack.dat"))
+
+        # Initialize base class
+        gr.hier_block.__init__(self, fg, self.agc, self.unpack)
+
+    def samples_per_baud(self):
+        return self.spb
+
+    def bits_per_baud(self):
+        return self.bits_per_symbol
+
+
+mpsk_demod = mpsk_demod__coherent_detection_of_differentially_encoded_psk
+#mpsk_demod = mpsk_demod__coherent_detection_of_nondifferentially_encoded_psk




reply via email to

[Prev in Thread] Current Thread [Next in Thread]