2 # GMSK modulation and demodulation.
5 # Copyright 2005,2006 Free Software Foundation, Inc.
7 # This file is part of GNU Radio
9 # GNU Radio is free software; you can redistribute it and/or modify
10 # it under the terms of the GNU General Public License as published by
11 # the Free Software Foundation; either version 2, or (at your option)
14 # GNU Radio is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 # GNU General Public License for more details.
19 # You should have received a copy of the GNU General Public License
20 # along with GNU Radio; see the file COPYING. If not, write to
21 # the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 # Boston, MA 02111-1307, USA.
25 # See gnuradio-examples/python/gmsk2 for examples
27 from gnuradio import gr
31 # /////////////////////////////////////////////////////////////////////////////
32 # GMSK mod/demod with steams of bytes as data i/o
33 # /////////////////////////////////////////////////////////////////////////////
35 class gmsk2_mod(gr.hier_block):
37 def __init__(self, fg, spb = 2, bt = 0.3):
39 Hierarchical block for Gaussian Minimum Shift Key (GMSK)
42 The input is a byte stream (unsigned char) and the
43 output is the complex modulated signal at baseband.
47 @param spb: samples per baud >= 2
49 @param bt: Gaussian filter bandwidth * symbol time
52 if not isinstance(spb, int) or spb < 2:
53 raise TypeError, "sbp must be an integer >= 2"
56 ntaps = 4 * spb # up to 3 bits in filter at once
57 sensitivity = (pi / 2) / spb # phase change per bit = pi / 2
59 # Turn it into NRZ data.
60 self.nrz = gr.bytes_to_syms()
62 # Form Gaussian filter
64 # Generate Gaussian response (Needs to be convolved with window below).
65 self.gaussian_taps = gr.firdes.gaussian(
68 bt, # bandwidth * symbol time
69 ntaps # number of taps
72 self.sqwave = (1,) * spb # rectangular window
73 self.taps = Numeric.convolve(Numeric.array(self.gaussian_taps),Numeric.array(self.sqwave))
74 self.gaussian_filter = gr.interp_fir_filter_fff(spb, self.taps)
77 self.fmmod = gr.frequency_modulator_fc(sensitivity)
80 fg.connect(self.nrz, self.gaussian_filter, self.fmmod)
82 # Initialize base class
83 gr.hier_block.__init__(self, fg, self.nrz, self.fmmod)
85 def samples_per_baud(self):
88 def bits_per_baud(self=None): # staticmethod that's also callable on an instance
90 bits_per_baud = staticmethod(bits_per_baud) # make it a static method. RTFM
93 class gmsk2_demod(gr.hier_block):
95 def __init__(self, fg, spb=2, omega=None, gain_mu=0.03, mu=0.5,
96 omega_relative_limit=0.000200, freq_error=0.0):
98 Hierarchical block for Gaussian Minimum Shift Key (GMSK)
101 The input is the complex modulated signal at baseband.
102 The output is a stream of symbols ready to be sliced at zero.
104 @param fg: flow graph
106 @param spb: samples per baud
109 Clock recovery parameters. These all have reasonble defaults.
111 @param omega: nominal relative freq (defaults to spb)
113 @param gain_mu: controls rate of mu adjustment
115 @param mu: fractional delay [0.0, 1.0]
117 @param omega_relative_limit: sets max variation in omega
118 @type omega_relative_limit: float, typically 0.000200 (200 ppm)
119 @param freq_error: bit rate error as a fraction
123 raise TypeError, "sbp >= 2"
127 omega = spb*(1+freq_error)
129 gain_omega = .25*gain_mu*gain_mu # critically damped
131 # Automatic gain control
132 self.preamp = gr.multiply_const_cc(10e-5)
133 self.agc = gr.agc_cc(1e-3, 1, 1, 1000)
136 sensitivity = (pi / 2) / spb
137 self.fmdemod = gr.quadrature_demod_cf(1.0 / sensitivity)
141 # the clock recovery block tracks the symbol clock and resamples as needed.
142 # the output of the block is a stream of soft symbols (float)
143 self.clock_recovery = gr.clock_recovery_mm_ff(omega, gain_omega, mu, gain_mu,
144 omega_relative_limit)
146 # slice the floats at 0, outputting 1 bit (the LSB of the output byte) per sample
147 self.slicer = gr.binary_slicer_fb()
149 fg.connect(self.preamp, self.agc, self.fmdemod, self.clock_recovery, self.slicer)
151 # Initialize base class
152 gr.hier_block.__init__(self, fg, self.preamp, self.slicer)
154 def samples_per_baud(self):
157 def bits_per_baud(self=None): # staticmethod that's also callable on an instance
159 bits_per_baud = staticmethod(bits_per_baud) # make it a static method. RTFM