ok,
I am attaching the file "ofdm_chanest_vcvc_imp.cc" and related files from
gr-digital in gnuradio tree.

I made new module named "gr-Channel_Estimation" and added a block named
"ofdm_chanest_MMSE_vcvc". I am attaching these files as well.

Thanks.


On Fri, Sep 11, 2015 at 3:38 PM, Jeff Long <willco...@gmail.com> wrote:

> The statement is fine. If you post more info, for example the file
> containing this statement, someone should be able to figure out why it
> doesn't work in context.
>
> - Jeff
>
> On 09/11/2015 05:59 AM, monika bansal wrote:
>
>> hii
>>
>> I am making a new module using gr_modtool.  i am getting an * error:
>> expression cannot be used as a function   d_fft_len(sync_symbol1.size()).*
>> *
>> *
>> But the same expression is used in ofdm_chanest_vcvc_imp.cc .
>>
>> How this statement is different for new module.
>> I am new to C++ so this question may be a stupid one :).
>>
>> please let me know what should i do...
>>   Thanks
>>
>>
>> _______________________________________________
>> Discuss-gnuradio mailing list
>> Discuss-gnuradio@gnu.org
>> https://lists.gnu.org/mailman/listinfo/discuss-gnuradio
>>
>>
>
> _______________________________________________
> Discuss-gnuradio mailing list
> Discuss-gnuradio@gnu.org
> https://lists.gnu.org/mailman/listinfo/discuss-gnuradio
>
/* -*- c++ -*- */
/* 
 * Copyright 2012,2013 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.
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <gnuradio/io_signature.h>
#include "ofdm_chanest_vcvc_impl.h"

namespace gr {
  namespace digital {

    ofdm_chanest_vcvc::sptr
    ofdm_chanest_vcvc::make(const std::vector<gr_complex> &sync_symbol1, const std::vector<gr_complex> &sync_symbol2, int n_data_symbols, int eq_noise_red_len, int max_carr_offset, bool force_one_sync_symbol)
    {
      return gnuradio::get_initial_sptr (
	  new ofdm_chanest_vcvc_impl(
	    sync_symbol1,
	    sync_symbol2,
	    n_data_symbols,
	    eq_noise_red_len,
	    max_carr_offset,
	    force_one_sync_symbol
	  )
      );
    }

    ofdm_chanest_vcvc_impl::ofdm_chanest_vcvc_impl(
	    const std::vector<gr_complex> &sync_symbol1,
	    const std::vector<gr_complex> &sync_symbol2,
	    int n_data_symbols,
	    int eq_noise_red_len,
	    int max_carr_offset,
	    bool force_one_sync_symbol
    ) : block("ofdm_chanest_vcvc",
	      io_signature::make(1, 1, sizeof (gr_complex) * sync_symbol1.size()),
	      io_signature::make(1, 2, sizeof (gr_complex) * sync_symbol1.size())),
      d_fft_len(sync_symbol1.size()),
      d_n_data_syms(n_data_symbols),
      d_n_sync_syms(1),
      d_eq_noise_red_len(eq_noise_red_len),
      d_ref_sym((sync_symbol2.size() && !force_one_sync_symbol) ? sync_symbol2 : sync_symbol1),
      d_corr_v(sync_symbol2),
      d_known_symbol_diffs(0, 0),
      d_new_symbol_diffs(0, 0),
      d_first_active_carrier(0),
      d_last_active_carrier(sync_symbol2.size()-1),
      d_interpolate(false)
    {
      // Set index of first and last active carrier
      for (int i = 0; i < d_fft_len; i++) {
	if (d_ref_sym[i] != gr_complex(0, 0)) {
	  d_first_active_carrier = i;
	  break;
	}
      }
      for (int i = d_fft_len-1; i >= 0; i--) {
	if (d_ref_sym[i] != gr_complex(0, 0)) {
	  d_last_active_carrier = i;
	  break;
	}
      }

      // Sanity checks
      if (sync_symbol2.size()) {
	if (sync_symbol1.size() != sync_symbol2.size()) {
	  throw std::invalid_argument("sync symbols must have equal length.");
	}
	if (!force_one_sync_symbol) {
	  d_n_sync_syms = 2;
	}
      } else {
	if (sync_symbol1[d_first_active_carrier+1] == gr_complex(0, 0)) {
	  d_last_active_carrier++;
	  d_interpolate = true;
	}
      }

      // Set up coarse freq estimation info
      // Allow all possible values:
      d_max_neg_carr_offset = -d_first_active_carrier;
      d_max_pos_carr_offset = d_fft_len - d_last_active_carrier - 1;
      if (max_carr_offset != -1) {
	d_max_neg_carr_offset = std::max(-max_carr_offset, d_max_neg_carr_offset);
	d_max_pos_carr_offset = std::min(max_carr_offset, d_max_pos_carr_offset);
      }
      // Carrier offsets must be even
      if (d_max_neg_carr_offset % 2)
	d_max_neg_carr_offset++;
      if (d_max_pos_carr_offset % 2)
	d_max_pos_carr_offset--;

      if (d_n_sync_syms == 2) {
	for (int i = 0; i < d_fft_len; i++) {
	  if (sync_symbol1[i] == gr_complex(0, 0)) {
	    d_corr_v[i] = gr_complex(0, 0);
	  } else {
	    d_corr_v[i] /= sync_symbol1[i];
	  }
	}
      } else {
	d_corr_v.resize(0, 0);
	d_known_symbol_diffs.resize(d_fft_len, 0);
	d_new_symbol_diffs.resize(d_fft_len, 0);
	for (int i = d_first_active_carrier; i < d_last_active_carrier-2 && i < d_fft_len-2; i += 2) {
	  d_known_symbol_diffs[i] = std::norm(sync_symbol1[i] - sync_symbol1[i+2]);
	}
      }

      set_output_multiple(d_n_data_syms);
      set_relative_rate((double) d_n_data_syms / (d_n_data_syms + d_n_sync_syms));
      set_tag_propagation_policy(TPP_DONT);
    }

    ofdm_chanest_vcvc_impl::~ofdm_chanest_vcvc_impl()
    {
    }

    void
    ofdm_chanest_vcvc_impl::forecast (int noutput_items, gr_vector_int &ninput_items_required)
    {
      ninput_items_required[0] = (noutput_items/d_n_data_syms) * (d_n_data_syms + d_n_sync_syms);
    }

    int
    ofdm_chanest_vcvc_impl::get_carr_offset(const gr_complex *sync_sym1, const gr_complex *sync_sym2)
    {
      int carr_offset = 0;
      if (d_corr_v.size()) {
	// Use Schmidl & Cox method
	float Bg_max = 0;
	// g here is 2g in the paper
	for (int g = d_max_neg_carr_offset; g <= d_max_pos_carr_offset; g += 2) {
	  gr_complex tmp = gr_complex(0, 0);
	  for (int k = 0; k < d_fft_len; k++) {
	    if (d_corr_v[k] != gr_complex(0, 0)) {
	      tmp += std::conj(sync_sym1[k+g]) * std::conj(d_corr_v[k]) * sync_sym2[k+g];
	    }
	  }
	  if (std::abs(tmp) > Bg_max) {
	    Bg_max = std::abs(tmp);
	    carr_offset = g;
	  }
	}
      } else {
	// Correlate
	std::fill(d_new_symbol_diffs.begin(), d_new_symbol_diffs.end(), 0);
	for(int i = 0; i < d_fft_len-2; i++) {
	  d_new_symbol_diffs[i] = std::norm(sync_sym1[i] - sync_sym1[i+2]);
	}

	float sum;
	float max = 0;
	for (int g = d_max_neg_carr_offset; g <= d_max_pos_carr_offset; g += 2) {
	  sum = 0;
	  for (int j = 0; j < d_fft_len; j++) {
	    if (d_known_symbol_diffs[j]) {
	      sum += (d_known_symbol_diffs[j] * d_new_symbol_diffs[j + g]);
	    }
	    if(sum > max) {
	      max = sum;
	      carr_offset = g;
	    }
	  }
	}
      }
      return carr_offset;
    }


    void
    ofdm_chanest_vcvc_impl::get_chan_taps(
	const gr_complex *sync_sym1,
	const gr_complex *sync_sym2,
	int carr_offset,
	std::vector<gr_complex> &taps)
    {
      const gr_complex *sym = ((d_n_sync_syms == 2) ? sync_sym2 : sync_sym1);
      std::fill(taps.begin(), taps.end(), gr_complex(0, 0));
      int loop_start = 0;
      int loop_end = d_fft_len;
      if (carr_offset > 0) {
	loop_start = carr_offset;
      } else if (carr_offset < 0) {
	loop_end = d_fft_len + carr_offset;
      }
      for (int i = loop_start; i < loop_end; i++) {
	if ((d_ref_sym[i-carr_offset] != gr_complex(0, 0))) {
	  taps[i-carr_offset] = sym[i] / d_ref_sym[i-carr_offset];
	}
      }

      if (d_interpolate) {
	for (int i = d_first_active_carrier + 1; i < d_last_active_carrier; i += 2) {
	  taps[i] = taps[i-1];
	}
	taps[d_last_active_carrier] = taps[d_last_active_carrier-1];
      }

      if (d_eq_noise_red_len) {
	// TODO
	// 1) IFFT
	// 2) Set all elements > d_eq_noise_red_len to zero
	// 3) FFT
      }
    }


    // Operates on a per-frame basis
    int
    ofdm_chanest_vcvc_impl::general_work (int noutput_items,
                       gr_vector_int &ninput_items,
                       gr_vector_const_void_star &input_items,
                       gr_vector_void_star &output_items)
    {
      const gr_complex *in = (const gr_complex *) input_items[0];
      gr_complex *out = (gr_complex *) output_items[0];
      const int framesize = d_n_sync_syms + d_n_data_syms;

      // Channel info estimation
      int carr_offset = get_carr_offset(in, in+d_fft_len);
      std::vector<gr_complex> chan_taps(d_fft_len, 0);
      get_chan_taps(in, in+d_fft_len, carr_offset, chan_taps);
      add_item_tag(0, nitems_written(0),
	  pmt::string_to_symbol("ofdm_sync_carr_offset"),
	  pmt::from_long(carr_offset));
      add_item_tag(0, nitems_written(0),
	  pmt::string_to_symbol("ofdm_sync_chan_taps"),
	  pmt::init_c32vector(d_fft_len, chan_taps));

      // Copy data symbols
      if (output_items.size() == 2) {
	gr_complex *out_chantaps = ((gr_complex *) output_items[1]);
	memcpy((void *) out_chantaps, (void *) &chan_taps[0], sizeof(gr_complex) * d_fft_len);
	produce(1, 1);
      }
      memcpy((void *) out,
	     (void *) &in[d_n_sync_syms * d_fft_len],
	     sizeof(gr_complex) * d_fft_len * d_n_data_syms);

      // Propagate tags
      std::vector<gr::tag_t> tags;
      get_tags_in_range(tags, 0,
	  nitems_read(0),
	  nitems_read(0)+framesize);
      for (unsigned t = 0; t < tags.size(); t++) {
	int offset = tags[t].offset - nitems_read(0);
	if (offset < d_n_sync_syms) {
	  offset = 0;
	} else {
	  offset -= d_n_sync_syms;
	}
	tags[t].offset = offset + nitems_written(0);
	add_item_tag(0, tags[t]);
      }

      produce(0, d_n_data_syms);
      consume_each(framesize);
      return WORK_CALLED_PRODUCE;
    }

  } /* namespace digital */
} /* namespace gr */

