コード例 #1
0
    def __init__(self, samp_rate,sps,alpha,mu,nB,nF,nW,description_name,mode):
        gr.hier_block2.__init__(self,
                                "physical_layer_driver",
                                gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature
                                gr.io_signature3(3, 3,
                                                 gr.sizeof_gr_complex,
                                                 gr.sizeof_gr_complex,
                                                 gr.sizeof_gr_complex*(1+sps*(nB+nF)))) # Output signature

        self._sps   = sps
        self._alpha = alpha
        self._mu    = mu
        self._nB    = nB
        self._nF    = nF
        self._nW    = nW

        m = importlib.import_module('digitalhf.physical_layer.'+description_name)
        self._physical_layer_driver_description = m.PhysicalLayer(sps)
        self._physical_layer_driver_description.set_mode(mode)

        ## TODO: get rrc tap information from physical layer description
        self._rrc_taps = filter.firdes.root_raised_cosine(1.0, samp_rate, samp_rate/sps, 0.35, 11*sps)
        preamble_offset,preamble_samples = self._physical_layer_driver_description.get_preamble_z()
        preamble_length          = len(preamble_samples)
        self._rrc_filter         = filter.fir_filter_ccc(1, (self._rrc_taps))
        self._corr_est           = digital.corr_est_cc(symbols    = (preamble_samples.tolist()),
                                                       sps        = sps,
                                                       mark_delay = preamble_offset,
                                                       threshold  = 0.5,
                                                       threshold_method = 1)
        self._doppler_correction = digitalhf.doppler_correction_cc(preamble_length, len(preamble_samples))
        self._adaptive_filter    = digitalhf.adaptive_dfe(sps, nB, nF, nW, mu, alpha)
        self._msg_proxy          = digitalhf.msg_proxy(self._physical_layer_driver_description)
        self.connect((self, 0),
                     (self._rrc_filter, 0),
                     (self._corr_est, 0),
                     (self._doppler_correction, 0),
                     (self._adaptive_filter, 0),
                     (self, 0))
        self.connect((self._corr_est, 1),        ## correlation
                     (self, 1))
        self.connect((self._adaptive_filter, 1), ## taps
                     (self, 2))

        self.msg_connect((self._doppler_correction, 'doppler'), (self._msg_proxy, 'doppler'))
        self.msg_connect((self._msg_proxy, 'doppler'), (self._doppler_correction, 'doppler'))

        self.msg_connect((self._adaptive_filter, 'frame_info'), (self._msg_proxy, 'frame_info'))
        self.msg_connect((self._msg_proxy, 'frame_info'), (self._adaptive_filter, 'frame_info'))

        constellations_data = self._physical_layer_driver_description.get_constellations()
        constellations_msg  = pmt.to_pmt([{'idx': idx, 'points': c['points'], 'symbols': c['symbols']}
                                          for (idx,c) in enumerate(constellations_data)])
        self._adaptive_filter.to_basic_block()._post(pmt.intern('constellations'), constellations_msg)

        self.message_port_register_hier_out('soft_dec')
        self.msg_connect((self._adaptive_filter, 'soft_dec'), (self, 'soft_dec'))
        self.msg_connect((self._msg_proxy, 'soft_dec'), (self, 'soft_dec'))
コード例 #2
0
    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))
コード例 #3
0
  def __init__(self):

    gr.hier_block2.__init__(self,"rpsinkdummy",
      gr.io_signature3(4,4,gr.sizeof_short,
                           gr.sizeof_float*vlen,
                           gr.sizeof_float),
      gr.io_signature (0,0,0))

    terminate_stream( self, (self,0) )
    terminate_stream( self, (self,1) )
    terminate_stream( self, (self,2) )
    terminate_stream( self, (self,3) )
コード例 #4
0
ファイル: music_doa_helper.py プロジェクト: Analias/gr-baz
	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))
コード例 #5
0
    def __init__(self,
                 samp_rate_hz,
                 sps,
                 SF,
                 shr,
                 filtered_preamble_code,
                 alpha=1e-3,
                 beta=5,
                 time_gap_chips=11,
                 max_offset_hz=0,
                 max_num_filters=1,
                 output_correlator_index=0):
        gr.hier_block2.__init__(
            self,
            "SpaRSe_synchronization_cc",
            gr.io_signature(1, 1, gr.sizeof_gr_complex),  # Input signature
            gr.io_signature3(3, 3, gr.sizeof_gr_complex, gr.sizeof_gr_complex,
                             gr.sizeof_float))  # Output signature

        self.delta_phi = lpwan.SpaRSe_utils.calculate_phase_increments(
            samp_rate_hz, SF, sps, max_offset_hz, max_num_filters)

        # Define blocks
        self.rotators = [blocks.rotator_cc(-phi) for phi in self.delta_phi]
        self.matched_filters = [
            filter.fft_filter_ccf(1,
                                  np.flipud(np.conj(filtered_preamble_code)))
            for i in xrange(len(self.delta_phi))
        ]
        self.preamble_detector = preamble_detector_cc(shr, sps, SF,
                                                      time_gap_chips, alpha,
                                                      beta, self.delta_phi,
                                                      output_correlator_index)
        self.skiphead = blocks.skiphead(
            gr.sizeof_gr_complex,
            sps * (SF + time_gap_chips) +
            4)  # the +4 is "empirical" but well tested for sps=4

        # Connect blocks with preamble detector and outputs
        for i in xrange(len(self.delta_phi)):
            self.connect(self, self.rotators[i], self.matched_filters[i],
                         (self.preamble_detector, i))
        self.connect(self, self.skiphead,
                     (self.preamble_detector, len(self.delta_phi)))
        for i in xrange(3):
            self.connect((self.preamble_detector, i), (self, i))
コード例 #6
0
ファイル: music_doa_helper.py プロジェクト: jdemel/gr-misc
    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))
コード例 #7
0
	def __init__(self, N, sample_rate, search_bw = 1, threshold = 10, threshold_mtm = 0.2,
	 tune_freq = 0, alpha_avg = 1, test_duration = 1, period = 3600, stats = False, output = False, rate = 10,
	  subject_channels = [], valve_callback = None):

		gr.hier_block2.__init__(self,
			"coherence_detector",
			gr.io_signature3(3, 3, gr.sizeof_float*N, gr.sizeof_float*N, gr.sizeof_float*N),
			gr.io_signature(0, 0, 0))
		self.N = N #lenght of the fft for spectral analysis
		self.sample_rate = sample_rate 
		self.search_bw = search_bw #search bandwidth within each channel
		self.threshold = threshold #threshold comparison
		self.threshold_mtm = threshold_mtm
		self.tune_freq = tune_freq #center frequency
		self.alpha_avg = alpha_avg #averaging factor for noise level between consecutive measurements
		self.output = output
		self.subject_channels = subject_channels
		self.subject_channels_outcome = [0.1]*len(subject_channels)
		self.rate = rate
		self.valve_callback = valve_callback

		#data queue to share data between theads
		self.q0 = Queue.Queue()

		#gnuradio msg queues
		self.msgq = gr.msg_queue(2)
		self.msgq1 = gr.msg_queue(2)
		self.msgq2 = gr.msg_queue(2)

		#######BLOCKS#####
		self.sink = blocks.message_sink(gr.sizeof_float * self.N, self.msgq, True)
		self.sink1 = blocks.message_sink(gr.sizeof_float * self.N, self.msgq1, True)
		self.sink2 = blocks.message_sink(gr.sizeof_float * self.N, self.msgq2, True)

		#####CONNECTIONS####
		self.connect((self,0), self.sink)
		self.connect((self,1), self.sink1)
		self.connect((self,2), self.sink2)

		self._watcher = watcher(self.msgq, self.msgq1, self.msgq2, self.tune_freq, self.threshold, self.threshold_mtm, self.search_bw, self.N,
		 self.sample_rate, self.q0, self.subject_channels, self.set_subject_channels_outcome, self.rate, self.valve_callback)
		if self.output != False:
			self._output_data = output_data(self.q0, self.sample_rate, self.tune_freq, self.N,
				 self.search_bw, self.output, self.subject_channels, self.get_subject_channels_outcome)
コード例 #8
0
    def __init__(self, SF, Ku):
        gr.hier_block2.__init__(
            self,
            "mu_demod",
            gr.io_signature(1, 1, gr.sizeof_gr_complex),  # Input signature
            gr.io_signature3(3, 3, gr.sizeof_short, gr.sizeof_short,
                             gr.sizeof_float))  # Output signature

        aggregator = ml_aggreg(SF, Ku)

        self.connect((aggregator, 0), (self, 0))
        self.connect((aggregator, 1), (self, 1))
        self.connect((aggregator, 2), (self, 2))

        for i in range(Ku):
            b = partial_ml(SF, i)

            self.connect((self, 0), b)
            self.connect((b, 0), (aggregator, i * 3 + 0))
            self.connect((b, 1), (aggregator, i * 3 + 1))
            self.connect((b, 2), (aggregator, i * 3 + 2))
コード例 #9
0
ファイル: auto_fec.py プロジェクト: Bugzilla69/gr-baz
	def __init__(self,
		sample_rate,
		ber_threshold=0,	# Above which to do search
		ber_smoothing=0,	# Alpha of BER smoother (0.01)
		ber_duration=0,		# Length before trying next combo
		ber_sample_decimation=1,
		settling_period=0,
		pre_lock_duration=0,
		#ber_sample_skip=0
		**kwargs):
		
		use_throttle = False
		base_duration = 1024
		if sample_rate > 0:
			use_throttle = True
			base_duration *= 4	# Has to be high enough for block-delay
		
		if ber_threshold == 0:
			ber_threshold = 512 * 4
		if ber_smoothing == 0:
			ber_smoothing = 0.01
		if ber_duration == 0:
			ber_duration = base_duration * 2 # 1000ms
		if settling_period == 0:
			settling_period = base_duration * 1 # 500ms
		if pre_lock_duration == 0:
			pre_lock_duration = base_duration * 2 #1000ms
		
		print "Creating Auto-FEC:"
		print "\tsample_rate:\t\t", sample_rate
		print "\tber_threshold:\t\t", ber_threshold
		print "\tber_smoothing:\t\t", ber_smoothing
		print "\tber_duration:\t\t", ber_duration
		print "\tber_sample_decimation:\t", ber_sample_decimation
		print "\tsettling_period:\t", settling_period
		print "\tpre_lock_duration:\t", pre_lock_duration
		print ""
		
		self.sample_rate = sample_rate
		self.ber_threshold = ber_threshold
		#self.ber_smoothing = ber_smoothing
		self.ber_duration = ber_duration
		self.settling_period = settling_period
		self.pre_lock_duration = pre_lock_duration
		#self.ber_sample_skip = ber_sample_skip
		
		self.data_lock = threading.Lock()

		gr.hier_block2.__init__(self, "auto_fec",
			gr.io_signature(1, 1, gr.sizeof_gr_complex),			# Post MPSK-receiver complex input
			gr.io_signature3(3, 3, gr.sizeof_char, gr.sizeof_float, gr.sizeof_float))	# Decoded packed bytes, BER metric, lock
		
		self.input_watcher = auto_fec_input_watcher(self)
		default_xform = self.input_watcher.xform_lock
		
		self.gr_conjugate_cc_0 = gr.conjugate_cc()
		self.connect((self, 0), (self.gr_conjugate_cc_0, 0))	# Input
		
		self.blks2_selector_0 = grc_blks2.selector(
			item_size=gr.sizeof_gr_complex*1,
			num_inputs=2,
			num_outputs=1,
			input_index=default_xform.get_conjugation_index(),
			output_index=0,
		)
		self.connect((self.gr_conjugate_cc_0, 0), (self.blks2_selector_0, 0))
		self.connect((self, 0), (self.blks2_selector_0, 1))		# Input
		
		self.gr_multiply_const_vxx_3 = gr.multiply_const_vcc((0.707*(1+1j), ))
		self.connect((self.blks2_selector_0, 0), (self.gr_multiply_const_vxx_3, 0))
		
		self.gr_multiply_const_vxx_2 = gr.multiply_const_vcc((default_xform.get_rotation(), ))	# phase_mult
		self.connect((self.gr_multiply_const_vxx_3, 0), (self.gr_multiply_const_vxx_2, 0))
		
		self.gr_complex_to_float_0_0 = gr.complex_to_float(1)
		self.connect((self.gr_multiply_const_vxx_2, 0), (self.gr_complex_to_float_0_0, 0))
		
		self.gr_interleave_1 = gr.interleave(gr.sizeof_float*1)
		self.connect((self.gr_complex_to_float_0_0, 1), (self.gr_interleave_1, 1))
		self.connect((self.gr_complex_to_float_0_0, 0), (self.gr_interleave_1, 0))
		
		self.gr_multiply_const_vxx_0 = gr.multiply_const_vff((1, ))	# invert
		self.connect((self.gr_interleave_1, 0), (self.gr_multiply_const_vxx_0, 0))
		
		self.baz_delay_2 = baz.delay(gr.sizeof_float*1, default_xform.get_puncture_delay())	# delay_puncture
		self.connect((self.gr_multiply_const_vxx_0, 0), (self.baz_delay_2, 0))
		
		self.depuncture_ff_0 = baz.depuncture_ff((_puncture_matrices[self.input_watcher.puncture_matrix][1]))	# puncture_matrix
		self.connect((self.baz_delay_2, 0), (self.depuncture_ff_0, 0))
		
		self.baz_delay_1 = baz.delay(gr.sizeof_float*1, default_xform.get_viterbi_delay())	# delay_viterbi
		self.connect((self.depuncture_ff_0, 0), (self.baz_delay_1, 0))
		
		self.swap_ff_0 = baz.swap_ff(default_xform.get_viterbi_swap())	# swap_viterbi
		self.connect((self.baz_delay_1, 0), (self.swap_ff_0, 0))
		
		self.gr_decode_ccsds_27_fb_0 = gr.decode_ccsds_27_fb()
		
		if use_throttle:
			print "==> Using throttle at sample rate:", self.sample_rate
			self.gr_throttle_0 = gr.throttle(gr.sizeof_float, self.sample_rate)
			self.connect((self.swap_ff_0, 0), (self.gr_throttle_0, 0))
			self.connect((self.gr_throttle_0, 0), (self.gr_decode_ccsds_27_fb_0, 0))
		else:
			self.connect((self.swap_ff_0, 0), (self.gr_decode_ccsds_27_fb_0, 0))
		
		self.connect((self.gr_decode_ccsds_27_fb_0, 0), (self, 0))	# Output bytes
		
		self.gr_add_const_vxx_1 = gr.add_const_vff((-4096, ))
		self.connect((self.gr_decode_ccsds_27_fb_0, 1), (self.gr_add_const_vxx_1, 0))
		
		self.gr_multiply_const_vxx_1 = gr.multiply_const_vff((-1, ))
		self.connect((self.gr_add_const_vxx_1, 0), (self.gr_multiply_const_vxx_1, 0))
		self.connect((self.gr_multiply_const_vxx_1, 0), (self, 1))	# Output BER
		
		self.gr_single_pole_iir_filter_xx_0 = gr.single_pole_iir_filter_ff(ber_smoothing, 1)
		self.connect((self.gr_multiply_const_vxx_1, 0), (self.gr_single_pole_iir_filter_xx_0, 0))
		
		self.gr_keep_one_in_n_0 = blocks.keep_one_in_n(gr.sizeof_float, ber_sample_decimation)
		self.connect((self.gr_single_pole_iir_filter_xx_0, 0), (self.gr_keep_one_in_n_0, 0))
		
		self.const_source_x_0 = gr.sig_source_f(0, gr.GR_CONST_WAVE, 0, 0, 0)	# Last param is const value
		if use_throttle:
			lock_throttle_rate = self.sample_rate // 16
			print "==> Using lock throttle rate:", lock_throttle_rate
			self.gr_throttle_1 = gr.throttle(gr.sizeof_float, lock_throttle_rate)
			self.connect((self.const_source_x_0, 0), (self.gr_throttle_1, 0))
			self.connect((self.gr_throttle_1, 0), (self, 2))
		else:
			self.connect((self.const_source_x_0, 0), (self, 2))
		
		self.msg_q = gr.msg_queue(2*256)	# message queue that holds at most 2 messages, increase to speed up process
		self.msg_sink = gr.message_sink(gr.sizeof_float, self.msg_q, dont_block=0)	# Block to speed up process
		self.connect((self.gr_keep_one_in_n_0, 0), self.msg_sink)
		
		self.input_watcher.start()
