~ubuntu-branches/ubuntu/precise/gnuradio/precise

« back to all changes in this revision

Viewing changes to gnuradio-core/src/python/gnuradio/blksimpl/dbpsk.py

  • Committer: Bazaar Package Importer
  • Author(s): Kamal Mostafa
  • Date: 2010-03-13 07:46:01 UTC
  • mfrom: (2.1.2 sid)
  • Revision ID: james.westby@ubuntu.com-20100313074601-zjsa893a87bozyh7
Tags: 3.2.2.dfsg-1ubuntu1
* Fix build for Ubuntu lucid (LP: #260406)
  - add binary package dep for libusrp0, libusrp2-0: adduser
  - debian/rules clean: remove pre-built Qt moc files

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#
2
 
# Copyright 2005,2006 Free Software Foundation, Inc.
3
 
4
 
# This file is part of GNU Radio
5
 
6
 
# GNU Radio is free software; you can redistribute it and/or modify
7
 
# it under the terms of the GNU General Public License as published by
8
 
# the Free Software Foundation; either version 3, or (at your option)
9
 
# any later version.
10
 
11
 
# GNU Radio is distributed in the hope that it will be useful,
12
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 
# GNU General Public License for more details.
15
 
16
 
# You should have received a copy of the GNU General Public License
17
 
# along with GNU Radio; see the file COPYING.  If not, write to
18
 
# the Free Software Foundation, Inc., 51 Franklin Street,
19
 
# Boston, MA 02110-1301, USA.
20
 
21
 
 
22
 
# See gnuradio-examples/python/gmsk2 for examples
23
 
 
24
 
"""
25
 
differential BPSK modulation and demodulation.
26
 
"""
27
 
 
28
 
from gnuradio import gr, gru, modulation_utils
29
 
from math import pi, sqrt
30
 
import psk
31
 
import cmath
32
 
import Numeric
33
 
from pprint import pprint
34
 
 
35
 
# default values (used in __init__ and add_options)
36
 
_def_samples_per_symbol = 2
37
 
_def_excess_bw = 0.35
38
 
_def_gray_code = True
39
 
_def_verbose = False
40
 
_def_log = False
41
 
 
42
 
_def_costas_alpha = None
43
 
_def_gain_mu = 0.03
44
 
_def_mu = 0.05
45
 
_def_omega_relative_limit = 0.005
46
 
 
47
 
 
48
 
# /////////////////////////////////////////////////////////////////////////////
49
 
#                             DBPSK modulator
50
 
# /////////////////////////////////////////////////////////////////////////////
51
 
 
52
 
class dbpsk_mod(gr.hier_block):
53
 
 
54
 
    def __init__(self, fg,
55
 
                 samples_per_symbol=_def_samples_per_symbol,
56
 
                 excess_bw=_def_excess_bw,
57
 
                 gray_code=_def_gray_code,
58
 
                 verbose=_def_verbose,
59
 
                 log=_def_log):
60
 
        """
61
 
        Hierarchical block for RRC-filtered differential BPSK modulation.
62
 
 
63
 
        The input is a byte stream (unsigned char) and the
64
 
        output is the complex modulated signal at baseband.
65
 
        
66
 
        @param fg: flow graph
67
 
        @type fg: flow graph
68
 
        @param samples_per_symbol: samples per baud >= 2
69
 
        @type samples_per_symbol: integer
70
 
        @param excess_bw: Root-raised cosine filter excess bandwidth
71
 
        @type excess_bw: float
72
 
        @param gray_code: Tell modulator to Gray code the bits
73
 
        @type gray_code: bool
74
 
        @param verbose: Print information about modulator?
75
 
        @type verbose: bool
76
 
        @param log: Log modulation data to files?
77
 
        @type log: bool
78
 
        """
79
 
 
80
 
        self._fg = fg
81
 
        self._samples_per_symbol = samples_per_symbol
82
 
        self._excess_bw = excess_bw
83
 
        self._gray_code = gray_code
84
 
 
85
 
        if not isinstance(self._samples_per_symbol, int) or self._samples_per_symbol < 2:
86
 
            raise TypeError, ("sbp must be an integer >= 2, is %d" % self._samples_per_symbol)
87
 
        
88
 
        ntaps = 11 * self._samples_per_symbol
89
 
 
90
 
        arity = pow(2,self.bits_per_symbol())
91
 
       
92
 
        # turn bytes into k-bit vectors
93
 
        self.bytes2chunks = \
94
 
          gr.packed_to_unpacked_bb(self.bits_per_symbol(), gr.GR_MSB_FIRST)
95
 
 
96
 
        if self._gray_code:
97
 
            self.symbol_mapper = gr.map_bb(psk.binary_to_gray[arity])
98
 
        else:
99
 
            self.symbol_mapper = gr.map_bb(psk.binary_to_ungray[arity])
100
 
 
101
 
        self.diffenc = gr.diff_encoder_bb(arity)
102
 
        
103
 
        self.chunks2symbols = gr.chunks_to_symbols_bc(psk.constellation[arity])
104
 
 
105
 
        # pulse shaping filter
106
 
        self.rrc_taps = gr.firdes.root_raised_cosine(
107
 
            self._samples_per_symbol, # gain  (samples_per_symbol since we're
108
 
                                      # interpolating by samples_per_symbol)
109
 
            self._samples_per_symbol, # sampling rate
110
 
            1.0,                      # symbol rate
111
 
            self._excess_bw,          # excess bandwidth (roll-off factor)
112
 
            ntaps)
113
 
 
114
 
        self.rrc_filter = gr.interp_fir_filter_ccf(self._samples_per_symbol,
115
 
                                                   self.rrc_taps)
116
 
 
117
 
        # Connect
118
 
        fg.connect(self.bytes2chunks, self.symbol_mapper, self.diffenc,
119
 
                   self.chunks2symbols, self.rrc_filter)
120
 
 
121
 
        if verbose:
122
 
            self._print_verbage()
123
 
            
124
 
        if log:
125
 
            self._setup_logging()
126
 
            
127
 
        # Initialize base class
128
 
        gr.hier_block.__init__(self, self._fg, self.bytes2chunks, self.rrc_filter)
129
 
 
130
 
    def samples_per_symbol(self):
131
 
        return self._samples_per_symbol
132
 
 
133
 
    def bits_per_symbol(self=None):   # static method that's also callable on an instance
134
 
        return 1
135
 
    bits_per_symbol = staticmethod(bits_per_symbol)      # make it a static method.  RTFM
136
 
 
137
 
    def add_options(parser):
138
 
        """
139
 
        Adds DBPSK modulation-specific options to the standard parser
140
 
        """
141
 
        parser.add_option("", "--excess-bw", type="float", default=_def_excess_bw,
142
 
                          help="set RRC excess bandwith factor [default=%default]")
143
 
        parser.add_option("", "--no-gray-code", dest="gray_code",
144
 
                          action="store_false", default=True,
145
 
                          help="disable gray coding on modulated bits (PSK)")
146
 
    add_options=staticmethod(add_options)
147
 
 
148
 
    def extract_kwargs_from_options(options):
149
 
        """
150
 
        Given command line options, create dictionary suitable for passing to __init__
151
 
        """
152
 
        return modulation_utils.extract_kwargs_from_options(dbpsk_mod.__init__,
153
 
                                                            ('self', 'fg'), options)
154
 
    extract_kwargs_from_options=staticmethod(extract_kwargs_from_options)
155
 
 
156
 
 
157
 
    def _print_verbage(self):
158
 
        print "bits per symbol = %d" % self.bits_per_symbol()
159
 
        print "Gray code = %s" % self._gray_code
160
 
        print "RRC roll-off factor = %.2f" % self._excess_bw
161
 
 
162
 
    def _setup_logging(self):
163
 
        print "Modulation logging turned on."
164
 
        self._fg.connect(self.bytes2chunks,
165
 
                         gr.file_sink(gr.sizeof_char, "bytes2chunks.dat"))
166
 
        self._fg.connect(self.symbol_mapper,
167
 
                         gr.file_sink(gr.sizeof_char, "graycoder.dat"))
168
 
        self._fg.connect(self.diffenc,
169
 
                         gr.file_sink(gr.sizeof_char, "diffenc.dat"))
170
 
        self._fg.connect(self.chunks2symbols,
171
 
                         gr.file_sink(gr.sizeof_gr_complex, "chunks2symbols.dat"))
172
 
        self._fg.connect(self.rrc_filter,
173
 
                         gr.file_sink(gr.sizeof_gr_complex, "rrc_filter.dat"))
174
 
              
175
 
 
176
 
# /////////////////////////////////////////////////////////////////////////////
177
 
#                             DBPSK demodulator
178
 
#
179
 
#      Differentially coherent detection of differentially encoded BPSK
180
 
# /////////////////////////////////////////////////////////////////////////////
181
 
 
182
 
class dbpsk_demod(gr.hier_block):
183
 
 
184
 
    def __init__(self, fg,
185
 
                 samples_per_symbol=_def_samples_per_symbol,
186
 
                 excess_bw=_def_excess_bw,
187
 
                 costas_alpha=_def_costas_alpha,
188
 
                 gain_mu=_def_gain_mu,
189
 
                 mu=_def_mu,
190
 
                 omega_relative_limit=_def_omega_relative_limit,
191
 
                 gray_code=_def_gray_code,
192
 
                 verbose=_def_verbose,
193
 
                 log=_def_log):
194
 
        """
195
 
        Hierarchical block for RRC-filtered differential BPSK demodulation
196
 
 
197
 
        The input is the complex modulated signal at baseband.
198
 
        The output is a stream of bits packed 1 bit per byte (LSB)
199
 
 
200
 
        @param fg: flow graph
201
 
        @type fg: flow graph
202
 
        @param samples_per_symbol: samples per symbol >= 2
203
 
        @type samples_per_symbol: float
204
 
        @param excess_bw: Root-raised cosine filter excess bandwidth
205
 
        @type excess_bw: float
206
 
        @param costas_alpha: loop filter gain
207
 
        @type costas_alphas: float
208
 
        @param gain_mu: for M&M block
209
 
        @type gain_mu: float
210
 
        @param mu: for M&M block
211
 
        @type mu: float
212
 
        @param omega_relative_limit: for M&M block
213
 
        @type omega_relative_limit: float
214
 
        @param gray_code: Tell modulator to Gray code the bits
215
 
        @type gray_code: bool
216
 
        @param verbose: Print information about modulator?
217
 
        @type verbose: bool
218
 
        @param debug: Print modualtion data to files?
219
 
        @type debug: bool
220
 
        """
221
 
        
222
 
        self._fg = fg
223
 
        self._samples_per_symbol = samples_per_symbol
224
 
        self._excess_bw = excess_bw
225
 
        self._costas_alpha = costas_alpha
226
 
        self._gain_mu = gain_mu
227
 
        self._mu = mu
228
 
        self._omega_relative_limit = omega_relative_limit
229
 
        self._gray_code = gray_code
230
 
        
231
 
        if samples_per_symbol < 2:
232
 
            raise TypeError, "samples_per_symbol must be >= 2, is %r" % (samples_per_symbol,)
233
 
 
234
 
        arity = pow(2,self.bits_per_symbol())
235
 
 
236
 
        # Automatic gain control
237
 
        scale = (1.0/16384.0)
238
 
        self.pre_scaler = gr.multiply_const_cc(scale)   # scale the signal from full-range to +-1
239
 
        #self.agc = gr.agc2_cc(0.6e-1, 1e-3, 1, 1, 100)
240
 
        self.agc = gr.feedforward_agc_cc(16, 1.0)
241
 
 
242
 
        
243
 
        # Costas loop (carrier tracking)
244
 
        # The Costas loop is not needed for BPSK, though it can help. Turn the Costas loop on
245
 
        # by setting an alpha value not None.
246
 
        if self._costas_alpha is not None:
247
 
            costas_order = 2
248
 
            beta = .25 * self._costas_alpha * self._costas_alpha
249
 
            self.costas_loop = gr.costas_loop_cc(self._costas_alpha, beta, 0.002, -0.002, costas_order)
250
 
 
251
 
        # RRC data filter
252
 
        ntaps = 11 * self._samples_per_symbol
253
 
        self.rrc_taps = gr.firdes.root_raised_cosine(
254
 
            1.0,                      # gain 
255
 
            self._samples_per_symbol, # sampling rate
256
 
            1.0,                      # symbol rate
257
 
            self._excess_bw,          # excess bandwidth (roll-off factor)
258
 
            ntaps)
259
 
 
260
 
        self.rrc_filter=gr.fir_filter_ccf(1, self.rrc_taps)
261
 
 
262
 
        # symbol clock recovery
263
 
        omega = self._samples_per_symbol
264
 
        gain_omega = .25 * self._gain_mu * self._gain_mu
265
 
        self.clock_recovery=gr.clock_recovery_mm_cc(omega, gain_omega,
266
 
                                                    self._mu, self._gain_mu,
267
 
                                                    self._omega_relative_limit)
268
 
 
269
 
        # find closest constellation point
270
 
        rot = 1
271
 
        rotated_const = map(lambda pt: pt * rot, psk.constellation[arity])
272
 
        #print "rotated_const =", rotated_const
273
 
 
274
 
        self.diffdec = gr.diff_phasor_cc()
275
 
        #self.diffdec = gr.diff_decoder_bb(arity)
276
 
 
277
 
        self.slicer = gr.constellation_decoder_cb(rotated_const, range(arity))
278
 
 
279
 
        if self._gray_code:
280
 
            self.symbol_mapper = gr.map_bb(psk.gray_to_binary[arity])
281
 
        else:
282
 
            self.symbol_mapper = gr.map_bb(psk.ungray_to_binary[arity])
283
 
        
284
 
        # unpack the k bit vector into a stream of bits
285
 
        self.unpack = gr.unpack_k_bits_bb(self.bits_per_symbol())
286
 
 
287
 
        if verbose:
288
 
            self._print_verbage()
289
 
 
290
 
        if log:
291
 
            self._setup_logging()
292
 
 
293
 
        # Connect and Initialize base class
294
 
        if self._costas_alpha is not None:   # With Costas Loop
295
 
            self._fg.connect(self.pre_scaler, self.agc, self.costas_loop,
296
 
                             self.rrc_filter, self.clock_recovery, self.diffdec,
297
 
                             self.slicer, self.symbol_mapper, self.unpack)
298
 
        else: # Without Costas Loop
299
 
            self._fg.connect(self.pre_scaler, self.agc,
300
 
                             self.rrc_filter, self.clock_recovery, self.diffdec,
301
 
                             self.slicer, self.symbol_mapper, self.unpack)
302
 
 
303
 
        gr.hier_block.__init__(self, self._fg, self.pre_scaler, self.unpack)
304
 
 
305
 
    def samples_per_symbol(self):
306
 
        return self._samples_per_symbol
307
 
 
308
 
    def bits_per_symbol(self=None):   # staticmethod that's also callable on an instance
309
 
        return 1
310
 
    bits_per_symbol = staticmethod(bits_per_symbol)      # make it a static method.  RTFM
311
 
 
312
 
    def _print_verbage(self):
313
 
        print "bits per symbol = %d"         % self.bits_per_symbol()
314
 
        print "Gray code = %s"               % self._gray_code
315
 
        print "RRC roll-off factor = %.2f"   % self._excess_bw
316
 
        if self._costas_alpha is not None:
317
 
            print "Costas Loop alpha = %.5f"     % self._costas_alpha
318
 
        else:
319
 
            print "Costas Loop is turned off"
320
 
        print "M&M symbol sync gain = %.5f"  % self._gain_mu
321
 
        print "M&M symbol sync mu = %.5f"    % self._mu
322
 
        print "M&M omega relative limit = %.5f" % self._omega_relative_limit
323
 
 
324
 
    def _setup_logging(self):
325
 
        print "Modulation logging turned on."
326
 
        self._fg.connect(self.pre_scaler,
327
 
                         gr.file_sink(gr.sizeof_gr_complex, "prescaler.dat"))
328
 
        self._fg.connect(self.agc,
329
 
                         gr.file_sink(gr.sizeof_gr_complex, "agc.dat"))
330
 
        if self._costas_alpha is not None:
331
 
            self._fg.connect(self.costas_loop,
332
 
                             gr.file_sink(gr.sizeof_gr_complex, "costas_loop.dat"))
333
 
            self._fg.connect((self.costas_loop,1),
334
 
                             gr.file_sink(gr.sizeof_gr_complex, "costas_error.dat"))
335
 
        self._fg.connect(self.rrc_filter,
336
 
                         gr.file_sink(gr.sizeof_gr_complex, "rrc_filter.dat"))
337
 
        self._fg.connect(self.clock_recovery,
338
 
                         gr.file_sink(gr.sizeof_gr_complex, "clock_recovery.dat"))
339
 
        self._fg.connect((self.clock_recovery,1),
340
 
                         gr.file_sink(gr.sizeof_gr_complex, "clock_recovery_error.dat"))
341
 
        self._fg.connect(self.diffdec,
342
 
                         gr.file_sink(gr.sizeof_gr_complex, "diffdec.dat"))        
343
 
        self._fg.connect(self.slicer,
344
 
                        gr.file_sink(gr.sizeof_char, "slicer.dat"))
345
 
        self._fg.connect(self.symbol_mapper,
346
 
                         gr.file_sink(gr.sizeof_char, "symbol_mapper.dat"))
347
 
        self._fg.connect(self.unpack,
348
 
                         gr.file_sink(gr.sizeof_char, "unpack.dat"))
349
 
        
350
 
    def add_options(parser):
351
 
        """
352
 
        Adds DBPSK demodulation-specific options to the standard parser
353
 
        """
354
 
        parser.add_option("", "--excess-bw", type="float", default=_def_excess_bw,
355
 
                          help="set RRC excess bandwith factor [default=%default] (PSK)")
356
 
        parser.add_option("", "--no-gray-code", dest="gray_code",
357
 
                          action="store_false", default=_def_gray_code,
358
 
                          help="disable gray coding on modulated bits (PSK)")
359
 
        parser.add_option("", "--costas-alpha", type="float", default=None,
360
 
                          help="set Costas loop alpha value [default=%default] (PSK)")
361
 
        parser.add_option("", "--gain-mu", type="float", default=_def_gain_mu,
362
 
                          help="set M&M symbol sync loop gain mu value [default=%default] (GMSK/PSK)")
363
 
        parser.add_option("", "--mu", type="float", default=_def_mu,
364
 
                          help="set M&M symbol sync loop mu value [default=%default] (GMSK/PSK)")
365
 
        parser.add_option("", "--omega-relative-limit", type="float", default=_def_omega_relative_limit,
366
 
                          help="M&M clock recovery omega relative limit [default=%default] (GMSK/PSK)")
367
 
    add_options=staticmethod(add_options)
368
 
    
369
 
    def extract_kwargs_from_options(options):
370
 
        """
371
 
        Given command line options, create dictionary suitable for passing to __init__
372
 
        """
373
 
        return modulation_utils.extract_kwargs_from_options(
374
 
                 dbpsk_demod.__init__, ('self', 'fg'), options)
375
 
    extract_kwargs_from_options=staticmethod(extract_kwargs_from_options)
376
 
 
377
 
#
378
 
# Add these to the mod/demod registry
379
 
#
380
 
modulation_utils.add_type_1_mod('dbpsk', dbpsk_mod)
381
 
modulation_utils.add_type_1_demod('dbpsk', dbpsk_demod)