def __init__( self, options, log = False ): ## Read configuration config = station_configuration() fft_length = config.fft_length cp_length = config.cp_length block_header = config.training_data data_subc = config.data_subcarriers virtual_subc = config.virtual_subcarriers total_subc = config.subcarriers block_length = config.block_length frame_length = config.frame_length dc_null = config.dc_null L = block_header.mm_periodic_parts ## Set Input/Output signature gr.hier_block2.__init__( self, "ofdm_inner_receiver", gr.io_signature( 1, 1, gr.sizeof_gr_complex ), gr.io_signaturev( 4, 4, [gr.sizeof_gr_complex * total_subc, # OFDM blocks gr.sizeof_char, # Frame start gr.sizeof_float * total_subc, gr.sizeof_float] ) ) # Normalized |CTF|^2 ## Input and output ports self.input = rx_input = self out_ofdm_blocks = ( self, 0 ) out_frame_start = ( self, 1 ) out_disp_ctf = ( self, 2 ) out_disp_cfo = ( self, 3 ) ## pre-FFT processing if options.ideal is False and options.ideal2 is False: if options.old_receiver is False: ## Compute autocorrelations for S&C preamble ## and cyclic prefix self._sc_metric = sc_metric = autocorrelator( fft_length/2, fft_length/2 ) self._gi_metric = gi_metric = autocorrelator( fft_length, cp_length ) self.connect( rx_input, sc_metric ) self.connect( rx_input, gi_metric ) ## Sync. Output contains OFDM blocks sync = ofdm.time_sync( fft_length, cp_length ) self.connect( rx_input, ( sync, 0 ) ) self.connect( sc_metric, ( sync, 1 ) ) self.connect( gi_metric, ( sync, 2 ) ) ofdm_blocks = ( sync, 0 ) frame_start = ( sync, 1 ) #log_to_file( self, ( sync, 1 ), "data/peak_detector.char" ) else: #Testing old/new metric self.tm = schmidl.recursive_timing_metric(fft_length) self.connect( self.input, self.tm) #log_to_file( self, self.tm, "data/rec_sc_metric_ofdm.float" ) timingmetric_shift = -2#int(-cp_length/4)# 0#-2 #int(-cp_length * 0.8) tmfilter = filter.fft_filter_fff(1, [1./cp_length]*cp_length) self.connect( self.tm, tmfilter ) self.tm = tmfilter self._pd_thres = 0.3 self._pd_lookahead = fft_length / 2 # empirically chosen peak_detector = ofdm.peak_detector_02_fb(self._pd_lookahead, self._pd_thres) self.connect(self.tm, peak_detector) #log_to_file( self, peak_detector, "data/rec_peak_detector.char" ) frame_start = [0]*frame_length frame_start[0] = 1 frame_start = self.frame_trigger_old = blocks.vector_source_b(frame_start,True) delayed_timesync = blocks.delay(gr.sizeof_char, (frame_length-1)*block_length + timingmetric_shift) self.connect( peak_detector, delayed_timesync ) self.block_sampler = ofdm.vector_sampler(gr.sizeof_gr_complex,block_length*frame_length) self.discard_cp = ofdm.vector_mask(block_length,cp_length,fft_length,[]) self.connect(self.input,self.block_sampler) self.connect(delayed_timesync,(self.block_sampler,1)) # TODO: dynamic solution vt2s = blocks.vector_to_stream(gr.sizeof_gr_complex*block_length, frame_length) self.connect(self.block_sampler,vt2s,self.discard_cp) #terminate_stream(self,ofdm_blocks) ofdm_blocks = self.discard_cp # else: # serial_to_parallel = blocks.stream_to_vector(gr.sizeof_gr_complex,block_length) # discard_cp = ofdm.vector_mask(block_length,cp_length,fft_length,[]) # ofdm_blocks = discard_cp # self.connect( rx_input, serial_to_parallel, discard_cp ) # frame_start = [0]*frame_length # frame_start[0] = 1 # frame_start = blocks.vector_source_b(frame_start,True) # # print "Disabled time synchronization stage" ## Compute autocorrelations for S&C preamble ## and cyclic prefix #log_to_file( self, sc_metric, "data/sc_metric_ofdm.float" ) #log_to_file(self, frame_start, "data/frame_start.compl") # log_to_file(self,ofdm_blocks,"data/ofdm_blocks_original.compl") if options.disable_time_sync or options.ideal or options.ideal2: if options.ideal is False and options.ideal2 is False: terminate_stream(self, ofdm_blocks) terminate_stream(self, frame_start) serial_to_parallel = blocks.stream_to_vector(gr.sizeof_gr_complex,block_length) discard_cp = ofdm.vector_mask_dc_null(block_length,cp_length,fft_length,dc_null, []) ofdm_blocks = discard_cp self.connect( rx_input, serial_to_parallel, discard_cp ) frame_start = [0]*frame_length frame_start[0] = 1 frame_start = blocks.vector_source_b(frame_start,True) print "Disabled time synchronization stage" print"\t\t\t\t\tframe_length = ",frame_length if options.ideal is False and options.ideal2 is False: ## Extract preamble, feed to Morelli & Mengali frequency offset estimator assert( block_header.mm_preamble_pos == 0 ) morelli_foe = ofdm.mm_frequency_estimator( fft_length, L,1,0 ) sampler_preamble = ofdm.vector_sampler( gr.sizeof_gr_complex * fft_length, 1 ) self.connect( ofdm_blocks, ( sampler_preamble, 0 ) ) self.connect( frame_start, ( sampler_preamble, 1 ) ) self.connect( sampler_preamble, morelli_foe ) freq_offset = morelli_foe ## Adaptive LMS FIR filtering of frequency offset lms_fir = ofdm.lms_fir_ff( 20, 1e-3 ) # TODO: verify parameter choice self.connect( freq_offset, lms_fir ) freq_offset = lms_fir #self.zmq_probe_freqoff = zeromq.pub_sink(gr.sizeof_float, 1, "tcp://*:5557") self.connect(lms_fir, blocks.keep_one_in_n(gr.sizeof_float,20) ,out_disp_cfo) else: self.connect(blocks.vector_source_f ([1]) ,out_disp_cfo) #log_to_file(self, lms_fir, "data/lms_fir.float") if options.disable_freq_sync or options.ideal or options.ideal2: if options.ideal is False and options.ideal2 is False: terminate_stream(self, freq_offset) freq_offset = blocks.vector_source_f([0.0],True) print "Disabled frequency synchronization stage" if options.ideal is False and options.ideal2 is False: ## Correct frequency shift, feed-forward structure frequency_shift = ofdm.frequency_shift_vcc( fft_length, -1.0/fft_length, cp_length ) self.connect( ofdm_blocks, ( frequency_shift, 0 ) ) self.connect( freq_offset, ( frequency_shift, 1 ) ) self.connect( frame_start, ( frequency_shift, 2 ) ) ofdm_blocks = frequency_shift ## FFT fft = fft_blocks.fft_vcc( fft_length, True, [], True ) self.connect( ofdm_blocks, fft ) ofdm_blocks = fft #log_to_file( self, fft, "data/compen.float" ) ## Remove virtual subcarriers if fft_length > data_subc: subcarrier_mask = ofdm.vector_mask_dc_null( fft_length, virtual_subc/2, total_subc, dc_null, [] ) self.connect( ofdm_blocks, subcarrier_mask ) ofdm_blocks = subcarrier_mask #log_to_file(self, ofdm_blocks, "data/vec_mask.compl") ## Least Squares estimator for channel transfer function (CTF) if options.logcir: log_to_file( self, ofdm_blocks, "data/OFDM_Blocks.compl" ) inv_preamble_fd = numpy.array( block_header.pilotsym_fd[ block_header.channel_estimation_pilot[0] ] ) inv_preamble_fd = numpy.concatenate([inv_preamble_fd[:total_subc/2],inv_preamble_fd[total_subc/2+dc_null:]]) #print "Channel estimation pilot: ", inv_preamble_fd inv_preamble_fd = 1. / inv_preamble_fd LS_channel_estimator0 = ofdm.multiply_const_vcc( list( inv_preamble_fd ) ) self.connect( ofdm_blocks, LS_channel_estimator0, gr.null_sink(gr.sizeof_gr_complex*total_subc)) log_to_file( self, LS_channel_estimator0, "data/OFDM_Blocks_eq.compl" ) ## post-FFT processing ## extract channel estimation preamble from frame if options.ideal is False and options.ideal2 is False: chest_pre_trigger = blocks.delay( gr.sizeof_char, 1) sampled_chest_preamble = ofdm.vector_sampler( gr.sizeof_gr_complex * total_subc, 1) self.connect( frame_start, chest_pre_trigger ) self.connect( chest_pre_trigger, ( sampled_chest_preamble, 1 ) ) self.connect( ofdm_blocks, ( sampled_chest_preamble, 0 ) ) ## Least Squares estimator for channel transfer function (CTF) inv_preamble_fd = numpy.array( block_header.pilotsym_fd[ block_header.channel_estimation_pilot[0] ] ) inv_preamble_fd = numpy.concatenate([inv_preamble_fd[:total_subc/2],inv_preamble_fd[total_subc/2+dc_null:]]) #print "Channel estimation pilot: ", inv_preamble_fd inv_preamble_fd = 1. / inv_preamble_fd LS_channel_estimator = ofdm.multiply_const_vcc( list( inv_preamble_fd ) ) self.connect( sampled_chest_preamble, LS_channel_estimator ) estimated_CTF = LS_channel_estimator if options.logcir: log_to_file( self, sampled_chest_preamble, "data/PREAM.compl" ) if not options.disable_ctf_enhancer: if options.logcir: ifft1 = fft_blocks.fft_vcc(total_subc,False,[],True) self.connect( estimated_CTF, ifft1,gr.null_sink(gr.sizeof_gr_complex*total_subc)) summ1 = ofdm.vector_sum_vcc(total_subc) c2m =gr.complex_to_mag(total_subc) self.connect( estimated_CTF,summ1 ,gr.null_sink(gr.sizeof_gr_complex)) self.connect( estimated_CTF, c2m,gr.null_sink(gr.sizeof_float*total_subc)) log_to_file( self, ifft1, "data/CIR1.compl" ) log_to_file( self, summ1, "data/CTFsumm1.compl" ) log_to_file( self, estimated_CTF, "data/CTF1.compl" ) log_to_file( self, c2m, "data/CTFmag1.float" ) ## MSE enhancer ctf_mse_enhancer = ofdm.CTF_MSE_enhancer( total_subc, cp_length + cp_length) self.connect( estimated_CTF, ctf_mse_enhancer ) # log_to_file( self, ctf_mse_enhancer, "data/ctf_mse_enhancer_original.compl") #ifft3 = fft_blocks.fft_vcc(total_subc,False,[],True) #null_noise = ofdm.noise_nulling(total_subc, cp_length + cp_length) #ctf_mse_enhancer = fft_blocks.fft_vcc(total_subc,True,[],True) #ctf_mse_enhancer = ofdm.vector_mask( fft_length, virtual_subc/2, # total_subc, [] ) #self.connect( estimated_CTF, ifft3,null_noise,ctf_mse_enhancer ) estimated_CTF = ctf_mse_enhancer print "Disabled CTF MSE enhancer" if options.logcir: ifft2 = fft_blocks.fft_vcc(total_subc,False,[],True) self.connect( estimated_CTF, ifft2,gr.null_sink(gr.sizeof_gr_complex*total_subc)) summ2 = ofdm.vector_sum_vcc(total_subc) c2m2 =gr.complex_to_mag(total_subc) self.connect( estimated_CTF,summ2 ,gr.null_sink(gr.sizeof_gr_complex)) self.connect( estimated_CTF, c2m2,gr.null_sink(gr.sizeof_float*total_subc)) log_to_file( self, ifft2, "data/CIR2.compl" ) log_to_file( self, summ2, "data/CTFsumm2.compl" ) log_to_file( self, estimated_CTF, "data/CTF2.compl" ) log_to_file( self, c2m2, "data/CTFmag2.float" ) ## Postprocess the CTF estimate ## CTF -> inverse CTF (for equalizer) ## CTF -> norm |.|^2 (for CTF display) ctf_postprocess = ofdm.postprocess_CTF_estimate( total_subc ) self.connect( estimated_CTF, ctf_postprocess ) inv_estimated_CTF = ( ctf_postprocess, 0 ) disp_CTF = ( ctf_postprocess, 1 ) # if options.disable_equalization or options.ideal: # terminate_stream(self, inv_estimated_CTF) # inv_estimated_CTF_vec = blocks.vector_source_c([1.0/fft_length*math.sqrt(total_subc)]*total_subc,True,total_subc) # inv_estimated_CTF_str = blocks.vector_to_stream(gr.sizeof_gr_complex, total_subc) # self.inv_estimated_CTF_mul = ofdm.multiply_const_ccf( 1.0/config.rms_amplitude ) # #inv_estimated_CTF_mul.set_k(1.0/config.rms_amplitude) # inv_estimated_CTF = blocks.stream_to_vector(gr.sizeof_gr_complex, total_subc) # self.connect( inv_estimated_CTF_vec, inv_estimated_CTF_str, self.inv_estimated_CTF_mul, inv_estimated_CTF) # print "Disabled equalization stage" ''' ## LMS Phase tracking ## Track residual frequency offset and sampling clock frequency offset nondata_blocks = [] for i in range(config.frame_length): if i in config.training_data.pilotsym_pos: nondata_blocks.append(i) print"\t\t\t\t\tnondata_blocks=",nondata_blocks pilot_subc = block_header.pilot_tones pilot_subcarriers = block_header.pilot_subc_sym print "PILOT SUBCARRIERS: ", pilot_subcarriers phase_tracking = ofdm.lms_phase_tracking_03( total_subc, pilot_subc, nondata_blocks, pilot_subcarriers,0 ) self.connect( ofdm_blocks, ( phase_tracking, 0 ) ) self.connect( inv_estimated_CTF, ( phase_tracking, 1 ) ) self.connect( frame_start, ( phase_tracking, 2 ) ) ## if options.scatter_plot_before_phase_tracking: self.before_phase_tracking = equalizer if options.disable_phase_tracking or options.ideal: terminate_stream(self, phase_tracking) print "Disabled phase tracking stage" else: ofdm_blocks = phase_tracking ''' ## Channel Equalizer if options.disable_equalization or options.ideal or options.ideal2: print "Disabled equalization stage" if options.ideal is False and options.ideal2 is False: terminate_stream(self, inv_estimated_CTF) else: equalizer = ofdm.channel_equalizer( total_subc ) self.connect( ofdm_blocks, ( equalizer, 0 ) ) self.connect( inv_estimated_CTF, ( equalizer, 1 ) ) self.connect( frame_start, ( equalizer, 2 ) ) ofdm_blocks = equalizer #log_to_file(self, equalizer,"data/equalizer_siso.compl") #log_to_file(self, ofdm_blocks, "data/equalizer.compl") ## LMS Phase tracking ## Track residual frequency offset and sampling clock frequency offset if options.ideal is False and options.ideal2 is False: nondata_blocks = [] for i in range(config.frame_length): if i in config.training_data.pilotsym_pos: nondata_blocks.append(i) print"\t\t\t\t\tnondata_blocks=",nondata_blocks pilot_subc = block_header.pilot_tones pilot_subcarriers = block_header.pilot_subc_sym print "PILOT SUBCARRIERS: ", pilot_subcarriers phase_tracking2 = ofdm.lms_phase_tracking_dc_null( total_subc, pilot_subc, nondata_blocks, pilot_subcarriers, dc_null ) self.connect( ofdm_blocks, ( phase_tracking2, 0 ) ) self.connect( frame_start, ( phase_tracking2, 1 ) ) ## if options.disable_phase_tracking or options.ideal or options.ideal2: if options.ideal is False and options.ideal2 is False: terminate_stream(self, phase_tracking2) print "Disabled phase tracking stage" else: ofdm_blocks = phase_tracking2 if options.scatter_plot_before_phase_tracking: self.before_phase_tracking = equalizer ## Output connections self.connect( ofdm_blocks, out_ofdm_blocks ) self.connect( frame_start, out_frame_start ) if options.ideal is False and options.ideal2 is False: self.connect( disp_CTF, out_disp_ctf ) else: self.connect( blocks.vector_source_f([1.0]*total_subc),blocks.stream_to_vector(gr.sizeof_float,total_subc), out_disp_ctf ) if log: log_to_file( self, sc_metric, "data/sc_metric.float" ) log_to_file( self, gi_metric, "data/gi_metric.float" ) log_to_file( self, morelli_foe, "data/morelli_foe.float" ) log_to_file( self, lms_fir, "data/lms_fir.float" ) log_to_file( self, sampler_preamble, "data/preamble.compl" ) log_to_file( self, sync, "data/sync.compl" ) log_to_file( self, frequency_shift, "data/frequency_shift.compl" ) log_to_file( self, fft, "data/fft.compl") log_to_file( self, fft, "data/fft.float", mag=True ) if vars().has_key( 'subcarrier_mask' ): log_to_file( self, subcarrier_mask, "data/subcarrier_mask.compl" ) log_to_file( self, ofdm_blocks, "data/ofdm_blocks_out.compl" ) log_to_file( self, frame_start, "data/frame_start.float", char_to_float=True ) log_to_file( self, sampled_chest_preamble, "data/sampled_chest_preamble.compl" ) log_to_file( self, LS_channel_estimator, "data/ls_channel_estimator.compl" ) log_to_file( self, LS_channel_estimator, "data/ls_channel_estimator.float", mag=True ) if "ctf_mse_enhancer" in locals(): log_to_file( self, ctf_mse_enhancer, "data/ctf_mse_enhancer.compl" ) log_to_file( self, ctf_mse_enhancer, "data/ctf_mse_enhancer.float", mag=True ) log_to_file( self, (ctf_postprocess,0), "data/inc_estimated_ctf.compl" ) log_to_file( self, (ctf_postprocess,1), "data/disp_ctf.float" ) log_to_file( self, equalizer, "data/equalizer.compl" ) log_to_file( self, equalizer, "data/equalizer.float", mag=True ) log_to_file( self, phase_tracking, "data/phase_tracking.compl" )
def __init__(self, options, log=False): ## Read configuration config = station_configuration() fft_length = config.fft_length cp_length = config.cp_length block_header = config.training_data data_subc = config.data_subcarriers virtual_subc = config.virtual_subcarriers total_subc = config.subcarriers block_length = config.block_length frame_length = config.frame_length L = block_header.mm_periodic_parts frame_data_blocks = options.data_blocks ## Set Input/Output signature gr.hier_block2.__init__( self, "ofdm_inner_receiver", gr.io_signature(2, 2, gr.sizeof_gr_complex), gr.io_signature5( 5, 5, gr.sizeof_gr_complex * total_subc, # OFDM blocks gr.sizeof_char, # Frame start gr.sizeof_float * total_subc, # Normalized |CTF|^2 gr.sizeof_char, # Frame start gr.sizeof_float * total_subc)) # Normalized |CTF|^2 ## Input and output ports self.input = rx_input = (self, 0) self.input2 = rx2_input = (self, 1) out_ofdm_blocks = (self, 0) out_frame_start = (self, 1) out_disp_ctf = (self, 2) out_frame_start2 = (self, 3) out_disp_ctf2 = (self, 4) ## pre-FFT processing ## Compute autocorrelations for S&C preamble ## and cyclic prefix sc_metric = autocorrelator(fft_length / 2, fft_length / 2) gi_metric = autocorrelator(fft_length, cp_length) self.connect(rx_input, sc_metric) self.connect(rx_input, gi_metric) sc_metric2 = autocorrelator(fft_length / 2, fft_length / 2) gi_metric2 = autocorrelator(fft_length, cp_length) self.connect(rx2_input, sc_metric2) self.connect(rx2_input, gi_metric2) ## Sync. Output contains OFDM blocks sync = ofdm.time_sync(fft_length, cp_length) self.connect(rx_input, (sync, 0)) self.connect(sc_metric, (sync, 1)) self.connect(gi_metric, (sync, 2)) ofdm_blocks = (sync, 0) frame_start = (sync, 1) sync2 = ofdm.time_sync(fft_length, cp_length) self.connect(rx2_input, (sync2, 0)) self.connect(sc_metric2, (sync2, 1)) self.connect(gi_metric2, (sync2, 2)) ofdm_blocks2 = (sync2, 0) frame_start2 = (sync2, 1) if options.disable_time_sync or options.ideal: terminate_stream(self, ofdm_blocks) terminate_stream(self, ofdm_blocks2) terminate_stream(self, frame_start) terminate_stream(self, frame_start2) serial_to_parallel = blocks.stream_to_vector( gr.sizeof_gr_complex, block_length) serial_to_parallel2 = blocks.stream_to_vector( gr.sizeof_gr_complex, block_length) discard_cp = ofdm.vector_mask(block_length, cp_length, fft_length, []) discard_cp2 = ofdm.vector_mask(block_length, cp_length, fft_length, []) ofdm_blocks = discard_cp ofdm_blocks2 = discard_cp2 self.connect(rx_input, serial_to_parallel, discard_cp) self.connect(rx2_input, serial_to_parallel2, discard_cp2) frame_start = [0] * frame_length frame_start[0] = 1 frame_start = blocks.vector_source_b(frame_start, True) frame_start2 = [0] * frame_length frame_start2[0] = 1 frame_start2 = blocks.vector_source_b(frame_start2, True) print "Disabled time synchronization stage" ## Extract preamble, feed to Morelli & Mengali frequency offset estimator assert (block_header.mm_preamble_pos == 0) morelli_foe = ofdm.mm_frequency_estimator(fft_length, L) sampler_preamble = ofdm.vector_sampler( gr.sizeof_gr_complex * fft_length, 1) self.connect(ofdm_blocks, (sampler_preamble, 0)) self.connect(frame_start, (sampler_preamble, 1)) self.connect(sampler_preamble, morelli_foe) freq_offset = morelli_foe morelli_foe2 = ofdm.mm_frequency_estimator(fft_length, L) sampler_preamble2 = ofdm.vector_sampler( gr.sizeof_gr_complex * fft_length, 1) self.connect(ofdm_blocks2, (sampler_preamble2, 0)) self.connect(frame_start2, (sampler_preamble2, 1)) self.connect(sampler_preamble2, morelli_foe2) freq_offset2 = morelli_foe2 ## Adaptive LMS FIR filtering of frequency offset lms_fir = ofdm.lms_fir_ff(20, 1e-3) # TODO: verify parameter choice self.connect(freq_offset, lms_fir) freq_offset = lms_fir lms_fir2 = ofdm.lms_fir_ff(20, 1e-3) # TODO: verify parameter choice self.connect(freq_offset2, lms_fir2) freq_offset2 = lms_fir2 # log_to_file(self, lms_fir, "data/lms_fir.float") # log_to_file(self, lms_fir2, "data/lms_fir2.float") if options.disable_freq_sync or options.ideal: terminate_stream(self, freq_offset) terminate_stream(self, freq_offset2) freq_offset = blocks.vector_source_f([0.0], True) freq_offset2 = blocks.vector_source_f([0.0], True) print "Disabled frequency synchronization stage" ## Correct frequency shift, feed-forward structure frequency_shift = ofdm.frequency_shift_vcc(fft_length, -1.0 / fft_length, cp_length) self.connect(ofdm_blocks, (frequency_shift, 0)) self.connect(freq_offset, (frequency_shift, 1)) self.connect(frame_start, (frequency_shift, 2)) ofdm_blocks = frequency_shift frequency_shift2 = ofdm.frequency_shift_vcc(fft_length, -1.0 / fft_length, cp_length) self.connect(ofdm_blocks2, (frequency_shift2, 0)) self.connect(freq_offset2, (frequency_shift2, 1)) self.connect(frame_start2, (frequency_shift2, 2)) ofdm_blocks2 = frequency_shift2 ## FFT fft = fft_blocks.fft_vcc(fft_length, True, [], True) self.connect(ofdm_blocks, fft) ofdm_blocks = fft fft2 = fft_blocks.fft_vcc(fft_length, True, [], True) self.connect(ofdm_blocks2, fft2) ofdm_blocks2 = fft2 ## Remove virtual subcarriers if fft_length > data_subc: subcarrier_mask = ofdm.vector_mask(fft_length, virtual_subc / 2, total_subc, []) self.connect(ofdm_blocks, subcarrier_mask) ofdm_blocks = subcarrier_mask subcarrier_mask2 = ofdm.vector_mask(fft_length, virtual_subc / 2, total_subc, []) self.connect(ofdm_blocks2, subcarrier_mask2) ofdm_blocks2 = subcarrier_mask2 ## Least Squares estimator for channel transfer function (CTF) # if options.logcir: # log_to_file( self, ofdm_blocks, "data/OFDM_Blocks.compl" ) # inv_preamble_fd = numpy.array( block_header.pilotsym_fd[ # block_header.channel_estimation_pilot[0] ] ) # print "Channel estimation pilot: ", inv_preamble_fd # inv_preamble_fd = 1. / inv_preamble_fd # LS_channel_estimator0 = ofdm.multiply_const_vcc( list( inv_preamble_fd ) ) # self.connect( ofdm_blocks, LS_channel_estimator0, blocks.null_sink(gr.sizeof_gr_complex*total_subc)) # log_to_file( self, LS_channel_estimator0, "data/OFDM_Blocks_eq.compl" ) ## post-FFT processing if options.est_preamble == 1: ## extract channel estimation preamble from frame chest_pre_trigger = blocks.delay(gr.sizeof_char, 1) sampled_chest_preamble = \ ofdm.vector_sampler( gr.sizeof_gr_complex * total_subc, 1 ) self.connect(frame_start, chest_pre_trigger) self.connect(chest_pre_trigger, (sampled_chest_preamble, 1)) self.connect(ofdm_blocks, (sampled_chest_preamble, 0)) chest_pre_trigger2 = blocks.delay(gr.sizeof_char, 1) sampled_chest_preamble2 = \ ofdm.vector_sampler( gr.sizeof_gr_complex * total_subc, 1 ) self.connect(frame_start2, chest_pre_trigger2) self.connect(chest_pre_trigger2, (sampled_chest_preamble2, 1)) self.connect(ofdm_blocks2, (sampled_chest_preamble2, 0)) ## Least Squares estimator for channel transfer function (CTF) # Taking inverse for estimating h11 (h12) inv_preamble_fd_1 = numpy.array(block_header.pilotsym_fd_1[ block_header.channel_estimation_pilot[0]]) inv_preamble_fd_1 = inv_preamble_fd_1[0::2] # Taking inverse for estimating h21 (h22) inv_preamble_fd_2 = numpy.array(block_header.pilotsym_fd_2[ block_header.channel_estimation_pilot[0]]) inv_preamble_fd_2 = inv_preamble_fd_2[1::2] inv_preamble_fd_1 = 1. / inv_preamble_fd_1 inv_preamble_fd_2 = 1. / inv_preamble_fd_2 ## Least Squares estimator for channel transfer function (CTF) dd = [] for i in range(total_subc / 2): dd.extend([i * 2]) skip_block_1 = ofdm.int_skip(total_subc, 2, 0) skip_block_2 = ofdm.int_skip(total_subc, 2, 1) # inta_estim_1 = ofdm.interpolator(total_subc,2,dd) # inta_estim_2 = ofdm.interpolator(total_subc,2,dd) LS_channel_estimator_1 = ofdm.multiply_const_vcc( list(inv_preamble_fd_1)) LS_channel_estimator_2 = ofdm.multiply_const_vcc( list(inv_preamble_fd_2)) self.connect(sampled_chest_preamble, skip_block_1, LS_channel_estimator_1) #,inta_estim_1 ) self.connect(sampled_chest_preamble, skip_block_2, LS_channel_estimator_2) #,inta_estim_2 ) estimated_CTF_1 = LS_channel_estimator_1 # h0 estimated_CTF_2 = LS_channel_estimator_2 # h1 skip_block_3 = ofdm.int_skip(total_subc, 2, 0) skip_block_4 = ofdm.int_skip(total_subc, 2, 1) # inta_estim_3 = ofdm.interpolator(total_subc,2,dd) # inta_estim_4 = ofdm.interpolator(total_subc,2,dd) LS_channel_estimator_3 = ofdm.multiply_const_vcc( list(inv_preamble_fd_1)) LS_channel_estimator_4 = ofdm.multiply_const_vcc( list(inv_preamble_fd_2)) self.connect(sampled_chest_preamble2, skip_block_3, LS_channel_estimator_3) #,inta_estim_3 ) self.connect(sampled_chest_preamble2, skip_block_4, LS_channel_estimator_4) #,inta_estim_4 ) estimated_CTF_3 = LS_channel_estimator_3 # h2 estimated_CTF_4 = LS_channel_estimator_4 # h3 if not options.disable_ctf_enhancer: # if options.logcir: # ifft1 = fft_blocks.fft_vcc(total_subc,False,[],True) # self.connect( estimated_CTF, ifft1,blocks.null_sink(gr.sizeof_gr_complex*total_subc)) # summ1 = ofdm.vector_sum_vcc(total_subc) # c2m =gr.complex_to_mag(total_subc) # self.connect( estimated_CTF,summ1 ,blocks.null_sink(gr.sizeof_gr_complex)) # self.connect( estimated_CTF, c2m,blocks.null_sink(gr.sizeof_float*total_subc)) # log_to_file( self, ifft1, "data/CIR1.compl" ) # log_to_file( self, summ1, "data/CTFsumm1.compl" ) # log_to_file( self, estimated_CTF, "data/CTF1.compl" ) # log_to_file( self, c2m, "data/CTFmag1.float" ) ## MSE enhancer ctf_mse_enhancer_1 = ofdm.CTF_MSE_enhancer( total_subc, cp_length + cp_length) ctf_mse_enhancer_2 = ofdm.CTF_MSE_enhancer( total_subc, cp_length + cp_length) self.connect(estimated_CTF_1, ctf_mse_enhancer_1) self.connect(estimated_CTF_2, ctf_mse_enhancer_2) ctf_mse_enhancer_3 = ofdm.CTF_MSE_enhancer( total_subc, cp_length + cp_length) ctf_mse_enhancer_4 = ofdm.CTF_MSE_enhancer( total_subc, cp_length + cp_length) self.connect(estimated_CTF_3, ctf_mse_enhancer_3) self.connect(estimated_CTF_4, ctf_mse_enhancer_4) estimated_CTF_1 = ctf_mse_enhancer_1 estimated_CTF_2 = ctf_mse_enhancer_2 estimated_CTF_3 = ctf_mse_enhancer_3 estimated_CTF_4 = ctf_mse_enhancer_4 print "Disabled CTF MSE enhancer" ctf_postprocess_1 = ofdm.postprocess_CTF_estimate(total_subc / 2) self.connect(estimated_CTF_1, (ctf_postprocess_1, 0)) ctf_postprocess_2 = ofdm.postprocess_CTF_estimate(total_subc / 2) self.connect(estimated_CTF_2, (ctf_postprocess_2, 0)) ctf_postprocess_3 = ofdm.postprocess_CTF_estimate(total_subc / 2) self.connect(estimated_CTF_3, (ctf_postprocess_3, 0)) ctf_postprocess_4 = ofdm.postprocess_CTF_estimate(total_subc / 2) self.connect(estimated_CTF_4, (ctf_postprocess_4, 0)) inv_CTF_1 = (ctf_postprocess_1, 0) disp_CTF_1 = (ctf_postprocess_1, 1) inv_CTF_2 = (ctf_postprocess_2, 0) disp_CTF_2 = (ctf_postprocess_2, 1) inv_CTF_3 = (ctf_postprocess_3, 0) disp_CTF_3 = (ctf_postprocess_3, 1) inv_CTF_4 = (ctf_postprocess_4, 0) disp_CTF_4 = (ctf_postprocess_4, 1) disp_CTF_RX0 = blocks.add_ff(total_subc / 2) disp_CTF_RX1 = blocks.add_ff(total_subc / 2) self.connect(disp_CTF_1, (disp_CTF_RX0, 0)) self.connect(disp_CTF_2, (disp_CTF_RX0, 1)) self.connect(disp_CTF_3, (disp_CTF_RX1, 0)) self.connect(disp_CTF_4, (disp_CTF_RX1, 1)) terminate_stream(self, disp_CTF_RX0) terminate_stream(self, disp_CTF_RX1) disp_CTF_RX0 = blocks.null_source(gr.sizeof_float * total_subc) disp_CTF_RX1 = blocks.null_source(gr.sizeof_float * total_subc) ## Channel Equalizer #log_to_file(self, ofdm_blocks, "data/vec_mask.compl") #log_to_file(self, ofdm_blocks2, "data/vec_mask2.compl") nondata_blocks = [] for i in range(config.frame_length): if i in config.training_data.pilotsym_pos: nondata_blocks.append(i) pilot_subc = block_header.pilot_tones pilot_subcarriers = block_header.pilot_subc_sym print "PILOT SUBCARRIERS: ", pilot_subcarriers phase_tracking = ofdm.lms_phase_tracking_03( total_subc, pilot_subc, nondata_blocks, pilot_subcarriers, 0) phase_tracking2 = ofdm.lms_phase_tracking_03( total_subc, pilot_subc, nondata_blocks, pilot_subcarriers, 0) ##phase_tracking = ofdm.LMS_phase_tracking2( total_subc, pilot_subc, ## nondata_blocks ) ##phase_tracking2 = ofdm.LMS_phase_tracking2( total_subc, pilot_subc, ## nondata_blocks ) # self.connect( ofdm_blocks, ( phase_tracking, 0 ) ) # self.connect( ofdm_blocks2, ( phase_tracking, 1 )) # self.connect( inv_CTF_1, ( phase_tracking, 2 ) ) # self.connect( inv_CTF_3, ( phase_tracking, 3 ) ) # self.connect( frame_start, ( phase_tracking, 4 ) ) # self.connect( frame_start2, ( phase_tracking, 5) ) # # self.connect( ofdm_blocks2, ( phase_tracking2, 0 ) ) # self.connect( ofdm_blocks, ( phase_tracking2, 1 )) # self.connect( inv_CTF_3, ( phase_tracking2, 2 ) ) # self.connect( inv_CTF_1, ( phase_tracking2, 3 ) ) # self.connect( frame_start2, ( phase_tracking2, 4 ) ) # self.connect( frame_start, ( phase_tracking2, 5 ) ) self.connect(ofdm_blocks, (phase_tracking, 0)) self.connect(inv_CTF_1, (phase_tracking, 1)) self.connect(frame_start, (phase_tracking, 2)) self.connect(ofdm_blocks2, (phase_tracking2, 0)) self.connect(inv_CTF_3, (phase_tracking2, 1)) self.connect(frame_start2, (phase_tracking2, 2)) #ofdm_blocks = phase_tracking #ofdm_blocks2 = phase_tracking2 self.connect(phase_tracking, blocks.null_sink(gr.sizeof_gr_complex * total_subc)) self.connect(phase_tracking2, blocks.null_sink(gr.sizeof_gr_complex * total_subc)) terminate_stream(self, inv_CTF_2) terminate_stream(self, inv_CTF_4) #terminate_stream(self, inv_CTF_1) #terminate_stream(self, inv_CTF_3) terminate_stream(self, estimated_CTF_3) terminate_stream(self, estimated_CTF_4) ##terminate_stream(self, (phase_tracking,1)) ##terminate_stream(self, (phase_tracking2,1)) '''equalizer = ofdm.channel_equalizer_mimo_2( total_subc ) self.connect( ofdm_blocks, ( equalizer, 0 ) ) self.connect( ofdm_blocks2, ( equalizer, 1 ) ) self.connect( inv_CTF_1, ( equalizer, 2 ) ) self.connect( inv_CTF_2, ( equalizer, 3 ) ) self.connect( inv_CTF_3, ( equalizer, 4 ) ) self.connect( inv_CTF_4, ( equalizer, 5 ) ) self.connect( frame_start, ( equalizer, 6 ) ) self.connect( frame_start2, ( equalizer, 7 ) ) ofdm_blocks = equalizer''' terminate_stream(self, inv_CTF_1) terminate_stream(self, inv_CTF_3) equalizer = ofdm.channel_equalizer_mimo_2(total_subc) self.connect(ofdm_blocks, (equalizer, 0)) self.connect(estimated_CTF_1, (equalizer, 1)) self.connect(estimated_CTF_2, (equalizer, 2)) self.connect(frame_start, (equalizer, 3)) ofdm_blocks = equalizer equalizer2 = ofdm.channel_equalizer_mimo_2(total_subc) self.connect(ofdm_blocks2, (equalizer2, 0)) self.connect(estimated_CTF_3, (equalizer2, 1)) self.connect(estimated_CTF_4, (equalizer2, 2)) self.connect(frame_start2, (equalizer2, 3)) ofdm_blocks2 = equalizer2 #ofdm_blocks = equalizer #ofdm_blocks2 = equalizer2 #log_to_file(self, equalizer,"data/equalizer.compl") #log_to_file(self, ofdm_blocks2,"data/equalizer.compl") #log_to_file(self, ofdm_blocks,"data/equalizer2.compl") ## LMS Phase tracking ## Track residual frequency offset and sampling clock frequency offset ''' nondata_blocks = [] for i in range(config.frame_length): if i in config.training_data.pilotsym_pos: nondata_blocks.append(i) pilot_subc = block_header.pilot_tones phase_tracking = ofdm.LMS_phase_tracking2( total_subc, pilot_subc, nondata_blocks ) self.connect( equalizer, ( phase_tracking, 0 ) ) self.connect( frame_start, ( phase_tracking, 1 ) ) phase_tracking2 = ofdm.LMS_phase_tracking2( total_subc, pilot_subc, nondata_blocks ) self.connect( equalizer2, ( phase_tracking2, 0 ) ) self.connect( frame_start2, ( phase_tracking2, 1 ) ) # if options.scatter_plot_before_phase_tracking: # self.before_phase_tracking = equalizer if options.disable_phase_tracking or options.ideal: terminate_stream(self, phase_tracking) terminate_stream(self, phase_tracking2) print "Disabled phase tracking stage" else: ofdm_blocks = phase_tracking ofdm_blocks2 = phase_tracking2 log_to_file(self,phase_tracking, "data/phase_tracking.compl") ''' combine = blocks.add_cc(config.subcarriers) self.connect(ofdm_blocks, (combine, 0)) self.connect(ofdm_blocks2, (combine, 1)) norm_val = [0.5] * 208 norm = ofdm.multiply_const_vcc(norm_val) self.connect(combine, norm) ofdm_blocks = norm ## div = gr.multiply_cc(config.subcarriers) ## const = blocks.vector_source_c([[0.5+0]*config.subcarriers],True) ## self.connect(ofdm_blocks,div) ## self.connect(const,(div,1)) ## ofdm_blocks=div # log_to_file(self,combine,"data/combine.compl") ## Output connections self.connect(ofdm_blocks, out_ofdm_blocks) self.connect(frame_start, out_frame_start) self.connect(disp_CTF_RX0, out_disp_ctf) self.connect(frame_start2, out_frame_start2) self.connect(disp_CTF_RX1, out_disp_ctf2) else: ## extract channel estimation preamble from frame chest_pre_trigger_11 = blocks.delay(gr.sizeof_char, 1) chest_pre_trigger_12 = blocks.delay(gr.sizeof_char, 2) sampled_chest_preamble_11 = \ ofdm.vector_sampler( gr.sizeof_gr_complex * total_subc, 1 ) sampled_chest_preamble_12 = \ ofdm.vector_sampler( gr.sizeof_gr_complex * total_subc, 1 ) self.connect(frame_start, chest_pre_trigger_11) self.connect(chest_pre_trigger_11, (sampled_chest_preamble_11, 1)) self.connect(ofdm_blocks, (sampled_chest_preamble_11, 0)) self.connect(frame_start, chest_pre_trigger_12) self.connect(chest_pre_trigger_12, (sampled_chest_preamble_12, 1)) self.connect(ofdm_blocks, (sampled_chest_preamble_12, 0)) chest_pre_trigger_21 = blocks.delay(gr.sizeof_char, 1) chest_pre_trigger_22 = blocks.delay(gr.sizeof_char, 2) sampled_chest_preamble_21 = \ ofdm.vector_sampler( gr.sizeof_gr_complex * total_subc, 1 ) sampled_chest_preamble_22 = \ ofdm.vector_sampler( gr.sizeof_gr_complex * total_subc, 1 ) self.connect(frame_start2, chest_pre_trigger_21) self.connect(chest_pre_trigger_21, (sampled_chest_preamble_21, 1)) self.connect(ofdm_blocks2, (sampled_chest_preamble_21, 0)) self.connect(frame_start2, chest_pre_trigger_22) self.connect(chest_pre_trigger_22, (sampled_chest_preamble_22, 1)) self.connect(ofdm_blocks2, (sampled_chest_preamble_22, 0)) # Taking inverse for estimating h11 (h12) inv_preamble_fd_1 = numpy.array(block_header.pilotsym_fd_1[ block_header.channel_estimation_pilot[0]]) #inv_preamble_fd_1 = inv_preamble_fd_1[0::2] # Taking inverse for estimating h21 (h22) inv_preamble_fd_2 = numpy.array(block_header.pilotsym_fd_2[ block_header.channel_estimation_pilot[0] + 1]) #inv_preamble_fd_2 = inv_preamble_fd_2[1::2] inv_preamble_fd_1 = 1. / inv_preamble_fd_1 inv_preamble_fd_2 = 1. / inv_preamble_fd_2 # dd = [] #for i in range (total_subc/2): # dd.extend([i*2]) skip_block_11 = ofdm.int_skip(total_subc, 2, 0) skip_block_111 = ofdm.int_skip(total_subc, 2, 0) skip_block_12 = ofdm.int_skip(total_subc, 2, 1) # inta_estim_1 = ofdm.interpolator(total_subc,2,dd) # inta_estim_2 = ofdm.interpolator(total_subc,2,dd) LS_channel_estimator_11 = ofdm.multiply_const_vcc( list(inv_preamble_fd_1)) LS_channel_estimator_12 = ofdm.multiply_const_vcc( list(inv_preamble_fd_2)) self.connect(sampled_chest_preamble_11, LS_channel_estimator_11) #,inta_estim_1 ) self.connect(sampled_chest_preamble_12, LS_channel_estimator_12) #,inta_estim_2 ) estimated_CTF_11 = LS_channel_estimator_11 # h0 estimated_CTF_12 = LS_channel_estimator_12 # h1 skip_block_21 = ofdm.int_skip(total_subc, 2, 0) skip_block_211 = ofdm.int_skip(total_subc, 2, 0) skip_block_22 = ofdm.int_skip(total_subc, 2, 1) # inta_estim_3 = ofdm.interpolator(total_subc,2,dd) # inta_estim_4 = ofdm.interpolator(total_subc,2,dd) LS_channel_estimator_21 = ofdm.multiply_const_vcc( list(inv_preamble_fd_1)) LS_channel_estimator_22 = ofdm.multiply_const_vcc( list(inv_preamble_fd_2)) self.connect(sampled_chest_preamble_21, LS_channel_estimator_21) #,inta_estim_3 ) self.connect(sampled_chest_preamble_22, LS_channel_estimator_22) #,inta_estim_4 ) estimated_CTF_21 = LS_channel_estimator_21 # h2 estimated_CTF_22 = LS_channel_estimator_22 # h3 if not options.disable_ctf_enhancer: # if options.logcir: # ifft1 = fft_blocks.fft_vcc(total_subc,False,[],True) # self.connect( estimated_CTF, ifft1,blocks.null_sink(gr.sizeof_gr_complex*total_subc)) # summ1 = ofdm.vector_sum_vcc(total_subc) # c2m =gr.complex_to_mag(total_subc) # self.connect( estimated_CTF,summ1 ,blocks.null_sink(gr.sizeof_gr_complex)) # self.connect( estimated_CTF, c2m,blocks.null_sink(gr.sizeof_float*total_subc)) # log_to_file( self, ifft1, "data/CIR1.compl" ) # log_to_file( self, summ1, "data/CTFsumm1.compl" ) # log_to_file( self, estimated_CTF, "data/CTF1.compl" ) # log_to_file( self, c2m, "data/CTFmag1.float" ) ## MSE enhancer ctf_mse_enhancer_11 = ofdm.CTF_MSE_enhancer( total_subc, cp_length + cp_length) ctf_mse_enhancer_12 = ofdm.CTF_MSE_enhancer( total_subc, cp_length + cp_length) self.connect(estimated_CTF_11, ctf_mse_enhancer_11) self.connect(estimated_CTF_12, ctf_mse_enhancer_12) ctf_mse_enhancer_21 = ofdm.CTF_MSE_enhancer( total_subc, cp_length + cp_length) ctf_mse_enhancer_22 = ofdm.CTF_MSE_enhancer( total_subc, cp_length + cp_length) self.connect(estimated_CTF_21, ctf_mse_enhancer_21) self.connect(estimated_CTF_22, ctf_mse_enhancer_22) estimated_CTF_11 = ctf_mse_enhancer_11 estimated_CTF_12 = ctf_mse_enhancer_12 estimated_CTF_21 = ctf_mse_enhancer_21 estimated_CTF_22 = ctf_mse_enhancer_22 print "Disabled CTF MSE enhancer" ctf_postprocess_11 = ofdm.postprocess_CTF_estimate(total_subc) self.connect(estimated_CTF_11, (ctf_postprocess_11, 0)) ctf_postprocess_12 = ofdm.postprocess_CTF_estimate(total_subc) self.connect(estimated_CTF_12, (ctf_postprocess_12, 0)) ctf_postprocess_21 = ofdm.postprocess_CTF_estimate(total_subc) self.connect(estimated_CTF_21, (ctf_postprocess_21, 0)) ctf_postprocess_22 = ofdm.postprocess_CTF_estimate(total_subc) self.connect(estimated_CTF_22, (ctf_postprocess_22, 0)) inv_CTF_11 = (ctf_postprocess_11, 0) disp_CTF_11 = (ctf_postprocess_11, 1) inv_CTF_12 = (ctf_postprocess_12, 0) disp_CTF_12 = (ctf_postprocess_12, 1) inv_CTF_21 = (ctf_postprocess_21, 0) disp_CTF_21 = (ctf_postprocess_21, 1) inv_CTF_22 = (ctf_postprocess_22, 0) disp_CTF_22 = (ctf_postprocess_22, 1) #disp_CTF_RX0 = blocks.add_ff(total_subc) #disp_CTF_RX1 = blocks.add_ff(total_subc) #self.connect ( disp_CTF_11, (disp_CTF_RX0, 0) ) #self.connect ( disp_CTF_12, (disp_CTF_RX0, 1) ) #self.connect ( disp_CTF_21, (disp_CTF_RX1, 0) ) #self.connect ( disp_CTF_22, (disp_CTF_RX1, 1) ) terminate_stream(self, disp_CTF_21) terminate_stream(self, disp_CTF_22) disp_CTF_RX0 = disp_CTF_11 disp_CTF_RX1 = disp_CTF_12 ## Channel Equalizer #log_to_file(self, ofdm_blocks, "data/vec_mask.compl") #log_to_file(self, ofdm_blocks2, "data/vec_mask2.compl") nondata_blocks = [] for i in range(config.frame_length): if i in config.training_data.pilotsym_pos: nondata_blocks.append(i) pilot_subc = block_header.pilot_tones pilot_subcarriers = block_header.pilot_subc_sym print "PILOT SUBCARRIERS: ", pilot_subcarriers phase_tracking = ofdm.lms_phase_tracking_03( total_subc, pilot_subc, nondata_blocks, pilot_subcarriers, 0) phase_tracking2 = ofdm.lms_phase_tracking_03( total_subc, pilot_subc, nondata_blocks, pilot_subcarriers, 0) ##phase_tracking = ofdm.LMS_phase_tracking2( total_subc, pilot_subc, ## nondata_blocks ) ##phase_tracking2 = ofdm.LMS_phase_tracking2( total_subc, pilot_subc, ## nondata_blocks ) # self.connect( ofdm_blocks, ( phase_tracking, 0 ) ) # self.connect( ofdm_blocks2, ( phase_tracking, 1 )) # self.connect( inv_CTF_1, ( phase_tracking, 2 ) ) # self.connect( inv_CTF_3, ( phase_tracking, 3 ) ) # self.connect( frame_start, ( phase_tracking, 4 ) ) # self.connect( frame_start2, ( phase_tracking, 5) ) # # self.connect( ofdm_blocks2, ( phase_tracking2, 0 ) ) # self.connect( ofdm_blocks, ( phase_tracking2, 1 )) # self.connect( inv_CTF_3, ( phase_tracking2, 2 ) ) # self.connect( inv_CTF_1, ( phase_tracking2, 3 ) ) # self.connect( frame_start2, ( phase_tracking2, 4 ) ) # self.connect( frame_start, ( phase_tracking2, 5 ) ) self.connect(ofdm_blocks, (phase_tracking, 0)) self.connect(inv_CTF_11, skip_block_111, (phase_tracking, 1)) self.connect(frame_start, (phase_tracking, 2)) self.connect(ofdm_blocks2, (phase_tracking2, 0)) self.connect(inv_CTF_21, skip_block_211, (phase_tracking2, 1)) self.connect(frame_start2, (phase_tracking2, 2)) if options.disable_phase_tracking or options.ideal: terminate_stream(self, phase_tracking) terminate_stream(self, phase_tracking2) print "Disabled phase tracking stage" else: ofdm_blocks = phase_tracking ofdm_blocks2 = phase_tracking2 self.connect(phase_tracking, blocks.null_sink(gr.sizeof_gr_complex * total_subc)) self.connect(phase_tracking2, blocks.null_sink(gr.sizeof_gr_complex * total_subc)) terminate_stream(self, inv_CTF_12) terminate_stream(self, inv_CTF_22) #terminate_stream(self, inv_CTF_1) #terminate_stream(self, inv_CTF_3) #terminate_stream(self, estimated_CTF_21) #terminate_stream(self, estimated_CTF_22) ##terminate_stream(self, (phase_tracking,1)) ##terminate_stream(self, (phase_tracking2,1)) equalizer = ofdm.channel_equalizer_mimo_3(total_subc) self.connect(ofdm_blocks, (equalizer, 0)) self.connect(ofdm_blocks2, (equalizer, 1)) self.connect(estimated_CTF_11, skip_block_11, (equalizer, 2)) self.connect(estimated_CTF_12, skip_block_12, (equalizer, 3)) self.connect(estimated_CTF_21, skip_block_21, (equalizer, 4)) self.connect(estimated_CTF_22, skip_block_22, (equalizer, 5)) self.connect(frame_start, (equalizer, 6)) self.connect(frame_start, (equalizer, 7)) ofdm_blocks = equalizer #terminate_stream(self, inv_CTF_11) #terminate_stream(self, inv_CTF_21) '''equalizer = ofdm.channel_equalizer_mimo_2( total_subc ) self.connect( ofdm_blocks, ( equalizer, 0 ) ) self.connect( estimated_CTF_11, skip_block_11, ( equalizer, 1 ) ) self.connect( estimated_CTF_12, skip_block_12, ( equalizer, 2 ) ) self.connect( frame_start, ( equalizer, 3 ) ) ofdm_blocks = equalizer equalizer2 = ofdm.channel_equalizer_mimo_2( total_subc ) self.connect( ofdm_blocks2, ( equalizer2, 0 ) ) self.connect( estimated_CTF_21, skip_block_21, ( equalizer2, 1 ) ) self.connect( estimated_CTF_22, skip_block_22, ( equalizer2, 2 ) ) self.connect( frame_start2, ( equalizer2, 3 ) ) ofdm_blocks2 = equalizer2''' #ofdm_blocks = equalizer #ofdm_blocks2 = equalizer2 #log_to_file(self, equalizer,"data/equalizer.compl") #log_to_file(self, ofdm_blocks2,"data/equalizer.compl") #log_to_file(self, ofdm_blocks,"data/equalizer2.compl") ## LMS Phase tracking ## Track residual frequency offset and sampling clock frequency offset ''' nondata_blocks = [] for i in range(config.frame_length): if i in config.training_data.pilotsym_pos: nondata_blocks.append(i) pilot_subc = block_header.pilot_tones phase_tracking = ofdm.LMS_phase_tracking2( total_subc, pilot_subc, nondata_blocks ) self.connect( equalizer, ( phase_tracking, 0 ) ) self.connect( frame_start, ( phase_tracking, 1 ) ) phase_tracking2 = ofdm.LMS_phase_tracking2( total_subc, pilot_subc, nondata_blocks ) self.connect( equalizer2, ( phase_tracking2, 0 ) ) self.connect( frame_start2, ( phase_tracking2, 1 ) ) # if options.scatter_plot_before_phase_tracking: # self.before_phase_tracking = equalizer if options.disable_phase_tracking or options.ideal: terminate_stream(self, phase_tracking) terminate_stream(self, phase_tracking2) print "Disabled phase tracking stage" else: ofdm_blocks = phase_tracking ofdm_blocks2 = phase_tracking2 log_to_file(self,phase_tracking, "data/phase_tracking.compl") ''' '''combine = blocks.add_cc(config.subcarriers) self.connect(ofdm_blocks, (combine,0)) self.connect(ofdm_blocks2, (combine,1)) norm_val = [0.5]*config.subcarriers norm = ofdm.multiply_const_vcc( norm_val) self.connect(combine,norm) ofdm_blocks = norm''' ## div = gr.multiply_cc(config.subcarriers) ## const = blocks.vector_source_c([[0.5+0]*config.subcarriers],True) ## self.connect(ofdm_blocks,div) ## self.connect(const,(div,1)) ## ofdm_blocks=div # log_to_file(self,combine,"data/combine.compl") ## Output connections self.connect(ofdm_blocks, out_ofdm_blocks) self.connect(frame_start, out_frame_start) self.connect(disp_CTF_RX0, out_disp_ctf) self.connect(frame_start2, out_frame_start2) self.connect(disp_CTF_RX1, out_disp_ctf2)
def __init__( self, options, log = False ): ## Read configuration config = station_configuration() fft_length = config.fft_length cp_length = config.cp_length block_header = config.training_data data_subc = config.data_subcarriers virtual_subc = config.virtual_subcarriers total_subc = config.subcarriers block_length = config.block_length frame_length = config.frame_length L = block_header.mm_periodic_parts frame_data_blocks = options.data_blocks ## Set Input/Output signature gr.hier_block2.__init__( self, "ofdm_inner_receiver", gr.io_signature( 1, 1, gr.sizeof_gr_complex ), gr.io_signature4( 4, 4, gr.sizeof_gr_complex * total_subc, # OFDM blocks gr.sizeof_char, # Frame start gr.sizeof_float * total_subc, # Normalized |CTF|^2 gr.sizeof_float * total_subc ) ) # Normalized |CTF|^2 ## Input and output ports self.input = rx_input = (self,0) out_ofdm_blocks = ( self, 0 ) out_frame_start = ( self, 1 ) out_disp_ctf = ( self, 2 ) out_disp_ctf2 = ( self, 3 ) ## pre-FFT processing ## Compute autocorrelations for S&C preamble ## and cyclic prefix sc_metric = autocorrelator( fft_length/2, fft_length/2 ) gi_metric = autocorrelator( fft_length, cp_length ) self.connect( rx_input, sc_metric ) self.connect( rx_input, gi_metric ) ## Sync. Output contains OFDM blocks sync = ofdm.time_sync( fft_length, cp_length ) self.connect( rx_input, ( sync, 0 ) ) self.connect( sc_metric, ( sync, 1 ) ) self.connect( gi_metric, ( sync, 2 ) ) ofdm_blocks = ( sync, 0 ) frame_start = ( sync, 1 ) if options.disable_time_sync or options.ideal: terminate_stream(self, ofdm_blocks) terminate_stream(self, frame_start) serial_to_parallel = blocks.stream_to_vector(gr.sizeof_gr_complex,block_length) discard_cp = ofdm.vector_mask(block_length,cp_length,fft_length,[]) ofdm_blocks = discard_cp self.connect( rx_input, serial_to_parallel, discard_cp ) frame_start = [0]*frame_length frame_start[0] = 1 frame_start = blocks.vector_source_b(frame_start,True) print "Disabled time synchronization stage" ## Extract preamble, feed to Morelli & Mengali frequency offset estimator assert( block_header.mm_preamble_pos == 0 ) morelli_foe = ofdm.mm_frequency_estimator( fft_length, L ) sampler_preamble = ofdm.vector_sampler( gr.sizeof_gr_complex * fft_length, 1 ) self.connect( ofdm_blocks, ( sampler_preamble, 0 ) ) self.connect( frame_start, ( sampler_preamble, 1 ) ) self.connect( sampler_preamble, morelli_foe ) freq_offset = morelli_foe ## Adaptive LMS FIR filtering of frequency offset lms_fir = ofdm.lms_fir_ff( 20, 1e-3 ) # TODO: verify parameter choice self.connect( freq_offset, lms_fir ) freq_offset = lms_fir log_to_file(self, lms_fir, "data/foe_21.float") # log_to_file(self, lms_fir, "data/lms_fir.float") # log_to_file(self, lms_fir2, "data/lms_fir2.float") if options.disable_freq_sync or options.ideal: terminate_stream(self, freq_offset) freq_offset = blocks.vector_source_f([0.0],True) print "Disabled frequency synchronization stage" ## Correct frequency shift, feed-forward structure frequency_shift = ofdm.frequency_shift_vcc( fft_length, -1.0/fft_length, cp_length ) self.connect( ofdm_blocks, ( frequency_shift, 0 ) ) self.connect( freq_offset, ( frequency_shift, 1 ) ) self.connect( frame_start, ( frequency_shift, 2 ) ) ofdm_blocks = frequency_shift ## FFT fft = fft_blocks.fft_vcc( fft_length, True, [], True ) self.connect( ofdm_blocks, fft ) ofdm_blocks = fft ## Remove virtual subcarriers if fft_length > data_subc: subcarrier_mask = ofdm.vector_mask( fft_length, virtual_subc/2, total_subc, [] ) self.connect( ofdm_blocks, subcarrier_mask ) ofdm_blocks = subcarrier_mask ## Least Squares estimator for channel transfer function (CTF) # if options.logcir: # log_to_file( self, ofdm_blocks, "data/OFDM_Blocks.compl" ) # inv_preamble_fd = numpy.array( block_header.pilotsym_fd[ # block_header.channel_estimation_pilot[0] ] ) # print "Channel estimation pilot: ", inv_preamble_fd # inv_preamble_fd = 1. / inv_preamble_fd # LS_channel_estimator0 = ofdm.multiply_const_vcc( list( inv_preamble_fd ) ) # self.connect( ofdm_blocks, LS_channel_estimator0, blocks.null_sink(gr.sizeof_gr_complex*total_subc)) # log_to_file( self, LS_channel_estimator0, "data/OFDM_Blocks_eq.compl" ) ## post-FFT processing ## extract channel estimation preamble from frame if options.est_preamble==1: chest_pre_trigger = blocks.delay( gr.sizeof_char, 1 ) sampled_chest_preamble = \ ofdm.vector_sampler( gr.sizeof_gr_complex * total_subc, 1 ) self.connect( frame_start, chest_pre_trigger ) self.connect( chest_pre_trigger, ( sampled_chest_preamble, 1 ) ) self.connect( ofdm_blocks, ( sampled_chest_preamble, 0 ) ) ## Least Squares estimator for channel transfer function (CTF) # Taking inverse for estimating h11 (h12) inv_preamble_fd_1 = numpy.array( block_header.pilotsym_fd_1[ block_header.channel_estimation_pilot[0] ] ) print "inv_preamble_fd_1: ",inv_preamble_fd_1 inv_preamble_fd_1 = inv_preamble_fd_1[0::2] #print "inv_preamble_fd_1 ", inv_preamble_fd_1 # Taking inverse for estimating h21 (h22) inv_preamble_fd_2 = numpy.array( block_header.pilotsym_fd_2[ block_header.channel_estimation_pilot[0] ] ) print "inv_preamble_fd_2: ",inv_preamble_fd_2 inv_preamble_fd_2 = inv_preamble_fd_2[1::2] #print "inv_preamble_fd_2 ", inv_preamble_fd_2 print "inv_preamble_fd_1: ",inv_preamble_fd_1 print "inv_preamble_fd_2: ",inv_preamble_fd_2 inv_preamble_fd_1 = 1. / inv_preamble_fd_1 inv_preamble_fd_2 = 1. / inv_preamble_fd_2 dd = [] for i in range (total_subc/2): dd.extend([i*2]) skip_block_1 = ofdm.int_skip(total_subc,2,0) skip_block_2 = ofdm.int_skip(total_subc,2,1) # inta_estim_1 = ofdm.interpolator(total_subc,2,dd) # inta_estim_2 = ofdm.interpolator(total_subc,2,dd) LS_channel_estimator_1 = ofdm.multiply_const_vcc( list( inv_preamble_fd_1 ) ) LS_channel_estimator_2 = ofdm.multiply_const_vcc( list( inv_preamble_fd_2 ) ) self.connect( sampled_chest_preamble,skip_block_1, LS_channel_estimator_1)#,inta_estim_1 ) self.connect( sampled_chest_preamble,skip_block_2, LS_channel_estimator_2)#,inta_estim_2 ) estimated_CTF_1 = LS_channel_estimator_1 # h0 estimated_CTF_2 = LS_channel_estimator_2 # h1 # h3 if not options.disable_ctf_enhancer: # if options.logcir: # ifft1 = fft_blocks.fft_vcc(total_subc,False,[],True) # self.connect( estimated_CTF, ifft1,blocks.null_sink(gr.sizeof_gr_complex*total_subc)) # summ1 = ofdm.vector_sum_vcc(total_subc) # c2m =gr.complex_to_mag(total_subc) # self.connect( estimated_CTF,summ1 ,blocks.null_sink(gr.sizeof_gr_complex)) # self.connect( estimated_CTF, c2m,blocks.null_sink(gr.sizeof_float*total_subc)) # log_to_file( self, ifft1, "data/CIR1.compl" ) # log_to_file( self, summ1, "data/CTFsumm1.compl" ) # log_to_file( self, estimated_CTF, "data/CTF1.compl" ) # log_to_file( self, c2m, "data/CTFmag1.float" ) ## MSE enhancer ctf_mse_enhancer_1 = ofdm.CTF_MSE_enhancer( total_subc, cp_length + cp_length) ctf_mse_enhancer_2 = ofdm.CTF_MSE_enhancer( total_subc, cp_length + cp_length) self.connect( estimated_CTF_1, ctf_mse_enhancer_1 ) self.connect( estimated_CTF_2, ctf_mse_enhancer_2 ) estimated_CTF_1 = ctf_mse_enhancer_1 estimated_CTF_2 = ctf_mse_enhancer_2 print "Disabled CTF MSE enhancer" ctf_postprocess_1 = ofdm.postprocess_CTF_estimate( total_subc/2 ) self.connect( estimated_CTF_1, ( ctf_postprocess_1, 0 ) ) ctf_postprocess_2 = ofdm.postprocess_CTF_estimate( total_subc/2 ) self.connect( estimated_CTF_2, ( ctf_postprocess_2, 0 ) ) inv_CTF_1 = ( ctf_postprocess_1, 0 ) disp_CTF_1 = ( ctf_postprocess_1, 1 ) inv_CTF_2 = ( ctf_postprocess_2, 0 ) disp_CTF_2 = ( ctf_postprocess_2, 1 ) disp_CTF_RX0 = blocks.add_ff(total_subc/2) self.connect ( disp_CTF_1, (disp_CTF_RX0, 0) ) self.connect ( disp_CTF_2, (disp_CTF_RX0, 1) ) terminate_stream(self,disp_CTF_RX0) terminate_stream(self,inv_CTF_2) disp_CTF_RX0 = blocks.null_source(gr.sizeof_float*total_subc) disp_CTF_RX1 = blocks.null_source(gr.sizeof_float*total_subc) ## Channel Equalizer #log_to_file(self, ofdm_blocks, "data/vec_mask.compl") #log_to_file(self, ofdm_blocks2, "data/vec_mask2.compl") nondata_blocks = [] for i in range(config.frame_length): if i in config.training_data.pilotsym_pos: nondata_blocks.append(i) pilot_subc = block_header.pilot_tones pilot_subcarriers = block_header.pilot_subc_sym print "PILOT SUBCARRIERS: ", pilot_subcarriers phase_tracking = ofdm.lms_phase_tracking_03( total_subc, pilot_subc, nondata_blocks,pilot_subcarriers,0 ) ##phase_tracking = ofdm.lms_phase_tracking_02( total_subc, pilot_subc, ## nondata_blocks ) ##phase_tracking2 = ofdm.lms_phase_tracking_02( total_subc, pilot_subc, ## nondata_blocks ) # self.connect( ofdm_blocks, ( phase_tracking, 0 ) ) # self.connect( ofdm_blocks2, ( phase_tracking, 1 )) # self.connect( inv_CTF_1, ( phase_tracking, 2 ) ) # self.connect( inv_CTF_3, ( phase_tracking, 3 ) ) # self.connect( frame_start, ( phase_tracking, 4 ) ) # self.connect( frame_start2, ( phase_tracking, 5) ) # # self.connect( ofdm_blocks2, ( phase_tracking2, 0 ) ) # self.connect( ofdm_blocks, ( phase_tracking2, 1 )) # self.connect( inv_CTF_3, ( phase_tracking2, 2 ) ) # self.connect( inv_CTF_1, ( phase_tracking2, 3 ) ) # self.connect( frame_start2, ( phase_tracking2, 4 ) ) # self.connect( frame_start, ( phase_tracking2, 5 ) ) self.connect( ofdm_blocks, ( phase_tracking, 0 ) ) self.connect( inv_CTF_1, ( phase_tracking, 1 ) ) self.connect( frame_start, ( phase_tracking, 2 ) ) #self.connect(phase_tracking,blocks.null_sink(gr.sizeof_gr_complex*total_subc)) ofdm_blocks = phase_tracking '''equalizer = ofdm.channel_equalizer_mimo_2( total_subc ) self.connect( ofdm_blocks, ( equalizer, 0 ) ) self.connect( ofdm_blocks2, ( equalizer, 1 ) ) self.connect( inv_CTF_1, ( equalizer, 2 ) ) self.connect( inv_CTF_2, ( equalizer, 3 ) ) self.connect( inv_CTF_3, ( equalizer, 4 ) ) self.connect( inv_CTF_4, ( equalizer, 5 ) ) self.connect( frame_start, ( equalizer, 6 ) ) self.connect( frame_start2, ( equalizer, 7 ) ) ofdm_blocks = equalizer''' equalizer = ofdm.channel_equalizer_mimo_2( total_subc ) self.connect( ofdm_blocks, ( equalizer, 0 ) ) self.connect( estimated_CTF_1, ( equalizer, 1 ) ) self.connect( estimated_CTF_2, ( equalizer, 2 ) ) self.connect( frame_start, ( equalizer, 3 ) ) #ofdm_blocks = equalizer #ofdm_blocks2 = equalizer2 ofdm_blocks = equalizer #log_to_file(self, equalizer,"data/equalizer.compl") log_to_file(self, ofdm_blocks,"data/equalizer.compl") log_to_file(self, estimated_CTF_1,"data/estimated_CTF_1.compl") log_to_file(self, estimated_CTF_2,"data/estimated_CTF_2.compl") ## LMS Phase tracking ## Track residual frequency offset and sampling clock frequency offset ''' nondata_blocks = [] for i in range(config.frame_length): if i in config.training_data.pilotsym_pos: nondata_blocks.append(i) pilot_subc = block_header.pilot_tones phase_tracking = ofdm.lms_phase_tracking_02( total_subc, pilot_subc, nondata_blocks ) self.connect( equalizer, ( phase_tracking, 0 ) ) self.connect( frame_start, ( phase_tracking, 1 ) ) phase_tracking2 = ofdm.lms_phase_tracking_02( total_subc, pilot_subc, nondata_blocks ) self.connect( equalizer2, ( phase_tracking2, 0 ) ) self.connect( frame_start2, ( phase_tracking2, 1 ) ) # if options.scatter_plot_before_phase_tracking: # self.before_phase_tracking = equalizer if options.disable_phase_tracking or options.ideal: terminate_stream(self, phase_tracking) terminate_stream(self, phase_tracking2) print "Disabled phase tracking stage" else: ofdm_blocks = phase_tracking ofdm_blocks2 = phase_tracking2 log_to_file(self,phase_tracking, "data/phase_tracking.compl") ''' '''combine = blocks.add_cc(config.subcarriers) self.connect(ofdm_blocks, (combine,0)) self.connect(ofdm_blocks2, (combine,1)) ofdm_blocks = combine''' ## div = gr.multiply_cc(config.subcarriers) ## const = blocks.vector_source_c([[0.5+0]*config.subcarriers],True) ## self.connect(ofdm_blocks,div) ## self.connect(const,(div,1)) ## ofdm_blocks=div # log_to_file(self,combine,"data/combine.compl") ## Output connections self.connect( ofdm_blocks, out_ofdm_blocks ) self.connect( frame_start, out_frame_start ) self.connect( disp_CTF_RX0, out_disp_ctf ) self.connect( disp_CTF_RX1, out_disp_ctf2 ) else: # (2 preambles for channel estimation) chest_pre_trigger_1 = blocks.delay( gr.sizeof_char, 1 ) chest_pre_trigger_2 = blocks.delay( gr.sizeof_char, 2 ) sampled_chest_preamble_1 = \ ofdm.vector_sampler( gr.sizeof_gr_complex * total_subc, 1 ) sampled_chest_preamble_2 = \ ofdm.vector_sampler( gr.sizeof_gr_complex * total_subc, 1 ) self.connect( frame_start, chest_pre_trigger_1 ) self.connect( chest_pre_trigger_1, ( sampled_chest_preamble_1, 1 ) ) self.connect( ofdm_blocks, ( sampled_chest_preamble_1, 0 ) ) self.connect( frame_start, chest_pre_trigger_2 ) self.connect( chest_pre_trigger_2, ( sampled_chest_preamble_2, 1 ) ) self.connect( ofdm_blocks, ( sampled_chest_preamble_2, 0 ) ) ## Least Squares estimator for channel transfer function (CTF) # Taking inverse for estimating h11 (h12) inv_preamble_fd_1 = numpy.array( block_header.pilotsym_fd_1[ block_header.channel_estimation_pilot[0] ] ) print "inv_preamble_fd_1: ",inv_preamble_fd_1 #inv_preamble_fd_1 = inv_preamble_fd_1[0::2] #print "inv_preamble_fd_1 ", inv_preamble_fd_1 # Taking inverse for estimating h21 (h22) inv_preamble_fd_2 = numpy.array( block_header.pilotsym_fd_2[ block_header.channel_estimation_pilot[0]+1 ] ) print "inv_preamble_fd_2: ",inv_preamble_fd_2 #inv_preamble_fd_2 = inv_preamble_fd_2[1::2] #print "inv_preamble_fd_2 ", inv_preamble_fd_2 print "inv_preamble_fd_1: ",inv_preamble_fd_1 print "inv_preamble_fd_2: ",inv_preamble_fd_2 inv_preamble_fd_1 = 1. / inv_preamble_fd_1 inv_preamble_fd_2 = 1. / inv_preamble_fd_2 #dd = [] #for i in range (total_subc/2): # dd.extend([i*2]) skip_block_1 = ofdm.int_skip(total_subc,2,0) skip_block_11 = ofdm.int_skip(total_subc,2,0) skip_block_2 = ofdm.int_skip(total_subc,2,1) # inta_estim_1 = ofdm.interpolator(total_subc,2,dd) # inta_estim_2 = ofdm.interpolator(total_subc,2,dd) LS_channel_estimator_1 = ofdm.multiply_const_vcc( list( inv_preamble_fd_1 ) ) LS_channel_estimator_2 = ofdm.multiply_const_vcc( list( inv_preamble_fd_2 ) ) self.connect( sampled_chest_preamble_1, LS_channel_estimator_1)#,inta_estim_1 ) self.connect( sampled_chest_preamble_2, LS_channel_estimator_2)#,inta_estim_2 ) estimated_CTF_1 = LS_channel_estimator_1 # h0 estimated_CTF_2 = LS_channel_estimator_2 # h1 # h3 if not options.disable_ctf_enhancer: # if options.logcir: # ifft1 = fft_blocks.fft_vcc(total_subc,False,[],True) # self.connect( estimated_CTF, ifft1,blocks.null_sink(gr.sizeof_gr_complex*total_subc)) # summ1 = ofdm.vector_sum_vcc(total_subc) # c2m =gr.complex_to_mag(total_subc) # self.connect( estimated_CTF,summ1 ,blocks.null_sink(gr.sizeof_gr_complex)) # self.connect( estimated_CTF, c2m,blocks.null_sink(gr.sizeof_float*total_subc)) # log_to_file( self, ifft1, "data/CIR1.compl" ) # log_to_file( self, summ1, "data/CTFsumm1.compl" ) # log_to_file( self, estimated_CTF, "data/CTF1.compl" ) # log_to_file( self, c2m, "data/CTFmag1.float" ) ## MSE enhancer ctf_mse_enhancer_1 = ofdm.CTF_MSE_enhancer( total_subc, cp_length + cp_length) ctf_mse_enhancer_2 = ofdm.CTF_MSE_enhancer( total_subc, cp_length + cp_length) self.connect( estimated_CTF_1, ctf_mse_enhancer_1 ) self.connect( estimated_CTF_2, ctf_mse_enhancer_2 ) estimated_CTF_1 = ctf_mse_enhancer_1 estimated_CTF_2 = ctf_mse_enhancer_2 print "Disabled CTF MSE enhancer" ctf_postprocess_1 = ofdm.postprocess_CTF_estimate( total_subc ) self.connect( estimated_CTF_1, ( ctf_postprocess_1, 0 ) ) ctf_postprocess_2 = ofdm.postprocess_CTF_estimate( total_subc ) self.connect( estimated_CTF_2, ( ctf_postprocess_2, 0 ) ) inv_CTF_1 = ( ctf_postprocess_1, 0 ) disp_CTF_1 = ( ctf_postprocess_1, 1 ) inv_CTF_2 = ( ctf_postprocess_2, 0 ) disp_CTF_2 = ( ctf_postprocess_2, 1 ) #disp_CTF_RX0 = blocks.add_ff(total_subc) #self.connect ( disp_CTF_1, (disp_CTF_RX0, 0) ) #self.connect ( disp_CTF_2, (disp_CTF_RX0, 1) ) #terminate_stream(self,disp_CTF_RX0) terminate_stream(self,inv_CTF_2) disp_CTF_RX0 = disp_CTF_1 disp_CTF_RX1 = disp_CTF_2 ## Channel Equalizer #log_to_file(self, ofdm_blocks, "data/vec_mask.compl") #log_to_file(self, ofdm_blocks2, "data/vec_mask2.compl") nondata_blocks = [] for i in range(config.frame_length): if i in config.training_data.pilotsym_pos: nondata_blocks.append(i) pilot_subc = block_header.pilot_tones pilot_subcarriers = block_header.pilot_subc_sym print "PILOT SUBCARRIERS: ", pilot_subcarriers phase_tracking = ofdm.lms_phase_tracking_03( total_subc, pilot_subc, nondata_blocks,pilot_subcarriers,0 ) ##phase_tracking = ofdm.lms_phase_tracking_02( total_subc, pilot_subc, ## nondata_blocks ) ##phase_tracking2 = ofdm.lms_phase_tracking_02( total_subc, pilot_subc, ## nondata_blocks ) # self.connect( ofdm_blocks, ( phase_tracking, 0 ) ) # self.connect( ofdm_blocks2, ( phase_tracking, 1 )) # self.connect( inv_CTF_1, ( phase_tracking, 2 ) ) # self.connect( inv_CTF_3, ( phase_tracking, 3 ) ) # self.connect( frame_start, ( phase_tracking, 4 ) ) # self.connect( frame_start2, ( phase_tracking, 5) ) # # self.connect( ofdm_blocks2, ( phase_tracking2, 0 ) ) # self.connect( ofdm_blocks, ( phase_tracking2, 1 )) # self.connect( inv_CTF_3, ( phase_tracking2, 2 ) ) # self.connect( inv_CTF_1, ( phase_tracking2, 3 ) ) # self.connect( frame_start2, ( phase_tracking2, 4 ) ) # self.connect( frame_start, ( phase_tracking2, 5 ) ) self.connect( ofdm_blocks, ( phase_tracking, 0 ) ) self.connect( inv_CTF_1, skip_block_11, ( phase_tracking, 1 ) ) self.connect( frame_start, ( phase_tracking, 2 ) ) #self.connect(phase_tracking,blocks.null_sink(gr.sizeof_gr_complex*total_subc)) if options.disable_phase_tracking or options.ideal: terminate_stream(self, phase_tracking) print "Disabled phase tracking stage" else: ofdm_blocks = phase_tracking '''equalizer = ofdm.channel_equalizer_mimo_2( total_subc ) self.connect( ofdm_blocks, ( equalizer, 0 ) ) self.connect( ofdm_blocks2, ( equalizer, 1 ) ) self.connect( inv_CTF_1, ( equalizer, 2 ) ) self.connect( inv_CTF_2, ( equalizer, 3 ) ) self.connect( inv_CTF_3, ( equalizer, 4 ) ) self.connect( inv_CTF_4, ( equalizer, 5 ) ) self.connect( frame_start, ( equalizer, 6 ) ) self.connect( frame_start2, ( equalizer, 7 ) ) ofdm_blocks = equalizer''' equalizer = ofdm.channel_equalizer_mimo_2( total_subc ) self.connect( ofdm_blocks, ( equalizer, 0 ) ) self.connect( estimated_CTF_1, skip_block_1, ( equalizer, 1 ) ) self.connect( estimated_CTF_2, skip_block_2, ( equalizer, 2 ) ) self.connect( frame_start, ( equalizer, 3 ) ) #ofdm_blocks = equalizer #ofdm_blocks2 = equalizer2 ofdm_blocks = equalizer #log_to_file(self, equalizer,"data/equalizer.compl") log_to_file(self, ofdm_blocks,"data/equalizer.compl") log_to_file(self, estimated_CTF_1,"data/estimated_CTF_1.compl") log_to_file(self, estimated_CTF_2,"data/estimated_CTF_2.compl") ## LMS Phase tracking ## Track residual frequency offset and sampling clock frequency offset ''' nondata_blocks = [] for i in range(config.frame_length): if i in config.training_data.pilotsym_pos: nondata_blocks.append(i) pilot_subc = block_header.pilot_tones phase_tracking = ofdm.lms_phase_tracking_02( total_subc, pilot_subc, nondata_blocks ) self.connect( equalizer, ( phase_tracking, 0 ) ) self.connect( frame_start, ( phase_tracking, 1 ) ) phase_tracking2 = ofdm.lms_phase_tracking_02( total_subc, pilot_subc, nondata_blocks ) self.connect( equalizer2, ( phase_tracking2, 0 ) ) self.connect( frame_start2, ( phase_tracking2, 1 ) ) # if options.scatter_plot_before_phase_tracking: # self.before_phase_tracking = equalizer if options.disable_phase_tracking or options.ideal: terminate_stream(self, phase_tracking) terminate_stream(self, phase_tracking2) print "Disabled phase tracking stage" else: ofdm_blocks = phase_tracking ofdm_blocks2 = phase_tracking2 log_to_file(self,phase_tracking, "data/phase_tracking.compl") ''' '''combine = blocks.add_cc(config.subcarriers) self.connect(ofdm_blocks, (combine,0)) self.connect(ofdm_blocks2, (combine,1)) ofdm_blocks = combine''' ## div = gr.multiply_cc(config.subcarriers) ## const = blocks.vector_source_c([[0.5+0]*config.subcarriers],True) ## self.connect(ofdm_blocks,div) ## self.connect(const,(div,1)) ## ofdm_blocks=div # log_to_file(self,combine,"data/combine.compl") ## Output connections self.connect( ofdm_blocks, out_ofdm_blocks ) self.connect( frame_start, out_frame_start ) self.connect( disp_CTF_RX0, out_disp_ctf ) self.connect( disp_CTF_RX1, out_disp_ctf2 )
def __init__(self, M=1024, K=4, qam_size=16, syms_per_frame=10, carriers=924, theta_sel=0, sel_eq=0, exclude_preamble=0, sel_preamble=0, zero_pads=1, extra_pad=False): gr.hier_block2.__init__( self, "fbmc_receiver_demo", gr.io_signature(1, 1, gr.sizeof_gr_complex * 1), gr.io_signature(1, 1, gr.sizeof_gr_complex * M), ) ################################################## # Parameters ################################################## self.theta_sel = theta_sel self.exclude_preamble = exclude_preamble self.sel_eq = sel_eq self.M = M self.K = K self.qam_size = qam_size self.syms_per_frame = syms_per_frame ################################################## # Variables ################################################## if self.exclude_preamble == 1 and self.sel_eq != 3: self.sel_eq = sel_eq = 3 warnings.warn( "Since exclude_preamble is set as 1, sel_eq is forced to be 3 (no equalizer)" ) self.skip = skip = 0 if exclude_preamble == 1 or sel_eq == 3 or sel_eq == 0: self.skip = skip = 0 else: self.skip = skip = 1 # Assertions assert (M > 0 and K > 0 and qam_size > 0), "M, K and qam_size should be bigger than 0" assert ((math.log(M) / math.log(2)) == int( math.log(M) / math.log(2))), "M should be a power of 2" assert (K == 4), "for now only K=4 s supported." assert (qam_size == 4 or qam_size == 16 or qam_size == 64 or qam_size == 128 or qam_size == 256 ), "Only 4-,16-,64-,128-,256-qam constellations are supported." assert (theta_sel == 0 or theta_sel == 1) assert (exclude_preamble == 0 or exclude_preamble == 1) ################################################## # Blocks ################################################## self.ofdm_vector_mask_0 = ofdm.vector_mask(M, (M - carriers) / 2, carriers, []) # self.ofdm_fbmc_symbol_estimation_vcb_0 = ofdm.fbmc_symbol_estimation_vcb(carriers, qam_size) # unsigned int M, unsigned int syms_per_frame, int sel_preamble, int zero_pads, bool extra_pad, int sel_eq self.ofdm_fbmc_subchannel_processing_vcvc_0 = ofdm.fbmc_subchannel_processing_vcvc( M, syms_per_frame, sel_preamble, zero_pads, extra_pad, sel_eq) self.ofdm_fbmc_separate_vcvc_0 = ofdm.fbmc_separate_vcvc(M, 2) self.ofdm_fbmc_remove_preamble_vcvc_0 = ofdm.fbmc_remove_preamble_vcvc( M, syms_per_frame, sel_preamble, zero_pads, extra_pad) self.ofdm_fbmc_polyphase_network_vcvc_3 = ofdm.fbmc_polyphase_network_vcvc( M, K, K * M - 1, True) self.ofdm_fbmc_polyphase_network_vcvc_2 = ofdm.fbmc_polyphase_network_vcvc( M, K, K * M - 1, True) self.ofdm_fbmc_overlapping_serial_to_parallel_cvc_0 = ofdm.fbmc_overlapping_serial_to_parallel_cvc( M) self.ofdm_fbmc_oqam_postprocessing_vcvc_0 = ofdm.fbmc_oqam_postprocessing_vcvc( M, 0, theta_sel) self.ofdm_fbmc_junction_vcvc_0 = ofdm.fbmc_junction_vcvc(M, 2) self.ofdm_fbmc_beta_multiplier_vcvc_1 = ofdm.fbmc_beta_multiplier_vcvc( M, K, K * M - 1, 0) self.fft_vxx_1 = fft.fft_vcc(M, True, ([]), True, 1) self.blocks_skiphead_0_0 = blocks.skiphead(gr.sizeof_gr_complex * M, skip) self.blocks_skiphead_0 = blocks.skiphead(gr.sizeof_gr_complex * M, 2 * K - 1 - 1) self.blocks_null_sink_0 = blocks.null_sink(gr.sizeof_gr_complex * M) self.blks2_selector_0_0 = grc_blks2.selector( item_size=gr.sizeof_gr_complex * M, num_inputs=2, num_outputs=1, input_index=exclude_preamble, output_index=0, ) ################################################## # Connections ################################################## self.connect((self.blks2_selector_0_0, 0), (self.ofdm_fbmc_oqam_postprocessing_vcvc_0, 0)) self.connect((self.ofdm_fbmc_remove_preamble_vcvc_0, 0), (self.blks2_selector_0_0, 0)) self.connect((self.blocks_skiphead_0_0, 0), (self.blks2_selector_0_0, 1)) self.connect((self.blocks_skiphead_0_0, 0), (self.ofdm_fbmc_remove_preamble_vcvc_0, 0)) self.connect((self.ofdm_fbmc_beta_multiplier_vcvc_1, 0), (self.blocks_skiphead_0, 0)) self.connect((self.fft_vxx_1, 0), (self.ofdm_fbmc_beta_multiplier_vcvc_1, 0)) self.connect((self.blocks_skiphead_0, 0), (self.ofdm_fbmc_subchannel_processing_vcvc_0, 0)) self.connect((self.ofdm_fbmc_junction_vcvc_0, 0), (self.fft_vxx_1, 0)) # self.connect((self.ofdm_fbmc_symbol_estimation_vcb_0, 0), ) self.connect((self.ofdm_fbmc_subchannel_processing_vcvc_0, 1), (self.blocks_null_sink_0, 0)) self.connect((self.ofdm_vector_mask_0, 0), (self, 0)) self.connect((self.ofdm_fbmc_oqam_postprocessing_vcvc_0, 0), (self.ofdm_vector_mask_0, 0)) self.connect((self.ofdm_fbmc_subchannel_processing_vcvc_0, 0), (self.blocks_skiphead_0_0, 0)) self.connect((self, 0), (self.ofdm_fbmc_overlapping_serial_to_parallel_cvc_0, 0)) self.connect((self.ofdm_fbmc_separate_vcvc_0, 0), (self.ofdm_fbmc_polyphase_network_vcvc_2, 0)) self.connect((self.ofdm_fbmc_separate_vcvc_0, 1), (self.ofdm_fbmc_polyphase_network_vcvc_3, 0)) self.connect((self.ofdm_fbmc_overlapping_serial_to_parallel_cvc_0, 0), (self.ofdm_fbmc_separate_vcvc_0, 0)) self.connect((self.ofdm_fbmc_polyphase_network_vcvc_2, 0), (self.ofdm_fbmc_junction_vcvc_0, 0)) self.connect((self.ofdm_fbmc_polyphase_network_vcvc_3, 0), (self.ofdm_fbmc_junction_vcvc_0, 1))
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, M=1024, K=4, qam_size=16, syms_per_frame=10, carriers=924, theta_sel=0, sel_eq=0, exclude_preamble=0, sel_preamble=0, zero_pads=1, extra_pad=False): gr.hier_block2.__init__(self, "fbmc_receiver_hier_cb", gr.io_signature(1, 1, gr.sizeof_gr_complex*1), gr.io_signature(1, 1, gr.sizeof_char*1), ) ################################################## # Parameters ################################################## self.theta_sel = theta_sel self.exclude_preamble = exclude_preamble self.sel_eq = sel_eq self.M = M self.K = K self.qam_size = qam_size self.syms_per_frame = syms_per_frame ################################################## # Variables ################################################## if self.exclude_preamble == 1 and self.sel_eq != 3: self.sel_eq = sel_eq = 3 warnings.warn("Since exclude_preamble is set as 1, sel_eq is forced to be 3 (no equalizer)") self.skip = skip = 0 if exclude_preamble == 1 or sel_eq == 3 or sel_eq== 0: self.skip = skip = 0 else: self.skip = skip = 1 # Assertions assert(M>0 and K>0 and qam_size>0), "M, K and qam_size should be bigger than 0" assert((math.log(M)/math.log(2))==int(math.log(M)/math.log(2))), "M should be a power of 2" assert(K==4), "for now only K=4 s supported." assert(qam_size==4 or qam_size==16 or qam_size==64 or qam_size==128 or qam_size==256 ), "Only 4-,16-,64-,128-,256-qam constellations are supported." assert(theta_sel==0 or theta_sel==1) assert(exclude_preamble==0 or exclude_preamble==1) ################################################## # Blocks ################################################## self.ofdm_vector_mask_0 = ofdm.vector_mask(M, (M-carriers)/2, carriers, []) self.ofdm_fbmc_symbol_estimation_vcb_0 = ofdm.fbmc_symbol_estimation_vcb(carriers, qam_size) # unsigned int M, unsigned int syms_per_frame, int sel_preamble, int zero_pads, bool extra_pad, int sel_eq self.ofdm_fbmc_subchannel_processing_vcvc_0 = ofdm.fbmc_subchannel_processing_vcvc(M, syms_per_frame, sel_preamble, zero_pads, extra_pad, sel_eq) self.ofdm_fbmc_separate_vcvc_0 = ofdm.fbmc_separate_vcvc(M, 2) self.ofdm_fbmc_remove_preamble_vcvc_0 = ofdm.fbmc_remove_preamble_vcvc(M, syms_per_frame, sel_preamble, zero_pads, extra_pad) self.ofdm_fbmc_polyphase_network_vcvc_3 = ofdm.fbmc_polyphase_network_vcvc(M, K, K*M-1, True) self.ofdm_fbmc_polyphase_network_vcvc_2 = ofdm.fbmc_polyphase_network_vcvc(M, K, K*M-1, True) self.ofdm_fbmc_overlapping_serial_to_parallel_cvc_0 = ofdm.fbmc_overlapping_serial_to_parallel_cvc(M) self.ofdm_fbmc_oqam_postprocessing_vcvc_0 = ofdm.fbmc_oqam_postprocessing_vcvc(M, 0, theta_sel) self.ofdm_fbmc_junction_vcvc_0 = ofdm.fbmc_junction_vcvc(M, 2) self.ofdm_fbmc_beta_multiplier_vcvc_1 = ofdm.fbmc_beta_multiplier_vcvc(M, K, K*M-1, 0) self.fft_vxx_1 = fft.fft_vcc(M, True, ([]), True, 1) self.blocks_skiphead_0_0 = blocks.skiphead(gr.sizeof_gr_complex*M, skip) self.blocks_skiphead_0 = blocks.skiphead(gr.sizeof_gr_complex*M, 2*K-1-1) self.blocks_null_sink_0 = blocks.null_sink(gr.sizeof_gr_complex*M) self.blks2_selector_0_0 = grc_blks2.selector( item_size=gr.sizeof_gr_complex*M, num_inputs=2, num_outputs=1, input_index=exclude_preamble, output_index=0, ) ################################################## # Connections ################################################## self.connect((self.blks2_selector_0_0, 0), (self.ofdm_fbmc_oqam_postprocessing_vcvc_0, 0)) self.connect((self.ofdm_fbmc_remove_preamble_vcvc_0, 0), (self.blks2_selector_0_0, 0)) self.connect((self.blocks_skiphead_0_0, 0), (self.blks2_selector_0_0, 1)) self.connect((self.blocks_skiphead_0_0, 0), (self.ofdm_fbmc_remove_preamble_vcvc_0, 0)) self.connect((self.ofdm_fbmc_beta_multiplier_vcvc_1, 0), (self.blocks_skiphead_0, 0)) self.connect((self.fft_vxx_1, 0), (self.ofdm_fbmc_beta_multiplier_vcvc_1, 0)) self.connect((self.blocks_skiphead_0, 0), (self.ofdm_fbmc_subchannel_processing_vcvc_0, 0)) self.connect((self.ofdm_fbmc_junction_vcvc_0, 0), (self.fft_vxx_1, 0)) self.connect((self.ofdm_fbmc_symbol_estimation_vcb_0, 0), (self, 0)) self.connect((self.ofdm_fbmc_subchannel_processing_vcvc_0, 1), (self.blocks_null_sink_0, 0)) self.connect((self.ofdm_vector_mask_0, 0), (self.ofdm_fbmc_symbol_estimation_vcb_0, 0)) self.connect((self.ofdm_fbmc_oqam_postprocessing_vcvc_0, 0), (self.ofdm_vector_mask_0, 0)) self.connect((self.ofdm_fbmc_subchannel_processing_vcvc_0, 0), (self.blocks_skiphead_0_0, 0)) self.connect((self, 0), (self.ofdm_fbmc_overlapping_serial_to_parallel_cvc_0, 0)) self.connect((self.ofdm_fbmc_separate_vcvc_0, 0), (self.ofdm_fbmc_polyphase_network_vcvc_2, 0)) self.connect((self.ofdm_fbmc_separate_vcvc_0, 1), (self.ofdm_fbmc_polyphase_network_vcvc_3, 0)) self.connect((self.ofdm_fbmc_overlapping_serial_to_parallel_cvc_0, 0), (self.ofdm_fbmc_separate_vcvc_0, 0)) self.connect((self.ofdm_fbmc_polyphase_network_vcvc_2, 0), (self.ofdm_fbmc_junction_vcvc_0, 0)) self.connect((self.ofdm_fbmc_polyphase_network_vcvc_3, 0), (self.ofdm_fbmc_junction_vcvc_0, 1))
def __init__(self, options, log=False): ## Read configuration config = station_configuration() fft_length = config.fft_length cp_length = config.cp_length block_header = config.training_data data_subc = config.data_subcarriers virtual_subc = config.virtual_subcarriers total_subc = config.subcarriers block_length = config.block_length frame_length = config.frame_length dc_null = config.dc_null L = block_header.mm_periodic_parts ## Set Input/Output signature gr.hier_block2.__init__( self, "ofdm_inner_receiver", gr.io_signature(1, 1, gr.sizeof_gr_complex), gr.io_signaturev( 4, 4, [ gr.sizeof_gr_complex * total_subc, # OFDM blocks gr.sizeof_char, # Frame start gr.sizeof_float * total_subc, gr.sizeof_float ])) # Normalized |CTF|^2 ## Input and output ports self.input = rx_input = self out_ofdm_blocks = (self, 0) out_frame_start = (self, 1) out_disp_ctf = (self, 2) out_disp_cfo = (self, 3) ## pre-FFT processing if options.ideal is False and options.ideal2 is False: if options.old_receiver is False: ## Compute autocorrelations for S&C preamble ## and cyclic prefix self._sc_metric = sc_metric = autocorrelator( fft_length / 2, fft_length / 2) self._gi_metric = gi_metric = autocorrelator( fft_length, cp_length) self.connect(rx_input, sc_metric) self.connect(rx_input, gi_metric) ## Sync. Output contains OFDM blocks sync = ofdm.time_sync(fft_length, cp_length) self.connect(rx_input, (sync, 0)) self.connect(sc_metric, (sync, 1)) self.connect(gi_metric, (sync, 2)) ofdm_blocks = (sync, 0) frame_start = (sync, 1) #log_to_file( self, ( sync, 1 ), "data/peak_detector.char" ) else: #Testing old/new metric self.tm = schmidl.recursive_timing_metric(fft_length) self.connect(self.input, self.tm) #log_to_file( self, self.tm, "data/rec_sc_metric_ofdm.float" ) timingmetric_shift = -2 #int(-cp_length/4)# 0#-2 #int(-cp_length * 0.8) tmfilter = filter.fft_filter_fff(1, [1. / cp_length] * cp_length) self.connect(self.tm, tmfilter) self.tm = tmfilter self._pd_thres = 0.3 self._pd_lookahead = fft_length / 2 # empirically chosen peak_detector = ofdm.peak_detector_02_fb( self._pd_lookahead, self._pd_thres) self.connect(self.tm, peak_detector) #log_to_file( self, peak_detector, "data/rec_peak_detector.char" ) frame_start = [0] * frame_length frame_start[0] = 1 frame_start = self.frame_trigger_old = blocks.vector_source_b( frame_start, True) delayed_timesync = blocks.delay( gr.sizeof_char, (frame_length - 1) * block_length + timingmetric_shift) self.connect(peak_detector, delayed_timesync) self.block_sampler = ofdm.vector_sampler( gr.sizeof_gr_complex, block_length * frame_length) self.discard_cp = ofdm.vector_mask(block_length, cp_length, fft_length, []) self.connect(self.input, self.block_sampler) self.connect(delayed_timesync, (self.block_sampler, 1)) # TODO: dynamic solution vt2s = blocks.vector_to_stream( gr.sizeof_gr_complex * block_length, frame_length) self.connect(self.block_sampler, vt2s, self.discard_cp) #terminate_stream(self,ofdm_blocks) ofdm_blocks = self.discard_cp # else: # serial_to_parallel = blocks.stream_to_vector(gr.sizeof_gr_complex,block_length) # discard_cp = ofdm.vector_mask(block_length,cp_length,fft_length,[]) # ofdm_blocks = discard_cp # self.connect( rx_input, serial_to_parallel, discard_cp ) # frame_start = [0]*frame_length # frame_start[0] = 1 # frame_start = blocks.vector_source_b(frame_start,True) # # print "Disabled time synchronization stage" ## Compute autocorrelations for S&C preamble ## and cyclic prefix #log_to_file( self, sc_metric, "data/sc_metric_ofdm.float" ) #log_to_file(self, frame_start, "data/frame_start.compl") # log_to_file(self,ofdm_blocks,"data/ofdm_blocks_original.compl") if options.disable_time_sync or options.ideal or options.ideal2: if options.ideal is False and options.ideal2 is False: terminate_stream(self, ofdm_blocks) terminate_stream(self, frame_start) serial_to_parallel = blocks.stream_to_vector( gr.sizeof_gr_complex, block_length) discard_cp = ofdm.vector_mask_dc_null(block_length, cp_length, fft_length, dc_null, []) ofdm_blocks = discard_cp self.connect(rx_input, serial_to_parallel, discard_cp) frame_start = [0] * frame_length frame_start[0] = 1 frame_start = blocks.vector_source_b(frame_start, True) print "Disabled time synchronization stage" print "\t\t\t\t\tframe_length = ", frame_length if options.ideal is False and options.ideal2 is False: ## Extract preamble, feed to Morelli & Mengali frequency offset estimator assert (block_header.mm_preamble_pos == 0) morelli_foe = ofdm.mm_frequency_estimator(fft_length, L, 1, 0) sampler_preamble = ofdm.vector_sampler( gr.sizeof_gr_complex * fft_length, 1) self.connect(ofdm_blocks, (sampler_preamble, 0)) self.connect(frame_start, (sampler_preamble, 1)) self.connect(sampler_preamble, morelli_foe) freq_offset = morelli_foe ## Adaptive LMS FIR filtering of frequency offset lms_fir = ofdm.lms_fir_ff(20, 1e-3) # TODO: verify parameter choice self.connect(freq_offset, lms_fir) freq_offset = lms_fir #self.zmq_probe_freqoff = zeromq.pub_sink(gr.sizeof_float, 1, "tcp://*:5557") self.connect(lms_fir, blocks.keep_one_in_n(gr.sizeof_float, 20), out_disp_cfo) else: self.connect(blocks.vector_source_f([1]), out_disp_cfo) #log_to_file(self, lms_fir, "data/lms_fir.float") if options.disable_freq_sync or options.ideal or options.ideal2: if options.ideal is False and options.ideal2 is False: terminate_stream(self, freq_offset) freq_offset = blocks.vector_source_f([0.0], True) print "Disabled frequency synchronization stage" if options.ideal is False and options.ideal2 is False: ## Correct frequency shift, feed-forward structure frequency_shift = ofdm.frequency_shift_vcc(fft_length, -1.0 / fft_length, cp_length) self.connect(ofdm_blocks, (frequency_shift, 0)) self.connect(freq_offset, (frequency_shift, 1)) self.connect(frame_start, (frequency_shift, 2)) ofdm_blocks = frequency_shift ## FFT fft = fft_blocks.fft_vcc(fft_length, True, [], True) self.connect(ofdm_blocks, fft) ofdm_blocks = fft #log_to_file( self, fft, "data/compen.float" ) ## Remove virtual subcarriers if fft_length > data_subc: subcarrier_mask = ofdm.vector_mask_dc_null(fft_length, virtual_subc / 2, total_subc, dc_null, []) self.connect(ofdm_blocks, subcarrier_mask) ofdm_blocks = subcarrier_mask #log_to_file(self, ofdm_blocks, "data/vec_mask.compl") ## Least Squares estimator for channel transfer function (CTF) if options.logcir: log_to_file(self, ofdm_blocks, "data/OFDM_Blocks.compl") inv_preamble_fd = numpy.array(block_header.pilotsym_fd[ block_header.channel_estimation_pilot[0]]) inv_preamble_fd = numpy.concatenate([ inv_preamble_fd[:total_subc / 2], inv_preamble_fd[total_subc / 2 + dc_null:] ]) #print "Channel estimation pilot: ", inv_preamble_fd inv_preamble_fd = 1. / inv_preamble_fd LS_channel_estimator0 = ofdm.multiply_const_vcc( list(inv_preamble_fd)) self.connect(ofdm_blocks, LS_channel_estimator0, gr.null_sink(gr.sizeof_gr_complex * total_subc)) log_to_file(self, LS_channel_estimator0, "data/OFDM_Blocks_eq.compl") ## post-FFT processing ## extract channel estimation preamble from frame if options.ideal is False and options.ideal2 is False: chest_pre_trigger = blocks.delay(gr.sizeof_char, 1) sampled_chest_preamble = ofdm.vector_sampler( gr.sizeof_gr_complex * total_subc, 1) self.connect(frame_start, chest_pre_trigger) self.connect(chest_pre_trigger, (sampled_chest_preamble, 1)) self.connect(ofdm_blocks, (sampled_chest_preamble, 0)) ## Least Squares estimator for channel transfer function (CTF) inv_preamble_fd = numpy.array(block_header.pilotsym_fd[ block_header.channel_estimation_pilot[0]]) inv_preamble_fd = numpy.concatenate([ inv_preamble_fd[:total_subc / 2], inv_preamble_fd[total_subc / 2 + dc_null:] ]) #print "Channel estimation pilot: ", inv_preamble_fd inv_preamble_fd = 1. / inv_preamble_fd LS_channel_estimator = ofdm.multiply_const_vcc( list(inv_preamble_fd)) self.connect(sampled_chest_preamble, LS_channel_estimator) estimated_CTF = LS_channel_estimator if options.logcir: log_to_file(self, sampled_chest_preamble, "data/PREAM.compl") if not options.disable_ctf_enhancer: if options.logcir: ifft1 = fft_blocks.fft_vcc(total_subc, False, [], True) self.connect( estimated_CTF, ifft1, gr.null_sink(gr.sizeof_gr_complex * total_subc)) summ1 = ofdm.vector_sum_vcc(total_subc) c2m = gr.complex_to_mag(total_subc) self.connect(estimated_CTF, summ1, gr.null_sink(gr.sizeof_gr_complex)) self.connect(estimated_CTF, c2m, gr.null_sink(gr.sizeof_float * total_subc)) log_to_file(self, ifft1, "data/CIR1.compl") log_to_file(self, summ1, "data/CTFsumm1.compl") log_to_file(self, estimated_CTF, "data/CTF1.compl") log_to_file(self, c2m, "data/CTFmag1.float") ## MSE enhancer ctf_mse_enhancer = ofdm.CTF_MSE_enhancer( total_subc, cp_length + cp_length) self.connect(estimated_CTF, ctf_mse_enhancer) # log_to_file( self, ctf_mse_enhancer, "data/ctf_mse_enhancer_original.compl") #ifft3 = fft_blocks.fft_vcc(total_subc,False,[],True) #null_noise = ofdm.noise_nulling(total_subc, cp_length + cp_length) #ctf_mse_enhancer = fft_blocks.fft_vcc(total_subc,True,[],True) #ctf_mse_enhancer = ofdm.vector_mask( fft_length, virtual_subc/2, # total_subc, [] ) #self.connect( estimated_CTF, ifft3,null_noise,ctf_mse_enhancer ) estimated_CTF = ctf_mse_enhancer print "Disabled CTF MSE enhancer" if options.logcir: ifft2 = fft_blocks.fft_vcc(total_subc, False, [], True) self.connect(estimated_CTF, ifft2, gr.null_sink(gr.sizeof_gr_complex * total_subc)) summ2 = ofdm.vector_sum_vcc(total_subc) c2m2 = gr.complex_to_mag(total_subc) self.connect(estimated_CTF, summ2, gr.null_sink(gr.sizeof_gr_complex)) self.connect(estimated_CTF, c2m2, gr.null_sink(gr.sizeof_float * total_subc)) log_to_file(self, ifft2, "data/CIR2.compl") log_to_file(self, summ2, "data/CTFsumm2.compl") log_to_file(self, estimated_CTF, "data/CTF2.compl") log_to_file(self, c2m2, "data/CTFmag2.float") ## Postprocess the CTF estimate ## CTF -> inverse CTF (for equalizer) ## CTF -> norm |.|^2 (for CTF display) ctf_postprocess = ofdm.postprocess_CTF_estimate(total_subc) self.connect(estimated_CTF, ctf_postprocess) inv_estimated_CTF = (ctf_postprocess, 0) disp_CTF = (ctf_postprocess, 1) # if options.disable_equalization or options.ideal: # terminate_stream(self, inv_estimated_CTF) # inv_estimated_CTF_vec = blocks.vector_source_c([1.0/fft_length*math.sqrt(total_subc)]*total_subc,True,total_subc) # inv_estimated_CTF_str = blocks.vector_to_stream(gr.sizeof_gr_complex, total_subc) # self.inv_estimated_CTF_mul = ofdm.multiply_const_ccf( 1.0/config.rms_amplitude ) # #inv_estimated_CTF_mul.set_k(1.0/config.rms_amplitude) # inv_estimated_CTF = blocks.stream_to_vector(gr.sizeof_gr_complex, total_subc) # self.connect( inv_estimated_CTF_vec, inv_estimated_CTF_str, self.inv_estimated_CTF_mul, inv_estimated_CTF) # print "Disabled equalization stage" ''' ## LMS Phase tracking ## Track residual frequency offset and sampling clock frequency offset nondata_blocks = [] for i in range(config.frame_length): if i in config.training_data.pilotsym_pos: nondata_blocks.append(i) print"\t\t\t\t\tnondata_blocks=",nondata_blocks pilot_subc = block_header.pilot_tones pilot_subcarriers = block_header.pilot_subc_sym print "PILOT SUBCARRIERS: ", pilot_subcarriers phase_tracking = ofdm.lms_phase_tracking_03( total_subc, pilot_subc, nondata_blocks, pilot_subcarriers,0 ) self.connect( ofdm_blocks, ( phase_tracking, 0 ) ) self.connect( inv_estimated_CTF, ( phase_tracking, 1 ) ) self.connect( frame_start, ( phase_tracking, 2 ) ) ## if options.scatter_plot_before_phase_tracking: self.before_phase_tracking = equalizer if options.disable_phase_tracking or options.ideal: terminate_stream(self, phase_tracking) print "Disabled phase tracking stage" else: ofdm_blocks = phase_tracking ''' ## Channel Equalizer if options.disable_equalization or options.ideal or options.ideal2: print "Disabled equalization stage" if options.ideal is False and options.ideal2 is False: terminate_stream(self, inv_estimated_CTF) else: equalizer = ofdm.channel_equalizer(total_subc) self.connect(ofdm_blocks, (equalizer, 0)) self.connect(inv_estimated_CTF, (equalizer, 1)) self.connect(frame_start, (equalizer, 2)) ofdm_blocks = equalizer #log_to_file(self, equalizer,"data/equalizer_siso.compl") #log_to_file(self, ofdm_blocks, "data/equalizer.compl") ## LMS Phase tracking ## Track residual frequency offset and sampling clock frequency offset if options.ideal is False and options.ideal2 is False: nondata_blocks = [] for i in range(config.frame_length): if i in config.training_data.pilotsym_pos: nondata_blocks.append(i) print "\t\t\t\t\tnondata_blocks=", nondata_blocks pilot_subc = block_header.pilot_tones pilot_subcarriers = block_header.pilot_subc_sym print "PILOT SUBCARRIERS: ", pilot_subcarriers phase_tracking2 = ofdm.lms_phase_tracking_dc_null( total_subc, pilot_subc, nondata_blocks, pilot_subcarriers, dc_null) self.connect(ofdm_blocks, (phase_tracking2, 0)) self.connect(frame_start, (phase_tracking2, 1)) ## if options.disable_phase_tracking or options.ideal or options.ideal2: if options.ideal is False and options.ideal2 is False: terminate_stream(self, phase_tracking2) print "Disabled phase tracking stage" else: ofdm_blocks = phase_tracking2 if options.scatter_plot_before_phase_tracking: self.before_phase_tracking = equalizer ## Output connections self.connect(ofdm_blocks, out_ofdm_blocks) self.connect(frame_start, out_frame_start) if options.ideal is False and options.ideal2 is False: self.connect(disp_CTF, out_disp_ctf) else: self.connect(blocks.vector_source_f([1.0] * total_subc), blocks.stream_to_vector(gr.sizeof_float, total_subc), out_disp_ctf) if log: log_to_file(self, sc_metric, "data/sc_metric.float") log_to_file(self, gi_metric, "data/gi_metric.float") log_to_file(self, morelli_foe, "data/morelli_foe.float") log_to_file(self, lms_fir, "data/lms_fir.float") log_to_file(self, sampler_preamble, "data/preamble.compl") log_to_file(self, sync, "data/sync.compl") log_to_file(self, frequency_shift, "data/frequency_shift.compl") log_to_file(self, fft, "data/fft.compl") log_to_file(self, fft, "data/fft.float", mag=True) if vars().has_key('subcarrier_mask'): log_to_file(self, subcarrier_mask, "data/subcarrier_mask.compl") log_to_file(self, ofdm_blocks, "data/ofdm_blocks_out.compl") log_to_file(self, frame_start, "data/frame_start.float", char_to_float=True) log_to_file(self, sampled_chest_preamble, "data/sampled_chest_preamble.compl") log_to_file(self, LS_channel_estimator, "data/ls_channel_estimator.compl") log_to_file(self, LS_channel_estimator, "data/ls_channel_estimator.float", mag=True) if "ctf_mse_enhancer" in locals(): log_to_file(self, ctf_mse_enhancer, "data/ctf_mse_enhancer.compl") log_to_file(self, ctf_mse_enhancer, "data/ctf_mse_enhancer.float", mag=True) log_to_file(self, (ctf_postprocess, 0), "data/inc_estimated_ctf.compl") log_to_file(self, (ctf_postprocess, 1), "data/disp_ctf.float") log_to_file(self, equalizer, "data/equalizer.compl") log_to_file(self, equalizer, "data/equalizer.float", mag=True) log_to_file(self, phase_tracking, "data/phase_tracking.compl")
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"