def __init__(self,subcarriers, frame_length): #config = station_configuration() total_subc = subcarriers vlen = total_subc gr.hier_block2.__init__(self,"ofdm_frame_sampler_grc", gr.io_signature2(2,2,gr.sizeof_gr_complex*vlen, gr.sizeof_char), gr.io_signature2(2,2,gr.sizeof_gr_complex*vlen, gr.sizeof_char)) ft = [0] * 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 = vector_sampler( gr.sizeof_gr_complex * total_subc, frame_length ) symbol_output = blocks.vector_to_stream( gr.sizeof_gr_complex * total_subc, frame_length ) delayed_frame_start = blocks.delay( gr.sizeof_char, frame_length - 1 ) damn_static_frame_trigger = blocks.vector_source_b( ft, True ) self.connect( self, frame_sampler, symbol_output, self ) self.connect( (self,1), delayed_frame_start, ( frame_sampler, 1 ) ) self.connect( damn_static_frame_trigger, (self,1) )
def __init__(self, dab_params, bit_rate, address, subch_size, protection, output_float, verbose=False, debug=False): if output_float: # map short samples to the range [-1,1] in floats gr.hier_block2.__init__(self, "dab_audio_decoder_ff", # Input signature gr.io_signature(1, 1, gr.sizeof_float * dab_params.num_carriers * 2), # Output signature gr.io_signature2(2, 2, gr.sizeof_float, gr.sizeof_float)) else: # output signed 16 bit integers (directly from decoder) gr.hier_block2.__init__(self, "dab_audio_decoder_ff", # Input signature gr.io_signature(1, 1, gr.sizeof_float * dab_params.num_carriers * 2), # Output signature gr.io_signature2(2, 2, gr.sizeof_short, gr.sizeof_short)) self.msc_dec = grdab.msc_decode(dab_params, address, subch_size, protection) self.unpack = blocks.packed_to_unpacked_bb_make(1, gr.GR_MSB_FIRST) self.mp2_dec = grdab.mp2_decode_bs_make(bit_rate / 8) self.connect((self, 0), self.msc_dec, self.unpack, self.mp2_dec) if output_float: # map short samples to the range [-1,1] in floats self.s2f_left = blocks.short_to_float_make(1, 32767) self.s2f_right = blocks.short_to_float_make(1, 32767) self.gain_left = blocks.multiply_const_ff(1, 1) self.gain_right = blocks.multiply_const_ff(1, 1) self.connect((self.mp2_dec, 0), self.s2f_left, self.gain_left, (self, 0)) self.connect((self.mp2_dec, 1), self.s2f_right, self.gain_right, (self, 1)) else: # output signed 16 bit integers (directly from decoder) self.connect((self.mp2_dec, 0), (self, 0)) self.connect((self.mp2_dec, 1), (self, 1))
def __init__(self, dab_params, bit_rate, address, subch_size, protection, output_float, verbose=False, debug=False): if output_float: # map short samples to the range [-1,1] in floats gr.hier_block2.__init__(self, "dabplus_audio_decoder_ff", # Input signature gr.io_signature(1, 1, gr.sizeof_float * dab_params.num_carriers * 2), # Output signature gr.io_signature2(2, 2, gr.sizeof_float, gr.sizeof_float)) else: # output signed 16 bit integers (directly from decoder) gr.hier_block2.__init__(self, "dabplus_audio_decoder_ff", # Input signature gr.io_signature(1, 1, gr.sizeof_float * dab_params.num_carriers * 2), # Output signature gr.io_signature2(2, 2, gr.sizeof_short, gr.sizeof_short)) self.dp = dab_params self.bit_rate_n = bit_rate / 8 self.address = address self.size = subch_size self.protection = protection self.output_float = output_float self.verbose = verbose self.debug = debug # sanity check # if self.bit_rate_n*6 != self.size: # log = gr.logger("log") # log.debug("bit rate and subchannel size are not fitting") # log.set_level("ERROR") # raise ValueError # MSC decoder extracts logical frames out of transmission frame and decodes it self.msc_decoder = grdab.msc_decode(self.dp, self.address, self.size, self.protection, self.verbose, self.debug) # firecode synchronizes to superframes and checks self.firecode = grdab.firecode_check_bb_make(self.bit_rate_n) # Reed-Solomon error repair self.rs = grdab.reed_solomon_decode_bb_make(self.bit_rate_n) # mp4 decoder self.mp4 = grdab.mp4_decode_bs_make(self.bit_rate_n) self.connect((self, 0), self.msc_decoder, self.firecode, self.rs, self.mp4) if self.output_float: # map short samples to the range [-1,1] in floats self.s2f_left = blocks.short_to_float_make(1, 32767) self.s2f_right = blocks.short_to_float_make(1, 32767) self.gain_left = blocks.multiply_const_ff(1, 1) self.gain_right = blocks.multiply_const_ff(1, 1) self.connect((self.mp4, 0), self.s2f_left, self.gain_left, (self, 0)) self.connect((self.mp4, 1), self.s2f_right, self.gain_right, (self, 1)) else: # output signed 16 bit integers (directly from decoder) self.connect((self.mp4, 0), (self, 0)) self.connect((self.mp4, 1), (self, 1))
def __init__(self, dab_params, bit_rate, address, subch_size, protection, output_float, verbose=False, debug=False): if output_float: # map short samples to the range [-1,1] in floats gr.hier_block2.__init__( self, "dab_audio_decoder_ff", # Input signature gr.io_signature(1, 1, gr.sizeof_float * dab_params.num_carriers * 2), # Output signature gr.io_signature2(2, 2, gr.sizeof_float, gr.sizeof_float)) else: # output signed 16 bit integers (directly from decoder) gr.hier_block2.__init__( self, "dab_audio_decoder_ff", # Input signature gr.io_signature(1, 1, gr.sizeof_float * dab_params.num_carriers * 2), # Output signature gr.io_signature2(2, 2, gr.sizeof_short, gr.sizeof_short)) self.msc_dec = grdab.msc_decode(dab_params, address, subch_size, protection) self.unpack = blocks.packed_to_unpacked_bb_make(1, gr.GR_MSB_FIRST) self.mp2_dec = grdab.mp2_decode_bs_make(bit_rate / 8) self.connect((self, 0), self.msc_dec, self.unpack, self.mp2_dec) if output_float: # map short samples to the range [-1,1] in floats self.s2f_left = blocks.short_to_float_make(1, 32767) self.s2f_right = blocks.short_to_float_make(1, 32767) self.gain_left = blocks.multiply_const_ff(1, 1) self.gain_right = blocks.multiply_const_ff(1, 1) self.connect((self.mp2_dec, 0), self.s2f_left, self.gain_left, (self, 0)) self.connect((self.mp2_dec, 1), self.s2f_right, self.gain_right, (self, 1)) else: # output signed 16 bit integers (directly from decoder) self.connect((self.mp2_dec, 0), (self, 0)) self.connect((self.mp2_dec, 1), (self, 1))
def __init__(self, vlen): gr.hier_block2.__init__( self, "coarse_frequency_offset_estimation", gr.io_signature2(2, 2, gr.sizeof_gr_complex, gr.sizeof_char), gr.io_signature(1, 1, gr.sizeof_float)) ## Preamble Extraction sampler = vector_sampler(gr.sizeof_gr_complex, vlen) self.connect(self, sampler) self.connect((self, 1), (sampler, 1)) ## Split block into two parts splitter = gr.vector_to_streams(gr.sizeof_gr_complex * vlen / 2, 2) self.connect(sampler, splitter) ## Multiply 2nd sub-part with conjugate of 1st sub-part conj_mult = gr.multiply_conjugate_cc(vlen / 2) self.connect((splitter, 1), (conj_mult, 0)) self.connect((splitter, 0), (conj_mult, 1)) ## Sum of Products psum = vector_sum_vcc(vlen / 2) self.connect((conj_mult, 0), psum) ## Complex to Angle angle = complex_to_arg() self.connect(psum, angle) ## Normalize norm = gr.multiply_const_ff(1.0 / math.pi) self.connect(angle, norm) ## Setup Output Connections self.connect(norm, self)
def __init__(self, fft_length): gr.hier_block2.__init__( self, "foe", gr.io_signature2(2, 2, gr.sizeof_gr_complex, gr.sizeof_char), gr.io_signature(1, 1, gr.sizeof_float)) self.input = (self, 0) self.time_sync = (self, 1) # P(d) self.nominator = schmidl_nominator(fft_length) # sample nominator sampler = vector_sampler(gr.sizeof_gr_complex, 1) self.connect(self.input, self.nominator, (sampler, 0)) self.connect(self.time_sync, (sampler, 1)) # calculate epsilon from P(d), epsilon is normalized fractional frequency offset angle = complex_to_arg() self.epsilon = gr.multiply_const_ff(1.0 / math.pi) self.connect(sampler, angle, self.epsilon, self) try: gr.hier_block.update_var_names(self, "foe", vars()) gr.hier_block.update_var_names(self, "foe", vars(self)) except: pass
def __init__(self): gr.hier_block2.__init__( self, "OFDM PHY", gr.io_signature(1, 1, gr.sizeof_gr_complex * 1), gr.io_signature2(2, 2, gr.sizeof_gr_complex * 1, gr.sizeof_char)) # Message Port self.message_port_register_hier_out("from_mac") self.message_port_register_hier_in("to_mac") # Blocks self.tx_pdu = blocks.pdu_to_tagged_stream(blocks.byte_t, "packet_length") self.tx_path = ofdm_tx(scramble_bits=True) self.rx_path = ofdm_rx(scramble_bits=True) self.rx_pdu = blocks.tagged_stream_to_pdu(blocks.byte_t, "packet_length") # Connections self.connect(self.tx_pdu, self.tx_path, self) self.connect(self, self.rx_path, self.rx_pdu) self.connect((self.rx_path, 1), (self, 1)) # Message Connection self.msg_connect(self, "from_mac", self.tx_pdu, "pdus") self.msg_connect(self.rx_pdu, "pdus", self, "to_mac")
def __init__(self, args, bandwidth, freq=None, lo_offset=None, gain=None, spec=None, antenna=None, clock_source=None, time_source=None, verbose=False): gr.hier_block2.__init__(self, "uhd_receiver", gr.io_signature(0,0,0), gr.io_signature2(2,2,gr.sizeof_gr_complex,gr.sizeof_gr_complex)) # Set up the UHD interface as a receiver uhd_interface.__init__(self, False, True, args, bandwidth, freq, lo_offset, gain, spec, antenna, clock_source, time_source) self.u.set_clock_source("mimo", 1) self.u.set_time_source("mimo", 1) #self.u.set_time_source("mimo", 0) #self.u.set_clock_source("external", 1) #self.u.set_time_source("external", 1) #self.u.set_clock_source("external", 0) #self.u.set_time_source("external", 0) #self.u.set_samp_rate(bandwidth) #self.u.set_center_freq(freq, 0) #self.u.set_center_freq(freq, 1) self.connect((self.u,0), (self,0)) self.connect((self.u,1), (self,1)) if(verbose): self._print_verbage()
def __init__(self, fft_length, cp_length): gr.hier_block2.__init__(self, "ofdm_receiver", gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature gr.io_signature2(2, 2, gr.sizeof_gr_complex, gr.sizeof_float)) # Output signature # nco_sensitivity = -1.0/fft_length # correct for fine frequency # self.nco = gr.frequency_modulator_fc(nco_sensitivity) # self.sigmix = gr.multiply_cc() # self.sampler = Heyutu.OFDM_Sampler(fft_length, cp_length) # self.sync = Heyutu.Heyutu_OFDM_Sync.ofdm_sync_ml(fft_length, cp_length) # self.connect(self, self.sync) # self.connect((self.sync,0), self.nco, (self.sigmix,1)) # use sync freq. offset output to derotate input signal # self.connect(self, (self.sigmix,0)) # signal to be derotated # self.connect(self.sigmix, (self.sampler,0)) # sample off timing signal detected in sync alg # self.connect((self.sync,1), (self.sampler,1)) # timing signal to sample at self.sync = Heyutu.Heyutu_OFDM_Sync.ofdm_sync_ml(fft_length, cp_length) self.sampler = Heyutu.OFDM_Sampler(fft_length, cp_length) self.connect(self, self.sync) self.connect(self, (self.sampler,0)) self.connect(self.sync, (self.sampler, 1)) self.connect((self.sampler, 0), (self, 0)) self.connect((self.sampler, 1), (self, 1))
def __init__(self, options): gr.hier_block2.__init__( self, "ber_reference_source", gr.io_signature2(2, 2, gr.sizeof_short, gr.sizeof_int), gr.io_signature(1, 1, gr.sizeof_char), ) ## ID Source id_src = (self, 0) ## Bitcount Source bc_src = (self, 1) ## Reference Data Source # rand_file = file('random.dat','rb') # rand_string = rand_file.read() # rand_file.close() # rand_data = [ord(rand_string[i]) for i in range(len(rand_string))] # We have to use a fix seed so that Tx and Rx have the same random sequence in order to calculate BER seed(30214345) # Maximum bitloading is 8 and maximum ID is 256 print "Generating random bits..." rand_data = [chr(getrandbits(1)) for x in range(options.subcarriers * 8 * options.data_blocks * 256)] ref_src = self._reference_data_source = reference_data_source_02_ib(rand_data) self.connect(id_src, (ref_src, 0)) self.connect(bc_src, (ref_src, 1)) ## Setup Output self.connect(ref_src, self)
def __init__(self, fft_length): gr.hier_block2.__init__(self, "foe", gr.io_signature2(2,2,gr.sizeof_gr_complex,gr.sizeof_char), gr.io_signature(1,1,gr.sizeof_float)) self.input = (self,0) self.time_sync = (self,1) # P(d) self.nominator = schmidl_nominator(fft_length) # sample nominator sampler = vector_sampler(gr.sizeof_gr_complex,1) self.connect(self.input, self.nominator, (sampler,0)) self.connect(self.time_sync, (sampler,1)) # calculate epsilon from P(d), epsilon is normalized fractional frequency offset angle = complex_to_arg() self.epsilon = gr.multiply_const_ff(1.0/math.pi) self.connect(sampler, angle, self.epsilon, self) try: gr.hier_block.update_var_names(self, "foe", vars()) gr.hier_block.update_var_names(self, "foe", vars(self)) except: pass
def __init__(self, vlen): gr.hier_block2.__init__(self, "coarse_frequency_offset_estimation", gr.io_signature2(2,2,gr.sizeof_gr_complex,gr.sizeof_char), gr.io_signature (1,1,gr.sizeof_float)) ## Preamble Extraction sampler = vector_sampler(gr.sizeof_gr_complex,vlen) self.connect(self,sampler) self.connect((self,1),(sampler,1)) ## Split block into two parts splitter = gr.vector_to_streams(gr.sizeof_gr_complex*vlen/2,2) self.connect(sampler,splitter) ## Multiply 2nd sub-part with conjugate of 1st sub-part conj_mult = gr.multiply_conjugate_cc(vlen/2) self.connect((splitter,1),(conj_mult,0)) self.connect((splitter,0),(conj_mult,1)) ## Sum of Products psum = vector_sum_vcc(vlen/2) self.connect((conj_mult,0),psum) ## Complex to Angle angle = complex_to_arg() self.connect(psum,angle) ## Normalize norm = gr.multiply_const_ff(1.0/math.pi) self.connect(angle,norm) ## Setup Output Connections self.connect(norm,self)
def __init__(self, options): gr.hier_block2.__init__( self, "ber_reference_source", gr.io_signature2(2, 2, gr.sizeof_short, gr.sizeof_int), gr.io_signature(1, 1, gr.sizeof_char)) ## ID Source id_src = (self, 0) ## Bitcount Source bc_src = (self, 1) ## Reference Data Source # rand_file = file('random.dat','rb') # rand_string = rand_file.read() # rand_file.close() # rand_data = [ord(rand_string[i]) for i in range(len(rand_string))] # We have to use a fix seed so that Tx and Rx have the same random sequence in order to calculate BER seed(30214345) # Maximum bitloading is 8 and maximum ID is 256 print "Generating random bits..." rand_data = [ chr(getrandbits(1)) for x in range(options.subcarriers * 8 * options.data_blocks * 256) ] ref_src = self._reference_data_source = reference_data_source_02_ib( rand_data) self.connect(id_src, (ref_src, 0)) self.connect(bc_src, (ref_src, 1)) ## Setup Output self.connect(ref_src, self)
def __init__(self, args, bandwidth, freq=None, lo_offset=None, gain=None, spec=None, antenna=None, clock_source=None, time_source=None, verbose=False): gr.hier_block2.__init__( self, "uhd_receiver", gr.io_signature(0, 0, 0), gr.io_signature2(2, 2, gr.sizeof_gr_complex, gr.sizeof_gr_complex)) # Set up the UHD interface as a receiver uhd_interface.__init__(self, False, True, args, bandwidth, freq, lo_offset, gain, spec, antenna, clock_source, time_source) self.u.set_clock_source("mimo", 1) self.u.set_time_source("mimo", 1) #self.u.set_time_source("mimo", 0) #self.u.set_clock_source("external", 1) #self.u.set_time_source("external", 1) #self.u.set_clock_source("external", 0) #self.u.set_time_source("external", 0) #self.u.set_samp_rate(bandwidth) #self.u.set_center_freq(freq, 0) #self.u.set_center_freq(freq, 1) self.connect((self.u, 0), (self, 0)) self.connect((self.u, 1), (self, 1)) if (verbose): self._print_verbage()
def __init__(self, auto_carrier, carrier, all_spectrum, freq_central, samp_rate, nintems, signal_bw, noise_bw, avg_alpha, average, win): """ Estimates the SNR. Provide access to the setting the filter and sample rate. Args: sample_rate: Incoming stream sample rate nintems: Number of FFT bins avg_alpha: FFT averaging (over time) constant [0.0-1.0] average: Whether to average [True, False] win: the window taps generation function auto_carrier: To allow self-detection of the carrier, so the highest bin [True, False] carrier: To evalutaion of the CNR or SNR [True, False] all_spectrum: To set the whole spectrum (less the signal's one) to evaluate noise power density [True, False] freq_central: Sets the central frequency (for the bandwidth) of the signal (in the CNR mode, it is the manual set of the carrier's frequency) signal_bw: Sets the bandwidth (for the SNR mode) of the signal to the power evaluation noise_bw: Sets the bandwidth (if all_sepctrum is false) of the noise to the power evaluation """ gr.hier_block2.__init__(self, "snr_estimator_cfv", gr.io_signature(1,1, gr.sizeof_gr_complex), # Input signature gr.io_signature2(2,2, gr.sizeof_float, gr.sizeof_float * nintems)) # Output signature self.auto_carrier = auto_carrier self.carrier = carrier self.all_spectrum = all_spectrum self.freq_central = freq_central self.samp_rate = samp_rate self.nintems = nintems self.signal_bw = signal_bw self.noise_bw = noise_bw self.avg_alpha = avg_alpha self.average = average self.win = win fft_window = self.win(self.nintems) self.fft = fft.fft_vcc(self.nintems, True, fft_window, True) self._sd = blocks.stream_to_vector(gr.sizeof_gr_complex, self.nintems) self.c2magsq = blocks.complex_to_mag_squared(self.nintems) self._avg = filter.single_pole_iir_filter_ff(1.0, self.nintems) self.snr = flaress.snr(self.auto_carrier, self.carrier, self.all_spectrum, self.freq_central, self.samp_rate, self.nintems, self.signal_bw, self.noise_bw) window_power = sum(map(lambda x: x*x, fft_window)) self.log = blocks.nlog10_ff(10, self.nintems, -20*math.log10(self.nintems) # Adjust for number of bins -10*math.log10(float(window_power)/self.nintems) # Adjust for windowing loss -20*math.log10(float(2)/2)) # Adjust for reference scale self.connect(self, self._sd, self.fft, self.c2magsq, self._avg, self.snr, (self, 0)) self.connect(self._avg, self.log, (self, 1)) self._average = average self._avg_alpha = avg_alpha self.set_avg_alpha(avg_alpha) self.set_average(average)
def __init__(self, m, n, nsamples, angular_resolution, frequency, array_spacing, antenna_array, output_spectrum=False): self.m = m self.n = n self.nsamples = nsamples self.angular_resolution = angular_resolution self.l = 299792458.0 / frequency self.antenna_array = [[array_spacing * x, array_spacing * y] for [x, y] in antenna_array] if (nsamples % m) != 0: raise Exception("nsamples must be multiple of m") if output_spectrum: output_sig = gr.io_signature3( 3, 3, (gr.sizeof_float * n), (gr.sizeof_float * n), (gr.sizeof_float * angular_resolution)) else: output_sig = gr.io_signature2(2, 2, (gr.sizeof_float * n), (gr.sizeof_float * n)) # output_sig = gr.io_signature2(2, 2, (gr.sizeof_float * n), (gr.sizeof_float * angular_resolution)) #else: # output_sig = gr.io_signature(1, 1, (gr.sizeof_float * n)) gr.hier_block2.__init__( self, "music_doa_helper", gr.io_signature(1, 1, (gr.sizeof_gr_complex * nsamples)), output_sig) #gr.io_signature3(1, 3, (gr.sizeof_float * n), # (gr.sizeof_float * angular_resolution), # (gr.sizeof_float * angular_resolution))) print "MUSIC DOA Helper: M: %d, N: %d, # samples: %d, steps of %f degress, lambda: %f, array: %s" % ( self.m, self.n, self.nsamples, (360.0 / self.angular_resolution), self.l, str(self.antenna_array)) #print "--> Calculating array response..." self.array_response = calculate_antenna_array_response( self.antenna_array, self.angular_resolution, self.l) #print "--> Done." #print self.array_response self.impl = baz.music_doa(self.m, self.n, self.nsamples, self.array_response, self.angular_resolution) self.connect(self, self.impl) self.connect((self.impl, 0), (self, 0)) self.connect((self.impl, 1), (self, 1)) if output_spectrum: self.connect((self.impl, 2), (self, 2))
def __init__(self, total_subcarriers, frame_length, frame_data_part, training_data): #config = station_configuration() total_subc = total_subcarriers vlen = total_subc gr.hier_block2.__init__( self, "fbmc_frame_sampler_grc", gr.io_signature2(2, 2, gr.sizeof_gr_complex * vlen, gr.sizeof_char), gr.io_signature2(2, 2, gr.sizeof_gr_complex * vlen, gr.sizeof_char)) frame_size = frame_data_part + training_data.fbmc_no_preambles / 2 print "frame_size: ", frame_size ft = [0] * frame_size 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 = vector_sampler(gr.sizeof_gr_complex * total_subc, frame_size) symbol_output = blocks.vector_to_stream( gr.sizeof_gr_complex * total_subc, frame_size) #delayed_frame_start = blocks.delay( gr.sizeof_char, config.frame_length-1 - config.training_data.fbmc_no_preambles/2 ) delayed_frame_start = blocks.delay(gr.sizeof_char, frame_length / 2 - 1) damn_static_frame_trigger = blocks.vector_source_b(ft, True) #oqam_postpro = ofdm.fbmc_oqam_postprocessing_vcvc(total_subc,0,0) self.connect(self, frame_sampler, symbol_output, self) #self.connect( (self,1), blocks.keep_m_in_n(gr.sizeof_char,frame_data_part + training_data.fbmc_no_preambles/2,2*frame_data_part + training_data.fbmc_no_preambles,0),delayed_frame_start, ( frame_sampler, 1 ) ) self.connect((self, 1), delayed_frame_start, (frame_sampler, 1)) #self.connect( self, blocks.multiply_const_vcc(([1.0]*total_subc)) ,self) #terminate_stream(self,frame_sampler) self.connect(damn_static_frame_trigger, (self, 1))
def __init__(self,options): config = station_configuration() total_subc = config.subcarriers vlen = total_subc gr.hier_block2.__init__(self,"fbmc_frame_sampler", gr.io_signature2(2,2,gr.sizeof_gr_complex*vlen, gr.sizeof_char), gr.io_signature2(2,2,gr.sizeof_gr_complex*vlen, gr.sizeof_char)) frame_size = config.frame_data_part + config.training_data.fbmc_no_preambles/2 print "frame_size: ", frame_size ft = [0] * frame_size 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, frame_size ) symbol_output = blocks.vector_to_stream( gr.sizeof_gr_complex * total_subc, frame_size ) #delayed_frame_start = blocks.delay( gr.sizeof_char, config.frame_length-1 - config.training_data.fbmc_no_preambles/2 ) delayed_frame_start = blocks.delay( gr.sizeof_char, config.frame_length/2-1) damn_static_frame_trigger = blocks.vector_source_b( ft, True ) #oqam_postpro = ofdm.fbmc_oqam_postprocessing_vcvc(total_subc,0,0) self.connect( self, frame_sampler, symbol_output ,self) #self.connect( (self,1), blocks.keep_m_in_n(gr.sizeof_char,config.frame_data_part + config.training_data.fbmc_no_preambles/2,2*config.frame_data_part + config.training_data.fbmc_no_preambles,0),delayed_frame_start, ( frame_sampler, 1 ) ) self.connect( (self,1), delayed_frame_start, ( frame_sampler, 1 ) ) #self.connect( self, blocks.multiply_const_vcc(([1.0]*total_subc)) ,self) #terminate_stream(self,frame_sampler) self.connect( damn_static_frame_trigger, (self,1) )
def __init__(self,options): config = station_configuration() total_subc = config.subcarriers vlen = total_subc gr.hier_block2.__init__(self,"ofdm_frame_sampler", gr.io_signature2(2,2,gr.sizeof_gr_complex*vlen, gr.sizeof_char), gr.io_signature2(2,2,gr.sizeof_gr_complex*vlen, gr.sizeof_char)) 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 ) 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 ) #oqam_postpro = ofdm.fbmc_oqam_postprocessing_vcvc(total_subc,0,0) if options.enable_erasure_decision: self.frame_gate = vector_sampler( gr.sizeof_gr_complex * total_subc * config.frame_length, 1 ) self.connect( self, frame_sampler, self.frame_gate, symbol_output ) else: self.connect( self, frame_sampler, symbol_output, self ) self.connect( (self,1), delayed_frame_start, ( frame_sampler, 1 ) ) self.connect( damn_static_frame_trigger, (self,1) )
def __init__(self, itemsize, filename): gr.hier_block2.__init__( self, "file_source2", gr.io_signature(0, 0, 0), gr.io_signature2(2, 2, itemsize[0], itemsize[1])) self.file_source0 = blocks.file_source(itemsize=itemsize[0], filename=filename[0]) self.file_source1 = blocks.file_source(itemsize=itemsize[1], filename=filename[1]) self.connect(self.file_source0, (self, 0)) self.connect(self.file_source1, (self, 1))
def __init__(self, ): gr.hier_block2.__init__(self, "decode_bch_vfvb", gr.io_signature(1,1, gr.sizeof_float*120), # Input signature gr.io_signature2(2,2, gr.sizeof_char*24, gr.sizeof_char)) # Output signature # Define blocks self.rate_unmatch = lte.rate_unmatch_vff() self.viterbi = lte.viterbi_vfvb() self.crc = lte.crc_calculator_vbvb() self.connect(self, self.rate_unmatch, self.viterbi, (self.crc, 0), (self, 0)) self.connect((self.crc, 1), (self, 1))
def __init__(self, m, n, nsamples, angular_resolution, frequency, array_spacing, antenna_array, output_spectrum=False): self.m = m self.n = n self.nsamples = nsamples self.angular_resolution = angular_resolution self.l = 299792458.0 / frequency self.antenna_array = [[array_spacing * x, array_spacing * y] for [x,y] in antenna_array] if (nsamples % m) != 0: raise Exception("nsamples must be multiple of m") if output_spectrum: output_sig = gr.io_signature3(3, 3, (gr.sizeof_float * n), (gr.sizeof_float * n), (gr.sizeof_float * angular_resolution)) else: output_sig = gr.io_signature2(2, 2, (gr.sizeof_float * n), (gr.sizeof_float * n)) # output_sig = gr.io_signature2(2, 2, (gr.sizeof_float * n), (gr.sizeof_float * angular_resolution)) #else: # output_sig = gr.io_signature(1, 1, (gr.sizeof_float * n)) gr.hier_block2.__init__(self, "music_doa_helper", gr.io_signature(1, 1, (gr.sizeof_gr_complex * nsamples)), output_sig) #gr.io_signature3(1, 3, (gr.sizeof_float * n), # (gr.sizeof_float * angular_resolution), # (gr.sizeof_float * angular_resolution))) print "MUSIC DOA Helper: M: %d, N: %d, # samples: %d, steps of %f degress, lambda: %f, array: %s" % ( self.m, self.n, self.nsamples, (360.0/self.angular_resolution), self.l, str(self.antenna_array) ) #print "--> Calculating array response..." self.array_response = calculate_antenna_array_response(self.antenna_array, self.angular_resolution, self.l) #print "--> Done." #print self.array_response self.impl = baz.music_doa(self.m, self.n, self.nsamples, self.array_response, self.angular_resolution) self.connect(self, self.impl) self.connect((self.impl, 0), (self, 0)) self.connect((self.impl, 1), (self, 1)) if output_spectrum: self.connect((self.impl, 2), (self, 2))
def __init__(self, itemsize, filename, append=[False, False]): gr.hier_block2.__init__( self, "file_sink2", gr.io_signature2(2, 2, itemsize[0], itemsize[1]), gr.io_signature(0, 0, 0)) self.file_sink0 = blocks.file_sink(itemsize=itemsize[0], filename=filename[0], append=append[0]) self.file_sink1 = blocks.file_sink(itemsize=itemsize[1], filename=filename[1], append=append[1]) self.connect((self, 0), self.file_sink0) self.connect((self, 1), self.file_sink1)
def __init__(self,subcarriers,operational_block): gr.hier_block2.__init__(self, "common_power_allocator", gr.io_signature2(2,2,gr.sizeof_gr_complex*subcarriers, gr.sizeof_float*subcarriers), gr.io_signature (1,1,gr.sizeof_gr_complex*subcarriers)) data = (self,0) power = (self,1) to_ampl = sqrt_vff(subcarriers) f2c = gr.float_to_complex(subcarriers) adjust = operational_block self.connect(data,(adjust,0)) self.connect(power,to_ampl,f2c,(adjust,1)) self.connect(adjust, self)
def __init__(self, subcarriers, operational_block): gr.hier_block2.__init__( self, "common_power_allocator", gr.io_signature2(2, 2, gr.sizeof_gr_complex * subcarriers, gr.sizeof_float * subcarriers), gr.io_signature(1, 1, gr.sizeof_gr_complex * subcarriers)) data = (self, 0) power = (self, 1) to_ampl = sqrt_vff(subcarriers) f2c = gr.float_to_complex(subcarriers) adjust = operational_block self.connect(data, (adjust, 0)) self.connect(power, to_ampl, f2c, (adjust, 1)) self.connect(adjust, self)
def __init__(self, options): """ @param options: parsed raw.ofdm_params """ self.params = ofdm_params(options) params = self.params gr.hier_block2.__init__( self, "ofdm_mod", gr.io_signature2(2, 2, gr.sizeof_gr_complex * params.data_tones, gr.sizeof_char), # Input signature gr.io_signature(1, 1, gr.sizeof_gr_complex)) # Output signature win = [] #[1 for i in range(self._fft_length)] # see gr_fft_vcc_fftw that it works differently if win = [1 1 1 ...] self.mapper = raw.ofdm_mapper(params.padded_carriers) self.preambles = digital.ofdm_insert_preamble(params.fft_length, params.padded_preambles) self.ifft = gr.fft_vcc(params.fft_length, False, win, True) self.cp_adder = digital.ofdm_cyclic_prefixer( params.fft_length, params.fft_length + params.cp_length) self.scale = gr.multiply_const_cc(1.0 / math.sqrt(params.fft_length)) self.connect((self, 0), self.mapper, (self.preambles, 0)) self.connect((self, 1), (self.preambles, 1)) self.connect(self.preambles, self.ifft, self.cp_adder, self.scale, self) if options.log: self.connect( self.mapper, gr.file_sink(gr.sizeof_gr_complex * params.fft_length, "tx-map.dat")) self.connect( self.preambles, gr.file_sink(gr.sizeof_gr_complex * params.fft_length, "tx-pre.dat")) self.connect( self.ifft, gr.file_sink(gr.sizeof_gr_complex * params.fft_length, "tx-ifft.dat")) self.connect(self.cp_adder, gr.file_sink(gr.sizeof_gr_complex, "tx-cp.dat"))
def __init__(self, m, n, nsamples, angular_resolution, frequency, array_spacing, antenna_array, output_spectrum=False): self.c = 299792458.0 # speed of light in m/s [SciPy could be used for this but would introduce a new dependency] self.m = m self.n = n self.nsamples = nsamples self.angular_resolution = angular_resolution self.l_lambda = self.c / frequency # wavelength! Unfortunately 'lambda' is a Python key word. self.antenna_array = [[array_spacing * x, array_spacing * y] for [x, y] in antenna_array] if (nsamples % m) != 0: raise Exception("nsamples must be multiple of m") if output_spectrum: output_sig = gr.io_signature3(3, 3, (gr.sizeof_float * n), (gr.sizeof_float * n), (gr.sizeof_float * angular_resolution)) else: output_sig = gr.io_signature2(2, 2, (gr.sizeof_float * n), (gr.sizeof_float * n)) gr.hier_block2.__init__(self, "music_doa_helper", gr.io_signature(1, 1, (gr.sizeof_gr_complex * nsamples)), output_sig) print "MUSIC DOA Helper: M: %d, N: %d, # samples: %d, steps of %f degress, lambda: %f, array: %s" % ( self.m, self.n, self.nsamples, (360.0 / self.angular_resolution), self.l_lambda, str(self.antenna_array) ) #print "--> Calculating array response..." self.array_response = calculate_antenna_array_response(self.antenna_array, self.angular_resolution, self.l_lambda) #print "--> Done." #print self.array_response self.impl = misc.music_doa(self.m, self.n, self.nsamples, self.array_response, self.angular_resolution) self.connect(self, self.impl) self.connect((self.impl, 0), (self, 0)) self.connect((self.impl, 1), (self, 1)) if output_spectrum: self.connect((self.impl, 2), (self, 2))
def __init__(self, itemsize, filename): gr.hier_block2.__init__(self, "file_source2", gr.io_signature(0, 0, 0), gr.io_signature2(2, 2, itemsize[0], itemsize[1])) self.file_source0 = blocks.file_source( itemsize=itemsize[0], filename=filename[0] ) self.file_source1 = blocks.file_source( itemsize=itemsize[1], filename=filename[1] ) self.connect(self.file_source0, (self, 0)) self.connect(self.file_source1, (self, 1))
def __init__(self, itemsize, filename, append=[False, False]): gr.hier_block2.__init__(self, "file_sink2", gr.io_signature2(2, 2, itemsize[0], itemsize[1]), gr.io_signature(0, 0, 0)) self.file_sink0 = blocks.file_sink( itemsize=itemsize[0], filename=filename[0], append=append[0] ) self.file_sink1 = blocks.file_sink( itemsize=itemsize[1], filename=filename[1], append=append[1] ) self.connect((self, 0), self.file_sink0) self.connect((self, 1), self.file_sink1)
def __init__(self, fft_length, L): gr.hier_block2.__init__(self, "morelli_foe", gr.io_signature2(2,2,gr.sizeof_gr_complex,gr.sizeof_char), gr.io_signature(1,1,gr.sizeof_float)) data_in = (self,0) trig_in = (self,1) est_out = (self,0) #inp = gr.kludge_copy(gr.sizeof_gr_complex) #self.connect(data_in,inp) inp = data_in sampler = vector_sampler(gr.sizeof_gr_complex,fft_length) self.connect(inp,(sampler,0)) self.connect(trig_in,(sampler,1)) est = mm_frequency_estimator(fft_length,L) self.connect(sampler,est,est_out)
def __init__(self, data_tones, num_symbols, mode=0): symbol_size = data_tones * gr.sizeof_gr_complex gr.hier_block2.__init__(self, "SNR", gr.io_signature2(2,2, symbol_size, symbol_size), gr.io_signature(1,1, gr.sizeof_float)) sub = gr.sub_cc(data_tones) self.connect((self,0), (sub,0)) self.connect((self,1), (sub,1)) err = gr.complex_to_mag_squared(data_tones); self.connect(sub, err); pow = gr.complex_to_mag_squared(data_tones); self.connect((self,1), pow); if mode == 0: # one snr per symbol (num_symbols is ignored) snr = gr.divide_ff() self.connect(pow, gr.vector_to_stream(gr.sizeof_float, data_tones), gr.integrate_ff(data_tones), (snr,0)) self.connect(err, gr.vector_to_stream(gr.sizeof_float, data_tones), gr.integrate_ff(data_tones), (snr,1)) out = snr elif mode == 1: # one snr per packet snr = gr.divide_ff() self.connect(pow, gr.vector_to_stream(gr.sizeof_float, data_tones), gr.integrate_ff(data_tones*num_symbols), (snr,0)) self.connect(err, gr.vector_to_stream(gr.sizeof_float, data_tones), gr.integrate_ff(data_tones*num_symbols), (snr,1)) out = snr elif mode == 2: # one snr per frequency bin snr = gr.divide_ff(data_tones) self.connect(pow, raw.symbol_avg(data_tones, num_symbols), (snr,0)) self.connect(err, raw.symbol_avg(data_tones, num_symbols), (snr,1)) out = gr.vector_to_stream(gr.sizeof_float, data_tones) self.connect(snr, out) self.connect(out, gr.nlog10_ff(10), self)
def __init__(self, framebytes, numframes, mode=0): gr.hier_block2.__init__(self, "BER", gr.io_signature2(2,2, framebytes, framebytes), gr.io_signature(1,1, gr.sizeof_float)) xor = gr.xor_bb() self.connect((self,0), gr.vector_to_stream(gr.sizeof_char, framebytes), (xor,0)) self.connect((self,1), gr.vector_to_stream(gr.sizeof_char, framebytes), (xor,1)) if mode == 0: # one ber per packet ber = raw.ber_avg(1, framebytes) self.connect(xor, ber) elif mode == 1: # one ber per byte in packet ber = raw.ber_avg(framebytes, numframes) self.connect(xor, gr.stream_to_vector(gr.sizeof_char, framebytes), ber) self.connect(ber, self)
def __init__(self, fft_length, cp_length, nsymbols, freq_offset, logging=False): gr.hier_block2.__init__( self, "ofdm_sync_fixed", gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature gr.io_signature2(2, 2, gr.sizeof_float, gr.sizeof_char)) # Output signature # Use a fixed trigger point instead of sync block symbol_length = fft_length + cp_length pkt_length = nsymbols * symbol_length data = (pkt_length) * [ 0, ] data[(symbol_length) - 1] = 1 self.peak_trigger = blocks.vector_source_b(data, True) # Use a pre-defined frequency offset foffset = (pkt_length) * [ math.pi * freq_offset, ] self.frequency_offset = blocks.vector_source_f(foffset, True) self.connect(self, blocks.null_sink(gr.sizeof_gr_complex)) self.connect(self.frequency_offset, (self, 0)) self.connect(self.peak_trigger, (self, 1)) if logging: self.connect( self.peak_trigger, blocks.file_sink(gr.sizeof_char, "ofdm_sync_fixed-peaks_b.dat"))
def __init__(self, options): """ @param options: parsed raw.ofdm_params """ self.params = ofdm_params(options) params = self.params gr.hier_block2.__init__(self, "ofdm_mod", gr.io_signature2(2, 2, gr.sizeof_gr_complex*params.data_tones, gr.sizeof_char), # Input signature gr.io_signature(1, 1, gr.sizeof_gr_complex)) # Output signature win = [] #[1 for i in range(self._fft_length)] # see gr_fft_vcc_fftw that it works differently if win = [1 1 1 ...] self.mapper = raw.ofdm_mapper(params.padded_carriers) self.preambles = digital.ofdm_insert_preamble(params.fft_length, params.padded_preambles) self.ifft = gr.fft_vcc(params.fft_length, False, win, True) self.cp_adder = digital.ofdm_cyclic_prefixer(params.fft_length, params.fft_length + params.cp_length) self.scale = gr.multiply_const_cc(1.0 / math.sqrt(params.fft_length)) self.connect((self,0), self.mapper, (self.preambles,0)) self.connect((self,1), (self.preambles,1)) self.connect(self.preambles, self.ifft, self.cp_adder, self.scale, self) if options.log: self.connect(self.mapper, gr.file_sink(gr.sizeof_gr_complex*params.fft_length, "tx-map.dat")) self.connect(self.preambles, gr.file_sink(gr.sizeof_gr_complex*params.fft_length, "tx-pre.dat")) self.connect(self.ifft, gr.file_sink(gr.sizeof_gr_complex*params.fft_length, "tx-ifft.dat")) self.connect(self.cp_adder, gr.file_sink(gr.sizeof_gr_complex, "tx-cp.dat"))
def __init__(self, fft_length, cp_length, nsymbols, freq_offset, logging=False): gr.hier_block2.__init__(self, "ofdm_sync_fixed", gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature gr.io_signature2(2, 2, gr.sizeof_float, gr.sizeof_char)) # Output signature # Use a fixed trigger point instead of sync block symbol_length = fft_length + cp_length pkt_length = nsymbols*symbol_length data = (pkt_length)*[0,] data[(symbol_length)-1] = 1 self.peak_trigger = blocks.vector_source_b(data, True) # Use a pre-defined frequency offset foffset = (pkt_length)*[math.pi*freq_offset,] self.frequency_offset = blocks.vector_source_f(foffset, True) self.connect(self, blocks.null_sink(gr.sizeof_gr_complex)) self.connect(self.frequency_offset, (self,0)) self.connect(self.peak_trigger, (self,1)) if logging: self.connect(self.peak_trigger, blocks.file_sink(gr.sizeof_char, "ofdm_sync_fixed-peaks_b.dat"))
def __init__(self, samples_per_symbol=1): gr.hier_block2.__init__(self, 'gsm_modulate_burst', gr.io_signature2(2, 2, 58 * 2, 1), gr.io_signature(1, 1, gr.sizeof_gr_complex)) # take care of the packetizer conf = mlse.make_packet_config_gsm() self.packetbuilder = mlse.packetbuilder_midamble_vbb(conf) self.connect(self, self.packetbuilder) self.connect((self, 1), (self.packetbuilder, 1)) # tsc_index # append 8 1-bits to the packet for the idle-time between bursts. # This is necessary among others to flush the gmsk-modulator which is causal. # (We use 1-bits because that's what the gsm-standard says) # (we also only use 8 bits, because the specified value of 8.25 only works # properly with samplerates that are a multiple of 4.) self.guardbits = gr.vector_source_b((1, ) * 8, True, 8) self.guard_cat = mlse.vector_concat_vv(148, 8) self.connect(self.packetbuilder, self.guard_cat) self.connect(self.guardbits, (self.guard_cat, 1)) # we now have a vector of bits, transform that into a stream self.tostream = gr.vector_to_stream(1, 148 + 8) # do the precoding: self.diffcode = gr.diff_decoder_bb(2) self.nrz = gr.map_bb([1, -1]) self.connect(self.guard_cat, self.tostream, self.diffcode, self.nrz) # modulate self.mod = digital.gmskmod_bc(samples_per_symbol, 0.3, 8) # skip the first gmsk_length*samplerate/2 samples to make this block # acausal. # self.skiphead = gr.skiphead(gr.sizeof_gr_complex, int(samples_per_symbol*4.5)); # self.connect(self.nrz, self.mod, self.skiphead, self) self.connect(self.nrz, self.mod, self) # workaround: we need a negative delay later,
def __init__(self, samples_per_symbol = 1): gr.hier_block2.__init__(self, 'gsm_modulate_burst', gr.io_signature2(2,2,58*2,1), gr.io_signature(1, 1, gr.sizeof_gr_complex)) # take care of the packetizer conf = mlse.make_packet_config_gsm() self.packetbuilder = mlse.packetbuilder_midamble_vbb(conf) self.connect(self, self.packetbuilder) self.connect((self,1), (self.packetbuilder,1)) # tsc_index # append 8 1-bits to the packet for the idle-time between bursts. # This is necessary among others to flush the gmsk-modulator which is causal. # (We use 1-bits because that's what the gsm-standard says) # (we also only use 8 bits, because the specified value of 8.25 only works # properly with samplerates that are a multiple of 4.) self.guardbits = gr.vector_source_b((1,)*8,True,8) self.guard_cat = mlse.vector_concat_vv(148,8) self.connect(self.packetbuilder, self.guard_cat) self.connect(self.guardbits, (self.guard_cat,1)) # we now have a vector of bits, transform that into a stream self.tostream = gr.vector_to_stream(1, 148+8) # do the precoding: self.diffcode = gr.diff_decoder_bb(2); self.nrz = gr.map_bb([1,-1]) self.connect(self.guard_cat, self.tostream, self.diffcode, self.nrz) # modulate self.mod = digital.gmskmod_bc(samples_per_symbol, 0.3, 8) # skip the first gmsk_length*samplerate/2 samples to make this block # acausal. # self.skiphead = gr.skiphead(gr.sizeof_gr_complex, int(samples_per_symbol*4.5)); # self.connect(self.nrz, self.mod, self.skiphead, self) self.connect(self.nrz, self.mod, self) # workaround: we need a negative delay later,
def __init__(self, fft_length, cp_length, occupied_tones, snr, ks, carrier_map_bin, nc_filter, logging=False): """ Hierarchical block for receiving OFDM symbols. The input is the complex modulated signal at baseband. Synchronized packets are sent back to the demodulator. @param fft_length: total number of subcarriers @type fft_length: int @param cp_length: length of cyclic prefix as specified in subcarriers (<= fft_length) @type cp_length: int @param occupied_tones: number of subcarriers used for data @type occupied_tones: int @param snr: estimated signal to noise ratio used to guide cyclic prefix synchronizer @type snr: float @param ks: known symbols used as preambles to each packet @type ks: list of lists @param logging: turn file logging on or off @type logging: bool """ gr.hier_block2.__init__(self, "ofdm_receiver", gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature gr.io_signature2(2, 2, gr.sizeof_gr_complex*occupied_tones, gr.sizeof_char)) # Output signature bw = (float(occupied_tones) / float(fft_length)) / 2.0 tb = bw*0.04 print "ofdm_receiver:__init__:occupied_tones %s fft_length %d " % (occupied_tones, fft_length) chan_coeffs = filter.firdes.low_pass (1.0, # gain 1.0, # sampling rate bw+tb, # midpoint of trans. band tb, # width of trans. band filter.firdes.WIN_HAMMING) # filter type self.chan_filt = filter.fft_filter_ccc(1, chan_coeffs) # linklab, get ofdm parameters self._fft_length = fft_length self._occupied_tones = occupied_tones self._cp_length = cp_length self._nc_filter = nc_filter self._carrier_map_bin = carrier_map_bin win = [1 for i in range(fft_length)] # linklab, initialization function self.initialize(ks, self._carrier_map_bin) zeros_on_left = int(math.ceil((fft_length - occupied_tones)/2.0)) ks0 = fft_length*[0,] ks0[zeros_on_left : zeros_on_left + occupied_tones] = ks[0] ks0 = np_fft.ifftshift(ks0) ks0time = np_fft.ifft(ks0) # ADD SCALING FACTOR ks0time = ks0time.tolist() SYNC = "pn" if SYNC == "ml": nco_sensitivity = -1.0/fft_length # correct for fine frequency self.ofdm_sync = ofdm_sync_ml(fft_length, cp_length, snr, ks0time, logging) elif SYNC == "pn": nco_sensitivity = -2.0/fft_length # correct for fine frequency self.ofdm_sync = ofdm_sync_pn(fft_length, cp_length, logging) elif SYNC == "pnac": nco_sensitivity = -2.0/fft_length # correct for fine frequency self.ofdm_sync = ofdm_sync_pnac(fft_length, cp_length, ks0time, logging) # for testing only; do not user over the air # remove filter and filter delay for this elif SYNC == "fixed": self.chan_filt = gr.multiply_const_cc(1.0) nsymbols = 18 # enter the number of symbols per packet freq_offset = 0.0 # if you use a frequency offset, enter it here nco_sensitivity = -2.0/fft_length # correct for fine frequency self.ofdm_sync = ofdm_sync_fixed(fft_length, cp_length, nsymbols, freq_offset, logging) # Set up blocks # Create a delay line, linklab self.delay = blocks.delay(gr.sizeof_gr_complex, fft_length) self.nco = analog.frequency_modulator_fc(nco_sensitivity) # generate a signal proportional to frequency error of sync block self.sigmix = blocks.multiply_cc() self.sampler = gr_papyrus.ofdm_sampler(fft_length, fft_length+cp_length) self.fft_demod = gr_fft.fft_vcc(fft_length, True, win, True) self.ofdm_frame_acq = gr_papyrus.ofdm_frame_acquisition(occupied_tones, fft_length, cp_length, ks[0]) # linklab, check current mode: non-contiguous OFDM or not if self._nc_filter: print '\nMulti-band Filter Turned ON!' # linklab, non-contiguous filter self.ncofdm_filt = ncofdm_filt(self._fft_length, self._occupied_tones, self._carrier_map_bin) self.connect(self, self.chan_filt, self.ncofdm_filt) self.connect(self.ncofdm_filt, self.ofdm_sync) # into the synchronization alg. self.connect((self.ofdm_sync,0), self.nco, (self.sigmix,1)) # use sync freq. offset output to derotate input signal self.connect(self.ncofdm_filt, self.delay, (self.sigmix,0)) # signal to be derotated else : print '\nMulti-band Filter Turned OFF!' self.connect(self, self.chan_filt) self.connect(self.chan_filt, self.ofdm_sync) # into the synchronization alg. self.connect((self.ofdm_sync,0), self.nco, (self.sigmix,1)) # use sync freq. offset output to derotate input signal self.connect(self.chan_filt, self.delay, (self.sigmix,0)) # signal to be derotated self.connect(self.sigmix, (self.sampler,0)) # sample off timing signal detected in sync alg self.connect((self.ofdm_sync,1), (self.sampler,1)) # timing signal to sample at self.connect((self.sampler,0), self.fft_demod) # send derotated sampled signal to FFT self.connect(self.fft_demod, (self.ofdm_frame_acq,0)) # find frame start and equalize signal self.connect((self.sampler,1), (self.ofdm_frame_acq,1)) # send timing signal to signal frame start self.connect((self.ofdm_frame_acq,0), (self,0)) # finished with fine/coarse freq correction, self.connect((self.ofdm_frame_acq,1), (self,1)) # frame and symbol timing, and equalization if logging: self.connect(self.chan_filt, gr.file_sink(gr.sizeof_gr_complex, "ofdm_receiver-chan_filt_c.dat")) self.connect(self.fft_demod, gr.file_sink(gr.sizeof_gr_complex*fft_length, "ofdm_receiver-fft_out_c.dat")) self.connect(self.ofdm_frame_acq, gr.file_sink(gr.sizeof_gr_complex*occupied_tones, "ofdm_receiver-frame_acq_c.dat")) self.connect((self.ofdm_frame_acq,1), gr.file_sink(1, "ofdm_receiver-found_corr_b.dat")) self.connect(self.sampler, gr.file_sink(gr.sizeof_gr_complex*fft_length, "ofdm_receiver-sampler_c.dat")) self.connect(self.sigmix, gr.file_sink(gr.sizeof_gr_complex, "ofdm_receiver-sigmix_c.dat")) self.connect(self.nco, gr.file_sink(gr.sizeof_gr_complex, "ofdm_receiver-nco_c.dat"))
def __init__(self, fft_length, cp_length, logging=False): """ OFDM synchronization using PN Correlation: T. M. Schmidl and D. C. Cox, "Robust Frequency and Timing Synchonization for OFDM," IEEE Trans. Communications, vol. 45, no. 12, 1997. """ gr.hier_block2.__init__(self, "ofdm_sync_pn", gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature gr.io_signature2(2, 2, gr.sizeof_float, gr.sizeof_char)) # Output signature self.input = gr.add_const_cc(0) # PN Sync # Create a delay line self.delay = gr.delay(gr.sizeof_gr_complex, fft_length/2) # Correlation from ML Sync self.conjg = gr.conjugate_cc(); self.corr = gr.multiply_cc(); # Create a moving sum filter for the corr output if 1: moving_sum_taps = [1.0 for i in range(fft_length//2)] self.moving_sum_filter = gr.fir_filter_ccf(1,moving_sum_taps) else: moving_sum_taps = [complex(1.0,0.0) for i in range(fft_length//2)] self.moving_sum_filter = gr.fft_filter_ccc(1,moving_sum_taps) # Create a moving sum filter for the input self.inputmag2 = gr.complex_to_mag_squared() # Modified by Yong (12.06.27) #movingsum2_taps = [1.0 for i in range(fft_length//2)] movingsum2_taps = [0.5 for i in range(fft_length)] if 1: self.inputmovingsum = gr.fir_filter_fff(1,movingsum2_taps) else: self.inputmovingsum = gr.fft_filter_fff(1,movingsum2_taps) self.square = gr.multiply_ff() self.normalize = gr.divide_ff() # Get magnitude (peaks) and angle (phase/freq error) self.c2mag = gr.complex_to_mag_squared() self.angle = gr.complex_to_arg() self.sample_and_hold = gr.sample_and_hold_ff() #ML measurements input to sampler block and detect self.sub1 = gr.add_const_ff(-1) self.pk_detect = gr.peak_detector_fb(0.20, 0.20, 30, 0.001) #self.pk_detect = gr.peak_detector2_fb(9) self.connect(self, self.input) # Calculate the frequency offset from the correlation of the preamble self.connect(self.input, self.delay) self.connect(self.input, (self.corr,0)) self.connect(self.delay, self.conjg) self.connect(self.conjg, (self.corr,1)) self.connect(self.corr, self.moving_sum_filter) self.connect(self.moving_sum_filter, self.c2mag) self.connect(self.moving_sum_filter, self.angle) self.connect(self.angle, (self.sample_and_hold,0)) # Get the power of the input signal to normalize the output of the correlation self.connect(self.input, self.inputmag2, self.inputmovingsum) self.connect(self.inputmovingsum, (self.square,0)) self.connect(self.inputmovingsum, (self.square,1)) self.connect(self.square, (self.normalize,1)) self.connect(self.c2mag, (self.normalize,0)) # Create a moving sum filter for the corr output matched_filter_taps = [1.0/cp_length for i in range(cp_length)] self.matched_filter = gr.fir_filter_fff(1,matched_filter_taps) self.connect(self.normalize, self.matched_filter) self.connect(self.matched_filter, self.sub1, self.pk_detect) #self.connect(self.matched_filter, self.pk_detect) self.connect(self.pk_detect, (self.sample_and_hold,1)) # Set output signals # Output 0: fine frequency correction value # Output 1: timing signal self.connect(self.sample_and_hold, (self,0)) self.connect(self.pk_detect, (self,1)) if logging: self.connect(self.matched_filter, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-mf_f.dat")) self.connect(self.c2mag, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-nominator_f.dat")) self.connect(self.square, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-denominator_f.dat")) self.connect(self.normalize, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-theta_f.dat")) self.connect(self.angle, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-epsilon_f.dat")) self.connect(self.pk_detect, gr.file_sink(gr.sizeof_char, "ofdm_sync_pn-peaks_b.dat")) self.connect(self.sample_and_hold, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-sample_and_hold_f.dat")) self.connect(self.input, gr.file_sink(gr.sizeof_gr_complex, "ofdm_sync_pn-input_c.dat"))
def __init__(self, fft_length, cp_length, snr, kstime, logging): ''' Maximum Likelihood OFDM synchronizer: J. van de Beek, M. Sandell, and P. O. Borjesson, "ML Estimation of Time and Frequency Offset in OFDM Systems," IEEE Trans. Signal Processing, vol. 45, no. 7, pp. 1800-1805, 1997. ''' gr.hier_block2.__init__(self, "ofdm_sync_ml", gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature gr.io_signature2(2, 2, gr.sizeof_float, gr.sizeof_char)) # Output signature self.input = blocks.add_const_cc(0) SNR = 10.0**(snr / 10.0) rho = SNR / (SNR + 1.0) symbol_length = fft_length + cp_length # ML Sync # Energy Detection from ML Sync self.connect(self, self.input) # Create a delay line self.delay = blocks.delay(gr.sizeof_gr_complex, fft_length) self.connect(self.input, self.delay) # magnitude squared blocks self.magsqrd1 = blocks.complex_to_mag_squared() self.magsqrd2 = blocks.complex_to_mag_squared() self.adder = blocks.add_ff() moving_sum_taps = [rho / 2 for i in range(cp_length)] self.moving_sum_filter = filter.fir_filter_fff(1,moving_sum_taps) self.connect(self.input,self.magsqrd1) self.connect(self.delay,self.magsqrd2) self.connect(self.magsqrd1,(self.adder,0)) self.connect(self.magsqrd2,(self.adder,1)) self.connect(self.adder,self.moving_sum_filter) # Correlation from ML Sync self.conjg = blocks.conjugate_cc(); self.mixer = blocks.multiply_cc(); movingsum2_taps = [1.0 for i in range(cp_length)] self.movingsum2 = filter.fir_filter_ccf(1,movingsum2_taps) # Correlator data handler self.c2mag = blocks.complex_to_mag() self.angle = blocks.complex_to_arg() self.connect(self.input,(self.mixer,1)) self.connect(self.delay,self.conjg,(self.mixer,0)) self.connect(self.mixer,self.movingsum2,self.c2mag) self.connect(self.movingsum2,self.angle) # ML Sync output arg, need to find maximum point of this self.diff = blocks.sub_ff() self.connect(self.c2mag,(self.diff,0)) self.connect(self.moving_sum_filter,(self.diff,1)) #ML measurements input to sampler block and detect self.f2c = blocks.float_to_complex() self.pk_detect = blocks.peak_detector_fb(0.2, 0.25, 30, 0.0005) self.sample_and_hold = blocks.sample_and_hold_ff() # use the sync loop values to set the sampler and the NCO # self.diff = theta # self.angle = epsilon self.connect(self.diff, self.pk_detect) # The DPLL corrects for timing differences between CP correlations use_dpll = 0 if use_dpll: self.dpll = gr.dpll_bb(float(symbol_length),0.01) self.connect(self.pk_detect, self.dpll) self.connect(self.dpll, (self.sample_and_hold,1)) else: self.connect(self.pk_detect, (self.sample_and_hold,1)) self.connect(self.angle, (self.sample_and_hold,0)) ################################ # correlate against known symbol # This gives us the same timing signal as the PN sync block only on the preamble # we don't use the signal generated from the CP correlation because we don't want # to readjust the timing in the middle of the packet or we ruin the equalizer settings. kstime = [k.conjugate() for k in kstime] kstime.reverse() self.kscorr = filter.fir_filter_ccc(1, kstime) self.corrmag = blocks.complex_to_mag_squared() self.div = blocks.divide_ff() # The output signature of the correlation has a few spikes because the rest of the # system uses the repeated preamble symbol. It needs to work that generically if # anyone wants to use this against a WiMAX-like signal since it, too, repeats. # The output theta of the correlator above is multiplied with this correlation to # identify the proper peak and remove other products in this cross-correlation self.threshold_factor = 0.1 self.slice = blocks.threshold_ff(self.threshold_factor, self.threshold_factor, 0) self.f2b = blocks.float_to_char() self.b2f = blocks.char_to_float() self.mul = blocks.multiply_ff() # Normalize the power of the corr output by the energy. This is not really needed # and could be removed for performance, but it makes for a cleaner signal. # if this is removed, the threshold value needs adjustment. self.connect(self.input, self.kscorr, self.corrmag, (self.div,0)) self.connect(self.moving_sum_filter, (self.div,1)) self.connect(self.div, (self.mul,0)) self.connect(self.pk_detect, self.b2f, (self.mul,1)) self.connect(self.mul, self.slice) # Set output signals # Output 0: fine frequency correction value # Output 1: timing signal self.connect(self.sample_and_hold, (self,0)) self.connect(self.slice, self.f2b, (self,1)) if logging: self.connect(self.moving_sum_filter, blocks.file_sink(gr.sizeof_float, "ofdm_sync_ml-energy_f.dat")) self.connect(self.diff, blocks.file_sink(gr.sizeof_float, "ofdm_sync_ml-theta_f.dat")) self.connect(self.angle, blocks.file_sink(gr.sizeof_float, "ofdm_sync_ml-epsilon_f.dat")) self.connect(self.corrmag, blocks.file_sink(gr.sizeof_float, "ofdm_sync_ml-corrmag_f.dat")) self.connect(self.kscorr, blocks.file_sink(gr.sizeof_gr_complex, "ofdm_sync_ml-kscorr_c.dat")) self.connect(self.div, blocks.file_sink(gr.sizeof_float, "ofdm_sync_ml-div_f.dat")) self.connect(self.mul, blocks.file_sink(gr.sizeof_float, "ofdm_sync_ml-mul_f.dat")) self.connect(self.slice, blocks.file_sink(gr.sizeof_float, "ofdm_sync_ml-slice_f.dat")) self.connect(self.pk_detect, blocks.file_sink(gr.sizeof_char, "ofdm_sync_ml-peaks_b.dat")) if use_dpll: self.connect(self.dpll, blocks.file_sink(gr.sizeof_char, "ofdm_sync_ml-dpll_b.dat")) self.connect(self.sample_and_hold, blocks.file_sink(gr.sizeof_float, "ofdm_sync_ml-sample_and_hold_f.dat")) self.connect(self.input, blocks.file_sink(gr.sizeof_gr_complex, "ofdm_sync_ml-input_c.dat"))
def __init__(self, dab_params, verbose=False, debug=False): """ Hierarchical block for FIC decoding @param dab_params DAB parameter object (dab.parameters.dab_parameters) """ gr.hier_block2.__init__( self, "fic", gr.io_signature2(2, 2, gr.sizeof_float * dab_params.num_carriers * 2, gr.sizeof_char), gr.io_signature(1, 1, gr.sizeof_char * 32)) self.dp = dab_params self.verbose = verbose self.debug = debug # FIB selection and block partitioning self.select_fic_syms = dab.select_vectors(gr.sizeof_float, self.dp.num_carriers * 2, self.dp.num_fic_syms, 0) self.repartition_fic = dab.repartition_vectors( gr.sizeof_float, self.dp.num_carriers * 2, self.dp.fic_punctured_codeword_length, self.dp.num_fic_syms, self.dp.num_cifs) # unpuncturing self.unpuncture = dab.unpuncture_vff( self.dp.assembled_fic_puncturing_sequence, 0) # convolutional coding # self.fsm = trellis.fsm(self.dp.conv_code_in_bits, self.dp.conv_code_out_bits, self.dp.conv_code_generator_polynomials) self.fsm = trellis.fsm( 1, 4, [0133, 0171, 0145, 0133 ]) # OK (dumped to text and verified partially) self.conv_v2s = blocks.vector_to_stream( gr.sizeof_float, self.dp.fic_conv_codeword_length) # self.conv_decode = trellis.viterbi_combined_fb(self.fsm, 20, 0, 0, 1, [1./sqrt(2),-1/sqrt(2)] , trellis.TRELLIS_EUCLIDEAN) table = [ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1 ] assert (len(table) / 4 == self.fsm.O()) table = [(1 - 2 * x) / sqrt(2) for x in table] self.conv_decode = trellis.viterbi_combined_fb( self.fsm, 774, 0, 0, 4, table, trellis.TRELLIS_EUCLIDEAN) #self.conv_s2v = blocks.stream_to_vector(gr.sizeof_char, 774) self.conv_prune = dab.prune(gr.sizeof_char, self.dp.fic_conv_codeword_length / 4, 0, self.dp.conv_code_add_bits_input) # energy dispersal self.prbs_src = blocks.vector_source_b( self.dp.prbs(self.dp.energy_dispersal_fic_vector_length), True) #self.energy_v2s = blocks.vector_to_stream(gr.sizeof_char, self.dp.energy_dispersal_fic_vector_length) self.add_mod_2 = blocks.xor_bb() self.energy_s2v = blocks.stream_to_vector( gr.sizeof_char, self.dp.energy_dispersal_fic_vector_length) self.cut_into_fibs = dab.repartition_vectors( gr.sizeof_char, self.dp.energy_dispersal_fic_vector_length, self.dp.fib_bits, 1, self.dp.energy_dispersal_fic_fibs_per_vector) # connect all self.nullsink = blocks.null_sink(gr.sizeof_char) self.pack = blocks.unpacked_to_packed_bb(1, gr.GR_MSB_FIRST) self.fibout = blocks.stream_to_vector(1, 32) # self.filesink = gr.file_sink(gr.sizeof_char, "debug/fic.dat") self.fibsink = dab.fib_sink_vb() # self.connect((self,0), (self.select_fic_syms,0), (self.repartition_fic,0), self.unpuncture, self.conv_v2s, self.conv_decode, self.conv_s2v, self.conv_prune, self.energy_v2s, self.add_mod_2, self.energy_s2v, (self.cut_into_fibs,0), gr.vector_to_stream(1,256), gr.unpacked_to_packed_bb(1,gr.GR_MSB_FIRST), self.filesink) self.connect( (self, 0), (self.select_fic_syms, 0), (self.repartition_fic, 0), self.unpuncture, self.conv_v2s, self.conv_decode, #self.conv_s2v, self.conv_prune, #self.energy_v2s, self.add_mod_2, self.energy_s2v, (self.cut_into_fibs, 0), blocks.vector_to_stream(1, 256), self.pack, self.fibout, self.fibsink) self.connect(self.fibout, self) self.connect(self.prbs_src, (self.add_mod_2, 1)) self.connect((self, 1), (self.select_fic_syms, 1), (self.repartition_fic, 1), (self.cut_into_fibs, 1), self.nullsink) if self.debug: self.connect( (self, 0), blocks.file_sink(gr.sizeof_float * self.dp.num_carriers * 2, "debug/transmission_frame.dat")) self.connect( (self, 1), blocks.file_sink(gr.sizeof_char, "debug/transmission_frame_trigger.dat")) self.connect( self.select_fic_syms, blocks.file_sink(gr.sizeof_float * self.dp.num_carriers * 2, "debug/fic_select_syms.dat")) self.connect( self.repartition_fic, blocks.file_sink( gr.sizeof_float * self.dp.fic_punctured_codeword_length, "debug/fic_repartitioned.dat")) self.connect( self.unpuncture, blocks.file_sink( gr.sizeof_float * self.dp.fic_conv_codeword_length, "debug/fic_unpunctured.dat")) self.connect( self.conv_decode, blocks.file_sink(gr.sizeof_char, "debug/fic_decoded.dat")) self.connect( self.conv_prune, blocks.file_sink(gr.sizeof_char, "debug/fic_decoded_pruned.dat")) #self.connect(self.conv_decode, blocks.file_sink(gr.sizeof_char * self.dp.energy_dispersal_fic_vector_length, "debug/fic_energy_dispersal_undone.dat")) self.connect( self.pack, blocks.file_sink(gr.sizeof_char, "debug/fic_energy_undone.dat"))
def __init__(self, dab_params, rx_params, debug=False): """ OFDM time and coarse frequency synchronisation for DAB @param mode DAB mode (1-4) @param debug if True: write data streams out to files """ dp = dab_params rp = rx_params gr.hier_block2.__init__( self, "ofdm_sync_dab", gr.io_signature(1, 1, gr.sizeof_gr_complex), # input signature gr.io_signature2(2, 2, gr.sizeof_gr_complex, gr.sizeof_char)) # output signature # workaround for a problem that prevents connecting more than one block directly (see trac ticket #161) #self.input = gr.kludge_copy(gr.sizeof_gr_complex) self.input = blocks.multiply_const_cc(1) # FIXME self.connect(self, self.input) # # null-symbol detection # # (outsourced to detect_zero.py) self.ns_detect = dab.detect_null(dp.ns_length, debug) self.connect(self.input, self.ns_detect) # # fine frequency synchronisation # # the code for fine frequency synchronisation is adapted from # ofdm_sync_ml.py; it abuses the cyclic prefix to find the fine # frequency error, as suggested in "ML Estimation of Timing and # Frequency Offset in OFDM Systems", by Jan-Jaap van de Beek, # Magnus Sandell, Per Ola Börjesson, see # http://www.sm.luth.se/csee/sp/research/report/bsb96r.html self.ffe = dab.ofdm_ffe_all_in_one(dp.symbol_length, dp.fft_length, rp.symbols_for_ffs_estimation, rp.ffs_alpha, int(dp.sample_rate)) if rp.correct_ffe: self.ffs_delay_input_for_correction = blocks.delay( gr.sizeof_gr_complex, dp.symbol_length * rp.symbols_for_ffs_estimation ) # by delaying the input, we can use the ff offset estimation from the first symbol to correct the first symbol itself self.ffs_delay_frame_start = blocks.delay( gr.sizeof_char, dp.symbol_length * rp.symbols_for_ffs_estimation ) # sample the value at the end of the symbol .. self.ffs_nco = analog.frequency_modulator_fc( 1 ) # ffs_sample_and_hold directly outputs phase error per sample self.ffs_mixer = blocks.multiply_cc() # calculate fine frequency error self.connect(self.input, (self.ffe, 0)) self.connect(self.ns_detect, (self.ffe, 1)) if rp.correct_ffe: # do the correction self.connect(self.ffe, self.ffs_nco, (self.ffs_mixer, 0)) self.connect(self.input, self.ffs_delay_input_for_correction, (self.ffs_mixer, 1)) # output - corrected signal and start of DAB frames self.connect(self.ffs_mixer, (self, 0)) self.connect(self.ns_detect, self.ffs_delay_frame_start, (self, 1)) else: # just patch the signal through self.connect(self.ffe, blocks.null_sink(gr.sizeof_float)) self.connect(self.input, (self, 0)) # frame start still needed .. self.connect(self.ns_detect, (self, 1)) if debug: self.connect( self.ffe, blocks.multiply_const_ff(1. / (dp.T * 2 * pi)), blocks.file_sink(gr.sizeof_float, "debug/ofdm_sync_dab_fine_freq_err_f.dat"))
def __init__(self, dab_params, verbose=False, debug=False): """ Hierarchical block for OFDM modulation @param dab_params DAB parameter object (dab.parameters.dab_parameters) @param debug enables debug output to files """ dp = dab_params gr.hier_block2.__init__(self,"ofdm_mod", gr.io_signature2(2, 2, gr.sizeof_char*dp.num_carriers/4, gr.sizeof_char), # input signature gr.io_signature (1, 1, gr.sizeof_gr_complex)) # output signature # symbol mapping self.mapper = dab.qpsk_mapper_vbc(dp.num_carriers) # add pilot symbol self.insert_pilot = dab.ofdm_insert_pilot_vcc(dp.prn) # phase sum self.sum_phase = dab.sum_phasor_trig_vcc(dp.num_carriers) # frequency interleaving self.interleave = dab.frequency_interleaver_vcc(dp.frequency_interleaving_sequence_array) # add central carrier & move to middle self.move_and_insert_carrier = dab.ofdm_move_and_insert_zero(dp.fft_length, dp.num_carriers) # ifft self.ifft = fft.fft_vcc(dp.fft_length, False, [], True) # cyclic prefixer self.prefixer = digital.ofdm_cyclic_prefixer(dp.fft_length, dp.symbol_length) # convert back to vectors self.s2v = blocks.stream_to_vector(gr.sizeof_gr_complex, dp.symbol_length) # add null symbol self.insert_null = dab.insert_null_symbol(dp.ns_length, dp.symbol_length) # # connect it all # # data self.connect((self,0), self.mapper, (self.insert_pilot,0), (self.sum_phase,0), self.interleave, self.move_and_insert_carrier, self.ifft, self.prefixer, self.s2v, (self.insert_null,0)) self.connect(self.insert_null, self) # control signal (frame start) self.connect((self,1), (self.insert_pilot,1), (self.sum_phase,1), (self.insert_null,1)) if debug: self.connect(self.mapper, blocks.file_sink(gr.sizeof_gr_complex*dp.num_carriers, "debug/generated_signal_mapper.dat")) self.connect(self.insert_pilot, blocks.file_sink(gr.sizeof_gr_complex*dp.num_carriers, "debug/generated_signal_insert_pilot.dat")) self.connect(self.sum_phase, blocks.file_sink(gr.sizeof_gr_complex*dp.num_carriers, "debug/generated_signal_sum_phase.dat")) self.connect(self.interleave, blocks.file_sink(gr.sizeof_gr_complex*dp.num_carriers, "debug/generated_signal_interleave.dat")) self.connect(self.move_and_insert_carrier, blocks.file_sink(gr.sizeof_gr_complex*dp.fft_length, "debug/generated_signal_move_and_insert_carrier.dat")) self.connect(self.ifft, blocks.file_sink(gr.sizeof_gr_complex*dp.fft_length, "debug/generated_signal_ifft.dat")) self.connect(self.prefixer, blocks.file_sink(gr.sizeof_gr_complex, "debug/generated_signal_prefixer.dat")) self.connect(self.insert_null, blocks.file_sink(gr.sizeof_gr_complex, "debug/generated_signal.dat"))
def __init__(self, dab_params, rx_params, verbose=False, debug=False): """ Hierarchical block for OFDM demodulation @param dab_params DAB parameter object (dab.parameters.dab_parameters) @param rx_params RX parameter object (dab.parameters.receiver_parameters) @param debug enables debug output to files @param verbose whether to produce verbose messages """ self.dp = dp = dab_params self.rp = rp = rx_params self.verbose = verbose if self.rp.softbits: gr.hier_block2.__init__(self,"ofdm_demod", gr.io_signature (1, 1, gr.sizeof_gr_complex), # input signature gr.io_signature2(2, 2, gr.sizeof_float*self.dp.num_carriers*2, gr.sizeof_char)) # output signature else: gr.hier_block2.__init__(self,"ofdm_demod", gr.io_signature (1, 1, gr.sizeof_gr_complex), # input signature gr.io_signature2(2, 2, gr.sizeof_char*self.dp.num_carriers/4, gr.sizeof_char)) # output signature # workaround for a problem that prevents connecting more than one block directly (see trac ticket #161) #self.input = gr.kludge_copy(gr.sizeof_gr_complex) self.input = blocks.multiply_const_cc(1.0) # FIXME self.connect(self, self.input) # input filtering if self.rp.input_fft_filter: if verbose: print "--> RX filter enabled" lowpass_taps = filter.firdes_low_pass(1.0, # gain dp.sample_rate, # sampling rate rp.filt_bw, # cutoff frequency rp.filt_tb, # width of transition band filter.firdes.WIN_HAMMING) # Hamming window self.fft_filter = filter.fft_filter_ccc(1, lowpass_taps) # correct sample rate offset, if enabled if self.rp.autocorrect_sample_rate: if verbose: print "--> dynamic sample rate correction enabled" self.rate_detect_ns = dab.detect_null(dp.ns_length, False) self.rate_estimator = dab.estimate_sample_rate_bf(dp.sample_rate, dp.frame_length) self.rate_prober = blocks.probe_signal_f() self.connect(self.input, self.rate_detect_ns, self.rate_estimator, self.rate_prober) # self.resample = gr.fractional_interpolator_cc(0, 1) self.resample = dab.fractional_interpolator_triggered_update_cc(0,1) self.connect(self.rate_detect_ns, (self.resample,1)) self.updater = Timer(0.1,self.update_correction) # self.updater = threading.Thread(target=self.update_correction) self.run_interpolater_update_thread = True self.updater.setDaemon(True) self.updater.start() else: self.run_interpolater_update_thread = False if self.rp.sample_rate_correction_factor != 1: if verbose: print "--> static sample rate correction enabled" self.resample = gr.fractional_interpolator_cc(0, self.rp.sample_rate_correction_factor) # timing and fine frequency synchronisation self.sync = dab.ofdm_sync_dab2(self.dp, self.rp, debug) # ofdm symbol sampler self.sampler = dab.ofdm_sampler(dp.fft_length, dp.cp_length, dp.symbols_per_frame, rp.cp_gap) # fft for symbol vectors self.fft = fft.fft_vcc(dp.fft_length, True, [], True) # coarse frequency synchronisation self.cfs = dab.ofdm_coarse_frequency_correct(dp.fft_length, dp.num_carriers, dp.cp_length) # diff phasor self.phase_diff = dab.diff_phasor_vcc(dp.num_carriers) # remove pilot symbol self.remove_pilot = dab.ofdm_remove_first_symbol_vcc(dp.num_carriers) # magnitude equalisation if self.rp.equalize_magnitude: if verbose: print "--> magnitude equalization enabled" self.equalizer = dab.magnitude_equalizer_vcc(dp.num_carriers, rp.symbols_for_magnitude_equalization) # frequency deinterleaving self.deinterleave = dab.frequency_interleaver_vcc(dp.frequency_deinterleaving_sequence_array) # symbol demapping self.demapper = dab.qpsk_demapper_vcb(dp.num_carriers) # # connect everything # if self.rp.autocorrect_sample_rate or self.rp.sample_rate_correction_factor != 1: self.connect(self.input, self.resample) self.input2 = self.resample else: self.input2 = self.input if self.rp.input_fft_filter: self.connect(self.input2, self.fft_filter, self.sync) else: self.connect(self.input2, self.sync) # data stream self.connect((self.sync, 0), (self.sampler, 0), self.fft, (self.cfs, 0), self.phase_diff, (self.remove_pilot,0)) if self.rp.equalize_magnitude: self.connect((self.remove_pilot,0), (self.equalizer,0), self.deinterleave) else: self.connect((self.remove_pilot,0), self.deinterleave) if self.rp.softbits: if verbose: print "--> using soft bits" self.softbit_interleaver = dab.complex_to_interleaved_float_vcf(self.dp.num_carriers) self.connect(self.deinterleave, self.softbit_interleaver, (self,0)) else: self.connect(self.deinterleave, self.demapper, (self,0)) # control stream self.connect((self.sync, 1), (self.sampler, 1), (self.cfs, 1), (self.remove_pilot,1)) if self.rp.equalize_magnitude: self.connect((self.remove_pilot,1), (self.equalizer,1), (self,1)) else: self.connect((self.remove_pilot,1), (self,1)) # calculate an estimate of the SNR self.phase_var_decim = blocks.keep_one_in_n(gr.sizeof_gr_complex*self.dp.num_carriers, self.rp.phase_var_estimate_downsample) self.phase_var_arg = blocks.complex_to_arg(dp.num_carriers) self.phase_var_v2s = blocks.vector_to_stream(gr.sizeof_float, dp.num_carriers) self.phase_var_mod = dab.modulo_ff(pi/2) self.phase_var_avg_mod = filter.iir_filter_ffd([rp.phase_var_estimate_alpha], [0,1-rp.phase_var_estimate_alpha]) self.phase_var_sub_avg = blocks.sub_ff() self.phase_var_sqr = blocks.multiply_ff() self.phase_var_avg = filter.iir_filter_ffd([rp.phase_var_estimate_alpha], [0,1-rp.phase_var_estimate_alpha]) self.probe_phase_var = blocks.probe_signal_f() self.connect((self.remove_pilot,0), self.phase_var_decim, self.phase_var_arg, self.phase_var_v2s, self.phase_var_mod, (self.phase_var_sub_avg,0), (self.phase_var_sqr,0)) self.connect(self.phase_var_mod, self.phase_var_avg_mod, (self.phase_var_sub_avg,1)) self.connect(self.phase_var_sub_avg, (self.phase_var_sqr,1)) self.connect(self.phase_var_sqr, self.phase_var_avg, self.probe_phase_var) # measure processing rate self.measure_rate = dab.measure_processing_rate(gr.sizeof_gr_complex, 2000000) self.connect(self.input, self.measure_rate) # debugging if debug: self.connect(self.fft, blocks.file_sink(gr.sizeof_gr_complex*dp.fft_length, "debug/ofdm_after_fft.dat")) self.connect((self.cfs,0), blocks.file_sink(gr.sizeof_gr_complex*dp.num_carriers, "debug/ofdm_after_cfs.dat")) self.connect(self.phase_diff, blocks.file_sink(gr.sizeof_gr_complex*dp.num_carriers, "debug/ofdm_diff_phasor.dat")) self.connect((self.remove_pilot,0), blocks.file_sink(gr.sizeof_gr_complex*dp.num_carriers, "debug/ofdm_pilot_removed.dat")) self.connect((self.remove_pilot,1), blocks.file_sink(gr.sizeof_char, "debug/ofdm_after_cfs_trigger.dat")) self.connect(self.deinterleave, blocks.file_sink(gr.sizeof_gr_complex*dp.num_carriers, "debug/ofdm_deinterleaved.dat")) if self.rp.equalize_magnitude: self.connect(self.equalizer, blocks.file_sink(gr.sizeof_gr_complex*dp.num_carriers, "debug/ofdm_equalizer.dat")) if self.rp.softbits: self.connect(self.softbit_interleaver, blocks.file_sink(gr.sizeof_float*dp.num_carriers*2, "debug/softbits.dat"))
def __init__(self, fft_length, cp_length, occupied_tones, snr, ks, logging=False): """ Hierarchical block for receiving OFDM symbols. The input is the complex modulated signal at baseband. Synchronized packets are sent back to the demodulator. Args: fft_length: total number of subcarriers (int) cp_length: length of cyclic prefix as specified in subcarriers (<= fft_length) (int) occupied_tones: number of subcarriers used for data (int) snr: estimated signal to noise ratio used to guide cyclic prefix synchronizer (float) ks: known symbols used as preambles to each packet (list of lists) logging: turn file logging on or off (bool) """ gr.hier_block2.__init__(self, "ofdm_receiver", gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature gr.io_signature2(2, 2, gr.sizeof_gr_complex*occupied_tones, gr.sizeof_char)) # Output signature bw = (float(occupied_tones) / float(fft_length)) / 2.0 tb = bw*0.08 chan_coeffs = filter.firdes.low_pass (1.0, # gain 1.0, # sampling rate bw+tb, # midpoint of trans. band tb, # width of trans. band filter.firdes.WIN_HAMMING) # filter type self.chan_filt = filter.fft_filter_ccc(1, chan_coeffs) win = [1 for i in range(fft_length)] zeros_on_left = int(math.ceil((fft_length - occupied_tones)/2.0)) ks0 = fft_length*[0,] ks0[zeros_on_left : zeros_on_left + occupied_tones] = ks[0] ks0 = fft.ifftshift(ks0) ks0time = fft.ifft(ks0) # ADD SCALING FACTOR ks0time = ks0time.tolist() SYNC = "pn" if SYNC == "ml": nco_sensitivity = -1.0/fft_length # correct for fine frequency self.ofdm_sync = ofdm_sync_ml(fft_length, cp_length, snr, ks0time, logging) elif SYNC == "pn": nco_sensitivity = -2.0/fft_length # correct for fine frequency self.ofdm_sync = ofdm_sync_pn(fft_length, cp_length, logging) elif SYNC == "pnac": nco_sensitivity = -2.0/fft_length # correct for fine frequency self.ofdm_sync = ofdm_sync_pnac(fft_length, cp_length, ks0time, logging) # for testing only; do not user over the air # remove filter and filter delay for this elif SYNC == "fixed": self.chan_filt = blocks.multiply_const_cc(1.0) nsymbols = 18 # enter the number of symbols per packet freq_offset = 0.0 # if you use a frequency offset, enter it here nco_sensitivity = -2.0/fft_length # correct for fine frequency self.ofdm_sync = ofdm_sync_fixed(fft_length, cp_length, nsymbols, freq_offset, logging) # Set up blocks self.nco = analog.frequency_modulator_fc(nco_sensitivity) # generate a signal proportional to frequency error of sync block self.sigmix = blocks.multiply_cc() self.sampler = digital.ofdm_sampler(fft_length, fft_length+cp_length) self.fft_demod = gr_fft.fft_vcc(fft_length, True, win, True) self.ofdm_frame_acq = digital.ofdm_frame_acquisition(occupied_tones, fft_length, cp_length, ks[0]) self.connect(self, self.chan_filt) # filter the input channel self.connect(self.chan_filt, self.ofdm_sync) # into the synchronization alg. self.connect((self.ofdm_sync,0), self.nco, (self.sigmix,1)) # use sync freq. offset output to derotate input signal self.connect(self.chan_filt, (self.sigmix,0)) # signal to be derotated self.connect(self.sigmix, (self.sampler,0)) # sample off timing signal detected in sync alg self.connect((self.ofdm_sync,1), (self.sampler,1)) # timing signal to sample at self.connect((self.sampler,0), self.fft_demod) # send derotated sampled signal to FFT self.connect(self.fft_demod, (self.ofdm_frame_acq,0)) # find frame start and equalize signal self.connect((self.sampler,1), (self.ofdm_frame_acq,1)) # send timing signal to signal frame start self.connect((self.ofdm_frame_acq,0), (self,0)) # finished with fine/coarse freq correction, self.connect((self.ofdm_frame_acq,1), (self,1)) # frame and symbol timing, and equalization if logging: self.connect(self.chan_filt, blocks.file_sink(gr.sizeof_gr_complex, "ofdm_receiver-chan_filt_c.dat")) self.connect(self.fft_demod, blocks.file_sink(gr.sizeof_gr_complex*fft_length, "ofdm_receiver-fft_out_c.dat")) self.connect(self.ofdm_frame_acq, blocks.file_sink(gr.sizeof_gr_complex*occupied_tones, "ofdm_receiver-frame_acq_c.dat")) self.connect((self.ofdm_frame_acq,1), blocks.file_sink(1, "ofdm_receiver-found_corr_b.dat")) self.connect(self.sampler, blocks.file_sink(gr.sizeof_gr_complex*fft_length, "ofdm_receiver-sampler_c.dat")) self.connect(self.sigmix, blocks.file_sink(gr.sizeof_gr_complex, "ofdm_receiver-sigmix_c.dat")) self.connect(self.nco, blocks.file_sink(gr.sizeof_gr_complex, "ofdm_receiver-nco_c.dat"))
def __init__(self, fft_length, cp_length, snr, kstime, logging): ''' Maximum Likelihood OFDM synchronizer: J. van de Beek, M. Sandell, and P. O. Borjesson, "ML Estimation of Time and Frequency Offset in OFDM Systems," IEEE Trans. Signal Processing, vol. 45, no. 7, pp. 1800-1805, 1997. ''' gr.hier_block2.__init__( self, "ofdm_sync_ml", gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature gr.io_signature2(2, 2, gr.sizeof_float, gr.sizeof_char)) # Output signature self.input = blocks.add_const_cc(0) SNR = 10.0**(snr / 10.0) rho = SNR / (SNR + 1.0) symbol_length = fft_length + cp_length # ML Sync # Energy Detection from ML Sync self.connect(self, self.input) # Create a delay line self.delay = blocks.delay(gr.sizeof_gr_complex, fft_length) self.connect(self.input, self.delay) # magnitude squared blocks self.magsqrd1 = blocks.complex_to_mag_squared() self.magsqrd2 = blocks.complex_to_mag_squared() self.adder = blocks.add_ff() moving_sum_taps = [rho / 2 for i in range(cp_length)] self.moving_sum_filter = filter.fir_filter_fff(1, moving_sum_taps) self.connect(self.input, self.magsqrd1) self.connect(self.delay, self.magsqrd2) self.connect(self.magsqrd1, (self.adder, 0)) self.connect(self.magsqrd2, (self.adder, 1)) self.connect(self.adder, self.moving_sum_filter) # Correlation from ML Sync self.conjg = blocks.conjugate_cc() self.mixer = blocks.multiply_cc() movingsum2_taps = [1.0 for i in range(cp_length)] self.movingsum2 = filter.fir_filter_ccf(1, movingsum2_taps) # Correlator data handler self.c2mag = blocks.complex_to_mag() self.angle = blocks.complex_to_arg() self.connect(self.input, (self.mixer, 1)) self.connect(self.delay, self.conjg, (self.mixer, 0)) self.connect(self.mixer, self.movingsum2, self.c2mag) self.connect(self.movingsum2, self.angle) # ML Sync output arg, need to find maximum point of this self.diff = blocks.sub_ff() self.connect(self.c2mag, (self.diff, 0)) self.connect(self.moving_sum_filter, (self.diff, 1)) #ML measurements input to sampler block and detect self.f2c = blocks.float_to_complex() self.pk_detect = blocks.peak_detector_fb(0.2, 0.25, 30, 0.0005) self.sample_and_hold = blocks.sample_and_hold_ff() # use the sync loop values to set the sampler and the NCO # self.diff = theta # self.angle = epsilon self.connect(self.diff, self.pk_detect) # The DPLL corrects for timing differences between CP correlations use_dpll = 0 if use_dpll: self.dpll = gr.dpll_bb(float(symbol_length), 0.01) self.connect(self.pk_detect, self.dpll) self.connect(self.dpll, (self.sample_and_hold, 1)) else: self.connect(self.pk_detect, (self.sample_and_hold, 1)) self.connect(self.angle, (self.sample_and_hold, 0)) ################################ # correlate against known symbol # This gives us the same timing signal as the PN sync block only on the preamble # we don't use the signal generated from the CP correlation because we don't want # to readjust the timing in the middle of the packet or we ruin the equalizer settings. kstime = [k.conjugate() for k in kstime] kstime.reverse() self.kscorr = filter.fir_filter_ccc(1, kstime) self.corrmag = blocks.complex_to_mag_squared() self.div = blocks.divide_ff() # The output signature of the correlation has a few spikes because the rest of the # system uses the repeated preamble symbol. It needs to work that generically if # anyone wants to use this against a WiMAX-like signal since it, too, repeats. # The output theta of the correlator above is multiplied with this correlation to # identify the proper peak and remove other products in this cross-correlation self.threshold_factor = 0.1 self.slice = blocks.threshold_ff(self.threshold_factor, self.threshold_factor, 0) self.f2b = blocks.float_to_char() self.b2f = blocks.char_to_float() self.mul = blocks.multiply_ff() # Normalize the power of the corr output by the energy. This is not really needed # and could be removed for performance, but it makes for a cleaner signal. # if this is removed, the threshold value needs adjustment. self.connect(self.input, self.kscorr, self.corrmag, (self.div, 0)) self.connect(self.moving_sum_filter, (self.div, 1)) self.connect(self.div, (self.mul, 0)) self.connect(self.pk_detect, self.b2f, (self.mul, 1)) self.connect(self.mul, self.slice) # Set output signals # Output 0: fine frequency correction value # Output 1: timing signal self.connect(self.sample_and_hold, (self, 0)) self.connect(self.slice, self.f2b, (self, 1)) if logging: self.connect( self.moving_sum_filter, blocks.file_sink(gr.sizeof_float, "ofdm_sync_ml-energy_f.dat")) self.connect( self.diff, blocks.file_sink(gr.sizeof_float, "ofdm_sync_ml-theta_f.dat")) self.connect( self.angle, blocks.file_sink(gr.sizeof_float, "ofdm_sync_ml-epsilon_f.dat")) self.connect( self.corrmag, blocks.file_sink(gr.sizeof_float, "ofdm_sync_ml-corrmag_f.dat")) self.connect( self.kscorr, blocks.file_sink(gr.sizeof_gr_complex, "ofdm_sync_ml-kscorr_c.dat")) self.connect( self.div, blocks.file_sink(gr.sizeof_float, "ofdm_sync_ml-div_f.dat")) self.connect( self.mul, blocks.file_sink(gr.sizeof_float, "ofdm_sync_ml-mul_f.dat")) self.connect( self.slice, blocks.file_sink(gr.sizeof_float, "ofdm_sync_ml-slice_f.dat")) self.connect( self.pk_detect, blocks.file_sink(gr.sizeof_char, "ofdm_sync_ml-peaks_b.dat")) if use_dpll: self.connect( self.dpll, blocks.file_sink(gr.sizeof_char, "ofdm_sync_ml-dpll_b.dat")) self.connect( self.sample_and_hold, blocks.file_sink(gr.sizeof_float, "ofdm_sync_ml-sample_and_hold_f.dat")) self.connect( self.input, blocks.file_sink(gr.sizeof_gr_complex, "ofdm_sync_ml-input_c.dat"))
def __init__(self, p, logging=False): """ Hierarchical block for receiving OFDM symbols. The input is the complex modulated signal at baseband. Synchronized packets are sent back to the demodulator. @param params: Raw OFDM parameters @type params: ofdm_params @param logging: turn file logging on or off @type logging: bool """ from numpy import fft gr.hier_block2.__init__( self, "ofdm_receiver", gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature gr.io_signature2(2, 2, gr.sizeof_gr_complex * p.occupied_tones, gr.sizeof_char)) # Output signature # low-pass filter the input channel bw = (float(p.occupied_tones) / float(p.fft_length)) / 2.0 tb = bw * 0.08 lpf_coeffs = gr.firdes.low_pass( 1.0, # gain 1.0, # sampling rate bw + tb, # midpoint of trans. band tb, # width of trans. band gr.firdes.WIN_HAMMING) # filter type lpf = gr.fft_filter_ccc(1, lpf_coeffs) #lpf = gr.add_const_cc(0.0) ## no-op low-pass-filter self.connect(self, lpf) # to the synchronization algorithm #from gnuradio import blks2impl #from gnuradio.blks2impl.ofdm_sync_pn import ofdm_sync_pn sync = ofdm_sync(p.fft_length, p.cp_length, p.half_sync, logging) self.connect(lpf, sync) # correct for fine frequency offset computed in sync (up to +-pi/fft_length) # NOTE: frame_acquisition can correct coarse freq offset (i.e. kpi/fft_length) if p.half_sync: nco_sensitivity = 2.0 / p.fft_length else: nco_sensitivity = 1.0 / (p.fft_length + p.cp_length) #nco_sensitivity = 0 nco = gr.frequency_modulator_fc(nco_sensitivity) sigmix = gr.multiply_cc() self.connect((sync, 0), (sigmix, 0)) self.connect((sync, 1), nco, (sigmix, 1)) # sample at symbol boundaries # NOTE: (sync,2) indicates the first sample of the symbol! sampler = raw.ofdm_sampler(p.fft_length, p.fft_length + p.cp_length, timeout=100) self.connect(sigmix, (sampler, 0)) self.connect((sync, 2), (sampler, 1)) # timing signal to sample at # fft on the symbols win = [1 for i in range(p.fft_length)] # see gr_fft_vcc_fftw that it works differently if win = [] fft = gr.fft_vcc(p.fft_length, True, win, True) self.connect((sampler, 0), fft) # use the preamble to correct the coarse frequency offset and initial equalizer frame_acq = raw.ofdm_frame_acquisition(p.fft_length, p.cp_length, p.preambles) self.frame_acq = frame_acq self.connect(fft, (frame_acq, 0)) self.connect((sampler, 1), (frame_acq, 1)) self.connect((frame_acq, 0), (self, 0)) # finished with fine/coarse freq correction self.connect((frame_acq, 1), (self, 1)) # frame and symbol timing if logging: self.connect(lpf, gr.file_sink(gr.sizeof_gr_complex, "rx-filt.dat")) self.connect( fft, gr.file_sink(gr.sizeof_gr_complex * p.fft_length, "rx-fft.dat")) self.connect((frame_acq, 0), gr.file_sink(gr.sizeof_gr_complex * p.occupied_tones, "rx-acq.dat")) self.connect((frame_acq, 1), gr.file_sink(1, "rx-detect.datb")) self.connect( sampler, gr.file_sink(gr.sizeof_gr_complex * p.fft_length, "rx-sampler.dat")) self.connect(sigmix, gr.file_sink(gr.sizeof_gr_complex, "rx-sigmix.dat")) self.connect(nco, gr.file_sink(gr.sizeof_gr_complex, "rx-nco.dat"))
def __init__(self, dab_params, verbose=False, debug=False): """ Hierarchical block for OFDM modulation @param dab_params DAB parameter object (grdab.parameters.dab_parameters) @param debug enables debug output to files """ dp = dab_params gr.hier_block2.__init__( self, "ofdm_mod", gr.io_signature2(2, 2, gr.sizeof_char * dp.num_carriers / 4, gr.sizeof_char), # input signature gr.io_signature(1, 1, gr.sizeof_gr_complex)) # output signature # symbol mapping self.mapper_v2s = blocks.vector_to_stream_make(gr.sizeof_char, 384) self.mapper_unpack = blocks.packed_to_unpacked_bb_make( 1, gr.GR_MSB_FIRST) self.mapper = grdab.mapper_bc_make(dp.num_carriers) self.mapper_s2v = blocks.stream_to_vector_make(gr.sizeof_gr_complex, 1536) # add pilot symbol self.insert_pilot = grdab.ofdm_insert_pilot_vcc(dp.prn) # phase sum self.sum_phase = grdab.sum_phasor_trig_vcc(dp.num_carriers) # frequency interleaving self.interleave = grdab.frequency_interleaver_vcc( dp.frequency_interleaving_sequence_array) # add central carrier & move to middle self.move_and_insert_carrier = grdab.ofdm_move_and_insert_zero( dp.fft_length, dp.num_carriers) # ifft self.ifft = fft.fft_vcc(dp.fft_length, False, [], True) # cyclic prefixer self.prefixer = digital.ofdm_cyclic_prefixer(dp.fft_length, dp.symbol_length) # convert back to vectors self.s2v = blocks.stream_to_vector(gr.sizeof_gr_complex, dp.symbol_length) # add null symbol self.insert_null = grdab.insert_null_symbol(dp.ns_length, dp.symbol_length) # # connect it all # # data self.connect((self, 0), self.mapper_v2s, self.mapper_unpack, self.mapper, self.mapper_s2v, (self.insert_pilot, 0), (self.sum_phase, 0), self.interleave, self.move_and_insert_carrier, self.ifft, self.prefixer, self.s2v, (self.insert_null, 0)) self.connect(self.insert_null, self) # control signal (frame start) self.connect((self, 1), (self.insert_pilot, 1), (self.sum_phase, 1), (self.insert_null, 1)) if debug: #self.connect(self.mapper, blocks.file_sink(gr.sizeof_gr_complex*dp.num_carriers, "debug/generated_signal_mapper.dat")) self.connect( self.insert_pilot, blocks.file_sink(gr.sizeof_gr_complex * dp.num_carriers, "debug/generated_signal_insert_pilot.dat")) self.connect( self.sum_phase, blocks.file_sink(gr.sizeof_gr_complex * dp.num_carriers, "debug/generated_signal_sum_phase.dat")) self.connect( self.interleave, blocks.file_sink(gr.sizeof_gr_complex * dp.num_carriers, "debug/generated_signal_interleave.dat")) self.connect( self.move_and_insert_carrier, blocks.file_sink( gr.sizeof_gr_complex * dp.fft_length, "debug/generated_signal_move_and_insert_carrier.dat")) self.connect( self.ifft, blocks.file_sink(gr.sizeof_gr_complex * dp.fft_length, "debug/generated_signal_ifft.dat")) self.connect( self.prefixer, blocks.file_sink(gr.sizeof_gr_complex, "debug/generated_signal_prefixer.dat")) self.connect( self.insert_null, blocks.file_sink(gr.sizeof_gr_complex, "debug/generated_signal.dat"))
def __init__(self, fft_length, cp_length, kstime, overrate, logging=True): """ OFDM synchronization using PN Correlation: T. M. Schmidl and D. C. Cox, "Robust Frequency and Timing Synchonization for OFDM," IEEE Trans. Communications, vol. 45, no. 12, 1997. """ gr.hier_block2.__init__( self, "ofdm_sync_pn", gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature gr.io_signature2(2, 2, gr.sizeof_float, gr.sizeof_char)) # Output signature self.input = blocks.add_const_cc(0) # cross-correlate with the known symbol kstime = [k.conjugate() for k in kstime] kstime.reverse() self.crosscorr_filter = filter.fir_filter_ccc(1, kstime) # PN Sync self.corrmag = blocks.complex_to_mag_squared() self.delay = blocks.delay(gr.sizeof_gr_complex, fft_length * overrate / 2) # Correlation from ML Sync self.conjg = blocks.conjugate_cc() self.corr = blocks.multiply_cc() #self.sub = blocks.add_const_ff(-1) self.pk_detect = blocks.peak_detector_fb(0.40, 0.25, fft_length * overrate, 0.00000000000) self.connect(self, self.input) self.connect(self.input, self.crosscorr_filter) self.connect(self.crosscorr_filter, self.corrmag) #self.inputmag = blocks.complex_to_mag_squared() #self.normalize = blocks.divide_ff() #self.inputmovingsum = filter.fir_filter_fff(1, [1.0] * (fft_length//2)) self.square = blocks.multiply_ff() #self.connect(self.input,self.inputmag,self.inputmovingsum) self.connect(self.corrmag, (self.square, 0)) self.connect(self.corrmag, (self.square, 1)) self.dsquare = blocks.multiply_ff() self.connect(self.square, (self.dsquare, 0)) self.connect(self.square, (self.dsquare, 1)) self.connect(self.dsquare, self.pk_detect) # Create a moving sum filter for the corr output self.moving_sum_filter = filter.fir_filter_ccf( 1, [1.0] * (fft_length * overrate // 2)) # Get magnitude (peaks) and angle (phase/freq error) self.angle = blocks.complex_to_arg() self.sample_and_hold = blocks.sample_and_hold_ff() # Calculate the frequency offset from the correlation of the preamble self.connect(self.input, self.delay) self.connect(self.input, (self.corr, 0)) self.connect(self.delay, self.conjg) self.connect(self.conjg, (self.corr, 1)) self.connect(self.corr, self.moving_sum_filter) self.connect(self.moving_sum_filter, self.angle) self.connect(self.angle, (self.sample_and_hold, 0)) self.connect(self.pk_detect, (self.sample_and_hold, 1)) # Set output signals # Output 0: fine frequency correction value # Output 1: timing signal self.connect(self.sample_and_hold, (self, 0)) self.connect(self.pk_detect, (self, 1)) if logging: self.connect( self.dsquare, blocks.file_sink(gr.sizeof_float, "ofdm_sync_pn-dsquare.dat")) self.connect( self.corrmag, blocks.file_sink(gr.sizeof_float, "ofdm_sync_pn-corrmag.dat")) self.connect( self.angle, blocks.file_sink(gr.sizeof_float, "ofdm_sync_pn-epsilon_f.dat")) self.connect( self.pk_detect, blocks.file_sink(gr.sizeof_char, "ofdm_sync_pn-peaks_b.dat")) self.connect( self.sample_and_hold, blocks.file_sink(gr.sizeof_float, "ofdm_sync_pn-sample_and_hold_f.dat")) self.connect( self.input, blocks.file_sink(gr.sizeof_gr_complex, "ofdm_sync_pn-input_c.dat"))
def __init__(self, fft_length, cp_length, occupied_tones, snr, ks, carrier_map_bin, nc_filter, logging=False): """ Hierarchical block for receiving OFDM symbols. The input is the complex modulated signal at baseband. Synchronized packets are sent back to the demodulator. @param fft_length: total number of subcarriers @type fft_length: int @param cp_length: length of cyclic prefix as specified in subcarriers (<= fft_length) @type cp_length: int @param occupied_tones: number of subcarriers used for data @type occupied_tones: int @param snr: estimated signal to noise ratio used to guide cyclic prefix synchronizer @type snr: float @param ks: known symbols used as preambles to each packet @type ks: list of lists @param logging: turn file logging on or off @type logging: bool """ gr.hier_block2.__init__( self, "ofdm_receiver", gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature gr.io_signature2(2, 2, gr.sizeof_gr_complex * occupied_tones, gr.sizeof_char)) # Output signature bw = (float(occupied_tones) / float(fft_length)) / 2.0 tb = bw * 0.04 print "ofdm_receiver:__init__:occupied_tones %s fft_length %d " % ( occupied_tones, fft_length) chan_coeffs = filter.firdes.low_pass( 1.0, # gain 1.0, # sampling rate bw + tb, # midpoint of trans. band tb, # width of trans. band filter.firdes.WIN_HAMMING) # filter type self.chan_filt = filter.fft_filter_ccc(1, chan_coeffs) # linklab, get ofdm parameters self._fft_length = fft_length self._occupied_tones = occupied_tones self._cp_length = cp_length self._nc_filter = nc_filter self._carrier_map_bin = carrier_map_bin win = [1 for i in range(fft_length)] # linklab, initialization function self.initialize(ks, self._carrier_map_bin) zeros_on_left = int(math.ceil((fft_length - occupied_tones) / 2.0)) ks0 = fft_length * [ 0, ] ks0[zeros_on_left:zeros_on_left + occupied_tones] = ks[0] ks0 = np_fft.ifftshift(ks0) ks0time = np_fft.ifft(ks0) # ADD SCALING FACTOR ks0time = ks0time.tolist() SYNC = "pn" if SYNC == "ml": nco_sensitivity = -1.0 / fft_length # correct for fine frequency self.ofdm_sync = ofdm_sync_ml(fft_length, cp_length, snr, ks0time, logging) elif SYNC == "pn": nco_sensitivity = -2.0 / fft_length # correct for fine frequency self.ofdm_sync = ofdm_sync_pn(fft_length, cp_length, logging) elif SYNC == "pnac": nco_sensitivity = -2.0 / fft_length # correct for fine frequency self.ofdm_sync = ofdm_sync_pnac(fft_length, cp_length, ks0time, logging) # for testing only; do not user over the air # remove filter and filter delay for this elif SYNC == "fixed": self.chan_filt = gr.multiply_const_cc(1.0) nsymbols = 18 # enter the number of symbols per packet freq_offset = 0.0 # if you use a frequency offset, enter it here nco_sensitivity = -2.0 / fft_length # correct for fine frequency self.ofdm_sync = ofdm_sync_fixed(fft_length, cp_length, nsymbols, freq_offset, logging) # Set up blocks # Create a delay line, linklab self.delay = blocks.delay(gr.sizeof_gr_complex, fft_length) self.nco = analog.frequency_modulator_fc( nco_sensitivity ) # generate a signal proportional to frequency error of sync block self.sigmix = blocks.multiply_cc() self.sampler = gr_papyrus.ofdm_sampler(fft_length, fft_length + cp_length) self.fft_demod = gr_fft.fft_vcc(fft_length, True, win, True) self.ofdm_frame_acq = gr_papyrus.ofdm_frame_acquisition( occupied_tones, fft_length, cp_length, ks[0]) # linklab, check current mode: non-contiguous OFDM or not if self._nc_filter: print '\nMulti-band Filter Turned ON!' # linklab, non-contiguous filter self.ncofdm_filt = ncofdm_filt(self._fft_length, self._occupied_tones, self._carrier_map_bin) self.connect(self, self.chan_filt, self.ncofdm_filt) self.connect(self.ncofdm_filt, self.ofdm_sync) # into the synchronization alg. self.connect( (self.ofdm_sync, 0), self.nco, (self.sigmix, 1)) # use sync freq. offset output to derotate input signal self.connect(self.ncofdm_filt, self.delay, (self.sigmix, 0)) # signal to be derotated else: print '\nMulti-band Filter Turned OFF!' self.connect(self, self.chan_filt) self.connect(self.chan_filt, self.ofdm_sync) # into the synchronization alg. self.connect( (self.ofdm_sync, 0), self.nco, (self.sigmix, 1)) # use sync freq. offset output to derotate input signal self.connect(self.chan_filt, self.delay, (self.sigmix, 0)) # signal to be derotated self.connect( self.sigmix, (self.sampler, 0)) # sample off timing signal detected in sync alg self.connect((self.ofdm_sync, 1), (self.sampler, 1)) # timing signal to sample at self.connect((self.sampler, 0), self.fft_demod) # send derotated sampled signal to FFT self.connect( self.fft_demod, (self.ofdm_frame_acq, 0)) # find frame start and equalize signal self.connect((self.sampler, 1), (self.ofdm_frame_acq, 1)) # send timing signal to signal frame start self.connect((self.ofdm_frame_acq, 0), (self, 0)) # finished with fine/coarse freq correction, self.connect((self.ofdm_frame_acq, 1), (self, 1)) # frame and symbol timing, and equalization if logging: self.connect( self.chan_filt, gr.file_sink(gr.sizeof_gr_complex, "ofdm_receiver-chan_filt_c.dat")) self.connect( self.fft_demod, gr.file_sink(gr.sizeof_gr_complex * fft_length, "ofdm_receiver-fft_out_c.dat")) self.connect( self.ofdm_frame_acq, gr.file_sink(gr.sizeof_gr_complex * occupied_tones, "ofdm_receiver-frame_acq_c.dat")) self.connect((self.ofdm_frame_acq, 1), gr.file_sink(1, "ofdm_receiver-found_corr_b.dat")) self.connect( self.sampler, gr.file_sink(gr.sizeof_gr_complex * fft_length, "ofdm_receiver-sampler_c.dat")) self.connect( self.sigmix, gr.file_sink(gr.sizeof_gr_complex, "ofdm_receiver-sigmix_c.dat")) self.connect( self.nco, gr.file_sink(gr.sizeof_gr_complex, "ofdm_receiver-nco_c.dat"))
def __init__(self, dab_params, rx_params, debug=False): """ OFDM time and coarse frequency synchronisation for DAB @param mode DAB mode (1-4) @param debug if True: write data streams out to files """ dp = dab_params rp = rx_params gr.hier_block2.__init__(self,"ofdm_sync_dab", gr.io_signature(1, 1, gr.sizeof_gr_complex), # input signature gr.io_signature2(2, 2, gr.sizeof_gr_complex, gr.sizeof_char)) # output signature # workaround for a problem that prevents connecting more than one block directly (see trac ticket #161) self.input = gr.kludge_copy(gr.sizeof_gr_complex) self.connect(self, self.input) # # null-symbol detection # # (outsourced to detect_zero.py) self.ns_detect = detect_null.detect_null(dp.ns_length, debug) self.connect(self.input, self.ns_detect) # # fine frequency synchronisation # # the code for fine frequency synchronisation is adapted from # ofdm_sync_ml.py; it abuses the cyclic prefix to find the fine # frequency error, as suggested in "ML Estimation of Timing and # Frequency Offset in OFDM Systems", by Jan-Jaap van de Beek, # Magnus Sandell, Per Ola Börjesson, see # http://www.sm.luth.se/csee/sp/research/report/bsb96r.html self.ffs_delay = gr.delay(gr.sizeof_gr_complex, dp.fft_length) self.ffs_conj = gr.conjugate_cc() self.ffs_mult = gr.multiply_cc() self.ffs_moving_sum = dab_swig.moving_sum_cc(dp.cp_length) self.ffs_arg = gr.complex_to_arg() self.ffs_sample_and_average = dab_swig.ofdm_ffs_sample(dp.symbol_length, dp.fft_length, rp.symbols_for_ffs_estimation, rp.ffs_alpha, dp.sample_rate) if rp.correct_ffe: self.ffs_delay_input_for_correction = gr.delay(gr.sizeof_gr_complex, dp.symbol_length*rp.symbols_for_ffs_estimation) # by delaying the input, we can use the ff offset estimation from the first symbol to correct the first symbol itself self.ffs_delay_frame_start = gr.delay(gr.sizeof_char, dp.symbol_length*rp.symbols_for_ffs_estimation) # sample the value at the end of the symbol .. self.ffs_nco = gr.frequency_modulator_fc(1) # ffs_sample_and_hold directly outputs phase error per sample self.ffs_mixer = gr.multiply_cc() # calculate fine frequency error self.connect(self.input, self.ffs_conj, self.ffs_mult) self.connect(self.input, self.ffs_delay, (self.ffs_mult, 1)) self.connect(self.ffs_mult, self.ffs_moving_sum, self.ffs_arg, (self.ffs_sample_and_average, 0)) self.connect(self.ns_detect, (self.ffs_sample_and_average, 1)) if rp.correct_ffe: # do the correction self.connect(self.ffs_sample_and_average, self.ffs_nco, (self.ffs_mixer, 0)) self.connect(self.input, self.ffs_delay_input_for_correction, (self.ffs_mixer, 1)) # output - corrected signal and start of DAB frames self.connect(self.ffs_mixer, (self, 0)) self.connect(self.ns_detect, self.ffs_delay_frame_start, (self, 1)) else: # just patch the signal through self.connect(self.ffs_sample_and_average, gr.null_sink(gr.sizeof_float)) self.connect(self.input, (self,0)) # frame start still needed .. self.connect(self.ns_detect, (self,1)) if debug: self.connect(self.ffs_sample_and_average, gr.multiply_const_ff(1./(dp.T*2*pi)), gr.file_sink(gr.sizeof_float, "debug/ofdm_sync_dab_fine_freq_err_f.dat")) self.connect(self.ffs_mixer, gr.file_sink(gr.sizeof_gr_complex, "debug/ofdm_sync_dab_fine_freq_corrected_c.dat"))
def __init__(self, fft_length, cp_length, occupied_tones, snr, logging=False): """ Hierarchical block for receiving OFDM symbols. The input is the complex modulated signal at baseband. Synchronized packets are sent back to the demodulator. @param fft_length: total number of subcarriers @type fft_length: int @param cp_length: length of cyclic prefix as specified in subcarriers (<= fft_length) @type cp_length: int @param occupied_tones: number of subcarriers used for data @type occupied_tones: int @param snr: estimated signal to noise ratio used to guide cyclic prefix synchronizer @type snr: float @param logging: turn file logging on or off @type logging: bool """ gr.hier_block2.__init__( self, "ofdm_receiver", gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature gr.io_signature2(2, 2, gr.sizeof_gr_complex * fft_length, gr.sizeof_char * fft_length)) # Output signature bw = (float(occupied_tones) / float(fft_length)) / 2.0 tb = bw * 0.08 chan_coeffs = gr.firdes.low_pass( 1.0, # gain 1.0, # sampling rate bw + tb, # midpoint of trans. band tb, # width of trans. band gr.firdes.WIN_HAMMING) # filter type #self.chan_filt = gr.fft_filter_ccc(1, chan_coeffs) self.chan_filt = gr.multiply_cc(1) win = [1 for i in range(fft_length)] ks0time = fft_length * (0, ) SYNC = "ml" if SYNC == "ml": #TODO -1.0/... nco_sensitivity = -1.0 / fft_length # correct for fine frequency self.ofdm_sync = ofdm_sync_ml.ofdm_sync_ml(fft_length, cp_length, snr, ks0time, logging) elif SYNC == "pn": nco_sensitivity = -2.0 / fft_length # correct for fine frequency self.ofdm_sync = ofdm_sync_pn.ofdm_sync_pn(fft_length, cp_length, logging) elif SYNC == "pnac": nco_sensitivity = -2.0 / fft_length # correct for fine frequency self.ofdm_sync = ofdm_sync_pnac.ofdm_sync_pnac( fft_length, cp_length, ks0time, logging) # for testing only; do not user over the air # remove filter and filter delay for this elif SYNC == "fixed": self.chan_filt = gr.multiply_const_cc(1.0) nsymbols = 18 # enter the number of symbols per packet freq_offset = 0.0 # if you use a frequency offset, enter it here nco_sensitivity = -2.0 / fft_length # correct for fine frequency self.ofdm_sync = ofdm_sync_fixed.ofdm_sync_fixed( fft_length, cp_length, nsymbols, freq_offset, logging) # Set up blocks #self.grnull = gr.null_sink(4); self.nco = gr.frequency_modulator_fc( nco_sensitivity ) # generate a signal proportional to frequency error of sync block self.sigmix = gr.multiply_cc() self.sampler = digital_swig.ofdm_sampler(fft_length, fft_length + cp_length) self.fft_demod = gr.fft_vcc(fft_length, True, win, True) self.connect(self, self.chan_filt) # filter the input channel self.connect(self.chan_filt, self.ofdm_sync) # into the synchronization alg. self.connect( (self.ofdm_sync, 0), self.nco, (self.sigmix, 1)) # use sync freq. offset output to derotate input signal self.connect(self.chan_filt, (self.sigmix, 0)) # signal to be derotated self.connect( self.sigmix, (self.sampler, 0)) # sample off timing signal detected in sync alg #self.connect(self.chan_filt, (self.sampler,0)) # sample off timing signal detected in sync alg self.connect((self.ofdm_sync, 1), (self.sampler, 1)) # timing signal to sample at self.connect((self.sampler, 0), self.fft_demod) # send derotated sampled signal to FFT self.connect(self.fft_demod, (self, 0)) # frequency domain signal sent to output 0 self.connect((self.sampler, 1), (self, 1)) # timing sent to output 1 print "setup OK" logging = 0 if logging: self.connect( self.chan_filt, gr.file_sink(gr.sizeof_gr_complex, "ofdm_receiver-chan_filt_c.dat")) self.connect((self.ofdm_sync, 0), gr.file_sink(gr.sizeof_float, "ofdm_receiver-sync_0.dat")) self.connect((self.ofdm_sync, 1), gr.file_sink(gr.sizeof_char, "ofdm_receiver-sync_1.dat")) self.connect( self.nco, gr.file_sink(gr.sizeof_gr_complex, "ofdm_receiver-nco_c.dat")) self.connect( self.sigmix, gr.file_sink(gr.sizeof_gr_complex, "ofdm_receiver-sigmix_c.dat")) self.connect((self.sampler, 0), gr.file_sink(gr.sizeof_gr_complex * fft_length, "ofdm_receiver-sampler_0.dat")) self.connect((self.sampler, 1), gr.file_sink(gr.sizeof_char * fft_length, "ofdm_receiver-sampler_1.dat")) self.connect( self.fft_demod, gr.file_sink(gr.sizeof_gr_complex * fft_length, "ofdm_receiver-fft_out_c.dat"))
def __init__( self, alpha=0.35, baud=45.45, decimation=1, mark_freq=2295, samp_rate=48000, space_freq=2125, ): gr.hier_block2.__init__( self, "RTTY Demod", gr.io_signature(1, 1, gr.sizeof_gr_complex), gr.io_signature2(4, 4, gr.sizeof_char, gr.sizeof_float), ) ################################################## # Parameters ################################################## self.alpha = alpha self.baud = baud self.decimation = decimation self.mark_freq = mark_freq self.samp_rate = samp_rate self.space_freq = space_freq ################################################## # Blocks ################################################## self._threshold = blocks.threshold_ff(0, 0, 0) self._subtract = blocks.sub_ff(1) self._float_to_char = blocks.float_to_char(1, 1) self._space_tone_detector = tone_detector_cf(decimation, space_freq, samp_rate, baud, 0.35) self._mark_tone_detector = tone_detector_cf(decimation, mark_freq, samp_rate, baud, 0.35) self._baudot_decode = baudot_decode_bb() self._word_extractor = async_word_extractor_bb(5, samp_rate / decimation, baud) ################################################## # Connections ################################################## self.connect(self._word_extractor, self._baudot_decode, self) self.connect(self, self._mark_tone_detector, self._subtract) self.connect(self, self._space_tone_detector, (self._subtract, 1)) self.connect( self._subtract, self._threshold, self._float_to_char, self._word_extractor, ) self.connect(self._subtract, (self, 1)) self.connect(self._mark_tone_detector, (self, 2)) self.connect(self._space_tone_detector, (self, 3))