summaryrefslogtreecommitdiff
path: root/gnuradio-core/src/python/gnuradio/blks2impl/cpm.py
diff options
context:
space:
mode:
authorjcorgan <jcorgan@221aa14e-8319-0410-a670-987f0aec2ac5>2007-09-18 18:59:00 +0000
committerjcorgan <jcorgan@221aa14e-8319-0410-a670-987f0aec2ac5>2007-09-18 18:59:00 +0000
commite692e71305ecd71d3681fe37f3d76f350d67e276 (patch)
treedc320c9261303aa9a92f4d12bdba85f82720d1bf /gnuradio-core/src/python/gnuradio/blks2impl/cpm.py
parent6ad04a094ced626e46c210b9847eae46a1ae8e67 (diff)
Merge r6461:6464 from jcorgan/t162-staging into trunk.
* Final gr.top_block and gr.hier_block2 implementation inside gnuradio-core/src/lib/runtime * Implementation of gr.hier_block2 versions of all the old-style blocks in blks. These live in blks2. * Addition of gr.hier_block2 based versions of gr-wxgui blocks * Conversion of all the example code in gnuradio-examples to use this new code * Conversion of all the gr-utils scripts to use the new code The OFDM examples and related hierarchical blocks have not yet been converted. Code in the rest of the tree that is outside the core and example components has also not yet been converted. git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@6466 221aa14e-8319-0410-a670-987f0aec2ac5
Diffstat (limited to 'gnuradio-core/src/python/gnuradio/blks2impl/cpm.py')
-rw-r--r--gnuradio-core/src/python/gnuradio/blks2impl/cpm.py249
1 files changed, 249 insertions, 0 deletions
diff --git a/gnuradio-core/src/python/gnuradio/blks2impl/cpm.py b/gnuradio-core/src/python/gnuradio/blks2impl/cpm.py
new file mode 100644
index 0000000000..8f593cd51e
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/blks2impl/cpm.py
@@ -0,0 +1,249 @@
+#
+# CPM modulation and demodulation.
+#
+#
+# Copyright 2005,2006,2007 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 3, 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/digital for examples
+
+from gnuradio import gr
+from gnuradio import modulation_utils
+from math import pi
+import numpy
+from pprint import pprint
+import inspect
+
+# default values (used in __init__ and add_options)
+_def_samples_per_symbol = 2
+_def_bits_per_symbol = 1
+_def_h_numerator = 1
+_def_h_denominator = 2
+_def_cpm_type = 0 # 0=CPFSK, 1=GMSK, 2=RC, 3=GENERAL
+_def_bt = 0.35
+_def_symbols_per_pulse = 1
+_def_generic_taps = numpy.empty(1)
+_def_verbose = False
+_def_log = False
+
+
+# /////////////////////////////////////////////////////////////////////////////
+# CPM modulator
+# /////////////////////////////////////////////////////////////////////////////
+
+class cpm_mod(gr.hier_block2):
+ def __init__(self,
+ samples_per_symbol=_def_samples_per_symbol,
+ bits_per_symbol=_def_bits_per_symbol,
+ h_numerator=_def_h_numerator,
+ h_denominator=_def_h_denominator,
+ cpm_type=_def_cpm_type,
+ bt=_def_bt,
+ symbols_per_pulse=_def_symbols_per_pulse,
+ generic_taps=_def_generic_taps,
+ verbose=_def_verbose,
+ log=_def_log):
+ """
+ Hierarchical block for Continuous Phase
+ modulation.
+
+ The input is a byte stream (unsigned char)
+ representing packed bits and the
+ output is the complex modulated signal at baseband.
+
+ See Proakis for definition of generic CPM signals:
+ s(t)=exp(j phi(t))
+ phi(t)= 2 pi h int_0^t f(t') dt'
+ f(t)=sum_k a_k g(t-kT)
+ (normalizing assumption: int_0^infty g(t) dt = 1/2)
+
+ @param samples_per_symbol: samples per baud >= 2
+ @type samples_per_symbol: integer
+ @param bits_per_symbol: bits per symbol
+ @type bits_per_symbol: integer
+ @param h_numerator: numerator of modulation index
+ @type h_numerator: integer
+ @param h_denominator: denominator of modulation index (numerator and denominator must be relative primes)
+ @type h_denominator: integer
+ @param cpm_type: supported types are: 0=CPFSK, 1=GMSK, 2=RC, 3=GENERAL
+ @type cpm_type: integer
+ @param bt: bandwidth symbol time product for GMSK
+ @type bt: float
+ @param symbols_per_pulse: shaping pulse duration in symbols
+ @type symbols_per_pulse: integer
+ @param generic_taps: define a generic CPM pulse shape (sum = samples_per_symbol/2)
+ @type generic_taps: array of floats
+
+ @param verbose: Print information about modulator?
+ @type verbose: bool
+ @param debug: Print modulation data to files?
+ @type debug: bool
+ """
+
+ gr.hier_block2.__init__("cpm_mod",
+ gr.io_signature(1, 1, gr.sizeof_char), # Input signature
+ gr.io_signature(1, 1, gr.sizeof_gr_complex)) # Output signature
+
+ self._samples_per_symbol = samples_per_symbol
+ self._bits_per_symbol = bits_per_symbol
+ self._h_numerator = h_numerator
+ self._h_denominator = h_denominator
+ self._cpm_type = cpm_type
+ self._bt=bt
+ if cpm_type == 0 or cpm_type == 2 or cpm_type == 3: # CPFSK, RC, Generic
+ self._symbols_per_pulse = symbols_per_pulse
+ elif cpm_type == 1: # GMSK
+ self._symbols_per_pulse = 4
+ else:
+ raise TypeError, ("cpm_type must be an integer in {0,1,2,3}, is %r" % (cpm_type,))
+
+ self._generic_taps=numpy.array(generic_taps)
+
+ if not isinstance(samples_per_symbol, int) or samples_per_symbol < 2:
+ raise TypeError, ("samples_per_symbol must be an integer >= 2, is %r" % (samples_per_symbol,))
+
+ self.nsymbols = 2**bits_per_symbol
+ self.sym_alphabet=numpy.arange(-(self.nsymbols-1),self.nsymbols,2)
+
+
+ self.ntaps = self._symbols_per_pulse * samples_per_symbol
+ sensitivity = 2 * pi * h_numerator / h_denominator / samples_per_symbol
+
+ # Unpack Bytes into bits_per_symbol groups
+ self.B2s = gr.packed_to_unpacked_bb(bits_per_symbol,gr.GR_MSB_FIRST)
+
+
+ # Turn it into symmetric PAM data.
+ self.pam = gr.chunks_to_symbols_bf(self.sym_alphabet,1)
+
+ # Generate pulse (sum of taps = samples_per_symbol/2)
+ if cpm_type == 0: # CPFSK
+ self.taps= (1.0/self._symbols_per_pulse/2,) * self.ntaps
+ elif cpm_type == 1: # GMSK
+ gaussian_taps = gr.firdes.gaussian(
+ 1.0/2, # gain
+ samples_per_symbol, # symbol_rate
+ bt, # bandwidth * symbol time
+ self.ntaps # number of taps
+ )
+ sqwave = (1,) * samples_per_symbol # rectangular window
+ self.taps = numpy.convolve(numpy.array(gaussian_taps),numpy.array(sqwave))
+ elif cpm_type == 2: # Raised Cosine
+ # generalize it for arbitrary roll-off factor
+ self.taps = (1-numpy.cos(2*pi*numpy.arange(0,self.ntaps)/samples_per_symbol/self._symbols_per_pulse))/(2*self._symbols_per_pulse)
+ elif cpm_type == 3: # Generic CPM
+ self.taps = generic_taps
+ else:
+ raise TypeError, ("cpm_type must be an integer in {0,1,2,3}, is %r" % (cpm_type,))
+
+ self.filter = gr.interp_fir_filter_fff(samples_per_symbol, self.taps)
+
+ # FM modulation
+ self.fmmod = gr.frequency_modulator_fc(sensitivity)
+
+ if verbose:
+ self._print_verbage()
+
+ if log:
+ self._setup_logging()
+
+ # Connect
+ self.connect(self, self.B2s, self.pam, self.filter, self.fmmod, self)
+
+ #def samples_per_symbol(self):
+ #return self._samples_per_symbol
+
+ #def bits_per_symbol(self):
+ #return self._bits_per_symbol
+
+ #def h_numerator(self):
+ #return self._h_numerator
+
+ #def h_denominator(self):
+ #return self._h_denominator
+
+ #def cpm_type(self):
+ #return self._cpm_type
+
+ #def bt(self):
+ #return self._bt
+
+ #def symbols_per_pulse(self):
+ #return self._symbols_per_pulse
+
+
+ def _print_verbage(self):
+ print "Samples per symbol = %d" % self._samples_per_symbol
+ print "Bits per symbol = %d" % self._bits_per_symbol
+ print "h = " , self._h_numerator , " / " , self._h_denominator
+ print "Symbol alphabet = " , self.sym_alphabet
+ print "Symbols per pulse = %d" % self._symbols_per_pulse
+ print "taps = " , self.taps
+
+ print "CPM type = %d" % self._cpm_type
+ if self._cpm_type == 1:
+ print "Gaussian filter BT = %.2f" % self._bt
+
+
+ def _setup_logging(self):
+ print "Modulation logging turned on."
+ self.connect(self.B2s,
+ gr.file_sink(gr.sizeof_float, "symbols.dat"))
+ self.connect(self.pam,
+ gr.file_sink(gr.sizeof_float, "pam.dat"))
+ self.connect(self.filter,
+ gr.file_sink(gr.sizeof_float, "filter.dat"))
+ self.connect(self.fmmod,
+ gr.file_sink(gr.sizeof_gr_complex, "fmmod.dat"))
+
+
+ def add_options(parser):
+ """
+ Adds CPM modulation-specific options to the standard parser
+ """
+ parser.add_option("", "--bt", type="float", default=_def_bt,
+ help="set bandwidth-time product [default=%default] (GMSK)")
+ add_options=staticmethod(add_options)
+
+
+ def extract_kwargs_from_options(options):
+ """
+ Given command line options, create dictionary suitable for passing to __init__
+ """
+ return modulation_utils.extract_kwargs_from_options(cpm_mod.__init__,
+ ('self',), options)
+ extract_kwargs_from_options=staticmethod(extract_kwargs_from_options)
+
+
+
+# /////////////////////////////////////////////////////////////////////////////
+# CPM demodulator
+# /////////////////////////////////////////////////////////////////////////////
+#
+# Not yet implemented
+#
+
+
+
+#
+# Add these to the mod/demod registry
+#
+modulation_utils.add_type_1_mod('cpm', cpm_mod)
+#modulation_utils.add_type_1_demod('cpm', cpm_demod)