diff options
Diffstat (limited to 'gnuradio-core/src/lib/general')
18 files changed, 2069 insertions, 2 deletions
diff --git a/gnuradio-core/src/lib/general/Makefile.am b/gnuradio-core/src/lib/general/Makefile.am index 3ceea7a6d..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 \ @@ -139,6 +143,7 @@ libgeneral_la_SOURCES = \ gr_rms_cf.cc \ gr_rms_ff.cc \ gr_short_to_float.cc \ + gr_int_to_float.cc \ gr_simple_correlator.cc \ gr_simple_framer.cc \ gr_simple_squelch_cc.cc \ @@ -212,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 \ @@ -261,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 \ @@ -273,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 \ @@ -301,6 +310,7 @@ grinclude_HEADERS = \ gr_rms_cf.h \ gr_rms_ff.h \ gr_short_to_float.h \ + gr_int_to_float.h \ gr_simple_correlator.h \ gr_simple_framer.h \ gr_simple_framer_sync.h \ @@ -386,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 \ @@ -418,6 +431,7 @@ swiginclude_HEADERS = \ gr_glfsr_source_b.i \ gr_glfsr_source_f.i \ gr_head.i \ + gr_int_to_float.i \ gr_interleave.i \ gr_interleaved_short_to_complex.i \ gr_iqcomp_cc.i \ @@ -427,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 \ @@ -437,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 fb9c4c0f2..d9648ef64 100644 --- a/gnuradio-core/src/lib/general/general.i +++ b/gnuradio-core/src/lib/general/general.i @@ -42,6 +42,7 @@ #include <gr_float_to_char.h> #include <gr_float_to_uchar.h> #include <gr_short_to_float.h> +#include <gr_int_to_float.h> #include <gr_char_to_float.h> #include <gr_uchar_to_float.h> #include <gr_frequency_modulator_fc.h> @@ -69,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> @@ -97,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> @@ -111,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> @@ -167,6 +172,7 @@ %include "gr_float_to_char.i" %include "gr_float_to_uchar.i" %include "gr_short_to_float.i" +%include "gr_int_to_float.i" %include "gr_char_to_float.i" %include "gr_uchar_to_float.i" %include "gr_frequency_modulator_fc.i" @@ -194,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" @@ -222,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" @@ -236,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(§or_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(§or_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/gnuradio-core/src/lib/general/gr_int_to_float.cc b/gnuradio-core/src/lib/general/gr_int_to_float.cc new file mode 100644 index 000000000..b5a19e5c0 --- /dev/null +++ b/gnuradio-core/src/lib/general/gr_int_to_float.cc @@ -0,0 +1,59 @@ +/* -*- c++ -*- */ +/* + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <gr_int_to_float.h> +#include <gr_io_signature.h> + +gr_int_to_float_sptr +gr_make_int_to_float () +{ + return gnuradio::get_initial_sptr(new gr_int_to_float ()); +} + +gr_int_to_float::gr_int_to_float () + : gr_sync_block ("gr_int_to_float", + gr_make_io_signature (1, 1, sizeof (int32_t)), + gr_make_io_signature (1, 1, sizeof (float))) +{ +} + +int +gr_int_to_float::work (int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) +{ + const int32_t *in = (const int32_t *) input_items[0]; + float *out = (float *) output_items[0]; + + for(int i=0; i < noutput_items; i++) { + out[i] = (float)in[i]; + } + + return noutput_items; +} + + + diff --git a/gnuradio-core/src/lib/general/gr_int_to_float.h b/gnuradio-core/src/lib/general/gr_int_to_float.h new file mode 100644 index 000000000..cf1223be5 --- /dev/null +++ b/gnuradio-core/src/lib/general/gr_int_to_float.h @@ -0,0 +1,51 @@ +/* -*- c++ -*- */ +/* + * 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. + */ + +#ifndef INCLUDED_GR_INT_TO_FLOAT_H +#define INCLUDED_GR_INT_TO_FLOAT_H + +#include <gr_sync_block.h> + +class gr_int_to_float; +typedef boost::shared_ptr<gr_int_to_float> gr_int_to_float_sptr; + +gr_int_to_float_sptr +gr_make_int_to_float (); + +/*! + * \brief Convert stream of short to a stream of float + * \ingroup converter_blk + */ + +class gr_int_to_float : public gr_sync_block +{ + friend gr_int_to_float_sptr gr_make_int_to_float (); + gr_int_to_float (); + + public: + virtual int work (int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); +}; + + +#endif /* INCLUDED_GR_INT_TO_FLOAT_H */ diff --git a/gnuradio-core/src/lib/general/gr_int_to_float.i b/gnuradio-core/src/lib/general/gr_int_to_float.i new file mode 100644 index 000000000..8cb9e35b5 --- /dev/null +++ b/gnuradio-core/src/lib/general/gr_int_to_float.i @@ -0,0 +1,30 @@ +/* -*- c++ -*- */ +/* + * 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. + */ + +GR_SWIG_BLOCK_MAGIC(gr,int_to_float) + +gr_int_to_float_sptr gr_make_int_to_float (); + +class gr_int_to_float : public gr_sync_block +{ + gr_int_to_float (); +}; diff --git a/gnuradio-core/src/lib/general/gr_metric_type.h b/gnuradio-core/src/lib/general/gr_metric_type.h new file mode 100644 index 000000000..74c93b55e --- /dev/null +++ b/gnuradio-core/src/lib/general/gr_metric_type.h @@ -0,0 +1,31 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_GR_METRIC_TYPE_H +#define INCLUDED_GR_METRIC_TYPE_H + +typedef enum { + TRELLIS_EUCLIDEAN = 200, TRELLIS_HARD_SYMBOL, TRELLIS_HARD_BIT +} trellis_metric_type_t; + +#endif + diff --git a/gnuradio-core/src/lib/general/gr_ofdm_frame_sink2.cc b/gnuradio-core/src/lib/general/gr_ofdm_frame_sink2.cc new file mode 100644 index 000000000..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(); +}; |