コード例 #10
0
    def __init__(self,
                 fft_length,
                 cp_length,
                 preambles,
                 mode='RAW',
                 logging=False):
        gr.hier_block2.__init__(
            self,
            "ofdm_sync_pn",
            gr.io_signature(1, 1, gr.sizeof_gr_complex),  # Input signature
            gr.io_signature3(
                3,
                3,  # Output signature
                gr.sizeof_gr_complex,  # delayed input
                gr.sizeof_float,  # fine frequency offset
                gr.sizeof_char  # timing indicator
            ))

        period = fft_length / 2
        window = fft_length / 2

        # Calculate the frequency offset from the correlation of the preamble
        x_corr = blocks.multiply_cc()
        self.connect(self, blocks.conjugate_cc(), (x_corr, 0))
        self.connect(self, blocks.delay(gr.sizeof_gr_complex, period),
                     (x_corr, 1))
        P_d = blocks.moving_average_cc(window, 1.0)
        self.connect(x_corr, P_d)

        P_d_angle = blocks.complex_to_arg()
        self.connect(P_d, P_d_angle)

        # Get the power of the input signal to normalize the output of the correlation
        R_d = blocks.moving_average_ff(window, 1.0)
        self.connect(self, blocks.complex_to_mag_squared(), R_d)
        R_d_squared = blocks.multiply_ff()  # this is retarded
        self.connect(R_d, (R_d_squared, 0))
        self.connect(R_d, (R_d_squared, 1))
        M_d = blocks.divide_ff()
        self.connect(P_d, blocks.complex_to_mag_squared(), (M_d, 0))
        self.connect(R_d_squared, (M_d, 1))

        # Now we need to detect peak of M_d
        # the peak is up to cp_length long, but noisy, so average it out
        matched_filter = blocks.moving_average_ff(cp_length, 1.0 / cp_length)

        # NOTE: the look_ahead parameter doesn't do anything
        # these parameters are kind of magic, increase 1 and 2 (==) to be more tolerant
        peak_detect = raw.peak_detector_fb(0.25, 0.55, 30, 0.001)

        # offset by -1
        self.connect(M_d, matched_filter, blocks.add_const_ff(-1), peak_detect)

        # peak_detect indicates the time M_d is highest, which is the end of the symbol.
        # nco(t) = P_d_angle(t-offset) sampled at peak_detect(t)
        # modulate input(t - fft_length) by nco(t)
        # signal to sample input(t) at t-offset
        #
        ##########################################################
        # IMPORTANT NOTES:
        # We can't delay by < 0 so instead:
        # input is delayed by some_length
        # signal to sample is delayed by some_length - offset
        ##########################################################
        # peak_delay and offset are for cutting CP
        # FIXME: until we figure out how to do this, just offset by 6 or cp_length/2
        symbol_length = fft_length + cp_length
        peak_delay = cp_length
        offset = 6  #cp_length/2
        self.offset = offset

        # regenerate peak using cross-correlation
        # * RAW mode: use raw_generate_peak2 block to filter peaks
        # * PNC mode: use raw_generate_peak3 block to identify the proper peak for two users
        # PNC mode delays all input peak_delay samples
        # * cp_length: delay for cross-correlation since auto-correlation is not so accurate
        # * 3 symbol_length: delay for identifying mode for PNC
        # * -offset: for cp cut
        if mode == 'PNC':
            # The block structure is
            # signal -> 3*symbol_length+cp_length-offset     -> (self,0) [signal]
            # signal -> cp_length delay -> auto  -> (peak,0) -> (self,2) [peak]
            # signal -> cp_length delay          -> (peak,1) -> (self,1) [cfo]
            # cfo    -> cp_length delay          -> (peak,2)
            #
            # we let cross's signal go faster to identify the beginning
            # we use cross's peak output to find cfo, so the delay of cfo should = cross delay
            # we use raw_regenerate_peak to do cross-corr, and symbols energy after STS to identify mode
            # so the signal is further delayed by three symbols more
            self.signal_cross_delay = blocks.delay(gr.sizeof_gr_complex,
                                                   peak_delay)
            self.cfo_cross_delay = blocks.delay(gr.sizeof_float, peak_delay)

            LOOK_AHEAD_NSYM = 3
            self.connect(self, self.signal_cross_delay)
            self.connect(P_d_angle, self.cfo_cross_delay)

            peak = raw.regenerate_peak3(fft_length, fft_length + cp_length,
                                        LOOK_AHEAD_NSYM, peak_delay, preambles,
                                        False)
            self.connect(peak_detect, (peak, 0))
            self.connect(self.signal_cross_delay, (peak, 1))
            self.connect(self.cfo_cross_delay, (peak, 2))

            self.signal_delay = blocks.delay(
                gr.sizeof_gr_complex,
                LOOK_AHEAD_NSYM * symbol_length + peak_delay - offset)
            self.connect(self, self.signal_delay, (self, 0))  # signal output
            self.connect((peak, 1), (self, 1))  # cfo output
            self.connect((peak, 0), (self, 2))  # peak output

            if logging:
                self.connect(
                    self.cfo_cross_delay,
                    blocks.file_sink(gr.sizeof_float, 'logs/input-cfo.dat'))
                #self.connect(cross, blocks.file_sink(gr.sizeof_float, 'logs/cross.dat'))
                self.connect(
                    self.signal_cross_delay,
                    blocks.file_sink(gr.sizeof_gr_complex,
                                     'logs/cross-signal.dat'))

        if mode == 'RAW':
            LOOK_AHEAD_NSYM = 0
            peak = raw.regenerate_peak2(fft_length, fft_length + cp_length,
                                        LOOK_AHEAD_NSYM, preambles)
            self.signal_delay1 = blocks.delay(gr.sizeof_gr_complex,
                                              peak_delay - offset)
            self.signal_delay2 = blocks.delay(gr.sizeof_gr_complex, offset)
            self.cfo_delay = blocks.delay(
                gr.sizeof_float,
                peak_delay)  # we generate the same delay with signal
            self.connect(peak_detect, (peak, 0))
            self.connect(P_d_angle, self.cfo_delay, (peak, 1))
            self.connect(self, self.signal_delay1, self.signal_delay2,
                         (peak, 2))

            self.connect(self.signal_delay1, (self, 0))  # signal output
            self.connect((peak, 1), (self, 1))  # cfo output
            self.connect((peak, 0), (self, 2))  # raw peak output

            if logging:
                self.connect(
                    self.signal_delay1,
                    blocks.file_sink(gr.sizeof_gr_complex,
                                     'logs/test-out-signal.dat'))
                self.connect((peak, 0),
                             blocks.file_sink(gr.sizeof_char,
                                              'logs/test-out-peak.datb'))
                self.connect(
                    self.cfo_delay,
                    blocks.file_sink(gr.sizeof_float, 'logs/test-cfo.dat'))
                self.connect(
                    peak_detect,
                    blocks.file_sink(gr.sizeof_char,
                                     'logs/test-out-auto-peak.datb'))

        if logging:
            #self.connect(self.signal_delay1, blocks.file_sink(gr.sizeof_gr_complex, 'logs/test-signal.dat'))
            self.connect((peak, 0),
                         blocks.file_sink(gr.sizeof_char, 'logs/peak.datb'))
            self.connect((peak, 1),
                         blocks.file_sink(gr.sizeof_float,
                                          'logs/peak-cfo.dat'))
            self.connect(matched_filter,
                         blocks.file_sink(gr.sizeof_float, 'logs/sync-mf.dat'))
            self.connect(M_d,
                         blocks.file_sink(gr.sizeof_float, 'logs/sync-M.dat'))
            self.connect(
                P_d, blocks.file_sink(gr.sizeof_gr_complex,
                                      'logs/sync-pd.dat'))
            self.connect(R_d,
                         blocks.file_sink(gr.sizeof_float, 'logs/sync-rd.dat'))
            self.connect(
                R_d_squared,
                blocks.file_sink(gr.sizeof_float, 'logs/sync-rd-squared.dat'))
            self.connect(
                P_d_angle,
                blocks.file_sink(gr.sizeof_float, 'logs/sync-angle.dat'))
            self.connect(
                peak_detect,
                blocks.file_sink(gr.sizeof_char, 'logs/sync-peaks.datb'))
