Example #1
0
    def test_stretch_01(self):
        tb = self.tb

        data = 10*[1,]
        data0 = map(lambda x: x/20.0, data)
        data1 = map(lambda x: x/10.0, data)

        expected_result0 = 10*[0.05,]
        expected_result1 = 10*[0.1,]

        src0 = gr.vector_source_f(data0, False)
        src1 = gr.vector_source_f(data1, False)
        inter = gr.streams_to_vector(gr.sizeof_float, 2)
        op = blocks.stretch_ff(0.1, 2)
        deinter = gr.vector_to_streams(gr.sizeof_float, 2)
        dst0 = gr.vector_sink_f()
        dst1 = gr.vector_sink_f()
        
        tb.connect(src0, (inter,0))
        tb.connect(src1, (inter,1))
        tb.connect(inter, op)
        tb.connect(op, deinter)
        tb.connect((deinter,0), dst0)
        tb.connect((deinter,1), dst1)
        tb.run()

        dst0_data = dst0.data()
        dst1_data = dst1.data()

        self.assertFloatTuplesAlmostEqual(expected_result0, dst0_data, 4)
        self.assertFloatTuplesAlmostEqual(expected_result1, dst1_data, 4)
Example #2
0
    def __init__(self, mpoints, taps=None):
        """
        Takes 1 complex stream in, produces M complex streams out
        that runs at 1/M times the input sample rate

        @param mpoints: number of freq bins/interpolation factor/subbands
        @param taps:    filter taps for subband filter

        Same channel to frequency mapping as described above.
        """
        item_size = gr.sizeof_gr_complex
        gr.hier_block2.__init__(
            self,
            "analysis_filterbank",
            gr.io_signature(1, 1, item_size),  # Input signature
            gr.io_signature(mpoints, mpoints, item_size),
        )  # Output signature

        if taps is None:
            taps = _generate_synthesis_taps(mpoints)

        # pad taps to multiple of mpoints
        r = len(taps) % mpoints
        if r != 0:
            taps = taps + (mpoints - r) * (0,)

        # split in mpoints separate set of taps
        sub_taps = _split_taps(taps, mpoints)

        # print >> sys.stderr, "mpoints =", mpoints, "len(sub_taps) =", len(sub_taps)

        self.s2ss = gr.stream_to_streams(item_size, mpoints)
        # filters here
        self.ss2v = gr.streams_to_vector(item_size, mpoints)
        self.fft = gr.fft_vcc(mpoints, True, [])
        self.v2ss = gr.vector_to_streams(item_size, mpoints)

        self.connect(self, self.s2ss)

        # build mpoints fir filters...
        for i in range(mpoints):
            f = gr.fft_filter_ccc(1, sub_taps[mpoints - i - 1])
            self.connect((self.s2ss, i), f)
            self.connect(f, (self.ss2v, i))
            self.connect((self.v2ss, i), (self, i))

        self.connect(self.ss2v, self.fft, self.v2ss)
Example #3
0
    def __init__(self, mpoints, taps=None):
        """
        Takes 1 complex stream in, produces M complex streams out
        that runs at 1/M times the input sample rate

        @param mpoints: number of freq bins/interpolation factor/subbands
        @param taps:    filter taps for subband filter

        Same channel to frequency mapping as described above.
        """
        item_size = gr.sizeof_gr_complex
        gr.hier_block2.__init__(
            self,
            "analysis_filterbank",
            gr.io_signature(1, 1, item_size),  # Input signature
            gr.io_signature(mpoints, mpoints, item_size))  # Output signature

        if taps is None:
            taps = _generate_synthesis_taps(mpoints)

        # pad taps to multiple of mpoints
        r = len(taps) % mpoints
        if r != 0:
            taps = taps + (mpoints - r) * (0, )

        # split in mpoints separate set of taps
        sub_taps = _split_taps(taps, mpoints)

        # print >> sys.stderr, "mpoints =", mpoints, "len(sub_taps) =", len(sub_taps)

        self.s2ss = gr.stream_to_streams(item_size, mpoints)
        # filters here
        self.ss2v = gr.streams_to_vector(item_size, mpoints)
        self.fft = gr.fft_vcc(mpoints, True, [])
        self.v2ss = gr.vector_to_streams(item_size, mpoints)

        self.connect(self, self.s2ss)

        # build mpoints fir filters...
        for i in range(mpoints):
            f = gr.fft_filter_ccc(1, sub_taps[mpoints - i - 1])
            self.connect((self.s2ss, i), f)
            self.connect(f, (self.ss2v, i))
            self.connect((self.v2ss, i), (self, i))

        self.connect(self.ss2v, self.fft, self.v2ss)
    def test_003(self):

        #Test streams_to_vector (using stream_to_streams & vector_to_stream).

        n = 8
        src_len = n * 8
        src_data = tuple(range(src_len))
        expected_results = src_data

        src = gr.vector_source_i(src_data)
        op1 = gr.stream_to_streams(gr.sizeof_int, n)
        op2 = gr.streams_to_vector(gr.sizeof_int, n)
        op3 = gr.vector_to_stream(gr.sizeof_int, n)
        dst = gr.vector_sink_i()

        self.tb.connect(src, op1)
        for i in range(n):
            self.tb.connect((op1, i), (op2, i))
        self.tb.connect(op2, op3, dst)

        self.tb.run()
        self.assertEqual(expected_results, dst.data())