/* -*- c++ -*- */
/* 
 * Copyright 2013 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.
 */

#ifndef INCLUDED_DIGITAL_OFDM_CHANEST_VCVC_IMPL_H
#define INCLUDED_DIGITAL_OFDM_CHANEST_VCVC_IMPL_H

#include <gnuradio/digital/ofdm_chanest_vcvc.h>

namespace gr {
  namespace digital {

    class ofdm_chanest_vcvc_impl : public ofdm_chanest_vcvc
    {
     private:
      int d_fft_len; //! FFT length
      int d_n_data_syms; //! Number of data symbols following the sync symbol(s)
      int d_n_sync_syms; //! Number of sync symbols (1 or 2)
      //! 0 if no noise reduction is done for the initial channel state estimation. Otherwise, the maximum length of the channel delay in samples.
      int d_eq_noise_red_len;
      //! Is sync_symbol1 if d_n_sync_syms == 1, otherwise sync_symbol2. Used as a reference symbol to estimate the channel.
      std::vector<gr_complex> d_ref_sym;
      //! If d_n_sync_syms == 2 this is used as a differential correlation vector (called 'v' in [1]).
      std::vector<gr_complex> d_corr_v;
      //! If d_n_sync_syms == 1 we use this instead of d_corr_v to estimate the coarse freq. offset
      std::vector<float> d_known_symbol_diffs;
      //! If d_n_sync_syms == 1 we use this instead of d_corr_v to estimate the coarse freq. offset (temp. variable)
      std::vector<float> d_new_symbol_diffs;
      //! The index of the first carrier with data (index 0 is not DC here, but the lowest frequency)
      int d_first_active_carrier;
      //! The index of the last carrier with data
      int d_last_active_carrier;
      //! If true, the channel estimation must be interpolated
      bool d_interpolate;
      //! Maximum carrier offset (negative value!)
      int d_max_neg_carr_offset;
      //! Maximum carrier offset (positive value!)
      int d_max_pos_carr_offset;

