diff options
-rw-r--r-- | gr-digital/python/__init__.py | 1 | ||||
-rw-r--r-- | gr-digital/python/gmsk.py | 106 |
2 files changed, 43 insertions, 64 deletions
diff --git a/gr-digital/python/__init__.py b/gr-digital/python/__init__.py index 4046f7faf..7173fa09d 100644 --- a/gr-digital/python/__init__.py +++ b/gr-digital/python/__init__.py @@ -26,6 +26,7 @@ from psk2 import * from bpsk import * from qpsk import * from qam import * +from gmsk import * from pkt import * from packet_utils import * from crc import * diff --git a/gr-digital/python/gmsk.py b/gr-digital/python/gmsk.py index 3b6c016a0..ba122821e 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) |