From 245ef56d20f1c947e3c0f42e2edf15515e00db10 Mon Sep 17 00:00:00 2001
From: Tom Rondeau <trondeau@vt.edu>
Date: Tue, 30 Aug 2011 17:40:42 -0400
Subject: digital: adding GMSK as a modulation type. Updated to use PFB-based
 clock recovery alg instead of M&M.

---
 gr-digital/python/gmsk.py | 106 ++++++++++++++++++----------------------------
 1 file changed, 42 insertions(+), 64 deletions(-)

(limited to 'gr-digital/python/gmsk.py')

diff --git a/gr-digital/python/gmsk.py b/gr-digital/python/gmsk.py
index 3b6c016a0b..ba122821e1 100644
--- a/gr-digital/python/gmsk.py
+++ b/gr-digital/python/gmsk.py
@@ -25,7 +25,9 @@
 # See gnuradio-examples/python/digital for examples
 
 from gnuradio import gr
-from gnuradio import modulation_utils
+import digital_swig
+import modulation_utils2
+
 from math import pi
 import numpy
 from pprint import pprint
@@ -37,11 +39,9 @@ _def_bt = 0.35
 _def_verbose = False
 _def_log = False
 
-_def_gain_mu = None
-_def_mu = 0.5
-_def_freq_error = 0.0
-_def_omega_relative_limit = 0.005
-
+# Symbol timing recovery 
+_def_timing_bw = 2*pi/100.0
+_def_timing_max_dev = 1.5
 
 # /////////////////////////////////////////////////////////////////////////////
 #                              GMSK modulator
@@ -79,7 +79,8 @@ class gmsk_mod(gr.hier_block2):
         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" % (samples_per_symbol,))
+            raise TypeError, ("samples_per_symbol must be an integer >= 2, is %r" % \
+                                  (samples_per_symbol,))
 
 	ntaps = 4 * samples_per_symbol			# up to 3 bits in filter at once
 	sensitivity = (pi / 2) / samples_per_symbol	# phase change per bit = pi / 2
@@ -128,11 +129,11 @@ class gmsk_mod(gr.hier_block2):
     def _setup_logging(self):
         print "Modulation logging turned on."
         self.connect(self.nrz,
-                     gr.file_sink(gr.sizeof_float, "nrz.dat"))
+                     gr.file_sink(gr.sizeof_float, "tx_gmsk_nrz.32f"))
         self.connect(self.gaussian_filter,
-                     gr.file_sink(gr.sizeof_float, "gaussian_filter.dat"))
+                     gr.file_sink(gr.sizeof_float, "tx_gmsk_gaussian_filter.32f"))
         self.connect(self.fmmod,
-                     gr.file_sink(gr.sizeof_gr_complex, "fmmod.dat"))
+                     gr.file_sink(gr.sizeof_gr_complex, "tx_gmsk_fmmod.32fc"))
 
 
     def add_options(parser):
@@ -148,7 +149,7 @@ class gmsk_mod(gr.hier_block2):
         """
         Given command line options, create dictionary suitable for passing to __init__
         """