      //! Calculate the coarse frequency offset in number of carriers
      int get_carr_offset(const gr_complex *sync_sym1, const gr_complex *sync_sym2);
      //! Estimate the channel (phase and amplitude offset per carrier)
      void get_chan_taps(const gr_complex *sync_sym1, const gr_complex *sync_sym2, int carr_offset, std::vector<gr_complex> &taps);

     public:
      ofdm_chanest_vcvc_impl(const std::vector<gr_complex> &sync_symbol1, const std::vector<gr_complex> &sync_symbol2, int n_data_symbols, int eq_noise_red_len, int max_carr_offset, bool force_one_sync_symbol);
      ~ofdm_chanest_vcvc_impl();

      void forecast (int noutput_items, gr_vector_int &ninput_items_required);
      int general_work(int noutput_items,
		       gr_vector_int &ninput_items,
		       gr_vector_const_void_star &input_items,
		       gr_vector_void_star &output_items);
    };

  } // namespace digital
} // namespace gr

#endif /* INCLUDED_DIGITAL_OFDM_CHANEST_VCVC_IMPL_H */

/* -*- c++ -*- */
/* 
 * Copyright 2013 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.
 */

#ifndef INCLUDED_DIGITAL_OFDM_CHANEST_VCVC_H
#define INCLUDED_DIGITAL_OFDM_CHANEST_VCVC_H

