summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Reynwar2011-01-14 23:30:35 -0700
committerBen Reynwar2011-01-14 23:30:35 -0700
commit1ec42d6fa313c6d3eeefae783a74a8600da3b76e (patch)
treed61de000096572fa53f16c5a24289ad29cde530e
parent016dc56eb54860e98fe5ba2a99b12adfb74c7c83 (diff)
downloadgnuradio-1ec42d6fa313c6d3eeefae783a74a8600da3b76e.tar.gz
gnuradio-1ec42d6fa313c6d3eeefae783a74a8600da3b76e.tar.bz2
gnuradio-1ec42d6fa313c6d3eeefae783a74a8600da3b76e.zip
Tidied QAM modulation.
-rw-r--r--gnuradio-core/src/python/gnuradio/blks2impl/generic_mod_demod.py10
-rw-r--r--gnuradio-core/src/python/gnuradio/blks2impl/qam.py113
-rw-r--r--gnuradio-core/src/python/gnuradio/utils/Makefile.am1
-rw-r--r--gnuradio-core/src/python/gnuradio/utils/gray_code.py44
4 files changed, 75 insertions, 93 deletions
diff --git a/gnuradio-core/src/python/gnuradio/blks2impl/generic_mod_demod.py b/gnuradio-core/src/python/gnuradio/blks2impl/generic_mod_demod.py
index 60a3fc777..90dcac971 100644
--- a/gnuradio-core/src/python/gnuradio/blks2impl/generic_mod_demod.py
+++ b/gnuradio-core/src/python/gnuradio/blks2impl/generic_mod_demod.py
@@ -45,6 +45,8 @@ _def_timing_beta = 0.010
_def_timing_max_dev = 1.5
# Fine frequency / Phase correction
_def_phase_alpha = 0.1
+# Number of points in constellation
+_def_constellation_points = 16
# /////////////////////////////////////////////////////////////////////////////
# Generic modulator
@@ -128,8 +130,10 @@ class generic_mod(gr.hier_block2):
def add_options(parser):
"""
- Adds generic modulation-specific options to the standard parser
+ Adds generic modulation options to the standard parser
"""
+ parser.add_option("-p", "--constellation-points", type="int", default=_def_constellation_points,
+ help="set the number of constellation points (must be a power of 4 for QAM) [default=%default]")
parser.add_option("", "--excess-bw", type="float", default=_def_excess_bw,
help="set RRC excess bandwith factor [default=%default]")
add_options=staticmethod(add_options)
@@ -320,8 +324,10 @@ class generic_demod(gr.hier_block2):
def add_options(parser):
"""
- Adds generic demodulation-specific options to the standard parser
+ Adds generic demodulation options to the standard parser
"""
+ parser.add_option("-p", "--constellation-points", type="int", default=_def_constellation_points,
+ help="set the number of constellation points (must be a power of 4 for QAM) [default=%default]")
parser.add_option("", "--excess-bw", type="float", default=_def_excess_bw,
help="set RRC excess bandwith factor [default=%default]")
parser.add_option("", "--freq-alpha", type="float", default=_def_freq_alpha,
diff --git a/gnuradio-core/src/python/gnuradio/blks2impl/qam.py b/gnuradio-core/src/python/gnuradio/blks2impl/qam.py
index 22d80503b..b6096d2cb 100644
--- a/gnuradio-core/src/python/gnuradio/blks2impl/qam.py
+++ b/gnuradio-core/src/python/gnuradio/blks2impl/qam.py
@@ -24,13 +24,12 @@ QAM modulation and demodulation.
"""
from math import pi, sqrt, log
-from itertools import islice
from gnuradio import gr, gru, modulation_utils2
from gnuradio.blks2impl.generic_mod_demod import generic_mod, generic_demod
+from gnuradio.utils.gray_code import gray_code
-
-# default values (used in __init__ and add_options)
+# Default number of points in constellation.
_def_constellation_points = 16
def is_power_of_four(x):
@@ -48,31 +47,6 @@ def get_bits(x, n, k):
# Remove all bits bigger than n+k-1
return v % pow(2, k)
-def gray_codes():
- """ Generates gray codes."""
- gcs = [0, 1]
- yield 0
- yield 1
- # The last power of two passed through.
- lp2 = 2
- # The next power of two that will be passed through.
- np2 = 4
- i = 2
- while True:
- if i == lp2:
- # if i is a power of two then gray number is of form 1100000...
- result = i + i/2
- else:
- # if not we take advantage of the symmetry of all but the last bit
- # around a power of two.
- result = gcs[2*lp2-1-i] + lp2
- gcs.append(result)
- yield result
- i += 1
- if i == np2:
- lp2 = i
- np2 = i*2
-
def make_constellation(m):
"""
Create a constellation with m possible symbols where m must be
@@ -90,7 +64,7 @@ def make_constellation(m):
# The quadrant has 'side' points along each side of a quadrant.
side = int(sqrtm/2)
# Number rows and columns using gray codes.
- gcs = list(islice(gray_codes(), side))
+ gcs = gray_code(side)
# Get inverse gray codes.
i_gcs = dict([(v, key) for key, v in enumerate(gcs)])
# The distance between points is found.
@@ -125,7 +99,21 @@ def make_constellation(m):
const_map.append(get_c(x, y, quad))
return const_map
-
+
+
+# /////////////////////////////////////////////////////////////////////////////
+# QAM constellation
+# /////////////////////////////////////////////////////////////////////////////
+
+def qam_constellation(constellation_points=_def_constellation_points):
+ """
+ Creates a QAM constellation object.
+ """
+ points = make_constellation(constellation_points)
+ side = int(sqrt(constellation_points))
+ width = 2.0/(side-1)
+ constellation = gr.constellation_sector(points, side, side, width, width)
+ return constellation
# /////////////////////////////////////////////////////////////////////////////
# QAM modulator
@@ -141,39 +129,14 @@ class qam_mod(generic_mod):
The input is a byte stream (unsigned char) and the
output is the complex modulated signal at baseband.
- @param m: Number of constellation points. Must be a power of four.
- @type m: integer
- @param samples_per_symbol: samples per baud >= 2
- @type samples_per_symbol: integer
- @param excess_bw: Root-raised cosine filter excess bandwidth
- @type excess_bw: float
- @param verbose: Print information about modulator?
- @type verbose: bool
- @param log: Log modulation data to files?
- @type log: bool
+ See generic_mod block for list of parameters.
"""
if not isinstance(constellation_points, int) or not is_power_of_four(constellation_points):
raise ValueError("number of constellation points must be a power of four.")
-
- points = make_constellation(constellation_points)
- side = int(sqrt(constellation_points))
- assert(side * side == constellation_points)
- width = 2.0/(side-1)
- constellation = gr.constellation_sector(points, side, side, width, width)
- #constellation = gr.constellation(points)
-
+ constellation = qam_constellation(constellation_points)
super(qam_mod, self).__init__(constellation, *args, **kwargs)
- def add_options(parser):
- """
- Adds QAM modulation-specific options to the standard parser
- """
- parser.add_option("-p", "--constellation-points", type="int", default=_def_constellation_points,
- help="set the number of constellation points (must be a power of 4) [default=%default]")
- generic_mod.add_options(parser)
- add_options=staticmethod(add_options)
-
# /////////////////////////////////////////////////////////////////////////////
# QAM demodulator
#
@@ -189,44 +152,12 @@ class qam_demod(generic_demod):
The input is a byte stream (unsigned char) and the
output is the complex modulated signal at baseband.
- @param m: Number of constellation points. Must be a power of four.
- @type m: integer
- @param samples_per_symbol: samples per symbol >= 2
- @type samples_per_symbol: float
- @param excess_bw: Root-raised cosine filter excess bandwidth
- @type excess_bw: float
- @param freq_alpha: loop filter gain for frequency recovery
- @type freq_alpha: float
- @param timing_alpha: loop alpha gain for timing recovery
- @type timing_alpha: float
- @param timing_max_dev: timing loop maximum rate deviations
- @type timing_max_dev: float
- @param phase_alpha: loop filter gain in phase loop
- @type phase_alphas: float
- @param verbose: Print information about modulator?
- @type verbose: bool
- @param debug: Print modualtion data to files?
- @type debug: bool
+ See generic_demod block for list of parameters.
"""
- points = make_constellation(constellation_points)
- side = int(sqrt(constellation_points))
- assert(side * side == constellation_points)
- width = 2.0/(side-1)
- constellation = gr.constellation_sector(points, side, side, width, width)
- #constellation = gr.constellation(points)
-
+ constellation = qam_constellation(constellation_points)
super(qam_demod, self).__init__(constellation, *args, **kwargs)
- def add_options(parser):
- """
- Adds QAM demodulation-specific options to the standard parser
- """
- parser.add_option("", "--constellation-points", type="int", default=_def_constellation_points,
- help="set the number of constellation points (must be a power of 4) [default=%default]")
- generic_demod.add_options(parser)
- add_options=staticmethod(add_options)
-
#
# Add these to the mod/demod registry
#
diff --git a/gnuradio-core/src/python/gnuradio/utils/Makefile.am b/gnuradio-core/src/python/gnuradio/utils/Makefile.am
index ed6958669..4c8e46891 100644
--- a/gnuradio-core/src/python/gnuradio/utils/Makefile.am
+++ b/gnuradio-core/src/python/gnuradio/utils/Makefile.am
@@ -29,6 +29,7 @@ TESTS = \
nobase_utilspython_PYTHON = \
__init__.py \
+ gray_code.py \
doxyxml/__init__.py \
doxyxml/base.py \
doxyxml/doxyindex.py \
diff --git a/gnuradio-core/src/python/gnuradio/utils/gray_code.py b/gnuradio-core/src/python/gnuradio/utils/gray_code.py
new file mode 100644
index 000000000..af8b8cd14
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/utils/gray_code.py
@@ -0,0 +1,44 @@
+
+class GrayCodeGenerator(object):
+ """
+ Generates and caches gray codes.
+ """
+
+ def __init__(self):
+ self.gcs = [0, 1]
+ # The last power of two passed through.
+ self.lp2 = 2
+ # The next power of two that will be passed through.
+ self.np2 = 4
+ # Curent index
+ self.i = 2
+
+ def get_gray_code(self, length):
+ """
+ Returns a list of gray code of given length.
+ """
+ if len(self.gcs) < length:
+ self.generate_new_gray_code(length)
+ return self.gcs[:length]
+
+ def generate_new_gray_code(self, length):
+ """
+ Generates new gray code and places into cache.
+ """
+ while len(self.gcs) < length:
+ if self.i == self.lp2:
+ # if i is a power of two then gray number is of form 1100000...
+ result = self.i + self.i/2
+ else:
+ # if not we take advantage of the symmetry of all but the last bit
+ # around a power of two.
+ result = self.gcs[2*self.lp2-1-self.i] + self.lp2
+ self.gcs.append(result)
+ self.i += 1
+ if self.i == self.np2:
+ self.lp2 = self.i
+ self.np2 = self.i*2
+
+_gray_code_generator = GrayCodeGenerator()
+
+gray_code = _gray_code_generator.get_gray_code