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., 51 Franklin Street,
# Boston, MA 02110-1301, 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
|