#include <gnuradio/digital/api.h>
#include <gnuradio/block.h>

namespace gr {
  namespace digital {

    /*!
     * \brief Estimate channel and coarse frequency offset for OFDM from preambles
     * \ingroup ofdm_blk
     * \ingroup syncronizers_blk
     *
     * Input: OFDM symbols (in frequency domain). The first one (or two) symbols are expected
     *        to be synchronisation symbols, which are used to estimate the coarse freq offset
     *        and the initial equalizer taps (these symbols are removed from the stream).
     *        The following \p n_data_symbols are passed through unmodified (the actual equalisation
     *        must be done elsewhere).
     * Output: The data symbols, without the synchronisation symbols.
     *         The first data symbol passed through has two tags:
     *         'ofdm_sync_carr_offset' (integer), the coarse frequency offset as number of carriers,
     *         and 'ofdm_sync_eq_taps' (complex vector).
     *         Any tags attached to the synchronisation symbols are attached to the first data
     *         symbol. All other tags are propagated as expected.
     *
     * Note: The vector on ofdm_sync_eq_taps is already frequency-corrected, whereas the rest is not.
     *
     * This block assumes the frequency offset is even (i.e. an integer multiple of 2).
     *
     * [1] Schmidl, T.M. and Cox, D.C., "Robust frequency and timing synchronization for OFDM",
     *     Communications, IEEE Transactions on, 1997.
     * [2] K.D. Kammeyer, "Nachrichtenuebertragung," Chapter. 16.3.2.
     */
    class DIGITAL_API ofdm_chanest_vcvc : virtual public block
    {
     public:
      typedef boost::shared_ptr<ofdm_chanest_vcvc> sptr;

      /*!
       * \param sync_symbol1 First synchronisation symbol in the frequency domain. Its length must be
       *                     the FFT length. For Schmidl & Cox synchronisation, every second sub-carrier
       *                     has to be zero.
       * \param sync_symbol2 Second synchronisation symbol in the frequency domain. Must be equal to
       *                     the FFT length, or zero length if only one synchronisation symbol is used.
       *                     Using this symbol is how synchronisation is described in [1]. Leaving this
       *                     empty forces us to interpolate the equalizer taps.
       *                     If you are using an unusual sub-carrier configuration (e.g. because of OFDMA),
       *                     this sync symbol is used to identify the active sub-carriers. If you only
       *                     have one synchronisation symbol, set the active sub-carriers to a non-zero
       *                     value in here, and also set \p force_one_sync_symbol parameter to true.
       * \param n_data_symbols The number of data symbols following each set of synchronisation symbols.
       *                       Must be at least 1.
       * \param eq_noise_red_len If non-zero, noise reduction for the equalizer taps is done according
       *                         to [2]. In this case, it is the channel influence time in number of
       *                         samples. A good value is usually the length of the cyclic prefix.
       * \param max_carr_offset Limit the number of sub-carriers the frequency offset can maximally be.
       *                        Leave this zero to try all possibilities.
       * \param force_one_sync_symbol See \p sync_symbol2.
       */
      static sptr make(
	  const std::vector<gr_complex> &sync_symbol1,
	  const std::vector<gr_complex> &sync_symbol2,
	  int n_data_symbols,
	  int eq_noise_red_len=0,
	  int max_carr_offset=-1,
	  bool force_one_sync_symbol=false
      );
    };

  } // namespace digital
} // namespace gr