Example #5
0
    def test_003(self):
        """
        Test streams_to_vector (using stream_to_streams & vector_to_stream).
        """
        n = 8
        src_len = n * 8
        src_data = tuple(range(src_len))
        expected_results = src_data

        src = gr.vector_source_i(src_data)
        op1 = gr.stream_to_streams(gr.sizeof_int, n)
        op2 = gr.streams_to_vector(gr.sizeof_int, n)
        op3 = gr.vector_to_stream(gr.sizeof_int, n)
        dst = gr.vector_sink_i()

        self.tb.connect(src, op1)
        for i in range(n):
            self.tb.connect((op1, i), (op2, i))
        self.tb.connect(op2, op3, dst)

        self.tb.run()
        self.assertEqual(expected_results, dst.data())
Example #6
0
    def test_stretch_01(self):
        tb = self.tb

        data = 10 * [
            1,
        ]
        data0 = map(lambda x: x / 20.0, data)
        data1 = map(lambda x: x / 10.0, data)

        expected_result0 = 10 * [
            0.05,
        ]
        expected_result1 = 10 * [
            0.1,
        ]

        src0 = gr.vector_source_f(data0, False)
        src1 = gr.vector_source_f(data1, False)
        inter = gr.streams_to_vector(gr.sizeof_float, 2)
        op = blocks.stretch_ff(0.1, 2)
        deinter = gr.vector_to_streams(gr.sizeof_float, 2)
        dst0 = gr.vector_sink_f()
        dst1 = gr.vector_sink_f()

        tb.connect(src0, (inter, 0))
        tb.connect(src1, (inter, 1))
        tb.connect(inter, op)
        tb.connect(op, deinter)
        tb.connect((deinter, 0), dst0)
        tb.connect((deinter, 1), dst1)
        tb.run()

        dst0_data = dst0.data()
        dst1_data = dst1.data()

        self.assertFloatTuplesAlmostEqual(expected_result0, dst0_data, 4)
        self.assertFloatTuplesAlmostEqual(expected_result1, dst1_data, 4)
