~ubuntu-branches/ubuntu/trusty/gnuradio/trusty-updates

« back to all changes in this revision

Viewing changes to gr-digital/python/cpm.py

  • Committer: Package Import Robot
  • Author(s): A. Maitland Bottoms
  • Date: 2012-02-26 21:26:16 UTC
  • mfrom: (1.1.4)
  • Revision ID: package-import@ubuntu.com-20120226212616-vsfkbi1158xshdql
Tags: 3.5.1-1
* new upstream version, re-packaged from scratch with modern tools
    closes: #642716, #645332, #394849, #616832, #590048, #642580,
    #647018, #557050, #559640, #631863
* CMake build

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#
 
2
# CPM modulation and demodulation.  
 
3
#
 
4
#
 
5
# Copyright 2005-2007,2011 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 3, 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., 51 Franklin Street,
 
22
# Boston, MA 02110-1301, USA.
 
23
 
24
 
 
25
# See gnuradio-examples/python/digital for examples
 
26
 
 
27
from gnuradio import gr, blks2
 
28
from math import pi
 
29
import numpy
 
30
 
 
31
import digital_swig
 
32
import modulation_utils
 
33
 
 
34
# default values (used in __init__ and add_options)
 
35
_def_samples_per_symbol = 2
 
36
_def_bits_per_symbol = 1
 
37
_def_h_numerator = 1
 
38
_def_h_denominator = 2
 
39
_def_cpm_type = 0 # 0=CPFSK, 1=GMSK, 2=RC, 3=GENERAL
 
40
_def_bt = 0.35
 
41
_def_symbols_per_pulse = 1
 
42
_def_generic_taps = numpy.empty(1)
 
43
_def_verbose = False
 
44
_def_log = False
 
45
 
 
46
 
 
47
# /////////////////////////////////////////////////////////////////////////////
 
48
#                              CPM modulator
 
49
# /////////////////////////////////////////////////////////////////////////////
 
50
 
 
51
class cpm_mod(gr.hier_block2):
 
52
    def __init__(self, 
 
53
                 samples_per_symbol=_def_samples_per_symbol,
 
54
                 bits_per_symbol=_def_bits_per_symbol,
 
55
                 h_numerator=_def_h_numerator,
 
56
                 h_denominator=_def_h_denominator,
 
57
                 cpm_type=_def_cpm_type,
 
58
                 bt=_def_bt,
 
59
                 symbols_per_pulse=_def_symbols_per_pulse,
 
60
                 generic_taps=_def_generic_taps,
 
61
                 verbose=_def_verbose,
 
62
                 log=_def_log):
 
63
        """
 
64
        Hierarchical block for Continuous Phase
 
65
        modulation.
 
66
 
 
67
        The input is a byte stream (unsigned char) 
 
68
        representing packed bits and the
 
69
        output is the complex modulated signal at baseband.
 
70
 
 
71
        See Proakis for definition of generic CPM signals:
 
72
        s(t)=exp(j phi(t))
 
73
        phi(t)= 2 pi h int_0^t f(t') dt'
 
74
        f(t)=sum_k a_k g(t-kT)
 
75
        (normalizing assumption: int_0^infty g(t) dt = 1/2)
 
76
 
 
77
        @param samples_per_symbol: samples per baud >= 2
 
78
        @type samples_per_symbol: integer
 
79
        @param bits_per_symbol: bits per symbol
 
80
        @type bits_per_symbol: integer
 
81
        @param h_numerator: numerator of modulation index
 
82
        @type h_numerator: integer
 
83
        @param h_denominator: denominator of modulation index (numerator and denominator must be relative primes)
 
84
        @type h_denominator: integer
 
85
        @param cpm_type: supported types are: 0=CPFSK, 1=GMSK, 2=RC, 3=GENERAL
 
86
        @type cpm_type: integer
 
87
        @param bt: bandwidth symbol time product for GMSK
 
88
        @type bt: float
 
89
        @param symbols_per_pulse: shaping pulse duration in symbols
 
90
        @type symbols_per_pulse: integer
 
91
        @param generic_taps: define a generic CPM pulse shape (sum = samples_per_symbol/2)
 
92
        @type generic_taps: array of floats
 
93
 
 
94
        @param verbose: Print information about modulator?
 
95
        @type verbose: bool
 
96
        @param debug: Print modulation data to files?
 
97
        @type debug: bool       
 
98
        """
 