#endif /* INCLUDED_DIGITAL_OFDM_CHANEST_VCVC_H */

/* -*- c++ -*- */
/* 
 * Copyright 2015 <+YOU OR YOUR COMPANY+>.
 * 
 * This 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.
 * 
 * This software 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 this software; see the file COPYING.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street,
 * Boston, MA 02110-1301, USA.
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <gnuradio/io_signature.h>
#include "ofdm_chanest_MMSE_vcvc_impl.h"

namespace gr {
  namespace Channel_Estimation {

    ofdm_chanest_MMSE_vcvc::sptr
    ofdm_chanest_MMSE_vcvc::make(const std::vector<gr_complex> &sync_symbol1, const std::vector<gr_complex> &sync_symbol2, int n_data_symbols, int eq_noise_red_len, int max_carr_offset, bool force_one_sync_symbol, float noise_voltage)
    {
      return gnuradio::get_initial_sptr
        (new ofdm_chanest_MMSE_vcvc_impl(
	    sync_symbol1,
	    sync_symbol2,
	    n_data_symbols,
	    eq_noise_red_len,
	    max_carr_offset,
	    force_one_sync_symbol,
	    noise_voltage
	)
      );
    }

    /*
     * The private constructor
     */
    ofdm_chanest_MMSE_vcvc_impl::ofdm_chanest_MMSE_vcvc_impl(
	    const std::vector<gr_complex> &sync_symbol1,
	    const std::vector<gr_complex> &sync_symbol2,
	    int n_data_symbols,
	    int eq_noise_red_len,
	    int max_carr_offset,
	    bool force_one_sync_symbol,
	    float noise_voltage)
      : gr::block("ofdm_chanest_MMSE_vcvc",
              gr::io_signature::make(1, 1, sizeof (gr_complex) * sync_symbol1.size()),
              gr::io_signature::make(1, 2, sizeof (gr_complex) * sync_symbol1.size()),
      d_noise_voltage(noise_voltage),
      d_fft_len(sync_symbol1.size()),
      d_n_data_syms(n_data_symbols),
      d_n_sync_syms(1),
      d_eq_noise_red_len(eq_noise_red_len),
      d_ref_sym((sync_symbol2.size() && !force_one_sync_symbol) ? sync_symbol2 : sync_symbol1),
      d_corr_v(sync_symbol2),
      d_known_symbol_diffs(0, 0),
      d_new_symbol_diffs(0, 0),
      d_first_active_carrier(0),
      d_last_active_carrier(sync_symbol2.size()-1),
      d_interpolate(false)
      
    {
      // Set index of first and last active carrier
      for (int i = 0; i < d_fft_len; i++) {
	if (d_ref_sym[i] != gr_complex(0, 0)) {
	  d_first_active_carrier = i;
	  break;
	}
      }
      for (int i = d_fft_len-1; i >= 0; i--) {
	if (d_ref_sym[i] != gr_complex(0, 0)) {
	  d_last_active_carrier = i;
	  break;
	}
      }

      // Sanity checks
      if (sync_symbol2.size()) {
	if (sync_symbol1.size() != sync_symbol2.size()) {
	  throw std::invalid_argument("sync symbols must have equal length.");
	}
	if (!force_one_sync_symbol) {
	  d_n_sync_syms = 2;
	}
      } else {
	if (sync_symbol1[d_first_active_carrier+1] == gr_complex(0, 0)) {
	  d_last_active_carrier++;
	  d_interpolate = true;
	}
      }

      // Set up coarse freq estimation info
      // Allow all possible values:
      d_max_neg_carr_offset = -d_first_active_carrier;
      d_max_pos_carr_offset = d_fft_len - d_last_active_carrier - 1;
      if (max_carr_offset != -1) {
	d_max_neg_carr_offset = std::max(-max_carr_offset, d_max_neg_carr_offset);
	d_max_pos_carr_offset = std::min(max_carr_offset, d_max_pos_carr_offset);
      }
      // Carrier offsets must be even
      if (d_max_neg_carr_offset % 2)
	d_max_neg_carr_offset++;
      if (d_max_pos_carr_offset % 2)
	d_max_pos_carr_offset--;

      if (d_n_sync_syms == 2) {
	for (int i = 0; i < d_fft_len; i++) {
	  if (sync_symbol1[i] == gr_complex(0, 0)) {
	    d_corr_v[i] = gr_complex(0, 0);
	  } else {
	    d_corr_v[i] /= sync_symbol1[i];
	  }
	}
      } else {
	d_corr_v.resize(0, 0);
	d_known_symbol_diffs.resize(d_fft_len, 0);
	d_new_symbol_diffs.resize(d_fft_len, 0);
	for (int i = d_first_active_carrier; i < d_last_active_carrier-2 && i < d_fft_len-2; i += 2) {
	  d_known_symbol_diffs[i] = std::norm(sync_symbol1[i] - sync_symbol1[i+2]);
	}
      }

      set_output_multiple(d_n_data_syms);
      set_relative_rate((double) d_n_data_syms / (d_n_data_syms + d_n_sync_syms));
      set_tag_propagation_policy(TPP_DONT);
    }

    ofdm_chanest_vcvc_impl::~ofdm_chanest_vcvc_impl()
    {
    }

    /*
     * Our virtual destructor.
     */
    ofdm_chanest_MMSE_vcvc_impl::~ofdm_chanest_MMSE_vcvc_impl()
    {
    }

    void
    ofdm_chanest_vcvc_impl::forecast (int noutput_items, gr_vector_int &ninput_items_required)
    { /* <+forecast+> e.g. ninput_items_required[0] = noutput_items */

      ninput_items_required[0] = (noutput_items/d_n_data_syms) * (d_n_data_syms + d_n_sync_syms);
    }


    int
    ofdm_chanest_vcvc_impl::get_carr_offset(const gr_complex *sync_sym1, const gr_complex *sync_sym2)
    {
      int carr_offset = 0;
      if (d_corr_v.size()) {
	// Use Schmidl & Cox method
	float Bg_max = 0;
	// g here is 2g in the paper
	for (int g = d_max_neg_carr_offset; g <= d_max_pos_carr_offset; g += 2) {
	  gr_complex tmp = gr_complex(0, 0);
	  for (int k = 0; k < d_fft_len; k++) {
	    if (d_corr_v[k] != gr_complex(0, 0)) {
	      tmp += std::conj(sync_sym1[k+g]) * std::conj(d_corr_v[k]) * sync_sym2[k+g];
	    }
	  }
	  if (std::abs(tmp) > Bg_max) {
	    Bg_max = std::abs(tmp);
	    carr_offset = g;
	  }
	}
      } else {
	// Correlate
	std::fill(d_new_symbol_diffs.begin(), d_new_symbol_diffs.end(), 0);
	for(int i = 0; i < d_fft_len-2; i++) {
	  d_new_symbol_diffs[i] = std::norm(sync_sym1[i] - sync_sym1[i+2]);
	}

	float sum;
	float max = 0;
	for (int g = d_max_neg_carr_offset; g <= d_max_pos_carr_offset; g += 2) {
	  sum = 0;
	  for (int j = 0; j < d_fft_len; j++) {
	    if (d_known_symbol_diffs[j]) {
	      sum += (d_known_symbol_diffs[j] * d_new_symbol_diffs[j + g]);
	    }
	    if(sum > max) {
	      max = sum;
	      carr_offset = g;
	    }
	  }
	}
      }
      return carr_offset;
    }


    void
    ofdm_chanest_vcvc_impl::get_chan_taps(
	const gr_complex *sync_sym1,
	const gr_complex *sync_sym2,
	int carr_offset,
	std::vector<gr_complex> &taps, 
        float noise_voltage)
    {
      const gr_complex *sym = ((d_n_sync_syms == 2) ? sync_sym2 : sync_sym1);
      std::fill(taps.begin(), taps.end(), gr_complex(0, 0));
      int loop_start = 0;
      int loop_end = d_fft_len;
      if (carr_offset > 0) {
	loop_start = carr_offset;
      } else if (carr_offset < 0) {
	loop_end = d_fft_len + carr_offset;
      }
      for (int i = loop_start; i < loop_end; i++) {
	if ((d_ref_sym[i-carr_offset] != gr_complex(0, 0))) {
	  taps[i-carr_offset] = sym[i]*conj(d_ref_sym[i-carr_offset])/(pow(d_noise_voltage,2.0)+pow(abs(d_ref_sym[i-carr_offset]),2.0)); //sym[i] / d_ref_sym[i-carr_offset];
	}
      }

      if (d_interpolate) {
	for (int i = d_first_active_carrier + 1; i < d_last_active_carrier; i += 2) {
	  taps[i] = taps[i-1];
	}
	taps[d_last_active_carrier] = taps[d_last_active_carrier-1];
      }

      if (d_eq_noise_red_len) {
	// TODO
	// 1) IFFT
	// 2) Set all elements > d_eq_noise_red_len to zero
	// 3) FFT
      }
    }



// Operates on a per-frame basis
    int
    ofdm_chanest_MMSE_vcvc_impl::general_work (int noutput_items,
                       gr_vector_int &ninput_items,
                       gr_vector_const_void_star &input_items,
                       gr_vector_void_star &output_items)
    {
       // const <+ITYPE*> *in = (const <+ITYPE*> *) input_items[0];
       // <+OTYPE*> *out = (<+OTYPE*> *) output_items[0];
      const gr_complex *in = (const gr_complex *) input_items[0];
      gr_complex *out = (gr_complex *) output_items[0];
      const int framesize = d_n_sync_syms + d_n_data_syms;  
        // Do <+signal processing+>
        // Tell runtime system how many input items we consumed on
        // each input stream.
        //consume_each (noutput_items);

        // Tell runtime system how many output items we produced.
       //return noutput_items;

 // Channel info estimation
      int carr_offset = get_carr_offset(in, in+d_fft_len);
      std::vector<gr_complex> chan_taps(d_fft_len, 0);
      get_chan_taps(in, in+d_fft_len, carr_offset, chan_taps);
      add_item_tag(0, nitems_written(0),
	  pmt::string_to_symbol("ofdm_sync_carr_offset"),
	  pmt::from_long(carr_offset));
      add_item_tag(0, nitems_written(0),
	  pmt::string_to_symbol("ofdm_sync_chan_taps"),
	  pmt::init_c32vector(d_fft_len, chan_taps));

      // Copy data symbols
      if (output_items.size() == 2) {
	gr_complex *out_chantaps = ((gr_complex *) output_items[1]);
	memcpy((void *) out_chantaps, (void *) &chan_taps[0], sizeof(gr_complex) * d_fft_len);
	produce(1, 1);
      }
      memcpy((void *) out,
	     (void *) &in[d_n_sync_syms * d_fft_len],
	     sizeof(gr_complex) * d_fft_len * d_n_data_syms);

      // Propagate tags
      std::vector<gr::tag_t> tags;
      get_tags_in_range(tags, 0,
	  nitems_read(0),
	  nitems_read(0)+framesize);
      for (unsigned t = 0; t < tags.size(); t++) {
	int offset = tags[t].offset - nitems_read(0);
	if (offset < d_n_sync_syms) {
	  offset = 0;
	} else {
	  offset -= d_n_sync_syms;
	}
	tags[t].offset = offset + nitems_written(0);
	add_item_tag(0, tags[t]);
      }

      produce(0, d_n_data_syms);
      consume_each(framesize);
      return WORK_CALLED_PRODUCE;

    }


  } /* namespace Channel_Estimation */
} /* namespace gr */

