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