/*---------------------------------------------------------------------------* * IT++ * *---------------------------------------------------------------------------* * Copyright (c) 1995-2003 by Tony Ottosson, Thomas Eriksson, Pål Frenger, * * Tobias Ringström, and Jonas Samuelsson. * * * * Permission to use, copy, modify, and distribute this software and its * * documentation under the terms of the GNU General Public License is hereby * * granted. No representations are made about the suitability of this * * software for any purpose. It is provided "as is" without expressed or * * implied warranty. See the GNU General Public License for more details. * *---------------------------------------------------------------------------*/ /*! \file \brief Definition of a binary convolutional encoder class \author Tony Ottosson 951019, Revised completely 980205. 1.16 2003/05/22 08:55:17 */ #ifndef __convcode_h #define __convcode_h #include "base/vec.h" #include "base/mat.h" #include "base/binary.h" #include "base/array.h" using std::string; namespace itpp { /*! \ingroup fec \brief Binary Convolutional rate 1/n class The codes are given as feedforward encoders an given in the Proakis form. That is the binary generators (K-tuples) are converted to octal integers. Observe that the constraint length (K) is defined as the number of meomory cells plus one (as in Proakis). Encoding is performed with the encode function. Also available is the encode_tail function which automatically add a tail of K-1 zeros and also assume that the encoder starts in the zero state. Observe that decode_tail is used for data encoded with encode_tail, and decode assumes that the memory truncation length either is the default (5*K) or set using the set_truncation_length function. Example of use: (rate 1/3 constraint length K=7 ODS code using BPSK over AWGN) \code BPSK bpsk; Convolutional_Code code; ivec generator(3); generator(0)=0133; generator(1)=0165; generator(2)=0171; code.set_generator_polynomials(generator, 7); bvec bits=randb(100), encoded_bits, decoded_bits; vec tx_signal, rx_signal; code.encode_tail(bits, encoded_bits); tx_signal = bpsk.modulate_bits(encoded_bits); rx_signal = tx_signal + sqrt(0.5)*randn(tx_signal.size()); code.decode_tail(rx_signal, decoded_bits); \endcode Comment: ODS-code stand for Optimum Distance Spectrum Code. For details see T. Ottosson, "Coding, Modulation and Multiuser Decoding for DS-CDMA Systems," Ph.d. thesis, Department of Information Theory, Scool of Electrical and Computer Engineering, Chalmers University of Technology, Göteborg 1997. It is also possible to set the generatorpolynomials directly using the builtin tables which consists of: Maximum Free Distance (MFD) Codes of rates R=1/2 through R=1/8 and Optimum Distance Spectrum (ODS) Codes of rates R=1/2 through R=1/4. */ class Convolutional_Code { public: //! Constructor Convolutional_Code(void) { trunc_length = 0; K = 0; m = 0; set_start_state(0); } //! Destructor virtual ~Convolutional_Code(void) {} /*! \brief Set the code according to built-in tables The \a type_of_code can be either \a MFD or \a ODS for maximum free distance codes (according to Proakis) or Optimum Distance Spectrum Codes accoring to Frenger, Orten and Ottosson. */ void set_code(string type_of_code, int inverse_rate, int constraint_length); //! Set generator polynomials. Given in Proakis integer form void set_generator_polynomials(const ivec &gen, int constraint_length); //! Get generator polynomials ivec get_generator_polynomials(void) { return gen_pol; } //! Return rate of code double get_rate(void) { return rate; } //! Encode a binary vector of inputs starting from state set by the set_state function void encode(const bvec &input, bvec &output); //! Encode a binary vector of inputs starting from state set by the set_state function bvec encode(const bvec &input) { bvec output; encode(input, output); return output; } /*! \brief Encoding that strarts and ends in the zero state Encode a binary vector of inputs starting from zero state and also adds a tail of K-1 zeros to force the encoder into the zero state. Well suited for packet transmission. */ void encode_tail(const bvec &input, bvec &output); //! Encode a binary vector of inputs starting from state set by the set_state function bvec encode_tail(const bvec &input) { bvec output; encode_tail(input, output); return output; } //! Encode a binary vector of inputs using tailbiting. void encode_tailbite(const bvec &input, bvec &output); //! Encode a binary vector of inputs using tailbiting. bvec encode_tailbite(const bvec &input) { bvec output; encode_tailbite(input, output); return output; } /*! \brief Encode a binary bit startinf from the internal encoder state. To initialize the encoder state use set_start_state() and init_encoder() */ void encode_bit(const bin &input, bvec &output); //! Encode a binary bit startinf from the internal encoder state. bvec encode_bit(const bin &input) { bvec output; encode_bit(input, output); return output; } //! Set the encoder internal state in start_state (set by set_start_state()). void init_encoder() { encoder_state = start_state; } /*! \brief Decode a block of encoded data where encode_tail has been used. Thus is assumes a decoder start state of zero and that a tail of K-1 zeros has been added. No memory truncation. */ virtual void decode_tail(const vec &received_signal, bvec &output); //! Decode a block of encoded data where encode_tail has been used virtual bvec decode_tail(const vec &received_signal) { bvec output; decode_tail(received_signal, output); return output; } //! Decode a block of encoded data where encode_tailbite has been used. Tries all start states. virtual void decode_tailbite(const vec &received_signal, bvec &output); //! Decode a block of encoded data where encode_tailbite has been used. Tries all start states. virtual bvec decode_tailbite(const vec &received_signal) { bvec output; decode_tail(received_signal, output); return output; } //! Viterbi decoding using truncation of memory (default = 5*K) virtual void decode(const vec &received_signal, bvec &output); //! Viterbi decoding using truncation of memory (default = 5*K) virtual bvec decode(const vec &received_signal) { bvec output; decode(received_signal, output); return output; } /*! \brief Calculate the inverse sequence Assumes that encode_tail is used in the encoding process. Returns false if there is an error in the coded sequence (not a valid codeword). Do not check that the tail forces the encoder into the zeroth state. */ bool inverse_tail(const bvec coded_sequence, bvec &input); //! Set encoder and decoder start state. The generator polynomials must be set first. void set_start_state(const int state) { it_error_if(state<0 || (state>=(1< &spectrum, int dmax, int no_terms); //void calculate_spectrum(Array &spectrum, int dmax, int no_terms); /*! \brief Cederwall's fast algorithm See IT No. 6, pp. 1146-1159, Nov. 1989 for details. Calculates both the weight spectrum (Ad) and the information weight spectrum (Cd) and returns it as ivec:s in the 0:th and 1:st component of spectrum, respectively. The FAST algorithm is good for calculating only a few terms in the spectrum. If many terms are desired, use calc_spectrum instead. The algorithm returns -1 if the code tested is worse that the input dfree and Cdfree. It returns 0 if the code MAY be catastrophic (assuming that test_catastrophic is true), and returns 1 if everything went right. \arg \c dfree the free distance of the code (or an upper bound) \arg \c no_terms including the dfree term that should be calculated \arg \c Cdfree is the best value of information weight spectrum found so far Observe that there is a risk that some of the integers are overflow if many terms are calculated in the spectrum. */ int fast(Array &spectrum, const int dfree, const int no_terms, const int Cdfree = 1000000, const bool test_catastrophic = false); //int fast(Array &spectrum, const int dfree, const int no_terms, // const int Cdfree = 1000000, const bool test_catastrophic = false); protected: //! Next state from instate given the input int next_state(const int instate, const int input) { return ( (instate >> 1) | (input << (m-1))); } //! The previous state from state given the input int previous_state(const int state, const int input) { return ( ((state << 1) | input) & ((1<> (m-1)); } //! Number of generators int n; //! Constraint length int K; //! Memory of the encoder int m; // number of states int no_states; //! Generator polynomials ivec gen_pol; //! Generator polynomials for the reverse code ivec gen_pol_rev; //! The current encoder state int encoder_state; //! The encoder start state int start_state; //! The decoder truncation length int trunc_length; //! The rate of the code double rate; //! Auxilary table used by the codec bvec xor_int_table; //! output in int format for state and input when moving backwards in the trellis imat output_reverse_int; }; // --------------- Some other functions that maybe should be moved ----------- /*! \relates Convolutional_Code \brief Reverses the bitrepresentation of in (of size length) and converts to an integer */ int reverse_int(int length, int in); /*! \relates Convolutional_Code \brief Calculate the Hamming weight of the binary representation of in of size length */ int weight_int(int length, int in); /*! \relates Convolutional_Code \brief Compare two distance spectra. Return 1 if v1 is less, 0 if v2 less, and -1 if equal. */ int compare_spectra(ivec v1, ivec v2); //int compare_spectra(llvec v1, llvec v2); /*! \relates Convolutional_Code \brief Compare two distance spectra using a weight profile. Return 1 if v1 is less, 0 if v2 less, and -1 if equal. */ int compare_spectra(ivec v1, ivec v2, vec weight_profile); } //namespace itpp #endif // __convcode_h