Example #1
0
  def publish_rx_spectrum(self,fftlen):
    ## RX Spectrum

    fftlen = 256
    my_window = window.hamming(fftlen) #.blackmanharris(fftlen)
    rxs_sampler = vector_sampler(gr.sizeof_gr_complex,fftlen)
    rxs_trigger = gr.vector_source_b(concatenate([[1],[0]*199]),True)
    rxs_window = blocks.multiply_const_vcc(my_window)
    rxs_spectrum = gr.fft_vcc(fftlen,True,[],True)
    rxs_mag = gr.complex_to_mag(fftlen)
    rxs_avg = gr.single_pole_iir_filter_ff(0.01,fftlen)
    rxs_logdb = gr.nlog10_ff(20.0,fftlen,-20*log10(fftlen))
    rxs_decimate_rate = gr.keep_one_in_n(gr.sizeof_float*fftlen,1)
    msgq = gr.msg_queue(5)
    rxs_msg_sink = gr.message_sink(gr.sizeof_float*fftlen,msgq,True)
    self.connect(rxs_trigger,(rxs_sampler,1))
    t = self.u if self.filter is None else self.filter
    self.connect(t,rxs_sampler,rxs_window,
                 rxs_spectrum,rxs_mag,rxs_avg,rxs_logdb, rxs_decimate_rate,
                 rxs_msg_sink)
    self.servants.append(corba_data_buffer_servant("spectrum",fftlen,msgq))

    print "RXS trigger unique id", rxs_trigger.unique_id()
    
    print "Publishing RX baseband under id: spectrum"
  def build_blocks( self, vlen, cp_len, snr_db, sigpow, startup, N,
                           LOS_power, no_taps, have_LOS ):


    self.fading_channel =  \
      static_fading_channel( LOS_power, no_taps, vlen, have_LOS )

    self.freq_resp = self.fading_channel.freq_resp
    assert( len(self.freq_resp) == vlen )

    ############################################################################
    # select channel estimator to be tested her
   # self.uut = channel_estimator_003( vlen, cp_len )
    self.uut = channel_estimator_001( vlen)
    ############################################################################

    block = self.uut.preamble_td
    #print abs(sigpow)
    #print sum(numpy.abs(block)**2.0)/len(block)
    assert( abs( sigpow - sum(numpy.abs(block)**2.0)/len(block) ) < 1e-4 ) # power


    if cp_len > 0:
      block = concatenate([ block[ len(block) - cp_len : len(block) ], block ])
    self.block = block

    self.compare = gr.add_const_vcc( -1.0 * numpy.array(self.freq_resp) )
    self.mean_squared_error = vector_acc_se2( vlen, startup, N )
    self.dst = gr.vector_sink_f()

    self.awgn_channel = awgn_channel( snr_db, sigpow )
    self.block_src = gr.vector_source_c( self.block, True )
    self.sampler = ofdm.vector_sampler( gr.sizeof_gr_complex, vlen )
    self.perfect_trigger = perfect_block_trigger( len(self.block) )
    self.fft = scaled_fft( vlen )
Example #3
0
    def supply_rx_baseband(self):
        ## RX Spectrum
        if self.__dict__.has_key('rx_baseband'):
            return self.rx_baseband

        config = self.config

        fftlen = config.fft_length

        my_window = window.hamming(fftlen)  #.blackmanharris(fftlen)
        rxs_sampler = vector_sampler(gr.sizeof_gr_complex, fftlen)
        rxs_trigger = blocks.vector_source_b(concatenate([[1], [0] * 199]),
                                             True)
        rxs_window = blocks.multiply_const_vcc(my_window)
        rxs_spectrum = gr.fft_vcc(fftlen, True, [], True)
        rxs_mag = gr.complex_to_mag(fftlen)
        rxs_avg = gr.single_pole_iir_filter_ff(0.01, fftlen)
        rxs_logdb = gr.nlog10_ff(20.0, fftlen, -20 * log10(fftlen))
        rxs_decimate_rate = gr.keep_one_in_n(gr.sizeof_float * fftlen, 50)

        t = self.u if self.filter is None else self.filter
        self.connect(rxs_trigger, (rxs_sampler, 1))
        self.connect(t, rxs_sampler, rxs_window, rxs_spectrum, rxs_mag,
                     rxs_avg, rxs_logdb, rxs_decimate_rate)
        if self._options.log:
            log_to_file(self, rxs_decimate_rate, "data/supply_rx.float")
        self.rx_baseband = rxs_decimate_rate
        return rxs_decimate_rate
Example #4
0
def main():
    parser = OptionParser(conflict_handler="resolve")
    expert_grp = parser.add_option_group("Expert")
    add_options(parser, expert_grp)
    (options, args) = parser.parse_args()

    fft_length = options.fft_length or 512
    file = options.file or "input.compl"
    out = options.out or "output.compl"

    src = gr.file_source(gr.sizeof_gr_complex, file)
    sampler = ofdm.vector_sampler(gr.sizeof_gr_complex, fft_length)
    trig = gr.vector_source_b([1], True)

    fft = gr.fft_vcc(fft_length, True, [], True)
    mag = gr.complex_to_mag(fft_length)
    avg = gr.single_pole_iir_filter_ff(0.01, fft_length)
    nlog = gr.nlog10_ff(20, fft_length, -10 * math.log10(fft_length))
    dst = gr.file_sink(gr.sizeof_float * fft_length, out)

    fg = gr.top_block()
    fg.connect(src, sampler, fft, mag, avg, nlog, dst)
    fg.connect(trig, (sampler, 1))
    #  fg.connect(src,limit,
    #             gr.stream_to_vector(gr.sizeof_gr_complex,fft_length),
    #             fft,
    #             gr.multiply_const_vcc([1./fft_length]*fft_length),
    #             gr.complex_to_mag(fft_length),
    #             gr.nlog10_ff(10.0,fft_length),
    #             dst)
    #  fg.connect( src, fft, dst )

    fg.run()
    print "done"
Example #5
0
def main():
  parser = OptionParser(conflict_handler="resolve")
  expert_grp = parser.add_option_group("Expert")
  add_options(parser, expert_grp)
  (options, args) = parser.parse_args ()

  fft_length = options.fft_length or 512
  file = options.file or "input.compl"
  out = options.out or "output.compl"

  src = gr.file_source(gr.sizeof_gr_complex,file)
  sampler = ofdm.vector_sampler( gr.sizeof_gr_complex, fft_length )
  trig = gr.vector_source_b([1],True)

  fft = gr.fft_vcc( fft_length, True, [], True )
  mag = gr.complex_to_mag( fft_length )
  avg = gr.single_pole_iir_filter_ff(0.01, fft_length)
  nlog = gr.nlog10_ff( 20, fft_length, -10*math.log10(fft_length) )
  dst = gr.file_sink( gr.sizeof_float * fft_length, out )

  fg = gr.top_block()
  fg.connect( src, sampler, fft, mag, avg, nlog, dst )
  fg.connect( trig, (sampler,1))
#  fg.connect(src,limit,
#             gr.stream_to_vector(gr.sizeof_gr_complex,fft_length),
#             fft,
#             gr.multiply_const_vcc([1./fft_length]*fft_length),
#             gr.complex_to_mag(fft_length),
#             gr.nlog10_ff(10.0,fft_length),
#             dst)
#  fg.connect( src, fft, dst )

  fg.run()
  print "done"
  def __init__(self,subcarriers, frame_length):
    #config = station_configuration()

    total_subc = subcarriers
    vlen = total_subc

    gr.hier_block2.__init__(self,"ofdm_frame_sampler_grc",
      gr.io_signature2(2,2,gr.sizeof_gr_complex*vlen,
                       gr.sizeof_char),
      gr.io_signature2(2,2,gr.sizeof_gr_complex*vlen,
                 gr.sizeof_char))


    ft = [0] * frame_length
    ft[0] = 1

    # The next block ensures that only complete frames find their way into
    # the old outer receiver. The dynamic frame start trigger is hence
    # replaced with a static one, fixed to the frame length.

    frame_sampler = vector_sampler( gr.sizeof_gr_complex * total_subc,
                                              frame_length )
    symbol_output = blocks.vector_to_stream( gr.sizeof_gr_complex * total_subc,
                                              frame_length )
    delayed_frame_start = blocks.delay( gr.sizeof_char, frame_length - 1 )
    damn_static_frame_trigger = blocks.vector_source_b( ft, True )

    self.connect( self, frame_sampler, symbol_output, self )

    self.connect( (self,1), delayed_frame_start, ( frame_sampler, 1 ) )

    self.connect( damn_static_frame_trigger, (self,1) )
Example #7
0
  def __init__(self, vlen):
    gr.hier_block2.__init__(self, "coarse_frequency_offset_estimation",
        gr.io_signature2(2,2,gr.sizeof_gr_complex,gr.sizeof_char),
        gr.io_signature (1,1,gr.sizeof_float))

    ## Preamble Extraction
    sampler = vector_sampler(gr.sizeof_gr_complex,vlen)
    self.connect(self,sampler)
    self.connect((self,1),(sampler,1))

    ## Split block into two parts
    splitter = gr.vector_to_streams(gr.sizeof_gr_complex*vlen/2,2)
    self.connect(sampler,splitter)

    ## Multiply 2nd sub-part with conjugate of 1st sub-part
    conj_mult = gr.multiply_conjugate_cc(vlen/2)
    self.connect((splitter,1),(conj_mult,0))
    self.connect((splitter,0),(conj_mult,1))

    ## Sum of Products
    psum = vector_sum_vcc(vlen/2)
    self.connect((conj_mult,0),psum)

    ## Complex to Angle
    angle = complex_to_arg()
    self.connect(psum,angle)

    ## Normalize
    norm = gr.multiply_const_ff(1.0/math.pi)
    self.connect(angle,norm)

    ## Setup Output Connections
    self.connect(norm,self)
Example #8
0
    def __init__(self, fft_length):
        gr.hier_block2.__init__(
            self, "foe",
            gr.io_signature2(2, 2, gr.sizeof_gr_complex, gr.sizeof_char),
            gr.io_signature(1, 1, gr.sizeof_float))

        self.input = (self, 0)
        self.time_sync = (self, 1)

        # P(d)
        self.nominator = schmidl_nominator(fft_length)

        # sample nominator
        sampler = vector_sampler(gr.sizeof_gr_complex, 1)
        self.connect(self.input, self.nominator, (sampler, 0))
        self.connect(self.time_sync, (sampler, 1))

        # calculate epsilon from P(d), epsilon is normalized fractional frequency offset
        angle = complex_to_arg()
        self.epsilon = gr.multiply_const_ff(1.0 / math.pi)

        self.connect(sampler, angle, self.epsilon, self)

        try:
            gr.hier_block.update_var_names(self, "foe", vars())
            gr.hier_block.update_var_names(self, "foe", vars(self))
        except:
            pass
Example #9
0
  def __init__(self, fft_length):
    gr.hier_block2.__init__(self, "foe",
        gr.io_signature2(2,2,gr.sizeof_gr_complex,gr.sizeof_char),
        gr.io_signature(1,1,gr.sizeof_float))

    self.input = (self,0)
    self.time_sync = (self,1)

    # P(d)
    self.nominator = schmidl_nominator(fft_length)

    # sample nominator
    sampler = vector_sampler(gr.sizeof_gr_complex,1)
    self.connect(self.input, self.nominator, (sampler,0))
    self.connect(self.time_sync, (sampler,1))

    # calculate epsilon from P(d), epsilon is normalized fractional frequency offset
    angle = complex_to_arg()
    self.epsilon = gr.multiply_const_ff(1.0/math.pi)

    self.connect(sampler, angle, self.epsilon, self)

    try:
        gr.hier_block.update_var_names(self, "foe", vars())
        gr.hier_block.update_var_names(self, "foe", vars(self))
    except:
        pass
Example #10
0
    def __init__(self, vlen):
        gr.hier_block2.__init__(
            self, "coarse_frequency_offset_estimation",
            gr.io_signature2(2, 2, gr.sizeof_gr_complex, gr.sizeof_char),
            gr.io_signature(1, 1, gr.sizeof_float))

        ## Preamble Extraction
        sampler = vector_sampler(gr.sizeof_gr_complex, vlen)
        self.connect(self, sampler)
        self.connect((self, 1), (sampler, 1))

        ## Split block into two parts
        splitter = gr.vector_to_streams(gr.sizeof_gr_complex * vlen / 2, 2)
        self.connect(sampler, splitter)

        ## Multiply 2nd sub-part with conjugate of 1st sub-part
        conj_mult = gr.multiply_conjugate_cc(vlen / 2)
        self.connect((splitter, 1), (conj_mult, 0))
        self.connect((splitter, 0), (conj_mult, 1))

        ## Sum of Products
        psum = vector_sum_vcc(vlen / 2)
        self.connect((conj_mult, 0), psum)

        ## Complex to Angle
        angle = complex_to_arg()
        self.connect(psum, angle)

        ## Normalize
        norm = gr.multiply_const_ff(1.0 / math.pi)
        self.connect(angle, norm)

        ## Setup Output Connections
        self.connect(norm, self)
Example #11
0
  def supply_rx_baseband(self):
    ## RX Spectrum
    if self.__dict__.has_key('rx_baseband'):
      return self.rx_baseband

    config = self.config

    fftlen = config.fft_length

    my_window = window.hamming(fftlen) #.blackmanharris(fftlen)
    rxs_sampler = vector_sampler(gr.sizeof_gr_complex,fftlen)
    rxs_trigger = gr.vector_source_b(concatenate([[1],[0]*199]),True)
    rxs_window = blocks.multiply_const_vcc(my_window)
    rxs_spectrum = gr.fft_vcc(fftlen,True,[],True)
    rxs_mag = gr.complex_to_mag(fftlen)
    rxs_avg = gr.single_pole_iir_filter_ff(0.01,fftlen)
    rxs_logdb = gr.nlog10_ff(20.0,fftlen,-20*log10(fftlen))
    rxs_decimate_rate = gr.keep_one_in_n(gr.sizeof_float*fftlen,50)

    t = self.u if self.filter is None else self.filter
    self.connect(rxs_trigger,(rxs_sampler,1))
    self.connect(t,rxs_sampler,rxs_window,
                 rxs_spectrum,rxs_mag,rxs_avg,rxs_logdb, rxs_decimate_rate)
    if self._options.log:
          log_to_file(self, rxs_decimate_rate, "data/supply_rx.float")
    self.rx_baseband = rxs_decimate_rate
    return rxs_decimate_rate
Example #12
0
  def test_007_vector_sampler(self):
    data = range(1,577,1) # 1..576
    trigger = numpy.concatenate([[0]*575,[1]])
    blocks = 10000
    expected = data[64:577]
    assert(len(expected)==512)
    expected = numpy.concatenate([expected*blocks])
    assert(len(expected) == 512*blocks)

    src = gr.vector_source_c(data,True)
    src2 = gr.vector_source_b(trigger.tolist(),True)
    dst = gr.vector_sink_c()
    sampler = ofdm.vector_sampler(gr.sizeof_gr_complex,512)
    v2s = gr.vector_to_stream(gr.sizeof_gr_complex,512)

    self.fg.connect(src, (sampler,0))
    self.fg.connect(src2,gr.head(gr.sizeof_char,blocks*576), (sampler,1))
    self.fg.connect(sampler, v2s, dst)

    self.fg.run()
    #self.assertEqual(numpy.array(expected,numpy.Complex), numpy.array(dst.data(), numpy.Complex))
    if numpy.array(expected).all() != numpy.array(dst.data()).all():
      print "up"
      print len(expected),len(dst.data())
      vec = dst.data()
      for i in range(min(len(expected),len(dst.data()))):
        if vec[i] != expected[i]:
          print "e at ",i
  def __init__( self, vlen, cp_len ):
    gr.hier_block2.__init__( self,
          "perfect_ofdm_block_sampler",
          gr.io_signature( 1, 1, gr.sizeof_gr_complex ),
          gr.io_signature( 1, 1, gr.sizeof_gr_complex * vlen ) )

    sampler = ofdm.vector_sampler( gr.sizeof_gr_complex, vlen )
    perfect_trigger = perfect_block_trigger( vlen + cp_len )

    self.connect( self, sampler, self )
    self.connect( perfect_trigger, ( sampler, 1 ) )

    self.perfect_trigger = perfect_trigger
Example #14
0
  def __init__(self,options):
    config = station_configuration()

    total_subc = config.subcarriers
    vlen = total_subc

    gr.hier_block2.__init__(self,"ofdm_frame_sampler",
      gr.io_signature2(2,2,gr.sizeof_gr_complex*vlen,
                       gr.sizeof_char),
      gr.io_signature2(2,2,gr.sizeof_gr_complex*vlen,
                 gr.sizeof_char))


    ft = [0] * config.frame_length
    ft[0] = 1

    # The next block ensures that only complete frames find their way into
    # the old outer receiver. The dynamic frame start trigger is hence
    # replaced with a static one, fixed to the frame length.

    frame_sampler = ofdm.vector_sampler( gr.sizeof_gr_complex * total_subc,
                                              config.frame_length )
    symbol_output = blocks.vector_to_stream( gr.sizeof_gr_complex * total_subc,
                                              config.frame_length )
    delayed_frame_start = blocks.delay( gr.sizeof_char, config.frame_length - 1 )
    damn_static_frame_trigger = blocks.vector_source_b( ft, True )
    
    #oqam_postpro = ofdm.fbmc_oqam_postprocessing_vcvc(total_subc,0,0)
    if options.enable_erasure_decision:
      self.frame_gate = vector_sampler(
        gr.sizeof_gr_complex * total_subc * config.frame_length, 1 )
      self.connect( self, frame_sampler, self.frame_gate,
                    symbol_output )
    else:
      self.connect( self, frame_sampler, symbol_output, self )

    self.connect( (self,1), delayed_frame_start, ( frame_sampler, 1 ) )

    self.connect( damn_static_frame_trigger, (self,1) )
Example #15
0
  def publish_tm_window(self,unique_id):
    """
    corbaname: ofdm_ti.unique_id
    """
    raise SystemError,"Bad guy! Obey the gnuradio hierarchy ..."

    config = self.config
    msgq = gr.msg_queue(10)
    msg_sink = gr.message_sink(gr.sizeof_float*config.fft_length,msgq,True)
    sampler = vector_sampler(gr.sizeof_float,config.fft_length)

    self.connect(self.receiver.timing_metric,(sampler,0))
    self.connect(self.receiver.time_sync,delay(gr.sizeof_char,config.fft_length/2-1),(sampler,1))
    self.connect(sampler,msg_sink)

    self.servants.append(corba_data_buffer_servant(str(unique_id),config.fft_length,msgq))
Example #16
0
    def __init__(self, total_subcarriers, frame_length, frame_data_part,
                 training_data):
        #config = station_configuration()

        total_subc = total_subcarriers
        vlen = total_subc

        gr.hier_block2.__init__(
            self, "fbmc_frame_sampler_grc",
            gr.io_signature2(2, 2, gr.sizeof_gr_complex * vlen,
                             gr.sizeof_char),
            gr.io_signature2(2, 2, gr.sizeof_gr_complex * vlen,
                             gr.sizeof_char))

        frame_size = frame_data_part + training_data.fbmc_no_preambles / 2
        print "frame_size: ", frame_size
        ft = [0] * frame_size
        ft[0] = 1

        # The next block ensures that only complete frames find their way into
        # the old outer receiver. The dynamic frame start trigger is hence
        # replaced with a static one, fixed to the frame length.

        frame_sampler = vector_sampler(gr.sizeof_gr_complex * total_subc,
                                       frame_size)
        symbol_output = blocks.vector_to_stream(
            gr.sizeof_gr_complex * total_subc, frame_size)
        #delayed_frame_start = blocks.delay( gr.sizeof_char, config.frame_length-1  - config.training_data.fbmc_no_preambles/2 )
        delayed_frame_start = blocks.delay(gr.sizeof_char,
                                           frame_length / 2 - 1)

        damn_static_frame_trigger = blocks.vector_source_b(ft, True)

        #oqam_postpro = ofdm.fbmc_oqam_postprocessing_vcvc(total_subc,0,0)

        self.connect(self, frame_sampler, symbol_output, self)

        #self.connect( (self,1), blocks.keep_m_in_n(gr.sizeof_char,frame_data_part + training_data.fbmc_no_preambles/2,2*frame_data_part + training_data.fbmc_no_preambles,0),delayed_frame_start, ( frame_sampler, 1 ) )
        self.connect((self, 1), delayed_frame_start, (frame_sampler, 1))

        #self.connect( self, blocks.multiply_const_vcc(([1.0]*total_subc)) ,self)
        #terminate_stream(self,frame_sampler)

        self.connect(damn_static_frame_trigger, (self, 1))
Example #17
0
    def test_008(self):
        vlen = 128
        syms = 4
        bin1 = vlen / 2 + 4
        bin1_val = 1.0
        cp_length = vlen / 4

        expec = numpy.array(numpy.zeros(vlen), numpy.complex)
        expec[bin1] = bin1_val
        expec = concatenate([expec] * syms)

        epsilon = [-0.5]
        frame_trigger = numpy.concatenate([[1], [0] * (syms - 1)])

        freq_shift = ofdm.frequency_shift_vcc(vlen, 1.0 / vlen, cp_length)

        fft = gr.fft_vcc(vlen, True, [], True)  # natural order, dc = vlen / 2
        fft_scale = gr.multiply_const_vcc([1.0 / vlen] * vlen)

        sampler = ofdm.vector_sampler(gr.sizeof_gr_complex, vlen)

        trigger_vec = concatenate([[0] * (vlen + cp_length - 1), [1]])
        trigger_vec = concatenate([trigger_vec] * syms)
        trigger = gr.vector_source_b(trigger_vec.tolist())

        src = gr.sig_source_c(vlen, gr.GR_COS_WAVE, 4.5, 1.0,
                              0.0)  # bin vlen/2 + 4.5
        dst = gr.vector_sink_c()
        v2s = gr.vector_to_stream(gr.sizeof_gr_complex, vlen)

        eps = gr.vector_source_f(epsilon)
        trig = gr.vector_source_b(frame_trigger.tolist())

        self.fg.connect(src, (sampler, 0))
        self.fg.connect(trigger, (sampler, 1))
        self.fg.connect(sampler, (freq_shift, 0))
        self.fg.connect(eps, (freq_shift, 1))
        self.fg.connect(trig, (freq_shift, 2))
        self.fg.connect(freq_shift, fft, fft_scale, v2s, dst)
        self.fg.run()

        self.assertComplexTuplesAlmostEqual2(expec, dst.data(), 1e-5, 1e-5)
Example #18
0
  def __init__(self, fft_length, L):
    gr.hier_block2.__init__(self, "morelli_foe",
        gr.io_signature2(2,2,gr.sizeof_gr_complex,gr.sizeof_char),
        gr.io_signature(1,1,gr.sizeof_float))
    
    data_in = (self,0)
    trig_in = (self,1)
    est_out = (self,0)
    
    #inp = gr.kludge_copy(gr.sizeof_gr_complex)
    #self.connect(data_in,inp)
    inp = data_in

    
    sampler = vector_sampler(gr.sizeof_gr_complex,fft_length)
    self.connect(inp,(sampler,0))
    self.connect(trig_in,(sampler,1))
    
    est = mm_frequency_estimator(fft_length,L)
    self.connect(sampler,est,est_out)
Example #19
0
  def test_008 (self):
    vlen = 128
    syms = 4
    bin1 = vlen/2 + 4
    bin1_val = 1.0
    cp_length = vlen/4
        
    expec = numpy.array(numpy.zeros(vlen), numpy.complex)
    expec[bin1] = bin1_val
    expec = concatenate([expec]*syms)
    
    epsilon = [-0.5]
    frame_trigger = numpy.concatenate([[1],[0]*(syms-1)])
    
    freq_shift = ofdm.frequency_shift_vcc(vlen, 1.0/vlen, cp_length)
    
    fft = gr.fft_vcc(vlen, True, [], True) # natural order, dc = vlen / 2
    fft_scale = gr.multiply_const_vcc([1.0/vlen]*vlen)
    
    sampler = ofdm.vector_sampler(gr.sizeof_gr_complex,vlen)
    
    trigger_vec = concatenate([[0]*(vlen+cp_length-1),[1]])
    trigger_vec = concatenate([trigger_vec]*syms)
    trigger = gr.vector_source_b(trigger_vec.tolist())
    
    src = gr.sig_source_c(vlen, gr.GR_COS_WAVE, 4.5, 1.0, 0.0) # bin vlen/2 + 4.5
    dst = gr.vector_sink_c()
    v2s = gr.vector_to_stream(gr.sizeof_gr_complex, vlen)
    
    eps = gr.vector_source_f(epsilon)
    trig = gr.vector_source_b(frame_trigger.tolist())
    
    self.fg.connect(src, (sampler,0))
    self.fg.connect(trigger, (sampler,1))    
    self.fg.connect(sampler, (freq_shift,0))
    self.fg.connect(eps, (freq_shift,1))
    self.fg.connect(trig, (freq_shift,2))
    self.fg.connect(freq_shift, fft, fft_scale, v2s, dst)
    self.fg.run()

    self.assertComplexTuplesAlmostEqual2(expec, dst.data(), 1e-5, 1e-5)  
Example #20
0
  def __init__(self,options):
    config = station_configuration()

    total_subc = config.subcarriers
    vlen = total_subc

    gr.hier_block2.__init__(self,"fbmc_frame_sampler",
      gr.io_signature2(2,2,gr.sizeof_gr_complex*vlen,
                       gr.sizeof_char),
      gr.io_signature2(2,2,gr.sizeof_gr_complex*vlen,
                 gr.sizeof_char))

    frame_size = config.frame_data_part + config.training_data.fbmc_no_preambles/2
    print "frame_size: ", frame_size
    ft = [0] * frame_size
    ft[0] = 1

    # The next block ensures that only complete frames find their way into
    # the old outer receiver. The dynamic frame start trigger is hence
    # replaced with a static one, fixed to the frame length.

    frame_sampler = ofdm.vector_sampler( gr.sizeof_gr_complex * total_subc,
                                              frame_size )
    symbol_output = blocks.vector_to_stream( gr.sizeof_gr_complex * total_subc,
                                              frame_size )
    #delayed_frame_start = blocks.delay( gr.sizeof_char, config.frame_length-1  - config.training_data.fbmc_no_preambles/2 )
    delayed_frame_start = blocks.delay( gr.sizeof_char, config.frame_length/2-1)

    damn_static_frame_trigger = blocks.vector_source_b( ft, True )
    
    #oqam_postpro = ofdm.fbmc_oqam_postprocessing_vcvc(total_subc,0,0)

    self.connect( self, frame_sampler, symbol_output ,self)

    #self.connect( (self,1), blocks.keep_m_in_n(gr.sizeof_char,config.frame_data_part + config.training_data.fbmc_no_preambles/2,2*config.frame_data_part + config.training_data.fbmc_no_preambles,0),delayed_frame_start, ( frame_sampler, 1 ) )
    self.connect( (self,1), delayed_frame_start, ( frame_sampler, 1 ) )

    #self.connect( self, blocks.multiply_const_vcc(([1.0]*total_subc)) ,self)
    #terminate_stream(self,frame_sampler)

    self.connect( damn_static_frame_trigger, (self,1) )
Example #21
0
    def __init__(self, vlen):
        gr.hier_block2.__init__(
            self, "snr_estimator",
            gr.io_signature2(2, 2, gr.sizeof_gr_complex, gr.sizeof_char),
            gr.io_signature(1, 1, gr.sizeof_float))

        data_in = (self, 0)
        trig_in = (self, 1)
        snr_out = (self, 0)

        ## Preamble Extraction
        sampler = vector_sampler(gr.sizeof_gr_complex, vlen)
        self.connect(data_in, sampler)
        self.connect(trig_in, (sampler, 1))

        ## Algorithm implementation
        estim = sc_snr_estimator(vlen)
        self.connect(sampler, estim)
        self.connect(estim, snr_out)

        return

        ## Split block into two parts
        splitter = gr.vector_to_streams(gr.sizeof_gr_complex * vlen / 2, 2)
        self.connect(sampler, splitter)

        ## Conjugate first half block
        conj = gr.conjugate_cc(vlen / 2)
        self.connect(splitter, conj)

        ## Vector multiplication of both half blocks
        vmult = gr.multiply_vcc(vlen / 2)
        self.connect(conj, vmult)
        self.connect((splitter, 1), (vmult, 1))

        ## Sum of Products
        psum = vector_sum_vcc(vlen / 2)
        self.connect(vmult, psum)

        ## Magnitude of P(d)
        p_mag = gr.complex_to_mag()
        self.connect(psum, p_mag)

        ## Squared Magnitude of block
        r_magsqrd = gr.complex_to_mag_squared(vlen)
        self.connect(sampler, r_magsqrd)

        ## Sum of squared second half block
        r_sum = vector_sum_vff(vlen)
        self.connect(r_magsqrd, r_sum)

        ## Square Root of Metric
        m_sqrt = gr.divide_ff()
        self.connect(p_mag, (m_sqrt, 0))
        self.connect(r_sum, gr.multiply_const_ff(0.5), (m_sqrt, 1))

        ## Denominator of SNR estimate
        denom = gr.add_const_ff(1)
        neg_m_sqrt = gr.multiply_const_ff(-1.0)
        self.connect(m_sqrt, limit_vff(1, 1 - 2e-5, -1000), neg_m_sqrt, denom)

        ## SNR estimate
        snr_est = gr.divide_ff()
        self.connect(m_sqrt, (snr_est, 0))
        self.connect(denom, (snr_est, 1))

        ## Setup Output Connections
        self.connect(snr_est, self)
