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 <[email protected]> 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
>> [email protected]
>> https://lists.gnu.org/mailman/listinfo/discuss-gnuradio
>>
>>
>
> _______________________________________________
> Discuss-gnuradio mailing list
> [email protected]
> 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
[email protected]
https://lists.gnu.org/mailman/listinfo/discuss-gnuradio