-        return modulation_utils.extract_kwargs_from_options(gmsk_mod.__init__,
+        return modulation_utils2.extract_kwargs_from_options(gmsk_mod.__init__,
                                                             ('self',), options)
     extract_kwargs_from_options=staticmethod(extract_kwargs_from_options)
 
@@ -162,10 +163,8 @@ class gmsk_demod(gr.hier_block2):
 
     def __init__(self,
                  samples_per_symbol=_def_samples_per_symbol,
-                 gain_mu=_def_gain_mu,
-                 mu=_def_mu,
-                 omega_relative_limit=_def_omega_relative_limit,
-                 freq_error=_def_freq_error,
+                 bt=_def_bt,
+                 timing_bw=_def_timing_bw,
                  verbose=_def_verbose,
                  log=_def_log):
         """
@@ -177,21 +176,12 @@ class gmsk_demod(gr.hier_block2):
 
 	@param samples_per_symbol: samples per baud
 	@type samples_per_symbol: integer
+        @param timing_bw: timing recovery loop lock-in bandwidth
+        @type timing_bw: float
         @param verbose: Print information about modulator?
         @type verbose: bool
         @param log: Print modualtion data to files?
         @type log: bool 
-
-        Clock recovery parameters.  These all have reasonble defaults.
-        
-        @param gain_mu: controls rate of mu adjustment
-        @type gain_mu: float
-        @param mu: fractional delay [0.0, 1.0]
-        @type mu: float
-        @param omega_relative_limit: sets max variation in omega
-        @type omega_relative_limit: float, typically 0.000200 (200 ppm)
-        @param freq_error: bit rate error as a fraction
-        @param float
 	"""
 
 	gr.hier_block2.__init__(self, "gmsk_demod",
@@ -199,33 +189,31 @@ class gmsk_demod(gr.hier_block2):
 				gr.io_signature(1, 1, gr.sizeof_char))       # Output signature
 
         self._samples_per_symbol = samples_per_symbol
-        self._gain_mu = gain_mu
-        self._mu = mu
-        self._omega_relative_limit = omega_relative_limit
-        self._freq_error = freq_error
+        self._bt = bt
+        self._timing_bw = timing_bw
+        self._timing_max_dev= _def_timing_max_dev
         
         if samples_per_symbol < 2:
             raise TypeError, "samples_per_symbol >= 2, is %f" % samples_per_symbol
 
-        self._omega = samples_per_symbol*(1+self._freq_error)
-
-        if not self._gain_mu:
-            self._gain_mu = 0.175
-            
-	self._gain_omega = .25 * self._gain_mu * self._gain_mu        # critically damped
-
 	# Demodulate FM
 	sensitivity = (pi / 2) / samples_per_symbol
 	self.fmdemod = gr.quadrature_demod_cf(1.0 / sensitivity)
 
 	# the clock recovery block tracks the symbol clock and resamples as needed.
 	# the output of the block is a stream of soft symbols (float)
-	self.clock_recovery = gr.clock_recovery_mm_ff(self._omega, self._gain_omega,
-                                                      self._mu, self._gain_mu,
-                                                      self._omega_relative_limit)
-
+        nfilts = 32
+        ntaps = 11 * int(self._samples_per_symbol*nfilts) 
+	taps = gr.firdes.gaussian(nfilts,
+                                  nfilts*self._samples_per_symbol,
+                                  self._bt, ntaps)
+        self.clock_recovery = \
+            gr.pfb_clock_sync_fff(self._samples_per_symbol,
+                                  self._timing_bw, taps,
+                                  nfilts, nfilts//2, self._timing_max_dev)
+            
         # slice the floats at 0, outputting 1 bit (the LSB of the output byte) per sample
-        self.slicer = gr.binary_slicer_fb()
+        self.slicer = digital_swig.binary_slicer_fb()
 
         if verbose:
             self._print_verbage()
@@ -245,48 +233,38 @@ class gmsk_demod(gr.hier_block2):
 
 
     def _print_verbage(self):
-        print "bits per symbol = %d" % self.bits_per_symbol()
-        print "M&M clock recovery omega = %f" % self._omega
-        print "M&M clock recovery gain mu = %f" % self._gain_mu
-        print "M&M clock recovery mu = %f" % self._mu
-        print "M&M clock recovery omega rel. limit = %f" % self._omega_relative_limit
-        print "frequency error = %f" % self._freq_error
+        print "bits per symbol:     %d" % self.bits_per_symbol()
+        print "Bandwidth-Time Prod: %f" % self._bw
+        print "Timing bandwidth:    %.2e" % self._timing_bw
 
 
     def _setup_logging(self):
         print "Demodulation logging turned on."
         self.connect(self.fmdemod,
-                    gr.file_sink(gr.sizeof_float, "fmdemod.dat"))
+                    gr.file_sink(gr.sizeof_float, "rx_gmsk_fmdemod.32f"))
         self.connect(self.clock_recovery,
-                    gr.file_sink(gr.sizeof_float, "clock_recovery.dat"))
+                    gr.file_sink(gr.sizeof_float, "rx_gmsk_clock_recovery.32f"))
         self.connect(self.slicer,
-                    gr.file_sink(gr.sizeof_char, "slicer.dat"))
+                    gr.file_sink(gr.sizeof_char, "rx_gmsk_slicer.8b"))
 
     def add_options(parser):
         """
         Adds GMSK demodulation-specific options to the standard parser
         """
-        parser.add_option("", "--gain-mu", type="float", default=_def_gain_mu,
-                          help="M&M clock recovery gain mu [default=%default] (GMSK/PSK)")
-        parser.add_option("", "--mu", type="float", default=_def_mu,
-                          help="M&M clock recovery mu [default=%default] (GMSK/PSK)")
-        parser.add_option("", "--omega-relative-limit", type="float", default=_def_omega_relative_limit,
-                          help="M&M clock recovery omega relative limit [default=%default] (GMSK/PSK)")
-        parser.add_option("", "--freq-error", type="float", default=_def_freq_error,
-                          help="M&M clock recovery frequency error [default=%default] (GMSK)")
+        parser.add_option("", "--timing-bw", type="float", default=_def_timing_bw,
+                          help="set timing symbol sync loop gain lock-in bandwidth [default=%default]")
     add_options=staticmethod(add_options)
 
     def extract_kwargs_from_options(options):
         """
         Given command line options, create dictionary suitable for passing to __init__
         """
-        return modulation_utils.extract_kwargs_from_options(gmsk_demod.__init__,
-                                                            ('self',), options)
+        return modulation_utils2.extract_kwargs_from_options(gmsk_demod.__init__,
+                                                             ('self',), options)
     extract_kwargs_from_options=staticmethod(extract_kwargs_from_options)
 
-
 #
 # Add these to the mod/demod registry
 #
-modulation_utils.add_type_1_mod('gmsk', gmsk_mod)
-modulation_utils.add_type_1_demod('gmsk', gmsk_demod)
+modulation_utils2.add_type_1_mod('gmsk', gmsk_mod)
+modulation_utils2.add_type_1_demod('gmsk', gmsk_demod)
-- 
cgit v1.2.3