summaryrefslogtreecommitdiff
path: root/gnuradio-core
diff options
context:
space:
mode:
Diffstat (limited to 'gnuradio-core')
-rw-r--r--gnuradio-core/src/lib/filter/gr_pfb_clock_sync_ccf.h8
-rw-r--r--gnuradio-core/src/lib/general/Makefile.am15
-rw-r--r--gnuradio-core/src/lib/general/general.i8
-rw-r--r--gnuradio-core/src/lib/general/gr_constellation.cc368
-rw-r--r--gnuradio-core/src/lib/general/gr_constellation.h322
-rw-r--r--gnuradio-core/src/lib/general/gr_constellation.i146
-rw-r--r--gnuradio-core/src/lib/general/gr_constellation_decoder2_cb.cc78
-rw-r--r--gnuradio-core/src/lib/general/gr_constellation_decoder2_cb.h64
-rw-r--r--gnuradio-core/src/lib/general/gr_constellation_decoder2_cb.i38
-rw-r--r--gnuradio-core/src/lib/general/gr_constellation_receiver_cb.cc131
-rw-r--r--gnuradio-core/src/lib/general/gr_constellation_receiver_cb.h149
-rw-r--r--gnuradio-core/src/lib/general/gr_constellation_receiver_cb.i43
-rw-r--r--gnuradio-core/src/lib/general/gr_metric_type.h31
-rw-r--r--gnuradio-core/src/lib/general/gr_ofdm_frame_sink2.cc374
-rw-r--r--gnuradio-core/src/lib/general/gr_ofdm_frame_sink2.h120
-rw-r--r--gnuradio-core/src/lib/general/gr_ofdm_frame_sink2.i39
-rw-r--r--gnuradio-core/src/lib/swig/Makefile.am2
-rw-r--r--gnuradio-core/src/lib/swig/Makefile.swig.gen12
-rw-r--r--gnuradio-core/src/lib/swig/gnuradio.i2
-rw-r--r--gnuradio-core/src/python/gnuradio/Makefile.am2
-rw-r--r--gnuradio-core/src/python/gnuradio/blks2impl/Makefile.am8
-rw-r--r--gnuradio-core/src/python/gnuradio/blks2impl/bpsk.py98
-rw-r--r--gnuradio-core/src/python/gnuradio/blks2impl/generic_mod_demod.py395
-rw-r--r--gnuradio-core/src/python/gnuradio/blks2impl/ofdm.py75
-rw-r--r--gnuradio-core/src/python/gnuradio/blks2impl/pkt.py36
-rw-r--r--gnuradio-core/src/python/gnuradio/blks2impl/psk2.py121
-rw-r--r--gnuradio-core/src/python/gnuradio/blks2impl/qam.py287
-rw-r--r--gnuradio-core/src/python/gnuradio/blks2impl/qam16.py208
-rw-r--r--gnuradio-core/src/python/gnuradio/blks2impl/qam256.py209
-rw-r--r--gnuradio-core/src/python/gnuradio/blks2impl/qam64.py208
-rw-r--r--gnuradio-core/src/python/gnuradio/blks2impl/qam8.py209
-rw-r--r--gnuradio-core/src/python/gnuradio/blks2impl/qpsk.py79
-rw-r--r--gnuradio-core/src/python/gnuradio/gr/Makefile.am1
-rw-r--r--gnuradio-core/src/python/gnuradio/gr/qa_constellation.py202
-rw-r--r--gnuradio-core/src/python/gnuradio/gr/qa_constellation_receiver.py144
-rw-r--r--gnuradio-core/src/python/gnuradio/modulation_utils2.py20
-rw-r--r--gnuradio-core/src/python/gnuradio/utils/Makefile.am35
-rw-r--r--gnuradio-core/src/python/gnuradio/utils/__init__.py0
-rw-r--r--gnuradio-core/src/python/gnuradio/utils/alignment.py139
-rw-r--r--gnuradio-core/src/python/gnuradio/utils/gray_code.py45
-rw-r--r--gnuradio-core/src/python/gnuradio/utils/mod_codes.py11
-rw-r--r--gnuradio-core/src/python/gnuradio/utils/run_tests.in16
42 files changed, 3507 insertions, 991 deletions
diff --git a/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_ccf.h b/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_ccf.h
index 4e6ef5fc4..fc80d2961 100644
--- a/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_ccf.h
+++ b/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_ccf.h
@@ -47,7 +47,7 @@ class gr_fir_ccf;
* derivative of the filtered signal, which in turn maximizes the SNR and
* minimizes ISI.
*
- * This approach works by setting up two filterbanks; one filterbanke contains the
+ * This approach works by setting up two filterbanks; one filterbank contains the
* signal's pulse shaping matched filter (such as a root raised cosine filter),
* where each branch of the filterbank contains a different phase of the filter.
* The second filterbank contains the derivatives of the filters in the first
@@ -84,8 +84,8 @@ class gr_fir_ccf;
* the block constructor, we just ask for "gain," which is d_alpha while d_beta is
* equal to (gain^2)/4.
*
- * The clock sync block needs to know the number of samples per second (sps), because it
- * only returns a single point representing the sample. The sps can be any positive real
+ * The clock sync block needs to know the number of samples per symbol (sps), because it
+ * only returns a single point representing the symbol. The sps can be any positive real
* number and does not need to be an integer. The filter taps must also be specified. The
* taps are generated by first conceiving of the prototype filter that would be the signal's
* matched filter. Then interpolate this by the number of filters in the filterbank. These
@@ -115,7 +115,7 @@ class gr_pfb_clock_sync_ccf : public gr_block
private:
/*!
* Build the polyphase filterbank timing synchronizer.
- * \param sps (double) The number of samples per second in the incoming signal
+ * \param sps (double) The number of samples per symbol in the incoming signal
* \param gain (float) The alpha gain of the control loop; beta = (gain^2)/4 by default.
* \param taps (vector<int>) The filter taps.
* \param filter_size (uint) The number of filters in the filterbank (default = 32).
diff --git a/gnuradio-core/src/lib/general/Makefile.am b/gnuradio-core/src/lib/general/Makefile.am
index 3ceea7a6d..8f895f364 100644
--- a/gnuradio-core/src/lib/general/Makefile.am
+++ b/gnuradio-core/src/lib/general/Makefile.am
@@ -56,7 +56,10 @@ libgeneral_la_SOURCES = \
gr_complex_to_xxx.cc \
gr_conjugate_cc.cc \
gr_copy.cc \
+ gr_constellation.cc \
gr_constellation_decoder_cb.cc \
+ gr_constellation_decoder2_cb.cc \
+ gr_constellation_receiver_cb.cc \
gr_correlate_access_code_bb.cc \
gr_costas_loop_cc.cc \
gr_count_bits.cc \
@@ -111,6 +114,7 @@ libgeneral_la_SOURCES = \
gr_ofdm_demapper_vcb.cc \
gr_ofdm_mapper_bcv.cc \
gr_ofdm_frame_sink.cc \
+ gr_ofdm_frame_sink2.cc \
gr_ofdm_insert_preamble.cc \
gr_ofdm_sampler.cc \
gr_pa_2x2_phase_combiner.cc \
@@ -212,7 +216,10 @@ grinclude_HEADERS = \
gr_complex_to_interleaved_short.h \
gr_complex_to_xxx.h \
gr_conjugate_cc.h \
+ gr_constellation.h \
gr_constellation_decoder_cb.h \
+ gr_constellation_decoder2_cb.h \
+ gr_constellation_receiver_cb.h \
gr_copy.h \
gr_correlate_access_code_bb.h \
gr_costas_loop_cc.h \
@@ -261,8 +268,8 @@ grinclude_HEADERS = \
gr_log2_const.h \
gr_map_bb.h \
gr_math.h \
+ gr_metric_type.h \
gr_misc.h \
- gr_mpsk_receiver_cc.h \
gr_nco.h \
gr_nlog10_ff.h \
gr_nop.h \
@@ -273,6 +280,7 @@ grinclude_HEADERS = \
gr_ofdm_demapper_vcb.h \
gr_ofdm_mapper_bcv.h \
gr_ofdm_frame_sink.h \
+ gr_ofdm_frame_sink2.h \
gr_ofdm_insert_preamble.h \
gr_ofdm_sampler.h \
gr_pa_2x2_phase_combiner.h \
@@ -386,7 +394,10 @@ swiginclude_HEADERS = \
gr_complex_to_interleaved_short.i \
gr_complex_to_xxx.i \
gr_conjugate_cc.i \
+ gr_constellation.i \
gr_constellation_decoder_cb.i \
+ gr_constellation_decoder2_cb.i \
+ gr_constellation_receiver_cb.i \
gr_copy.i \
gr_correlate_access_code_bb.i \
gr_costas_loop_cc.i \
@@ -427,7 +438,6 @@ swiginclude_HEADERS = \
gr_lms_dfe_cc.i \
gr_lms_dfe_ff.i \
gr_map_bb.i \
- gr_mpsk_receiver_cc.i \
gr_nlog10_ff.i \
gr_nop.i \
gr_null_sink.i \
@@ -437,6 +447,7 @@ swiginclude_HEADERS = \
gr_ofdm_demapper_vcb.i \
gr_ofdm_mapper_bcv.i \
gr_ofdm_frame_sink.i \
+ gr_ofdm_frame_sink2.i \
gr_ofdm_insert_preamble.i \
gr_ofdm_sampler.i \
gr_pa_2x2_phase_combiner.i \
diff --git a/gnuradio-core/src/lib/general/general.i b/gnuradio-core/src/lib/general/general.i
index fb9c4c0f2..dddda60af 100644
--- a/gnuradio-core/src/lib/general/general.i
+++ b/gnuradio-core/src/lib/general/general.i
@@ -69,6 +69,8 @@
#include <gr_fake_channel_coder_pp.h>
#include <gr_throttle.h>
#include <gr_mpsk_receiver_cc.h>
+#include <gr_constellation_receiver_cb.h>
+#include <gr_constellation.h>
#include <gr_stream_mux.h>
#include <gr_stream_to_streams.h>
#include <gr_streams_to_stream.h>
@@ -97,6 +99,7 @@
#include <gr_ofdm_cyclic_prefixer.h>
#include <gr_ofdm_mapper_bcv.h>
#include <gr_ofdm_frame_sink.h>
+#include <gr_ofdm_frame_sink2.h>
#include <gr_ofdm_insert_preamble.h>
#include <gr_ofdm_sampler.h>
#include <gr_regenerate_bb.h>
@@ -111,6 +114,7 @@
#include <gr_correlate_access_code_bb.h>
#include <gr_diff_phasor_cc.h>
#include <gr_constellation_decoder_cb.h>
+#include <gr_constellation_decoder2_cb.h>
#include <gr_binary_slicer_fb.h>
#include <gr_diff_encoder_bb.h>
#include <gr_diff_decoder_bb.h>
@@ -194,6 +198,8 @@
%include "gr_fake_channel_coder_pp.i"
%include "gr_throttle.i"
%include "gr_mpsk_receiver_cc.i"
+%include "gr_constellation_receiver_cb.i"
+%include "gr_constellation.i"
%include "gr_stream_mux.i"
%include "gr_stream_to_streams.i"
%include "gr_streams_to_stream.i"
@@ -222,6 +228,7 @@
%include "gr_ofdm_cyclic_prefixer.i"
%include "gr_ofdm_mapper_bcv.i"
%include "gr_ofdm_frame_sink.i"
+%include "gr_ofdm_frame_sink2.i"
%include "gr_ofdm_insert_preamble.i"
%include "gr_ofdm_sampler.i"
%include "gr_regenerate_bb.i"
@@ -236,6 +243,7 @@
%include "gr_correlate_access_code_bb.i"
%include "gr_diff_phasor_cc.i"
%include "gr_constellation_decoder_cb.i"
+%include "gr_constellation_decoder2_cb.i"
%include "gr_binary_slicer_fb.i"
%include "gr_diff_encoder_bb.i"
%include "gr_diff_decoder_bb.i"
diff --git a/gnuradio-core/src/lib/general/gr_constellation.cc b/gnuradio-core/src/lib/general/gr_constellation.cc
new file mode 100644
index 000000000..69b6e1bdc
--- /dev/null
+++ b/gnuradio-core/src/lib/general/gr_constellation.cc
@@ -0,0 +1,368 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2010 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.
+ */
+
+#include <gr_io_signature.h>
+#include <gr_constellation.h>
+#include <gr_metric_type.h>
+#include <gr_math.h>
+#include <gr_complex.h>
+#include <math.h>
+#include <iostream>
+#include <stdlib.h>
+#include <float.h>
+#include <stdexcept>
+
+#define M_TWOPI (2*M_PI)
+#define SQRT_TWO 0.707107
+
+// Base Constellation Class
+
+gr_constellation::gr_constellation (std::vector<gr_complex> constellation, std::vector<unsigned int> pre_diff_code,
+ unsigned int rotational_symmetry, unsigned int dimensionality) :
+ d_constellation(constellation),
+ d_pre_diff_code(pre_diff_code),
+ d_rotational_symmetry(rotational_symmetry),
+ d_dimensionality(dimensionality)
+{
+ if (pre_diff_code.size() == 0)
+ d_apply_pre_diff_code = false;
+ else if (pre_diff_code.size() != constellation.size())
+ throw std::runtime_error ("The constellation and pre-diff code must be of the same length.");
+ else
+ d_apply_pre_diff_code = true;
+ calc_arity();
+}
+
+gr_constellation::gr_constellation () :
+ d_apply_pre_diff_code(false),
+ d_rotational_symmetry(0),
+ d_dimensionality(1)
+{
+ calc_arity();
+}
+
+//! Returns the constellation points for a symbol value
+void gr_constellation::map_to_points(unsigned int value, gr_complex *points) {
+ for (unsigned int i=0; i<d_dimensionality; i++)
+ points[i] = d_constellation[value*d_dimensionality + i];
+}
+
+std::vector<gr_complex> gr_constellation::map_to_points_v(unsigned int value) {
+ std::vector<gr_complex> points_v;
+ points_v.resize(d_dimensionality);
+ map_to_points(value, &(points_v[0]));
+ return points_v;
+}
+
+float gr_constellation::get_distance(unsigned int index, const gr_complex *sample) {
+ float dist = 0;
+ for (unsigned int i=0; i<d_dimensionality; i++) {
+ dist += norm(sample[i] - d_constellation[index*d_dimensionality + i]);
+ }
+ return dist;
+}
+
+unsigned int gr_constellation::get_closest_point(const gr_complex *sample) {
+
+ unsigned int min_index = 0;
+ float min_euclid_dist;
+ float euclid_dist;
+
+ min_euclid_dist = get_distance(0, sample);
+ min_index = 0;
+ for (unsigned int j = 1; j < d_arity; j++){
+ euclid_dist = get_distance(j, sample);
+ if (euclid_dist < min_euclid_dist){
+ min_euclid_dist = euclid_dist;
+ min_index = j;
+ }
+ }
+ return min_index;
+}
+
+unsigned int gr_constellation::decision_maker_pe(const gr_complex *sample, float *phase_error)
+{
+ unsigned int index = decision_maker(sample);
+ *phase_error = 0;
+ for (unsigned int d=0; d<d_dimensionality; d++)
+ *phase_error += -arg(sample[d]*conj(d_constellation[index+d]));
+ return index;
+}
+
+/*
+unsigned int gr_constellation::decision_maker_e(const gr_complex *sample, float *error)
+{
+ unsigned int index = decision_maker(sample);
+ *error = 0;
+ for (unsigned int d=0; d<d_dimensionality; d++)
+ *error += sample[d]*conj(d_constellation[index+d]);
+ return index;
+}
+*/
+
+std::vector<gr_complex> gr_constellation::s_points () {
+ if (d_dimensionality != 1)
+ throw std::runtime_error ("s_points only works for dimensionality 1 constellations.");
+ else
+ return d_constellation;
+}
+
+std::vector<std::vector<gr_complex> > gr_constellation::v_points () {
+ std::vector<std::vector<gr_complex> > vv_const;
+ vv_const.resize(d_arity);
+ for (unsigned int p=0; p<d_arity; p++) {
+ std::vector<gr_complex> v_const;
+ v_const.resize(d_dimensionality);
+ for (unsigned int d=0; d<d_dimensionality; d++) {
+ v_const[d] = d_constellation[p*d_dimensionality+d];
+ }
+ vv_const[p] = v_const;
+ }
+ return vv_const;
+}
+
+void gr_constellation::calc_metric(const gr_complex *sample, float *metric, trellis_metric_type_t type) {
+ switch (type){
+ case TRELLIS_EUCLIDEAN:
+ calc_euclidean_metric(sample, metric);
+ break;
+ case TRELLIS_HARD_SYMBOL:
+ calc_hard_symbol_metric(sample, metric);
+ break;
+ case TRELLIS_HARD_BIT:
+ throw std::runtime_error ("Invalid metric type (not yet implemented).");
+ break;
+ default:
+ throw std::runtime_error ("Invalid metric type.");
+ }
+}
+
+void gr_constellation::calc_euclidean_metric(const gr_complex *sample, float *metric) {
+ for (unsigned int o=0; o<d_arity; o++) {
+ metric[o] = get_distance(o, sample);
+ }
+}
+
+void gr_constellation::calc_hard_symbol_metric(const gr_complex *sample, float *metric){
+ float minm = FLT_MAX;
+ unsigned int minmi = 0;
+ for (unsigned int o=0; o<d_arity; o++) {
+ float dist = get_distance(o, sample);
+ if (dist < minm) {
+ minm = dist;
+ minmi = o;
+ }
+ }
+ for(unsigned int o=0; o<d_arity; o++) {
+ metric[o] = (o==minmi?0.0:1.0);
+ }
+}
+
+void gr_constellation::calc_arity () {
+ if (d_constellation.size() % d_dimensionality != 0)
+ throw std::runtime_error ("Constellation vector size must be a multiple of the dimensionality.");
+ d_arity = d_constellation.size()/d_dimensionality;
+}
+
+unsigned int gr_constellation::decision_maker_v (std::vector<gr_complex> sample) {
+ assert(sample.size() == d_dimensionality);
+ return decision_maker (&(sample[0]));
+}
+
+gr_constellation_calcdist_sptr
+gr_make_constellation_calcdist(std::vector<gr_complex> constellation, std::vector<unsigned int> pre_diff_code,
+ unsigned int rotational_symmetry, unsigned int dimensionality)
+{
+ return gr_constellation_calcdist_sptr(new gr_constellation_calcdist (constellation, pre_diff_code, rotational_symmetry,
+ dimensionality));
+}
+
+gr_constellation_calcdist::gr_constellation_calcdist(std::vector<gr_complex> constellation,
+ std::vector<unsigned int> pre_diff_code,
+ unsigned int rotational_symmetry,
+ unsigned int dimensionality) :
+ gr_constellation(constellation, pre_diff_code, rotational_symmetry, dimensionality)
+{}
+
+// Chooses points base on shortest distance.
+// Inefficient.
+unsigned int gr_constellation_calcdist::decision_maker(const gr_complex *sample)
+{
+ return get_closest_point(sample);
+}
+
+gr_constellation_sector::gr_constellation_sector (std::vector<gr_complex> constellation,
+ std::vector<unsigned int> pre_diff_code,
+ unsigned int rotational_symmetry,
+ unsigned int dimensionality,
+ unsigned int n_sectors) :
+ gr_constellation(constellation, pre_diff_code, rotational_symmetry, dimensionality),
+ n_sectors(n_sectors)
+{
+}
+
+unsigned int gr_constellation_sector::decision_maker (const gr_complex *sample) {
+ unsigned int sector;
+ sector = get_sector(sample);
+ return sector_values[sector];
+}
+
+void gr_constellation_sector::find_sector_values () {
+ unsigned int i;
+ sector_values.clear();
+ for (i=0; i<n_sectors; i++) {
+ sector_values.push_back(calc_sector_value(i));
+ }
+}
+
+gr_constellation_rect_sptr
+gr_make_constellation_rect(std::vector<gr_complex> constellation,
+ std::vector<unsigned int> pre_diff_code,
+ unsigned int rotational_symmetry,
+ unsigned int real_sectors, unsigned int imag_sectors,
+ float width_real_sectors, float width_imag_sectors)
+{
+ return gr_constellation_rect_sptr(new gr_constellation_rect (constellation, pre_diff_code, rotational_symmetry,
+ real_sectors, imag_sectors, width_real_sectors,
+ width_imag_sectors));
+ }
+
+gr_constellation_rect::gr_constellation_rect (std::vector<gr_complex> constellation,
+ std::vector<unsigned int> pre_diff_code,
+ unsigned int rotational_symmetry,
+ unsigned int real_sectors, unsigned int imag_sectors,
+ float width_real_sectors, float width_imag_sectors) :
+ gr_constellation_sector(constellation, pre_diff_code, rotational_symmetry, 1, real_sectors * imag_sectors),
+ n_real_sectors(real_sectors), n_imag_sectors(imag_sectors),
+ d_width_real_sectors(width_real_sectors), d_width_imag_sectors(width_imag_sectors)
+{
+ find_sector_values();
+}
+
+unsigned int gr_constellation_rect::get_sector (const gr_complex *sample) {
+ int real_sector, imag_sector;
+ unsigned int sector;
+ real_sector = int(real(*sample)/d_width_real_sectors + n_real_sectors/2.0);
+ if (real_sector < 0) real_sector = 0;
+ if (real_sector >= n_real_sectors) real_sector = n_real_sectors-1;
+ imag_sector = int(imag(*sample)/d_width_imag_sectors + n_imag_sectors/2.0);
+ if (imag_sector < 0) imag_sector = 0;
+ if (imag_sector >= n_imag_sectors) imag_sector = n_imag_sectors-1;
+ sector = real_sector * n_imag_sectors + imag_sector;
+ return sector;
+}
+
+unsigned int gr_constellation_rect::calc_sector_value (unsigned int sector) {
+ unsigned int real_sector, imag_sector;
+ gr_complex sector_center;
+ unsigned int closest_point;
+ real_sector = float(sector)/n_imag_sectors;
+ imag_sector = sector - real_sector * n_imag_sectors;
+ sector_center = gr_complex((real_sector + 0.5 - n_real_sectors/2.0) * d_width_real_sectors,
+ (imag_sector + 0.5 - n_imag_sectors/2.0) * d_width_imag_sectors);
+ closest_point = get_closest_point(&sector_center);
+ return closest_point;
+}
+
+
+gr_constellation_psk_sptr
+gr_make_constellation_psk(std::vector<gr_complex> constellation,
+ std::vector<unsigned int> pre_diff_code,
+ unsigned int n_sectors)
+{
+ return gr_constellation_psk_sptr(new gr_constellation_psk (constellation, pre_diff_code,
+ n_sectors));
+}
+
+gr_constellation_psk::gr_constellation_psk (std::vector<gr_complex> constellation,
+ std::vector<unsigned int> pre_diff_code,
+ unsigned int n_sectors) :
+ gr_constellation_sector(constellation, pre_diff_code, constellation.size(), 1, n_sectors)
+{
+ find_sector_values();
+}
+
+unsigned int gr_constellation_psk::get_sector (const gr_complex *sample) {
+ float phase = arg(*sample);
+ float width = M_TWOPI / n_sectors;
+ int sector = floor(phase/width + 0.5);
+ unsigned int u_sector;
+ if (sector < 0) sector += n_sectors;
+ u_sector = sector;
+ return sector;
+}
+
+unsigned int gr_constellation_psk::calc_sector_value (unsigned int sector) {
+ float phase = sector * M_TWOPI / n_sectors;
+ gr_complex sector_center = gr_complex(cos(phase), sin(phase));
+ unsigned int closest_point = get_closest_point(&sector_center);
+ return closest_point;
+}
+
+
+gr_constellation_bpsk_sptr
+gr_make_constellation_bpsk()
+{
+ return gr_constellation_bpsk_sptr(new gr_constellation_bpsk ());
+}
+
+gr_constellation_bpsk::gr_constellation_bpsk ()
+{
+ d_constellation.resize(2);
+ d_constellation[0] = gr_complex(-1, 0);
+ d_constellation[1] = gr_complex(1, 0);
+ d_rotational_symmetry = 2;
+ d_dimensionality = 1;
+ calc_arity();
+}
+
+unsigned int gr_constellation_bpsk::decision_maker(const gr_complex *sample)
+{
+ return (real(*sample) > 0);
+}
+
+
+gr_constellation_qpsk_sptr
+gr_make_constellation_qpsk()
+{
+ return gr_constellation_qpsk_sptr(new gr_constellation_qpsk ());
+}
+
+gr_constellation_qpsk::gr_constellation_qpsk ()
+{
+ d_constellation.resize(4);
+ // Gray-coded
+ d_constellation[0] = gr_complex(-SQRT_TWO, -SQRT_TWO);
+ d_constellation[1] = gr_complex(SQRT_TWO, -SQRT_TWO);
+ d_constellation[2] = gr_complex(-SQRT_TWO, SQRT_TWO);
+ d_constellation[3] = gr_complex(SQRT_TWO, SQRT_TWO);
+ d_rotational_symmetry = 4;
+ d_dimensionality = 1;
+ calc_arity();
+}
+
+unsigned int gr_constellation_qpsk::decision_maker(const gr_complex *sample)
+{
+ // Real component determines small bit.
+ // Imag component determines big bit.
+ return 2*(imag(*sample)>0) + (real(*sample)>0);
+}
diff --git a/gnuradio-core/src/lib/general/gr_constellation.h b/gnuradio-core/src/lib/general/gr_constellation.h
new file mode 100644
index 000000000..4ae539572
--- /dev/null
+++ b/gnuradio-core/src/lib/general/gr_constellation.h
@@ -0,0 +1,322 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2010 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.
+ */
+
+#ifndef INCLUDED_GR_CONSTELLATION_H
+#define INCLUDED_GR_CONSTELLATION_H
+
+#include <vector>
+#include <math.h>
+#include <gr_complex.h>
+#include <boost/enable_shared_from_this.hpp>
+#include <gr_metric_type.h>
+
+/************************************************************/
+/* gr_constellation */
+/* */
+/* Base class defining interface. */
+/************************************************************/
+
+class gr_constellation;
+typedef boost::shared_ptr<gr_constellation> gr_constellation_sptr;
+
+class gr_constellation : public boost::enable_shared_from_this<gr_constellation>
+{
+public:
+ gr_constellation (std::vector<gr_complex> constellation, std::vector<unsigned int> pre_diff_code,
+ unsigned int rotational_symmetry, unsigned int dimensionality);
+ gr_constellation ();
+
+ //! Returns the constellation points for a symbol value
+ void map_to_points(unsigned int value, gr_complex *points);
+ std::vector<gr_complex> map_to_points_v(unsigned int value);
+
+ //! Returns the constellation point that matches best.
+ virtual unsigned int decision_maker (const gr_complex *sample) = 0;
+ //! Takes a vector rather than a pointer. Better for SWIG wrapping.
+ unsigned int decision_maker_v (std::vector<gr_complex> sample);
+ //! Also calculates the phase error.
+ unsigned int decision_maker_pe (const gr_complex *sample, float *phase_error);
+ //! Calculates distance.
+ unsigned int decision_maker_e (const gr_complex *sample, float *error);
+
+ //! Calculates metrics for all points in the constellation.
+ //! For use with the viterbi algorithm.
+ virtual void calc_metric(const gr_complex *sample, float *metric, trellis_metric_type_t type);
+ virtual void calc_euclidean_metric(const gr_complex *sample, float *metric);
+ virtual void calc_hard_symbol_metric(const gr_complex *sample, float *metric);
+
+ //! Returns the set of points in this constellation.
+ std::vector<gr_complex> points() { return d_constellation;}
+ //! Returns the vector of points in this constellation.
+ //! Raise error if dimensionality is not one.
+ std::vector<gr_complex> s_points();
+ //! Returns a vector of vectors of points.
+ std::vector<std::vector<gr_complex> > v_points();
+ //! Whether to apply an encoding before doing differential encoding. (e.g. gray coding)
+ bool apply_pre_diff_code() { return d_apply_pre_diff_code;}
+ //! Returns the encoding to apply before differential encoding.
+ std::vector<unsigned int> pre_diff_code() { return d_pre_diff_code;}
+ //! Returns the order of rotational symmetry.
+ unsigned int rotational_symmetry() { return d_rotational_symmetry;}
+ //! Returns the number of complex numbers in a single symbol.
+ unsigned int dimensionality() {return d_dimensionality;}
+
+ unsigned int bits_per_symbol () {
+ return floor(log(d_constellation.size())/d_dimensionality/log(2));
+ }
+
+ unsigned int arity () {
+ return d_arity;
+ }
+
+ gr_constellation_sptr base() {
+ return shared_from_this();
+ }
+
+ protected:
+
+ std::vector<gr_complex> d_constellation;
+ std::vector<unsigned int> d_pre_diff_code;
+ bool d_apply_pre_diff_code;
+ unsigned int d_rotational_symmetry;
+ unsigned int d_dimensionality;
+ unsigned int d_arity;
+
+ float get_distance(unsigned int index, const gr_complex *sample);
+ unsigned int get_closest_point(const gr_complex *sample);
+ void calc_arity ();
+};
+
+/************************************************************/
+/* gr_constellation_calcdist */
+/* */
+/* Constellation which calculates the distance to each */
+/* point in the constellation for decision making. */
+/* Inefficient for large constellations. */
+/************************************************************/
+
+class gr_constellation_calcdist;
+typedef boost::shared_ptr<gr_constellation_calcdist> gr_constellation_calcdist_sptr;
+
+// public constructor
+gr_constellation_calcdist_sptr
+gr_make_constellation_calcdist (std::vector<gr_complex> constellation, std::vector<unsigned int> pre_diff_code,
+ unsigned int rotational_symmetry, unsigned int dimensionality);
+
+
+class gr_constellation_calcdist : public gr_constellation
+{
+ public:
+ gr_constellation_calcdist (std::vector<gr_complex> constellation,
+ std::vector<unsigned int> pre_diff_code,
+ unsigned int rotational_symmetry,
+ unsigned int dimensionality);
+ unsigned int decision_maker (const gr_complex *sample);
+ // void calc_metric(gr_complex *sample, float *metric, trellis_metric_type_t type);
+ // void calc_euclidean_metric(gr_complex *sample, float *metric);
+ // void calc_hard_symbol_metric(gr_complex *sample, float *metric);
+
+ private:
+ friend gr_constellation_calcdist_sptr
+ gr_make_constellation_calcdist (std::vector<gr_complex> constellation);
+};
+
+/************************************************************/
+/* gr_constellation_sector */
+/* */
+/* An abstract class. */
+/* Constellation space is divided into sectors. */
+/* Each sector is associated with the nearest constellation */
+/* point. */
+/************************************************************/
+
+class gr_constellation_sector : public gr_constellation
+{
+ public:
+
+ gr_constellation_sector (std::vector<gr_complex> constellation,
+ std::vector<unsigned int> pre_diff_code,
+ unsigned int rotational_symmetry,
+ unsigned int dimensionality,
+ unsigned int n_sectors);
+
+ unsigned int decision_maker (const gr_complex *sample);
+
+ protected:
+
+ virtual unsigned int get_sector (const gr_complex *sample) = 0;
+ virtual unsigned int calc_sector_value (unsigned int sector) = 0;
+ void find_sector_values ();
+
+ unsigned int n_sectors;
+
+ private:
+
+ std::vector<unsigned int> sector_values;
+
+};
+
+/************************************************************/
+/* gr_constellation_rect */
+/* */
+/* Only implemented for 1-(complex)dimensional */
+/* constellation. */
+/* Constellation space is divided into rectangular sectors. */
+/* Each sector is associated with the nearest constellation */
+/* point. */
+/* Works well for square QAM. */
+/* Works for any generic constellation provided sectors are */
+/* not too large. */
+/************************************************************/
+
+class gr_constellation_rect;
+typedef boost::shared_ptr<gr_constellation_rect> gr_constellation_rect_sptr;
+
+// public constructor
+gr_constellation_rect_sptr
+gr_make_constellation_rect (std::vector<gr_complex> constellation, std::vector<unsigned int> pre_diff_code,
+ unsigned int rotational_symmetry,
+ unsigned int real_sectors, unsigned int imag_sectors,
+ float width_real_sectors, float width_imag_sectors);
+
+class gr_constellation_rect : public gr_constellation_sector
+{
+ public:
+
+ gr_constellation_rect (std::vector<gr_complex> constellation, std::vector<unsigned int> pre_diff_code,
+ unsigned int rotational_symmetry,
+ unsigned int real_sectors, unsigned int imag_sectors,
+ float width_real_sectors, float width_imag_sectors);
+
+ protected:
+
+ unsigned int get_sector (const gr_complex *sample);
+
+ unsigned int calc_sector_value (unsigned int sector);
+
+ private:
+
+ unsigned int n_real_sectors;
+ unsigned int n_imag_sectors;
+ float d_width_real_sectors;
+ float d_width_imag_sectors;
+
+ friend gr_constellation_rect_sptr
+ gr_make_constellation_rect (std::vector<gr_complex> constellation, std::vector<unsigned int> pre_diff_code,
+ unsigned int rotational_symmetry,
+ unsigned int real_sectors, unsigned int imag_sectors,
+ float width_real_sectors, float width_imag_sectors);
+
+};
+
+/************************************************************/
+/* gr_constellation_psk */
+/* */
+/* Constellation space is divided into pie slices sectors. */
+/* Each slice is associated with the nearest constellation */
+/* point. */
+/* Works well for PSK but nothing else. */
+/* Assumes that there is a constellation point at 1. */
+/************************************************************/
+
+class gr_constellation_psk;
+typedef boost::shared_ptr<gr_constellation_psk> gr_constellation_psk_sptr;
+
+// public constructor
+gr_constellation_psk_sptr
+gr_make_constellation_psk (std::vector<gr_complex> constellation, std::vector<unsigned int> pre_diff_code,
+ unsigned int n_sectors);
+
+class gr_constellation_psk : public gr_constellation_sector
+{
+ public:
+
+ gr_constellation_psk (std::vector<gr_complex> constellation, std::vector<unsigned int> pre_diff_code,
+ unsigned int n_sectors);
+
+ protected:
+
+ unsigned int get_sector (const gr_complex *sample);
+
+ unsigned int calc_sector_value (unsigned int sector);
+
+ private:
+
+ friend gr_constellation_psk_sptr
+ gr_make_constellation_psk (std::vector<gr_complex> constellation, std::vector<unsigned int> pre_diff_code,
+ unsigned int n_sectors);
+
+};
+
+/************************************************************/
+/* gr_constellation_bpsk */
+/* */
+/* Only works for BPSK. */
+/* */
+/************************************************************/
+
+class gr_constellation_bpsk;
+typedef boost::shared_ptr<gr_constellation_bpsk> gr_constellation_bpsk_sptr;
+
+// public constructor
+gr_constellation_bpsk_sptr
+gr_make_constellation_bpsk ();
+
+class gr_constellation_bpsk : public gr_constellation
+{
+ public:
+
+ gr_constellation_bpsk ();
+ unsigned int decision_maker (const gr_complex *sample);
+
+ friend gr_constellation_bpsk_sptr
+ gr_make_constellation_bpsk ();
+
+};
+
+/************************************************************/
+/* gr_constellation_qpsk */
+/* */
+/* Only works for QPSK. */
+/* */
+/************************************************************/
+
+class gr_constellation_qpsk;
+typedef boost::shared_ptr<gr_constellation_qpsk> gr_constellation_qpsk_sptr;
+
+// public constructor
+gr_constellation_qpsk_sptr
+gr_make_constellation_qpsk ();
+
+class gr_constellation_qpsk : public gr_constellation
+{
+ public:
+
+ gr_constellation_qpsk ();
+ unsigned int decision_maker (const gr_complex *sample);
+
+ friend gr_constellation_qpsk_sptr
+ gr_make_constellation_qpsk ();
+
+};
+
+#endif
diff --git a/gnuradio-core/src/lib/general/gr_constellation.i b/gnuradio-core/src/lib/general/gr_constellation.i
new file mode 100644
index 000000000..bc1724c3a
--- /dev/null
+++ b/gnuradio-core/src/lib/general/gr_constellation.i
@@ -0,0 +1,146 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2010 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.
+ */
+
+%template(gr_complex_vector) std::vector<gr_complex>;
+%template(unsigned_int_vector) std::vector<unsigned int>;
+
+// Make sure metric types get SWIGed.
+%include gr_metric_type.h
+
+class gr_constellation;
+typedef boost::shared_ptr<gr_constellation> gr_constellation_sptr;
+%template(gr_constellation_sptr) boost::shared_ptr<gr_constellation>;
+
+class gr_constellation
+{
+public:
+ gr_constellation (std::vector<gr_complex> constellation,
+ std::vector<unsigned int> pre_diff_code,
+ unsigned int rotational_symmetry,
+ unsigned int dimensionality);
+ std::vector<gr_complex> points();
+ std::vector<gr_complex> s_points();
+ std::vector<std::vector<gr_complex> > v_points();
+ virtual unsigned int decision_maker (gr_complex *sample) = 0;
+ unsigned int decision_maker_v (std::vector<gr_complex> sample);
+ // void calc_metric(gr_complex *sample, float *metric, trellis_metric_type_t type);
+ // void calc_euclidean_metric(gr_complex *sample, float *metric);
+ // void calc_hard_symbol_metric(gr_complex *sample, float *metric);
+ std::vector<gr_complex> map_to_points_v(unsigned int value);
+ unsigned int bits_per_symbol ();
+ unsigned int arity ();
+ gr_constellation_sptr base ();
+ bool apply_pre_diff_code();
+ std::vector<unsigned int> pre_diff_code();
+ unsigned int rotational_symmetry();
+ unsigned int dimensionality();
+};
+
+class gr_constellation_calcdist;
+typedef boost::shared_ptr<gr_constellation_calcdist> gr_constellation_calcdist_sptr;
+%template(gr_constellation_calcdist_sptr) boost::shared_ptr<gr_constellation_calcdist>;
+%rename(constellation_calcdist) gr_make_constellation_calcdist;
+gr_constellation_calcdist_sptr
+gr_make_constellation_calcdist(std::vector<gr_complex> constellation,
+ std::vector<unsigned int> pre_diff_code,
+ unsigned int rotational_symmetry,
+ unsigned int dimensionality);
+%ignore gr_constellation_calcdist;
+
+class gr_constellation_calcdist: public gr_constellation
+{
+ public:
+ gr_constellation_calcdist (std::vector<gr_complex> constellation,
+ std::vector<unsigned int> pre_diff_code,
+ unsigned int rotational_symmetry,
+ unsigned int dimensionality);
+ unsigned int decision_maker (const gr_complex *sample);
+};
+
+class gr_constellation_sector: public gr_constellation
+{
+};
+
+class gr_constellation_rect;
+typedef boost::shared_ptr<gr_constellation_rect> gr_constellation_rect_sptr;
+%template(gr_constellation_rect_sptr) boost::shared_ptr<gr_constellation_rect>;
+%rename(constellation_rect) gr_make_constellation_rect;
+gr_constellation_rect_sptr gr_make_constellation_rect(std::vector<gr_complex> constellation,
+ std::vector<unsigned int> pre_diff_code,
+ unsigned int rotational_symmetry,
+ unsigned int real_sectors, unsigned int imag_sectors,
+ float width_real_sectors, float width_imag_sectors);
+%ignore gr_constellation_rect;
+
+class gr_constellation_rect : public gr_constellation_sector
+{
+public:
+ gr_constellation_rect (std::vector<gr_complex> constellation,
+ std::vector<unsigned int> pre_diff_code,
+ unsigned int rotational_symmetry,
+ unsigned int real_sectors, unsigned int imag_sectors,
+ float width_real_sectors, float width_imag_sectors);
+};
+
+class gr_constellation_psk;
+typedef boost::shared_ptr<gr_constellation_psk> gr_constellation_psk_sptr;
+%template(gr_constellation_psk_sptr) boost::shared_ptr<gr_constellation_psk>;
+%rename(constellation_psk) gr_make_constellation_psk;
+gr_constellation_psk_sptr gr_make_constellation_psk(std::vector<gr_complex> constellation,
+ std::vector<unsigned int> pre_diff_code,
+ unsigned int n_sectors);
+%ignore gr_constellation_psk;
+
+class gr_constellation_psk : public gr_constellation_sector
+{
+public:
+ gr_constellation_psk (std::vector<gr_complex> constellation,
+ std::vector<unsigned int> pre_diff_code,
+ unsigned int n_sectors);
+};
+
+class gr_constellation_bpsk;
+typedef boost::shared_ptr<gr_constellation_bpsk> gr_constellation_bpsk_sptr;
+%template(gr_constellation_bpsk_sptr) boost::shared_ptr<gr_constellation_bpsk>;
+%rename(constellation_bpsk) gr_make_constellation_bpsk;
+gr_constellation_bpsk_sptr gr_make_constellation_bpsk();
+%ignore gr_constellation_bpsk;
+
+class gr_constellation_bpsk : public gr_constellation
+{
+public:
+ gr_constellation_bpsk ();
+};
+
+class gr_constellation_qpsk;
+typedef boost::shared_ptr<gr_constellation_qpsk> gr_constellation_qpsk_sptr;
+%template(gr_constellation_qpsk_sptr) boost::shared_ptr<gr_constellation_qpsk>;
+%rename(constellation_qpsk) gr_make_constellation_qpsk;
+gr_constellation_qpsk_sptr gr_make_constellation_qpsk();
+%ignore gr_constellation_qpsk;
+
+class gr_constellation_qpsk : public gr_constellation
+{
+public:
+ gr_constellation_qpsk ();
+};
+
diff --git a/gnuradio-core/src/lib/general/gr_constellation_decoder2_cb.cc b/gnuradio-core/src/lib/general/gr_constellation_decoder2_cb.cc
new file mode 100644
index 000000000..a63c1d38a
--- /dev/null
+++ b/gnuradio-core/src/lib/general/gr_constellation_decoder2_cb.cc
@@ -0,0 +1,78 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2006, 2011 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gr_constellation_decoder2_cb.h>
+#include <gr_constellation.h>
+#include <gr_io_signature.h>
+#include <iostream>
+
+gr_constellation_decoder2_cb_sptr
+gr_make_constellation_decoder2_cb (gr_constellation_sptr constellation)
+{
+ return gr_constellation_decoder2_cb_sptr
+ (new gr_constellation_decoder2_cb(constellation));
+}
+
+gr_constellation_decoder2_cb::
+gr_constellation_decoder2_cb (gr_constellation_sptr constellation)
+ : gr_block ("constellation_decoder2_cb",
+ gr_make_io_signature (1, 1, sizeof (gr_complex)),
+ gr_make_io_signature (1, 1, sizeof (unsigned char))),
+ d_constellation(constellation),
+ d_dim(constellation->dimensionality())
+{
+ set_relative_rate (1.0 / ((double) d_dim));
+}
+
+void
+gr_constellation_decoder2_cb::forecast (int noutput_items,
+ gr_vector_int &ninput_items_required)
+{
+ unsigned int input_required = noutput_items * d_dim;
+
+ unsigned ninputs = ninput_items_required.size();
+ for (unsigned int i = 0; i < ninputs; i++)
+ ninput_items_required[i] = input_required;
+}
+
+
+int
+gr_constellation_decoder2_cb::
+general_work (int noutput_items,
+ gr_vector_int &ninput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items)
+{
+ gr_complex const *in = (const gr_complex *) input_items[0];
+ unsigned char *out = (unsigned char *) output_items[0];
+
+ for(int i = 0; i < noutput_items; i++){
+ out[i] = d_constellation->decision_maker(&(in[i*d_dim]));
+ }
+
+ consume_each (noutput_items * d_dim);
+ return noutput_items;
+}
diff --git a/gnuradio-core/src/lib/general/gr_constellation_decoder2_cb.h b/gnuradio-core/src/lib/general/gr_constellation_decoder2_cb.h
new file mode 100644
index 000000000..51891b636
--- /dev/null
+++ b/gnuradio-core/src/lib/general/gr_constellation_decoder2_cb.h
@@ -0,0 +1,64 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2006, 2011 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.
+ */
+
+#ifndef INCLUDED_GR_CONSTELLATION_DECODER2_CB_H
+#define INCLUDED_GR_CONSTELLATION_DECODER2_CB_H
+
+#include <gr_block.h>
+#include <gr_constellation.h>
+#include <vector>
+
+class gr_constellation_decoder2_cb;
+typedef boost::shared_ptr<gr_constellation_decoder2_cb> gr_constellation_decoder2_cb_sptr;
+
+gr_constellation_decoder2_cb_sptr
+gr_make_constellation_decoder2_cb (gr_constellation_sptr constellation);
+
+/*!
+ * \brief Constellation Decoder
+ * \ingroup coding_blk
+ *
+ */
+class gr_constellation_decoder2_cb : public gr_block
+{
+
+ private:
+ gr_constellation_sptr d_constellation;
+ unsigned int d_dim;
+
+ friend gr_constellation_decoder2_cb_sptr
+ gr_make_constellation_decoder2_cb (gr_constellation_sptr constellation);
+
+ gr_constellation_decoder2_cb (gr_constellation_sptr constellation);
+
+ public:
+
+ void forecast (int noutput_items,
+ gr_vector_int &ninput_items_required);
+
+ int general_work (int noutput_items,
+ gr_vector_int &ninput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items);
+};
+
+#endif
diff --git a/gnuradio-core/src/lib/general/gr_constellation_decoder2_cb.i b/gnuradio-core/src/lib/general/gr_constellation_decoder2_cb.i
new file mode 100644
index 000000000..2865363d8
--- /dev/null
+++ b/gnuradio-core/src/lib/general/gr_constellation_decoder2_cb.i
@@ -0,0 +1,38 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2006, 2011 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.
+ */
+
+GR_SWIG_BLOCK_MAGIC(gr,constellation_decoder2_cb)
+
+gr_constellation_decoder2_cb_sptr
+gr_make_constellation_decoder2_cb (gr_constellation_sptr constellation);
+
+class gr_constellation_decoder2_cb : public gr_sync_block
+{
+ private:
+ gr_constellation_decoder2_cb (gr_constellation_sptr constellation);
+
+ friend gr_constellation_decoder2_cb_sptr
+ gr_make_constellation_decoder2_cb (gr_constellation_sptr constellation);
+
+ public:
+ ~gr_constellation_decoder2_cb();
+};
diff --git a/gnuradio-core/src/lib/general/gr_constellation_receiver_cb.cc b/gnuradio-core/src/lib/general/gr_constellation_receiver_cb.cc
new file mode 100644
index 000000000..dae70d931
--- /dev/null
+++ b/gnuradio-core/src/lib/general/gr_constellation_receiver_cb.cc
@@ -0,0 +1,131 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2005,2006,2007,2010 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gr_io_signature.h>
+#include <gr_prefs.h>
+#include <gr_constellation.h>
+#include <gr_constellation_receiver_cb.h>
+#include <stdexcept>
+#include <gr_math.h>
+#include <gr_expj.h>
+
+
+#define M_TWOPI (2*M_PI)
+#define VERBOSE_MM 0 // Used for debugging symbol timing loop
+#define VERBOSE_COSTAS 0 // Used for debugging phase and frequency tracking
+
+// Public constructor
+
+gr_constellation_receiver_cb_sptr
+gr_make_constellation_receiver_cb(gr_constellation_sptr constell,
+ float alpha, float beta,
+ float fmin, float fmax)
+{
+ return gnuradio::get_initial_sptr(new gr_constellation_receiver_cb (constell,
+ alpha, beta,
+ fmin, fmax));
+}
+
+static int ios[] = {sizeof(char), sizeof(float), sizeof(float), sizeof(float)};
+static std::vector<int> iosig(ios, ios+sizeof(ios)/sizeof(int));
+gr_constellation_receiver_cb::gr_constellation_receiver_cb (gr_constellation_sptr constellation,
+ float alpha, float beta,
+ float fmin, float fmax)
+ : gr_block ("constellation_receiver_cb",
+ gr_make_io_signature (1, 1, sizeof (gr_complex)),
+ gr_make_io_signaturev (1, 4, iosig)),
+ d_constellation(constellation),
+ d_alpha(alpha), d_beta(beta), d_freq(0), d_max_freq(fmax), d_min_freq(fmin), d_phase(0),
+ d_current_const_point(0)
+{
+ if (d_constellation->dimensionality() != 1)
+ throw std::runtime_error ("This receiver only works with constellations of dimension 1.");
+}
+
+void
+gr_constellation_receiver_cb::phase_error_tracking(float phase_error)
+{
+ d_freq += d_beta*phase_error; // adjust frequency based on error
+ d_phase += d_freq + d_alpha*phase_error; // adjust phase based on error
+
+ // Make sure we stay within +-2pi
+ while(d_phase > M_TWOPI)
+ d_phase -= M_TWOPI;
+ while(d_phase < -M_TWOPI)
+ d_phase += M_TWOPI;
+
+ // Limit the frequency range
+ d_freq = gr_branchless_clip(d_freq, d_max_freq);
+
+#if VERBOSE_COSTAS
+ printf("cl: phase_error: %f phase: %f freq: %f sample: %f+j%f constellation: %f+j%f\n",
+ phase_error, d_phase, d_freq, sample.real(), sample.imag(),
+ d_constellation->points()[d_current_const_point].real(), d_constellation->points()[d_current_const_point].imag());
+#endif
+}
+
+int
+gr_constellation_receiver_cb::general_work (int noutput_items,
+ gr_vector_int &ninput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items)
+{
+ const gr_complex *in = (const gr_complex *) input_items[0];
+ unsigned char *out = (unsigned char *) output_items[0];
+
+ int i=0;
+
+ float phase_error;
+ unsigned int sym_value;
+ gr_complex sample, nco;
+
+ float *out_err = 0, *out_phase = 0, *out_freq = 0;
+ if(output_items.size() == 4) {
+ out_err = (float *) output_items[1];
+ out_phase = (float *) output_items[2];
+ out_freq = (float *) output_items[3];
+ }
+
+ while((i < noutput_items) && (i < ninput_items[0])) {
+ sample = in[i];
+ nco = gr_expj(d_phase); // get the NCO value for derotating the current sample
+ sample = nco*sample; // get the downconverted symbol
+ sym_value = d_constellation->decision_maker_pe(&sample, &phase_error);
+ // phase_error = -arg(sample*conj(d_constellation->points()[sym_value]));
+ phase_error_tracking(phase_error); // corrects phase and frequency offsets
+ out[i] = sym_value;
+ if(output_items.size() == 4) {
+ out_err[i] = phase_error;
+ out_phase[i] = d_phase;
+ out_freq[i] = d_freq;
+ }
+ i++;
+ }
+
+ consume_each(i);
+ return i;
+}
+
diff --git a/gnuradio-core/src/lib/general/gr_constellation_receiver_cb.h b/gnuradio-core/src/lib/general/gr_constellation_receiver_cb.h
new file mode 100644
index 000000000..d40d77fff
--- /dev/null
+++ b/gnuradio-core/src/lib/general/gr_constellation_receiver_cb.h
@@ -0,0 +1,149 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2004,2007,2010 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.
+ */
+
+#ifndef INCLUDED_GR_CONSTELLATION_RECEIVER_CB_H
+#define INCLUDED_GR_CONSTELLATION_RECEIVER_CB_H
+
+#include <gr_block.h>
+#include <gr_constellation.h>
+#include <gr_complex.h>
+#include <math.h>
+#include <fstream>
+
+class gr_constellation_receiver_cb;
+typedef boost::shared_ptr<gr_constellation_receiver_cb> gr_constellation_receiver_cb_sptr;
+
+// public constructor
+gr_constellation_receiver_cb_sptr
+gr_make_constellation_receiver_cb (gr_constellation_sptr constellation,
+ float alpha, float beta,
+ float fmin, float fmax);
+
+/*!
+ * \brief This block takes care of receiving generic modulated signals through phase, frequency, and symbol
+ * synchronization.
+ * \ingroup sync_blk
+ * \ingroup demod_blk
+ *
+ * This block takes care of receiving generic modulated signals through phase, frequency, and symbol
+ * synchronization. It performs carrier frequency and phase locking as well as symbol timing recovery.
+ *
+ * The phase and frequency synchronization are based on a Costas loop that finds the error of the incoming
+ * signal point compared to its nearest constellation point. The frequency and phase of the NCO are
+ * updated according to this error.
+ *
+ * The symbol synchronization is done using a modified Mueller and Muller circuit from the paper:
+ *
+ * G. R. Danesfahani, T.G. Jeans, "Optimisation of modified Mueller and Muller
+ * algorithm," Electronics Letters, Vol. 31, no. 13, 22 June 1995, pp. 1032 - 1033.
+ *
+ * This circuit interpolates the downconverted sample (using the NCO developed by the Costas loop)
+ * every mu samples, then it finds the sampling error based on this and the past symbols and the decision
+ * made on the samples. Like the phase error detector, there are optimized decision algorithms for BPSK
+ * and QPKS, but 8PSK uses another brute force computation against all possible symbols. The modifications
+ * to the M&M used here reduce self-noise.
+ *
+ */
+
+class gr_constellation_receiver_cb : public gr_block
+{
+ public:
+ int general_work (int noutput_items,
+ gr_vector_int &ninput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items);
+
+
+ // Member function related to the phase/frequency tracking portion of the receiver
+ //! (CL) Returns the value for alpha (the phase gain term)
+ float alpha() const { return d_alpha; }
+
+ //! (CL) Returns the value of beta (the frequency gain term)
+ float beta() const { return d_beta; }
+
+ //! (CL) Returns the current value of the frequency of the NCO in the Costas loop
+ float freq() const { return d_freq; }
+
+ //! (CL) Returns the current value of the phase of the NCO in the Costal loop
+ float phase() const { return d_phase; }
+
+ //! (CL) Sets the value for alpha (the phase gain term)
+ void set_alpha(float alpha) { d_alpha = alpha; }
+
+ //! (CL) Setss the value of beta (the frequency gain term)
+ void set_beta(float beta) { d_beta = beta; }
+
+ //! (CL) Sets the current value of the frequency of the NCO in the Costas loop
+ void set_freq(float freq) { d_freq = freq; }
+
+ //! (CL) Setss the current value of the phase of the NCO in the Costal loop
+ void set_phase(float phase) { d_phase = phase; }
+
+
+protected:
+
+ /*!
+ * \brief Constructor to synchronize incoming M-PSK symbols
+ *
+ * \param constellation constellation of points for generic modulation
+ * \param alpha gain parameter to adjust the phase in the Costas loop (~0.01)
+ * \param beta gain parameter to adjust the frequency in the Costas loop (~alpha^2/4)
+ * \param fmin minimum normalized frequency value the loop can achieve
+ * \param fmax maximum normalized frequency value the loop can achieve
+ *
+ * The constructor also chooses which phase detector and decision maker to use in the work loop based on the
+ * value of M.
+ */
+ gr_constellation_receiver_cb (gr_constellation_sptr constellation,
+ float alpha, float beta,
+ float fmin, float fmax);
+
+ void phase_error_tracking(float phase_error);
+
+ private:
+ unsigned int d_M;
+
+ // Members related to carrier and phase tracking
+ float d_alpha;
+ float d_beta;
+ float d_freq, d_max_freq, d_min_freq;
+ float d_phase;
+
+ gr_constellation_sptr d_constellation;
+ unsigned int d_current_const_point;
+
+ //! delay line length.
+ static const unsigned int DLLEN = 8;
+
+ //! delay line plus some length for overflow protection
+ gr_complex d_dl[2*DLLEN] __attribute__ ((aligned(8)));
+
+ //! index to delay line
+ unsigned int d_dl_idx;
+
+ friend gr_constellation_receiver_cb_sptr
+ gr_make_constellation_receiver_cb (gr_constellation_sptr constell,
+ float alpha, float beta,
+ float fmin, float fmax);
+};
+
+#endif
diff --git a/gnuradio-core/src/lib/general/gr_constellation_receiver_cb.i b/gnuradio-core/src/lib/general/gr_constellation_receiver_cb.i
new file mode 100644
index 000000000..2298d5099
--- /dev/null
+++ b/gnuradio-core/src/lib/general/gr_constellation_receiver_cb.i
@@ -0,0 +1,43 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2004 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.
+ */
+
+GR_SWIG_BLOCK_MAGIC(gr,constellation_receiver_cb);
+
+gr_constellation_receiver_cb_sptr gr_make_constellation_receiver_cb (gr_constellation_sptr constellation,
+ float alpha, float beta,
+ float fmin, float fmax);
+class gr_constellation_receiver_cb : public gr_block
+{
+ private:
+ gr_constellation_receiver_cb (gr_contellation_sptr constellation,
+ float alpha, float beta,
+ float fmin, float fmax);
+public:
+ float alpha() const { return d_alpha; }
+ float beta() const { return d_beta; }
+ float freq() const { return d_freq; }
+ float phase() const { return d_phase; }
+ void set_alpha(float alpha) { d_alpha = alpha; }
+ void set_beta(float beta) { d_beta = beta; }
+ void set_freq(float freq) { d_freq = freq; }
+ void set_phase(float phase) { d_phase = phase; }
+};
diff --git a/gnuradio-core/src/lib/general/gr_metric_type.h b/gnuradio-core/src/lib/general/gr_metric_type.h
new file mode 100644
index 000000000..74c93b55e
--- /dev/null
+++ b/gnuradio-core/src/lib/general/gr_metric_type.h
@@ -0,0 +1,31 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2004 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.
+ */
+
+#ifndef INCLUDED_GR_METRIC_TYPE_H
+#define INCLUDED_GR_METRIC_TYPE_H
+
+typedef enum {
+ TRELLIS_EUCLIDEAN = 200, TRELLIS_HARD_SYMBOL, TRELLIS_HARD_BIT
+} trellis_metric_type_t;
+
+#endif
+
diff --git a/gnuradio-core/src/lib/general/gr_ofdm_frame_sink2.cc b/gnuradio-core/src/lib/general/gr_ofdm_frame_sink2.cc
new file mode 100644
index 000000000..f0cb0fb0a
--- /dev/null
+++ b/gnuradio-core/src/lib/general/gr_ofdm_frame_sink2.cc
@@ -0,0 +1,374 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2007,2008,2010 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gr_ofdm_frame_sink2.h>
+#include <gr_io_signature.h>
+#include <gr_expj.h>
+#include <gr_math.h>
+#include <math.h>
+#include <cstdio>
+#include <stdexcept>
+#include <iostream>
+#include <string.h>
+#include <gr_constellation.h>
+
+#define VERBOSE 0
+
+inline void
+gr_ofdm_frame_sink2::enter_search()
+{
+ if (VERBOSE)
+ fprintf(stderr, "@ enter_search\n");
+
+ d_state = STATE_SYNC_SEARCH;
+
+}
+
+inline void
+gr_ofdm_frame_sink2::enter_have_sync()
+{
+ if (VERBOSE)
+ fprintf(stderr, "@ enter_have_sync\n");
+
+ d_state = STATE_HAVE_SYNC;
+
+ // clear state of demapper
+ d_byte_offset = 0;
+ d_partial_byte = 0;
+
+ d_header = 0;
+ d_headerbytelen_cnt = 0;
+
+ // Resetting PLL
+ d_freq = 0.0;
+ d_phase = 0.0;
+ fill(d_dfe.begin(), d_dfe.end(), gr_complex(1.0,0.0));
+}
+
+inline void
+gr_ofdm_frame_sink2::enter_have_header()
+{
+ d_state = STATE_HAVE_HEADER;
+
+ // header consists of two 16-bit shorts in network byte order
+ // payload length is lower 12 bits
+ // whitener offset is upper 4 bits
+ d_packetlen = (d_header >> 16) & 0x0fff;
+ d_packet_whitener_offset = (d_header >> 28) & 0x000f;
+ d_packetlen_cnt = 0;
+
+ if (VERBOSE)
+ fprintf(stderr, "@ enter_have_header (payload_len = %d) (offset = %d)\n",
+ d_packetlen, d_packet_whitener_offset);
+}
+
+
+unsigned int gr_ofdm_frame_sink2::demapper(const gr_complex *in,
+ unsigned char *out)
+{
+ unsigned int i=0, bytes_produced=0;
+ gr_complex carrier;
+
+ carrier=gr_expj(d_phase);
+
+ gr_complex accum_error = 0.0;
+ //while(i < d_occupied_carriers) {
+ while(i < d_subcarrier_map.size()) {
+ if(d_nresid > 0) {
+ d_partial_byte |= d_resid;
+ d_byte_offset += d_nresid;
+ d_nresid = 0;
+ d_resid = 0;
+ }
+
+ //while((d_byte_offset < 8) && (i < d_occupied_carriers)) {
+ while((d_byte_offset < 8) && (i < d_subcarrier_map.size())) {
+ //gr_complex sigrot = in[i]*carrier*d_dfe[i];
+ gr_complex sigrot = in[d_subcarrier_map[i]]*carrier*d_dfe[i];
+
+ if(d_derotated_output != NULL){
+ d_derotated_output[i] = sigrot;
+ }
+
+ unsigned char bits = d_constell->decision_maker(&sigrot);
+
+ gr_complex closest_sym = d_constell->points()[bits];
+
+ accum_error += sigrot * conj(closest_sym);
+
+ // FIX THE FOLLOWING STATEMENT
+ if (norm(sigrot)> 0.001) d_dfe[i] += d_eq_gain*(closest_sym/sigrot-d_dfe[i]);
+
+ i++;
+
+ if((8 - d_byte_offset) >= d_nbits) {
+ d_partial_byte |= bits << (d_byte_offset);
+ d_byte_offset += d_nbits;
+ }
+ else {
+ d_nresid = d_nbits-(8-d_byte_offset);
+ int mask = ((1<<(8-d_byte_offset))-1);
+ d_partial_byte |= (bits & mask) << d_byte_offset;
+ d_resid = bits >> (8-d_byte_offset);
+ d_byte_offset += (d_nbits - d_nresid);
+ }
+ //printf("demod symbol: %.4f + j%.4f bits: %x partial_byte: %x byte_offset: %d resid: %x nresid: %d\n",
+ // in[i-1].real(), in[i-1].imag(), bits, d_partial_byte, d_byte_offset, d_resid, d_nresid);
+ }
+
+ if(d_byte_offset == 8) {
+ //printf("demod byte: %x \n\n", d_partial_byte);
+ out[bytes_produced++] = d_partial_byte;
+ d_byte_offset = 0;
+ d_partial_byte = 0;
+ }
+ }
+ //std::cerr << "accum_error " << accum_error << std::endl;
+
+ float angle = arg(accum_error);
+
+ d_freq = d_freq - d_freq_gain*angle;
+ d_phase = d_phase + d_freq - d_phase_gain*angle;
+ if (d_phase >= 2*M_PI) d_phase -= 2*M_PI;
+ if (d_phase <0) d_phase += 2*M_PI;
+
+ //if(VERBOSE)
+ // std::cerr << angle << "\t" << d_freq << "\t" << d_phase << "\t" << std::endl;
+
+ return bytes_produced;
+}
+
+
+gr_ofdm_frame_sink2_sptr
+gr_make_ofdm_frame_sink2(gr_constellation_sptr constell,
+ gr_msg_queue_sptr target_queue, unsigned int occupied_carriers,
+ float phase_gain, float freq_gain)
+{
+ return gnuradio::get_initial_sptr(new gr_ofdm_frame_sink2(constell,
+ target_queue, occupied_carriers,
+ phase_gain, freq_gain));
+}
+
+
+gr_ofdm_frame_sink2::gr_ofdm_frame_sink2(gr_constellation_sptr constell,
+ gr_msg_queue_sptr target_queue, unsigned int occupied_carriers,
+ float phase_gain, float freq_gain)
+ : gr_sync_block ("ofdm_frame_sink2",
+ gr_make_io_signature2 (2, 2, sizeof(gr_complex)*occupied_carriers, sizeof(char)),
+ gr_make_io_signature (1, 1, sizeof(gr_complex)*occupied_carriers)),
+ d_constell(constell),
+ d_target_queue(target_queue), d_occupied_carriers(occupied_carriers),
+ d_byte_offset(0), d_partial_byte(0),
+ d_resid(0), d_nresid(0),d_phase(0),d_freq(0),d_phase_gain(phase_gain),d_freq_gain(freq_gain),
+ d_eq_gain(0.05)
+{
+ if (d_constell->dimensionality() != 1)
+ throw std::runtime_error ("This receiver only works with constellations of dimension 1.");
+
+ std::string carriers = "FE7F";
+
+ // A bit hacky to fill out carriers to occupied_carriers length
+ int diff = (d_occupied_carriers - 4*carriers.length());
+ while(diff > 7) {
+ carriers.insert(0, "f");
+ carriers.insert(carriers.length(), "f");
+ diff -= 8;
+ }
+
+ // if there's extras left to be processed
+ // divide remaining to put on either side of current map
+ // all of this is done to stick with the concept of a carrier map string that
+ // can be later passed by the user, even though it'd be cleaner to just do this
+ // on the carrier map itself
+ int diff_left=0;
+ int diff_right=0;
+
+ // dictionary to convert from integers to ascii hex representation
+ char abc[16] = {'0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
+ if(diff > 0) {
+ char c[2] = {0,0};
+
+ diff_left = (int)ceil((float)diff/2.0f); // number of carriers to put on the left side
+ c[0] = abc[(1 << diff_left) - 1]; // convert to bits and move to ASCI integer
+ carriers.insert(0, c);
+
+ diff_right = diff - diff_left; // number of carriers to put on the right side
+ c[0] = abc[0xF^((1 << diff_right) - 1)]; // convert to bits and move to ASCI integer
+ carriers.insert(carriers.length(), c);
+ }
+
+ // It seemed like such a good idea at the time...
+ // because we are only dealing with the occupied_carriers
+ // at this point, the diff_left in the following compensates
+ // for any offset from the 0th carrier introduced
+ unsigned int i,j,k;
+ for(i = 0; i < (d_occupied_carriers/4)+diff_left; i++) {
+ char c = carriers[i];
+ for(j = 0; j < 4; j++) {
+ k = (strtol(&c, NULL, 16) >> (3-j)) & 0x1;
+ if(k) {
+ d_subcarrier_map.push_back(4*i + j - diff_left);
+ }
+ }
+ }
+
+ // make sure we stay in the limit currently imposed by the occupied_carriers
+ if(d_subcarrier_map.size() > d_occupied_carriers) {
+ throw std::invalid_argument("gr_ofdm_mapper_bcv: subcarriers allocated exceeds size of occupied carriers");
+ }
+
+ d_bytes_out = new unsigned char[d_occupied_carriers];
+ d_dfe.resize(occupied_carriers);
+ fill(d_dfe.begin(), d_dfe.end(), gr_complex(1.0,0.0));
+
+ d_nbits = d_constell->bits_per_symbol();
+
+ enter_search();
+}
+
+gr_ofdm_frame_sink2::~gr_ofdm_frame_sink2 ()
+{
+ delete [] d_bytes_out;
+}
+
+
+int
+gr_ofdm_frame_sink2::work (int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items)
+{
+ const gr_complex *in = (const gr_complex *) input_items[0];
+ const char *sig = (const char *) input_items[1];
+ unsigned int j = 0;
+ unsigned int bytes=0;
+
+ // If the output is connected, send it the derotated symbols
+ if(output_items.size() >= 1)
+ d_derotated_output = (gr_complex *)output_items[0];
+ else
+ d_derotated_output = NULL;
+
+ if (VERBOSE)
+ fprintf(stderr,">>> Entering state machine\n");
+
+ switch(d_state) {
+
+ case STATE_SYNC_SEARCH: // Look for flag indicating beginning of pkt
+ if (VERBOSE)
+ fprintf(stderr,"SYNC Search, noutput=%d\n", noutput_items);
+
+ if (sig[0]) { // Found it, set up for header decode
+ enter_have_sync();
+ }
+ break;
+
+ case STATE_HAVE_SYNC:
+ // only demod after getting the preamble signal; otherwise, the
+ // equalizer taps will screw with the PLL performance
+ bytes = demapper(&in[0], d_bytes_out);
+
+ if (VERBOSE) {
+ if(sig[0])
+ printf("ERROR -- Found SYNC in HAVE_SYNC\n");
+ fprintf(stderr,"Header Search bitcnt=%d, header=0x%08x\n",
+ d_headerbytelen_cnt, d_header);
+ }
+
+ j = 0;
+ while(j < bytes) {
+ d_header = (d_header << 8) | (d_bytes_out[j] & 0xFF);
+ j++;
+
+ if (++d_headerbytelen_cnt == HEADERBYTELEN) {
+
+ if (VERBOSE)
+ fprintf(stderr, "got header: 0x%08x\n", d_header);
+
+ // we have a full header, check to see if it has been received properly
+ if (header_ok()){
+ enter_have_header();
+
+ if (VERBOSE)
+ printf("\nPacket Length: %d\n", d_packetlen);
+
+ while((j < bytes) && (d_packetlen_cnt < d_packetlen)) {
+ d_packet[d_packetlen_cnt++] = d_bytes_out[j++];
+ }
+
+ if(d_packetlen_cnt == d_packetlen) {
+ gr_message_sptr msg =
+ gr_make_message(0, d_packet_whitener_offset, 0, d_packetlen);
+ memcpy(msg->msg(), d_packet, d_packetlen_cnt);
+ d_target_queue->insert_tail(msg); // send it
+ msg.reset(); // free it up
+
+ enter_search();
+ }
+ }
+ else {
+ enter_search(); // bad header
+ }
+ }
+ }
+ break;
+
+ case STATE_HAVE_HEADER:
+ bytes = demapper(&in[0], d_bytes_out);
+
+ if (VERBOSE) {
+ if(sig[0])
+ printf("ERROR -- Found SYNC in HAVE_HEADER at %d, length of %d\n", d_packetlen_cnt, d_packetlen);
+ fprintf(stderr,"Packet Build\n");
+ }
+
+ j = 0;
+ while(j < bytes) {
+ d_packet[d_packetlen_cnt++] = d_bytes_out[j++];
+
+ if (d_packetlen_cnt == d_packetlen){ // packet is filled
+ // build a message
+ // NOTE: passing header field as arg1 is not scalable
+ gr_message_sptr msg =
+ gr_make_message(0, d_packet_whitener_offset, 0, d_packetlen_cnt);
+ memcpy(msg->msg(), d_packet, d_packetlen_cnt);
+
+ d_target_queue->insert_tail(msg); // send it
+ msg.reset(); // free it up
+
+ enter_search();
+ break;
+ }
+ }
+ break;
+
+ default:
+ assert(0);
+
+ } // switch
+
+ return 1;
+}
diff --git a/gnuradio-core/src/lib/general/gr_ofdm_frame_sink2.h b/gnuradio-core/src/lib/general/gr_ofdm_frame_sink2.h
new file mode 100644
index 000000000..647ce7958
--- /dev/null
+++ b/gnuradio-core/src/lib/general/gr_ofdm_frame_sink2.h
@@ -0,0 +1,120 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 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.
+ */
+
+#ifndef INCLUDED_GR_OFDM_FRAME_SINK2_H
+#define INCLUDED_GR_OFDM_FRAME_SINK2_H
+
+#include <gr_sync_block.h>
+#include <gr_msg_queue.h>
+#include <gr_constellation.h>
+
+class gr_ofdm_frame_sink2;
+typedef boost::shared_ptr<gr_ofdm_frame_sink2> gr_ofdm_frame_sink2_sptr;
+
+gr_ofdm_frame_sink2_sptr
+gr_make_ofdm_frame_sink2 (gr_constellation_sptr constell,
+ gr_msg_queue_sptr target_queue, unsigned int occupied_tones,
+ float phase_gain=0.25, float freq_gain=0.25*0.25/4.0);
+
+/*!
+ * \brief Takes an OFDM symbol in, demaps it into bits of 0's and 1's, packs
+ * them into packets, and sends to to a message queue sink.
+ * \ingroup sink_blk
+ * \ingroup ofdm_blk
+ *
+ * NOTE: The mod input parameter simply chooses a pre-defined demapper/slicer. Eventually,
+ * we want to be able to pass in a reference to an object to do the demapping and slicing
+ * for a given modulation type.
+ */
+class gr_ofdm_frame_sink2 : public gr_sync_block
+{
+ friend gr_ofdm_frame_sink2_sptr
+ gr_make_ofdm_frame_sink2 (gr_constellation_sptr constell,
+ gr_msg_queue_sptr target_queue, unsigned int occupied_tones,
+ float phase_gain, float freq_gain);
+
+ private:
+ enum state_t {STATE_SYNC_SEARCH, STATE_HAVE_SYNC, STATE_HAVE_HEADER};
+
+ static const int MAX_PKT_LEN = 4096;
+ static const int HEADERBYTELEN = 4;
+
+ gr_msg_queue_sptr d_target_queue; // where to send the packet when received
+ state_t d_state;
+ unsigned int d_header; // header bits
+ int d_headerbytelen_cnt; // how many so far
+
+ unsigned char *d_bytes_out; // hold the current bytes produced by the demapper
+
+ unsigned int d_occupied_carriers;
+ unsigned int d_byte_offset;
+ unsigned int d_partial_byte;
+
+ unsigned char d_packet[MAX_PKT_LEN]; // assembled payload
+ int d_packetlen; // length of packet
+ int d_packet_whitener_offset; // offset into whitener string to use
+ int d_packetlen_cnt; // how many so far
+
+ gr_complex * d_derotated_output; // Pointer to output stream to send deroated symbols out
+
+ gr_constellation_sptr d_constell;
+ std::vector<gr_complex> d_dfe;
+ unsigned int d_nbits;
+
+ unsigned char d_resid;
+ unsigned int d_nresid;
+ float d_phase;
+ float d_freq;
+ float d_phase_gain;
+ float d_freq_gain;
+ float d_eq_gain;
+
+ std::vector<int> d_subcarrier_map;
+
+ protected:
+ gr_ofdm_frame_sink2(gr_constellation_sptr constell,
+ gr_msg_queue_sptr target_queue, unsigned int occupied_tones,
+ float phase_gain, float freq_gain);
+
+ void enter_search();
+ void enter_have_sync();
+ void enter_have_header();
+
+ bool header_ok()
+ {
+ // confirm that two copies of header info are identical
+ return ((d_header >> 16) ^ (d_header & 0xffff)) == 0;
+ }
+
+ unsigned char slicer(const gr_complex x);
+ unsigned int demapper(const gr_complex *in,
+ unsigned char *out);
+
+ public:
+ ~gr_ofdm_frame_sink2();
+
+ int work(int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items);
+};
+
+#endif /* INCLUDED_GR_OFDM_FRAME_SINK2_H */
diff --git a/gnuradio-core/src/lib/general/gr_ofdm_frame_sink2.i b/gnuradio-core/src/lib/general/gr_ofdm_frame_sink2.i
new file mode 100644
index 000000000..24d4b32bd
--- /dev/null
+++ b/gnuradio-core/src/lib/general/gr_ofdm_frame_sink2.i
@@ -0,0 +1,39 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 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.
+ */
+
+GR_SWIG_BLOCK_MAGIC(gr,ofdm_frame_sink2);
+
+gr_ofdm_frame_sink2_sptr
+gr_make_ofdm_frame_sink2(gr_constellation_sptr constell,
+ gr_msg_queue_sptr target_queue, unsigned int occupied_tones,
+ float phase_gain=0.25, float freq_gain=0.25*0.25/4);
+
+class gr_ofdm_frame_sink2 : public gr_sync_block
+{
+ protected:
+ gr_ofdm_frame_sink2(gr_constellation_sptr constell,
+ gr_msg_queue_sptr target_queue, unsigned int occupied_tones,
+ float phase_gain, float freq_gain);
+
+ public:
+ ~gr_ofdm_frame_sink2();
+};
diff --git a/gnuradio-core/src/lib/swig/Makefile.am b/gnuradio-core/src/lib/swig/Makefile.am
index f8e7640ae..d304a2123 100644
--- a/gnuradio-core/src/lib/swig/Makefile.am
+++ b/gnuradio-core/src/lib/swig/Makefile.am
@@ -45,7 +45,7 @@ TOP_SWIG_IFILES = \
swiginclude_HEADERS = \
gnuradio.i \
gr_swig_block_magic.i \
- gr_shared_ptr.i
+ gr_shared_ptr.i
# SWIG headers that get installed in ${prefix}/include/gnuradio/swig/...
nobase_swiginclude_HEADERS = \
diff --git a/gnuradio-core/src/lib/swig/Makefile.swig.gen b/gnuradio-core/src/lib/swig/Makefile.swig.gen
index 0c3247565..cede68817 100644
--- a/gnuradio-core/src/lib/swig/Makefile.swig.gen
+++ b/gnuradio-core/src/lib/swig/Makefile.swig.gen
@@ -105,7 +105,7 @@ _gnuradio_core_runtime_la_CXXFLAGS = \
$(gnuradio_core_runtime_la_swig_cxxflags)
python/gnuradio_core_runtime.cc: gnuradio_core_runtime.py
-gnuradio_core_runtime.py: gnuradio_core_runtime.i
+gnuradio_core_runtime.py: gnuradio_core_runtime.i
# Include the python dependencies for this file
-include python/gnuradio_core_runtime.d
@@ -250,7 +250,7 @@ _gnuradio_core_general_la_CXXFLAGS = \
$(gnuradio_core_general_la_swig_cxxflags)
python/gnuradio_core_general.cc: gnuradio_core_general.py
-gnuradio_core_general.py: gnuradio_core_general.i
+gnuradio_core_general.py: gnuradio_core_general.i
# Include the python dependencies for this file
-include python/gnuradio_core_general.d
@@ -395,7 +395,7 @@ _gnuradio_core_gengen_la_CXXFLAGS = \
$(gnuradio_core_gengen_la_swig_cxxflags)
python/gnuradio_core_gengen.cc: gnuradio_core_gengen.py
-gnuradio_core_gengen.py: gnuradio_core_gengen.i
+gnuradio_core_gengen.py: gnuradio_core_gengen.i
# Include the python dependencies for this file
-include python/gnuradio_core_gengen.d
@@ -540,7 +540,7 @@ _gnuradio_core_filter_la_CXXFLAGS = \
$(gnuradio_core_filter_la_swig_cxxflags)
python/gnuradio_core_filter.cc: gnuradio_core_filter.py
-gnuradio_core_filter.py: gnuradio_core_filter.i
+gnuradio_core_filter.py: gnuradio_core_filter.i
# Include the python dependencies for this file
-include python/gnuradio_core_filter.d
@@ -685,7 +685,7 @@ _gnuradio_core_io_la_CXXFLAGS = \
$(gnuradio_core_io_la_swig_cxxflags)
python/gnuradio_core_io.cc: gnuradio_core_io.py
-gnuradio_core_io.py: gnuradio_core_io.i
+gnuradio_core_io.py: gnuradio_core_io.i
# Include the python dependencies for this file
-include python/gnuradio_core_io.d
@@ -830,7 +830,7 @@ _gnuradio_core_hier_la_CXXFLAGS = \
$(gnuradio_core_hier_la_swig_cxxflags)
python/gnuradio_core_hier.cc: gnuradio_core_hier.py
-gnuradio_core_hier.py: gnuradio_core_hier.i
+gnuradio_core_hier.py: gnuradio_core_hier.i
# Include the python dependencies for this file
-include python/gnuradio_core_hier.d
diff --git a/gnuradio-core/src/lib/swig/gnuradio.i b/gnuradio-core/src/lib/swig/gnuradio.i
index 1856d5007..ba8357c40 100644
--- a/gnuradio-core/src/lib/swig/gnuradio.i
+++ b/gnuradio-core/src/lib/swig/gnuradio.i
@@ -35,7 +35,7 @@
#include <complex>
%}
-%feature("autodoc","1");
+// %feature("autodoc","1");
#ifdef SWIGGUILE
// Export constants and enums as scheme variables, not functions.
diff --git a/gnuradio-core/src/python/gnuradio/Makefile.am b/gnuradio-core/src/python/gnuradio/Makefile.am
index a3f3518de..55a2ba1df 100644
--- a/gnuradio-core/src/python/gnuradio/Makefile.am
+++ b/gnuradio-core/src/python/gnuradio/Makefile.am
@@ -22,7 +22,7 @@
include $(top_srcdir)/Makefile.common
if PYTHON
-SUBDIRS = gr gru gruimpl blks2 blks2impl vocoder
+SUBDIRS = gr gru gruimpl blks2 blks2impl vocoder utils
grpython_PYTHON = \
__init__.py \
diff --git a/gnuradio-core/src/python/gnuradio/blks2impl/Makefile.am b/gnuradio-core/src/python/gnuradio/blks2impl/Makefile.am
index 7b24fb69d..6a2e7d5f7 100644
--- a/gnuradio-core/src/python/gnuradio/blks2impl/Makefile.am
+++ b/gnuradio-core/src/python/gnuradio/blks2impl/Makefile.am
@@ -29,6 +29,7 @@ grblkspythondir = $(grpythondir)/blks2impl
grblkspython_PYTHON = \
__init__.py \
am_demod.py \
+ bpsk.py \
channel_model.py \
dbpsk.py \
dbpsk2.py \
@@ -38,6 +39,7 @@ grblkspython_PYTHON = \
filterbank.py \
fm_demod.py \
fm_emph.py \
+ generic_mod_demod.py \
generic_usrp.py \
gmsk.py \
cpm.py \
@@ -56,11 +58,9 @@ grblkspython_PYTHON = \
pfb_interpolator.py \
pkt.py \
psk.py \
+ psk2.py \
qam.py \
- qam8.py \
- qam16.py \
- qam64.py \
- qam256.py \
+ qpsk.py \
rational_resampler.py \
standard_squelch.py \
stream_to_vector_decimator.py \
diff --git a/gnuradio-core/src/python/gnuradio/blks2impl/bpsk.py b/gnuradio-core/src/python/gnuradio/blks2impl/bpsk.py
new file mode 100644
index 000000000..222178abb
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/blks2impl/bpsk.py
@@ -0,0 +1,98 @@
+#
+# 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 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.
+#
+
+"""
+BPSK modulation and demodulation.
+"""
+
+from math import pi, log
+from cmath import exp
+
+from gnuradio import gr, modulation_utils2
+from gnuradio.blks2impl.generic_mod_demod import generic_mod, generic_demod
+
+# Default number of points in constellation.
+_def_constellation_points = 2
+# Whether differential coding is used.
+_def_differential = True
+
+# /////////////////////////////////////////////////////////////////////////////
+# BPSK constellation
+# /////////////////////////////////////////////////////////////////////////////
+
+def bpsk_constellation(m=_def_constellation_points):
+ if m != _def_constellation_points:
+ raise ValueError("BPSK can only have 2 constellation points.")
+ return gr.constellation_bpsk()
+
+# /////////////////////////////////////////////////////////////////////////////
+# BPSK modulator
+# /////////////////////////////////////////////////////////////////////////////
+
+class bpsk_mod(generic_mod):
+
+ def __init__(self, constellation_points=_def_constellation_points,
+ *args, **kwargs):
+
+ """
+ Hierarchical block for RRC-filtered BPSK modulation.
+
+ The input is a byte stream (unsigned char) and the
+ output is the complex modulated signal at baseband.
+
+ See generic_mod block for list of parameters.
+ """
+
+ constellation = gr.constellation_bpsk()
+ if constellation_points != 2:
+ raise ValueError('Number of constellation points must be 2 for BPSK.')
+ super(bpsk_mod, self).__init__(constellation, *args, **kwargs)
+
+# /////////////////////////////////////////////////////////////////////////////
+# BPSK demodulator
+#
+# /////////////////////////////////////////////////////////////////////////////
+
+class bpsk_demod(generic_demod):
+
+ def __init__(self, constellation_points=_def_constellation_points,
+ *args, **kwargs):
+
+ """
+ Hierarchical block for RRC-filtered BPSK modulation.
+
+ The input is a byte stream (unsigned char) and the
+ output is the complex modulated signal at baseband.
+
+ See generic_demod block for list of parameters.
+ """
+
+ constellation = gr.constellation_bpsk()
+ if constellation_points != 2:
+ raise ValueError('Number of constellation points must be 2 for BPSK.')
+ super(bpsk_demod, self).__init__(constellation, *args, **kwargs)
+
+#
+# Add these to the mod/demod registry
+#
+modulation_utils2.add_type_1_mod('bpsk', bpsk_mod)
+modulation_utils2.add_type_1_demod('bpsk', bpsk_demod)
+modulation_utils2.add_type_1_constellation('bpsk', bpsk_constellation)
diff --git a/gnuradio-core/src/python/gnuradio/blks2impl/generic_mod_demod.py b/gnuradio-core/src/python/gnuradio/blks2impl/generic_mod_demod.py
new file mode 100644
index 000000000..b88ff72a0
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/blks2impl/generic_mod_demod.py
@@ -0,0 +1,395 @@
+#
+# Copyright 2005,2006,2007,2009 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
+
+"""
+Generic modulation and demodulation.
+"""
+
+from gnuradio import gr
+from gnuradio.modulation_utils2 import extract_kwargs_from_options_for_class
+from gnuradio.utils import mod_codes
+
+# default values (used in __init__ and add_options)
+_def_samples_per_symbol = 2
+_def_excess_bw = 0.35
+_def_verbose = False
+_def_log = False
+
+# Frequency correction
+_def_freq_alpha = 0.010
+# Symbol timing recovery
+_def_timing_alpha = 0.100
+_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
+# Whether differential coding is used.
+_def_differential = True
+
+def add_common_options(parser):
+ """
+ Sets options common to both modulator and demodulator.
+ """
+ parser.add_option("-p", "--constellation-points", type="int", default=_def_constellation_points,
+ help="set the number of constellation points (must be a power of 2 (power of 4 for QAM) [default=%default]")
+ parser.add_option("", "--differential", action="store_true", dest="differential", default=True,
+ help="use differential encoding [default=%default]")
+ parser.add_option("", "--not-differential", action="store_false", dest="differential",
+ help="do not use differential encoding [default=%default]")
+ parser.add_option("", "--mod-code", type="choice", choices=mod_codes.codes,
+ default=mod_codes.NO_CODE,
+ help="Select modulation code from: %s [default=%%default]"
+ % (', '.join(mod_codes.codes),))
+ parser.add_option("", "--excess-bw", type="float", default=_def_excess_bw,
+ help="set RRC excess bandwith factor [default=%default]")
+
+
+# /////////////////////////////////////////////////////////////////////////////
+# Generic modulator
+# /////////////////////////////////////////////////////////////////////////////
+
+class generic_mod(gr.hier_block2):
+
+ def __init__(self, constellation,
+ differential=_def_differential,
+ samples_per_symbol=_def_samples_per_symbol,
+ excess_bw=_def_excess_bw,
+ verbose=_def_verbose,
+ log=_def_log):
+ """
+ Hierarchical block for RRC-filtered differential generic modulation.
+
+ The input is a byte stream (unsigned char) and the
+ output is the complex modulated signal at baseband.
+
+ @param constellation: determines the modulation type
+ @type constellation: gnuradio.gr.gr_constellation
+ @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
+ """
+
+ gr.hier_block2.__init__(self, "generic_mod",
+ gr.io_signature(1, 1, gr.sizeof_char), # Input signature
+ gr.io_signature(1, 1, gr.sizeof_gr_complex)) # Output signature
+
+ self._constellation = constellation.base()
+ self._samples_per_symbol = samples_per_symbol
+ self._excess_bw = excess_bw
+ self._differential = differential
+
+ if not isinstance(self._samples_per_symbol, int) or self._samples_per_symbol < 2:
+ raise TypeError, ("sbp must be an integer >= 2, is %d" % self._samples_per_symbol)
+
+ ntaps = 11 * self._samples_per_symbol
+
+ arity = pow(2,self.bits_per_symbol())
+
+ # turn bytes into k-bit vectors
+ self.bytes2chunks = \
+ gr.packed_to_unpacked_bb(self.bits_per_symbol(), gr.GR_MSB_FIRST)
+
+ if self._constellation.apply_pre_diff_code():
+ self.symbol_mapper = gr.map_bb(self._constellation.pre_diff_code())
+
+ if differential:
+ self.diffenc = gr.diff_encoder_bb(arity)
+
+ self.chunks2symbols = gr.chunks_to_symbols_bc(self._constellation.points())
+
+ # pulse shaping filter
+ self.rrc_taps = gr.firdes.root_raised_cosine(
+ self._samples_per_symbol, # gain (samples_per_symbol since we're
+ # interpolating by samples_per_symbol)
+ self._samples_per_symbol, # sampling rate
+ 1.0, # symbol rate
+ self._excess_bw, # excess bandwidth (roll-off factor)
+ ntaps)
+ self.rrc_filter = gr.interp_fir_filter_ccf(self._samples_per_symbol,
+ self.rrc_taps)
+
+ # Connect
+ blocks = [self, self.bytes2chunks]
+ if self._constellation.apply_pre_diff_code():
+ blocks.append(self.symbol_mapper)
+ if differential:
+ blocks.append(self.diffenc)
+ blocks += [self.chunks2symbols, self.rrc_filter, self]
+ self.connect(*blocks)
+
+ if verbose:
+ self._print_verbage()
+
+ if log:
+ self._setup_logging()
+
+
+ def samples_per_symbol(self):
+ return self._samples_per_symbol
+
+ def bits_per_symbol(self): # static method that's also callable on an instance
+ return self._constellation.bits_per_symbol()
+
+ def add_options(parser):
+ """
+ Adds generic modulation options to the standard parser
+ """
+ add_common_options(parser)
+ add_options=staticmethod(add_options)
+
+ def extract_kwargs_from_options(cls, options):
+ """
+ Given command line options, create dictionary suitable for passing to __init__
+ """
+ return extract_kwargs_from_options_for_class(cls, options)
+ extract_kwargs_from_options=classmethod(extract_kwargs_from_options)
+
+
+ def _print_verbage(self):
+ print "\nModulator:"
+ print "bits per symbol: %d" % self.bits_per_symbol()
+ print "RRC roll-off factor: %.2f" % self._excess_bw
+
+ def _setup_logging(self):
+ print "Modulation logging turned on."
+ self.connect(self.bytes2chunks,
+ gr.file_sink(gr.sizeof_char, "tx_bytes2chunks.dat"))
+ if self._constellation.apply_pre_diff_code():
+ self.connect(self.symbol_mapper,
+ gr.file_sink(gr.sizeof_char, "tx_symbol_mapper.dat"))
+ if self._differential:
+ self.connect(self.diffenc,
+ gr.file_sink(gr.sizeof_char, "tx_diffenc.dat"))
+ self.connect(self.chunks2symbols,
+ gr.file_sink(gr.sizeof_gr_complex, "tx_chunks2symbols.dat"))
+ self.connect(self.rrc_filter,
+ gr.file_sink(gr.sizeof_gr_complex, "tx_rrc_filter.dat"))
+
+
+# /////////////////////////////////////////////////////////////////////////////
+# Generic demodulator
+#
+# Differentially coherent detection of differentially encoded generically
+# modulated signal.
+# /////////////////////////////////////////////////////////////////////////////
+
+class generic_demod(gr.hier_block2):
+
+ def __init__(self, constellation,
+ samples_per_symbol=_def_samples_per_symbol,
+ differential=_def_differential,
+ excess_bw=_def_excess_bw,
+ freq_alpha=_def_freq_alpha,
+ timing_alpha=_def_timing_alpha,
+ timing_max_dev=_def_timing_max_dev,
+ phase_alpha=_def_phase_alpha,
+ verbose=_def_verbose,
+ log=_def_log):
+ """
+ Hierarchical block for RRC-filtered differential generic demodulation.
+
+ The input is the complex modulated signal at baseband.
+ The output is a stream of bits packed 1 bit per byte (LSB)
+
+ @param constellation: determines the modulation type
+ @type constellation: gnuradio.gr.gr_constellation
+ @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
+ """
+
+ gr.hier_block2.__init__(self, "generic_demod",
+ gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature
+ gr.io_signature(1, 1, gr.sizeof_char)) # Output signature
+
+ self._constellation = constellation.base()
+ self._samples_per_symbol = samples_per_symbol
+ self._excess_bw = excess_bw
+ self._phase_alpha = phase_alpha
+ self._freq_alpha = freq_alpha
+ self._freq_beta = 0.10*self._freq_alpha
+ self._timing_alpha = timing_alpha
+ self._timing_beta = _def_timing_beta
+ self._timing_max_dev=timing_max_dev
+ self._differential = differential
+
+ if not isinstance(self._samples_per_symbol, int) or self._samples_per_symbol < 2:
+ raise TypeError, ("sbp must be an integer >= 2, is %d" % self._samples_per_symbol)
+
+ arity = pow(2,self.bits_per_symbol())
+
+ # Automatic gain control
+ self.agc = gr.agc2_cc(0.6e-1, 1e-3, 1, 1, 100)
+
+ # Frequency correction
+ self.freq_recov = gr.fll_band_edge_cc(self._samples_per_symbol, self._excess_bw,
+ 11*int(self._samples_per_symbol),
+ self._freq_alpha, self._freq_beta)
+
+ # symbol timing recovery with RRC data filter
+ nfilts = 32
+ ntaps = 11 * int(self._samples_per_symbol*nfilts)
+ taps = gr.firdes.root_raised_cosine(nfilts, nfilts,
+ 1.0/float(self._samples_per_symbol),
+ self._excess_bw, ntaps)
+ self.time_recov = gr.pfb_clock_sync_ccf(self._samples_per_symbol,
+ self._timing_alpha,
+ taps, nfilts, nfilts/2, self._timing_max_dev)
+ self.time_recov.set_beta(self._timing_beta)
+
+ #self._phase_beta = 0.25 * self._phase_alpha * self._phase_alpha
+ self._phase_beta = 0.25 * self._phase_alpha * self._phase_alpha
+ fmin = -0.25
+ fmax = 0.25
+
+ self.receiver = gr.constellation_receiver_cb(
+ self._constellation,
+ self._phase_alpha, self._phase_beta,
+ fmin, fmax)
+
+ # Do differential decoding based on phase change of symbols
+ if differential:
+ self.diffdec = gr.diff_decoder_bb(arity)
+
+ if self._constellation.apply_pre_diff_code():
+ self.symbol_mapper = gr.map_bb(
+ mod_codes.invert_code(self._constellation.pre_diff_code()))
+
+ # unpack the k bit vector into a stream of bits
+ self.unpack = gr.unpack_k_bits_bb(self.bits_per_symbol())
+
+ if verbose:
+ self._print_verbage()
+
+ if log:
+ self._setup_logging()
+
+ # Connect and Initialize base class
+ blocks = [self, self.agc, self.freq_recov, self.time_recov, self.receiver]
+ if differential:
+ blocks.append(self.diffdec)
+ if self._constellation.apply_pre_diff_code():
+ blocks.append(self.symbol_mapper)
+ blocks += [self.unpack, self]
+ self.connect(*blocks)
+
+ def samples_per_symbol(self):
+ return self._samples_per_symbol
+
+ def bits_per_symbol(self): # staticmethod that's also callable on an instance
+ return self._constellation.bits_per_symbol()
+
+ def _print_verbage(self):
+ print "\nDemodulator:"
+ print "bits per symbol: %d" % self.bits_per_symbol()
+ print "RRC roll-off factor: %.2f" % self._excess_bw
+ print "FLL gain: %.2e" % self._freq_alpha
+ print "Timing alpha gain: %.2e" % self._timing_alpha
+ print "Timing beta gain: %.2e" % self._timing_beta
+ print "Timing max dev: %.2f" % self._timing_max_dev
+ print "Phase track alpha: %.2e" % self._phase_alpha
+ print "Phase track beta: %.2e" % self._phase_beta
+
+ def _setup_logging(self):
+ print "Modulation logging turned on."
+ self.connect(self.agc,
+ gr.file_sink(gr.sizeof_gr_complex, "rx_agc.dat"))
+ self.connect((self.freq_recov, 0),
+ gr.file_sink(gr.sizeof_gr_complex, "rx_freq_recov.dat"))
+ self.connect((self.freq_recov, 1),
+ gr.file_sink(gr.sizeof_float, "rx_freq_recov_freq.dat"))
+ self.connect((self.freq_recov, 2),
+ gr.file_sink(gr.sizeof_float, "rx_freq_recov_phase.dat"))
+ self.connect((self.freq_recov, 3),
+ gr.file_sink(gr.sizeof_gr_complex, "rx_freq_recov_error.dat"))
+ self.connect((self.time_recov, 0),
+ gr.file_sink(gr.sizeof_gr_complex, "rx_time_recov.dat"))
+ self.connect((self.time_recov, 1),
+ gr.file_sink(gr.sizeof_float, "rx_time_recov_error.dat"))
+ self.connect((self.time_recov, 2),
+ gr.file_sink(gr.sizeof_float, "rx_time_recov_rate.dat"))
+ self.connect((self.time_recov, 3),
+ gr.file_sink(gr.sizeof_float, "rx_time_recov_phase.dat"))
+ self.connect((self.receiver, 0),
+ gr.file_sink(gr.sizeof_char, "rx_receiver.dat"))
+ self.connect((self.receiver, 1),
+ gr.file_sink(gr.sizeof_float, "rx_receiver_error.dat"))
+ self.connect((self.receiver, 2),
+ gr.file_sink(gr.sizeof_float, "rx_receiver_phase.dat"))
+ self.connect((self.receiver, 3),
+ gr.file_sink(gr.sizeof_float, "rx_receiver_freq.dat"))
+ if self._differential:
+ self.connect(self.diffdec,
+ gr.file_sink(gr.sizeof_char, "rx_diffdec.dat"))
+ if self._constellation.apply_pre_diff_code():
+ self.connect(self.symbol_mapper,
+ gr.file_sink(gr.sizeof_char, "rx_symbol_mapper.dat"))
+ self.connect(self.unpack,
+ gr.file_sink(gr.sizeof_char, "rx_unpack.dat"))
+
+ def add_options(parser):
+ """
+ Adds generic demodulation options to the standard parser
+ """
+ # Add options shared with modulator.
+ add_common_options(parser)
+ # Add options specific to demodulator.
+ parser.add_option("", "--freq-alpha", type="float", default=_def_freq_alpha,
+ help="set frequency lock loop alpha gain value [default=%default]")
+ parser.add_option("", "--phase-alpha", type="float", default=_def_phase_alpha,
+ help="set phase tracking loop alpha value [default=%default]")
+ parser.add_option("", "--timing-alpha", type="float", default=_def_timing_alpha,
+ help="set timing symbol sync loop gain alpha value [default=%default]")
+ parser.add_option("", "--timing-beta", type="float", default=_def_timing_beta,
+ help="set timing symbol sync loop gain beta value [default=%default]")
+ parser.add_option("", "--timing-max-dev", type="float", default=_def_timing_max_dev,
+ help="set timing symbol sync loop maximum deviation [default=%default]")
+ add_options=staticmethod(add_options)
+
+ def extract_kwargs_from_options(cls, options):
+ """
+ Given command line options, create dictionary suitable for passing to __init__
+ """
+ return extract_kwargs_from_options_for_class(cls, options)
+ extract_kwargs_from_options=classmethod(extract_kwargs_from_options)
+
diff --git a/gnuradio-core/src/python/gnuradio/blks2impl/ofdm.py b/gnuradio-core/src/python/gnuradio/blks2impl/ofdm.py
index 2663f7cf8..3b1cd12ac 100644
--- a/gnuradio-core/src/python/gnuradio/blks2impl/ofdm.py
+++ b/gnuradio-core/src/python/gnuradio/blks2impl/ofdm.py
@@ -21,12 +21,26 @@
#
import math
-from gnuradio import gr, ofdm_packet_utils
+from gnuradio import gr, ofdm_packet_utils, modulation_utils2
import gnuradio.gr.gr_threading as _threading
import psk, qam
from gnuradio.blks2impl.ofdm_receiver import ofdm_receiver
+def _add_common_options(normal, expert):
+ """
+ Adds OFDM-specific options to the Options Parser that are common
+ both to the modulator and demodulator.
+ """
+ mods_list = ", ".join(modulation_utils2.type_1_constellations().keys())
+ normal.add_option("-m", "--modulation", type="string", default="psk",
+ help="set modulation type (" + mods_list + ") [default=%default]")
+ expert.add_option("", "--fft-length", type="intx", default=512,
+ help="set the number of FFT bins [default=%default]")
+ expert.add_option("", "--occupied-tones", type="intx", default=200,
+ help="set the number of occupied FFT bins [default=%default]")
+ expert.add_option("", "--cp-length", type="intx", default=128,
+ help="set the number of bits in the cyclic prefix [default=%default]")
# /////////////////////////////////////////////////////////////////////////////
# mod/demod with packets as i/o
@@ -61,6 +75,8 @@ class ofdm_mod(gr.hier_block2):
self._fft_length = options.fft_length
self._occupied_tones = options.occupied_tones
self._cp_length = options.cp_length
+
+ arity = options.constellation_points
win = [] #[1 for i in range(self._fft_length)]
@@ -82,19 +98,9 @@ class ofdm_mod(gr.hier_block2):
symbol_length = options.fft_length + options.cp_length
- mods = {"bpsk": 2, "qpsk": 4, "8psk": 8, "qam8": 8, "qam16": 16, "qam64": 64, "qam256": 256}
- arity = mods[self._modulation]
-
- rot = 1
- if self._modulation == "qpsk":
- rot = (0.707+0.707j)
-
- if(self._modulation.find("psk") >= 0):
- rotated_const = map(lambda pt: pt * rot, psk.gray_constellation[arity])
- elif(self._modulation.find("qam") >= 0):
- rotated_const = map(lambda pt: pt * rot, qam.constellation[arity])
- #print rotated_const
- self._pkt_input = gr.ofdm_mapper_bcv(rotated_const, msgq_limit,
+ const = modulation_utils2.type_1_constellations()[self._modulation](arity).points()
+
+ self._pkt_input = gr.ofdm_mapper_bcv(const, msgq_limit,
options.occupied_tones, options.fft_length)
self.preambles = gr.ofdm_insert_preamble(self._fft_length, padded_preambles)
@@ -140,14 +146,10 @@ class ofdm_mod(gr.hier_block2):
"""
Adds OFDM-specific options to the Options Parser
"""
- normal.add_option("-m", "--modulation", type="string", default="bpsk",
- help="set modulation type (bpsk, qpsk, 8psk, qam{16,64}) [default=%default]")
- expert.add_option("", "--fft-length", type="intx", default=512,
- help="set the number of FFT bins [default=%default]")
- expert.add_option("", "--occupied-tones", type="intx", default=200,
- help="set the number of occupied FFT bins [default=%default]")
- expert.add_option("", "--cp-length", type="intx", default=128,
- help="set the number of bits in the cyclic prefix [default=%default]")
+ _add_common_options(normal, expert)
+ for mod in modulation_utils2.type_1_mods().values():
+ mod.add_options(expert)
+
# Make a static method to call before instantiation
add_options = staticmethod(add_options)
@@ -196,6 +198,9 @@ class ofdm_demod(gr.hier_block2):
self._cp_length = options.cp_length
self._snr = options.snr
+ arity = options.constellation_points
+ print("con points is %s" % options.constellation_points)
+
# Use freq domain to get doubled-up known symbol for correlation in time domain
zeros_on_left = int(math.ceil((self._fft_length - self._occupied_tones)/2.0))
ksfreq = known_symbols_4512_3[0:self._occupied_tones]
@@ -211,22 +216,11 @@ class ofdm_demod(gr.hier_block2):
self._occupied_tones, self._snr, preambles,
options.log)
- mods = {"bpsk": 2, "qpsk": 4, "8psk": 8, "qam8": 8, "qam16": 16, "qam64": 64, "qam256": 256}
- arity = mods[self._modulation]
-
- rot = 1
- if self._modulation == "qpsk":
- rot = (0.707+0.707j)
-
- if(self._modulation.find("psk") >= 0):
- rotated_const = map(lambda pt: pt * rot, psk.gray_constellation[arity])
- elif(self._modulation.find("qam") >= 0):
- rotated_const = map(lambda pt: pt * rot, qam.constellation[arity])
- #print rotated_const
+ constell = modulation_utils2.type_1_constellations()[self._modulation](arity)
phgain = 0.25
frgain = phgain*phgain / 4.0
- self.ofdm_demod = gr.ofdm_frame_sink(rotated_const, range(arity),
+ self.ofdm_demod = gr.ofdm_frame_sink2(constell.base(),
self._rcvd_pktq,
self._occupied_tones,
phgain, frgain)
@@ -253,14 +247,9 @@ class ofdm_demod(gr.hier_block2):
"""
Adds OFDM-specific options to the Options Parser
"""
- normal.add_option("-m", "--modulation", type="string", default="bpsk",
- help="set modulation type (bpsk or qpsk) [default=%default]")
- expert.add_option("", "--fft-length", type="intx", default=512,
- help="set the number of FFT bins [default=%default]")
- expert.add_option("", "--occupied-tones", type="intx", default=200,
- help="set the number of occupied FFT bins [default=%default]")
- expert.add_option("", "--cp-length", type="intx", default=128,
- help="set the number of bits in the cyclic prefix [default=%default]")
+ _add_common_options(normal, expert)
+ for mod in modulation_utils2.type_1_mods().values():
+ mod.add_options(expert)
# Make a static method to call before instantiation
add_options = staticmethod(add_options)
diff --git a/gnuradio-core/src/python/gnuradio/blks2impl/pkt.py b/gnuradio-core/src/python/gnuradio/blks2impl/pkt.py
index 908437ef2..aa720d1a5 100644
--- a/gnuradio-core/src/python/gnuradio/blks2impl/pkt.py
+++ b/gnuradio-core/src/python/gnuradio/blks2impl/pkt.py
@@ -34,7 +34,8 @@ class mod_pkts(gr.hier_block2):
Send packets by calling send_pkt
"""
- def __init__(self, modulator, access_code=None, msgq_limit=2, pad_for_usrp=True, use_whitener_offset=False):
+ def __init__(self, modulator, access_code=None, msgq_limit=2, pad_for_usrp=True, use_whitener_offset=False,
+ modulate=True):
"""
Hierarchical block for sending packets
@@ -49,13 +50,18 @@ class mod_pkts(gr.hier_block2):
@type msgq_limit: int
@param pad_for_usrp: If true, packets are padded such that they end up a multiple of 128 samples
@param use_whitener_offset: If true, start of whitener XOR string is incremented each packet
+ @param modulate: If false, no modulation will be performed.
See gmsk_mod for remaining parameters
"""
+ if modulate:
+ output_size = gr.sizeof_gr_complex
+ else:
+ output_size = gr.sizeof_char
gr.hier_block2.__init__(self, "mod_pkts",
gr.io_signature(0, 0, 0), # Input signature
- gr.io_signature(1, 1, gr.sizeof_gr_complex)) # Output signature
+ gr.io_signature(1, 1, output_size)) # Output signature
self._modulator = modulator
self._pad_for_usrp = pad_for_usrp
@@ -70,7 +76,10 @@ class mod_pkts(gr.hier_block2):
# accepts messages from the outside world
self._pkt_input = gr.message_source(gr.sizeof_char, msgq_limit)
- self.connect(self._pkt_input, self._modulator, self)
+ if modulate:
+ self.connect(self._pkt_input, self._modulator, self)
+ else:
+ self.connect(self._pkt_input, self)
def send_pkt(self, payload='', eof=False):
"""
@@ -106,13 +115,15 @@ class demod_pkts(gr.hier_block2):
app via the callback.
"""
- def __init__(self, demodulator, access_code=None, callback=None, threshold=-1):
+ def __init__(self, demodulator, access_code=None, callback=None, threshold=-1, demodulate=True):
"""
Hierarchical block for demodulating and deframing packets.
The input is the complex modulated signal at baseband.
Demodulated packets are sent to the handler.
+ If demodulator is None it is assumed the input is already demodulated.
+
@param demodulator: instance of demodulator class (gr_block or hier_block2)
@type demodulator: complex baseband in
@param access_code: AKA sync vector
@@ -123,9 +134,14 @@ class demod_pkts(gr.hier_block2):
@type threshold: int
"""
+ if demodulator is not None:
+ input_size = gr.sizeof_gr_complex
+ else:
+ input_size = gr.sizeof_char
+
gr.hier_block2.__init__(self, "demod_pkts",
- gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature
- gr.io_signature(0, 0, 0)) # Output signature
+ gr.io_signature(1, 1, input_size), # Input signature
+ gr.io_signature(0, 0, 0)) # Output signature
self._demodulator = demodulator
if access_code is None:
@@ -141,9 +157,13 @@ class demod_pkts(gr.hier_block2):
self.correlator = gr.correlate_access_code_bb(access_code, threshold)
self.framer_sink = gr.framer_sink_1(self._rcvd_pktq)
- self.connect(self, self._demodulator, self.correlator, self.framer_sink)
+ if self._demodulator is not None:
+ self.connect(self, self._demodulator, self.correlator, self.framer_sink)
+ else:
+ self.connect(self, self.correlator, self.framer_sink)
- self._watcher = _queue_watcher_thread(self._rcvd_pktq, callback)
+ if callback is not None:
+ self._watcher = _queue_watcher_thread(self._rcvd_pktq, callback)
class _queue_watcher_thread(_threading.Thread):
diff --git a/gnuradio-core/src/python/gnuradio/blks2impl/psk2.py b/gnuradio-core/src/python/gnuradio/blks2impl/psk2.py
new file mode 100644
index 000000000..95f25e75a
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/blks2impl/psk2.py
@@ -0,0 +1,121 @@
+#
+# 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 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.
+#
+
+"""
+PSK modulation and demodulation.
+"""
+
+from math import pi, log
+from cmath import exp
+
+from gnuradio import gr, modulation_utils2
+from gnuradio.blks2impl.generic_mod_demod import generic_mod, generic_demod
+from gnuradio.utils import mod_codes, gray_code
+
+# Default number of points in constellation.
+_def_constellation_points = 4
+# The default encoding (e.g. gray-code, set-partition)
+_def_mod_code = mod_codes.GRAY_CODE
+
+def create_encodings(mod_code, arity):
+ post_diff_code = None
+ if mod_code not in mod_codes.codes:
+ raise ValueError('That modulation code does not exist.')
+ if mod_code == mod_codes.GRAY_CODE:
+ pre_diff_code = gray_code.gray_code(arity)
+ elif mod_code == mod_codes.SET_PARTITION_CODE:
+ pre_diff_code = set_partition_code.set_partition_code(arity)
+ elif mod_code == mod_codes.NO_CODE:
+ pre_diff_code = []
+ else:
+ raise ValueError('That modulation code is not implemented for this constellation.')
+ return (pre_diff_code, post_diff_code)
+
+# /////////////////////////////////////////////////////////////////////////////
+# PSK constellation
+# /////////////////////////////////////////////////////////////////////////////
+
+def psk_constellation(m=_def_constellation_points, mod_code=_def_mod_code):
+ """
+ Creates a PSK constellation object.
+ """
+ k = log(m) / log(2.0)
+ if (k != int(k)):
+ raise StandardError('Number of constellation points must be a power of two.')
+ points = [exp(2*pi*(0+1j)*i/m) for i in range(0,m)]
+ pre_diff_code, post_diff_code = create_encodings(mod_code, m)
+ if post_diff_code is not None:
+ inverse_post_diff_code = mod_codes.invert_code(post_diff_code)
+ points = [points[x] for x in inverse_post_diff_code]
+ constellation = gr.constellation_psk(points, pre_diff_code, m)
+ return constellation
+
+# /////////////////////////////////////////////////////////////////////////////
+# PSK modulator
+# /////////////////////////////////////////////////////////////////////////////
+
+class psk_mod(generic_mod):
+
+ def __init__(self, constellation_points=_def_constellation_points,
+ mod_code=_def_mod_code,
+ *args, **kwargs):
+
+ """
+ Hierarchical block for RRC-filtered PSK modulation.
+
+ The input is a byte stream (unsigned char) and the
+ output is the complex modulated signal at baseband.
+
+ See generic_mod block for list of parameters.
+ """
+
+ constellation = psk_constellation(constellation_points, mod_code)
+ super(psk_mod, self).__init__(constellation, *args, **kwargs)
+
+# /////////////////////////////////////////////////////////////////////////////
+# PSK demodulator
+#
+# /////////////////////////////////////////////////////////////////////////////
+
+class psk_demod(generic_demod):
+
+ def __init__(self, constellation_points=_def_constellation_points,
+ mod_code=_def_mod_code,
+ *args, **kwargs):
+
+ """
+ Hierarchical block for RRC-filtered PSK modulation.
+
+ The input is a byte stream (unsigned char) and the
+ output is the complex modulated signal at baseband.
+
+ See generic_demod block for list of parameters.
+ """
+
+ constellation = psk_constellation(constellation_points, mod_code)
+ super(psk_demod, self).__init__(constellation, *args, **kwargs)
+
+#
+# Add these to the mod/demod registry
+#
+modulation_utils2.add_type_1_mod('psk', psk_mod)
+modulation_utils2.add_type_1_demod('psk', psk_demod)
+modulation_utils2.add_type_1_constellation('psk', psk_constellation)
diff --git a/gnuradio-core/src/python/gnuradio/blks2impl/qam.py b/gnuradio-core/src/python/gnuradio/blks2impl/qam.py
index 22b1e1dab..bdd27e9bb 100644
--- a/gnuradio-core/src/python/gnuradio/blks2impl/qam.py
+++ b/gnuradio-core/src/python/gnuradio/blks2impl/qam.py
@@ -19,95 +19,208 @@
# Boston, MA 02110-1301, USA.
#
-from math import pi, sqrt
-import math
+"""
+QAM modulation and demodulation.
+"""
-# These constellations are generated for Gray coding when symbos [1, ..., m] are used
-# Mapping to Gray coding is therefore unnecessary
+from math import pi, sqrt, log
-def make_constellation(m):
- # number of bits/symbol (log2(M))
- k = int(math.log10(m) / math.log10(2.0))
+from gnuradio import gr, modulation_utils2
+from gnuradio.blks2impl.generic_mod_demod import generic_mod, generic_demod
+from gnuradio.utils.gray_code import gray_code
+from gnuradio.utils import mod_codes
- coeff = 1
+# Default number of points in constellation.
+_def_constellation_points = 16
+# Whether the quadrant bits are coded differentially.
+_def_differential = True
+# Whether gray coding is used. If differential is True then gray
+# coding is used within but not between each quadrant.
+_def_mod_code = mod_codes.NO_CODE
+
+def is_power_of_four(x):
+ v = log(x)/log(4)
+ return int(v) == v
+
+def get_bit(x, n):
+ """ Get the n'th bit of integer x (from little end)."""
+ return (x&(0x01 << n)) >> n
+
+def get_bits(x, n, k):
+ """ Get the k bits of integer x starting at bit n(from little end)."""
+ # Remove the n smallest bits
+ v = x >> n
+ # Remove all bits bigger than n+k-1
+ return v % pow(2, k)
+
+def make_differential_constellation(m, gray_coded):
+ """
+ Create a constellation with m possible symbols where m must be
+ a power of 4.
+
+ Points are laid out in a square grid.
+
+ Bits referring to the quadrant are differentilly encoded,
+ remaining bits are gray coded.
+
+ """
+ sqrtm = pow(m, 0.5)
+ if (not isinstance(m, int) or m < 4 or not is_power_of_four(m)):
+ raise ValueError("m must be a power of 4 integer.")
+ # Each symbol holds k bits.
+ k = int(log(m) / log(2.0))
+ # First create a constellation for one quadrant containing m/4 points.
+ # The quadrant has 'side' points along each side of a quadrant.
+ side = int(sqrtm/2)
+ if gray_coded:
+ # Number rows and columns using gray codes.
+ gcs = gray_code(side)
+ # Get inverse gray codes.
+ i_gcs = dict([(v, key) for key, v in enumerate(gcs)])
+ else:
+ i_gcs = dict([(i, i) for i in range(0, side)])
+ # The distance between points is found.
+ step = 1/(side-0.5)
+
+ gc_to_x = [(i_gcs[gc]+0.5)*step for gc in range(0, side)]
+
+ # Takes the (x, y) location of the point with the quadrant along
+ # with the quadrant number. (x, y) are integers referring to which
+ # point within the quadrant it is.
+ # A complex number representing this location of this point is returned.
+ def get_c(gc_x, gc_y, quad):
+ if quad == 0:
+ return complex(gc_to_x[gc_x], gc_to_x[gc_y])
+ if quad == 1:
+ return complex(-gc_to_x[gc_y], gc_to_x[gc_x])
+ if quad == 2:
+ return complex(-gc_to_x[gc_x], -gc_to_x[gc_y])
+ if quad == 3:
+ return complex(gc_to_x[gc_y], -gc_to_x[gc_x])
+ raise StandardError("Impossible!")
+
+ # First two bits determine quadrant.
+ # Next (k-2)/2 bits determine x position.
+ # Following (k-2)/2 bits determine y position.
+ # How x and y relate to real and imag depends on quadrant (see get_c function).
+ const_map = []
+ for i in range(m):
+ y = get_bits(i, 0, (k-2)/2)
+ x = get_bits(i, (k-2)/2, (k-2)/2)
+ quad = get_bits(i, k-2, 2)
+ const_map.append(get_c(x, y, quad))
+
+ return const_map
+
+def make_not_differential_constellation(m, gray_coded):
+ side = int(pow(m, 0.5))
+ if (not isinstance(m, int) or m < 4 or not is_power_of_four(m)):
+ raise ValueError("m must be a power of 4 integer.")
+ # Each symbol holds k bits.
+ k = int(log(m) / log(2.0))
+ if gray_coded:
+ # Number rows and columns using gray codes.
+ gcs = gray_code(side)
+ # Get inverse gray codes.
+ i_gcs = mod_codes.invert_code(gcs)
+ else:
+ i_gcs = range(0, side)
+ # The distance between points is found.
+ step = 2.0/(side-1)
+
+ gc_to_x = [-1 + i_gcs[gc]*step for gc in range(0, side)]
+ # First k/2 bits determine x position.
+ # Following k/2 bits determine y position.
const_map = []
for i in range(m):
- a = (i&(0x01 << k-1)) >> k-1
- b = (i&(0x01 << k-2)) >> k-2
- bits_i = [((i&(0x01 << k-j-1)) >> k-j-1) for j in range(2, k, 2)]
- bits_q = [((i&(0x01 << k-j-1)) >> k-j-1) for j in range(3, k, 2)]
-
- ss = 0
- ll = len(bits_i)
- for ii in range(ll):
- rr = 0
- for jj in range(ll-ii):
- rr = abs(bits_i[jj] - rr)
- ss += rr*pow(2.0, ii+1)
- re = (2*a-1)*(ss+1)
-
- ss = 0
- ll = len(bits_q)
- for ii in range(ll):
- rr = 0
- for jj in range(ll-ii):
- rr = abs(bits_q[jj] - rr)
- ss += rr*pow(2.0, ii+1)
- im = (2*b-1)*(ss+1)
-
- a = max(re, im)
- if a > coeff:
- coeff = a
- const_map.append(complex(re, im))
-
- norm_map = [complex(i.real/coeff, i.imag/coeff) for i in const_map]
- return norm_map
-
-# Common definition of constellations for Tx and Rx
-constellation = {
- 4 : make_constellation(4), # QAM4 (QPSK)
- 8 : make_constellation(8), # QAM8
- 16: make_constellation(16), # QAM16
- 64: make_constellation(64), # QAM64
- 256: make_constellation(256) # QAM256
- }
-
-# -----------------------
-# Do Gray code
-# -----------------------
-# binary to gray coding
-binary_to_gray = {
- 4 : range(4),
- 8 : range(8),
- 16: range(16),
- 64: range(64),
- 256: range(256)
- }
-
-# gray to binary
-gray_to_binary = {
- 4 : range(4),
- 8 : range(8),
- 16: range(16),
- 64: range(64),
- 256: range(256)
- }
-
-# -----------------------
-# Don't Gray code
-# -----------------------
-# identity mapping
-binary_to_ungray = {
- 4 : range(4),
- 8 : range(8),
- 16: range(16),
- 64: range(64)
- }
-
-# identity mapping
-ungray_to_binary = {
- 4 : range(4),
- 8 : range(8),
- 16: range(16),
- 64: range(64)
- }
+ y = gc_to_x[get_bits(i, 0, k/2)]
+ x = gc_to_x[get_bits(i, k/2, k/2)]
+ const_map.append(complex(x,y))
+ return const_map
+
+# /////////////////////////////////////////////////////////////////////////////
+# QAM constellation
+# /////////////////////////////////////////////////////////////////////////////
+
+def qam_constellation(constellation_points=_def_constellation_points,
+ differential=_def_differential,
+ mod_code=_def_mod_code):
+ """
+ Creates a QAM constellation object.
+ """
+ if mod_code == mod_codes.GRAY_CODE:
+ gray_coded = True
+ elif mod_code == mod_codes.NO_CODE:
+ gray_coded = False
+ else:
+ raise ValueError("Mod code is not implemented for QAM")
+ if differential:
+ points = make_differential_constellation(constellation_points, gray_coded)
+ else:
+ points = make_not_differential_constellation(constellation_points, gray_coded)
+ side = int(sqrt(constellation_points))
+ width = 2.0/(side-1)
+ # No pre-diff code
+ # Should add one so that we can gray-code the quadrant bits too.
+ pre_diff_code = []
+ constellation = gr.constellation_rect(points, pre_diff_code, 4, side, side, width, width)
+ return constellation
+
+# /////////////////////////////////////////////////////////////////////////////
+# QAM modulator
+# /////////////////////////////////////////////////////////////////////////////
+
+class qam_mod(generic_mod):
+
+ def __init__(self, constellation_points=_def_constellation_points,
+ differential=_def_differential,
+ mod_code=_def_mod_code,
+ *args, **kwargs):
+
+ """
+ Hierarchical block for RRC-filtered QAM modulation.
+
+ The input is a byte stream (unsigned char) and the
+ output is the complex modulated signal at baseband.
+
+ See generic_mod block for list of parameters.
+ """
+
+ constellation = qam_constellation(constellation_points, differential, mod_code)
+ # We take care of the gray coding in the constellation generation so it doesn't
+ # need to be done in the block.
+ super(qam_mod, self).__init__(constellation, differential=differential,
+ *args, **kwargs)
+
+# /////////////////////////////////////////////////////////////////////////////
+# QAM demodulator
+#
+# /////////////////////////////////////////////////////////////////////////////
+
+class qam_demod(generic_demod):
+
+ def __init__(self, constellation_points=_def_constellation_points,
+ differential=_def_differential,
+ mod_code=_def_mod_code,
+ *args, **kwargs):
+
+ """
+ Hierarchical block for RRC-filtered QAM modulation.
+
+ The input is a byte stream (unsigned char) and the
+ output is the complex modulated signal at baseband.
+
+ See generic_demod block for list of parameters.
+ """
+ constellation = qam_constellation(constellation_points, differential, mod_code)
+ # We take care of the gray coding in the constellation generation so it doesn't
+ # need to be done in the block.
+ super(qam_demod, self).__init__(constellation, differential=differential,
+ *args, **kwargs)
+
+#
+# Add these to the mod/demod registry
+#
+modulation_utils2.add_type_1_mod('qam', qam_mod)
+modulation_utils2.add_type_1_demod('qam', qam_demod)
+modulation_utils2.add_type_1_constellation('qam', qam_constellation)
diff --git a/gnuradio-core/src/python/gnuradio/blks2impl/qam16.py b/gnuradio-core/src/python/gnuradio/blks2impl/qam16.py
deleted file mode 100644
index 0bdb9c6fb..000000000
--- a/gnuradio-core/src/python/gnuradio/blks2impl/qam16.py
+++ /dev/null
@@ -1,208 +0,0 @@
-#
-# 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
-
-"""
-QAM16 modulation and demodulation.
-"""
-
-from gnuradio import gr, gru, modulation_utils
-from math import pi, sqrt
-import qam
-import cmath
-from pprint import pprint
-
-# default values (used in __init__ and add_options)
-_def_samples_per_symbol = 2
-_def_excess_bw = 0.35
-_def_gray_code = True
-_def_verbose = False
-_def_log = False
-
-_def_costas_alpha = None
-_def_gain_mu = 0.03
-_def_mu = 0.05
-_def_omega_relative_limit = 0.005
-
-
-# /////////////////////////////////////////////////////////////////////////////
-# QAM16 modulator
-# /////////////////////////////////////////////////////////////////////////////
-
-class qam16_mod(gr.hier_block2):
-
- def __init__(self,
- samples_per_symbol=_def_samples_per_symbol,
- excess_bw=_def_excess_bw,
- gray_code=_def_gray_code,
- verbose=_def_verbose,
- log=_def_log):
-
- """
- Hierarchical block for RRC-filtered QPSK modulation.
-
- The input is a byte stream (unsigned char) and the
- output is the complex modulated signal at baseband.
-
- @param samples_per_symbol: samples per symbol >= 2
- @type samples_per_symbol: integer
- @param excess_bw: Root-raised cosine filter excess bandwidth
- @type excess_bw: float
- @param gray_code: Tell modulator to Gray code the bits
- @type gray_code: bool
- @param verbose: Print information about modulator?
- @type verbose: bool
- @param debug: Print modualtion data to files?
- @type debug: bool
- """
-
- gr.hier_block2.__init__(self, "qam16_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._excess_bw = excess_bw
- self._gray_code = gray_code
-
- if not isinstance(samples_per_symbol, int) or samples_per_symbol < 2:
- raise TypeError, ("sbp must be an integer >= 2, is %d" % samples_per_symbol)
-
- ntaps = 11 * samples_per_symbol
-
- arity = pow(2, self.bits_per_symbol())
-
- # turn bytes into k-bit vectors
- self.bytes2chunks = \
- gr.packed_to_unpacked_bb(self.bits_per_symbol(), gr.GR_MSB_FIRST)
-
- if self._gray_code:
- self.symbol_mapper = gr.map_bb(qam.binary_to_gray[arity])
- else:
- self.symbol_mapper = gr.map_bb(qam.binary_to_ungray[arity])
-
- self.diffenc = gr.diff_encoder_bb(arity)
-
- rot = 1.0
- print "constellation with %d arity" % arity
- rotated_const = map(lambda pt: pt * rot, qam.constellation[arity])
- self.chunks2symbols = gr.chunks_to_symbols_bc(rotated_const)
-
- # pulse shaping filter
- self.rrc_taps = gr.firdes.root_raised_cosine(
- self._samples_per_symbol, # gain (sps since we're interpolating by sps)
- self._samples_per_symbol, # sampling rate
- 1.0, # symbol rate
- self._excess_bw, # excess bandwidth (roll-off factor)
- ntaps)
-
- self.rrc_filter = gr.interp_fir_filter_ccf(self._samples_per_symbol, self.rrc_taps)
-
- if verbose:
- self._print_verbage()
-
- if log:
- self._setup_logging()
-
- # Connect
- self.connect(self, self.bytes2chunks, self.symbol_mapper, self.diffenc,
- self.chunks2symbols, self.rrc_filter, self)
-
- def samples_per_symbol(self):
- return self._samples_per_symbol
-
- def bits_per_symbol(self=None): # staticmethod that's also callable on an instance
- return 4
- bits_per_symbol = staticmethod(bits_per_symbol) # make it a static method. RTFM
-
- def _print_verbage(self):
- print "bits per symbol = %d" % self.bits_per_symbol()
- print "Gray code = %s" % self._gray_code
- print "RRS roll-off factor = %f" % self._excess_bw
-
- def _setup_logging(self):
- print "Modulation logging turned on."
- self.connect(self.bytes2chunks,
- gr.file_sink(gr.sizeof_char, "bytes2chunks.dat"))
- self.connect(self.symbol_mapper,
- gr.file_sink(gr.sizeof_char, "graycoder.dat"))
- self.connect(self.diffenc,
- gr.file_sink(gr.sizeof_char, "diffenc.dat"))
- self.connect(self.chunks2symbols,
- gr.file_sink(gr.sizeof_gr_complex, "chunks2symbols.dat"))
- self.connect(self.rrc_filter,
- gr.file_sink(gr.sizeof_gr_complex, "rrc_filter.dat"))
-
- def add_options(parser):
- """
- Adds QAM modulation-specific options to the standard parser
- """
- parser.add_option("", "--excess-bw", type="float", default=_def_excess_bw,
- help="set RRC excess bandwith factor [default=%default] (PSK)")
- parser.add_option("", "--no-gray-code", dest="gray_code",
- action="store_false", default=_def_gray_code,
- help="disable gray coding on modulated bits (PSK)")
- 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(qam16_mod.__init__,
- ('self',), options)
- extract_kwargs_from_options=staticmethod(extract_kwargs_from_options)
-
-
-# /////////////////////////////////////////////////////////////////////////////
-# QAM16 demodulator
-#
-# /////////////////////////////////////////////////////////////////////////////
-
-class qam16_demod(gr.hier_block2):
-
- def __init__(self,
- samples_per_symbol=_def_samples_per_symbol,
- excess_bw=_def_excess_bw,
- costas_alpha=_def_costas_alpha,
- gain_mu=_def_gain_mu,
- mu=_def_mu,
- omega_relative_limit=_def_omega_relative_limit,
- gray_code=_def_gray_code,
- verbose=_def_verbose,
- log=_def_log):
-
- gr.hier_block2.__init__(self, "qam16_demod",
- gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature
- gr.io_signature(1, 1, gr.sizeof_char)) # Output signature
- # do this
- pass
-
- def bits_per_symbol(self=None): # staticmethod that's also callable on an instance
- return 4
- bits_per_symbol = staticmethod(bits_per_symbol) # make it a static method. RTFM
-
-#
-# Add these to the mod/demod registry
-#
-# NOT READY TO BE USED YET -- ENABLE AT YOUR OWN RISK
-#modulation_utils.add_type_1_mod('qam16', qam16_mod)
-#modulation_utils.add_type_1_demod('qam16', qam16_demod)
diff --git a/gnuradio-core/src/python/gnuradio/blks2impl/qam256.py b/gnuradio-core/src/python/gnuradio/blks2impl/qam256.py
deleted file mode 100644
index fc455f17c..000000000
--- a/gnuradio-core/src/python/gnuradio/blks2impl/qam256.py
+++ /dev/null
@@ -1,209 +0,0 @@
-#
-# 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
-
-"""
-QAM256 modulation and demodulation.
-"""
-
-from gnuradio import gr, gru, modulation_utils
-from math import pi, sqrt
-import qam
-import cmath
-from pprint import pprint
-
-# default values (used in __init__ and add_options)
-_def_samples_per_symbol = 2
-_def_excess_bw = 0.35
-_def_gray_code = True
-_def_verbose = False
-_def_log = False
-
-_def_costas_alpha = None
-_def_gain_mu = 0.03
-_def_mu = 0.05
-_def_omega_relative_limit = 0.005
-
-
-# /////////////////////////////////////////////////////////////////////////////
-# QAM256 modulator
-# /////////////////////////////////////////////////////////////////////////////
-
-class qam256_mod(gr.hier_block2):
-
- def __init__(self,
- samples_per_symbol=_def_samples_per_symbol,
- excess_bw=_def_excess_bw,
- gray_code=_def_gray_code,
- verbose=_def_verbose,
- log=_def_log):
-
- """
- Hierarchical block for RRC-filtered QPSK modulation.
-
- The input is a byte stream (unsigned char) and the
- output is the complex modulated signal at baseband.
-
- @param samples_per_symbol: samples per symbol >= 2
- @type samples_per_symbol: integer
- @param excess_bw: Root-raised cosine filter excess bandwidth
- @type excess_bw: float
- @param gray_code: Tell modulator to Gray code the bits
- @type gray_code: bool
- @param verbose: Print information about modulator?
- @type verbose: bool
- @param debug: Print modualtion data to files?
- @type debug: bool
- """
-
- gr.hier_block2.__init__(self, "qam256_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._excess_bw = excess_bw
- self._gray_code = gray_code
-
- if not isinstance(samples_per_symbol, int) or samples_per_symbol < 2:
- raise TypeError, ("sbp must be an integer >= 2, is %d" % samples_per_symbol)
-
- ntaps = 11 * samples_per_symbol
-
- arity = pow(2, self.bits_per_symbol())
-
- # turn bytes into k-bit vectors
- self.bytes2chunks = \
- gr.packed_to_unpacked_bb(self.bits_per_symbol(), gr.GR_MSB_FIRST)
-
- if self._gray_code:
- self.symbol_mapper = gr.map_bb(qam.binary_to_gray[arity])
- else:
- self.symbol_mapper = gr.map_bb(qam.binary_to_ungray[arity])
-
- self.diffenc = gr.diff_encoder_bb(arity)
-
- rot = 1.0
- print "constellation with %d arity" % arity
- rotated_const = map(lambda pt: pt * rot, qam.constellation[arity])
- self.chunks2symbols = gr.chunks_to_symbols_bc(rotated_const)
-
- # pulse shaping filter
- self.rrc_taps = gr.firdes.root_raised_cosine(
- self._samples_per_symbol, # gain (sps since we're interpolating by sps)
- self._samples_per_symbol, # sampling rate
- 1.0, # symbol rate
- self._excess_bw, # excess bandwidth (roll-off factor)
- ntaps)
-
- self.rrc_filter = gr.interp_fir_filter_ccf(self._samples_per_symbol, self.rrc_taps)
-
- if verbose:
- self._print_verbage()
-
- if log:
- self._setup_logging()
-
- # Connect
- self.connect(self, self.bytes2chunks, self.symbol_mapper, self.diffenc,
- self.chunks2symbols, self.rrc_filter, self)
-
- def samples_per_symbol(self):
- return self._samples_per_symbol
-
- def bits_per_symbol(self=None): # staticmethod that's also callable on an instance
- return 8
- bits_per_symbol = staticmethod(bits_per_symbol) # make it a static method. RTFM
-
- def _print_verbage(self):
- print "bits per symbol = %d" % self.bits_per_symbol()
- print "Gray code = %s" % self._gray_code
- print "RRS roll-off factor = %f" % self._excess_bw
-
- def _setup_logging(self):
- print "Modulation logging turned on."
- self.connect(self.bytes2chunks,
- gr.file_sink(gr.sizeof_char, "bytes2chunks.dat"))
- self.connect(self.symbol_mapper,
- gr.file_sink(gr.sizeof_char, "graycoder.dat"))
- self.connect(self.diffenc,
- gr.file_sink(gr.sizeof_char, "diffenc.dat"))
- self.connect(self.chunks2symbols,
- gr.file_sink(gr.sizeof_gr_complex, "chunks2symbols.dat"))
- self.connect(self.rrc_filter,
- gr.file_sink(gr.sizeof_gr_complex, "rrc_filter.dat"))
-
- def add_options(parser):
- """
- Adds QAM modulation-specific options to the standard parser
- """
- parser.add_option("", "--excess-bw", type="float", default=_def_excess_bw,
- help="set RRC excess bandwith factor [default=%default] (PSK)")
- parser.add_option("", "--no-gray-code", dest="gray_code",
- action="store_false", default=_def_gray_code,
- help="disable gray coding on modulated bits (PSK)")
- 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(qam256_mod.__init__,
- ('self',), options)
- extract_kwargs_from_options=staticmethod(extract_kwargs_from_options)
-
-
-# /////////////////////////////////////////////////////////////////////////////
-# QAM256 demodulator
-#
-# /////////////////////////////////////////////////////////////////////////////
-
-class qam256_demod(gr.hier_block2):
-
- def __init__(self,
- samples_per_symbol=_def_samples_per_symbol,
- excess_bw=_def_excess_bw,
- costas_alpha=_def_costas_alpha,
- gain_mu=_def_gain_mu,
- mu=_def_mu,
- omega_relative_limit=_def_omega_relative_limit,
- gray_code=_def_gray_code,
- verbose=_def_verbose,
- log=_def_log):
-
- gr.hier_block2.__init__(self, "qam256_demod",
- gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature
- gr.io_signature(1, 1, gr.sizeof_char)) # Output signature
-
- # do this
- pass
-
- def bits_per_symbol(self=None): # staticmethod that's also callable on an instance
- return 8
- bits_per_symbol = staticmethod(bits_per_symbol) # make it a static method. RTFM
-
-#
-# Add these to the mod/demod registry
-#
-# NOT READY TO BE USED YET -- ENABLE AT YOUR OWN RISK
-#modulation_utils.add_type_1_mod('qam256', qam256_mod)
-#modulation_utils.add_type_1_demod('qam256', qam256_demod)
diff --git a/gnuradio-core/src/python/gnuradio/blks2impl/qam64.py b/gnuradio-core/src/python/gnuradio/blks2impl/qam64.py
deleted file mode 100644
index 5509f3745..000000000
--- a/gnuradio-core/src/python/gnuradio/blks2impl/qam64.py
+++ /dev/null
@@ -1,208 +0,0 @@
-#
-# 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
-
-"""
-differential QPSK modulation and demodulation.
-"""
-
-from gnuradio import gr, gru, modulation_utils
-from math import pi, sqrt
-import qam
-import cmath
-from pprint import pprint
-
-# default values (used in __init__ and add_options)
-_def_samples_per_symbol = 2
-_def_excess_bw = 0.35
-_def_gray_code = True
-_def_verbose = False
-_def_log = False
-
-_def_costas_alpha = None
-_def_gain_mu = 0.03
-_def_mu = 0.05
-_def_omega_relative_limit = 0.005
-
-
-# /////////////////////////////////////////////////////////////////////////////
-# QAM64 modulator
-# /////////////////////////////////////////////////////////////////////////////
-
-class qam64_mod(gr.hier_block2):
-
- def __init__(self,
- samples_per_symbol=_def_samples_per_symbol,
- excess_bw=_def_excess_bw,
- gray_code=_def_gray_code,
- verbose=_def_verbose,
- log=_def_log):
-
- """
- Hierarchical block for RRC-filtered QPSK modulation.
-
- The input is a byte stream (unsigned char) and the
- output is the complex modulated signal at baseband.
-
- @param samples_per_symbol: samples per symbol >= 2
- @type samples_per_symbol: integer
- @param excess_bw: Root-raised cosine filter excess bandwidth
- @type excess_bw: float
- @param gray_code: Tell modulator to Gray code the bits
- @type gray_code: bool
- @param verbose: Print information about modulator?
- @type verbose: bool
- @param debug: Print modualtion data to files?
- @type debug: bool
- """
-
- gr.hier_block2.__init__(self, "qam64_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._excess_bw = excess_bw
- self._gray_code = gray_code
-
- if not isinstance(samples_per_symbol, int) or samples_per_symbol < 2:
- raise TypeError, ("sbp must be an integer >= 2, is %d" % samples_per_symbol)
-
- ntaps = 11 * samples_per_symbol
-
- arity = pow(2, self.bits_per_symbol())
-
- # turn bytes into k-bit vectors
- self.bytes2chunks = \
- gr.packed_to_unpacked_bb(self.bits_per_symbol(), gr.GR_MSB_FIRST)
-
- if self._gray_code:
- self.symbol_mapper = gr.map_bb(qam.binary_to_gray[arity])
- else:
- self.symbol_mapper = gr.map_bb(qam.binary_to_ungray[arity])
-
- self.diffenc = gr.diff_encoder_bb(arity)
-
- rot = 1.0
- print "constellation with %d arity" % arity
- rotated_const = map(lambda pt: pt * rot, qam.constellation[arity])
- self.chunks2symbols = gr.chunks_to_symbols_bc(rotated_const)
-
- # pulse shaping filter
- self.rrc_taps = gr.firdes.root_raised_cosine(
- self._samples_per_symbol, # gain (sps since we're interpolating by sps)
- self._samples_per_symbol, # sampling rate
- 1.0, # symbol rate
- self._excess_bw, # excess bandwidth (roll-off factor)
- ntaps)
-
- self.rrc_filter = gr.interp_fir_filter_ccf(self._samples_per_symbol, self.rrc_taps)
-
- if verbose:
- self._print_verbage()
-
- if log:
- self._setup_logging()
-
- # Connect
- self.connect(self, self.bytes2chunks, self.symbol_mapper, self.diffenc,
- self.chunks2symbols, self.rrc_filter, self)
-
- def samples_per_symbol(self):
- return self._samples_per_symbol
-
- def bits_per_symbol(self=None): # staticmethod that's also callable on an instance
- return 6
- bits_per_symbol = staticmethod(bits_per_symbol) # make it a static method. RTFM
-
- def _print_verbage(self):
- print "bits per symbol = %d" % self.bits_per_symbol()
- print "Gray code = %s" % self._gray_code
- print "RRS roll-off factor = %f" % self._excess_bw
-
- def _setup_logging(self):
- print "Modulation logging turned on."
- self.connect(self.bytes2chunks,
- gr.file_sink(gr.sizeof_char, "bytes2chunks.dat"))
- self.connect(self.symbol_mapper,
- gr.file_sink(gr.sizeof_char, "graycoder.dat"))
- self.connect(self.diffenc,
- gr.file_sink(gr.sizeof_char, "diffenc.dat"))
- self.connect(self.chunks2symbols,
- gr.file_sink(gr.sizeof_gr_complex, "chunks2symbols.dat"))
- self.connect(self.rrc_filter,
- gr.file_sink(gr.sizeof_gr_complex, "rrc_filter.dat"))
-
- def add_options(parser):
- """
- Adds QAM modulation-specific options to the standard parser
- """
- parser.add_option("", "--excess-bw", type="float", default=_def_excess_bw,
- help="set RRC excess bandwith factor [default=%default] (PSK)")
- parser.add_option("", "--no-gray-code", dest="gray_code",
- action="store_false", default=_def_gray_code,
- help="disable gray coding on modulated bits (PSK)")
- 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(qam64_mod.__init__,
- ('self',), options)
- extract_kwargs_from_options=staticmethod(extract_kwargs_from_options)
-
-
-# /////////////////////////////////////////////////////////////////////////////
-# QAM16 demodulator
-#
-# /////////////////////////////////////////////////////////////////////////////
-
-class qam64_demod(gr.hier_block2):
-
- def __init__(self,
- samples_per_symbol=_def_samples_per_symbol,
- excess_bw=_def_excess_bw,
- costas_alpha=_def_costas_alpha,
- gain_mu=_def_gain_mu,
- mu=_def_mu,
- omega_relative_limit=_def_omega_relative_limit,
- gray_code=_def_gray_code,
- verbose=_def_verbose,
- log=_def_log):
-
- gr.hier_block2.__init__(self, "qam64_demod",
- gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature
- gr.io_signature(1, 1, gr.sizeof_char)) # Output signature
-
- # do this
- pass
-
- def bits_per_symbol(self=None): # staticmethod that's also callable on an instance
- return 6
- bits_per_symbol = staticmethod(bits_per_symbol) # make it a static method. RTFM
-
-#
-# Add these to the mod/demod registry
-#
-# NOT READY TO BE USED YET -- ENABLE AT YOUR OWN RISK
-#modulation_utils.add_type_1_mod('qam64', qam64_mod)
-#modulation_utils.add_type_1_demod('qam16', qam16_demod)
diff --git a/gnuradio-core/src/python/gnuradio/blks2impl/qam8.py b/gnuradio-core/src/python/gnuradio/blks2impl/qam8.py
deleted file mode 100644
index 6a7b35597..000000000
--- a/gnuradio-core/src/python/gnuradio/blks2impl/qam8.py
+++ /dev/null
@@ -1,209 +0,0 @@
-#
-# 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
-
-"""
-QAM8 modulation and demodulation.
-"""
-
-from gnuradio import gr, gru, modulation_utils
-from math import pi, sqrt
-import qam
-import cmath
-from pprint import pprint
-
-# default values (used in __init__ and add_options)
-_def_samples_per_symbol = 2
-_def_excess_bw = 0.35
-_def_gray_code = True
-_def_verbose = False
-_def_log = False
-
-_def_costas_alpha = None
-_def_gain_mu = 0.03
-_def_mu = 0.05
-_def_omega_relative_limit = 0.005
-
-
-# /////////////////////////////////////////////////////////////////////////////
-# QAM8 modulator
-# /////////////////////////////////////////////////////////////////////////////
-
-class qam8_mod(gr.hier_block2):
-
- def __init__(self,
- samples_per_symbol=_def_samples_per_symbol,
- excess_bw=_def_excess_bw,
- gray_code=_def_gray_code,
- verbose=_def_verbose,
- log=_def_log):
-
- """
- Hierarchical block for RRC-filtered QPSK modulation.
-
- The input is a byte stream (unsigned char) and the
- output is the complex modulated signal at baseband.
-
- @param samples_per_symbol: samples per symbol >= 2
- @type samples_per_symbol: integer
- @param excess_bw: Root-raised cosine filter excess bandwidth
- @type excess_bw: float
- @param gray_code: Tell modulator to Gray code the bits
- @type gray_code: bool
- @param verbose: Print information about modulator?
- @type verbose: bool
- @param debug: Print modualtion data to files?
- @type debug: bool
- """
-
- gr.hier_block2.__init__(self, "qam8_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._excess_bw = excess_bw
- self._gray_code = gray_code
-
- if not isinstance(samples_per_symbol, int) or samples_per_symbol < 2:
- raise TypeError, ("sbp must be an integer >= 2, is %d" % samples_per_symbol)
-
- ntaps = 11 * samples_per_symbol
-
- arity = pow(2, self.bits_per_symbol())
-
- # turn bytes into k-bit vectors
- self.bytes2chunks = \
- gr.packed_to_unpacked_bb(self.bits_per_symbol(), gr.GR_MSB_FIRST)
-
- if self._gray_code:
- self.symbol_mapper = gr.map_bb(qam.binary_to_gray[arity])
- else:
- self.symbol_mapper = gr.map_bb(qam.binary_to_ungray[arity])
-
- self.diffenc = gr.diff_encoder_bb(arity)
-
- rot = 1.0
- print "constellation with %d arity" % arity
- rotated_const = map(lambda pt: pt * rot, qam.constellation[arity])
- self.chunks2symbols = gr.chunks_to_symbols_bc(rotated_const)
-
- # pulse shaping filter
- self.rrc_taps = gr.firdes.root_raised_cosine(
- self._samples_per_symbol, # gain (sps since we're interpolating by sps)
- self._samples_per_symbol, # sampling rate
- 1.0, # symbol rate
- self._excess_bw, # excess bandwidth (roll-off factor)
- ntaps)
-
- self.rrc_filter = gr.interp_fir_filter_ccf(self._samples_per_symbol, self.rrc_taps)
-
- if verbose:
- self._print_verbage()
-
- if log:
- self._setup_logging()
-
- # Connect
- self.connect(self, self.bytes2chunks, self.symbol_mapper, self.diffenc,
- self.chunks2symbols, self.rrc_filter, self)
-
- def samples_per_symbol(self):
- return self._samples_per_symbol
-
- def bits_per_symbol(self=None): # staticmethod that's also callable on an instance
- return 3
- bits_per_symbol = staticmethod(bits_per_symbol) # make it a static method. RTFM
-
- def _print_verbage(self):
- print "bits per symbol = %d" % self.bits_per_symbol()
- print "Gray code = %s" % self._gray_code
- print "RRS roll-off factor = %f" % self._excess_bw
-
- def _setup_logging(self):
- print "Modulation logging turned on."
- self.connect(self.bytes2chunks,
- gr.file_sink(gr.sizeof_char, "bytes2chunks.dat"))
- self.connect(self.symbol_mapper,
- gr.file_sink(gr.sizeof_char, "graycoder.dat"))
- self.connect(self.diffenc,
- gr.file_sink(gr.sizeof_char, "diffenc.dat"))
- self.connect(self.chunks2symbols,
- gr.file_sink(gr.sizeof_gr_complex, "chunks2symbols.dat"))
- self.connect(self.rrc_filter,
- gr.file_sink(gr.sizeof_gr_complex, "rrc_filter.dat"))
-
- def add_options(parser):
- """
- Adds QAM modulation-specific options to the standard parser
- """
- parser.add_option("", "--excess-bw", type="float", default=_def_excess_bw,
- help="set RRC excess bandwith factor [default=%default] (PSK)")
- parser.add_option("", "--no-gray-code", dest="gray_code",
- action="store_false", default=_def_gray_code,
- help="disable gray coding on modulated bits (PSK)")
- 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(qam8_mod.__init__,
- ('self',), options)
- extract_kwargs_from_options=staticmethod(extract_kwargs_from_options)
-
-
-# /////////////////////////////////////////////////////////////////////////////
-# QAM8 demodulator
-#
-# /////////////////////////////////////////////////////////////////////////////
-
-class qam8_demod(gr.hier_block2):
-
- def __init__(self,
- samples_per_symbol=_def_samples_per_symbol,
- excess_bw=_def_excess_bw,
- costas_alpha=_def_costas_alpha,
- gain_mu=_def_gain_mu,
- mu=_def_mu,
- omega_relative_limit=_def_omega_relative_limit,
- gray_code=_def_gray_code,
- verbose=_def_verbose,
- log=_def_log):
-
- gr.hier_block2.__init__(self, "qam8_demod",
- gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature
- gr.io_signature(1, 1, gr.sizeof_char)) # Output signature
-
- # do this
- pass
-
- def bits_per_symbol(self=None): # staticmethod that's also callable on an instance
- return 3
- bits_per_symbol = staticmethod(bits_per_symbol) # make it a static method. RTFM
-
-#
-# Add these to the mod/demod registry
-#
-# NOT READY TO BE USED YET -- ENABLE AT YOUR OWN RISK
-modulation_utils.add_type_1_mod('qam8', qam8_mod)
-#modulation_utils.add_type_1_demod('qam8', qam8_demod)
diff --git a/gnuradio-core/src/python/gnuradio/blks2impl/qpsk.py b/gnuradio-core/src/python/gnuradio/blks2impl/qpsk.py
new file mode 100644
index 000000000..f62ae232c
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/blks2impl/qpsk.py
@@ -0,0 +1,79 @@
+#
+# 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 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.
+#
+
+"""
+QPSK modulation.
+
+Demodulation is not included since the generic_mod_demod
+doesn't work for non-differential encodings.
+"""
+
+from gnuradio import gr, modulation_utils2
+from gnuradio.blks2impl.generic_mod_demod import generic_mod
+
+
+# Default number of points in constellation.
+_def_constellation_points = 4
+# Whether differential coding is used.
+_def_differential = False
+_def_gray_coded = True
+
+# /////////////////////////////////////////////////////////////////////////////
+# QPSK constellation
+# /////////////////////////////////////////////////////////////////////////////
+
+def qpsk_constellation(m=_def_constellation_points):
+ if m != _def_constellation_points:
+ raise ValueError("QPSK can only have 4 constellation points.")
+ return gr.constellation_qpsk()
+
+# /////////////////////////////////////////////////////////////////////////////
+# QPSK modulator
+# /////////////////////////////////////////////////////////////////////////////
+
+class qpsk_mod(generic_mod):
+
+ def __init__(self, constellation_points=_def_constellation_points,
+ differential=_def_differential,
+ gray_coded=_def_gray_coded,
+ *args, **kwargs):
+
+ """
+ Hierarchical block for RRC-filtered QPSK modulation.
+
+ The input is a byte stream (unsigned char) and the
+ output is the complex modulated signal at baseband.
+
+ See generic_mod block for list of parameters.
+ """
+
+ constellation = gr.constellation_qpsk()
+ if constellation_points != 4:
+ raise ValueError("QPSK can only have 4 constellation points.")
+ if differential or not gray_coded:
+ raise ValueError("This QPSK mod/demod works only for gray-coded, non-differential.")
+ super(qpsk_mod, self).__init__(constellation, differential, gray_coded, *args, **kwargs)
+
+#
+# Add these to the mod/demod registry
+#
+modulation_utils2.add_type_1_mod('qpsk', qpsk_mod)
+modulation_utils2.add_type_1_constellation('qpsk', qpsk_constellation)
diff --git a/gnuradio-core/src/python/gnuradio/gr/Makefile.am b/gnuradio-core/src/python/gnuradio/gr/Makefile.am
index b8da9cf48..db2cc6eb3 100644
--- a/gnuradio-core/src/python/gnuradio/gr/Makefile.am
+++ b/gnuradio-core/src/python/gnuradio/gr/Makefile.am
@@ -51,6 +51,7 @@ noinst_PYTHON = \
qa_classify.py \
qa_cma_equalizer.py \
qa_complex_to_xxx.py \
+ qa_constellation.py \
qa_constellation_decoder_cb.py \
qa_copy.py \
qa_correlate_access_code.py \
diff --git a/gnuradio-core/src/python/gnuradio/gr/qa_constellation.py b/gnuradio-core/src/python/gnuradio/gr/qa_constellation.py
new file mode 100644
index 000000000..6ac3d95b6
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/gr/qa_constellation.py
@@ -0,0 +1,202 @@
+#!/usr/bin/env python
+#
+# Copyright 2004,2007,2010 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.
+#
+
+import random
+from cmath import exp, pi, log
+from itertools import product
+
+from gnuradio import gr, gr_unittest, blks2
+from gnuradio.utils import mod_codes
+
+tested_mod_codes = (mod_codes.NO_CODE, mod_codes.GRAY_CODE)
+
+# A list of the constellations to test.
+# Each constellation is given by a 3-tuple.
+# First item is a function to generate the constellation
+# Second item is a dictionary of arguments for function with lists of
+# possible values.
+# Third item is whether differential encoding should be tested.
+# Fourth item is the name of the argument to constructor that specifices
+# whether differential encoding is used.
+
+def twod_constell():
+ """
+
+ """
+ points = ((1+0j), (0+1j),
+ (-1+0j), (0-1j))
+ rot_sym = 2
+ dim = 2
+ return gr.constellation_calcdist(points, [], rot_sym, dim)
+
+def threed_constell():
+ oned_points = ((1+0j), (0+1j), (-1+0j), (0-1j))
+ points = []
+ r4 = range(0, 4)
+ for ia, ib, ic in product(r4, r4, r4):
+ points += [oned_points[ia], oned_points[ib], oned_points[ic]]
+ rot_sym = 4
+ dim = 3
+ return gr.constellation_calcdist(points, [], rot_sym, dim)
+
+tested_constellation_info = (
+ (blks2.psk_constellation,
+ {'m': (2, 4, 8, 16, 32, 64),
+ 'mod_code': tested_mod_codes, },
+ True, None),
+ (blks2.qam_constellation,
+ {'constellation_points': (4, 16, 64),
+ 'mod_code': tested_mod_codes, },
+ True, 'differential'),
+ (blks2.bpsk_constellation, {}, True, None),
+ # No differential testing for qpsk because it is gray-coded.
+ # This is because soft decision making is simpler if we can assume
+ # gray coding.
+ (blks2.qpsk_constellation, {}, False, None),
+ (twod_constell, {}, True, None),
+ (threed_constell, {}, True, None),
+ )
+
+def tested_constellations():
+ """
+ Generator to produce (constellation, differential) tuples for testing purposes.
+ """
+ for constructor, poss_args, differential, diff_argname in tested_constellation_info:
+ if differential:
+ diff_poss = (True, False)
+ else:
+ diff_poss = (False,)
+ poss_args = [[argname, argvalues, 0] for argname, argvalues in poss_args.items()]
+ for current_diff in diff_poss:
+ # Add an index into args to keep track of current position in argvalues
+ while True:
+ current_args = dict([(argname, argvalues[argindex])
+ for argname, argvalues, argindex in poss_args])
+ if diff_argname is not None:
+ current_args[diff_argname] = current_diff
+ constellation = constructor(**current_args)
+ yield (constellation, current_diff)
+ for this_poss_arg in poss_args:
+ argname, argvalues, argindex = this_poss_arg
+ if argindex < len(argvalues) - 1:
+ this_poss_arg[2] += 1
+ break
+ else:
+ this_poss_arg[2] = 0
+ if sum([argindex for argname, argvalues, argindex in poss_args]) == 0:
+ break
+
+
+class test_constellation (gr_unittest.TestCase):
+
+ src_length = 256
+
+ def setUp(self):
+ # Generate a list of random bits.
+ self.src_data = tuple([random.randint(0,1) for i in range(0, self.src_length)])
+
+ def tearDown(self):
+ pass
+
+ def test_hard_decision(self):
+ for constellation, differential in tested_constellations():
+ if differential:
+ rs = constellation.rotational_symmetry()
+ rotations = [exp(i*2*pi*(0+1j)/rs) for i in range(0, rs)]
+ else:
+ rotations = [None]
+ for rotation in rotations:
+ src = gr.vector_source_b(self.src_data)
+ content = mod_demod(constellation, differential, rotation)
+ dst = gr.vector_sink_b()
+ self.tb = gr.top_block()
+ self.tb.connect(src, content, dst)
+ self.tb.run()
+ data = dst.data()
+ # Don't worry about cut off data for now.
+ first = constellation.bits_per_symbol()
+ self.assertEqual (self.src_data[first:len(data)], data[first:])
+
+
+class mod_demod(gr.hier_block2):
+ def __init__(self, constellation, differential, rotation):
+ if constellation.arity() > 256:
+ # If this becomes limiting some of the blocks should be generalised so that they can work
+ # with shorts and ints as well as chars.
+ raise ValueError("Constellation cannot contain more than 256 points.")
+
+ gr.hier_block2.__init__(self, "mod_demod",
+ gr.io_signature(1, 1, gr.sizeof_char), # Input signature
+ gr.io_signature(1, 1, gr.sizeof_char)) # Output signature
+
+ arity = constellation.arity()
+
+ # TX
+ self.constellation = constellation
+ self.differential = differential
+ self.blocks = [self]
+ # We expect a stream of unpacked bits.
+ # First step is to pack them.
+ self.blocks.append(
+ gr.unpacked_to_packed_bb(1, gr.GR_MSB_FIRST))
+ # Second step we unpack them such that we have k bits in each byte where
+ # each constellation symbol hold k bits.
+ self.blocks.append(
+ gr.packed_to_unpacked_bb(self.constellation.bits_per_symbol(),
+ gr.GR_MSB_FIRST))
+ # Apply any pre-differential coding
+ # Gray-coding is done here if we're also using differential coding.
+ if self.constellation.apply_pre_diff_code():
+ self.blocks.append(gr.map_bb(self.constellation.pre_diff_code()))
+ # Differential encoding.
+ if self.differential:
+ self.blocks.append(gr.diff_encoder_bb(arity))
+ # Convert to constellation symbols.
+ self.blocks.append(gr.chunks_to_symbols_bc(self.constellation.points(), self.constellation.dimensionality()))
+ # CHANNEL
+ # Channel just consists of a rotation to check differential coding.
+ if rotation is not None:
+ self.blocks.append(gr.multiply_const_cc(rotation))
+
+ # RX
+ # Convert the constellation symbols back to binary values.
+ self.blocks.append(gr.constellation_decoder2_cb(self.constellation.base()))
+ # Differential decoding.
+ if self.differential:
+ self.blocks.append(gr.diff_decoder_bb(arity))
+ # Decode any pre-differential coding.
+ if self.constellation.apply_pre_diff_code():
+ self.blocks.append(gr.map_bb(
+ mod_codes.invert_code(self.constellation.pre_diff_code())))
+ # unpack the k bit vector into a stream of bits
+ self.blocks.append(gr.unpack_k_bits_bb(
+ self.constellation.bits_per_symbol()))
+ # connect to block output
+ check_index = len(self.blocks)
+ self.blocks = self.blocks[:check_index]
+ self.blocks.append(self)
+
+ self.connect(*self.blocks)
+
+
+if __name__ == '__main__':
+ gr_unittest.run(test_constellation, "test_constellation.xml")
diff --git a/gnuradio-core/src/python/gnuradio/gr/qa_constellation_receiver.py b/gnuradio-core/src/python/gnuradio/gr/qa_constellation_receiver.py
new file mode 100644
index 000000000..8d7719739
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/gr/qa_constellation_receiver.py
@@ -0,0 +1,144 @@
+#!/usr/bin/env python
+#
+# Copyright 2011 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.
+#
+
+import random
+
+from gnuradio import gr, blks2, packet_utils, gr_unittest
+from gnuradio.utils import mod_codes, alignment
+
+from qa_constellation import tested_constellations, twod_constell
+
+# Set a seed so that if errors turn up they are reproducible.
+# 1234 fails
+random.seed(1239)
+
+# TESTING PARAMETERS
+# The number of symbols to test with.
+# We need this many to let the frequency recovery block converge.
+DATA_LENGTH = 200000
+# Test fails if fraction of output that is correct is less than this.
+REQ_CORRECT = 0.8
+
+# CHANNEL PARAMETERS
+NOISE_VOLTAGE = 0.01
+FREQUENCY_OFFSET = 0.01
+TIMING_OFFSET = 1.0
+
+# RECEIVER PARAMETERS
+# Increased from normal default of 0.01 to speed things up.
+FREQ_ALPHA = 0.02
+# Decreased from normal default of 0.1 is required for the constellations
+# with smaller point separations.
+PHASE_ALPHA = 0.02
+
+
+class test_constellation_receiver (gr_unittest.TestCase):
+
+ # We ignore the first half of the output data since often it takes
+ # a while for the receiver to lock on.
+ ignore_fraction = 0.8
+ seed = 1234
+ max_data_length = DATA_LENGTH * 6
+ max_num_samples = 1000
+
+ def test_basic(self):
+ """
+ Tests a bunch of different constellations by using generic
+ modulation, a channel, and generic demodulation. The generic
+ demodulation uses constellation_receiver which is what
+ we're really trying to test.
+ """
+ # Assumes not more than 64 points in a constellation
+ # Generates some random input data to use.
+ self.src_data = tuple(
+ [random.randint(0,1) for i in range(0, self.max_data_length)])
+ # Generates some random indices to use for comparing input and
+ # output data (a full comparison is too slow in python).
+ self.indices = alignment.random_sample(
+ self.max_data_length, self.max_num_samples, self.seed)
+
+ for constellation, differential in tested_constellations():
+ # The constellation_receiver doesn't work for constellations
+ # of multple dimensions (i.e. multiple complex numbers to a
+ # single symbol).
+ # That is not implemented since the receiver has no way of
+ # knowing where the beginning of a symbol is.
+ # It also doesn't work for non-differential modulation.
+ if constellation.dimensionality() != 1 or not differential:
+ continue
+ data_length = DATA_LENGTH * constellation.bits_per_symbol()
+ tb = rec_test_tb(constellation, differential,
+ src_data=self.src_data[:data_length])
+ tb.run()
+ data = tb.dst.data()
+ d1 = tb.src_data[:int(len(tb.src_data)*self.ignore_fraction)]
+ d2 = data[:int(len(data)*self.ignore_fraction)]
+ correct, overlap, offset, indices = alignment.align_sequences(
+ d1, d2, indices=self.indices)
+ print(constellation, constellation.arity(), differential, correct, overlap, offset)
+ self.assertTrue(correct > REQ_CORRECT)
+
+ def single(self):
+ constellation = blks2.psk_constellation(64, mod_codes.NO_CODE)
+ tb = rec_test_tb(constellation, True, DATA_LENGTH)
+ tb.run()
+ data = tb.dst.data()
+ d1 = tb.src_data[:int(len(tb.src_data)*self.ignore_fraction)]
+ d2 = data[:int(len(data)*self.ignore_fraction)]
+ seed = random.randint(0, 256)
+ correct, overlap, offset, indices = alignment.align_sequences(d1, d2, seed=seed)
+ print(constellation, constellation.arity(), correct, overlap, offset)
+
+
+class rec_test_tb (gr.top_block):
+ """
+ Takes a constellation an runs a generic modulation, channel,
+ and generic demodulation.
+ """
+ def __init__(self, constellation, differential,
+ data_length=None, src_data=None):
+ """
+ constellation -- a constellation object
+ differential -- whether differential encoding is used
+ data_length -- the number of bits of data to use
+ src_data -- a list of the bits to use
+ """
+ super(rec_test_tb, self).__init__()
+ # Transmission Blocks
+ if src_data is None:
+ self.src_data = tuple([random.randint(0,1) for i in range(0, data_length)])
+ else:
+ self.src_data = src_data
+ packer = gr.unpacked_to_packed_bb(1, gr.GR_MSB_FIRST)
+ src = gr.vector_source_b(self.src_data)
+ mod = blks2.generic_mod(constellation, differential=differential)
+ # Channel
+ channel = gr.channel_model(NOISE_VOLTAGE, FREQUENCY_OFFSET, TIMING_OFFSET)
+ # Receiver Blocks
+ demod = blks2.generic_demod(constellation, differential=differential, log=True,
+ freq_alpha=FREQ_ALPHA,
+ phase_alpha=PHASE_ALPHA)
+ self.dst = gr.vector_sink_b()
+ self.connect(src, packer, mod, channel, demod, self.dst)
+
+if __name__ == '__main__':
+ gr_unittest.run(test_constellation_receiver, "test_constellation_receiver.xml")
diff --git a/gnuradio-core/src/python/gnuradio/modulation_utils2.py b/gnuradio-core/src/python/gnuradio/modulation_utils2.py
index c5dba3e79..f30055f4a 100644
--- a/gnuradio-core/src/python/gnuradio/modulation_utils2.py
+++ b/gnuradio-core/src/python/gnuradio/modulation_utils2.py
@@ -47,6 +47,15 @@ def type_1_demods():
def add_type_1_demod(name, demod_class):
_type_1_demodulators[name] = demod_class
+# Also record the constellation making functions of the modulations
+_type_1_constellations = {}
+
+def type_1_constellations():
+ return _type_1_constellations
+
+def add_type_1_constellation(name, constellation):
+ _type_1_constellations[name] = constellation
+
def extract_kwargs_from_options(function, excluded_args, options):
"""
@@ -79,3 +88,14 @@ def extract_kwargs_from_options(function, excluded_args, options):
if getattr(options, kw) is not None:
d[kw] = getattr(options, kw)
return d
+
+def extract_kwargs_from_options_for_class(cls, options):
+ """
+ Given command line options, create dictionary suitable for passing to __init__
+ """
+ d = extract_kwargs_from_options(
+ cls.__init__, ('self',), options)
+ for base in cls.__bases__:
+ if hasattr(base, 'extract_kwargs_from_options'):
+ d.update(base.extract_kwargs_from_options(options))
+ return d
diff --git a/gnuradio-core/src/python/gnuradio/utils/Makefile.am b/gnuradio-core/src/python/gnuradio/utils/Makefile.am
new file mode 100644
index 000000000..c35951b44
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/utils/Makefile.am
@@ -0,0 +1,35 @@
+#
+# Copyright 2007,2009 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.
+#
+
+include $(top_srcdir)/Makefile.common
+
+if PYTHON
+utilspythondir = $(grpythondir)/utils
+
+TESTS = \
+ run_tests
+
+nobase_utilspython_PYTHON = \
+ __init__.py \
+ gray_code.py \
+ mod_codes.py \
+ alignment.py
+endif \ No newline at end of file
diff --git a/gnuradio-core/src/python/gnuradio/utils/__init__.py b/gnuradio-core/src/python/gnuradio/utils/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/utils/__init__.py
diff --git a/gnuradio-core/src/python/gnuradio/utils/alignment.py b/gnuradio-core/src/python/gnuradio/utils/alignment.py
new file mode 100644
index 000000000..d32365866
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/utils/alignment.py
@@ -0,0 +1,139 @@
+#!/usr/bin/env python
+#
+# Copyright 2011 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.
+#
+"""
+This module contains functions for aligning sequences.
+
+>>> import random
+>>> random.seed(1234)
+>>> ran_seq = [random.randint(0,1) for i in range(0, 100)]
+>>> offset_seq = [0] * 20 + ran_seq
+>>> correct, overlap, offset = align_sequences(ran_seq, offset_seq)
+>>> print(correct, overlap, offset)
+(1.0, 100, -20)
+>>> offset_err_seq = []
+>>> for bit in offset_seq:
+... if random.randint(0,4) == 4:
+... offset_err_seq.append(random.randint(0,1))
+... else:
+... offset_err_seq.append(bit)
+>>> correct, overlap, offset = align_sequences(ran_seq, offset_err_seq)
+>>> print(overlap, offset)
+(100, -20)
+
+"""
+
+import random
+
+# DEFAULT PARAMETERS
+# If the fraction of matching bits between two sequences is greater than
+# this the sequences are assumed to be aligned.
+def_correct_cutoff = 0.9
+# The maximum offset to test during sequence alignment.
+def_max_offset = 500
+# The maximum number of samples to take from two sequences to check alignment.
+def_num_samples = 1000
+
+def compare_sequences(d1, d2, offset, sample_indices=None):
+ """
+ Takes two binary sequences and an offset and returns the number of
+ matching entries and the number of compared entries.
+ d1 & d2 -- sequences
+ offset -- offset of d2 relative to d1
+ sample_indices -- a list of indices to use for the comparison
+ """
+ max_index = min(len(d1), len(d2)+offset)
+ if sample_indices is None:
+ sample_indices = range(0, max_index)
+ correct = 0
+ total = 0
+ for i in sample_indices:
+ if i >= max_index:
+ break
+ if d1[i] == d2[i-offset]:
+ correct += 1
+ total += 1
+ return (correct, total)
+
+def random_sample(size, num_samples=def_num_samples, seed=None):
+ """
+ Returns a set of random integers between 0 and (size-1).
+ The set contains no more than num_samples integers.
+ """
+ random.seed(seed)
+ if num_samples > size:
+ indices = set(range(0, size))
+ else:
+ if num_samples > size/2:
+ num_samples = num_samples/2
+ indices = set([])
+ while len(indices) < num_samples:
+ index = random.randint(0, size-1)
+ indices.add(index)
+ indices = list(indices)
+ indices.sort()
+ return indices
+
+def align_sequences(d1, d2,
+ num_samples=def_num_samples,
+ max_offset=def_max_offset,
+ correct_cutoff=def_correct_cutoff,
+ seed=None,
+ indices=None):
+ """
+ Takes two sequences and finds the offset and which the two sequences best
+ match. It returns the fraction correct, the number of entries compared,
+ the offset.
+ d1 & d2 -- sequences to compare
+ num_samples -- the maximum number of entries to compare
+ max_offset -- the maximum offset between the sequences that is checked
+ correct_cutoff -- If the fraction of bits correct is greater than this then
+ the offset is assumed to optimum.
+ seed -- a random number seed
+ indices -- an explicit list of the indices used to compare the two sequences
+ """
+ max_overlap = max(len(d1), len(d2))
+ if indices is None:
+ indices = random_sample(max_overlap, num_samples, seed)
+ max_frac_correct = 0
+ best_offset = None
+ best_compared = None
+ best_correct = None
+ pos_range = range(0, min(len(d1), max_offset))
+ neg_range = range(-1, -min(len(d2), max_offset), -1)
+ # Interleave the positive and negative offsets.
+ int_range = [item for items in zip(pos_range, neg_range) for item in items]
+ for offset in int_range:
+ correct, compared = compare_sequences(d1, d2, offset, indices)
+ frac_correct = 1.0*correct/compared
+ if frac_correct > max_frac_correct:
+ max_frac_correct = frac_correct
+ best_offset = offset
+ best_compared = compared
+ best_correct = correct
+ if frac_correct > correct_cutoff:
+ break
+ return max_frac_correct, best_compared, best_offset, indices
+
+if __name__ == "__main__":
+ import doctest
+ doctest.testmod()
+
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..70cb9d7e2
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/utils/gray_code.py
@@ -0,0 +1,45 @@
+
+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
+
diff --git a/gnuradio-core/src/python/gnuradio/utils/mod_codes.py b/gnuradio-core/src/python/gnuradio/utils/mod_codes.py
new file mode 100644
index 000000000..db3dc252d
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/utils/mod_codes.py
@@ -0,0 +1,11 @@
+GRAY_CODE = 'gray'
+SET_PARTITION_CODE = 'set-partition'
+NO_CODE = 'none'
+
+codes = (GRAY_CODE, SET_PARTITION_CODE, NO_CODE)
+
+def invert_code(code):
+ c = enumerate(code)
+ ic = [(b, a) for (a, b) in c]
+ ic.sort()
+ return [a for (b, a) in ic]
diff --git a/gnuradio-core/src/python/gnuradio/utils/run_tests.in b/gnuradio-core/src/python/gnuradio/utils/run_tests.in
new file mode 100644
index 000000000..504f33728
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/utils/run_tests.in
@@ -0,0 +1,16 @@
+#!/bin/sh
+
+# 1st parameter is absolute path to component source directory
+# 2nd parameter is absolute path to component build directory
+# 3rd parameter is path to Python QA directory
+
+# Note: calling master run_tests.sh in gnuradio core is not strictly
+# correct, as it will result in a partially bogus PYTHONPATH, but it
+# does make the correct paths in the second half so all is well.
+
+@PYTHON@ @srcdir@/doxyxml/__init__.py
+
+# @top_builddir@/run_tests.sh \
+# @abs_top_srcdir@/gnuradio-core \
+# @abs_top_builddir@/gnuradio-core \
+# @srcdir@