Example #22
0
    def __init__(self):
        gr.top_block.__init__(self, "Top Block")
        Qt.QWidget.__init__(self)
        self.setWindowTitle("Top Block")
        try:
             self.setWindowIcon(Qt.QIcon.fromTheme('gnuradio-grc'))
        except:
             pass
        self.top_scroll_layout = Qt.QVBoxLayout()
        self.setLayout(self.top_scroll_layout)
        self.top_scroll = Qt.QScrollArea()
        self.top_scroll.setFrameStyle(Qt.QFrame.NoFrame)
        self.top_scroll_layout.addWidget(self.top_scroll)
        self.top_scroll.setWidgetResizable(True)
        self.top_widget = Qt.QWidget()
        self.top_scroll.setWidget(self.top_widget)
        self.top_layout = Qt.QVBoxLayout(self.top_widget)
        self.top_grid_layout = Qt.QGridLayout()
        self.top_layout.addLayout(self.top_grid_layout)

        self.settings = Qt.QSettings("GNU Radio", "top_block")
        self.restoreGeometry(self.settings.value("geometry").toByteArray())


        ##################################################
        # Variables
        ##################################################
        self.used_id_bits = used_id_bits = 8
        self.subcarriers = subcarriers = 208
        self.id_blocks = id_blocks = 1
        self.fft_length = fft_length = 256
        self.fbmc = fbmc = 1
        self.estimation_preamble = estimation_preamble = 0
        self.data_blocks = data_blocks = 10
        self.training_data = training_data = default_block_header(subcarriers,fft_length,fbmc,estimation_preamble,[])
        self.repeated_id_bits = repeated_id_bits = subcarriers/used_id_bits
        self.data_part = data_part = data_blocks + id_blocks
        self.whitener_seed = whitener_seed = seed(1)
        self.whitener_pn = whitener_pn = [randint(0,1) for i in range(used_id_bits*repeated_id_bits)]
        self.variable_function_probe_2 = variable_function_probe_2 = 0
        self.variable_function_probe_1 = variable_function_probe_1 = 0
        self.variable_function_probe_0 = variable_function_probe_0 = 0
        self.tx_hostname = tx_hostname = "localhost"
        self.samp_rate = samp_rate = 4*250000
        self.interleaver = interleaver = trellis.interleaver(2000,666)
        self.frame_length = frame_length = 2*data_part + training_data.fbmc_no_preambles
        self.filter_length = filter_length = 4
        self.disable_freq_sync = disable_freq_sync = 1
        self.coding = coding = 1
        self.chunkdivisor = chunkdivisor = int(numpy.ceil(data_blocks/5.0))
        self.ber_window = ber_window = 100000
        self.amplitude = amplitude = 1
        self.SNR = SNR = 40

        ##################################################
        # Blocks
        ##################################################
        self._amplitude_layout = Qt.QVBoxLayout()
        self._amplitude_tool_bar = Qt.QToolBar(self)
        self._amplitude_layout.addWidget(self._amplitude_tool_bar)
        self._amplitude_tool_bar.addWidget(Qt.QLabel("amplitude"+": "))
        class qwt_counter_pyslot(Qwt.QwtCounter):
            def __init__(self, parent=None):
                Qwt.QwtCounter.__init__(self, parent)
            @pyqtSlot('double')
            def setValue(self, value):
                super(Qwt.QwtCounter, self).setValue(value)
        self._amplitude_counter = qwt_counter_pyslot()
        self._amplitude_counter.setRange(0, 1, 0.02)
        self._amplitude_counter.setNumButtons(2)
        self._amplitude_counter.setValue(self.amplitude)
        self._amplitude_tool_bar.addWidget(self._amplitude_counter)
        self._amplitude_counter.valueChanged.connect(self.set_amplitude)
        self._amplitude_slider = Qwt.QwtSlider(None, Qt.Qt.Horizontal, Qwt.QwtSlider.BottomScale, Qwt.QwtSlider.BgSlot)
        self._amplitude_slider.setRange(0, 1, 0.02)
        self._amplitude_slider.setValue(self.amplitude)
        self._amplitude_slider.setMinimumWidth(200)
        self._amplitude_slider.valueChanged.connect(self.set_amplitude)
        self._amplitude_layout.addWidget(self._amplitude_slider)
        self.top_layout.addLayout(self._amplitude_layout)
        self.tx_rpc_manager_0 = tx_rpc_manager(fft_length, subcarriers, data_blocks, frame_length, 0, 0.0, samp_rate)
        self.tigr_transmit_control_0 = tigr_transmit_control(
            subcarriers=subcarriers,
            fft_length=fft_length,
            used_id_bits=used_id_bits,
            estimation_preamble=estimation_preamble,
            filter_length=filter_length,
            fbmc=fbmc,
            data_blocks=data_blocks,
            data_part=data_part,
            repeated_id_bits=repeated_id_bits,
            coding=coding,
        )
        self.tigr_scatterplot_0 = tigr_scatterplot(
            subcarriers=subcarriers,
            fbmc=fbmc,
            fft_length=fft_length,
            estimation_preamble=estimation_preamble,
            data_blocks=data_blocks,
            data_part=11,
            frame_length=frame_length,
        )
        self.rx_rpc_manager_0 = rx_rpc_manager()
        self.rms = fbmc_rms_amplifier(amplitude, subcarriers)
        self.zeromq_pub_sink_1 = zeromq.pub_sink(gr.sizeof_float, subcarriers, "tcp://*:5559", 100)
        self.zeromq_pub_sink_0 = zeromq.pub_sink(gr.sizeof_float, 1, "tcp://*:5557", 100)
        def _variable_function_probe_2_probe():
            while True:
                val = self.rx_rpc_manager_0.add_set_scatter_subcarrier_interface(self.tigr_scatterplot_0.ofdm_vector_element_0.set_element)
                try:
                    self.set_variable_function_probe_2(val)
                except AttributeError:
                    pass
                time.sleep(1.0 / (0.000000001))
        _variable_function_probe_2_thread = threading.Thread(target=_variable_function_probe_2_probe)
        _variable_function_probe_2_thread.daemon = True
        _variable_function_probe_2_thread.start()
        def _variable_function_probe_1_probe():
            while True:
                val = self.tx_rpc_manager_0.add_tx_modulation_interface(self.tigr_transmit_control_0.ofdm_allocation_src_0.set_allocation)
                try:
                    self.set_variable_function_probe_1(val)
                except AttributeError:
                    pass
                time.sleep(1.0 / (0.000000001))
        _variable_function_probe_1_thread = threading.Thread(target=_variable_function_probe_1_probe)
        _variable_function_probe_1_thread.daemon = True
        _variable_function_probe_1_thread.start()
        def _variable_function_probe_0_probe():
            while True:
                val = self.tx_rpc_manager_0.add_tx_ampl_interface(self.rms.set_rms_amplitude)
                try:
                    self.set_variable_function_probe_0(val)
                except AttributeError:
                    pass
                time.sleep(1.0 / (0.000000001))
        _variable_function_probe_0_thread = threading.Thread(target=_variable_function_probe_0_probe)
        _variable_function_probe_0_thread.daemon = True
        _variable_function_probe_0_thread.start()
        self.trellis_permutation_0 = trellis.permutation(interleaver.K(), (interleaver.DEINTER()), 1, gr.sizeof_float*1)
        self.tigr_fbmc_snr_estimator_0 = tigr_fbmc_snr_estimator(
            subcarriers=subcarriers,
            fbmc=fbmc,
            fft_length=fft_length,
            estimation_preamble=estimation_preamble,
            frame_length=frame_length,
        )
        self.tigr_fbmc_inner_receiver_0 = tigr_fbmc_inner_receiver(
            subcarriers=subcarriers,
            fft_length=fft_length,
            data_blocks=data_blocks,
            estimation_preamble=estimation_preamble,
            filter_length=filter_length,
            frame_length=frame_length,
            disable_freq_sync=disable_freq_sync,
        )
        self.tigr_ber_measurement_0 = tigr_ber_measurement(
            subcarriers=subcarriers,
            fbmc=fbmc,
            fft_length=fft_length,
            estimation_preamble=estimation_preamble,
            ber_window=ber_window,
            data_blocks=data_blocks,
        )
        self.single_pole_iir_filter_xx_0 = filter.single_pole_iir_filter_ff(0.1, subcarriers)
        self.ofdm_viterbi_combined_fb_0 = ofdm.viterbi_combined_fb(ofdm.fsm(ofdm.fsm(1,2,[91,121])), subcarriers, -1, -1, 2, chunkdivisor, ([-1,-1,-1,1,1,-1,1,1]), ofdm.TRELLIS_EUCLIDEAN)
        self.ofdm_vector_sampler_0 = ofdm.vector_sampler(gr.sizeof_gr_complex*subcarriers, 1)
        self.ofdm_vector_padding_0 = ofdm.vector_padding(subcarriers, fft_length,  -1)
        self.ofdm_multiply_frame_fc_0 = ofdm.multiply_frame_fc(data_part, subcarriers)
        self.ofdm_multiply_const_ii_0 = ofdm.multiply_const_ii(1./int(numpy.ceil(data_blocks/5.0)))
        self.ofdm_generic_softdemapper_vcf_0 = ofdm.generic_softdemapper_vcf(subcarriers, data_part, 1)
        self.ofdm_fbmc_separate_vcvc_1 = ofdm.fbmc_separate_vcvc(fft_length, 2)
        self.ofdm_fbmc_polyphase_network_vcvc_1 = ofdm.fbmc_polyphase_network_vcvc(fft_length, filter_length, filter_length*fft_length-1, False)
        self.ofdm_fbmc_polyphase_network_vcvc_0 = ofdm.fbmc_polyphase_network_vcvc(fft_length, filter_length, filter_length*fft_length-1, False)
        self.ofdm_fbmc_pilot_block_inserter_0 = fbmc_pilot_block_inserter(subcarriers, data_part, training_data, 5)
        self.ofdm_fbmc_pilot_block_filter_0 = fbmc_pilot_block_filter(subcarriers, frame_length, data_part, training_data)
        self.ofdm_fbmc_overlapping_parallel_to_serial_vcc_0 = ofdm.fbmc_overlapping_parallel_to_serial_vcc(fft_length)
        self.ofdm_fbmc_oqam_preprocessing_vcvc_0 = ofdm.fbmc_oqam_preprocessing_vcvc(subcarriers, 0, 0)
        self.ofdm_fbmc_frame_sampler_0 = fbmc_frame_sampler(subcarriers, frame_length, data_part, training_data)
        self.ofdm_fbmc_beta_multiplier_vcvc_0 = ofdm.fbmc_beta_multiplier_vcvc(fft_length, filter_length, fft_length*fft_length-1, 0)
        self.ofdm_dynamic_trigger_ib_0 = ofdm.dynamic_trigger_ib(0)
        self.ofdm_depuncture_ff_0 = ofdm.depuncture_ff(subcarriers, 0)
        self.ofdm_coded_bpsk_soft_decoder_0 = ofdm.coded_bpsk_soft_decoder(subcarriers, used_id_bits, (whitener_pn))
        self.ofdm_allocation_buffer_0 = ofdm.allocation_buffer(subcarriers, data_blocks, "tcp://"+tx_hostname+":3333", 1)
        self.fft_vxx_1 = fft.fft_vcc(fft_length, False, ([]), True, 1)
        self.channels_channel_model_0 = channels.channel_model(
        	noise_voltage=math.sqrt(1.0*fft_length/subcarriers)*math.sqrt(0.5)*10**(-SNR/20.0),
        	frequency_offset=0.0/fft_length,
        	epsilon=1,
        	taps=((1.0 ), ),
        	noise_seed=0,
        	block_tags=False
        )
        self.blocks_vector_source_x_0 = blocks.vector_source_b([1] + [0]*(data_blocks/2-1), True, 1, [])
        self.blocks_throttle_0 = blocks.throttle(gr.sizeof_gr_complex*1, samp_rate,True)
        self.blocks_keep_one_in_n_1 = blocks.keep_one_in_n(gr.sizeof_float*subcarriers, 20)
        self.blks2_selector_0 = grc_blks2.selector(
        	item_size=gr.sizeof_float*1,
        	num_inputs=2,
        	num_outputs=1,
        	input_index=0,
        	output_index=0,
        )

        ##################################################
        # Connections
        ##################################################
        self.connect((self.ofdm_fbmc_polyphase_network_vcvc_0, 0), (self.ofdm_fbmc_overlapping_parallel_to_serial_vcc_0, 0))
        self.connect((self.ofdm_fbmc_polyphase_network_vcvc_1, 0), (self.ofdm_fbmc_overlapping_parallel_to_serial_vcc_0, 1))
        self.connect((self.ofdm_fbmc_separate_vcvc_1, 1), (self.ofdm_fbmc_polyphase_network_vcvc_1, 0))
        self.connect((self.ofdm_fbmc_oqam_preprocessing_vcvc_0, 0), (self.ofdm_fbmc_pilot_block_inserter_0, 0))
        self.connect((self.ofdm_fbmc_pilot_block_inserter_0, 0), (self.ofdm_vector_padding_0, 0))
        self.connect((self.ofdm_fbmc_beta_multiplier_vcvc_0, 0), (self.fft_vxx_1, 0))
        self.connect((self.fft_vxx_1, 0), (self.ofdm_fbmc_separate_vcvc_1, 0))
        self.connect((self.tigr_transmit_control_0, 0), (self.ofdm_fbmc_oqam_preprocessing_vcvc_0, 0))
        self.connect((self.single_pole_iir_filter_xx_0, 0), (self.blocks_keep_one_in_n_1, 0))
        self.connect((self.ofdm_fbmc_frame_sampler_0, 1), (self.ofdm_fbmc_pilot_block_filter_0, 1))
        self.connect((self.ofdm_fbmc_frame_sampler_0, 0), (self.ofdm_fbmc_pilot_block_filter_0, 0))
        self.connect((self.ofdm_fbmc_pilot_block_filter_0, 1), (self.ofdm_vector_sampler_0, 1))
        self.connect((self.ofdm_vector_sampler_0, 0), (self.ofdm_coded_bpsk_soft_decoder_0, 0))
        self.connect((self.ofdm_coded_bpsk_soft_decoder_0, 0), (self.ofdm_allocation_buffer_0, 0))
        self.connect((self.ofdm_allocation_buffer_0, 1), (self.ofdm_generic_softdemapper_vcf_0, 1))
        self.connect((self.single_pole_iir_filter_xx_0, 0), (self.ofdm_generic_softdemapper_vcf_0, 2))
        self.connect((self.ofdm_generic_softdemapper_vcf_0, 0), (self.trellis_permutation_0, 0))
        self.connect((self.ofdm_depuncture_ff_0, 0), (self.ofdm_viterbi_combined_fb_0, 0))
        self.connect((self.ofdm_allocation_buffer_0, 1), (self.ofdm_depuncture_ff_0, 1))
        self.connect((self.blocks_vector_source_x_0, 0), (self.ofdm_depuncture_ff_0, 2))
        self.connect((self.ofdm_allocation_buffer_0, 0), (self.ofdm_multiply_const_ii_0, 0))
        self.connect((self.ofdm_multiply_const_ii_0, 0), (self.ofdm_viterbi_combined_fb_0, 1))
        self.connect((self.ofdm_fbmc_separate_vcvc_1, 0), (self.ofdm_fbmc_polyphase_network_vcvc_0, 0))
        self.connect((self.ofdm_viterbi_combined_fb_0, 0), (self.tigr_ber_measurement_0, 2))
        self.connect((self.ofdm_dynamic_trigger_ib_0, 0), (self.tigr_ber_measurement_0, 3))
        self.connect((self.ofdm_fbmc_frame_sampler_0, 0), (self.tigr_fbmc_snr_estimator_0, 0))
        self.connect((self.ofdm_fbmc_frame_sampler_0, 1), (self.tigr_fbmc_snr_estimator_0, 1))
        self.connect((self.tigr_fbmc_inner_receiver_0, 1), (self.ofdm_fbmc_frame_sampler_0, 1))
        self.connect((self.tigr_fbmc_inner_receiver_0, 2), (self.ofdm_fbmc_frame_sampler_0, 0))
        self.connect((self.rms, 0), (self.blocks_throttle_0, 0))
        self.connect((self.tigr_fbmc_inner_receiver_0, 3), (self.zeromq_pub_sink_0, 0))
        self.connect((self.blocks_keep_one_in_n_1, 0), (self.zeromq_pub_sink_1, 0))
        self.connect((self.ofdm_vector_padding_0, 0), (self.ofdm_fbmc_beta_multiplier_vcvc_0, 0))
        self.connect((self.tigr_fbmc_inner_receiver_0, 0), (self.single_pole_iir_filter_xx_0, 0))
        self.connect((self.ofdm_fbmc_overlapping_parallel_to_serial_vcc_0, 0), (self.rms, 0))
        self.connect((self.ofdm_allocation_buffer_0, 0), (self.ofdm_dynamic_trigger_ib_0, 0))
        self.connect((self.ofdm_coded_bpsk_soft_decoder_0, 0), (self.tigr_ber_measurement_0, 0))
        self.connect((self.ofdm_allocation_buffer_0, 0), (self.tigr_ber_measurement_0, 1))
        self.connect((self.blks2_selector_0, 0), (self.ofdm_depuncture_ff_0, 0))
        self.connect((self.trellis_permutation_0, 0), (self.blks2_selector_0, 1))
        self.connect((self.ofdm_generic_softdemapper_vcf_0, 0), (self.blks2_selector_0, 0))
        self.connect((self.blocks_throttle_0, 0), (self.channels_channel_model_0, 0))
        self.connect((self.channels_channel_model_0, 0), (self.tigr_fbmc_inner_receiver_0, 0))
        self.connect((self.ofdm_fbmc_pilot_block_filter_0, 0), (self.ofdm_vector_sampler_0, 0))
        self.connect((self.ofdm_allocation_buffer_0, 2), (self.ofdm_multiply_frame_fc_0, 1))
        self.connect((self.ofdm_fbmc_pilot_block_filter_0, 0), (self.ofdm_multiply_frame_fc_0, 0))
        self.connect((self.ofdm_multiply_frame_fc_0, 0), (self.tigr_scatterplot_0, 0))
        self.connect((self.ofdm_multiply_frame_fc_0, 0), (self.ofdm_generic_softdemapper_vcf_0, 0))
Example #23
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
Example #24
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
Example #25
0
  def __init__(self, vlen):
    gr.hier_block2.__init__(self, "snr_estimator",
        gr.io_signature2(2,2,gr.sizeof_gr_complex,gr.sizeof_char),
        gr.io_signature (1,1,gr.sizeof_float))
    
    data_in = (self,0)
    trig_in = (self,1)
    snr_out = (self,0)

    ## Preamble Extraction
    sampler = vector_sampler(gr.sizeof_gr_complex,vlen)
    self.connect(data_in,sampler)
    self.connect(trig_in,(sampler,1))
    
    ## Algorithm implementation
    estim = sc_snr_estimator(vlen)
    self.connect(sampler,estim)
    self.connect(estim,snr_out)
    
    return 
  
  
  

    ## Split block into two parts
    splitter = gr.vector_to_streams(gr.sizeof_gr_complex*vlen/2,2)
    self.connect(sampler,splitter)

    ## Conjugate first half block
    conj = gr.conjugate_cc(vlen/2)
    self.connect(splitter,conj)

    ## Vector multiplication of both half blocks
    vmult = gr.multiply_vcc(vlen/2)
    self.connect(conj,vmult)
    self.connect((splitter,1),(vmult,1))

    ## Sum of Products
    psum = vector_sum_vcc(vlen/2)
    self.connect(vmult,psum)

    ## Magnitude of P(d)
    p_mag = gr.complex_to_mag()
    self.connect(psum,p_mag)

    ## Squared Magnitude of block
    r_magsqrd = gr.complex_to_mag_squared(vlen)
    self.connect(sampler,r_magsqrd)

    ## Sum of squared second half block
    r_sum = vector_sum_vff(vlen)
    self.connect(r_magsqrd,r_sum)

    ## Square Root of Metric
    m_sqrt = gr.divide_ff()
    self.connect(p_mag,(m_sqrt,0))
    self.connect(r_sum,gr.multiply_const_ff(0.5),(m_sqrt,1))

    ## Denominator of SNR estimate
    denom = gr.add_const_ff(1)
    neg_m_sqrt = gr.multiply_const_ff(-1.0)
    self.connect(m_sqrt,limit_vff(1,1-2e-5,-1000),neg_m_sqrt,denom)

    ## SNR estimate
    snr_est = gr.divide_ff()
    self.connect(m_sqrt,(snr_est,0))
    self.connect(denom,(snr_est,1))

    ## Setup Output Connections
    self.connect(snr_est,self)