コード例 #11
0
ファイル: schmidl.py プロジェクト: WindyCitySDR/gr-ofdm
  def __init__(self, fft_length, block_length, block_header, range, options):
    gr.hier_block2.__init__(self, "integer_fo_estimator",
      gr.io_signature3(3,3,gr.sizeof_gr_complex,gr.sizeof_float,gr.sizeof_char),
      gr.io_signature2(3,3,gr.sizeof_float,gr.sizeof_char))
    
    raise NotImplementedError,"Obsolete class"

    self._range = range

    # threshold after integer part frequency offset estimation
    # if peak value below threshold, assume false triggering
    self._thr_lo = 0.4 #0.19 # empirically found threshold. see ioe_metric.float
    self._thr_hi = 0.4 #0.2

    # stuff to be removed after bugfix for hierblock2s
    self.input = gr.kludge_copy(gr.sizeof_gr_complex)
    self.time_sync = gr.kludge_copy(gr.sizeof_char)
    self.epsilon = (self,1)
    self.connect((self,0),self.input)
    self.connect((self,2),self.time_sync)

    delay(gr.sizeof_char,
          block_header.schmidl_fine_sync[0]*block_length)

    # sample ofdm symbol (preamble 1 and 2)
    sampler_symbol1 = vector_sampler(gr.sizeof_gr_complex,fft_length)
    sampler_symbol2 = vector_sampler(gr.sizeof_gr_complex,fft_length)
    time_delay1 = delay(gr.sizeof_char,block_length*block_header.schmidl_fine_sync[1])
    self.connect(self.input, (sampler_symbol1,0))
    self.connect(self.input, (sampler_symbol2,0))
    if block_header.schmidl_fine_sync[0] > 0:
      time_delay0 = delay(gr.sizeof_char,block_length*block_header.schmidl_fine_sync[0])
      self.connect(self.time_sync, time_delay0, (sampler_symbol1,1))
    else:
      self.connect(self.time_sync, (sampler_symbol1,1))
    self.connect(self.time_sync, time_delay1, (sampler_symbol2,1))

    # negative fractional frequency offset estimate
    epsilon = gr.multiply_const_ff(-1.0)
    self.connect(self.epsilon, epsilon)

    # compensate for fractional frequency offset on per symbol base
    #  freq_shift: vector length, modulator sensitivity
    #  freq_shift third input: reset phase accumulator

    # symbol/preamble 1
    freq_shift_sym1 = frequency_shift_vcc(fft_length, 1.0/fft_length)
    self.connect(sampler_symbol1, (freq_shift_sym1,0))
    self.connect(epsilon, (freq_shift_sym1,1))
    self.connect(gr.vector_source_b([1], True), (freq_shift_sym1,2))

    # symbol/preamble 2
    freq_shift_sym2 = frequency_shift_vcc(fft_length, 1.0/fft_length)
    self.connect(sampler_symbol2, (freq_shift_sym2,0))
    self.connect(epsilon, (freq_shift_sym2,1))
    self.connect(gr.vector_source_b([1], True), (freq_shift_sym2,2))

    # fourier transfrom on both preambles
    fft_sym1 = gr.fft_vcc(fft_length, True, [], True) # Forward + Blockshift
    fft_sym2 = gr.fft_vcc(fft_length, True, [], True) # Forward + Blockshift

    # calculate schmidl's metric for estimation of freq. offset's integer part
    assert(hasattr(block_header, "schmidl_fine_sync"))
    pre1 = block_header.pilotsym_fd[block_header.schmidl_fine_sync[0]]
    pre2 = block_header.pilotsym_fd[block_header.schmidl_fine_sync[1]]
    diff_pn = concatenate([[conjugate(math.sqrt(2)*pre2[2*i]/pre1[2*i]),0.0j] for i in arange(len(pre1)/2)])
    cfo_estimator = schmidl_cfo_estimator(fft_length, len(pre1),
                                          self._range, diff_pn)
    self.connect(freq_shift_sym1, fft_sym1, (cfo_estimator,0))   # preamble 1
    self.connect(freq_shift_sym2, fft_sym2, (cfo_estimator,1))   # preamble 2

    # search for maximum and its argument in interval [-range .. +range]
    #arg_max = arg_max_vff(2*self._range + 1)
    arg_max_s = gr.argmax_fs(2*self._range+1)
    arg_max = gr.short_to_float()
    ifo_max = gr.max_ff(2*self._range + 1) # vlen
    ifo_estimate = gr.add_const_ff(-self._range)
    self.connect(cfo_estimator, arg_max_s, arg_max, ifo_estimate)
    self.connect(cfo_estimator, ifo_max)
    self.connect((arg_max_s,1),gr.null_sink(gr.sizeof_short))

    # threshold maximal value
    ifo_threshold = gr.threshold_ff(self._thr_lo, self._thr_hi, 0.0)
    ifo_thr_f2b = gr.float_to_char()
    self.connect(ifo_max, ifo_threshold, ifo_thr_f2b)

    # gating the streams ifo_estimate (integer part) and epsilon (frac. part)
    # if the metric's peak value was above the chosen threshold, assume to have
    # found a new burst. peak value below threshold results in blocking the
    # streams
    self.gate = gate_ff()
    self.connect(ifo_thr_f2b, (self.gate,0)) # threshold stream
    self.connect(ifo_estimate, (self.gate,1))
    self.connect(epsilon, (self.gate,2))


    # peak filtering
    # resynchronize and suppress peaks that didn't match a preamble
    filtered_time_sync = peak_resync_bb(True) # replace
    self.connect(self.time_sync, (filtered_time_sync,0))
    self.connect(ifo_thr_f2b, (filtered_time_sync,1))


    # find complete estimation for frequency offset
    # add together fractional and integer part
    freq_offset = gr.add_ff()
    self.connect((self.gate,1), gr.multiply_const_ff(-1.0), (freq_offset,0)) # integer offset
    self.connect((self.gate,2), (freq_offset,1)) # frac offset

    # output connections
    self.connect(freq_offset, (self,0))
    self.connect(filtered_time_sync, (self,1))
    self.connect((self.gate,0), (self,2)) # used for frame trigger


    #########################################
    # debugging
    if options.log:
      self.epsilon2_sink = gr.vector_sink_f()
      self.connect(epsilon, self.epsilon2_sink)

      self.connect(cfo_estimator, gr.file_sink(gr.sizeof_float*(self._range*2+1), "data/ioe_metric.float"))

      # output joint stream
      preamble_stream = gr.streams_to_vector(fft_length * gr.sizeof_gr_complex, 2)
      self.connect(fft_sym1, (preamble_stream,0))
      self.connect(fft_sym2, (preamble_stream,1))
      self.connect(preamble_stream, gr.file_sink(gr.sizeof_gr_complex * 2 * fft_length, "data/preambles.compl"))

      # output, preambles before and after correction, magnitude and complex spectrum
      self.connect(sampler_symbol1, gr.fft_vcc(fft_length, True, [], True), gr.file_sink(gr.sizeof_gr_complex * fft_length, "data/pre1_bef.compl"))
      self.connect(sampler_symbol1, gr.fft_vcc(fft_length, True, [], True), gr.complex_to_mag(fft_length), gr.file_sink(gr.sizeof_float * fft_length, "data/pre1_bef.float"))
      self.connect(sampler_symbol2, gr.fft_vcc(fft_length, True, [], True), gr.file_sink(gr.sizeof_gr_complex * fft_length, "data/pre2_bef.compl"))
      self.connect(sampler_symbol2, gr.fft_vcc(fft_length, True, [], True), gr.complex_to_mag(fft_length), gr.file_sink(gr.sizeof_float * fft_length, "data/pre2_bef.float"))
      self.connect(freq_shift_sym1, gr.fft_vcc(fft_length, True, [], True), gr.file_sink(gr.sizeof_gr_complex * fft_length,"data/pre1.compl"))
      self.connect(freq_shift_sym1, gr.fft_vcc(fft_length, True, [], True), gr.complex_to_mag(fft_length), gr.file_sink(gr.sizeof_float * fft_length,"data/pre1.float"))
      self.connect(freq_shift_sym2, gr.fft_vcc(fft_length, True, [], True), gr.file_sink(gr.sizeof_gr_complex * fft_length,"data/pre2.compl"))
      self.connect(freq_shift_sym2, gr.fft_vcc(fft_length, True, [], True), gr.complex_to_mag(fft_length), gr.file_sink(gr.sizeof_float * fft_length,"data/pre2.float"))

      # calculate epsilon from corrected source to check function
      test_cp = cyclic_prefixer(fft_length, block_length)
      test_eps = foe(fft_length)
      self.connect(freq_shift_sym1, test_cp, test_eps, gr.file_sink(gr.sizeof_float, "data/eps_after.float"))

    try:
        gr.hier_block.update_var_names(self, "ifo_estimator", vars())
        gr.hier_block.update_var_names(self, "ifo_estimator", vars(self))
    except:
        pass
コード例 #12
0
    def __init__(self, fft_length, cp_length, half_sync, logging=False):
        gr.hier_block2.__init__(
            self,
            "ofdm_sync_pn",
            gr.io_signature(1, 1, gr.sizeof_gr_complex),  # Input signature
            gr.io_signature3(
                3,
                3,  # Output signature
                gr.sizeof_gr_complex,  # delayed input
                gr.sizeof_float,  # fine frequency offset
                gr.sizeof_char  # timing indicator
            ))

        if half_sync:
            period = fft_length / 2
            window = fft_length / 2
        else:  # full symbol
            period = fft_length + cp_length
            window = fft_length  # makes the plateau cp_length long

        # Calculate the frequency offset from the correlation of the preamble
        x_corr = gr.multiply_cc()
        self.connect(self, gr.conjugate_cc(), (x_corr, 0))
        self.connect(self, gr.delay(gr.sizeof_gr_complex, period), (x_corr, 1))
        P_d = gr.moving_average_cc(window, 1.0)
        self.connect(x_corr, P_d)

        P_d_angle = gr.complex_to_arg()
        self.connect(P_d, P_d_angle)

        # Get the power of the input signal to normalize the output of the correlation
        R_d = gr.moving_average_ff(window, 1.0)
        self.connect(self, gr.complex_to_mag_squared(), R_d)
        R_d_squared = gr.multiply_ff()  # this is retarded
        self.connect(R_d, (R_d_squared, 0))
        self.connect(R_d, (R_d_squared, 1))
        M_d = gr.divide_ff()
        self.connect(P_d, gr.complex_to_mag_squared(), (M_d, 0))
        self.connect(R_d_squared, (M_d, 1))

        # Now we need to detect peak of M_d

        # NOTE: replaced fir_filter with moving_average for clarity
        # the peak is up to cp_length long, but noisy, so average it out
        #matched_filter_taps = [1.0/cp_length for i in range(cp_length)]
        #matched_filter = gr.fir_filter_fff(1, matched_filter_taps)
        matched_filter = gr.moving_average_ff(cp_length, 1.0 / cp_length)

        # NOTE: the look_ahead parameter doesn't do anything
        # these parameters are kind of magic, increase 1 and 2 (==) to be more tolerant
        #peak_detect = raw.peak_detector_fb(0.55, 0.55, 30, 0.001)
        peak_detect = raw.peak_detector_fb(0.25, 0.25, 30, 0.001)
        # NOTE: gr.peak_detector_fb is broken!
        #peak_detect = gr.peak_detector_fb(0.55, 0.55, 30, 0.001)
        #peak_detect = gr.peak_detector_fb(0.45, 0.45, 30, 0.001)
        #peak_detect = gr.peak_detector_fb(0.30, 0.30, 30, 0.001)

        # offset by -1
        self.connect(M_d, matched_filter, gr.add_const_ff(-1), peak_detect)

        # peak_detect indicates the time M_d is highest, which is the end of the symbol.
        # We should try to sample in the middle of the plateau!!
        # FIXME until we figure out how to do this, just offset by cp_length/2
        offset = 6  #cp_length/2

        # nco(t) = P_d_angle(t-offset) sampled at peak_detect(t)
        # modulate input(t - fft_length) by nco(t)
        # signal to sample input(t) at t-offset
        #
        # We can't delay by < 0 so instead:
        # input is delayed by fft_length
        # P_d_angle is delayed by offset
        # signal to sample is delayed by fft_length - offset
        #
        phi = gr.sample_and_hold_ff()
        self.connect(peak_detect, (phi, 1))
        self.connect(P_d_angle, gr.delay(gr.sizeof_float, offset), (phi, 0))
        #self.connect(P_d_angle, matched_filter2, (phi,0)) # why isn't this better?!?

        # FIXME: we add fft_length delay so that the preamble is nco corrected too
        # BUT is this buffering worth it? consider implementing sync as a proper block

        # delay the input signal to follow the frequency offset signal
        self.connect(self, gr.delay(gr.sizeof_gr_complex,
                                    (fft_length + offset)), (self, 0))
        self.connect(phi, (self, 1))
        self.connect(peak_detect, (self, 2))

        if logging:
            self.connect(matched_filter,
                         gr.file_sink(gr.sizeof_float, "sync-mf.dat"))
            self.connect(M_d, gr.file_sink(gr.sizeof_float, "sync-M.dat"))
            self.connect(P_d_angle,
                         gr.file_sink(gr.sizeof_float, "sync-angle.dat"))
            self.connect(peak_detect,
                         gr.file_sink(gr.sizeof_char, "sync-peaks.datb"))
            self.connect(phi, gr.file_sink(gr.sizeof_float, "sync-phi.dat"))
