diff options
Diffstat (limited to 'gnuradio-core/src/python/gnuradio/blksimpl/gmsk2.py')
-rw-r--r-- | gnuradio-core/src/python/gnuradio/blksimpl/gmsk2.py | 159 |
1 files changed, 159 insertions, 0 deletions
diff --git a/gnuradio-core/src/python/gnuradio/blksimpl/gmsk2.py b/gnuradio-core/src/python/gnuradio/blksimpl/gmsk2.py new file mode 100644 index 0000000000..68d189679d --- /dev/null +++ b/gnuradio-core/src/python/gnuradio/blksimpl/gmsk2.py @@ -0,0 +1,159 @@ +# +# GMSK modulation and demodulation. +# +# +# 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 + +from gnuradio import gr +from math import pi +import Numeric + +# ///////////////////////////////////////////////////////////////////////////// +# GMSK mod/demod with steams of bytes as data i/o +# ///////////////////////////////////////////////////////////////////////////// + +class gmsk2_mod(gr.hier_block): + + def __init__(self, fg, spb = 2, bt = 0.3): + """ + Hierarchical block for Gaussian Minimum Shift Key (GMSK) + 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 bt: Gaussian filter bandwidth * symbol time + @type bt: float + """ + if not isinstance(spb, int) or spb < 2: + raise TypeError, "sbp must be an integer >= 2" + self.spb = spb + + ntaps = 4 * spb # up to 3 bits in filter at once + sensitivity = (pi / 2) / spb # phase change per bit = pi / 2 + + # Turn it into NRZ data. + self.nrz = gr.bytes_to_syms() + + # Form Gaussian filter + + # Generate Gaussian response (Needs to be convolved with window below). + self.gaussian_taps = gr.firdes.gaussian( + 1, # gain + spb, # symbol_rate + bt, # bandwidth * symbol time + ntaps # number of taps + ) + + self.sqwave = (1,) * spb # rectangular window + self.taps = Numeric.convolve(Numeric.array(self.gaussian_taps),Numeric.array(self.sqwave)) + self.gaussian_filter = gr.interp_fir_filter_fff(spb, self.taps) + + # FM modulation + self.fmmod = gr.frequency_modulator_fc(sensitivity) + + # Connect + fg.connect(self.nrz, self.gaussian_filter, self.fmmod) + + # Initialize base class + gr.hier_block.__init__(self, fg, self.nrz, self.fmmod) + + 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 gmsk2_demod(gr.hier_block): + + def __init__(self, fg, spb=2, omega=None, gain_mu=0.03, mu=0.5, + omega_relative_limit=0.000200, freq_error=0.0): + """ + Hierarchical block for Gaussian Minimum Shift Key (GMSK) + demodulation. + + The input is the complex modulated signal at baseband. + The output is a stream of symbols ready to be sliced at zero. + + @param fg: flow graph + @type fg: flow graph + @param spb: samples per baud + @type spb: integer + + Clock recovery parameters. These all have reasonble defaults. + + @param omega: nominal relative freq (defaults to spb) + @type omega: float + @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 + """ + if spb < 2: + raise TypeError, "sbp >= 2" + self.spb = spb + + if omega is None: + omega = spb*(1+freq_error) + + gain_omega = .25*gain_mu*gain_mu # critically damped + + # Automatic gain control + self.preamp = gr.multiply_const_cc(10e-5) + self.agc = gr.agc_cc(1e-3, 1, 1, 1000) + + # Demodulate FM + sensitivity = (pi / 2) / spb + self.fmdemod = gr.quadrature_demod_cf(1.0 / sensitivity) + + alpha = 0.0008 + + # 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(omega, gain_omega, mu, gain_mu, + omega_relative_limit) + + # slice the floats at 0, outputting 1 bit (the LSB of the output byte) per sample + self.slicer = gr.binary_slicer_fb() + + fg.connect(self.preamp, self.agc, self.fmdemod, self.clock_recovery, self.slicer) + + # Initialize base class + gr.hier_block.__init__(self, fg, self.preamp, self.slicer) + + 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 |