/* -*- c++ -*- */
/* 
 * Copyright 2015 <+YOU OR YOUR COMPANY+>.
 * 
 * This 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.
 * 
 * This software 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 this software; see the file COPYING.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street,
 * Boston, MA 02110-1301, USA.
 */

#ifndef INCLUDED_CHANNEL_ESTIMATION_OFDM_CHANEST_MMSE_VCVC_IMPL_H
#define INCLUDED_CHANNEL_ESTIMATION_OFDM_CHANEST_MMSE_VCVC_IMPL_H

#include <Channel_Estimation/ofdm_chanest_MMSE_vcvc.h>

namespace gr {
  namespace Channel_Estimation {

    class ofdm_chanest_MMSE_vcvc_impl : public ofdm_chanest_MMSE_vcvc
    {
     private:
      // Nothing to declare in this block.
      float d_noise_voltage;
      int d_fft_len; //! FFT length
      int d_n_data_syms; //! Number of data symbols following the sync symbol(s)
      int d_n_sync_syms; //! Number of sync symbols (1 or 2)
      //! 0 if no noise reduction is done for the initial channel state estimation. Otherwise, the maximum length of the channel delay in samples.
      int d_eq_noise_red_len;
      //! Is sync_symbol1 if d_n_sync_syms == 1, otherwise sync_symbol2. Used as a reference symbol to estimate the channel.
      std::vector<gr_complex> d_ref_sym;
      //! If d_n_sync_syms == 2 this is used as a differential correlation vector (called 'v' in [1]).
      std::vector<gr_complex> d_corr_v;
      //! If d_n_sync_syms == 1 we use this instead of d_corr_v to estimate the coarse freq. offset
      std::vector<float> d_known_symbol_diffs;
      //! If d_n_sync_syms == 1 we use this instead of d_corr_v to estimate the coarse freq. offset (temp. variable)
      std::vector<float> d_new_symbol_diffs;
      //! The index of the first carrier with data (index 0 is not DC here, but the lowest frequency)
      int d_first_active_carrier;
      //! The index of the last carrier with data
      int d_last_active_carrier;
      //! If true, the channel estimation must be interpolated
      bool d_interpolate;
      //! Maximum carrier offset (negative value!)
      int d_max_neg_carr_offset;
      //! Maximum carrier offset (positive value!)
      int d_max_pos_carr_offset;

