diff options
author | trondeau <trondeau@221aa14e-8319-0410-a670-987f0aec2ac5> | 2008-04-17 14:37:19 +0000 |
---|---|---|
committer | trondeau <trondeau@221aa14e-8319-0410-a670-987f0aec2ac5> | 2008-04-17 14:37:19 +0000 |
commit | b96d58fda01e00e8a9f710824dffe9123d93e35f (patch) | |
tree | 42955f45614f575974cf5266d4bbc76b7c22c105 | |
parent | 8bce0d9e3f61b4af7799ed519109b83b926d4e12 (diff) |
Improved the pnac ofdm sync block. This is based on a VTC'99 paper by Tufvesson, et al. that does a bit more work than the Schmidl and Cox to produce a more identifiable peak for the timing. This seems to work well in the simulation for low frequency errors. The correlation doesn't seem to track well, though. See the comments for more info. Also, the peak detection requires unity amplitude for the threshold detection. So, who wants to make an OFDM AGC?
git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@8217 221aa14e-8319-0410-a670-987f0aec2ac5
-rw-r--r-- | gnuradio-core/src/python/gnuradio/blks2impl/ofdm_sync_pnac.py | 74 |
1 files changed, 43 insertions, 31 deletions
diff --git a/gnuradio-core/src/python/gnuradio/blks2impl/ofdm_sync_pnac.py b/gnuradio-core/src/python/gnuradio/blks2impl/ofdm_sync_pnac.py index 89f70ed2b4..10a1259641 100644 --- a/gnuradio-core/src/python/gnuradio/blks2impl/ofdm_sync_pnac.py +++ b/gnuradio-core/src/python/gnuradio/blks2impl/ofdm_sync_pnac.py @@ -26,7 +26,25 @@ from gnuradio import gr class ofdm_sync_pnac(gr.hier_block2): def __init__(self, fft_length, cp_length, kstime, logging=False): - + """ + OFDM synchronization using PN Correlation and initial cross-correlation: + F. Tufvesson, O. Edfors, and M. Faulkner, "Time and Frequency Synchronization for OFDM using + PN-Sequency Preambles," IEEE Proc. VTC, 1999, pp. 2203-2207. + + This implementation is meant to be a more robust version of the Schmidl and Cox receiver design. + By correlating against the preamble and using that as the input to the time-delayed correlation, + this circuit produces a very clean timing signal at the end of the preamble. The timing is + more accurate and does not have the problem associated with determining the timing from the + plateau structure in the Schmidl and Cox. + + This implementation appears to require that the signal is received with a normalized power or signal + scalling factor to reduce ambiguities intorduced from partial correlation of the cyclic prefix and + the peak detection. A better peak detection block might fix this. + + Also, the cross-correlation falls apart as the frequency offset gets larger and completely fails + when an integer offset is introduced. Another thing to look at. + """ + gr.hier_block2.__init__(self, "ofdm_sync_pnac", gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature gr.io_signature2(2, 2, gr.sizeof_float, gr.sizeof_char)) # Output signature @@ -42,7 +60,6 @@ class ofdm_sync_pnac(gr.hier_block2): kstime = [k.conjugate() for k in kstime[0:fft_length//2]] kstime.reverse() self.crosscorr_filter = gr.fir_filter_ccc(1, kstime) - self.connect(self.crosscorr_filter, gr.file_sink(gr.sizeof_gr_complex, "crosscorr.dat")) # Create a delay line self.delay = gr.delay(gr.sizeof_gr_complex, fft_length/2) @@ -51,63 +68,58 @@ class ofdm_sync_pnac(gr.hier_block2): self.conjg = gr.conjugate_cc(); self.corr = gr.multiply_cc(); - # Create a moving sum filter for the corr output - moving_sum_taps = [1.0 for i in range(fft_length//2)] - self.moving_sum_filter = gr.fir_filter_ccf(1,moving_sum_taps) - # Create a moving sum filter for the input - self.inputmag2 = gr.complex_to_mag_squared() - movingsum2_taps = [1.0 for i in range(fft_length//2)] - self.inputmovingsum = gr.fir_filter_fff(1,movingsum2_taps) - self.square = gr.multiply_ff() - self.normalize = gr.divide_ff() + self.mag = gr.complex_to_mag_squared() + movingsum_taps = (fft_length//1)*[1.0,] + self.power = gr.fir_filter_fff(1,movingsum_taps) # Get magnitude (peaks) and angle (phase/freq error) self.c2mag = gr.complex_to_mag_squared() self.angle = gr.complex_to_arg() - + self.compare = gr.sub_ff() + self.sample_and_hold = gr.sample_and_hold_ff() #ML measurements input to sampler block and detect - self.sub1 = gr.add_const_ff(-1) - self.pk_detect = gr.peak_detector_fb(0.20, 0.20, 30, 0.001) + self.threshold = gr.threshold_ff(0,0,0) # threshold detection might need to be tweaked + self.peaks = gr.float_to_char() self.connect(self, self.input) # Cross-correlate input signal with known preamble self.connect(self.input, self.crosscorr_filter) - # use the output of the cross-correlation as input to Schmidl&Cox + # use the output of the cross-correlation as input time-shifted correlation self.connect(self.crosscorr_filter, self.delay) self.connect(self.crosscorr_filter, (self.corr,0)) self.connect(self.delay, self.conjg) self.connect(self.conjg, (self.corr,1)) - self.connect(self.corr, self.moving_sum_filter) - self.connect(self.moving_sum_filter, self.c2mag) - self.connect(self.moving_sum_filter, self.angle) + self.connect(self.corr, self.c2mag) + self.connect(self.corr, self.angle) self.connect(self.angle, (self.sample_and_hold,0)) + + # Get the power of the input signal to compare against the correlation + self.connect(self.crosscorr_filter, self.mag, self.power) - # Get the power of the input signal to normalize the output of the correlation - self.connect(self.crosscorr_filter, self.inputmag2, self.inputmovingsum) - self.connect(self.inputmovingsum, (self.square,0)) - self.connect(self.inputmovingsum, (self.square,1)) - self.connect(self.square, (self.normalize,1)) - self.connect(self.c2mag, (self.normalize,0)) - - self.connect(self.normalize, self.sub1, self.pk_detect) - self.connect(self.pk_detect, (self.sample_and_hold,1)) + # Compare the power to the correlator output to determine timing peak + # When the peak occurs, it peaks above zero, so the thresholder detects this + self.connect(self.c2mag, (self.compare,0)) + self.connect(self.power, (self.compare,1)) + self.connect(self.compare, self.threshold) + self.connect(self.threshold, self.peaks, (self.sample_and_hold,1)) # Set output signals # Output 0: fine frequency correction value # Output 1: timing signal self.connect(self.sample_and_hold, (self,0)) - self.connect(self.pk_detect, (self,1)) + self.connect(self.peaks, (self,1)) if logging: + self.connect(self.compare, gr.file_sink(gr.sizeof_float, "ofdm_sync_pnac-compare_f.dat")) self.connect(self.c2mag, gr.file_sink(gr.sizeof_float, "ofdm_sync_pnac-theta_f.dat")) - self.connect(self.normalize, gr.file_sink(gr.sizeof_float, "ofdm_sync_pnac-normalized_f.dat")) - self.connect(self.sub1, gr.file_sink(gr.sizeof_float, "ofdm_sync_pnac-sub1_f.dat")) + self.connect(self.power, gr.file_sink(gr.sizeof_float, "ofdm_sync_pnac-inputpower_f.dat")) self.connect(self.angle, gr.file_sink(gr.sizeof_float, "ofdm_sync_pnac-epsilon_f.dat")) - self.connect(self.pk_detect, gr.file_sink(gr.sizeof_char, "ofdm_sync_pnac-peaks_b.dat")) + self.connect(self.threshold, gr.file_sink(gr.sizeof_float, "ofdm_sync_pnac-threshold_f.dat")) + self.connect(self.peaks, gr.file_sink(gr.sizeof_char, "ofdm_sync_pnac-peaks_b.dat")) self.connect(self.sample_and_hold, gr.file_sink(gr.sizeof_float, "ofdm_sync_pnac-sample_and_hold_f.dat")) self.connect(self.input, gr.file_sink(gr.sizeof_gr_complex, "ofdm_sync_pnac-input_c.dat")) |