summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.swig1
-rw-r--r--Makefile.swig.gen.t2
-rw-r--r--config/grc_gnuradio_core.m46
-rw-r--r--gnuradio-core/src/lib/filter/gr_pfb_clock_sync_ccf.h4
-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.h (renamed from gr-trellis/src/lib/trellis_metric_type.h)4
-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/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.py289
-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.py203
-rw-r--r--gnuradio-core/src/python/gnuradio/gr/qa_constellation_receiver.py132
-rw-r--r--gnuradio-core/src/python/gnuradio/gr_xmlrunner.py12
-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__.py21
-rw-r--r--gnuradio-core/src/python/gnuradio/utils/alignment.py139
-rw-r--r--gnuradio-core/src/python/gnuradio/utils/gray_code.py66
-rw-r--r--gnuradio-core/src/python/gnuradio/utils/mod_codes.py33
-rw-r--r--gnuradio-core/src/python/gnuradio/utils/run_tests.in11
-rwxr-xr-xgnuradio-examples/python/digital/benchmark_qt_loopback2.py25
-rw-r--r--gnuradio-examples/python/digital/simple.py64
-rw-r--r--gnuradio-examples/python/digital/simple_qam.py76
-rw-r--r--gr-atsc/src/lib/Makefile.swig.gen2
-rw-r--r--gr-cvsd-vocoder/src/lib/Makefile.swig.gen2
-rw-r--r--gr-gsm-fr-vocoder/src/lib/Makefile.swig.gen2
-rw-r--r--gr-msdd6000/src/Makefile.swig.gen4
-rw-r--r--gr-noaa/swig/Makefile.swig.gen2
-rw-r--r--gr-pager/swig/Makefile.swig.gen2
-rw-r--r--gr-qtgui/src/lib/Makefile.swig.gen2
-rw-r--r--gr-radio-astronomy/src/lib/Makefile.swig.gen2
-rw-r--r--gr-trellis/src/lib/Makefile.am4
-rw-r--r--gr-trellis/src/lib/Makefile.swig.gen2
-rw-r--r--gr-trellis/src/lib/fsm.cc2
-rw-r--r--gr-trellis/src/lib/fsm.h102
-rw-r--r--gr-trellis/src/lib/trellis.i12
-rw-r--r--gr-trellis/src/lib/trellis_calc_metric.h2
-rw-r--r--gr-trellis/src/lib/trellis_constellation_metrics_cf.cc92
-rw-r--r--gr-trellis/src/lib/trellis_constellation_metrics_cf.h61
-rw-r--r--gr-trellis/src/lib/trellis_constellation_metrics_cf.i33
-rwxr-xr-xgr-trellis/src/python/qa_trellis.py119
-rw-r--r--gr-usrp/src/Makefile.swig.gen2
-rw-r--r--gr-usrp2/src/Makefile.swig.gen2
-rw-r--r--gr-video-sdl/src/Makefile.swig.gen2
-rw-r--r--usrp/host/swig/Makefile.swig.gen2
70 files changed, 4105 insertions, 1051 deletions
diff --git a/Makefile.swig b/Makefile.swig
index 2ed69c6c7..87e918c35 100644
--- a/Makefile.swig
+++ b/Makefile.swig
@@ -169,6 +169,7 @@ gnuradio/%.scm : %.i
## Rule that (re)generates Makefile.swig.gen using TOP_SWIG_IFILES and
## Makefile.swig.gen.t
##
+
## Create $(srcdir)/Makefile.swig.gen, containing all of the rules
## for running SWIG to generate or re-generate outputs. SWIG file
## names are to be defined in TOP_SWIG_IFILES, and must include the
diff --git a/Makefile.swig.gen.t b/Makefile.swig.gen.t
index 4d37e0e21..0410413ed 100644
--- a/Makefile.swig.gen.t
+++ b/Makefile.swig.gen.t
@@ -105,7 +105,7 @@ _@NAME@_la_CXXFLAGS = \
$(@NAME@_la_swig_cxxflags)
python/@NAME@.cc: @NAME@.py
-@NAME@.py: @NAME@.i
+@NAME@.py: @NAME@.i
# Include the python dependencies for this file
-include python/@NAME@.d
diff --git a/config/grc_gnuradio_core.m4 b/config/grc_gnuradio_core.m4
index 15086be0f..7cb25cfe4 100644
--- a/config/grc_gnuradio_core.m4
+++ b/config/grc_gnuradio_core.m4
@@ -107,6 +107,8 @@ AC_DEFUN([GRC_GNURADIO_CORE],[
gnuradio-core/src/python/gnuradio/gru/Makefile \
gnuradio-core/src/python/gnuradio/gruimpl/Makefile \
gnuradio-core/src/python/gnuradio/vocoder/Makefile \
+ gnuradio-core/src/python/gnuradio/utils/run_tests \
+ gnuradio-core/src/python/gnuradio/utils/Makefile \
gnuradio-core/src/tests/Makefile \
gnuradio-core/src/utils/Makefile \
])
@@ -117,6 +119,8 @@ AC_DEFUN([GRC_GNURADIO_CORE],[
[
chmod +x gnuradio-core/src/python/gnuradio/gr/run_tests
chmod +x gnuradio-core/src/guile/run_guile_tests
- ])
+ ]) \
+ AC_CONFIG_COMMANDS([run_tests_utils],[chmod +x gnuradio-core/src/python/gnuradio/utils/run_tests])
])
+
])
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 684ac85ce..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
@@ -85,7 +85,7 @@ class gr_fir_ccf;
* equal to (gain^2)/4.
*
* The clock sync block needs to know the number of samples per symbol (sps), because it
- * only returns a single point representing the sample. The sps can be any positive real
+ * 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
diff --git a/gnuradio-core/src/lib/general/Makefile.am b/gnuradio-core/src/lib/general/Makefile.am
index 2a7a4b025..3b8997d8c 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 \
@@ -213,7 +217,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 \
@@ -262,8 +269,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 \
@@ -274,6 +281,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 \
@@ -388,7 +396,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 \
@@ -430,7 +441,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 \
@@ -440,6 +450,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 e8a18ab19..d9648ef64 100644
--- a/gnuradio-core/src/lib/general/general.i
+++ b/gnuradio-core/src/lib/general/general.i
@@ -70,6 +70,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>
@@ -98,6 +100,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>
@@ -112,6 +115,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>
@@ -196,6 +200,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"
@@ -224,6 +230,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"
@@ -238,6 +245,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..eede99ffd
--- /dev/null
+++ b/gnuradio-core/src/lib/general/gr_constellation.cc
@@ -0,0 +1,368 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2010, 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.
+ */
+
+#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..f6726a9b5
--- /dev/null
+++ b/gnuradio-core/src/lib/general/gr_constellation.h
@@ -0,0 +1,322 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2010, 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_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..179e68136
--- /dev/null
+++ b/gnuradio-core/src/lib/general/gr_constellation.i
@@ -0,0 +1,146 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2010, 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.
+ */
+
+%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..c1b56f44f
--- /dev/null
+++ b/gnuradio-core/src/lib/general/gr_constellation_receiver_cb.cc
@@ -0,0 +1,131 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2005,2006,2007,2010,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_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..80ffcc873
--- /dev/null
+++ b/gnuradio-core/src/lib/general/gr_constellation_receiver_cb.h
@@ -0,0 +1,149 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2004,2007,2010,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_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..f4df49701
--- /dev/null
+++ b/gnuradio-core/src/lib/general/gr_constellation_receiver_cb.i
@@ -0,0 +1,43 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2004,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_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/gr-trellis/src/lib/trellis_metric_type.h b/gnuradio-core/src/lib/general/gr_metric_type.h
index a1040f108..74c93b55e 100644
--- a/gr-trellis/src/lib/trellis_metric_type.h
+++ b/gnuradio-core/src/lib/general/gr_metric_type.h
@@ -20,8 +20,8 @@
* Boston, MA 02110-1301, USA.
*/
-#ifndef INCLUDED_TRELLIS_METRIC_TYPE_H
-#define INCLUDED_TRELLIS_METRIC_TYPE_H
+#ifndef INCLUDED_GR_METRIC_TYPE_H
+#define INCLUDED_GR_METRIC_TYPE_H
typedef enum {
TRELLIS_EUCLIDEAN = 200, TRELLIS_HARD_SYMBOL, TRELLIS_HARD_BIT
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..40574b4e9
--- /dev/null
+++ b/gnuradio-core/src/lib/general/gr_ofdm_frame_sink2.cc
@@ -0,0 +1,374 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2007,2008,2010,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_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..de8c6a37e
--- /dev/null
+++ b/gnuradio-core/src/lib/general/gr_ofdm_frame_sink2.h
@@ -0,0 +1,120 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2007,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_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..8fa320089
--- /dev/null
+++ b/gnuradio-core/src/lib/general/gr_ofdm_frame_sink2.i
@@ -0,0 +1,39 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2007,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,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/python/gnuradio/Makefile.am b/gnuradio-core/src/python/gnuradio/Makefile.am
index eff35e95c..1bec7dd19 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..16524de94
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/blks2impl/bpsk.py
@@ -0,0 +1,98 @@
+#
+# Copyright 2005,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.
+#
+
+"""
+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..44779754b
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/blks2impl/generic_mod_demod.py
@@ -0,0 +1,395 @@
+#
+# Copyright 2005,2006,2007,2009,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.
+#
+
+# 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..aaa9659a4
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/blks2impl/psk2.py
@@ -0,0 +1,121 @@
+#
+# Copyright 2005,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.
+#
+
+"""
+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..9c135b25a 100644
--- a/gnuradio-core/src/python/gnuradio/blks2impl/qam.py
+++ b/gnuradio-core/src/python/gnuradio/blks2impl/qam.py
@@ -1,5 +1,5 @@
#
-# Copyright 2005,2006 Free Software Foundation, Inc.
+# Copyright 2005,2006,2011 Free Software Foundation, Inc.
#
# This file is part of GNU Radio
#
@@ -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..4af8d0018
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/blks2impl/qpsk.py
@@ -0,0 +1,79 @@
+#
+# Copyright 2005,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.
+#
+
+"""
+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 f1b4ba2b1..78480b412 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..5c3c04160
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/gr/qa_constellation.py
@@ -0,0 +1,203 @@
+#!/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 cmath import exp, pi, log
+
+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 in r4:
+ for ib in r4:
+ for ic in 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..544c84cd4
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/gr/qa_constellation_receiver.py
@@ -0,0 +1,132 @@
+#!/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)
+ self.assertTrue(correct > REQ_CORRECT)
+
+
+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,
+ 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/gr_xmlrunner.py b/gnuradio-core/src/python/gnuradio/gr_xmlrunner.py
index ded77f5f3..c3dc5cf13 100644
--- a/gnuradio-core/src/python/gnuradio/gr_xmlrunner.py
+++ b/gnuradio-core/src/python/gnuradio/gr_xmlrunner.py
@@ -6,8 +6,6 @@ XML Test Runner for PyUnit
# the Public Domain. With contributions by Paolo Borelli and others.
# Added to GNU Radio Oct. 3, 2010
-from __future__ import with_statement
-
__version__ = "0.1"
import os.path
@@ -185,7 +183,9 @@ class XMLTestRunner(object):
result = _XMLTestResult(classname)
start_time = time.time()
- with _fake_std_streams():
+ fss = _fake_std_streams()
+ fss.__enter__()
+ try:
test(result)
try:
out_s = sys.stdout.getvalue()
@@ -195,6 +195,8 @@ class XMLTestRunner(object):
err_s = sys.stderr.getvalue()
except AttributeError:
err_s = ""
+ finally:
+ fss.__exit__(None, None, None)
time_taken = time.time() - start_time
result.print_report(stream, time_taken, out_s, err_s)
@@ -218,8 +220,8 @@ class _fake_std_streams(object):
def __enter__(self):
self._orig_stdout = sys.stdout
self._orig_stderr = sys.stderr
- sys.stdout = StringIO()
- sys.stderr = StringIO()
+ #sys.stdout = StringIO()
+ #sys.stderr = StringIO()
def __exit__(self, exc_type, exc_val, exc_tb):
sys.stdout = self._orig_stdout
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..b3e997f9f
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/utils/__init__.py
@@ -0,0 +1,21 @@
+#!/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.
+#
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..926a1ded1
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/utils/gray_code.py
@@ -0,0 +1,66 @@
+#!/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.
+#
+
+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..caacda5cc
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/utils/mod_codes.py
@@ -0,0 +1,33 @@
+#!/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.
+#
+
+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..adcbdfd21
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/utils/run_tests.in
@@ -0,0 +1,11 @@
+#!/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.
+
+# Nothing in here at the moment.
diff --git a/gnuradio-examples/python/digital/benchmark_qt_loopback2.py b/gnuradio-examples/python/digital/benchmark_qt_loopback2.py
index 02ae4b25f..a36f4fbd4 100755
--- a/gnuradio-examples/python/digital/benchmark_qt_loopback2.py
+++ b/gnuradio-examples/python/digital/benchmark_qt_loopback2.py
@@ -20,11 +20,11 @@
# Boston, MA 02110-1301, USA.
#
-from gnuradio import gr, gru, modulation_utils2
+from gnuradio import gr, modulation_utils2
from gnuradio import eng_notation
from gnuradio.eng_option import eng_option
from optparse import OptionParser
-import random, time, struct, sys, os, math
+import struct, sys, math
from threading import Thread
@@ -319,6 +319,13 @@ class my_top_block(gr.top_block):
# Connect components
self.connect(self.txpath, self.throttle, self.rxpath)
+ if options.verbose:
+ self._print_verbage()
+
+ if options.log:
+ self._setup_logging()
+
+
# System Parameters
@@ -396,6 +403,15 @@ class my_top_block(gr.top_block):
self.rxpath.packet_receiver._demodulator.freq_recov.set_beta(self._gain_freq/10.0)
#self.rxpath.packet_receiver._demodulator.freq_recov.set_beta(self._gain_fre_beta)
+ def _print_verbage(self):
+ print "\nChannel:"
+ print "SNR: %d" % self.snr()
+ print "Noise voltage: %.2e" % self.get_noise_voltage(self.snr())
+ print "Frequency offset: %.2e" % self.frequency_offset()
+ print "Timing offset: %.2e" % self.timing_offset()
+
+ def _setup_logging(self):
+ pass
# /////////////////////////////////////////////////////////////////////////////
# Thread to handle the packet sending procedure
@@ -466,7 +482,7 @@ def main():
channel_grp = parser.add_option_group("Channel")
parser.add_option("-m", "--modulation", type="choice", choices=mods.keys(),
- default='dbpsk2',
+ default='psk',
help="Select modulation from: %s [default=%%default]"
% (', '.join(mods.keys()),))
@@ -512,6 +528,7 @@ def main():
tb = my_top_block(mods[options.modulation],
demods[options.modulation],
rx_callback, options)
+
tb.start()
packet_sender = th_send(send_pkt, options.megabytes, options.size)
@@ -527,7 +544,7 @@ def main():
packet_sender.join(1)
except KeyboardInterrupt:
packet_sender.stop()
-
+
if __name__ == '__main__':
try:
diff --git a/gnuradio-examples/python/digital/simple.py b/gnuradio-examples/python/digital/simple.py
new file mode 100644
index 000000000..6d340db36
--- /dev/null
+++ b/gnuradio-examples/python/digital/simple.py
@@ -0,0 +1,64 @@
+
+from gnuradio import gr, blks2, packet_utils
+
+# Some constants
+TX_AMPLITUDE = 0.25
+SAMPLE_RATE = 1e5
+# NOISE_VOLTAGE = 0.01
+NOISE_VOLTAGE = 0.01
+# FREQUENCY_OFFSET = 0
+FREQUENCY_OFFSET = 0.01
+TIMING_OFFSET = 1.0
+SAMPLES_PER_SYMBOL = 2
+GAIN = 1.0
+SW_DECIM = 1
+BAND_MIDPOINT = 1.0
+BAND_WIDTH = 0.5
+
+# Modulation/Demodulation methods
+modulator = blks2.dbpsk2_mod()
+demodulator = blks2.dbpsk2_demod()
+
+#Transmission Blocks
+packet_transmitter = blks2.mod_pkts(modulator, access_code=None, msgq_limit=4,
+ pad_for_usrp=True)
+amp = gr.multiply_const_cc(TX_AMPLITUDE)
+throttle = gr.throttle(gr.sizeof_gr_complex, SAMPLE_RATE)
+# Channel
+channel = gr.channel_model(NOISE_VOLTAGE, FREQUENCY_OFFSET, TIMING_OFFSET)
+# Receiver Blocks
+chan_coeffs = gr.firdes.low_pass(GAIN, SW_DECIM * SAMPLES_PER_SYMBOL,
+ BAND_MIDPOINT, BAND_WIDTH, gr.firdes.WIN_HANN)
+channel_filter = gr.fft_filter_ccc(SW_DECIM, chan_coeffs)
+packet_receiver = blks2.demod_pkts(demodulator, access_code=None, callback=None,
+ threshold=-1)
+# Put it all together and start it up (although nothing will be done
+# until we send some packets).
+tb = gr.top_block()
+tb.connect(packet_transmitter, amp, throttle, channel, channel_filter,
+ packet_receiver)
+tb.start()
+
+# The queue into which recieved packets are placed
+pkq = packet_receiver._rcvd_pktq
+
+# The function to create a packet and place it in a queue to be sent.
+sender = packet_transmitter.send_pkt
+
+# Some some packets (The second will not be recieved because it gets cut off
+# before it can finish. I think this occurs during modulation.)
+sender('hello there I wonder how long this needs to be before I start to see any errors.')
+sender('world')
+sender(eof=True)
+
+# Wait for all the packets to get sent and received.
+tb.wait()
+
+# Check how many messages have been received and print them.
+cnt = pkq.count()
+print('There are %s messages' % cnt)
+for a in range(0, cnt):
+ msg = pkq.delete_head()
+ ok, payload = packet_utils.unmake_packet(msg.to_string(), int(msg.arg1()))
+ print("Message %s is %s" % (a, payload))
+
diff --git a/gnuradio-examples/python/digital/simple_qam.py b/gnuradio-examples/python/digital/simple_qam.py
new file mode 100644
index 000000000..947d7faad
--- /dev/null
+++ b/gnuradio-examples/python/digital/simple_qam.py
@@ -0,0 +1,76 @@
+
+from gnuradio import gr, blks2, packet_utils
+
+# Some constants
+NOISE_VOLTAGE = 0.1
+FREQUENCY_OFFSET = 0.0000
+TIMING_OFFSET = 1.0
+SAMPLES_PER_SYMBOL = 2
+GAIN = 1.0
+SW_DECIM = 1
+BAND_MIDPOINT = 1.0
+BAND_WIDTH = 0.5
+FREQ_ALPHA = 0.005
+EXCESS_BW = 0.35
+
+# Modulation/Demodulation methods
+modulator = blks2.qam_mod(16, SAMPLES_PER_SYMBOL)
+demodulator = blks2.qam_demod(16, SAMPLES_PER_SYMBOL, freq_alpha=FREQ_ALPHA)
+
+#Transmission Blocks
+packet_transmitter = blks2.mod_pkts(modulator, access_code=None, msgq_limit=4,
+ pad_for_usrp=True)
+# Channel
+channel = gr.channel_model(NOISE_VOLTAGE, FREQUENCY_OFFSET, TIMING_OFFSET)
+# Receiver Blocks
+chan_coeffs = gr.firdes.low_pass(GAIN, SW_DECIM * SAMPLES_PER_SYMBOL,
+ BAND_MIDPOINT, BAND_WIDTH, gr.firdes.WIN_HANN)
+channel_filter = gr.fft_filter_ccc(SW_DECIM, chan_coeffs)
+packet_receiver = blks2.demod_pkts(demodulator, access_code=None, callback=None,
+ threshold=-1)
+# Put it all together and start it up (although nothing will be done
+# until we send some packets).
+tb = gr.top_block()
+tb.connect(packet_transmitter, channel, channel_filter,
+ packet_receiver)
+tb.start()
+
+# The queue into which recieved packets are placed
+pkq = packet_receiver._rcvd_pktq
+
+# The function to create a packet and place it in a queue to be sent.
+sender = packet_transmitter.send_pkt
+
+# Some some packets (The second will not be recieved because it gets cut off
+# before it can finish. I think this occurs during modulation.)
+
+# Send some large messages to start off with to let things lock.
+for i in range(0, int(20.0/SAMPLES_PER_SYMBOL)):
+ sender('a'*4000)
+
+sender('hello1')
+sender('hello2')
+sender('hello3')
+sender('hello4')
+sender('hello5')
+sender('hello6')
+sender('hello7')
+sender('hello8')
+sender('hello9')
+sender('hello10')
+sender('hello11')
+sender('hello12')
+sender('world')
+sender(eof=True)
+
+# Wait for all the packets to get sent and received.
+tb.wait()
+
+# Check how many messages have been received and print them.
+cnt = pkq.count()
+print('There are %s messages' % cnt)
+for a in range(0, cnt):
+ msg = pkq.delete_head()
+ ok, payload = packet_utils.unmake_packet(msg.to_string(), int(msg.arg1()))
+ print("Message %s is %s" % (a, payload))
+
diff --git a/gr-atsc/src/lib/Makefile.swig.gen b/gr-atsc/src/lib/Makefile.swig.gen
index 7dbb98b46..67f9c094a 100644
--- a/gr-atsc/src/lib/Makefile.swig.gen
+++ b/gr-atsc/src/lib/Makefile.swig.gen
@@ -105,7 +105,7 @@ _atsc_la_CXXFLAGS = \
$(atsc_la_swig_cxxflags)
python/atsc.cc: atsc.py
-atsc.py: atsc.i
+atsc.py: atsc.i
# Include the python dependencies for this file
-include python/atsc.d
diff --git a/gr-cvsd-vocoder/src/lib/Makefile.swig.gen b/gr-cvsd-vocoder/src/lib/Makefile.swig.gen
index e23427a0f..8e22f0a98 100644
--- a/gr-cvsd-vocoder/src/lib/Makefile.swig.gen
+++ b/gr-cvsd-vocoder/src/lib/Makefile.swig.gen
@@ -105,7 +105,7 @@ _cvsd_vocoder_la_CXXFLAGS = \
$(cvsd_vocoder_la_swig_cxxflags)
python/cvsd_vocoder.cc: cvsd_vocoder.py
-cvsd_vocoder.py: cvsd_vocoder.i
+cvsd_vocoder.py: cvsd_vocoder.i
# Include the python dependencies for this file
-include python/cvsd_vocoder.d
diff --git a/gr-gsm-fr-vocoder/src/lib/Makefile.swig.gen b/gr-gsm-fr-vocoder/src/lib/Makefile.swig.gen
index 77776abd8..174ef046d 100644
--- a/gr-gsm-fr-vocoder/src/lib/Makefile.swig.gen
+++ b/gr-gsm-fr-vocoder/src/lib/Makefile.swig.gen
@@ -105,7 +105,7 @@ _gsm_full_rate_la_CXXFLAGS = \
$(gsm_full_rate_la_swig_cxxflags)
python/gsm_full_rate.cc: gsm_full_rate.py
-gsm_full_rate.py: gsm_full_rate.i
+gsm_full_rate.py: gsm_full_rate.i
# Include the python dependencies for this file
-include python/gsm_full_rate.d
diff --git a/gr-msdd6000/src/Makefile.swig.gen b/gr-msdd6000/src/Makefile.swig.gen
index dbf137334..255e11b29 100644
--- a/gr-msdd6000/src/Makefile.swig.gen
+++ b/gr-msdd6000/src/Makefile.swig.gen
@@ -105,7 +105,7 @@ _msdd_la_CXXFLAGS = \
$(msdd_la_swig_cxxflags)
python/msdd.cc: msdd.py
-msdd.py: msdd.i
+msdd.py: msdd.i
# Include the python dependencies for this file
-include python/msdd.d
@@ -250,7 +250,7 @@ _msdd_rs_la_CXXFLAGS = \
$(msdd_rs_la_swig_cxxflags)
python/msdd_rs.cc: msdd_rs.py
-msdd_rs.py: msdd_rs.i
+msdd_rs.py: msdd_rs.i
# Include the python dependencies for this file
-include python/msdd_rs.d
diff --git a/gr-noaa/swig/Makefile.swig.gen b/gr-noaa/swig/Makefile.swig.gen
index f5e778811..757c368f5 100644
--- a/gr-noaa/swig/Makefile.swig.gen
+++ b/gr-noaa/swig/Makefile.swig.gen
@@ -105,7 +105,7 @@ _noaa_swig_la_CXXFLAGS = \
$(noaa_swig_la_swig_cxxflags)
python/noaa_swig.cc: noaa_swig.py
-noaa_swig.py: noaa_swig.i
+noaa_swig.py: noaa_swig.i
# Include the python dependencies for this file
-include python/noaa_swig.d
diff --git a/gr-pager/swig/Makefile.swig.gen b/gr-pager/swig/Makefile.swig.gen
index 70d215384..9f7467c1c 100644
--- a/gr-pager/swig/Makefile.swig.gen
+++ b/gr-pager/swig/Makefile.swig.gen
@@ -105,7 +105,7 @@ _pager_swig_la_CXXFLAGS = \
$(pager_swig_la_swig_cxxflags)
python/pager_swig.cc: pager_swig.py
-pager_swig.py: pager_swig.i
+pager_swig.py: pager_swig.i
# Include the python dependencies for this file
-include python/pager_swig.d
diff --git a/gr-qtgui/src/lib/Makefile.swig.gen b/gr-qtgui/src/lib/Makefile.swig.gen
index 9c4c0b58c..b7a0f3c07 100644
--- a/gr-qtgui/src/lib/Makefile.swig.gen
+++ b/gr-qtgui/src/lib/Makefile.swig.gen
@@ -105,7 +105,7 @@ _qtgui_la_CXXFLAGS = \
$(qtgui_la_swig_cxxflags)
python/qtgui.cc: qtgui.py
-qtgui.py: qtgui.i
+qtgui.py: qtgui.i
# Include the python dependencies for this file
-include python/qtgui.d
diff --git a/gr-radio-astronomy/src/lib/Makefile.swig.gen b/gr-radio-astronomy/src/lib/Makefile.swig.gen
index d560e3919..faad880cf 100644
--- a/gr-radio-astronomy/src/lib/Makefile.swig.gen
+++ b/gr-radio-astronomy/src/lib/Makefile.swig.gen
@@ -105,7 +105,7 @@ _ra_la_CXXFLAGS = \
$(ra_la_swig_cxxflags)
python/ra.cc: ra.py
-ra.py: ra.i
+ra.py: ra.i
# Include the python dependencies for this file
-include python/ra.d
diff --git a/gr-trellis/src/lib/Makefile.am b/gr-trellis/src/lib/Makefile.am
index 08e75291a..d6926f2a0 100644
--- a/gr-trellis/src/lib/Makefile.am
+++ b/gr-trellis/src/lib/Makefile.am
@@ -66,12 +66,12 @@ grinclude_HEADERS = \
quicksort_index.h \
base.h \
interleaver.h \
- trellis_metric_type.h \
trellis_calc_metric.h \
trellis_permutation.h \
trellis_siso_type.h \
trellis_siso_f.h \
trellis_siso_combined_f.h \
+ trellis_constellation_metrics_cf.h \
$(GENERATED_H)
lib_LTLIBRARIES = libgnuradio-trellis.la
@@ -85,6 +85,7 @@ libgnuradio_trellis_la_SOURCES = \
trellis_permutation.cc \
trellis_siso_f.cc \
trellis_siso_combined_f.cc \
+ trellis_constellation_metrics_cf.cc \
$(GENERATED_CC)
libgnuradio_trellis_la_LIBADD = \
@@ -119,6 +120,7 @@ trellis_swiginclude_headers = \
trellis_permutation.i \
trellis_siso_f.i \
trellis_siso_combined_f.i \
+ trellis_constellation_metrics_cf.i \
trellis_generated.i
# Do creation and inclusion of other Makefiles last
diff --git a/gr-trellis/src/lib/Makefile.swig.gen b/gr-trellis/src/lib/Makefile.swig.gen
index 784c146cf..2d014b946 100644
--- a/gr-trellis/src/lib/Makefile.swig.gen
+++ b/gr-trellis/src/lib/Makefile.swig.gen
@@ -105,7 +105,7 @@ _trellis_la_CXXFLAGS = \
$(trellis_la_swig_cxxflags)
python/trellis.cc: trellis.py
-trellis.py: trellis.i
+trellis.py: trellis.i
# Include the python dependencies for this file
-include python/trellis.d
diff --git a/gr-trellis/src/lib/fsm.cc b/gr-trellis/src/lib/fsm.cc
index 5950b56b9..889a3918b 100644
--- a/gr-trellis/src/lib/fsm.cc
+++ b/gr-trellis/src/lib/fsm.cc
@@ -417,7 +417,7 @@ void fsm::generate_TM()
done = find_es(s);
attempts ++;
}
- if (done == false) {
+ if (done == false and d_S > 1) {
//throw std::runtime_error ("fsm::generate_TM(): FSM appears to be disconnected\n");
printf("fsm::generate_TM(): FSM appears to be disconnected\n");
printf("state %d cannot be reached from all other states\n",s);
diff --git a/gr-trellis/src/lib/fsm.h b/gr-trellis/src/lib/fsm.h
index 0a90b2cd3..8bae91754 100644
--- a/gr-trellis/src/lib/fsm.h
+++ b/gr-trellis/src/lib/fsm.h
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2002 Free Software Foundation, Inc.
+ * Copyright 2002,2011 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
@@ -27,31 +27,114 @@
#include <iosfwd>
/*!
- * \brief FSM class
+ * \brief Finite State Machine Specification class.
+ *
+ * An instance of this class represents a finite state machine specification (FSMS)
+ * rather than the FSM itself. It particular the state of the FSM
+ * is not stored within an instance of this class.
*/
class fsm {
private:
+ // Input alphabet cardinality.
int d_I;
+ // Number of states.
int d_S;
+ // Output alphabet cardinality.
int d_O;
+ // NS means Next State.
+ // next_state = d_NS[current_state * d_I + input_symbol]
std::vector<int> d_NS;
+ // OS means Output Symbol.
+ // output_symbol = d_OS[current_state * d_I + input_symbol]
std::vector<int> d_OS;
+ // PS means Previous State.
std::vector< std::vector<int> > d_PS;
+ // PI means Previous Input Symbol.
+ // d_PS[current_state][k] and d_PI[current_state][k], is a pair of the form
+ // (previous_state, previous_input_symbol) that could have produced the
+ // current state.
std::vector< std::vector<int> > d_PI;
- std::vector<int> d_TMi;
+ // TM means Termination matrix.
+ // d_TMl[s*d_S+es] is the shortest number of steps to get from state s to
+ // state es.
std::vector<int> d_TMl;
+ // d_TMi[s*d_S+es] is the input symbol required to set off on the shortest
+ // path from state s to es.
+ std::vector<int> d_TMi;
void generate_PS_PI ();
void generate_TM ();
bool find_es(int es);
public:
+ /*!
+ * \brief Constructor to create an uninitialized FSMS.
+ */
fsm();
+ /*!
+ * \brief Constructor to copy an FSMS.
+ */
fsm(const fsm &FSM);
+ /*!
+ * \brief Constructor to to create an FSMS.
+ *
+ * \param I The number of possible input symbols.
+ * \param S The number of possible FSM states.
+ * \param O The number of possible output symbols.
+ * \param NS A mapping from (current state, input symbol) to next state.
+ * next_state = NS[current_state * I + input_symbol]
+ * \param OS A mapping from (current state, input symbol) to output symbol.
+ * output_symbol = OS[current_state * I + input_symbol]
+ *
+ */
fsm(int I, int S, int O, const std::vector<int> &NS, const std::vector<int> &OS);
+ /*!
+ * \brief Constructor to create an FSMS from file contents.
+ *
+ * \param name filename
+ *
+ */
fsm(const char *name);
+ /*!
+ * \brief Creates an FSMS from the generator matrix of a (n, k) binary convolutional code.
+ *
+ * \param k ???
+ * \param n ???
+ * \param G ???
+ *
+ */
fsm(int k, int n, const std::vector<int> &G);
+ /*!
+ * \brief Creates an FSMS describing ISI.
+ *
+ * \param mod_size modulation size
+ * \param ch_lenth channel length
+ *
+ */
fsm(int mod_size, int ch_length);
+ /*!
+ * \brief Creates an FSMS describing the trellis for a CPM.
+ *
+ * \param P ???? h=K/P (relatively prime)
+ * \param M alphabet size
+ * \param L pulse duration
+ *
+ * This FSM is based on the paper by B. Rimoldi
+ * "A decomposition approach to CPM", IEEE Trans. Info Theory, March 1988
+ * See also my own notes at http://www.eecs.umich.edu/~anastas/docs/cpm.pdf
+ */
fsm(int P, int M, int L);
+ /*!
+ * \brief Creates an FSMS describing the joint trellis of two FSMs.
+ *
+ * \param fsm1 first FSMS
+ * \param fsm2 second FSMS
+ */
fsm(const fsm &FSM1, const fsm &FSM2);
+ /*!
+ * \brief Creates an FSMS representing n stages through the originial FSM (AKA radix-n FSM).
+ *
+ * \param original FSMS
+ * \param n Number of stages.
+ */
fsm(const fsm &FSM, int n);
int I () const { return d_I; }
int S () const { return d_S; }
@@ -62,7 +145,20 @@ public:
const std::vector< std::vector<int> > & PI () const { return d_PI; }
const std::vector<int> & TMi () const { return d_TMi; }
const std::vector<int> & TMl () const { return d_TMl; }
+ /*!
+ * \brief Creates an svg image of the trellis representation.
+ *
+ * \param filename filename
+ * \param number_stages ????
+ *
+ */
void write_trellis_svg(std::string filename ,int number_stages);
+ /*!
+ * \brief Write the FSMS to a file.
+ *
+ * \param filename filename
+ *
+ */
void write_fsm_txt(std::string filename);
};
diff --git a/gr-trellis/src/lib/trellis.i b/gr-trellis/src/lib/trellis.i
index d035cea54..fe74c8d9f 100644
--- a/gr-trellis/src/lib/trellis.i
+++ b/gr-trellis/src/lib/trellis.i
@@ -28,8 +28,11 @@
#include "trellis_permutation.h"
#include "trellis_siso_f.h"
#include "trellis_siso_combined_f.h"
+#include "trellis_constellation_metrics_cf.h"
+#include "gr_constellation.h"
%}
+
// ----------------------------------------------------------------
%include "fsm.i"
@@ -38,12 +41,19 @@
%include "trellis_siso_f.i"
%include "trellis_siso_combined_f.i"
-%include "trellis_metric_type.h"
%include "trellis_siso_type.h"
+%include "trellis_constellation_metrics_cf.i"
%include "trellis_generated.i"
+%import "gr_metric_type.h"
+%import "gr_constellation.i"
+
+%pythoncode %{
+ from gnuradio.gr import TRELLIS_EUCLIDEAN, TRELLIS_HARD_SYMBOL, TRELLIS_HARD_BIT
+ %}
+
#if SWIGGUILE
%scheme %{
(load-extension-global "libguile-gnuradio-trellis" "scm_init_gnuradio_trellis_module")
diff --git a/gr-trellis/src/lib/trellis_calc_metric.h b/gr-trellis/src/lib/trellis_calc_metric.h
index fabf4e145..b9eacb086 100644
--- a/gr-trellis/src/lib/trellis_calc_metric.h
+++ b/gr-trellis/src/lib/trellis_calc_metric.h
@@ -25,7 +25,7 @@
#include <vector>
#include <gr_complex.h>
-#include <trellis_metric_type.h>
+#include <gr_metric_type.h>
template <class T>
diff --git a/gr-trellis/src/lib/trellis_constellation_metrics_cf.cc b/gr-trellis/src/lib/trellis_constellation_metrics_cf.cc
new file mode 100644
index 000000000..fb529aaa7
--- /dev/null
+++ b/gr-trellis/src/lib/trellis_constellation_metrics_cf.cc
@@ -0,0 +1,92 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2004,2010,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.
+ */
+
+// WARNING: this file is machine generated. Edits will be over written
+
+#ifndef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <trellis_constellation_metrics_cf.h>
+#include <gr_io_signature.h>
+#include <assert.h>
+#include <stdexcept>
+#include <iostream>
+
+
+
+trellis_constellation_metrics_cf_sptr
+trellis_make_constellation_metrics_cf (gr_constellation_sptr constellation, trellis_metric_type_t TYPE)
+{
+ return gnuradio::get_initial_sptr (new trellis_constellation_metrics_cf (constellation, TYPE));
+}
+
+
+
+trellis_constellation_metrics_cf::trellis_constellation_metrics_cf (gr_constellation_sptr constellation, trellis_metric_type_t TYPE)
+ : gr_block ("constellation_metrics_cf",
+ gr_make_io_signature (1, -1, sizeof (gr_complex)),
+ gr_make_io_signature (1, -1, sizeof (float))),
+ d_constellation (constellation),
+ d_TYPE (TYPE),
+ d_O (constellation->arity()),
+ d_D (constellation->dimensionality())
+{
+ set_relative_rate (1.0 * d_O / ((double) d_D));
+ set_output_multiple ((int)d_O);
+}
+
+void
+trellis_constellation_metrics_cf::forecast (int noutput_items, gr_vector_int &ninput_items_required)
+{
+ assert (noutput_items % d_O == 0);
+ unsigned int input_required = d_D * noutput_items / d_O;
+ unsigned int ninputs = ninput_items_required.size();
+ for (unsigned int i = 0; i < ninputs; i++)
+ ninput_items_required[i] = input_required;
+}
+
+
+
+int
+trellis_constellation_metrics_cf::general_work (int noutput_items,
+ gr_vector_int &ninput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items)
+{
+
+ assert (noutput_items % d_O == 0);
+ assert (input_items.size() == output_items.size());
+ unsigned int nstreams = input_items.size();
+
+for (unsigned int m=0;m<nstreams;m++) {
+ const gr_complex *in = (gr_complex *) input_items[m];
+ float *out = (float *) output_items[m];
+
+ for (unsigned int i = 0; i < noutput_items / d_O ; i++){
+ d_constellation->calc_metric(&(in[i*d_D]), &(out[i*d_O]), d_TYPE);
+ }
+}
+
+ consume_each (d_D * noutput_items / d_O);
+ return noutput_items;
+}
diff --git a/gr-trellis/src/lib/trellis_constellation_metrics_cf.h b/gr-trellis/src/lib/trellis_constellation_metrics_cf.h
new file mode 100644
index 000000000..df35f16d2
--- /dev/null
+++ b/gr-trellis/src/lib/trellis_constellation_metrics_cf.h
@@ -0,0 +1,61 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2004,2010,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_TRELLIS_CONSTELLATION_METRICS_CF_H
+#define INCLUDED_TRELLIS_CONSTELLATION_METRICS_CF_H
+
+#include <gr_block.h>
+#include <gr_constellation.h>
+#include <gr_metric_type.h>
+
+class trellis_constellation_metrics_cf;
+typedef boost::shared_ptr<trellis_constellation_metrics_cf> trellis_constellation_metrics_cf_sptr;
+
+trellis_constellation_metrics_cf_sptr trellis_make_constellation_metrics_cf (gr_constellation_sptr constellation, trellis_metric_type_t TYPE);
+
+/*!
+ * \brief Evaluate metrics for use by the Viterbi algorithm.
+ * \ingroup coding_blk
+ */
+class trellis_constellation_metrics_cf : public gr_block
+{
+ 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);
+ protected:
+ trellis_constellation_metrics_cf (gr_constellation_sptr constellation, trellis_metric_type_t TYPE);
+
+ private:
+ gr_constellation_sptr d_constellation;
+ trellis_metric_type_t d_TYPE;
+ unsigned int d_O;
+ unsigned int d_D;
+ friend trellis_constellation_metrics_cf_sptr trellis_make_constellation_metrics_cf (gr_constellation_sptr constellation, trellis_metric_type_t TYPE);
+
+};
+
+
+#endif
diff --git a/gr-trellis/src/lib/trellis_constellation_metrics_cf.i b/gr-trellis/src/lib/trellis_constellation_metrics_cf.i
new file mode 100644
index 000000000..f863453f2
--- /dev/null
+++ b/gr-trellis/src/lib/trellis_constellation_metrics_cf.i
@@ -0,0 +1,33 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2004,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.
+ */
+
+// WARNING: this file is machine generated. Edits will be over written
+
+GR_SWIG_BLOCK_MAGIC(trellis,constellation_metrics_cf);
+
+trellis_constellation_metrics_cf_sptr trellis_make_constellation_metrics_cf (gr_constellation_sptr constellation, trellis_metric_type_t TYPE);
+
+class trellis_constellation_metrics_cf : public gr_block
+{
+private:
+ trellis_constellation_metrics_cf (gr_constellation_sptr constellation, trellis_metric_type_t TYPE);
+};
diff --git a/gr-trellis/src/python/qa_trellis.py b/gr-trellis/src/python/qa_trellis.py
index cfeefea06..ba415e6c9 100755
--- a/gr-trellis/src/python/qa_trellis.py
+++ b/gr-trellis/src/python/qa_trellis.py
@@ -20,46 +20,45 @@
# Boston, MA 02110-1301, USA.
#
-from gnuradio import gr, gr_unittest
+import math
+
+
+from gnuradio import gr, gr_unittest, blks2
+# It's pretty ugly that we can't import trellis from gnuradio in this test
+# but because it runs on the non-installed python code it's all a mess.
import trellis
-class test_trellis (gr_unittest.TestCase):
+fsm_args = {"awgn1o2_4": (2, 4, 4,
+ (0, 2, 0, 2, 1, 3, 1, 3),
+ (0, 3, 3, 0, 1, 2, 2, 1),
+ ),
+ "rep2": (2, 1, 4, (0, 0), (0, 3)),
+ "nothing": (2, 1, 2, (0, 0), (0, 1)),
+ }
- def setUp (self):
- self.tb = gr.top_block ()
+constells = {2: blks2.bpsk_constellation(),
+ 4: blks2.qpsk_constellation(),
+ }
- def tearDown (self):
- self.tb = None
+class test_trellis (gr_unittest.TestCase):
def test_001_fsm (self):
- I = 2
- S = 4
- O = 4
- NS = (0, 2, 0, 2, 1, 3, 1, 3)
- OS = (0, 3, 3, 0, 1, 2, 2, 1)
- f = trellis.fsm(I,S,O,NS,OS)
- self.assertEqual((I,S,O,NS,OS),(f.I(),f.S(),f.O(),f.NS(),f.OS()))
+ f = trellis.fsm(*fsm_args["awgn1o2_4"])
+ self.assertEqual(fsm_args["awgn1o2_4"],(f.I(),f.S(),f.O(),f.NS(),f.OS()))
def test_002_fsm (self):
- I = 2
- S = 4
- O = 4
- NS = (0, 2, 0, 2, 1, 3, 1, 3)
- OS = (0, 3, 3, 0, 1, 2, 2, 1)
- f = trellis.fsm(I,S,O,NS,OS)
+ f = trellis.fsm(*fsm_args["awgn1o2_4"])
g = trellis.fsm(f)
self.assertEqual((g.I(),g.S(),g.O(),g.NS(),g.OS()),(f.I(),f.S(),f.O(),f.NS(),f.OS()))
def test_003_fsm (self):
- I = 2
- S = 4
- O = 4
- NS = (0, 2, 0, 2, 1, 3, 1, 3)
- OS = (0, 3, 3, 0, 1, 2, 2, 1)
- #f = trellis.fsm("awgn1o2_4.fsm")
- #self.assertEqual((I,S,O,NS,OS),(f.I(),f.S(),f.O(),f.NS(),f.OS()))
- # temporary fix so that make distcheck does not fail on this
- self.assertEqual(0,0)
+ f = trellis.fsm("awgn1o2_4.fsm")
+ self.assertEqual(fsm_args["awgn1o2_4"],(f.I(),f.S(),f.O(),f.NS(),f.OS()))
+
+ def test_004_fsm(self):
+ """ Test to make sure fsm works with a single state fsm."""
+ # Just checking that it initializes properly.
+ f = trellis.fsm(*fsm_args["rep2"])
def test_001_interleaver (self):
K = 5
@@ -68,5 +67,69 @@ class test_trellis (gr_unittest.TestCase):
i = trellis.interleaver(K,IN)
self.assertEqual((K,IN,DIN),(i.K(),i.INTER(),i.DEINTER()))
+ def test_001_viterbi(self):
+ """
+ Runs some coding/decoding tests with a few different FSM
+ specs.
+ """
+ for name, args in fsm_args.items():
+ constellation = constells[args[2]]
+ fsms = trellis.fsm(*args)
+ noise = 0.1
+ tb = trellis_tb(constellation, fsms, noise)
+ tb.run()
+ # Make sure all packets succesfully transmitted.
+ self.assertEqual(tb.dst.ntotal(), tb.dst.nright())
+
+
+class trellis_tb(gr.top_block):
+ """
+ A simple top block for use testing gr-trellis.
+ """
+ def __init__(self, constellation, f, N0=0.25, seed=-666L):
+ """
+ constellation - a constellation object used for modulation.
+ f - a finite state machine specification used for coding.
+ N0 - noise level
+ seed - random seed
+ """
+ super(trellis_tb, self).__init__()
+ # packet size in bits (make it multiple of 16 so it can be packed in a short)
+ packet_size = 1024*16
+ # bits per FSM input symbol
+ bitspersymbol = int(round(math.log(f.I())/math.log(2))) # bits per FSM input symbol
+ # packet size in trellis steps
+ K = packet_size/bitspersymbol
+
+ # TX
+ src = gr.lfsr_32k_source_s()
+ # packet size in shorts
+ src_head = gr.head (gr.sizeof_short, packet_size/16)
+ # unpack shorts to symbols compatible with the FSM input cardinality
+ s2fsmi = gr.packed_to_unpacked_ss(bitspersymbol, gr.GR_MSB_FIRST)
+ # initial FSM state = 0
+ enc = trellis.encoder_ss(f, 0)
+ mod = gr.chunks_to_symbols_sc(constellation.points(), 1)
+
+ # CHANNEL
+ add = gr.add_cc()
+ noise = gr.noise_source_c(gr.GR_GAUSSIAN,math.sqrt(N0/2),seed)
+
+ # RX
+ # data preprocessing to generate metrics for Viterbi
+ metrics = trellis.constellation_metrics_cf(constellation.base(), trellis.TRELLIS_EUCLIDEAN)
+ # Put -1 if the Initial/Final states are not set.
+ va = trellis.viterbi_s(f, K, 0, -1)
+ # pack FSM input symbols to shorts
+ fsmi2s = gr.unpacked_to_packed_ss(bitspersymbol, gr.GR_MSB_FIRST)
+ # check the output
+ self.dst = gr.check_lfsr_32k_s()
+
+ self.connect (src, src_head, s2fsmi, enc, mod)
+ self.connect (mod, (add, 0))
+ self.connect (noise, (add, 1))
+ self.connect (add, metrics, va, fsmi2s, self.dst)
+
+
if __name__ == '__main__':
gr_unittest.run(test_trellis, "test_trellis.xml")
diff --git a/gr-usrp/src/Makefile.swig.gen b/gr-usrp/src/Makefile.swig.gen
index c122d6dd9..00ecfcb54 100644
--- a/gr-usrp/src/Makefile.swig.gen
+++ b/gr-usrp/src/Makefile.swig.gen
@@ -105,7 +105,7 @@ _usrp_swig_la_CXXFLAGS = \
$(usrp_swig_la_swig_cxxflags)
python/usrp_swig.cc: usrp_swig.py
-usrp_swig.py: usrp_swig.i
+usrp_swig.py: usrp_swig.i
# Include the python dependencies for this file
-include python/usrp_swig.d
diff --git a/gr-usrp2/src/Makefile.swig.gen b/gr-usrp2/src/Makefile.swig.gen
index d791ae2fa..78cb4e5c6 100644
--- a/gr-usrp2/src/Makefile.swig.gen
+++ b/gr-usrp2/src/Makefile.swig.gen
@@ -105,7 +105,7 @@ _usrp2_swig_la_CXXFLAGS = \
$(usrp2_swig_la_swig_cxxflags)
python/usrp2_swig.cc: usrp2_swig.py
-usrp2_swig.py: usrp2_swig.i
+usrp2_swig.py: usrp2_swig.i
# Include the python dependencies for this file
-include python/usrp2_swig.d
diff --git a/gr-video-sdl/src/Makefile.swig.gen b/gr-video-sdl/src/Makefile.swig.gen
index d69203f79..ac66bc9a2 100644
--- a/gr-video-sdl/src/Makefile.swig.gen
+++ b/gr-video-sdl/src/Makefile.swig.gen
@@ -105,7 +105,7 @@ _video_sdl_la_CXXFLAGS = \
$(video_sdl_la_swig_cxxflags)
python/video_sdl.cc: video_sdl.py
-video_sdl.py: video_sdl.i
+video_sdl.py: video_sdl.i
# Include the python dependencies for this file
-include python/video_sdl.d
diff --git a/usrp/host/swig/Makefile.swig.gen b/usrp/host/swig/Makefile.swig.gen
index b4cc97caa..b772e97da 100644
--- a/usrp/host/swig/Makefile.swig.gen
+++ b/usrp/host/swig/Makefile.swig.gen
@@ -105,7 +105,7 @@ _usrp_prims_la_CXXFLAGS = \
$(usrp_prims_la_swig_cxxflags)
python/usrp_prims.cc: usrp_prims.py
-usrp_prims.py: usrp_prims.i
+usrp_prims.py: usrp_prims.i
# Include the python dependencies for this file
-include python/usrp_prims.d