def supply_rx_baseband(self): ## RX Spectrum if self.__dict__.has_key('rx_baseband'): return self.rx_baseband config = self.config fftlen = config.fft_length my_window = window.hamming(fftlen) #.blackmanharris(fftlen) rxs_sampler = vector_sampler(gr.sizeof_gr_complex,fftlen) rxs_trigger = gr.vector_source_b(concatenate([[1],[0]*199]),True) rxs_window = blocks.multiply_const_vcc(my_window) rxs_spectrum = gr.fft_vcc(fftlen,True,[],True) rxs_mag = gr.complex_to_mag(fftlen) rxs_avg = gr.single_pole_iir_filter_ff(0.01,fftlen) rxs_logdb = gr.nlog10_ff(20.0,fftlen,-20*log10(fftlen)) rxs_decimate_rate = gr.keep_one_in_n(gr.sizeof_float*fftlen,50) t = self.u if self.filter is None else self.filter self.connect(rxs_trigger,(rxs_sampler,1)) self.connect(t,rxs_sampler,rxs_window, rxs_spectrum,rxs_mag,rxs_avg,rxs_logdb, rxs_decimate_rate) if self._options.log: log_to_file(self, rxs_decimate_rate, "data/supply_rx.float") self.rx_baseband = rxs_decimate_rate return rxs_decimate_rate
def supply_rx_baseband(self): ## RX Spectrum if self.__dict__.has_key('rx_baseband'): return self.rx_baseband config = self.config fftlen = config.fft_length my_window = window.hamming(fftlen) #.blackmanharris(fftlen) rxs_sampler = vector_sampler(gr.sizeof_gr_complex, fftlen) rxs_trigger = blocks.vector_source_b(concatenate([[1], [0] * 199]), True) rxs_window = blocks.multiply_const_vcc(my_window) rxs_spectrum = gr.fft_vcc(fftlen, True, [], True) rxs_mag = gr.complex_to_mag(fftlen) rxs_avg = gr.single_pole_iir_filter_ff(0.01, fftlen) rxs_logdb = gr.nlog10_ff(20.0, fftlen, -20 * log10(fftlen)) rxs_decimate_rate = gr.keep_one_in_n(gr.sizeof_float * fftlen, 50) t = self.u if self.filter is None else self.filter self.connect(rxs_trigger, (rxs_sampler, 1)) self.connect(t, rxs_sampler, rxs_window, rxs_spectrum, rxs_mag, rxs_avg, rxs_logdb, rxs_decimate_rate) if self._options.log: log_to_file(self, rxs_decimate_rate, "data/supply_rx.float") self.rx_baseband = rxs_decimate_rate return rxs_decimate_rate
def setup_ber_measurement(self): """ Setup bit error rate measurement blocks. Using the decoded ID, a reference source identical to that in the transmitter reproduces the sent data. A measurement block compares the demodulated stream and the reference. It counts the bit errors within the given window (specified at the command line). Access the BER value via get_ber(). """ if self.measuring_ber(): return if(self._options.coding): decoding = self._data_decoder else: demod = self._data_demodulator config = station_configuration() ## Data Reference Source dref_src = self._data_reference_source = ber_reference_source(self._options) self.connect(self.id_dec,(dref_src,0)) self.connect(self.bitcount_src,(dref_src,1)) ## BER Measuring Tool ber_mst = self._ber_measuring_tool = ber_measurement(int(config.ber_window)) if(self._options.coding): self.connect(decoding,ber_mst) else: self.connect(demod,ber_mst) self.connect(dref_src,(ber_mst,1)) self._measuring_ber = True if self._options.enable_ber2: ber2 = ofdm.bit_position_dependent_ber( "BER2_" + strftime("%Y%m%d%H%M%S",gmtime()) ) if(self._options.coding): self.connect( decoding, ( ber2, 1 ) ) else: self.connect( demod, ( ber2, 1 ) ) self.connect( dref_src, ( ber2, 0 ) ) self.connect( bc_src, ( ber2, 2 ) ) if self._options.log: log_to_file(self, ber_mst, "data/ber_out.float") data_f = gr.char_to_float() self.connect(dref_src,data_f) log_to_file(self, data_f, "data/dataref_out.float")
def add_mobile_station(self,station_id): """ Adds new receiver mobile station. Station ID must be unique. Initializes BER reference source. """ # Initialize id_src = self._control._id_source dmux = self._data_multiplexer port = self._data_multiplexer_nextport self._data_multiplexer_nextport += 1 # Setup ctrl_port = self._control.add_mobile_station(station_id) options = self._options if options.imgxfer: ref_src = ofdm.imgtransfer_src( options.img ) else: ref_src = ber_reference_source(self._options) if(options.coding): ## Encoder encoder = self._encoder = ofdm.encoder_bb(fo,0) unpack = self._unpack = blocks.unpack_k_bits_bb(2) ## Puncturing if not options.nopunct: puncturing = self._puncturing = puncture_bb(options.subcarriers) #sah = gr.sample_and_hold_bb() #sah_trigger = blocks.vector_source_b([1,0],True) #decim_sah=gr.keep_one_in_n(gr.sizeof_char,2) self.connect(self._bitmap_trigger_puncturing,(puncturing,2)) frametrigger_bitmap_filter = blocks.vector_source_b([1,0],True) bitmap_filter = self._puncturing_bitmap_src_filter = skip(gr.sizeof_char*options.subcarriers,2)# skip_known_symbols(frame_length,subcarriers) bitmap_filter.skip_call(0) #self.connect(self._bitmap_src_puncturing,bitmap_filter,(puncturing,1)) self.connect(self._map_src,bitmap_filter,(puncturing,1)) self.connect(frametrigger_bitmap_filter,(bitmap_filter,1)) #bmt = gr.char_to_float() #self.connect(bitmap_filter,blocks.vector_to_stream(gr.sizeof_char,options.subcarriers), bmt) #log_to_file(self, bmt, "data/bitmap_filter_tx.float") self.connect((self._control,ctrl_port),ref_src,encoder,unpack) if not options.nopunct: self.connect(unpack,puncturing,(dmux,port)) #self.connect(sah_trigger, (sah,1)) else: self.connect(unpack,(dmux,port)) else: self.connect((self._control,ctrl_port),ref_src,(dmux,port)) if options.log and options.coding: log_to_file(self, encoder, "data/encoder_out.char") log_to_file(self, ref_src, "data/reference_data_src.char") log_to_file(self, unpack, "data/encoder_unpacked_out.char") if not options.nopunct: log_to_file(self, puncturing, "data/puncturing_out.char")
def filter_constellation_samples_to_file( self ): config = self.config vlen = config.data_subcarriers pda = self._power_deallocator bmaptrig_stream = [1, 1]+[0]*(config.frame_data_blocks-1) dm_trig = self._bitmap_trigger = blocks.vector_source_b(bmaptrig_stream, True) for i in range(8): print "pipe",i+1,"to",files[i] cfilter = ofdm.constellation_sample_filter( i+1, vlen ) self.connect( pda, (cfilter,0) ) self.connect( map_src, (cfilter,1) ) self.connect( dm_trig, (cfilter,2) ) log_to_file( self, cfilter, files[i] ) print "done"
def __init__ ( self, noise_power, coherence_time, taps ): gr.hier_block2.__init__(self, "fading_channel", gr.io_signature( 1, 1, gr.sizeof_gr_complex ), gr.io_signature( 1, 1, gr.sizeof_gr_complex ) ) inp = gr.kludge_copy( gr.sizeof_gr_complex ) self.connect( self, inp ) tap1_delay = gr.delay( gr.sizeof_gr_complex, 1 ) tap2_delay = gr.delay( gr.sizeof_gr_complex, 2 ) self.connect( inp, tap1_delay ) self.connect( inp, tap2_delay ) fd = 100 z = numpy.arange(-fd+0.1,fd,0.1) t = numpy.sqrt(1. / ( pi * fd * numpy.sqrt( 1. - (z/fd)**2 ) ) ) tap1_noise = ofdm.complex_white_noise( 0.0, taps[0] ) tap1_filter = gr.fft_filter_ccc(1, t) self.connect( tap1_noise, tap1_filter ) tap1_mult = gr.multiply_cc() self.connect( tap1_filter, (tap1_mult,0) ) self.connect( tap1_delay, (tap1_mult,1) ) tap2_noise = ofdm.complex_white_noise( 0.0, taps[1] ) tap2_filter = gr.fft_filter_ccc(1, t) self.connect( tap2_noise, tap2_filter ) tap2_mult = gr.multiply_cc() self.connect( tap2_filter, (tap2_mult,0) ) self.connect( tap2_delay, (tap2_mult,1) ) noise_src = ofdm.complex_white_noise( 0.0, sqrt( noise_power ) ) chan = gr.add_cc() self.connect( inp, (chan,0) ) self.connect( tap1_mult, (chan,1) ) self.connect( tap2_mult, (chan,2) ) self.connect( noise_src, (chan,3) ) self.connect( chan, self ) log_to_file( self, tap1_filter, "data/tap1_filter.compl") log_to_file( self, tap1_filter, "data/tap1_filter.float", mag=True) log_to_file( self, tap2_filter, "data/tap2_filter.compl") log_to_file( self, tap2_filter, "data/tap2_filter.float", mag=True)
def __init__(self, noise_power, coherence_time, taps): gr.hier_block2.__init__(self, "fading_channel", gr.io_signature(1, 1, gr.sizeof_gr_complex), gr.io_signature(1, 1, gr.sizeof_gr_complex)) inp = gr.kludge_copy(gr.sizeof_gr_complex) self.connect(self, inp) tap1_delay = gr.delay(gr.sizeof_gr_complex, 1) tap2_delay = gr.delay(gr.sizeof_gr_complex, 2) self.connect(inp, tap1_delay) self.connect(inp, tap2_delay) fd = 100 z = numpy.arange(-fd + 0.1, fd, 0.1) t = numpy.sqrt(1. / (pi * fd * numpy.sqrt(1. - (z / fd)**2))) tap1_noise = ofdm.complex_white_noise(0.0, taps[0]) tap1_filter = gr.fft_filter_ccc(1, t) self.connect(tap1_noise, tap1_filter) tap1_mult = gr.multiply_cc() self.connect(tap1_filter, (tap1_mult, 0)) self.connect(tap1_delay, (tap1_mult, 1)) tap2_noise = ofdm.complex_white_noise(0.0, taps[1]) tap2_filter = gr.fft_filter_ccc(1, t) self.connect(tap2_noise, tap2_filter) tap2_mult = gr.multiply_cc() self.connect(tap2_filter, (tap2_mult, 0)) self.connect(tap2_delay, (tap2_mult, 1)) noise_src = ofdm.complex_white_noise(0.0, sqrt(noise_power)) chan = gr.add_cc() self.connect(inp, (chan, 0)) self.connect(tap1_mult, (chan, 1)) self.connect(tap2_mult, (chan, 2)) self.connect(noise_src, (chan, 3)) self.connect(chan, self) log_to_file(self, tap1_filter, "data/tap1_filter.compl") log_to_file(self, tap1_filter, "data/tap1_filter.float", mag=True) log_to_file(self, tap2_filter, "data/tap2_filter.compl") log_to_file(self, tap2_filter, "data/tap2_filter.float", mag=True)
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 publish_rx_performance_measure(self): if self._rx_performance_measure_initialized(): return self.rx_performance_measure_initialized = True config = station_configuration() vlen = config.data_subcarriers vlen_sinr_sc = config.subcarriers # self.rx_per_sink = rpsink = rpsink_dummy() self.setup_ber_measurement() self.setup_snr_measurement() self.setup_snr_measurement_2() ber_mst = self._ber_measuring_tool if self._options.sinr_est: sinr_mst = self._sinr_measurement sinr_mst_2 = self._sinr_measurement_2 else: snr_mst = self._snr_measurement snr_mst_2 = self._snr_measurement_2 # 1. frame id # 2. channel transfer function ctf = self.filter_ctf() ctf_2 = self.filter_ctf_2() self.zmq_probe_ctf = zeromq.pub_sink(gr.sizeof_float,config.data_subcarriers, "tcp://*:5559") self.zmq_probe_ctf_2 = zeromq.pub_sink(gr.sizeof_float,config.data_subcarriers, "tcp://*:5558") self.connect(ctf, blocks.keep_one_in_n(gr.sizeof_float*config.data_subcarriers,20) ,self.zmq_probe_ctf) self.connect(ctf_2, blocks.keep_one_in_n(gr.sizeof_float*config.data_subcarriers,20) ,self.zmq_probe_ctf_2) # 3. BER ### FIXME HACK print "Normal BER measurement" trig_src = dynamic_trigger_ib(False) self.connect(self.bitcount_src,trig_src) ber_sampler = vector_sampler(gr.sizeof_float,1) self.connect(ber_mst,(ber_sampler,0)) self.connect(trig_src,(ber_sampler,1)) if self._options.log: trig_src_float = gr.char_to_float() self.connect(trig_src,trig_src_float) log_to_file(self, trig_src_float , 'data/dynamic_trigger_out.float') if self._options.sinr_est is False: self.zmq_probe_ber = zeromq.pub_sink(gr.sizeof_float, 1, "tcp://*:5556") self.connect(ber_sampler,blocks.keep_one_in_n(gr.sizeof_float,20) ,self.zmq_probe_ber) self.zmq_probe_snr = zeromq.pub_sink(gr.sizeof_float, 1, "tcp://*:5555") self.connect(snr_mst,blocks.keep_one_in_n(gr.sizeof_float,20) ,self.zmq_probe_snr) self.zmq_probe_snr_2 = zeromq.pub_sink(gr.sizeof_float, 1, "tcp://*:5554") self.connect(snr_mst_2,blocks.keep_one_in_n(gr.sizeof_float,20) ,self.zmq_probe_snr_2)
def __init__(self, options): gr.top_block.__init__(self, "ofdm_tx") self._tx_freq = options.tx_freq # tranmitter's center frequency self._tx_subdev_spec = options.tx_subdev_spec # daughterboard to use self._fusb_block_size = options.fusb_block_size # usb info for USRP self._fusb_nblocks = options.fusb_nblocks # usb info for USRP self._which = options.which_usrp self._bandwidth = options.bandwidth self.servants = [] self._interface = options.interface self._mac_addr = options.mac_addr self._options = copy.copy(options) self._interpolation = 1 f1 = numpy.array([ -107, 0, 445, 0, -1271, 0, 2959, 0, -6107, 0, 11953, 0, -24706, 0, 82359, 262144 / 2, 82359, 0, -24706, 0, 11953, 0, -6107, 0, 2959, 0, -1271, 0, 445, 0, -107 ], numpy.float64) / 262144. print "Software interpolation: %d" % (self._interpolation) bw = 0.5 / self._interpolation tb = bw / 5 if self._interpolation > 1: self.filter = gr.hier_block2( "filter", gr.io_signature(1, 1, gr.sizeof_gr_complex), gr.io_signature(1, 1, gr.sizeof_gr_complex)) self.filter.connect(self.filter, gr.interp_fir_filter_ccf(2, f1), gr.interp_fir_filter_ccf(2, f1), self.filter) print "New" # # # self.filt_coeff = optfir.low_pass(1.0, 1.0, bw, bw+tb, 0.2, 60.0, 0) # self.filter = gr.interp_fir_filter_ccf(self._interpolation,self.filt_coeff) # print "Software interpolation filter length: %d" % (len(self.filt_coeff)) else: self.filter = None if not options.from_file is None: # sent captured file to usrp self.src = gr.file_source(gr.sizeof_gr_complex, options.from_file) self._setup_usrp_sink() if hasattr(self, "filter"): self.connect(self.src, self.filter, self.u) #,self.filter else: self.connect(self.src, self.u) return self._setup_tx_path(options) config = station_configuration() self.enable_info_tx("info_tx", "pa_user") # if not options.no_cheat: # self.txpath.enable_channel_cheating("channelcheat") self.txpath.enable_txpower_adjust("txpower") self.txpath.publish_txpower("txpower_info") #self.enable_txfreq_adjust("txfreq") if options.nullsink: self.dst = gr.null_sink(gr.sizeof_gr_complex) self.dst_2 = gr.null_sink(gr.sizeof_gr_complex) else: if not options.to_file is None: # capture transmitter's stream to disk self.dst = gr.file_sink(gr.sizeof_gr_complex, options.to_file) self.dst_2 = gr.file_sink(gr.sizeof_gr_complex, options.to_file) tmp = gr.throttle(gr.sizeof_gr_complex, 1e5) tmp_2 = gr.throttle(gr.sizeof_gr_complex, 1e5) self.connect(tmp, self.dst) self.connect(tmp_2, self.dst_2) self.dst = tmp self.dst_2 = tmp_2 if options.force_filter: print "Forcing filter usage" self.connect(self.filter, self.dst) self.dst = self.filter else: # connect transmitter to usrp self._setup_usrp_sink() if options.dyn_freq: self.enable_txfreq_adjust("txfreq") if self.filter is not None: self.connect(self.filter, self.dst) self.dst = self.filter if options.record: log_to_file(self, self.txpath, "data/txpath_out.compl") #self.publish_spectrum( 256 ) if options.measure: self.m = throughput_measure(gr.sizeof_gr_complex) self.connect(self.m, self.dst) self.dst = self.m if options.samplingoffset is not None: soff = options.samplingoffset interp = gr.fractional_interpolator_cc(0.0, soff) self.connect(interp, self.dst) self.dst = interp if options.snr is not None: # if options.berm is not None: # noise_sigma = 380 #empirically given, gives the received SNR range of (1:28) for tx amp. range of (500:10000) which is set in rm_ber_measurement.py # #check for fading channel # else: snr_db = options.snr snr = 10.0**(snr_db / 10.0) noise_sigma = sqrt(config.rms_amplitude**2 / snr) print " Noise St. Dev. %d" % (noise_sigma) awgn_chan = gr.add_cc() awgn_noise_src = ofdm.complex_white_noise(0.0, noise_sigma) self.connect(awgn_noise_src, (awgn_chan, 1)) self.connect(awgn_chan, self.dst) self.dst = awgn_chan if options.berm is False: fad_chan = itpp.tdl_channel() #[0, -7, -20], [0, 2, 6] #fad_chan.set_norm_doppler( 1e-9 ) #fad_chan.set_LOS( [500.,0,0] ) fad_chan.set_channel_profile(itpp.ITU_Pedestrian_A, 5e-8) fad_chan.set_norm_doppler(1e-8) # fad_chan = gr.fir_filter_ccc(1,[1.0,0.0,2e-1+0.1j,1e-4-0.04j]) self.connect(fad_chan, self.dst) self.dst = fad_chan if options.freqoff is not None: freq_shift = gr.multiply_cc() norm_freq = options.freqoff / config.fft_length freq_off_src = gr.sig_source_c(1.0, gr.GR_SIN_WAVE, norm_freq, 1.0, 0.0) self.connect(freq_off_src, (freq_shift, 1)) dst = self.dst self.connect(freq_shift, dst) self.dst = freq_shift self.connect((self.txpath, 0), self.dst) self.connect((self.txpath, 1), self.dst_2) if options.cheat: self.txpath.enable_channel_cheating("channelcheat") print "Hit Strg^C to terminate"
def __init__ (self, options): gr.top_block.__init__(self, "ofdm_benchmark") ##self._tx_freq = options.tx_freq # tranmitter's center frequency ##self._tx_subdev_spec = options.tx_subdev_spec # daughterboard to use ##self._fusb_block_size = options.fusb_block_size # usb info for USRP ##self._fusb_nblocks = options.fusb_nblocks # usb info for USRP ##self._which = options.which_usrp self._bandwidth = options.bandwidth self.servants = [] self._verbose = options.verbose ##self._interface = options.interface ##self._mac_addr = options.mac_addr self._options = copy.copy( options ) self._interpolation = 1 f1 = numpy.array([-107,0,445,0,-1271,0,2959,0,-6107,0,11953, 0,-24706,0,82359,262144/2,82359,0,-24706,0, 11953,0,-6107,0,2959,0,-1271,0,445,0,-107], numpy.float64)/262144. print "Software interpolation: %d" % (self._interpolation) bw = 1.0/self._interpolation tb = bw/5 if self._interpolation > 1: self.tx_filter = gr.hier_block2("filter", gr.io_signature(1,1,gr.sizeof_gr_complex), gr.io_signature(1,1,gr.sizeof_gr_complex)) self.tx_filter2 = gr.hier_block2("filter", gr.io_signature(1,1,gr.sizeof_gr_complex), gr.io_signature(1,1,gr.sizeof_gr_complex)) self.tx_filter.connect( self.tx_filter, gr.interp_fir_filter_ccf(2,f1), gr.interp_fir_filter_ccf(2,f1), self.tx_filter ) self.tx_filter2.connect( self.tx_filter2, gr.interp_fir_filter_ccf(2,f1), gr.interp_fir_filter_ccf(2,f1), self.tx_filter2 ) print "New" else: self.tx_filter = None self.tx_filter2 = None self.decimation = 1 if self.decimation > 1: bw = 0.5/self.decimation * 1 tb = bw/5 # gain, sampling rate, passband cutoff, stopband cutoff # passband ripple in dB, stopband attenuation in dB # extra taps filt_coeff = optfir.low_pass(1.0, 1.0, bw, bw+tb, 0.1, 60.0, 1) print "Software decimation filter length: %d" % (len(filt_coeff)) self.rx_filter = gr.fir_filter_ccf(self.decimation,filt_coeff) self.rx_filter2 = gr.fir_filter_ccf(self.decimation,filt_coeff) else: self.rx_filter = None self.rx_filter2 = None ## if not options.from_file is None: ## # sent captured file to usrp ## self.src = gr.file_source(gr.sizeof_gr_complex,options.from_file) ## self._setup_usrp_sink() ## if hasattr(self, "filter"): ## self.connect(self.src,self.filter,self.u) #,self.filter ## else: ## self.connect(self.src,self.u) ## ## return self._setup_tx_path(options) self._setup_rx_path(options) config = station_configuration() self.enable_info_tx("info_tx", "pa_user") # if not options.no_cheat: # self.txpath.enable_channel_cheating("channelcheat") self.txpath.enable_txpower_adjust("txpower") self.txpath.publish_txpower("txpower_info") if options.disable_equalization or options.ideal: #print "CHANGE set_k" self.rxpath.enable_estim_power_adjust("estim_power") #self.rxpath.publish_estim_power("txpower_info") #self.enable_txfreq_adjust("txfreq") if options.imgxfer: self.rxpath.setup_imgtransfer_sink() if not options.no_decoding: self.rxpath.publish_rx_performance_measure() self.dst = (self.rxpath,0) self.dst2 = (self.rxpath,1) if options.force_rx_filter: print "Forcing rx filter usage" self.connect( self.rx_filter, self.dst ) self.connect( self.rx_filter2, self.dst2 ) self.dst = self.rx_filter self.dst2 = self.rx_filter2 if options.measure: self.m = throughput_measure(gr.sizeof_gr_complex) self.m2 = throughput_measure(gr.sizeof_gr_complex) self.connect( self.m, self.dst ) self.connect( self.m2, self.dst2 ) self.dst = self.m self.dst2 = self.m2 if options.snr is not None: if options.berm is not False: noise_sigma = 380 #empirically given, gives the received SNR range of (1:28) for tx amp. range of (500:10000) which is set in rm_ber_measurement.py #check for fading channel else: snr_db = options.snr snr = 10.0**(snr_db/10.0) noise_sigma = sqrt( config.rms_amplitude**2 / snr ) print " Noise St. Dev. %d" % (noise_sigma) awgn_chan = blocks.add_cc() awgn_chan2 = blocks.add_cc() awgn_noise_src = ofdm.complex_white_noise( 0.0, noise_sigma ) awgn_noise_src2 = ofdm.complex_white_noise( 0.0, noise_sigma ) self.connect( awgn_chan, self.dst ) self.connect( awgn_chan2, self.dst2 ) self.connect( awgn_noise_src, (awgn_chan,1) ) self.connect( awgn_noise_src2, (awgn_chan2,1) ) self.dst = awgn_chan self.dst2 = awgn_chan2 if options.freqoff is not None: freq_shift = blocks.multiply_cc() freq_shift2 = blocks.multiply_cc() norm_freq = options.freqoff / config.fft_length freq_off_src = analog.sig_source_c(1.0, analog.GR_SIN_WAVE, norm_freq, 1.0, 0.0 ) freq_off_src2 = analog.sig_source_c(1.0, analog.GR_SIN_WAVE, norm_freq, 1.0, 0.0 ) self.connect( freq_off_src, ( freq_shift, 1 ) ) self.connect( freq_off_src2, ( freq_shift2, 1 ) ) dst = self.dst dst2 = self.dst2 self.connect( freq_shift, dst ) self.connect( freq_shift2, dst2 ) self.dst = freq_shift self.dst2 = freq_shift2 if options.multipath: if options.itu_channel: fad_chan = itpp.tdl_channel( ) #[0, -7, -20], [0, 2, 6] #fad_chan.set_norm_doppler( 1e-9 ) #fad_chan.set_LOS( [500.,0,0] ) fad_chan2 = itpp.tdl_channel( ) fad_chan.set_channel_profile( itpp.ITU_Pedestrian_A, 5e-8 ) fad_chan.set_norm_doppler( 1e-8 ) fad_chan2.set_channel_profile( itpp.ITU_Pedestrian_A, 5e-8 ) fad_chan2.set_norm_doppler( 1e-8 ) else: fad_chan = gr.fir_filter_ccc(1,[1.0,0.0,2e-1+0.1j,1e-4-0.04j]) fad_chan2 = gr.fir_filter_ccc(1,[1.0,0.0,2e-1+0.1j,1e-4-0.04j]) self.connect( fad_chan, self.dst ) self.connect( fad_chan2, self.dst2 ) self.dst = fad_chan self.dst2 = fad_chan2 if options.samplingoffset is not None: soff = options.samplingoffset interp = moms(1000000+soff,1000000) interp2 = moms(1000000+soff,1000000) self.connect( interp, self.dst ) self.connect( interp2, self.dst2 ) self.dst = interp self.dst2 = interp2 if options.record: log_to_file( self, interp, "data/interp_out.compl" ) log_to_file( self, interp2, "data/interp2_out.compl" ) tmm =blocks.throttle(gr.sizeof_gr_complex,self._bandwidth) tmm2 =blocks.throttle(gr.sizeof_gr_complex,self._bandwidth) tmm_add = blocks.add_cc() tmm2_add = blocks.add_cc() self.connect( tmm, tmm_add ) self.connect( tmm2, (tmm_add,1) ) self.connect( tmm, tmm2_add ) self.connect( tmm2, (tmm2_add,1) ) self.connect( tmm_add, self.dst ) self.connect( tmm2_add, self.dst2 ) self.dst = tmm self.dst2 = tmm2 inter = blocks.interleave(gr.sizeof_gr_complex) deinter = blocks.deinterleave(gr.sizeof_gr_complex) self.connect(inter, deinter) self.connect((deinter,0),self.dst) self.connect((deinter,1),self.dst2) self.dst = inter self.dst2 = (inter,1) if options.force_tx_filter: print "Forcing tx filter usage" self.connect( self.tx_filter, self.dst ) self.connect( self.tx_filter2, self.dst2 ) self.dst = self.tx_filter self.dst2 = self.tx_filter2 if options.record: log_to_file( self, self.txpath, "data/txpath_out.compl" ) log_to_file( self, self.txpath2, "data/txpath2_out.compl" ) if options.nullsink: self.connect(gr.null_source(gr.sizeof_gr_complex), self.dst) self.connect(gr.null_source(gr.sizeof_gr_complex), self.dst2) self.dst = gr.null_sink(gr.sizeof_gr_complex) self.dst2 = gr.null_sink(gr.sizeof_gr_complex) self.connect( self.txpath,self.dst ) self.connect( (self.txpath,1),self.dst2 ) if options.cheat: self.txpath.enable_channel_cheating("channelcheat") print "Hit Strg^C to terminate" if options.event_rxbaseband: self.publish_rx_baseband_measure() if options.with_old_gui: self.publish_spectrum(256) self.rxpath.publish_ctf("ctf_display") self.rxpath.publish_ber_measurement(["ber"]) self.rxpath.publish_average_snr(["totalsnr"]) if options.sinr_est: self.rxpath.publish_sinrsc("sinrsc_display") print "Hit Strg^C to terminate" # Display some information about the setup if self._verbose: self._print_verbage()
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 cp_length = config.cp_length print "data_subc: ", config.data_subcarriers print "total_subc: ", config.subcarriers print "frame_lengthframe_length: ", frame_length ## Set Input/Output signature gr.hier_block2.__init__( self, "fbmc_inner_receiver", gr.io_signature( 1, 1, gr.sizeof_gr_complex ), gr.io_signaturev( 4, 4, [gr.sizeof_float * total_subc, # Normalized |CTF|^2 gr.sizeof_char, # Frame start gr.sizeof_gr_complex * total_subc, # OFDM blocks, SNR est gr.sizeof_float] ) ) # CFO ## Input and output ports self.input = rx_input = self out_ofdm_blocks = ( self, 2 ) out_frame_start = ( self, 1 ) out_disp_ctf = ( self, 0 ) out_disp_cfo = ( self, 3 ) #out_snr_pream = ( self, 3 ) ## pre-FFT processing ''' ## 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 ) terminate_stream(self, gi_metric) ## Sync. Output contains OFDM blocks sync = ofdm.time_sync( fft_length/2, 1) self.connect( rx_input, ( sync, 0 ) ) self.connect( sc_metric, ( sync, 1 ) ) self.connect( sc_metric, ( sync, 2 ) ) ofdm_blocks = ( sync, 0 ) frame_start = ( sync, 1 ) log_to_file( self, ( sync, 1 ), "data/fbmc_peak_detector.char" ) ''' if options.ideal is False and options.ideal2 is False: #Testing old/new metric self.tm = schmidl.recursive_timing_metric(2*fft_length) self.connect( self.input, self.tm) #log_to_file( self, self.tm, "data/fbmc_rec_sc_metric_ofdm.float" ) timingmetric_shift = 0 #-2 #int(-cp_length * 0.8) tmfilter = filter.fft_filter_fff(1, [2./fft_length]*(fft_length/2))# ofdm.lms_fir_ff( fft_length, 1e-3 ) #; filter.fir_filter_fff(1, [1./fft_length]*fft_length) self.connect( self.tm, tmfilter ) self.tm = tmfilter #log_to_file( self, self.tm, "data/fbmc_rec_sc_metric_ofdm2.float" ) self._pd_thres = 0.6 self._pd_lookahead = fft_length # 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/fbmc_rec_peak_detector.char" ) #frame_start = [0]*frame_length #frame_start[0] = 1 #frame_start = blocks.vector_source_b(frame_start,True) #OLD #delayed_timesync = blocks.delay(gr.sizeof_char, # (frame_length-10)*fft_length/2 - fft_length/4 -1 + timingmetric_shift) delayed_timesync = blocks.delay(gr.sizeof_char, (frame_length-10)*fft_length/2 - fft_length/4 + int(2.5*fft_length) + timingmetric_shift-1) #delayed_timesync = blocks.delay(gr.sizeof_char, #(frame_length-10)*fft_length/2 - fft_length/4 + int(3.5*fft_length) + timingmetric_shift-1) self.connect( peak_detector, delayed_timesync ) self.block_sampler = ofdm.vector_sampler(gr.sizeof_gr_complex,fft_length/2*frame_length) self.connect(self.input,self.block_sampler) self.connect(delayed_timesync,(self.block_sampler,1)) #log_to_file( self, self.block_sampler, "data/fbmc_block_sampler.compl" ) vt2s = blocks.vector_to_stream(gr.sizeof_gr_complex*fft_length, frame_length/2) self.connect(self.block_sampler,vt2s) #terminate_stream(self,ofdm_blocks) ofdm_blocks = vt2s ''' # TODO: dynamic solution vt2s = blocks.vector_to_stream(gr.sizeof_gr_complex*block_length/2, frame_length) self.connect(self.block_sampler,vt2s) terminate_stream(self,( sync, 0 )) ofdm_blocks = vt2s ''' ##stv_help = blocks.stream_to_vector(gr.sizeof_gr_complex*config.fft_length/2, 1) #stv_help = blocks.vector_to_stream(gr.sizeof_gr_complex*config.fft_length/2, 2) ##self.connect(ofdm_blocks, stv_help) ##ofdm_blocks = stv_help #ofdm_blocks = ( sync, 0 ) #frame_start = ( sync, 1 ) #log_to_file(self, frame_start, "data/frame_start.compl") #log_to_file( self, sc_metric, "data/sc_metric.float" ) #log_to_file( self, gi_metric, "data/gi_metric.float" ) #log_to_file( self, (sync,1), "data/sync.float" ) # log_to_file(self,ofdm_blocks,"data/ofdm_blocks_original.compl") frame_start = [0]*int(frame_length/2) frame_start[0] = 1 frame_start = blocks.vector_source_b(frame_start,True) #frame_start2 = [0]*int(frame_length/2) #frame_start2[0] = 1 #frame_start2 = blocks.vector_source_b(frame_start2,True) 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,fft_length) #discard_cp = ofdm.vector_mask(block_length,cp_length,fft_length,[]) #serial_to_parallel = blocks.stream_to_vector(gr.sizeof_gr_complex,block_length) #discard_cp = ofdm.vector_mask(block_length,cp_length,fft_length,[]) #self.connect( rx_input,serial_to_parallel) #self.connect( rx_input, blocks.delay(gr.sizeof_gr_complex,0),serial_to_parallel) initial_skip = blocks.skiphead(gr.sizeof_gr_complex,2*fft_length) self.connect( rx_input, initial_skip) if options.ideal is False and options.ideal2 is False: self.connect( initial_skip, serial_to_parallel) ofdm_blocks = serial_to_parallel else: ofdm_blocks = initial_skip #self.connect( rx_input, serial_to_parallel, discard_cp ) frame_start = [0]*int(frame_length/2) frame_start[0] = 1 frame_start = blocks.vector_source_b(frame_start,True) #frame_start2 = [0]*int(frame_length/2) #frame_start2[0] = 1 #frame_start2 = blocks.vector_source_b(frame_start2,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, 2, 1, config.fbmc ) sampler_preamble = ofdm.vector_sampler( gr.sizeof_gr_complex * fft_length, 1 ) self.connect( ofdm_blocks, ( sampler_preamble, 0 ) ) self.connect( frame_start, blocks.delay( gr.sizeof_char, 1 ), ( sampler_preamble, 1 ) ) self.connect( sampler_preamble, morelli_foe ) freq_offset = morelli_foe print "FRAME_LENGTH: ", frame_length #log_to_file( self, sampler_preamble, "data/sampler_preamble.compl" ) #log_to_file( self, rx_input, "data/rx_input.compl" ) #log_to_file( self, ofdm_blocks, "data/rx_input.compl" ) #Extracting preamble for SNR estimation #fft_snr_est = fft_blocks.fft_vcc( fft_length, True, [], True ) #self.connect( sampler_preamble, blocks.stream_to_vector(gr.sizeof_gr_complex*fft_length/2, 2), fft_snr_est ) ## Remove virtual subcarriers #if fft_length > data_subc: #subcarrier_mask_snr_est = ofdm.vector_mask( fft_length, virtual_subc/2, # total_subc, [] ) #self.connect( fft_snr_est, subcarrier_mask_snr_est ) #fft_snr_est = subcarrier_mask_snr_est #log_to_file(self, ofdm_blocks, "data/vec_mask.compl") ## Least Squares estimator for channel transfer function (CTF) #self.connect( fft_snr_est, out_snr_pream ) # Connecting to output ## 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.connect(freq_offset, 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, 0) #freq_shift = blocks.multiply_cc() #norm_freq = -0.1 / config.fft_length #freq_off = self.freq_off_src = analog.sig_source_c(1.0, analog.GR_SIN_WAVE, norm_freq, 1.0, 0.0 ) self.connect( ofdm_blocks, ( frequency_shift, 0 ) ) self.connect( freq_offset, ( frequency_shift, 1 ) ) self.connect( frame_start,blocks.delay( gr.sizeof_char, 0), ( frequency_shift, 2 ) ) #self.connect(frequency_shift,s2help) #ofdm_blocks = s2help ofdm_blocks = frequency_shift #terminate_stream(self, frequency_shift) #inner_pb_filt = self._inner_pilot_block_filter = fbmc_inner_pilot_block_filter() #self.connect(ofdm_blocks,inner_pb_filt) #self.connect(frame_start,(inner_pb_filt,1)) #self.connect((inner_pb_filt,1),blocks.null_sink(gr.sizeof_char)) #ofdm_blocks = (inner_pb_filt,0) overlap_ser_to_par = ofdm.fbmc_overlapping_serial_to_parallel_cvc(fft_length) self.separate_vcvc = ofdm.fbmc_separate_vcvc(fft_length, 2) self.polyphase_network_vcvc_1 = ofdm.fbmc_polyphase_network_vcvc(fft_length, 4, 4*fft_length-1, True) self.polyphase_network_vcvc_2 = ofdm.fbmc_polyphase_network_vcvc(fft_length, 4, 4*fft_length-1, True) self.junction_vcvc = ofdm.fbmc_junction_vcvc(fft_length, 2) self.fft_fbmc = fft_blocks.fft_vcc(fft_length, True, [], True) print "config.training_data.fbmc_no_preambles: ", config.training_data.fbmc_no_preambles #center_preamble = [1, -1j, -1, 1j] #self.preamble = preamble = [0]*total_subc + center_preamble*((int)(total_subc/len(center_preamble)))+[0]*total_subc self.preamble = preamble = config.training_data.fbmc_pilotsym_fd_list #inv_preamble = 1. / numpy.array(self.preamble) #print "self.preamble: ", len(self.preamble #print "inv_preamble: ", list(inv_preamble) #print "self.preamble", self.preamble #print "self.preamble2", self.preamble2 self.multiply_const= ofdm.multiply_const_vcc(([1.0/(math.sqrt(fft_length*0.6863))]*total_subc)) self.beta_multiplier_vcvc = ofdm.fbmc_beta_multiplier_vcvc(total_subc, 4, 4*fft_length-1, 0) #self.skiphead = blocks.skiphead(gr.sizeof_gr_complex*total_subc, 2*4-1-1) self.skiphead = blocks.skiphead(gr.sizeof_gr_complex*total_subc,2) self.skiphead_1 = blocks.skiphead(gr.sizeof_gr_complex*total_subc, 0) #self.remove_preamble_vcvc = ofdm.fbmc_remove_preamble_vcvc(total_subc, config.frame_data_part/2, config.training_data.fbmc_no_preambles*total_subc/2) #self.subchannel_processing_vcvc = ofdm.fbmc_subchannel_processing_vcvc(total_subc, config.frame_data_part, 1, 2, 1, 0) self.oqam_postprocessing_vcvc = ofdm.fbmc_oqam_postprocessing_vcvc(total_subc, 0, 0) #log_to_file( self, ofdm_blocks, "data/PRE_FBMC.compl" ) #log_to_file( self, self.fft_fbmc, "data/FFT_FBMC.compl" ) if options.ideal is False and options.ideal2 is False: self.subchannel_processing_vcvc = ofdm.fbmc_subchannel_processing_vcvc(total_subc, config.frame_data_part, 3, 2, 1, 0) help2 = blocks.keep_one_in_n(gr.sizeof_gr_complex*total_subc,frame_length) self.connect ((self.subchannel_processing_vcvc,1),help2) #log_to_file( self, self.subchannel_processing_vcvc, "data/fbmc_subc.compl" ) #terminate_stream(self, help2) if options.ideal is False and options.ideal2 is False: self.connect(ofdm_blocks, blocks.vector_to_stream(gr.sizeof_gr_complex, fft_length),overlap_ser_to_par) else: self.connect(ofdm_blocks,overlap_ser_to_par) self.connect(overlap_ser_to_par, self.separate_vcvc) self.connect((self.separate_vcvc, 1), (self.polyphase_network_vcvc_2, 0)) self.connect((self.separate_vcvc, 0), (self.polyphase_network_vcvc_1, 0)) self.connect((self.polyphase_network_vcvc_1, 0), (self.junction_vcvc, 0)) self.connect((self.polyphase_network_vcvc_2, 0), (self.junction_vcvc, 1)) self.connect(self.junction_vcvc, self.fft_fbmc) ofdm_blocks = self.fft_fbmc print "config.dc_null: ", config.dc_null if fft_length > data_subc: subcarrier_mask_fbmc = ofdm.vector_mask_dc_null( fft_length, virtual_subc/2, total_subc, config.dc_null, [] ) self.connect( ofdm_blocks, subcarrier_mask_fbmc ) ofdm_blocks = subcarrier_mask_fbmc #log_to_file(self, ofdm_blocks, "data/vec_mask.compl") ## Least Squares estimator for channel transfer function (CTF) #log_to_file( self, subcarrier_mask, "data/OFDM_Blocks.compl" ) self.connect(ofdm_blocks, self.beta_multiplier_vcvc) ofdm_blocks = self.beta_multiplier_vcvc #self.connect(ofdm_blocks,self.multiply_const) #self.connect(self.multiply_const, (self.skiphead, 0)) self.connect(ofdm_blocks, (self.skiphead, 0)) #log_to_file( self, self.skiphead, "data/fbmc_skiphead_4.compl" ) #self.connect(ofdm_blocks, self.multiply_const) #self.connect(self.multiply_const, self.beta_multiplier_vcvc) #self.connect((self.beta_multiplier_vcvc, 0), (self.skiphead, 0)) if options.ideal or options.ideal2: self.connect((self.skiphead, 0),(self.skiphead_1, 0)) else: self.connect((self.skiphead, 0), (self.subchannel_processing_vcvc, 0)) self.connect((self.subchannel_processing_vcvc, 0), (self.skiphead_1, 0)) #log_to_file( self, self.skiphead, "data/fbmc_subc.compl" ) #self.connect((self.skiphead_1, 0),(self.remove_preamble_vcvc, 0)) #self.connect((self.remove_preamble_vcvc, 0), (self.oqam_postprocessing_vcvc, 0)) #ofdm_blocks = self.oqam_postprocessing_vcvc #log_to_file( self, self.subchannel_processing_vcvc, "data/subc_0.compl" ) #log_to_file( self, (self.subchannel_processing_vcvc,1), "data/subc_1.compl" ) self.connect((self.skiphead_1, 0),(self.oqam_postprocessing_vcvc, 0)) #self.connect((self.oqam_postprocessing_vcvc, 0), (self.remove_preamble_vcvc, 0) ) ofdm_blocks = (self.oqam_postprocessing_vcvc, 0)#(self.remove_preamble_vcvc, 0) #log_to_file( self, (self.oqam_postprocessing_vcvc, 0), "data/fbmc_before_remove.compl" ) #log_to_file( self, self.skiphead, "data/SKIP_HEAD_FBMC.compl" ) #log_to_file( self, self.beta_multiplier_vcvc, "data/BETA_REC_FBMC.compl" ) #log_to_file( self, self.oqam_postprocessing_vcvc, "data/REC_OUT_FBMC.compl" ) """ DISABLED OFDM CHANNEL ESTIMATION PREMBLE -> CORRECT LATER to compare FBMC and OFDM channel estimation #TAKING THE CHANNEL ESTIMATION PREAMBLE chest_pre_trigger = blocks.delay( gr.sizeof_char, 3 ) sampled_chest_preamble = ofdm.vector_sampler( gr.sizeof_gr_complex * fft_length/2, 2 ) self.connect( frame_start, chest_pre_trigger ) self.connect( chest_pre_trigger, ( sampled_chest_preamble, 1 ) ) self.connect( frequency_shift, ( sampled_chest_preamble, 0 ) ) #ofdm_blocks = sampled_chest_preamble ## FFT fft = fft_blocks.fft_vcc( fft_length, True, [], True ) self.connect( sampled_chest_preamble, fft ) ofdm_blocks_est = fft log_to_file( self, sampled_chest_preamble, "data/SAMPLED_EST_PREAMBLE.compl" ) log_to_file( self, ofdm_blocks_est, "data/FFT.compl" ) ## Remove virtual subcarriers if fft_length > data_subc: subcarrier_mask = ofdm.vector_mask( fft_length, virtual_subc/2, total_subc, [] ) self.connect( ofdm_blocks_est, subcarrier_mask ) ofdm_blocks_est = subcarrier_mask #log_to_file(self, ofdm_blocks, "data/vec_mask.compl") ## Least Squares estimator for channel transfer function (CTF) log_to_file( self, subcarrier_mask, "data/OFDM_Blocks.compl" ) ## post-FFT processing ## 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 ) ) ## Least Squares estimator for channel transfer function (CTF) 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_estimator = ofdm.multiply_const_vcc( list( inv_preamble_fd ) ) self.connect( ofdm_blocks_est, LS_channel_estimator ) estimated_CTF = LS_channel_estimator terminate_stream(self,estimated_CTF) """ if options.ideal is False and options.ideal2 is False: 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.fbmc_postprocess_CTF_estimate( total_subc ) self.connect( help2, ctf_postprocess ) #estimated_SNR = ( ctf_postprocess, 0 ) disp_CTF = ( ctf_postprocess, 0 ) #self.connect(estimated_SNR,out_snr_pream) #log_to_file( self, estimated_SNR, "data/fbmc_SNR.float" ) #Disable measured SNR output #terminate_stream(self, estimated_SNR) #self.connect(blocks.vector_source_f([10.0],True) ,out_snr_pream) # 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 ##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 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 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): gr.top_block.__init__(self, "ofdm_mrrc_benchmark") ##self._tx_freq = options.tx_freq # tranmitter's center frequency ##self._tx_subdev_spec = options.tx_subdev_spec # daughterboard to use ##self._fusb_block_size = options.fusb_block_size # usb info for USRP ##self._fusb_nblocks = options.fusb_nblocks # usb info for USRP ##self._which = options.which_usrp self._bandwidth = options.bandwidth self.servants = [] self._verbose = options.verbose ##self._interface = options.interface ##self._mac_addr = options.mac_addr self._options = copy.copy( options ) self._interpolation = 1 f1 = numpy.array([-107,0,445,0,-1271,0,2959,0,-6107,0,11953, 0,-24706,0,82359,262144/2,82359,0,-24706,0, 11953,0,-6107,0,2959,0,-1271,0,445,0,-107], numpy.float64)/262144. print "Software interpolation: %d" % (self._interpolation) bw = 1.0/self._interpolation tb = bw/5 if self._interpolation > 1: self.tx_filter = gr.hier_block2("filter", gr.io_signature(1,1,gr.sizeof_gr_complex), gr.io_signature(1,1,gr.sizeof_gr_complex)) self.tx_filter2 = gr.hier_block2("filter", gr.io_signature(1,1,gr.sizeof_gr_complex), gr.io_signature(1,1,gr.sizeof_gr_complex)) self.tx_filter.connect( self.tx_filter, gr.interp_fir_filter_ccf(2,f1), gr.interp_fir_filter_ccf(2,f1), self.tx_filter ) self.tx_filter2.connect( self.tx_filter2, gr.interp_fir_filter_ccf(2,f1), gr.interp_fir_filter_ccf(2,f1), self.tx_filter2 ) print "New" else: self.tx_filter = None self.tx_filter2 = None self.decimation = 1 if self.decimation > 1: bw = 0.5/self.decimation * 1 tb = bw/5 # gain, sampling rate, passband cutoff, stopband cutoff # passband ripple in dB, stopband attenuation in dB # extra taps filt_coeff = optfir.low_pass(1.0, 1.0, bw, bw+tb, 0.1, 60.0, 1) print "Software decimation filter length: %d" % (len(filt_coeff)) self.rx_filter = gr.fir_filter_ccf(self.decimation,filt_coeff) self.rx_filter2 = gr.fir_filter_ccf(self.decimation,filt_coeff) else: self.rx_filter = None self.rx_filter2 = None ## if not options.from_file is None: ## # sent captured file to usrp ## self.src = gr.file_source(gr.sizeof_gr_complex,options.from_file) ## self._setup_usrp_sink() ## if hasattr(self, "filter"): ## self.connect(self.src,self.filter,self.u) #,self.filter ## else: ## self.connect(self.src,self.u) ## ## return self._setup_tx_path(options) self._setup_rx_path(options) self._setup_rpc_manager() config = self.config = station_configuration() #self.enable_txfreq_adjust("txfreq") if options.imgxfer: self.rxpath.setup_imgtransfer_sink() if not options.no_decoding: self.rxpath.publish_rx_performance_measure() self.dst = (self.rxpath,0) self.dst2 = (self.rxpath,1) if options.force_rx_filter: print "Forcing rx filter usage" self.connect( self.rx_filter, self.dst ) self.connect( self.rx_filter2, self.dst2 ) self.dst = self.rx_filter self.dst2 = self.rx_filter2 if options.measure: self.m = throughput_measure(gr.sizeof_gr_complex) self.m2 = throughput_measure(gr.sizeof_gr_complex) self.connect( self.m, self.dst ) self.connect( self.m2, self.dst2 ) self.dst = self.m self.dst2 = self.m2 if options.snr is not None: if options.berm is not None: noise_sigma = 380/32767.0 #empirically given, gives the received SNR range of (1:28) for tx amp. range of (500:10000) which is set in rm_ber_measurement.py print " Noise St. Dev. %f" % (noise_sigma)#check for fading channel else: snr_db = options.snr snr = 10.0**(snr_db/10.0) noise_sigma = sqrt( config.rms_amplitude**2 / snr ) print " Noise St. Dev. %f" % (noise_sigma) awgn_chan = blocks.add_cc() awgn_chan2 = blocks.add_cc() awgn_noise_src = analog.fastnoise_source_c(analog.GR_GAUSSIAN, noise_sigma, 0, 8192) awgn_noise_src2 = analog.fastnoise_source_c(analog.GR_GAUSSIAN, noise_sigma*2, 0, 2192) self.connect( awgn_chan, self.dst ) self.connect( awgn_chan2, self.dst2 ) self.connect( awgn_noise_src, (awgn_chan,1) ) self.connect( awgn_noise_src2, (awgn_chan2,1) ) self.dst = awgn_chan self.dst2 = awgn_chan2 if options.freqoff is not None: freq_off = self.freq_off = channel.freq_offset(options.freqoff ) freq_off2 = self.freq_off2 = channel.freq_offset(options.freqoff ) dst = self.dst dst2 = self.dst2 self.connect( freq_off, dst ) self.connect( freq_off2, dst2 ) self.dst = freq_off self.dst2 = freq_off2 self.rpc_mgr_tx.add_interface("set_freq_offset",self.freq_off.set_freqoff) self.rpc_mgr_tx.add_interface("set_freq_offset2",self.freq_off2.set_freqoff) if options.multipath: if options.itu_channel: self.fad_chan = channel.itpp_channel(options.bandwidth) #fad_chan.set_norm_doppler( 1e-9 ) #fad_chan.set_LOS( [500.,0,0] ) self.fad_chan2 = channel.itpp_channel(options.bandwidth) self.fad_chan.set_channel_profile( itpp.ITU_Pedestrian_A, 5e-8 ) self.fad_chan.set_norm_doppler( 1e-8 ) self.fad_chan2.set_channel_profile( itpp.ITU_Pedestrian_A, 5e-8 ) self.fad_chan2.set_norm_doppler( 1e-8 ) self.rpc_mgr_tx.add_interface("set_channel_profile",self.fad_chan.set_channel_profile) self.rpc_mgr_tx.add_interface("set_channel_profile",self.fad_chan2.set_channel_profile) else: fad_chan = filter.fir_filter_ccc(1,[1.0,0.0,2e-1+0.1j,1e-4-0.04j]) fad_chan2 = filter.fir_filter_ccc(1,[1.0,0.0,2e-1+0.1j,1e-4-0.04j]) self.connect( self.fad_chan, self.dst ) self.connect( self.fad_chan2, self.dst2 ) self.dst = self.fad_chan self.dst2 = self.fad_chan2 if options.samplingoffset is not None: soff = options.samplingoffset interp = moms(1000000*(1.0+soff),1000000) interp2 = moms(1000000*(1.0+soff),1000000) self.connect( interp, self.dst ) self.connect( interp2, self.dst2 ) self.dst = interp self.dst2 = interp2 if options.record: log_to_file( self, interp, "data/interp_out.compl" ) log_to_file( self, interp2, "data/interp2_out.compl" ) tmm =blocks.throttle(gr.sizeof_gr_complex, 1e6) #tmm2 =blocks.throttle(gr.sizeof_gr_complex, 1e6) #self.connect( tmm, self.dst ) #self.connect( tmm2, self.dst2 ) #self.dst = tmm #self.dst2 = tmm2 #inter = blocks.interleave(gr.sizeof_gr_complex) #deinter = blocks.deinterleave(gr.sizeof_gr_complex) # Interleaving input/output streams ##self.connect(inter, deinter) #self.connect((deinter,0),self.dst) #self.connect((deinter,1),self.dst2) #self.dst = inter #self.dst2 = (inter,1) if options.force_tx_filter: print "Forcing tx filter usage" self.connect( self.tx_filter, self.dst ) self.connect( self.tx_filter2, self.dst2 ) self.dst = self.tx_filter self.dst2 = self.tx_filter2 if options.record: log_to_file( self, self.txpath, "data/txpath_out.compl" ) log_to_file( self, self.txpath2, "data/txpath2_out.compl" ) if options.nullsink: self.connect(gr.null_source(gr.sizeof_gr_complex), self.dst) self.connect(gr.null_source(gr.sizeof_gr_complex), self.dst2) self.dst = gr.null_sink(gr.sizeof_gr_complex) self.dst2 = gr.null_sink(gr.sizeof_gr_complex) self.connect( self.txpath,tmm,self.dst ) self.connect( tmm,self.dst2 ) #self.connect( self.txpath,self.dst2 ) print "Hit Strg^C to terminate" if self._verbose: self._print_verbage()
def __init__ (self, options): gr.top_block.__init__(self, "ofdm_benchmark") self._bandwidth = options.bandwidth self.servants = [] self._verbose = options.verbose self._options = copy.copy( options ) self.ideal = options.ideal self.ideal2 = options.ideal2 rms_amp = options.rms_amplitude self._interpolation = 1 f1 = numpy.array([-107,0,445,0,-1271,0,2959,0,-6107,0,11953, 0,-24706,0,82359,262144/2,82359,0,-24706,0, 11953,0,-6107,0,2959,0,-1271,0,445,0,-107], numpy.float64)/262144. print "Software interpolation: %d" % (self._interpolation) bw = 1.0/self._interpolation tb = bw/5 if self._interpolation > 1: self.tx_filter = gr.hier_block2("filter", gr.io_signature(1,1,gr.sizeof_gr_complex), gr.io_signature(1,1,gr.sizeof_gr_complex)) self.tx_filter.connect( self.tx_filter, gr.interp_fir_filter_ccf(2,f1), gr.interp_fir_filter_ccf(2,f1), self.tx_filter ) print "New" else: self.tx_filter = None self.decimation = 1 if self.decimation > 1: bw = 0.5/self.decimation * 1 tb = bw/5 # gain, sampling rate, passband cutoff, stopband cutoff # passband ripple in dB, stopband attenuation in dB # extra taps filt_coeff = optfir.low_pass(1.0, 1.0, bw, bw+tb, 0.1, 60.0, 1) print "Software decimation filter length: %d" % (len(filt_coeff)) self.rx_filter = gr.fir_filter_ccf(self.decimation,filt_coeff) else: self.rx_filter = None self._setup_tx_path(options) self._setup_rx_path(options) self._setup_rpc_manager() config = self.config = station_configuration() if options.imgxfer: self.rxpath.setup_imgtransfer_sink() if not options.no_decoding: self.rxpath.publish_rx_performance_measure() # capture transmitter's stream to disk #self.dst = gr.file_sink(gr.sizeof_gr_complex,options.to_file) self.dst= self.rxpath if options.force_rx_filter: print "Forcing rx filter usage" self.connect( self.rx_filter, self.dst ) self.dst = self.rx_filter if options.ideal or self.ideal2: self._amplifier = ofdm.multiply_const_ccf( 1.0 ) self.connect( self._amplifier, self.dst ) self.dst = self._amplifier self.set_rms_amplitude(rms_amp) if options.measure: self.m = throughput_measure(gr.sizeof_gr_complex) self.connect( self.m, self.dst ) self.dst = self.m if options.snr is not None: if options.berm is not None: # empirically determined to reach 30db SNR max in simulation mode noise_sigma = 0.0035 else: snr_db = options.snr snr = 10.0**(snr_db/10.0) noise_sigma = sqrt( config.rms_amplitude**2 / snr ) print " Noise St. Dev. %f" % (noise_sigma) awgn_chan = blocks.add_cc() #awgn_noise_src = ofdm.complex_white_noise( 0.0, noise_sigma ) awgn_noise_src = analog.fastnoise_source_c(analog.GR_GAUSSIAN, noise_sigma, 0, 8192) self.connect( awgn_noise_src, (awgn_chan,1) ) self.connect( awgn_chan, self.dst ) self.dst = awgn_chan if options.freqoff is not None: freq_off = self.freq_off = channel.freq_offset(options.freqoff ) dst = self.dst self.connect(freq_off, dst) self.dst = freq_off self.rpc_mgr_tx.add_interface("set_freq_offset",self.freq_off.set_freqoff) if options.multipath: if options.itu_channel: self.fad_chan = channel.itpp_channel(options.bandwidth) self.rpc_mgr_tx.add_interface("set_channel_profile",self.fad_chan.set_channel_profile) self.rpc_mgr_tx.add_interface("set_norm_doppler",self.fad_chan.set_norm_doppler) else: #self.fad_chan = filter.fir_filter_ccc(1,[1.0,0.0,2e-1+0.1j,1e-4-0.04j]) # filter coefficients for the lab exercise self.fad_chan = filter.fir_filter_ccc(1,[0.3267,0.8868,0.3267]) #self.fad_chan = filter.fir_filter_ccc(1,[0,0,0.1,0.2,0.01,0.3])#0.3267,0.8868,0.3267]) #self.fad_chan = channels.selective_fading_model(5, 0.1, False, 1, -1, [0, 0, 0], [0.3267,0.8868,0.3267], 10 ) #self.fad_chan = channels.fading_model(6, 0.05, False); #self.fad_chan = channels.dynamic_channel_model(1000000, 0, 0, 0, 0, 3, 0.01, False, 0, [2e-6,4e-6,8e-6],[0.3267,0.8868,0.3267], 20, 0, 0) self.connect(self.fad_chan, self.dst) self.dst = self.fad_chan if options.samplingoffset is not None: soff = options.samplingoffset interp = moms(1000000*(1.0+soff),1000000) #interp = filter.fractional_resampler_cc(0,1000000*(1.0+soff)/1000000.0) self.connect( interp, self.dst ) self.dst = interp if options.record: log_to_file( self, interp, "data/interp_out.compl" ) tmm =blocks.throttle(gr.sizeof_gr_complex,options.bandwidth) self.connect( tmm, self.dst ) self.dst = tmm if options.force_tx_filter: print "Forcing tx filter usage" self.connect( self.tx_filter, self.dst ) self.dst = self.tx_filter if options.record: log_to_file( self, self.txpath, "data/txpath_out.compl" ) if options.scatterplot: print "Scatterplot enabled" self.connect( self.txpath,self.dst ) print "Hit Strg^C to terminate" print "Hit Strg^C to terminate" # Display some information about the setup if self._verbose: self._print_verbage()
def publish_rx_performance_measure(self): if self._rx_performance_measure_initialized(): return self.rx_performance_measure_initialized = True config = station_configuration() vlen = config.data_subcarriers vlen_sinr_sc = config.subcarriers if self.ideal2 is False: self.setup_ber_measurement() self.setup_snr_measurement() ber_mst = self._ber_measuring_tool if self._options.sinr_est: sinr_mst = self._sinr_measurement else: if self.ideal2 is False: snr_mst = self._snr_measurement if self.ideal is False and self.ideal2 is False: self.ctf = self.filter_ctf() self.zmq_probe_ctf = zeromq.pub_sink(gr.sizeof_float,config.data_subcarriers, "tcp://*:5559") self.connect(self.ctf, blocks.keep_one_in_n(gr.sizeof_float*config.data_subcarriers,20) ,self.zmq_probe_ctf) else: #self.zmq_probe_ctf = zeromq.pub_sink(gr.sizeof_float,config.subcarriers, "tcp://*:5559") self.connect(self.ctf,blocks.null_sink(gr.sizeof_float*config.subcarriers)) #self.rx_per_sink = rpsink = corba_rxinfo_sink("himalaya",config.ns_ip, # config.ns_port,vlen,config.rx_station_id) # print "BER img xfer" # self.connect(ber_mst,(rpsink,3)) # ## no sampling needed # 3. SNR if self.ideal2 is False: print "Normal BER measurement" trig_src = dynamic_trigger_ib(False) self.connect(self.bitcount_src,trig_src) ber_sampler = vector_sampler(gr.sizeof_float,1) self.connect(ber_mst,(ber_sampler,0)) self.connect(trig_src,(ber_sampler,1)) else: if(self._options.coding): demod = self._data_decoder else: demod = self._data_demodulator self.connect(self.bitcount_src,blocks.null_sink(gr.sizeof_int) ) self.connect(demod,blocks.null_sink(gr.sizeof_char)) if self._options.log: trig_src_float = gr.char_to_float() self.connect(trig_src,trig_src_float) log_to_file(self, trig_src_float , 'data/dynamic_trigger_out.float') if self._options.sinr_est is False and self.ideal2 is False: self.zmq_probe_ber = zeromq.pub_sink(gr.sizeof_float, 1, "tcp://*:5556") self.connect(ber_sampler,blocks.keep_one_in_n(gr.sizeof_float,20) ,self.zmq_probe_ber) if self.ideal2 is False: self.zmq_probe_snr = zeromq.pub_sink(gr.sizeof_float, 1, "tcp://*:5555") self.connect(snr_mst,blocks.keep_one_in_n(gr.sizeof_float,20) ,self.zmq_probe_snr)
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 cp_length = config.cp_length print "data_subc: ", config.data_subcarriers print "total_subc: ", config.subcarriers print "frame_lengthframe_length: ", frame_length ## Set Input/Output signature gr.hier_block2.__init__( self, "fbmc_inner_receiver", gr.io_signature(1, 1, gr.sizeof_gr_complex), gr.io_signaturev( 4, 4, [ gr.sizeof_float * total_subc, # Normalized |CTF|^2 gr.sizeof_char, # Frame start gr.sizeof_gr_complex * total_subc, # OFDM blocks, SNR est gr.sizeof_float ])) # CFO ## Input and output ports self.input = rx_input = self out_ofdm_blocks = (self, 2) out_frame_start = (self, 1) out_disp_ctf = (self, 0) out_disp_cfo = (self, 3) #out_snr_pream = ( self, 3 ) ## pre-FFT processing ''' ## 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 ) terminate_stream(self, gi_metric) ## Sync. Output contains OFDM blocks sync = ofdm.time_sync( fft_length/2, 1) self.connect( rx_input, ( sync, 0 ) ) self.connect( sc_metric, ( sync, 1 ) ) self.connect( sc_metric, ( sync, 2 ) ) ofdm_blocks = ( sync, 0 ) frame_start = ( sync, 1 ) log_to_file( self, ( sync, 1 ), "data/fbmc_peak_detector.char" ) ''' if options.ideal is False and options.ideal2 is False: #Testing old/new metric self.tm = schmidl.recursive_timing_metric(2 * fft_length) self.connect(self.input, self.tm) #log_to_file( self, self.tm, "data/fbmc_rec_sc_metric_ofdm.float" ) timingmetric_shift = 0 #-2 #int(-cp_length * 0.8) tmfilter = filter.fft_filter_fff( 1, [2. / fft_length] * (fft_length / 2) ) # ofdm.lms_fir_ff( fft_length, 1e-3 ) #; filter.fir_filter_fff(1, [1./fft_length]*fft_length) self.connect(self.tm, tmfilter) self.tm = tmfilter #log_to_file( self, self.tm, "data/fbmc_rec_sc_metric_ofdm2.float" ) self._pd_thres = 0.6 self._pd_lookahead = fft_length # 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/fbmc_rec_peak_detector.char" ) #frame_start = [0]*frame_length #frame_start[0] = 1 #frame_start = blocks.vector_source_b(frame_start,True) #OLD #delayed_timesync = blocks.delay(gr.sizeof_char, # (frame_length-10)*fft_length/2 - fft_length/4 -1 + timingmetric_shift) delayed_timesync = blocks.delay( gr.sizeof_char, (frame_length - 10) * fft_length / 2 - fft_length / 4 + int(2.5 * fft_length) + timingmetric_shift - 1) #delayed_timesync = blocks.delay(gr.sizeof_char, #(frame_length-10)*fft_length/2 - fft_length/4 + int(3.5*fft_length) + timingmetric_shift-1) self.connect(peak_detector, delayed_timesync) self.block_sampler = ofdm.vector_sampler( gr.sizeof_gr_complex, fft_length / 2 * frame_length) self.connect(self.input, self.block_sampler) self.connect(delayed_timesync, (self.block_sampler, 1)) #log_to_file( self, self.block_sampler, "data/fbmc_block_sampler.compl" ) vt2s = blocks.vector_to_stream(gr.sizeof_gr_complex * fft_length, frame_length / 2) self.connect(self.block_sampler, vt2s) #terminate_stream(self,ofdm_blocks) ofdm_blocks = vt2s ''' # TODO: dynamic solution vt2s = blocks.vector_to_stream(gr.sizeof_gr_complex*block_length/2, frame_length) self.connect(self.block_sampler,vt2s) terminate_stream(self,( sync, 0 )) ofdm_blocks = vt2s ''' ##stv_help = blocks.stream_to_vector(gr.sizeof_gr_complex*config.fft_length/2, 1) #stv_help = blocks.vector_to_stream(gr.sizeof_gr_complex*config.fft_length/2, 2) ##self.connect(ofdm_blocks, stv_help) ##ofdm_blocks = stv_help #ofdm_blocks = ( sync, 0 ) #frame_start = ( sync, 1 ) #log_to_file(self, frame_start, "data/frame_start.compl") #log_to_file( self, sc_metric, "data/sc_metric.float" ) #log_to_file( self, gi_metric, "data/gi_metric.float" ) #log_to_file( self, (sync,1), "data/sync.float" ) # log_to_file(self,ofdm_blocks,"data/ofdm_blocks_original.compl") frame_start = [0] * int(frame_length / 2) frame_start[0] = 1 frame_start = blocks.vector_source_b(frame_start, True) #frame_start2 = [0]*int(frame_length/2) #frame_start2[0] = 1 #frame_start2 = blocks.vector_source_b(frame_start2,True) 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, fft_length) #discard_cp = ofdm.vector_mask(block_length,cp_length,fft_length,[]) #serial_to_parallel = blocks.stream_to_vector(gr.sizeof_gr_complex,block_length) #discard_cp = ofdm.vector_mask(block_length,cp_length,fft_length,[]) #self.connect( rx_input,serial_to_parallel) #self.connect( rx_input, blocks.delay(gr.sizeof_gr_complex,0),serial_to_parallel) initial_skip = blocks.skiphead(gr.sizeof_gr_complex, 2 * fft_length) self.connect(rx_input, initial_skip) if options.ideal is False and options.ideal2 is False: self.connect(initial_skip, serial_to_parallel) ofdm_blocks = serial_to_parallel else: ofdm_blocks = initial_skip #self.connect( rx_input, serial_to_parallel, discard_cp ) frame_start = [0] * int(frame_length / 2) frame_start[0] = 1 frame_start = blocks.vector_source_b(frame_start, True) #frame_start2 = [0]*int(frame_length/2) #frame_start2[0] = 1 #frame_start2 = blocks.vector_source_b(frame_start2,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, 2, 1, config.fbmc) sampler_preamble = ofdm.vector_sampler( gr.sizeof_gr_complex * fft_length, 1) self.connect(ofdm_blocks, (sampler_preamble, 0)) self.connect(frame_start, blocks.delay(gr.sizeof_char, 1), (sampler_preamble, 1)) self.connect(sampler_preamble, morelli_foe) freq_offset = morelli_foe print "FRAME_LENGTH: ", frame_length #log_to_file( self, sampler_preamble, "data/sampler_preamble.compl" ) #log_to_file( self, rx_input, "data/rx_input.compl" ) #log_to_file( self, ofdm_blocks, "data/rx_input.compl" ) #Extracting preamble for SNR estimation #fft_snr_est = fft_blocks.fft_vcc( fft_length, True, [], True ) #self.connect( sampler_preamble, blocks.stream_to_vector(gr.sizeof_gr_complex*fft_length/2, 2), fft_snr_est ) ## Remove virtual subcarriers #if fft_length > data_subc: #subcarrier_mask_snr_est = ofdm.vector_mask( fft_length, virtual_subc/2, # total_subc, [] ) #self.connect( fft_snr_est, subcarrier_mask_snr_est ) #fft_snr_est = subcarrier_mask_snr_est #log_to_file(self, ofdm_blocks, "data/vec_mask.compl") ## Least Squares estimator for channel transfer function (CTF) #self.connect( fft_snr_est, out_snr_pream ) # Connecting to output ## 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.connect(freq_offset, 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, 0) #freq_shift = blocks.multiply_cc() #norm_freq = -0.1 / config.fft_length #freq_off = self.freq_off_src = analog.sig_source_c(1.0, analog.GR_SIN_WAVE, norm_freq, 1.0, 0.0 ) self.connect(ofdm_blocks, (frequency_shift, 0)) self.connect(freq_offset, (frequency_shift, 1)) self.connect(frame_start, blocks.delay(gr.sizeof_char, 0), (frequency_shift, 2)) #self.connect(frequency_shift,s2help) #ofdm_blocks = s2help ofdm_blocks = frequency_shift #terminate_stream(self, frequency_shift) #inner_pb_filt = self._inner_pilot_block_filter = fbmc_inner_pilot_block_filter() #self.connect(ofdm_blocks,inner_pb_filt) #self.connect(frame_start,(inner_pb_filt,1)) #self.connect((inner_pb_filt,1),blocks.null_sink(gr.sizeof_char)) #ofdm_blocks = (inner_pb_filt,0) overlap_ser_to_par = ofdm.fbmc_overlapping_serial_to_parallel_cvc( fft_length) self.separate_vcvc = ofdm.fbmc_separate_vcvc(fft_length, 2) self.polyphase_network_vcvc_1 = ofdm.fbmc_polyphase_network_vcvc( fft_length, 4, 4 * fft_length - 1, True) self.polyphase_network_vcvc_2 = ofdm.fbmc_polyphase_network_vcvc( fft_length, 4, 4 * fft_length - 1, True) self.junction_vcvc = ofdm.fbmc_junction_vcvc(fft_length, 2) self.fft_fbmc = fft_blocks.fft_vcc(fft_length, True, [], True) print "config.training_data.fbmc_no_preambles: ", config.training_data.fbmc_no_preambles #center_preamble = [1, -1j, -1, 1j] #self.preamble = preamble = [0]*total_subc + center_preamble*((int)(total_subc/len(center_preamble)))+[0]*total_subc self.preamble = preamble = config.training_data.fbmc_pilotsym_fd_list #inv_preamble = 1. / numpy.array(self.preamble) #print "self.preamble: ", len(self.preamble #print "inv_preamble: ", list(inv_preamble) #print "self.preamble", self.preamble #print "self.preamble2", self.preamble2 self.multiply_const = ofdm.multiply_const_vcc( ([1.0 / (math.sqrt(fft_length * 0.6863))] * total_subc)) self.beta_multiplier_vcvc = ofdm.fbmc_beta_multiplier_vcvc( total_subc, 4, 4 * fft_length - 1, 0) #self.skiphead = blocks.skiphead(gr.sizeof_gr_complex*total_subc, 2*4-1-1) self.skiphead = blocks.skiphead(gr.sizeof_gr_complex * total_subc, 2) self.skiphead_1 = blocks.skiphead(gr.sizeof_gr_complex * total_subc, 0) #self.remove_preamble_vcvc = ofdm.fbmc_remove_preamble_vcvc(total_subc, config.frame_data_part/2, config.training_data.fbmc_no_preambles*total_subc/2) #self.subchannel_processing_vcvc = ofdm.fbmc_subchannel_processing_vcvc(total_subc, config.frame_data_part, 1, 2, 1, 0) self.oqam_postprocessing_vcvc = ofdm.fbmc_oqam_postprocessing_vcvc( total_subc, 0, 0) #log_to_file( self, ofdm_blocks, "data/PRE_FBMC.compl" ) #log_to_file( self, self.fft_fbmc, "data/FFT_FBMC.compl" ) if options.ideal is False and options.ideal2 is False: self.subchannel_processing_vcvc = ofdm.fbmc_subchannel_processing_vcvc( total_subc, config.frame_data_part, 3, 2, 1, 0) help2 = blocks.keep_one_in_n(gr.sizeof_gr_complex * total_subc, frame_length) self.connect((self.subchannel_processing_vcvc, 1), help2) #log_to_file( self, self.subchannel_processing_vcvc, "data/fbmc_subc.compl" ) #terminate_stream(self, help2) if options.ideal is False and options.ideal2 is False: self.connect( ofdm_blocks, blocks.vector_to_stream(gr.sizeof_gr_complex, fft_length), overlap_ser_to_par) else: self.connect(ofdm_blocks, overlap_ser_to_par) self.connect(overlap_ser_to_par, self.separate_vcvc) self.connect((self.separate_vcvc, 1), (self.polyphase_network_vcvc_2, 0)) self.connect((self.separate_vcvc, 0), (self.polyphase_network_vcvc_1, 0)) self.connect((self.polyphase_network_vcvc_1, 0), (self.junction_vcvc, 0)) self.connect((self.polyphase_network_vcvc_2, 0), (self.junction_vcvc, 1)) self.connect(self.junction_vcvc, self.fft_fbmc) ofdm_blocks = self.fft_fbmc print "config.dc_null: ", config.dc_null if fft_length > data_subc: subcarrier_mask_fbmc = ofdm.vector_mask_dc_null( fft_length, virtual_subc / 2, total_subc, config.dc_null, []) self.connect(ofdm_blocks, subcarrier_mask_fbmc) ofdm_blocks = subcarrier_mask_fbmc #log_to_file(self, ofdm_blocks, "data/vec_mask.compl") ## Least Squares estimator for channel transfer function (CTF) #log_to_file( self, subcarrier_mask, "data/OFDM_Blocks.compl" ) self.connect(ofdm_blocks, self.beta_multiplier_vcvc) ofdm_blocks = self.beta_multiplier_vcvc #self.connect(ofdm_blocks,self.multiply_const) #self.connect(self.multiply_const, (self.skiphead, 0)) self.connect(ofdm_blocks, (self.skiphead, 0)) #log_to_file( self, self.skiphead, "data/fbmc_skiphead_4.compl" ) #self.connect(ofdm_blocks, self.multiply_const) #self.connect(self.multiply_const, self.beta_multiplier_vcvc) #self.connect((self.beta_multiplier_vcvc, 0), (self.skiphead, 0)) if options.ideal or options.ideal2: self.connect((self.skiphead, 0), (self.skiphead_1, 0)) else: self.connect((self.skiphead, 0), (self.subchannel_processing_vcvc, 0)) self.connect((self.subchannel_processing_vcvc, 0), (self.skiphead_1, 0)) #log_to_file( self, self.skiphead, "data/fbmc_subc.compl" ) #self.connect((self.skiphead_1, 0),(self.remove_preamble_vcvc, 0)) #self.connect((self.remove_preamble_vcvc, 0), (self.oqam_postprocessing_vcvc, 0)) #ofdm_blocks = self.oqam_postprocessing_vcvc #log_to_file( self, self.subchannel_processing_vcvc, "data/subc_0.compl" ) #log_to_file( self, (self.subchannel_processing_vcvc,1), "data/subc_1.compl" ) self.connect((self.skiphead_1, 0), (self.oqam_postprocessing_vcvc, 0)) #self.connect((self.oqam_postprocessing_vcvc, 0), (self.remove_preamble_vcvc, 0) ) ofdm_blocks = (self.oqam_postprocessing_vcvc, 0 ) #(self.remove_preamble_vcvc, 0) #log_to_file( self, (self.oqam_postprocessing_vcvc, 0), "data/fbmc_before_remove.compl" ) #log_to_file( self, self.skiphead, "data/SKIP_HEAD_FBMC.compl" ) #log_to_file( self, self.beta_multiplier_vcvc, "data/BETA_REC_FBMC.compl" ) #log_to_file( self, self.oqam_postprocessing_vcvc, "data/REC_OUT_FBMC.compl" ) """ DISABLED OFDM CHANNEL ESTIMATION PREMBLE -> CORRECT LATER to compare FBMC and OFDM channel estimation #TAKING THE CHANNEL ESTIMATION PREAMBLE chest_pre_trigger = blocks.delay( gr.sizeof_char, 3 ) sampled_chest_preamble = ofdm.vector_sampler( gr.sizeof_gr_complex * fft_length/2, 2 ) self.connect( frame_start, chest_pre_trigger ) self.connect( chest_pre_trigger, ( sampled_chest_preamble, 1 ) ) self.connect( frequency_shift, ( sampled_chest_preamble, 0 ) ) #ofdm_blocks = sampled_chest_preamble ## FFT fft = fft_blocks.fft_vcc( fft_length, True, [], True ) self.connect( sampled_chest_preamble, fft ) ofdm_blocks_est = fft log_to_file( self, sampled_chest_preamble, "data/SAMPLED_EST_PREAMBLE.compl" ) log_to_file( self, ofdm_blocks_est, "data/FFT.compl" ) ## Remove virtual subcarriers if fft_length > data_subc: subcarrier_mask = ofdm.vector_mask( fft_length, virtual_subc/2, total_subc, [] ) self.connect( ofdm_blocks_est, subcarrier_mask ) ofdm_blocks_est = subcarrier_mask #log_to_file(self, ofdm_blocks, "data/vec_mask.compl") ## Least Squares estimator for channel transfer function (CTF) log_to_file( self, subcarrier_mask, "data/OFDM_Blocks.compl" ) ## post-FFT processing ## 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 ) ) ## Least Squares estimator for channel transfer function (CTF) 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_estimator = ofdm.multiply_const_vcc( list( inv_preamble_fd ) ) self.connect( ofdm_blocks_est, LS_channel_estimator ) estimated_CTF = LS_channel_estimator terminate_stream(self,estimated_CTF) """ if options.ideal is False and options.ideal2 is False: 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.fbmc_postprocess_CTF_estimate(total_subc) self.connect(help2, ctf_postprocess) #estimated_SNR = ( ctf_postprocess, 0 ) disp_CTF = (ctf_postprocess, 0) #self.connect(estimated_SNR,out_snr_pream) #log_to_file( self, estimated_SNR, "data/fbmc_SNR.float" ) #Disable measured SNR output #terminate_stream(self, estimated_SNR) #self.connect(blocks.vector_source_f([10.0],True) ,out_snr_pream) # 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 ##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 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 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): gr.hier_block2.__init__(self, "fbmc_receive_path", gr.io_signature(1,1,gr.sizeof_gr_complex), gr.io_signature(0,0,0)) print "This is FBMC receive path 1x1" common_options.defaults(options) config = self.config = station_configuration() config.data_subcarriers = dsubc = options.subcarriers config.cp_length = 0 config.frame_data_blocks = options.data_blocks config._verbose = options.verbose #TODO: update config.fft_length = options.fft_length config.dc_null = options.dc_null config.training_data = default_block_header(dsubc, config.fft_length,config.dc_null,options) config.coding = options.coding config.ber_window = options.ber_window config.periodic_parts = 8 config.frame_id_blocks = 1 # FIXME self._options = copy.copy(options) #FIXME: do we need this? config.fbmc = options.fbmc config.block_length = config.fft_length + config.cp_length config.frame_data_part = config.frame_data_blocks + config.frame_id_blocks config.frame_length = config.training_data.fbmc_no_preambles + 2*config.frame_data_part config.postpro_frame_length = config.frame_data_part + \ config.training_data.no_pilotsyms config.subcarriers = dsubc + \ config.training_data.pilot_subcarriers config.virtual_subcarriers = config.fft_length - config.subcarriers - config.dc_null total_subc = config.subcarriers # check some bounds if config.fft_length < config.subcarriers: raise SystemError, "Subcarrier number must be less than FFT length" if config.fft_length < config.cp_length: raise SystemError, "Cyclic prefix length must be less than FFT length" #self.input = gr.kludge_copy(gr.sizeof_gr_complex) #self.connect( self, self.input ) self.input = self self.ideal = options.ideal self.ideal2 = options.ideal2 ## Inner receiver ## Timing & Frequency Synchronization ## Channel estimation + Equalization ## Phase Tracking for sampling clock frequency offset correction inner_receiver = self.inner_receiver = fbmc_inner_receiver( options, options.log ) self.connect( self.input, inner_receiver ) ofdm_blocks = ( inner_receiver, 2 ) frame_start = ( inner_receiver, 1 ) disp_ctf = ( inner_receiver, 0 ) #self.snr_est_preamble = ( inner_receiver, 3 ) #terminate_stream(self,snr_est_preamble) disp_cfo = ( inner_receiver, 3 ) if self.ideal is False and self.ideal2 is False: self.zmq_probe_freqoff = zeromq.pub_sink(gr.sizeof_float, 1, "tcp://*:5557") self.connect(disp_cfo, self.zmq_probe_freqoff) else: self.connect(disp_cfo, blocks.null_sink(gr.sizeof_float)) # for ID decoder used_id_bits = config.used_id_bits = 8 #TODO: constant in source code! rep_id_bits = config.rep_id_bits = dsubc/used_id_bits #BPSK if options.log: print "rep_id_bits %d" % (rep_id_bits) if dsubc % used_id_bits <> 0: raise SystemError,"Data subcarriers need to be multiple of 10" ## Workaround to avoid periodic structure seed(1) whitener_pn = [randint(0,1) for i in range(used_id_bits*rep_id_bits)] ## NOTE!!! BIG HACK!!! ## first preamble ain't equalized .... ## for Milan's SNR estimator ## Outer Receiver ## Make new inner receiver compatible with old outer receiver ## FIXME: renew outer receiver self.ctf = disp_ctf #frame_sampler = ofdm_frame_sampler(options) frame_sampler = fbmc_frame_sampler(options) self.connect( ofdm_blocks, frame_sampler) self.connect( frame_start, (frame_sampler,1) ) # # ft = [0] * config.frame_length # ft[0] = 1 # # # The next block ensures that only complete frames find their way into # # the old outer receiver. The dynamic frame start trigger is hence # # replaced with a static one, fixed to the frame length. # # frame_sampler = ofdm.vector_sampler( gr.sizeof_gr_complex * total_subc, # config.frame_length ) # self.symbol_output = blocks.vector_to_stream( gr.sizeof_gr_complex * total_subc, # config.frame_length ) # delayed_frame_start = blocks.delay( gr.sizeof_char, config.frame_length - 1 ) # damn_static_frame_trigger = blocks.vector_source_b( ft, True ) # # if options.enable_erasure_decision: # frame_gate = vector_sampler( # gr.sizeof_gr_complex * total_subc * config.frame_length, 1 ) # self.connect( ofdm_blocks, frame_sampler, frame_gate, # self.symbol_output ) # else: # self.connect( ofdm_blocks, frame_sampler, self.symbol_output ) # # self.connect( frame_start, delayed_frame_start, ( frame_sampler, 1 ) ) if options.enable_erasure_decision: frame_gate = frame_sampler.frame_gate self.symbol_output = frame_sampler orig_frame_start = frame_start frame_start = (frame_sampler,1) self.frame_trigger = frame_start #terminate_stream(self, self.frame_trigger) ## Pilot block filter pb_filt = self._pilot_block_filter = fbmc_pilot_block_filter() self.connect(self.symbol_output,pb_filt) self.connect(self.frame_trigger,(pb_filt,1)) self.frame_data_trigger = (pb_filt,1) #self.symbol_output = pb_filt #if options.log: #log_to_file(self, pb_filt, "data/pb_filt_out.compl") if config.fbmc: pda_in = pb_filt else: ## Pilot subcarrier filter ps_filt = self._pilot_subcarrier_filter = pilot_subcarrier_filter() self.connect(self.symbol_output,ps_filt) if options.log: log_to_file(self, ps_filt, "data/ps_filt_out.compl") pda_in = ps_filt ## Workaround to avoid periodic structure # for ID decoder seed(1) whitener_pn = [randint(0,1) for i in range(used_id_bits*rep_id_bits)] if not options.enable_erasure_decision: ## ID Block Filter # Filter ID block, skip data blocks id_bfilt = self._id_block_filter = vector_sampler( gr.sizeof_gr_complex * dsubc, 1 ) if not config.frame_id_blocks == 1: raise SystemExit, "# ID Blocks > 1 not supported" self.connect( pda_in , id_bfilt ) self.connect( self.frame_data_trigger, ( id_bfilt, 1 ) ) # trigger #log_to_file( self, id_bfilt, "data/id_bfilt.compl" ) ## ID Demapper and Decoder, soft decision self.id_dec = self._id_decoder = ofdm.coded_bpsk_soft_decoder( dsubc, used_id_bits, whitener_pn ) self.connect( id_bfilt, self.id_dec ) print "Using coded BPSK soft decoder for ID detection" else: # options.enable_erasure_decision: id_bfilt = self._id_block_filter = vector_sampler( gr.sizeof_gr_complex * total_subc, config.frame_id_blocks ) id_bfilt_trig_delay = 0 for x in range( config.frame_length ): if x in config.training_data.pilotsym_pos: id_bfilt_trig_delay += 1 else: break print "Position of ID block within complete frame: %d" %(id_bfilt_trig_delay) assert( id_bfilt_trig_delay > 0 ) # else not supported id_bfilt_trig = blocks.delay( gr.sizeof_char, id_bfilt_trig_delay ) self.connect( ofdm_blocks, id_bfilt ) self.connect( orig_frame_start, id_bfilt_trig, ( id_bfilt, 1 ) ) self.id_dec = self._id_decoder = ofdm.coded_bpsk_soft_decoder( total_subc, used_id_bits, whitener_pn, config.training_data.shifted_pilot_tones ) self.connect( id_bfilt, self.id_dec ) print "Using coded BPSK soft decoder for ID detection" # The threshold block either returns 1.0 if the llr-value from the # id decoder is below the threshold, else 0.0. Hence we convert this # into chars, 0 and 1, and use it as trigger for the sampler. min_llr = ( self.id_dec, 1 ) erasure_threshold = gr.threshold_ff( 10.0, 10.0, 0 ) # FIXME is it the optimal threshold? erasure_dec = gr.float_to_char() id_gate = vector_sampler( gr.sizeof_short, 1 ) ctf_gate = vector_sampler( gr.sizeof_float * total_subc, 1 ) self.connect( self.id_dec , id_gate ) self.connect( self.ctf, ctf_gate ) self.connect( min_llr, erasure_threshold, erasure_dec ) self.connect( erasure_dec, ( frame_gate, 1 ) ) self.connect( erasure_dec, ( id_gate, 1 ) ) self.connect( erasure_dec, ( ctf_gate, 1 ) ) self.id_dec = self._id_decoder = id_gate self.ctf = ctf_gate print "Erasure decision for IDs is enabled" if options.log: id_dec_f = gr.short_to_float() self.connect(self.id_dec,id_dec_f) log_to_file(self, id_dec_f, "data/id_dec_out.float") if options.log: log_to_file(self, id_bfilt, "data/id_blockfilter_out.compl") # TODO: refactor names if options.log: map_src_f = gr.char_to_float(dsubc) self.connect(map_src,map_src_f) log_to_file(self, map_src_f, "data/map_src_out.float") ## Allocation Control if options.static_allocation: #DEBUG if options.coding: mode = 1 # Coding mode 1-9 bitspermode = [0.5,1,1.5,2,3,4,4.5,5,6] # Information bits per mode bitcount_vec = [(int)(config.data_subcarriers*config.frame_data_blocks*bitspermode[mode-1])] bitloading = mode else: bitloading = 1 bitcount_vec = [config.data_subcarriers*config.frame_data_blocks*bitloading] #bitcount_vec = [config.data_subcarriers*config.frame_data_blocks] self.bitcount_src = blocks.vector_source_i(bitcount_vec,True,1) # 0s for ID block, then data #bitloading_vec = [0]*dsubc+[0]*(dsubc/2)+[2]*(dsubc/2) bitloading_vec = [0]*dsubc+[bitloading]*dsubc bitloading_src = blocks.vector_source_b(bitloading_vec,True,dsubc) power_vec = [1]*config.data_subcarriers power_src = blocks.vector_source_f(power_vec,True,dsubc) else: self.allocation_buffer = ofdm.allocation_buffer(config.data_subcarriers, config.frame_data_blocks, "tcp://"+options.tx_hostname+":3333",config.coding) self.bitcount_src = (self.allocation_buffer,0) bitloading_src = (self.allocation_buffer,1) power_src = (self.allocation_buffer,2) self.connect(self.id_dec, self.allocation_buffer) if options.benchmarking: self.allocation_buffer.set_allocation([4]*config.data_subcarriers,[1]*config.data_subcarriers) if options.log: log_to_file(self, self.bitcount_src, "data/bitcount_src_rx.int") log_to_file(self, bitloading_src, "data/bitloading_src_rx.char") log_to_file(self, power_src, "data/power_src_rx.cmplx") log_to_file(self, self.id_dec, "data/id_dec_rx.short") ## Power Deallocator pda = self._power_deallocator = multiply_frame_fc(config.frame_data_part, dsubc) self.connect(pda_in,(pda,0)) self.connect(power_src,(pda,1)) ## Demodulator # if 0: # ac_vector = [0.0+0.0j]*208 # ac_vector[0] = (2*10**(-0.452)) # ac_vector[3] = (10**(-0.651)) # ac_vector[7] = (10**(-1.151)) # csi_vector_inv=abs(numpy.fft.fft(numpy.sqrt(ac_vector)))**2 # dm_csi = numpy.fft.fftshift(csi_vector_inv) # TODO dm_csi = [1]*dsubc # TODO dm_csi = blocks.vector_source_f(dm_csi,True) ## Depuncturer dp_trig = [0]*(config.frame_data_blocks/2) dp_trig[0] = 1 dp_trig = blocks.vector_source_b(dp_trig,True) # TODO if(options.coding): fo=ofdm.fsm(1,2,[91,121]) if options.interleave: int_object=trellis.interleaver(2000,666) deinterlv = trellis.permutation(int_object.K(),int_object.DEINTER(),1,gr.sizeof_float) demod = self._data_demodulator = generic_softdemapper_vcf(dsubc, config.frame_data_part, config.coding) #self.connect(dm_csi,blocks.stream_to_vector(gr.sizeof_float,dsubc),(demod,2)) if(options.ideal): self.connect(dm_csi,blocks.stream_to_vector(gr.sizeof_float,dsubc),(demod,2)) else: dm_csi_filter = self.dm_csi_filter = filter.single_pole_iir_filter_ff(0.01,dsubc) self.connect(self.ctf, self.dm_csi_filter,(demod,2)) #log_to_file(self, dm_csi_filter, "data/softs_csi.float") #self.connect(dm_trig,(demod,3)) else: demod = self._data_demodulator = generic_demapper_vcb(dsubc, config.frame_data_part) if options.benchmarking: # Do receiver benchmarking until the number of frames x symbols are collected self.connect(pda,blocks.head(gr.sizeof_gr_complex*dsubc, options.N*config.frame_data_blocks),demod) else: self.connect(pda,demod) self.connect(bitloading_src,(demod,1)) if(options.coding): ## Depuncturing if not options.nopunct: depuncturing = depuncture_ff(dsubc,0) frametrigger_bitmap_filter = blocks.vector_source_b([1,0],True) self.connect(bitloading_src,(depuncturing,1)) self.connect(dp_trig,(depuncturing,2)) ## Decoding chunkdivisor = int(numpy.ceil(config.frame_data_blocks/5.0)) print "Number of chunks at Viterbi decoder: ", chunkdivisor decoding = self._data_decoder = ofdm.viterbi_combined_fb(fo,dsubc,-1,-1,2,chunkdivisor,[-1,-1,-1,1,1,-1,1,1],ofdm.TRELLIS_EUCLIDEAN) if options.log and options.coding: log_to_file(self, decoding, "data/decoded.char") if not options.nopunct: log_to_file(self, depuncturing, "data/vit_in.float") if not options.nopunct: if options.interleave: self.connect(demod,deinterlv,depuncturing,decoding) else: self.connect(demod,depuncturing,decoding) else: self.connect(demod,decoding) self.connect(self.bitcount_src, multiply_const_ii(1./chunkdivisor), (decoding,1)) if options.scatterplot or options.scatter_plot_before_phase_tracking: if self.ideal2 is False: scatter_vec_elem = self._scatter_vec_elem = ofdm.vector_element(dsubc,40) scatter_s2v = self._scatter_s2v = blocks.stream_to_vector(gr.sizeof_gr_complex,config.frame_data_blocks) scatter_id_filt = skip(gr.sizeof_gr_complex*dsubc,config.frame_data_blocks) scatter_id_filt.skip_call(0) scatter_trig = [0]*config.frame_data_part scatter_trig[0] = 1 scatter_trig = blocks.vector_source_b(scatter_trig,True) self.connect(scatter_trig,(scatter_id_filt,1)) self.connect(scatter_vec_elem,scatter_s2v) if not options.scatter_plot_before_phase_tracking: print "Enabling Scatterplot for data subcarriers" self.connect(pda,scatter_id_filt,scatter_vec_elem) # Work on this #scatter_sink = ofdm.scatterplot_sink(dsubc) #self.connect(pda,scatter_sink) #self.connect(map_src,(scatter_sink,1)) #self.connect(dm_trig,(scatter_sink,2)) #print "Enabled scatterplot gui interface" self.zmq_probe_scatter = zeromq.pub_sink(gr.sizeof_gr_complex,config.frame_data_blocks, "tcp://*:5560") self.connect(scatter_s2v, blocks.keep_one_in_n(gr.sizeof_gr_complex*config.frame_data_blocks,20), self.zmq_probe_scatter) else: print "Enabling Scatterplot for data before phase tracking" inner_rx = inner_receiver.before_phase_tracking #scatter_sink2 = ofdm.scatterplot_sink(dsubc,"phase_tracking") op = copy.copy(options) op.enable_erasure_decision = False new_framesampler = ofdm_frame_sampler(op) self.connect( inner_rx, new_framesampler ) self.connect( orig_frame_start, (new_framesampler,1) ) new_ps_filter = pilot_subcarrier_filter() new_pb_filter = fbmc_pilot_block_filter() self.connect( (new_framesampler,1), (new_pb_filter,1) ) self.connect( new_framesampler, new_pb_filter, new_ps_filter, scatter_id_filt, scatter_vec_elem ) #self.connect( new_ps_filter, scatter_sink2 ) #self.connect( map_src, (scatter_sink2,1)) #self.connect( dm_trig, (scatter_sink2,2)) if options.log: if(options.coding): log_to_file(self, demod, "data/data_stream_out.float") else: data_f = gr.char_to_float() self.connect(demod,data_f) log_to_file(self, data_f, "data/data_stream_out.float") if options.sfo_feedback: used_id_bits = 8 rep_id_bits = config.data_subcarriers/used_id_bits seed(1) whitener_pn = [randint(0,1) for i in range(used_id_bits*rep_id_bits)] id_enc = ofdm.repetition_encoder_sb(used_id_bits,rep_id_bits,whitener_pn) self.connect( self.id_dec, id_enc ) id_mod = ofdm_bpsk_modulator(dsubc) self.connect( id_enc, id_mod ) id_mod_conj = gr.conjugate_cc(dsubc) self.connect( id_mod, id_mod_conj ) id_mult = blocks.multiply_vcc(dsubc) self.connect( id_bfilt, ( id_mult,0) ) self.connect( id_mod_conj, ( id_mult,1) ) # id_mult_avg = filter.single_pole_iir_filter_cc(0.01,dsubc) # self.connect( id_mult, id_mult_avg ) id_phase = gr.complex_to_arg(dsubc) self.connect( id_mult, id_phase ) log_to_file( self, id_phase, "data/id_phase.float" ) est=ofdm.LS_estimator_straight_slope(dsubc) self.connect(id_phase,est) slope=blocks.multiply_const_ff(1e6/2/3.14159265) self.connect( (est,0), slope ) log_to_file( self, slope, "data/slope.float" ) log_to_file( self, (est,1), "data/offset.float" ) # ------------------------------------------------------------------------ # # Display some information about the setup if config._verbose: self._print_verbage() ## debug logging ## if options.log: # log_to_file(self,self.ofdm_symbols,"data/unequalized_rx_ofdm_symbols.compl") # log_to_file(self,self.ofdm_symbols,"data/unequalized_rx_ofdm_symbols.float",mag=True) fftlen = 256 my_window = window.hamming(fftlen) #.blackmanharris(fftlen) rxs_sampler = vector_sampler(gr.sizeof_gr_complex,fftlen) rxs_sampler_vect = concatenate([[1],[0]*49]) rxs_trigger = blocks.vector_source_b(rxs_sampler_vect.tolist(),True) rxs_window = blocks.multiply_const_vcc(my_window) rxs_spectrum = gr.fft_vcc(fftlen,True,[],True) rxs_mag = gr.complex_to_mag(fftlen) rxs_avg = filter.single_pole_iir_filter_ff(0.01,fftlen) #rxs_logdb = blocks.nlog10_ff(20.0,fftlen,-20*log10(fftlen)) rxs_logdb = gr.kludge_copy( gr.sizeof_float * fftlen ) rxs_decimate_rate = gr.keep_one_in_n(gr.sizeof_float*fftlen,1) self.connect(rxs_trigger,(rxs_sampler,1)) self.connect(self.input,rxs_sampler,rxs_window, rxs_spectrum,rxs_mag,rxs_avg,rxs_logdb, rxs_decimate_rate) log_to_file( self, rxs_decimate_rate, "data/psd_input.float" ) #output branches self.publish_rx_performance_measure()
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): gr.top_block.__init__(self, "fbmc_benchmark") self._bandwidth = options.bandwidth self.servants = [] self._verbose = options.verbose self._options = copy.copy( options ) self.ideal = options.ideal self.ideal2 = options.ideal2 rms_amp = options.rms_amplitude #Disable OFDM channel estimation preamble -> Still experimental options.est_preamble = 0 self._interpolation = 1 f1 = numpy.array([-107,0,445,0,-1271,0,2959,0,-6107,0,11953, 0,-24706,0,82359,262144/2,82359,0,-24706,0, 11953,0,-6107,0,2959,0,-1271,0,445,0,-107], numpy.float64)/262144. print "Software interpolation: %d" % (self._interpolation) bw = 1.0/self._interpolation tb = bw/5 if self._interpolation > 1: self.tx_filter = gr.hier_block2("filter", gr.io_signature(1,1,gr.sizeof_gr_complex), gr.io_signature(1,1,gr.sizeof_gr_complex)) self.tx_filter.connect( self.tx_filter, gr.interp_fir_filter_ccf(2,f1), gr.interp_fir_filter_ccf(2,f1), self.tx_filter ) print "New" else: self.tx_filter = None self.decimation = 1 if self.decimation > 1: bw = 0.5/self.decimation * 1 tb = bw/5 # gain, sampling rate, passband cutoff, stopband cutoff # passband ripple in dB, stopband attenuation in dB # extra taps filt_coeff = optfir.low_pass(1.0, 1.0, bw, bw+tb, 0.1, 60.0, 1) print "Software decimation filter length: %d" % (len(filt_coeff)) self.rx_filter = gr.fir_filter_ccf(self.decimation,filt_coeff) else: self.rx_filter = None self._setup_tx_path(options) self._setup_rx_path(options) self._setup_rpc_manager() config = self.config = station_configuration() if options.imgxfer: self.rxpath.setup_imgtransfer_sink() if not options.no_decoding: self.rxpath.publish_rx_performance_measure() # capture transmitter's stream to disk #self.dst = gr.file_sink(gr.sizeof_gr_complex,options.to_file) self.dst= self.rxpath if options.force_rx_filter: print "Forcing rx filter usage" self.connect( self.rx_filter, self.dst ) self.dst = self.rx_filter if options.ideal or self.ideal2: self._amplifier = ofdm.multiply_const_ccf( 1.0 ) self.connect( self._amplifier, self.dst ) self.dst = self._amplifier self.set_rms_amplitude(rms_amp) if options.measure: self.m = throughput_measure(gr.sizeof_gr_complex) self.connect( self.m, self.dst ) self.dst = self.m if options.snr is not None: if options.berm is not None: #noise_sigma = 0.0001/32767.0 noise_sigma = 380/32767.0#250/32767.0 #380/32767.0 #empirically given, gives the received SNR range of (1:28) for tx amp. range of (500:10000) which is set in rm_ber_measurement.py #check for fading channel else: snr_db = options.snr snr = 10.0**(snr_db/10.0) noise_sigma = sqrt( config.rms_amplitude**2 / snr ) print " Noise St. Dev. %d" % (noise_sigma) awgn_chan = blocks.add_cc() #awgn_noise_src = ofdm.complex_white_noise( 0.0, noise_sigma ) #noise_sigma = 0.000000000001 awgn_noise_src = analog.fastnoise_source_c(analog.GR_GAUSSIAN, noise_sigma, 0, 8192) self.connect( awgn_noise_src, (awgn_chan,1) ) self.connect( awgn_chan,self.dst ) #self.connect( awgn_chan, blocks.skiphead( gr.sizeof_gr_complex, 3* config.fft_length ),self.dst ) self.dst = awgn_chan if options.freqoff is not None: freq_off = self.freq_off = channel.freq_offset(options.freqoff ) dst = self.dst self.connect(freq_off, dst) self.dst = freq_off self.rpc_mgr_tx.add_interface("set_freq_offset",self.freq_off.set_freqoff) #log_to_file( self, self.freq_off, "data/TRANSMITTER_OUT.compl" ) if options.multipath: if options.itu_channel: self.fad_chan = channel.itpp_channel(options.bandwidth) self.rpc_mgr_tx.add_interface("set_channel_profile",self.fad_chan.set_channel_profile) else: #self.fad_chan = filter.fir_filter_ccc(1,[1.0,0.0,2e-1+0.1j,1e-4-0.04j]) # filter coefficients for the lab exercise self.fad_chan = filter.fir_filter_ccc(1,[0,0,0.3267,0.8868,0.3267]) self.connect(self.fad_chan, self.dst) self.dst = self.fad_chan if options.samplingoffset is not None: soff = options.samplingoffset interp = moms(1000000*(1.0+soff),1000000) self.connect( interp, self.dst ) self.dst = interp if options.record: log_to_file( self, interp, "data/interp_out.compl" ) tmm =blocks.throttle(gr.sizeof_gr_complex,1e6) self.connect( tmm, self.dst ) self.dst = tmm if options.force_tx_filter: print "Forcing tx filter usage" self.connect( self.tx_filter, self.dst ) self.dst = self.tx_filter if options.record: log_to_file( self, self.txpath, "data/txpath_out.compl" ) if options.scatterplot: print "Scatterplot enabled" self.connect( self.txpath,self.dst ) #log_to_file( self, self.txpath, "data/fbmc_rx_input.compl" ) print "Hit Strg^C to terminate" print "Hit Strg^C to terminate" # Display some information about the setup if self._verbose: self._print_verbage()
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, options): gr.hier_block2.__init__(self, "transmit_path", gr.io_signature(0, 0, 0), gr.io_signature(1, 1, gr.sizeof_gr_complex)) common_options.defaults(options) config = self.config = station_configuration() config.data_subcarriers = options.subcarriers config.cp_length = options.cp_length config.frame_data_blocks = options.data_blocks config._verbose = options.verbose config.fft_length = options.fft_length config.dc_null = options.dc_null config.training_data = default_block_header(config.data_subcarriers, config.fft_length, config.dc_null, options) config.coding = options.coding config.bandwidth = options.bandwidth config.gui_frame_rate = options.gui_frame_rate config.fbmc = options.fbmc config.frame_id_blocks = 1 # FIXME # digital rms amplitude sent to USRP rms_amp = options.rms_amplitude self._options = copy.copy(options) config.block_length = config.fft_length + config.cp_length config.frame_data_part = config.frame_data_blocks + config.frame_id_blocks config.frame_length = config.frame_data_part + \ config.training_data.no_pilotsyms config.subcarriers = config.data_subcarriers + \ config.training_data.pilot_subcarriers config.virtual_subcarriers = config.fft_length - config.subcarriers - config.dc_null # default values if parameters not set if rms_amp is None: rms_amp = math.sqrt(config.subcarriers) config.rms_amplitude = rms_amp # check some bounds if config.fft_length < config.subcarriers: raise SystemError, "Subcarrier number must be less than FFT length" if config.fft_length < config.cp_length: raise SystemError, "Cyclic prefix length must be less than FFT length" ## shortcuts blen = config.block_length flen = config.frame_length dsubc = config.data_subcarriers vsubc = config.virtual_subcarriers # Adaptive Transmitter Concept used_id_bits = config.used_id_bits = 8 #TODO: no constant in source code rep_id_bits = config.rep_id_bits = config.data_subcarriers / used_id_bits #BPSK if config.data_subcarriers % used_id_bits <> 0: raise SystemError, "Data subcarriers need to be multiple of %d" % ( used_id_bits) # adapt OFDM frame rate and GUI display frame rate self.keep_frame_n = int( 1.0 / (config.frame_length * (config.cp_length + config.fft_length) / config.bandwidth) / config.gui_frame_rate) ## Allocation Control self.allocation_src = allocation_src( config.data_subcarriers, config.frame_data_blocks, config.coding, "tcp://*:3333", "tcp://" + options.rx_hostname + ":3322") if options.static_allocation: #DEBUG # how many bits per subcarrier if options.coding: mode = 1 # Coding mode 1-9 bitspermode = [0.5, 1, 1.5, 2, 3, 4, 4.5, 5, 6] # Information bits per mode modulbitspermode = [1, 2, 2, 4, 4, 6, 6, 6, 8] # Coding bits per mode bitcount_vec = [ (int)(config.data_subcarriers * config.frame_data_blocks * bitspermode[mode - 1]) ] modul_bitcount_vec = [ config.data_subcarriers * config.frame_data_blocks * modulbitspermode[mode - 1] ] bitcount_src = blocks.vector_source_i(bitcount_vec, True, 1) modul_bitcount_src = blocks.vector_source_i( modul_bitcount_vec, True, 1) bitloading = mode else: bitloading = 1 bitcount_vec = [ config.data_subcarriers * config.frame_data_blocks * bitloading ] bitcount_src = blocks.vector_source_i(bitcount_vec, True, 1) modul_bitcount_src = bitcount_src # id's for frames id_vec = range(0, 256) id_src = blocks.vector_source_s(id_vec, True, 1) # bitloading for ID symbol and then once for data symbols #bitloading_vec = [1]*dsubc+[0]*(dsubc/2)+[2]*(dsubc/2) #test_allocation = [bitloading]*(int)(config.data_subcarriers/8)+ [0]*(int)(config.data_subcarriers/4*3) + [bitloading]*(int)(config.data_subcarriers/8) #bitloading_vec = [1]*dsubc+[bitloading]*dsubc test_allocation = [bitloading] * dsubc bitloading_vec = [bitloading] * dsubc + test_allocation bitloading_src = blocks.vector_source_b(bitloading_vec, True, dsubc) # bitcount for frames #bitcount_vec = [config.data_subcarriers*config.frame_data_blocks*bitloading] bitcount_vec = [config.frame_data_blocks * sum(test_allocation)] bitcount_src = blocks.vector_source_i(bitcount_vec, True, 1) # power loading, here same for all symbols #power_vec = [1]*(int)(config.data_subcarriers/8)+ [0]*(int)(config.data_subcarriers/4*3) + [1]*(int)(config.data_subcarriers/8) power_vec = [1] * config.data_subcarriers power_src = blocks.vector_source_f(power_vec, True, dsubc) # mux control stream to mux id and data bits mux_vec = [0] * dsubc + [1] * bitcount_vec[0] mux_ctrl = blocks.vector_source_b(mux_vec, True, 1) else: id_src = (self.allocation_src, 0) bitcount_src = (self.allocation_src, 4) bitloading_src = (self.allocation_src, 2) power_src = (self.allocation_src, 1) if options.coding: modul_bitcount_src = (self.allocation_src, 5) else: modul_bitcount_src = bitcount_src mux_ctrl = ofdm.tx_mux_ctrl(dsubc) self.connect(modul_bitcount_src, mux_ctrl) #Initial allocation self.allocation_src.set_allocation([2] * config.data_subcarriers, [1] * config.data_subcarriers) self.allocation_src.set_allocation_scheme(0) if options.benchmarking: self.allocation_src.set_allocation( [4] * config.data_subcarriers, [1] * config.data_subcarriers) if options.lab_special_case: self.allocation_src.set_allocation( [0] * (config.data_subcarriers / 4) + [2] * (config.data_subcarriers / 2) + [0] * (config.data_subcarriers / 4), [1] * config.data_subcarriers) if options.log: log_to_file(self, id_src, "data/id_src.short") log_to_file(self, bitcount_src, "data/bitcount_src.int") log_to_file(self, bitloading_src, "data/bitloading_src.char") log_to_file(self, power_src, "data/power_src.cmplx") ## GUI probe output zmq_probe_bitloading = zeromq.pub_sink(gr.sizeof_char, dsubc, "tcp://*:4445") # also skip ID symbol bitloading with keep_one_in_n (side effect) # factor 2 for bitloading because we have two vectors per frame, one for id symbol and one for all payload/data symbols # factor config.frame_data_part for power because there is one vector per ofdm symbol per frame self.connect(bitloading_src, blocks.keep_one_in_n(gr.sizeof_char * dsubc, 2 * 40), zmq_probe_bitloading) zmq_probe_power = zeromq.pub_sink(gr.sizeof_float, dsubc, "tcp://*:4444") #self.connect(power_src, blocks.keep_one_in_n(gr.sizeof_gr_complex*dsubc,40), blocks.complex_to_real(dsubc), zmq_probe_power) self.connect(power_src, blocks.keep_one_in_n(gr.sizeof_float * dsubc, 40), zmq_probe_power) ## Workaround to avoid periodic structure seed(1) whitener_pn = [ randint(0, 1) for i in range(used_id_bits * rep_id_bits) ] ## ID Encoder id_enc = self._id_encoder = repetition_encoder_sb( used_id_bits, rep_id_bits, whitener_pn) self.connect(id_src, id_enc) if options.log: id_enc_f = gr.char_to_float() self.connect(id_enc, id_enc_f) log_to_file(self, id_enc_f, "data/id_enc_out.float") ## Reference Data Source ber_ref_src = ber_reference_source(self._options) self.connect(id_src, (ber_ref_src, 0)) self.connect(bitcount_src, (ber_ref_src, 1)) if options.log: log_to_file(self, ber_ref_src, "data/ber_rec_src_tx.char") if options.log: log_to_file(self, btrig, "data/bitmap_trig.char") ## Bitmap Update Trigger for puncturing if not options.nopunct: bmaptrig_stream_puncturing = [ 1 ] + [0] * (config.frame_data_blocks / 2 - 1) btrig_puncturing = self._bitmap_trigger_puncturing = blocks.vector_source_b( bmaptrig_stream_puncturing, True) bmapsrc_stream_puncturing = [1] * dsubc + [2] * dsubc bsrc_puncturing = self._bitmap_src_puncturing = blocks.vector_source_b( bmapsrc_stream_puncturing, True, dsubc) if options.log and options.coding and not options.nopunct: log_to_file(self, btrig_puncturing, "data/bitmap_trig_puncturing.char") ## Frame Trigger ftrig_stream = [1] + [0] * (config.frame_data_part - 1) ftrig = self._frame_trigger = blocks.vector_source_b( ftrig_stream, True) ## Data Multiplexer # Input 0: control stream # Input 1: encoded ID stream # Inputs 2..n: data streams dmux = self._data_multiplexer = stream_controlled_mux_b() self.connect(mux_ctrl, (dmux, 0)) self.connect(id_enc, (dmux, 1)) if options.coding: fo = trellis.fsm(1, 2, [91, 121]) encoder = self._encoder = trellis.encoder_bb(fo, 0) unpack = self._unpack = blocks.unpack_k_bits_bb(2) self.connect(ber_ref_src, encoder, unpack) if options.interleave: int_object = trellis.interleaver(2000, 666) interlv = trellis.permutation(int_object.K(), int_object.INTER(), 1, gr.sizeof_char) if not options.nopunct: bmaptrig_stream_puncturing = [ 1 ] + [0] * (config.frame_data_blocks / 2 - 1) btrig_puncturing = self._bitmap_trigger_puncturing = blocks.vector_source_b( bmaptrig_stream_puncturing, True) puncturing = self._puncturing = puncture_bb( config.data_subcarriers) self.connect(bitloading_src, (puncturing, 1)) self.connect(self._bitmap_trigger_puncturing, (puncturing, 2)) self.connect(unpack, puncturing) last_block = puncturing if options.interleave: self.connect(last_block, interlv) last_block = interlv if options.benchmarking: self.connect(last_block, blocks.head(gr.sizeof_char, options.N), (dmux, 2)) else: self.connect(last_block, (dmux, 2)) else: if options.benchmarking: self.connect(unpack, blocks.head(gr.sizeof_char, options.N), (dmux, 2)) else: self.connect(unpack, (dmux, 2)) else: if options.benchmarking: self.connect(ber_ref_src, blocks.head(gr.sizeof_char, options.N), (dmux, 2)) else: self.connect(ber_ref_src, (dmux, 2)) if options.log: dmux_f = gr.char_to_float() self.connect(dmux, dmux_f) log_to_file(self, dmux_f, "data/dmux_out.float") ## Modulator mod = self._modulator = generic_mapper_bcv(config.data_subcarriers, config.coding, config.frame_data_part) self.connect(dmux, (mod, 0)) self.connect(bitloading_src, (mod, 1)) #log_to_file(self, mod, "data/mod_out.compl") if options.log: log_to_file(self, mod, "data/mod_out.compl") modi = blocks.complex_to_imag(config.data_subcarriers) modr = blocks.complex_to_real(config.data_subcarriers) self.connect(mod, modi) self.connect(mod, modr) log_to_file(self, modi, "data/mod_imag_out.float") log_to_file(self, modr, "data/mod_real_out.float") ## Power allocator pa = self._power_allocator = multiply_frame_fc(config.frame_data_part, config.data_subcarriers) self.connect(mod, (pa, 0)) self.connect(power_src, (pa, 1)) if options.log: log_to_file(self, pa, "data/pa_out.compl") # Standard Transmitter Parts ## Pilot subcarriers psubc = self._pilot_subcarrier_inserter = pilot_subcarrier_inserter() self.connect(pa, psubc) if options.log: log_to_file(self, psubc, "data/psubc_out.compl") ## Add virtual subcarriers if config.fft_length > config.subcarriers: vsubc = self._virtual_subcarrier_extender = \ vector_padding_dc_null(config.subcarriers, config.fft_length,config.dc_null) self.connect(psubc, vsubc) else: vsubc = self._virtual_subcarrier_extender = psubc if options.log: log_to_file(self, vsubc, "data/vsubc_out.compl") ## IFFT, no window, block shift ifft = self._ifft = fft_blocks.fft_vcc(config.fft_length, False, [], True) self.connect(vsubc, ifft) if options.log: log_to_file(self, ifft, "data/ifft_out.compl") ## Pilot blocks (preambles) pblocks = self._pilot_block_inserter = pilot_block_inserter(5, False) self.connect(ifft, pblocks) if options.log: log_to_file(self, pblocks, "data/pilot_block_ins_out.compl") ## Cyclic Prefix cp = self._cyclic_prefixer = cyclic_prefixer(config.fft_length, config.block_length) self.connect(pblocks, cp) lastblock = cp if options.log: log_to_file(self, cp, "data/cp_out.compl") #Digital Amplifier for resource allocation #if not options.coding: rep = blocks.repeat(gr.sizeof_gr_complex, config.frame_length * config.block_length) amp = blocks.multiply_cc() self.connect(lastblock, (amp, 0)) self.connect((self.allocation_src, 3), rep, (amp, 1)) lastblock = amp ## Digital Amplifier #amp = self._amplifier = gr.multiply_const_cc(1) amp = self._amplifier = ofdm.multiply_const_ccf(1.0) self.connect(lastblock, amp) self.set_rms_amplitude(rms_amp) if options.log: log_to_file(self, amp, "data/amp_tx_out.compl") ## Tx parameters bandwidth = options.bandwidth or 2e6 bits = 8 * config.data_subcarriers * config.frame_data_blocks # max. QAM256 samples_per_frame = config.frame_length * config.block_length tb = samples_per_frame / bandwidth # set dummy carrier frequency if none available due to baseband mode if (options.tx_freq is None): options.tx_freq = 0.0 self.tx_parameters = {'carrier_frequency':options.tx_freq/1e9,'fft_size':config.fft_length, 'cp_size':config.cp_length \ , 'subcarrier_spacing':options.bandwidth/config.fft_length/1e3 \ , 'data_subcarriers':config.data_subcarriers, 'bandwidth':options.bandwidth/1e6 \ , 'frame_length':config.frame_length \ , 'symbol_time':(config.cp_length + config.fft_length)/options.bandwidth*1e6, 'max_data_rate':(bits/tb)/1e6} ## Setup Output self.connect(amp, self) # Display some information about the setup if config._verbose: self._print_verbage()
def __init__(self, options): gr.top_block.__init__(self, "ofdm_mrrc_benchmark") ##self._tx_freq = options.tx_freq # tranmitter's center frequency ##self._tx_subdev_spec = options.tx_subdev_spec # daughterboard to use ##self._fusb_block_size = options.fusb_block_size # usb info for USRP ##self._fusb_nblocks = options.fusb_nblocks # usb info for USRP ##self._which = options.which_usrp self._bandwidth = options.bandwidth self.servants = [] self._verbose = options.verbose ##self._interface = options.interface ##self._mac_addr = options.mac_addr self._options = copy.copy(options) self._interpolation = 1 f1 = numpy.array([ -107, 0, 445, 0, -1271, 0, 2959, 0, -6107, 0, 11953, 0, -24706, 0, 82359, 262144 / 2, 82359, 0, -24706, 0, 11953, 0, -6107, 0, 2959, 0, -1271, 0, 445, 0, -107 ], numpy.float64) / 262144. print "Software interpolation: %d" % (self._interpolation) bw = 1.0 / self._interpolation tb = bw / 5 if self._interpolation > 1: self.tx_filter = gr.hier_block2( "filter", gr.io_signature(1, 1, gr.sizeof_gr_complex), gr.io_signature(1, 1, gr.sizeof_gr_complex)) self.tx_filter2 = gr.hier_block2( "filter", gr.io_signature(1, 1, gr.sizeof_gr_complex), gr.io_signature(1, 1, gr.sizeof_gr_complex)) self.tx_filter.connect(self.tx_filter, gr.interp_fir_filter_ccf(2, f1), gr.interp_fir_filter_ccf(2, f1), self.tx_filter) self.tx_filter2.connect(self.tx_filter2, gr.interp_fir_filter_ccf(2, f1), gr.interp_fir_filter_ccf(2, f1), self.tx_filter2) print "New" else: self.tx_filter = None self.tx_filter2 = None self.decimation = 1 if self.decimation > 1: bw = 0.5 / self.decimation * 1 tb = bw / 5 # gain, sampling rate, passband cutoff, stopband cutoff # passband ripple in dB, stopband attenuation in dB # extra taps filt_coeff = optfir.low_pass(1.0, 1.0, bw, bw + tb, 0.1, 60.0, 1) print "Software decimation filter length: %d" % (len(filt_coeff)) self.rx_filter = gr.fir_filter_ccf(self.decimation, filt_coeff) self.rx_filter2 = gr.fir_filter_ccf(self.decimation, filt_coeff) else: self.rx_filter = None self.rx_filter2 = None ## if not options.from_file is None: ## # sent captured file to usrp ## self.src = gr.file_source(gr.sizeof_gr_complex,options.from_file) ## self._setup_usrp_sink() ## if hasattr(self, "filter"): ## self.connect(self.src,self.filter,self.u) #,self.filter ## else: ## self.connect(self.src,self.u) ## ## return self._setup_tx_path(options) self._setup_rx_path(options) self._setup_rpc_manager() config = self.config = station_configuration() #self.enable_txfreq_adjust("txfreq") if options.imgxfer: self.rxpath.setup_imgtransfer_sink() if not options.no_decoding: self.rxpath.publish_rx_performance_measure() self.dst = (self.rxpath, 0) self.dst2 = (self.rxpath, 1) if options.force_rx_filter: print "Forcing rx filter usage" self.connect(self.rx_filter, self.dst) self.connect(self.rx_filter2, self.dst2) self.dst = self.rx_filter self.dst2 = self.rx_filter2 if options.measure: self.m = throughput_measure(gr.sizeof_gr_complex) self.m2 = throughput_measure(gr.sizeof_gr_complex) self.connect(self.m, self.dst) self.connect(self.m2, self.dst2) self.dst = self.m self.dst2 = self.m2 if options.snr is not None: if options.berm is not None: noise_sigma = 380 / 32767.0 #empirically given, gives the received SNR range of (1:28) for tx amp. range of (500:10000) which is set in rm_ber_measurement.py print " Noise St. Dev. %f" % (noise_sigma ) #check for fading channel else: snr_db = options.snr snr = 10.0**(snr_db / 10.0) noise_sigma = sqrt(config.rms_amplitude**2 / snr) print " Noise St. Dev. %f" % (noise_sigma) awgn_chan = blocks.add_cc() awgn_chan2 = blocks.add_cc() awgn_noise_src = analog.fastnoise_source_c(analog.GR_GAUSSIAN, noise_sigma, 0, 8192) awgn_noise_src2 = analog.fastnoise_source_c( analog.GR_GAUSSIAN, noise_sigma * 2, 0, 2192) self.connect(awgn_chan, self.dst) self.connect(awgn_chan2, self.dst2) self.connect(awgn_noise_src, (awgn_chan, 1)) self.connect(awgn_noise_src2, (awgn_chan2, 1)) self.dst = awgn_chan self.dst2 = awgn_chan2 if options.freqoff is not None: freq_off = self.freq_off = channel.freq_offset(options.freqoff) freq_off2 = self.freq_off2 = channel.freq_offset(options.freqoff) dst = self.dst dst2 = self.dst2 self.connect(freq_off, dst) self.connect(freq_off2, dst2) self.dst = freq_off self.dst2 = freq_off2 self.rpc_mgr_tx.add_interface("set_freq_offset", self.freq_off.set_freqoff) self.rpc_mgr_tx.add_interface("set_freq_offset2", self.freq_off2.set_freqoff) if options.multipath: if options.itu_channel: self.fad_chan = channel.itpp_channel(options.bandwidth) #fad_chan.set_norm_doppler( 1e-9 ) #fad_chan.set_LOS( [500.,0,0] ) self.fad_chan2 = channel.itpp_channel(options.bandwidth) self.fad_chan.set_channel_profile(itpp.ITU_Pedestrian_A, 5e-8) self.fad_chan.set_norm_doppler(1e-8) self.fad_chan2.set_channel_profile(itpp.ITU_Pedestrian_A, 5e-8) self.fad_chan2.set_norm_doppler(1e-8) self.rpc_mgr_tx.add_interface( "set_channel_profile", self.fad_chan.set_channel_profile) self.rpc_mgr_tx.add_interface( "set_channel_profile", self.fad_chan2.set_channel_profile) else: fad_chan = filter.fir_filter_ccc( 1, [1.0, 0.0, 2e-1 + 0.1j, 1e-4 - 0.04j]) fad_chan2 = filter.fir_filter_ccc( 1, [1.0, 0.0, 2e-1 + 0.1j, 1e-4 - 0.04j]) self.connect(self.fad_chan, self.dst) self.connect(self.fad_chan2, self.dst2) self.dst = self.fad_chan self.dst2 = self.fad_chan2 if options.samplingoffset is not None: soff = options.samplingoffset interp = moms(1000000 * (1.0 + soff), 1000000) interp2 = moms(1000000 * (1.0 + soff), 1000000) self.connect(interp, self.dst) self.connect(interp2, self.dst2) self.dst = interp self.dst2 = interp2 if options.record: log_to_file(self, interp, "data/interp_out.compl") log_to_file(self, interp2, "data/interp2_out.compl") tmm = blocks.throttle(gr.sizeof_gr_complex, 1e6) #tmm2 =blocks.throttle(gr.sizeof_gr_complex, 1e6) #self.connect( tmm, self.dst ) #self.connect( tmm2, self.dst2 ) #self.dst = tmm #self.dst2 = tmm2 #inter = blocks.interleave(gr.sizeof_gr_complex) #deinter = blocks.deinterleave(gr.sizeof_gr_complex) # Interleaving input/output streams ##self.connect(inter, deinter) #self.connect((deinter,0),self.dst) #self.connect((deinter,1),self.dst2) #self.dst = inter #self.dst2 = (inter,1) if options.force_tx_filter: print "Forcing tx filter usage" self.connect(self.tx_filter, self.dst) self.connect(self.tx_filter2, self.dst2) self.dst = self.tx_filter self.dst2 = self.tx_filter2 if options.record: log_to_file(self, self.txpath, "data/txpath_out.compl") log_to_file(self, self.txpath2, "data/txpath2_out.compl") if options.nullsink: self.connect(gr.null_source(gr.sizeof_gr_complex), self.dst) self.connect(gr.null_source(gr.sizeof_gr_complex), self.dst2) self.dst = gr.null_sink(gr.sizeof_gr_complex) self.dst2 = gr.null_sink(gr.sizeof_gr_complex) self.connect(self.txpath, tmm, self.dst) self.connect(tmm, self.dst2) #self.connect( self.txpath,self.dst2 ) print "Hit Strg^C to terminate" if self._verbose: self._print_verbage()
def __init__(self, options): gr.top_block.__init__(self, "ofdm_benchmark") self._bandwidth = options.bandwidth self.servants = [] self._verbose = options.verbose self._options = copy.copy(options) self.ideal = options.ideal self.ideal2 = options.ideal2 rms_amp = options.rms_amplitude self._interpolation = 1 f1 = numpy.array([ -107, 0, 445, 0, -1271, 0, 2959, 0, -6107, 0, 11953, 0, -24706, 0, 82359, 262144 / 2, 82359, 0, -24706, 0, 11953, 0, -6107, 0, 2959, 0, -1271, 0, 445, 0, -107 ], numpy.float64) / 262144. print "Software interpolation: %d" % (self._interpolation) bw = 1.0 / self._interpolation tb = bw / 5 if self._interpolation > 1: self.tx_filter = gr.hier_block2( "filter", gr.io_signature(1, 1, gr.sizeof_gr_complex), gr.io_signature(1, 1, gr.sizeof_gr_complex)) self.tx_filter.connect(self.tx_filter, gr.interp_fir_filter_ccf(2, f1), gr.interp_fir_filter_ccf(2, f1), self.tx_filter) print "New" else: self.tx_filter = None self.decimation = 1 if self.decimation > 1: bw = 0.5 / self.decimation * 1 tb = bw / 5 # gain, sampling rate, passband cutoff, stopband cutoff # passband ripple in dB, stopband attenuation in dB # extra taps filt_coeff = optfir.low_pass(1.0, 1.0, bw, bw + tb, 0.1, 60.0, 1) print "Software decimation filter length: %d" % (len(filt_coeff)) self.rx_filter = gr.fir_filter_ccf(self.decimation, filt_coeff) else: self.rx_filter = None self._setup_tx_path(options) self._setup_rx_path(options) self._setup_rpc_manager() config = self.config = station_configuration() if options.imgxfer: self.rxpath.setup_imgtransfer_sink() if not options.no_decoding: self.rxpath.publish_rx_performance_measure() # capture transmitter's stream to disk #self.dst = gr.file_sink(gr.sizeof_gr_complex,options.to_file) self.dst = self.rxpath if options.force_rx_filter: print "Forcing rx filter usage" self.connect(self.rx_filter, self.dst) self.dst = self.rx_filter if options.ideal or self.ideal2: self._amplifier = ofdm.multiply_const_ccf(1.0) self.connect(self._amplifier, self.dst) self.dst = self._amplifier self.set_rms_amplitude(rms_amp) if options.measure: self.m = throughput_measure(gr.sizeof_gr_complex) self.connect(self.m, self.dst) self.dst = self.m if options.snr is not None: if options.berm is not None: noise_sigma = 380 / 32767.0 #empirically given, gives the received SNR range of (1:28) for tx amp. range of (500:10000) which is set in rm_ber_measurement.py #check for fading channel else: snr_db = options.snr snr = 10.0**(snr_db / 10.0) noise_sigma = sqrt(config.rms_amplitude**2 / snr) print " Noise St. Dev. %f" % (noise_sigma) awgn_chan = blocks.add_cc() #awgn_noise_src = ofdm.complex_white_noise( 0.0, noise_sigma ) awgn_noise_src = analog.fastnoise_source_c(analog.GR_GAUSSIAN, noise_sigma, 0, 8192) self.connect(awgn_noise_src, (awgn_chan, 1)) self.connect(awgn_chan, self.dst) self.dst = awgn_chan if options.freqoff is not None: freq_off = self.freq_off = channel.freq_offset(options.freqoff) dst = self.dst self.connect(freq_off, dst) self.dst = freq_off self.rpc_mgr_tx.add_interface("set_freq_offset", self.freq_off.set_freqoff) if options.multipath: if options.itu_channel: self.fad_chan = channel.itpp_channel(options.bandwidth) self.rpc_mgr_tx.add_interface( "set_channel_profile", self.fad_chan.set_channel_profile) self.rpc_mgr_tx.add_interface("set_norm_doppler", self.fad_chan.set_norm_doppler) else: #self.fad_chan = filter.fir_filter_ccc(1,[1.0,0.0,2e-1+0.1j,1e-4-0.04j]) # filter coefficients for the lab exercise self.fad_chan = filter.fir_filter_ccc(1, [0.3267, 0.8868, 0.3267]) #self.fad_chan = filter.fir_filter_ccc(1,[0,0,0.1,0.2,0.01,0.3])#0.3267,0.8868,0.3267]) #self.fad_chan = channels.selective_fading_model(5, 0.1, False, 1, -1, [0, 0, 0], [0.3267,0.8868,0.3267], 10 ) #self.fad_chan = channels.fading_model(6, 0.05, False); #self.fad_chan = channels.dynamic_channel_model(1000000, 0, 0, 0, 0, 3, 0.01, False, 0, [2e-6,4e-6,8e-6],[0.3267,0.8868,0.3267], 20, 0, 0) self.connect(self.fad_chan, self.dst) self.dst = self.fad_chan if options.samplingoffset is not None: soff = options.samplingoffset interp = moms(1000000 * (1.0 + soff), 1000000) #interp = filter.fractional_resampler_cc(0,1000000*(1.0+soff)/1000000.0) self.connect(interp, self.dst) self.dst = interp if options.record: log_to_file(self, interp, "data/interp_out.compl") tmm = blocks.throttle(gr.sizeof_gr_complex, options.bandwidth) self.connect(tmm, self.dst) self.dst = tmm if options.force_tx_filter: print "Forcing tx filter usage" self.connect(self.tx_filter, self.dst) self.dst = self.tx_filter if options.record: log_to_file(self, self.txpath, "data/txpath_out.compl") if options.scatterplot: print "Scatterplot enabled" self.connect(self.txpath, self.dst) print "Hit Strg^C to terminate" print "Hit Strg^C to terminate" # Display some information about the setup if self._verbose: self._print_verbage()
def __init__ (self, options): gr.top_block.__init__(self, "ofdm_tx") self._tx_freq = options.tx_freq # tranmitter's center frequency self._tx_subdev_spec = options.tx_subdev_spec # daughterboard to use self._fusb_block_size = options.fusb_block_size # usb info for USRP self._fusb_nblocks = options.fusb_nblocks # usb info for USRP self._which = options.which_usrp self._bandwidth = options.bandwidth self.servants = [] self._interface = options.interface self._mac_addr = options.mac_addr self._options = copy.copy( options ) self._interpolation = 1 f1 = numpy.array([-107,0,445,0,-1271,0,2959,0,-6107,0,11953, 0,-24706,0,82359,262144/2,82359,0,-24706,0, 11953,0,-6107,0,2959,0,-1271,0,445,0,-107], numpy.float64)/262144. print "Software interpolation: %d" % (self._interpolation) bw = 0.5/self._interpolation tb = bw/5 if self._interpolation > 1: self.filter = gr.hier_block2("filter", gr.io_signature(1,1,gr.sizeof_gr_complex), gr.io_signature(1,1,gr.sizeof_gr_complex)) self.filter.connect( self.filter, gr.interp_fir_filter_ccf(2,f1), gr.interp_fir_filter_ccf(2,f1), self.filter ) print "New" # # # self.filt_coeff = optfir.low_pass(1.0, 1.0, bw, bw+tb, 0.2, 60.0, 0) # self.filter = gr.interp_fir_filter_ccf(self._interpolation,self.filt_coeff) # print "Software interpolation filter length: %d" % (len(self.filt_coeff)) else: self.filter = None if not options.from_file is None: # sent captured file to usrp self.src = gr.file_source(gr.sizeof_gr_complex,options.from_file) self._setup_usrp_sink() if hasattr(self, "filter"): self.connect(self.src,self.filter,self.u) #,self.filter else: self.connect(self.src,self.u) return self._setup_tx_path(options) config = station_configuration() self.enable_info_tx("info_tx", "pa_user") # if not options.no_cheat: # self.txpath.enable_channel_cheating("channelcheat") self.txpath.enable_txpower_adjust("txpower") self.txpath.publish_txpower("txpower_info") #self.enable_txfreq_adjust("txfreq") if options.nullsink: self.dst = gr.null_sink( gr.sizeof_gr_complex ) else: if not options.to_file is None: # capture transmitter's stream to disk self.dst = gr.file_sink(gr.sizeof_gr_complex,options.to_file) tmp = gr.throttle(gr.sizeof_gr_complex,1e5) self.connect( tmp, self.dst ) self.dst = tmp if options.force_filter: print "Forcing filter usage" self.connect( self.filter, self.dst ) self.dst = self.filter else: # connect transmitter to usrp self._setup_usrp_sink() if options.dyn_freq: self.enable_txfreq_adjust("txfreq") if self.filter is not None: self.connect( self.filter,self.dst ) self.dst = self.filter if options.record: log_to_file( self, self.txpath, "data/txpath_out.compl" ) #self.publish_spectrum( 256 ) if options.measure: self.m = throughput_measure(gr.sizeof_gr_complex) self.connect( self.m, self.dst ) self.dst = self.m if options.samplingoffset is not None: soff = options.samplingoffset interp = gr.fractional_interpolator_cc(0.0,soff) self.connect( interp, self.dst ) self.dst = interp if options.snr is not None: # if options.berm is not None: # noise_sigma = 380 #empirically given, gives the received SNR range of (1:28) for tx amp. range of (500:10000) which is set in rm_ber_measurement.py # #check for fading channel # else: snr_db = options.snr snr = 10.0**(snr_db/10.0) noise_sigma = sqrt( config.rms_amplitude**2 / snr ) print " Noise St. Dev. %d" % (noise_sigma) awgn_chan = gr.add_cc() awgn_noise_src = ofdm.complex_white_noise( 0.0, noise_sigma ) self.connect( awgn_noise_src, (awgn_chan,1) ) self.connect( awgn_chan, self.dst ) self.dst = awgn_chan if options.berm is False: fad_chan = itpp.tdl_channel( ) #[0, -7, -20], [0, 2, 6] #fad_chan.set_norm_doppler( 1e-9 ) #fad_chan.set_LOS( [500.,0,0] ) fad_chan.set_channel_profile( itpp.ITU_Pedestrian_A, 5e-8 ) fad_chan.set_norm_doppler( 1e-8 ) # fad_chan = gr.fir_filter_ccc(1,[1.0,0.0,2e-1+0.1j,1e-4-0.04j]) self.connect( fad_chan, self.dst ) self.dst = fad_chan if options.freqoff is not None: freq_shift = gr.multiply_cc() norm_freq = options.freqoff / config.fft_length freq_off_src = gr.sig_source_c(1.0, gr.GR_SIN_WAVE, norm_freq, 1.0, 0.0 ) self.connect( freq_off_src, ( freq_shift, 1 ) ) dst = self.dst self.connect( freq_shift, dst ) self.dst = freq_shift self.connect( self.txpath, self.dst ) if options.cheat: self.txpath.enable_channel_cheating("channelcheat") print "Hit Strg^C to terminate"
def __init__(self, options): gr.hier_block2.__init__(self, "transmit_path", gr.io_signature(0,0,0), gr.io_signature(2,2,gr.sizeof_gr_complex)) common_options.defaults(options) config = self.config = station_configuration() config.data_subcarriers = options.subcarriers config.cp_length = options.cp_length config.frame_data_blocks = options.data_blocks config._verbose = options.verbose config.fft_length = options.fft_length config.training_data = default_block_header(config.data_subcarriers, config.fft_length,options) config.tx_station_id = options.station_id config.coding = options.coding if config.tx_station_id is None: raise SystemError, "Station ID not set" config.frame_id_blocks = 1 # FIXME # digital rms amplitude sent to USRP rms_amp = options.rms_amplitude self._options = copy.copy(options) self.servants = [] # FIXME config.block_length = config.fft_length + config.cp_length config.frame_data_part = config.frame_data_blocks + config.frame_id_blocks config.frame_length = config.frame_data_part + \ config.training_data.no_pilotsyms config.subcarriers = config.data_subcarriers + \ config.training_data.pilot_subcarriers config.virtual_subcarriers = config.fft_length - config.subcarriers # default values if parameters not set if rms_amp is None: rms_amp = math.sqrt(config.subcarriers) config.rms_amplitude = rms_amp # check some bounds if config.fft_length < config.subcarriers: raise SystemError, "Subcarrier number must be less than FFT length" if config.fft_length < config.cp_length: raise SystemError, "Cyclic prefix length must be less than FFT length" ## shortcuts blen = config.block_length flen = config.frame_length dsubc = config.data_subcarriers vsubc = config.virtual_subcarriers # ------------------------------------------------------------------------ # # Adaptive Transmitter Concept used_id_bits = config.used_id_bits = 8 #TODO: no constant in source code rep_id_bits = config.rep_id_bits = config.data_subcarriers/used_id_bits #BPSK if config.data_subcarriers % used_id_bits <> 0: raise SystemError,"Data subcarriers need to be multiple of %d" % (used_id_bits) ## Control Part if options.debug: self._control = ctrl = static_tx_control(options) print "Statix TX Control used" else: self._control = ctrl = corba_tx_control(options) print "CORBA TX Control used" id_src = (ctrl,0) mux_src = (ctrl,1) map_src = self._map_src = (ctrl,2) pa_src = (ctrl,3) if options.log: id_src_f = gr.short_to_float() self.connect(id_src,id_src_f) log_to_file(self, id_src_f, "data/id_src_out.float") mux_src_f = gr.short_to_float() self.connect(mux_src,mux_src_f) log_to_file(self, mux_src_f, "data/mux_src_out.float") map_src_s = blocks.vector_to_stream(gr.sizeof_char,config.data_subcarriers) map_src_f = gr.char_to_float() self.connect(map_src,map_src_s,map_src_f) ##log_to_file(self, map_src_f, "data/map_src.float") ##log_to_file(self, pa_src, "data/pa_src_out.float") ## Workaround to avoid periodic structure seed(1) whitener_pn = [randint(0,1) for i in range(used_id_bits*rep_id_bits)] ## ID Encoder id_enc = self._id_encoder = repetition_encoder_sb(used_id_bits,rep_id_bits,whitener_pn) self.connect(id_src,id_enc) if options.log: id_enc_f = gr.char_to_float() self.connect(id_enc,id_enc_f) log_to_file(self, id_enc_f, "data/id_enc_out.float") ## Bitmap Update Trigger # TODO #bmaptrig_stream = concatenate([[1, 2],[0]*(config.frame_data_part-7)]) bmaptrig_stream = concatenate([[1, 1],[0]*(config.frame_data_part-2)]) print"bmaptrig_stream = ",bmaptrig_stream btrig = self._bitmap_trigger = blocks.vector_source_b(bmaptrig_stream.tolist(), True) if options.log: log_to_file(self, btrig, "data/bitmap_trig.char") ## Bitmap Update Trigger for puncturing # TODO if not options.nopunct: #bmaptrig_stream_puncturing = concatenate([[1],[0]*(config.frame_data_part-2)]) bmaptrig_stream_puncturing = concatenate([[1],[0]*(config.frame_data_blocks/2-1)]) btrig_puncturing = self._bitmap_trigger_puncturing = blocks.vector_source_b(bmaptrig_stream_puncturing.tolist(), True) bmapsrc_stream_puncturing = concatenate([[1]*dsubc,[2]*dsubc]) bsrc_puncturing = self._bitmap_src_puncturing = blocks.vector_source_b(bmapsrc_stream_puncturing.tolist(), True, dsubc) if options.log and options.coding and not options.nopunct: log_to_file(self, btrig_puncturing, "data/bitmap_trig_puncturing.char") ## Frame Trigger # TODO ftrig_stream = concatenate([[1],[0]*(config.frame_data_part-1)]) ftrig = self._frame_trigger = blocks.vector_source_b(ftrig_stream.tolist(),True) ## Data Multiplexer # Input 0: control stream # Input 1: encoded ID stream # Inputs 2..n: data streams dmux = self._data_multiplexer = stream_controlled_mux_b() self.connect(mux_src,(dmux,0)) self.connect(id_enc,(dmux,1)) self._data_multiplexer_nextport = 2 if options.log: dmux_f = gr.char_to_float() self.connect(dmux,dmux_f) log_to_file(self, dmux_f, "data/dmux_out.float") ## Modulator mod = self._modulator = generic_mapper_bcv(config.data_subcarriers,options.coding) self.connect(dmux,(mod,0)) self.connect(map_src,(mod,1)) self.connect(btrig,(mod,2)) if options.log: log_to_file(self, mod, "data/mod_out.compl") modi = gr.complex_to_imag(config.data_subcarriers) modr = gr.complex_to_real(config.data_subcarriers) self.connect(mod,modi) self.connect(mod,modr) log_to_file(self, modi, "data/mod_imag_out.float") log_to_file(self, modr, "data/mod_real_out.float") ## Power allocator if options.debug: ## static pa = self._power_allocator = power_allocator(config.data_subcarriers) self.connect(mod,(pa,0)) self.connect(pa_src,(pa,1)) else: ## with CORBA control event channel ns_ip = ctrl.ns_ip ns_port = ctrl.ns_port evchan = ctrl.evchan pa = self._power_allocator = corba_power_allocator(dsubc, \ evchan, ns_ip, ns_port, True) self.connect(mod,(pa,0)) self.connect(id_src,(pa,1)) self.connect(ftrig,(pa,2)) if options.log: log_to_file(self, pa, "data/pa_out.compl") ## Pilot subcarriers psubc = self._pilot_subcarrier_inserter = pilot_subcarrier_inserter() self.connect( pa ,psubc ) pilot_subc = config.training_data.shifted_pilot_tones; print "pilot_subc", pilot_subc stc = stc_encoder( config.subcarriers, config.frame_data_blocks, pilot_subc ) self.connect(psubc, stc) if options.log: log_to_file(self, psubc, "data/psubc_out.compl") log_to_file(self, psubc_2, "data/psubc2_out.compl") log_to_file(self, pa, "data/pa.compl") log_to_file(self, ( stc, 0 ), "data/stc_0.compl") log_to_file(self, ( stc, 1 ), "data/stc_1.compl") ## Add virtual subcarriers if config.fft_length > config.subcarriers: vsubc = self._virtual_subcarrier_extender = \ vector_padding(config.subcarriers, config.fft_length) self.connect(stc,vsubc) vsubc_2 = self._virtual_subcarrier_extender_2 = \ vector_padding(config.subcarriers, config.fft_length) self.connect((stc,1),vsubc_2) else: vsubc = self._virtual_subcarrier_extender = psubc vsubc_2 = self._virtual_subcarrier_extender_2 = psubc_2 log_to_file(self, psubc, "data/psubc.compl") log_to_file(self, stc, "data/stc1.compl") log_to_file(self, (stc,1), "data/stc2.compl") if options.log: log_to_file(self, vsubc, "data/vsubc_out.compl") log_to_file(self, vsubc_2, "data/vsubc2_out.compl") ## IFFT, no window, block shift ifft = self._ifft = fft_blocks.fft_vcc(config.fft_length,False,[],True) self.connect(vsubc,ifft) ifft_2 = self._ifft_2 = fft_blocks.fft_vcc(config.fft_length,False,[],True) self.connect(vsubc_2,ifft_2) if options.log: log_to_file(self, ifft, "data/ifft_out.compl") log_to_file(self, ifft_2, "data/ifft2_out.compl") ## Pilot blocks (preambles) pblocks = self._pilot_block_inserter = pilot_block_inserter(1, False) self.connect( ifft, pblocks ) pblocks_2 = self._pilot_block_inserter_2 = pilot_block_inserter( 2, False) self.connect( ifft_2, pblocks_2 ) if options.log: log_to_file(self, pblocks, "data/pilot_block_ins_out.compl") log_to_file(self, pblocks_2, "data/pilot_block_ins2_out.compl") ## Cyclic Prefix cp = self._cyclic_prefixer = cyclic_prefixer(config.fft_length, config.block_length) self.connect( pblocks, cp ) cp_2 = self._cyclic_prefixer_2 = cyclic_prefixer(config.fft_length, config.block_length) self.connect( pblocks_2, cp_2 ) lastblock = cp lastblock_2 = cp_2 if options.log: log_to_file(self, cp, "data/cp_out.compl") log_to_file(self, cp_2, "data/cp2_out.compl") if options.cheat: ## Artificial Channel # kept to compare with previous system achan_ir = concatenate([[1.0],[0.0]*(config.cp_length-1)]) achan = self._artificial_channel = gr.fir_filter_ccc(1,achan_ir) self.connect( lastblock, achan ) lastblock = achan achan_2 = self._artificial_channel_2 = gr.fir_filter_ccc(1,achan_ir) self.connect( lastblock_2, achan_2 ) lastblock_2 = achan_2 ## Digital Amplifier amp = self._amplifier = ofdm.multiply_const_ccf( 1.0/math.sqrt(2) ) self.connect( lastblock, amp ) amp_2 = self._amplifier_2 = ofdm.multiply_const_ccf( 1.0/math.sqrt(2) ) self.connect( lastblock_2, amp_2 ) self.set_rms_amplitude(rms_amp) if options.log: log_to_file(self, amp, "data/amp_tx_out.compl") log_to_file(self, amp_2, "data/amp_tx2_out.compl") ## Setup Output self.connect(amp,(self,0)) self.connect(amp_2,(self,1)) # ------------------------------------------------------------------------ # # Display some information about the setup if config._verbose: self._print_verbage()
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 setup_snr_measurement(self): """ Perform SNR measurement. It uses the data reference from the BER measurement. I.e. if that is not setup, it will be setup. Only data subcarriers that are assigned to the station are considered in the measurement. Note that there is no sink prepared. You need to setup a sink, e.g. with one or more invocation of a "publish.."-function. SNR output is in dB. """ if not self.measuring_ber(): self.setup_ber_measurement() print "Warning: Setup BER Measurement forced" if self.measuring_snr(): return config = station_configuration() vlen = config.subcarriers frame_length = config.frame_length L = config.periodic_parts snr_est_filt = skip(gr.sizeof_gr_complex*vlen,frame_length/2) skipping_symbols = [0] + range(config.training_data.fbmc_no_preambles/2,frame_length/2) for x in skipping_symbols: snr_est_filt.skip_call(x) #snr_est_filt = skip(gr.sizeof_gr_complex*vlen,frame_length) #for x in range(1,frame_length): #snr_est_filt.skip_call(x) ## NOTE HACK!! first preamble is not equalized self.connect(self.symbol_output,snr_est_filt) self.connect(self.frame_trigger,(snr_est_filt,1)) # snrm = self._snr_measurement = milans_snr_estimator( vlen, vlen, L ) # # self.connect(snr_est_filt,snrm) # # if self._options.log: # log_to_file(self, self._snr_measurement, "data/milan_snr.float") #Addition for SINR estimation if self._options.sinr_est: snr_est_filt_2 = skip(gr.sizeof_gr_complex*vlen,frame_length) for x in range(frame_length): if x != config.training_data.channel_estimation_pilot[0]: snr_est_filt_2.skip_call(x) self.connect(self.symbol_output,snr_est_filt_2) self.connect(self.frame_trigger,(snr_est_filt_2,1)) sinrm = self._sinr_measurement = milans_sinr_sc_estimator2( vlen, vlen, L ) self.connect(snr_est_filt,sinrm) self.connect(snr_est_filt_2,(sinrm,1)) if self._options.log: log_to_file(self, (self._sinr_measurement,0), "data/milan_sinr_sc.float") log_to_file(self, (self._sinr_measurement,1), "data/milan_snr.float") else: #snrm = self._snr_measurement = milans_snr_estimator( vlen, vlen, L ) snr_estim = fbmc_snr_estimator( vlen, config.training_data.fbmc_no_preambles/2 -1 ) scsnrdb = filter.single_pole_iir_filter_ff(0.1) snrm = self._snr_measurement = blocks.nlog10_ff(10,1,0) #self.connect(self.snr_est_preamble,scsnrdb,snrm) #terminate_stream(self,self.snr_est_preamble) #self.connect(self.snr_est_preamble,snr_estim,scsnrdb,snrm) #self.connect((snr_estim,1),blocks.null_sink(gr.sizeof_float)) #log_to_file(self, snrm, "data/snrm.float") #log_to_file(self, snrm, "data/snrm.float") collect_preambles = blocks.stream_to_vector(gr.sizeof_gr_complex*vlen, config.training_data.fbmc_no_preambles/2 -1) self.connect(snr_est_filt, collect_preambles) self.connect(collect_preambles,snr_estim,scsnrdb,snrm) self.connect((snr_estim,1),blocks.null_sink(gr.sizeof_float))
def add_mobile_station(self, station_id): """ Adds new receiver mobile station. Station ID must be unique. Initializes BER reference source. """ # Initialize id_src = self._control._id_source dmux = self._data_multiplexer port = self._data_multiplexer_nextport self._data_multiplexer_nextport += 1 # Setup ctrl_port = self._control.add_mobile_station(station_id) options = self._options if options.imgxfer: ref_src = ofdm.imgtransfer_src(options.img) else: ref_src = ber_reference_source(self._options) if (options.coding): ## Encoder encoder = self._encoder = ofdm.encoder_bb(fo, 0) unpack = self._unpack = blocks.unpack_k_bits_bb(2) ## Puncturing if not options.nopunct: puncturing = self._puncturing = puncture_bb( options.subcarriers) #sah = gr.sample_and_hold_bb() #sah_trigger = blocks.vector_source_b([1,0],True) #decim_sah=gr.keep_one_in_n(gr.sizeof_char,2) self.connect(self._bitmap_trigger_puncturing, (puncturing, 2)) frametrigger_bitmap_filter = blocks.vector_source_b([1, 0], True) bitmap_filter = self._puncturing_bitmap_src_filter = skip( gr.sizeof_char * options.subcarriers, 2) # skip_known_symbols(frame_length,subcarriers) bitmap_filter.skip_call(0) #self.connect(self._bitmap_src_puncturing,bitmap_filter,(puncturing,1)) self.connect(self._map_src, bitmap_filter, (puncturing, 1)) self.connect(frametrigger_bitmap_filter, (bitmap_filter, 1)) #bmt = gr.char_to_float() #self.connect(bitmap_filter,blocks.vector_to_stream(gr.sizeof_char,options.subcarriers), bmt) #log_to_file(self, bmt, "data/bitmap_filter_tx.float") self.connect((self._control, ctrl_port), ref_src, encoder, unpack) if not options.nopunct: self.connect(unpack, puncturing, (dmux, port)) #self.connect(sah_trigger, (sah,1)) else: self.connect(unpack, (dmux, port)) else: self.connect((self._control, ctrl_port), ref_src, (dmux, port)) if options.log and options.coding: log_to_file(self, encoder, "data/encoder_out.char") log_to_file(self, ref_src, "data/reference_data_src.char") log_to_file(self, unpack, "data/encoder_unpacked_out.char") if not options.nopunct: log_to_file(self, puncturing, "data/puncturing_out.char")
def __init__(self, options): gr.hier_block2.__init__( self, "fbmc_transmit_path", gr.io_signature(0, 0, 0), gr.io_signature(1, 1, gr.sizeof_gr_complex) ) common_options.defaults(options) config = self.config = station_configuration() config.data_subcarriers = options.subcarriers config.cp_length = 0 config.frame_data_blocks = options.data_blocks config._verbose = options.verbose config.fft_length = options.fft_length config.dc_null = options.dc_null config.training_data = default_block_header(config.data_subcarriers, config.fft_length, config.dc_null, options) config.coding = options.coding config.fbmc = options.fbmc config.adaptive_fbmc = options.adaptive_fbmc config.frame_id_blocks = 1 # FIXME # digital rms amplitude sent to USRP rms_amp = options.rms_amplitude self._options = copy.copy(options) config.block_length = config.fft_length + config.cp_length config.frame_data_part = config.frame_data_blocks + config.frame_id_blocks config.frame_length = config.training_data.fbmc_no_preambles + 2 * config.frame_data_part config.subcarriers = config.data_subcarriers + config.training_data.pilot_subcarriers config.virtual_subcarriers = config.fft_length - config.subcarriers - config.dc_null # default values if parameters not set if rms_amp is None: rms_amp = math.sqrt(config.subcarriers) config.rms_amplitude = rms_amp # check some bounds if config.fft_length < config.subcarriers: raise SystemError, "Subcarrier number must be less than FFT length" if config.fft_length < config.cp_length: raise SystemError, "Cyclic prefix length must be less than FFT length" ## shortcuts blen = config.block_length flen = config.frame_length dsubc = config.data_subcarriers vsubc = config.virtual_subcarriers # Adaptive Transmitter Concept used_id_bits = config.used_id_bits = 8 # TODO: no constant in source code rep_id_bits = config.rep_id_bits = config.data_subcarriers / used_id_bits # BPSK if config.data_subcarriers % used_id_bits <> 0: raise SystemError, "Data subcarriers need to be multiple of %d" % (used_id_bits) ## Allocation Control self.allocation_src = allocation_src( config.data_subcarriers, config.frame_data_blocks, config.coding, "tcp://*:3333", "tcp://" + options.rx_hostname + ":3322", ) if options.static_allocation: # DEBUG # how many bits per subcarrier if options.coding: mode = 1 # Coding mode 1-9 bitspermode = [0.5, 1, 1.5, 2, 3, 4, 4.5, 5, 6] # Information bits per mode modulbitspermode = [1, 2, 2, 4, 4, 6, 6, 6, 8] # Coding bits per mode bitcount_vec = [(int)(config.data_subcarriers * config.frame_data_blocks * bitspermode[mode - 1])] modul_bitcount_vec = [config.data_subcarriers * config.frame_data_blocks * modulbitspermode[mode - 1]] bitcount_src = blocks.vector_source_i(bitcount_vec, True, 1) modul_bitcount_src = blocks.vector_source_i(modul_bitcount_vec, True, 1) bitloading = mode else: bitloading = 1 bitcount_vec = [config.data_subcarriers * config.frame_data_blocks * bitloading] bitcount_src = blocks.vector_source_i(bitcount_vec, True, 1) modul_bitcount_src = bitcount_src # id's for frames id_vec = range(0, 256) id_src = blocks.vector_source_s(id_vec, True, 1) # bitloading for ID symbol and then once for data symbols # bitloading_vec = [1]*dsubc+[0]*(dsubc/2)+[2]*(dsubc/2) test_allocation = ( [bitloading] * (int)(config.data_subcarriers / 8) + [0] * (int)(config.data_subcarriers / 4 * 3) + [bitloading] * (int)(config.data_subcarriers / 8) ) # bitloading_vec = [1]*dsubc+[bitloading]*dsubc bitloading_vec = [1] * dsubc + test_allocation bitloading_src = blocks.vector_source_b(bitloading_vec, True, dsubc) # bitcount for frames # bitcount_vec = [config.data_subcarriers*config.frame_data_blocks*bitloading] bitcount_vec = [config.frame_data_blocks * sum(test_allocation)] bitcount_src = blocks.vector_source_i(bitcount_vec, True, 1) # power loading, here same for all symbols power_vec = ( [1] * (int)(config.data_subcarriers / 8) + [0] * (int)(config.data_subcarriers / 4 * 3) + [1] * (int)(config.data_subcarriers / 8) ) power_src = blocks.vector_source_f(power_vec, True, dsubc) # mux control stream to mux id and data bits mux_vec = [0] * dsubc + [1] * bitcount_vec[0] mux_ctrl = blocks.vector_source_b(mux_vec, True, 1) else: id_src = (self.allocation_src, 0) bitcount_src = (self.allocation_src, 4) bitloading_src = (self.allocation_src, 2) power_src = (self.allocation_src, 1) if options.coding: modul_bitcount_src = (self.allocation_src, 5) else: modul_bitcount_src = bitcount_src mux_ctrl = ofdm.tx_mux_ctrl(dsubc) self.connect(modul_bitcount_src, mux_ctrl) # Initial allocation self.allocation_src.set_allocation([4] * config.data_subcarriers, [1] * config.data_subcarriers) if options.benchmarking: self.allocation_src.set_allocation([4] * config.data_subcarriers, [1] * config.data_subcarriers) if options.lab_special_case: self.allocation_src.set_allocation( [0] * (config.data_subcarriers / 4) + [2] * (config.data_subcarriers / 2) + [0] * (config.data_subcarriers / 4), [1] * config.data_subcarriers, ) if options.log: log_to_file(self, id_src, "data/id_src.short") log_to_file(self, bitcount_src, "data/bitcount_src.int") log_to_file(self, bitloading_src, "data/bitloading_src.char") log_to_file(self, power_src, "data/power_src.cmplx") ## GUI probe output zmq_probe_bitloading = zeromq.pub_sink(gr.sizeof_char, dsubc, "tcp://*:4445") # also skip ID symbol bitloading with keep_one_in_n (side effect) # factor 2 for bitloading because we have two vectors per frame, one for id symbol and one for all payload/data symbols # factor config.frame_data_part for power because there is one vector per ofdm symbol per frame self.connect(bitloading_src, blocks.keep_one_in_n(gr.sizeof_char * dsubc, 2 * 40), zmq_probe_bitloading) zmq_probe_power = zeromq.pub_sink(gr.sizeof_float, dsubc, "tcp://*:4444") # self.connect(power_src, blocks.keep_one_in_n(gr.sizeof_gr_complex*dsubc,40), blocks.complex_to_real(dsubc), zmq_probe_power) self.connect(power_src, blocks.keep_one_in_n(gr.sizeof_float * dsubc, 40), zmq_probe_power) ## Workaround to avoid periodic structure seed(1) whitener_pn = [randint(0, 1) for i in range(used_id_bits * rep_id_bits)] ## ID Encoder id_enc = self._id_encoder = repetition_encoder_sb(used_id_bits, rep_id_bits, whitener_pn) self.connect(id_src, id_enc) if options.log: id_enc_f = gr.char_to_float() self.connect(id_enc, id_enc_f) log_to_file(self, id_enc_f, "data/id_enc_out.float") ## Reference Data Source ber_ref_src = ber_reference_source(self._options) self.connect(id_src, (ber_ref_src, 0)) self.connect(bitcount_src, (ber_ref_src, 1)) if options.log: log_to_file(self, ber_ref_src, "data/ber_rec_src_tx.char") if options.log: log_to_file(self, btrig, "data/bitmap_trig.char") ## Frame Trigger ftrig_stream = [1] + [0] * (config.frame_data_part - 1) ftrig = self._frame_trigger = blocks.vector_source_b(ftrig_stream, True) ## Data Multiplexer # Input 0: control stream # Input 1: encoded ID stream # Inputs 2..n: data streams dmux = self._data_multiplexer = stream_controlled_mux_b() self.connect(mux_ctrl, (dmux, 0)) self.connect(id_enc, (dmux, 1)) if options.coding: fo = trellis.fsm(1, 2, [91, 121]) encoder = self._encoder = trellis.encoder_bb(fo, 0) unpack = self._unpack = blocks.unpack_k_bits_bb(2) self.connect(ber_ref_src, encoder, unpack) if options.interleave: int_object = trellis.interleaver(2000, 666) interlv = trellis.permutation(int_object.K(), int_object.INTER(), 1, gr.sizeof_char) if not options.nopunct: bmaptrig_stream_puncturing = [1] + [0] * (config.frame_data_blocks / 2 - 1) btrig_puncturing = self._bitmap_trigger_puncturing = blocks.vector_source_b( bmaptrig_stream_puncturing, True ) puncturing = self._puncturing = puncture_bb(config.data_subcarriers) self.connect(bitloading_src, (puncturing, 1)) self.connect(self._bitmap_trigger_puncturing, (puncturing, 2)) self.connect(unpack, puncturing) last_block = puncturing if options.interleave: self.connect(last_block, interlv) last_block = interlv if options.benchmarking: self.connect(last_block, blocks.head(gr.sizeof_char, options.N), (dmux, 2)) else: self.connect(last_block, (dmux, 2)) else: if options.benchmarking: self.connect(unpack, blocks.head(gr.sizeof_char, options.N), (dmux, 2)) else: self.connect(unpack, (dmux, 2)) else: if options.benchmarking: self.connect(ber_ref_src, blocks.head(gr.sizeof_char, options.N), (dmux, 2)) else: self.connect(ber_ref_src, (dmux, 2)) if options.log: dmux_f = gr.char_to_float() self.connect(dmux, dmux_f) log_to_file(self, dmux_f, "data/dmux_out.float") ## Modulator mod = self._modulator = generic_mapper_bcv(config.data_subcarriers, config.coding, config.frame_data_part) self.connect(dmux, (mod, 0)) self.connect(bitloading_src, (mod, 1)) if options.log: log_to_file(self, mod, "data/mod_out.compl") modi = blocks.complex_to_imag(config.data_subcarriers) modr = blocks.complex_to_real(config.data_subcarriers) self.connect(mod, modi) self.connect(mod, modr) log_to_file(self, modi, "data/mod_imag_out.float") log_to_file(self, modr, "data/mod_real_out.float") ## Power allocator pa = self._power_allocator = multiply_frame_fc(config.frame_data_part, config.data_subcarriers) self.connect(mod, (pa, 0)) self.connect(power_src, (pa, 1)) if options.log: log_to_file(self, pa, "data/pa_out.compl") if options.fbmc: psubc = pa else: psubc = self._pilot_subcarrier_inserter = pilot_subcarrier_inserter() self.connect(pa, psubc) if options.log: log_to_file(self, psubc, "data/psubc_out.compl") subcarriers = config.subcarriers # fbmc_pblocks_timing = self._fbmc_timing_pilot_block_inserter = fbmc_timing_pilot_block_inserter(5,False) oqam_prep = self._oqam_prep = fbmc_oqam_preprocessing_vcvc(config.subcarriers, 0, 0) self.connect(psubc, oqam_prep) fbmc_pblocks = self._fbmc_pilot_block_inserter = fbmc_pilot_block_inserter(5, False) self.connect(oqam_prep, fbmc_pblocks) # log_to_file(self, fbmc_pblocks, "data/fbmc_pblocks_out.compl") # fbmc_insert_pream = self._fbmc_insert_pream = fbmc_insert_preamble_vcvc(M, syms_per_frame, preamble) # log_to_file(self, oqam_prep, "data/oqam_prep.compl") # log_to_file(self, psubc, "data/psubc_out.compl") # fbmc_pblocks = fbmc_pblocks_timing # log_to_file(self, fbmc_pblocks, "data/fbmc_pblocks_out.compl") beta_mult = self._beta_mult = fbmc_beta_multiplier_vcvc(config.subcarriers, 4, 4 * config.fft_length - 1, 0) self.connect(fbmc_pblocks, beta_mult) log_to_file(self, beta_mult, "data/beta_mult.compl") ## Add virtual subcarriers if config.fft_length > subcarriers: vsubc = self._virtual_subcarrier_extender = vector_padding_dc_null( config.subcarriers, config.fft_length, config.dc_null ) self.connect(beta_mult, vsubc) else: vsubc = self._virtual_subcarrier_extender = beta_mult if options.log: log_to_file(self, vsubc, "data/vsubc_out.compl") ## IFFT, no window, block shift ifft = self._ifft = fft_blocks.fft_vcc(config.fft_length, False, [], True) self.connect(vsubc, ifft) if options.log: log_to_file(self, ifft, "data/ifft_out.compl") # FBMC separate stream + filterbanks separate_oqam = self._separate_oqam = fbmc_separate_vcvc(config.fft_length, 2) poly_netw_1 = self._poly_netw_1 = fbmc_polyphase_network_vcvc( config.fft_length, 4, 4 * config.fft_length - 1, False ) poly_netw_2 = self._poly_netw_2 = fbmc_polyphase_network_vcvc( config.fft_length, 4, 4 * config.fft_length - 1, False ) overlap_p2s = self._overlap_p2s = fbmc_overlapping_parallel_to_serial_vcc(config.fft_length) self.connect(ifft, (separate_oqam, 0), poly_netw_1) self.connect((separate_oqam, 1), poly_netw_2) self.connect(poly_netw_1, (overlap_p2s, 0)) self.connect(poly_netw_2, (overlap_p2s, 1)) ## Pilot blocks (preambles) # pblocks = self._pilot_block_inserter = pilot_block_inserter2(5,False) # self.connect( overlap_p2s, blocks.stream_to_vector(gr.sizeof_gr_complex,config.fft_length/2), pblocks ) # log_to_file(self, pblocks, "data/fbmc_pilot_block_ins_out.compl") if options.log: log_to_file(self, pblocks, "data/pilot_block_ins_out.compl") ## Cyclic Prefix # cp = self._cyclic_prefixer = cyclic_prefixer(config.fft_length, # config.block_length) # cp= blocks.vector_to_stream(gr.sizeof_gr_complex, config.fft_length/2) # self.connect(pblocks, cp ) # self.connect( overlap_p2s,blocks.stream_to_vector(gr.sizeof_gr_complex,config.fft_length/2), cp ) lastblock = overlap_p2s if options.log: log_to_file(self, overlap_p2s, "data/overlap_p2s_out.compl") # Digital Amplifier for resource allocation if config.adaptive_fbmc: rep = blocks.repeat(gr.sizeof_gr_complex, config.frame_length * config.block_length) amp = blocks.multiply_cc() self.connect(lastblock, (amp, 0)) self.connect((self.allocation_src, 3), rep, (amp, 1)) lastblock = amp else: self.connect((self.allocation_src, 3), blocks.null_sink(gr.sizeof_gr_complex)) ## Digital Amplifier # amp = self._amplifier = gr.multiply_const_cc(1) amp = self._amplifier = ofdm.multiply_const_ccf(1.0) self.connect(lastblock, amp) self.set_rms_amplitude(rms_amp) # log_to_file(self, amp, "data/amp_tx_out.compl") if options.log: log_to_file(self, amp, "data/amp_tx_out.compl") ## Tx parameters bandwidth = options.bandwidth or 2e6 bits = 8 * config.data_subcarriers * config.frame_data_blocks # max. QAM256 samples_per_frame = config.frame_length * config.block_length tb = samples_per_frame / bandwidth # set dummy carrier frequency if none available due to baseband mode if options.tx_freq is None: options.tx_freq = 0.0 self.tx_parameters = { "carrier_frequency": options.tx_freq / 1e9, "fft_size": config.fft_length, "cp_size": config.cp_length, "subcarrier_spacing": options.bandwidth / config.fft_length / 1e3, "data_subcarriers": config.data_subcarriers, "bandwidth": options.bandwidth / 1e6, "frame_length": config.frame_length, "symbol_time": (config.cp_length + config.fft_length) / options.bandwidth * 1e6, "max_data_rate": (bits / tb) / 1e6, } ## Setup Output self.connect(amp, self) # Display some information about the setup if config._verbose: self._print_verbage()
def __init__(self, options): gr.hier_block2.__init__(self, "transmit_path", gr.io_signature(0, 0, 0), gr.io_signature(2, 2, gr.sizeof_gr_complex)) common_options.defaults(options) config = self.config = station_configuration() config.data_subcarriers = options.subcarriers config.cp_length = options.cp_length config.frame_data_blocks = options.data_blocks config._verbose = options.verbose config.fft_length = options.fft_length config.training_data = default_block_header(config.data_subcarriers, config.fft_length, options) config.tx_station_id = options.station_id config.coding = options.coding if config.tx_station_id is None: raise SystemError, "Station ID not set" config.frame_id_blocks = 1 # FIXME # digital rms amplitude sent to USRP rms_amp = options.rms_amplitude self._options = copy.copy(options) self.servants = [] # FIXME config.block_length = config.fft_length + config.cp_length config.frame_data_part = config.frame_data_blocks + config.frame_id_blocks config.frame_length = config.frame_data_part + \ config.training_data.no_pilotsyms config.subcarriers = config.data_subcarriers + \ config.training_data.pilot_subcarriers config.virtual_subcarriers = config.fft_length - config.subcarriers # default values if parameters not set if rms_amp is None: rms_amp = math.sqrt(config.subcarriers) config.rms_amplitude = rms_amp # check some bounds if config.fft_length < config.subcarriers: raise SystemError, "Subcarrier number must be less than FFT length" if config.fft_length < config.cp_length: raise SystemError, "Cyclic prefix length must be less than FFT length" ## shortcuts blen = config.block_length flen = config.frame_length dsubc = config.data_subcarriers vsubc = config.virtual_subcarriers # ------------------------------------------------------------------------ # # Adaptive Transmitter Concept used_id_bits = config.used_id_bits = 8 #TODO: no constant in source code rep_id_bits = config.rep_id_bits = config.data_subcarriers / used_id_bits #BPSK if config.data_subcarriers % used_id_bits <> 0: raise SystemError, "Data subcarriers need to be multiple of %d" % ( used_id_bits) ## Control Part if options.debug: self._control = ctrl = static_tx_control(options) print "Statix TX Control used" else: self._control = ctrl = corba_tx_control(options) print "CORBA TX Control used" id_src = (ctrl, 0) mux_src = (ctrl, 1) map_src = self._map_src = (ctrl, 2) pa_src = (ctrl, 3) if options.log: id_src_f = gr.short_to_float() self.connect(id_src, id_src_f) log_to_file(self, id_src_f, "data/id_src_out.float") mux_src_f = gr.short_to_float() self.connect(mux_src, mux_src_f) log_to_file(self, mux_src_f, "data/mux_src_out.float") map_src_s = blocks.vector_to_stream(gr.sizeof_char, config.data_subcarriers) map_src_f = gr.char_to_float() self.connect(map_src, map_src_s, map_src_f) ##log_to_file(self, map_src_f, "data/map_src.float") ##log_to_file(self, pa_src, "data/pa_src_out.float") ## Workaround to avoid periodic structure seed(1) whitener_pn = [ randint(0, 1) for i in range(used_id_bits * rep_id_bits) ] ## ID Encoder id_enc = self._id_encoder = repetition_encoder_sb( used_id_bits, rep_id_bits, whitener_pn) self.connect(id_src, id_enc) if options.log: id_enc_f = gr.char_to_float() self.connect(id_enc, id_enc_f) log_to_file(self, id_enc_f, "data/id_enc_out.float") ## Bitmap Update Trigger # TODO #bmaptrig_stream = concatenate([[1, 2],[0]*(config.frame_data_part-7)]) bmaptrig_stream = concatenate([[1, 1], [0] * (config.frame_data_part - 2)]) print "bmaptrig_stream = ", bmaptrig_stream btrig = self._bitmap_trigger = blocks.vector_source_b( bmaptrig_stream.tolist(), True) if options.log: log_to_file(self, btrig, "data/bitmap_trig.char") ## Bitmap Update Trigger for puncturing # TODO if not options.nopunct: #bmaptrig_stream_puncturing = concatenate([[1],[0]*(config.frame_data_part-2)]) bmaptrig_stream_puncturing = concatenate( [[1], [0] * (config.frame_data_blocks / 2 - 1)]) btrig_puncturing = self._bitmap_trigger_puncturing = blocks.vector_source_b( bmaptrig_stream_puncturing.tolist(), True) bmapsrc_stream_puncturing = concatenate([[1] * dsubc, [2] * dsubc]) bsrc_puncturing = self._bitmap_src_puncturing = blocks.vector_source_b( bmapsrc_stream_puncturing.tolist(), True, dsubc) if options.log and options.coding and not options.nopunct: log_to_file(self, btrig_puncturing, "data/bitmap_trig_puncturing.char") ## Frame Trigger # TODO ftrig_stream = concatenate([[1], [0] * (config.frame_data_part - 1)]) ftrig = self._frame_trigger = blocks.vector_source_b( ftrig_stream.tolist(), True) ## Data Multiplexer # Input 0: control stream # Input 1: encoded ID stream # Inputs 2..n: data streams dmux = self._data_multiplexer = stream_controlled_mux_b() self.connect(mux_src, (dmux, 0)) self.connect(id_enc, (dmux, 1)) self._data_multiplexer_nextport = 2 if options.log: dmux_f = gr.char_to_float() self.connect(dmux, dmux_f) log_to_file(self, dmux_f, "data/dmux_out.float") ## Modulator mod = self._modulator = generic_mapper_bcv(config.data_subcarriers, options.coding) self.connect(dmux, (mod, 0)) self.connect(map_src, (mod, 1)) self.connect(btrig, (mod, 2)) if options.log: log_to_file(self, mod, "data/mod_out.compl") modi = gr.complex_to_imag(config.data_subcarriers) modr = gr.complex_to_real(config.data_subcarriers) self.connect(mod, modi) self.connect(mod, modr) log_to_file(self, modi, "data/mod_imag_out.float") log_to_file(self, modr, "data/mod_real_out.float") ## Power allocator if options.debug: ## static pa = self._power_allocator = power_allocator( config.data_subcarriers) self.connect(mod, (pa, 0)) self.connect(pa_src, (pa, 1)) else: ## with CORBA control event channel ns_ip = ctrl.ns_ip ns_port = ctrl.ns_port evchan = ctrl.evchan pa = self._power_allocator = corba_power_allocator(dsubc, \ evchan, ns_ip, ns_port, True) self.connect(mod, (pa, 0)) self.connect(id_src, (pa, 1)) self.connect(ftrig, (pa, 2)) if options.log: log_to_file(self, pa, "data/pa_out.compl") ## Pilot subcarriers psubc = self._pilot_subcarrier_inserter = pilot_subcarrier_inserter() self.connect(pa, psubc) pilot_subc = config.training_data.shifted_pilot_tones print "pilot_subc", pilot_subc stc = stc_encoder(config.subcarriers, config.frame_data_blocks, pilot_subc) self.connect(psubc, stc) if options.log: log_to_file(self, psubc, "data/psubc_out.compl") log_to_file(self, psubc_2, "data/psubc2_out.compl") log_to_file(self, pa, "data/pa.compl") log_to_file(self, (stc, 0), "data/stc_0.compl") log_to_file(self, (stc, 1), "data/stc_1.compl") ## Add virtual subcarriers if config.fft_length > config.subcarriers: vsubc = self._virtual_subcarrier_extender = \ vector_padding(config.subcarriers, config.fft_length) self.connect(stc, vsubc) vsubc_2 = self._virtual_subcarrier_extender_2 = \ vector_padding(config.subcarriers, config.fft_length) self.connect((stc, 1), vsubc_2) else: vsubc = self._virtual_subcarrier_extender = psubc vsubc_2 = self._virtual_subcarrier_extender_2 = psubc_2 log_to_file(self, psubc, "data/psubc.compl") log_to_file(self, stc, "data/stc1.compl") log_to_file(self, (stc, 1), "data/stc2.compl") if options.log: log_to_file(self, vsubc, "data/vsubc_out.compl") log_to_file(self, vsubc_2, "data/vsubc2_out.compl") ## IFFT, no window, block shift ifft = self._ifft = fft_blocks.fft_vcc(config.fft_length, False, [], True) self.connect(vsubc, ifft) ifft_2 = self._ifft_2 = fft_blocks.fft_vcc(config.fft_length, False, [], True) self.connect(vsubc_2, ifft_2) if options.log: log_to_file(self, ifft, "data/ifft_out.compl") log_to_file(self, ifft_2, "data/ifft2_out.compl") ## Pilot blocks (preambles) pblocks = self._pilot_block_inserter = pilot_block_inserter(1, False) self.connect(ifft, pblocks) pblocks_2 = self._pilot_block_inserter_2 = pilot_block_inserter( 2, False) self.connect(ifft_2, pblocks_2) if options.log: log_to_file(self, pblocks, "data/pilot_block_ins_out.compl") log_to_file(self, pblocks_2, "data/pilot_block_ins2_out.compl") ## Cyclic Prefix cp = self._cyclic_prefixer = cyclic_prefixer(config.fft_length, config.block_length) self.connect(pblocks, cp) cp_2 = self._cyclic_prefixer_2 = cyclic_prefixer( config.fft_length, config.block_length) self.connect(pblocks_2, cp_2) lastblock = cp lastblock_2 = cp_2 if options.log: log_to_file(self, cp, "data/cp_out.compl") log_to_file(self, cp_2, "data/cp2_out.compl") if options.cheat: ## Artificial Channel # kept to compare with previous system achan_ir = concatenate([[1.0], [0.0] * (config.cp_length - 1)]) achan = self._artificial_channel = gr.fir_filter_ccc(1, achan_ir) self.connect(lastblock, achan) lastblock = achan achan_2 = self._artificial_channel_2 = gr.fir_filter_ccc( 1, achan_ir) self.connect(lastblock_2, achan_2) lastblock_2 = achan_2 ## Digital Amplifier amp = self._amplifier = ofdm.multiply_const_ccf(1.0 / math.sqrt(2)) self.connect(lastblock, amp) amp_2 = self._amplifier_2 = ofdm.multiply_const_ccf(1.0 / math.sqrt(2)) self.connect(lastblock_2, amp_2) self.set_rms_amplitude(rms_amp) if options.log: log_to_file(self, amp, "data/amp_tx_out.compl") log_to_file(self, amp_2, "data/amp_tx2_out.compl") ## Setup Output self.connect(amp, (self, 0)) self.connect(amp_2, (self, 1)) # ------------------------------------------------------------------------ # # Display some information about the setup if config._verbose: self._print_verbage()
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( 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 )