99
 
 
100
        gr.hier_block2.__init__(self, "cpm_mod", 
 
101
                                gr.io_signature(1, 1, gr.sizeof_char),       # Input signature
 
102
                                gr.io_signature(1, 1, gr.sizeof_gr_complex)) #  Output signature
 
103
 
 
104
        self._samples_per_symbol = samples_per_symbol
 
105
        self._bits_per_symbol = bits_per_symbol
 
106
        self._h_numerator = h_numerator
 
107
        self._h_denominator = h_denominator
 
108
        self._cpm_type = cpm_type
 
109
        self._bt=bt
 
110
        if cpm_type == 0 or cpm_type == 2 or cpm_type == 3: # CPFSK, RC, Generic
 
111
            self._symbols_per_pulse = symbols_per_pulse
 
112
        elif cpm_type == 1: # GMSK
 
113
            self._symbols_per_pulse = 4
 
114
        else:
 
115
            raise TypeError, ("cpm_type must be an integer in {0,1,2,3}, is %r" % (cpm_type,))
 
116
 
 
117
        self._generic_taps=numpy.array(generic_taps)
 
118
 
 
119
        if samples_per_symbol < 2:
 
120
            raise TypeError, ("samples_per_symbol must be >= 2, is %r" % (samples_per_symbol,))
 
121
 
 
122
        self.nsymbols = 2**bits_per_symbol
 
123
        self.sym_alphabet = numpy.arange(-(self.nsymbols-1),self.nsymbols,2).tolist()
 
124
 
 
125
 
 
126
        self.ntaps = int(self._symbols_per_pulse * samples_per_symbol)
 
127
        sensitivity = 2 * pi * h_numerator / h_denominator / samples_per_symbol
 
128
 
 
129
        # Unpack Bytes into bits_per_symbol groups
 
130
        self.B2s = gr.packed_to_unpacked_bb(bits_per_symbol,gr.GR_MSB_FIRST)
 
131
 
 
132
 
 
133
        # Turn it into symmetric PAM data.
 
134
        self.pam = gr.chunks_to_symbols_bf(self.sym_alphabet,1)
 
135
 
 
136
        # Generate pulse (sum of taps = samples_per_symbol/2)
 
137
        if cpm_type == 0: # CPFSK
 
138
            self.taps= (1.0/self._symbols_per_pulse/2,) * self.ntaps
 
139
        elif cpm_type == 1: # GMSK
 
140
            gaussian_taps = gr.firdes.gaussian(
 
141
                1.0/2,                     # gain
 
142
                samples_per_symbol,    # symbol_rate
 
143
                bt,                    # bandwidth * symbol time
 
144
                self.ntaps                  # number of taps
 
145
                )
 
146
            sqwave = (1,) * samples_per_symbol       # rectangular window
 
147
            self.taps = numpy.convolve(numpy.array(gaussian_taps),numpy.array(sqwave))
 
148
        elif cpm_type == 2: # Raised Cosine
 
149
            # generalize it for arbitrary roll-off factor
 
150
            self.taps = (1-numpy.cos(2*pi*numpy.arange(0,self.ntaps)/samples_per_symbol/self._symbols_per_pulse))/(2*self._symbols_per_pulse)
 
151
        elif cpm_type == 3: # Generic CPM
 
152
            self.taps = generic_taps
 
153
        else:
 
