/* -*- 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 #include #include #include #include #include #include #include #include #include #define M_TWOPI (2*M_PI) #define SQRT_TWO 0.707107 // Base Constellation Class gr_constellation::gr_constellation (std::vector constellation, std::vector 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 gr_constellation::map_to_points_v(unsigned int value) { std::vector 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 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 > gr_constellation::v_points () { std::vector > vv_const; vv_const.resize(d_arity); for (unsigned int p=0; p v_const; v_const.resize(d_dimensionality); for (unsigned int d=0; d sample) { assert(sample.size() == d_dimensionality); return decision_maker (&(sample[0])); } gr_constellation_calcdist_sptr gr_make_constellation_calcdist(std::vector constellation, std::vector 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 constellation, std::vector 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 constellation, std::vector 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 constellation, std::vector 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 constellation, std::vector 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 constellation, std::vector 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 constellation, std::vector 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); }