コード例 #13
0
    def __init__(self, fft_length, cp_length, occupied_tones, snr, ks, threshold, options, 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 apurv--
            gr.io_signature3(
                3, 3, gr.sizeof_gr_complex * occupied_tones, gr.sizeof_char, gr.sizeof_gr_complex * occupied_tones
            ),
        )  # apurv++, goes into frame sink for hestimates
        # gr.io_signature4(4, 4, gr.sizeof_gr_complex*occupied_tones, gr.sizeof_char, gr.sizeof_gr_complex*occupied_tones, gr.sizeof_gr_complex*fft_length))     # apurv++, goes into frame sink for hestimates

        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)

        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()

        nco_sensitivity = -2.0 / fft_length  # correct for fine frequency
        self.ofdm_sync = ofdm_sync_pn(
            fft_length, cp_length, ks0time, threshold, options.threshold_type, options.threshold_gap, logging
        )  # apurv++

        # Set up blocks

        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, len(ks) + 1, 100
        )  # 1 for the extra preamble which ofdm_rx doesn't know about (check frame_sink)
        self.fft_demod = gr.fft_vcc(fft_length, True, win, True)
        self.ofdm_frame_acq = digital_swig.ofdm_frame_acquisition(occupied_tones, fft_length, cp_length, ks)

        if options.verbose:
            self._print_verbage(options)

        # apurv++ modified to allow collected time domain data to artifically pass through the rx chain #

        # to replay the input manually, use this #
        # self.connect(self, gr.null_sink(gr.sizeof_gr_complex))
        # self.connect(gr.file_source(gr.sizeof_gr_complex, "input.dat"), self.chan_filt)

        ############# input -> chan_filt ##############
        self.connect(self, self.chan_filt)

        use_chan_filt = options.use_chan_filt
        correct_freq_offset = 0

        if use_chan_filt == 1:
            ##### chan_filt -> SYNC, chan_filt -> SIGMIX ####
            self.connect(self.chan_filt, self.ofdm_sync)
            if correct_freq_offset == 1:
                # enable if frequency offset correction is required #
                self.connect(
                    self.chan_filt, gr.delay(gr.sizeof_gr_complex, (fft_length)), (self.sigmix, 0)
                )  # apurv++ follow freq offset
            else:
                self.connect(self.chan_filt, (self.sampler, 0))
                ###self.connect(self.chan_filt, gr.delay(gr.sizeof_gr_complex, (fft_length)), (self.sampler, 0))		## extra delay

                # self.connect(self.chan_filt, gr.file_sink(gr.sizeof_gr_complex, "ofdm_receiver-chan_filt_c.dat"))
        elif use_chan_filt == 2:
            #### alternative: chan_filt-> NULL, file_source -> SYNC, file_source -> SIGMIX ####
            self.connect(self.chan_filt, gr.null_sink(gr.sizeof_gr_complex))
            if correct_freq_offset == 1:
                self.connect(gr.file_source(gr.sizeof_gr_complex, "chan_filt.dat"), self.ofdm_sync)
                self.connect(
                    gr.file_source(gr.sizeof_gr_complex, "chan_filt.dat"),
                    gr.delay(gr.sizeof_gr_complex, (fft_length)),
                    (self.sigmix, 0),
                )
            else:
                self.connect(gr.file_source(gr.sizeof_gr_complex, "chan_filt.dat"), self.ofdm_sync)
                self.connect(gr.file_source(gr.sizeof_gr_complex, "chan_filt.dat"), (self.sampler, 0))
        else:
            # chan_filt->NULL #
            self.connect(self.chan_filt, gr.null_sink(gr.sizeof_gr_complex))

        method = options.method
        if method == -1:
            ################## for offline analysis, dump sampler input till the frame_sink, using io_signature4 #################
            if correct_freq_offset == 1:
                # enable if frequency offset correction is required #
                self.connect((self.ofdm_sync, 0), self.nco, (self.sigmix, 1))  # freq offset (0'ed :/)
                self.connect(self.sigmix, (self.sampler, 0))  # corrected output (0'ed FF)
                self.connect(
                    (self.ofdm_sync, 1), gr.delay(gr.sizeof_char, fft_length), (self.sampler, 1)
                )  # timing signal

            else:
                # disable frequency offset correction completely #
                self.connect((self.ofdm_sync, 0), gr.null_sink(gr.sizeof_float))
                self.connect((self.ofdm_sync, 1), (self.sampler, 1))  # timing signal,

                # self.connect((self.ofdm_sync,0), (self.sampler, 2))						##added
                ##self.connect((self.ofdm_sync,1), gr.delay(gr.sizeof_char, fft_length+cp_length), (self.sampler, 1))           # timing signal, ##extra delay

                # route received time domain to sink (all-the-way) for offline analysis #
            self.connect((self.sampler, 0), (self.ofdm_frame_acq, 2))
            # self.connect((self.sampler, 1), gr.file_sink(gr.sizeof_char*fft_length, "sampler_timing.dat"))

        elif method == 0:
            # NORMAL functioning #
            if correct_freq_offset == 1:
                self.connect(
                    (self.ofdm_sync, 0), self.nco, (self.sigmix, 1)
                )  # use sync freq. offset output to derotate input signal
                self.connect(self.sigmix, (self.sampler, 0))  # sample off timing signal detected in sync alg
                self.connect((self.ofdm_sync, 1), gr.delay(gr.sizeof_char, fft_length), (self.sampler, 1))  # delay?
            else:
                self.connect((self.ofdm_sync, 1), (self.sampler, 1))

                # self.connect((self.sampler, 2), (self.ofdm_frame_acq, 2))
                #######################################################################

        use_default = options.use_default
        if use_default == 0:  # (set method == 0)
            # sampler-> NULL, replay trace->fft_demod, ofdm_frame_acq (time domain) #
            # self.connect((self.sampler, 0), gr.null_sink(gr.sizeof_gr_complex*fft_length))
            # self.connect((self.sampler, 1), gr.null_sink(gr.sizeof_char*fft_length))

            self.connect(gr.file_source(gr.sizeof_gr_complex * fft_length, "symbols_src.dat"), self.fft_demod)
            self.connect(gr.file_source(gr.sizeof_char * fft_length, "timing_src.dat"), (self.ofdm_frame_acq, 1))
            self.connect(self.fft_demod, (self.ofdm_frame_acq, 0))
        elif use_default == 1:  # (set method == -1)
            # normal functioning #
            self.connect((self.sampler, 0), self.fft_demod)  # send derotated sampled signal to FFT
            self.connect((self.sampler, 1), (self.ofdm_frame_acq, 1))  # send timing signal to signal frame start
            self.connect(self.fft_demod, (self.ofdm_frame_acq, 0))
        elif use_default == 2:
            # replay directly to ofdm_frame_acq (frequency domain) #
            self.connect(gr.file_source(gr.sizeof_gr_complex * fft_length, "symbols_src.dat"), (self.ofdm_frame_acq, 0))
            self.connect(gr.file_source(gr.sizeof_char * fft_length, "timing_src.dat"), (self.ofdm_frame_acq, 1))

        ########################### some logging start ##############################
        # self.connect((self.ofdm_sync,1), gr.delay(gr.sizeof_char, fft_length), gr.file_sink(gr.sizeof_char, "ofdm_sync_pn-peaks_b.dat"))
        # self.connect((self.sampler, 0), gr.file_sink(gr.sizeof_gr_complex*fft_length, "ofdm_receiver-sampler_c.dat"))
        # self.connect((self.sampler, 1), gr.file_sink(gr.sizeof_char*fft_length, "ofdm_timing_sampler_c.dat"))
        ############################ some logging end ###############################

        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
        self.connect((self.ofdm_frame_acq, 2), (self, 2))  # equalizer: hestimates

        # self.connect((self.ofdm_frame_acq,3), (self,3))           # ref sampler above

        # apurv++ ends #

        # 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"))

        # apurv++ log the fine frequency offset corrected symbols #
        # self.connect((self.ofdm_frame_acq, 1), gr.file_sink(gr.sizeof_char, "ofdm_timing_frame_acq_c.dat"))
        # self.connect((self.ofdm_frame_acq, 2), gr.file_sink(gr.sizeof_gr_complex*occupied_tones, "ofdm_hestimates_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.chan_filt, gr.file_sink(gr.sizeof_gr_complex, "ofdm_receiver-chan_filt_c.dat"))
        # self.connect(self, gr.file_sink(gr.sizeof_gr_complex, "ofdm_input_c.dat"))
        # apurv++ end #

        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"))
コード例 #14
0
    def __init__(self, fft_length, block_length, block_header, range, options):
        gr.hier_block2.__init__(
            self, "integer_fo_estimator",
            gr.io_signature3(3, 3, gr.sizeof_gr_complex, gr.sizeof_float,
                             gr.sizeof_char),
            gr.io_signature2(3, 3, gr.sizeof_float, gr.sizeof_char))

        raise NotImplementedError, "Obsolete class"

        self._range = range

        # threshold after integer part frequency offset estimation
        # if peak value below threshold, assume false triggering
        self._thr_lo = 0.4  #0.19 # empirically found threshold. see ioe_metric.float
        self._thr_hi = 0.4  #0.2

        # stuff to be removed after bugfix for hierblock2s
        self.input = gr.kludge_copy(gr.sizeof_gr_complex)
        self.time_sync = gr.kludge_copy(gr.sizeof_char)
        self.epsilon = (self, 1)
        self.connect((self, 0), self.input)
        self.connect((self, 2), self.time_sync)

        delay(gr.sizeof_char, block_header.schmidl_fine_sync[0] * block_length)

        # sample ofdm symbol (preamble 1 and 2)
        sampler_symbol1 = vector_sampler(gr.sizeof_gr_complex, fft_length)
        sampler_symbol2 = vector_sampler(gr.sizeof_gr_complex, fft_length)
        time_delay1 = delay(gr.sizeof_char,
                            block_length * block_header.schmidl_fine_sync[1])
        self.connect(self.input, (sampler_symbol1, 0))
        self.connect(self.input, (sampler_symbol2, 0))
        if block_header.schmidl_fine_sync[0] > 0:
            time_delay0 = delay(
                gr.sizeof_char,
                block_length * block_header.schmidl_fine_sync[0])
            self.connect(self.time_sync, time_delay0, (sampler_symbol1, 1))
        else:
            self.connect(self.time_sync, (sampler_symbol1, 1))
        self.connect(self.time_sync, time_delay1, (sampler_symbol2, 1))

        # negative fractional frequency offset estimate
        epsilon = gr.multiply_const_ff(-1.0)
        self.connect(self.epsilon, epsilon)

        # compensate for fractional frequency offset on per symbol base
        #  freq_shift: vector length, modulator sensitivity
        #  freq_shift third input: reset phase accumulator

        # symbol/preamble 1
        freq_shift_sym1 = frequency_shift_vcc(fft_length, 1.0 / fft_length)
        self.connect(sampler_symbol1, (freq_shift_sym1, 0))
        self.connect(epsilon, (freq_shift_sym1, 1))
        self.connect(gr.vector_source_b([1], True), (freq_shift_sym1, 2))

        # symbol/preamble 2
        freq_shift_sym2 = frequency_shift_vcc(fft_length, 1.0 / fft_length)
        self.connect(sampler_symbol2, (freq_shift_sym2, 0))
        self.connect(epsilon, (freq_shift_sym2, 1))
        self.connect(gr.vector_source_b([1], True), (freq_shift_sym2, 2))

        # fourier transfrom on both preambles
        fft_sym1 = gr.fft_vcc(fft_length, True, [],
                              True)  # Forward + Blockshift
        fft_sym2 = gr.fft_vcc(fft_length, True, [],
                              True)  # Forward + Blockshift

        # calculate schmidl's metric for estimation of freq. offset's integer part
        assert (hasattr(block_header, "schmidl_fine_sync"))
        pre1 = block_header.pilotsym_fd[block_header.schmidl_fine_sync[0]]
        pre2 = block_header.pilotsym_fd[block_header.schmidl_fine_sync[1]]
        diff_pn = concatenate(
            [[conjugate(math.sqrt(2) * pre2[2 * i] / pre1[2 * i]), 0.0j]
             for i in arange(len(pre1) / 2)])
        cfo_estimator = schmidl_cfo_estimator(fft_length, len(pre1),
                                              self._range, diff_pn)
        self.connect(freq_shift_sym1, fft_sym1,
                     (cfo_estimator, 0))  # preamble 1
        self.connect(freq_shift_sym2, fft_sym2,
                     (cfo_estimator, 1))  # preamble 2

        # search for maximum and its argument in interval [-range .. +range]
        #arg_max = arg_max_vff(2*self._range + 1)
        arg_max_s = gr.argmax_fs(2 * self._range + 1)
        arg_max = gr.short_to_float()
        ifo_max = gr.max_ff(2 * self._range + 1)  # vlen
        ifo_estimate = gr.add_const_ff(-self._range)
        self.connect(cfo_estimator, arg_max_s, arg_max, ifo_estimate)
        self.connect(cfo_estimator, ifo_max)
        self.connect((arg_max_s, 1), gr.null_sink(gr.sizeof_short))

        # threshold maximal value
        ifo_threshold = gr.threshold_ff(self._thr_lo, self._thr_hi, 0.0)
        ifo_thr_f2b = gr.float_to_char()
        self.connect(ifo_max, ifo_threshold, ifo_thr_f2b)

        # gating the streams ifo_estimate (integer part) and epsilon (frac. part)
        # if the metric's peak value was above the chosen threshold, assume to have
        # found a new burst. peak value below threshold results in blocking the
        # streams
        self.gate = gate_ff()
        self.connect(ifo_thr_f2b, (self.gate, 0))  # threshold stream
        self.connect(ifo_estimate, (self.gate, 1))
        self.connect(epsilon, (self.gate, 2))

        # peak filtering
        # resynchronize and suppress peaks that didn't match a preamble
        filtered_time_sync = peak_resync_bb(True)  # replace
        self.connect(self.time_sync, (filtered_time_sync, 0))
        self.connect(ifo_thr_f2b, (filtered_time_sync, 1))

        # find complete estimation for frequency offset
        # add together fractional and integer part
        freq_offset = gr.add_ff()
        self.connect((self.gate, 1), gr.multiply_const_ff(-1.0),
                     (freq_offset, 0))  # integer offset
        self.connect((self.gate, 2), (freq_offset, 1))  # frac offset

        # output connections
        self.connect(freq_offset, (self, 0))
        self.connect(filtered_time_sync, (self, 1))
        self.connect((self.gate, 0), (self, 2))  # used for frame trigger

        #########################################
        # debugging
        if options.log:
            self.epsilon2_sink = gr.vector_sink_f()
            self.connect(epsilon, self.epsilon2_sink)

            self.connect(
                cfo_estimator,
                gr.file_sink(gr.sizeof_float * (self._range * 2 + 1),
                             "data/ioe_metric.float"))

            # output joint stream
            preamble_stream = gr.streams_to_vector(
                fft_length * gr.sizeof_gr_complex, 2)
            self.connect(fft_sym1, (preamble_stream, 0))
            self.connect(fft_sym2, (preamble_stream, 1))
            self.connect(
                preamble_stream,
                gr.file_sink(gr.sizeof_gr_complex * 2 * fft_length,
                             "data/preambles.compl"))

            # output, preambles before and after correction, magnitude and complex spectrum
            self.connect(
                sampler_symbol1, gr.fft_vcc(fft_length, True, [], True),
                gr.file_sink(gr.sizeof_gr_complex * fft_length,
                             "data/pre1_bef.compl"))
            self.connect(
                sampler_symbol1, gr.fft_vcc(fft_length, True, [], True),
                gr.complex_to_mag(fft_length),
                gr.file_sink(gr.sizeof_float * fft_length,
                             "data/pre1_bef.float"))
            self.connect(
                sampler_symbol2, gr.fft_vcc(fft_length, True, [], True),
                gr.file_sink(gr.sizeof_gr_complex * fft_length,
                             "data/pre2_bef.compl"))
            self.connect(
                sampler_symbol2, gr.fft_vcc(fft_length, True, [], True),
                gr.complex_to_mag(fft_length),
                gr.file_sink(gr.sizeof_float * fft_length,
                             "data/pre2_bef.float"))
            self.connect(
                freq_shift_sym1, gr.fft_vcc(fft_length, True, [], True),
                gr.file_sink(gr.sizeof_gr_complex * fft_length,
                             "data/pre1.compl"))
            self.connect(
                freq_shift_sym1, gr.fft_vcc(fft_length, True, [], True),
                gr.complex_to_mag(fft_length),
                gr.file_sink(gr.sizeof_float * fft_length, "data/pre1.float"))
            self.connect(
                freq_shift_sym2, gr.fft_vcc(fft_length, True, [], True),
                gr.file_sink(gr.sizeof_gr_complex * fft_length,
                             "data/pre2.compl"))
            self.connect(
                freq_shift_sym2, gr.fft_vcc(fft_length, True, [], True),
                gr.complex_to_mag(fft_length),
                gr.file_sink(gr.sizeof_float * fft_length, "data/pre2.float"))

            # calculate epsilon from corrected source to check function
            test_cp = cyclic_prefixer(fft_length, block_length)
            test_eps = foe(fft_length)
            self.connect(freq_shift_sym1, test_cp, test_eps,
                         gr.file_sink(gr.sizeof_float, "data/eps_after.float"))

        try:
            gr.hier_block.update_var_names(self, "ifo_estimator", vars())
            gr.hier_block.update_var_names(self, "ifo_estimator", vars(self))
        except:
            pass
