summaryrefslogtreecommitdiff
path: root/gnuradio-core/src/python/gnuradio/blksimpl/gmsk2.py
blob: 68d189679d03f8769bbef9bddfd66a828855347e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
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