GNU Radio 3.7.2git-79-g931a7b07 C++ API
constellation.h
Go to the documentation of this file.
1 /* -*- c++ -*- */
2 /*
3  * Copyright 2010-2012 Free Software Foundation, Inc.
4  *
5  * This file is part of GNU Radio
6  *
7  * GNU Radio is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3, or (at your option)
10  * any later version.
11  *
12  * GNU Radio is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with GNU Radio; see the file COPYING. If not, write to
19  * the Free Software Foundation, Inc., 51 Franklin Street,
20  * Boston, MA 02110-1301, USA.
21  */
22 
23 #ifndef INCLUDED_DIGITAL_CONSTELLATION_H
24 #define INCLUDED_DIGITAL_CONSTELLATION_H
25 
26 #include <gnuradio/digital/api.h>
28 #include <boost/enable_shared_from_this.hpp>
29 #include <gnuradio/gr_complex.h>
30 #include <vector>
31 
32 namespace gr {
33  namespace digital {
34 
35  /************************************************************/
36  /* constellation */
37  /* */
38  /* Base class defining interface. */
39  /************************************************************/
40 
41  class constellation;
42  typedef boost::shared_ptr<constellation> constellation_sptr;
43 
44  /*!
45  * \brief An abstracted constellation object
46  * \ingroup symbol_coding_blk
47  *
48  * \details
49  * The constellation objects hold the necessary information to pass
50  * around constellation information for modulators and
51  * demodulators. These objects contain the mapping between the bits
52  * and the constellation points used to represent them as well as
53  * methods for slicing the symbol space. Various implementations are
54  * possible for efficiency and ease of use.
55  *
56  * Standard constellations (BPSK, QPSK, QAM, etc) can be inherited
57  * from this class and overloaded to perform optimized slicing and
58  * constellation mappings.
59  */
61  : public boost::enable_shared_from_this<constellation>
62  {
63  public:
64  constellation(std::vector<gr_complex> constell,
65  std::vector<int> pre_diff_code,
66  unsigned int rotational_symmetry,
67  unsigned int dimensionality);
68  constellation();
69  virtual ~constellation();
70 
71  //! Returns the constellation points for a symbol value
72  void map_to_points(unsigned int value, gr_complex *points);
73  std::vector<gr_complex> map_to_points_v(unsigned int value);
74 
75  //! Returns the constellation point that matches best.
76  virtual unsigned int decision_maker(const gr_complex *sample) = 0;
77  //! Takes a vector rather than a pointer. Better for SWIG wrapping.
78  unsigned int decision_maker_v(std::vector<gr_complex> sample);
79  //! Also calculates the phase error.
80  unsigned int decision_maker_pe(const gr_complex *sample, float *phase_error);
81  //! Calculates distance.
82  //unsigned int decision_maker_e(const gr_complex *sample, float *error);
83 
84  //! Calculates metrics for all points in the constellation.
85  //! For use with the viterbi algorithm.
86  virtual void calc_metric(const gr_complex *sample, float *metric, gr::digital::trellis_metric_type_t type);
87  virtual void calc_euclidean_metric(const gr_complex *sample, float *metric);
88  virtual void calc_hard_symbol_metric(const gr_complex *sample, float *metric);
89 
90  //! Returns the set of points in this constellation.
91  std::vector<gr_complex> points() { return d_constellation;}
92  //! Returns the vector of points in this constellation.
93  //! Raise error if dimensionality is not one.
94  std::vector<gr_complex> s_points();
95  //! Returns a vector of vectors of points.
96  std::vector<std::vector<gr_complex> > v_points();
97  //! Whether to apply an encoding before doing differential encoding. (e.g. gray coding)
98  bool apply_pre_diff_code() { return d_apply_pre_diff_code;}
99  //! Whether to apply an encoding before doing differential encoding. (e.g. gray coding)
100  void set_pre_diff_code(bool a) { d_apply_pre_diff_code = a;}
101  //! Returns the encoding to apply before differential encoding.
102  std::vector<int> pre_diff_code() { return d_pre_diff_code;}
103  //! Returns the order of rotational symmetry.
104  unsigned int rotational_symmetry() { return d_rotational_symmetry;}
105  //! Returns the number of complex numbers in a single symbol.
106  unsigned int dimensionality() {return d_dimensionality;}
107 
108  unsigned int bits_per_symbol()
109  {
110  return floor(log(double(d_constellation.size()))/d_dimensionality/log(2.0));
111  }
112 
113  unsigned int arity()
114  {
115  return d_arity;
116  }
117 
119  {
120  return shared_from_this();
121  }
122 
123  /*! \brief Generates the soft decision LUT based on
124  * constellation and symbol map.
125  *
126  * \details Generates the soft decision LUT based on
127  * constellation and symbol map. It can be given a estimate of
128  * the noise power in the channel as \p npwr.
129  *
130  * \param precision Number of bits of precision on each axis.
131  * \param npwr Estimate of the noise power (if known).
132  *
133  * This is expensive to compute.
134  */
135  void gen_soft_dec_lut(int precision, float npwr=1.0);
136 
137  /*! \brief Calculate soft decisions for the given \p sample.
138  *
139  * \details Calculate the soft decisions from the given \p sample
140  * at the given noise power \p npwr.
141  *
142  * This is a very costly algorithm (especially for higher order
143  * modulations) and should be used sparingly. It uses the
144  * gen_soft_dec_lut function to generate the LUT, which
145  * should be done once or if a large change in the noise floor
146  * is detected.
147  *
148  * Instead of using this function, generate the LUT using the
149  * gen_soft_dec_lut after creating the constellation object
150  * and then use the soft_decision_maker function to return the
151  * answer from the LUT.
152  *
153  * \param sample The complex sample to get the soft decisions.
154  * \param npwr Estimate of the noise power (if known).
155  */
156  virtual std::vector<float> calc_soft_dec(gr_complex sample, float npwr=1.0);
157 
158  /*! \brief Define a soft decision look-up table.
159  *
160  * \details Define a soft decision look-up table (LUT). Because
161  * soft decisions can be calculated in various ways with various
162  * levels of accuracy and complexity, this function allows
163  * users to create a LUT in their own way.
164  *
165  * Setting the LUT here means that has_soft_dec_lut will return
166  * true. Decision vectors returned by soft_decision_maker will
167  * be calculated using this LUT.
168  *
169  * \param soft_dec_lut The soft decision LUT as a vector of
170  * tuples (vectors in C++) of soft decisions. Each
171  * element of the LUT is a vector of k-bit floats (where
172  * there are k bits/sample in the constellation).
173  * \param precision The number of bits of precision used when
174  * generating the LUT.
175  */
176  void set_soft_dec_lut(const std::vector< std::vector<float> > &soft_dec_lut,
177  int precision);
178 
179  //! Returns True if the soft decision LUT has been defined, False otherwise.
180  bool has_soft_dec_lut();
181 
182  /*! \brief Returns the soft decisions for the given \p sample.
183  *
184  * \details Returns the soft decisions for the given \p
185  * sample. If a LUT is defined for the object, the decisions
186  * will be calculated from there. Otherwise, this function will
187  * call calc_soft_dec directly to calculate the soft decisions.
188  *
189  * \param sample The complex sample to get the soft decisions.
190  */
191  std::vector<float> soft_decision_maker(gr_complex sample);
192 
193  protected:
194  std::vector<gr_complex> d_constellation;
195  std::vector<int> d_pre_diff_code;
197  unsigned int d_rotational_symmetry;
198  unsigned int d_dimensionality;
199  unsigned int d_arity;
200  //! The factor by which the user given constellation points were
201  //! scaled by to achieve an average amplitude of 1.
203  float d_re_min, d_re_max, d_im_min, d_im_max;
204 
205  std::vector< std::vector<float> > d_soft_dec_lut;
207  float d_lut_scale;
208 
209  float get_distance(unsigned int index, const gr_complex *sample);
210  unsigned int get_closest_point(const gr_complex *sample);
211  void calc_arity();
212 
213  void max_min_axes();
214  };
215 
216  /************************************************************/
217  /* constellation_calcdist */
218  /* */
219  /************************************************************/
220 
221  /*! \brief Calculate Euclidian distance for any constellation
222  * \ingroup digital
223  *
224  * Constellation which calculates the distance to each point in the
225  * constellation for decision making. Inefficient for large
226  * constellations.
227  */
229  : public constellation
230  {
231  public:
233 
234  /*!
235  * Make a general constellation object that calculates the Euclidean distance for hard decisions.
236  *
237  * \param constell List of constellation points (order of list matches pre_diff_code)
238  * \param pre_diff_code List of alphabet symbols (before applying any differential
239  * coding) (order of list matches constell)
240  * \param rotational_symmetry Number of rotations around unit circle that have the same representation.
241  * \param dimensionality Number of dimensions to the constellation.
242  */
243  static sptr make(std::vector<gr_complex> constell,
244  std::vector<int> pre_diff_code,
245  unsigned int rotational_symmetry,
246  unsigned int dimensionality);
247 
248  unsigned int decision_maker(const gr_complex *sample);
249  // void calc_metric(gr_complex *sample, float *metric, trellis_metric_type_t type);
250  // void calc_euclidean_metric(gr_complex *sample, float *metric);
251  // void calc_hard_symbol_metric(gr_complex *sample, float *metric);
252 
253  protected:
254  constellation_calcdist(std::vector<gr_complex> constell,
255  std::vector<int> pre_diff_code,
256  unsigned int rotational_symmetry,
257  unsigned int dimensionality);
258  };
259 
260 
261  /************************************************************/
262  /*! constellation_sector */
263  /************************************************************/
264 
265  /*!
266  * \brief Sectorized digital constellation
267  * \ingroup digital
268  *
269  * Constellation space is divided into sectors. Each sector is
270  * associated with the nearest constellation point.
271  *
272  */
274  {
275  public:
276 
277  constellation_sector(std::vector<gr_complex> constell,
278  std::vector<int> pre_diff_code,
279  unsigned int rotational_symmetry,
280  unsigned int dimensionality,
281  unsigned int n_sectors);
282 
284 
285  unsigned int decision_maker(const gr_complex *sample);
286 
287  protected:
288  virtual unsigned int get_sector(const gr_complex *sample) = 0;
289  virtual unsigned int calc_sector_value(unsigned int sector) = 0;
290  void find_sector_values();
291 
292  unsigned int n_sectors;
293 
294  private:
295  std::vector<int> sector_values;
296  };
297 
298  /************************************************************/
299  /* constellation_rect */
300  /************************************************************/
301 
302  /*!
303  * \brief Rectangular digital constellation
304  * \ingroup digital
305  *
306  * Only implemented for 1-(complex)dimensional constellation.
307  *
308  * Constellation space is divided into rectangular sectors. Each
309  * sector is associated with the nearest constellation point.
310  *
311  * Works well for square QAM.
312  *
313  * Works for any generic constellation provided sectors are not
314  * too large.
315  */
316 
317 
319  : public constellation_sector
320  {
321  public:
323 
324  /*!
325  * Make a rectangular constellation object.
326  *
327  * \param constell List of constellation points (order of list matches pre_diff_code)
328  * \param pre_diff_code List of alphabet symbols (before applying any differential
329  * coding) (order of list matches constell)
330  * \param rotational_symmetry Number of rotations around unit circle that have the same representation.
331  * \param real_sectors Number of sectors the real axis is split in to.
332  * \param imag_sectors Number of sectors the imag axis is split in to.
333  * \param width_real_sectors width of each real sector to calculate decision boundaries.
334  * \param width_imag_sectors width of each imag sector to calculate decision boundaries.
335  */
336  static constellation_rect::sptr make(std::vector<gr_complex> constell,
337  std::vector<int> pre_diff_code,
338  unsigned int rotational_symmetry,
339  unsigned int real_sectors,
340  unsigned int imag_sectors,
341  float width_real_sectors,
342  float width_imag_sectors);
344 
345  protected:
346 
347  constellation_rect(std::vector<gr_complex> constell,
348  std::vector<int> pre_diff_code,
349  unsigned int rotational_symmetry,
350  unsigned int real_sectors,
351  unsigned int imag_sectors,
352  float width_real_sectors,
353  float width_imag_sectors);
354 
355  unsigned int get_sector(const gr_complex *sample);
356 
357  unsigned int calc_sector_value(unsigned int sector);
358 
359  private:
360  unsigned int n_real_sectors;
361  unsigned int n_imag_sectors;
362  float d_width_real_sectors;
363  float d_width_imag_sectors;
364  };
365 
366 
367  /************************************************************/
368  /* constellation_expl_rect */
369  /************************************************************/
370 
371  /*!
372  * \brief Rectangular digital constellation
373  * \ingroup digital
374  *
375  * Only implemented for 1-(complex)dimensional constellation.
376  *
377  * Constellation space is divided into rectangular sectors. Each
378  * sector is associated with the nearest constellation point.
379  *
380  * This class is different from constellation_rect in that the
381  * mapping from sector to constellation point is explicitly passed
382  * into the constructor as sector_values. Usually we do not need
383  * this, since we want each sector to be automatically mapped to
384  * the closest constellation point, however sometimes it's nice to
385  * have the flexibility.
386  */
388  : public constellation_rect
389  {
390  public:
392 
393  static sptr make(std::vector<gr_complex> constellation,
394  std::vector<int> pre_diff_code,
395  unsigned int rotational_symmetry,
396  unsigned int real_sectors,
397  unsigned int imag_sectors,
398  float width_real_sectors,
399  float width_imag_sectors,
400  std::vector<unsigned int> sector_values);
402 
403  protected:
404  constellation_expl_rect(std::vector<gr_complex> constellation,
405  std::vector<int> pre_diff_code,
406  unsigned int rotational_symmetry,
407  unsigned int real_sectors,
408  unsigned int imag_sectors,
409  float width_real_sectors,
410  float width_imag_sectors,
411  std::vector<unsigned int> sector_values);
412 
413  unsigned int calc_sector_value (unsigned int sector) {
414  return d_sector_values[sector];
415  }
416 
417  private:
418  std::vector<unsigned int> d_sector_values;
419  };
420 
421  /************************************************************/
422  /* constellation_psk */
423  /************************************************************/
424 
425  /*!
426  * \brief constellation_psk
427  * \ingroup digital
428  *
429  * Constellation space is divided into pie slices sectors.
430  *
431  * Each slice is associated with the nearest constellation point.
432  *
433  * Works well for PSK but nothing else.
434  *
435  * Assumes that there is a constellation point at 1.x
436  */
438  {
439  public:
441 
442  // public constructor
443  static sptr make(std::vector<gr_complex> constell,
444  std::vector<int> pre_diff_code,
445  unsigned int n_sectors);
446 
448 
449  protected:
450  unsigned int get_sector(const gr_complex *sample);
451 
452  unsigned int calc_sector_value(unsigned int sector);
453 
454  constellation_psk(std::vector<gr_complex> constell,
455  std::vector<int> pre_diff_code,
456  unsigned int n_sectors);
457  };
458 
459 
460  /************************************************************/
461  /* constellation_bpsk */
462  /* */
463  /* Only works for BPSK. */
464  /* */
465  /************************************************************/
466 
467  /*!
468  * \brief Digital constellation for BPSK
469  * \ingroup digital
470  */
472  {
473  public:
475 
476  // public constructor
477  static sptr make();
478 
480 
481  unsigned int decision_maker(const gr_complex *sample);
482 
483  protected:
485  };
486 
487 
488  /************************************************************/
489  /* constellation_qpsk */
490  /* */
491  /* Only works for QPSK. */
492  /* */
493  /************************************************************/
494 
495  /*!
496  * \brief Digital constellation for QPSK
497  * \ingroup digital
498  *
499  * 01 | 11
500  * -------
501  * 00 | 10
502  */
504  {
505  public:
507 
508  // public constructor
509  static sptr make();
510 
512 
513  unsigned int decision_maker(const gr_complex *sample);
514 
515  protected:
517  };
518 
519 
520  /************************************************************/
521  /* constellation_dqpsk */
522  /* */
523  /* Works with differential encoding; slower decisions. */
524  /* */
525  /************************************************************/
526 
527  /*!
528  * \brief Digital constellation for DQPSK
529  * \ingroup digital
530  *
531  * 01 | 00
532  * -------
533  * 11 | 10
534  */
536  {
537  public:
539 
540  // public constructor
541  static sptr make();
542 
544 
545  unsigned int decision_maker(const gr_complex *sample);
546 
547  protected:
549  };
550 
551 
552  /************************************************************/
553  /* constellation_8psk */
554  /* */
555  /* Only works for 8PSK. */
556  /* */
557  /************************************************************/
558 
559  /*!
560  * \brief Digital constellation for 8PSK
561  * \ingroup digital
562  *
563  * 101 | 100
564  * 001 | 000
565  * -----------------
566  * 011 | 010
567  * 111 | 110
568  */
570  {
571  public:
573 
574  // public constructor
575  static sptr make();
576 
578 
579  unsigned int decision_maker(const gr_complex *sample);
580 
581  protected:
583  };
584 
585  } /* namespace digital */
586 } /* namespace gr */
587 
588 #endif /* INCLUDED_DIGITAL_CONSTELLATION_H */