Beispiel #1
0
  def __init__ ( self, noise_power, coherence_time, taps ):
    gr.hier_block2.__init__(self,
      "fading_channel", 
      gr.io_signature( 1, 1, gr.sizeof_gr_complex ),
      gr.io_signature( 1, 1, gr.sizeof_gr_complex ) )

    inp = gr.kludge_copy( gr.sizeof_gr_complex )
    self.connect( self, inp )
    
    tap1_delay = gr.delay( gr.sizeof_gr_complex, 1 )
    tap2_delay = gr.delay( gr.sizeof_gr_complex, 2 )
    self.connect( inp, tap1_delay )
    self.connect( inp, tap2_delay )
    
    fd = 100
    z = numpy.arange(-fd+0.1,fd,0.1)
    t = numpy.sqrt(1. / ( pi * fd * numpy.sqrt( 1. - (z/fd)**2 ) ) )
    
    tap1_noise = ofdm.complex_white_noise( 0.0, taps[0] )
    tap1_filter = gr.fft_filter_ccc(1, t)
    self.connect( tap1_noise, tap1_filter )
    
    tap1_mult = gr.multiply_cc()
    self.connect( tap1_filter, (tap1_mult,0) )
    self.connect( tap1_delay, (tap1_mult,1) )
    
    tap2_noise = ofdm.complex_white_noise( 0.0, taps[1] )
    tap2_filter = gr.fft_filter_ccc(1, t)
    
    self.connect( tap2_noise, tap2_filter )
    
    tap2_mult = gr.multiply_cc()
    self.connect( tap2_filter, (tap2_mult,0) )
    self.connect( tap2_delay, (tap2_mult,1) )
    
    noise_src = ofdm.complex_white_noise( 0.0, sqrt( noise_power ) )
    chan = gr.add_cc()
    
    self.connect( inp, (chan,0) )
    self.connect( tap1_mult, (chan,1) )
    self.connect( tap2_mult, (chan,2) )
    self.connect( noise_src, (chan,3) )
    
    self.connect( chan, self )
    
    log_to_file( self, tap1_filter, "data/tap1_filter.compl")
    log_to_file( self, tap1_filter, "data/tap1_filter.float", mag=True)
    log_to_file( self, tap2_filter, "data/tap2_filter.compl")
    log_to_file( self, tap2_filter, "data/tap2_filter.float", mag=True)
Beispiel #2
0
    def __init__(self, noise_power, coherence_time, taps):
        gr.hier_block2.__init__(self, "fading_channel",
                                gr.io_signature(1, 1, gr.sizeof_gr_complex),
                                gr.io_signature(1, 1, gr.sizeof_gr_complex))

        inp = gr.kludge_copy(gr.sizeof_gr_complex)
        self.connect(self, inp)

        tap1_delay = gr.delay(gr.sizeof_gr_complex, 1)
        tap2_delay = gr.delay(gr.sizeof_gr_complex, 2)
        self.connect(inp, tap1_delay)
        self.connect(inp, tap2_delay)

        fd = 100
        z = numpy.arange(-fd + 0.1, fd, 0.1)
        t = numpy.sqrt(1. / (pi * fd * numpy.sqrt(1. - (z / fd)**2)))

        tap1_noise = ofdm.complex_white_noise(0.0, taps[0])
        tap1_filter = gr.fft_filter_ccc(1, t)
        self.connect(tap1_noise, tap1_filter)

        tap1_mult = gr.multiply_cc()
        self.connect(tap1_filter, (tap1_mult, 0))
        self.connect(tap1_delay, (tap1_mult, 1))

        tap2_noise = ofdm.complex_white_noise(0.0, taps[1])
        tap2_filter = gr.fft_filter_ccc(1, t)

        self.connect(tap2_noise, tap2_filter)

        tap2_mult = gr.multiply_cc()
        self.connect(tap2_filter, (tap2_mult, 0))
        self.connect(tap2_delay, (tap2_mult, 1))

        noise_src = ofdm.complex_white_noise(0.0, sqrt(noise_power))
        chan = gr.add_cc()

        self.connect(inp, (chan, 0))
        self.connect(tap1_mult, (chan, 1))
        self.connect(tap2_mult, (chan, 2))
        self.connect(noise_src, (chan, 3))

        self.connect(chan, self)

        log_to_file(self, tap1_filter, "data/tap1_filter.compl")
        log_to_file(self, tap1_filter, "data/tap1_filter.float", mag=True)
        log_to_file(self, tap2_filter, "data/tap2_filter.compl")
        log_to_file(self, tap2_filter, "data/tap2_filter.float", mag=True)
Beispiel #3
0
 def __init__(self, n, delay):
     gr.hier_block2.__init__(self, 'decimate', gr.io_signature(1, 1, 1),
                             gr.io_signature(1, 1, 1))
     self.n = n
     self.delay = delay
     self.block_delay = gr.delay(1, delay)
     self.block_1_in_n = gr.keep_one_in_n(1, n)
     self.connect(self, self.block_delay, self.block_1_in_n, self)
	def __init__(self):
		grc_wxgui.top_block_gui.__init__(self, title="Top Block")

		##################################################
		# Variables
		##################################################
		self.variable_slider_0 = variable_slider_0 = 30
		self.samp_rate = samp_rate = 32000

		##################################################
		# Blocks
		##################################################
		_variable_slider_0_sizer = wx.BoxSizer(wx.VERTICAL)
		self._variable_slider_0_text_box = forms.text_box(
			parent=self.GetWin(),
			sizer=_variable_slider_0_sizer,
			value=self.variable_slider_0,
			callback=self.set_variable_slider_0,
			label='variable_slider_0',
			converter=forms.float_converter(),
			proportion=0,
		)
		self._variable_slider_0_slider = forms.slider(
			parent=self.GetWin(),
			sizer=_variable_slider_0_sizer,
			value=self.variable_slider_0,
			callback=self.set_variable_slider_0,
			minimum=0,
			maximum=100,
			num_steps=100,
			style=wx.SL_HORIZONTAL,
			cast=float,
			proportion=1,
		)
		self.Add(_variable_slider_0_sizer)
		self.sbfan_0 = sbfan.sbfan(1,0,0)
		self.plot_sink_0 = plot_sink.plot_sink_f(
			self.GetWin(),
			title="Scope Plot",
			vlen=1,
			decim=1,
			gsz=1000,
			zoom=0,
		)
		self.Add(self.plot_sink_0.win)
		self.gr_sig_source_x_0 = gr.sig_source_f(samp_rate, gr.GR_SIN_WAVE, 1000, 30, 0)
		self.gr_delay_0 = gr.delay(gr.sizeof_float*1, 5)
		self.gr_add_const_vxx_0 = gr.add_const_vff((30, ))
		self.const_source_x_0 = gr.sig_source_f(0, gr.GR_CONST_WAVE, 0, 0, 40)

		##################################################
		# Connections
		##################################################
		self.connect((self.const_source_x_0, 0), (self.sbfan_0, 0))
		self.connect((self.gr_sig_source_x_0, 0), (self.gr_add_const_vxx_0, 0))
		self.connect((self.sbfan_0, 0), (self.plot_sink_0, 0))
		self.connect((self.gr_add_const_vxx_0, 0), (self.gr_delay_0, 0))
		self.connect((self.gr_delay_0, 0), (self.sbfan_0, 1))
Beispiel #5
0
 def __init__(self, n, delay):
     gr.hier_block2.__init__(self, 'decimate',
             gr.io_signature(1,1,1),
             gr.io_signature(1,1,1))
     self.n=n
     self.delay=delay
     self.block_delay = gr.delay(1,delay)
     self.block_1_in_n = gr.keep_one_in_n(1, n)
     self.connect(self, self.block_delay, self.block_1_in_n, self)
    def __init__(self, seed,fD,chan_pwrs,path_delays,flag_indep=False,flag_norm=True,flag_fadeEnable=False):
        gr.hier_block2.__init__(self,
            "multipath_rayleigh_cc",
            gr.io_signature(1, 1, gr.sizeof_gr_complex*1),  # Input signature
            gr.io_signature(1, 1, gr.sizeof_gr_complex*1)) # Output signature

        ##################################################
        # Parameters
        ##################################################
        self.fD = fD #Doppler Bandwidth = fd*(1.0/chan_rate)
        self.chan_pwrs = chan_pwrs
        self.path_delays_samples = path_delays
        self.chan_seed = seed
        self.mode = flag_fadeEnable #Enables fading for underlaying single path fading block

        # Checks that there is the same number of delays as there are powers.
        if len(self.chan_pwrs) != len(self.path_delays_us):
            raise ValueError, "The vector length of chan_pwrs does not match the vector length of path_delays."
            # Could this be improved?
            sys.exit(1)

        self.c2f_blks = []      # for list of gr.complex_to_float().
        self.delay_blks = []    # for list of gr.filter_delay_fc ().
        self.chan_blks = []     # for list of tait.flat_rayleigh_channel_cc().

        # Normalizes the channel powers if required
        if flag_norm is True:
            self.chan_pwrs = 1.0*np.array(chan_pwrs)/np.sqrt((chan_pwrs ** 2).sum(-1))

        # Populate the lists above with the correct number of blocks.
        for i in range (len(self.path_delays_samples)):
            print "create delay block %d" %(i)
            
            # Delay block is required.
            self.delay_blks.append(gr.delay(gr.sizeof_gr_complex*1, int(self.path_delays_samples[i])))
                
            self.chan_blks.append(rccBlocks.rayleighChan_cc(chan_seed + i, self.fD, self.chan_pwrs[i], flag_indep,self.mode))

        self.sum = gr.add_vcc(1)  

        # Create multiple instances of the "src -> delay -> channel" connection.
        for i in range (len(self.chan_blks)):
            print i
            self.connect( (self,0), (self.chan_blks[i],0) )
            self.connect( (self.chan_blks[i],0), (self.delay_blks[i],0) )
            self.connect( (self.delay_blks[i],0), (self.sum, i) )
        #self.connect( (self,0), (self.chan_blks[0],0) )
        #self.connect( (self.chan_blks[0],0), (self.delay_blks[0],0) )
        #self.connect( (self.delay_blks[0],0), (self, 0) )  
        self.connect((self.sum, 0), (self,0) )         
    def test_010(self):
        delta_t = 10
        tb = self.tb
        src_data = [float(x) for x in range(0, 100)]
        expected_result = tuple(delta_t * [0.0] + src_data[0:-delta_t])

        src = gr.vector_source_f(src_data)
        op = gr.delay(gr.sizeof_float, delta_t)
        dst = gr.vector_sink_f()

        tb.connect(src, op, dst)
        tb.run()
        dst_data = dst.data()
        self.assertEqual(expected_result, dst_data)
Beispiel #8
0
def build_graph(input, output, acq_coeffs, sync_coeffs, sync_thresh, sync_window):

  # Initialize our top block
  fg = gr.top_block()

  # Source is a file
  src = gr.file_source (gr.sizeof_gr_complex, input)

  # Read coefficients for the acquisition filter (FIR filter)
  dfile = open(acq_coeffs, 'r')
  data = []
  for line in dfile:
    data.append(complex(*map(float,line.strip().strip("()").split(" "))).conjugate())
  dfile.close()
  data.reverse()
  mfilter = gr.fir_filter_ccc(1, data)    # Our matched filter!
  
  # Read coefficients for the sync block
  dfile = open(sync_coeffs, 'r')
  data = []
  for line in dfile:
    data.append(complex(*map(float,line.strip().strip("()").split(" "))).conjugate())
  dfile.close()
  sync = cmusdrg.mf_sync_ccf(data)    # Sync block!

  # Delay component, to sync the original complex with MF output
  delay = gr.delay(gr.sizeof_gr_complex, len(data)-1)

  # Acquisition filter with threshold and window
  acq = cmusdrg.acquisition_filter_ccc(sync_thresh, sync_window)

  # Connect complex input to matched filter and delay
  fg.connect(src, mfilter)
  fg.connect(src, delay)

  # Connect the mfilter and delay to the acquisition filter
  fg.connect(mfilter, (acq, 0))
  fg.connect(delay, (acq, 1))

  # Connect the acquisition filter to the sync block
  fg.connect((acq, 0), (sync, 0))
  fg.connect((acq, 1), (sync, 1))

  # Two file sinks for the output
  fsink = gr.file_sink (gr.sizeof_char, output+"_sync")
  fsink2 = gr.file_sink (gr.sizeof_gr_complex, output+"_acq")
  fg.connect((acq,0), fsink2)
  fg.connect(sync, fsink)

  return fg
Beispiel #9
0
    def test_010 (self):
        delta_t = 10
        tb = self.tb
        src_data = [float(x) for x in range(0, 100)]
        expected_result = tuple(delta_t*[0.0] + src_data[0:-delta_t])

        src = gr.vector_source_f(src_data)
        op = gr.delay(gr.sizeof_float, delta_t)
        dst = gr.vector_sink_f ()

        tb.connect (src, op, dst)
        tb.run ()
        dst_data = dst.data ()
        self.assertEqual (expected_result, dst_data)
Beispiel #10
0
	def __init__(self):
		grc_wxgui.top_block_gui.__init__(self, title="Top Block")
		_icon_path = "/home/pfb/.local/share/icons/hicolor/32x32/apps/gnuradio-grc.png"
		self.SetIcon(wx.Icon(_icon_path, wx.BITMAP_TYPE_ANY))

		##################################################
		# Variables
		##################################################
		self.samp_rate = samp_rate = 16000000

		##################################################
		# Blocks
		##################################################
		self.M_Sequence = gr.vector_source_f((-1,  -1,   1,   1,  -1,   1,   1,   1,   1,  -1,   1,   1,   1,  -1,   1,  -1,  -1,  -1,  -1,  -1, -1,  -1,   1,  -1,   1,  -1,   1,   1,  -1,  -1,  -1,   1,   1,  -1,  -1,   1,   1,   1,  -1,  -1,  -1,  -1,  -1,  -1,   1,   1,   1,   1,   1,  -1,   1,  -1,  -1,   1,  -1,   1,  -1,   1,  -1,  -1,  1,  -1,  -1,  -1,  -1,  -1,   1,  -1,  -1,  -1,  -1,   1,   1,   1,  -1,   1,   1,   1,   1,   1,  1,  -1,   1,   1,  -1,  -1,  -1,  -1,   1,   1,  -1,  -1,  -1,   1,  -1,  -1,   1,   1,  -1,  -1,  -1,  -1,  -1,   1,   1,  -1,   1,  -1,  -1,  -1,   1,  -1,   1,  -1,  -1,   1,   1,  -1,   1,  -1,  1,  -1,  -1,  -1,  -1,   1,  -1,   1,   1,   1,  -1,  -1,   1,   1,   1,   1,  -1,   1,  -1,   1,  1,   1,   1,   1,  -1,  -1,  -1,   1,   1,   1,  -1,  -1,   1,  -1,   1,  -1,  -1,  -1,   1,   1,  1,   1,  -1,  -1,  -1,  -1,   1,  -1,  -1,   1,  -1,  -1,   1,  -1,   1,   1,   1,   1,  -1,  -1,  1,  -1,  -1,  -1,   1,  -1,  -1,  -1,   1,   1,  -1,   1,   1,  -1,   1,   1,   1,  -1,  -1,  -1,  1,  -1,   1,   1,  -1,  -1,   1,   1,  -1,  -1,   1,  -1,   1,   1,  -1,   1,   1,  -1,  -1,   1,  -1,  -1,   1,   1,   1,  -1,   1,  -1,   1,  -1,   1,  -1,   1,   1,   1,  -1,   1,   1,  -1,   1,  -1,   1,   1,  -1,   1,  -1,  -1,   1,   1,   1,   1,   1,   1,   1,   1), True, 1)
		self.M_Sequence_Baseband_Modulator = blks2.dbpsk_mod(
			samples_per_symbol=2,
			excess_bw=0.35,
			gray_code=False,
			verbose=False,
			log=False,
		)
		self.blks2_dxpsk_mod_0 = blks2.dbpsk_mod(
			samples_per_symbol=2,
			excess_bw=0.35,
			gray_code=True,
			verbose=False,
			log=False,
		)
		self.gr_add_xx_0 = gr.add_vcc(1)
		self.gr_delay_0 = gr.delay(gr.sizeof_char*1, 16)
		self.gr_file_sink_0 = gr.file_sink(gr.sizeof_gr_complex*1, "../M_Sequence_Baseband.cmplx")
		self.gr_float_to_char_0 = gr.float_to_char()
		self.gr_multiply_const_vxx_0 = gr.multiply_const_vcc((0, ))
		self.gr_throttle_0 = gr.throttle(gr.sizeof_gr_complex*1, samp_rate)

		##################################################
		# Connections
		##################################################
		self.connect((self.gr_throttle_0, 0), (self.gr_file_sink_0, 0))
		self.connect((self.gr_delay_0, 0), (self.blks2_dxpsk_mod_0, 0))
		self.connect((self.blks2_dxpsk_mod_0, 0), (self.gr_multiply_const_vxx_0, 0))
		self.connect((self.gr_multiply_const_vxx_0, 0), (self.gr_add_xx_0, 1))
		self.connect((self.M_Sequence_Baseband_Modulator, 0), (self.gr_add_xx_0, 0))
		self.connect((self.gr_add_xx_0, 0), (self.gr_throttle_0, 0))
		self.connect((self.M_Sequence, 0), (self.gr_float_to_char_0, 0))
		self.connect((self.gr_float_to_char_0, 0), (self.M_Sequence_Baseband_Modulator, 0))
		self.connect((self.gr_float_to_char_0, 0), (self.gr_delay_0, 0))