コード例 #15
0
ファイル: raw_ofdm_mod.py プロジェクト: ljxangus/ofdm
    def __init__(self, options, noutputs=2):
        """
    @param options: parsed raw.ofdm_params
    """
        self.params = ofdm_params(options)
        params = self.params

        if noutputs == 2:
            output_signature = gr.io_signature2(
                2, 2, gr.sizeof_gr_complex * params.data_tones, gr.sizeof_char)
        elif noutputs == 3:
            output_signature = gr.io_signature3(
                3, 3, gr.sizeof_gr_complex * params.data_tones, gr.sizeof_char,
                gr.sizeof_float)
        elif noutputs == 4:
            output_signature = gr.io_signature4(
                4, 4, gr.sizeof_gr_complex * params.data_tones, gr.sizeof_char,
                gr.sizeof_float, gr.sizeof_float)
        else:
            # error
            raise Exception("unsupported number of outputs")

        gr.hier_block2.__init__(self, "ofdm_demod",
                                gr.io_signature(1, 1, gr.sizeof_gr_complex),
                                output_signature)

        self.ofdm_recv = ofdm_receiver(params, options.log)

        # FIXME: magic parameters
        phgain = 0.4
        frgain = phgain * phgain / 4.0
        eqgain = 0.05
        self.ofdm_demod = raw.ofdm_demapper(params.carriers, phgain, frgain,
                                            eqgain)

        # the studios can't handle the whole ofdm in one thread
        #ofdm_recv = raw.wrap_sts(self.ofdm_recv)
        ofdm_recv = self.ofdm_recv

        self.connect(self, ofdm_recv)
        self.connect((ofdm_recv, 0), (self.ofdm_demod, 0))
        self.connect((ofdm_recv, 1), (self.ofdm_demod, 1))

        self.connect(self.ofdm_demod, (self, 0))
        self.connect((ofdm_recv, 1), (self, 1))

        if noutputs > 2:
            # average noise power per (pilot) subcarrier
            self.connect((self.ofdm_demod, 1), (self, 2))

        if noutputs > 3:
            # average signal power per subcarrier
            self.connect(
                (ofdm_recv, 0),
                gr.vector_to_stream(gr.sizeof_float, params.occupied_tones),
                gr.integrate_ff(params.occupied_tones),
                gr.multiply_ff(1.0 / params.occupied_tones), (self, 3))

        if options.log:
            self.connect(
                (self.ofdm_demod, 2),
                gr.file_sink(gr.sizeof_gr_complex * params.occupied_tones,
                             'rx-eq.dat'))
            self.connect((self.ofdm_demod, 1),
                         gr.file_sink(gr.sizeof_float, 'rx-noise.dat'))
            self.connect((self.ofdm_demod, 0),
                         gr.file_sink(gr.sizeof_gr_complex * params.data_tones,
                                      'rx-demap.dat'))
コード例 #16
0
    def __init__(self, fft_length, cp_length, half_sync, kstime, ks1time, threshold, logging=False):
        gr.hier_block2.__init__(
            self,
            "ofdm_sync_pn",
            gr.io_signature(1, 1, gr.sizeof_gr_complex),  # Input signature
            gr.io_signature3(
                3,
                3,  # Output signature
                gr.sizeof_gr_complex,  # delayed input
                gr.sizeof_float,  # fine frequency offset
                gr.sizeof_char,  # timing indicator
            ),
        )

        if half_sync:
            period = fft_length / 2
            window = fft_length / 2
        else:  # full symbol
            period = fft_length + cp_length
            window = fft_length  # makes the plateau cp_length long

        # Calculate the frequency offset from the correlation of the preamble
        x_corr = gr.multiply_cc()
        self.connect(self, gr.conjugate_cc(), (x_corr, 0))
        self.connect(self, gr.delay(gr.sizeof_gr_complex, period), (x_corr, 1))
        P_d = gr.moving_average_cc(window, 1.0)
        self.connect(x_corr, P_d)

        # offset by -1
        phi = gr.sample_and_hold_ff()
        self.corrmag = gr.complex_to_mag_squared()
        P_d_angle = gr.complex_to_arg()
        self.connect(P_d, P_d_angle, (phi, 0))

        cross_correlate = 1
        if cross_correlate == 1:
            # cross-correlate with the known symbol
            kstime = [k.conjugate() for k in kstime]
            kstime.reverse()
            self.crosscorr_filter = gr.fir_filter_ccc(1, kstime)

            """
        self.f2b = gr.float_to_char()
        self.slice = gr.threshold_ff(threshold, threshold, 0, fft_length)
        #self.connect(self, self.crosscorr_filter, self.corrmag, self.slice, self.f2b)
	self.connect(self.f2b, (phi,1))
	self.connect(self.f2b, (self,2))
	self.connect(self.f2b, gr.file_sink(gr.sizeof_char, "ofdm_f2b.dat"))
	"""

            # new method starts here - only crosscorrelate and use peak_detect block #
            peak_detect = gr.peak_detector_fb(100, 100, 30, 0.001)
            self.corrmag1 = gr.complex_to_mag_squared()
            self.connect(self, self.crosscorr_filter, self.corrmag, peak_detect)

            self.connect(peak_detect, (phi, 1))
            self.connect(peak_detect, (self, 2))

            self.connect(peak_detect, gr.file_sink(gr.sizeof_char, "sync-peaks_b.dat"))
            self.connect(self.corrmag, gr.file_sink(gr.sizeof_float, "ofdm_corrmag.dat"))
            self.connect(self, gr.delay(gr.sizeof_gr_complex, (fft_length)), (self, 0))

        else:
            # Get the power of the input signal to normalize the output of the correlation
            R_d = gr.moving_average_ff(window, 1.0)
            self.connect(self, gr.complex_to_mag_squared(), R_d)
            R_d_squared = gr.multiply_ff()  # this is retarded
            self.connect(R_d, (R_d_squared, 0))
            self.connect(R_d, (R_d_squared, 1))
            M_d = gr.divide_ff()
            self.connect(P_d, gr.complex_to_mag_squared(), (M_d, 0))
            self.connect(R_d_squared, (M_d, 1))

            # Now we need to detect peak of M_d
            matched_filter = gr.moving_average_ff(cp_length, 1.0 / cp_length)
            peak_detect = gr.peak_detector_fb(0.25, 0.25, 30, 0.001)
            self.connect(M_d, matched_filter, gr.add_const_ff(-1), peak_detect)
            offset = cp_length / 2  # cp_length/2
            self.connect(peak_detect, (phi, 1))
            self.connect(peak_detect, (self, 2))
            self.connect(P_d_angle, gr.delay(gr.sizeof_float, offset), (phi, 0))
            self.connect(
                self, gr.delay(gr.sizeof_gr_complex, (fft_length + offset)), (self, 0)
            )  # delay the input to follow the freq offset
            self.connect(peak_detect, gr.delay(gr.sizeof_char, (fft_length + offset)), (self, 2))
            self.connect(peak_detect, gr.file_sink(gr.sizeof_char, "sync-peaks_b.dat"))
            self.connect(matched_filter, gr.file_sink(gr.sizeof_float, "sync-mf.dat"))

        self.connect(phi, (self, 1))

        if logging:
            self.connect(matched_filter, gr.file_sink(gr.sizeof_float, "sync-mf.dat"))
            self.connect(M_d, gr.file_sink(gr.sizeof_float, "sync-M.dat"))
            self.connect(P_d_angle, gr.file_sink(gr.sizeof_float, "sync-angle.dat"))
            self.connect(peak_detect, gr.file_sink(gr.sizeof_char, "sync-peaks.datb"))
            self.connect(phi, gr.file_sink(gr.sizeof_float, "sync-phi.dat"))
