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, options, noutputs=2): """ @param options: parsed raw.ofdm_params """ self.params = ofdm_params(options) params = self.params if noutputs == 2: output_signature = gr.io_signature2( 2, 2, gr.sizeof_gr_complex * params.data_tones, gr.sizeof_char) elif noutputs == 3: output_signature = gr.io_signature3( 3, 3, gr.sizeof_gr_complex * params.data_tones, gr.sizeof_char, gr.sizeof_float) elif noutputs == 4: output_signature = gr.io_signature4( 4, 4, gr.sizeof_gr_complex * params.data_tones, gr.sizeof_char, gr.sizeof_float, gr.sizeof_float) else: # error raise Exception("unsupported number of outputs") gr.hier_block2.__init__(self, "ofdm_demod", gr.io_signature(1, 1, gr.sizeof_gr_complex), output_signature) self.ofdm_recv = ofdm_receiver(params, options.log) # FIXME: magic parameters phgain = 0.4 frgain = phgain * phgain / 4.0 eqgain = 0.05 self.ofdm_demod = raw.ofdm_demapper(params.carriers, phgain, frgain, eqgain) # the studios can't handle the whole ofdm in one thread #ofdm_recv = raw.wrap_sts(self.ofdm_recv) ofdm_recv = self.ofdm_recv self.connect(self, ofdm_recv) self.connect((ofdm_recv, 0), (self.ofdm_demod, 0)) self.connect((ofdm_recv, 1), (self.ofdm_demod, 1)) self.connect(self.ofdm_demod, (self, 0)) self.connect((ofdm_recv, 1), (self, 1)) if noutputs > 2: # average noise power per (pilot) subcarrier self.connect((self.ofdm_demod, 1), (self, 2)) if noutputs > 3: # average signal power per subcarrier self.connect( (ofdm_recv, 0), gr.vector_to_stream(gr.sizeof_float, params.occupied_tones), gr.integrate_ff(params.occupied_tones), gr.multiply_ff(1.0 / params.occupied_tones), (self, 3)) if options.log: self.connect( (self.ofdm_demod, 2), gr.file_sink(gr.sizeof_gr_complex * params.occupied_tones, 'rx-eq.dat')) self.connect((self.ofdm_demod, 1), gr.file_sink(gr.sizeof_float, 'rx-noise.dat')) self.connect((self.ofdm_demod, 0), gr.file_sink(gr.sizeof_gr_complex * params.data_tones, 'rx-demap.dat'))
def __init__(self, fft_length, cp_length, occupied_tones, snr, ks, carrier_map_bin, nc_filter, logging=False): gr.hier_block2.__init__(self, "ofdm_receiver", gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature gr.io_signature4(4, 4, gr.sizeof_gr_complex*occupied_tones, gr.sizeof_char, gr.sizeof_char, gr.sizeof_float)) # Output signature self._fft_length = fft_length self._occupied_tones = occupied_tones self._cp_length = cp_length self._nc_filter = nc_filter self._carrier_map_bin = carrier_map_bin win = [1 for i in range(self._fft_length)] self.initialize(ks, self._carrier_map_bin) SYNC = "pn" if SYNC == "ml": nco_sensitivity = -1.0/fft_length # correct for fine frequency self.ofdm_sync = ofdm_sync_ml(fft_length, cp_length, snr, self._ks0time, logging) elif SYNC == "pn": nco_sensitivity = -2.0/fft_length # correct for fine frequency self.ofdm_sync = ofdm_sync_pn.ofdm_sync_pn(fft_length, cp_length, logging) elif SYNC == "pnac": nco_sensitivity = -2.0/fft_length # correct for fine frequency self.ofdm_sync = ofdm_sync_pnac(fft_length, cp_length, self._ks0time, logging) elif SYNC == "fixed": # for testing only; do not user over the air self.chan_filt = gr.multiply_const_cc(1.0) # remove filter and filter delay for this nsymbols = 18 # enter the number of symbols per packet freq_offset = 0.0 # if you use a frequency offset, enter it here nco_sensitivity = -2.0/fft_length # correct for fine frequency self.ofdm_sync = ofdm_sync_fixed(fft_length, cp_length, nsymbols, freq_offset, logging) self.reset_filter() # TODO: why? Create a delay line, linklab self.delay = gr.delay(gr.sizeof_gr_complex, fft_length) self.nco = gr.frequency_modulator_fc(nco_sensitivity) # generate a signal proportional to frequency error of sync block self.sigmix = gr.multiply_cc() self.sampler = flex.ofdm_sampler(fft_length, fft_length+cp_length) self.fft_demod = gr.fft_vcc(fft_length, True, win, True) self.ofdm_frame_acq = flex.ofdm_frame_acquisition(self._occupied_tones, self._fft_length, self._cp_length, self._ks[0], 1) if self._nc_filter: print '\nMulti-band Filter Turned ON!' self.ncofdm_filt = ncofdm_filt(self._fft_length, self._occupied_tones, self._carrier_map_bin) self.connect(self, self.chan_filt, self.ncofdm_filt) self.connect(self.ncofdm_filt, self.ofdm_sync) # into the synchronization alg. self.connect((self.ofdm_sync,0), self.nco, (self.sigmix,1)) # use sync freq. offset output to derotate input signal self.connect(self.ncofdm_filt, self.delay, (self.sigmix,0)) # signal to be derotated else : print '\nMulti-band Filter Turned OFF!' self.connect(self, self.chan_filt) self.connect(self.chan_filt, self.ofdm_sync) # into the synchronization alg. self.connect((self.ofdm_sync,0), self.nco, (self.sigmix,1)) # use sync freq. offset output to derotate input signal self.connect(self.chan_filt, self.delay, (self.sigmix,0)) # signal to be derotated self.connect(self.sigmix, (self.sampler,0)) # sample off timing signal detected in sync alg self.connect((self.ofdm_sync,1), (self.sampler,1)) # timing signal to sample at self.connect((self.sampler,0), self.fft_demod) # send derotated sampled signal to FFT self.connect(self.fft_demod, (self.ofdm_frame_acq,0)) # find frame start and equalize signal # TODO: do we need a char delay for the timing signal? self.connect((self.sampler,1), (self.ofdm_frame_acq,1)) # send timing signal to signal frame start # TODO: reconnect properly self.connect((self.ofdm_frame_acq,0), (self,0)) # finished with fine/coarse freq correction, self.connect((self.ofdm_sync,1), gr.delay(gr.sizeof_char,1), (self,1)) self.connect((self.ofdm_frame_acq,1), (self,2)) # frame and symbol timing, and equalization self.connect((self.ofdm_frame_acq,2), (self,3)) # snr estimates if logging: self.connect(self.chan_filt, gr.file_sink(gr.sizeof_gr_complex, "flex_ofdm_recv-chan_filt_c.dat")) self.connect(self.ncofdm_filt, gr.file_sink(gr.sizeof_gr_complex, "flex_ofdm_recv-ncofdm_filt_c.dat")) self.connect(self.nco, gr.file_sink(gr.sizeof_gr_complex, "flex_ofdm_recv-nco_c.dat")) self.connect(self.fft_demod, gr.file_sink(gr.sizeof_gr_complex*fft_length, "flex_ofdm_recv-fft_out_c.dat")) self.connect(self.ofdm_frame_acq, gr.file_sink(gr.sizeof_gr_complex*occupied_tones, "flex_ofdm_recv-frame_acq_data_c.dat")) self.connect((self.ofdm_frame_acq,3), gr.keep_one_in_n(gr.sizeof_float*occupied_tones, 32), gr.file_sink(gr.sizeof_float*occupied_tones, "flex_ofdm_recv-frame_acq_gain_f.dat")) self.connect((self.ofdm_frame_acq,1), gr.file_sink(1, "flex_ofdm_recv-frame_acq_signal_b.dat")) self.connect((self.ofdm_frame_acq,2), gr.file_sink(gr.sizeof_float, "flex_ofdm_recv-frame_acq_snr_f.dat")) self.connect(self.sampler, gr.file_sink(gr.sizeof_gr_complex*fft_length, "flex_ofdm_recv-sampler_data_c.dat")) self.connect(self.sampler, gr.file_sink(gr.sizeof_gr_complex*fft_length, "flex_ofdm_recv-sampler_data_c.dat")) self.connect((self.sampler, 1), gr.file_sink(1*fft_length, "flex_ofdm_recv-sampler_signal_b.dat")) self.connect((self.ofdm_sync, 1), gr.file_sink(1, "flex_ofdm_recv-sync_b.dat")) self.connect(self.sigmix, gr.file_sink(gr.sizeof_gr_complex, "flex_ofdm_recv-sigmix_c.dat")) else: self.connect((self.ofdm_frame_acq,3), gr.null_sink(gr.sizeof_float*self._occupied_tones))
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, options, noutputs = 2): """ @param options: parsed raw.ofdm_params """ self.params = ofdm_params(options) params = self.params if noutputs == 2: output_signature = gr.io_signature2(2, 2, gr.sizeof_gr_complex*params.data_tones, gr.sizeof_char ) elif noutputs == 3: output_signature = gr.io_signature3(3, 3, gr.sizeof_gr_complex*params.data_tones, gr.sizeof_char, gr.sizeof_float ) elif noutputs == 4: output_signature = gr.io_signature4(4, 4, gr.sizeof_gr_complex*params.data_tones, gr.sizeof_char, gr.sizeof_float, gr.sizeof_float ) else: # error raise Exception("unsupported number of outputs") gr.hier_block2.__init__(self, "ofdm_demod", gr.io_signature(1, 1, gr.sizeof_gr_complex), output_signature ) self.ofdm_recv = ofdm_receiver(params, options.log) # FIXME: magic parameters phgain = 0.4 frgain = phgain*phgain / 4.0 eqgain = 0.05 self.ofdm_demod = raw.ofdm_demapper(params.carriers, phgain, frgain, eqgain) # the studios can't handle the whole ofdm in one thread #ofdm_recv = raw.wrap_sts(self.ofdm_recv) ofdm_recv = self.ofdm_recv self.connect(self, ofdm_recv) self.connect((ofdm_recv,0), (self.ofdm_demod,0)) self.connect((ofdm_recv,1), (self.ofdm_demod,1)) self.connect(self.ofdm_demod, (self,0)) self.connect((ofdm_recv,1), (self,1)) if noutputs > 2: # average noise power per (pilot) subcarrier self.connect((self.ofdm_demod,1), (self,2)) if noutputs > 3: # average signal power per subcarrier self.connect((ofdm_recv,0), gr.vector_to_stream(gr.sizeof_float, params.occupied_tones), gr.integrate_ff(params.occupied_tones), gr.multiply_ff(1.0/params.occupied_tones), (self,3)) if options.log: self.connect((self.ofdm_demod, 2), gr.file_sink(gr.sizeof_gr_complex*params.occupied_tones, 'rx-eq.dat')) self.connect((self.ofdm_demod, 1), gr.file_sink(gr.sizeof_float, 'rx-noise.dat')) self.connect((self.ofdm_demod, 0), gr.file_sink(gr.sizeof_gr_complex*params.data_tones, 'rx-demap.dat'))