/*---------------------------------------------------------------------------*
* IT++ *
*---------------------------------------------------------------------------*
* Copyright (c) 1995-2001 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 Definitions of interleaver classes
\author Pål Frenger
1.12
2004/05/10 15:08:58
*/
#ifndef __interleave_h
#define __interleave_h
#include "base/binary.h"
#include "base/matfunc.h"
#include "base/random.h"
#include "base/vec.h"
#include "base/mat.h"
namespace itpp {
/*! \defgroup interl Interleavers
*/
/*! \ingroup interl
\class Block_Interleaver comm/interleave.h
\brief Block Interleaver Class.
Data is written row-wise and read column-wise when interleaving.
<h3>Example of use:</h3>
\code
BPSK bpsk;
bvec bits = "0 1 1 0 0 0 1 1 1 1 0 0 1 0 0 1";
vec symbols = bpsk.modulate_bits(bits);
Block_Interleaver<double> block_interleaver(4,4);
vec interleaved_symbols = block_interleaver.interleave(symbols);
\endcode
*/
template <class T>
class Block_Interleaver {
public:
//! Block_Interleaver constructor
Block_Interleaver(void) {rows = 0; cols = 0;};
//! Block_Interleaver constructor
Block_Interleaver(int in_rows, int in_cols);
//! Function for block interleaving. May add some zeros.
Vec<T> interleave(const Vec<T> &input);
//! Function for block interleaving. May add some zeros.
void interleave(const Vec<T> &input, Vec<T> &output);
//! Function for block deinterleaving. Removes additional zeros if \a keepzeros = 0.
Vec<T> deinterleave(const Vec<T> &input, short keepzeros = 0 );
//! Function for block deinterleaving. Removes additional zeros if \a keepzeros = 0.
void deinterleave(const Vec<T> &input, Vec<T> &output, short keepzeros = 0 );
//! Set the number of \a rows for block interleaving
void set_rows(int in_rows) {rows = in_rows;};
//! Set the number of \a columns for block interleaving
void set_cols(int in_cols) {cols = in_cols;};
//! Get the number of \a rows for block interleaving
int get_rows(void) {return rows;};
//! Get the number of \a columns for block interleaving
int get_cols(void) {return cols;};
private:
int rows, cols, input_length;
};
/*! \ingroup interl
\class Cross_Interleaver comm/interleave.h
\brief Cross Interleaver Class.
<h3> Example of use: </h3>
\code
BPSK bpsk;
bvec bits = "0 1 1 0 0 0 1 1 1 1 0 0 1 0 0 1";
vec symbols = bpsk.modulate_bits(bits);
Cross_Interleaver<double> cross_interleaver(4);
vec interleaved_symbols = cross_interleaver.interleave(symbols);
\endcode
<ul>
<li> See S. B. Wicker, "Error control systems for digital communications and storage,"
Prentice Hall 1995, p. 427 for details. </li>
</ul>
*/
template <class T>
class Cross_Interleaver {
public:
//! Cross_Interleaver constructor
Cross_Interleaver(void) {order = 0;};
//! Cross_Interleaver constructor
Cross_Interleaver(int in_order);
//! Function for cross interleaving. Adds some zeros.
Vec<T> interleave(const Vec<T> &input);
//! Function for cross interleaving. Adds some zeros.
void interleave(const Vec<T> &input, Vec<T> &output);
//! Function for cross deinterleaving. Removes aditional zeros if \a keepzeros = 0.
Vec<T> deinterleave(const Vec<T> &input, short keepzeros = 0);
//! Function for cross deinterleaving. Removes aditional zeros if \a keepzeros = 0.
void deinterleave(const Vec<T> &input, Vec<T> &output, short keepzeros = 0);
//! Set the \a order of the Cross Interleaver
void set_order(int in_order);
//! Get the \a order of the Cross Interleaver
int get_order(void) {return order;};
private:
int order;
int input_length;
Mat<T> inter_matrix;
Vec<T> tempvec, zerostemp;
};
/*! \ingroup interl
\class Sequence_Interleaver comm/interleave.h
\brief Sequence Interleaver Class
<h3> Example of use: </h3>
\code
BPSK bpsk;
bvec bits = "0 1 1 0 0 0 1 1 1 1 0 0 1 0 0 1";
vec symbols = bpsk.modulate_bits(bits);
Sequence_Interleaver<double> sequence_interleaver(16);
sequence_interleaver.randomize_interleaver_sequence();
vec interleaved_symbols = sequence_snterleaver.interleave(symbols);
\endcode
*/
template <class T>
class Sequence_Interleaver {
public:
//! Sequence_Interleaver constructor.
Sequence_Interleaver(void) {interleaver_depth = 0;};
/*!
\brief Sequence_Interleaver constructor.
Chooses a random sequence of length \a in_interleaver_depth for interleaving.
*/
Sequence_Interleaver(int in_interleaver_depth);
/*!
\brief Sequence_Interleaver constructor.
Uses the \a in_interleaver_sequence for interleaving.
*/
Sequence_Interleaver(ivec in_interleaver_sequence);
//! Function for sequence interleaving. May add some zeros.
Vec<T> interleave(const Vec<T> &input);
//! Function for sequence interleaving. May add some zeros.
void interleave(const Vec<T> &input, Vec<T> &output);
//! Function for sequence deinterleaving. Removes additional zeros if \a keepzeros = 0.
Vec<T> deinterleave(const Vec<T> &input, short keepzeros = 0 );
//! Function for sequence deinterleaving. Removes additional zeros if \a keepzeros = 0.
void deinterleave(const Vec<T> &input, Vec<T> &output, short keepzeros = 0 );
//! Generate a new random sequence for interleaving.
void randomize_interleaver_sequence();
//! Returns the interleaver sequence presently used.
ivec get_interleaver_sequence();
//! Set the interleaver sequence to be used.
void set_interleaver_sequence(ivec in_interleaver_sequence);
//! Set the length of the interleaver sequence to be used.
void set_interleaver_depth(int in_interleaver_depth) { interleaver_depth = in_interleaver_depth; };
//! Get the length of the interleaver sequence presently used.
int get_interleaver_depth(void) { return interleaver_depth; };
private:
ivec interleaver_sequence;
int interleaver_depth, input_length;
};
//-----------------------------------------------------------------------------
// Implementation of templated members starts here
//-----------------------------------------------------------------------------
//-------------------------- Block Interleaver ---------------------------------
template<class T>
Block_Interleaver<T>::Block_Interleaver(int in_rows, int in_cols)
{
rows = in_rows;
cols = in_cols;
input_length = 0;
};
template<class T>
void Block_Interleaver<T>::interleave(const Vec<T> &input, Vec<T> &output)
{
input_length = input.length();
int steps = (int)std::ceil( double(input_length)/double(rows*cols) );
int output_length = steps * rows * cols;
output.set_length(output_length,false);
int s, r, c;
if (input_length==output_length) {
//Block interleaver loop: All steps.
for (s=0; s<steps; s++) {
for (c=0; c<cols; c++) {
for (r=0; r<rows; r++) {
output(s*rows*cols+r*cols+c) = input(s*rows*cols+c*rows+r);
}
}
}
} else {
//Block interleaver loop: All, but the last, steps.
for (s=0; s<steps-1; s++) {
for (c=0; c<cols; c++) {
for (r=0; r<rows; r++) {
output(s*rows*cols+r*cols+c) = input(s*rows*cols+c*rows+r);
}
}
}
//The last step.
Vec<T> zerovect(output_length - input_length);
zerovect.clear();
Vec<T> temp_last_input = concat( input.right(rows*cols-zerovect.length()), zerovect );
for (c=0; c<cols; c++) {
for (r=0; r<rows; r++) {
output((steps-1)*rows*cols+r*cols+c) = temp_last_input(c*rows+r);
}
}
}
}
template<class T>
Vec<T> Block_Interleaver<T>::interleave(const Vec<T> &input)
{
Vec<T> output;
interleave(input,output);
return output;
}
template<class T>
void Block_Interleaver<T>::deinterleave(const Vec<T> &input, Vec<T> &output, short keepzeros)
{
int thisinput_length = input.length();
int steps = (int)std::ceil( double(thisinput_length)/double(rows*cols) );
int output_length = steps * rows * cols;
output.set_size(output_length,false);
int s, r, c;
if (thisinput_length==output_length) {
//Block deinterleaver loop: All, but the last, steps.
for (s=0; s<steps; s++) {
for (r=0; r<rows; r++) {
for (c=0; c<cols; c++) {
output(s*rows*cols+c*rows+r) = input(s*rows*cols+r*cols+c);
}
}
}
} else {
//Block deinterleaver loop: All, but the last, steps.
for (s=0; s<steps-1; s++) {
for (r=0; r<rows; r++) {
for (c=0; c<cols; c++) {
output(s*rows*cols+c*rows+r) = input(s*rows*cols+r*cols+c);
}
}
}
//The last step.
Vec<T> zerovect(output_length - thisinput_length);
zerovect.clear();
Vec<T> temp_last_input = concat( input.right(rows*cols-zerovect.length()), zerovect );
for (r=0; r<rows; r++) {
for (c=0; c<cols; c++) {
output((steps-1)*rows*cols+c*rows+r) = temp_last_input(r*cols+c);
}
}
}
if (keepzeros == 0)
output.set_size(input_length,true);
}
template<class T>
Vec<T> Block_Interleaver<T>::deinterleave(const Vec<T> &input, short keepzeros)
{
Vec<T> output;
deinterleave(input,output,keepzeros);
return output;
}
//---------------------------- Cross Interleaver ---------------------------
template<class T>
Cross_Interleaver<T>::Cross_Interleaver(int in_order)
{
order = in_order;
input_length = 0;
inter_matrix.set_size(order,order,false);
tempvec.set_size(order,false);
zerostemp.set_size(order,false);
}
template<class T>
void Cross_Interleaver<T>::interleave(const Vec<T> &input, Vec<T> &output)
{
input_length = input.length();
int steps = (int)std::ceil( float(input_length) / order ) + order;
int output_length = steps * order;
output.set_length(output_length,false);
int i, r, c;
inter_matrix.clear();
zerostemp.clear();
//Cross interleaver loop:
for (i=0; i< steps; i++ ){
//Shift the matrix to the right:
for (c=order-1; c>0; c--)
inter_matrix.set_col(c, inter_matrix.get_col(c-1) );
// Write the new data to the matrix
if ((i*order+order)<input_length)
tempvec = input.mid(i*order,order);
else if ((i*order)<input_length)
tempvec = concat( input.right(input_length-i*order), zerostemp.left(order-(input_length-i*order)) );
else
tempvec.clear();
inter_matrix.set_col(0,tempvec);
//Read the matrix diagonal-wise:
for (r=0; r<order; r++)
output(i*order+r) = inter_matrix(r,r);
}
}
template<class T>
Vec<T> Cross_Interleaver<T>::interleave(const Vec<T> &input)
{
Vec<T> output;
interleave(input,output);
return output;
}
template<class T>
void Cross_Interleaver<T>::deinterleave(const Vec<T> &input, Vec<T> &output, short keepzeros)
{
int thisinput_length = input.length();
int steps = (int)std::ceil( float(thisinput_length) / order ) + order;
int output_length = steps * order;
output.set_size(output_length,false);
int i, r, c;
inter_matrix.clear();
zerostemp.clear();
//Cross interleaver loop:
for (i=0; i<steps; i++ ){
//Shift the matrix to the right:
for (c=order-1; c>0; c--)
inter_matrix.set_col(c,inter_matrix.get_col(c-1));
// Write the new data to the matrix
if ((i*order+order)<thisinput_length)
tempvec = input.mid(i*order,order);
else if ((i*order)<thisinput_length)
tempvec = concat( input.right(thisinput_length-i*order), zerostemp.left(order-(thisinput_length-i*order)) );
else
tempvec.clear();
inter_matrix.set_col(0,tempvec);
//Read the matrix diagonal-wise:
for (r=0; r<order; r++)
output(i*order+r) = inter_matrix(r,order-1-r);
}
if (keepzeros == 0)
output = output.mid(round_i(std::pow(double(order),2))-order,input_length);
}
template<class T>
Vec<T> Cross_Interleaver<T>::deinterleave(const Vec<T> &input, short keepzeros)
{
Vec<T> output;
deinterleave(input,output,keepzeros);
return output;
}
template<class T>
void Cross_Interleaver<T>::set_order(int in_order)
{
order = in_order;
input_length = 0;
inter_matrix.set_size(order,order,false);
tempvec.set_size(order,false);
zerostemp.set_size(order,false);
}
//------------------- Sequence Interleaver --------------------------------
template<class T>
Sequence_Interleaver<T>::Sequence_Interleaver(int in_interleaver_depth)
{
interleaver_depth = in_interleaver_depth;
interleaver_sequence = sort_index(randu(in_interleaver_depth));
input_length = 0;
}
template<class T>
Sequence_Interleaver<T>::Sequence_Interleaver(ivec in_interleaver_sequence)
{
interleaver_depth = in_interleaver_sequence.length();
interleaver_sequence = in_interleaver_sequence;
input_length = 0;
}
template<class T>
void Sequence_Interleaver<T>::interleave(const Vec<T> &input, Vec<T> &output)
{
input_length = input.length();
int steps = (int)std::ceil( double(input_length)/double(interleaver_depth) );
int output_length = steps*interleaver_depth;
output.set_size(output_length,false);
int s, i;
if (input_length==output_length) {
//Sequence interleaver loop: All steps.
for (s=0; s<steps; s++) {
for (i=0; i<interleaver_depth; i++) {
output(s*interleaver_depth+i) = input(s*interleaver_depth+interleaver_sequence(i));
}
}
} else {
//Sequence interleaver loop: All, but the last, steps.
for (s=0; s<steps-1; s++) {
for (i=0; i<interleaver_depth; i++) {
output(s*interleaver_depth+i) = input(s*interleaver_depth+interleaver_sequence(i));
}
}
//The last step.
Vec<T> zerovect(output_length - input_length);
zerovect.clear();
Vec<T> temp_last_input = concat( input.right(interleaver_depth-zerovect.length()), zerovect );
for (i=0; i<interleaver_depth; i++) {
output((steps-1)*interleaver_depth+i) = temp_last_input(interleaver_sequence(i));
}
}
}
template<class T>
Vec<T> Sequence_Interleaver<T>::interleave(const Vec<T> &input)
{
Vec<T> output;
interleave(input,output);
return output;
}
template<class T>
void Sequence_Interleaver<T>::deinterleave(const Vec<T> &input, Vec<T> &output, short keepzeros)
{
int thisinput_length = input.length();
int steps = (int)std::ceil( double(thisinput_length)/double(interleaver_depth) );
int output_length = steps*interleaver_depth;
//long_long thisinput_length = input.length();
//long_long steps = (long_long)std::ceil( double(thisinput_length)/double(interleaver_depth) );
//long_long output_length = steps*interleaver_depth;
output.set_length(output_length,false);
int s, i;
//long_long s, i;
if (thisinput_length == output_length) {
//Sequence interleaver loop: All steps.
for (s=0; s<steps; s++) {
for (i=0; i<interleaver_depth; i++) {
output(s*interleaver_depth+interleaver_sequence(i)) = input(s*interleaver_depth+i);
}
}
} else {
//Sequence interleaver loop: All, but the last, steps.
for (s=0; s<steps-1; s++) {
for (i=0; i<interleaver_depth; i++) {
output(s*interleaver_depth+interleaver_sequence(i)) = input(s*interleaver_depth+i);
}
}
//The last step.
Vec<T> zerovect(output_length - thisinput_length);
zerovect.clear();
Vec<T> temp_last_input = concat( input.right(interleaver_depth-zerovect.length()), zerovect );
for (i=0; i<interleaver_depth; i++) {
output((steps-1)*interleaver_depth+interleaver_sequence(i)) = temp_last_input(i);
}
if (keepzeros == 0)
output.set_size(input_length,true);
}
}
template<class T>
Vec<T> Sequence_Interleaver<T>::deinterleave(const Vec<T> &input, short keepzeros)
{
Vec<T> output;
deinterleave(input,output,keepzeros);
return output;
}
template<class T>
void Sequence_Interleaver<T>::randomize_interleaver_sequence()
{
interleaver_sequence = sort_index(randu(interleaver_depth));
}
template<class T>
ivec Sequence_Interleaver<T>::get_interleaver_sequence()
{
return interleaver_sequence;
}
template<class T>
void Sequence_Interleaver<T>::set_interleaver_sequence(ivec in_interleaver_sequence)
{
interleaver_sequence = in_interleaver_sequence;
interleaver_depth = interleaver_sequence.size();
}
} //namespace itpp
#endif // __interleave_h
syntax highlighted by Code2HTML, v. 0.9.1