コード例 #17
0
    def __init__(
        self, fft_length, cp_length, occupied_tones, snr, ks, threshold, options, logging=False
    ):  # apurv++: added num_symbols, use_chan_filt
        """
    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
    """

        gr.hier_block2.__init__(
            self,
            "ofdm_receiver",
            gr.io_signature(1, 1, gr.sizeof_gr_complex),  # Input signature
            gr.io_signature3(
                3, 3, gr.sizeof_gr_complex * occupied_tones, gr.sizeof_char, gr.sizeof_gr_complex * occupied_tones
            ),
        )  # Output signature

        # low-pass filter the input channel
        bw = (float(occupied_tones) / float(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
        self.chan_filt = gr.fft_filter_ccc(1, lpf_coeffs)
        self.connect(self, self.chan_filt)
        self.connect(self.chan_filt, gr.file_sink(gr.sizeof_gr_complex, "rx-filt.dat"))

        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)
        ks0time = ks0time.tolist()

        ks1 = fft_length * [0]
        ks1[zeros_on_left : zeros_on_left + occupied_tones] = ks[1]
        ks1 = fft.ifftshift(ks1)
        ks1time = fft.ifft(ks1)
        ks1time = ks1time.tolist()

        # sync = ofdm_sync_pn(fft_length, cp_length, True, logging)		# raw
        sync = ofdm_sync_pn(fft_length, cp_length, True, ks0time, ks1time, threshold, logging)  # crosscorr version

        use_chan_filt = 1
        if use_chan_filt == 0:
            self.connect(gr.file_source(gr.sizeof_gr_complex, "chan-filt.dat"), sync)
        else:
            self.connect(self.chan_filt, sync)

        # correct for fine frequency offset computed in sync (up to +-pi/fft_length)
        nco_sensitivity = 2.0 / fft_length

        nco = gr.frequency_modulator_fc(nco_sensitivity)
        sigmix = gr.multiply_cc()

        # sample at symbol boundaries
        # NOTE: (sync,2) indicates the first sample of the symbol!
        sampler = digital_swig.ofdm_sampler(fft_length, fft_length + cp_length, len(ks) + 1, timeout=100)  # apurv--

        # frequency offset correction #
        self.connect((sync, 0), (sigmix, 0))
        self.connect((sync, 1), nco, (sigmix, 1))
        self.connect(sigmix, (sampler, 0))
        self.connect((sync, 2), (sampler, 1))

        """
    self.connect((sync,0), (sampler,0))
    self.connect((sync,2), (sampler,1))  # timing signal to sample at
    self.connect((sync,1), gr.file_sink(gr.sizeof_float, "offset.dat"))
    """

        self.connect((sampler, 1), gr.file_sink(gr.sizeof_char, "sampler_timing.dat"))
        # self.connect((sampler, 2), gr.file_sink(gr.sizeof_char*fft_length, "sampler_timing_fft.dat"))

        # fft on the symbols
        win = [1 for i in range(fft_length)]
        # see gr_fft_vcc_fftw that it works differently if win = []
        fft1 = gr.fft_vcc(fft_length, True, win, True)
        self.connect((sampler, 0), fft1)

        # use the preamble to correct the coarse frequency offset and initial equalizer
        ###frame_acq = raw.ofdm_frame_acquisition(fft_length, cp_length, preambles_raw, carriers)
        frame_acq = digital_swig.ofdm_frame_acquisition(occupied_tones, fft_length, cp_length, ks)

        self.frame_acq = frame_acq

        # normal operation #
        self.connect((fft1, 0), gr.file_sink(gr.sizeof_gr_complex * options.fft_length, "fft-out.dat"))
        self.connect((sampler, 1), gr.file_sink(gr.sizeof_char, "sampler_timing.dat"))
        self.connect(fft1, (frame_acq, 0))
        self.connect((sampler, 1), (frame_acq, 1))

        """ 
    # enable to have manual input to frame_acq # 
    self.connect(fft1, gr.null_sink(gr.sizeof_gr_complex*options.fft_length))
    self.connect(gr.file_source(gr.sizeof_gr_complex*options.fft_length, "combined.dat"), (frame_acq,0))
    self.connect(gr.file_source(gr.sizeof_char, "combined_t.dat"), (frame_acq,1))
    """

        # self.connect(fft, gr.null_sink(gr.sizeof_gr_complex*options.fft_length))
        # self.connect((sampler, 1), gr.null_sink(gr.sizeof_char))
        # self.connect(gr.file_source(gr.sizeof_gr_complex*options.fft_length, "symbols_src.dat"), (frame_acq, 0))
        # self.connect(gr.file_source(gr.sizeof_char, "timing.dat"), (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
        self.connect((frame_acq, 2), (self, 2))  # hestimates

        self.connect((frame_acq, 0), gr.file_sink(gr.sizeof_gr_complex * occupied_tones, "rx-acq.dat"))
        self.connect((frame_acq, 1), gr.file_sink(gr.sizeof_char, "timing-acq.dat"))

        if logging:
            self.connect(self.chan_filt, gr.file_sink(gr.sizeof_gr_complex, "rx-filt.dat"))
            self.connect(fft1, gr.file_sink(gr.sizeof_gr_complex * fft_length, "rx-fft.dat"))
            self.connect((frame_acq, 0), gr.file_sink(gr.sizeof_gr_complex * 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 * 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"))
コード例 #18
0
    def __init__(
            self,
            sample_rate,
            ber_threshold=0,  # Above which to do search
            ber_smoothing=0,  # Alpha of BER smoother (0.01)
            ber_duration=0,  # Length before trying next combo
            ber_sample_decimation=1,
            settling_period=0,
            pre_lock_duration=0,
            #ber_sample_skip=0
            **kwargs):

        use_throttle = False
        base_duration = 1024
        if sample_rate > 0:
            use_throttle = True
            base_duration *= 4  # Has to be high enough for block-delay

        if ber_threshold == 0:
            ber_threshold = 512 * 4
        if ber_smoothing == 0:
            ber_smoothing = 0.01
        if ber_duration == 0:
            ber_duration = base_duration * 2  # 1000ms
        if settling_period == 0:
            settling_period = base_duration * 1  # 500ms
        if pre_lock_duration == 0:
            pre_lock_duration = base_duration * 2  #1000ms

        print "Creating Auto-FEC:"
        print "\tsample_rate:\t\t", sample_rate
        print "\tber_threshold:\t\t", ber_threshold
        print "\tber_smoothing:\t\t", ber_smoothing
        print "\tber_duration:\t\t", ber_duration
        print "\tber_sample_decimation:\t", ber_sample_decimation
        print "\tsettling_period:\t", settling_period
        print "\tpre_lock_duration:\t", pre_lock_duration
        print ""

        self.sample_rate = sample_rate
        self.ber_threshold = ber_threshold
        #self.ber_smoothing = ber_smoothing
        self.ber_duration = ber_duration
        self.settling_period = settling_period
        self.pre_lock_duration = pre_lock_duration
        #self.ber_sample_skip = ber_sample_skip

        self.data_lock = threading.Lock()

        gr.hier_block2.__init__(
            self,
            "auto_fec",
            gr.io_signature(
                1, 1,
                gr.sizeof_gr_complex),  # Post MPSK-receiver complex input
            gr.io_signature3(
                3, 3, gr.sizeof_char, gr.sizeof_float,
                gr.sizeof_float))  # Decoded packed bytes, BER metric, lock

        self.input_watcher = auto_fec_input_watcher(self)
        default_xform = self.input_watcher.xform_lock

        self.gr_conjugate_cc_0 = gr.conjugate_cc()
        self.connect((self, 0), (self.gr_conjugate_cc_0, 0))  # Input

        self.blks2_selector_0 = grc_blks2.selector(
            item_size=gr.sizeof_gr_complex * 1,
            num_inputs=2,
            num_outputs=1,
            input_index=default_xform.get_conjugation_index(),
            output_index=0,
        )
        self.connect((self.gr_conjugate_cc_0, 0), (self.blks2_selector_0, 0))
        self.connect((self, 0), (self.blks2_selector_0, 1))  # Input

        self.gr_multiply_const_vxx_3 = gr.multiply_const_vcc(
            (0.707 * (1 + 1j), ))
        self.connect((self.blks2_selector_0, 0),
                     (self.gr_multiply_const_vxx_3, 0))

        self.gr_multiply_const_vxx_2 = gr.multiply_const_vcc(
            (default_xform.get_rotation(), ))  # phase_mult
        self.connect((self.gr_multiply_const_vxx_3, 0),
                     (self.gr_multiply_const_vxx_2, 0))

        self.gr_complex_to_float_0_0 = gr.complex_to_float(1)
        self.connect((self.gr_multiply_const_vxx_2, 0),
                     (self.gr_complex_to_float_0_0, 0))

        self.gr_interleave_1 = gr.interleave(gr.sizeof_float * 1)
        self.connect((self.gr_complex_to_float_0_0, 1),
                     (self.gr_interleave_1, 1))
        self.connect((self.gr_complex_to_float_0_0, 0),
                     (self.gr_interleave_1, 0))

        self.gr_multiply_const_vxx_0 = gr.multiply_const_vff((1, ))  # invert
        self.connect((self.gr_interleave_1, 0),
                     (self.gr_multiply_const_vxx_0, 0))

        self.baz_delay_2 = baz.delay(
            gr.sizeof_float * 1,
            default_xform.get_puncture_delay())  # delay_puncture
        self.connect((self.gr_multiply_const_vxx_0, 0), (self.baz_delay_2, 0))

        self.depuncture_ff_0 = baz.depuncture_ff(
            (_puncture_matrices[self.input_watcher.puncture_matrix][1]
             ))  # puncture_matrix
        self.connect((self.baz_delay_2, 0), (self.depuncture_ff_0, 0))

        self.baz_delay_1 = baz.delay(
            gr.sizeof_float * 1,
            default_xform.get_viterbi_delay())  # delay_viterbi
        self.connect((self.depuncture_ff_0, 0), (self.baz_delay_1, 0))

        self.swap_ff_0 = baz.swap_ff(
            default_xform.get_viterbi_swap())  # swap_viterbi
        self.connect((self.baz_delay_1, 0), (self.swap_ff_0, 0))

        self.gr_decode_ccsds_27_fb_0 = gr.decode_ccsds_27_fb()

        if use_throttle:
            print "==> Using throttle at sample rate:", self.sample_rate
            self.gr_throttle_0 = gr.throttle(gr.sizeof_float, self.sample_rate)
            self.connect((self.swap_ff_0, 0), (self.gr_throttle_0, 0))
            self.connect((self.gr_throttle_0, 0),
                         (self.gr_decode_ccsds_27_fb_0, 0))
        else:
            self.connect((self.swap_ff_0, 0),
                         (self.gr_decode_ccsds_27_fb_0, 0))

        self.connect((self.gr_decode_ccsds_27_fb_0, 0),
                     (self, 0))  # Output bytes

        self.gr_add_const_vxx_1 = gr.add_const_vff((-4096, ))
        self.connect((self.gr_decode_ccsds_27_fb_0, 1),
                     (self.gr_add_const_vxx_1, 0))

        self.gr_multiply_const_vxx_1 = gr.multiply_const_vff((-1, ))
        self.connect((self.gr_add_const_vxx_1, 0),
                     (self.gr_multiply_const_vxx_1, 0))
        self.connect((self.gr_multiply_const_vxx_1, 0),
                     (self, 1))  # Output BER

        self.gr_single_pole_iir_filter_xx_0 = gr.single_pole_iir_filter_ff(
            ber_smoothing, 1)
        self.connect((self.gr_multiply_const_vxx_1, 0),
                     (self.gr_single_pole_iir_filter_xx_0, 0))

        self.gr_keep_one_in_n_0 = blocks.keep_one_in_n(gr.sizeof_float,
                                                       ber_sample_decimation)
        self.connect((self.gr_single_pole_iir_filter_xx_0, 0),
                     (self.gr_keep_one_in_n_0, 0))

        self.const_source_x_0 = gr.sig_source_f(0, gr.GR_CONST_WAVE, 0, 0,
                                                0)  # Last param is const value
        if use_throttle:
            lock_throttle_rate = self.sample_rate // 16
            print "==> Using lock throttle rate:", lock_throttle_rate
            self.gr_throttle_1 = gr.throttle(gr.sizeof_float,
                                             lock_throttle_rate)
            self.connect((self.const_source_x_0, 0), (self.gr_throttle_1, 0))
            self.connect((self.gr_throttle_1, 0), (self, 2))
        else:
            self.connect((self.const_source_x_0, 0), (self, 2))

        self.msg_q = gr.msg_queue(
            2 * 256
        )  # message queue that holds at most 2 messages, increase to speed up process
        self.msg_sink = gr.message_sink(
            gr.sizeof_float, self.msg_q,
            dont_block=0)  # Block to speed up process
        self.connect((self.gr_keep_one_in_n_0, 0), self.msg_sink)

        self.input_watcher.start()
コード例 #19
0
    def __init__(self,
                 fft_length,
                 cp_length,
                 occupied_tones,
                 snr,
                 ks,
                 threshold,
                 options,
                 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 apurv--
            gr.io_signature3(3, 3, gr.sizeof_gr_complex * occupied_tones,
                             gr.sizeof_char,
                             gr.sizeof_gr_complex * occupied_tones
                             ))  # apurv++, goes into frame sink for hestimates
        #gr.io_signature4(4, 4, gr.sizeof_gr_complex*occupied_tones, gr.sizeof_char, gr.sizeof_gr_complex*occupied_tones, gr.sizeof_gr_complex*fft_length))     # apurv++, goes into frame sink for hestimates

        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)

        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()

        nco_sensitivity = -2.0 / fft_length  # correct for fine frequency
        self.ofdm_sync = ofdm_sync_pn(fft_length, cp_length, ks0time,
                                      threshold, options.threshold_type,
                                      options.threshold_gap,
                                      logging)  # apurv++

        # Set up blocks

        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,
            len(ks) + 1, 100
        )  # 1 for the extra preamble which ofdm_rx doesn't know about (check frame_sink)
        self.fft_demod = gr.fft_vcc(fft_length, True, win, True)
        self.ofdm_frame_acq = digital_swig.ofdm_frame_acquisition(
            occupied_tones, fft_length, cp_length, ks)

        if options.verbose:
            self._print_verbage(options)

# apurv++ modified to allow collected time domain data to artifically pass through the rx chain #

# to replay the input manually, use this #
#self.connect(self, gr.null_sink(gr.sizeof_gr_complex))
#self.connect(gr.file_source(gr.sizeof_gr_complex, "input.dat"), self.chan_filt)

############# input -> chan_filt ##############
        self.connect(self, self.chan_filt)

        use_chan_filt = options.use_chan_filt
        correct_freq_offset = 0

        if use_chan_filt == 1:
            ##### chan_filt -> SYNC, chan_filt -> SIGMIX ####
            self.connect(self.chan_filt, self.ofdm_sync)
            if correct_freq_offset == 1:
                # enable if frequency offset correction is required #
                self.connect(self.chan_filt,
                             gr.delay(gr.sizeof_gr_complex, (fft_length)),
                             (self.sigmix, 0))  # apurv++ follow freq offset
            else:
                self.connect(self.chan_filt, (self.sampler, 0))
                ###self.connect(self.chan_filt, gr.delay(gr.sizeof_gr_complex, (fft_length)), (self.sampler, 0))		## extra delay

                #self.connect(self.chan_filt, gr.file_sink(gr.sizeof_gr_complex, "ofdm_receiver-chan_filt_c.dat"))
        elif use_chan_filt == 2:
            #### alternative: chan_filt-> NULL, file_source -> SYNC, file_source -> SIGMIX ####
            self.connect(self.chan_filt, gr.null_sink(gr.sizeof_gr_complex))
            if correct_freq_offset == 1:
                self.connect(
                    gr.file_source(gr.sizeof_gr_complex, "chan_filt.dat"),
                    self.ofdm_sync)
                self.connect(
                    gr.file_source(gr.sizeof_gr_complex, "chan_filt.dat"),
                    gr.delay(gr.sizeof_gr_complex, (fft_length)),
                    (self.sigmix, 0))
            else:
                self.connect(
                    gr.file_source(gr.sizeof_gr_complex, "chan_filt.dat"),
                    self.ofdm_sync)
                self.connect(
                    gr.file_source(gr.sizeof_gr_complex, "chan_filt.dat"),
                    (self.sampler, 0))
        else:
            # chan_filt->NULL #
            self.connect(self.chan_filt, gr.null_sink(gr.sizeof_gr_complex))

        method = options.method
        if method == -1:
            ################## for offline analysis, dump sampler input till the frame_sink, using io_signature4 #################
            if correct_freq_offset == 1:
                # enable if frequency offset correction is required #
                self.connect((self.ofdm_sync, 0), self.nco,
                             (self.sigmix, 1))  # freq offset (0'ed :/)
                self.connect(self.sigmix,
                             (self.sampler, 0))  # corrected output (0'ed FF)
                self.connect((self.ofdm_sync, 1),
                             gr.delay(gr.sizeof_char, fft_length),
                             (self.sampler, 1))  # timing signal

            else:
                # disable frequency offset correction completely #
                self.connect((self.ofdm_sync, 0),
                             gr.null_sink(gr.sizeof_float))
                self.connect((self.ofdm_sync, 1),
                             (self.sampler, 1))  # timing signal,

                #self.connect((self.ofdm_sync,0), (self.sampler, 2))						##added
                ##self.connect((self.ofdm_sync,1), gr.delay(gr.sizeof_char, fft_length+cp_length), (self.sampler, 1))           # timing signal, ##extra delay

                # route received time domain to sink (all-the-way) for offline analysis #
            self.connect((self.sampler, 0), (self.ofdm_frame_acq, 2))
            #self.connect((self.sampler, 1), gr.file_sink(gr.sizeof_char*fft_length, "sampler_timing.dat"))

        elif method == 0:
            # NORMAL functioning #
            if correct_freq_offset == 1:
                self.connect(
                    (self.ofdm_sync, 0), self.nco, (self.sigmix, 1)
                )  # use sync freq. offset output to derotate input signal
                self.connect(
                    self.sigmix,
                    (self.sampler,
                     0))  # sample off timing signal detected in sync alg
                self.connect((self.ofdm_sync, 1),
                             gr.delay(gr.sizeof_char, fft_length),
                             (self.sampler, 1))  # delay?
            else:
                self.connect((self.ofdm_sync, 1), (self.sampler, 1))

#self.connect((self.sampler, 2), (self.ofdm_frame_acq, 2))
#######################################################################

        use_default = options.use_default
        if use_default == 0:  #(set method == 0)
            # sampler-> NULL, replay trace->fft_demod, ofdm_frame_acq (time domain) #
            #self.connect((self.sampler, 0), gr.null_sink(gr.sizeof_gr_complex*fft_length))
            #self.connect((self.sampler, 1), gr.null_sink(gr.sizeof_char*fft_length))

            self.connect(
                gr.file_source(gr.sizeof_gr_complex * fft_length,
                               "symbols_src.dat"), self.fft_demod)
            self.connect(
                gr.file_source(gr.sizeof_char * fft_length, "timing_src.dat"),
                (self.ofdm_frame_acq, 1))
            self.connect(self.fft_demod, (self.ofdm_frame_acq, 0))
        elif use_default == 1:  #(set method == -1)
            # normal functioning #
            self.connect(
                (self.sampler, 0),
                self.fft_demod)  # send derotated sampled signal to FFT
            self.connect((self.sampler, 1),
                         (self.ofdm_frame_acq,
                          1))  # send timing signal to signal frame start
            self.connect(self.fft_demod, (self.ofdm_frame_acq, 0))
        elif use_default == 2:
            # replay directly to ofdm_frame_acq (frequency domain) #
            self.connect(
                gr.file_source(gr.sizeof_gr_complex * fft_length,
                               "symbols_src.dat"), (self.ofdm_frame_acq, 0))
            self.connect(
                gr.file_source(gr.sizeof_char * fft_length, "timing_src.dat"),
                (self.ofdm_frame_acq, 1))

########################### some logging start ##############################
#self.connect((self.ofdm_sync,1), gr.delay(gr.sizeof_char, fft_length), gr.file_sink(gr.sizeof_char, "ofdm_sync_pn-peaks_b.dat"))
#self.connect((self.sampler, 0), gr.file_sink(gr.sizeof_gr_complex*fft_length, "ofdm_receiver-sampler_c.dat"))
#self.connect((self.sampler, 1), gr.file_sink(gr.sizeof_char*fft_length, "ofdm_timing_sampler_c.dat"))
############################ some logging end ###############################

        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
        self.connect((self.ofdm_frame_acq, 2),
                     (self, 2))  # equalizer: hestimates

        #self.connect((self.ofdm_frame_acq,3), (self,3))           # ref sampler above

        # apurv++ ends #

        #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"))

        # apurv++ log the fine frequency offset corrected symbols #
        #self.connect((self.ofdm_frame_acq, 1), gr.file_sink(gr.sizeof_char, "ofdm_timing_frame_acq_c.dat"))
        #self.connect((self.ofdm_frame_acq, 2), gr.file_sink(gr.sizeof_gr_complex*occupied_tones, "ofdm_hestimates_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.chan_filt, gr.file_sink(gr.sizeof_gr_complex, "ofdm_receiver-chan_filt_c.dat"))
        #self.connect(self, gr.file_sink(gr.sizeof_gr_complex, "ofdm_input_c.dat"))
        # apurv++ end #

        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"))
コード例 #20
0
ファイル: ofdm_receiver.py プロジェクト: RabbitNick/extrasy
    def __init__(self, fft_length, cp_length, occupied_tones, snr, ks, vcsthresh, vcsbackoff, logging=False, use_coding=0):
        """
	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_signature3(3, 3, gr.sizeof_gr_complex*occupied_tones, gr.sizeof_char, gr.sizeof_float)) # 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)
        
        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 = digital_ll.ofdm_sync_pn(fft_length,
                                          cp_length,
                                          vcsthresh,
                                          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

        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)
        
        if vcsbackoff:
            preamble_sense_time = vcsbackoff
        else:
            if use_coding:
                preamble_sense_time = fft_length*50
            else:
                preamble_sense_time = fft_length*25
        #preamble_sense_taps = [1.0 for i in range(preamble_sense_time)]
        #self.preamble_sense_avg = gr.fir_filter_fff(1,preamble_sense_taps)
        self.preamble_sense_avg = digital_ll.downcounter(preamble_sense_time)
        self.char2float = gr.char_to_float()
        
        #self.ofdm_frame_acq = digital_swig.ofdm_frame_acquisition(occupied_tones,
        #                                                          fft_length,
        #                                                          cp_length, ks[0])
        print 'Using newest ofdm frame acquisition function'
        self.ofdm_frame_acq = digital_ll.digital_ll_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_sync,1), self.char2float)             # the timing signal held high by filter for some time
        self.connect(self.char2float, self.preamble_sense_avg)
        self.connect(self.preamble_sense_avg, (self,2))               # virtual carrier sense signal
        
        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"))
            self.connect(self.preamble_sense_avg, gr.file_sink(gr.sizeof_float, "ofdm_receiver-vcs.dat"))
コード例 #21
0
ファイル: raw_ofdm_sync.py プロジェクト: UpYou/ofdm
  def __init__(self, fft_length, cp_length, half_sync, logging=False):
    gr.hier_block2.__init__(self, "ofdm_sync_pn",
      gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature
      gr.io_signature3(3, 3,    # Output signature
        gr.sizeof_gr_complex,   # delayed input
        gr.sizeof_float,        # fine frequency offset
        gr.sizeof_char          # timing indicator
      ))

    if half_sync:
      period = fft_length/2
      window = fft_length/2
    else: # full symbol
      period = fft_length + cp_length
      window = fft_length       # makes the plateau cp_length long

    # Calculate the frequency offset from the correlation of the preamble
    x_corr = gr.multiply_cc()
    self.connect(self, gr.conjugate_cc(), (x_corr, 0))
    self.connect(self, gr.delay(gr.sizeof_gr_complex, period), (x_corr, 1))
    P_d = gr.moving_average_cc(window, 1.0)
    self.connect(x_corr, P_d)

    P_d_angle = gr.complex_to_arg()
    self.connect(P_d, P_d_angle)

    # Get the power of the input signal to normalize the output of the correlation
    R_d = gr.moving_average_ff(window, 1.0)
    self.connect(self, gr.complex_to_mag_squared(), R_d)
    R_d_squared = gr.multiply_ff() # this is retarded
    self.connect(R_d, (R_d_squared, 0))
    self.connect(R_d, (R_d_squared, 1))
    M_d = gr.divide_ff()
    self.connect(P_d, gr.complex_to_mag_squared(), (M_d, 0))
    self.connect(R_d_squared, (M_d, 1))

    # Now we need to detect peak of M_d

    # NOTE: replaced fir_filter with moving_average for clarity
    # the peak is up to cp_length long, but noisy, so average it out
    #matched_filter_taps = [1.0/cp_length for i in range(cp_length)]
    #matched_filter = gr.fir_filter_fff(1, matched_filter_taps)
    matched_filter = gr.moving_average_ff(cp_length, 1.0/cp_length)

    # NOTE: the look_ahead parameter doesn't do anything
    # these parameters are kind of magic, increase 1 and 2 (==) to be more tolerant
    #peak_detect = raw.peak_detector_fb(0.55, 0.55, 30, 0.001)
    peak_detect = raw.peak_detector_fb(0.25, 0.25, 30, 0.001)
    # NOTE: gr.peak_detector_fb is broken!
    #peak_detect = gr.peak_detector_fb(0.55, 0.55, 30, 0.001)
    #peak_detect = gr.peak_detector_fb(0.45, 0.45, 30, 0.001)
    #peak_detect = gr.peak_detector_fb(0.30, 0.30, 30, 0.001)

    # offset by -1
    self.connect(M_d, matched_filter, gr.add_const_ff(-1), peak_detect)

    # peak_detect indicates the time M_d is highest, which is the end of the symbol.
    # We should try to sample in the middle of the plateau!!
    # FIXME until we figure out how to do this, just offset by cp_length/2
    offset = 6 #cp_length/2

    # nco(t) = P_d_angle(t-offset) sampled at peak_detect(t)
    # modulate input(t - fft_length) by nco(t)
    # signal to sample input(t) at t-offset
    #
    # We can't delay by < 0 so instead:
    # input is delayed by fft_length
    # P_d_angle is delayed by offset
    # signal to sample is delayed by fft_length - offset
    #
    phi = gr.sample_and_hold_ff()
    self.connect(peak_detect, (phi,1))
    self.connect(P_d_angle, gr.delay(gr.sizeof_float, offset), (phi,0))
    #self.connect(P_d_angle, matched_filter2, (phi,0)) # why isn't this better?!?

    # FIXME: we add fft_length delay so that the preamble is nco corrected too
    # BUT is this buffering worth it? consider implementing sync as a proper block

    # delay the input signal to follow the frequency offset signal
    self.connect(self, gr.delay(gr.sizeof_gr_complex, (fft_length+offset)), (self,0))
    self.connect(phi, (self,1))
    self.connect(peak_detect, (self,2))

    if logging:
      self.connect(matched_filter, gr.file_sink(gr.sizeof_float, "sync-mf.dat"))
      self.connect(M_d, gr.file_sink(gr.sizeof_float, "sync-M.dat"))
      self.connect(P_d_angle, gr.file_sink(gr.sizeof_float, "sync-angle.dat"))
      self.connect(peak_detect, gr.file_sink(gr.sizeof_char, "sync-peaks.datb"))
      self.connect(phi, gr.file_sink(gr.sizeof_float, "sync-phi.dat"))
コード例 #22
0
ファイル: ofdm_receiver.py プロジェクト: extrasyllmit/extrasy
    def __init__(self,
                 fft_length,
                 cp_length,
                 occupied_tones,
                 snr,
                 ks,
                 vcsthresh,
                 vcsbackoff,
                 logging=False,
                 use_coding=0):
        """
	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_signature3(3, 3, gr.sizeof_gr_complex * occupied_tones,
                             gr.sizeof_char,
                             gr.sizeof_float))  # 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)

        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 = digital_ll.ofdm_sync_pn(fft_length, cp_length,
                                                     vcsthresh, 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

        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)

        if vcsbackoff:
            preamble_sense_time = vcsbackoff
        else:
            if use_coding:
                preamble_sense_time = fft_length * 50
            else:
                preamble_sense_time = fft_length * 25
        #preamble_sense_taps = [1.0 for i in range(preamble_sense_time)]
        #self.preamble_sense_avg = gr.fir_filter_fff(1,preamble_sense_taps)
        self.preamble_sense_avg = digital_ll.downcounter(preamble_sense_time)
        self.char2float = gr.char_to_float()

        #self.ofdm_frame_acq = digital_swig.ofdm_frame_acquisition(occupied_tones,
        #                                                          fft_length,
        #                                                          cp_length, ks[0])
        print 'Using newest ofdm frame acquisition function'
        self.ofdm_frame_acq = digital_ll.digital_ll_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_sync, 1), self.char2float
                     )  # the timing signal held high by filter for some time
        self.connect(self.char2float, self.preamble_sense_avg)
        self.connect(self.preamble_sense_avg,
                     (self, 2))  # virtual carrier sense signal

        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"))
            self.connect(
                self.preamble_sense_avg,
                gr.file_sink(gr.sizeof_float, "ofdm_receiver-vcs.dat"))
