3 * Copyright 2006, 2007 Free Software Foundation, Inc.
5 * This file is part of GNU Radio
7 * GNU Radio is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2, or (at your option)
12 * GNU Radio is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with GNU Radio; see the file COPYING. If not, write to
19 * the Free Software Foundation, Inc., 51 Franklin Street,
20 * Boston, MA 02110-1301, USA.
27 #include <gr_ofdm_correlator.h>
28 #include <gr_io_signature.h>
32 #define M_TWOPI (2*M_PI)
33 #define MAX_NUM_SYMBOLS 1000
35 gr_ofdm_correlator_sptr
36 gr_make_ofdm_correlator (unsigned int occupied_carriers, unsigned int fft_length,
38 const std::vector<gr_complex> &known_symbol1,
39 const std::vector<gr_complex> &known_symbol2,
40 unsigned int max_fft_shift_len)
42 return gr_ofdm_correlator_sptr (new gr_ofdm_correlator (occupied_carriers, fft_length, cplen,
43 known_symbol1, known_symbol2,
47 gr_ofdm_correlator::gr_ofdm_correlator (unsigned occupied_carriers, unsigned int fft_length,
49 const std::vector<gr_complex> &known_symbol1,
50 const std::vector<gr_complex> &known_symbol2,
51 unsigned int max_fft_shift_len)
52 : gr_block ("ofdm_correlator",
53 gr_make_io_signature (1, 1, sizeof(gr_complex)*fft_length),
54 gr_make_io_signature2 (2, 2, sizeof(gr_complex)*occupied_carriers, sizeof(char))),
55 d_occupied_carriers(occupied_carriers),
56 d_fft_length(fft_length),
58 d_freq_shift_len(max_fft_shift_len),
59 d_known_symbol1(known_symbol1),
60 d_known_symbol2(known_symbol2),
64 d_diff_corr_factor.resize(d_occupied_carriers);
65 d_hestimate.resize(d_occupied_carriers);
67 std::vector<gr_complex>::iterator i1, i2;
69 unsigned int i = 0, j = 0;
70 gr_complex one(1.0, 0.0);
71 for(i1 = d_known_symbol1.begin(), i2 = d_known_symbol2.begin(); i1 != d_known_symbol1.end(); i1++, i2++) {
72 d_diff_corr_factor[i] = one / ((*i1) * conj(*i2));
76 d_phase_lut = new gr_complex[(2*d_freq_shift_len+1) * MAX_NUM_SYMBOLS];
77 for(i = 0; i <= 2*d_freq_shift_len; i++) {
78 for(j = 0; j < MAX_NUM_SYMBOLS; j++) {
79 d_phase_lut[j + i*MAX_NUM_SYMBOLS] = gr_expj(-M_TWOPI*d_cplen/d_fft_length*(i-d_freq_shift_len)*j);
84 gr_ofdm_correlator::~gr_ofdm_correlator(void)
86 delete [] d_phase_lut;
90 gr_ofdm_correlator::forecast (int noutput_items, gr_vector_int &ninput_items_required)
92 unsigned ninputs = ninput_items_required.size ();
93 for (unsigned i = 0; i < ninputs; i++)
94 ninput_items_required[i] = 2;
98 gr_ofdm_correlator::coarse_freq_comp(int freq_delta, int symbol_count)
100 // return gr_complex(cos(-M_TWOPI*freq_delta*d_cplen/d_fft_length*symbol_count),
101 // sin(-M_TWOPI*freq_delta*d_cplen/d_fft_length*symbol_count));
102 //return gr_expj(-M_TWOPI*freq_delta*d_cplen/d_fft_length*symbol_count);
104 assert(d_freq_shift_len + freq_delta >= 0);
105 assert(symbol_count <= MAX_NUM_SYMBOLS);
107 return d_phase_lut[MAX_NUM_SYMBOLS * (d_freq_shift_len + freq_delta) + symbol_count];
111 gr_ofdm_correlator::correlate(const gr_complex *previous, const gr_complex *current,
115 int search_delta = 0;
118 gr_complex h_sqrd = gr_complex(0.0,0.0);
121 while(!found && ((unsigned)abs(search_delta) < d_freq_shift_len)) {
122 h_sqrd = gr_complex(0.0,0.0);
125 for(i = 0; i < d_occupied_carriers; i++) {
126 h_sqrd = h_sqrd + previous[i+zeros_on_left+search_delta] *
127 conj(coarse_freq_comp(search_delta,1)*current[i+zeros_on_left+search_delta]) *
128 d_diff_corr_factor[i];
129 power = power + norm(current[i+zeros_on_left+search_delta]); // No need to do coarse freq here
133 printf("bin %d\th_sqrd = ( %f, %f )\t power = %f\t real(h)/p = %f\t angle = %f\n",
134 search_delta, h_sqrd.real(), h_sqrd.imag(), power, h_sqrd.real()/power, arg(h_sqrd));
137 // FIXME: Look at h_sqrd.read() > power
138 if((h_sqrd.real() > 0.82*power) && (h_sqrd.real() < 1.1 * power)) {
140 d_coarse_freq = search_delta;
142 //d_snr_est = 10*log10(power/(power-h_sqrd.real()));
144 // check for low noise power; sets maximum SNR at 100 dB
145 if(fabs(h_sqrd.imag()) <= 1e-12) {
149 d_snr_est = 10*log10(fabs(h_sqrd.real()/h_sqrd.imag()));
153 printf("CORR: Found, bin %d\tSNR Est %f dB\tcorr power fraction %f\n",
154 search_delta, d_snr_est, h_sqrd.real()/power);
157 // search_delta,10*log10(h_sqrd.real()/fabs(h_sqrd.imag())),h_sqrd.real()/power);
161 if(search_delta <= 0)
162 search_delta = (-search_delta) + 2;
164 search_delta = -search_delta;
171 gr_ofdm_correlator::calculate_equalizer(const gr_complex *previous, const gr_complex *current,
176 for(i = 0; i < d_occupied_carriers; i++) {
177 // FIXME possibly add small epsilon in divisor to protect from div 0
178 //d_hestimate[i] = 0.5F * (d_known_symbol1[i] / previous[i+zeros_on_left] +
179 // d_known_symbol2[i] / (coarse_freq_comp(d_coarse_freq,1)*
180 // current[i+zeros_on_left+d_coarse_freq]));
181 d_hestimate[i] = 0.5F * (d_known_symbol1[i] / previous[i+zeros_on_left+d_coarse_freq] +
182 d_known_symbol2[i] / (coarse_freq_comp(d_coarse_freq,1)*
183 current[i+zeros_on_left+d_coarse_freq]));
186 fprintf(stderr, "\n");
191 gr_ofdm_correlator::general_work(int noutput_items,
192 gr_vector_int &ninput_items,
193 gr_vector_const_void_star &input_items,
194 gr_vector_void_star &output_items)
196 const gr_complex *in = (const gr_complex *)input_items[0];
197 const gr_complex *previous = &in[0];
198 const gr_complex *current = &in[d_fft_length];
200 gr_complex *out = (gr_complex *) output_items[0];
201 char *sig = (char *) output_items[1];
205 int unoccupied_carriers = d_fft_length - d_occupied_carriers;
206 int zeros_on_left = (int)ceil(unoccupied_carriers/2.0);
208 bool corr = correlate(previous, current, zeros_on_left);
210 calculate_equalizer(previous, current, zeros_on_left);
217 for(i = 0; i < d_occupied_carriers; i++) {
218 out[i] = d_hestimate[i]*coarse_freq_comp(d_coarse_freq,d_phase_count)*current[i+zeros_on_left+d_coarse_freq];