      //! Calculate the coarse frequency offset in number of carriers
      int get_carr_offset(const gr_complex *sync_sym1, const gr_complex *sync_sym2);
      //! Estimate the channel (phase and amplitude offset per carrier)
      void get_chan_taps(const gr_complex *sync_sym1, const gr_complex *sync_sym2, int carr_offset, std::vector<gr_complex> &taps);
      
     public:
      ofdm_chanest_MMSE_vcvc_impl(const std::vector<gr_complex> &sync_symbol1, const std::vector<gr_complex> &sync_symbol2, int n_data_symbols, int eq_noise_red_len, int max_carr_offset, bool force_one_sync_symbol, float noise_voltage);
      ~ofdm_chanest_MMSE_vcvc_impl();

      // Where all the action really happens
      void forecast (int noutput_items, gr_vector_int &ninput_items_required);

      int general_work(int noutput_items,
		       gr_vector_int &ninput_items,
		       gr_vector_const_void_star &input_items,
		       gr_vector_void_star &output_items);
    };

  } // namespace Channel_Estimation
} // namespace gr

#endif /* INCLUDED_CHANNEL_ESTIMATION_OFDM_CHANEST_MMSE_VCVC_IMPL_H */

/* -*- c++ -*- */
/* 
 * Copyright 2015 <+YOU OR YOUR COMPANY+>.
 * 
 * This 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.
 * 
 * This software 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 this software; see the file COPYING.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street,
 * Boston, MA 02110-1301, USA.
 */


