def __init__(self, fft_length, cp_length, snr, kstime, logging): ''' Maximum Likelihood OFDM synchronizer: J. van de Beek, M. Sandell, and P. O. Borjesson, "ML Estimation of Time and Frequency Offset in OFDM Systems," IEEE Trans. Signal Processing, vol. 45, no. 7, pp. 1800-1805, 1997. ''' gr.hier_block2.__init__(self, "ofdm_sync_ml", gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature gr.io_signature2(2, 2, gr.sizeof_float, gr.sizeof_char)) # Output signature self.input = blocks.add_const_cc(0) SNR = 10.0**(snr / 10.0) rho = SNR / (SNR + 1.0) symbol_length = fft_length + cp_length # ML Sync # Energy Detection from ML Sync self.connect(self, self.input) # Create a delay line self.delay = blocks.delay(gr.sizeof_gr_complex, fft_length) self.connect(self.input, self.delay) # magnitude squared blocks self.magsqrd1 = blocks.complex_to_mag_squared() self.magsqrd2 = blocks.complex_to_mag_squared() self.adder = blocks.add_ff() moving_sum_taps = [rho / 2 for i in range(cp_length)] self.moving_sum_filter = filter.fir_filter_fff(1,moving_sum_taps) self.connect(self.input,self.magsqrd1) self.connect(self.delay,self.magsqrd2) self.connect(self.magsqrd1,(self.adder,0)) self.connect(self.magsqrd2,(self.adder,1)) self.connect(self.adder,self.moving_sum_filter) # Correlation from ML Sync self.conjg = blocks.conjugate_cc(); self.mixer = blocks.multiply_cc(); movingsum2_taps = [1.0 for i in range(cp_length)] self.movingsum2 = filter.fir_filter_ccf(1,movingsum2_taps) # Correlator data handler self.c2mag = blocks.complex_to_mag() self.angle = blocks.complex_to_arg() self.connect(self.input,(self.mixer,1)) self.connect(self.delay,self.conjg,(self.mixer,0)) self.connect(self.mixer,self.movingsum2,self.c2mag) self.connect(self.movingsum2,self.angle) # ML Sync output arg, need to find maximum point of this self.diff = blocks.sub_ff() self.connect(self.c2mag,(self.diff,0)) self.connect(self.moving_sum_filter,(self.diff,1)) #ML measurements input to sampler block and detect self.f2c = blocks.float_to_complex() self.pk_detect = blocks.peak_detector_fb(0.2, 0.25, 30, 0.0005) self.sample_and_hold = blocks.sample_and_hold_ff() # use the sync loop values to set the sampler and the NCO # self.diff = theta # self.angle = epsilon self.connect(self.diff, self.pk_detect) # The DPLL corrects for timing differences between CP correlations use_dpll = 0 if use_dpll: self.dpll = gr.dpll_bb(float(symbol_length),0.01) self.connect(self.pk_detect, self.dpll) self.connect(self.dpll, (self.sample_and_hold,1)) else: self.connect(self.pk_detect, (self.sample_and_hold,1)) self.connect(self.angle, (self.sample_and_hold,0)) ################################ # correlate against known symbol # This gives us the same timing signal as the PN sync block only on the preamble # we don't use the signal generated from the CP correlation because we don't want # to readjust the timing in the middle of the packet or we ruin the equalizer settings. kstime = [k.conjugate() for k in kstime] kstime.reverse() self.kscorr = filter.fir_filter_ccc(1, kstime) self.corrmag = blocks.complex_to_mag_squared() self.div = blocks.divide_ff() # The output signature of the correlation has a few spikes because the rest of the # system uses the repeated preamble symbol. It needs to work that generically if # anyone wants to use this against a WiMAX-like signal since it, too, repeats. # The output theta of the correlator above is multiplied with this correlation to # identify the proper peak and remove other products in this cross-correlation self.threshold_factor = 0.1 self.slice = blocks.threshold_ff(self.threshold_factor, self.threshold_factor, 0) self.f2b = blocks.float_to_char() self.b2f = blocks.char_to_float() self.mul = blocks.multiply_ff() # Normalize the power of the corr output by the energy. This is not really needed # and could be removed for performance, but it makes for a cleaner signal. # if this is removed, the threshold value needs adjustment. self.connect(self.input, self.kscorr, self.corrmag, (self.div,0)) self.connect(self.moving_sum_filter, (self.div,1)) self.connect(self.div, (self.mul,0)) self.connect(self.pk_detect, self.b2f, (self.mul,1)) self.connect(self.mul, self.slice) # Set output signals # Output 0: fine frequency correction value # Output 1: timing signal self.connect(self.sample_and_hold, (self,0)) self.connect(self.slice, self.f2b, (self,1)) if logging: self.connect(self.moving_sum_filter, blocks.file_sink(gr.sizeof_float, "ofdm_sync_ml-energy_f.dat")) self.connect(self.diff, blocks.file_sink(gr.sizeof_float, "ofdm_sync_ml-theta_f.dat")) self.connect(self.angle, blocks.file_sink(gr.sizeof_float, "ofdm_sync_ml-epsilon_f.dat")) self.connect(self.corrmag, blocks.file_sink(gr.sizeof_float, "ofdm_sync_ml-corrmag_f.dat")) self.connect(self.kscorr, blocks.file_sink(gr.sizeof_gr_complex, "ofdm_sync_ml-kscorr_c.dat")) self.connect(self.div, blocks.file_sink(gr.sizeof_float, "ofdm_sync_ml-div_f.dat")) self.connect(self.mul, blocks.file_sink(gr.sizeof_float, "ofdm_sync_ml-mul_f.dat")) self.connect(self.slice, blocks.file_sink(gr.sizeof_float, "ofdm_sync_ml-slice_f.dat")) self.connect(self.pk_detect, blocks.file_sink(gr.sizeof_char, "ofdm_sync_ml-peaks_b.dat")) if use_dpll: self.connect(self.dpll, blocks.file_sink(gr.sizeof_char, "ofdm_sync_ml-dpll_b.dat")) self.connect(self.sample_and_hold, blocks.file_sink(gr.sizeof_float, "ofdm_sync_ml-sample_and_hold_f.dat")) self.connect(self.input, blocks.file_sink(gr.sizeof_gr_complex, "ofdm_sync_ml-input_c.dat"))
def __init__(self, fft_length, block_length, frame_data_part, block_header, options): gr.hier_block2.__init__( self, "ofdm_receiver", gr.io_signature(1, 1, gr.sizeof_gr_complex), gr.io_signature2(2, 2, gr.sizeof_gr_complex * fft_length, gr.sizeof_char)) frame_length = frame_data_part + block_header.no_pilotsyms cp_length = block_length - fft_length self.input = gr.kludge_copy(gr.sizeof_gr_complex) self.connect(self, self.input) self.blocks_out = (self, 0) self.frame_trigger_out = (self, 1) self.snr_out = (self, 2) if options.log: log_to_file(self, self.input, "data/receiver_input.compl") # peak detector: thresholds low, high #self._pd_thres_lo = 0.09 #self._pd_thres_hi = 0.1 self._pd_thres = 0.2 self._pd_lookahead = fft_length / 2 # empirically chosen ######################### # coarse timing offset estimator # self.tm = schmidl.modified_timing_metric(fft_length,[1]*(fft_length)) self.tm = schmidl.recursive_timing_metric(fft_length) self.connect(self.input, self.tm) assert (hasattr(block_header, 'sc_preamble_pos')) assert (block_header.sc_preamble_pos == 0 ) # TODO: relax this restriction if options.filter_timingmetric: timingmetric_shift = -2 #int(-cp_length * 0.8) tmfilter = gr.fir_filter_fff(1, [1. / cp_length] * cp_length) self.connect(self.tm, tmfilter) self.timing_metric = tmfilter print "Filtering timing metric, experimental" else: self.timing_metric = self.tm timingmetric_shift = int(-cp_length / 4) if options.log: log_to_file(self, self.timing_metric, "data/tm.float") # peak detection #threshold = gr.threshold_ff(self._pd_thres_lo,self._pd_thres_hi,0) #muted_tm = gr.multiply_ff() peak_detector = peak_detector_02_fb(self._pd_lookahead, self._pd_thres) #self.connect(self.timing_metric, threshold, (muted_tm,0)) #self.connect(self.timing_metric, (muted_tm,1)) #self.connect(muted_tm, peak_detector) self.connect(self.timing_metric, peak_detector) if options.log: pd_float = gr.char_to_float() self.connect(peak_detector, pd_float) log_to_file(self, pd_float, "data/peakdetector.float") if options.no_timesync: terminate_stream(self, peak_detector) trigger = [0] * (frame_length * block_length) trigger[block_length - 1] = 1 peak_detector = blocks.vector_source_b(trigger, True) print "Bypassing timing synchronisation" # TODO: refine detected peaks with 90% average method as proposed # from Schmidl & Cox: # Starting from peak, find first points to the left and right whose # value is less than or equal 90% of the peak value. New trigger point # is average of both # Frequency Offset Estimation # Used: Algorithm as proposed from Morelli & Mengali # Idea: Use periodic preamble, correlate identical parts, determine # phase offset. This phase offset is a function of the frequency offset. assert (hasattr(block_header, 'mm_preamble_pos')) foe = morelli_foe(fft_length, block_header.mm_periodic_parts) self.connect(self.input, (foe, 0)) if block_header.mm_preamble_pos > 0: delayed_trigger = gr.delay( gr.sizeof_char, block_header.mm_preamble_pos * block_length) self.connect(peak_detector, delayed_trigger, (foe, 1)) else: self.connect(peak_detector, (foe, 1)) self.freq_offset = foe if options.log: log_to_file(self, self.freq_offset, "data/freqoff_out.float") if options.average_freqoff: #avg_foe = gr.single_pole_iir_filter_ff( 0.1 ) avg_foe = ofdm.lms_fir_ff(20, 1e-3) self.connect(self.freq_offset, avg_foe) self.freq_offset = avg_foe #log_to_file( self, avg_foe, "data/freqoff_out_avg.float" ) print "EXPERIMENTAL!!! Filtering frequency offset estimate" if options.no_freqsync: terminate_stream(self, self.freq_offset) self.freq_offset = blocks.vector_source_f([0.0], True) print "Bypassing frequency offset estimator, offset=0.0" # TODO: dynamic solution frametrig_seq = concatenate([[1], [0] * (frame_length - 1)]) self.time_sync = peak_detector self.frame_trigger = blocks.vector_source_b(frametrig_seq, True) self.connect(self.frame_trigger, self.frame_trigger_out) ########################## # symbol extraction and processing # First, we extract the whole ofdm block, then we divide this block into # several ofdm symbols. This asserts that all symbols belonging to the # same ofdm block will be a consecutive order. # extract ofdm symbols # compensate frequency offset # TODO: use PLL and update/reset signals delayed_timesync = gr.delay(gr.sizeof_char, (frame_length - 1) * block_length + timingmetric_shift) self.connect(self.time_sync, delayed_timesync) self.block_sampler = vector_sampler(gr.sizeof_gr_complex, block_length * frame_length) self.discard_cp = vector_mask(block_length, cp_length, fft_length, []) if options.use_dpll: dpll = gr.dpll_bb(frame_length * block_length, .01) self.connect(delayed_timesync, dpll) if options.log: dpll_f = gr.char_to_float() delayed_timesync_f = gr.char_to_float() self.connect(dpll, dpll_f) self.connect(delayed_timesync, delayed_timesync_f) log_to_file(self, dpll_f, "data/dpll.float") log_to_file(self, delayed_timesync_f, "data/dpll_in.float") delayed_timesync = dpll print "Using DPLL, EXPERIMENTAL!!!!!" self.connect(self.input, self.block_sampler) self.connect(delayed_timesync, (self.block_sampler, 1)) if options.log: log_to_file(self, self.block_sampler, "data/block_sampler_out.compl") # TODO: dynamic solution self.ofdm_symbols = blocks.vector_to_stream( gr.sizeof_gr_complex * block_length, frame_length) self.connect(self.block_sampler, self.ofdm_symbols, self.discard_cp) if options.log: log_to_file(self, self.discard_cp, "data/discard_cp_out.compl") dcp_fft = gr.fft_vcc(fft_length, True, [], True) self.connect(self.discard_cp, dcp_fft) log_to_file(self, dcp_fft, "data/discard_cp_fft.compl") # reset phase accumulator inside freq_shift on every block start # setup output connection freq_shift = frequency_shift_vcc(fft_length, -1.0 / fft_length, cp_length) self.connect(self.discard_cp, (freq_shift, 0)) self.connect(self.freq_offset, (freq_shift, 1)) self.connect(self.frame_trigger, (freq_shift, 2)) self.connect(freq_shift, self.blocks_out) if options.log: log_to_file(self, freq_shift, "data/freqshift_out.compl") if options.no_freqshift: terminate_stream(self, freq_shift) freq_shift = self.discard_cp print "Bypassing frequency shift block"
def __init__(self, fft_length, cp_length, snr, kstime, logging): ''' Maximum Likelihood OFDM synchronizer: J. van de Beek, M. Sandell, and P. O. Borjesson, "ML Estimation of Time and Frequency Offset in OFDM Systems," IEEE Trans. Signal Processing, vol. 45, no. 7, pp. 1800-1805, 1997. ''' gr.hier_block2.__init__( self, "ofdm_sync_ml", gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature gr.io_signature2(2, 2, gr.sizeof_float, gr.sizeof_char)) # Output signature self.input = blocks.add_const_cc(0) SNR = 10.0**(snr / 10.0) rho = SNR / (SNR + 1.0) symbol_length = fft_length + cp_length # ML Sync # Energy Detection from ML Sync self.connect(self, self.input) # Create a delay line self.delay = blocks.delay(gr.sizeof_gr_complex, fft_length) self.connect(self.input, self.delay) # magnitude squared blocks self.magsqrd1 = blocks.complex_to_mag_squared() self.magsqrd2 = blocks.complex_to_mag_squared() self.adder = blocks.add_ff() moving_sum_taps = [rho / 2 for i in range(cp_length)] self.moving_sum_filter = filter.fir_filter_fff(1, moving_sum_taps) self.connect(self.input, self.magsqrd1) self.connect(self.delay, self.magsqrd2) self.connect(self.magsqrd1, (self.adder, 0)) self.connect(self.magsqrd2, (self.adder, 1)) self.connect(self.adder, self.moving_sum_filter) # Correlation from ML Sync self.conjg = blocks.conjugate_cc() self.mixer = blocks.multiply_cc() movingsum2_taps = [1.0 for i in range(cp_length)] self.movingsum2 = filter.fir_filter_ccf(1, movingsum2_taps) # Correlator data handler self.c2mag = blocks.complex_to_mag() self.angle = blocks.complex_to_arg() self.connect(self.input, (self.mixer, 1)) self.connect(self.delay, self.conjg, (self.mixer, 0)) self.connect(self.mixer, self.movingsum2, self.c2mag) self.connect(self.movingsum2, self.angle) # ML Sync output arg, need to find maximum point of this self.diff = blocks.sub_ff() self.connect(self.c2mag, (self.diff, 0)) self.connect(self.moving_sum_filter, (self.diff, 1)) #ML measurements input to sampler block and detect self.f2c = blocks.float_to_complex() self.pk_detect = blocks.peak_detector_fb(0.2, 0.25, 30, 0.0005) self.sample_and_hold = blocks.sample_and_hold_ff() # use the sync loop values to set the sampler and the NCO # self.diff = theta # self.angle = epsilon self.connect(self.diff, self.pk_detect) # The DPLL corrects for timing differences between CP correlations use_dpll = 0 if use_dpll: self.dpll = gr.dpll_bb(float(symbol_length), 0.01) self.connect(self.pk_detect, self.dpll) self.connect(self.dpll, (self.sample_and_hold, 1)) else: self.connect(self.pk_detect, (self.sample_and_hold, 1)) self.connect(self.angle, (self.sample_and_hold, 0)) ################################ # correlate against known symbol # This gives us the same timing signal as the PN sync block only on the preamble # we don't use the signal generated from the CP correlation because we don't want # to readjust the timing in the middle of the packet or we ruin the equalizer settings. kstime = [k.conjugate() for k in kstime] kstime.reverse() self.kscorr = filter.fir_filter_ccc(1, kstime) self.corrmag = blocks.complex_to_mag_squared() self.div = blocks.divide_ff() # The output signature of the correlation has a few spikes because the rest of the # system uses the repeated preamble symbol. It needs to work that generically if # anyone wants to use this against a WiMAX-like signal since it, too, repeats. # The output theta of the correlator above is multiplied with this correlation to # identify the proper peak and remove other products in this cross-correlation self.threshold_factor = 0.1 self.slice = blocks.threshold_ff(self.threshold_factor, self.threshold_factor, 0) self.f2b = blocks.float_to_char() self.b2f = blocks.char_to_float() self.mul = blocks.multiply_ff() # Normalize the power of the corr output by the energy. This is not really needed # and could be removed for performance, but it makes for a cleaner signal. # if this is removed, the threshold value needs adjustment. self.connect(self.input, self.kscorr, self.corrmag, (self.div, 0)) self.connect(self.moving_sum_filter, (self.div, 1)) self.connect(self.div, (self.mul, 0)) self.connect(self.pk_detect, self.b2f, (self.mul, 1)) self.connect(self.mul, self.slice) # Set output signals # Output 0: fine frequency correction value # Output 1: timing signal self.connect(self.sample_and_hold, (self, 0)) self.connect(self.slice, self.f2b, (self, 1)) if logging: self.connect( self.moving_sum_filter, blocks.file_sink(gr.sizeof_float, "ofdm_sync_ml-energy_f.dat")) self.connect( self.diff, blocks.file_sink(gr.sizeof_float, "ofdm_sync_ml-theta_f.dat")) self.connect( self.angle, blocks.file_sink(gr.sizeof_float, "ofdm_sync_ml-epsilon_f.dat")) self.connect( self.corrmag, blocks.file_sink(gr.sizeof_float, "ofdm_sync_ml-corrmag_f.dat")) self.connect( self.kscorr, blocks.file_sink(gr.sizeof_gr_complex, "ofdm_sync_ml-kscorr_c.dat")) self.connect( self.div, blocks.file_sink(gr.sizeof_float, "ofdm_sync_ml-div_f.dat")) self.connect( self.mul, blocks.file_sink(gr.sizeof_float, "ofdm_sync_ml-mul_f.dat")) self.connect( self.slice, blocks.file_sink(gr.sizeof_float, "ofdm_sync_ml-slice_f.dat")) self.connect( self.pk_detect, blocks.file_sink(gr.sizeof_char, "ofdm_sync_ml-peaks_b.dat")) if use_dpll: self.connect( self.dpll, blocks.file_sink(gr.sizeof_char, "ofdm_sync_ml-dpll_b.dat")) self.connect( self.sample_and_hold, blocks.file_sink(gr.sizeof_float, "ofdm_sync_ml-sample_and_hold_f.dat")) self.connect( self.input, blocks.file_sink(gr.sizeof_gr_complex, "ofdm_sync_ml-input_c.dat"))
def __init__(self, fft_length, block_length, frame_data_part, block_header, options): gr.hier_block2.__init__(self, "ofdm_receiver", gr.io_signature (1,1,gr.sizeof_gr_complex), gr.io_signature2(2,2,gr.sizeof_gr_complex*fft_length, gr.sizeof_char)) frame_length = frame_data_part + block_header.no_pilotsyms cp_length = block_length-fft_length self.input=gr.kludge_copy(gr.sizeof_gr_complex) self.connect(self, self.input) self.blocks_out = (self,0) self.frame_trigger_out = (self,1) self.snr_out = (self,2) if options.log: log_to_file(self, self.input, "data/receiver_input.compl") # peak detector: thresholds low, high #self._pd_thres_lo = 0.09 #self._pd_thres_hi = 0.1 self._pd_thres = 0.2 self._pd_lookahead = fft_length / 2 # empirically chosen ######################### # coarse timing offset estimator # self.tm = schmidl.modified_timing_metric(fft_length,[1]*(fft_length)) self.tm = schmidl.recursive_timing_metric(fft_length) self.connect(self.input,self.tm) assert(hasattr(block_header, 'sc_preamble_pos')) assert(block_header.sc_preamble_pos == 0) # TODO: relax this restriction if options.filter_timingmetric: timingmetric_shift = -2 #int(-cp_length * 0.8) tmfilter = gr.fir_filter_fff(1, [1./cp_length]*cp_length) self.connect( self.tm, tmfilter ) self.timing_metric = tmfilter print "Filtering timing metric, experimental" else: self.timing_metric = self.tm timingmetric_shift = int(-cp_length/4) if options.log: log_to_file(self, self.timing_metric, "data/tm.float") # peak detection #threshold = gr.threshold_ff(self._pd_thres_lo,self._pd_thres_hi,0) #muted_tm = gr.multiply_ff() peak_detector = peak_detector_02_fb(self._pd_lookahead, self._pd_thres) #self.connect(self.timing_metric, threshold, (muted_tm,0)) #self.connect(self.timing_metric, (muted_tm,1)) #self.connect(muted_tm, peak_detector) self.connect(self.timing_metric, peak_detector) if options.log: pd_float = gr.char_to_float() self.connect(peak_detector,pd_float) log_to_file(self, pd_float, "data/peakdetector.float") if options.no_timesync: terminate_stream( self, peak_detector ) trigger = [0]*(frame_length*block_length) trigger[ block_length-1 ] = 1 peak_detector = blocks.vector_source_b( trigger, True ) print "Bypassing timing synchronisation" # TODO: refine detected peaks with 90% average method as proposed # from Schmidl & Cox: # Starting from peak, find first points to the left and right whose # value is less than or equal 90% of the peak value. New trigger point # is average of both # Frequency Offset Estimation # Used: Algorithm as proposed from Morelli & Mengali # Idea: Use periodic preamble, correlate identical parts, determine # phase offset. This phase offset is a function of the frequency offset. assert(hasattr(block_header, 'mm_preamble_pos')) foe = morelli_foe(fft_length,block_header.mm_periodic_parts) self.connect(self.input,(foe,0)) if block_header.mm_preamble_pos > 0: delayed_trigger = gr.delay(gr.sizeof_char, block_header.mm_preamble_pos*block_length) self.connect(peak_detector,delayed_trigger,(foe,1)) else: self.connect(peak_detector,(foe,1)) self.freq_offset = foe if options.log: log_to_file(self, self.freq_offset, "data/freqoff_out.float") if options.average_freqoff: #avg_foe = gr.single_pole_iir_filter_ff( 0.1 ) avg_foe = ofdm.lms_fir_ff( 20, 1e-3 ) self.connect( self.freq_offset, avg_foe ) self.freq_offset = avg_foe #log_to_file( self, avg_foe, "data/freqoff_out_avg.float" ) print "EXPERIMENTAL!!! Filtering frequency offset estimate" if options.no_freqsync: terminate_stream( self, self.freq_offset ) self.freq_offset = blocks.vector_source_f( [0.0], True ) print "Bypassing frequency offset estimator, offset=0.0" # TODO: dynamic solution frametrig_seq = concatenate([[1],[0]*(frame_length-1)]) self.time_sync = peak_detector self.frame_trigger = blocks.vector_source_b(frametrig_seq,True) self.connect(self.frame_trigger, self.frame_trigger_out) ########################## # symbol extraction and processing # First, we extract the whole ofdm block, then we divide this block into # several ofdm symbols. This asserts that all symbols belonging to the # same ofdm block will be a consecutive order. # extract ofdm symbols # compensate frequency offset # TODO: use PLL and update/reset signals delayed_timesync = gr.delay(gr.sizeof_char, (frame_length-1)*block_length+timingmetric_shift) self.connect( self.time_sync, delayed_timesync ) self.block_sampler = vector_sampler(gr.sizeof_gr_complex,block_length*frame_length) self.discard_cp = vector_mask(block_length,cp_length,fft_length,[]) if options.use_dpll: dpll = gr.dpll_bb( frame_length * block_length , .01 ) self.connect( delayed_timesync, dpll ) if options.log: dpll_f = gr.char_to_float() delayed_timesync_f = gr.char_to_float() self.connect( dpll, dpll_f ) self.connect( delayed_timesync, delayed_timesync_f ) log_to_file( self, dpll_f, "data/dpll.float" ) log_to_file( self, delayed_timesync_f, "data/dpll_in.float" ) delayed_timesync = dpll print "Using DPLL, EXPERIMENTAL!!!!!" self.connect(self.input,self.block_sampler) self.connect(delayed_timesync,(self.block_sampler,1)) if options.log: log_to_file(self, self.block_sampler, "data/block_sampler_out.compl") # TODO: dynamic solution self.ofdm_symbols = blocks.vector_to_stream(gr.sizeof_gr_complex*block_length, frame_length) self.connect(self.block_sampler,self.ofdm_symbols,self.discard_cp) if options.log: log_to_file(self, self.discard_cp, "data/discard_cp_out.compl") dcp_fft = gr.fft_vcc(fft_length, True, [], True) self.connect(self.discard_cp,dcp_fft) log_to_file(self, dcp_fft, "data/discard_cp_fft.compl") # reset phase accumulator inside freq_shift on every block start # setup output connection freq_shift = frequency_shift_vcc(fft_length, -1.0/fft_length, cp_length) self.connect(self.discard_cp,(freq_shift,0)) self.connect(self.freq_offset,(freq_shift,1)) self.connect(self.frame_trigger,(freq_shift,2)) self.connect(freq_shift, self.blocks_out) if options.log: log_to_file(self, freq_shift, "data/freqshift_out.compl") if options.no_freqshift: terminate_stream( self, freq_shift ) freq_shift = self.discard_cp print "Bypassing frequency shift block"