Beispiel #11
0
def delayline_ff(delay):
    return gr.delay(gr.sizeof_float, delay)
    def __init__(self, fft_length, cp_length, kstime, logging=False):
        """
        OFDM synchronization using PN Correlation and initial cross-correlation:
        F. Tufvesson, O. Edfors, and M. Faulkner, "Time and Frequency Synchronization for OFDM using
        PN-Sequency Preambles," IEEE Proc. VTC, 1999, pp. 2203-2207.

        This implementation is meant to be a more robust version of the Schmidl and Cox receiver design.
        By correlating against the preamble and using that as the input to the time-delayed correlation,
        this circuit produces a very clean timing signal at the end of the preamble. The timing is 
        more accurate and does not have the problem associated with determining the timing from the
        plateau structure in the Schmidl and Cox.

        This implementation appears to require that the signal is received with a normalized power or signal
        scalling factor to reduce ambiguities intorduced from partial correlation of the cyclic prefix and
        the peak detection. A better peak detection block might fix this.

        Also, the cross-correlation falls apart as the frequency offset gets larger and completely fails
        when an integer offset is introduced. Another thing to look at.
        """

	gr.hier_block2.__init__(self, "ofdm_sync_pnac",
				gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature
                                gr.io_signature2(2, 2, gr.sizeof_float, gr.sizeof_char)) # Output signature

            
        self.input = gr.add_const_cc(0)

        symbol_length = fft_length + cp_length

        # PN Sync with cross-correlation input

        # cross-correlate with the known symbol
        kstime = [k.conjugate() for k in kstime[0:fft_length//2]]
        kstime.reverse()
        self.crosscorr_filter = filter.fir_filter_ccc(1, kstime)
        
        # Create a delay line
        self.delay = gr.delay(gr.sizeof_gr_complex, fft_length/2)

        # Correlation from ML Sync
        self.conjg = gr.conjugate_cc();
        self.corr = gr.multiply_cc();

        # Create a moving sum filter for the input
        self.mag = gr.complex_to_mag_squared()
        movingsum_taps = (fft_length//1)*[1.0,]
        self.power = filter.fir_filter_fff(1,movingsum_taps)
     
        # Get magnitude (peaks) and angle (phase/freq error)
        self.c2mag = gr.complex_to_mag_squared()
        self.angle = gr.complex_to_arg()
        self.compare = gr.sub_ff()
        
        self.sample_and_hold = gr.sample_and_hold_ff()

        #ML measurements input to sampler block and detect
        self.threshold = gr.threshold_ff(0,0,0)      # threshold detection might need to be tweaked
        self.peaks = gr.float_to_char()

        self.connect(self, self.input)

        # Cross-correlate input signal with known preamble
        self.connect(self.input, self.crosscorr_filter)

        # use the output of the cross-correlation as input time-shifted correlation
        self.connect(self.crosscorr_filter, self.delay)
        self.connect(self.crosscorr_filter, (self.corr,0))
        self.connect(self.delay, self.conjg)
        self.connect(self.conjg, (self.corr,1))
        self.connect(self.corr, self.c2mag)
        self.connect(self.corr, self.angle)
        self.connect(self.angle, (self.sample_and_hold,0))
        
        # Get the power of the input signal to compare against the correlation
        self.connect(self.crosscorr_filter, self.mag, self.power)

        # Compare the power to the correlator output to determine timing peak
        # When the peak occurs, it peaks above zero, so the thresholder detects this
        self.connect(self.c2mag, (self.compare,0))
        self.connect(self.power, (self.compare,1))
        self.connect(self.compare, self.threshold)
        self.connect(self.threshold, self.peaks, (self.sample_and_hold,1))

        # Set output signals
        #    Output 0: fine frequency correction value
        #    Output 1: timing signal
        self.connect(self.sample_and_hold, (self,0))
        self.connect(self.peaks, (self,1))

        if logging:
            self.connect(self.compare, gr.file_sink(gr.sizeof_float, "ofdm_sync_pnac-compare_f.dat"))
            self.connect(self.c2mag, gr.file_sink(gr.sizeof_float, "ofdm_sync_pnac-theta_f.dat"))
            self.connect(self.power, gr.file_sink(gr.sizeof_float, "ofdm_sync_pnac-inputpower_f.dat"))
            self.connect(self.angle, gr.file_sink(gr.sizeof_float, "ofdm_sync_pnac-epsilon_f.dat"))
            self.connect(self.threshold, gr.file_sink(gr.sizeof_float, "ofdm_sync_pnac-threshold_f.dat"))
            self.connect(self.peaks, gr.file_sink(gr.sizeof_char, "ofdm_sync_pnac-peaks_b.dat"))
            self.connect(self.sample_and_hold, gr.file_sink(gr.sizeof_float, "ofdm_sync_pnac-sample_and_hold_f.dat"))
            self.connect(self.input, gr.file_sink(gr.sizeof_gr_complex, "ofdm_sync_pnac-input_c.dat"))
Beispiel #13
0
	def __init__(self, mode, debug=False):
		"""
		OFDM time and coarse frequency synchronisation for DAB

		@param mode DAB mode (1-4)
		@param debug if True: write data streams out to files
		"""

		if mode<1 or mode>4:
			raise ValueError, "Invalid DAB mode: "+str(mode)+" (modes 1-4 exist)"

		# get the correct DAB parameters
		dp = parameters.dab_parameters(mode)
		rp = parameters.receiver_parameters(mode)
		
		gr.hier_block2.__init__(self,"ofdm_sync_dab",
		                        gr.io_signature(1, 1, gr.sizeof_gr_complex), # input signature
					gr.io_signature2(2, 2, gr.sizeof_gr_complex, gr.sizeof_char)) # output signature

		# workaround for a problem that prevents connecting more than one block directly (see trac ticket #161)
		self.input = gr.kludge_copy(gr.sizeof_gr_complex)
		self.connect(self, self.input)

		#
		# null-symbol detection
		#
		# (outsourced to detect_zero.py)
		
		self.ns_detect = detect_null.detect_null(dp.ns_length, debug)
		self.connect(self.input, self.ns_detect)

		#
		# fine frequency synchronisation
		#

		# the code for fine frequency synchronisation is adapted from
		# ofdm_sync_ml.py; it abuses the cyclic prefix to find the fine
		# frequency error, as suggested in "ML Estimation of Timing and
		# Frequency Offset in OFDM Systems", by Jan-Jaap van de Beek,
		# Magnus Sandell, Per Ola Börjesson, see
		# http://www.sm.luth.se/csee/sp/research/report/bsb96r.html

		self.ffs_delay = gr.delay(gr.sizeof_gr_complex, dp.fft_length)
		self.ffs_conj = gr.conjugate_cc()
		self.ffs_mult = gr.multiply_cc()
		# self.ffs_moving_sum = gr.fir_filter_ccf(1, [1]*dp.cp_length)
		self.ffs_moving_sum = dab_swig.moving_sum_cc(dp.cp_length)
		self.ffs_angle = gr.complex_to_arg()
		self.ffs_angle_scale = gr.multiply_const_ff(1./dp.fft_length)
		self.ffs_delay_sample_and_hold = gr.delay(gr.sizeof_char, dp.symbol_length) # sample the value at the end of the symbol ..
		self.ffs_sample_and_hold = gr.sample_and_hold_ff()
		self.ffs_delay_input_for_correction = gr.delay(gr.sizeof_gr_complex, dp.symbol_length) # by delaying the input, we can use the ff offset estimation from the first symbol to correct the first symbol itself
		self.ffs_nco = gr.frequency_modulator_fc(1) # ffs_sample_and_hold directly outputs phase error per sample
		self.ffs_mixer = gr.multiply_cc()

		# calculate fine frequency error
		self.connect(self.input, self.ffs_conj, self.ffs_mult)
		self.connect(self.input, self.ffs_delay, (self.ffs_mult, 1))
		self.connect(self.ffs_mult, self.ffs_moving_sum, self.ffs_angle)
		# only use the value from the first half of the first symbol
		self.connect(self.ffs_angle, self.ffs_angle_scale, (self.ffs_sample_and_hold, 0))
		self.connect(self.ns_detect, self.ffs_delay_sample_and_hold, (self.ffs_sample_and_hold, 1))
		# do the correction
		self.connect(self.ffs_sample_and_hold, self.ffs_nco, (self.ffs_mixer, 0))
		self.connect(self.input, self.ffs_delay_input_for_correction, (self.ffs_mixer, 1))

		# output - corrected signal and start of DAB frames
		self.connect(self.ffs_mixer, (self, 0))
		self.connect(self.ffs_delay_sample_and_hold, (self, 1))

		if debug:
			self.connect(self.ffs_angle, gr.file_sink(gr.sizeof_float, "debug/ofdm_sync_dab_ffs_angle.dat"))
			self.connect(self.ffs_sample_and_hold, gr.multiply_const_ff(1./(dp.T*2*pi)), gr.file_sink(gr.sizeof_float, "debug/ofdm_sync_dab_fine_freq_err_f.dat"))
			self.connect(self.ffs_mixer, gr.file_sink(gr.sizeof_gr_complex, "debug/ofdm_sync_dab_fine_freq_corrected_c.dat"))
except ImportError:
    pass
import gnuradio
from gnuradio import gr
import sys

if __name__ == '__main__':

    duration = float(sys.argv[1])
    what = sys.argv[2]

    tb = gr.top_block()
    src0 = gr.null_source(8)
    sink = gr.null_sink(8)

    if what == 'extras_delay': delay_block = grextras.Delay(8)
    if what == 'core_delay': delay_block = gr.delay(8, 0)
    delay_block.set_delay(1000)

    tb.connect(src0, (delay_block, 0))
    tb.connect(delay_block, sink)

    import time
    tb.start()
    time.sleep(duration)
    print '##RESULT##', sink.nitems_read(0) / duration
    import sys
    sys.stdout.flush()
    tb.stop()
    tb.wait()
Beispiel #15
0
    def __init__(self, mode, debug=False):
        """
		OFDM time and coarse frequency synchronisation for DAB

		@param mode DAB mode (1-4)
		@param debug if True: write data streams out to files
		"""

        if mode < 1 or mode > 4:
            raise ValueError, "Invalid DAB mode: " + str(
                mode) + " (modes 1-4 exist)"

        # get the correct DAB parameters
        dp = parameters.dab_parameters(mode)
        rp = parameters.receiver_parameters(mode)

        gr.hier_block2.__init__(
            self,
            "ofdm_sync_dab",
            gr.io_signature(1, 1, gr.sizeof_gr_complex),  # input signature
            gr.io_signature2(2, 2, gr.sizeof_gr_complex,
                             gr.sizeof_char))  # output signature

        # workaround for a problem that prevents connecting more than one block directly (see trac ticket #161)
        self.input = gr.kludge_copy(gr.sizeof_gr_complex)
        self.connect(self, self.input)

        #
        # null-symbol detection
        #
        # (outsourced to detect_zero.py)

        self.ns_detect = detect_null.detect_null(dp.ns_length, debug)
        self.connect(self.input, self.ns_detect)

        #
        # fine frequency synchronisation
        #

        # the code for fine frequency synchronisation is adapted from
        # ofdm_sync_ml.py; it abuses the cyclic prefix to find the fine
        # frequency error, as suggested in "ML Estimation of Timing and
        # Frequency Offset in OFDM Systems", by Jan-Jaap van de Beek,
        # Magnus Sandell, Per Ola Börjesson, see
        # http://www.sm.luth.se/csee/sp/research/report/bsb96r.html

        self.ffs_delay = gr.delay(gr.sizeof_gr_complex, dp.fft_length)
        self.ffs_conj = gr.conjugate_cc()
        self.ffs_mult = gr.multiply_cc()
        # self.ffs_moving_sum = gr.fir_filter_ccf(1, [1]*dp.cp_length)
        self.ffs_moving_sum = dab_swig.moving_sum_cc(dp.cp_length)
        self.ffs_angle = gr.complex_to_arg()
        self.ffs_angle_scale = gr.multiply_const_ff(1. / dp.fft_length)
        self.ffs_delay_sample_and_hold = gr.delay(
            gr.sizeof_char,
            dp.symbol_length)  # sample the value at the end of the symbol ..
        self.ffs_sample_and_hold = gr.sample_and_hold_ff()
        self.ffs_delay_input_for_correction = gr.delay(
            gr.sizeof_gr_complex, dp.symbol_length
        )  # by delaying the input, we can use the ff offset estimation from the first symbol to correct the first symbol itself
        self.ffs_nco = gr.frequency_modulator_fc(
            1)  # ffs_sample_and_hold directly outputs phase error per sample
        self.ffs_mixer = gr.multiply_cc()

        # calculate fine frequency error
        self.connect(self.input, self.ffs_conj, self.ffs_mult)
        self.connect(self.input, self.ffs_delay, (self.ffs_mult, 1))
        self.connect(self.ffs_mult, self.ffs_moving_sum, self.ffs_angle)
        # only use the value from the first half of the first symbol
        self.connect(self.ffs_angle, self.ffs_angle_scale,
                     (self.ffs_sample_and_hold, 0))
        self.connect(self.ns_detect, self.ffs_delay_sample_and_hold,
                     (self.ffs_sample_and_hold, 1))
        # do the correction
        self.connect(self.ffs_sample_and_hold, self.ffs_nco,
                     (self.ffs_mixer, 0))
        self.connect(self.input, self.ffs_delay_input_for_correction,
                     (self.ffs_mixer, 1))

        # output - corrected signal and start of DAB frames
        self.connect(self.ffs_mixer, (self, 0))
        self.connect(self.ffs_delay_sample_and_hold, (self, 1))

        if debug:
            self.connect(
                self.ffs_angle,
                gr.file_sink(gr.sizeof_float,
                             "debug/ofdm_sync_dab_ffs_angle.dat"))
            self.connect(
                self.ffs_sample_and_hold,
                gr.multiply_const_ff(1. / (dp.T * 2 * pi)),
                gr.file_sink(gr.sizeof_float,
                             "debug/ofdm_sync_dab_fine_freq_err_f.dat"))
            self.connect(
                self.ffs_mixer,
                gr.file_sink(gr.sizeof_gr_complex,
                             "debug/ofdm_sync_dab_fine_freq_corrected_c.dat"))
Beispiel #16
0
def delayline_ff(delay):
    return gr.delay(gr.sizeof_float,delay)
Beispiel #17
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"))
Beispiel #18
0
    def __init__(self,
                 fft_length,
                 cp_length,
                 kstime,
                 threshold,
                 threshold_type,
                 threshold_gap,
                 logging=False):
        """
        OFDM synchronization using PN Correlation:
        T. M. Schmidl and D. C. Cox, "Robust Frequency and Timing
        Synchonization for OFDM," IEEE Trans. Communications, vol. 45,
        no. 12, 1997.
        """

        gr.hier_block2.__init__(
            self,
            "ofdm_sync_pn",
            gr.io_signature(1, 1, gr.sizeof_gr_complex),  # Input signature
            gr.io_signature2(2, 2, gr.sizeof_float,
                             gr.sizeof_char))  # Output signature

        self.input = gr.add_const_cc(0)

        # PN Sync

        # Create a delay line
        self.delay = gr.delay(gr.sizeof_gr_complex, fft_length / 2)

        # Correlation from ML Sync
        self.conjg = gr.conjugate_cc()
        self.corr = gr.multiply_cc()

        # Create a moving sum filter for the corr output
        if 1:
            moving_sum_taps = [1.0 for i in range(fft_length // 2)]
            self.moving_sum_filter = gr.fir_filter_ccf(1, moving_sum_taps)
        else:
            moving_sum_taps = [
                complex(1.0, 0.0) for i in range(fft_length // 2)
            ]
            self.moving_sum_filter = gr.fft_filter_ccc(1, moving_sum_taps)

        # Create a moving sum filter for the input
        self.inputmag2 = gr.complex_to_mag_squared()
        movingsum2_taps = [1.0 for i in range(fft_length // 2)]
        #movingsum2_taps = [0.5 for i in range(fft_length*4)]		#apurv - implementing Veljo's suggestion, when pause b/w packets

        if 1:
            self.inputmovingsum = gr.fir_filter_fff(1, movingsum2_taps)
        else:
            self.inputmovingsum = gr.fft_filter_fff(1, movingsum2_taps)

        self.square = gr.multiply_ff()
        self.normalize = gr.divide_ff()

        # Get magnitude (peaks) and angle (phase/freq error)
        self.c2mag = gr.complex_to_mag_squared()
        self.angle = gr.complex_to_arg()

        self.sample_and_hold = gr.sample_and_hold_ff()

        #ML measurements input to sampler block and detect
        self.sub1 = gr.add_const_ff(-1)
        self.pk_detect = gr.peak_detector_fb(
            0.20, 0.20, 30, 0.001
        )  #apurv - implementing Veljo's suggestion, when pause b/w packets

        self.connect(self, self.input)

        # Calculate the frequency offset from the correlation of the preamble
        self.connect(self.input, self.delay)
        self.connect(self.input, (self.corr, 0))
        self.connect(self.delay, self.conjg)
        self.connect(self.conjg, (self.corr, 1))

        self.connect(self.corr, self.moving_sum_filter)
        #self.connect(self.moving_sum_filter, self.c2mag)
        self.connect(self.moving_sum_filter, self.angle)
        self.connect(self.angle, (self.sample_and_hold, 0))  # apurv--
        #self.connect(self.angle, gr.delay(gr.sizeof_float, offset), (self.sample_and_hold, 0))	#apurv++

        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)

            # get the magnitude #
            self.corrmag = gr.complex_to_mag_squared()

            self.f2b = gr.float_to_char()
            self.threshold_factor = threshold  #0.0012 #0.012   #0.0015
            if 0:
                self.slice = gr.threshold_ff(self.threshold_factor,
                                             self.threshold_factor, 0,
                                             fft_length)
            else:
                #thresholds = [self.threshold_factor, 9e-5]
                self.slice = gr.threshold_ff(threshold, threshold, 0,
                                             fft_length, threshold_type,
                                             threshold_gap)

            self.connect(self.input, self.crosscorr_filter, self.corrmag,
                         self.slice, self.f2b)

            # some debug dump #
            self.connect(self.corrmag,
                         gr.file_sink(gr.sizeof_float, "ofdm_corrmag.dat"))
            #self.connect(self.f2b, gr.file_sink(gr.sizeof_char, "ofdm_f2b.dat"))

        self.connect(self.f2b, (self.sample_and_hold, 1))

        # Set output signals
        #    Output 0: fine frequency correction value
        #    Output 1: timing signal
        self.connect(self.sample_and_hold, (self, 0))
        #self.connect(self.pk_detect, (self,1))									#removed
        #self.connect(self.f2b, gr.delay(gr.sizeof_char, 1), (self, 1))
        self.connect(self.f2b, (self, 1))

        if logging:
            self.connect(
                self.matched_filter,
                gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-mf_f.dat"))
            self.connect(
                self.normalize,
                gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-theta_f.dat"))
            self.connect(
                self.angle,
                gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-epsilon_f.dat"))
            self.connect(
                self.pk_detect,
                gr.file_sink(gr.sizeof_char, "ofdm_sync_pn-peaks_b.dat"))
            self.connect(
                self.sample_and_hold,
                gr.file_sink(gr.sizeof_float,
                             "ofdm_sync_pn-sample_and_hold_f.dat"))
            self.connect(
                self.input,
                gr.file_sink(gr.sizeof_gr_complex, "ofdm_sync_pn-input_c.dat"))
    def __init__(self, fft_length, cp_length, 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"))
Beispiel #20
0
    def __init__(self, fft_length, cp_length, snr=30):
        ''' Maximum Likelihood OFDM synchronizer:
        J. van de Beek, M. Sandell, and P. O. Borjesson, "ML Estimation
        of Time and Frequency Offset in OFDM Systems," IEEE Trans.
        Signal Processing, vol. 45, no. 7, pp. 1800-1805, 1997.
        '''

	gr.hier_block2.__init__(self, "ofdm_sync_ml",
				gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature
                                gr.io_signature(1, 1, gr.sizeof_float)) # Output signature

        self.input = gr.add_const_cc(0)

        SNR = 10.0**(snr/10.0)	# 10**2=10*10=100
        rho = SNR / (SNR + 1.0)
        symbol_length = fft_length + cp_length

        # ML Sync

        # Energy Detection from ML Sync

        self.connect(self, self.input)

        # Create a delay line
        self.delay = gr.delay(gr.sizeof_gr_complex, fft_length)
        self.connect(self.input, self.delay)

        # magnitude squared blocks
        self.magsqrd1 = gr.complex_to_mag_squared()
        self.magsqrd2 = gr.complex_to_mag_squared()
        self.adder = gr.add_ff()

        moving_sum_taps = [rho/2 for i in range(cp_length)]
        self.moving_sum_filter = gr.fir_filter_fff(1,moving_sum_taps)
        
        self.connect(self.input,self.magsqrd1)
        self.connect(self.delay,self.magsqrd2)
        self.connect(self.magsqrd1,(self.adder,0))
        self.connect(self.magsqrd2,(self.adder,1))
        self.connect(self.adder,self.moving_sum_filter)
        

        # Correlation from ML Sync
        self.conjg = gr.conjugate_cc();
        self.mixer = gr.multiply_cc();

        movingsum2_taps = [1.0 for i in range(cp_length)]
        self.movingsum2 = gr.fir_filter_ccf(1,movingsum2_taps)
        
        # Correlator data handler
        self.c2mag = gr.complex_to_mag()
        self.connect(self.input,(self.mixer,1))
        self.connect(self.delay,self.conjg,(self.mixer,0))
        self.connect(self.mixer,self.movingsum2,self.c2mag)

        # ML Sync output arg, need to find maximum point of this
        self.diff = gr.sub_ff()
        self.connect(self.c2mag,(self.diff,0))
        self.connect(self.moving_sum_filter,(self.diff,1))

	self.symbol_finder = Heyutu.symbol_finder_ff(fft_length, cp_length)
	self.connect(self.diff, self.symbol_finder)

        #ML measurements input to sampler block and detect
        #self.f2c = gr.float_to_complex()
        #self.pk_detect = gr.peak_detector_fb(0.2, 0.25, 30, 0.0005)
#	self.pk_detect = gr.peak_detector_fb(0.3, 0.4, 30, 0.001)

        # use the sync loop values to set the sampler and the NCO
        #     self.diff = theta
               
#        self.connect(self.diff, self.pk_detect)

        # The DPLL corrects for timing differences between CP correlations
#        self.dpll = gr.dpll_bb(float(symbol_length),0.01)
#        self.connect(self.pk_detect, self.dpll)

#        self.b2f = gr.char_to_float()
        
 
#        self.connect(self.dpll, self.b2f)        

        # Set output signals
        #    Output 0: timing signal
#        self.connect(self.b2f, (self,0))
#	self.connect(self.diff, (self,0))
	self.connect(self.symbol_finder, (self, 0))
    import gras
    import grextras
except ImportError: pass
import gnuradio
from gnuradio import gr
import sys

if __name__ == '__main__':

    duration = float(sys.argv[1])
    what = sys.argv[2]

    tb = gr.top_block()
    src0 = gr.null_source(8)
    sink = gr.null_sink(8)

    if what == 'extras_delay': delay_block = grextras.Delay(8)
    if what == 'core_delay': delay_block = gr.delay(8, 0)
    delay_block.set_delay(1000)

    tb.connect(src0, (delay_block, 0))
    tb.connect(delay_block, sink)

    import time
    tb.start()
    time.sleep(duration)
    print '##RESULT##', sink.nitems_read(0)/duration
    import sys; sys.stdout.flush()
    tb.stop()
    tb.wait()
Beispiel #22
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"))
Beispiel #23
0
def delayline_cc(delay):
    return gr.delay(gr.sizeof_gr_complex,delay)
    def __init__(self, fft_length, cp_length, logging=False):
        """
        OFDM synchronization using PN Correlation:
        T. M. Schmidl and D. C. Cox, "Robust Frequency and Timing
        Synchonization for OFDM," IEEE Trans. Communications, vol. 45,
        no. 12, 1997. Improved with averaging over the whole FFT and 
        peak averaging over cp_length.
        """
        
	gr.hier_block2.__init__(self, "ofdm_sync_pn",
				gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature
                                gr.io_signature2(2, 2, gr.sizeof_float, gr.sizeof_char)) # Output signature

        self.input = gr.add_const_cc(0)

        self.delay = gr.delay(gr.sizeof_gr_complex, fft_length/2)

        self.conjg = gr.conjugate_cc();
        self.corr = gr.multiply_cc();

        moving_sum_taps = [1.0 for i in range(fft_length//2)]
        self.moving_sum_filter = gr.fir_filter_ccf(1,moving_sum_taps)
        
        self.inputmag2 = gr.complex_to_mag_squared()
        
        #movingsum2_taps = [0.125 for i in range(fft_length*4)]
        movingsum2_taps = [0.5 for i in range(fft_length*4)]
        self.inputmovingsum = gr.fir_filter_fff(1,movingsum2_taps)
        
        self.square = gr.multiply_ff()
        self.normalize = gr.divide_ff()
     
        self.c2mag = gr.complex_to_mag_squared()
        self.angle = gr.complex_to_arg()

        self.sample_and_hold = flex.sample_and_hold_ff()

        self.sub1 = gr.add_const_ff(-1)
        # linklab, change peak detector parameters: use higher threshold to detect rise/fall of peak
        #self.pk_detect = gr.peak_detector_fb(0.20, 0.20, 30, 0.001)
        self.pk_detect = flex.peak_detector_fb(0.7, 0.7, 30, 0.001) # linklab
        #self.pk_detect = gr.peak_detector2_fb(9)

        self.connect(self, self.input)
        
        # Lower branch:        
        self.connect(self.input, self.delay)
        self.connect(self.input, (self.corr,0))
        self.connect(self.delay, self.conjg)
        self.connect(self.conjg, (self.corr,1))
        self.connect(self.corr, self.moving_sum_filter)
        self.connect(self.moving_sum_filter, self.c2mag)
        self.connect(self.moving_sum_filter, self.angle)
        self.connect(self.angle, (self.sample_and_hold,0))
        self.connect(self.c2mag, (self.normalize,0))

        # Upper branch
        self.connect(self.input, self.inputmag2, self.inputmovingsum)
        self.connect(self.inputmovingsum, (self.square,0))
        self.connect(self.inputmovingsum, (self.square,1))
        self.connect(self.square, (self.normalize,1))
 
        matched_filter_taps = [1.0/cp_length for i in range(cp_length)]
        self.matched_filter = gr.fir_filter_fff(1,matched_filter_taps)
        self.connect(self.normalize, self.matched_filter)
       
        # linklab, provide the signal power into peak detector, linklab
        self.connect(self.square, (self.pk_detect,1))

        self.connect(self.matched_filter, self.sub1, (self.pk_detect, 0))
        self.connect(self.pk_detect, (self.sample_and_hold,1))

        # Set output signals
        #    Output 0: fine frequency correction value
        #    Output 1: timing signal
        self.connect(self.sample_and_hold, (self,0))
        self.connect(self.pk_detect, (self,1))

        if logging:
            self.connect(self.square, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-square.dat"))						
            self.connect(self.c2mag, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-c2mag.dat"))			
            self.connect(self.matched_filter, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-mf_f.dat"))
            self.connect(self.sub1, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-sub1.dat"))
            self.connect(self.normalize, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-theta_f.dat"))
            self.connect(self.angle, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-epsilon_f.dat"))
            self.connect(self.pk_detect, gr.file_sink(gr.sizeof_char, "ofdm_sync_pn-peaks_b.dat"))
            self.connect(self.sample_and_hold, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-sample_and_hold_f.dat"))
            self.connect(self.input, gr.file_sink(gr.sizeof_gr_complex, "ofdm_sync_pn-input_c.dat"))
    def __init__(self, fft_length, cp_length, kstime, threshold, threshold_type, threshold_gap, logging=False):
        """
        OFDM synchronization using PN Correlation:
        T. M. Schmidl and D. C. Cox, "Robust Frequency and Timing
        Synchonization for OFDM," IEEE Trans. Communications, vol. 45,
        no. 12, 1997.
        """
        
	gr.hier_block2.__init__(self, "ofdm_sync_pn",
				gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature
                                gr.io_signature2(2, 2, gr.sizeof_float, gr.sizeof_char)) # Output signature

        self.input = gr.add_const_cc(0)

        # PN Sync

        # Create a delay line
        self.delay = gr.delay(gr.sizeof_gr_complex, fft_length/2)

        # Correlation from ML Sync
        self.conjg = gr.conjugate_cc();
        self.corr = gr.multiply_cc();

        # Create a moving sum filter for the corr output
        if 1:
            moving_sum_taps = [1.0 for i in range(fft_length//2)]
            self.moving_sum_filter = gr.fir_filter_ccf(1,moving_sum_taps)
        else:
            moving_sum_taps = [complex(1.0,0.0) for i in range(fft_length//2)]
            self.moving_sum_filter = gr.fft_filter_ccc(1,moving_sum_taps)

        # Create a moving sum filter for the input
        self.inputmag2 = gr.complex_to_mag_squared()
        movingsum2_taps = [1.0 for i in range(fft_length//2)]
	#movingsum2_taps = [0.5 for i in range(fft_length*4)]		#apurv - implementing Veljo's suggestion, when pause b/w packets

        if 1:
            self.inputmovingsum = gr.fir_filter_fff(1,movingsum2_taps)
        else:
            self.inputmovingsum = gr.fft_filter_fff(1,movingsum2_taps)

        self.square = gr.multiply_ff()
        self.normalize = gr.divide_ff()
     
        # Get magnitude (peaks) and angle (phase/freq error)
        self.c2mag = gr.complex_to_mag_squared()
        self.angle = gr.complex_to_arg()

        self.sample_and_hold = gr.sample_and_hold_ff()

        #ML measurements input to sampler block and detect
        self.sub1 = gr.add_const_ff(-1)
        self.pk_detect = gr.peak_detector_fb(0.20, 0.20, 30, 0.001)	#apurv - implementing Veljo's suggestion, when pause b/w packets

        self.connect(self, self.input)
        
        # Calculate the frequency offset from the correlation of the preamble
        self.connect(self.input, self.delay)
        self.connect(self.input, (self.corr,0))
        self.connect(self.delay, self.conjg)
        self.connect(self.conjg, (self.corr,1))


        self.connect(self.corr, self.moving_sum_filter)
        #self.connect(self.moving_sum_filter, self.c2mag)
        self.connect(self.moving_sum_filter, self.angle)
        self.connect(self.angle, (self.sample_and_hold,0))		# apurv--
	#self.connect(self.angle, gr.delay(gr.sizeof_float, offset), (self.sample_and_hold, 0))	#apurv++

	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)

	   # get the magnitude #
	   self.corrmag = gr.complex_to_mag_squared()

	   self.f2b = gr.float_to_char()
	   self.threshold_factor = threshold #0.0012 #0.012   #0.0015
	   if 0:
	      self.slice = gr.threshold_ff(self.threshold_factor, self.threshold_factor, 0, fft_length)
	   else:
	      #thresholds = [self.threshold_factor, 9e-5]
	      self.slice = gr.threshold_ff(threshold, threshold, 0, fft_length, threshold_type, threshold_gap)

	   self.connect(self.input, self.crosscorr_filter, self.corrmag, self.slice, self.f2b)

	   # some debug dump #
	   self.connect(self.corrmag, gr.file_sink(gr.sizeof_float, "ofdm_corrmag.dat"))
	   #self.connect(self.f2b, gr.file_sink(gr.sizeof_char, "ofdm_f2b.dat"))
	   

	self.connect(self.f2b, (self.sample_and_hold,1))
	
        # Set output signals
        #    Output 0: fine frequency correction value
        #    Output 1: timing signal
        self.connect(self.sample_and_hold, (self,0))
	#self.connect(self.pk_detect, (self,1))									#removed
	#self.connect(self.f2b, gr.delay(gr.sizeof_char, 1), (self, 1))
	self.connect(self.f2b, (self, 1))

        if logging:
            self.connect(self.matched_filter, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-mf_f.dat"))
            self.connect(self.normalize, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-theta_f.dat"))
            self.connect(self.angle, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-epsilon_f.dat"))
            self.connect(self.pk_detect, gr.file_sink(gr.sizeof_char, "ofdm_sync_pn-peaks_b.dat"))
            self.connect(self.sample_and_hold, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-sample_and_hold_f.dat"))
            self.connect(self.input, gr.file_sink(gr.sizeof_gr_complex, "ofdm_sync_pn-input_c.dat"))
Beispiel #26
0
  def __init__(self, fft_length, block_length, frame_data_part, block_header,
               options):
    gr.hier_block2.__init__(self, "ofdm_receiver",
        gr.io_signature (1,1,gr.sizeof_gr_complex),
        gr.io_signature2(2,2,gr.sizeof_gr_complex*fft_length,
                             gr.sizeof_char))

    
    frame_length = frame_data_part + block_header.no_pilotsyms
    cp_length = block_length-fft_length
    
    

    self.input=gr.kludge_copy(gr.sizeof_gr_complex)
    self.connect(self, self.input)
    
    self.blocks_out = (self,0)
    self.frame_trigger_out = (self,1)
    self.snr_out = (self,2)


    if options.log:
      log_to_file(self, self.input, "data/receiver_input.compl")



    # peak detector: thresholds low, high
    #self._pd_thres_lo = 0.09
    #self._pd_thres_hi = 0.1
    self._pd_thres = 0.2
    self._pd_lookahead = fft_length / 2 # empirically chosen
    
    

    #########################
    # coarse timing offset estimator
#    self.tm = schmidl.modified_timing_metric(fft_length,[1]*(fft_length))
    self.tm = schmidl.recursive_timing_metric(fft_length)
    self.connect(self.input,self.tm)
    assert(hasattr(block_header, 'sc_preamble_pos'))
    assert(block_header.sc_preamble_pos == 0) # TODO: relax this restriction
    
    if options.filter_timingmetric:
      timingmetric_shift = -2 #int(-cp_length * 0.8)
      tmfilter = gr.fir_filter_fff(1, [1./cp_length]*cp_length)
      self.connect( self.tm, tmfilter )
      self.timing_metric = tmfilter
      print "Filtering timing metric, experimental"
    else:
      self.timing_metric = self.tm
      timingmetric_shift = int(-cp_length/4)
    
    if options.log:
      log_to_file(self, self.timing_metric, "data/tm.float")
        


    # peak detection
    #threshold = gr.threshold_ff(self._pd_thres_lo,self._pd_thres_hi,0)
    #muted_tm = gr.multiply_ff()
    peak_detector = peak_detector_02_fb(self._pd_lookahead, self._pd_thres)
    #self.connect(self.timing_metric, threshold, (muted_tm,0))
    #self.connect(self.timing_metric, (muted_tm,1))
    #self.connect(muted_tm, peak_detector)
    self.connect(self.timing_metric, peak_detector)

    if options.log:
      pd_float = gr.char_to_float()
      self.connect(peak_detector,pd_float)
      log_to_file(self, pd_float, "data/peakdetector.float")
      
    if options.no_timesync:
      terminate_stream( self, peak_detector )
      trigger = [0]*(frame_length*block_length)
      trigger[ block_length-1 ] = 1
      peak_detector = blocks.vector_source_b( trigger, True )
      print "Bypassing timing synchronisation"
    
    
    # TODO: refine detected peaks with 90% average method as proposed
    # from Schmidl & Cox:
    # Starting from peak, find first points to the left and right whose
    # value is less than or equal 90% of the peak value. New trigger point
    # is average of both
    
    
    
    
    
    # Frequency Offset Estimation
    # Used: Algorithm as proposed from Morelli & Mengali
    # Idea: Use periodic preamble, correlate identical parts, determine
    # phase offset. This phase offset is a function of the frequency offset.
    
    assert(hasattr(block_header, 'mm_preamble_pos'))

    foe = morelli_foe(fft_length,block_header.mm_periodic_parts)
    self.connect(self.input,(foe,0))
    
    if block_header.mm_preamble_pos > 0:
      delayed_trigger = gr.delay(gr.sizeof_char,
                                 block_header.mm_preamble_pos*block_length)
      self.connect(peak_detector,delayed_trigger,(foe,1))
    else:
      self.connect(peak_detector,(foe,1))
    
    self.freq_offset = foe

    if options.log:
      log_to_file(self, self.freq_offset, "data/freqoff_out.float")
      
      
    if options.average_freqoff:
      #avg_foe = gr.single_pole_iir_filter_ff( 0.1 )
      avg_foe = ofdm.lms_fir_ff( 20, 1e-3 )
      self.connect( self.freq_offset, avg_foe )
      self.freq_offset = avg_foe
      #log_to_file( self, avg_foe, "data/freqoff_out_avg.float" )
      print "EXPERIMENTAL!!! Filtering frequency offset estimate"
      
    
    if options.no_freqsync:
      terminate_stream( self, self.freq_offset )
      self.freq_offset = blocks.vector_source_f( [0.0], True )
      print "Bypassing frequency offset estimator, offset=0.0"
      
    
    # TODO: dynamic solution
    frametrig_seq = concatenate([[1],[0]*(frame_length-1)])
    self.time_sync = peak_detector
    self.frame_trigger = blocks.vector_source_b(frametrig_seq,True)
    self.connect(self.frame_trigger, self.frame_trigger_out)
    




    ##########################
    # symbol extraction and processing
    #  First, we extract the whole ofdm block, then we divide this block into
    #  several ofdm symbols. This asserts that all symbols belonging to the
    #  same ofdm block will be a consecutive order.
    #  extract ofdm symbols
    #  compensate frequency offset

    # TODO: use PLL and update/reset signals
    delayed_timesync = gr.delay(gr.sizeof_char,
                                (frame_length-1)*block_length+timingmetric_shift)
    self.connect( self.time_sync, delayed_timesync )
    
    self.block_sampler = vector_sampler(gr.sizeof_gr_complex,block_length*frame_length)
    self.discard_cp = vector_mask(block_length,cp_length,fft_length,[])

    
    if options.use_dpll:
      dpll = gr.dpll_bb( frame_length * block_length , .01 )
      self.connect( delayed_timesync, dpll )
      
      if options.log:
        dpll_f = gr.char_to_float()
        delayed_timesync_f = gr.char_to_float()
        self.connect( dpll, dpll_f )
        self.connect( delayed_timesync, delayed_timesync_f )
        log_to_file( self, dpll_f, "data/dpll.float" )
        log_to_file( self, delayed_timesync_f, "data/dpll_in.float" )
        
      delayed_timesync = dpll
      print "Using DPLL, EXPERIMENTAL!!!!!"

    self.connect(self.input,self.block_sampler)
    self.connect(delayed_timesync,(self.block_sampler,1))
    
    if options.log:
      log_to_file(self, self.block_sampler, "data/block_sampler_out.compl")



    # TODO: dynamic solution
    self.ofdm_symbols = blocks.vector_to_stream(gr.sizeof_gr_complex*block_length,
                                            frame_length)
    self.connect(self.block_sampler,self.ofdm_symbols,self.discard_cp)

    if options.log:
      log_to_file(self, self.discard_cp, "data/discard_cp_out.compl")
      dcp_fft = gr.fft_vcc(fft_length, True, [], True)
      self.connect(self.discard_cp,dcp_fft)
      log_to_file(self, dcp_fft, "data/discard_cp_fft.compl")


    # reset phase accumulator inside freq_shift on every block start
    # setup output connection


    freq_shift = frequency_shift_vcc(fft_length, -1.0/fft_length, cp_length)

    self.connect(self.discard_cp,(freq_shift,0))
    self.connect(self.freq_offset,(freq_shift,1))
    self.connect(self.frame_trigger,(freq_shift,2))
    self.connect(freq_shift, self.blocks_out)
    
    if options.log:
      log_to_file(self, freq_shift, "data/freqshift_out.compl")
      
    if options.no_freqshift:
      terminate_stream( self, freq_shift )
      freq_shift = self.discard_cp
      print "Bypassing frequency shift block"
    def __init__(self, fft_length, cp_length, occupied_tones, snr, ks, carrier_map_bin, nc_filter, logging=False):
        gr.hier_block2.__init__(self, "ofdm_receiver",
                        gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature
                        gr.io_signature4(4, 4, gr.sizeof_gr_complex*occupied_tones, gr.sizeof_char, gr.sizeof_char, gr.sizeof_float)) # Output signature

        self._fft_length = fft_length
        self._occupied_tones = occupied_tones
        self._cp_length = cp_length
        self._nc_filter = nc_filter
        self._carrier_map_bin = carrier_map_bin

        win = [1 for i in range(self._fft_length)]

        self.initialize(ks, self._carrier_map_bin)

        SYNC = "pn"
        if SYNC == "ml":
            nco_sensitivity = -1.0/fft_length                             # correct for fine frequency
            self.ofdm_sync = ofdm_sync_ml(fft_length, cp_length, snr, self._ks0time, logging)
        elif SYNC == "pn":
            nco_sensitivity = -2.0/fft_length                             # correct for fine frequency
            self.ofdm_sync = ofdm_sync_pn.ofdm_sync_pn(fft_length, cp_length, logging)
        elif SYNC == "pnac":
            nco_sensitivity = -2.0/fft_length                             # correct for fine frequency
            self.ofdm_sync = ofdm_sync_pnac(fft_length, cp_length, self._ks0time, logging)
        elif SYNC == "fixed":                                             # for testing only; do not user over the air
            self.chan_filt = gr.multiply_const_cc(1.0)                    # remove filter and filter delay for this
            nsymbols = 18                                                 # enter the number of symbols per packet
            freq_offset = 0.0                                             # if you use a frequency offset, enter it here
            nco_sensitivity = -2.0/fft_length                             # correct for fine frequency
            self.ofdm_sync = ofdm_sync_fixed(fft_length, cp_length, nsymbols, freq_offset, logging)

        self.reset_filter()


        # TODO: why? Create a delay line, linklab
        self.delay = gr.delay(gr.sizeof_gr_complex, fft_length)

        self.nco = gr.frequency_modulator_fc(nco_sensitivity)         # generate a signal proportional to frequency error of sync block
        self.sigmix = gr.multiply_cc()
        self.sampler = flex.ofdm_sampler(fft_length, fft_length+cp_length)
        self.fft_demod = gr.fft_vcc(fft_length, True, win, True)
        self.ofdm_frame_acq = flex.ofdm_frame_acquisition(self._occupied_tones, self._fft_length,
                                                                                                        self._cp_length, self._ks[0], 1)

        if self._nc_filter:
            print '\nMulti-band Filter Turned ON!'
            self.ncofdm_filt = ncofdm_filt(self._fft_length, self._occupied_tones, self._carrier_map_bin)
            self.connect(self, self.chan_filt, self.ncofdm_filt)
            self.connect(self.ncofdm_filt, self.ofdm_sync)             # into the synchronization alg.
            self.connect((self.ofdm_sync,0), self.nco, (self.sigmix,1))   # use sync freq. offset output to derotate input signal
            self.connect(self.ncofdm_filt, self.delay, (self.sigmix,0))                 # signal to be derotated
        else :
            print '\nMulti-band Filter Turned OFF!'
            self.connect(self, self.chan_filt)
            self.connect(self.chan_filt, self.ofdm_sync)             # into the synchronization alg.
            self.connect((self.ofdm_sync,0), self.nco, (self.sigmix,1))   # use sync freq. offset output to derotate input signal
            self.connect(self.chan_filt, self.delay, (self.sigmix,0))                 # signal to be derotated

        self.connect(self.sigmix, (self.sampler,0))                   # sample off timing signal detected in sync alg
        self.connect((self.ofdm_sync,1), (self.sampler,1))            # timing signal to sample at

        self.connect((self.sampler,0), self.fft_demod)                # send derotated sampled signal to FFT
        self.connect(self.fft_demod, (self.ofdm_frame_acq,0))         # find frame start and equalize signal
        # TODO: do we need a char delay for the timing signal?
        self.connect((self.sampler,1), (self.ofdm_frame_acq,1))       # send timing signal to signal frame start

        # TODO: reconnect properly
        self.connect((self.ofdm_frame_acq,0), (self,0))               # finished with fine/coarse freq correction,
        self.connect((self.ofdm_sync,1), gr.delay(gr.sizeof_char,1), (self,1))

        self.connect((self.ofdm_frame_acq,1), (self,2))               # frame and symbol timing, and equalization
        self.connect((self.ofdm_frame_acq,2), (self,3))               # snr estimates

        if logging:
            self.connect(self.chan_filt, gr.file_sink(gr.sizeof_gr_complex, "flex_ofdm_recv-chan_filt_c.dat"))
            self.connect(self.ncofdm_filt, gr.file_sink(gr.sizeof_gr_complex, "flex_ofdm_recv-ncofdm_filt_c.dat"))
            self.connect(self.nco, gr.file_sink(gr.sizeof_gr_complex, "flex_ofdm_recv-nco_c.dat"))
            self.connect(self.fft_demod, gr.file_sink(gr.sizeof_gr_complex*fft_length, "flex_ofdm_recv-fft_out_c.dat"))
            self.connect(self.ofdm_frame_acq, gr.file_sink(gr.sizeof_gr_complex*occupied_tones, "flex_ofdm_recv-frame_acq_data_c.dat"))
            self.connect((self.ofdm_frame_acq,3), gr.keep_one_in_n(gr.sizeof_float*occupied_tones, 32), gr.file_sink(gr.sizeof_float*occupied_tones, "flex_ofdm_recv-frame_acq_gain_f.dat"))
            self.connect((self.ofdm_frame_acq,1), gr.file_sink(1, "flex_ofdm_recv-frame_acq_signal_b.dat"))
            self.connect((self.ofdm_frame_acq,2), gr.file_sink(gr.sizeof_float, "flex_ofdm_recv-frame_acq_snr_f.dat"))
            self.connect(self.sampler, gr.file_sink(gr.sizeof_gr_complex*fft_length, "flex_ofdm_recv-sampler_data_c.dat"))
            self.connect(self.sampler, gr.file_sink(gr.sizeof_gr_complex*fft_length, "flex_ofdm_recv-sampler_data_c.dat"))
            self.connect((self.sampler, 1), gr.file_sink(1*fft_length, "flex_ofdm_recv-sampler_signal_b.dat"))
            self.connect((self.ofdm_sync, 1), gr.file_sink(1, "flex_ofdm_recv-sync_b.dat"))
            self.connect(self.sigmix, gr.file_sink(gr.sizeof_gr_complex, "flex_ofdm_recv-sigmix_c.dat"))
        else:
            self.connect((self.ofdm_frame_acq,3), gr.null_sink(gr.sizeof_float*self._occupied_tones))
Beispiel #28
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"))
Beispiel #29
0
	def __init__(self):
		grc_wxgui.top_block_gui.__init__(self, title="Ofdm Rx")

		##################################################
		# Variables
		##################################################
		self.window_size = window_size = 48
		self.sync_length = sync_length = 320 - 64
		self.samp_rate = samp_rate = 10e6
		self.gain = gain = 0
		self.freq = freq = 5.825e9

		##################################################
		# Blocks
		##################################################
		self._samp_rate_chooser = forms.radio_buttons(
			parent=self.GetWin(),
			value=self.samp_rate,
			callback=self.set_samp_rate,
			label="Sample Rate",
			choices=[10e6, 20e6],
			labels=["10 Mhz", "20 Mhz"],
			style=wx.RA_HORIZONTAL,
		)
		self.Add(self._samp_rate_chooser)
		_gain_sizer = wx.BoxSizer(wx.VERTICAL)
		self._gain_text_box = forms.text_box(
			parent=self.GetWin(),
			sizer=_gain_sizer,
			value=self.gain,
			callback=self.set_gain,
			label='gain',
			converter=forms.float_converter(),
			proportion=0,
		)
		self._gain_slider = forms.slider(
			parent=self.GetWin(),
			sizer=_gain_sizer,
			value=self.gain,
			callback=self.set_gain,
			minimum=0,
			maximum=100,
			num_steps=100,
			style=wx.SL_HORIZONTAL,
			cast=float,
			proportion=1,
		)
		self.Add(_gain_sizer)
		self._freq_chooser = forms.drop_down(
			parent=self.GetWin(),
			value=self.freq,
			callback=self.set_freq,
			label="Channel",
			choices=[2412000000.0, 2417000000.0, 2422000000.0, 2427000000.0, 2432000000.0, 2437000000.0, 2442000000.0, 2447000000.0, 2452000000.0, 2457000000.0, 2462000000.0, 2467000000.0, 2472000000.0, 2484000000.0, 5170000000.0, 5180000000.0, 5190000000.0, 5200000000.0, 5210000000.0, 5220000000.0, 5230000000.0, 5240000000.0, 5260000000.0, 5280000000.0, 5300000000.0, 5320000000.0, 5500000000.0, 5520000000.0, 5540000000.0, 5560000000.0, 5580000000.0, 5600000000.0, 5620000000.0, 5640000000.0, 5660000000.0, 5680000000.0, 5700000000.0, 5745000000.0, 5765000000.0, 5785000000.0, 5805000000.0, 5825000000.0, 5860000000.0, 5870000000.0, 5880000000.0, 5890000000.0, 5900000000.0, 5910000000.0, 5920000000.0],
			labels=['  1 | 2412.0 | 11g', '  2 | 2417.0 | 11g', '  3 | 2422.0 | 11g', '  4 | 2427.0 | 11g', '  5 | 2432.0 | 11g', '  6 | 2437.0 | 11g', '  7 | 2442.0 | 11g', '  8 | 2447.0 | 11g', '  9 | 2452.0 | 11g', ' 10 | 2457.0 | 11g', ' 11 | 2462.0 | 11g', ' 12 | 2467.0 | 11g', ' 13 | 2472.0 | 11g', ' 14 | 2484.0 | 11g', ' 34 | 5170.0 | 11a', ' 36 | 5180.0 | 11a', ' 38 | 5190.0 | 11a', ' 40 | 5200.0 | 11a', ' 42 | 5210.0 | 11a', ' 44 | 5220.0 | 11a', ' 46 | 5230.0 | 11a', ' 48 | 5240.0 | 11a', ' 52 | 5260.0 | 11a', ' 56 | 5280.0 | 11a', ' 58 | 5300.0 | 11a', ' 60 | 5320.0 | 11a', '100 | 5500.0 | 11a', '104 | 5520.0 | 11a', '108 | 5540.0 | 11a', '112 | 5560.0 | 11a', '116 | 5580.0 | 11a', '120 | 5600.0 | 11a', '124 | 5620.0 | 11a', '128 | 5640.0 | 11a', '132 | 5660.0 | 11a', '136 | 5680.0 | 11a', '140 | 5700.0 | 11a', '149 | 5745.0 | 11a', '153 | 5765.0 | 11a', '157 | 5785.0 | 11a', '161 | 5805.0 | 11a', '165 | 5825.0 | 11a', '172 | 5860.0 | 11p', '174 | 5870.0 | 11p', '176 | 5880.0 | 11p', '178 | 5890.0 | 11p', '180 | 5900.0 | 11p', '182 | 5910.0 | 11p', '184 | 5920.0 | 11p'],
		)
		self.Add(self._freq_chooser)
		self.uhd_usrp_source_0 = uhd.usrp_source(
			device_addr="",
			stream_args=uhd.stream_args(
				cpu_format="fc32",
				channels=range(1),
			),
		)
		self.uhd_usrp_source_0.set_samp_rate(samp_rate)
		self.uhd_usrp_source_0.set_center_freq(freq, 0)
		self.uhd_usrp_source_0.set_gain(gain, 0)
		self.ieee802_1_ofdm_sync_short_0 = gr_ieee802_11.ofdm_sync_short(0.8, 80 * 80, 2, False)
		self.ieee802_1_ofdm_sync_long_0 = gr_ieee802_11.ofdm_sync_long(sync_length, 100, False)
		self.ieee802_1_ofdm_equalize_symbols_0 = gr_ieee802_11.ofdm_equalize_symbols(False)
		self.ieee802_1_ofdm_decode_signal_0 = gr_ieee802_11.ofdm_decode_signal(False)
		self.ieee802_1_ofdm_decode_mac_0 = gr_ieee802_11.ofdm_decode_mac(False)
		self.ieee802_11_ofdm_parse_mac_0 = gr_ieee802_11.ofdm_parse_mac(True)
		self.gr_stream_to_vector_0 = gr.stream_to_vector(gr.sizeof_gr_complex*1, 64)
		self.gr_socket_pdu_0 = gr.socket_pdu("UDP_SERVER", "", "12345", 10000)
		self.gr_skiphead_0 = gr.skiphead(gr.sizeof_gr_complex*1, 20000000)
		self.gr_multiply_xx_0 = gr.multiply_vcc(1)
		self.gr_divide_xx_0 = gr.divide_ff(1)
		self.gr_delay_0_0 = gr.delay(gr.sizeof_gr_complex*1, sync_length)
		self.gr_delay_0 = gr.delay(gr.sizeof_gr_complex*1, 16)
		self.gr_conjugate_cc_0 = gr.conjugate_cc()
		self.gr_complex_to_mag_squared_0 = gr.complex_to_mag_squared(1)
		self.gr_complex_to_mag_0 = gr.complex_to_mag(1)
		self.fir_filter_xxx_0_0 = filter.fir_filter_ccf(1, ([1]*window_size))
		self.fir_filter_xxx_0 = filter.fir_filter_fff(1, ([1]*window_size))
		self.fft_vxx_0 = fft.fft_vcc(64, True, (), True, 1)

		##################################################
		# Connections
		##################################################
		self.connect((self.uhd_usrp_source_0, 0), (self.gr_skiphead_0, 0))
		self.connect((self.gr_skiphead_0, 0), (self.gr_complex_to_mag_squared_0, 0))
		self.connect((self.fir_filter_xxx_0, 0), (self.gr_divide_xx_0, 1))
		self.connect((self.gr_complex_to_mag_squared_0, 0), (self.fir_filter_xxx_0, 0))
		self.connect((self.gr_skiphead_0, 0), (self.gr_multiply_xx_0, 0))
		self.connect((self.gr_conjugate_cc_0, 0), (self.gr_multiply_xx_0, 1))
		self.connect((self.gr_complex_to_mag_0, 0), (self.gr_divide_xx_0, 0))
		self.connect((self.gr_multiply_xx_0, 0), (self.fir_filter_xxx_0_0, 0))
		self.connect((self.fir_filter_xxx_0_0, 0), (self.gr_complex_to_mag_0, 0))
		self.connect((self.gr_skiphead_0, 0), (self.gr_delay_0, 0))
		self.connect((self.gr_delay_0, 0), (self.gr_conjugate_cc_0, 0))
		self.connect((self.fft_vxx_0, 0), (self.ieee802_1_ofdm_equalize_symbols_0, 0))
		self.connect((self.ieee802_1_ofdm_equalize_symbols_0, 0), (self.ieee802_1_ofdm_decode_signal_0, 0))
		self.connect((self.ieee802_1_ofdm_decode_signal_0, 0), (self.ieee802_1_ofdm_decode_mac_0, 0))
		self.connect((self.ieee802_1_ofdm_sync_short_0, 0), (self.gr_delay_0_0, 0))
		self.connect((self.gr_delay_0, 0), (self.ieee802_1_ofdm_sync_short_0, 0))
		self.connect((self.gr_divide_xx_0, 0), (self.ieee802_1_ofdm_sync_short_0, 1))
		self.connect((self.gr_delay_0_0, 0), (self.ieee802_1_ofdm_sync_long_0, 1))
		self.connect((self.ieee802_1_ofdm_sync_short_0, 0), (self.ieee802_1_ofdm_sync_long_0, 0))
		self.connect((self.ieee802_1_ofdm_sync_long_0, 0), (self.gr_stream_to_vector_0, 0))
		self.connect((self.gr_stream_to_vector_0, 0), (self.fft_vxx_0, 0))

		##################################################
		# Asynch Message Connections
		##################################################
		self.msg_connect(self.ieee802_1_ofdm_decode_mac_0, "out", self.ieee802_11_ofdm_parse_mac_0, "in")
		self.msg_connect(self.ieee802_11_ofdm_parse_mac_0, "out", self.gr_socket_pdu_0, "pdus")
Beispiel #30
0
    def __init__(self, fft_length, cp_length, kstime, logging=False):
        """
        OFDM synchronization using PN Correlation and initial cross-correlation:
        F. Tufvesson, O. Edfors, and M. Faulkner, "Time and Frequency Synchronization for OFDM using
        PN-Sequency Preambles," IEEE Proc. VTC, 1999, pp. 2203-2207.

        This implementation is meant to be a more robust version of the Schmidl and Cox receiver design.
        By correlating against the preamble and using that as the input to the time-delayed correlation,
        this circuit produces a very clean timing signal at the end of the preamble. The timing is 
        more accurate and does not have the problem associated with determining the timing from the
        plateau structure in the Schmidl and Cox.

        This implementation appears to require that the signal is received with a normalized power or signal
        scalling factor to reduce ambiguities intorduced from partial correlation of the cyclic prefix and
        the peak detection. A better peak detection block might fix this.

        Also, the cross-correlation falls apart as the frequency offset gets larger and completely fails
        when an integer offset is introduced. Another thing to look at.
        """

        gr.hier_block2.__init__(
            self,
            "ofdm_sync_pnac",
            gr.io_signature(1, 1, gr.sizeof_gr_complex),  # Input signature
            gr.io_signature2(2, 2, gr.sizeof_float,
                             gr.sizeof_char))  # Output signature

        self.input = gr.add_const_cc(0)

        symbol_length = fft_length + cp_length

        # PN Sync with cross-correlation input

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

        # Create a delay line
        self.delay = gr.delay(gr.sizeof_gr_complex, fft_length / 2)

        # Correlation from ML Sync
        self.conjg = gr.conjugate_cc()
        self.corr = gr.multiply_cc()

        # Create a moving sum filter for the input
        self.mag = gr.complex_to_mag_squared()
        movingsum_taps = (fft_length // 1) * [
            1.0,
        ]
        self.power = gr.fir_filter_fff(1, movingsum_taps)

        # Get magnitude (peaks) and angle (phase/freq error)
        self.c2mag = gr.complex_to_mag_squared()
        self.angle = gr.complex_to_arg()
        self.compare = gr.sub_ff()

        self.sample_and_hold = gr.sample_and_hold_ff()

        #ML measurements input to sampler block and detect
        self.threshold = gr.threshold_ff(
            0, 0, 0)  # threshold detection might need to be tweaked
        self.peaks = gr.float_to_char()

        self.connect(self, self.input)

        # Cross-correlate input signal with known preamble
        self.connect(self.input, self.crosscorr_filter)

        # use the output of the cross-correlation as input time-shifted correlation
        self.connect(self.crosscorr_filter, self.delay)
        self.connect(self.crosscorr_filter, (self.corr, 0))
        self.connect(self.delay, self.conjg)
        self.connect(self.conjg, (self.corr, 1))
        self.connect(self.corr, self.c2mag)
        self.connect(self.corr, self.angle)
        self.connect(self.angle, (self.sample_and_hold, 0))

        # Get the power of the input signal to compare against the correlation
        self.connect(self.crosscorr_filter, self.mag, self.power)

        # Compare the power to the correlator output to determine timing peak
        # When the peak occurs, it peaks above zero, so the thresholder detects this
        self.connect(self.c2mag, (self.compare, 0))
        self.connect(self.power, (self.compare, 1))
        self.connect(self.compare, self.threshold)
        self.connect(self.threshold, self.peaks, (self.sample_and_hold, 1))

        # Set output signals
        #    Output 0: fine frequency correction value
        #    Output 1: timing signal
        self.connect(self.sample_and_hold, (self, 0))
        self.connect(self.peaks, (self, 1))

        if logging:
            self.connect(
                self.compare,
                gr.file_sink(gr.sizeof_float, "ofdm_sync_pnac-compare_f.dat"))
            self.connect(
                self.c2mag,
                gr.file_sink(gr.sizeof_float, "ofdm_sync_pnac-theta_f.dat"))
            self.connect(
                self.power,
                gr.file_sink(gr.sizeof_float,
                             "ofdm_sync_pnac-inputpower_f.dat"))
            self.connect(
                self.angle,
                gr.file_sink(gr.sizeof_float, "ofdm_sync_pnac-epsilon_f.dat"))
            self.connect(
                self.threshold,
                gr.file_sink(gr.sizeof_float,
                             "ofdm_sync_pnac-threshold_f.dat"))
            self.connect(
                self.peaks,
                gr.file_sink(gr.sizeof_char, "ofdm_sync_pnac-peaks_b.dat"))
            self.connect(
                self.sample_and_hold,
                gr.file_sink(gr.sizeof_float,
                             "ofdm_sync_pnac-sample_and_hold_f.dat"))
            self.connect(
                self.input,
                gr.file_sink(gr.sizeof_gr_complex,
                             "ofdm_sync_pnac-input_c.dat"))
    def __init__(self, fft_length, cp_length, snr, kstime, logging):
        ''' Maximum Likelihood OFDM synchronizer:
        J. van de Beek, M. Sandell, and P. O. Borjesson, "ML Estimation
        of Time and Frequency Offset in OFDM Systems," IEEE Trans.
        Signal Processing, vol. 45, no. 7, pp. 1800-1805, 1997.
        '''

	gr.hier_block2.__init__(self, "ofdm_sync_ml",
				gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature
                                gr.io_signature2(2, 2, gr.sizeof_float, gr.sizeof_char)) # Output signature

        self.input = gr.add_const_cc(0)

        SNR = 10.0**(snr/10.0)
        rho = SNR / (SNR + 1.0)
        symbol_length = fft_length + cp_length

        # ML Sync

        # Energy Detection from ML Sync

        self.connect(self, self.input)

        # Create a delay line
        self.delay = gr.delay(gr.sizeof_gr_complex, fft_length)
        self.connect(self.input, self.delay)

        # magnitude squared blocks
        self.magsqrd1 = gr.complex_to_mag_squared()
        self.magsqrd2 = gr.complex_to_mag_squared()
        self.adder = gr.add_ff()

        moving_sum_taps = [rho/2 for i in range(cp_length)]
        self.moving_sum_filter = gr.fir_filter_fff(1,moving_sum_taps)
        
        self.connect(self.input,self.magsqrd1)
        self.connect(self.delay,self.magsqrd2)
        self.connect(self.magsqrd1,(self.adder,0))
        self.connect(self.magsqrd2,(self.adder,1))
        self.connect(self.adder,self.moving_sum_filter)
        

        # Correlation from ML Sync
        self.conjg = gr.conjugate_cc();
        self.mixer = gr.multiply_cc();

        movingsum2_taps = [1.0 for i in range(cp_length)]
        self.movingsum2 = gr.fir_filter_ccf(1,movingsum2_taps)
        
        # Correlator data handler
        self.c2mag = gr.complex_to_mag()
        self.angle = gr.complex_to_arg()
        self.connect(self.input,(self.mixer,1))
        self.connect(self.delay,self.conjg,(self.mixer,0))
        self.connect(self.mixer,self.movingsum2,self.c2mag)
        self.connect(self.movingsum2,self.angle)

        # ML Sync output arg, need to find maximum point of this
        self.diff = gr.sub_ff()
        self.connect(self.c2mag,(self.diff,0))
        self.connect(self.moving_sum_filter,(self.diff,1))

        #ML measurements input to sampler block and detect
        self.f2c = gr.float_to_complex()
        self.pk_detect = gr.peak_detector_fb(0.2, 0.25, 30, 0.0005)
        self.sample_and_hold = gr.sample_and_hold_ff()

        # use the sync loop values to set the sampler and the NCO
        #     self.diff = theta
        #     self.angle = epsilon
                          
        self.connect(self.diff, self.pk_detect)

        # The DPLL corrects for timing differences between CP correlations
        use_dpll = 0
        if use_dpll:
            self.dpll = gr.dpll_bb(float(symbol_length),0.01)
            self.connect(self.pk_detect, self.dpll)
            self.connect(self.dpll, (self.sample_and_hold,1))
        else:
            self.connect(self.pk_detect, (self.sample_and_hold,1))
            
        self.connect(self.angle, (self.sample_and_hold,0))

        ################################
        # correlate against known symbol
        # This gives us the same timing signal as the PN sync block only on the preamble
        # we don't use the signal generated from the CP correlation because we don't want
        # to readjust the timing in the middle of the packet or we ruin the equalizer settings.
        kstime = [k.conjugate() for k in kstime]
        kstime.reverse()
        self.kscorr = gr.fir_filter_ccc(1, kstime)
        self.corrmag = gr.complex_to_mag_squared()
        self.div = gr.divide_ff()

        # The output signature of the correlation has a few spikes because the rest of the
        # system uses the repeated preamble symbol. It needs to work that generically if 
        # anyone wants to use this against a WiMAX-like signal since it, too, repeats.
        # The output theta of the correlator above is multiplied with this correlation to
        # identify the proper peak and remove other products in this cross-correlation
        self.threshold_factor = 0.1
        self.slice = gr.threshold_ff(self.threshold_factor, self.threshold_factor, 0)
        self.f2b = gr.float_to_char()
        self.b2f = gr.char_to_float()
        self.mul = gr.multiply_ff()
        
        # Normalize the power of the corr output by the energy. This is not really needed
        # and could be removed for performance, but it makes for a cleaner signal.
        # if this is removed, the threshold value needs adjustment.
        self.connect(self.input, self.kscorr, self.corrmag, (self.div,0))
        self.connect(self.moving_sum_filter, (self.div,1))
        
        self.connect(self.div, (self.mul,0))
        self.connect(self.pk_detect, self.b2f, (self.mul,1))
        self.connect(self.mul, self.slice)
        
        # Set output signals
        #    Output 0: fine frequency correction value
        #    Output 1: timing signal
        self.connect(self.sample_and_hold, (self,0))
        self.connect(self.slice, self.f2b, (self,1))


        if logging:
            self.connect(self.moving_sum_filter, gr.file_sink(gr.sizeof_float, "ofdm_sync_ml-energy_f.dat"))
            self.connect(self.diff, gr.file_sink(gr.sizeof_float, "ofdm_sync_ml-theta_f.dat"))
            self.connect(self.angle, gr.file_sink(gr.sizeof_float, "ofdm_sync_ml-epsilon_f.dat"))
            self.connect(self.corrmag, gr.file_sink(gr.sizeof_float, "ofdm_sync_ml-corrmag_f.dat"))
            self.connect(self.kscorr, gr.file_sink(gr.sizeof_gr_complex, "ofdm_sync_ml-kscorr_c.dat"))
            self.connect(self.div, gr.file_sink(gr.sizeof_float, "ofdm_sync_ml-div_f.dat"))
            self.connect(self.mul, gr.file_sink(gr.sizeof_float, "ofdm_sync_ml-mul_f.dat"))
            self.connect(self.slice, gr.file_sink(gr.sizeof_float, "ofdm_sync_ml-slice_f.dat"))
            self.connect(self.pk_detect, gr.file_sink(gr.sizeof_char, "ofdm_sync_ml-peaks_b.dat"))
            if use_dpll:
                self.connect(self.dpll, gr.file_sink(gr.sizeof_char, "ofdm_sync_ml-dpll_b.dat"))

            self.connect(self.sample_and_hold, gr.file_sink(gr.sizeof_float, "ofdm_sync_ml-sample_and_hold_f.dat"))
            self.connect(self.input, gr.file_sink(gr.sizeof_gr_complex, "ofdm_sync_ml-input_c.dat"))
Beispiel #32
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"))
Beispiel #33
0
    def __init__(self, options):
        gr.top_block.__init__(self)

        self._bandwidth = options.bandwidth
        self._gain_a = options.tx_gain_a
        self._gain_b = options.tx_gain_b
        self._tx_amplitude_a = options.tx_amplitude_a
        self._tx_amplitude_b = options.tx_amplitude_b
        self._tx_freq = options.tx_freq
        self._args = options.args
        self._external = options.external
        self._ant = options.antenna
        self._spec = options.spec

        if (options.tx_freq is not None):
            self.uhd_usrp_sink_0 = uhd.usrp_sink(
                device_addr=options.args,
                stream_args=uhd.stream_args(
                    cpu_format="fc32",
                    channels=range(2),
                ),
            )
            if options.external:
                self.uhd_usrp_sink_0.set_clock_source("external", 0)
                self.uhd_usrp_sink_0.set_clock_source("external", 1)
                # we use mimo for time synchronization
                self.uhd_usrp_sink_0.set_time_source("internal", 0)
                self.uhd_usrp_sink_0.set_time_source("mimo", 1)
            else:
                self.uhd_usrp_sink_0.set_clock_source("internal", 0)
                self.uhd_usrp_sink_0.set_clock_source("mimo", 1)
                self.uhd_usrp_sink_0.set_time_source("internal", 0)
                self.uhd_usrp_sink_0.set_time_source("mimo", 1)
            self.uhd_usrp_sink_0.set_samp_rate(self._bandwidth)
            self.uhd_usrp_sink_0.set_center_freq(self._tx_freq, 0)
            self.uhd_usrp_sink_0.set_bandwidth(self._bandwidth, 0)
            self.uhd_usrp_sink_0.set_center_freq(self._tx_freq, 1)
            self.uhd_usrp_sink_0.set_bandwidth(self._bandwidth, 1)
        else:
            print "ERROR: NO MIMO SINK ..."

        options.interp = 100e6 / options.bandwidth  # FTW-specific convertion

        if (self._gain_a is None) or (self._gain_b is None):
            # if no gain was specified, use the mid-point in dB
            g = self.uhd_usrp_sink_0.get_gain_range()
            self._gain_a = float(g.start() + g.stop()) / 2
            self._gain_b = self._gain_a
            print "\nNo gain specified."
            print "Setting gain to %f (from [%f, %f])" % \
                (self._gain_a, g.start(), g.stop())
            self.uhd_usrp_sink_0.set_gain(self._gain_a, 0)
            self.uhd_usrp_sink_0.set_gain(self._gain_b, 1)

        # do this after for any adjustments to the options that may
        # occur in the sinks (specifically the UHD sink)
        if (options.from_file_a is not None) and (options.from_file_b
                                                  is not None):
            self.txpath_a = gr.file_source(gr.sizeof_gr_complex,
                                           options.from_file_a)
            self.txpath_b = gr.file_source(gr.sizeof_gr_complex,
                                           options.from_file_b)

        self.amp_a = gr.multiply_const_cc(self._tx_amplitude_a)
        self.amp_b = gr.multiply_const_cc(self._tx_amplitude_b)

        self.delay_a = gr.delay(gr.sizeof_gr_complex, 0)
        self.delay_b = gr.delay(gr.sizeof_gr_complex, 0)

        self.connect(self.txpath_a, self.amp_a, self.delay_a,
                     (self.uhd_usrp_sink_0, 0))
        self.connect(self.txpath_b, self.amp_b, self.delay_b,
                     (self.uhd_usrp_sink_0, 1))

        if options.log:
            self.connect(self.amp_a,
                         gr.file_sink(gr.sizeof_gr_complex, 'mimo_a.dat'))
            self.connect(self.amp_b,
                         gr.file_sink(gr.sizeof_gr_complex, 'mimo_b.dat'))

        if options.verbose:
            self._print_verbage()
    def __init__(self, options, hostname):
        gr.top_block.__init__(self)

        ##################################################
        # Variables
        ##################################################
        window_size = options.window_size
        sync_length = options.sync_length
        gain = options.gain
        freq = options.freq
        samp_rate = options.bandwidth
        self.uhd_usrp_source_0 = uhd.usrp_source(device_addr="", stream_args=uhd.stream_args(cpu_format="fc32", channels=range(1)))

        self.uhd_usrp_source_0.set_samp_rate(samp_rate)
        self.uhd_usrp_source_0.set_center_freq(freq, 0)
        self.uhd_usrp_source_0.set_gain(gain, 0)
        self.ieee802_1_ofdm_sync_short_0 = gr_ieee802_11.ofdm_sync_short(0.8, 80 * 80, 2, False)
        self.ieee802_1_ofdm_sync_long_0 = gr_ieee802_11.ofdm_sync_long(sync_length, 100, False)
        self.ieee802_1_ofdm_equalize_symbols_0 = gr_ieee802_11.ofdm_equalize_symbols(False)
        self.ieee802_1_ofdm_decode_signal_0 = gr_ieee802_11.ofdm_decode_signal(False)
        self.ieee802_1_ofdm_decode_mac_0 = gr_ieee802_11.ofdm_decode_mac(False)
        self.ieee802_11_ofdm_parse_mac_0 = gr_ieee802_11.ofdm_parse_mac(True)
        self.gr_stream_to_vector_0 = gr.stream_to_vector(gr.sizeof_gr_complex*1, 64)
        self.gr_socket_pdu_0 = gr.socket_pdu("TCP_SERVER", hostname, str(options.PHYRXport), 10000)
        self.gr_skiphead_0 = gr.skiphead(gr.sizeof_gr_complex*1, 20000000)
        self.gr_multiply_xx_0 = gr.multiply_vcc(1)
        self.gr_divide_xx_0 = gr.divide_ff(1)
        self.gr_delay_0_0 = gr.delay(gr.sizeof_gr_complex*1, sync_length)
        self.gr_delay_0 = gr.delay(gr.sizeof_gr_complex*1, 16)
        self.gr_conjugate_cc_0 = gr.conjugate_cc()
        self.gr_complex_to_mag_squared_0 = gr.complex_to_mag_squared(1)
        self.gr_complex_to_mag_0 = gr.complex_to_mag(1)
        self.fir_filter_xxx_0_0 = filter.fir_filter_ccf(1, ([1]*window_size))
        self.fir_filter_xxx_0 = filter.fir_filter_fff(1, ([1]*window_size))
        self.fft_vxx_0 = fft.fft_vcc(64, True, (), True, 1)
        self.message_debug = gr.message_debug()
        ##################################################
        # Connections
        ##################################################
        self.connect((self.uhd_usrp_source_0, 0), (self.gr_skiphead_0, 0))
        self.connect((self.gr_skiphead_0, 0), (self.gr_complex_to_mag_squared_0, 0))
        self.connect((self.fir_filter_xxx_0, 0), (self.gr_divide_xx_0, 1))
        self.connect((self.gr_complex_to_mag_squared_0, 0), (self.fir_filter_xxx_0, 0))
        self.connect((self.gr_skiphead_0, 0), (self.gr_multiply_xx_0, 0))
        self.connect((self.gr_conjugate_cc_0, 0), (self.gr_multiply_xx_0, 1))
        self.connect((self.gr_complex_to_mag_0, 0), (self.gr_divide_xx_0, 0))
        self.connect((self.gr_multiply_xx_0, 0), (self.fir_filter_xxx_0_0, 0))
        self.connect((self.fir_filter_xxx_0_0, 0), (self.gr_complex_to_mag_0, 0))
        self.connect((self.gr_skiphead_0, 0), (self.gr_delay_0, 0))
        self.connect((self.gr_delay_0, 0), (self.gr_conjugate_cc_0, 0))
        self.connect((self.fft_vxx_0, 0), (self.ieee802_1_ofdm_equalize_symbols_0, 0))
        self.connect((self.ieee802_1_ofdm_equalize_symbols_0, 0), (self.ieee802_1_ofdm_decode_signal_0, 0))
        self.connect((self.ieee802_1_ofdm_decode_signal_0, 0), (self.ieee802_1_ofdm_decode_mac_0, 0))
        self.connect((self.ieee802_1_ofdm_sync_short_0, 0), (self.gr_delay_0_0, 0))
        self.connect((self.gr_delay_0, 0), (self.ieee802_1_ofdm_sync_short_0, 0))
        self.connect((self.gr_divide_xx_0, 0), (self.ieee802_1_ofdm_sync_short_0, 1))
        self.connect((self.gr_delay_0_0, 0), (self.ieee802_1_ofdm_sync_long_0, 1))
        self.connect((self.ieee802_1_ofdm_sync_short_0, 0), (self.ieee802_1_ofdm_sync_long_0, 0))
        self.connect((self.ieee802_1_ofdm_sync_long_0, 0), (self.gr_stream_to_vector_0, 0))
        self.connect((self.gr_stream_to_vector_0, 0), (self.fft_vxx_0, 0))

        ##################################################
        # Asynch Message Connections
        ##################################################
        self.msg_connect(self.ieee802_1_ofdm_decode_mac_0, "out", self.ieee802_11_ofdm_parse_mac_0, "in")
        self.msg_connect(self.ieee802_11_ofdm_parse_mac_0, "out", self.gr_socket_pdu_0, "pdus")
    def __init__(
        self,
        vehicle_speed,
        carrier_freq,
        chan_rate,
        chan_seed,
        chan_pwrs,
        path_delays,
        flag_indep=False,
        flag_norm=True,
    ):
        gr.hier_block2.__init__(
            self,
            "multipath_rayleigh_cc",
            gr.io_signature(1, 1, gr.sizeof_gr_complex * 1),  # Input signature
            gr.io_signature(1, 1, gr.sizeof_gr_complex * 1),
        )  # Output signature

        # Define blocks and connect them

        ##################################################
        # Parameters
        ##################################################
        self.vehicle_speed = vehicle_speed
        self.chan_rate = chan_rate
        self.carrier_freq = carrier_freq
        self.chan_pwrs = chan_pwrs
        self.path_delays_us = path_delays
        self.chan_seed = chan_seed
        self.mode = 1  # Enables fading for underlaying single path fading block

        # Checks that there is the same number of delays as there are powers.
        if len(self.chan_pwrs) != len(self.path_delays_us):
            raise ValueError, "The vector length of chan_pwrs does not match the vector length of path_delays."
            # Could this be improved?
            sys.exit(1)
            ##################################################
            # Constants
            ##################################################
            # Speed of light in km/h
        speed_of_light = 3e8 * 3.6

        ##################################################
        # Variables
        ##################################################
        # vehicle_speed (km/h), carrier_freq (Hz) and speed_of_light (km/h)
        # units: (km/h * Hz) / (km/h) = Hz.
        fd = (vehicle_speed * carrier_freq) / speed_of_light
        # channel rate in samples/micro-seconds
        chan_rate_us = chan_rate * 1e-6
        # stores the path delays translated from micro-seconds to
        # equivalent delays in samples (based on the channel rate)
        self.path_delays_samples = path_delays_samples = np.round(np.array(self.path_delays_us) * chan_rate_us)
        self.fD = fD = (((1.0 * vehicle_speed / 3.6) * carrier_freq) / 3e8) * (1.0 / chan_rate)
        print "self.fD =", self.fD

        # 'T' is the inverse channel rate.
        self.fdT = fd * (1.0 / chan_rate)
        # Testing only
        print "self.fdT = ", self.fdT

        # Warn the user of the limited channel delay resolution
        if chan_rate_us < 1:
            print "Warning: at a channel rate of ", chan_rate, " samples/s the delay resolution is ", 1.0 / chan_rate, "seconds"

        self.c2f_blks = []  # for list of gr.complex_to_float().
        self.delay_blks = []  # for list of gr.filter_delay_fc ().
        self.chan_blks = []  # for list of tait.flat_rayleigh_channel_cc().

        # For testing only
        print "path delays in samples ", self.path_delays_samples

        # Normalizes the channel powers if required
        if flag_norm is True:
            self.chan_pwrs = 1.0 * np.array(chan_pwrs) / np.sqrt((chan_pwrs ** 2).sum(-1))

            # Populate the lists above with the correct number of blocks.
        for i in range(len(self.path_delays_samples)):
            print "create delay block %d" % (i)

            # Delay block is required.
            self.delay_blks.append(gr.delay(gr.sizeof_gr_complex * 1, int(self.path_delays_samples[i])))

            self.chan_blks.append(
                rccBlocks.channelModel_cc(chan_seed + i, self.fdT, self.chan_pwrs[i], flag_indep, self.mode)
            )

        self.sum = gr.add_vcc(1)

        # Create multiple instances of the "src -> delay -> channel" connection.
        for i in range(len(self.chan_blks)):
            print i
            self.connect((self, 0), (self.chan_blks[i], 0))
            self.connect((self.chan_blks[i], 0), (self.delay_blks[i], 0))
            self.connect((self.delay_blks[i], 0), (self.sum, i))
            # self.connect( (self,0), (self.chan_blks[0],0) )
            # self.connect( (self.chan_blks[0],0), (self.delay_blks[0],0) )
            # self.connect( (self.delay_blks[0],0), (self, 0) )
        self.connect((self.sum, 0), (self, 0))
Beispiel #36
0
    def __init__(self, fft_length, cp_length, logging=False):
        """
        OFDM synchronization using PN Correlation:
        T. M. Schmidl and D. C. Cox, "Robust Frequency and Timing
        Synchonization for OFDM," IEEE Trans. Communications, vol. 45,
        no. 12, 1997.
        """
        
	gr.hier_block2.__init__(self, "ofdm_sync_pn",
				gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature
                                gr.io_signature2(2, 2, gr.sizeof_float, gr.sizeof_char)) # Output signature

        self.input = gr.add_const_cc(0)

        # PN Sync

        # Create a delay line
        self.delay = gr.delay(gr.sizeof_gr_complex, fft_length/2)

        # Correlation from ML Sync
        self.conjg = gr.conjugate_cc();
        self.corr = gr.multiply_cc();

        # Create a moving sum filter for the corr output
        if 1:
            moving_sum_taps = [1.0 for i in range(fft_length//2)]
            self.moving_sum_filter = gr.fir_filter_ccf(1,moving_sum_taps)
        else:
            moving_sum_taps = [complex(1.0,0.0) for i in range(fft_length//2)]
            self.moving_sum_filter = gr.fft_filter_ccc(1,moving_sum_taps)

        # Create a moving sum filter for the input
        self.inputmag2 = gr.complex_to_mag_squared()

        # Modified by Yong (12.06.27)
        #movingsum2_taps = [1.0 for i in range(fft_length//2)]
        movingsum2_taps = [0.5 for i in range(fft_length)]

        if 1:
            self.inputmovingsum = gr.fir_filter_fff(1,movingsum2_taps)
        else:
            self.inputmovingsum = gr.fft_filter_fff(1,movingsum2_taps)

        self.square = gr.multiply_ff()
        self.normalize = gr.divide_ff()
     
        # Get magnitude (peaks) and angle (phase/freq error)
        self.c2mag = gr.complex_to_mag_squared()
        self.angle = gr.complex_to_arg()

        self.sample_and_hold = gr.sample_and_hold_ff()

        #ML measurements input to sampler block and detect
        self.sub1 = gr.add_const_ff(-1)
        self.pk_detect = gr.peak_detector_fb(0.20, 0.20, 30, 0.001)
        #self.pk_detect = gr.peak_detector2_fb(9)

        self.connect(self, self.input)
        
        # Calculate the frequency offset from the correlation of the preamble
        self.connect(self.input, self.delay)
        self.connect(self.input, (self.corr,0))
        self.connect(self.delay, self.conjg)
        self.connect(self.conjg, (self.corr,1))
        self.connect(self.corr, self.moving_sum_filter)
        self.connect(self.moving_sum_filter, self.c2mag)
        self.connect(self.moving_sum_filter, self.angle)
        self.connect(self.angle, (self.sample_and_hold,0))

        # Get the power of the input signal to normalize the output of the correlation
        self.connect(self.input, self.inputmag2, self.inputmovingsum)
        self.connect(self.inputmovingsum, (self.square,0))
        self.connect(self.inputmovingsum, (self.square,1))
        self.connect(self.square, (self.normalize,1))
        self.connect(self.c2mag, (self.normalize,0))

        # Create a moving sum filter for the corr output
        matched_filter_taps = [1.0/cp_length for i in range(cp_length)]
        self.matched_filter = gr.fir_filter_fff(1,matched_filter_taps)
        self.connect(self.normalize, self.matched_filter)
        
        self.connect(self.matched_filter, self.sub1, self.pk_detect)
        #self.connect(self.matched_filter, self.pk_detect)
        self.connect(self.pk_detect, (self.sample_and_hold,1))

        # Set output signals
        #    Output 0: fine frequency correction value
        #    Output 1: timing signal
        self.connect(self.sample_and_hold, (self,0))
        self.connect(self.pk_detect, (self,1))

        if logging:
            self.connect(self.matched_filter, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-mf_f.dat"))
            self.connect(self.c2mag, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-nominator_f.dat"))
            self.connect(self.square, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-denominator_f.dat"))
            self.connect(self.normalize, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-theta_f.dat"))
            self.connect(self.angle, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-epsilon_f.dat"))
            self.connect(self.pk_detect, gr.file_sink(gr.sizeof_char, "ofdm_sync_pn-peaks_b.dat"))
            self.connect(self.sample_and_hold, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-sample_and_hold_f.dat"))
            self.connect(self.input, gr.file_sink(gr.sizeof_gr_complex, "ofdm_sync_pn-input_c.dat"))
Beispiel #37
0
    def __init__(self, fft_length, block_length, frame_data_part, block_header,
                 options):
        gr.hier_block2.__init__(
            self, "ofdm_receiver", gr.io_signature(1, 1, gr.sizeof_gr_complex),
            gr.io_signature2(2, 2, gr.sizeof_gr_complex * fft_length,
                             gr.sizeof_char))

        frame_length = frame_data_part + block_header.no_pilotsyms
        cp_length = block_length - fft_length

        self.input = gr.kludge_copy(gr.sizeof_gr_complex)
        self.connect(self, self.input)

        self.blocks_out = (self, 0)
        self.frame_trigger_out = (self, 1)
        self.snr_out = (self, 2)

        if options.log:
            log_to_file(self, self.input, "data/receiver_input.compl")

        # peak detector: thresholds low, high
        #self._pd_thres_lo = 0.09
        #self._pd_thres_hi = 0.1
        self._pd_thres = 0.2
        self._pd_lookahead = fft_length / 2  # empirically chosen

        #########################
        # coarse timing offset estimator
        #    self.tm = schmidl.modified_timing_metric(fft_length,[1]*(fft_length))
        self.tm = schmidl.recursive_timing_metric(fft_length)
        self.connect(self.input, self.tm)
        assert (hasattr(block_header, 'sc_preamble_pos'))
        assert (block_header.sc_preamble_pos == 0
                )  # TODO: relax this restriction

        if options.filter_timingmetric:
            timingmetric_shift = -2  #int(-cp_length * 0.8)
            tmfilter = gr.fir_filter_fff(1, [1. / cp_length] * cp_length)
            self.connect(self.tm, tmfilter)
            self.timing_metric = tmfilter
            print "Filtering timing metric, experimental"
        else:
            self.timing_metric = self.tm
            timingmetric_shift = int(-cp_length / 4)

        if options.log:
            log_to_file(self, self.timing_metric, "data/tm.float")

        # peak detection
        #threshold = gr.threshold_ff(self._pd_thres_lo,self._pd_thres_hi,0)
        #muted_tm = gr.multiply_ff()
        peak_detector = peak_detector_02_fb(self._pd_lookahead, self._pd_thres)
        #self.connect(self.timing_metric, threshold, (muted_tm,0))
        #self.connect(self.timing_metric, (muted_tm,1))
        #self.connect(muted_tm, peak_detector)
        self.connect(self.timing_metric, peak_detector)

        if options.log:
            pd_float = gr.char_to_float()
            self.connect(peak_detector, pd_float)
            log_to_file(self, pd_float, "data/peakdetector.float")

        if options.no_timesync:
            terminate_stream(self, peak_detector)
            trigger = [0] * (frame_length * block_length)
            trigger[block_length - 1] = 1
            peak_detector = blocks.vector_source_b(trigger, True)
            print "Bypassing timing synchronisation"

        # TODO: refine detected peaks with 90% average method as proposed
        # from Schmidl & Cox:
        # Starting from peak, find first points to the left and right whose
        # value is less than or equal 90% of the peak value. New trigger point
        # is average of both

        # Frequency Offset Estimation
        # Used: Algorithm as proposed from Morelli & Mengali
        # Idea: Use periodic preamble, correlate identical parts, determine
        # phase offset. This phase offset is a function of the frequency offset.

        assert (hasattr(block_header, 'mm_preamble_pos'))

        foe = morelli_foe(fft_length, block_header.mm_periodic_parts)
        self.connect(self.input, (foe, 0))

        if block_header.mm_preamble_pos > 0:
            delayed_trigger = gr.delay(
                gr.sizeof_char, block_header.mm_preamble_pos * block_length)
            self.connect(peak_detector, delayed_trigger, (foe, 1))
        else:
            self.connect(peak_detector, (foe, 1))

        self.freq_offset = foe

        if options.log:
            log_to_file(self, self.freq_offset, "data/freqoff_out.float")

        if options.average_freqoff:
            #avg_foe = gr.single_pole_iir_filter_ff( 0.1 )
            avg_foe = ofdm.lms_fir_ff(20, 1e-3)
            self.connect(self.freq_offset, avg_foe)
            self.freq_offset = avg_foe
            #log_to_file( self, avg_foe, "data/freqoff_out_avg.float" )
            print "EXPERIMENTAL!!! Filtering frequency offset estimate"

        if options.no_freqsync:
            terminate_stream(self, self.freq_offset)
            self.freq_offset = blocks.vector_source_f([0.0], True)
            print "Bypassing frequency offset estimator, offset=0.0"

        # TODO: dynamic solution
        frametrig_seq = concatenate([[1], [0] * (frame_length - 1)])
        self.time_sync = peak_detector
        self.frame_trigger = blocks.vector_source_b(frametrig_seq, True)
        self.connect(self.frame_trigger, self.frame_trigger_out)

        ##########################
        # symbol extraction and processing
        #  First, we extract the whole ofdm block, then we divide this block into
        #  several ofdm symbols. This asserts that all symbols belonging to the
        #  same ofdm block will be a consecutive order.
        #  extract ofdm symbols
        #  compensate frequency offset

        # TODO: use PLL and update/reset signals
        delayed_timesync = gr.delay(gr.sizeof_char,
                                    (frame_length - 1) * block_length +
                                    timingmetric_shift)
        self.connect(self.time_sync, delayed_timesync)

        self.block_sampler = vector_sampler(gr.sizeof_gr_complex,
                                            block_length * frame_length)
        self.discard_cp = vector_mask(block_length, cp_length, fft_length, [])

        if options.use_dpll:
            dpll = gr.dpll_bb(frame_length * block_length, .01)
            self.connect(delayed_timesync, dpll)

            if options.log:
                dpll_f = gr.char_to_float()
                delayed_timesync_f = gr.char_to_float()
                self.connect(dpll, dpll_f)
                self.connect(delayed_timesync, delayed_timesync_f)
                log_to_file(self, dpll_f, "data/dpll.float")
                log_to_file(self, delayed_timesync_f, "data/dpll_in.float")

            delayed_timesync = dpll
            print "Using DPLL, EXPERIMENTAL!!!!!"

        self.connect(self.input, self.block_sampler)
        self.connect(delayed_timesync, (self.block_sampler, 1))

        if options.log:
            log_to_file(self, self.block_sampler,
                        "data/block_sampler_out.compl")

        # TODO: dynamic solution
        self.ofdm_symbols = blocks.vector_to_stream(
            gr.sizeof_gr_complex * block_length, frame_length)
        self.connect(self.block_sampler, self.ofdm_symbols, self.discard_cp)

        if options.log:
            log_to_file(self, self.discard_cp, "data/discard_cp_out.compl")
            dcp_fft = gr.fft_vcc(fft_length, True, [], True)
            self.connect(self.discard_cp, dcp_fft)
            log_to_file(self, dcp_fft, "data/discard_cp_fft.compl")

        # reset phase accumulator inside freq_shift on every block start
        # setup output connection

        freq_shift = frequency_shift_vcc(fft_length, -1.0 / fft_length,
                                         cp_length)

        self.connect(self.discard_cp, (freq_shift, 0))
        self.connect(self.freq_offset, (freq_shift, 1))
        self.connect(self.frame_trigger, (freq_shift, 2))
        self.connect(freq_shift, self.blocks_out)

        if options.log:
            log_to_file(self, freq_shift, "data/freqshift_out.compl")

        if options.no_freqshift:
            terminate_stream(self, freq_shift)
            freq_shift = self.discard_cp
            print "Bypassing frequency shift block"
Beispiel #38
0
def delayline_cc(delay):
    return gr.delay(gr.sizeof_gr_complex, delay)
	def __init__(self,vehicle_speed,carrier_freq,chan_rate,chan_seed,chan_pwrs,path_delays,flag_indep=False,flag_norm=True):
		gr.hier_block2.__init__(self,
		    "multipath_rayleigh_cc",
		    gr.io_signature(1, 1, gr.sizeof_gr_complex*1),  # Input signature
		    gr.io_signature(1, 1, gr.sizeof_gr_complex*1)) # Output signature

		    # Define blocks and connect them
            
		##################################################
		# Parameters
		##################################################
		self.vehicle_speed = vehicle_speed
		self.chan_rate = chan_rate
		self.carrier_freq = carrier_freq
		self.chan_pwrs = chan_pwrs
		self.path_delays_us = path_delays
		self.chan_seed = chan_seed
		self.mode = 1 #Enables fading for underlaying single path fading block
           
		# Checks that there is the same number of delays as there are powers.
		if len(self.chan_pwrs) != len(self.path_delays_us):
			raise ValueError, "The vector length of chan_pwrs does not match the vector length of path_delays."
			# Could this be improved?
			sys.exit(1)
		##################################################
		# Constants
		##################################################
		# Speed of light in km/h
		speed_of_light = 3e8 * 3.6
		
		##################################################
		# Variables
		##################################################
		# vehicle_speed (km/h), carrier_freq (Hz) and speed_of_light (km/h)
		# units: (km/h * Hz) / (km/h) = Hz. 
		fd = (vehicle_speed * carrier_freq) / speed_of_light
		# channel rate in samples/micro-seconds
		chan_rate_us = chan_rate * 1e-6
		# stores the path delays translated from micro-seconds to 
		# equivalent delays in samples (based on the channel rate)
		self.path_delays_samples = path_delays_samples = np.round(np.array(self.path_delays_us)*chan_rate_us)
		self.fD = fD = (((1.0*vehicle_speed/3.6)*carrier_freq)/3e8)*(1.0/chan_rate)
		print 'self.fD =', self.fD
		
		
		
		# 'T' is the inverse channel rate.
		self.fdT = fd * (1.0 / chan_rate)
		# Testing only
		print "self.fdT = ", self.fdT
		
		# Warn the user of the limited channel delay resolution
		if chan_rate_us < 1:
			print "Warning: at a channel rate of ", chan_rate, \
			" samples/s the delay resolution is ", 1.0/chan_rate, "seconds"
		
		self.c2f_blks = [] 		# for list of gr.complex_to_float().
		self.delay_blks = [] 	# for list of gr.filter_delay_fc ().
		self.chan_blks = [] 	# for list of tait.flat_rayleigh_channel_cc().
		
					
			
		# For testing only	
		print "path delays in samples ", self.path_delays_samples
		
		# Normalizes the channel powers if required
		if flag_norm is True:
			self.chan_pwrs = 1.0*np.array(chan_pwrs)/np.sqrt((chan_pwrs ** 2).sum(-1))
			
				
		# Populate the lists above with the correct number of blocks.
		for i in range (len(self.path_delays_samples)):
			print "create delay block %d" %(i)
			
			# Delay block is required.
			self.delay_blks.append(gr.delay(gr.sizeof_gr_complex*1, int(self.path_delays_samples[i])))
				
			self.chan_blks.append(rccBlocks.channelModel_cc(chan_seed + i, self.fdT, self.chan_pwrs[i], flag_indep,self.mode))
		
		
		self.sum = gr.add_vcc(1)  
		
		# Create multiple instances of the "src -> delay -> channel" connection.
		for i in range (len(self.chan_blks)):
			print i
			self.connect( (self,0), (self.chan_blks[i],0) )
			self.connect( (self.chan_blks[i],0), (self.delay_blks[i],0) )
			self.connect( (self.delay_blks[i],0), (self.sum, i) )
		#self.connect( (self,0), (self.chan_blks[0],0) )
		#self.connect( (self.chan_blks[0],0), (self.delay_blks[0],0) )
		#self.connect( (self.delay_blks[0],0), (self, 0) )	
		self.connect((self.sum, 0), (self,0) )         
Beispiel #40
0
 def __init__(self, fft_len=_def_fft_len, cp_len=_def_cp_len,
              frame_length_tag_key=_def_frame_length_tag_key,
              packet_length_tag_key=_def_packet_length_tag_key,
              packet_num_tag_key=_def_packet_num_tag_key,
              occupied_carriers=_def_occupied_carriers,
              pilot_carriers=_def_pilot_carriers,
              pilot_symbols=_def_pilot_symbols,
              bps_header=1,
              bps_payload=1,
              sync_word1=None,
              sync_word2=None
              ):
     gr.hier_block2.__init__(self, "ofdm_rx",
                 gr.io_signature(1, 1, gr.sizeof_gr_complex),
                 gr.io_signature(1, 1, gr.sizeof_char))
     self.fft_len           = fft_len
     self.cp_len            = cp_len
     self.frame_length_tag_key    = frame_length_tag_key
     self.packet_length_tag_key   = packet_length_tag_key
     self.occupied_carriers = occupied_carriers
     self.bps_header        = bps_header
     self.bps_payload       = bps_payload
     n_sync_words = 1
     header_constellation  = _get_constellation(bps_header)
     if sync_word1 is None:
         self.sync_word1 = _make_sync_word(fft_len, occupied_carriers, header_constellation)
     else:
         if len(sync_word1) != self.fft_len:
             raise ValueError("Length of sync sequence(s) must be FFT length.")
         self.sync_word1 = sync_word1
     self.sync_word2 = ()
     if sync_word2 is not None:
         if len(sync_word2) != fft_len:
             raise ValueError("Length of sync sequence(s) must be FFT length.")
         self.sync_word2 = sync_word2
         n_sync_words = 2
     else:
         sync_word2 = ()
     # Receiver path
     sync_detect = digital.ofdm_sync_sc_cfb(fft_len, cp_len)
     oscillator = analog.frequency_modulator_fc(-2.0 / fft_len)
     delay = gr.delay(gr.sizeof_gr_complex, fft_len+cp_len)
     mixer = gr.multiply_cc()
     hpd = digital.header_payload_demux(n_sync_words, fft_len, cp_len,
             frame_length_tag_key, "", True)
     self.connect(self, sync_detect)
     self.connect((sync_detect, 0), oscillator, (mixer, 0))
     self.connect(self, delay, (mixer, 1))
     self.connect(mixer, (hpd, 0))
     self.connect((sync_detect, 1), (hpd, 1))
     # Header demodulation
     header_fft = fft.fft_vcc(self.fft_len, True, (), True)
     chanest = digital.ofdm_chanest_vcvc(self.sync_word1, self.sync_word2, 1)
     header_equalizer = digital.ofdm_equalizer_simpledfe(
             fft_len, header_constellation.base(),
             occupied_carriers, pilot_carriers, pilot_symbols
     )
     header_eq = digital.ofdm_frame_equalizer_vcvc(header_equalizer.base(), frame_length_tag_key, True)
     header_serializer = digital.ofdm_serializer_vcc(fft_len, occupied_carriers)
     header_constellation = _get_constellation(bps_header)
     header_demod = digital.constellation_decoder_cb(header_constellation.base())
     header_formatter = digital.packet_header_ofdm(
             occupied_carriers, 1,
             packet_length_tag_key,
             frame_length_tag_key,
             packet_num_tag_key,
             bps_header
     )
     header_parser = digital.packet_headerparser_b(header_formatter.formatter())
     self.connect((hpd, 0), header_fft, chanest, header_eq, header_serializer, header_demod, header_parser)
     self.msg_connect(header_parser, "header_data", hpd, "header_data")
     # Payload demodulation
     payload_fft = fft.fft_vcc(self.fft_len, True, (), True)
     payload_equalizer = digital.ofdm_equalizer_simpledfe(
             fft_len, header_constellation.base(),
             occupied_carriers, pilot_carriers, pilot_symbols, 1
     )
     payload_eq = digital.ofdm_frame_equalizer_vcvc(payload_equalizer.base(), frame_length_tag_key)
     payload_serializer = digital.ofdm_serializer_vcc(fft_len, occupied_carriers)
     payload_constellation = _get_constellation(bps_payload)
     payload_demod = digital.constellation_decoder_cb(payload_constellation.base())
     bit_packer = blocks.repack_bits_bb(bps_payload, 8, packet_length_tag_key, True)
     self.connect((hpd, 1), payload_fft, payload_eq, payload_serializer, payload_demod, bit_packer, self)
Beispiel #41
0
	def __init__(self):
		grc_wxgui.top_block_gui.__init__(self, title="OFDM Rx")
		_icon_path = "/usr/share/icons/hicolor/32x32/apps/gnuradio-grc.png"
		self.SetIcon(wx.Icon(_icon_path, wx.BITMAP_TYPE_ANY))

		##################################################
		# Variables
		##################################################
		self.occupied_carriers = occupied_carriers = (range(-26, -21) + range(-20, -7) + range(-6, 0) + range(1, 7) + range(8, 21) + range(22, 27),)
		self.length_tag_name = length_tag_name = "frame_len"
		self.sync_word2 = sync_word2 = (0, 0, 0, 0, 0, 1, 1, -1.0, -1, 1.0, 1, 1.0, -1, -1.0, -1, 1.0, 1, -1.0, 1, 1.0, 1, -1.0, -1, -1.0, -1, 1.0, -1, 1.0, -1, 1.0, 1, -1.0, 0, 1.0, 1, -1.0, 1, 1.0, -1, -1.0, 1, -1.0, -1, -1.0, 1, 1.0, 1, -1.0, 1, 1.0, -1, 1.0, -1, -1.0, -1, 1.0, 1, -1.0, 0, 0, 0, 0, 0, 0)
		self.sync_word1 = sync_word1 = (0, 0, 0, 0, 0, 0, 0, -1.0, 0, 1.0, 0, 1.0, 0, -1.0, 0, 1.0, 0, -1.0, 0, 1.0, 0, -1.0, 0, -1.0, 0, 1.0, 0, 1.0, 0, 1.0, 0, -1.0, 0, 1.0, 0, -1.0, 0, 1.0, 0, -1.0, 0, -1.0, 0, -1.0, 0, 1.0, 0, -1.0, 0, 1.0, 0, 1.0, 0, -1.0, 0, 1.0, 0, -1.0, 0, 0, 0, 0, 0, 0)
		self.samp_rate = samp_rate = 3200000
		self.pilot_symbols = pilot_symbols = ((1, 1, 1, -1,),)
		self.pilot_carriers = pilot_carriers = ((-21, -7, 7, 21,),)
		self.payload_mod = payload_mod = digital.constellation_qpsk()
		self.header_mod = header_mod = digital.constellation_bpsk()
		self.header_formatter = header_formatter = digital.packet_header_ofdm(occupied_carriers, 1, length_tag_name)
		self.fft_len = fft_len = 64

		##################################################
		# Blocks
		##################################################
		self.gr_delay_0 = gr.delay(gr.sizeof_gr_complex*1, fft_len+fft_len/4)
		self.fft_vxx_0_0 = fft.fft_vcc(fft_len, True, (), True, 1)
		self.fft_vxx_0 = fft.fft_vcc(fft_len, True, (), True, 1)
		self.digital_packet_headerparser_b_0 = digital.packet_headerparser_b(header_formatter.formatter())
		self.digital_ofdm_sync_sc_cfb_0 = digital.ofdm_sync_sc_cfb(fft_len, fft_len/4, False)
		self.digital_ofdm_serializer_vcc_1 = digital.ofdm_serializer_vcc(fft_len, occupied_carriers, "length_tag_key", "", 1, "", True)
		self.digital_ofdm_serializer_vcc_0 = digital.ofdm_serializer_vcc(fft_len, occupied_carriers, length_tag_name, "", 0, "", True)
		self.digital_ofdm_frame_equalizer_vcvc_0_0 = digital.ofdm_frame_equalizer_vcvc(digital.ofdm_equalizer_simpledfe(fft_len, header_mod.base(), occupied_carriers, pilot_carriers, pilot_symbols).base(), fft_len/4, length_tag_name, True, 0)
		self.digital_ofdm_frame_equalizer_vcvc_0 = digital.ofdm_frame_equalizer_vcvc(digital.ofdm_equalizer_simpledfe(fft_len, header_mod.base(), occupied_carriers, pilot_carriers, pilot_symbols, 2).base(), fft_len/4, "length_tag_key", False, 0)
		self.digital_ofdm_chanest_vcvc_0 = digital.ofdm_chanest_vcvc((sync_word1), (sync_word2), 2, 0, -1, False)
		self.digital_header_payload_demux_0 = digital.header_payload_demux(3, fft_len, fft_len/4, length_tag_name, "", True, gr.sizeof_gr_complex)
		self.digital_constellation_decoder_cb_0_0 = digital.constellation_decoder_cb(header_mod.base())
		self.digital_constellation_decoder_cb_0 = digital.constellation_decoder_cb(payload_mod.base())
		self.blocks_throttle_0 = blocks.throttle(gr.sizeof_gr_complex*1, samp_rate)
		self.blocks_tag_debug_0 = blocks.tag_debug(gr.sizeof_char*1, "Rx Packets")
		self.blocks_multiply_xx_0 = blocks.multiply_vcc(1)
		self.analog_noise_source_x_0 = analog.noise_source_c(analog.GR_GAUSSIAN, 1, 0)
		self.analog_frequency_modulator_fc_0 = analog.frequency_modulator_fc(-2.0/fft_len)

		##################################################
		# Connections
		##################################################
		self.connect((self.digital_ofdm_frame_equalizer_vcvc_0_0, 0), (self.digital_ofdm_serializer_vcc_0, 0))
		self.connect((self.digital_header_payload_demux_0, 0), (self.fft_vxx_0, 0))
		self.connect((self.fft_vxx_0, 0), (self.digital_ofdm_chanest_vcvc_0, 0))
		self.connect((self.digital_ofdm_chanest_vcvc_0, 0), (self.digital_ofdm_frame_equalizer_vcvc_0_0, 0))
		self.connect((self.digital_constellation_decoder_cb_0_0, 0), (self.digital_packet_headerparser_b_0, 0))
		self.connect((self.digital_ofdm_serializer_vcc_0, 0), (self.digital_constellation_decoder_cb_0_0, 0))
		self.connect((self.digital_constellation_decoder_cb_0, 0), (self.blocks_tag_debug_0, 0))
		self.connect((self.fft_vxx_0_0, 0), (self.digital_ofdm_frame_equalizer_vcvc_0, 0))
		self.connect((self.digital_ofdm_frame_equalizer_vcvc_0, 0), (self.digital_ofdm_serializer_vcc_1, 0))
		self.connect((self.digital_header_payload_demux_0, 1), (self.fft_vxx_0_0, 0))
		self.connect((self.digital_ofdm_serializer_vcc_1, 0), (self.digital_constellation_decoder_cb_0, 0))
		self.connect((self.blocks_throttle_0, 0), (self.digital_ofdm_sync_sc_cfb_0, 0))
		self.connect((self.blocks_throttle_0, 0), (self.gr_delay_0, 0))
		self.connect((self.analog_noise_source_x_0, 0), (self.blocks_throttle_0, 0))
		self.connect((self.analog_frequency_modulator_fc_0, 0), (self.blocks_multiply_xx_0, 0))
		self.connect((self.digital_ofdm_sync_sc_cfb_0, 0), (self.analog_frequency_modulator_fc_0, 0))
		self.connect((self.gr_delay_0, 0), (self.blocks_multiply_xx_0, 1))
		self.connect((self.digital_ofdm_sync_sc_cfb_0, 1), (self.digital_header_payload_demux_0, 1))
		self.connect((self.blocks_multiply_xx_0, 0), (self.digital_header_payload_demux_0, 0))

		##################################################
		# Asynch Message Connections
		##################################################
		self.msg_connect(self.digital_packet_headerparser_b_0, "header_data", self.digital_header_payload_demux_0, "header_data")
Beispiel #42
0
    def __init__(self, fft_length, cp_length, logging=False):
        """
        OFDM synchronization using PN Correlation:
        T. M. Schmidl and D. C. Cox, "Robust Frequency and Timing
        Synchonization for OFDM," IEEE Trans. Communications, vol. 45,
        no. 12, 1997.
        """
        
	gr.hier_block2.__init__(self, "ofdm_sync_pn",
				gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature
                                gr.io_signature2(2, 2, gr.sizeof_float, gr.sizeof_char)) # Output signature

        self.input = gr.add_const_cc(0)

        # PN Sync

        # Create a delay line
        self.delay = gr.delay(gr.sizeof_gr_complex, fft_length/2)

        # Correlation from ML Sync
        self.conjg = gr.conjugate_cc();
        self.corr = gr.multiply_cc();

        # Create a moving sum filter for the corr output
        if 1:
            moving_sum_taps = [1.0 for i in range(fft_length//2)]
            self.moving_sum_filter = gr.fir_filter_ccf(1,moving_sum_taps)
        else:
            moving_sum_taps = [complex(1.0,0.0) for i in range(fft_length//2)]
            self.moving_sum_filter = gr.fft_filter_ccc(1,moving_sum_taps)

        # Create a moving sum filter for the input
        self.inputmag2 = gr.complex_to_mag_squared()
        movingsum2_taps = [1.0 for i in range(fft_length//2)]

        if 1:
            self.inputmovingsum = gr.fir_filter_fff(1,movingsum2_taps)
        else:
            self.inputmovingsum = gr.fft_filter_fff(1,movingsum2_taps)

        self.square = gr.multiply_ff()
        self.normalize = gr.divide_ff()
     
        # Get magnitude (peaks) and angle (phase/freq error)
        self.c2mag = gr.complex_to_mag_squared()
        self.angle = gr.complex_to_arg()

        self.sample_and_hold = gr.sample_and_hold_ff()

        #ML measurements input to sampler block and detect
        #self.sub1 = gr.add_const_ff(-1)
        self.sub1 = gr.add_const_ff(0)
        self.pk_detect = gr.peak_detector_fb(0.20, 0.20, 30, 0.001)
        #self.pk_detect = gr.peak_detector2_fb(9)

        self.connect(self, self.input)
        
        # Calculate the frequency offset from the correlation of the preamble
        self.connect(self.input, self.delay)
        self.connect(self.input, (self.corr,0))
        self.connect(self.delay, self.conjg)
        self.connect(self.conjg, (self.corr,1))
        self.connect(self.corr, self.moving_sum_filter)
        self.connect(self.moving_sum_filter, self.c2mag)
        self.connect(self.moving_sum_filter, self.angle)
        self.connect(self.angle, (self.sample_and_hold,0))

        # Get the power of the input signal to normalize the output of the correlation
        self.connect(self.input, self.inputmag2, self.inputmovingsum)
        self.connect(self.inputmovingsum, (self.square,0))
        self.connect(self.inputmovingsum, (self.square,1))
        self.connect(self.square, (self.normalize,1))
        self.connect(self.c2mag, (self.normalize,0))

        # Create a moving sum filter for the corr output
        matched_filter_taps = [1.0/cp_length for i in range(cp_length)]
        self.matched_filter = gr.fir_filter_fff(1,matched_filter_taps)
        self.connect(self.normalize, self.matched_filter)
        
        self.connect(self.matched_filter, self.sub1, self.pk_detect)
        #self.connect(self.matched_filter, self.pk_detect)
        self.connect(self.pk_detect, (self.sample_and_hold,1))

        # Set output signals
        #    Output 0: fine frequency correction value
        #    Output 1: timing signal
        self.connect(self.sample_and_hold, (self,0))
        self.connect(self.pk_detect, (self,1))

        if logging:
            self.connect(self.matched_filter, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-mf_f.dat"))
            self.connect(self.normalize, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-theta_f.dat"))
            self.connect(self.angle, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-epsilon_f.dat"))
            self.connect(self.pk_detect, gr.file_sink(gr.sizeof_char, "ofdm_sync_pn-peaks_b.dat"))
            self.connect(self.sample_and_hold, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-sample_and_hold_f.dat"))
            self.connect(self.input, gr.file_sink(gr.sizeof_gr_complex, "ofdm_sync_pn-input_c.dat"))
Beispiel #43
0
	def __init__(self, dab_params, rx_params, debug=False):
		"""
		OFDM time and coarse frequency synchronisation for DAB

		@param mode DAB mode (1-4)
		@param debug if True: write data streams out to files
		"""

		dp = dab_params
		rp = rx_params
		
		gr.hier_block2.__init__(self,"ofdm_sync_dab",
		                        gr.io_signature(1, 1, gr.sizeof_gr_complex), # input signature
					gr.io_signature2(2, 2, gr.sizeof_gr_complex, gr.sizeof_char)) # output signature

		# workaround for a problem that prevents connecting more than one block directly (see trac ticket #161)
		self.input = gr.kludge_copy(gr.sizeof_gr_complex)
		self.connect(self, self.input)

		#
		# null-symbol detection
		#
		# (outsourced to detect_zero.py)
		
		self.ns_detect = detect_null.detect_null(dp.ns_length, debug)
		self.connect(self.input, self.ns_detect)

		#
		# fine frequency synchronisation
		#

		# the code for fine frequency synchronisation is adapted from
		# ofdm_sync_ml.py; it abuses the cyclic prefix to find the fine
		# frequency error, as suggested in "ML Estimation of Timing and
		# Frequency Offset in OFDM Systems", by Jan-Jaap van de Beek,
		# Magnus Sandell, Per Ola Börjesson, see
		# http://www.sm.luth.se/csee/sp/research/report/bsb96r.html

		self.ffs_delay = gr.delay(gr.sizeof_gr_complex, dp.fft_length)
		self.ffs_conj = gr.conjugate_cc()
		self.ffs_mult = gr.multiply_cc()
		self.ffs_moving_sum = dab_swig.moving_sum_cc(dp.cp_length)
		self.ffs_arg = gr.complex_to_arg()
		self.ffs_sample_and_average = dab_swig.ofdm_ffs_sample(dp.symbol_length, dp.fft_length, rp.symbols_for_ffs_estimation, rp.ffs_alpha, dp.sample_rate)
		if rp.correct_ffe:
			self.ffs_delay_input_for_correction = gr.delay(gr.sizeof_gr_complex, dp.symbol_length*rp.symbols_for_ffs_estimation) # by delaying the input, we can use the ff offset estimation from the first symbol to correct the first symbol itself
			self.ffs_delay_frame_start = gr.delay(gr.sizeof_char, dp.symbol_length*rp.symbols_for_ffs_estimation) # sample the value at the end of the symbol ..
			self.ffs_nco = gr.frequency_modulator_fc(1) # ffs_sample_and_hold directly outputs phase error per sample
			self.ffs_mixer = gr.multiply_cc()

		# calculate fine frequency error
		self.connect(self.input, self.ffs_conj, self.ffs_mult)
		self.connect(self.input, self.ffs_delay, (self.ffs_mult, 1))
		self.connect(self.ffs_mult, self.ffs_moving_sum, self.ffs_arg, (self.ffs_sample_and_average, 0))
		self.connect(self.ns_detect, (self.ffs_sample_and_average, 1))

		if rp.correct_ffe: 
			# do the correction
			self.connect(self.ffs_sample_and_average, self.ffs_nco, (self.ffs_mixer, 0))
			self.connect(self.input, self.ffs_delay_input_for_correction, (self.ffs_mixer, 1))
			# output - corrected signal and start of DAB frames
			self.connect(self.ffs_mixer, (self, 0))
			self.connect(self.ns_detect, self.ffs_delay_frame_start, (self, 1))
		else: 
			# just patch the signal through
			self.connect(self.ffs_sample_and_average, gr.null_sink(gr.sizeof_float))
			self.connect(self.input, (self,0))
			# frame start still needed ..
			self.connect(self.ns_detect, (self,1))

		if debug:
			self.connect(self.ffs_sample_and_average, gr.multiply_const_ff(1./(dp.T*2*pi)), gr.file_sink(gr.sizeof_float, "debug/ofdm_sync_dab_fine_freq_err_f.dat"))
			self.connect(self.ffs_mixer, gr.file_sink(gr.sizeof_gr_complex, "debug/ofdm_sync_dab_fine_freq_corrected_c.dat"))
Beispiel #44
0
	def __init__(self):
		grc_wxgui.top_block_gui.__init__(self, title="Top Block")

		##################################################
		# Variables
		##################################################
		self.tranwidth = tranwidth = 10000
		self.tau = tau = 50e-6
		self.gain = gain = 20
		self.freq = freq = 100.0e6
		self.decim = decim = 80
		self.cutoff = cutoff = 100000

		##################################################
		# Blocks
		##################################################
		self._tranwidth_text_box = forms.text_box(
			parent=self.GetWin(),
			value=self.tranwidth,
			callback=self.set_tranwidth,
			label="tranwidth",
			converter=forms.float_converter(),
		)
		self.GridAdd(self._tranwidth_text_box, 1, 1, 1, 1)
		_tau_sizer = wx.BoxSizer(wx.VERTICAL)
		self._tau_text_box = forms.text_box(
			parent=self.GetWin(),
			sizer=_tau_sizer,
			value=self.tau,
			callback=self.set_tau,
			label="Zeitkonstante (Tau)",
			converter=forms.float_converter(),
			proportion=0,
		)
		self._tau_slider = forms.slider(
			parent=self.GetWin(),
			sizer=_tau_sizer,
			value=self.tau,
			callback=self.set_tau,
			minimum=0,
			maximum=100e-6,
			num_steps=100,
			style=wx.SL_HORIZONTAL,
			cast=float,
			proportion=1,
		)
		self.Add(_tau_sizer)
		_gain_sizer = wx.BoxSizer(wx.VERTICAL)
		self._gain_text_box = forms.text_box(
			parent=self.GetWin(),
			sizer=_gain_sizer,
			value=self.gain,
			callback=self.set_gain,
			label="Gain [dB]",
			converter=forms.float_converter(),
			proportion=0,
		)
		self._gain_slider = forms.slider(
			parent=self.GetWin(),
			sizer=_gain_sizer,
			value=self.gain,
			callback=self.set_gain,
			minimum=0,
			maximum=30,
			num_steps=60,
			style=wx.SL_HORIZONTAL,
			cast=float,
			proportion=1,
		)
		self.Add(_gain_sizer)
		_freq_sizer = wx.BoxSizer(wx.VERTICAL)
		self._freq_text_box = forms.text_box(
			parent=self.GetWin(),
			sizer=_freq_sizer,
			value=self.freq,
			callback=self.set_freq,
			label="Frequenz (UKW)",
			converter=forms.float_converter(),
			proportion=0,
		)
		self._freq_slider = forms.slider(
			parent=self.GetWin(),
			sizer=_freq_sizer,
			value=self.freq,
			callback=self.set_freq,
			minimum=87.5e6,
			maximum=108e6,
			num_steps=205,
			style=wx.SL_HORIZONTAL,
			cast=float,
			proportion=1,
		)
		self.GridAdd(_freq_sizer, 0, 0, 1, 1)
		self._decim_text_box = forms.text_box(
			parent=self.GetWin(),
			value=self.decim,
			callback=self.set_decim,
			label="Decimation",
			converter=forms.float_converter(),
		)
		self.GridAdd(self._decim_text_box, 1, 0, 1, 1)
		self._cutoff_text_box = forms.text_box(
			parent=self.GetWin(),
			value=self.cutoff,
			callback=self.set_cutoff,
			label="Cutoff",
			converter=forms.float_converter(),
		)
		self.GridAdd(self._cutoff_text_box, 0, 1, 1, 1)
		self.wxgui_fftsink2_0 = fftsink2.fft_sink_f(
			self.GetWin(),
			baseband_freq=0,
			y_per_div=10,
			y_divs=10,
			ref_level=0,
			ref_scale=2.0,
			sample_rate=64000000/decim,
			fft_size=1024,
			fft_rate=15,
			average=False,
			avg_alpha=None,
			title="FFT Plot",
			peak_hold=False,
		)
		self.Add(self.wxgui_fftsink2_0.win)
		self.uhd_usrp_source_0 = uhd.usrp_source(
			device_addr="type=usrp1",
			stream_args=uhd.stream_args(
				cpu_format="fc32",
				channels=range(1),
			),
		)
		self.uhd_usrp_source_0.set_subdev_spec("B:0", 0)
		self.uhd_usrp_source_0.set_samp_rate(64000000/decim)
		self.uhd_usrp_source_0.set_center_freq(freq, 0)
		self.uhd_usrp_source_0.set_gain(gain, 0)
		self.low_pass_filter_0_0 = gr.fir_filter_fff(1, firdes.low_pass(
			1, 44100, 15000, tranwidth, firdes.WIN_HAMMING, 6.76))
		self.low_pass_filter_0 = gr.fir_filter_ccf(1, firdes.low_pass(
			1, 64000000/decim, cutoff, tranwidth, firdes.WIN_HAMMING, 6.76))
		self.gr_multiply_xx_0 = gr.multiply_vcc(1)
		self.gr_iir_filter_ffd_1 = gr.iir_filter_ffd(((1.0/(1+tau*2*800000), 1.0/(1+tau*2*800000))), ((1, -(1-tau*2*800000)/(1+tau*2*800000))))
		self.gr_delay_0 = gr.delay(gr.sizeof_gr_complex*1, 1)
		self.gr_conjugate_cc_0 = gr.conjugate_cc()
		self.gr_complex_to_arg_0 = gr.complex_to_arg(1)
		self.blks2_rational_resampler_xxx_0 = blks2.rational_resampler_fff(
			interpolation=44100,
			decimation=64000000/decim,
			taps=None,
			fractional_bw=None,
		)
		self.audio_sink_0 = audio.sink(44100, "", True)

		##################################################
		# Connections
		##################################################
		self.connect((self.uhd_usrp_source_0, 0), (self.low_pass_filter_0, 0))
		self.connect((self.low_pass_filter_0, 0), (self.gr_delay_0, 0))
		self.connect((self.low_pass_filter_0, 0), (self.gr_multiply_xx_0, 0))
		self.connect((self.gr_delay_0, 0), (self.gr_conjugate_cc_0, 0))
		self.connect((self.gr_conjugate_cc_0, 0), (self.gr_multiply_xx_0, 1))
		self.connect((self.gr_multiply_xx_0, 0), (self.gr_complex_to_arg_0, 0))
		self.connect((self.gr_complex_to_arg_0, 0), (self.blks2_rational_resampler_xxx_0, 0))
		self.connect((self.blks2_rational_resampler_xxx_0, 0), (self.low_pass_filter_0_0, 0))
		self.connect((self.low_pass_filter_0_0, 0), (self.gr_iir_filter_ffd_1, 0))
		self.connect((self.gr_iir_filter_ffd_1, 0), (self.audio_sink_0, 0))
		self.connect((self.gr_complex_to_arg_0, 0), (self.wxgui_fftsink2_0, 0))