コード例 #23
0
    def __init__(self,
                 N,
                 sample_rate,
                 search_bw=1,
                 threshold=10,
                 threshold_mtm=0.2,
                 tune_freq=0,
                 alpha_avg=1,
                 test_duration=1,
                 period=3600,
                 stats=False,
                 output=False,
                 rate=10,
                 subject_channels=[],
                 valve_callback=None):

        gr.hier_block2.__init__(
            self, "coherence_detector",
            gr.io_signature3(3, 3, gr.sizeof_float * N, gr.sizeof_float * N,
                             gr.sizeof_float * N), gr.io_signature(0, 0, 0))
        self.N = N  #lenght of the fft for spectral analysis
        self.sample_rate = sample_rate
        self.search_bw = search_bw  #search bandwidth within each channel
        self.threshold = threshold  #threshold comparison
        self.threshold_mtm = threshold_mtm
        self.tune_freq = tune_freq  #center frequency
        self.alpha_avg = alpha_avg  #averaging factor for noise level between consecutive measurements
        self.output = output
        self.subject_channels = subject_channels
        self.subject_channels_outcome = [0.1] * len(subject_channels)
        self.rate = rate
        self.valve_callback = valve_callback

        #data queue to share data between theads
        self.q0 = Queue.Queue()

        #gnuradio msg queues
        self.msgq = gr.msg_queue(2)
        self.msgq1 = gr.msg_queue(2)
        self.msgq2 = gr.msg_queue(2)

        #######BLOCKS#####
        self.sink = blocks.message_sink(gr.sizeof_float * self.N, self.msgq,
                                        True)
        self.sink1 = blocks.message_sink(gr.sizeof_float * self.N, self.msgq1,
                                         True)
        self.sink2 = blocks.message_sink(gr.sizeof_float * self.N, self.msgq2,
                                         True)

        #####CONNECTIONS####
        self.connect((self, 0), self.sink)
        self.connect((self, 1), self.sink1)
        self.connect((self, 2), self.sink2)

        self._watcher = watcher(
            self.msgq, self.msgq1, self.msgq2, self.tune_freq, self.threshold,
            self.threshold_mtm, self.search_bw, self.N, self.sample_rate,
            self.q0, self.subject_channels, self.set_subject_channels_outcome,
            self.rate, self.valve_callback)
        if self.output != False:
            self._output_data = output_data(self.q0, self.sample_rate,
                                            self.tune_freq, self.N,
                                            self.search_bw, self.output,
                                            self.subject_channels,
                                            self.get_subject_channels_outcome)