Example #26
0
    def __init__(self, options, log=False):

        ## Read configuration
        config = station_configuration()

        fft_length = config.fft_length
        #cp_length     = config.cp_length
        block_header = config.training_data
        data_subc = config.data_subcarriers
        virtual_subc = config.virtual_subcarriers
        total_subc = config.subcarriers
        block_length = config.block_length
        frame_length = config.frame_length

        L = block_header.mm_periodic_parts

        cp_length = config.cp_length

        print "data_subc: ", config.data_subcarriers
        print "total_subc: ", config.subcarriers
        print "frame_lengthframe_length: ", frame_length

        ## Set Input/Output signature
        gr.hier_block2.__init__(
            self,
            "fbmc_inner_receiver",
            gr.io_signature(1, 1, gr.sizeof_gr_complex),
            gr.io_signaturev(
                4,
                4,
                [
                    gr.sizeof_float * total_subc,  # Normalized |CTF|^2 
                    gr.sizeof_char,  # Frame start
                    gr.sizeof_gr_complex * total_subc,  # OFDM blocks, SNR est
                    gr.sizeof_float
                ]))  # CFO

        ## Input and output ports
        self.input = rx_input = self

        out_ofdm_blocks = (self, 2)
        out_frame_start = (self, 1)
        out_disp_ctf = (self, 0)
        out_disp_cfo = (self, 3)
        #out_snr_pream    = ( self, 3 )

        ## pre-FFT processing
        '''
    ## Compute autocorrelations for S&C preamble
    ## and cyclic prefix
    
    self._sc_metric = sc_metric = autocorrelator( fft_length/2, fft_length/2 )
    self._gi_metric = gi_metric = autocorrelator( fft_length, cp_length )
    
    self.connect( rx_input, sc_metric )
    self.connect( rx_input, gi_metric )
    terminate_stream(self, gi_metric)
    
    ## Sync. Output contains OFDM blocks
    sync = ofdm.time_sync( fft_length/2, 1)
    self.connect( rx_input, ( sync, 0 ) )
    self.connect( sc_metric, ( sync, 1 ) )
    self.connect( sc_metric, ( sync, 2 ) )
    
    ofdm_blocks = ( sync, 0 )
    frame_start = ( sync, 1 )
    log_to_file( self, ( sync, 1 ), "data/fbmc_peak_detector.char" )
    '''
        if options.ideal is False and options.ideal2 is False:
            #Testing old/new metric
            self.tm = schmidl.recursive_timing_metric(2 * fft_length)
            self.connect(self.input, self.tm)
            #log_to_file( self, self.tm, "data/fbmc_rec_sc_metric_ofdm.float" )

            timingmetric_shift = 0  #-2 #int(-cp_length * 0.8)
            tmfilter = filter.fft_filter_fff(
                1, [2. / fft_length] * (fft_length / 2)
            )  # ofdm.lms_fir_ff( fft_length, 1e-3 ) #; filter.fir_filter_fff(1, [1./fft_length]*fft_length)
            self.connect(self.tm, tmfilter)
            self.tm = tmfilter
            #log_to_file( self, self.tm, "data/fbmc_rec_sc_metric_ofdm2.float" )

            self._pd_thres = 0.6
            self._pd_lookahead = fft_length  # empirically chosen
            peak_detector = ofdm.peak_detector_02_fb(self._pd_lookahead,
                                                     self._pd_thres)
            self.connect(self.tm, peak_detector)
            #log_to_file( self, peak_detector, "data/fbmc_rec_peak_detector.char" )

            #frame_start = [0]*frame_length
            #frame_start[0] = 1
            #frame_start = blocks.vector_source_b(frame_start,True)

            #OLD
            #delayed_timesync = blocks.delay(gr.sizeof_char,
            #                           (frame_length-10)*fft_length/2 - fft_length/4 -1 + timingmetric_shift)
            delayed_timesync = blocks.delay(
                gr.sizeof_char,
                (frame_length - 10) * fft_length / 2 - fft_length / 4 +
                int(2.5 * fft_length) + timingmetric_shift - 1)
            #delayed_timesync = blocks.delay(gr.sizeof_char,
            #(frame_length-10)*fft_length/2 - fft_length/4 + int(3.5*fft_length)  + timingmetric_shift-1)
            self.connect(peak_detector, delayed_timesync)

            self.block_sampler = ofdm.vector_sampler(
                gr.sizeof_gr_complex, fft_length / 2 * frame_length)

            self.connect(self.input, self.block_sampler)
            self.connect(delayed_timesync, (self.block_sampler, 1))
            #log_to_file( self, self.block_sampler, "data/fbmc_block_sampler.compl" )

            vt2s = blocks.vector_to_stream(gr.sizeof_gr_complex * fft_length,
                                           frame_length / 2)
            self.connect(self.block_sampler, vt2s)
            #terminate_stream(self,ofdm_blocks)

            ofdm_blocks = vt2s
            '''
        # TODO: dynamic solution
        vt2s = blocks.vector_to_stream(gr.sizeof_gr_complex*block_length/2,
                                                frame_length)
        self.connect(self.block_sampler,vt2s)
        terminate_stream(self,( sync, 0 ))
        ofdm_blocks = vt2s
        '''

            ##stv_help = blocks.stream_to_vector(gr.sizeof_gr_complex*config.fft_length/2, 1)
            #stv_help = blocks.vector_to_stream(gr.sizeof_gr_complex*config.fft_length/2, 2)
            ##self.connect(ofdm_blocks, stv_help)
            ##ofdm_blocks = stv_help
            #ofdm_blocks = ( sync, 0 )
            #frame_start = ( sync, 1 )
            #log_to_file(self, frame_start, "data/frame_start.compl")

            #log_to_file( self, sc_metric, "data/sc_metric.float" )
            #log_to_file( self, gi_metric, "data/gi_metric.float" )
            #log_to_file( self, (sync,1), "data/sync.float" )

            #    log_to_file(self,ofdm_blocks,"data/ofdm_blocks_original.compl")
            frame_start = [0] * int(frame_length / 2)
            frame_start[0] = 1
            frame_start = blocks.vector_source_b(frame_start, True)

            #frame_start2 = [0]*int(frame_length/2)
            #frame_start2[0] = 1
            #frame_start2 = blocks.vector_source_b(frame_start2,True)

        if options.disable_time_sync or options.ideal or options.ideal2:
            if options.ideal is False and options.ideal2 is False:
                terminate_stream(self, ofdm_blocks)
                terminate_stream(self, frame_start)

            serial_to_parallel = blocks.stream_to_vector(
                gr.sizeof_gr_complex, fft_length)
            #discard_cp = ofdm.vector_mask(block_length,cp_length,fft_length,[])
            #serial_to_parallel = blocks.stream_to_vector(gr.sizeof_gr_complex,block_length)
            #discard_cp = ofdm.vector_mask(block_length,cp_length,fft_length,[])
            #self.connect( rx_input,serial_to_parallel)

            #self.connect( rx_input, blocks.delay(gr.sizeof_gr_complex,0),serial_to_parallel)
            initial_skip = blocks.skiphead(gr.sizeof_gr_complex,
                                           2 * fft_length)
            self.connect(rx_input, initial_skip)
            if options.ideal is False and options.ideal2 is False:
                self.connect(initial_skip, serial_to_parallel)
                ofdm_blocks = serial_to_parallel
            else:
                ofdm_blocks = initial_skip
            #self.connect( rx_input, serial_to_parallel, discard_cp )

            frame_start = [0] * int(frame_length / 2)
            frame_start[0] = 1
            frame_start = blocks.vector_source_b(frame_start, True)

            #frame_start2 = [0]*int(frame_length/2)
            #frame_start2[0] = 1
            #frame_start2 = blocks.vector_source_b(frame_start2,True)

            print "Disabled time synchronization stage"

        print "\t\t\t\t\tframe_length = ", frame_length

        if options.ideal is False and options.ideal2 is False:
            ## Extract preamble, feed to Morelli & Mengali frequency offset estimator
            assert (block_header.mm_preamble_pos == 0)
            morelli_foe = ofdm.mm_frequency_estimator(fft_length, 2, 1,
                                                      config.fbmc)
            sampler_preamble = ofdm.vector_sampler(
                gr.sizeof_gr_complex * fft_length, 1)
            self.connect(ofdm_blocks, (sampler_preamble, 0))
            self.connect(frame_start, blocks.delay(gr.sizeof_char, 1),
                         (sampler_preamble, 1))
            self.connect(sampler_preamble, morelli_foe)
            freq_offset = morelli_foe
            print "FRAME_LENGTH: ", frame_length
            #log_to_file( self, sampler_preamble, "data/sampler_preamble.compl" )
            #log_to_file( self, rx_input, "data/rx_input.compl" )
            #log_to_file( self, ofdm_blocks, "data/rx_input.compl" )

            #Extracting preamble for SNR estimation
            #fft_snr_est = fft_blocks.fft_vcc( fft_length, True, [], True )
            #self.connect( sampler_preamble, blocks.stream_to_vector(gr.sizeof_gr_complex*fft_length/2, 2),  fft_snr_est )

            ## Remove virtual subcarriers
            #if fft_length > data_subc:
            #subcarrier_mask_snr_est = ofdm.vector_mask( fft_length, virtual_subc/2,
            #                       total_subc, [] )
            #self.connect( fft_snr_est, subcarrier_mask_snr_est )
            #fft_snr_est = subcarrier_mask_snr_est
            #log_to_file(self, ofdm_blocks, "data/vec_mask.compl")
            ## Least Squares estimator for channel transfer function (CTF)

            #self.connect( fft_snr_est, out_snr_pream ) # Connecting to output

            ## Adaptive LMS FIR filtering of frequency offset
            lms_fir = ofdm.lms_fir_ff(20,
                                      1e-3)  # TODO: verify parameter choice
            self.connect(freq_offset, lms_fir)
            freq_offset = lms_fir

            self.connect(freq_offset,
                         blocks.keep_one_in_n(gr.sizeof_float,
                                              20), out_disp_cfo)
        else:
            self.connect(blocks.vector_source_f([1]), out_disp_cfo)

        #log_to_file(self, lms_fir, "data/lms_fir.float")

        if options.disable_freq_sync or options.ideal or options.ideal2:
            if options.ideal is False and options.ideal2 is False:
                terminate_stream(self, freq_offset)
                freq_offset = blocks.vector_source_f([0.0], True)
            print "Disabled frequency synchronization stage"

        if options.ideal is False and options.ideal2 is False:
            ## Correct frequency shift, feed-forward structure
            frequency_shift = ofdm.frequency_shift_vcc(fft_length,
                                                       -1.0 / fft_length, 0)

            #freq_shift = blocks.multiply_cc()
            #norm_freq = -0.1 / config.fft_length
            #freq_off = self.freq_off_src = analog.sig_source_c(1.0, analog.GR_SIN_WAVE, norm_freq, 1.0, 0.0 )

            self.connect(ofdm_blocks, (frequency_shift, 0))
            self.connect(freq_offset, (frequency_shift, 1))
            self.connect(frame_start, blocks.delay(gr.sizeof_char, 0),
                         (frequency_shift, 2))

            #self.connect(frequency_shift,s2help)
            #ofdm_blocks = s2help
            ofdm_blocks = frequency_shift
        #terminate_stream(self, frequency_shift)

        #inner_pb_filt = self._inner_pilot_block_filter = fbmc_inner_pilot_block_filter()
        #self.connect(ofdm_blocks,inner_pb_filt)
        #self.connect(frame_start,(inner_pb_filt,1))
        #self.connect((inner_pb_filt,1),blocks.null_sink(gr.sizeof_char))

        #ofdm_blocks = (inner_pb_filt,0)

        overlap_ser_to_par = ofdm.fbmc_overlapping_serial_to_parallel_cvc(
            fft_length)
        self.separate_vcvc = ofdm.fbmc_separate_vcvc(fft_length, 2)
        self.polyphase_network_vcvc_1 = ofdm.fbmc_polyphase_network_vcvc(
            fft_length, 4, 4 * fft_length - 1, True)
        self.polyphase_network_vcvc_2 = ofdm.fbmc_polyphase_network_vcvc(
            fft_length, 4, 4 * fft_length - 1, True)
        self.junction_vcvc = ofdm.fbmc_junction_vcvc(fft_length, 2)
        self.fft_fbmc = fft_blocks.fft_vcc(fft_length, True, [], True)

        print "config.training_data.fbmc_no_preambles: ", config.training_data.fbmc_no_preambles
        #center_preamble = [1, -1j, -1, 1j]

        #self.preamble = preamble = [0]*total_subc + center_preamble*((int)(total_subc/len(center_preamble)))+[0]*total_subc

        self.preamble = preamble = config.training_data.fbmc_pilotsym_fd_list
        #inv_preamble = 1. / numpy.array(self.preamble)
        #print "self.preamble: ", len(self.preamble
        #print "inv_preamble: ", list(inv_preamble)

        #print "self.preamble", self.preamble
        #print "self.preamble2", self.preamble2

        self.multiply_const = ofdm.multiply_const_vcc(
            ([1.0 / (math.sqrt(fft_length * 0.6863))] * total_subc))
        self.beta_multiplier_vcvc = ofdm.fbmc_beta_multiplier_vcvc(
            total_subc, 4, 4 * fft_length - 1, 0)
        #self.skiphead = blocks.skiphead(gr.sizeof_gr_complex*total_subc, 2*4-1-1)
        self.skiphead = blocks.skiphead(gr.sizeof_gr_complex * total_subc, 2)
        self.skiphead_1 = blocks.skiphead(gr.sizeof_gr_complex * total_subc, 0)
        #self.remove_preamble_vcvc = ofdm.fbmc_remove_preamble_vcvc(total_subc, config.frame_data_part/2, config.training_data.fbmc_no_preambles*total_subc/2)
        #self.subchannel_processing_vcvc = ofdm.fbmc_subchannel_processing_vcvc(total_subc, config.frame_data_part, 1, 2, 1, 0)
        self.oqam_postprocessing_vcvc = ofdm.fbmc_oqam_postprocessing_vcvc(
            total_subc, 0, 0)

        #log_to_file( self, ofdm_blocks, "data/PRE_FBMC.compl" )
        #log_to_file( self, self.fft_fbmc, "data/FFT_FBMC.compl" )

        if options.ideal is False and options.ideal2 is False:
            self.subchannel_processing_vcvc = ofdm.fbmc_subchannel_processing_vcvc(
                total_subc, config.frame_data_part, 3, 2, 1, 0)
            help2 = blocks.keep_one_in_n(gr.sizeof_gr_complex * total_subc,
                                         frame_length)
            self.connect((self.subchannel_processing_vcvc, 1), help2)
            #log_to_file( self, self.subchannel_processing_vcvc, "data/fbmc_subc.compl" )

        #terminate_stream(self, help2)

        if options.ideal is False and options.ideal2 is False:
            self.connect(
                ofdm_blocks,
                blocks.vector_to_stream(gr.sizeof_gr_complex, fft_length),
                overlap_ser_to_par)
        else:
            self.connect(ofdm_blocks, overlap_ser_to_par)

        self.connect(overlap_ser_to_par, self.separate_vcvc)
        self.connect((self.separate_vcvc, 1),
                     (self.polyphase_network_vcvc_2, 0))
        self.connect((self.separate_vcvc, 0),
                     (self.polyphase_network_vcvc_1, 0))
        self.connect((self.polyphase_network_vcvc_1, 0),
                     (self.junction_vcvc, 0))
        self.connect((self.polyphase_network_vcvc_2, 0),
                     (self.junction_vcvc, 1))
        self.connect(self.junction_vcvc, self.fft_fbmc)

        ofdm_blocks = self.fft_fbmc
        print "config.dc_null: ", config.dc_null
        if fft_length > data_subc:
            subcarrier_mask_fbmc = ofdm.vector_mask_dc_null(
                fft_length, virtual_subc / 2, total_subc, config.dc_null, [])
            self.connect(ofdm_blocks, subcarrier_mask_fbmc)
            ofdm_blocks = subcarrier_mask_fbmc
            #log_to_file(self, ofdm_blocks, "data/vec_mask.compl")
            ## Least Squares estimator for channel transfer function (CTF)
            #log_to_file( self, subcarrier_mask, "data/OFDM_Blocks.compl" )

        self.connect(ofdm_blocks, self.beta_multiplier_vcvc)

        ofdm_blocks = self.beta_multiplier_vcvc
        #self.connect(ofdm_blocks,self.multiply_const)
        #self.connect(self.multiply_const, (self.skiphead, 0))

        self.connect(ofdm_blocks, (self.skiphead, 0))
        #log_to_file( self, self.skiphead, "data/fbmc_skiphead_4.compl" )

        #self.connect(ofdm_blocks, self.multiply_const)
        #self.connect(self.multiply_const, self.beta_multiplier_vcvc)
        #self.connect((self.beta_multiplier_vcvc, 0), (self.skiphead, 0))
        if options.ideal or options.ideal2:
            self.connect((self.skiphead, 0), (self.skiphead_1, 0))
        else:
            self.connect((self.skiphead, 0),
                         (self.subchannel_processing_vcvc, 0))
            self.connect((self.subchannel_processing_vcvc, 0),
                         (self.skiphead_1, 0))

        #log_to_file( self, self.skiphead, "data/fbmc_subc.compl" )
        #self.connect((self.skiphead_1, 0),(self.remove_preamble_vcvc, 0))
        #self.connect((self.remove_preamble_vcvc, 0),  (self.oqam_postprocessing_vcvc, 0))

        #ofdm_blocks = self.oqam_postprocessing_vcvc
        #log_to_file( self, self.subchannel_processing_vcvc, "data/subc_0.compl" )
        #log_to_file( self, (self.subchannel_processing_vcvc,1), "data/subc_1.compl" )

        self.connect((self.skiphead_1, 0), (self.oqam_postprocessing_vcvc, 0))
        #self.connect((self.oqam_postprocessing_vcvc, 0), (self.remove_preamble_vcvc, 0) )

        ofdm_blocks = (self.oqam_postprocessing_vcvc, 0
                       )  #(self.remove_preamble_vcvc, 0)
        #log_to_file( self, (self.oqam_postprocessing_vcvc, 0), "data/fbmc_before_remove.compl" )

        #log_to_file( self, self.skiphead, "data/SKIP_HEAD_FBMC.compl" )
        #log_to_file( self, self.beta_multiplier_vcvc, "data/BETA_REC_FBMC.compl" )
        #log_to_file( self, self.oqam_postprocessing_vcvc, "data/REC_OUT_FBMC.compl" )
        """ DISABLED OFDM CHANNEL ESTIMATION PREMBLE -> CORRECT LATER to compare FBMC and OFDM channel estimation
    #TAKING THE CHANNEL ESTIMATION PREAMBLE
    chest_pre_trigger = blocks.delay( gr.sizeof_char, 3 )
    sampled_chest_preamble = ofdm.vector_sampler( gr.sizeof_gr_complex * fft_length/2, 2 )
      
    self.connect( frame_start,       chest_pre_trigger )
    self.connect( chest_pre_trigger, ( sampled_chest_preamble, 1 ) )
    self.connect( frequency_shift,       ( sampled_chest_preamble, 0 ) )
    #ofdm_blocks = sampled_chest_preamble
    
        
    ## FFT
    fft = fft_blocks.fft_vcc( fft_length, True, [], True )
    self.connect( sampled_chest_preamble, fft )
    ofdm_blocks_est = fft
    log_to_file( self, sampled_chest_preamble, "data/SAMPLED_EST_PREAMBLE.compl" )
    log_to_file( self, ofdm_blocks_est, "data/FFT.compl" )
    
    
    ## Remove virtual subcarriers
    if fft_length > data_subc:
      subcarrier_mask = ofdm.vector_mask( fft_length, virtual_subc/2,
                                           total_subc, [] )
      self.connect( ofdm_blocks_est, subcarrier_mask )
      ofdm_blocks_est = subcarrier_mask
      #log_to_file(self, ofdm_blocks, "data/vec_mask.compl")
       ## Least Squares estimator for channel transfer function (CTF)
      log_to_file( self, subcarrier_mask, "data/OFDM_Blocks.compl" )
    
          
    ## post-FFT processing
      
    
    
    ## extract channel estimation preamble from frame
    ##chest_pre_trigger = blocks.delay( gr.sizeof_char, 
                                  ##1 )
    ##sampled_chest_preamble = \
     ## ofdm.vector_sampler( gr.sizeof_gr_complex * total_subc, 1 )
    ##self.connect( frame_start,       chest_pre_trigger )
    ##self.connect( chest_pre_trigger, ( sampled_chest_preamble, 1 ) )
    ##self.connect( ofdm_blocks,       ( sampled_chest_preamble, 0 ) )
    

    
    ## Least Squares estimator for channel transfer function (CTF)
    inv_preamble_fd = numpy.array( block_header.pilotsym_fd[ 
        block_header.channel_estimation_pilot[0] ] )
    #print "Channel estimation pilot: ", inv_preamble_fd
    inv_preamble_fd = 1. / inv_preamble_fd
    
    LS_channel_estimator = ofdm.multiply_const_vcc( list( inv_preamble_fd ) )
    self.connect( ofdm_blocks_est, LS_channel_estimator )
    estimated_CTF = LS_channel_estimator
    terminate_stream(self,estimated_CTF)
    """
        if options.ideal is False and options.ideal2 is False:
            if options.logcir:
                log_to_file(self, sampled_chest_preamble, "data/PREAM.compl")

            if not options.disable_ctf_enhancer:

                if options.logcir:
                    ifft1 = fft_blocks.fft_vcc(total_subc, False, [], True)
                    self.connect(
                        estimated_CTF, ifft1,
                        gr.null_sink(gr.sizeof_gr_complex * total_subc))
                    summ1 = ofdm.vector_sum_vcc(total_subc)
                    c2m = gr.complex_to_mag(total_subc)
                    self.connect(estimated_CTF, summ1,
                                 gr.null_sink(gr.sizeof_gr_complex))
                    self.connect(estimated_CTF, c2m,
                                 gr.null_sink(gr.sizeof_float * total_subc))
                    log_to_file(self, ifft1, "data/CIR1.compl")
                    log_to_file(self, summ1, "data/CTFsumm1.compl")
                    log_to_file(self, estimated_CTF, "data/CTF1.compl")
                    log_to_file(self, c2m, "data/CTFmag1.float")

                ## MSE enhancer
                ctf_mse_enhancer = ofdm.CTF_MSE_enhancer(
                    total_subc, cp_length + cp_length)
                self.connect(estimated_CTF, ctf_mse_enhancer)
                #      log_to_file( self, ctf_mse_enhancer, "data/ctf_mse_enhancer_original.compl")
                #ifft3 = fft_blocks.fft_vcc(total_subc,False,[],True)
                #null_noise = ofdm.noise_nulling(total_subc, cp_length + cp_length)
                #ctf_mse_enhancer = fft_blocks.fft_vcc(total_subc,True,[],True)
                #ctf_mse_enhancer = ofdm.vector_mask( fft_length, virtual_subc/2,
                # total_subc, [] )
                #self.connect( estimated_CTF, ifft3,null_noise,ctf_mse_enhancer )

                estimated_CTF = ctf_mse_enhancer
                print "Disabled CTF MSE enhancer"

            if options.logcir:
                ifft2 = fft_blocks.fft_vcc(total_subc, False, [], True)
                self.connect(estimated_CTF, ifft2,
                             gr.null_sink(gr.sizeof_gr_complex * total_subc))
                summ2 = ofdm.vector_sum_vcc(total_subc)
                c2m2 = gr.complex_to_mag(total_subc)
                self.connect(estimated_CTF, summ2,
                             gr.null_sink(gr.sizeof_gr_complex))
                self.connect(estimated_CTF, c2m2,
                             gr.null_sink(gr.sizeof_float * total_subc))
                log_to_file(self, ifft2, "data/CIR2.compl")
                log_to_file(self, summ2, "data/CTFsumm2.compl")
                log_to_file(self, estimated_CTF, "data/CTF2.compl")
                log_to_file(self, c2m2, "data/CTFmag2.float")

            ## Postprocess the CTF estimate
            ## CTF -> inverse CTF (for equalizer)
            ## CTF -> norm |.|^2 (for CTF display)
            ctf_postprocess = ofdm.fbmc_postprocess_CTF_estimate(total_subc)

            self.connect(help2, ctf_postprocess)
            #estimated_SNR = ( ctf_postprocess, 0 )
            disp_CTF = (ctf_postprocess, 0)
            #self.connect(estimated_SNR,out_snr_pream)
            #log_to_file( self, estimated_SNR, "data/fbmc_SNR.float" )

            #Disable measured SNR output
            #terminate_stream(self, estimated_SNR)
            #self.connect(blocks.vector_source_f([10.0],True) ,out_snr_pream)


#     if options.disable_equalization or options.ideal:
#       terminate_stream(self, inv_estimated_CTF)
#       inv_estimated_CTF_vec = blocks.vector_source_c([1.0/fft_length*math.sqrt(total_subc)]*total_subc,True,total_subc)
#       inv_estimated_CTF_str = blocks.vector_to_stream(gr.sizeof_gr_complex, total_subc)
#       self.inv_estimated_CTF_mul = ofdm.multiply_const_ccf( 1.0/config.rms_amplitude )
#       #inv_estimated_CTF_mul.set_k(1.0/config.rms_amplitude)
#       inv_estimated_CTF = blocks.stream_to_vector(gr.sizeof_gr_complex, total_subc)
#       self.connect( inv_estimated_CTF_vec, inv_estimated_CTF_str, self.inv_estimated_CTF_mul, inv_estimated_CTF)
#       print "Disabled equalization stage"
        '''
    ## LMS Phase tracking
    ## Track residual frequency offset and sampling clock frequency offset

    nondata_blocks = []
    for i in range(config.frame_length):
      if i in config.training_data.pilotsym_pos:
        nondata_blocks.append(i)
        
    print"\t\t\t\t\tnondata_blocks=",nondata_blocks
    pilot_subc = block_header.pilot_tones
    pilot_subcarriers = block_header.pilot_subc_sym
    print "PILOT SUBCARRIERS: ", pilot_subcarriers
        
    phase_tracking = ofdm.lms_phase_tracking_03( total_subc, pilot_subc,
                                               nondata_blocks, pilot_subcarriers,0 )
    self.connect( ofdm_blocks, ( phase_tracking, 0 ) )
    self.connect( inv_estimated_CTF, ( phase_tracking, 1 ) )
    self.connect( frame_start, ( phase_tracking, 2 ) ) ##
    
    if options.scatter_plot_before_phase_tracking:
      self.before_phase_tracking = equalizer
      
    
    if options.disable_phase_tracking or options.ideal:
      terminate_stream(self, phase_tracking)
      print "Disabled phase tracking stage"
    else:
      ofdm_blocks = phase_tracking
    '''
        ## Channel Equalizer
        ##equalizer = ofdm.channel_equalizer( total_subc )
        ##self.connect( ofdm_blocks,       ( equalizer, 0 ) )
        ##self.connect( inv_estimated_CTF, ( equalizer, 1 ) )
        ##self.connect( frame_start,       ( equalizer, 2 ) )
        ##ofdm_blocks = equalizer
        #log_to_file(self, equalizer,"data/equalizer_siso.compl")

        #log_to_file(self, ofdm_blocks, "data/equalizer.compl")

        ## LMS Phase tracking
        ## Track residual frequency offset and sampling clock frequency offset

        nondata_blocks = []
        for i in range(config.frame_length):
            if i in config.training_data.pilotsym_pos:
                nondata_blocks.append(i)

        print "\t\t\t\t\tnondata_blocks=", nondata_blocks
        pilot_subc = block_header.pilot_tones
        pilot_subcarriers = block_header.pilot_subc_sym
        print "PILOT SUBCARRIERS: ", pilot_subcarriers

        if options.scatter_plot_before_phase_tracking:
            self.before_phase_tracking = equalizer

        ## Output connections

        self.connect(ofdm_blocks, out_ofdm_blocks)
        self.connect(frame_start, out_frame_start)
        if options.ideal is False and options.ideal2 is False:
            self.connect(disp_CTF, out_disp_ctf)
        else:
            self.connect(blocks.vector_source_f([1.0] * total_subc),
                         blocks.stream_to_vector(gr.sizeof_float, total_subc),
                         out_disp_ctf)

        if log:
            log_to_file(self, sc_metric, "data/sc_metric.float")
            log_to_file(self, gi_metric, "data/gi_metric.float")
            log_to_file(self, morelli_foe, "data/morelli_foe.float")
            log_to_file(self, lms_fir, "data/lms_fir.float")
            log_to_file(self, sampler_preamble, "data/preamble.compl")
            log_to_file(self, sync, "data/sync.compl")
            log_to_file(self, frequency_shift, "data/frequency_shift.compl")
            log_to_file(self, fft, "data/fft.compl")
            log_to_file(self, fft, "data/fft.float", mag=True)

            if vars().has_key('subcarrier_mask'):
                log_to_file(self, subcarrier_mask,
                            "data/subcarrier_mask.compl")

            log_to_file(self, ofdm_blocks, "data/ofdm_blocks_out.compl")
            log_to_file(self,
                        frame_start,
                        "data/frame_start.float",
                        char_to_float=True)

            log_to_file(self, sampled_chest_preamble,
                        "data/sampled_chest_preamble.compl")
            log_to_file(self, LS_channel_estimator,
                        "data/ls_channel_estimator.compl")
            log_to_file(self,
                        LS_channel_estimator,
                        "data/ls_channel_estimator.float",
                        mag=True)

            if "ctf_mse_enhancer" in locals():
                log_to_file(self, ctf_mse_enhancer,
                            "data/ctf_mse_enhancer.compl")
                log_to_file(self,
                            ctf_mse_enhancer,
                            "data/ctf_mse_enhancer.float",
                            mag=True)

            log_to_file(self, (ctf_postprocess, 0),
                        "data/inc_estimated_ctf.compl")
            log_to_file(self, (ctf_postprocess, 1), "data/disp_ctf.float")

            log_to_file(self, equalizer, "data/equalizer.compl")
            log_to_file(self, equalizer, "data/equalizer.float", mag=True)

            log_to_file(self, phase_tracking, "data/phase_tracking.compl")
Example #27
0
  def publish_rx_performance_measure(self):
    if self._rx_performance_measure_initialized():
      return

    self.rx_performance_measure_initialized = True

    config = station_configuration()
    vlen = config.data_subcarriers
    vlen_sinr_sc = config.subcarriers

#    self.rx_per_sink = rpsink = rpsink_dummy()

    self.setup_ber_measurement()
    self.setup_snr_measurement()
    self.setup_snr_measurement_2()

    ber_mst = self._ber_measuring_tool
    if self._options.sinr_est:
        sinr_mst = self._sinr_measurement
        sinr_mst_2 = self._sinr_measurement_2
    else:
        snr_mst = self._snr_measurement
        snr_mst_2 = self._snr_measurement_2

    # 1. frame id

    # 2. channel transfer function
    ctf = self.filter_ctf()
    ctf_2 = self.filter_ctf_2()
    
    self.zmq_probe_ctf = zeromq.pub_sink(gr.sizeof_float,config.data_subcarriers, "tcp://*:5559")
    self.zmq_probe_ctf_2 = zeromq.pub_sink(gr.sizeof_float,config.data_subcarriers, "tcp://*:5558")
    self.connect(ctf, blocks.keep_one_in_n(gr.sizeof_float*config.data_subcarriers,20) ,self.zmq_probe_ctf)
    self.connect(ctf_2, blocks.keep_one_in_n(gr.sizeof_float*config.data_subcarriers,20) ,self.zmq_probe_ctf_2)
    
    # 3. BER
    ### FIXME HACK


    print "Normal BER measurement"


    trig_src = dynamic_trigger_ib(False)
    self.connect(self.bitcount_src,trig_src)

    ber_sampler = vector_sampler(gr.sizeof_float,1)
    self.connect(ber_mst,(ber_sampler,0))
    self.connect(trig_src,(ber_sampler,1))
      
    if self._options.log:
          trig_src_float = gr.char_to_float()
          self.connect(trig_src,trig_src_float)
          log_to_file(self, trig_src_float , 'data/dynamic_trigger_out.float')


    if self._options.sinr_est is False:
          self.zmq_probe_ber = zeromq.pub_sink(gr.sizeof_float, 1, "tcp://*:5556")
          self.connect(ber_sampler,blocks.keep_one_in_n(gr.sizeof_float,20) ,self.zmq_probe_ber)

          self.zmq_probe_snr = zeromq.pub_sink(gr.sizeof_float, 1, "tcp://*:5555")
          self.connect(snr_mst,blocks.keep_one_in_n(gr.sizeof_float,20) ,self.zmq_probe_snr)
          
          self.zmq_probe_snr_2 = zeromq.pub_sink(gr.sizeof_float, 1, "tcp://*:5554")
          self.connect(snr_mst_2,blocks.keep_one_in_n(gr.sizeof_float,20) ,self.zmq_probe_snr_2)
Example #28
0
    def __init__(self, options, log=False):

        ## Read configuration
        config = station_configuration()

        fft_length = config.fft_length
        cp_length = config.cp_length
        block_header = config.training_data
        data_subc = config.data_subcarriers
        virtual_subc = config.virtual_subcarriers
        total_subc = config.subcarriers
        block_length = config.block_length
        frame_length = config.frame_length
        dc_null = config.dc_null

        L = block_header.mm_periodic_parts

        ## Set Input/Output signature
        gr.hier_block2.__init__(
            self,
            "ofdm_inner_receiver",
            gr.io_signature(1, 1, gr.sizeof_gr_complex),
            gr.io_signaturev(
                4,
                4,
                [
                    gr.sizeof_gr_complex * total_subc,  # OFDM blocks
                    gr.sizeof_char,  # Frame start
                    gr.sizeof_float * total_subc,
                    gr.sizeof_float
                ]))  # Normalized |CTF|^2

        ## Input and output ports
        self.input = rx_input = self

        out_ofdm_blocks = (self, 0)
        out_frame_start = (self, 1)
        out_disp_ctf = (self, 2)
        out_disp_cfo = (self, 3)

        ## pre-FFT processing
        if options.ideal is False and options.ideal2 is False:
            if options.old_receiver is False:
                ## Compute autocorrelations for S&C preamble
                ## and cyclic prefix

                self._sc_metric = sc_metric = autocorrelator(
                    fft_length / 2, fft_length / 2)
                self._gi_metric = gi_metric = autocorrelator(
                    fft_length, cp_length)

                self.connect(rx_input, sc_metric)
                self.connect(rx_input, gi_metric)

                ## Sync. Output contains OFDM blocks
                sync = ofdm.time_sync(fft_length, cp_length)
                self.connect(rx_input, (sync, 0))
                self.connect(sc_metric, (sync, 1))
                self.connect(gi_metric, (sync, 2))
                ofdm_blocks = (sync, 0)
                frame_start = (sync, 1)
                #log_to_file( self, ( sync, 1 ), "data/peak_detector.char" )
            else:

                #Testing old/new metric
                self.tm = schmidl.recursive_timing_metric(fft_length)
                self.connect(self.input, self.tm)
                #log_to_file( self, self.tm, "data/rec_sc_metric_ofdm.float" )

                timingmetric_shift = -2  #int(-cp_length/4)# 0#-2 #int(-cp_length * 0.8)
                tmfilter = filter.fft_filter_fff(1,
                                                 [1. / cp_length] * cp_length)
                self.connect(self.tm, tmfilter)
                self.tm = tmfilter

                self._pd_thres = 0.3
                self._pd_lookahead = fft_length / 2  # empirically chosen
                peak_detector = ofdm.peak_detector_02_fb(
                    self._pd_lookahead, self._pd_thres)
                self.connect(self.tm, peak_detector)
                #log_to_file( self, peak_detector, "data/rec_peak_detector.char" )

                frame_start = [0] * frame_length
                frame_start[0] = 1
                frame_start = self.frame_trigger_old = blocks.vector_source_b(
                    frame_start, True)

                delayed_timesync = blocks.delay(
                    gr.sizeof_char,
                    (frame_length - 1) * block_length + timingmetric_shift)
                self.connect(peak_detector, delayed_timesync)

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

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

                # TODO: dynamic solution
                vt2s = blocks.vector_to_stream(
                    gr.sizeof_gr_complex * block_length, frame_length)
                self.connect(self.block_sampler, vt2s, self.discard_cp)
                #terminate_stream(self,ofdm_blocks)
                ofdm_blocks = self.discard_cp
#     else:
#       serial_to_parallel = blocks.stream_to_vector(gr.sizeof_gr_complex,block_length)
#       discard_cp = ofdm.vector_mask(block_length,cp_length,fft_length,[])
#       ofdm_blocks = discard_cp
#       self.connect( rx_input, serial_to_parallel, discard_cp )
#       frame_start = [0]*frame_length
#       frame_start[0] = 1
#       frame_start = blocks.vector_source_b(frame_start,True)
#
#       print "Disabled time synchronization stage"

## Compute autocorrelations for S&C preamble
## and cyclic prefix

#log_to_file( self, sc_metric, "data/sc_metric_ofdm.float" )
#log_to_file(self, frame_start, "data/frame_start.compl")

#    log_to_file(self,ofdm_blocks,"data/ofdm_blocks_original.compl")

        if options.disable_time_sync or options.ideal or options.ideal2:
            if options.ideal is False and options.ideal2 is False:
                terminate_stream(self, ofdm_blocks)
                terminate_stream(self, frame_start)

            serial_to_parallel = blocks.stream_to_vector(
                gr.sizeof_gr_complex, block_length)
            discard_cp = ofdm.vector_mask_dc_null(block_length, cp_length,
                                                  fft_length, dc_null, [])
            ofdm_blocks = discard_cp
            self.connect(rx_input, serial_to_parallel, discard_cp)

            frame_start = [0] * frame_length
            frame_start[0] = 1
            frame_start = blocks.vector_source_b(frame_start, True)

            print "Disabled time synchronization stage"

        print "\t\t\t\t\tframe_length = ", frame_length

        if options.ideal is False and options.ideal2 is False:
            ## Extract preamble, feed to Morelli & Mengali frequency offset estimator
            assert (block_header.mm_preamble_pos == 0)
            morelli_foe = ofdm.mm_frequency_estimator(fft_length, L, 1, 0)
            sampler_preamble = ofdm.vector_sampler(
                gr.sizeof_gr_complex * fft_length, 1)
            self.connect(ofdm_blocks, (sampler_preamble, 0))
            self.connect(frame_start, (sampler_preamble, 1))
            self.connect(sampler_preamble, morelli_foe)
            freq_offset = morelli_foe

            ## Adaptive LMS FIR filtering of frequency offset
            lms_fir = ofdm.lms_fir_ff(20,
                                      1e-3)  # TODO: verify parameter choice
            self.connect(freq_offset, lms_fir)
            freq_offset = lms_fir

            #self.zmq_probe_freqoff = zeromq.pub_sink(gr.sizeof_float, 1, "tcp://*:5557")
            self.connect(lms_fir, blocks.keep_one_in_n(gr.sizeof_float, 20),
                         out_disp_cfo)
        else:
            self.connect(blocks.vector_source_f([1]), out_disp_cfo)

            #log_to_file(self, lms_fir, "data/lms_fir.float")

        if options.disable_freq_sync or options.ideal or options.ideal2:
            if options.ideal is False and options.ideal2 is False:
                terminate_stream(self, freq_offset)
                freq_offset = blocks.vector_source_f([0.0], True)
            print "Disabled frequency synchronization stage"

        if options.ideal is False and options.ideal2 is False:
            ## Correct frequency shift, feed-forward structure
            frequency_shift = ofdm.frequency_shift_vcc(fft_length,
                                                       -1.0 / fft_length,
                                                       cp_length)
            self.connect(ofdm_blocks, (frequency_shift, 0))
            self.connect(freq_offset, (frequency_shift, 1))
            self.connect(frame_start, (frequency_shift, 2))
            ofdm_blocks = frequency_shift

        ## FFT
        fft = fft_blocks.fft_vcc(fft_length, True, [], True)
        self.connect(ofdm_blocks, fft)
        ofdm_blocks = fft
        #log_to_file( self, fft, "data/compen.float" )

        ## Remove virtual subcarriers
        if fft_length > data_subc:
            subcarrier_mask = ofdm.vector_mask_dc_null(fft_length,
                                                       virtual_subc / 2,
                                                       total_subc, dc_null, [])
            self.connect(ofdm_blocks, subcarrier_mask)
            ofdm_blocks = subcarrier_mask
            #log_to_file(self, ofdm_blocks, "data/vec_mask.compl")
            ## Least Squares estimator for channel transfer function (CTF)

            if options.logcir:
                log_to_file(self, ofdm_blocks, "data/OFDM_Blocks.compl")

                inv_preamble_fd = numpy.array(block_header.pilotsym_fd[
                    block_header.channel_estimation_pilot[0]])
                inv_preamble_fd = numpy.concatenate([
                    inv_preamble_fd[:total_subc / 2],
                    inv_preamble_fd[total_subc / 2 + dc_null:]
                ])
                #print "Channel estimation pilot: ", inv_preamble_fd
                inv_preamble_fd = 1. / inv_preamble_fd
                LS_channel_estimator0 = ofdm.multiply_const_vcc(
                    list(inv_preamble_fd))
                self.connect(ofdm_blocks, LS_channel_estimator0,
                             gr.null_sink(gr.sizeof_gr_complex * total_subc))
                log_to_file(self, LS_channel_estimator0,
                            "data/OFDM_Blocks_eq.compl")

        ## post-FFT processing

        ## extract channel estimation preamble from frame
        if options.ideal is False and options.ideal2 is False:
            chest_pre_trigger = blocks.delay(gr.sizeof_char, 1)
            sampled_chest_preamble = ofdm.vector_sampler(
                gr.sizeof_gr_complex * total_subc, 1)
            self.connect(frame_start, chest_pre_trigger)
            self.connect(chest_pre_trigger, (sampled_chest_preamble, 1))
            self.connect(ofdm_blocks, (sampled_chest_preamble, 0))

            ## Least Squares estimator for channel transfer function (CTF)
            inv_preamble_fd = numpy.array(block_header.pilotsym_fd[
                block_header.channel_estimation_pilot[0]])
            inv_preamble_fd = numpy.concatenate([
                inv_preamble_fd[:total_subc / 2],
                inv_preamble_fd[total_subc / 2 + dc_null:]
            ])
            #print "Channel estimation pilot: ", inv_preamble_fd
            inv_preamble_fd = 1. / inv_preamble_fd

            LS_channel_estimator = ofdm.multiply_const_vcc(
                list(inv_preamble_fd))
            self.connect(sampled_chest_preamble, LS_channel_estimator)
            estimated_CTF = LS_channel_estimator

            if options.logcir:
                log_to_file(self, sampled_chest_preamble, "data/PREAM.compl")

            if not options.disable_ctf_enhancer:

                if options.logcir:
                    ifft1 = fft_blocks.fft_vcc(total_subc, False, [], True)
                    self.connect(
                        estimated_CTF, ifft1,
                        gr.null_sink(gr.sizeof_gr_complex * total_subc))
                    summ1 = ofdm.vector_sum_vcc(total_subc)
                    c2m = gr.complex_to_mag(total_subc)
                    self.connect(estimated_CTF, summ1,
                                 gr.null_sink(gr.sizeof_gr_complex))
                    self.connect(estimated_CTF, c2m,
                                 gr.null_sink(gr.sizeof_float * total_subc))
                    log_to_file(self, ifft1, "data/CIR1.compl")
                    log_to_file(self, summ1, "data/CTFsumm1.compl")
                    log_to_file(self, estimated_CTF, "data/CTF1.compl")
                    log_to_file(self, c2m, "data/CTFmag1.float")

                ## MSE enhancer
                ctf_mse_enhancer = ofdm.CTF_MSE_enhancer(
                    total_subc, cp_length + cp_length)
                self.connect(estimated_CTF, ctf_mse_enhancer)
                #      log_to_file( self, ctf_mse_enhancer, "data/ctf_mse_enhancer_original.compl")
                #ifft3 = fft_blocks.fft_vcc(total_subc,False,[],True)
                #null_noise = ofdm.noise_nulling(total_subc, cp_length + cp_length)
                #ctf_mse_enhancer = fft_blocks.fft_vcc(total_subc,True,[],True)
                #ctf_mse_enhancer = ofdm.vector_mask( fft_length, virtual_subc/2,
                # total_subc, [] )
                #self.connect( estimated_CTF, ifft3,null_noise,ctf_mse_enhancer )

                estimated_CTF = ctf_mse_enhancer
                print "Disabled CTF MSE enhancer"

            if options.logcir:
                ifft2 = fft_blocks.fft_vcc(total_subc, False, [], True)
                self.connect(estimated_CTF, ifft2,
                             gr.null_sink(gr.sizeof_gr_complex * total_subc))
                summ2 = ofdm.vector_sum_vcc(total_subc)
                c2m2 = gr.complex_to_mag(total_subc)
                self.connect(estimated_CTF, summ2,
                             gr.null_sink(gr.sizeof_gr_complex))
                self.connect(estimated_CTF, c2m2,
                             gr.null_sink(gr.sizeof_float * total_subc))
                log_to_file(self, ifft2, "data/CIR2.compl")
                log_to_file(self, summ2, "data/CTFsumm2.compl")
                log_to_file(self, estimated_CTF, "data/CTF2.compl")
                log_to_file(self, c2m2, "data/CTFmag2.float")

        ## Postprocess the CTF estimate
        ## CTF -> inverse CTF (for equalizer)
        ## CTF -> norm |.|^2 (for CTF display)
            ctf_postprocess = ofdm.postprocess_CTF_estimate(total_subc)
            self.connect(estimated_CTF, ctf_postprocess)
            inv_estimated_CTF = (ctf_postprocess, 0)
            disp_CTF = (ctf_postprocess, 1)


