diff options
author | Ben Reynwar | 2011-02-20 09:13:55 -0700 |
---|---|---|
committer | Ben Reynwar | 2011-02-20 12:06:57 -0700 |
commit | 38fe2e1ba02029998f8feb46fccd0608eb181def (patch) | |
tree | 56d1120816261257b3be3f78050ef7d8be6c1ab6 /gnuradio-core | |
parent | e10ea35d7a32c525145877f2ef39642fc68d8c3f (diff) | |
download | gnuradio-38fe2e1ba02029998f8feb46fccd0608eb181def.tar.gz gnuradio-38fe2e1ba02029998f8feb46fccd0608eb181def.tar.bz2 gnuradio-38fe2e1ba02029998f8feb46fccd0608eb181def.zip |
Constellation objects accept n-dimensional points. (i.e. n complex numbers correspond to one symbol value.)
Diffstat (limited to 'gnuradio-core')
8 files changed, 316 insertions, 112 deletions
diff --git a/gnuradio-core/src/lib/general/gr_constellation.cc b/gnuradio-core/src/lib/general/gr_constellation.cc index 27590bf82..69b6e1bdc 100644 --- a/gnuradio-core/src/lib/general/gr_constellation.cc +++ b/gnuradio-core/src/lib/general/gr_constellation.cc @@ -34,20 +34,14 @@ #define M_TWOPI (2*M_PI) #define SQRT_TWO 0.707107 -gr_constellation_sptr -gr_make_constellation(std::vector<gr_complex> constellation, std::vector<unsigned int> pre_diff_code, - unsigned int rotational_symmetry) -{ - return gr_constellation_sptr(new gr_constellation (constellation, pre_diff_code, rotational_symmetry)); -} - // 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 rotational_symmetry, unsigned int dimensionality) : d_constellation(constellation), d_pre_diff_code(pre_diff_code), - d_rotational_symmetry(rotational_symmetry) + d_rotational_symmetry(rotational_symmetry), + d_dimensionality(dimensionality) { if (pre_diff_code.size() == 0) d_apply_pre_diff_code = false; @@ -55,25 +49,48 @@ gr_constellation::gr_constellation (std::vector<gr_complex> constellation, std:: 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_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 get_closest_point(std::vector<gr_complex> constellation, gr_complex sample) { +unsigned int gr_constellation::get_closest_point(const gr_complex *sample) { - unsigned int table_size = constellation.size(); unsigned int min_index = 0; float min_euclid_dist; float euclid_dist; - min_euclid_dist = norm(sample - constellation[0]); - min_index = 0; - for (unsigned int j = 1; j < table_size; j++){ - euclid_dist = norm(sample - constellation[j]); + 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; @@ -82,16 +99,48 @@ unsigned int get_closest_point(std::vector<gr_complex> constellation, gr_complex return min_index; } -// Chooses points base on shortest distance. -// Inefficient. -unsigned int gr_constellation::decision_maker(gr_complex sample) +unsigned int gr_constellation::decision_maker_pe(const gr_complex *sample, float *phase_error) { - unsigned int min_index; - min_index = get_closest_point(d_constellation, sample); - return min_index; + 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; } -void gr_constellation::calc_metric(gr_complex sample, float *metric, trellis_metric_type_t type) { +/* +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); @@ -107,39 +156,71 @@ void gr_constellation::calc_metric(gr_complex sample, float *metric, trellis_met } } -void gr_constellation::calc_euclidean_metric(gr_complex sample, float *metric) { - for (int o=0; o<d_constellation.size(); o++) { - gr_complex s = sample - d_constellation[o]; - metric[o] = s.real()*s.real()+s.imag()*s.imag(); +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(gr_complex sample, float *metric){ +void gr_constellation::calc_hard_symbol_metric(const gr_complex *sample, float *metric){ float minm = FLT_MAX; - int minmi = 0; - for (int o=0; o<d_constellation.size(); o++) { - gr_complex s = sample - d_constellation[o]; - float dist = s.real()*s.real()+s.imag()*s.imag(); + 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(int o=0; o<d_constellation.size(); 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), + gr_constellation(constellation, pre_diff_code, rotational_symmetry, dimensionality), n_sectors(n_sectors) { } -unsigned int gr_constellation_sector::decision_maker (gr_complex sample) { +unsigned int gr_constellation_sector::decision_maker (const gr_complex *sample) { unsigned int sector; sector = get_sector(sample); return sector_values[sector]; @@ -170,20 +251,20 @@ gr_constellation_rect::gr_constellation_rect (std::vector<gr_complex> constellat 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, real_sectors * 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 (gr_complex sample) { +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); + 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); + 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; @@ -198,7 +279,7 @@ unsigned int gr_constellation_rect::calc_sector_value (unsigned int sector) { 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(d_constellation, sector_center); + closest_point = get_closest_point(§or_center); return closest_point; } @@ -215,27 +296,25 @@ gr_make_constellation_psk(std::vector<gr_complex> constellation, 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(), n_sectors) + gr_constellation_sector(constellation, pre_diff_code, constellation.size(), 1, n_sectors) { find_sector_values(); } -unsigned int gr_constellation_psk::get_sector (gr_complex sample) { - float phase = arg(sample); +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; - // std::cout << phase << " " << width << " " << sector << std::endl; 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(d_constellation, sector_center); - // std::cout << phase << " " << sector_center << " " << closest_point << std::endl; + unsigned int closest_point = get_closest_point(§or_center); return closest_point; } @@ -252,11 +331,13 @@ gr_constellation_bpsk::gr_constellation_bpsk () 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(gr_complex sample) +unsigned int gr_constellation_bpsk::decision_maker(const gr_complex *sample) { - return (real(sample) > 0); + return (real(*sample) > 0); } @@ -275,11 +356,13 @@ gr_constellation_qpsk::gr_constellation_qpsk () 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(gr_complex sample) +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); + 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 index 4083e5b5b..4ae539572 100644 --- a/gnuradio-core/src/lib/general/gr_constellation.h +++ b/gnuradio-core/src/lib/general/gr_constellation.h @@ -32,50 +32,60 @@ /************************************************************/ /* gr_constellation */ /* */ -/* Decision maker uses nearest-point method. */ +/* Base class defining interface. */ /************************************************************/ class gr_constellation; typedef boost::shared_ptr<gr_constellation> gr_constellation_sptr; -// public constructor -gr_constellation_sptr -gr_make_constellation (std::vector<gr_complex> constellation, std::vector<unsigned int> pre_diff_code, - unsigned int rotational_symmetry); - class gr_constellation : public boost::enable_shared_from_this<gr_constellation> { - public: - +public: gr_constellation (std::vector<gr_complex> constellation, std::vector<unsigned int> pre_diff_code, - unsigned int rotational_symmetry); + 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;} - //! Returns the constellation point that matches best. - //! Also calculates the phase error. - virtual unsigned int decision_maker (gr_complex sample); - - //! Calculates metrics for all points in the constellation. - //! For use with the viterbi algorithm. - 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); - unsigned int bits_per_symbol () { - return floor(log(d_constellation.size())/log(2)); + return floor(log(d_constellation.size())/d_dimensionality/log(2)); } unsigned int arity () { - return d_constellation.size(); + return d_arity; } gr_constellation_sptr base() { @@ -88,10 +98,46 @@ class gr_constellation : public boost::enable_shared_from_this<gr_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_sptr - gr_make_constellation (std::vector<gr_complex> constellation); + friend gr_constellation_calcdist_sptr + gr_make_constellation_calcdist (std::vector<gr_complex> constellation); }; /************************************************************/ @@ -110,16 +156,15 @@ class gr_constellation_sector : public gr_constellation 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 (gr_complex sample); + unsigned int decision_maker (const gr_complex *sample); protected: - virtual unsigned int get_sector (gr_complex sample) = 0; - + 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; @@ -133,6 +178,8 @@ class gr_constellation_sector : public gr_constellation /************************************************************/ /* 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. */ @@ -162,7 +209,7 @@ class gr_constellation_rect : public gr_constellation_sector protected: - unsigned int get_sector (gr_complex sample); + unsigned int get_sector (const gr_complex *sample); unsigned int calc_sector_value (unsigned int sector); @@ -208,7 +255,7 @@ class gr_constellation_psk : public gr_constellation_sector protected: - unsigned int get_sector (gr_complex sample); + unsigned int get_sector (const gr_complex *sample); unsigned int calc_sector_value (unsigned int sector); @@ -239,7 +286,7 @@ class gr_constellation_bpsk : public gr_constellation public: gr_constellation_bpsk (); - unsigned int decision_maker (gr_complex sample); + unsigned int decision_maker (const gr_complex *sample); friend gr_constellation_bpsk_sptr gr_make_constellation_bpsk (); @@ -265,7 +312,7 @@ class gr_constellation_qpsk : public gr_constellation public: gr_constellation_qpsk (); - unsigned int decision_maker (gr_complex sample); + unsigned int decision_maker (const gr_complex *sample); friend gr_constellation_qpsk_sptr gr_make_constellation_qpsk (); diff --git a/gnuradio-core/src/lib/general/gr_constellation.i b/gnuradio-core/src/lib/general/gr_constellation.i index 18d0cc92b..bc1724c3a 100644 --- a/gnuradio-core/src/lib/general/gr_constellation.i +++ b/gnuradio-core/src/lib/general/gr_constellation.i @@ -29,26 +29,51 @@ class gr_constellation; typedef boost::shared_ptr<gr_constellation> gr_constellation_sptr; %template(gr_constellation_sptr) boost::shared_ptr<gr_constellation>; -%rename(constellation) gr_make_constellation; -gr_constellation_sptr gr_make_constellation(std::vector<gr_complex> constellation, - std::vector<unsigned int> pre_diff_code, - unsigned int rotational_symmetry); -%ignore 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 rotational_symmetry, + unsigned int dimensionality); std::vector<gr_complex> points(); - unsigned int decision_maker (gr_complex sample); + 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 diff --git a/gnuradio-core/src/lib/general/gr_constellation_decoder2_cb.cc b/gnuradio-core/src/lib/general/gr_constellation_decoder2_cb.cc index 9116d4776..a63c1d38a 100644 --- a/gnuradio-core/src/lib/general/gr_constellation_decoder2_cb.cc +++ b/gnuradio-core/src/lib/general/gr_constellation_decoder2_cb.cc @@ -27,6 +27,7 @@ #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) @@ -37,27 +38,41 @@ gr_make_constellation_decoder2_cb (gr_constellation_sptr constellation) gr_constellation_decoder2_cb:: gr_constellation_decoder2_cb (gr_constellation_sptr constellation) - : gr_sync_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) + : 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; +} -gr_constellation_decoder2_cb::~gr_constellation_decoder2_cb(){} int -gr_constellation_decoder2_cb::work(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) +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]); + 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 index d72761927..51891b636 100644 --- a/gnuradio-core/src/lib/general/gr_constellation_decoder2_cb.h +++ b/gnuradio-core/src/lib/general/gr_constellation_decoder2_cb.h @@ -23,7 +23,7 @@ #ifndef INCLUDED_GR_CONSTELLATION_DECODER2_CB_H #define INCLUDED_GR_CONSTELLATION_DECODER2_CB_H -#include <gr_sync_block.h> +#include <gr_block.h> #include <gr_constellation.h> #include <vector> @@ -38,11 +38,12 @@ gr_make_constellation_decoder2_cb (gr_constellation_sptr constellation); * \ingroup coding_blk * */ -class gr_constellation_decoder2_cb : public gr_sync_block +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); @@ -51,11 +52,13 @@ class gr_constellation_decoder2_cb : public gr_sync_block public: - ~gr_constellation_decoder2_cb(); //destructor - - int work (int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); + 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_receiver_cb.cc b/gnuradio-core/src/lib/general/gr_constellation_receiver_cb.cc index 6520b66b2..dae70d931 100644 --- a/gnuradio-core/src/lib/general/gr_constellation_receiver_cb.cc +++ b/gnuradio-core/src/lib/general/gr_constellation_receiver_cb.cc @@ -61,6 +61,8 @@ gr_constellation_receiver_cb::gr_constellation_receiver_cb (gr_constellation_spt 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 @@ -111,8 +113,8 @@ gr_constellation_receiver_cb::general_work (int noutput_items, 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(sample); - phase_error = -arg(sample*conj(d_constellation->points()[sym_value])); + 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) { diff --git a/gnuradio-core/src/lib/general/gr_ofdm_frame_sink2.cc b/gnuradio-core/src/lib/general/gr_ofdm_frame_sink2.cc index 8d104e7be..f0cb0fb0a 100644 --- a/gnuradio-core/src/lib/general/gr_ofdm_frame_sink2.cc +++ b/gnuradio-core/src/lib/general/gr_ofdm_frame_sink2.cc @@ -113,7 +113,7 @@ unsigned int gr_ofdm_frame_sink2::demapper(const gr_complex *in, d_derotated_output[i] = sigrot; } - unsigned char bits = d_constell->decision_maker(sigrot); + unsigned char bits = d_constell->decision_maker(&sigrot); gr_complex closest_sym = d_constell->points()[bits]; @@ -185,6 +185,9 @@ gr_ofdm_frame_sink2::gr_ofdm_frame_sink2(gr_constellation_sptr constell, 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 diff --git a/gnuradio-core/src/python/gnuradio/gr/qa_constellation.py b/gnuradio-core/src/python/gnuradio/gr/qa_constellation.py index 65d9006cb..054194789 100644 --- a/gnuradio-core/src/python/gnuradio/gr/qa_constellation.py +++ b/gnuradio-core/src/python/gnuradio/gr/qa_constellation.py @@ -22,6 +22,7 @@ import random from cmath import exp, pi, log +from itertools import product from gnuradio import gr, gr_unittest, blks2 from gnuradio.utils import mod_codes @@ -36,6 +37,27 @@ tested_mod_codes = (mod_codes.NO_CODE, mod_codes.GRAY_CODE) # Third item is whether differential encoding should be tested. # Fourth item is the name of the argument to constructor that specifices # whether differential encoding is used. + +def twod_constell(): + """ + + """ + points = ((1+0j), (0+1j), + (-1+0j), (0-1j)) + rot_sym = 2 + dim = 2 + return gr.constellation_calcdist(points, [], rot_sym, dim) + +def threed_constell(): + oned_points = ((1+0j), (0+1j), (-1+0j), (0-1j)) + points = [] + r4 = range(0, 4) + for ia, ib, ic in product(r4, r4, r4): + points += [oned_points[ia], oned_points[ib], oned_points[ic]] + rot_sym = 4 + dim = 3 + return gr.constellation_calcdist(points, [], rot_sym, dim) + tested_constellations = ( (blks2.psk_constellation, {'m': (2, 4, 8, 16, 32, 64), @@ -50,6 +72,8 @@ tested_constellations = ( # 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), ) class test_constellation (gr_unittest.TestCase): @@ -85,7 +109,7 @@ class test_constellation (gr_unittest.TestCase): rs = constellation.rotational_symmetry() rotations = [exp(i*2*pi*(0+1j)/rs) for i in range(0, rs)] else: - rotations = [1] + rotations = [None] for rotation in rotations: src = gr.vector_source_b(self.src_data) content = mod_demod(constellation, current_diff, rotation) @@ -143,11 +167,11 @@ class mod_demod(gr.hier_block2): 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.blocks.append(gr.chunks_to_symbols_bc(self.constellation.points(), self.constellation.dimensionality())) # CHANNEL # Channel just consists of a rotation to check differential coding. - self.blocks.append(gr.multiply_const_cc(rotation)) + if rotation is not None: + self.blocks.append(gr.multiply_const_cc(rotation)) # RX # Convert the constellation symbols back to binary values. @@ -163,6 +187,8 @@ class mod_demod(gr.hier_block2): 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) |