/*---------------------------------------------------------------------------*
 *                                   IT++			             *
 *---------------------------------------------------------------------------*
 * Copyright (c) 1995-2002 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 Implementation of an Orthogonal Frequency Division Multiplex (OFDM) class.
  \author Pål Frenger, Anders Persson and Tony Ottosson

  1.5

  2003/05/22 08:55:20
*/

#include "comm/ofdm.h"
#include "base/specmat.h"
#include "base/transforms.h"
#include "base/operators.h"

namespace itpp { 

  OFDM::OFDM(int inNfft, int inNcp)
  {
    set_parameters(inNfft, inNcp);
  }

  void OFDM::set_parameters(const int inNfft, const int inNcp){
    it_assert(inNfft >= 2, "OFDM: Nfft must be >=2.");
    it_assert(inNcp >=0 && inNcp <= inNfft, "OFDM: Ncp must be >=0 and <=Nfft.");
    Nfft = inNfft;
    Ncp = inNcp;  
    setup_done = true;
  }

  void OFDM::modulate(const cvec &input, cvec &output){
    it_assert(setup_done == true, "OFDM: You must set the length of the FFT and the cyclic prefix!");
    const int N = input.length()/Nfft;
    it_assert(N*Nfft == input.length(), "OFDM: Length of input vector is not a multiple of Nfft.");

    output.set_length(N*(Nfft+Ncp));
    cvec outtemp(Nfft);
    const double norm_factor = sqrt((double)(Nfft*Nfft)/(Nfft+Ncp));

    for(int i=0; i<N; i++) {
      outtemp = ifft(input.mid(i*Nfft, Nfft))*norm_factor;
      output.replace_mid((Nfft+Ncp)*i, concat(outtemp.right(Ncp), outtemp));
    }
  }

  cvec OFDM::modulate(const cvec &input)
  {
    it_assert(setup_done == true,"OFDM: You must set the length of the FFT and the cyclic prefix!");
    const int N = input.length()/Nfft;
    it_assert(input.length() == N*Nfft, "OFDM: Length of input vector is not a multiple of Nfft.");

    cvec output(N*(Nfft+Ncp));
    modulate(input, output);
    return output;
  }

  void OFDM::demodulate(const cvec& input, cvec &output){
    it_assert(setup_done == true, "OFDM: You must set the length of the FFT and the cyclic prefix!");
    const int N = input.length()/(Nfft+Ncp);
    it_assert(N*(Nfft+Ncp) == input.length(), "OFDM: Length of input vector is not a multiple of Nfft+Ncp.");

    output.set_length(N*Nfft);
    // normalize also taking the energy loss into the cyclic prefix into account
    const double norm_factor = 1.0/sqrt((double)(Nfft*Nfft)/(Nfft+Ncp));
    for(int i =0; i<N; i++)
      output.replace_mid(Nfft*i, fft(input.mid(i*(Nfft+Ncp)+Ncp, Nfft))*norm_factor);    
  }

  cvec OFDM::demodulate(const cvec &input){
    it_assert(setup_done == true, "OFDM: You must set the length of the FFT and the cyclic prefix!");
    const int N = input.length()/(Nfft+Ncp);
    it_assert(N*(Nfft+Ncp) == input.length(), "OFDM: Length of input vector is not a multiple of Nfft+Ncp.");

    cvec output(N*Nfft);
    demodulate(input, output);
    return output;
  }

} //namespace itpp


syntax highlighted by Code2HTML, v. 0.9.1