#ifndef INCLUDED_CHANNEL_ESTIMATION_OFDM_CHANEST_MMSE_VCVC_H
#define INCLUDED_CHANNEL_ESTIMATION_OFDM_CHANEST_MMSE_VCVC_H

#include <Channel_Estimation/api.h>
#include <gnuradio/block.h>

namespace gr {
  namespace Channel_Estimation {

    /*!
     * \brief <+description of block+>
     * \ingroup Channel_Estimation
     *
     */
    class CHANNEL_ESTIMATION_API ofdm_chanest_MMSE_vcvc : virtual public gr::block
    {
     public:
      typedef boost::shared_ptr<ofdm_chanest_MMSE_vcvc> sptr;

      /*!
       * \brief Return a shared_ptr to a new instance of Channel_Estimation::ofdm_chanest_MMSE_vcvc.
       *
       * To avoid accidental use of raw pointers, Channel_Estimation::ofdm_chanest_MMSE_vcvc's
       * constructor is in a private implementation
       * class. Channel_Estimation::ofdm_chanest_MMSE_vcvc::make is the public interface for
       * creating new instances.
       */
      static sptr make(
	  const std::vector<gr_complex> &sync_symbol1,
	  const std::vector<gr_complex> &sync_symbol2,
	  int n_data_symbols,
	  int eq_noise_red_len=0,
	  int max_carr_offset=-1,
	  bool force_one_sync_symbol=false,
	  float noise_voltage = 0.0
      );
    };

  } // namespace Channel_Estimation
} // namespace gr

#endif /* INCLUDED_CHANNEL_ESTIMATION_OFDM_CHANEST_MMSE_VCVC_H */

_______________________________________________
Discuss-gnuradio mailing list
Discuss-gnuradio@gnu.org
https://lists.gnu.org/mailman/listinfo/discuss-gnuradio

Reply via email to