Example #7
0
  def __init__(self, fft_length, block_length, block_header, range, options):
    gr.hier_block2.__init__(self, "integer_fo_estimator",
      gr.io_signature3(3,3,gr.sizeof_gr_complex,gr.sizeof_float,gr.sizeof_char),
      gr.io_signature2(3,3,gr.sizeof_float,gr.sizeof_char))
    
    raise NotImplementedError,"Obsolete class"

    self._range = range

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

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

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

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

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

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

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

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

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

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

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

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

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


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


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

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


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

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

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

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

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

    try:
        gr.hier_block.update_var_names(self, "ifo_estimator", vars())
        gr.hier_block.update_var_names(self, "ifo_estimator", vars(self))
    except:
        pass
    def __init__(self, fg, mpoints, taps=None):
        """
        Takes M complex streams in, produces single complex stream out
        that runs at M times the input sample rate

        @param fg:      flow_graph
        @param mpoints: number of freq bins/interpolation factor/subbands
        @param taps:    filter taps for subband filter

        The channel spacing is equal to the input sample rate.
        The total bandwidth and output sample rate are equal the input
        sample rate * nchannels.

        Output stream to frequency mapping:
        
          channel zero is at zero frequency.

          if mpoints is odd:
            
            Channels with increasing positive frequencies come from
            channels 1 through (N-1)/2.

            Channel (N+1)/2 is the maximum negative frequency, and
            frequency increases through N-1 which is one channel lower
            than the zero frequency.

          if mpoints is even:

            Channels with increasing positive frequencies come from
            channels 1 through (N/2)-1.

            Channel (N/2) is evenly split between the max positive and
            negative bins.

            Channel (N/2)+1 is the maximum negative frequency, and
            frequency increases through N-1 which is one channel lower
            than the zero frequency.

            Channels near the frequency extremes end up getting cut
            off by subsequent filters and therefore have diminished
            utility.
        """
        item_size = gr.sizeof_gr_complex

        if taps is None:
            taps = _generate_synthesis_taps(mpoints)

        # pad taps to multiple of mpoints
        r = len(taps) % mpoints
        if r != 0:
            taps = taps + (mpoints - r) * (0,)

        # split in mpoints separate set of taps
        sub_taps = _split_taps(taps, mpoints)

        self.ss2v = gr.streams_to_vector(item_size, mpoints)
        self.ifft = gr.fft_vcc(mpoints, False, [])
        self.v2ss = gr.vector_to_streams(item_size, mpoints)
        # mpoints filters go in here...
        self.ss2s = gr.streams_to_stream(item_size, mpoints)

        fg.connect(self.ss2v, self.ifft, self.v2ss)

        # build mpoints fir filters...
        for i in range(mpoints):
            f = gr.fft_filter_ccc(1, sub_taps[i])
            fg.connect((self.v2ss, i), f)
            fg.connect(f, (self.ss2s, i))

        gr.hier_block.__init__(self, fg, self.ss2v, self.ss2s)
    def __init__(self, mpoints, taps=None):
        """
        Takes M complex streams in, produces single complex stream out
        that runs at M times the input sample rate

        @param mpoints: number of freq bins/interpolation factor/subbands
        @param taps:    filter taps for subband filter

        The channel spacing is equal to the input sample rate.
        The total bandwidth and output sample rate are equal the input
        sample rate * nchannels.

        Output stream to frequency mapping:
        
          channel zero is at zero frequency.

          if mpoints is odd:
            
            Channels with increasing positive frequencies come from
            channels 1 through (N-1)/2.

            Channel (N+1)/2 is the maximum negative frequency, and
            frequency increases through N-1 which is one channel lower
            than the zero frequency.

          if mpoints is even:

            Channels with increasing positive frequencies come from
            channels 1 through (N/2)-1.

            Channel (N/2) is evenly split between the max positive and
            negative bins.

            Channel (N/2)+1 is the maximum negative frequency, and
            frequency increases through N-1 which is one channel lower
            than the zero frequency.

            Channels near the frequency extremes end up getting cut
            off by subsequent filters and therefore have diminished
            utility.
        """
        item_size = gr.sizeof_gr_complex
        gr.hier_block2.__init__(self, "synthesis_filterbank",
                                gr.io_signature(mpoints, mpoints, item_size), # Input signature
                                gr.io_signature(1, 1, item_size))             # Output signature


        if taps is None:
            taps = _generate_synthesis_taps(mpoints)

        # pad taps to multiple of mpoints
        r = len(taps) % mpoints
        if r != 0:
            taps = taps + (mpoints - r) * (0,)

        # split in mpoints separate set of taps
        sub_taps = _split_taps(taps, mpoints)

        self.ss2v = gr.streams_to_vector(item_size, mpoints)
        self.ifft = gr.fft_vcc(mpoints, False, [])
        self.v2ss = gr.vector_to_streams(item_size, mpoints)
        # mpoints filters go in here...
        self.ss2s = gr.streams_to_stream(item_size, mpoints)

        for i in range(mpoints):
            self.connect((self, i), (self.ss2v, i))
            
        self.connect(self.ss2v, self.ifft, self.v2ss)

        # build mpoints fir filters...
        for i in range(mpoints):
            f = gr.fft_filter_ccc(1, sub_taps[i])
            self.connect((self.v2ss, i), f)
            self.connect(f, (self.ss2s, i))

	self.connect(self.ss2s, self)
  def __init__( self, vlen, cp_len ):

    gr.hier_block2.__init__( self,
        "channel_estimator_003",
        gr.io_signature( 1, 1, gr.sizeof_gr_complex * vlen ),
        gr.io_signature( 1, 1, gr.sizeof_gr_complex * vlen ) )

    self.ch_est = channel_estimator_001( vlen )
    self.connect( self, self.ch_est )

    cir_len = cp_len + 1
    self.cir_len = cir_len
    self.vlen = vlen

    self.preamble_td = self.ch_est.td
    self.preamble_fd = self.ch_est.fd

    # CTF -> CIR
    self.cir_est = gr.fft_vcc( vlen, False, [], False ) # IFFT
    self.connect( self.ch_est, self.cir_est )

    # CIR -> energy per sample
    self.cir_energy = gr.complex_to_mag_squared( vlen )
    self.connect( self.cir_est, self.cir_energy )

    # prepare cyclic convolution of CIR vector
    self.cyclic_cir = gr.streams_to_vector( gr.sizeof_float * vlen, 2 )
    self.connect( self.cir_energy, ( self.cyclic_cir, 0 ) )
    self.connect( self.cir_energy, ( self.cyclic_cir, 1 ) )

    # Cyclic convolution of CIR vector
    # Pad CIR vector: 0 x cp_len, CIR, CIR, 0 x cp_len
    self.serial_ccir = gr.vector_to_stream( gr.sizeof_float, vlen * 2 )
    self.padded_sccir = gr.stream_mux( gr.sizeof_float,
                                       [ cir_len-1, 2*vlen, cir_len-1 ] )

    if cir_len > 1:
      self.conv = gr.fir_filter_fff( 1, [ 1 ] * cir_len )
    else:
      self.conv = gr.kludge_copy( gr.sizeof_float )


    self.connect( self.padded_sccir, self.conv )

    self.null_source = gr.null_source( gr.sizeof_float )
    self.connect( self.cyclic_cir, self.serial_ccir )
    self.connect( self.null_source, ( self.padded_sccir, 0 ) )
    self.connect( self.serial_ccir, ( self.padded_sccir, 1 ) )
    self.connect( self.null_source, ( self.padded_sccir, 2 ) )


    # Extract search window
    self.search_window = ofdm.vector_sampler( gr.sizeof_float, vlen )
    periodic_trigger_seq = [ 0 ] * ( ( vlen + cir_len-1 ) * 2 )
    periodic_trigger_seq[ cir_len-1 + cir_len-1 + vlen-1 ] = 1
    self.sampler_trigsrc = gr.vector_source_b( periodic_trigger_seq, True )
    self.connect( self.conv, self.search_window )
    self.connect( self.sampler_trigsrc, ( self.search_window, 1 ) )

    # Find point of maximum energy
    self.cir_start = gr.argmax_fs( vlen )
    self.connect( self.search_window, self.cir_start )
    self.connect( ( self.cir_start, 1 ), gr.null_sink( gr.sizeof_short ) )

    # Set to zero all samples that do not belong to the CIR
    self.filtered_cir = ofdm.interp_cir_set_noncir_to_zero( vlen, cir_len )
    #self.filtered_cir = gr.kludge_copy( gr.sizeof_gr_complex * vlen )
    self.connect( self.cir_est, self.filtered_cir )
    self.connect( self.cir_start, ( self.filtered_cir, 1 ) )
    #self.connect( self.cir_start, gr.null_sink( gr.sizeof_short ) )

    # CIR -> CTF
    self.filtered_ctf = gr.fft_vcc( vlen, True, [], False ) # FFT
    self.scaled_fctf = gr.multiply_const_vcc( [1./vlen]*vlen )
    self.connect( self.filtered_cir, self.filtered_ctf )
    self.connect( self.filtered_ctf, self.scaled_fctf )

    # Output connection
    self.connect( self.scaled_fctf, self )
Example #11
0
    def __init__(self, fft_length, block_length, block_header, range, options):
        gr.hier_block2.__init__(
            self, "integer_fo_estimator",
            gr.io_signature3(3, 3, gr.sizeof_gr_complex, gr.sizeof_float,
                             gr.sizeof_char),
            gr.io_signature2(3, 3, gr.sizeof_float, gr.sizeof_char))

        raise NotImplementedError, "Obsolete class"

        self._range = range

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        try:
            gr.hier_block.update_var_names(self, "ifo_estimator", vars())
            gr.hier_block.update_var_names(self, "ifo_estimator", vars(self))
        except:
            pass