#     if options.disable_equalization or options.ideal:
#       terminate_stream(self, inv_estimated_CTF)
#       inv_estimated_CTF_vec = blocks.vector_source_c([1.0/fft_length*math.sqrt(total_subc)]*total_subc,True,total_subc)
#       inv_estimated_CTF_str = blocks.vector_to_stream(gr.sizeof_gr_complex, total_subc)
#       self.inv_estimated_CTF_mul = ofdm.multiply_const_ccf( 1.0/config.rms_amplitude )
#       #inv_estimated_CTF_mul.set_k(1.0/config.rms_amplitude)
#       inv_estimated_CTF = blocks.stream_to_vector(gr.sizeof_gr_complex, total_subc)
#       self.connect( inv_estimated_CTF_vec, inv_estimated_CTF_str, self.inv_estimated_CTF_mul, inv_estimated_CTF)
#       print "Disabled equalization stage"
        '''
    ## LMS Phase tracking
    ## Track residual frequency offset and sampling clock frequency offset

    nondata_blocks = []
    for i in range(config.frame_length):
      if i in config.training_data.pilotsym_pos:
        nondata_blocks.append(i)
        
    print"\t\t\t\t\tnondata_blocks=",nondata_blocks
    pilot_subc = block_header.pilot_tones
    pilot_subcarriers = block_header.pilot_subc_sym
    print "PILOT SUBCARRIERS: ", pilot_subcarriers
        
    phase_tracking = ofdm.lms_phase_tracking_03( total_subc, pilot_subc,
                                               nondata_blocks, pilot_subcarriers,0 )
    self.connect( ofdm_blocks, ( phase_tracking, 0 ) )
    self.connect( inv_estimated_CTF, ( phase_tracking, 1 ) )
    self.connect( frame_start, ( phase_tracking, 2 ) ) ##
    
    if options.scatter_plot_before_phase_tracking:
      self.before_phase_tracking = equalizer
      
    
    if options.disable_phase_tracking or options.ideal:
      terminate_stream(self, phase_tracking)
      print "Disabled phase tracking stage"
    else:
      ofdm_blocks = phase_tracking
    '''
        ## Channel Equalizer
        if options.disable_equalization or options.ideal or options.ideal2:
            print "Disabled equalization stage"
            if options.ideal is False and options.ideal2 is False:
                terminate_stream(self, inv_estimated_CTF)
        else:
            equalizer = ofdm.channel_equalizer(total_subc)
            self.connect(ofdm_blocks, (equalizer, 0))
            self.connect(inv_estimated_CTF, (equalizer, 1))
            self.connect(frame_start, (equalizer, 2))
            ofdm_blocks = equalizer
        #log_to_file(self, equalizer,"data/equalizer_siso.compl")

        #log_to_file(self, ofdm_blocks, "data/equalizer.compl")

        ## LMS Phase tracking
        ## Track residual frequency offset and sampling clock frequency offset
        if options.ideal is False and options.ideal2 is False:
            nondata_blocks = []
            for i in range(config.frame_length):
                if i in config.training_data.pilotsym_pos:
                    nondata_blocks.append(i)

            print "\t\t\t\t\tnondata_blocks=", nondata_blocks
            pilot_subc = block_header.pilot_tones
            pilot_subcarriers = block_header.pilot_subc_sym
            print "PILOT SUBCARRIERS: ", pilot_subcarriers

            phase_tracking2 = ofdm.lms_phase_tracking_dc_null(
                total_subc, pilot_subc, nondata_blocks, pilot_subcarriers,
                dc_null)
            self.connect(ofdm_blocks, (phase_tracking2, 0))
            self.connect(frame_start, (phase_tracking2, 1))  ##

        if options.disable_phase_tracking or options.ideal or options.ideal2:
            if options.ideal is False and options.ideal2 is False:
                terminate_stream(self, phase_tracking2)
            print "Disabled phase tracking stage"
        else:
            ofdm_blocks = phase_tracking2

        if options.scatter_plot_before_phase_tracking:
            self.before_phase_tracking = equalizer

        ## Output connections

        self.connect(ofdm_blocks, out_ofdm_blocks)
        self.connect(frame_start, out_frame_start)
        if options.ideal is False and options.ideal2 is False:
            self.connect(disp_CTF, out_disp_ctf)
        else:
            self.connect(blocks.vector_source_f([1.0] * total_subc),
                         blocks.stream_to_vector(gr.sizeof_float, total_subc),
                         out_disp_ctf)

        if log:
            log_to_file(self, sc_metric, "data/sc_metric.float")
            log_to_file(self, gi_metric, "data/gi_metric.float")
            log_to_file(self, morelli_foe, "data/morelli_foe.float")
            log_to_file(self, lms_fir, "data/lms_fir.float")
            log_to_file(self, sampler_preamble, "data/preamble.compl")
            log_to_file(self, sync, "data/sync.compl")
            log_to_file(self, frequency_shift, "data/frequency_shift.compl")
            log_to_file(self, fft, "data/fft.compl")
            log_to_file(self, fft, "data/fft.float", mag=True)

            if vars().has_key('subcarrier_mask'):
                log_to_file(self, subcarrier_mask,
                            "data/subcarrier_mask.compl")

            log_to_file(self, ofdm_blocks, "data/ofdm_blocks_out.compl")
            log_to_file(self,
                        frame_start,
                        "data/frame_start.float",
                        char_to_float=True)

            log_to_file(self, sampled_chest_preamble,
                        "data/sampled_chest_preamble.compl")
            log_to_file(self, LS_channel_estimator,
                        "data/ls_channel_estimator.compl")
            log_to_file(self,
                        LS_channel_estimator,
                        "data/ls_channel_estimator.float",
                        mag=True)

            if "ctf_mse_enhancer" in locals():
                log_to_file(self, ctf_mse_enhancer,
                            "data/ctf_mse_enhancer.compl")
                log_to_file(self,
                            ctf_mse_enhancer,
                            "data/ctf_mse_enhancer.float",
                            mag=True)

            log_to_file(self, (ctf_postprocess, 0),
                        "data/inc_estimated_ctf.compl")
            log_to_file(self, (ctf_postprocess, 1), "data/disp_ctf.float")

            log_to_file(self, equalizer, "data/equalizer.compl")
            log_to_file(self, equalizer, "data/equalizer.float", mag=True)

            log_to_file(self, phase_tracking, "data/phase_tracking.compl")
  def __init__( self, 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 #30
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"
Example #31
0
  def publish_rx_performance_measure(self):
    if self._rx_performance_measure_initialized():
      return

    self.rx_performance_measure_initialized = True

    config = station_configuration()
    vlen = config.data_subcarriers
    vlen_sinr_sc = config.subcarriers

    if self.ideal2 is False:
        self.setup_ber_measurement()
        self.setup_snr_measurement()
        ber_mst = self._ber_measuring_tool
    
    if self._options.sinr_est:
        sinr_mst = self._sinr_measurement
    else:
        if self.ideal2 is False:
            snr_mst = self._snr_measurement

    if self.ideal is False and self.ideal2 is False:
        self.ctf = self.filter_ctf()
        self.zmq_probe_ctf = zeromq.pub_sink(gr.sizeof_float,config.data_subcarriers, "tcp://*:5559")
        self.connect(self.ctf, blocks.keep_one_in_n(gr.sizeof_float*config.data_subcarriers,20) ,self.zmq_probe_ctf)
    else:
        #self.zmq_probe_ctf = zeromq.pub_sink(gr.sizeof_float,config.subcarriers, "tcp://*:5559")
        self.connect(self.ctf,blocks.null_sink(gr.sizeof_float*config.subcarriers))
        #self.rx_per_sink = rpsink = corba_rxinfo_sink("himalaya",config.ns_ip,
#                                    config.ns_port,vlen,config.rx_station_id)



#      print "BER img xfer"
#      self.connect(ber_mst,(rpsink,3))
#      ## no sampling needed
      # 3. SNR

    if self.ideal2 is False:
        print "Normal BER measurement"
    
        trig_src = dynamic_trigger_ib(False)
        self.connect(self.bitcount_src,trig_src)
        
        ber_sampler = vector_sampler(gr.sizeof_float,1)
        self.connect(ber_mst,(ber_sampler,0))
        self.connect(trig_src,(ber_sampler,1))
    else:
        if(self._options.coding):
            demod = self._data_decoder
        else:
            demod = self._data_demodulator
        self.connect(self.bitcount_src,blocks.null_sink(gr.sizeof_int) )
        self.connect(demod,blocks.null_sink(gr.sizeof_char))
    
    
    if self._options.log:
          trig_src_float = gr.char_to_float()
          self.connect(trig_src,trig_src_float)
          log_to_file(self, trig_src_float , 'data/dynamic_trigger_out.float')
    
    
    if self._options.sinr_est is False and self.ideal2 is False:
          self.zmq_probe_ber = zeromq.pub_sink(gr.sizeof_float, 1, "tcp://*:5556")
          self.connect(ber_sampler,blocks.keep_one_in_n(gr.sizeof_float,20) ,self.zmq_probe_ber)
    
          if self.ideal2 is False:
              self.zmq_probe_snr = zeromq.pub_sink(gr.sizeof_float, 1, "tcp://*:5555")
              self.connect(snr_mst,blocks.keep_one_in_n(gr.sizeof_float,20) ,self.zmq_probe_snr)
Example #32
0
  def __init__( self, options, log = False ):
    
    ## Read configuration
    config = station_configuration()
    
    fft_length    = config.fft_length
    cp_length     = config.cp_length
    block_header  = config.training_data
    data_subc     = config.data_subcarriers
    virtual_subc  = config.virtual_subcarriers
    total_subc    = config.subcarriers
    block_length  = config.block_length
    frame_length  = config.frame_length
    
    L             = block_header.mm_periodic_parts
    
    frame_data_blocks    = options.data_blocks
    
    
    ## Set Input/Output signature
    gr.hier_block2.__init__( self, 
        "ofdm_inner_receiver",
        gr.io_signature(
            1, 1,
            gr.sizeof_gr_complex ),
        gr.io_signature4(
            4, 4,
            gr.sizeof_gr_complex * total_subc,    # OFDM blocks
            gr.sizeof_char,                       # Frame start
            gr.sizeof_float * total_subc,         # Normalized |CTF|^2
            gr.sizeof_float * total_subc ) )      # Normalized |CTF|^2
    
    
    ## Input and output ports
    self.input  = rx_input = (self,0)

    
    out_ofdm_blocks = ( self, 0 )
    out_frame_start = ( self, 1 )
    out_disp_ctf    = ( self, 2 )
    out_disp_ctf2    = ( self, 3 )
    
    ## pre-FFT processing
    
    
    ## Compute autocorrelations for S&C preamble
    ## and cyclic prefix
    sc_metric = autocorrelator( fft_length/2, fft_length/2 )
    gi_metric = autocorrelator( fft_length, cp_length )
    
    self.connect( rx_input, sc_metric )
    self.connect( rx_input, gi_metric )
    
    ## Sync. Output contains OFDM blocks
    sync = ofdm.time_sync( fft_length, cp_length )
    self.connect( rx_input, ( sync, 0 ) )
    self.connect( sc_metric, ( sync, 1 ) )
    self.connect( gi_metric, ( sync, 2 ) )
    ofdm_blocks = ( sync, 0 )
    frame_start = ( sync, 1 )
    
    if options.disable_time_sync or options.ideal:
      terminate_stream(self, ofdm_blocks)
      terminate_stream(self, frame_start)
      
      serial_to_parallel = blocks.stream_to_vector(gr.sizeof_gr_complex,block_length)
      discard_cp = ofdm.vector_mask(block_length,cp_length,fft_length,[])
      ofdm_blocks = discard_cp
      self.connect( rx_input, serial_to_parallel, discard_cp )
      
      frame_start = [0]*frame_length
      frame_start[0] = 1
      frame_start = blocks.vector_source_b(frame_start,True)
      
      print "Disabled time synchronization stage"
    
    
    
    ## Extract preamble, feed to Morelli & Mengali frequency offset estimator
    assert( block_header.mm_preamble_pos == 0 )
    morelli_foe = ofdm.mm_frequency_estimator( fft_length, L )
    sampler_preamble = ofdm.vector_sampler( gr.sizeof_gr_complex * fft_length,
                                            1 )
    self.connect( ofdm_blocks, ( sampler_preamble, 0 ) )
    self.connect( frame_start, ( sampler_preamble, 1 ) )
    self.connect( sampler_preamble, morelli_foe )
    freq_offset = morelli_foe
    
    
    
    ## Adaptive LMS FIR filtering of frequency offset
    lms_fir = ofdm.lms_fir_ff( 20, 1e-3 ) # TODO: verify parameter choice
    self.connect( freq_offset, lms_fir )
    freq_offset = lms_fir
    log_to_file(self, lms_fir, "data/foe_21.float")
    
#    log_to_file(self, lms_fir, "data/lms_fir.float")
#    log_to_file(self, lms_fir2, "data/lms_fir2.float")
    
    if options.disable_freq_sync or options.ideal:
       terminate_stream(self, freq_offset)
       freq_offset = blocks.vector_source_f([0.0],True)
       print "Disabled frequency synchronization stage"
    
    ## Correct frequency shift, feed-forward structure
    frequency_shift = ofdm.frequency_shift_vcc( fft_length, -1.0/fft_length,
                                                cp_length )
    self.connect( ofdm_blocks, ( frequency_shift, 0 ) )
    self.connect( freq_offset, ( frequency_shift, 1 ) )
    self.connect( frame_start, ( frequency_shift, 2 ) )
    ofdm_blocks = frequency_shift
    
    
    ## FFT
    fft = fft_blocks.fft_vcc( fft_length, True, [], True )
    self.connect( ofdm_blocks, fft )
    ofdm_blocks = fft
    
    ## Remove virtual subcarriers
    if fft_length > data_subc:
      subcarrier_mask = ofdm.vector_mask( fft_length, virtual_subc/2,
                                           total_subc, [] )
      self.connect( ofdm_blocks, subcarrier_mask )
      ofdm_blocks = subcarrier_mask
      
       ## Least Squares estimator for channel transfer function (CTF)
    
    
      # if options.logcir:
          # log_to_file( self, ofdm_blocks, "data/OFDM_Blocks.compl" )
          
          # inv_preamble_fd = numpy.array( block_header.pilotsym_fd[ 
            # block_header.channel_estimation_pilot[0] ] )
          # print "Channel estimation pilot: ", inv_preamble_fd
          # inv_preamble_fd = 1. / inv_preamble_fd
          # LS_channel_estimator0 = ofdm.multiply_const_vcc( list( inv_preamble_fd ) )
          # self.connect( ofdm_blocks, LS_channel_estimator0, blocks.null_sink(gr.sizeof_gr_complex*total_subc))
          # log_to_file( self, LS_channel_estimator0, "data/OFDM_Blocks_eq.compl" )
          
    ## post-FFT processing
      
    
    
    ## extract channel estimation preamble from frame
    
    if options.est_preamble==1:
        chest_pre_trigger = blocks.delay( gr.sizeof_char, 
                                      1 )
        sampled_chest_preamble = \
          ofdm.vector_sampler( gr.sizeof_gr_complex * total_subc, 1 )
        self.connect( frame_start,       chest_pre_trigger )
        self.connect( chest_pre_trigger, ( sampled_chest_preamble, 1 ) )
        self.connect( ofdm_blocks,       ( sampled_chest_preamble, 0 ) )
        
        
        ## Least Squares estimator for channel transfer function (CTF)
        
        # Taking inverse for estimating h11 (h12)
        inv_preamble_fd_1 = numpy.array( block_header.pilotsym_fd_1[ 
            block_header.channel_estimation_pilot[0] ] )
        print "inv_preamble_fd_1: ",inv_preamble_fd_1
        inv_preamble_fd_1 = inv_preamble_fd_1[0::2]
        #print "inv_preamble_fd_1 ", inv_preamble_fd_1
        
        # Taking inverse for estimating h21 (h22)
        inv_preamble_fd_2 = numpy.array( block_header.pilotsym_fd_2[ 
            block_header.channel_estimation_pilot[0] ] )
        print "inv_preamble_fd_2: ",inv_preamble_fd_2
        inv_preamble_fd_2 = inv_preamble_fd_2[1::2]
        #print "inv_preamble_fd_2 ", inv_preamble_fd_2
        
        print "inv_preamble_fd_1: ",inv_preamble_fd_1
        print "inv_preamble_fd_2: ",inv_preamble_fd_2
        
        
        inv_preamble_fd_1 = 1. / inv_preamble_fd_1
        inv_preamble_fd_2 = 1. / inv_preamble_fd_2
        
        dd = []
        for i in range (total_subc/2):
            dd.extend([i*2])
            
        skip_block_1 = ofdm.int_skip(total_subc,2,0)
        skip_block_2 = ofdm.int_skip(total_subc,2,1)
    #    inta_estim_1 = ofdm.interpolator(total_subc,2,dd)
    #    inta_estim_2 = ofdm.interpolator(total_subc,2,dd)
        
        LS_channel_estimator_1 = ofdm.multiply_const_vcc( list( inv_preamble_fd_1 ) )
        LS_channel_estimator_2 = ofdm.multiply_const_vcc( list( inv_preamble_fd_2 ) )
        self.connect( sampled_chest_preamble,skip_block_1, LS_channel_estimator_1)#,inta_estim_1 )
        self.connect( sampled_chest_preamble,skip_block_2, LS_channel_estimator_2)#,inta_estim_2 )
        
        estimated_CTF_1 = LS_channel_estimator_1                  # h0
        estimated_CTF_2 = LS_channel_estimator_2                  # h1              # h3
            
        
        if not options.disable_ctf_enhancer:
          
          # if options.logcir:
            # ifft1 = fft_blocks.fft_vcc(total_subc,False,[],True)
            # self.connect( estimated_CTF, ifft1,blocks.null_sink(gr.sizeof_gr_complex*total_subc))
            # summ1 = ofdm.vector_sum_vcc(total_subc)
            # c2m =gr.complex_to_mag(total_subc)
            # self.connect( estimated_CTF,summ1 ,blocks.null_sink(gr.sizeof_gr_complex))
            # self.connect( estimated_CTF, c2m,blocks.null_sink(gr.sizeof_float*total_subc))
            # log_to_file( self, ifft1, "data/CIR1.compl" )
            # log_to_file( self, summ1, "data/CTFsumm1.compl" )
            # log_to_file( self, estimated_CTF, "data/CTF1.compl" )
            # log_to_file( self, c2m, "data/CTFmag1.float" )
            
          ## MSE enhancer
          ctf_mse_enhancer_1 = ofdm.CTF_MSE_enhancer( total_subc, cp_length + cp_length)
          ctf_mse_enhancer_2 = ofdm.CTF_MSE_enhancer( total_subc, cp_length + cp_length)
          self.connect( estimated_CTF_1, ctf_mse_enhancer_1 )
          self.connect( estimated_CTF_2, ctf_mse_enhancer_2 )
          
            
          estimated_CTF_1 = ctf_mse_enhancer_1
          estimated_CTF_2 = ctf_mse_enhancer_2
          
          print "Disabled CTF MSE enhancer"
        
        ctf_postprocess_1 = ofdm.postprocess_CTF_estimate( total_subc/2 )
        self.connect( estimated_CTF_1, ( ctf_postprocess_1, 0 ) )
        ctf_postprocess_2 = ofdm.postprocess_CTF_estimate( total_subc/2 )
        self.connect( estimated_CTF_2, ( ctf_postprocess_2, 0 ) )
               
        inv_CTF_1 = ( ctf_postprocess_1, 0 )
        disp_CTF_1 = ( ctf_postprocess_1, 1 )
        inv_CTF_2 = ( ctf_postprocess_2, 0 )
        disp_CTF_2 = ( ctf_postprocess_2, 1 )  
    
        disp_CTF_RX0 = blocks.add_ff(total_subc/2)
        
        self.connect ( disp_CTF_1, (disp_CTF_RX0, 0) )
        self.connect ( disp_CTF_2, (disp_CTF_RX0, 1) )
    
    
        terminate_stream(self,disp_CTF_RX0)
        terminate_stream(self,inv_CTF_2)
        
        disp_CTF_RX0 = blocks.null_source(gr.sizeof_float*total_subc)
        disp_CTF_RX1 = blocks.null_source(gr.sizeof_float*total_subc)
        ## Channel Equalizer
        
        #log_to_file(self, ofdm_blocks, "data/vec_mask.compl")
        #log_to_file(self, ofdm_blocks2, "data/vec_mask2.compl")
        
        nondata_blocks = []
        for i in range(config.frame_length):
          if i in config.training_data.pilotsym_pos:
            nondata_blocks.append(i)
            
        pilot_subc = block_header.pilot_tones
        pilot_subcarriers = block_header.pilot_subc_sym
        print "PILOT SUBCARRIERS: ", pilot_subcarriers
        
        phase_tracking = ofdm.lms_phase_tracking_03( total_subc, pilot_subc,
                                                   nondata_blocks,pilot_subcarriers,0 )
       
        
        ##phase_tracking = ofdm.lms_phase_tracking_02( total_subc, pilot_subc,
         ##                                          nondata_blocks )
        ##phase_tracking2 = ofdm.lms_phase_tracking_02( total_subc, pilot_subc,
         ##                                           nondata_blocks )
        
    #    self.connect( ofdm_blocks,          ( phase_tracking, 0 ) )
    #    self.connect( ofdm_blocks2,          ( phase_tracking, 1 ))
    #    self.connect( inv_CTF_1,            ( phase_tracking, 2 ) )
    #    self.connect( inv_CTF_3,            ( phase_tracking, 3 ) )
    #    self.connect( frame_start,            ( phase_tracking, 4 ) )
    #    self.connect( frame_start2,            ( phase_tracking, 5) )
    #    
    #    self.connect( ofdm_blocks2,          ( phase_tracking2, 0 ) )
    #    self.connect( ofdm_blocks,          ( phase_tracking2, 1 ))
    #    self.connect( inv_CTF_3,            ( phase_tracking2, 2 ) )
    #    self.connect( inv_CTF_1,            ( phase_tracking2, 3 ) )
    #    self.connect( frame_start2,            ( phase_tracking2, 4 ) )
    #    self.connect( frame_start,            ( phase_tracking2, 5 ) )
        
        self.connect( ofdm_blocks,          ( phase_tracking, 0 ) )
        self.connect( inv_CTF_1,            ( phase_tracking, 1 ) )
        self.connect( frame_start,            ( phase_tracking, 2 ) )
        
        #self.connect(phase_tracking,blocks.null_sink(gr.sizeof_gr_complex*total_subc))
        
        ofdm_blocks = phase_tracking
       
          
        '''equalizer = ofdm.channel_equalizer_mimo_2( total_subc )
        self.connect(  ofdm_blocks,         ( equalizer, 0 ) )
        self.connect(  ofdm_blocks2,        ( equalizer, 1 ) )
        self.connect( inv_CTF_1,            ( equalizer, 2 ) )
        self.connect( inv_CTF_2,            ( equalizer, 3 ) )
        self.connect( inv_CTF_3,            ( equalizer, 4 ) )
        self.connect( inv_CTF_4,            ( equalizer, 5 ) )
        self.connect( frame_start,          ( equalizer, 6 ) )
        self.connect( frame_start2,         ( equalizer, 7 ) )
        ofdm_blocks = equalizer'''
          
    
        equalizer = ofdm.channel_equalizer_mimo_2( total_subc )    
        self.connect(  ofdm_blocks,          ( equalizer, 0 ) )
        self.connect( estimated_CTF_1,            ( equalizer, 1 ) )
        self.connect( estimated_CTF_2,            ( equalizer, 2 ) )
        self.connect( frame_start,          ( equalizer, 3 ) )
        #ofdm_blocks = equalizer
    
        #ofdm_blocks2 = equalizer2
        
    
        ofdm_blocks = equalizer
        
        #log_to_file(self, equalizer,"data/equalizer.compl")
        log_to_file(self, ofdm_blocks,"data/equalizer.compl")
        log_to_file(self, estimated_CTF_1,"data/estimated_CTF_1.compl")
        log_to_file(self, estimated_CTF_2,"data/estimated_CTF_2.compl")
        
        
        
        
        
        
        ## LMS Phase tracking
        ## Track residual frequency offset and sampling clock frequency offset
        '''
        nondata_blocks = []
        for i in range(config.frame_length):
          if i in config.training_data.pilotsym_pos:
            nondata_blocks.append(i)
            
        pilot_subc = block_header.pilot_tones
            
        phase_tracking = ofdm.lms_phase_tracking_02( total_subc, pilot_subc,
                                                   nondata_blocks )
        self.connect( equalizer, ( phase_tracking, 0 ) )
        self.connect( frame_start, ( phase_tracking, 1 ) )
        
        phase_tracking2 = ofdm.lms_phase_tracking_02( total_subc, pilot_subc,
                                                    nondata_blocks )
        self.connect( equalizer2, ( phase_tracking2, 0 ) )
        self.connect( frame_start2, ( phase_tracking2, 1 ) )
        
        # if options.scatter_plot_before_phase_tracking:
          # self.before_phase_tracking = equalizer
          
        
        if options.disable_phase_tracking or options.ideal:
          terminate_stream(self, phase_tracking)
          terminate_stream(self, phase_tracking2)
          print "Disabled phase tracking stage"
        else:
          ofdm_blocks = phase_tracking
          ofdm_blocks2 = phase_tracking2
          
        log_to_file(self,phase_tracking, "data/phase_tracking.compl")
        '''
          
        '''combine = blocks.add_cc(config.subcarriers)
        self.connect(ofdm_blocks, (combine,0))
        self.connect(ofdm_blocks2, (combine,1))
        ofdm_blocks = combine'''
    ##    div = gr.multiply_cc(config.subcarriers)
    ##    const = blocks.vector_source_c([[0.5+0]*config.subcarriers],True)
    ##    self.connect(ofdm_blocks,div)
    ##    self.connect(const,(div,1))
    ##    ofdm_blocks=div
    #    log_to_file(self,combine,"data/combine.compl")
        ## Output connections
        
        self.connect( ofdm_blocks, out_ofdm_blocks )
        self.connect( frame_start, out_frame_start )
        self.connect( disp_CTF_RX0, out_disp_ctf )
        self.connect( disp_CTF_RX1, out_disp_ctf2 )
        
    else: # (2 preambles for channel estimation)
        chest_pre_trigger_1 = blocks.delay( gr.sizeof_char, 
                                      1 )
        
        chest_pre_trigger_2 = blocks.delay( gr.sizeof_char, 
                                      2 )
        sampled_chest_preamble_1 = \
          ofdm.vector_sampler( gr.sizeof_gr_complex * total_subc, 1 )
          
        sampled_chest_preamble_2 = \
          ofdm.vector_sampler( gr.sizeof_gr_complex * total_subc, 1 ) 
           
        self.connect( frame_start,       chest_pre_trigger_1 )
        self.connect( chest_pre_trigger_1, ( sampled_chest_preamble_1, 1 ) )
        self.connect( ofdm_blocks,       ( sampled_chest_preamble_1, 0 ) )
        
        self.connect( frame_start,       chest_pre_trigger_2 )
        self.connect( chest_pre_trigger_2, ( sampled_chest_preamble_2, 1 ) )
        self.connect( ofdm_blocks,       ( sampled_chest_preamble_2, 0 ) )
        
        
        ## Least Squares estimator for channel transfer function (CTF)
        
        # Taking inverse for estimating h11 (h12)
        inv_preamble_fd_1 = numpy.array( block_header.pilotsym_fd_1[ 
            block_header.channel_estimation_pilot[0] ] )
        print "inv_preamble_fd_1: ",inv_preamble_fd_1
        #inv_preamble_fd_1 = inv_preamble_fd_1[0::2]
        #print "inv_preamble_fd_1 ", inv_preamble_fd_1
        
        # Taking inverse for estimating h21 (h22)
        inv_preamble_fd_2 = numpy.array( block_header.pilotsym_fd_2[ 
            block_header.channel_estimation_pilot[0]+1 ] )
        print "inv_preamble_fd_2: ",inv_preamble_fd_2
        #inv_preamble_fd_2 = inv_preamble_fd_2[1::2]
        #print "inv_preamble_fd_2 ", inv_preamble_fd_2
        
        print "inv_preamble_fd_1: ",inv_preamble_fd_1
        print "inv_preamble_fd_2: ",inv_preamble_fd_2
        
        
        inv_preamble_fd_1 = 1. / inv_preamble_fd_1
        inv_preamble_fd_2 = 1. / inv_preamble_fd_2
        
        #dd = []
        #for i in range (total_subc/2):
          #  dd.extend([i*2])
            
        skip_block_1 = ofdm.int_skip(total_subc,2,0)
        skip_block_11 = ofdm.int_skip(total_subc,2,0)
        skip_block_2 = ofdm.int_skip(total_subc,2,1)
    #    inta_estim_1 = ofdm.interpolator(total_subc,2,dd)
    #    inta_estim_2 = ofdm.interpolator(total_subc,2,dd)
        
        LS_channel_estimator_1 = ofdm.multiply_const_vcc( list( inv_preamble_fd_1 ) )
        LS_channel_estimator_2 = ofdm.multiply_const_vcc( list( inv_preamble_fd_2 ) )
        self.connect( sampled_chest_preamble_1, LS_channel_estimator_1)#,inta_estim_1 )
        self.connect( sampled_chest_preamble_2, LS_channel_estimator_2)#,inta_estim_2 )
        
        estimated_CTF_1 = LS_channel_estimator_1                  # h0
        estimated_CTF_2 = LS_channel_estimator_2                  # h1              # h3
            
        
        if not options.disable_ctf_enhancer:
          
          # if options.logcir:
            # ifft1 = fft_blocks.fft_vcc(total_subc,False,[],True)
            # self.connect( estimated_CTF, ifft1,blocks.null_sink(gr.sizeof_gr_complex*total_subc))
            # summ1 = ofdm.vector_sum_vcc(total_subc)
            # c2m =gr.complex_to_mag(total_subc)
            # self.connect( estimated_CTF,summ1 ,blocks.null_sink(gr.sizeof_gr_complex))
            # self.connect( estimated_CTF, c2m,blocks.null_sink(gr.sizeof_float*total_subc))
            # log_to_file( self, ifft1, "data/CIR1.compl" )
            # log_to_file( self, summ1, "data/CTFsumm1.compl" )
            # log_to_file( self, estimated_CTF, "data/CTF1.compl" )
            # log_to_file( self, c2m, "data/CTFmag1.float" )
            
          ## MSE enhancer
          ctf_mse_enhancer_1 = ofdm.CTF_MSE_enhancer( total_subc, cp_length + cp_length)
          ctf_mse_enhancer_2 = ofdm.CTF_MSE_enhancer( total_subc, cp_length + cp_length)
          self.connect( estimated_CTF_1, ctf_mse_enhancer_1 )
          self.connect( estimated_CTF_2, ctf_mse_enhancer_2 )
          
            
          estimated_CTF_1 = ctf_mse_enhancer_1
          estimated_CTF_2 = ctf_mse_enhancer_2
          
          print "Disabled CTF MSE enhancer"
        
        ctf_postprocess_1 = ofdm.postprocess_CTF_estimate( total_subc )
        self.connect( estimated_CTF_1, ( ctf_postprocess_1, 0 ) )
        ctf_postprocess_2 = ofdm.postprocess_CTF_estimate( total_subc )
        self.connect( estimated_CTF_2, ( ctf_postprocess_2, 0 ) )
               
        inv_CTF_1 = ( ctf_postprocess_1, 0 )
        disp_CTF_1 = ( ctf_postprocess_1, 1 )
        inv_CTF_2 = ( ctf_postprocess_2, 0 )
        disp_CTF_2 = ( ctf_postprocess_2, 1 )  
    
        #disp_CTF_RX0 = blocks.add_ff(total_subc)
        
        #self.connect ( disp_CTF_1, (disp_CTF_RX0, 0) )
        #self.connect ( disp_CTF_2, (disp_CTF_RX0, 1) )
    
    
        #terminate_stream(self,disp_CTF_RX0)
        terminate_stream(self,inv_CTF_2)
        
        disp_CTF_RX0 = disp_CTF_1
        disp_CTF_RX1 = disp_CTF_2
        ## Channel Equalizer
        
        #log_to_file(self, ofdm_blocks, "data/vec_mask.compl")
        #log_to_file(self, ofdm_blocks2, "data/vec_mask2.compl")
        
        nondata_blocks = []
        for i in range(config.frame_length):
          if i in config.training_data.pilotsym_pos:
            nondata_blocks.append(i)
            
        pilot_subc = block_header.pilot_tones
        pilot_subcarriers = block_header.pilot_subc_sym
        print "PILOT SUBCARRIERS: ", pilot_subcarriers
        
        phase_tracking = ofdm.lms_phase_tracking_03( total_subc, pilot_subc,
                                                   nondata_blocks,pilot_subcarriers,0 )
       
        
        ##phase_tracking = ofdm.lms_phase_tracking_02( total_subc, pilot_subc,
         ##                                          nondata_blocks )
        ##phase_tracking2 = ofdm.lms_phase_tracking_02( total_subc, pilot_subc,
         ##                                           nondata_blocks )
        
    #    self.connect( ofdm_blocks,          ( phase_tracking, 0 ) )
    #    self.connect( ofdm_blocks2,          ( phase_tracking, 1 ))
    #    self.connect( inv_CTF_1,            ( phase_tracking, 2 ) )
    #    self.connect( inv_CTF_3,            ( phase_tracking, 3 ) )
    #    self.connect( frame_start,            ( phase_tracking, 4 ) )
    #    self.connect( frame_start2,            ( phase_tracking, 5) )
    #    
    #    self.connect( ofdm_blocks2,          ( phase_tracking2, 0 ) )
    #    self.connect( ofdm_blocks,          ( phase_tracking2, 1 ))
    #    self.connect( inv_CTF_3,            ( phase_tracking2, 2 ) )
    #    self.connect( inv_CTF_1,            ( phase_tracking2, 3 ) )
    #    self.connect( frame_start2,            ( phase_tracking2, 4 ) )
    #    self.connect( frame_start,            ( phase_tracking2, 5 ) )
        
        self.connect( ofdm_blocks,          ( phase_tracking, 0 ) )
        self.connect( inv_CTF_1,    skip_block_11,   ( phase_tracking, 1 ) )
        self.connect( frame_start,            ( phase_tracking, 2 ) )
        
        #self.connect(phase_tracking,blocks.null_sink(gr.sizeof_gr_complex*total_subc))
        
        if options.disable_phase_tracking or options.ideal:
          terminate_stream(self, phase_tracking)
          print "Disabled phase tracking stage"
        else:
          ofdm_blocks = phase_tracking
          
       
          
        '''equalizer = ofdm.channel_equalizer_mimo_2( total_subc )
        self.connect(  ofdm_blocks,         ( equalizer, 0 ) )
        self.connect(  ofdm_blocks2,        ( equalizer, 1 ) )
        self.connect( inv_CTF_1,            ( equalizer, 2 ) )
        self.connect( inv_CTF_2,            ( equalizer, 3 ) )
        self.connect( inv_CTF_3,            ( equalizer, 4 ) )
        self.connect( inv_CTF_4,            ( equalizer, 5 ) )
        self.connect( frame_start,          ( equalizer, 6 ) )
        self.connect( frame_start2,         ( equalizer, 7 ) )
        ofdm_blocks = equalizer'''
          
    
        equalizer = ofdm.channel_equalizer_mimo_2( total_subc )    
        self.connect(  ofdm_blocks,          ( equalizer, 0 ) )
        self.connect( estimated_CTF_1,     skip_block_1,       ( equalizer, 1 ) )
        self.connect( estimated_CTF_2,    skip_block_2,        ( equalizer, 2 ) )
        self.connect( frame_start,          ( equalizer, 3 ) )
        #ofdm_blocks = equalizer
    
        #ofdm_blocks2 = equalizer2
        
    
        ofdm_blocks = equalizer
        
        #log_to_file(self, equalizer,"data/equalizer.compl")
        log_to_file(self, ofdm_blocks,"data/equalizer.compl")
        log_to_file(self, estimated_CTF_1,"data/estimated_CTF_1.compl")
        log_to_file(self, estimated_CTF_2,"data/estimated_CTF_2.compl")
        
        
        
        
        
        
        ## LMS Phase tracking
        ## Track residual frequency offset and sampling clock frequency offset
        '''
        nondata_blocks = []
        for i in range(config.frame_length):
          if i in config.training_data.pilotsym_pos:
            nondata_blocks.append(i)
            
        pilot_subc = block_header.pilot_tones
            
        phase_tracking = ofdm.lms_phase_tracking_02( total_subc, pilot_subc,
                                                   nondata_blocks )
        self.connect( equalizer, ( phase_tracking, 0 ) )
        self.connect( frame_start, ( phase_tracking, 1 ) )
        
        phase_tracking2 = ofdm.lms_phase_tracking_02( total_subc, pilot_subc,
                                                    nondata_blocks )
        self.connect( equalizer2, ( phase_tracking2, 0 ) )
        self.connect( frame_start2, ( phase_tracking2, 1 ) )
        
        # if options.scatter_plot_before_phase_tracking:
          # self.before_phase_tracking = equalizer
          
        
        if options.disable_phase_tracking or options.ideal:
          terminate_stream(self, phase_tracking)
          terminate_stream(self, phase_tracking2)
          print "Disabled phase tracking stage"
        else:
          ofdm_blocks = phase_tracking
          ofdm_blocks2 = phase_tracking2
          
        log_to_file(self,phase_tracking, "data/phase_tracking.compl")
        '''
          
        '''combine = blocks.add_cc(config.subcarriers)
        self.connect(ofdm_blocks, (combine,0))
        self.connect(ofdm_blocks2, (combine,1))
        ofdm_blocks = combine'''
    ##    div = gr.multiply_cc(config.subcarriers)
    ##    const = blocks.vector_source_c([[0.5+0]*config.subcarriers],True)
    ##    self.connect(ofdm_blocks,div)
    ##    self.connect(const,(div,1))
    ##    ofdm_blocks=div
    #    log_to_file(self,combine,"data/combine.compl")
        ## Output connections
        
        self.connect( ofdm_blocks, out_ofdm_blocks )
        self.connect( frame_start, out_frame_start )
        self.connect( disp_CTF_RX0, out_disp_ctf )
        self.connect( disp_CTF_RX1, out_disp_ctf2 )
Example #33
0
  def __init__( self, options, log = False ):
    
    ## Read configuration
    config = station_configuration()
    
    fft_length    = config.fft_length
    #cp_length     = config.cp_length
    block_header  = config.training_data
    data_subc     = config.data_subcarriers
    virtual_subc  = config.virtual_subcarriers
    total_subc    = config.subcarriers
    block_length  = config.block_length
    frame_length  = config.frame_length
    
    L             = block_header.mm_periodic_parts
    
        
    cp_length     = config.cp_length


    
    print "data_subc: ", config.data_subcarriers
    print "total_subc: ", config.subcarriers
    print "frame_lengthframe_length: ", frame_length
    
    
    ## Set Input/Output signature
    gr.hier_block2.__init__( self, 
        "fbmc_inner_receiver",
        gr.io_signature(
            1, 1,
            gr.sizeof_gr_complex ),
        gr.io_signaturev(
            4, 4,
            [gr.sizeof_float * total_subc,    # Normalized |CTF|^2 
            gr.sizeof_char,                       # Frame start
            gr.sizeof_gr_complex * total_subc, # OFDM blocks, SNR est
            gr.sizeof_float] ) )      # CFO
    
    
    ## Input and output ports
    self.input = rx_input = self
    
    out_ofdm_blocks = ( self, 2 )
    out_frame_start = ( self, 1 )
    out_disp_ctf    = ( self, 0 )
    out_disp_cfo    = ( self, 3 )
    #out_snr_pream    = ( self, 3 )
    
    
    
    
    ## pre-FFT processing
    
    '''
    ## Compute autocorrelations for S&C preamble
    ## and cyclic prefix
    
    self._sc_metric = sc_metric = autocorrelator( fft_length/2, fft_length/2 )
    self._gi_metric = gi_metric = autocorrelator( fft_length, cp_length )
    
    self.connect( rx_input, sc_metric )
    self.connect( rx_input, gi_metric )
    terminate_stream(self, gi_metric)
    
    ## Sync. Output contains OFDM blocks
    sync = ofdm.time_sync( fft_length/2, 1)
    self.connect( rx_input, ( sync, 0 ) )
    self.connect( sc_metric, ( sync, 1 ) )
    self.connect( sc_metric, ( sync, 2 ) )
    
    ofdm_blocks = ( sync, 0 )
    frame_start = ( sync, 1 )
    log_to_file( self, ( sync, 1 ), "data/fbmc_peak_detector.char" )
    '''
    if options.ideal is False and options.ideal2 is False:
        #Testing old/new metric
        self.tm = schmidl.recursive_timing_metric(2*fft_length)
        self.connect( self.input, self.tm)
        #log_to_file( self, self.tm, "data/fbmc_rec_sc_metric_ofdm.float" )
        
        timingmetric_shift = 0 #-2 #int(-cp_length * 0.8)
        tmfilter = filter.fft_filter_fff(1, [2./fft_length]*(fft_length/2))# ofdm.lms_fir_ff( fft_length, 1e-3 ) #; filter.fir_filter_fff(1, [1./fft_length]*fft_length)
        self.connect( self.tm, tmfilter )
        self.tm = tmfilter
        #log_to_file( self, self.tm, "data/fbmc_rec_sc_metric_ofdm2.float" )
        
        self._pd_thres = 0.6
        self._pd_lookahead = fft_length # empirically chosen
        peak_detector = ofdm.peak_detector_02_fb(self._pd_lookahead, self._pd_thres)
        self.connect(self.tm, peak_detector)
        #log_to_file( self, peak_detector, "data/fbmc_rec_peak_detector.char" )
        
        
        #frame_start = [0]*frame_length
        #frame_start[0] = 1
        #frame_start = blocks.vector_source_b(frame_start,True)
        
        #OLD
        #delayed_timesync = blocks.delay(gr.sizeof_char,
         #                           (frame_length-10)*fft_length/2 - fft_length/4 -1 + timingmetric_shift)
        delayed_timesync = blocks.delay(gr.sizeof_char,
                                    (frame_length-10)*fft_length/2 - fft_length/4  + int(2.5*fft_length)  + timingmetric_shift-1)
        #delayed_timesync = blocks.delay(gr.sizeof_char,
                                    #(frame_length-10)*fft_length/2 - fft_length/4 + int(3.5*fft_length)  + timingmetric_shift-1)
        self.connect( peak_detector, delayed_timesync )
        
        self.block_sampler = ofdm.vector_sampler(gr.sizeof_gr_complex,fft_length/2*frame_length)
        
        self.connect(self.input,self.block_sampler)
        self.connect(delayed_timesync,(self.block_sampler,1))
        #log_to_file( self, self.block_sampler, "data/fbmc_block_sampler.compl" )
        
        vt2s = blocks.vector_to_stream(gr.sizeof_gr_complex*fft_length,
                                                frame_length/2)
        self.connect(self.block_sampler,vt2s)
        #terminate_stream(self,ofdm_blocks)
        
        ofdm_blocks = vt2s
        
        '''
        # TODO: dynamic solution
        vt2s = blocks.vector_to_stream(gr.sizeof_gr_complex*block_length/2,
                                                frame_length)
        self.connect(self.block_sampler,vt2s)
        terminate_stream(self,( sync, 0 ))
        ofdm_blocks = vt2s
        '''
        
        
        
        
        
        ##stv_help = blocks.stream_to_vector(gr.sizeof_gr_complex*config.fft_length/2, 1)
        #stv_help = blocks.vector_to_stream(gr.sizeof_gr_complex*config.fft_length/2, 2)
       ##self.connect(ofdm_blocks, stv_help)
        ##ofdm_blocks = stv_help
        #ofdm_blocks = ( sync, 0 )
        #frame_start = ( sync, 1 )
        #log_to_file(self, frame_start, "data/frame_start.compl")
        
        #log_to_file( self, sc_metric, "data/sc_metric.float" )
        #log_to_file( self, gi_metric, "data/gi_metric.float" )
        #log_to_file( self, (sync,1), "data/sync.float" )
        
    #    log_to_file(self,ofdm_blocks,"data/ofdm_blocks_original.compl")
        frame_start = [0]*int(frame_length/2)
        frame_start[0] = 1
        frame_start = blocks.vector_source_b(frame_start,True)          
        
        #frame_start2 = [0]*int(frame_length/2)
        #frame_start2[0] = 1
        #frame_start2 = blocks.vector_source_b(frame_start2,True)
    
    if options.disable_time_sync or options.ideal or options.ideal2:
      if options.ideal is False and options.ideal2 is False:
        terminate_stream(self, ofdm_blocks)
        terminate_stream(self, frame_start)
      
      serial_to_parallel = blocks.stream_to_vector(gr.sizeof_gr_complex,fft_length)
      #discard_cp = ofdm.vector_mask(block_length,cp_length,fft_length,[])
      #serial_to_parallel = blocks.stream_to_vector(gr.sizeof_gr_complex,block_length)
      #discard_cp = ofdm.vector_mask(block_length,cp_length,fft_length,[])
      #self.connect( rx_input,serial_to_parallel)
      
      #self.connect( rx_input, blocks.delay(gr.sizeof_gr_complex,0),serial_to_parallel)
      initial_skip = blocks.skiphead(gr.sizeof_gr_complex,2*fft_length)
      self.connect( rx_input, initial_skip)
      if options.ideal is False and options.ideal2 is False:          
          self.connect(  initial_skip, serial_to_parallel)
          ofdm_blocks = serial_to_parallel
      else:
          ofdm_blocks = initial_skip
      #self.connect( rx_input, serial_to_parallel, discard_cp )
      
      frame_start = [0]*int(frame_length/2)
      frame_start[0] = 1
      frame_start = blocks.vector_source_b(frame_start,True)
      
      #frame_start2 = [0]*int(frame_length/2)
      #frame_start2[0] = 1
      #frame_start2 = blocks.vector_source_b(frame_start2,True)
      
      print "Disabled time synchronization stage"
    
    print"\t\t\t\t\tframe_length = ",frame_length
    
    if options.ideal is False and options.ideal2 is False:
        ## Extract preamble, feed to Morelli & Mengali frequency offset estimator
        assert( block_header.mm_preamble_pos == 0 )
        morelli_foe = ofdm.mm_frequency_estimator( fft_length, 2, 1, config.fbmc )
        sampler_preamble = ofdm.vector_sampler( gr.sizeof_gr_complex * fft_length,
                                                1 )
        self.connect( ofdm_blocks, ( sampler_preamble, 0 ) )
        self.connect( frame_start, blocks.delay( gr.sizeof_char, 1 ), ( sampler_preamble, 1 ) )
        self.connect( sampler_preamble, morelli_foe )
        freq_offset = morelli_foe
        print "FRAME_LENGTH: ", frame_length
        #log_to_file( self, sampler_preamble, "data/sampler_preamble.compl" )
        #log_to_file( self, rx_input, "data/rx_input.compl" )
        #log_to_file( self, ofdm_blocks, "data/rx_input.compl" )

        
        #Extracting preamble for SNR estimation
        #fft_snr_est = fft_blocks.fft_vcc( fft_length, True, [], True )
        #self.connect( sampler_preamble, blocks.stream_to_vector(gr.sizeof_gr_complex*fft_length/2, 2),  fft_snr_est )
        
        
        ## Remove virtual subcarriers
        #if fft_length > data_subc:
          #subcarrier_mask_snr_est = ofdm.vector_mask( fft_length, virtual_subc/2,
                        #                       total_subc, [] )
          #self.connect( fft_snr_est, subcarrier_mask_snr_est )
          #fft_snr_est = subcarrier_mask_snr_est
          #log_to_file(self, ofdm_blocks, "data/vec_mask.compl")
           ## Least Squares estimator for channel transfer function (CTF)
        
        #self.connect( fft_snr_est, out_snr_pream ) # Connecting to output
        
        ## Adaptive LMS FIR filtering of frequency offset
        lms_fir = ofdm.lms_fir_ff( 20, 1e-3 ) # TODO: verify parameter choice
        self.connect( freq_offset, lms_fir )
        freq_offset = lms_fir
        
        self.connect(freq_offset, blocks.keep_one_in_n(gr.sizeof_float,20) ,out_disp_cfo)
    else:
        self.connect(blocks.vector_source_f ([1]) ,out_disp_cfo)

    
    #log_to_file(self, lms_fir, "data/lms_fir.float")
    
    if options.disable_freq_sync or options.ideal or options.ideal2:
      if options.ideal is False and options.ideal2 is False:  
          terminate_stream(self, freq_offset)
          freq_offset = blocks.vector_source_f([0.0],True)
      print "Disabled frequency synchronization stage"
    
    if options.ideal is False and options.ideal2 is False:
        ## Correct frequency shift, feed-forward structure
        frequency_shift = ofdm.frequency_shift_vcc( fft_length, -1.0/fft_length,
                                                    0)
        
        #freq_shift = blocks.multiply_cc()
        #norm_freq = -0.1 / config.fft_length
        #freq_off = self.freq_off_src = analog.sig_source_c(1.0, analog.GR_SIN_WAVE, norm_freq, 1.0, 0.0 )
        
        self.connect( ofdm_blocks, ( frequency_shift, 0 ) )
        self.connect( freq_offset, ( frequency_shift, 1 ) )
        self.connect( frame_start,blocks.delay( gr.sizeof_char, 0), ( frequency_shift, 2 ) )
        
        

        
        #self.connect(frequency_shift,s2help)
        #ofdm_blocks = s2help
        ofdm_blocks = frequency_shift
    #terminate_stream(self, frequency_shift)
    
    
    
    #inner_pb_filt = self._inner_pilot_block_filter = fbmc_inner_pilot_block_filter()
    #self.connect(ofdm_blocks,inner_pb_filt)
    #self.connect(frame_start,(inner_pb_filt,1))
    #self.connect((inner_pb_filt,1),blocks.null_sink(gr.sizeof_char))
    
    #ofdm_blocks = (inner_pb_filt,0)
    
    
    overlap_ser_to_par = ofdm.fbmc_overlapping_serial_to_parallel_cvc(fft_length)
    self.separate_vcvc = ofdm.fbmc_separate_vcvc(fft_length, 2)
    self.polyphase_network_vcvc_1 = ofdm.fbmc_polyphase_network_vcvc(fft_length, 4, 4*fft_length-1, True)
    self.polyphase_network_vcvc_2 = ofdm.fbmc_polyphase_network_vcvc(fft_length, 4, 4*fft_length-1, True)
    self.junction_vcvc = ofdm.fbmc_junction_vcvc(fft_length, 2)
    self.fft_fbmc = fft_blocks.fft_vcc(fft_length, True, [], True)
    
    print "config.training_data.fbmc_no_preambles: ", config.training_data.fbmc_no_preambles
    #center_preamble = [1, -1j, -1, 1j]
    
    #self.preamble = preamble = [0]*total_subc + center_preamble*((int)(total_subc/len(center_preamble)))+[0]*total_subc
    
    self.preamble = preamble = config.training_data.fbmc_pilotsym_fd_list
    #inv_preamble = 1. / numpy.array(self.preamble)
    #print "self.preamble: ", len(self.preamble
    #print "inv_preamble: ", list(inv_preamble)
    
    #print "self.preamble", self.preamble
    #print "self.preamble2", self.preamble2
    
    
    self.multiply_const= ofdm.multiply_const_vcc(([1.0/(math.sqrt(fft_length*0.6863))]*total_subc))    
    self.beta_multiplier_vcvc = ofdm.fbmc_beta_multiplier_vcvc(total_subc, 4, 4*fft_length-1, 0)
    #self.skiphead = blocks.skiphead(gr.sizeof_gr_complex*total_subc, 2*4-1-1)
    self.skiphead = blocks.skiphead(gr.sizeof_gr_complex*total_subc,2)
    self.skiphead_1 = blocks.skiphead(gr.sizeof_gr_complex*total_subc, 0)
    #self.remove_preamble_vcvc = ofdm.fbmc_remove_preamble_vcvc(total_subc, config.frame_data_part/2, config.training_data.fbmc_no_preambles*total_subc/2)
    #self.subchannel_processing_vcvc = ofdm.fbmc_subchannel_processing_vcvc(total_subc, config.frame_data_part, 1, 2, 1, 0)
    self.oqam_postprocessing_vcvc = ofdm.fbmc_oqam_postprocessing_vcvc(total_subc, 0, 0)
    
    #log_to_file( self, ofdm_blocks, "data/PRE_FBMC.compl" )
    #log_to_file( self, self.fft_fbmc, "data/FFT_FBMC.compl" )

    if options.ideal is False and options.ideal2 is False:
        self.subchannel_processing_vcvc = ofdm.fbmc_subchannel_processing_vcvc(total_subc, config.frame_data_part, 3, 2, 1, 0)
        help2 = blocks.keep_one_in_n(gr.sizeof_gr_complex*total_subc,frame_length)
        self.connect ((self.subchannel_processing_vcvc,1),help2)
        #log_to_file( self, self.subchannel_processing_vcvc, "data/fbmc_subc.compl" )

    
    #terminate_stream(self, help2)
    
    if options.ideal is False and options.ideal2 is False:
        self.connect(ofdm_blocks, blocks.vector_to_stream(gr.sizeof_gr_complex, fft_length),overlap_ser_to_par)
    else:
        self.connect(ofdm_blocks,overlap_ser_to_par)
        
    self.connect(overlap_ser_to_par, self.separate_vcvc)
    self.connect((self.separate_vcvc, 1), (self.polyphase_network_vcvc_2, 0))
    self.connect((self.separate_vcvc, 0), (self.polyphase_network_vcvc_1, 0))
    self.connect((self.polyphase_network_vcvc_1, 0), (self.junction_vcvc, 0))
    self.connect((self.polyphase_network_vcvc_2, 0), (self.junction_vcvc, 1))
    self.connect(self.junction_vcvc, self.fft_fbmc)
    
    ofdm_blocks = self.fft_fbmc
    print "config.dc_null: ", config.dc_null
    if fft_length > data_subc:
      subcarrier_mask_fbmc = ofdm.vector_mask_dc_null( fft_length, virtual_subc/2,
                                           total_subc, config.dc_null, [] )
      self.connect( ofdm_blocks, subcarrier_mask_fbmc )
      ofdm_blocks = subcarrier_mask_fbmc
      #log_to_file(self, ofdm_blocks, "data/vec_mask.compl")
       ## Least Squares estimator for channel transfer function (CTF)
      #log_to_file( self, subcarrier_mask, "data/OFDM_Blocks.compl" )
      
    
    self.connect(ofdm_blocks, self.beta_multiplier_vcvc)
    
    ofdm_blocks = self.beta_multiplier_vcvc
    #self.connect(ofdm_blocks,self.multiply_const)
    #self.connect(self.multiply_const, (self.skiphead, 0))
    
    self.connect(ofdm_blocks, (self.skiphead, 0))
    #log_to_file( self, self.skiphead, "data/fbmc_skiphead_4.compl" )
    
    
    #self.connect(ofdm_blocks, self.multiply_const)
    #self.connect(self.multiply_const, self.beta_multiplier_vcvc)
    #self.connect((self.beta_multiplier_vcvc, 0), (self.skiphead, 0))
    if options.ideal or options.ideal2:
        self.connect((self.skiphead, 0),(self.skiphead_1, 0))
    else:
        self.connect((self.skiphead, 0), (self.subchannel_processing_vcvc, 0))
        self.connect((self.subchannel_processing_vcvc, 0), (self.skiphead_1, 0))
        
    #log_to_file( self, self.skiphead, "data/fbmc_subc.compl" )    
    #self.connect((self.skiphead_1, 0),(self.remove_preamble_vcvc, 0))
    #self.connect((self.remove_preamble_vcvc, 0),  (self.oqam_postprocessing_vcvc, 0))
    
    #ofdm_blocks = self.oqam_postprocessing_vcvc
    #log_to_file( self, self.subchannel_processing_vcvc, "data/subc_0.compl" )
    #log_to_file( self, (self.subchannel_processing_vcvc,1), "data/subc_1.compl" )
    
    
    
    self.connect((self.skiphead_1, 0),(self.oqam_postprocessing_vcvc, 0))
    #self.connect((self.oqam_postprocessing_vcvc, 0), (self.remove_preamble_vcvc, 0) )
    
    ofdm_blocks = (self.oqam_postprocessing_vcvc, 0)#(self.remove_preamble_vcvc, 0)
    #log_to_file( self, (self.oqam_postprocessing_vcvc, 0), "data/fbmc_before_remove.compl" )
    
    #log_to_file( self, self.skiphead, "data/SKIP_HEAD_FBMC.compl" )
    #log_to_file( self, self.beta_multiplier_vcvc, "data/BETA_REC_FBMC.compl" )
    #log_to_file( self, self.oqam_postprocessing_vcvc, "data/REC_OUT_FBMC.compl" )
        
    

    
    
    
    
    
    """ DISABLED OFDM CHANNEL ESTIMATION PREMBLE -> CORRECT LATER to compare FBMC and OFDM channel estimation
    #TAKING THE CHANNEL ESTIMATION PREAMBLE
    chest_pre_trigger = blocks.delay( gr.sizeof_char, 3 )
    sampled_chest_preamble = ofdm.vector_sampler( gr.sizeof_gr_complex * fft_length/2, 2 )
      
    self.connect( frame_start,       chest_pre_trigger )
    self.connect( chest_pre_trigger, ( sampled_chest_preamble, 1 ) )
    self.connect( frequency_shift,       ( sampled_chest_preamble, 0 ) )
    #ofdm_blocks = sampled_chest_preamble
    
        
    ## FFT
    fft = fft_blocks.fft_vcc( fft_length, True, [], True )
    self.connect( sampled_chest_preamble, fft )
    ofdm_blocks_est = fft
    log_to_file( self, sampled_chest_preamble, "data/SAMPLED_EST_PREAMBLE.compl" )
    log_to_file( self, ofdm_blocks_est, "data/FFT.compl" )
    
    
    ## Remove virtual subcarriers
    if fft_length > data_subc:
      subcarrier_mask = ofdm.vector_mask( fft_length, virtual_subc/2,
                                           total_subc, [] )
      self.connect( ofdm_blocks_est, subcarrier_mask )
      ofdm_blocks_est = subcarrier_mask
      #log_to_file(self, ofdm_blocks, "data/vec_mask.compl")
       ## Least Squares estimator for channel transfer function (CTF)
      log_to_file( self, subcarrier_mask, "data/OFDM_Blocks.compl" )
    
          
    ## post-FFT processing
      
    
    
    ## extract channel estimation preamble from frame
    ##chest_pre_trigger = blocks.delay( gr.sizeof_char, 
                                  ##1 )
    ##sampled_chest_preamble = \
     ## ofdm.vector_sampler( gr.sizeof_gr_complex * total_subc, 1 )
    ##self.connect( frame_start,       chest_pre_trigger )
    ##self.connect( chest_pre_trigger, ( sampled_chest_preamble, 1 ) )
    ##self.connect( ofdm_blocks,       ( sampled_chest_preamble, 0 ) )
    

    
    ## Least Squares estimator for channel transfer function (CTF)
    inv_preamble_fd = numpy.array( block_header.pilotsym_fd[ 
        block_header.channel_estimation_pilot[0] ] )
    #print "Channel estimation pilot: ", inv_preamble_fd
    inv_preamble_fd = 1. / inv_preamble_fd
    
    LS_channel_estimator = ofdm.multiply_const_vcc( list( inv_preamble_fd ) )
    self.connect( ofdm_blocks_est, LS_channel_estimator )
    estimated_CTF = LS_channel_estimator
    terminate_stream(self,estimated_CTF)
    """
    if options.ideal is False and options.ideal2 is False:
        if options.logcir:
         log_to_file( self, sampled_chest_preamble, "data/PREAM.compl" )
     
    
        if not options.disable_ctf_enhancer:
      
      
            if options.logcir:
                ifft1 = fft_blocks.fft_vcc(total_subc,False,[],True)
                self.connect( estimated_CTF, ifft1,gr.null_sink(gr.sizeof_gr_complex*total_subc))
                summ1 = ofdm.vector_sum_vcc(total_subc)
                c2m =gr.complex_to_mag(total_subc)
                self.connect( estimated_CTF,summ1 ,gr.null_sink(gr.sizeof_gr_complex))
                self.connect( estimated_CTF, c2m,gr.null_sink(gr.sizeof_float*total_subc))
                log_to_file( self, ifft1, "data/CIR1.compl" )
                log_to_file( self, summ1, "data/CTFsumm1.compl" )
                log_to_file( self, estimated_CTF, "data/CTF1.compl" )
                log_to_file( self, c2m, "data/CTFmag1.float" )
        
            ## MSE enhancer
            ctf_mse_enhancer = ofdm.CTF_MSE_enhancer( total_subc, cp_length + cp_length)
            self.connect( estimated_CTF, ctf_mse_enhancer )
#      log_to_file( self, ctf_mse_enhancer, "data/ctf_mse_enhancer_original.compl")
      #ifft3 = fft_blocks.fft_vcc(total_subc,False,[],True)
      #null_noise = ofdm.noise_nulling(total_subc, cp_length + cp_length)
      #ctf_mse_enhancer = fft_blocks.fft_vcc(total_subc,True,[],True)
      #ctf_mse_enhancer = ofdm.vector_mask( fft_length, virtual_subc/2,
                                          # total_subc, [] )
      #self.connect( estimated_CTF, ifft3,null_noise,ctf_mse_enhancer )
        
            estimated_CTF = ctf_mse_enhancer 
            print "Disabled CTF MSE enhancer"

        if options.logcir:
         ifft2 = fft_blocks.fft_vcc(total_subc,False,[],True)
         self.connect( estimated_CTF, ifft2,gr.null_sink(gr.sizeof_gr_complex*total_subc))
         summ2 = ofdm.vector_sum_vcc(total_subc)
         c2m2 =gr.complex_to_mag(total_subc)
         self.connect( estimated_CTF,summ2 ,gr.null_sink(gr.sizeof_gr_complex))
         self.connect( estimated_CTF, c2m2,gr.null_sink(gr.sizeof_float*total_subc))
         log_to_file( self, ifft2, "data/CIR2.compl" )
         log_to_file( self, summ2, "data/CTFsumm2.compl" )
         log_to_file( self, estimated_CTF, "data/CTF2.compl" )
         log_to_file( self, c2m2, "data/CTFmag2.float" )
         
        ## Postprocess the CTF estimate
        ## CTF -> inverse CTF (for equalizer)
        ## CTF -> norm |.|^2 (for CTF display)
        ctf_postprocess = ofdm.fbmc_postprocess_CTF_estimate( total_subc )
        
        self.connect( help2, ctf_postprocess )
        #estimated_SNR = ( ctf_postprocess, 0 )
        disp_CTF = ( ctf_postprocess, 0 )
        #self.connect(estimated_SNR,out_snr_pream)
        #log_to_file( self, estimated_SNR, "data/fbmc_SNR.float" )
        
        #Disable measured SNR output
        #terminate_stream(self, estimated_SNR)
        #self.connect(blocks.vector_source_f([10.0],True) ,out_snr_pream)
    
#     if options.disable_equalization or options.ideal:
#       terminate_stream(self, inv_estimated_CTF)
#       inv_estimated_CTF_vec = blocks.vector_source_c([1.0/fft_length*math.sqrt(total_subc)]*total_subc,True,total_subc)
#       inv_estimated_CTF_str = blocks.vector_to_stream(gr.sizeof_gr_complex, total_subc)
#       self.inv_estimated_CTF_mul = ofdm.multiply_const_ccf( 1.0/config.rms_amplitude )
#       #inv_estimated_CTF_mul.set_k(1.0/config.rms_amplitude)
#       inv_estimated_CTF = blocks.stream_to_vector(gr.sizeof_gr_complex, total_subc)
#       self.connect( inv_estimated_CTF_vec, inv_estimated_CTF_str, self.inv_estimated_CTF_mul, inv_estimated_CTF)
#       print "Disabled equalization stage"
    '''
    ## LMS Phase tracking
    ## Track residual frequency offset and sampling clock frequency offset

    nondata_blocks = []
    for i in range(config.frame_length):
      if i in config.training_data.pilotsym_pos:
        nondata_blocks.append(i)
        
    print"\t\t\t\t\tnondata_blocks=",nondata_blocks
    pilot_subc = block_header.pilot_tones
    pilot_subcarriers = block_header.pilot_subc_sym
    print "PILOT SUBCARRIERS: ", pilot_subcarriers
        
    phase_tracking = ofdm.lms_phase_tracking_03( total_subc, pilot_subc,
                                               nondata_blocks, pilot_subcarriers,0 )
    self.connect( ofdm_blocks, ( phase_tracking, 0 ) )
    self.connect( inv_estimated_CTF, ( phase_tracking, 1 ) )
    self.connect( frame_start, ( phase_tracking, 2 ) ) ##
    
    if options.scatter_plot_before_phase_tracking:
      self.before_phase_tracking = equalizer
      
    
    if options.disable_phase_tracking or options.ideal:
      terminate_stream(self, phase_tracking)
      print "Disabled phase tracking stage"
    else:
      ofdm_blocks = phase_tracking
    '''
    ## Channel Equalizer
    ##equalizer = ofdm.channel_equalizer( total_subc )
    ##self.connect( ofdm_blocks,       ( equalizer, 0 ) )
    ##self.connect( inv_estimated_CTF, ( equalizer, 1 ) )
    ##self.connect( frame_start,       ( equalizer, 2 ) )
    ##ofdm_blocks = equalizer
    #log_to_file(self, equalizer,"data/equalizer_siso.compl")
    
    
    #log_to_file(self, ofdm_blocks, "data/equalizer.compl")

    ## LMS Phase tracking
    ## Track residual frequency offset and sampling clock frequency offset

    nondata_blocks = []
    for i in range(config.frame_length):
      if i in config.training_data.pilotsym_pos:
        nondata_blocks.append(i)
        
    print"\t\t\t\t\tnondata_blocks=",nondata_blocks
    pilot_subc = block_header.pilot_tones
    pilot_subcarriers = block_header.pilot_subc_sym
    print "PILOT SUBCARRIERS: ", pilot_subcarriers
    
    if options.scatter_plot_before_phase_tracking:
      self.before_phase_tracking = equalizer
        

    ## Output connections

    self.connect( ofdm_blocks, out_ofdm_blocks )
    self.connect( frame_start, out_frame_start )
    if options.ideal is False and options.ideal2 is False:
        self.connect( disp_CTF, out_disp_ctf )
    else:
        self.connect( blocks.vector_source_f([1.0]*total_subc),blocks.stream_to_vector(gr.sizeof_float,total_subc), out_disp_ctf )
    
    

    if log:
      log_to_file( self, sc_metric, "data/sc_metric.float" )
      log_to_file( self, gi_metric, "data/gi_metric.float" )
      log_to_file( self, morelli_foe, "data/morelli_foe.float" )
      log_to_file( self, lms_fir, "data/lms_fir.float" )
      log_to_file( self, sampler_preamble, "data/preamble.compl" )
      log_to_file( self, sync, "data/sync.compl" )
      log_to_file( self, frequency_shift, "data/frequency_shift.compl" )
      log_to_file( self, fft, "data/fft.compl")
      log_to_file( self, fft, "data/fft.float", mag=True )
      
      if vars().has_key( 'subcarrier_mask' ):
        log_to_file( self, subcarrier_mask, "data/subcarrier_mask.compl" )
      
      log_to_file( self, ofdm_blocks, "data/ofdm_blocks_out.compl" )
      log_to_file( self, frame_start, "data/frame_start.float", 
                   char_to_float=True )
      
      log_to_file( self, sampled_chest_preamble, 
                   "data/sampled_chest_preamble.compl" )
      log_to_file( self, LS_channel_estimator, 
                   "data/ls_channel_estimator.compl" )
      log_to_file( self, LS_channel_estimator, 
                   "data/ls_channel_estimator.float", mag=True )
      
      if "ctf_mse_enhancer" in locals(): 
        log_to_file( self, ctf_mse_enhancer, "data/ctf_mse_enhancer.compl" )
        log_to_file( self, ctf_mse_enhancer, "data/ctf_mse_enhancer.float", 
                     mag=True )
      
      log_to_file( self, (ctf_postprocess,0), "data/inc_estimated_ctf.compl" )
      log_to_file( self, (ctf_postprocess,1), "data/disp_ctf.float" )
      
      log_to_file( self, equalizer, "data/equalizer.compl" )
      log_to_file( self, equalizer, "data/equalizer.float", mag=True )
      
      log_to_file( self, phase_tracking, "data/phase_tracking.compl" )
Example #34
0
  def __init__(self, options):
    gr.hier_block2.__init__(self, "fbmc_receive_path",
        gr.io_signature(1,1,gr.sizeof_gr_complex),
        gr.io_signature(0,0,0))

    print "This is  FBMC receive path 1x1"

    common_options.defaults(options)

    config = self.config = station_configuration()

    config.data_subcarriers     = dsubc = options.subcarriers
    config.cp_length            = 0
    config.frame_data_blocks    = options.data_blocks
    config._verbose             = options.verbose #TODO: update
    config.fft_length           = options.fft_length
    config.dc_null             = options.dc_null
    config.training_data        = default_block_header(dsubc,
                                          config.fft_length,config.dc_null,options)
    config.coding              = options.coding
    config.ber_window           = options.ber_window

    config.periodic_parts       = 8

    config.frame_id_blocks      = 1 # FIXME

    self._options               = copy.copy(options) #FIXME: do we need this?
    
    config.fbmc                 = options.fbmc

    

    config.block_length = config.fft_length + config.cp_length
    config.frame_data_part = config.frame_data_blocks + config.frame_id_blocks
    config.frame_length = config.training_data.fbmc_no_preambles + 2*config.frame_data_part 
    
    config.postpro_frame_length = config.frame_data_part + \
                          config.training_data.no_pilotsyms
    config.subcarriers = dsubc + \
                         config.training_data.pilot_subcarriers
    config.virtual_subcarriers = config.fft_length - config.subcarriers - config.dc_null

    total_subc = config.subcarriers
    


    # check some bounds
    if config.fft_length < config.subcarriers:
      raise SystemError, "Subcarrier number must be less than FFT length"
    if config.fft_length < config.cp_length:
      raise SystemError, "Cyclic prefix length must be less than FFT length"



    #self.input =  gr.kludge_copy(gr.sizeof_gr_complex)
    #self.connect( self, self.input )
    self.input = self
    self.ideal = options.ideal
    self.ideal2 = options.ideal2


    ## Inner receiver

    ## Timing & Frequency Synchronization
    ## Channel estimation + Equalization
    ## Phase Tracking for sampling clock frequency offset correction
    inner_receiver = self.inner_receiver = fbmc_inner_receiver( options, options.log )
    self.connect( self.input, inner_receiver )
    ofdm_blocks = ( inner_receiver, 2 )
    frame_start = ( inner_receiver, 1 )
    disp_ctf = ( inner_receiver, 0 )
    #self.snr_est_preamble = ( inner_receiver, 3 )
    #terminate_stream(self,snr_est_preamble)
    disp_cfo =  ( inner_receiver, 3 )
    
    if self.ideal is False and self.ideal2 is False:
        self.zmq_probe_freqoff = zeromq.pub_sink(gr.sizeof_float, 1, "tcp://*:5557")
        self.connect(disp_cfo, self.zmq_probe_freqoff)
    else:
        self.connect(disp_cfo, blocks.null_sink(gr.sizeof_float))




    # for ID decoder
    used_id_bits = config.used_id_bits = 8 #TODO: constant in source code!
    rep_id_bits = config.rep_id_bits = dsubc/used_id_bits #BPSK
    if options.log:
      print "rep_id_bits %d" % (rep_id_bits)
    if dsubc % used_id_bits <> 0:
      raise SystemError,"Data subcarriers need to be multiple of 10"

    ## Workaround to avoid periodic structure
    seed(1)
    whitener_pn = [randint(0,1) for i in range(used_id_bits*rep_id_bits)]





    ## NOTE!!! BIG HACK!!!
    ## first preamble ain't equalized ....
    ## for Milan's SNR estimator






    ## Outer Receiver

    ## Make new inner receiver compatible with old outer receiver
    ## FIXME: renew outer receiver

    self.ctf = disp_ctf

    #frame_sampler = ofdm_frame_sampler(options)
    frame_sampler = fbmc_frame_sampler(options)

    self.connect( ofdm_blocks, frame_sampler)
    self.connect( frame_start, (frame_sampler,1) )


#
#    ft = [0] * config.frame_length
#    ft[0] = 1
#
#    # The next block ensures that only complete frames find their way into
#    # the old outer receiver. The dynamic frame start trigger is hence
#    # replaced with a static one, fixed to the frame length.
#
#    frame_sampler = ofdm.vector_sampler( gr.sizeof_gr_complex * total_subc,
#                                              config.frame_length )
#    self.symbol_output = blocks.vector_to_stream( gr.sizeof_gr_complex * total_subc,
#                                              config.frame_length )
#    delayed_frame_start = blocks.delay( gr.sizeof_char, config.frame_length - 1 )
#    damn_static_frame_trigger = blocks.vector_source_b( ft, True )
#
#    if options.enable_erasure_decision:
#      frame_gate = vector_sampler(
#        gr.sizeof_gr_complex * total_subc * config.frame_length, 1 )
#      self.connect( ofdm_blocks, frame_sampler, frame_gate,
#                    self.symbol_output )
#    else:
#      self.connect( ofdm_blocks, frame_sampler, self.symbol_output )
#
#    self.connect( frame_start, delayed_frame_start, ( frame_sampler, 1 ) )

    if options.enable_erasure_decision:
      frame_gate = frame_sampler.frame_gate

    self.symbol_output = frame_sampler

    orig_frame_start = frame_start
    frame_start = (frame_sampler,1)
    self.frame_trigger = frame_start
    #terminate_stream(self, self.frame_trigger)








    ## Pilot block filter
    pb_filt = self._pilot_block_filter = fbmc_pilot_block_filter()
    self.connect(self.symbol_output,pb_filt)
    self.connect(self.frame_trigger,(pb_filt,1))

    self.frame_data_trigger = (pb_filt,1)
    
    #self.symbol_output = pb_filt
    

    #if options.log:
      #log_to_file(self, pb_filt, "data/pb_filt_out.compl")


    if config.fbmc:
        pda_in = pb_filt

    else:
        ## Pilot subcarrier filter
        ps_filt = self._pilot_subcarrier_filter = pilot_subcarrier_filter()
        self.connect(self.symbol_output,ps_filt)

        if options.log:
            log_to_file(self, ps_filt, "data/ps_filt_out.compl")
            
        pda_in = ps_filt

    


    ## Workaround to avoid periodic structure
    # for ID decoder
    seed(1)
    whitener_pn = [randint(0,1) for i in range(used_id_bits*rep_id_bits)]

    

    if not options.enable_erasure_decision:

      ## ID Block Filter
      # Filter ID block, skip data blocks
      id_bfilt = self._id_block_filter = vector_sampler(
            gr.sizeof_gr_complex * dsubc, 1 )
      if not config.frame_id_blocks == 1:
        raise SystemExit, "# ID Blocks > 1 not supported"

      self.connect(   pda_in     ,   id_bfilt      )
      self.connect( self.frame_data_trigger, ( id_bfilt, 1 ) ) # trigger

      #log_to_file( self, id_bfilt, "data/id_bfilt.compl" )

      ## ID Demapper and Decoder, soft decision
      self.id_dec = self._id_decoder = ofdm.coded_bpsk_soft_decoder( dsubc,
          used_id_bits, whitener_pn )
      self.connect( id_bfilt, self.id_dec )
      

      print "Using coded BPSK soft decoder for ID detection"


    else: # options.enable_erasure_decision:

      id_bfilt = self._id_block_filter = vector_sampler(
        gr.sizeof_gr_complex * total_subc, config.frame_id_blocks )

      id_bfilt_trig_delay = 0
      for x in range( config.frame_length ):
        if x in config.training_data.pilotsym_pos:
          id_bfilt_trig_delay += 1
        else:
          break
      print "Position of ID block within complete frame: %d" %(id_bfilt_trig_delay)

      assert( id_bfilt_trig_delay > 0 ) # else not supported

      id_bfilt_trig = blocks.delay( gr.sizeof_char, id_bfilt_trig_delay )

      self.connect( ofdm_blocks, id_bfilt )
      self.connect( orig_frame_start, id_bfilt_trig, ( id_bfilt, 1 ) )

      self.id_dec = self._id_decoder = ofdm.coded_bpsk_soft_decoder( total_subc,
          used_id_bits, whitener_pn, config.training_data.shifted_pilot_tones )
      self.connect( id_bfilt, self.id_dec )

      print "Using coded BPSK soft decoder for ID detection"

      # The threshold block either returns 1.0 if the llr-value from the
      # id decoder is below the threshold, else 0.0. Hence we convert this
      # into chars, 0 and 1, and use it as trigger for the sampler.

      min_llr = ( self.id_dec, 1 )
      erasure_threshold = gr.threshold_ff( 10.0, 10.0, 0 ) # FIXME is it the optimal threshold?
      erasure_dec = gr.float_to_char()
      id_gate = vector_sampler( gr.sizeof_short, 1 )
      ctf_gate = vector_sampler( gr.sizeof_float * total_subc, 1 )


      self.connect( self.id_dec ,       id_gate )
      self.connect( self.ctf,      ctf_gate )

      self.connect( min_llr,       erasure_threshold,  erasure_dec )
      self.connect( erasure_dec, ( frame_gate, 1 ) )
      self.connect( erasure_dec, ( id_gate,    1 ) )
      self.connect( erasure_dec, ( ctf_gate,   1 ) )

      self.id_dec = self._id_decoder = id_gate
      self.ctf = ctf_gate



      print "Erasure decision for IDs is enabled"




    if options.log:
      id_dec_f = gr.short_to_float()
      self.connect(self.id_dec,id_dec_f)
      log_to_file(self, id_dec_f, "data/id_dec_out.float")


    if options.log:
      log_to_file(self, id_bfilt, "data/id_blockfilter_out.compl")


    # TODO: refactor names




    if options.log:
      map_src_f = gr.char_to_float(dsubc)
      self.connect(map_src,map_src_f)
      log_to_file(self, map_src_f, "data/map_src_out.float")

    ## Allocation Control
    if options.static_allocation: #DEBUG
        
        if options.coding:
            mode = 1 # Coding mode 1-9
            bitspermode = [0.5,1,1.5,2,3,4,4.5,5,6] # Information bits per mode
            bitcount_vec = [(int)(config.data_subcarriers*config.frame_data_blocks*bitspermode[mode-1])]
            bitloading = mode
        else:
            bitloading = 1
            bitcount_vec = [config.data_subcarriers*config.frame_data_blocks*bitloading]
        #bitcount_vec = [config.data_subcarriers*config.frame_data_blocks]
        self.bitcount_src = blocks.vector_source_i(bitcount_vec,True,1)
        # 0s for ID block, then data
        #bitloading_vec = [0]*dsubc+[0]*(dsubc/2)+[2]*(dsubc/2)
        bitloading_vec = [0]*dsubc+[bitloading]*dsubc
        bitloading_src = blocks.vector_source_b(bitloading_vec,True,dsubc)
        power_vec = [1]*config.data_subcarriers
        power_src = blocks.vector_source_f(power_vec,True,dsubc)
    else:
        self.allocation_buffer = ofdm.allocation_buffer(config.data_subcarriers, config.frame_data_blocks, "tcp://"+options.tx_hostname+":3333",config.coding)
        self.bitcount_src = (self.allocation_buffer,0)
        bitloading_src = (self.allocation_buffer,1)
        power_src = (self.allocation_buffer,2)
        self.connect(self.id_dec, self.allocation_buffer)
        if options.benchmarking:
            self.allocation_buffer.set_allocation([4]*config.data_subcarriers,[1]*config.data_subcarriers)

    if options.log:
        log_to_file(self, self.bitcount_src, "data/bitcount_src_rx.int")
        log_to_file(self, bitloading_src, "data/bitloading_src_rx.char")
        log_to_file(self, power_src, "data/power_src_rx.cmplx")
        log_to_file(self, self.id_dec, "data/id_dec_rx.short")

    ## Power Deallocator
    pda = self._power_deallocator = multiply_frame_fc(config.frame_data_part, dsubc)
    self.connect(pda_in,(pda,0))
    self.connect(power_src,(pda,1))

    ## Demodulator
#    if 0:
#          ac_vector = [0.0+0.0j]*208
#          ac_vector[0] = (2*10**(-0.452))
#          ac_vector[3] = (10**(-0.651))
#          ac_vector[7] = (10**(-1.151))
#          csi_vector_inv=abs(numpy.fft.fft(numpy.sqrt(ac_vector)))**2
#          dm_csi = numpy.fft.fftshift(csi_vector_inv) # TODO

    dm_csi = [1]*dsubc # TODO
    dm_csi = blocks.vector_source_f(dm_csi,True)
    ## Depuncturer
    dp_trig = [0]*(config.frame_data_blocks/2)
    dp_trig[0] = 1
    dp_trig = blocks.vector_source_b(dp_trig,True) # TODO



    if(options.coding):
        fo=ofdm.fsm(1,2,[91,121])
        if options.interleave:
            int_object=trellis.interleaver(2000,666)
            deinterlv = trellis.permutation(int_object.K(),int_object.DEINTER(),1,gr.sizeof_float)
        
        demod = self._data_demodulator = generic_softdemapper_vcf(dsubc, config.frame_data_part, config.coding)
        #self.connect(dm_csi,blocks.stream_to_vector(gr.sizeof_float,dsubc),(demod,2))
        if(options.ideal):
            self.connect(dm_csi,blocks.stream_to_vector(gr.sizeof_float,dsubc),(demod,2))
        else:
            dm_csi_filter = self.dm_csi_filter = filter.single_pole_iir_filter_ff(0.01,dsubc)
            self.connect(self.ctf, self.dm_csi_filter,(demod,2))
            #log_to_file(self, dm_csi_filter, "data/softs_csi.float")
        #self.connect(dm_trig,(demod,3))
    else:
        demod = self._data_demodulator = generic_demapper_vcb(dsubc, config.frame_data_part)
    if options.benchmarking:
        # Do receiver benchmarking until the number of frames x symbols are collected
        self.connect(pda,blocks.head(gr.sizeof_gr_complex*dsubc, options.N*config.frame_data_blocks),demod)
    else:        
        self.connect(pda,demod)
    self.connect(bitloading_src,(demod,1))

    if(options.coding):
        ## Depuncturing
        if not options.nopunct:
            depuncturing = depuncture_ff(dsubc,0)
            frametrigger_bitmap_filter = blocks.vector_source_b([1,0],True)
            self.connect(bitloading_src,(depuncturing,1))
            self.connect(dp_trig,(depuncturing,2))

        ## Decoding
        chunkdivisor = int(numpy.ceil(config.frame_data_blocks/5.0))
        print "Number of chunks at Viterbi decoder: ", chunkdivisor
        decoding = self._data_decoder = ofdm.viterbi_combined_fb(fo,dsubc,-1,-1,2,chunkdivisor,[-1,-1,-1,1,1,-1,1,1],ofdm.TRELLIS_EUCLIDEAN)

        
        if options.log and options.coding:
            log_to_file(self, decoding, "data/decoded.char")
            if not options.nopunct:
                log_to_file(self, depuncturing, "data/vit_in.float")

        if not options.nopunct:
            if options.interleave:
                self.connect(demod,deinterlv,depuncturing,decoding)
            else:
                self.connect(demod,depuncturing,decoding)
        else:
            self.connect(demod,decoding)
        self.connect(self.bitcount_src, multiply_const_ii(1./chunkdivisor), (decoding,1))

    if options.scatterplot or options.scatter_plot_before_phase_tracking:
        if self.ideal2 is False:
            scatter_vec_elem = self._scatter_vec_elem = ofdm.vector_element(dsubc,40)
            scatter_s2v = self._scatter_s2v = blocks.stream_to_vector(gr.sizeof_gr_complex,config.frame_data_blocks)
    
            scatter_id_filt = skip(gr.sizeof_gr_complex*dsubc,config.frame_data_blocks)
            scatter_id_filt.skip_call(0)
            scatter_trig = [0]*config.frame_data_part
            scatter_trig[0] = 1
            scatter_trig = blocks.vector_source_b(scatter_trig,True)
            self.connect(scatter_trig,(scatter_id_filt,1))
            self.connect(scatter_vec_elem,scatter_s2v)
    
            if not options.scatter_plot_before_phase_tracking:
                print "Enabling Scatterplot for data subcarriers"
                self.connect(pda,scatter_id_filt,scatter_vec_elem)
                  # Work on this
                  #scatter_sink = ofdm.scatterplot_sink(dsubc)
                  #self.connect(pda,scatter_sink)
                  #self.connect(map_src,(scatter_sink,1))
                  #self.connect(dm_trig,(scatter_sink,2))
                  #print "Enabled scatterplot gui interface"
                self.zmq_probe_scatter = zeromq.pub_sink(gr.sizeof_gr_complex,config.frame_data_blocks, "tcp://*:5560")
                self.connect(scatter_s2v, blocks.keep_one_in_n(gr.sizeof_gr_complex*config.frame_data_blocks,20), self.zmq_probe_scatter)
            else:
                print "Enabling Scatterplot for data before phase tracking"
                inner_rx = inner_receiver.before_phase_tracking
                #scatter_sink2 = ofdm.scatterplot_sink(dsubc,"phase_tracking")
                op = copy.copy(options)
                op.enable_erasure_decision = False
                new_framesampler = ofdm_frame_sampler(op)
                self.connect( inner_rx, new_framesampler )
                self.connect( orig_frame_start, (new_framesampler,1) )
                new_ps_filter = pilot_subcarrier_filter()
                new_pb_filter = fbmc_pilot_block_filter()
    
                self.connect( (new_framesampler,1), (new_pb_filter,1) )
                self.connect( new_framesampler, new_pb_filter,
                             new_ps_filter, scatter_id_filt, scatter_vec_elem )
    
                #self.connect( new_ps_filter, scatter_sink2 )
                #self.connect( map_src, (scatter_sink2,1))
                #self.connect( dm_trig, (scatter_sink2,2))


    if options.log:
      if(options.coding):
          log_to_file(self, demod, "data/data_stream_out.float")
      else:
          data_f = gr.char_to_float()
          self.connect(demod,data_f)
          log_to_file(self, data_f, "data/data_stream_out.float")



    if options.sfo_feedback:
      used_id_bits = 8
      rep_id_bits = config.data_subcarriers/used_id_bits

      seed(1)
      whitener_pn = [randint(0,1) for i in range(used_id_bits*rep_id_bits)]

      id_enc = ofdm.repetition_encoder_sb(used_id_bits,rep_id_bits,whitener_pn)
      self.connect( self.id_dec, id_enc )

      id_mod = ofdm_bpsk_modulator(dsubc)
      self.connect( id_enc, id_mod )

      id_mod_conj = gr.conjugate_cc(dsubc)
      self.connect( id_mod, id_mod_conj )

      id_mult = blocks.multiply_vcc(dsubc)
      self.connect( id_bfilt, ( id_mult,0) )
      self.connect( id_mod_conj, ( id_mult,1) )

#      id_mult_avg = filter.single_pole_iir_filter_cc(0.01,dsubc)
#      self.connect( id_mult, id_mult_avg )

      id_phase = gr.complex_to_arg(dsubc)
      self.connect( id_mult, id_phase )

      log_to_file( self, id_phase, "data/id_phase.float" )

      est=ofdm.LS_estimator_straight_slope(dsubc)
      self.connect(id_phase,est)

      slope=blocks.multiply_const_ff(1e6/2/3.14159265)
      self.connect( (est,0), slope )

      log_to_file( self, slope, "data/slope.float" )
      log_to_file( self, (est,1), "data/offset.float" )

    # ------------------------------------------------------------------------ #




    # Display some information about the setup
    if config._verbose:
      self._print_verbage()

    ## debug logging ##
    if options.log:
#      log_to_file(self,self.ofdm_symbols,"data/unequalized_rx_ofdm_symbols.compl")
#      log_to_file(self,self.ofdm_symbols,"data/unequalized_rx_ofdm_symbols.float",mag=True)


      fftlen = 256
      my_window = window.hamming(fftlen) #.blackmanharris(fftlen)
      rxs_sampler = vector_sampler(gr.sizeof_gr_complex,fftlen)
      rxs_sampler_vect = concatenate([[1],[0]*49])
      rxs_trigger = blocks.vector_source_b(rxs_sampler_vect.tolist(),True)
      rxs_window = blocks.multiply_const_vcc(my_window)
      rxs_spectrum = gr.fft_vcc(fftlen,True,[],True)
      rxs_mag = gr.complex_to_mag(fftlen)
      rxs_avg = filter.single_pole_iir_filter_ff(0.01,fftlen)
      #rxs_logdb = blocks.nlog10_ff(20.0,fftlen,-20*log10(fftlen))
      rxs_logdb = gr.kludge_copy( gr.sizeof_float * fftlen )
      rxs_decimate_rate = gr.keep_one_in_n(gr.sizeof_float*fftlen,1)
      self.connect(rxs_trigger,(rxs_sampler,1))
      self.connect(self.input,rxs_sampler,rxs_window,
                   rxs_spectrum,rxs_mag,rxs_avg,rxs_logdb, rxs_decimate_rate)
      log_to_file( self, rxs_decimate_rate, "data/psd_input.float" )


    #output branches
    self.publish_rx_performance_measure()
Example #35
0
    def __init__(self, options, log=False):

        ## Read configuration
        config = station_configuration()

        fft_length = config.fft_length
        cp_length = config.cp_length
        block_header = config.training_data
        data_subc = config.data_subcarriers
        virtual_subc = config.virtual_subcarriers
        total_subc = config.subcarriers
        block_length = config.block_length
        frame_length = config.frame_length

        L = block_header.mm_periodic_parts

        frame_data_blocks = options.data_blocks

        ## Set Input/Output signature
        gr.hier_block2.__init__(
            self,
            "ofdm_inner_receiver",
            gr.io_signature(2, 2, gr.sizeof_gr_complex),
            gr.io_signature5(
                5,
                5,
                gr.sizeof_gr_complex * total_subc,  # OFDM blocks
                gr.sizeof_char,  # Frame start
                gr.sizeof_float * total_subc,  # Normalized |CTF|^2
                gr.sizeof_char,  # Frame start
                gr.sizeof_float * total_subc))  # Normalized |CTF|^2

        ## Input and output ports
        self.input = rx_input = (self, 0)
        self.input2 = rx2_input = (self, 1)

        out_ofdm_blocks = (self, 0)
        out_frame_start = (self, 1)
        out_disp_ctf = (self, 2)
        out_frame_start2 = (self, 3)
        out_disp_ctf2 = (self, 4)

        ## pre-FFT processing

        ## Compute autocorrelations for S&C preamble
        ## and cyclic prefix
        sc_metric = autocorrelator(fft_length / 2, fft_length / 2)
        gi_metric = autocorrelator(fft_length, cp_length)

        self.connect(rx_input, sc_metric)
        self.connect(rx_input, gi_metric)

        sc_metric2 = autocorrelator(fft_length / 2, fft_length / 2)
        gi_metric2 = autocorrelator(fft_length, cp_length)

        self.connect(rx2_input, sc_metric2)
        self.connect(rx2_input, gi_metric2)

        ## Sync. Output contains OFDM blocks
        sync = ofdm.time_sync(fft_length, cp_length)
        self.connect(rx_input, (sync, 0))
        self.connect(sc_metric, (sync, 1))
        self.connect(gi_metric, (sync, 2))
        ofdm_blocks = (sync, 0)
        frame_start = (sync, 1)

        sync2 = ofdm.time_sync(fft_length, cp_length)
        self.connect(rx2_input, (sync2, 0))
        self.connect(sc_metric2, (sync2, 1))
        self.connect(gi_metric2, (sync2, 2))
        ofdm_blocks2 = (sync2, 0)
        frame_start2 = (sync2, 1)

        if options.disable_time_sync or options.ideal:
            terminate_stream(self, ofdm_blocks)
            terminate_stream(self, ofdm_blocks2)
            terminate_stream(self, frame_start)
            terminate_stream(self, frame_start2)

            serial_to_parallel = blocks.stream_to_vector(
                gr.sizeof_gr_complex, block_length)
            serial_to_parallel2 = blocks.stream_to_vector(
                gr.sizeof_gr_complex, block_length)
            discard_cp = ofdm.vector_mask(block_length, cp_length, fft_length,
                                          [])
            discard_cp2 = ofdm.vector_mask(block_length, cp_length, fft_length,
                                           [])
            ofdm_blocks = discard_cp
            ofdm_blocks2 = discard_cp2
            self.connect(rx_input, serial_to_parallel, discard_cp)
            self.connect(rx2_input, serial_to_parallel2, discard_cp2)

            frame_start = [0] * frame_length
            frame_start[0] = 1
            frame_start = blocks.vector_source_b(frame_start, True)
            frame_start2 = [0] * frame_length
            frame_start2[0] = 1
            frame_start2 = blocks.vector_source_b(frame_start2, True)

            print "Disabled time synchronization stage"

        ## Extract preamble, feed to Morelli & Mengali frequency offset estimator
        assert (block_header.mm_preamble_pos == 0)
        morelli_foe = ofdm.mm_frequency_estimator(fft_length, L)
        sampler_preamble = ofdm.vector_sampler(
            gr.sizeof_gr_complex * fft_length, 1)
        self.connect(ofdm_blocks, (sampler_preamble, 0))
        self.connect(frame_start, (sampler_preamble, 1))
        self.connect(sampler_preamble, morelli_foe)
        freq_offset = morelli_foe

        morelli_foe2 = ofdm.mm_frequency_estimator(fft_length, L)
        sampler_preamble2 = ofdm.vector_sampler(
            gr.sizeof_gr_complex * fft_length, 1)
        self.connect(ofdm_blocks2, (sampler_preamble2, 0))
        self.connect(frame_start2, (sampler_preamble2, 1))
        self.connect(sampler_preamble2, morelli_foe2)
        freq_offset2 = morelli_foe2

        ## Adaptive LMS FIR filtering of frequency offset
        lms_fir = ofdm.lms_fir_ff(20, 1e-3)  # TODO: verify parameter choice
        self.connect(freq_offset, lms_fir)
        freq_offset = lms_fir

        lms_fir2 = ofdm.lms_fir_ff(20, 1e-3)  # TODO: verify parameter choice
        self.connect(freq_offset2, lms_fir2)
        freq_offset2 = lms_fir2

        #    log_to_file(self, lms_fir, "data/lms_fir.float")
        #    log_to_file(self, lms_fir2, "data/lms_fir2.float")

        if options.disable_freq_sync or options.ideal:
            terminate_stream(self, freq_offset)
            terminate_stream(self, freq_offset2)
            freq_offset = blocks.vector_source_f([0.0], True)
            freq_offset2 = blocks.vector_source_f([0.0], True)
            print "Disabled frequency synchronization stage"

        ## Correct frequency shift, feed-forward structure
        frequency_shift = ofdm.frequency_shift_vcc(fft_length,
                                                   -1.0 / fft_length,
                                                   cp_length)
        self.connect(ofdm_blocks, (frequency_shift, 0))
        self.connect(freq_offset, (frequency_shift, 1))
        self.connect(frame_start, (frequency_shift, 2))
        ofdm_blocks = frequency_shift

        frequency_shift2 = ofdm.frequency_shift_vcc(fft_length,
                                                    -1.0 / fft_length,
                                                    cp_length)
        self.connect(ofdm_blocks2, (frequency_shift2, 0))
        self.connect(freq_offset2, (frequency_shift2, 1))
        self.connect(frame_start2, (frequency_shift2, 2))
        ofdm_blocks2 = frequency_shift2

        ## FFT
        fft = fft_blocks.fft_vcc(fft_length, True, [], True)
        self.connect(ofdm_blocks, fft)
        ofdm_blocks = fft

        fft2 = fft_blocks.fft_vcc(fft_length, True, [], True)
        self.connect(ofdm_blocks2, fft2)
        ofdm_blocks2 = fft2

        ## Remove virtual subcarriers
        if fft_length > data_subc:
            subcarrier_mask = ofdm.vector_mask(fft_length, virtual_subc / 2,
                                               total_subc, [])
            self.connect(ofdm_blocks, subcarrier_mask)
            ofdm_blocks = subcarrier_mask

            subcarrier_mask2 = ofdm.vector_mask(fft_length, virtual_subc / 2,
                                                total_subc, [])
            self.connect(ofdm_blocks2, subcarrier_mask2)
            ofdm_blocks2 = subcarrier_mask2

            ## Least Squares estimator for channel transfer function (CTF)

            # if options.logcir:
            # log_to_file( self, ofdm_blocks, "data/OFDM_Blocks.compl" )

            # inv_preamble_fd = numpy.array( block_header.pilotsym_fd[
            # block_header.channel_estimation_pilot[0] ] )
            # print "Channel estimation pilot: ", inv_preamble_fd
            # inv_preamble_fd = 1. / inv_preamble_fd
            # LS_channel_estimator0 = ofdm.multiply_const_vcc( list( inv_preamble_fd ) )
            # self.connect( ofdm_blocks, LS_channel_estimator0, blocks.null_sink(gr.sizeof_gr_complex*total_subc))
            # log_to_file( self, LS_channel_estimator0, "data/OFDM_Blocks_eq.compl" )

        ## post-FFT processing

        if options.est_preamble == 1:
            ## extract channel estimation preamble from frame
            chest_pre_trigger = blocks.delay(gr.sizeof_char, 1)
            sampled_chest_preamble = \
              ofdm.vector_sampler( gr.sizeof_gr_complex * total_subc, 1 )
            self.connect(frame_start, chest_pre_trigger)
            self.connect(chest_pre_trigger, (sampled_chest_preamble, 1))
            self.connect(ofdm_blocks, (sampled_chest_preamble, 0))

            chest_pre_trigger2 = blocks.delay(gr.sizeof_char, 1)
            sampled_chest_preamble2 = \
              ofdm.vector_sampler( gr.sizeof_gr_complex * total_subc, 1 )
            self.connect(frame_start2, chest_pre_trigger2)
            self.connect(chest_pre_trigger2, (sampled_chest_preamble2, 1))
            self.connect(ofdm_blocks2, (sampled_chest_preamble2, 0))

            ## Least Squares estimator for channel transfer function (CTF)

            # Taking inverse for estimating h11 (h12)
            inv_preamble_fd_1 = numpy.array(block_header.pilotsym_fd_1[
                block_header.channel_estimation_pilot[0]])
            inv_preamble_fd_1 = inv_preamble_fd_1[0::2]

            # Taking inverse for estimating h21 (h22)
            inv_preamble_fd_2 = numpy.array(block_header.pilotsym_fd_2[
                block_header.channel_estimation_pilot[0]])
            inv_preamble_fd_2 = inv_preamble_fd_2[1::2]

            inv_preamble_fd_1 = 1. / inv_preamble_fd_1
            inv_preamble_fd_2 = 1. / inv_preamble_fd_2

            ## Least Squares estimator for channel transfer function (CTF)

            dd = []
            for i in range(total_subc / 2):
                dd.extend([i * 2])

            skip_block_1 = ofdm.int_skip(total_subc, 2, 0)
            skip_block_2 = ofdm.int_skip(total_subc, 2, 1)
            #    inta_estim_1 = ofdm.interpolator(total_subc,2,dd)
            #    inta_estim_2 = ofdm.interpolator(total_subc,2,dd)

            LS_channel_estimator_1 = ofdm.multiply_const_vcc(
                list(inv_preamble_fd_1))
            LS_channel_estimator_2 = ofdm.multiply_const_vcc(
                list(inv_preamble_fd_2))
            self.connect(sampled_chest_preamble, skip_block_1,
                         LS_channel_estimator_1)  #,inta_estim_1 )
            self.connect(sampled_chest_preamble, skip_block_2,
                         LS_channel_estimator_2)  #,inta_estim_2 )

            estimated_CTF_1 = LS_channel_estimator_1  # h0
            estimated_CTF_2 = LS_channel_estimator_2  # h1

            skip_block_3 = ofdm.int_skip(total_subc, 2, 0)
            skip_block_4 = ofdm.int_skip(total_subc, 2, 1)
            #    inta_estim_3 = ofdm.interpolator(total_subc,2,dd)
            #    inta_estim_4 = ofdm.interpolator(total_subc,2,dd)

            LS_channel_estimator_3 = ofdm.multiply_const_vcc(
                list(inv_preamble_fd_1))
            LS_channel_estimator_4 = ofdm.multiply_const_vcc(
                list(inv_preamble_fd_2))

            self.connect(sampled_chest_preamble2, skip_block_3,
                         LS_channel_estimator_3)  #,inta_estim_3 )
            self.connect(sampled_chest_preamble2, skip_block_4,
                         LS_channel_estimator_4)  #,inta_estim_4 )

            estimated_CTF_3 = LS_channel_estimator_3  # h2
            estimated_CTF_4 = LS_channel_estimator_4  # h3

            if not options.disable_ctf_enhancer:

                # if options.logcir:
                # ifft1 = fft_blocks.fft_vcc(total_subc,False,[],True)
                # self.connect( estimated_CTF, ifft1,blocks.null_sink(gr.sizeof_gr_complex*total_subc))
                # summ1 = ofdm.vector_sum_vcc(total_subc)
                # c2m =gr.complex_to_mag(total_subc)
                # self.connect( estimated_CTF,summ1 ,blocks.null_sink(gr.sizeof_gr_complex))
                # self.connect( estimated_CTF, c2m,blocks.null_sink(gr.sizeof_float*total_subc))
                # log_to_file( self, ifft1, "data/CIR1.compl" )
                # log_to_file( self, summ1, "data/CTFsumm1.compl" )
                # log_to_file( self, estimated_CTF, "data/CTF1.compl" )
                # log_to_file( self, c2m, "data/CTFmag1.float" )

                ## MSE enhancer
                ctf_mse_enhancer_1 = ofdm.CTF_MSE_enhancer(
                    total_subc, cp_length + cp_length)
                ctf_mse_enhancer_2 = ofdm.CTF_MSE_enhancer(
                    total_subc, cp_length + cp_length)
                self.connect(estimated_CTF_1, ctf_mse_enhancer_1)
                self.connect(estimated_CTF_2, ctf_mse_enhancer_2)

                ctf_mse_enhancer_3 = ofdm.CTF_MSE_enhancer(
                    total_subc, cp_length + cp_length)
                ctf_mse_enhancer_4 = ofdm.CTF_MSE_enhancer(
                    total_subc, cp_length + cp_length)
                self.connect(estimated_CTF_3, ctf_mse_enhancer_3)
                self.connect(estimated_CTF_4, ctf_mse_enhancer_4)

                estimated_CTF_1 = ctf_mse_enhancer_1
                estimated_CTF_2 = ctf_mse_enhancer_2

                estimated_CTF_3 = ctf_mse_enhancer_3
                estimated_CTF_4 = ctf_mse_enhancer_4
                print "Disabled CTF MSE enhancer"

            ctf_postprocess_1 = ofdm.postprocess_CTF_estimate(total_subc / 2)
            self.connect(estimated_CTF_1, (ctf_postprocess_1, 0))
            ctf_postprocess_2 = ofdm.postprocess_CTF_estimate(total_subc / 2)
            self.connect(estimated_CTF_2, (ctf_postprocess_2, 0))
            ctf_postprocess_3 = ofdm.postprocess_CTF_estimate(total_subc / 2)
            self.connect(estimated_CTF_3, (ctf_postprocess_3, 0))
            ctf_postprocess_4 = ofdm.postprocess_CTF_estimate(total_subc / 2)
            self.connect(estimated_CTF_4, (ctf_postprocess_4, 0))

            inv_CTF_1 = (ctf_postprocess_1, 0)
            disp_CTF_1 = (ctf_postprocess_1, 1)
            inv_CTF_2 = (ctf_postprocess_2, 0)
            disp_CTF_2 = (ctf_postprocess_2, 1)
            inv_CTF_3 = (ctf_postprocess_3, 0)
            disp_CTF_3 = (ctf_postprocess_3, 1)
            inv_CTF_4 = (ctf_postprocess_4, 0)
            disp_CTF_4 = (ctf_postprocess_4, 1)

            disp_CTF_RX0 = blocks.add_ff(total_subc / 2)
            disp_CTF_RX1 = blocks.add_ff(total_subc / 2)

            self.connect(disp_CTF_1, (disp_CTF_RX0, 0))
            self.connect(disp_CTF_2, (disp_CTF_RX0, 1))
            self.connect(disp_CTF_3, (disp_CTF_RX1, 0))
            self.connect(disp_CTF_4, (disp_CTF_RX1, 1))

            terminate_stream(self, disp_CTF_RX0)
            terminate_stream(self, disp_CTF_RX1)

            disp_CTF_RX0 = blocks.null_source(gr.sizeof_float * total_subc)
            disp_CTF_RX1 = blocks.null_source(gr.sizeof_float * total_subc)
            ## Channel Equalizer

            #log_to_file(self, ofdm_blocks, "data/vec_mask.compl")
            #log_to_file(self, ofdm_blocks2, "data/vec_mask2.compl")

            nondata_blocks = []
            for i in range(config.frame_length):
                if i in config.training_data.pilotsym_pos:
                    nondata_blocks.append(i)

            pilot_subc = block_header.pilot_tones
            pilot_subcarriers = block_header.pilot_subc_sym
            print "PILOT SUBCARRIERS: ", pilot_subcarriers

            phase_tracking = ofdm.lms_phase_tracking_03(
                total_subc, pilot_subc, nondata_blocks, pilot_subcarriers, 0)
            phase_tracking2 = ofdm.lms_phase_tracking_03(
                total_subc, pilot_subc, nondata_blocks, pilot_subcarriers, 0)

            ##phase_tracking = ofdm.LMS_phase_tracking2( total_subc, pilot_subc,
            ##                                          nondata_blocks )
            ##phase_tracking2 = ofdm.LMS_phase_tracking2( total_subc, pilot_subc,
            ##                                           nondata_blocks )

            #    self.connect( ofdm_blocks,          ( phase_tracking, 0 ) )
            #    self.connect( ofdm_blocks2,          ( phase_tracking, 1 ))
            #    self.connect( inv_CTF_1,            ( phase_tracking, 2 ) )
            #    self.connect( inv_CTF_3,            ( phase_tracking, 3 ) )
            #    self.connect( frame_start,            ( phase_tracking, 4 ) )
            #    self.connect( frame_start2,            ( phase_tracking, 5) )
            #
            #    self.connect( ofdm_blocks2,          ( phase_tracking2, 0 ) )
            #    self.connect( ofdm_blocks,          ( phase_tracking2, 1 ))
            #    self.connect( inv_CTF_3,            ( phase_tracking2, 2 ) )
            #    self.connect( inv_CTF_1,            ( phase_tracking2, 3 ) )
            #    self.connect( frame_start2,            ( phase_tracking2, 4 ) )
            #    self.connect( frame_start,            ( phase_tracking2, 5 ) )

            self.connect(ofdm_blocks, (phase_tracking, 0))
            self.connect(inv_CTF_1, (phase_tracking, 1))
            self.connect(frame_start, (phase_tracking, 2))

            self.connect(ofdm_blocks2, (phase_tracking2, 0))
            self.connect(inv_CTF_3, (phase_tracking2, 1))
            self.connect(frame_start2, (phase_tracking2, 2))

            #ofdm_blocks = phase_tracking
            #ofdm_blocks2 = phase_tracking2
            self.connect(phase_tracking,
                         blocks.null_sink(gr.sizeof_gr_complex * total_subc))
            self.connect(phase_tracking2,
                         blocks.null_sink(gr.sizeof_gr_complex * total_subc))

            terminate_stream(self, inv_CTF_2)
            terminate_stream(self, inv_CTF_4)
            #terminate_stream(self, inv_CTF_1)
            #terminate_stream(self, inv_CTF_3)
            terminate_stream(self, estimated_CTF_3)
            terminate_stream(self, estimated_CTF_4)
            ##terminate_stream(self, (phase_tracking,1))
            ##terminate_stream(self, (phase_tracking2,1))
            '''equalizer = ofdm.channel_equalizer_mimo_2( total_subc )
        self.connect(  ofdm_blocks,         ( equalizer, 0 ) )
        self.connect(  ofdm_blocks2,        ( equalizer, 1 ) )
        self.connect( inv_CTF_1,            ( equalizer, 2 ) )
        self.connect( inv_CTF_2,            ( equalizer, 3 ) )
        self.connect( inv_CTF_3,            ( equalizer, 4 ) )
        self.connect( inv_CTF_4,            ( equalizer, 5 ) )
        self.connect( frame_start,          ( equalizer, 6 ) )
        self.connect( frame_start2,         ( equalizer, 7 ) )
        ofdm_blocks = equalizer'''

            terminate_stream(self, inv_CTF_1)
            terminate_stream(self, inv_CTF_3)

            equalizer = ofdm.channel_equalizer_mimo_2(total_subc)
            self.connect(ofdm_blocks, (equalizer, 0))
            self.connect(estimated_CTF_1, (equalizer, 1))
            self.connect(estimated_CTF_2, (equalizer, 2))
            self.connect(frame_start, (equalizer, 3))
            ofdm_blocks = equalizer

            equalizer2 = ofdm.channel_equalizer_mimo_2(total_subc)
            self.connect(ofdm_blocks2, (equalizer2, 0))
            self.connect(estimated_CTF_3, (equalizer2, 1))
            self.connect(estimated_CTF_4, (equalizer2, 2))
            self.connect(frame_start2, (equalizer2, 3))
            ofdm_blocks2 = equalizer2

            #ofdm_blocks = equalizer
            #ofdm_blocks2 = equalizer2

            #log_to_file(self, equalizer,"data/equalizer.compl")
            #log_to_file(self, ofdm_blocks2,"data/equalizer.compl")
            #log_to_file(self, ofdm_blocks,"data/equalizer2.compl")

            ## LMS Phase tracking
            ## Track residual frequency offset and sampling clock frequency offset
            '''
        nondata_blocks = []
        for i in range(config.frame_length):
          if i in config.training_data.pilotsym_pos:
            nondata_blocks.append(i)
            
        pilot_subc = block_header.pilot_tones
            
        phase_tracking = ofdm.LMS_phase_tracking2( total_subc, pilot_subc,
                                                   nondata_blocks )
        self.connect( equalizer, ( phase_tracking, 0 ) )
        self.connect( frame_start, ( phase_tracking, 1 ) )
        
        phase_tracking2 = ofdm.LMS_phase_tracking2( total_subc, pilot_subc,
                                                    nondata_blocks )
        self.connect( equalizer2, ( phase_tracking2, 0 ) )
        self.connect( frame_start2, ( phase_tracking2, 1 ) )
        
        # if options.scatter_plot_before_phase_tracking:
          # self.before_phase_tracking = equalizer
          
        
        if options.disable_phase_tracking or options.ideal:
          terminate_stream(self, phase_tracking)
          terminate_stream(self, phase_tracking2)
          print "Disabled phase tracking stage"
        else:
          ofdm_blocks = phase_tracking
          ofdm_blocks2 = phase_tracking2
          
        log_to_file(self,phase_tracking, "data/phase_tracking.compl")
        '''

            combine = blocks.add_cc(config.subcarriers)
            self.connect(ofdm_blocks, (combine, 0))
            self.connect(ofdm_blocks2, (combine, 1))

            norm_val = [0.5] * 208
            norm = ofdm.multiply_const_vcc(norm_val)
            self.connect(combine, norm)

            ofdm_blocks = norm
            ##    div = gr.multiply_cc(config.subcarriers)
            ##    const = blocks.vector_source_c([[0.5+0]*config.subcarriers],True)
            ##    self.connect(ofdm_blocks,div)
            ##    self.connect(const,(div,1))
            ##    ofdm_blocks=div
            #    log_to_file(self,combine,"data/combine.compl")
            ## Output connections

            self.connect(ofdm_blocks, out_ofdm_blocks)
            self.connect(frame_start, out_frame_start)
            self.connect(disp_CTF_RX0, out_disp_ctf)
            self.connect(frame_start2, out_frame_start2)
            self.connect(disp_CTF_RX1, out_disp_ctf2)

        else:
            ## extract channel estimation preamble from frame

            chest_pre_trigger_11 = blocks.delay(gr.sizeof_char, 1)
            chest_pre_trigger_12 = blocks.delay(gr.sizeof_char, 2)
            sampled_chest_preamble_11 = \
              ofdm.vector_sampler( gr.sizeof_gr_complex * total_subc, 1 )
            sampled_chest_preamble_12 = \
              ofdm.vector_sampler( gr.sizeof_gr_complex * total_subc, 1 )

            self.connect(frame_start, chest_pre_trigger_11)
            self.connect(chest_pre_trigger_11, (sampled_chest_preamble_11, 1))
            self.connect(ofdm_blocks, (sampled_chest_preamble_11, 0))

            self.connect(frame_start, chest_pre_trigger_12)
            self.connect(chest_pre_trigger_12, (sampled_chest_preamble_12, 1))
            self.connect(ofdm_blocks, (sampled_chest_preamble_12, 0))

            chest_pre_trigger_21 = blocks.delay(gr.sizeof_char, 1)
            chest_pre_trigger_22 = blocks.delay(gr.sizeof_char, 2)
            sampled_chest_preamble_21 = \
              ofdm.vector_sampler( gr.sizeof_gr_complex * total_subc, 1 )
            sampled_chest_preamble_22 = \
              ofdm.vector_sampler( gr.sizeof_gr_complex * total_subc, 1 )

            self.connect(frame_start2, chest_pre_trigger_21)
            self.connect(chest_pre_trigger_21, (sampled_chest_preamble_21, 1))
            self.connect(ofdm_blocks2, (sampled_chest_preamble_21, 0))

            self.connect(frame_start2, chest_pre_trigger_22)
            self.connect(chest_pre_trigger_22, (sampled_chest_preamble_22, 1))
            self.connect(ofdm_blocks2, (sampled_chest_preamble_22, 0))

            # Taking inverse for estimating h11 (h12)
            inv_preamble_fd_1 = numpy.array(block_header.pilotsym_fd_1[
                block_header.channel_estimation_pilot[0]])
            #inv_preamble_fd_1 = inv_preamble_fd_1[0::2]

            # Taking inverse for estimating h21 (h22)
            inv_preamble_fd_2 = numpy.array(block_header.pilotsym_fd_2[
                block_header.channel_estimation_pilot[0] + 1])
            #inv_preamble_fd_2 = inv_preamble_fd_2[1::2]

            inv_preamble_fd_1 = 1. / inv_preamble_fd_1
            inv_preamble_fd_2 = 1. / inv_preamble_fd_2

            # dd = []
            #for i in range (total_subc/2):
            # dd.extend([i*2])

            skip_block_11 = ofdm.int_skip(total_subc, 2, 0)
            skip_block_111 = ofdm.int_skip(total_subc, 2, 0)
            skip_block_12 = ofdm.int_skip(total_subc, 2, 1)
            #    inta_estim_1 = ofdm.interpolator(total_subc,2,dd)
            #    inta_estim_2 = ofdm.interpolator(total_subc,2,dd)

            LS_channel_estimator_11 = ofdm.multiply_const_vcc(
                list(inv_preamble_fd_1))
            LS_channel_estimator_12 = ofdm.multiply_const_vcc(
                list(inv_preamble_fd_2))
            self.connect(sampled_chest_preamble_11,
                         LS_channel_estimator_11)  #,inta_estim_1 )
            self.connect(sampled_chest_preamble_12,
                         LS_channel_estimator_12)  #,inta_estim_2 )

            estimated_CTF_11 = LS_channel_estimator_11  # h0
            estimated_CTF_12 = LS_channel_estimator_12  # h1

            skip_block_21 = ofdm.int_skip(total_subc, 2, 0)
            skip_block_211 = ofdm.int_skip(total_subc, 2, 0)
            skip_block_22 = ofdm.int_skip(total_subc, 2, 1)
            #    inta_estim_3 = ofdm.interpolator(total_subc,2,dd)
            #    inta_estim_4 = ofdm.interpolator(total_subc,2,dd)

            LS_channel_estimator_21 = ofdm.multiply_const_vcc(
                list(inv_preamble_fd_1))
            LS_channel_estimator_22 = ofdm.multiply_const_vcc(
                list(inv_preamble_fd_2))

            self.connect(sampled_chest_preamble_21,
                         LS_channel_estimator_21)  #,inta_estim_3 )
            self.connect(sampled_chest_preamble_22,
                         LS_channel_estimator_22)  #,inta_estim_4 )

            estimated_CTF_21 = LS_channel_estimator_21  # h2
            estimated_CTF_22 = LS_channel_estimator_22  # h3

            if not options.disable_ctf_enhancer:

                # if options.logcir:
                # ifft1 = fft_blocks.fft_vcc(total_subc,False,[],True)
                # self.connect( estimated_CTF, ifft1,blocks.null_sink(gr.sizeof_gr_complex*total_subc))
                # summ1 = ofdm.vector_sum_vcc(total_subc)
                # c2m =gr.complex_to_mag(total_subc)
                # self.connect( estimated_CTF,summ1 ,blocks.null_sink(gr.sizeof_gr_complex))
                # self.connect( estimated_CTF, c2m,blocks.null_sink(gr.sizeof_float*total_subc))
                # log_to_file( self, ifft1, "data/CIR1.compl" )
                # log_to_file( self, summ1, "data/CTFsumm1.compl" )
                # log_to_file( self, estimated_CTF, "data/CTF1.compl" )
                # log_to_file( self, c2m, "data/CTFmag1.float" )

                ## MSE enhancer
                ctf_mse_enhancer_11 = ofdm.CTF_MSE_enhancer(
                    total_subc, cp_length + cp_length)
                ctf_mse_enhancer_12 = ofdm.CTF_MSE_enhancer(
                    total_subc, cp_length + cp_length)
                self.connect(estimated_CTF_11, ctf_mse_enhancer_11)
                self.connect(estimated_CTF_12, ctf_mse_enhancer_12)

                ctf_mse_enhancer_21 = ofdm.CTF_MSE_enhancer(
                    total_subc, cp_length + cp_length)
                ctf_mse_enhancer_22 = ofdm.CTF_MSE_enhancer(
                    total_subc, cp_length + cp_length)
                self.connect(estimated_CTF_21, ctf_mse_enhancer_21)
                self.connect(estimated_CTF_22, ctf_mse_enhancer_22)

                estimated_CTF_11 = ctf_mse_enhancer_11
                estimated_CTF_12 = ctf_mse_enhancer_12

                estimated_CTF_21 = ctf_mse_enhancer_21
                estimated_CTF_22 = ctf_mse_enhancer_22
                print "Disabled CTF MSE enhancer"

            ctf_postprocess_11 = ofdm.postprocess_CTF_estimate(total_subc)
            self.connect(estimated_CTF_11, (ctf_postprocess_11, 0))
            ctf_postprocess_12 = ofdm.postprocess_CTF_estimate(total_subc)
            self.connect(estimated_CTF_12, (ctf_postprocess_12, 0))

            ctf_postprocess_21 = ofdm.postprocess_CTF_estimate(total_subc)
            self.connect(estimated_CTF_21, (ctf_postprocess_21, 0))
            ctf_postprocess_22 = ofdm.postprocess_CTF_estimate(total_subc)
            self.connect(estimated_CTF_22, (ctf_postprocess_22, 0))

            inv_CTF_11 = (ctf_postprocess_11, 0)
            disp_CTF_11 = (ctf_postprocess_11, 1)
            inv_CTF_12 = (ctf_postprocess_12, 0)
            disp_CTF_12 = (ctf_postprocess_12, 1)
            inv_CTF_21 = (ctf_postprocess_21, 0)
            disp_CTF_21 = (ctf_postprocess_21, 1)
            inv_CTF_22 = (ctf_postprocess_22, 0)
            disp_CTF_22 = (ctf_postprocess_22, 1)

            #disp_CTF_RX0 = blocks.add_ff(total_subc)
            #disp_CTF_RX1 = blocks.add_ff(total_subc)

            #self.connect ( disp_CTF_11, (disp_CTF_RX0, 0) )
            #self.connect ( disp_CTF_12, (disp_CTF_RX0, 1) )
            #self.connect ( disp_CTF_21, (disp_CTF_RX1, 0) )
            #self.connect ( disp_CTF_22, (disp_CTF_RX1, 1) )

            terminate_stream(self, disp_CTF_21)
            terminate_stream(self, disp_CTF_22)

            disp_CTF_RX0 = disp_CTF_11
            disp_CTF_RX1 = disp_CTF_12
            ## Channel Equalizer

            #log_to_file(self, ofdm_blocks, "data/vec_mask.compl")
            #log_to_file(self, ofdm_blocks2, "data/vec_mask2.compl")

            nondata_blocks = []
            for i in range(config.frame_length):
                if i in config.training_data.pilotsym_pos:
                    nondata_blocks.append(i)

            pilot_subc = block_header.pilot_tones
            pilot_subcarriers = block_header.pilot_subc_sym
            print "PILOT SUBCARRIERS: ", pilot_subcarriers

            phase_tracking = ofdm.lms_phase_tracking_03(
                total_subc, pilot_subc, nondata_blocks, pilot_subcarriers, 0)
            phase_tracking2 = ofdm.lms_phase_tracking_03(
                total_subc, pilot_subc, nondata_blocks, pilot_subcarriers, 0)

            ##phase_tracking = ofdm.LMS_phase_tracking2( total_subc, pilot_subc,
            ##                                          nondata_blocks )
            ##phase_tracking2 = ofdm.LMS_phase_tracking2( total_subc, pilot_subc,
            ##                                           nondata_blocks )

            #    self.connect( ofdm_blocks,          ( phase_tracking, 0 ) )
            #    self.connect( ofdm_blocks2,          ( phase_tracking, 1 ))
            #    self.connect( inv_CTF_1,            ( phase_tracking, 2 ) )
            #    self.connect( inv_CTF_3,            ( phase_tracking, 3 ) )
            #    self.connect( frame_start,            ( phase_tracking, 4 ) )
            #    self.connect( frame_start2,            ( phase_tracking, 5) )
            #
            #    self.connect( ofdm_blocks2,          ( phase_tracking2, 0 ) )
            #    self.connect( ofdm_blocks,          ( phase_tracking2, 1 ))
            #    self.connect( inv_CTF_3,            ( phase_tracking2, 2 ) )
            #    self.connect( inv_CTF_1,            ( phase_tracking2, 3 ) )
            #    self.connect( frame_start2,            ( phase_tracking2, 4 ) )
            #    self.connect( frame_start,            ( phase_tracking2, 5 ) )

            self.connect(ofdm_blocks, (phase_tracking, 0))
            self.connect(inv_CTF_11, skip_block_111, (phase_tracking, 1))
            self.connect(frame_start, (phase_tracking, 2))

            self.connect(ofdm_blocks2, (phase_tracking2, 0))
            self.connect(inv_CTF_21, skip_block_211, (phase_tracking2, 1))
            self.connect(frame_start2, (phase_tracking2, 2))

            if options.disable_phase_tracking or options.ideal:
                terminate_stream(self, phase_tracking)
                terminate_stream(self, phase_tracking2)
                print "Disabled phase tracking stage"
            else:
                ofdm_blocks = phase_tracking
                ofdm_blocks2 = phase_tracking2

            self.connect(phase_tracking,
                         blocks.null_sink(gr.sizeof_gr_complex * total_subc))
            self.connect(phase_tracking2,
                         blocks.null_sink(gr.sizeof_gr_complex * total_subc))

            terminate_stream(self, inv_CTF_12)
            terminate_stream(self, inv_CTF_22)
            #terminate_stream(self, inv_CTF_1)
            #terminate_stream(self, inv_CTF_3)
            #terminate_stream(self, estimated_CTF_21)
            #terminate_stream(self, estimated_CTF_22)
            ##terminate_stream(self, (phase_tracking,1))
            ##terminate_stream(self, (phase_tracking2,1))

            equalizer = ofdm.channel_equalizer_mimo_3(total_subc)
            self.connect(ofdm_blocks, (equalizer, 0))
            self.connect(ofdm_blocks2, (equalizer, 1))
            self.connect(estimated_CTF_11, skip_block_11, (equalizer, 2))
            self.connect(estimated_CTF_12, skip_block_12, (equalizer, 3))
            self.connect(estimated_CTF_21, skip_block_21, (equalizer, 4))
            self.connect(estimated_CTF_22, skip_block_22, (equalizer, 5))
            self.connect(frame_start, (equalizer, 6))
            self.connect(frame_start, (equalizer, 7))
            ofdm_blocks = equalizer

            #terminate_stream(self, inv_CTF_11)
            #terminate_stream(self, inv_CTF_21)
            '''equalizer = ofdm.channel_equalizer_mimo_2( total_subc )    
        self.connect(  ofdm_blocks,          ( equalizer, 0 ) )
        self.connect( estimated_CTF_11,    skip_block_11,        ( equalizer, 1 ) )
        self.connect( estimated_CTF_12,   skip_block_12,         ( equalizer, 2 ) )
        self.connect( frame_start,          ( equalizer, 3 ) )
        ofdm_blocks = equalizer
        
        equalizer2 = ofdm.channel_equalizer_mimo_2( total_subc )    
        self.connect( ofdm_blocks2,         ( equalizer2, 0 ) )
        self.connect( estimated_CTF_21,  skip_block_21,            ( equalizer2, 1 ) )
        self.connect( estimated_CTF_22,    skip_block_22,        ( equalizer2, 2 ) )
        self.connect( frame_start2,         ( equalizer2, 3 ) )
        ofdm_blocks2 = equalizer2'''

            #ofdm_blocks = equalizer
            #ofdm_blocks2 = equalizer2

            #log_to_file(self, equalizer,"data/equalizer.compl")
            #log_to_file(self, ofdm_blocks2,"data/equalizer.compl")
            #log_to_file(self, ofdm_blocks,"data/equalizer2.compl")

            ## LMS Phase tracking
            ## Track residual frequency offset and sampling clock frequency offset
            '''
        nondata_blocks = []
        for i in range(config.frame_length):
          if i in config.training_data.pilotsym_pos:
            nondata_blocks.append(i)
            
        pilot_subc = block_header.pilot_tones
            
        phase_tracking = ofdm.LMS_phase_tracking2( total_subc, pilot_subc,
                                                   nondata_blocks )
        self.connect( equalizer, ( phase_tracking, 0 ) )
        self.connect( frame_start, ( phase_tracking, 1 ) )
        
        phase_tracking2 = ofdm.LMS_phase_tracking2( total_subc, pilot_subc,
                                                    nondata_blocks )
        self.connect( equalizer2, ( phase_tracking2, 0 ) )
        self.connect( frame_start2, ( phase_tracking2, 1 ) )
        
        # if options.scatter_plot_before_phase_tracking:
          # self.before_phase_tracking = equalizer
          
        
        if options.disable_phase_tracking or options.ideal:
          terminate_stream(self, phase_tracking)
          terminate_stream(self, phase_tracking2)
          print "Disabled phase tracking stage"
        else:
          ofdm_blocks = phase_tracking
          ofdm_blocks2 = phase_tracking2
          
        log_to_file(self,phase_tracking, "data/phase_tracking.compl")
        '''
            '''combine = blocks.add_cc(config.subcarriers)
        self.connect(ofdm_blocks, (combine,0))
        self.connect(ofdm_blocks2, (combine,1))
        
        norm_val = [0.5]*config.subcarriers
        norm = ofdm.multiply_const_vcc( norm_val)
        self.connect(combine,norm)
        
        ofdm_blocks = norm'''
            ##    div = gr.multiply_cc(config.subcarriers)
            ##    const = blocks.vector_source_c([[0.5+0]*config.subcarriers],True)
            ##    self.connect(ofdm_blocks,div)
            ##    self.connect(const,(div,1))
            ##    ofdm_blocks=div
            #    log_to_file(self,combine,"data/combine.compl")
            ## Output connections

            self.connect(ofdm_blocks, out_ofdm_blocks)
            self.connect(frame_start, out_frame_start)
            self.connect(disp_CTF_RX0, out_disp_ctf)
            self.connect(frame_start2, out_frame_start2)
            self.connect(disp_CTF_RX1, out_disp_ctf2)
Example #36
0
  def __init__( self, options, log = False ):
    
    ## Read configuration
    config = station_configuration()
    
    fft_length    = config.fft_length
    cp_length     = config.cp_length
    block_header  = config.training_data
    data_subc     = config.data_subcarriers
    virtual_subc  = config.virtual_subcarriers
    total_subc    = config.subcarriers
    block_length  = config.block_length
    frame_length  = config.frame_length
    dc_null       = config.dc_null
    
    L             = block_header.mm_periodic_parts
    
    
    ## Set Input/Output signature
    gr.hier_block2.__init__( self, 
        "ofdm_inner_receiver",
        gr.io_signature(
            1, 1,
            gr.sizeof_gr_complex ),
        gr.io_signaturev(
            4, 4,
            [gr.sizeof_gr_complex * total_subc,    # OFDM blocks
            gr.sizeof_char,                       # Frame start
            gr.sizeof_float * total_subc,
            gr.sizeof_float] ) )      # Normalized |CTF|^2 
    
    
    ## Input and output ports
    self.input = rx_input = self
    
    out_ofdm_blocks = ( self, 0 )
    out_frame_start = ( self, 1 )
    out_disp_ctf    = ( self, 2 )
    out_disp_cfo    = ( self, 3 )
    
    
    ## pre-FFT processing
    if options.ideal is False and options.ideal2 is False:
        if options.old_receiver is False:
            ## Compute autocorrelations for S&C preamble
            ## and cyclic prefix
            
            self._sc_metric = sc_metric = autocorrelator( fft_length/2, fft_length/2 )
            self._gi_metric = gi_metric = autocorrelator( fft_length, cp_length )
            
            self.connect( rx_input, sc_metric )
            self.connect( rx_input, gi_metric )    
            
            ## Sync. Output contains OFDM blocks
            sync = ofdm.time_sync( fft_length, cp_length )
            self.connect( rx_input, ( sync, 0 ) )
            self.connect( sc_metric, ( sync, 1 ) )
            self.connect( gi_metric, ( sync, 2 ) )
            ofdm_blocks = ( sync, 0 )
            frame_start = ( sync, 1 )
            #log_to_file( self, ( sync, 1 ), "data/peak_detector.char" )
        else:
    
            #Testing old/new metric
            self.tm = schmidl.recursive_timing_metric(fft_length)
            self.connect( self.input, self.tm)
            #log_to_file( self, self.tm, "data/rec_sc_metric_ofdm.float" )
            
            timingmetric_shift = -2#int(-cp_length/4)# 0#-2 #int(-cp_length * 0.8)
            tmfilter = filter.fft_filter_fff(1, [1./cp_length]*cp_length)
            self.connect( self.tm, tmfilter )
            self.tm = tmfilter
        
            
            
            self._pd_thres = 0.3
            self._pd_lookahead = fft_length / 2 # empirically chosen
            peak_detector = ofdm.peak_detector_02_fb(self._pd_lookahead, self._pd_thres)
            self.connect(self.tm, peak_detector)
            #log_to_file( self, peak_detector, "data/rec_peak_detector.char" )
            
            
            frame_start = [0]*frame_length
            frame_start[0] = 1
            frame_start = self.frame_trigger_old = blocks.vector_source_b(frame_start,True)
            
            
            delayed_timesync = blocks.delay(gr.sizeof_char,
                                        (frame_length-1)*block_length + timingmetric_shift)
            self.connect( peak_detector, delayed_timesync )
            
            self.block_sampler = ofdm.vector_sampler(gr.sizeof_gr_complex,block_length*frame_length)
            self.discard_cp = ofdm.vector_mask(block_length,cp_length,fft_length,[])
            
            self.connect(self.input,self.block_sampler)
            self.connect(delayed_timesync,(self.block_sampler,1))
        
            # TODO: dynamic solution
            vt2s = blocks.vector_to_stream(gr.sizeof_gr_complex*block_length,
                                                    frame_length)
            self.connect(self.block_sampler,vt2s,self.discard_cp)
            #terminate_stream(self,ofdm_blocks)
            ofdm_blocks = self.discard_cp
#     else:
#       serial_to_parallel = blocks.stream_to_vector(gr.sizeof_gr_complex,block_length)
#       discard_cp = ofdm.vector_mask(block_length,cp_length,fft_length,[])
#       ofdm_blocks = discard_cp
#       self.connect( rx_input, serial_to_parallel, discard_cp )
#       frame_start = [0]*frame_length
#       frame_start[0] = 1
#       frame_start = blocks.vector_source_b(frame_start,True)
#       
#       print "Disabled time synchronization stage"
    
    ## Compute autocorrelations for S&C preamble
    ## and cyclic prefix
    
    #log_to_file( self, sc_metric, "data/sc_metric_ofdm.float" )
    #log_to_file(self, frame_start, "data/frame_start.compl")
    
#    log_to_file(self,ofdm_blocks,"data/ofdm_blocks_original.compl")
    
    if options.disable_time_sync or options.ideal or options.ideal2:
      if options.ideal is False and options.ideal2 is False:
          terminate_stream(self, ofdm_blocks)
          terminate_stream(self, frame_start)
      
      serial_to_parallel = blocks.stream_to_vector(gr.sizeof_gr_complex,block_length)
      discard_cp = ofdm.vector_mask_dc_null(block_length,cp_length,fft_length,dc_null, [])
      ofdm_blocks = discard_cp
      self.connect( rx_input, serial_to_parallel, discard_cp )
      
      frame_start = [0]*frame_length
      frame_start[0] = 1
      frame_start = blocks.vector_source_b(frame_start,True)
      
      print "Disabled time synchronization stage"
    
    print"\t\t\t\t\tframe_length = ",frame_length
    
    
    
    
    if options.ideal is False and options.ideal2 is False:
        ## Extract preamble, feed to Morelli & Mengali frequency offset estimator
        assert( block_header.mm_preamble_pos == 0 )
        morelli_foe = ofdm.mm_frequency_estimator( fft_length, L,1,0 )
        sampler_preamble = ofdm.vector_sampler( gr.sizeof_gr_complex * fft_length,
                                            1 )
        self.connect( ofdm_blocks, ( sampler_preamble, 0 ) )
        self.connect( frame_start, ( sampler_preamble, 1 ) )
        self.connect( sampler_preamble, morelli_foe )
        freq_offset = morelli_foe
    
    
        ## Adaptive LMS FIR filtering of frequency offset
        lms_fir = ofdm.lms_fir_ff( 20, 1e-3 ) # TODO: verify parameter choice
        self.connect( freq_offset, lms_fir )
        freq_offset = lms_fir
    
        #self.zmq_probe_freqoff = zeromq.pub_sink(gr.sizeof_float, 1, "tcp://*:5557")
        self.connect(lms_fir, blocks.keep_one_in_n(gr.sizeof_float,20) ,out_disp_cfo)
    else:
        self.connect(blocks.vector_source_f ([1]) ,out_disp_cfo)
    
        #log_to_file(self, lms_fir, "data/lms_fir.float")
    
    if options.disable_freq_sync or options.ideal or options.ideal2:
      if options.ideal is False and options.ideal2 is False:
          terminate_stream(self, freq_offset)
          freq_offset = blocks.vector_source_f([0.0],True)
      print "Disabled frequency synchronization stage"
    
    if options.ideal is False and options.ideal2 is False:
        ## Correct frequency shift, feed-forward structure
        frequency_shift = ofdm.frequency_shift_vcc( fft_length, -1.0/fft_length,
                                                    cp_length )
        self.connect( ofdm_blocks, ( frequency_shift, 0 ) )
        self.connect( freq_offset, ( frequency_shift, 1 ) )
        self.connect( frame_start, ( frequency_shift, 2 ) )
        ofdm_blocks = frequency_shift
    
    
    
    
    ## FFT
    fft = fft_blocks.fft_vcc( fft_length, True, [], True )
    self.connect( ofdm_blocks, fft )
    ofdm_blocks = fft
    #log_to_file( self, fft, "data/compen.float" )
    
    
    
    ## Remove virtual subcarriers
    if fft_length > data_subc:
      subcarrier_mask = ofdm.vector_mask_dc_null( fft_length, virtual_subc/2,
                                           total_subc, dc_null, [] )
      self.connect( ofdm_blocks, subcarrier_mask )
      ofdm_blocks = subcarrier_mask
      #log_to_file(self, ofdm_blocks, "data/vec_mask.compl")
       ## Least Squares estimator for channel transfer function (CTF)
    
    
      if options.logcir:
          log_to_file( self, ofdm_blocks, "data/OFDM_Blocks.compl" )
          
          inv_preamble_fd = numpy.array( block_header.pilotsym_fd[ 
            block_header.channel_estimation_pilot[0] ] )
          inv_preamble_fd = numpy.concatenate([inv_preamble_fd[:total_subc/2],inv_preamble_fd[total_subc/2+dc_null:]])
          #print "Channel estimation pilot: ", inv_preamble_fd
          inv_preamble_fd = 1. / inv_preamble_fd
          LS_channel_estimator0 = ofdm.multiply_const_vcc( list( inv_preamble_fd ) )
          self.connect( ofdm_blocks, LS_channel_estimator0, gr.null_sink(gr.sizeof_gr_complex*total_subc))
          log_to_file( self, LS_channel_estimator0, "data/OFDM_Blocks_eq.compl" )
          
    ## post-FFT processing
      
    
    
    ## extract channel estimation preamble from frame
    if options.ideal is False and options.ideal2 is False:
        chest_pre_trigger = blocks.delay( gr.sizeof_char, 1)
        sampled_chest_preamble = ofdm.vector_sampler( gr.sizeof_gr_complex * total_subc, 1)
        self.connect( frame_start,       chest_pre_trigger )
        self.connect( chest_pre_trigger, ( sampled_chest_preamble, 1 ) )
        self.connect( ofdm_blocks,       ( sampled_chest_preamble, 0 ) )
    

    
        ## Least Squares estimator for channel transfer function (CTF)
        inv_preamble_fd = numpy.array( block_header.pilotsym_fd[ 
                                                            block_header.channel_estimation_pilot[0] ] )
        inv_preamble_fd = numpy.concatenate([inv_preamble_fd[:total_subc/2],inv_preamble_fd[total_subc/2+dc_null:]])    
        #print "Channel estimation pilot: ", inv_preamble_fd
        inv_preamble_fd = 1. / inv_preamble_fd
    
        LS_channel_estimator = ofdm.multiply_const_vcc( list( inv_preamble_fd ) )
        self.connect( sampled_chest_preamble, LS_channel_estimator )
        estimated_CTF = LS_channel_estimator
    
        if options.logcir:
             log_to_file( self, sampled_chest_preamble, "data/PREAM.compl" )
     
    
        if not options.disable_ctf_enhancer:
      
      
            if options.logcir:
                ifft1 = fft_blocks.fft_vcc(total_subc,False,[],True)
                self.connect( estimated_CTF, ifft1,gr.null_sink(gr.sizeof_gr_complex*total_subc))
                summ1 = ofdm.vector_sum_vcc(total_subc)
                c2m =gr.complex_to_mag(total_subc)
                self.connect( estimated_CTF,summ1 ,gr.null_sink(gr.sizeof_gr_complex))
                self.connect( estimated_CTF, c2m,gr.null_sink(gr.sizeof_float*total_subc))
                log_to_file( self, ifft1, "data/CIR1.compl" )
                log_to_file( self, summ1, "data/CTFsumm1.compl" )
                log_to_file( self, estimated_CTF, "data/CTF1.compl" )
                log_to_file( self, c2m, "data/CTFmag1.float" )
        
            ## MSE enhancer
            ctf_mse_enhancer = ofdm.CTF_MSE_enhancer( total_subc, cp_length + cp_length)
            self.connect( estimated_CTF, ctf_mse_enhancer )
#      log_to_file( self, ctf_mse_enhancer, "data/ctf_mse_enhancer_original.compl")
      #ifft3 = fft_blocks.fft_vcc(total_subc,False,[],True)
      #null_noise = ofdm.noise_nulling(total_subc, cp_length + cp_length)
      #ctf_mse_enhancer = fft_blocks.fft_vcc(total_subc,True,[],True)
      #ctf_mse_enhancer = ofdm.vector_mask( fft_length, virtual_subc/2,
                                          # total_subc, [] )
      #self.connect( estimated_CTF, ifft3,null_noise,ctf_mse_enhancer )
        
            estimated_CTF = ctf_mse_enhancer 
            print "Disabled CTF MSE enhancer"

        if options.logcir:
             ifft2 = fft_blocks.fft_vcc(total_subc,False,[],True)
             self.connect( estimated_CTF, ifft2,gr.null_sink(gr.sizeof_gr_complex*total_subc))
             summ2 = ofdm.vector_sum_vcc(total_subc)
             c2m2 =gr.complex_to_mag(total_subc)
             self.connect( estimated_CTF,summ2 ,gr.null_sink(gr.sizeof_gr_complex))
             self.connect( estimated_CTF, c2m2,gr.null_sink(gr.sizeof_float*total_subc))
             log_to_file( self, ifft2, "data/CIR2.compl" )
             log_to_file( self, summ2, "data/CTFsumm2.compl" )
             log_to_file( self, estimated_CTF, "data/CTF2.compl" )
             log_to_file( self, c2m2, "data/CTFmag2.float" )
         
    ## Postprocess the CTF estimate
    ## CTF -> inverse CTF (for equalizer)
    ## CTF -> norm |.|^2 (for CTF display)
        ctf_postprocess = ofdm.postprocess_CTF_estimate( total_subc )
        self.connect( estimated_CTF, ctf_postprocess )
        inv_estimated_CTF = ( ctf_postprocess, 0 )
        disp_CTF = ( ctf_postprocess, 1 )
    
#     if options.disable_equalization or options.ideal:
#       terminate_stream(self, inv_estimated_CTF)
#       inv_estimated_CTF_vec = blocks.vector_source_c([1.0/fft_length*math.sqrt(total_subc)]*total_subc,True,total_subc)
#       inv_estimated_CTF_str = blocks.vector_to_stream(gr.sizeof_gr_complex, total_subc)
#       self.inv_estimated_CTF_mul = ofdm.multiply_const_ccf( 1.0/config.rms_amplitude )
#       #inv_estimated_CTF_mul.set_k(1.0/config.rms_amplitude)
#       inv_estimated_CTF = blocks.stream_to_vector(gr.sizeof_gr_complex, total_subc)
#       self.connect( inv_estimated_CTF_vec, inv_estimated_CTF_str, self.inv_estimated_CTF_mul, inv_estimated_CTF)
#       print "Disabled equalization stage"
    '''
    ## LMS Phase tracking
    ## Track residual frequency offset and sampling clock frequency offset

    nondata_blocks = []
    for i in range(config.frame_length):
      if i in config.training_data.pilotsym_pos:
        nondata_blocks.append(i)
        
    print"\t\t\t\t\tnondata_blocks=",nondata_blocks
    pilot_subc = block_header.pilot_tones
    pilot_subcarriers = block_header.pilot_subc_sym
    print "PILOT SUBCARRIERS: ", pilot_subcarriers
        
    phase_tracking = ofdm.lms_phase_tracking_03( total_subc, pilot_subc,
                                               nondata_blocks, pilot_subcarriers,0 )
    self.connect( ofdm_blocks, ( phase_tracking, 0 ) )
    self.connect( inv_estimated_CTF, ( phase_tracking, 1 ) )
    self.connect( frame_start, ( phase_tracking, 2 ) ) ##
    
    if options.scatter_plot_before_phase_tracking:
      self.before_phase_tracking = equalizer
      
    
    if options.disable_phase_tracking or options.ideal:
      terminate_stream(self, phase_tracking)
      print "Disabled phase tracking stage"
    else:
      ofdm_blocks = phase_tracking
    '''
    ## Channel Equalizer
    if options.disable_equalization or options.ideal or options.ideal2:
        print "Disabled equalization stage"
        if options.ideal is False and options.ideal2 is False:
            terminate_stream(self, inv_estimated_CTF)
    else:
        equalizer = ofdm.channel_equalizer( total_subc )
        self.connect( ofdm_blocks,       ( equalizer, 0 ) )
        self.connect( inv_estimated_CTF, ( equalizer, 1 ) )
        self.connect( frame_start,       ( equalizer, 2 ) )
        ofdm_blocks = equalizer
    #log_to_file(self, equalizer,"data/equalizer_siso.compl")
    
    
    #log_to_file(self, ofdm_blocks, "data/equalizer.compl")

    ## LMS Phase tracking
    ## Track residual frequency offset and sampling clock frequency offset
    if options.ideal is False and options.ideal2 is False:
        nondata_blocks = []
        for i in range(config.frame_length):
          if i in config.training_data.pilotsym_pos:
            nondata_blocks.append(i)
            
        print"\t\t\t\t\tnondata_blocks=",nondata_blocks
        pilot_subc = block_header.pilot_tones
        pilot_subcarriers = block_header.pilot_subc_sym
        print "PILOT SUBCARRIERS: ", pilot_subcarriers
         
        phase_tracking2 = ofdm.lms_phase_tracking_dc_null( total_subc, pilot_subc,
                                                   nondata_blocks, pilot_subcarriers, dc_null  )
        self.connect( ofdm_blocks, ( phase_tracking2, 0 ) )
        self.connect( frame_start, ( phase_tracking2, 1 ) ) ##
        
    if options.disable_phase_tracking or options.ideal or options.ideal2:
        if options.ideal is False and options.ideal2 is False:
            terminate_stream(self, phase_tracking2)
        print "Disabled phase tracking stage"
    else:
        ofdm_blocks = phase_tracking2
    
    if options.scatter_plot_before_phase_tracking:
      self.before_phase_tracking = equalizer


    ## Output connections

    self.connect( ofdm_blocks, out_ofdm_blocks )
    self.connect( frame_start, out_frame_start )
    if options.ideal is False and options.ideal2 is False:
        self.connect( disp_CTF, out_disp_ctf )
    else:
        self.connect( blocks.vector_source_f([1.0]*total_subc),blocks.stream_to_vector(gr.sizeof_float,total_subc), out_disp_ctf )

    if log:
      log_to_file( self, sc_metric, "data/sc_metric.float" )
      log_to_file( self, gi_metric, "data/gi_metric.float" )
      log_to_file( self, morelli_foe, "data/morelli_foe.float" )
      log_to_file( self, lms_fir, "data/lms_fir.float" )
      log_to_file( self, sampler_preamble, "data/preamble.compl" )
      log_to_file( self, sync, "data/sync.compl" )
      log_to_file( self, frequency_shift, "data/frequency_shift.compl" )
      log_to_file( self, fft, "data/fft.compl")
      log_to_file( self, fft, "data/fft.float", mag=True )
      
      if vars().has_key( 'subcarrier_mask' ):
        log_to_file( self, subcarrier_mask, "data/subcarrier_mask.compl" )
      
      log_to_file( self, ofdm_blocks, "data/ofdm_blocks_out.compl" )
      log_to_file( self, frame_start, "data/frame_start.float", 
                   char_to_float=True )
      
      log_to_file( self, sampled_chest_preamble, 
                   "data/sampled_chest_preamble.compl" )
      log_to_file( self, LS_channel_estimator, 
                   "data/ls_channel_estimator.compl" )
      log_to_file( self, LS_channel_estimator, 
                   "data/ls_channel_estimator.float", mag=True )
      
      if "ctf_mse_enhancer" in locals(): 
        log_to_file( self, ctf_mse_enhancer, "data/ctf_mse_enhancer.compl" )
        log_to_file( self, ctf_mse_enhancer, "data/ctf_mse_enhancer.float", 
                     mag=True )
      
      log_to_file( self, (ctf_postprocess,0), "data/inc_estimated_ctf.compl" )
      log_to_file( self, (ctf_postprocess,1), "data/disp_ctf.float" )
      
      log_to_file( self, equalizer, "data/equalizer.compl" )
      log_to_file( self, equalizer, "data/equalizer.float", mag=True )
      
      log_to_file( self, phase_tracking, "data/phase_tracking.compl" )
Example #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"