コード例 #24
0
    def __init__(self,
                 fft_length,
                 cp_length,
                 preambles,
                 sample_rate=10e6,
                 mode='RAW',
                 logging=False):
        gr.hier_block2.__init__(
            self,
            "ofdm_sync_fir",
            gr.io_signature(1, 1, gr.sizeof_gr_complex),  # Input signature
            gr.io_signature3(
                3,
                3,  # Output signature
                gr.sizeof_gr_complex,  # delayed input
                gr.sizeof_float,  # fine frequency offset
                gr.sizeof_char  # timing indicator
            ))

        period = 16
        window = 48
        symbol_length = fft_length + cp_length

        # Calculate the frequency offset from the correlation of the preamble
        x_corr = blocks.multiply_cc()
        P_d = blocks.moving_average_cc(window, 1.0)
        #P_d = gnuradio.filter.fir_filter_ccf(1, [1.0]*window)
        P_d_angle = blocks.complex_to_arg()
        period_delay = blocks.delay(gr.sizeof_gr_complex, period)
        conj = blocks.conjugate_cc()

        self.connect(self, period_delay, (x_corr, 0))
        self.connect(self, conj, (x_corr, 1))
        self.connect(x_corr, P_d, P_d_angle)

        # Get the power of the input signal to normalize the output of the correlation
        R_d = blocks.moving_average_ff(window, 1.0)
        #R_d = gnuradio.filter.fir_filter_fff(1, [1.0]*window)
        self.connect(self, blocks.complex_to_mag_squared(), R_d)

        ## using volk divide
        #M_d = blocks.divide_ff()
        M_d = raw.divide_ff()
        self.connect(P_d, blocks.complex_to_mag(), (M_d, 0))
        self.connect(R_d, (M_d, 1))

        peak_detect = raw.peak_detector2_fb(0.75)
        # NOTE: Trainning symbol format: STS STS LTS1 LTS2
        # because of the moving_average with parameter "window",  M_d outputs pulse which indicates the last sample of STS, but need to be adjusted
        # Cross correlation operation generate peaks only at the last sample of LTS
        # so, in order to reduce the cross-corr computation,
        # we delay the peak flag with some delay(less than symbol_length to get some tolerance)
        # the threshold setted in peak_detector will intruduce some samples
        if mode == 'PNC':
            autocorr_flag_delay = symbol_length * 2 - cp_length
        elif mode == 'RAW':
            autocorr_flag_delay = symbol_length
        autoflag_delay = blocks.delay(gr.sizeof_float, autocorr_flag_delay)

        self.connect(self, (peak_detect, 0))
        self.connect(M_d, autoflag_delay, (peak_detect, 1))

        if sample_rate > 15e6:
            period_delay.set_min_output_buffer(96000)
            conj.set_min_output_buffer(96000)
            x_corr.set_min_output_buffer(96000)
            P_d.set_min_output_buffer(96000)
            P_d_angle.set_min_output_buffer(96000)
            M_d.set_min_output_buffer(96000)
            peak_detect.set_min_output_buffer(96000)
            autoflag_delay.set_min_output_buffer(96000)

        if False:
            self.connect(
                M_d, blocks.file_sink(gr.sizeof_float, 'logs/rx-sync-M_d.dat'))
            self.connect(
                autoflag_delay,
                blocks.file_sink(gr.sizeof_float,
                                 'logs/rx-autoflag_delay.dat'))
            self.connect(
                peak_detect,
                blocks.file_sink(gr.sizeof_char, 'logs/rx-sync-peak.datb'))
            self.connect((peak_detect, 1),
                         blocks.file_sink(gr.sizeof_float,
                                          'logs/rx-sync-peak.datf'))

        ##########################################################
        # peak_delay and offset are for cutting CP
        # FIXME: until we figure out how to do this, just offset by 6 or cp_length/2
        #symbol_length = fft_length+cp_length
        peak_delay = cp_length
        offset = 8  #cp_length/2
        self.offset = offset

        # regenerate peak using cross-correlation
        # * RAW mode: use raw_generate_peak2 block to filter peaks
        # * PNC mode: use raw_generate_peak3 block to identify the proper peak for two users
        # PNC mode delays all input peak_delay samples
        # * cp_length: delay for cross-correlation since auto-correlation is not so accurate
        # * 3 symbol_length: delay for identifying mode for PNC
        # * -offset: for cp cut
        if mode == 'PNC':
            # The block structure is
            # signal -> 3*symbol_length+cp_length-offset     -> (self,0) [signal]
            # signal -> cp_length delay -> auto  -> (peak,0) -> (self,2) [peak]
            # signal -> cp_length delay          -> (peak,1) -> (self,1) [cfo]
            # cfo    -> cp_length delay          -> (peak,2)
            #
            # we let cross's signal go faster to identify the beginning
            # we use cross's peak output to find cfo, so the delay of cfo should = cross delay
            # we use raw_regenerate_peak to do cross-corr, and symbols energy after STS to identify mode
            # so the signal is further delayed by three symbols more
            self.cfo_cross_delay = blocks.delay(gr.sizeof_float, peak_delay)

            LOOK_AHEAD_NSYM = 0
            peak_cross_range = cp_length * 2

            #self.connect(autoflag_delay, blocks.file_sink(gr.sizeof_float, 'logs/rx-autoflag_delay.dat'))

            peak = raw.regenerate_peak3(fft_length, fft_length + cp_length,
                                        LOOK_AHEAD_NSYM, peak_cross_range,
                                        preambles, False)
            self.connect(peak_detect, (peak, 0))
            self.connect(self, (peak, 1))
            self.connect(P_d_angle, self.cfo_cross_delay, (peak, 2))

            self.signal_delay = blocks.delay(
                gr.sizeof_gr_complex,
                autocorr_flag_delay + cp_length + peak_cross_range - offset)
            self.connect(self, self.signal_delay, (self, 0))  # signal output
            self.connect((peak, 1), (self, 1))  # cfo output
            self.connect((peak, 0), (self, 2))  # peak output
            #self.connect((peak,1), blocks.null_sink(gr.sizeof_float))
            #self.connect((peak,0), blocks.null_sink(gr.sizeof_char))
            #self.connect(blocks.null_source(gr.sizeof_float), (self,1))
            #self.connect(blocks.null_source(gr.sizeof_char), (self,2))

            if logging:
                self.connect(
                    self.cfo_cross_delay,
                    blocks.file_sink(gr.sizeof_float, 'logs/input-cfo.dat'))
                #self.connect(cross, blocks.file_sink(gr.sizeof_float, 'logs/cross.dat'))
                self.connect(
                    self.signal_cross_delay,
                    blocks.file_sink(gr.sizeof_gr_complex,
                                     'logs/cross-signal.dat'))

        if mode == 'RAW':
            LOOK_AHEAD_NSYM = 0
            peak = raw.regenerate_peak2(fft_length, fft_length+cp_length, \
                                                    LOOK_AHEAD_NSYM, preambles, False)
            # do LTS cross correlation will set a flag at the last sample of LTS
            # signal delay is the same as the path(cross signal), but delay to pos(in 1st cp of LTS)
            # so as the sample cut the data from LTS to end;
            self.signal_delay = blocks.delay(
                gr.sizeof_gr_complex, symbol_length -
                offset)  #self.cross_delay + symbol_length - offset

            if sample_rate > 15e6:
                self.signal_delay.set_min_output_buffer(96000)
                #peak.set_max_noutput_items(2048)
                #peak.set_max_noutput_items(96000)

            self.cfo_delay = autocorr_flag_delay + peak_delay

            self.connect(peak_detect, (peak, 0))
            self.connect(P_d_angle,
                         blocks.delay(gr.sizeof_float, self.cfo_delay),
                         (peak, 1))
            self.connect(self, (peak, 2))

            self.connect(self, self.signal_delay, (self, 0))  # signal output
            self.connect((peak, 1), (self, 1))  # cfo output
            self.connect((peak, 0), (self, 2))  # raw peak output

            self.peak = peak
コード例 #25
0
ファイル: raw_ofdm_mod.py プロジェクト: UpYou/ofdm
  def __init__(self, options, noutputs = 2):
    """
    @param options: parsed raw.ofdm_params
    """
    self.params = ofdm_params(options)
    params = self.params

    if noutputs == 2:
      output_signature = gr.io_signature2(2, 2,
        gr.sizeof_gr_complex*params.data_tones,
        gr.sizeof_char
      )
    elif noutputs == 3:
      output_signature = gr.io_signature3(3, 3,
        gr.sizeof_gr_complex*params.data_tones,
        gr.sizeof_char,
        gr.sizeof_float
      )
    elif noutputs == 4:
      output_signature = gr.io_signature4(4, 4,
        gr.sizeof_gr_complex*params.data_tones,
        gr.sizeof_char,
        gr.sizeof_float,
        gr.sizeof_float
      )
    else:
      # error
      raise Exception("unsupported number of outputs")

    gr.hier_block2.__init__(self, "ofdm_demod",
      gr.io_signature(1, 1, gr.sizeof_gr_complex),
      output_signature
    )

    self.ofdm_recv = ofdm_receiver(params, options.log)

    # FIXME: magic parameters
    phgain = 0.4
    frgain = phgain*phgain / 4.0
    eqgain = 0.05
    self.ofdm_demod = raw.ofdm_demapper(params.carriers,
                                        phgain, frgain, eqgain)

    # the studios can't handle the whole ofdm in one thread
    #ofdm_recv = raw.wrap_sts(self.ofdm_recv)
    ofdm_recv = self.ofdm_recv

    self.connect(self, ofdm_recv)
    self.connect((ofdm_recv,0), (self.ofdm_demod,0))
    self.connect((ofdm_recv,1), (self.ofdm_demod,1))

    self.connect(self.ofdm_demod, (self,0))
    self.connect((ofdm_recv,1), (self,1))

    if noutputs > 2:
      # average noise power per (pilot) subcarrier
      self.connect((self.ofdm_demod,1), (self,2))

    if noutputs > 3:
      # average signal power per subcarrier
      self.connect((ofdm_recv,0),
        gr.vector_to_stream(gr.sizeof_float, params.occupied_tones),
        gr.integrate_ff(params.occupied_tones),
        gr.multiply_ff(1.0/params.occupied_tones), (self,3))

    if options.log:
      self.connect((self.ofdm_demod, 2),
                   gr.file_sink(gr.sizeof_gr_complex*params.occupied_tones,
                                'rx-eq.dat'))
      self.connect((self.ofdm_demod, 1),
                   gr.file_sink(gr.sizeof_float,
                                'rx-noise.dat'))
      self.connect((self.ofdm_demod, 0),
                   gr.file_sink(gr.sizeof_gr_complex*params.data_tones,
                                'rx-demap.dat'))