Houston, we have a trunk.
[debian/gnuradio] / gnuradio-core / src / python / gnuradio / blksimpl / gmsk2.py
1 #
2 # GMSK modulation and demodulation.  
3 #
4 #
5 # Copyright 2005,2006 Free Software Foundation, Inc.
6
7 # This file is part of GNU Radio
8
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)
12 # any later version.
13
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.
18
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.
23
24
25 # See gnuradio-examples/python/gmsk2 for examples
26
27 from gnuradio import gr
28 from math import pi
29 import Numeric
30
31 # /////////////////////////////////////////////////////////////////////////////
32 #            GMSK mod/demod with steams of bytes as data i/o
33 # /////////////////////////////////////////////////////////////////////////////
34
35 class gmsk2_mod(gr.hier_block):
36
37     def __init__(self, fg, spb = 2, bt = 0.3):
38         """
39         Hierarchical block for Gaussian Minimum Shift Key (GMSK)
40         modulation.
41
42         The input is a byte stream (unsigned char) and the
43         output is the complex modulated signal at baseband.
44
45         @param fg: flow graph
46         @type fg: flow graph
47         @param spb: samples per baud >= 2
48         @type spb: integer
49         @param bt: Gaussian filter bandwidth * symbol time
50         @type bt: float
51         """
52         if not isinstance(spb, int) or spb < 2:
53             raise TypeError, "sbp must be an integer >= 2"
54         self.spb = spb
55
56         ntaps = 4 * spb                 # up to 3 bits in filter at once
57         sensitivity = (pi / 2) / spb    # phase change per bit = pi / 2
58
59         # Turn it into NRZ data.
60         self.nrz = gr.bytes_to_syms()
61
62         # Form Gaussian filter
63
64         # Generate Gaussian response (Needs to be convolved with window below).
65         self.gaussian_taps = gr.firdes.gaussian(
66                 1,              # gain
67                 spb,            # symbol_rate
68                 bt,             # bandwidth * symbol time
69                 ntaps           # number of taps
70                 )
71
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)
75
76         # FM modulation
77         self.fmmod = gr.frequency_modulator_fc(sensitivity)
78                 
79         # Connect
80         fg.connect(self.nrz, self.gaussian_filter, self.fmmod)
81
82         # Initialize base class
83         gr.hier_block.__init__(self, fg, self.nrz, self.fmmod)
84
85     def samples_per_baud(self):
86         return self.spb
87
88     def bits_per_baud(self=None):   # staticmethod that's also callable on an instance
89         return 1
90     bits_per_baud = staticmethod(bits_per_baud)      # make it a static method.  RTFM
91
92
93 class gmsk2_demod(gr.hier_block):
94
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):
97         """
98         Hierarchical block for Gaussian Minimum Shift Key (GMSK)
99         demodulation.
100
101         The input is the complex modulated signal at baseband.
102         The output is a stream of symbols ready to be sliced at zero.
103
104         @param fg: flow graph
105         @type fg: flow graph
106         @param spb: samples per baud
107         @type spb: integer
108
109         Clock recovery parameters.  These all have reasonble defaults.
110         
111         @param omega: nominal relative freq (defaults to spb)
112         @type omega: float
113         @param gain_mu: controls rate of mu adjustment
114         @type gain_mu: float
115         @param mu: fractional delay [0.0, 1.0]
116         @type mu: float
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
120         @param float
121         """
122         if spb < 2:
123             raise TypeError, "sbp >= 2"
124         self.spb = spb
125         
126         if omega is None:
127             omega = spb*(1+freq_error)
128
129         gain_omega = .25*gain_mu*gain_mu        # critically damped
130
131         # Automatic gain control
132         self.preamp = gr.multiply_const_cc(10e-5)
133         self.agc = gr.agc_cc(1e-3, 1, 1, 1000)
134
135         # Demodulate FM
136         sensitivity = (pi / 2) / spb
137         self.fmdemod = gr.quadrature_demod_cf(1.0 / sensitivity)
138
139         alpha = 0.0008
140
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)
145
146         # slice the floats at 0, outputting 1 bit (the LSB of the output byte) per sample
147         self.slicer = gr.binary_slicer_fb()
148
149         fg.connect(self.preamp, self.agc, self.fmdemod, self.clock_recovery, self.slicer)
150         
151         # Initialize base class
152         gr.hier_block.__init__(self, fg, self.preamp, self.slicer)
153
154     def samples_per_baud(self):
155         return self.spb
156
157     def bits_per_baud(self=None):   # staticmethod that's also callable on an instance
158         return 1
159     bits_per_baud = staticmethod(bits_per_baud)      # make it a static method.  RTFM