154
            raise TypeError, ("cpm_type must be an integer in {0,1,2,3}, is %r" % (cpm_type,))
 
155
 
 
156
        self.filter = blks2.pfb_arb_resampler_fff(samples_per_symbol, self.taps)
 
157
 
 
158
        # FM modulation
 
159
        self.fmmod = gr.frequency_modulator_fc(sensitivity)
 
160
                
 
161
        if verbose:
 
162
            self._print_verbage()
 
163
         
 
164
        if log:
 
165
            self._setup_logging()
 
166
 
 
167
        # Connect
 
168
        self.connect(self, self.B2s, self.pam, self.filter, self.fmmod, self)
 
169
 
 
170
    def samples_per_symbol(self):
 
171
        return self._samples_per_symbol
 
172
    
 
173
    def bits_per_symbol(self):  
 
174
        return self._bits_per_symbol
 
175
    
 
176
    def h_numerator(self):  
 
177
        return self._h_numerator
 
178
 
 
179
    def h_denominator(self):  
 
180
        return self._h_denominator
 
181
 
 
182
    def cpm_type(self):  
 
183
        return self._cpm_type
 
184
 
 
185
    def bt(self):  
 
186
        return self._bt
 
187
 
 
188
    def symbols_per_pulse(self):  
 
189
        return self._symbols_per_pulse
 
190
 
 
191
 
 
192
    def _print_verbage(self):
 
193
        print "Samples per symbol = %d" % self._samples_per_symbol
 
194
        print "Bits per symbol = %d" % self._bits_per_symbol
 
195
        print "h = " , self._h_numerator , " / " ,  self._h_denominator
 
196
        print "Symbol alphabet = " , self.sym_alphabet
 
197
        print "Symbols per pulse = %d" % self._symbols_per_pulse
 
198
        print "taps = " , self.taps
 
199
 
 
200
        print "CPM type = %d" % self._cpm_type
 
201
        if self._cpm_type == 1:
 
202
             print "Gaussian filter BT = %.2f" % self._bt
 
203
 
 
204
 
 
205
    def _setup_logging(self):
 
206
        print "Modulation logging turned on."
 
207
        self.connect(self.B2s,
 
208
                     gr.file_sink(gr.sizeof_float, "symbols.dat"))
 
209
        self.connect(self.pam,
 
210
                     gr.file_sink(gr.sizeof_float, "pam.dat"))
 
211
        self.connect(self.filter,
 
212
                     gr.file_sink(gr.sizeof_float, "filter.dat"))
 
213
        self.connect(self.fmmod,
 
214
                     gr.file_sink(gr.sizeof_gr_complex, "fmmod.dat"))
 
215
 
 
216
 
 
217
    def add_options(parser):
 
218
        """
 
219
        Adds CPM modulation-specific options to the standard parser
 
220
        """
 
221
        parser.add_option("", "--bt", type="float", default=_def_bt,
 
222
                          help="set bandwidth-time product [default=%default] (GMSK)")
 
223
    add_options=staticmethod(add_options)
 
224
 
 
225
 
 
226
    def extract_kwargs_from_options(options):
 
227
        """
 
228
        Given command line options, create dictionary suitable for passing to __init__
 
229
        """
 
230
        return modulation_utils.extract_kwargs_from_options(cpm_mod.__init__,
 
231
                                                             ('self',), options)
 
232
    extract_kwargs_from_options=staticmethod(extract_kwargs_from_options)
 
233
 
 
234
 
 
235
 
 
236
# /////////////////////////////////////////////////////////////////////////////
 
237
#                            CPM demodulator
 
238
# /////////////////////////////////////////////////////////////////////////////
 
239
#
 
240
# Not yet implemented
 
241
#
 
242
 
 
243
#
 
244
# Add these to the mod/demod registry
 
245
#
 
246
modulation_utils.add_type_1_mod('cpm', cpm_mod)
 
247
#modulation_utils.add_type_1_demod('cpm', cpm_demod)