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 #2
0
    def __init__(self, dab_params, bit_rate, address, subch_size, protection, output_float, verbose=False, debug=False):
        if output_float: # map short samples to the range [-1,1] in floats
            gr.hier_block2.__init__(self,
                                    "dab_audio_decoder_ff",
                                    # Input signature
                                    gr.io_signature(1, 1, gr.sizeof_float * dab_params.num_carriers * 2),
                                    # Output signature
                                    gr.io_signature2(2, 2, gr.sizeof_float, gr.sizeof_float))
        else: # output signed 16 bit integers (directly from decoder)
            gr.hier_block2.__init__(self,
                                    "dab_audio_decoder_ff",
                                    # Input signature
                                    gr.io_signature(1, 1, gr.sizeof_float * dab_params.num_carriers * 2),
                                    # Output signature
                                    gr.io_signature2(2, 2, gr.sizeof_short, gr.sizeof_short))

        self.msc_dec = grdab.msc_decode(dab_params, address, subch_size, protection)
        self.unpack = blocks.packed_to_unpacked_bb_make(1, gr.GR_MSB_FIRST)
        self.mp2_dec = grdab.mp2_decode_bs_make(bit_rate / 8)
        self.connect((self, 0), self.msc_dec, self.unpack, self.mp2_dec)

        if output_float:
            # map short samples to the range [-1,1] in floats
            self.s2f_left = blocks.short_to_float_make(1, 32767)
            self.s2f_right = blocks.short_to_float_make(1, 32767)
            self.gain_left = blocks.multiply_const_ff(1, 1)
            self.gain_right = blocks.multiply_const_ff(1, 1)
            self.connect((self.mp2_dec, 0), self.s2f_left, self.gain_left, (self, 0))
            self.connect((self.mp2_dec, 1), self.s2f_right, self.gain_right, (self, 1))
        else:
            # output signed 16 bit integers (directly from decoder)
            self.connect((self.mp2_dec, 0), (self, 0))
            self.connect((self.mp2_dec, 1), (self, 1))
    def __init__(self, dab_params, bit_rate, address, subch_size, protection, output_float, verbose=False, debug=False):
        if output_float: # map short samples to the range [-1,1] in floats
            gr.hier_block2.__init__(self,
                                    "dabplus_audio_decoder_ff",
                                    # Input signature
                                    gr.io_signature(1, 1, gr.sizeof_float * dab_params.num_carriers * 2),
                                    # Output signature
                                    gr.io_signature2(2, 2, gr.sizeof_float, gr.sizeof_float))
        else: # output signed 16 bit integers (directly from decoder)
            gr.hier_block2.__init__(self,
                                    "dabplus_audio_decoder_ff",
                                    # Input signature
                                    gr.io_signature(1, 1, gr.sizeof_float * dab_params.num_carriers * 2),
                                    # Output signature
                                    gr.io_signature2(2, 2, gr.sizeof_short, gr.sizeof_short))
        self.dp = dab_params
        self.bit_rate_n = bit_rate / 8
        self.address = address
        self.size = subch_size
        self.protection = protection
        self.output_float = output_float
        self.verbose = verbose
        self.debug = debug

        # sanity check
        # if self.bit_rate_n*6 != self.size:
        #     log = gr.logger("log")
        #     log.debug("bit rate and subchannel size are not fitting")
        #     log.set_level("ERROR")
        #     raise ValueError

        # MSC decoder extracts logical frames out of transmission frame and decodes it
        self.msc_decoder = grdab.msc_decode(self.dp, self.address, self.size, self.protection, self.verbose, self.debug)
        # firecode synchronizes to superframes and checks
        self.firecode = grdab.firecode_check_bb_make(self.bit_rate_n)
        # Reed-Solomon error repair
        self.rs = grdab.reed_solomon_decode_bb_make(self.bit_rate_n)
        # mp4 decoder
        self.mp4 = grdab.mp4_decode_bs_make(self.bit_rate_n)

        self.connect((self, 0), self.msc_decoder, self.firecode, self.rs, self.mp4)

        if self.output_float:
            # map short samples to the range [-1,1] in floats
            self.s2f_left = blocks.short_to_float_make(1, 32767)
            self.s2f_right = blocks.short_to_float_make(1, 32767)
            self.gain_left = blocks.multiply_const_ff(1, 1)
            self.gain_right = blocks.multiply_const_ff(1, 1)
            self.connect((self.mp4, 0), self.s2f_left, self.gain_left, (self, 0))
            self.connect((self.mp4, 1), self.s2f_right, self.gain_right, (self, 1))
        else:
            # output signed 16 bit integers (directly from decoder)
            self.connect((self.mp4, 0), (self, 0))
            self.connect((self.mp4, 1), (self, 1))
Example #4
0
    def __init__(self,
                 dab_params,
                 bit_rate,
                 address,
                 subch_size,
                 protection,
                 output_float,
                 verbose=False,
                 debug=False):
        if output_float:  # map short samples to the range [-1,1] in floats
            gr.hier_block2.__init__(
                self,
                "dab_audio_decoder_ff",
                # Input signature
                gr.io_signature(1, 1,
                                gr.sizeof_float * dab_params.num_carriers * 2),
                # Output signature
                gr.io_signature2(2, 2, gr.sizeof_float, gr.sizeof_float))
        else:  # output signed 16 bit integers (directly from decoder)
            gr.hier_block2.__init__(
                self,
                "dab_audio_decoder_ff",
                # Input signature
                gr.io_signature(1, 1,
                                gr.sizeof_float * dab_params.num_carriers * 2),
                # Output signature
                gr.io_signature2(2, 2, gr.sizeof_short, gr.sizeof_short))

        self.msc_dec = grdab.msc_decode(dab_params, address, subch_size,
                                        protection)
        self.unpack = blocks.packed_to_unpacked_bb_make(1, gr.GR_MSB_FIRST)
        self.mp2_dec = grdab.mp2_decode_bs_make(bit_rate / 8)
        self.connect((self, 0), self.msc_dec, self.unpack, self.mp2_dec)

        if output_float:
            # map short samples to the range [-1,1] in floats
            self.s2f_left = blocks.short_to_float_make(1, 32767)
            self.s2f_right = blocks.short_to_float_make(1, 32767)
            self.gain_left = blocks.multiply_const_ff(1, 1)
            self.gain_right = blocks.multiply_const_ff(1, 1)
            self.connect((self.mp2_dec, 0), self.s2f_left, self.gain_left,
                         (self, 0))
            self.connect((self.mp2_dec, 1), self.s2f_right, self.gain_right,
                         (self, 1))
        else:
            # output signed 16 bit integers (directly from decoder)
            self.connect((self.mp2_dec, 0), (self, 0))
            self.connect((self.mp2_dec, 1), (self, 1))
Example #5
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 #6
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 #7
0
    def __init__(self):
        gr.hier_block2.__init__(
            self, "OFDM PHY",
            gr.io_signature(1, 1, gr.sizeof_gr_complex * 1),
            gr.io_signature2(2, 2, gr.sizeof_gr_complex * 1, gr.sizeof_char))
        
        # Message Port
        self.message_port_register_hier_out("from_mac")
        self.message_port_register_hier_in("to_mac")

        # Blocks
        self.tx_pdu = blocks.pdu_to_tagged_stream(blocks.byte_t, "packet_length")
        self.tx_path = ofdm_tx(scramble_bits=True)

        self.rx_path = ofdm_rx(scramble_bits=True)
        self.rx_pdu = blocks.tagged_stream_to_pdu(blocks.byte_t, "packet_length")

        # Connections
        self.connect(self.tx_pdu, self.tx_path, self)
        self.connect(self, self.rx_path, self.rx_pdu)
        self.connect((self.rx_path, 1), (self, 1))

        # Message Connection
        self.msg_connect(self, "from_mac", self.tx_pdu, "pdus")
        self.msg_connect(self.rx_pdu, "pdus", self, "to_mac")
Example #8
0
    def __init__(self, args, bandwidth, freq=None, lo_offset=None, gain=None,
                 spec=None, antenna=None, clock_source=None, time_source=None, verbose=False):
        gr.hier_block2.__init__(self, "uhd_receiver",
                                gr.io_signature(0,0,0),
                                gr.io_signature2(2,2,gr.sizeof_gr_complex,gr.sizeof_gr_complex))

        # Set up the UHD interface as a receiver
        uhd_interface.__init__(self, False, True, args, bandwidth,
                               freq, lo_offset, gain, spec, antenna, clock_source, time_source)


        self.u.set_clock_source("mimo", 1)
        self.u.set_time_source("mimo", 1)
        #self.u.set_time_source("mimo", 0)
        #self.u.set_clock_source("external", 1)
        #self.u.set_time_source("external", 1)
        #self.u.set_clock_source("external", 0)
        #self.u.set_time_source("external", 0)
        #self.u.set_samp_rate(bandwidth)
        #self.u.set_center_freq(freq, 0)
        #self.u.set_center_freq(freq, 1)
        self.connect((self.u,0), (self,0))
        self.connect((self.u,1), (self,1))

        if(verbose):
            self._print_verbage()
Example #9
0
    def __init__(self, fft_length, cp_length):


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

#	nco_sensitivity = -1.0/fft_length   # correct for fine frequency	
#	self.nco = gr.frequency_modulator_fc(nco_sensitivity)
#	self.sigmix = gr.multiply_cc()
#	self.sampler = Heyutu.OFDM_Sampler(fft_length, cp_length)
#	self.sync = Heyutu.Heyutu_OFDM_Sync.ofdm_sync_ml(fft_length, cp_length)
	
#	self.connect(self, self.sync)
#	self.connect((self.sync,0), self.nco, (self.sigmix,1))   # use sync freq. offset output to derotate input signal
#	self.connect(self, (self.sigmix,0))                 # signal to be derotated
#       self.connect(self.sigmix, (self.sampler,0))                   # sample off timing signal detected in sync alg
#      self.connect((self.sync,1), (self.sampler,1))            # timing signal to sample at

	
	self.sync = Heyutu.Heyutu_OFDM_Sync.ofdm_sync_ml(fft_length, cp_length)

	self.sampler = Heyutu.OFDM_Sampler(fft_length, cp_length)

	self.connect(self, self.sync)

	self.connect(self, (self.sampler,0))

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

	self.connect((self.sampler, 0), (self, 0))

	self.connect((self.sampler, 1), (self, 1))
Example #10
0
    def __init__(self, options):
        gr.hier_block2.__init__(
            self,
            "ber_reference_source",
            gr.io_signature2(2, 2, gr.sizeof_short, gr.sizeof_int),
            gr.io_signature(1, 1, gr.sizeof_char),
        )

        ## ID Source
        id_src = (self, 0)
        ## Bitcount Source
        bc_src = (self, 1)

        ## Reference Data Source
        #    rand_file = file('random.dat','rb')
        #    rand_string = rand_file.read()
        #    rand_file.close()
        #    rand_data = [ord(rand_string[i]) for i in range(len(rand_string))]
        # We have to use a fix seed so that Tx and Rx have the same random sequence in order to calculate BER
        seed(30214345)
        # Maximum bitloading is 8 and maximum ID is 256
        print "Generating random bits..."
        rand_data = [chr(getrandbits(1)) for x in range(options.subcarriers * 8 * options.data_blocks * 256)]

        ref_src = self._reference_data_source = reference_data_source_02_ib(rand_data)
        self.connect(id_src, (ref_src, 0))
        self.connect(bc_src, (ref_src, 1))

        ## Setup Output
        self.connect(ref_src, self)
Example #11
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 #12
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 #13
0
    def __init__(self, options):
        gr.hier_block2.__init__(
            self, "ber_reference_source",
            gr.io_signature2(2, 2, gr.sizeof_short, gr.sizeof_int),
            gr.io_signature(1, 1, gr.sizeof_char))

        ## ID Source
        id_src = (self, 0)
        ## Bitcount Source
        bc_src = (self, 1)

        ## Reference Data Source
        #    rand_file = file('random.dat','rb')
        #    rand_string = rand_file.read()
        #    rand_file.close()
        #    rand_data = [ord(rand_string[i]) for i in range(len(rand_string))]
        # We have to use a fix seed so that Tx and Rx have the same random sequence in order to calculate BER
        seed(30214345)
        # Maximum bitloading is 8 and maximum ID is 256
        print "Generating random bits..."
        rand_data = [
            chr(getrandbits(1))
            for x in range(options.subcarriers * 8 * options.data_blocks * 256)
        ]

        ref_src = self._reference_data_source = reference_data_source_02_ib(
            rand_data)
        self.connect(id_src, (ref_src, 0))
        self.connect(bc_src, (ref_src, 1))

        ## Setup Output
        self.connect(ref_src, self)
Example #14
0
    def __init__(self,
                 args,
                 bandwidth,
                 freq=None,
                 lo_offset=None,
                 gain=None,
                 spec=None,
                 antenna=None,
                 clock_source=None,
                 time_source=None,
                 verbose=False):
        gr.hier_block2.__init__(
            self, "uhd_receiver", gr.io_signature(0, 0, 0),
            gr.io_signature2(2, 2, gr.sizeof_gr_complex, gr.sizeof_gr_complex))

        # Set up the UHD interface as a receiver
        uhd_interface.__init__(self, False, True, args, bandwidth, freq,
                               lo_offset, gain, spec, antenna, clock_source,
                               time_source)

        self.u.set_clock_source("mimo", 1)
        self.u.set_time_source("mimo", 1)
        #self.u.set_time_source("mimo", 0)
        #self.u.set_clock_source("external", 1)
        #self.u.set_time_source("external", 1)
        #self.u.set_clock_source("external", 0)
        #self.u.set_time_source("external", 0)
        #self.u.set_samp_rate(bandwidth)
        #self.u.set_center_freq(freq, 0)
        #self.u.set_center_freq(freq, 1)
        self.connect((self.u, 0), (self, 0))
        self.connect((self.u, 1), (self, 1))

        if (verbose):
            self._print_verbage()
Example #15
0
    def __init__(self, auto_carrier, carrier, all_spectrum, freq_central, samp_rate, nintems, signal_bw, noise_bw, avg_alpha, average, win):
        """
        Estimates the SNR.
        Provide access to the setting the filter and sample rate.

        Args:
            sample_rate: Incoming stream sample rate
            nintems: Number of FFT bins
            avg_alpha: FFT averaging (over time) constant [0.0-1.0]
            average: Whether to average [True, False]
            win: the window taps generation function
            auto_carrier: To allow self-detection of the carrier, so the highest bin [True, False]
            carrier: To evalutaion of the CNR or SNR [True, False]
            all_spectrum: To set the whole spectrum (less the signal's one) to evaluate noise power density [True, False]
            freq_central: Sets the central frequency (for the bandwidth) of the signal (in the CNR mode, it is the manual set of the carrier's frequency)
            signal_bw: Sets the bandwidth (for the SNR mode) of the signal to the power evaluation
            noise_bw: Sets the bandwidth (if all_sepctrum is false) of the noise to the power evaluation
        """
        gr.hier_block2.__init__(self, "snr_estimator_cfv",
            gr.io_signature(1,1, gr.sizeof_gr_complex),  # Input signature
            gr.io_signature2(2,2, gr.sizeof_float, gr.sizeof_float * nintems)) # Output signature


        self.auto_carrier = auto_carrier
        self.carrier = carrier
        self.all_spectrum = all_spectrum
        self.freq_central = freq_central
        self.samp_rate = samp_rate
        self.nintems = nintems
        self.signal_bw = signal_bw
        self.noise_bw = noise_bw
        self.avg_alpha = avg_alpha
        self.average = average
        self.win = win

       
        
        fft_window = self.win(self.nintems)

        self.fft = fft.fft_vcc(self.nintems, True, fft_window, True)

        self._sd = blocks.stream_to_vector(gr.sizeof_gr_complex, self.nintems)
        self.c2magsq = blocks.complex_to_mag_squared(self.nintems)
        self._avg = filter.single_pole_iir_filter_ff(1.0, self.nintems)

        self.snr = flaress.snr(self.auto_carrier, self.carrier, self.all_spectrum, self.freq_central, self.samp_rate, self.nintems, self.signal_bw, self.noise_bw)

        window_power = sum(map(lambda x: x*x, fft_window))
        self.log = blocks.nlog10_ff(10, self.nintems,
                                     -20*math.log10(self.nintems)              # Adjust for number of bins
                                     -10*math.log10(float(window_power)/self.nintems) # Adjust for windowing loss
                                     -20*math.log10(float(2)/2))      # Adjust for reference scale
        
        self.connect(self, self._sd, self.fft, self.c2magsq, self._avg, self.snr, (self, 0))
        self.connect(self._avg, self.log, (self, 1))

        self._average = average
        self._avg_alpha = avg_alpha
        self.set_avg_alpha(avg_alpha)
        self.set_average(average)
Example #16
0
    def __init__(self,
                 m,
                 n,
                 nsamples,
                 angular_resolution,
                 frequency,
                 array_spacing,
                 antenna_array,
                 output_spectrum=False):

        self.m = m
        self.n = n
        self.nsamples = nsamples
        self.angular_resolution = angular_resolution
        self.l = 299792458.0 / frequency
        self.antenna_array = [[array_spacing * x, array_spacing * y]
                              for [x, y] in antenna_array]

        if (nsamples % m) != 0:
            raise Exception("nsamples must be multiple of m")

        if output_spectrum:
            output_sig = gr.io_signature3(
                3, 3, (gr.sizeof_float * n), (gr.sizeof_float * n),
                (gr.sizeof_float * angular_resolution))
        else:
            output_sig = gr.io_signature2(2, 2, (gr.sizeof_float * n),
                                          (gr.sizeof_float * n))
        #	output_sig = gr.io_signature2(2, 2, (gr.sizeof_float * n), (gr.sizeof_float * angular_resolution))
        #else:
        #	output_sig = gr.io_signature(1, 1, (gr.sizeof_float * n))

        gr.hier_block2.__init__(
            self, "music_doa_helper",
            gr.io_signature(1, 1, (gr.sizeof_gr_complex * nsamples)),
            output_sig)
        #gr.io_signature3(1, 3,	(gr.sizeof_float * n),
        #						(gr.sizeof_float * angular_resolution),
        #						(gr.sizeof_float * angular_resolution)))

        print "MUSIC DOA Helper: M: %d, N: %d, # samples: %d, steps of %f degress, lambda: %f, array: %s" % (
            self.m, self.n, self.nsamples,
            (360.0 / self.angular_resolution), self.l, str(self.antenna_array))

        #print "--> Calculating array response..."
        self.array_response = calculate_antenna_array_response(
            self.antenna_array, self.angular_resolution, self.l)
        #print "--> Done."
        #print self.array_response
        self.impl = baz.music_doa(self.m, self.n, self.nsamples,
                                  self.array_response, self.angular_resolution)

        self.connect(self, self.impl)

        self.connect((self.impl, 0), (self, 0))
        self.connect((self.impl, 1), (self, 1))
        if output_spectrum:
            self.connect((self.impl, 2), (self, 2))
Example #17
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 #18
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 #19
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 #20
0
    def __init__(self, itemsize, filename):
        gr.hier_block2.__init__(
            self, "file_source2", gr.io_signature(0, 0, 0),
            gr.io_signature2(2, 2, itemsize[0], itemsize[1]))

        self.file_source0 = blocks.file_source(itemsize=itemsize[0],
                                               filename=filename[0])

        self.file_source1 = blocks.file_source(itemsize=itemsize[1],
                                               filename=filename[1])

        self.connect(self.file_source0, (self, 0))
        self.connect(self.file_source1, (self, 1))
Example #21
0
    def __init__(self, ):

        gr.hier_block2.__init__(self, "decode_bch_vfvb",
				gr.io_signature(1,1, gr.sizeof_float*120),  # Input signature
				gr.io_signature2(2,2, gr.sizeof_char*24, gr.sizeof_char)) # Output signature
        
        # Define blocks        
        self.rate_unmatch = lte.rate_unmatch_vff()
        self.viterbi = lte.viterbi_vfvb()
        self.crc = lte.crc_calculator_vbvb()

        self.connect(self, self.rate_unmatch, self.viterbi, (self.crc, 0), (self, 0))
        self.connect((self.crc, 1), (self, 1))
Example #22
0
	def __init__(self, m, n, nsamples, angular_resolution, frequency, array_spacing, antenna_array, output_spectrum=False):
		
		self.m = m
		self.n = n
		self.nsamples = nsamples
		self.angular_resolution = angular_resolution
		self.l = 299792458.0 / frequency
		self.antenna_array = [[array_spacing * x, array_spacing * y] for [x,y] in antenna_array]
		
		if (nsamples % m) != 0:
			raise Exception("nsamples must be multiple of m")
		
		if output_spectrum:
			output_sig = gr.io_signature3(3, 3, (gr.sizeof_float * n), (gr.sizeof_float * n), (gr.sizeof_float * angular_resolution))
		else:
			output_sig = gr.io_signature2(2, 2, (gr.sizeof_float * n), (gr.sizeof_float * n))
		#	output_sig = gr.io_signature2(2, 2, (gr.sizeof_float * n), (gr.sizeof_float * angular_resolution))
		#else:
		#	output_sig = gr.io_signature(1, 1, (gr.sizeof_float * n))
		
		gr.hier_block2.__init__(self, "music_doa_helper",
								gr.io_signature(1, 1, (gr.sizeof_gr_complex * nsamples)),
								output_sig)
								#gr.io_signature3(1, 3,	(gr.sizeof_float * n),
								#						(gr.sizeof_float * angular_resolution),
								#						(gr.sizeof_float * angular_resolution)))
		
		print "MUSIC DOA Helper: M: %d, N: %d, # samples: %d, steps of %f degress, lambda: %f, array: %s" % (
			self.m,
			self.n,
			self.nsamples,
			(360.0/self.angular_resolution),
			self.l,
			str(self.antenna_array)
		)
		
		#print "--> Calculating array response..."
		self.array_response = calculate_antenna_array_response(self.antenna_array, self.angular_resolution, self.l)
		#print "--> Done."
		#print self.array_response
		self.impl = baz.music_doa(self.m, self.n, self.nsamples, self.array_response, self.angular_resolution)
		
		self.connect(self, self.impl)
		
		self.connect((self.impl, 0), (self, 0))
		self.connect((self.impl, 1), (self, 1))
		if output_spectrum:
			self.connect((self.impl, 2), (self, 2))
Example #23
0
    def __init__(self, itemsize, filename, append=[False, False]):
        gr.hier_block2.__init__(
            self, "file_sink2", gr.io_signature2(2, 2, itemsize[0],
                                                 itemsize[1]),
            gr.io_signature(0, 0, 0))

        self.file_sink0 = blocks.file_sink(itemsize=itemsize[0],
                                           filename=filename[0],
                                           append=append[0])

        self.file_sink1 = blocks.file_sink(itemsize=itemsize[1],
                                           filename=filename[1],
                                           append=append[1])

        self.connect((self, 0), self.file_sink0)
        self.connect((self, 1), self.file_sink1)
Example #24
0
  def __init__(self,subcarriers,operational_block):
    gr.hier_block2.__init__(self, "common_power_allocator",
      gr.io_signature2(2,2,gr.sizeof_gr_complex*subcarriers,
                           gr.sizeof_float*subcarriers),
      gr.io_signature (1,1,gr.sizeof_gr_complex*subcarriers))

    data = (self,0)
    power = (self,1)

    to_ampl = sqrt_vff(subcarriers)
    f2c = gr.float_to_complex(subcarriers)
    adjust = operational_block

    self.connect(data,(adjust,0))
    self.connect(power,to_ampl,f2c,(adjust,1))
    self.connect(adjust, self)
Example #25
0
    def __init__(self, subcarriers, operational_block):
        gr.hier_block2.__init__(
            self, "common_power_allocator",
            gr.io_signature2(2, 2, gr.sizeof_gr_complex * subcarriers,
                             gr.sizeof_float * subcarriers),
            gr.io_signature(1, 1, gr.sizeof_gr_complex * subcarriers))

        data = (self, 0)
        power = (self, 1)

        to_ampl = sqrt_vff(subcarriers)
        f2c = gr.float_to_complex(subcarriers)
        adjust = operational_block

        self.connect(data, (adjust, 0))
        self.connect(power, to_ampl, f2c, (adjust, 1))
        self.connect(adjust, self)
Example #26
0
    def __init__(self, options):
        """
    @param options: parsed raw.ofdm_params
    """

        self.params = ofdm_params(options)
        params = self.params

        gr.hier_block2.__init__(
            self,
            "ofdm_mod",
            gr.io_signature2(2, 2, gr.sizeof_gr_complex * params.data_tones,
                             gr.sizeof_char),  # Input signature
            gr.io_signature(1, 1, gr.sizeof_gr_complex))  # Output signature

        win = []  #[1 for i in range(self._fft_length)]
        # see gr_fft_vcc_fftw that it works differently if win = [1 1 1 ...]

        self.mapper = raw.ofdm_mapper(params.padded_carriers)
        self.preambles = digital.ofdm_insert_preamble(params.fft_length,
                                                      params.padded_preambles)
        self.ifft = gr.fft_vcc(params.fft_length, False, win, True)
        self.cp_adder = digital.ofdm_cyclic_prefixer(
            params.fft_length, params.fft_length + params.cp_length)
        self.scale = gr.multiply_const_cc(1.0 / math.sqrt(params.fft_length))

        self.connect((self, 0), self.mapper, (self.preambles, 0))
        self.connect((self, 1), (self.preambles, 1))
        self.connect(self.preambles, self.ifft, self.cp_adder, self.scale,
                     self)

        if options.log:
            self.connect(
                self.mapper,
                gr.file_sink(gr.sizeof_gr_complex * params.fft_length,
                             "tx-map.dat"))
            self.connect(
                self.preambles,
                gr.file_sink(gr.sizeof_gr_complex * params.fft_length,
                             "tx-pre.dat"))
            self.connect(
                self.ifft,
                gr.file_sink(gr.sizeof_gr_complex * params.fft_length,
                             "tx-ifft.dat"))
            self.connect(self.cp_adder,
                         gr.file_sink(gr.sizeof_gr_complex, "tx-cp.dat"))
Example #27
0
    def __init__(self, m, n, nsamples, angular_resolution, frequency, array_spacing, antenna_array,
                 output_spectrum=False):

        self.c = 299792458.0 # speed of light in m/s [SciPy could be used for this but would introduce a new dependency]
        self.m = m
        self.n = n
        self.nsamples = nsamples
        self.angular_resolution = angular_resolution
        self.l_lambda = self.c / frequency # wavelength! Unfortunately 'lambda' is a Python key word.
        self.antenna_array = [[array_spacing * x, array_spacing * y] for [x, y] in antenna_array]

        if (nsamples % m) != 0:
            raise Exception("nsamples must be multiple of m")

        if output_spectrum:
            output_sig = gr.io_signature3(3, 3, (gr.sizeof_float * n), (gr.sizeof_float * n),
                                          (gr.sizeof_float * angular_resolution))
        else:
            output_sig = gr.io_signature2(2, 2, (gr.sizeof_float * n), (gr.sizeof_float * n))

        gr.hier_block2.__init__(self, "music_doa_helper",
                                gr.io_signature(1, 1, (gr.sizeof_gr_complex * nsamples)),
                                output_sig)

        print "MUSIC DOA Helper: M: %d, N: %d, # samples: %d, steps of %f degress, lambda: %f, array: %s" % (
            self.m,
            self.n,
            self.nsamples,
            (360.0 / self.angular_resolution),
            self.l_lambda,
            str(self.antenna_array)
        )

        #print "--> Calculating array response..."
        self.array_response = calculate_antenna_array_response(self.antenna_array, self.angular_resolution, self.l_lambda)
        #print "--> Done."
        #print self.array_response
        self.impl = misc.music_doa(self.m, self.n, self.nsamples, self.array_response, self.angular_resolution)

        self.connect(self, self.impl)

        self.connect((self.impl, 0), (self, 0))
        self.connect((self.impl, 1), (self, 1))
        if output_spectrum:
            self.connect((self.impl, 2), (self, 2))
Example #28
0
    def __init__(self, itemsize, filename):
        gr.hier_block2.__init__(self,
            "file_source2",
        gr.io_signature(0, 0, 0),
        gr.io_signature2(2, 2, itemsize[0], itemsize[1]))

        self.file_source0 = blocks.file_source(
                itemsize=itemsize[0],
                filename=filename[0]
        )
        
        self.file_source1 = blocks.file_source(
                itemsize=itemsize[1],
                filename=filename[1]
        )

        self.connect(self.file_source0, (self, 0))
        self.connect(self.file_source1, (self, 1))
Example #29
0
    def __init__(self, itemsize, filename, append=[False, False]):
        gr.hier_block2.__init__(self,
            "file_sink2",
            gr.io_signature2(2, 2, itemsize[0], itemsize[1]),
            gr.io_signature(0, 0, 0))

        self.file_sink0 = blocks.file_sink(
                itemsize=itemsize[0],
                filename=filename[0],
                append=append[0]
        )
        
        self.file_sink1 = blocks.file_sink(
                itemsize=itemsize[1],
                filename=filename[1],
                append=append[1]
        )

        self.connect((self, 0), self.file_sink0)
        self.connect((self, 1), self.file_sink1)
Example #30
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 #31
0
  def __init__(self, data_tones, num_symbols, mode=0):
    symbol_size = data_tones * gr.sizeof_gr_complex
    gr.hier_block2.__init__(self, "SNR",
      gr.io_signature2(2,2, symbol_size, symbol_size),
      gr.io_signature(1,1, gr.sizeof_float))

    sub = gr.sub_cc(data_tones)
    self.connect((self,0), (sub,0))
    self.connect((self,1), (sub,1))

    err = gr.complex_to_mag_squared(data_tones);
    self.connect(sub, err);
    pow = gr.complex_to_mag_squared(data_tones);
    self.connect((self,1), pow);

    if mode == 0:
      # one snr per symbol (num_symbols is ignored)
      snr = gr.divide_ff()
      self.connect(pow, gr.vector_to_stream(gr.sizeof_float, data_tones),
        gr.integrate_ff(data_tones), (snr,0))
      self.connect(err, gr.vector_to_stream(gr.sizeof_float, data_tones),
        gr.integrate_ff(data_tones), (snr,1))
      out = snr
    elif mode == 1:
      # one snr per packet
      snr = gr.divide_ff()
      self.connect(pow, gr.vector_to_stream(gr.sizeof_float, data_tones),
        gr.integrate_ff(data_tones*num_symbols), (snr,0))
      self.connect(err, gr.vector_to_stream(gr.sizeof_float, data_tones),
        gr.integrate_ff(data_tones*num_symbols), (snr,1))
      out = snr
    elif mode == 2:
      # one snr per frequency bin
      snr = gr.divide_ff(data_tones)
      self.connect(pow, raw.symbol_avg(data_tones, num_symbols), (snr,0))
      self.connect(err, raw.symbol_avg(data_tones, num_symbols), (snr,1))
      out = gr.vector_to_stream(gr.sizeof_float, data_tones)
      self.connect(snr, out)

    self.connect(out, gr.nlog10_ff(10), self)
Example #32
0
  def __init__(self, framebytes, numframes, mode=0):
    gr.hier_block2.__init__(self, "BER",
      gr.io_signature2(2,2, framebytes, framebytes),
      gr.io_signature(1,1, gr.sizeof_float))

    xor = gr.xor_bb()
    self.connect((self,0), gr.vector_to_stream(gr.sizeof_char, framebytes), (xor,0))
    self.connect((self,1), gr.vector_to_stream(gr.sizeof_char, framebytes), (xor,1))

    if mode == 0:
      # one ber per packet
      ber = raw.ber_avg(1, framebytes)
      self.connect(xor,
                   ber)
    elif mode == 1:
      # one ber per byte in packet
      ber = raw.ber_avg(framebytes, numframes)
      self.connect(xor,
                   gr.stream_to_vector(gr.sizeof_char, framebytes),
                   ber)

    self.connect(ber, self)
    def __init__(self,
                 fft_length,
                 cp_length,
                 nsymbols,
                 freq_offset,
                 logging=False):

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

        # Use a fixed trigger point instead of sync block
        symbol_length = fft_length + cp_length
        pkt_length = nsymbols * symbol_length
        data = (pkt_length) * [
            0,
        ]
        data[(symbol_length) - 1] = 1
        self.peak_trigger = blocks.vector_source_b(data, True)

        # Use a pre-defined frequency offset
        foffset = (pkt_length) * [
            math.pi * freq_offset,
        ]
        self.frequency_offset = blocks.vector_source_f(foffset, True)

        self.connect(self, blocks.null_sink(gr.sizeof_gr_complex))
        self.connect(self.frequency_offset, (self, 0))
        self.connect(self.peak_trigger, (self, 1))

        if logging:
            self.connect(
                self.peak_trigger,
                blocks.file_sink(gr.sizeof_char,
                                 "ofdm_sync_fixed-peaks_b.dat"))
Example #34
0
  def __init__(self, options):
    """
    @param options: parsed raw.ofdm_params
    """

    self.params = ofdm_params(options)
    params = self.params

    gr.hier_block2.__init__(self, "ofdm_mod",
      gr.io_signature2(2, 2, gr.sizeof_gr_complex*params.data_tones, gr.sizeof_char), # Input signature
      gr.io_signature(1, 1, gr.sizeof_gr_complex)) # Output signature

    win = [] #[1 for i in range(self._fft_length)]
    # see gr_fft_vcc_fftw that it works differently if win = [1 1 1 ...]

    self.mapper = raw.ofdm_mapper(params.padded_carriers)
    self.preambles = digital.ofdm_insert_preamble(params.fft_length, params.padded_preambles)
    self.ifft = gr.fft_vcc(params.fft_length, False, win, True)
    self.cp_adder = digital.ofdm_cyclic_prefixer(params.fft_length, params.fft_length + params.cp_length)
    self.scale = gr.multiply_const_cc(1.0 / math.sqrt(params.fft_length))

    self.connect((self,0), self.mapper, (self.preambles,0))
    self.connect((self,1), (self.preambles,1))
    self.connect(self.preambles, self.ifft, self.cp_adder, self.scale, self)

    if options.log:
        self.connect(self.mapper,
                     gr.file_sink(gr.sizeof_gr_complex*params.fft_length,
                                  "tx-map.dat"))
        self.connect(self.preambles,
                     gr.file_sink(gr.sizeof_gr_complex*params.fft_length,
                                  "tx-pre.dat"))
        self.connect(self.ifft,
                     gr.file_sink(gr.sizeof_gr_complex*params.fft_length,
                                  "tx-ifft.dat"))
        self.connect(self.cp_adder,
                     gr.file_sink(gr.sizeof_gr_complex,
                                  "tx-cp.dat"))
Example #35
0
    def __init__(self, fft_length, cp_length, nsymbols, freq_offset, logging=False):

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

        # Use a fixed trigger point instead of sync block
        symbol_length = fft_length + cp_length
        pkt_length = nsymbols*symbol_length
        data = (pkt_length)*[0,]
        data[(symbol_length)-1] = 1
        self.peak_trigger = blocks.vector_source_b(data, True)

        # Use a pre-defined frequency offset
        foffset = (pkt_length)*[math.pi*freq_offset,]
        self.frequency_offset = blocks.vector_source_f(foffset, True)

        self.connect(self, blocks.null_sink(gr.sizeof_gr_complex))
        self.connect(self.frequency_offset, (self,0))
        self.connect(self.peak_trigger, (self,1))

        if logging:
            self.connect(self.peak_trigger, blocks.file_sink(gr.sizeof_char, "ofdm_sync_fixed-peaks_b.dat"))
    def __init__(self, samples_per_symbol=1):
        gr.hier_block2.__init__(self, 'gsm_modulate_burst',
                                gr.io_signature2(2, 2, 58 * 2, 1),
                                gr.io_signature(1, 1, gr.sizeof_gr_complex))

        # take care of the packetizer
        conf = mlse.make_packet_config_gsm()
        self.packetbuilder = mlse.packetbuilder_midamble_vbb(conf)
        self.connect(self, self.packetbuilder)
        self.connect((self, 1), (self.packetbuilder, 1))  # tsc_index

        # append 8 1-bits to the packet for the idle-time between bursts.
        # This is necessary among others to flush the gmsk-modulator which is causal.
        # (We use 1-bits because that's what the gsm-standard says)
        # (we also only use 8 bits, because the specified value of 8.25 only works
        # properly with samplerates that are a multiple of 4.)
        self.guardbits = gr.vector_source_b((1, ) * 8, True, 8)
        self.guard_cat = mlse.vector_concat_vv(148, 8)
        self.connect(self.packetbuilder, self.guard_cat)
        self.connect(self.guardbits, (self.guard_cat, 1))

        # we now have a vector of bits, transform that into a stream
        self.tostream = gr.vector_to_stream(1, 148 + 8)
        # do the precoding:
        self.diffcode = gr.diff_decoder_bb(2)
        self.nrz = gr.map_bb([1, -1])
        self.connect(self.guard_cat, self.tostream, self.diffcode, self.nrz)

        # modulate
        self.mod = digital.gmskmod_bc(samples_per_symbol, 0.3, 8)

        # skip the first gmsk_length*samplerate/2 samples to make this block
        # acausal.
        #        self.skiphead = gr.skiphead(gr.sizeof_gr_complex, int(samples_per_symbol*4.5));
        #        self.connect(self.nrz, self.mod, self.skiphead, self)
        self.connect(self.nrz, self.mod,
                     self)  # workaround: we need a negative delay later,
    def __init__(self, samples_per_symbol = 1):
        gr.hier_block2.__init__(self, 'gsm_modulate_burst',
                gr.io_signature2(2,2,58*2,1),
                gr.io_signature(1, 1, gr.sizeof_gr_complex))
        
        # take care of the packetizer
        conf = mlse.make_packet_config_gsm()
        self.packetbuilder = mlse.packetbuilder_midamble_vbb(conf)
        self.connect(self, self.packetbuilder)
        self.connect((self,1), (self.packetbuilder,1)) # tsc_index

        # append 8 1-bits to the packet for the idle-time between bursts.
        # This is necessary among others to flush the gmsk-modulator which is causal.
        # (We use 1-bits because that's what the gsm-standard says)
        # (we also only use 8 bits, because the specified value of 8.25 only works 
        # properly with samplerates that are a multiple of 4.)
        self.guardbits = gr.vector_source_b((1,)*8,True,8)
        self.guard_cat = mlse.vector_concat_vv(148,8)
        self.connect(self.packetbuilder, self.guard_cat)
        self.connect(self.guardbits, (self.guard_cat,1))

        # we now have a vector of bits, transform that into a stream
        self.tostream = gr.vector_to_stream(1, 148+8)
        # do the precoding:
        self.diffcode = gr.diff_decoder_bb(2);
        self.nrz = gr.map_bb([1,-1])
        self.connect(self.guard_cat, self.tostream, self.diffcode, self.nrz)

        # modulate
        self.mod = digital.gmskmod_bc(samples_per_symbol, 0.3, 8)

        # skip the first gmsk_length*samplerate/2 samples to make this block
        # acausal.
#        self.skiphead = gr.skiphead(gr.sizeof_gr_complex, int(samples_per_symbol*4.5));
#        self.connect(self.nrz, self.mod, self.skiphead, self)
        self.connect(self.nrz, self.mod, self)  # workaround: we need a negative delay later,
Example #38
0
    def __init__(self, fft_length, cp_length, occupied_tones, snr, ks, carrier_map_bin, nc_filter, logging=False):
        """
	Hierarchical block for receiving OFDM symbols.

	The input is the complex modulated signal at baseband.
        Synchronized packets are sent back to the demodulator.

        @param fft_length: total number of subcarriers
        @type  fft_length: int
        @param cp_length: length of cyclic prefix as specified in subcarriers (<= fft_length)
        @type  cp_length: int
        @param occupied_tones: number of subcarriers used for data
        @type  occupied_tones: int
        @param snr: estimated signal to noise ratio used to guide cyclic prefix synchronizer
        @type  snr: float
        @param ks: known symbols used as preambles to each packet
        @type  ks: list of lists
        @param logging: turn file logging on or off
        @type  logging: bool
	"""

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

        bw = (float(occupied_tones) / float(fft_length)) / 2.0
        tb = bw*0.04
        print "ofdm_receiver:__init__:occupied_tones %s fft_length %d "  % (occupied_tones, fft_length)
        
        chan_coeffs = filter.firdes.low_pass (1.0,                     # gain
                                          1.0,                     # sampling rate
                                          bw+tb,                   # midpoint of trans. band
                                          tb,                      # width of trans. band
                                          filter.firdes.WIN_HAMMING)   # filter type
        
        self.chan_filt = filter.fft_filter_ccc(1, chan_coeffs)

        # linklab, get ofdm parameters
        self._fft_length = fft_length
        self._occupied_tones = occupied_tones
        self._cp_length = cp_length
        self._nc_filter = nc_filter
        self._carrier_map_bin = carrier_map_bin
        
        win = [1 for i in range(fft_length)]
        
        # linklab, initialization function
        self.initialize(ks, self._carrier_map_bin)
        

        zeros_on_left = int(math.ceil((fft_length - occupied_tones)/2.0))
        ks0 = fft_length*[0,]
        ks0[zeros_on_left : zeros_on_left + occupied_tones] = ks[0]

        ks0 = np_fft.ifftshift(ks0)
        ks0time = np_fft.ifft(ks0)
        # ADD SCALING FACTOR
        ks0time = ks0time.tolist()

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

        # Set up blocks

        # Create a delay line, linklab
        self.delay = blocks.delay(gr.sizeof_gr_complex, fft_length)

        self.nco = analog.frequency_modulator_fc(nco_sensitivity)         # generate a signal proportional to frequency error of sync block
        self.sigmix = blocks.multiply_cc()
        self.sampler = gr_papyrus.ofdm_sampler(fft_length, fft_length+cp_length)
        self.fft_demod = gr_fft.fft_vcc(fft_length, True, win, True)
        self.ofdm_frame_acq = gr_papyrus.ofdm_frame_acquisition(occupied_tones,
                                                                  fft_length,
                                                                  cp_length, ks[0])
              # linklab, check current mode: non-contiguous OFDM or not
        if self._nc_filter:
            print '\nMulti-band Filter Turned ON!'
            # linklab, non-contiguous filter
            self.ncofdm_filt = ncofdm_filt(self._fft_length, self._occupied_tones, self._carrier_map_bin)
            self.connect(self, self.chan_filt, self.ncofdm_filt)
            self.connect(self.ncofdm_filt, self.ofdm_sync)             # into the synchronization alg.
            self.connect((self.ofdm_sync,0), self.nco, (self.sigmix,1))   # use sync freq. offset output to derotate input signal
            self.connect(self.ncofdm_filt, self.delay, (self.sigmix,0))                 # signal to be derotated
        else :
            print '\nMulti-band Filter Turned OFF!'
            self.connect(self, self.chan_filt)
            self.connect(self.chan_filt, self.ofdm_sync)             # into the synchronization alg.
            self.connect((self.ofdm_sync,0), self.nco, (self.sigmix,1))   # use sync freq. offset output to derotate input signal
            self.connect(self.chan_filt, self.delay, (self.sigmix,0))                 # signal to be derotated

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

        self.connect((self.sampler,0), self.fft_demod)                # send derotated sampled signal to FFT
        self.connect(self.fft_demod, (self.ofdm_frame_acq,0))         # find frame start and equalize signal
        self.connect((self.sampler,1), (self.ofdm_frame_acq,1))       # send timing signal to signal frame start
        self.connect((self.ofdm_frame_acq,0), (self,0))               # finished with fine/coarse freq correction,
        self.connect((self.ofdm_frame_acq,1), (self,1))               # frame and symbol timing, and equalization

        if logging:
            self.connect(self.chan_filt, gr.file_sink(gr.sizeof_gr_complex, "ofdm_receiver-chan_filt_c.dat"))
            self.connect(self.fft_demod, gr.file_sink(gr.sizeof_gr_complex*fft_length, "ofdm_receiver-fft_out_c.dat"))
            self.connect(self.ofdm_frame_acq,
                         gr.file_sink(gr.sizeof_gr_complex*occupied_tones, "ofdm_receiver-frame_acq_c.dat"))
            self.connect((self.ofdm_frame_acq,1), gr.file_sink(1, "ofdm_receiver-found_corr_b.dat"))
            self.connect(self.sampler, gr.file_sink(gr.sizeof_gr_complex*fft_length, "ofdm_receiver-sampler_c.dat"))
            self.connect(self.sigmix, gr.file_sink(gr.sizeof_gr_complex, "ofdm_receiver-sigmix_c.dat"))
            self.connect(self.nco, gr.file_sink(gr.sizeof_gr_complex, "ofdm_receiver-nco_c.dat"))
Example #39
0
    def __init__(self, fft_length, cp_length, logging=False):
        """
        OFDM synchronization using PN Correlation:
        T. M. Schmidl and D. C. Cox, "Robust Frequency and Timing
        Synchonization for OFDM," IEEE Trans. Communications, vol. 45,
        no. 12, 1997.
        """
        
	gr.hier_block2.__init__(self, "ofdm_sync_pn",
				gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature
                                gr.io_signature2(2, 2, gr.sizeof_float, gr.sizeof_char)) # Output signature

        self.input = gr.add_const_cc(0)

        # PN Sync

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

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

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

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

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

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

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

        self.sample_and_hold = gr.sample_and_hold_ff()

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

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

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

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

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

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

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

        self.input = blocks.add_const_cc(0)

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

        # ML Sync

        # Energy Detection from ML Sync

        self.connect(self, self.input)

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

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

        moving_sum_taps = [rho / 2 for i in range(cp_length)]
        self.moving_sum_filter = filter.fir_filter_fff(1,moving_sum_taps)

        self.connect(self.input,self.magsqrd1)
        self.connect(self.delay,self.magsqrd2)
        self.connect(self.magsqrd1,(self.adder,0))
        self.connect(self.magsqrd2,(self.adder,1))
        self.connect(self.adder,self.moving_sum_filter)


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

        movingsum2_taps = [1.0 for i in range(cp_length)]
        self.movingsum2 = filter.fir_filter_ccf(1,movingsum2_taps)

        # Correlator data handler
        self.c2mag = blocks.complex_to_mag()
        self.angle = blocks.complex_to_arg()
        self.connect(self.input,(self.mixer,1))
        self.connect(self.delay,self.conjg,(self.mixer,0))
        self.connect(self.mixer,self.movingsum2,self.c2mag)
        self.connect(self.movingsum2,self.angle)

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

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

        # use the sync loop values to set the sampler and the NCO
        #     self.diff = theta
        #     self.angle = epsilon

        self.connect(self.diff, self.pk_detect)

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

        self.connect(self.angle, (self.sample_and_hold,0))

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

        # The output signature of the correlation has a few spikes because the rest of the
        # system uses the repeated preamble symbol. It needs to work that generically if
        # anyone wants to use this against a WiMAX-like signal since it, too, repeats.
        # The output theta of the correlator above is multiplied with this correlation to
        # identify the proper peak and remove other products in this cross-correlation
        self.threshold_factor = 0.1
        self.slice = blocks.threshold_ff(self.threshold_factor, self.threshold_factor, 0)
        self.f2b = blocks.float_to_char()
        self.b2f = blocks.char_to_float()
        self.mul = blocks.multiply_ff()

        # Normalize the power of the corr output by the energy. This is not really needed
        # and could be removed for performance, but it makes for a cleaner signal.
        # if this is removed, the threshold value needs adjustment.
        self.connect(self.input, self.kscorr, self.corrmag, (self.div,0))
        self.connect(self.moving_sum_filter, (self.div,1))

        self.connect(self.div, (self.mul,0))
        self.connect(self.pk_detect, self.b2f, (self.mul,1))
        self.connect(self.mul, self.slice)

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


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

            self.connect(self.sample_and_hold, blocks.file_sink(gr.sizeof_float, "ofdm_sync_ml-sample_and_hold_f.dat"))
            self.connect(self.input, blocks.file_sink(gr.sizeof_gr_complex, "ofdm_sync_ml-input_c.dat"))
Example #41
0
    def __init__(self, dab_params, verbose=False, debug=False):
        """
        Hierarchical block for FIC decoding

        @param dab_params DAB parameter object (dab.parameters.dab_parameters)
        """
        gr.hier_block2.__init__(
            self, "fic",
            gr.io_signature2(2, 2,
                             gr.sizeof_float * dab_params.num_carriers * 2,
                             gr.sizeof_char),
            gr.io_signature(1, 1, gr.sizeof_char * 32))

        self.dp = dab_params
        self.verbose = verbose
        self.debug = debug

        # FIB selection and block partitioning
        self.select_fic_syms = dab.select_vectors(gr.sizeof_float,
                                                  self.dp.num_carriers * 2,
                                                  self.dp.num_fic_syms, 0)
        self.repartition_fic = dab.repartition_vectors(
            gr.sizeof_float, self.dp.num_carriers * 2,
            self.dp.fic_punctured_codeword_length, self.dp.num_fic_syms,
            self.dp.num_cifs)

        # unpuncturing
        self.unpuncture = dab.unpuncture_vff(
            self.dp.assembled_fic_puncturing_sequence, 0)

        # convolutional coding
        # self.fsm = trellis.fsm(self.dp.conv_code_in_bits, self.dp.conv_code_out_bits, self.dp.conv_code_generator_polynomials)
        self.fsm = trellis.fsm(
            1, 4, [0133, 0171, 0145, 0133
                   ])  # OK (dumped to text and verified partially)
        self.conv_v2s = blocks.vector_to_stream(
            gr.sizeof_float, self.dp.fic_conv_codeword_length)
        # self.conv_decode = trellis.viterbi_combined_fb(self.fsm, 20, 0, 0, 1, [1./sqrt(2),-1/sqrt(2)] , trellis.TRELLIS_EUCLIDEAN)
        table = [
            0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1,
            0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0,
            1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1
        ]
        assert (len(table) / 4 == self.fsm.O())
        table = [(1 - 2 * x) / sqrt(2) for x in table]
        self.conv_decode = trellis.viterbi_combined_fb(
            self.fsm, 774, 0, 0, 4, table, trellis.TRELLIS_EUCLIDEAN)
        #self.conv_s2v = blocks.stream_to_vector(gr.sizeof_char, 774)
        self.conv_prune = dab.prune(gr.sizeof_char,
                                    self.dp.fic_conv_codeword_length / 4, 0,
                                    self.dp.conv_code_add_bits_input)

        # energy dispersal
        self.prbs_src = blocks.vector_source_b(
            self.dp.prbs(self.dp.energy_dispersal_fic_vector_length), True)
        #self.energy_v2s = blocks.vector_to_stream(gr.sizeof_char, self.dp.energy_dispersal_fic_vector_length)
        self.add_mod_2 = blocks.xor_bb()
        self.energy_s2v = blocks.stream_to_vector(
            gr.sizeof_char, self.dp.energy_dispersal_fic_vector_length)
        self.cut_into_fibs = dab.repartition_vectors(
            gr.sizeof_char, self.dp.energy_dispersal_fic_vector_length,
            self.dp.fib_bits, 1, self.dp.energy_dispersal_fic_fibs_per_vector)

        # connect all
        self.nullsink = blocks.null_sink(gr.sizeof_char)
        self.pack = blocks.unpacked_to_packed_bb(1, gr.GR_MSB_FIRST)
        self.fibout = blocks.stream_to_vector(1, 32)
        # self.filesink = gr.file_sink(gr.sizeof_char, "debug/fic.dat")
        self.fibsink = dab.fib_sink_vb()

        # self.connect((self,0), (self.select_fic_syms,0), (self.repartition_fic,0), self.unpuncture, self.conv_v2s, self.conv_decode, self.conv_s2v, self.conv_prune, self.energy_v2s, self.add_mod_2, self.energy_s2v, (self.cut_into_fibs,0), gr.vector_to_stream(1,256), gr.unpacked_to_packed_bb(1,gr.GR_MSB_FIRST), self.filesink)
        self.connect(
            (self, 0),
            (self.select_fic_syms, 0),
            (self.repartition_fic, 0),
            self.unpuncture,
            self.conv_v2s,
            self.conv_decode,
            #self.conv_s2v,
            self.conv_prune,
            #self.energy_v2s,
            self.add_mod_2,
            self.energy_s2v,
            (self.cut_into_fibs, 0),
            blocks.vector_to_stream(1, 256),
            self.pack,
            self.fibout,
            self.fibsink)
        self.connect(self.fibout, self)
        self.connect(self.prbs_src, (self.add_mod_2, 1))
        self.connect((self, 1), (self.select_fic_syms, 1),
                     (self.repartition_fic, 1), (self.cut_into_fibs, 1),
                     self.nullsink)

        if self.debug:
            self.connect(
                (self, 0),
                blocks.file_sink(gr.sizeof_float * self.dp.num_carriers * 2,
                                 "debug/transmission_frame.dat"))
            self.connect(
                (self, 1),
                blocks.file_sink(gr.sizeof_char,
                                 "debug/transmission_frame_trigger.dat"))
            self.connect(
                self.select_fic_syms,
                blocks.file_sink(gr.sizeof_float * self.dp.num_carriers * 2,
                                 "debug/fic_select_syms.dat"))
            self.connect(
                self.repartition_fic,
                blocks.file_sink(
                    gr.sizeof_float * self.dp.fic_punctured_codeword_length,
                    "debug/fic_repartitioned.dat"))
            self.connect(
                self.unpuncture,
                blocks.file_sink(
                    gr.sizeof_float * self.dp.fic_conv_codeword_length,
                    "debug/fic_unpunctured.dat"))
            self.connect(
                self.conv_decode,
                blocks.file_sink(gr.sizeof_char, "debug/fic_decoded.dat"))
            self.connect(
                self.conv_prune,
                blocks.file_sink(gr.sizeof_char,
                                 "debug/fic_decoded_pruned.dat"))
            #self.connect(self.conv_decode, blocks.file_sink(gr.sizeof_char * self.dp.energy_dispersal_fic_vector_length, "debug/fic_energy_dispersal_undone.dat"))
            self.connect(
                self.pack,
                blocks.file_sink(gr.sizeof_char,
                                 "debug/fic_energy_undone.dat"))
Example #42
0
    def __init__(self, dab_params, rx_params, debug=False):
        """
		OFDM time and coarse frequency synchronisation for DAB

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

        dp = dab_params
        rp = rx_params

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

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

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

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

        #
        # fine frequency synchronisation
        #

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

        self.ffe = dab.ofdm_ffe_all_in_one(dp.symbol_length, dp.fft_length,
                                           rp.symbols_for_ffs_estimation,
                                           rp.ffs_alpha, int(dp.sample_rate))
        if rp.correct_ffe:
            self.ffs_delay_input_for_correction = blocks.delay(
                gr.sizeof_gr_complex,
                dp.symbol_length * rp.symbols_for_ffs_estimation
            )  # by delaying the input, we can use the ff offset estimation from the first symbol to correct the first symbol itself
            self.ffs_delay_frame_start = blocks.delay(
                gr.sizeof_char,
                dp.symbol_length * rp.symbols_for_ffs_estimation
            )  # sample the value at the end of the symbol ..
            self.ffs_nco = analog.frequency_modulator_fc(
                1
            )  # ffs_sample_and_hold directly outputs phase error per sample
            self.ffs_mixer = blocks.multiply_cc()

        # calculate fine frequency error
        self.connect(self.input, (self.ffe, 0))
        self.connect(self.ns_detect, (self.ffe, 1))

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

        if debug:
            self.connect(
                self.ffe, blocks.multiply_const_ff(1. / (dp.T * 2 * pi)),
                blocks.file_sink(gr.sizeof_float,
                                 "debug/ofdm_sync_dab_fine_freq_err_f.dat"))
Example #43
0
	def __init__(self, dab_params, verbose=False, debug=False):
		"""
		Hierarchical block for OFDM modulation

		@param dab_params DAB parameter object (dab.parameters.dab_parameters)
		@param debug enables debug output to files
		"""

		dp = dab_params

		gr.hier_block2.__init__(self,"ofdm_mod",
		                        gr.io_signature2(2, 2, gr.sizeof_char*dp.num_carriers/4, gr.sizeof_char), # input signature
					gr.io_signature (1, 1, gr.sizeof_gr_complex)) # output signature


		# symbol mapping
		self.mapper = dab.qpsk_mapper_vbc(dp.num_carriers)

		# add pilot symbol
		self.insert_pilot = dab.ofdm_insert_pilot_vcc(dp.prn)

		# phase sum
		self.sum_phase = dab.sum_phasor_trig_vcc(dp.num_carriers)

		# frequency interleaving
		self.interleave = dab.frequency_interleaver_vcc(dp.frequency_interleaving_sequence_array)

		# add central carrier & move to middle
		self.move_and_insert_carrier = dab.ofdm_move_and_insert_zero(dp.fft_length, dp.num_carriers)

		# ifft
		self.ifft = fft.fft_vcc(dp.fft_length, False, [], True)

		# cyclic prefixer
		self.prefixer = digital.ofdm_cyclic_prefixer(dp.fft_length, dp.symbol_length)

		# convert back to vectors
		self.s2v = blocks.stream_to_vector(gr.sizeof_gr_complex, dp.symbol_length)

		# add null symbol
		self.insert_null = dab.insert_null_symbol(dp.ns_length, dp.symbol_length)

		#
		# connect it all
		#

		# data
		self.connect((self,0), self.mapper, (self.insert_pilot,0), (self.sum_phase,0), self.interleave, self.move_and_insert_carrier, self.ifft, self.prefixer, self.s2v, (self.insert_null,0))
		self.connect(self.insert_null, self)

		# control signal (frame start)
		self.connect((self,1), (self.insert_pilot,1), (self.sum_phase,1), (self.insert_null,1))

		if debug:
			self.connect(self.mapper, blocks.file_sink(gr.sizeof_gr_complex*dp.num_carriers, "debug/generated_signal_mapper.dat"))
			self.connect(self.insert_pilot, blocks.file_sink(gr.sizeof_gr_complex*dp.num_carriers, "debug/generated_signal_insert_pilot.dat"))
			self.connect(self.sum_phase, blocks.file_sink(gr.sizeof_gr_complex*dp.num_carriers, "debug/generated_signal_sum_phase.dat"))
			self.connect(self.interleave, blocks.file_sink(gr.sizeof_gr_complex*dp.num_carriers, "debug/generated_signal_interleave.dat"))
			self.connect(self.move_and_insert_carrier, blocks.file_sink(gr.sizeof_gr_complex*dp.fft_length, "debug/generated_signal_move_and_insert_carrier.dat"))
			self.connect(self.ifft, blocks.file_sink(gr.sizeof_gr_complex*dp.fft_length, "debug/generated_signal_ifft.dat"))
			self.connect(self.prefixer, blocks.file_sink(gr.sizeof_gr_complex, "debug/generated_signal_prefixer.dat"))
			self.connect(self.insert_null, blocks.file_sink(gr.sizeof_gr_complex, "debug/generated_signal.dat"))
Example #44
0
	def __init__(self, dab_params, rx_params, verbose=False, debug=False):
		"""
		Hierarchical block for OFDM demodulation

		@param dab_params DAB parameter object (dab.parameters.dab_parameters)
		@param rx_params RX parameter object (dab.parameters.receiver_parameters)
		@param debug enables debug output to files
		@param verbose whether to produce verbose messages
		"""

		self.dp = dp = dab_params
		self.rp = rp = rx_params
		self.verbose = verbose

		if self.rp.softbits:
			gr.hier_block2.__init__(self,"ofdm_demod",
						gr.io_signature (1, 1, gr.sizeof_gr_complex), # input signature
						gr.io_signature2(2, 2, gr.sizeof_float*self.dp.num_carriers*2, gr.sizeof_char)) # output signature
		else:
			gr.hier_block2.__init__(self,"ofdm_demod",
						gr.io_signature (1, 1, gr.sizeof_gr_complex), # input signature
						gr.io_signature2(2, 2, gr.sizeof_char*self.dp.num_carriers/4, gr.sizeof_char)) # output signature

		

		# workaround for a problem that prevents connecting more than one block directly (see trac ticket #161)
		#self.input = gr.kludge_copy(gr.sizeof_gr_complex)
		self.input = blocks.multiply_const_cc(1.0) # FIXME
		self.connect(self, self.input)
		
		# input filtering
		if self.rp.input_fft_filter: 
			if verbose: print "--> RX filter enabled"
			lowpass_taps = filter.firdes_low_pass(1.0,                     # gain
							  dp.sample_rate,          # sampling rate
							  rp.filt_bw,              # cutoff frequency
							  rp.filt_tb,              # width of transition band
							  filter.firdes.WIN_HAMMING)   # Hamming window
			self.fft_filter = filter.fft_filter_ccc(1, lowpass_taps)
		

		# correct sample rate offset, if enabled
		if self.rp.autocorrect_sample_rate:
			if verbose: print "--> dynamic sample rate correction enabled"
			self.rate_detect_ns = dab.detect_null(dp.ns_length, False)
			self.rate_estimator = dab.estimate_sample_rate_bf(dp.sample_rate, dp.frame_length)
			self.rate_prober = blocks.probe_signal_f()
			self.connect(self.input, self.rate_detect_ns, self.rate_estimator, self.rate_prober)
			# self.resample = gr.fractional_interpolator_cc(0, 1)
			self.resample = dab.fractional_interpolator_triggered_update_cc(0,1)
			self.connect(self.rate_detect_ns, (self.resample,1))
			self.updater = Timer(0.1,self.update_correction)
			# self.updater = threading.Thread(target=self.update_correction)
			self.run_interpolater_update_thread = True
			self.updater.setDaemon(True)
			self.updater.start()
		else:
			self.run_interpolater_update_thread = False
			if self.rp.sample_rate_correction_factor != 1:
				if verbose: print "--> static sample rate correction enabled"
				self.resample = gr.fractional_interpolator_cc(0, self.rp.sample_rate_correction_factor)

		# timing and fine frequency synchronisation
		self.sync = dab.ofdm_sync_dab2(self.dp, self.rp, debug)

		# ofdm symbol sampler
		self.sampler = dab.ofdm_sampler(dp.fft_length, dp.cp_length, dp.symbols_per_frame, rp.cp_gap)
		
		# fft for symbol vectors
		self.fft = fft.fft_vcc(dp.fft_length, True, [], True)

		# coarse frequency synchronisation
		self.cfs = dab.ofdm_coarse_frequency_correct(dp.fft_length, dp.num_carriers, dp.cp_length)

		# diff phasor
		self.phase_diff = dab.diff_phasor_vcc(dp.num_carriers)

		# remove pilot symbol
		self.remove_pilot = dab.ofdm_remove_first_symbol_vcc(dp.num_carriers)

		# magnitude equalisation
		if self.rp.equalize_magnitude:
			if verbose: print "--> magnitude equalization enabled"
			self.equalizer = dab.magnitude_equalizer_vcc(dp.num_carriers, rp.symbols_for_magnitude_equalization)

		# frequency deinterleaving
		self.deinterleave = dab.frequency_interleaver_vcc(dp.frequency_deinterleaving_sequence_array)
		
		# symbol demapping
		self.demapper = dab.qpsk_demapper_vcb(dp.num_carriers)

		#
		# connect everything
		#

		if self.rp.autocorrect_sample_rate or self.rp.sample_rate_correction_factor != 1:
			self.connect(self.input, self.resample)
			self.input2 = self.resample
		else:
			self.input2 = self.input
		if self.rp.input_fft_filter:
			self.connect(self.input2, self.fft_filter, self.sync)
		else:
			self.connect(self.input2, self.sync)

		# data stream
		self.connect((self.sync, 0), (self.sampler, 0), self.fft, (self.cfs, 0), self.phase_diff, (self.remove_pilot,0))
		if self.rp.equalize_magnitude:
			self.connect((self.remove_pilot,0), (self.equalizer,0), self.deinterleave)
		else:
			self.connect((self.remove_pilot,0), self.deinterleave)
		if self.rp.softbits:
			if verbose: print "--> using soft bits"
			self.softbit_interleaver = dab.complex_to_interleaved_float_vcf(self.dp.num_carriers)
			self.connect(self.deinterleave, self.softbit_interleaver, (self,0))
		else:
			self.connect(self.deinterleave, self.demapper, (self,0))

		# control stream
		self.connect((self.sync, 1), (self.sampler, 1), (self.cfs, 1), (self.remove_pilot,1))
		if self.rp.equalize_magnitude:
			self.connect((self.remove_pilot,1), (self.equalizer,1), (self,1))
		else:
			self.connect((self.remove_pilot,1), (self,1))
			
		# calculate an estimate of the SNR
		self.phase_var_decim   = blocks.keep_one_in_n(gr.sizeof_gr_complex*self.dp.num_carriers, self.rp.phase_var_estimate_downsample)
		self.phase_var_arg     = blocks.complex_to_arg(dp.num_carriers)
		self.phase_var_v2s     = blocks.vector_to_stream(gr.sizeof_float, dp.num_carriers)
		self.phase_var_mod     = dab.modulo_ff(pi/2)
		self.phase_var_avg_mod = filter.iir_filter_ffd([rp.phase_var_estimate_alpha], [0,1-rp.phase_var_estimate_alpha]) 
		self.phase_var_sub_avg = blocks.sub_ff()
		self.phase_var_sqr     = blocks.multiply_ff()
		self.phase_var_avg     = filter.iir_filter_ffd([rp.phase_var_estimate_alpha], [0,1-rp.phase_var_estimate_alpha]) 
		self.probe_phase_var   = blocks.probe_signal_f()
		self.connect((self.remove_pilot,0), self.phase_var_decim, self.phase_var_arg, self.phase_var_v2s, self.phase_var_mod, (self.phase_var_sub_avg,0), (self.phase_var_sqr,0))
		self.connect(self.phase_var_mod, self.phase_var_avg_mod, (self.phase_var_sub_avg,1))
		self.connect(self.phase_var_sub_avg, (self.phase_var_sqr,1))
		self.connect(self.phase_var_sqr, self.phase_var_avg, self.probe_phase_var)

		# measure processing rate
		self.measure_rate = dab.measure_processing_rate(gr.sizeof_gr_complex, 2000000) 
		self.connect(self.input, self.measure_rate)

		# debugging
		if debug:
			self.connect(self.fft, blocks.file_sink(gr.sizeof_gr_complex*dp.fft_length, "debug/ofdm_after_fft.dat"))
			self.connect((self.cfs,0), blocks.file_sink(gr.sizeof_gr_complex*dp.num_carriers, "debug/ofdm_after_cfs.dat"))
			self.connect(self.phase_diff, blocks.file_sink(gr.sizeof_gr_complex*dp.num_carriers, "debug/ofdm_diff_phasor.dat"))
			self.connect((self.remove_pilot,0), blocks.file_sink(gr.sizeof_gr_complex*dp.num_carriers, "debug/ofdm_pilot_removed.dat"))
			self.connect((self.remove_pilot,1), blocks.file_sink(gr.sizeof_char, "debug/ofdm_after_cfs_trigger.dat"))
			self.connect(self.deinterleave, blocks.file_sink(gr.sizeof_gr_complex*dp.num_carriers, "debug/ofdm_deinterleaved.dat"))
			if self.rp.equalize_magnitude:
				self.connect(self.equalizer, blocks.file_sink(gr.sizeof_gr_complex*dp.num_carriers, "debug/ofdm_equalizer.dat"))
			if self.rp.softbits:
				self.connect(self.softbit_interleaver, blocks.file_sink(gr.sizeof_float*dp.num_carriers*2, "debug/softbits.dat"))
Example #45
0
    def __init__(self, fft_length, cp_length, occupied_tones, snr, ks, logging=False):
        """
	Hierarchical block for receiving OFDM symbols.

	The input is the complex modulated signal at baseband.
        Synchronized packets are sent back to the demodulator.

        Args:
            fft_length: total number of subcarriers (int)
            cp_length: length of cyclic prefix as specified in subcarriers (<= fft_length) (int)
            occupied_tones: number of subcarriers used for data (int)
            snr: estimated signal to noise ratio used to guide cyclic prefix synchronizer (float)
            ks: known symbols used as preambles to each packet (list of lists)
            logging: turn file logging on or off (bool)
	"""

	gr.hier_block2.__init__(self, "ofdm_receiver",
				gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature
                                gr.io_signature2(2, 2, gr.sizeof_gr_complex*occupied_tones, gr.sizeof_char)) # Output signature
        
        bw = (float(occupied_tones) / float(fft_length)) / 2.0
        tb = bw*0.08
        chan_coeffs = filter.firdes.low_pass (1.0,                     # gain
                                              1.0,                     # sampling rate
                                              bw+tb,                   # midpoint of trans. band
                                              tb,                      # width of trans. band
                                              filter.firdes.WIN_HAMMING)   # filter type
        self.chan_filt = filter.fft_filter_ccc(1, chan_coeffs)
        
        win = [1 for i in range(fft_length)]

        zeros_on_left = int(math.ceil((fft_length - occupied_tones)/2.0))
        ks0 = fft_length*[0,]
        ks0[zeros_on_left : zeros_on_left + occupied_tones] = ks[0]
        
        ks0 = fft.ifftshift(ks0)
        ks0time = fft.ifft(ks0)
        # ADD SCALING FACTOR
        ks0time = ks0time.tolist()

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

        # Set up blocks

        self.nco = analog.frequency_modulator_fc(nco_sensitivity)         # generate a signal proportional to frequency error of sync block
        self.sigmix = blocks.multiply_cc()
        self.sampler = digital.ofdm_sampler(fft_length, fft_length+cp_length)
        self.fft_demod = gr_fft.fft_vcc(fft_length, True, win, True)
        self.ofdm_frame_acq = digital.ofdm_frame_acquisition(occupied_tones,
                                                                  fft_length,
                                                                  cp_length, ks[0])

        self.connect(self, self.chan_filt)                            # filter the input channel
        self.connect(self.chan_filt, self.ofdm_sync)                  # into the synchronization alg.
        self.connect((self.ofdm_sync,0), self.nco, (self.sigmix,1))   # use sync freq. offset output to derotate input signal
        self.connect(self.chan_filt, (self.sigmix,0))                 # signal to be derotated
        self.connect(self.sigmix, (self.sampler,0))                   # sample off timing signal detected in sync alg
        self.connect((self.ofdm_sync,1), (self.sampler,1))            # timing signal to sample at

        self.connect((self.sampler,0), self.fft_demod)                # send derotated sampled signal to FFT
        self.connect(self.fft_demod, (self.ofdm_frame_acq,0))         # find frame start and equalize signal
        self.connect((self.sampler,1), (self.ofdm_frame_acq,1))       # send timing signal to signal frame start
        self.connect((self.ofdm_frame_acq,0), (self,0))               # finished with fine/coarse freq correction,
        self.connect((self.ofdm_frame_acq,1), (self,1))               # frame and symbol timing, and equalization

        if logging:
            self.connect(self.chan_filt, blocks.file_sink(gr.sizeof_gr_complex, "ofdm_receiver-chan_filt_c.dat"))
            self.connect(self.fft_demod, blocks.file_sink(gr.sizeof_gr_complex*fft_length, "ofdm_receiver-fft_out_c.dat"))
            self.connect(self.ofdm_frame_acq,
                         blocks.file_sink(gr.sizeof_gr_complex*occupied_tones, "ofdm_receiver-frame_acq_c.dat"))
            self.connect((self.ofdm_frame_acq,1), blocks.file_sink(1, "ofdm_receiver-found_corr_b.dat"))
            self.connect(self.sampler, blocks.file_sink(gr.sizeof_gr_complex*fft_length, "ofdm_receiver-sampler_c.dat"))
            self.connect(self.sigmix, blocks.file_sink(gr.sizeof_gr_complex, "ofdm_receiver-sigmix_c.dat"))
            self.connect(self.nco, blocks.file_sink(gr.sizeof_gr_complex, "ofdm_receiver-nco_c.dat"))
Example #46
0
    def __init__(self, fft_length, cp_length, snr, kstime, logging):
        ''' Maximum Likelihood OFDM synchronizer:
        J. van de Beek, M. Sandell, and P. O. Borjesson, "ML Estimation
        of Time and Frequency Offset in OFDM Systems," IEEE Trans.
        Signal Processing, vol. 45, no. 7, pp. 1800-1805, 1997.
        '''

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

        self.input = blocks.add_const_cc(0)

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

        # ML Sync

        # Energy Detection from ML Sync

        self.connect(self, self.input)

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

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

        moving_sum_taps = [rho / 2 for i in range(cp_length)]
        self.moving_sum_filter = filter.fir_filter_fff(1, moving_sum_taps)

        self.connect(self.input, self.magsqrd1)
        self.connect(self.delay, self.magsqrd2)
        self.connect(self.magsqrd1, (self.adder, 0))
        self.connect(self.magsqrd2, (self.adder, 1))
        self.connect(self.adder, self.moving_sum_filter)

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

        movingsum2_taps = [1.0 for i in range(cp_length)]
        self.movingsum2 = filter.fir_filter_ccf(1, movingsum2_taps)

        # Correlator data handler
        self.c2mag = blocks.complex_to_mag()
        self.angle = blocks.complex_to_arg()
        self.connect(self.input, (self.mixer, 1))
        self.connect(self.delay, self.conjg, (self.mixer, 0))
        self.connect(self.mixer, self.movingsum2, self.c2mag)
        self.connect(self.movingsum2, self.angle)

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

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

        # use the sync loop values to set the sampler and the NCO
        #     self.diff = theta
        #     self.angle = epsilon

        self.connect(self.diff, self.pk_detect)

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

        self.connect(self.angle, (self.sample_and_hold, 0))

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

        # The output signature of the correlation has a few spikes because the rest of the
        # system uses the repeated preamble symbol. It needs to work that generically if
        # anyone wants to use this against a WiMAX-like signal since it, too, repeats.
        # The output theta of the correlator above is multiplied with this correlation to
        # identify the proper peak and remove other products in this cross-correlation
        self.threshold_factor = 0.1
        self.slice = blocks.threshold_ff(self.threshold_factor,
                                         self.threshold_factor, 0)
        self.f2b = blocks.float_to_char()
        self.b2f = blocks.char_to_float()
        self.mul = blocks.multiply_ff()

        # Normalize the power of the corr output by the energy. This is not really needed
        # and could be removed for performance, but it makes for a cleaner signal.
        # if this is removed, the threshold value needs adjustment.
        self.connect(self.input, self.kscorr, self.corrmag, (self.div, 0))
        self.connect(self.moving_sum_filter, (self.div, 1))

        self.connect(self.div, (self.mul, 0))
        self.connect(self.pk_detect, self.b2f, (self.mul, 1))
        self.connect(self.mul, self.slice)

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

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

            self.connect(
                self.sample_and_hold,
                blocks.file_sink(gr.sizeof_float,
                                 "ofdm_sync_ml-sample_and_hold_f.dat"))
            self.connect(
                self.input,
                blocks.file_sink(gr.sizeof_gr_complex,
                                 "ofdm_sync_ml-input_c.dat"))
Example #47
0
    def __init__(self, p, logging=False):
        """
    Hierarchical block for receiving OFDM symbols.

    The input is the complex modulated signal at baseband.
    Synchronized packets are sent back to the demodulator.

    @param params: Raw OFDM parameters
    @type  params: ofdm_params
    @param logging: turn file logging on or off
    @type  logging: bool
    """
        from numpy import fft

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

        # low-pass filter the input channel
        bw = (float(p.occupied_tones) / float(p.fft_length)) / 2.0
        tb = bw * 0.08
        lpf_coeffs = gr.firdes.low_pass(
            1.0,  # gain
            1.0,  # sampling rate
            bw + tb,  # midpoint of trans. band
            tb,  # width of trans. band
            gr.firdes.WIN_HAMMING)  # filter type
        lpf = gr.fft_filter_ccc(1, lpf_coeffs)
        #lpf = gr.add_const_cc(0.0)  ## no-op low-pass-filter
        self.connect(self, lpf)

        # to the synchronization algorithm
        #from gnuradio import blks2impl
        #from gnuradio.blks2impl.ofdm_sync_pn import ofdm_sync_pn
        sync = ofdm_sync(p.fft_length, p.cp_length, p.half_sync, logging)
        self.connect(lpf, sync)

        # correct for fine frequency offset computed in sync (up to +-pi/fft_length)
        # NOTE: frame_acquisition can correct coarse freq offset (i.e. kpi/fft_length)
        if p.half_sync:
            nco_sensitivity = 2.0 / p.fft_length
        else:
            nco_sensitivity = 1.0 / (p.fft_length + p.cp_length)
        #nco_sensitivity = 0

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

        self.connect((sync, 0), (sigmix, 0))
        self.connect((sync, 1), nco, (sigmix, 1))

        # sample at symbol boundaries
        # NOTE: (sync,2) indicates the first sample of the symbol!
        sampler = raw.ofdm_sampler(p.fft_length,
                                   p.fft_length + p.cp_length,
                                   timeout=100)
        self.connect(sigmix, (sampler, 0))
        self.connect((sync, 2), (sampler, 1))  # timing signal to sample at

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

        # use the preamble to correct the coarse frequency offset and initial equalizer
        frame_acq = raw.ofdm_frame_acquisition(p.fft_length, p.cp_length,
                                               p.preambles)

        self.frame_acq = frame_acq
        self.connect(fft, (frame_acq, 0))
        self.connect((sampler, 1), (frame_acq, 1))

        self.connect((frame_acq, 0),
                     (self, 0))  # finished with fine/coarse freq correction
        self.connect((frame_acq, 1), (self, 1))  # frame and symbol timing

        if logging:
            self.connect(lpf, gr.file_sink(gr.sizeof_gr_complex,
                                           "rx-filt.dat"))
            self.connect(
                fft,
                gr.file_sink(gr.sizeof_gr_complex * p.fft_length,
                             "rx-fft.dat"))
            self.connect((frame_acq, 0),
                         gr.file_sink(gr.sizeof_gr_complex * p.occupied_tones,
                                      "rx-acq.dat"))
            self.connect((frame_acq, 1), gr.file_sink(1, "rx-detect.datb"))
            self.connect(
                sampler,
                gr.file_sink(gr.sizeof_gr_complex * p.fft_length,
                             "rx-sampler.dat"))
            self.connect(sigmix,
                         gr.file_sink(gr.sizeof_gr_complex, "rx-sigmix.dat"))
            self.connect(nco, gr.file_sink(gr.sizeof_gr_complex, "rx-nco.dat"))
Example #48
0
    def __init__(self, dab_params, verbose=False, debug=False):
        """
		Hierarchical block for OFDM modulation

		@param dab_params DAB parameter object (grdab.parameters.dab_parameters)
		@param debug enables debug output to files
		"""

        dp = dab_params

        gr.hier_block2.__init__(
            self,
            "ofdm_mod",
            gr.io_signature2(2, 2, gr.sizeof_char * dp.num_carriers / 4,
                             gr.sizeof_char),  # input signature
            gr.io_signature(1, 1, gr.sizeof_gr_complex))  # output signature

        # symbol mapping
        self.mapper_v2s = blocks.vector_to_stream_make(gr.sizeof_char, 384)
        self.mapper_unpack = blocks.packed_to_unpacked_bb_make(
            1, gr.GR_MSB_FIRST)
        self.mapper = grdab.mapper_bc_make(dp.num_carriers)
        self.mapper_s2v = blocks.stream_to_vector_make(gr.sizeof_gr_complex,
                                                       1536)

        # add pilot symbol
        self.insert_pilot = grdab.ofdm_insert_pilot_vcc(dp.prn)

        # phase sum
        self.sum_phase = grdab.sum_phasor_trig_vcc(dp.num_carriers)

        # frequency interleaving
        self.interleave = grdab.frequency_interleaver_vcc(
            dp.frequency_interleaving_sequence_array)

        # add central carrier & move to middle
        self.move_and_insert_carrier = grdab.ofdm_move_and_insert_zero(
            dp.fft_length, dp.num_carriers)

        # ifft
        self.ifft = fft.fft_vcc(dp.fft_length, False, [], True)

        # cyclic prefixer
        self.prefixer = digital.ofdm_cyclic_prefixer(dp.fft_length,
                                                     dp.symbol_length)

        # convert back to vectors
        self.s2v = blocks.stream_to_vector(gr.sizeof_gr_complex,
                                           dp.symbol_length)

        # add null symbol
        self.insert_null = grdab.insert_null_symbol(dp.ns_length,
                                                    dp.symbol_length)

        #
        # connect it all
        #

        # data
        self.connect((self, 0), self.mapper_v2s, self.mapper_unpack,
                     self.mapper, self.mapper_s2v, (self.insert_pilot, 0),
                     (self.sum_phase, 0), self.interleave,
                     self.move_and_insert_carrier, self.ifft, self.prefixer,
                     self.s2v, (self.insert_null, 0))
        self.connect(self.insert_null, self)

        # control signal (frame start)
        self.connect((self, 1), (self.insert_pilot, 1), (self.sum_phase, 1),
                     (self.insert_null, 1))

        if debug:
            #self.connect(self.mapper, blocks.file_sink(gr.sizeof_gr_complex*dp.num_carriers, "debug/generated_signal_mapper.dat"))
            self.connect(
                self.insert_pilot,
                blocks.file_sink(gr.sizeof_gr_complex * dp.num_carriers,
                                 "debug/generated_signal_insert_pilot.dat"))
            self.connect(
                self.sum_phase,
                blocks.file_sink(gr.sizeof_gr_complex * dp.num_carriers,
                                 "debug/generated_signal_sum_phase.dat"))
            self.connect(
                self.interleave,
                blocks.file_sink(gr.sizeof_gr_complex * dp.num_carriers,
                                 "debug/generated_signal_interleave.dat"))
            self.connect(
                self.move_and_insert_carrier,
                blocks.file_sink(
                    gr.sizeof_gr_complex * dp.fft_length,
                    "debug/generated_signal_move_and_insert_carrier.dat"))
            self.connect(
                self.ifft,
                blocks.file_sink(gr.sizeof_gr_complex * dp.fft_length,
                                 "debug/generated_signal_ifft.dat"))
            self.connect(
                self.prefixer,
                blocks.file_sink(gr.sizeof_gr_complex,
                                 "debug/generated_signal_prefixer.dat"))
            self.connect(
                self.insert_null,
                blocks.file_sink(gr.sizeof_gr_complex,
                                 "debug/generated_signal.dat"))
Example #49
0
    def __init__(self, fft_length, cp_length, kstime, overrate, logging=True):
        """
        OFDM synchronization using PN Correlation:
        T. M. Schmidl and D. C. Cox, "Robust Frequency and Timing
        Synchonization for OFDM," IEEE Trans. Communications, vol. 45,
        no. 12, 1997.
        """

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

        self.input = blocks.add_const_cc(0)

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

        # PN Sync
        self.corrmag = blocks.complex_to_mag_squared()
        self.delay = blocks.delay(gr.sizeof_gr_complex,
                                  fft_length * overrate / 2)

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

        #self.sub = blocks.add_const_ff(-1)
        self.pk_detect = blocks.peak_detector_fb(0.40, 0.25,
                                                 fft_length * overrate,
                                                 0.00000000000)

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

        #self.inputmag = blocks.complex_to_mag_squared()
        #self.normalize = blocks.divide_ff()
        #self.inputmovingsum = filter.fir_filter_fff(1, [1.0] * (fft_length//2))
        self.square = blocks.multiply_ff()

        #self.connect(self.input,self.inputmag,self.inputmovingsum)
        self.connect(self.corrmag, (self.square, 0))
        self.connect(self.corrmag, (self.square, 1))
        self.dsquare = blocks.multiply_ff()
        self.connect(self.square, (self.dsquare, 0))
        self.connect(self.square, (self.dsquare, 1))
        self.connect(self.dsquare, self.pk_detect)

        # Create a moving sum filter for the corr output
        self.moving_sum_filter = filter.fir_filter_ccf(
            1, [1.0] * (fft_length * overrate // 2))

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

        self.sample_and_hold = blocks.sample_and_hold_ff()

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

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

        if logging:
            self.connect(
                self.dsquare,
                blocks.file_sink(gr.sizeof_float, "ofdm_sync_pn-dsquare.dat"))
            self.connect(
                self.corrmag,
                blocks.file_sink(gr.sizeof_float, "ofdm_sync_pn-corrmag.dat"))
            self.connect(
                self.angle,
                blocks.file_sink(gr.sizeof_float,
                                 "ofdm_sync_pn-epsilon_f.dat"))
            self.connect(
                self.pk_detect,
                blocks.file_sink(gr.sizeof_char, "ofdm_sync_pn-peaks_b.dat"))
            self.connect(
                self.sample_and_hold,
                blocks.file_sink(gr.sizeof_float,
                                 "ofdm_sync_pn-sample_and_hold_f.dat"))
            self.connect(
                self.input,
                blocks.file_sink(gr.sizeof_gr_complex,
                                 "ofdm_sync_pn-input_c.dat"))
Example #50
0
    def __init__(self,
                 fft_length,
                 cp_length,
                 occupied_tones,
                 snr,
                 ks,
                 carrier_map_bin,
                 nc_filter,
                 logging=False):
        """
	Hierarchical block for receiving OFDM symbols.

	The input is the complex modulated signal at baseband.
        Synchronized packets are sent back to the demodulator.

        @param fft_length: total number of subcarriers
        @type  fft_length: int
        @param cp_length: length of cyclic prefix as specified in subcarriers (<= fft_length)
        @type  cp_length: int
        @param occupied_tones: number of subcarriers used for data
        @type  occupied_tones: int
        @param snr: estimated signal to noise ratio used to guide cyclic prefix synchronizer
        @type  snr: float
        @param ks: known symbols used as preambles to each packet
        @type  ks: list of lists
        @param logging: turn file logging on or off
        @type  logging: bool
	"""

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

        bw = (float(occupied_tones) / float(fft_length)) / 2.0
        tb = bw * 0.04
        print "ofdm_receiver:__init__:occupied_tones %s fft_length %d " % (
            occupied_tones, fft_length)

        chan_coeffs = filter.firdes.low_pass(
            1.0,  # gain
            1.0,  # sampling rate
            bw + tb,  # midpoint of trans. band
            tb,  # width of trans. band
            filter.firdes.WIN_HAMMING)  # filter type

        self.chan_filt = filter.fft_filter_ccc(1, chan_coeffs)

        # linklab, get ofdm parameters
        self._fft_length = fft_length
        self._occupied_tones = occupied_tones
        self._cp_length = cp_length
        self._nc_filter = nc_filter
        self._carrier_map_bin = carrier_map_bin

        win = [1 for i in range(fft_length)]

        # linklab, initialization function
        self.initialize(ks, self._carrier_map_bin)

        zeros_on_left = int(math.ceil((fft_length - occupied_tones) / 2.0))
        ks0 = fft_length * [
            0,
        ]
        ks0[zeros_on_left:zeros_on_left + occupied_tones] = ks[0]

        ks0 = np_fft.ifftshift(ks0)
        ks0time = np_fft.ifft(ks0)
        # ADD SCALING FACTOR
        ks0time = ks0time.tolist()

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

        # Set up blocks

        # Create a delay line, linklab
        self.delay = blocks.delay(gr.sizeof_gr_complex, fft_length)

        self.nco = analog.frequency_modulator_fc(
            nco_sensitivity
        )  # generate a signal proportional to frequency error of sync block
        self.sigmix = blocks.multiply_cc()
        self.sampler = gr_papyrus.ofdm_sampler(fft_length,
                                               fft_length + cp_length)
        self.fft_demod = gr_fft.fft_vcc(fft_length, True, win, True)
        self.ofdm_frame_acq = gr_papyrus.ofdm_frame_acquisition(
            occupied_tones, fft_length, cp_length, ks[0])
        # linklab, check current mode: non-contiguous OFDM or not
        if self._nc_filter:
            print '\nMulti-band Filter Turned ON!'
            # linklab, non-contiguous filter
            self.ncofdm_filt = ncofdm_filt(self._fft_length,
                                           self._occupied_tones,
                                           self._carrier_map_bin)
            self.connect(self, self.chan_filt, self.ncofdm_filt)
            self.connect(self.ncofdm_filt,
                         self.ofdm_sync)  # into the synchronization alg.
            self.connect(
                (self.ofdm_sync, 0), self.nco,
                (self.sigmix,
                 1))  # use sync freq. offset output to derotate input signal
            self.connect(self.ncofdm_filt, self.delay,
                         (self.sigmix, 0))  # signal to be derotated
        else:
            print '\nMulti-band Filter Turned OFF!'
            self.connect(self, self.chan_filt)
            self.connect(self.chan_filt,
                         self.ofdm_sync)  # into the synchronization alg.
            self.connect(
                (self.ofdm_sync, 0), self.nco,
                (self.sigmix,
                 1))  # use sync freq. offset output to derotate input signal
            self.connect(self.chan_filt, self.delay,
                         (self.sigmix, 0))  # signal to be derotated

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

        self.connect((self.sampler, 0),
                     self.fft_demod)  # send derotated sampled signal to FFT
        self.connect(
            self.fft_demod,
            (self.ofdm_frame_acq, 0))  # find frame start and equalize signal
        self.connect((self.sampler, 1),
                     (self.ofdm_frame_acq,
                      1))  # send timing signal to signal frame start
        self.connect((self.ofdm_frame_acq, 0),
                     (self, 0))  # finished with fine/coarse freq correction,
        self.connect((self.ofdm_frame_acq, 1),
                     (self, 1))  # frame and symbol timing, and equalization

        if logging:
            self.connect(
                self.chan_filt,
                gr.file_sink(gr.sizeof_gr_complex,
                             "ofdm_receiver-chan_filt_c.dat"))
            self.connect(
                self.fft_demod,
                gr.file_sink(gr.sizeof_gr_complex * fft_length,
                             "ofdm_receiver-fft_out_c.dat"))
            self.connect(
                self.ofdm_frame_acq,
                gr.file_sink(gr.sizeof_gr_complex * occupied_tones,
                             "ofdm_receiver-frame_acq_c.dat"))
            self.connect((self.ofdm_frame_acq, 1),
                         gr.file_sink(1, "ofdm_receiver-found_corr_b.dat"))
            self.connect(
                self.sampler,
                gr.file_sink(gr.sizeof_gr_complex * fft_length,
                             "ofdm_receiver-sampler_c.dat"))
            self.connect(
                self.sigmix,
                gr.file_sink(gr.sizeof_gr_complex,
                             "ofdm_receiver-sigmix_c.dat"))
            self.connect(
                self.nco,
                gr.file_sink(gr.sizeof_gr_complex, "ofdm_receiver-nco_c.dat"))
Example #51
0
	def __init__(self, dab_params, rx_params, debug=False):
		"""
		OFDM time and coarse frequency synchronisation for DAB

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

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

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

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

		#
		# fine frequency synchronisation
		#

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

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

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

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

		if debug:
			self.connect(self.ffs_sample_and_average, gr.multiply_const_ff(1./(dp.T*2*pi)), gr.file_sink(gr.sizeof_float, "debug/ofdm_sync_dab_fine_freq_err_f.dat"))
			self.connect(self.ffs_mixer, gr.file_sink(gr.sizeof_gr_complex, "debug/ofdm_sync_dab_fine_freq_corrected_c.dat"))
Example #52
0
	def __init__(self, dab_params, rx_params, verbose=False, debug=False):
		"""
		Hierarchical block for OFDM demodulation

		@param dab_params DAB parameter object (dab.parameters.dab_parameters)
		@param rx_params RX parameter object (dab.parameters.receiver_parameters)
		@param debug enables debug output to files
		@param verbose whether to produce verbose messages
		"""

		self.dp = dp = dab_params
		self.rp = rp = rx_params
		self.verbose = verbose

		if self.rp.softbits:
			gr.hier_block2.__init__(self,"ofdm_demod",
						gr.io_signature (1, 1, gr.sizeof_gr_complex), # input signature
						gr.io_signature2(2, 2, gr.sizeof_float*self.dp.num_carriers*2, gr.sizeof_char)) # output signature
		else:
			gr.hier_block2.__init__(self,"ofdm_demod",
						gr.io_signature (1, 1, gr.sizeof_gr_complex), # input signature
						gr.io_signature2(2, 2, gr.sizeof_char*self.dp.num_carriers/4, gr.sizeof_char)) # output signature

		

		# workaround for a problem that prevents connecting more than one block directly (see trac ticket #161)
		#self.input = gr.kludge_copy(gr.sizeof_gr_complex)
		self.input = blocks.multiply_const_cc(1.0) # FIXME
		self.connect(self, self.input)
		
		# input filtering
		if self.rp.input_fft_filter: 
			if verbose: print "--> RX filter enabled"
			lowpass_taps = filter.firdes_low_pass(1.0,                     # gain
							  dp.sample_rate,          # sampling rate
							  rp.filt_bw,              # cutoff frequency
							  rp.filt_tb,              # width of transition band
							  filter.firdes.WIN_HAMMING)   # Hamming window
			self.fft_filter = filter.fft_filter_ccc(1, lowpass_taps)
		

		# correct sample rate offset, if enabled
		if self.rp.autocorrect_sample_rate:
			if verbose: print "--> dynamic sample rate correction enabled"
			self.rate_detect_ns = dab.detect_null(dp.ns_length, False)
			self.rate_estimator = dab.estimate_sample_rate_bf(dp.sample_rate, dp.frame_length)
			self.rate_prober = blocks.probe_signal_f()
			self.connect(self.input, self.rate_detect_ns, self.rate_estimator, self.rate_prober)
			# self.resample = gr.fractional_interpolator_cc(0, 1)
			self.resample = dab.fractional_interpolator_triggered_update_cc(0,1)
			self.connect(self.rate_detect_ns, (self.resample,1))
			self.updater = Timer(0.1,self.update_correction)
			# self.updater = threading.Thread(target=self.update_correction)
			self.run_interpolater_update_thread = True
			self.updater.setDaemon(True)
			self.updater.start()
		else:
			self.run_interpolater_update_thread = False
			if self.rp.sample_rate_correction_factor != 1:
				if verbose: print "--> static sample rate correction enabled"
				self.resample = gr.fractional_interpolator_cc(0, self.rp.sample_rate_correction_factor)

		# timing and fine frequency synchronisation
		self.sync = dab.ofdm_sync_dab2(self.dp, self.rp, debug)

		# ofdm symbol sampler
		self.sampler = dab.ofdm_sampler(dp.fft_length, dp.cp_length, dp.symbols_per_frame, rp.cp_gap)
		
		# fft for symbol vectors
		self.fft = fft.fft_vcc(dp.fft_length, True, [], True)

		# coarse frequency synchronisation
		self.cfs = dab.ofdm_coarse_frequency_correct(dp.fft_length, dp.num_carriers, dp.cp_length)

		# diff phasor
		self.phase_diff = dab.diff_phasor_vcc(dp.num_carriers)

		# remove pilot symbol
		self.remove_pilot = dab.ofdm_remove_first_symbol_vcc(dp.num_carriers)

		# magnitude equalisation
		if self.rp.equalize_magnitude:
			if verbose: print "--> magnitude equalization enabled"
			self.equalizer = dab.magnitude_equalizer_vcc(dp.num_carriers, rp.symbols_for_magnitude_equalization)

		# frequency deinterleaving
		self.deinterleave = dab.frequency_interleaver_vcc(dp.frequency_deinterleaving_sequence_array)
		
		# symbol demapping
		self.demapper = dab.qpsk_demapper_vcb(dp.num_carriers)

		#
		# connect everything
		#

		if self.rp.autocorrect_sample_rate or self.rp.sample_rate_correction_factor != 1:
			self.connect(self.input, self.resample)
			self.input2 = self.resample
		else:
			self.input2 = self.input
		if self.rp.input_fft_filter:
			self.connect(self.input2, self.fft_filter, self.sync)
		else:
			self.connect(self.input2, self.sync)

		# data stream
		self.connect((self.sync, 0), (self.sampler, 0), self.fft, (self.cfs, 0), self.phase_diff, (self.remove_pilot,0))
		if self.rp.equalize_magnitude:
			self.connect((self.remove_pilot,0), (self.equalizer,0), self.deinterleave)
		else:
			self.connect((self.remove_pilot,0), self.deinterleave)
		if self.rp.softbits:
			if verbose: print "--> using soft bits"
			self.softbit_interleaver = dab.complex_to_interleaved_float_vcf(self.dp.num_carriers)
			self.connect(self.deinterleave, self.softbit_interleaver, (self,0))
		else:
			self.connect(self.deinterleave, self.demapper, (self,0))

		# control stream
		self.connect((self.sync, 1), (self.sampler, 1), (self.cfs, 1), (self.remove_pilot,1))
		if self.rp.equalize_magnitude:
			self.connect((self.remove_pilot,1), (self.equalizer,1), (self,1))
		else:
			self.connect((self.remove_pilot,1), (self,1))
			
		# calculate an estimate of the SNR
		self.phase_var_decim   = blocks.keep_one_in_n(gr.sizeof_gr_complex*self.dp.num_carriers, self.rp.phase_var_estimate_downsample)
		self.phase_var_arg     = blocks.complex_to_arg(dp.num_carriers)
		self.phase_var_v2s     = blocks.vector_to_stream(gr.sizeof_float, dp.num_carriers)
		self.phase_var_mod     = dab.modulo_ff(pi/2)
		self.phase_var_avg_mod = filter.iir_filter_ffd([rp.phase_var_estimate_alpha], [0,1-rp.phase_var_estimate_alpha]) 
		self.phase_var_sub_avg = blocks.sub_ff()
		self.phase_var_sqr     = blocks.multiply_ff()
		self.phase_var_avg     = filter.iir_filter_ffd([rp.phase_var_estimate_alpha], [0,1-rp.phase_var_estimate_alpha]) 
		self.probe_phase_var   = blocks.probe_signal_f()
		self.connect((self.remove_pilot,0), self.phase_var_decim, self.phase_var_arg, self.phase_var_v2s, self.phase_var_mod, (self.phase_var_sub_avg,0), (self.phase_var_sqr,0))
		self.connect(self.phase_var_mod, self.phase_var_avg_mod, (self.phase_var_sub_avg,1))
		self.connect(self.phase_var_sub_avg, (self.phase_var_sqr,1))
		self.connect(self.phase_var_sqr, self.phase_var_avg, self.probe_phase_var)

		# measure processing rate
		self.measure_rate = dab.measure_processing_rate(gr.sizeof_gr_complex, 2000000) 
		self.connect(self.input, self.measure_rate)

		# debugging
		if debug:
			self.connect(self.fft, blocks.file_sink(gr.sizeof_gr_complex*dp.fft_length, "debug/ofdm_after_fft.dat"))
			self.connect((self.cfs,0), blocks.file_sink(gr.sizeof_gr_complex*dp.num_carriers, "debug/ofdm_after_cfs.dat"))
			self.connect(self.phase_diff, blocks.file_sink(gr.sizeof_gr_complex*dp.num_carriers, "debug/ofdm_diff_phasor.dat"))
			self.connect((self.remove_pilot,0), blocks.file_sink(gr.sizeof_gr_complex*dp.num_carriers, "debug/ofdm_pilot_removed.dat"))
			self.connect((self.remove_pilot,1), blocks.file_sink(gr.sizeof_char, "debug/ofdm_after_cfs_trigger.dat"))
			self.connect(self.deinterleave, blocks.file_sink(gr.sizeof_gr_complex*dp.num_carriers, "debug/ofdm_deinterleaved.dat"))
			if self.rp.equalize_magnitude:
				self.connect(self.equalizer, blocks.file_sink(gr.sizeof_gr_complex*dp.num_carriers, "debug/ofdm_equalizer.dat"))
			if self.rp.softbits:
				self.connect(self.softbit_interleaver, blocks.file_sink(gr.sizeof_float*dp.num_carriers*2, "debug/softbits.dat"))
Example #53
0
    def __init__(self,
                 fft_length,
                 cp_length,
                 occupied_tones,
                 snr,
                 logging=False):
        """
	Hierarchical block for receiving OFDM symbols.

	The input is the complex modulated signal at baseband.
        Synchronized packets are sent back to the demodulator.

        @param fft_length: total number of subcarriers
        @type  fft_length: int
        @param cp_length: length of cyclic prefix as specified in subcarriers (<= fft_length)
        @type  cp_length: int
        @param occupied_tones: number of subcarriers used for data
        @type  occupied_tones: int
        @param snr: estimated signal to noise ratio used to guide cyclic prefix synchronizer
        @type  snr: float
        @param logging: turn file logging on or off
        @type  logging: bool
	"""

        gr.hier_block2.__init__(
            self,
            "ofdm_receiver",
            gr.io_signature(1, 1, gr.sizeof_gr_complex),  # Input signature
            gr.io_signature2(2, 2, gr.sizeof_gr_complex * fft_length,
                             gr.sizeof_char * fft_length))  # Output signature

        bw = (float(occupied_tones) / float(fft_length)) / 2.0
        tb = bw * 0.08
        chan_coeffs = gr.firdes.low_pass(
            1.0,  # gain
            1.0,  # sampling rate
            bw + tb,  # midpoint of trans. band
            tb,  # width of trans. band
            gr.firdes.WIN_HAMMING)  # filter type
        #self.chan_filt = gr.fft_filter_ccc(1, chan_coeffs)
        self.chan_filt = gr.multiply_cc(1)

        win = [1 for i in range(fft_length)]

        ks0time = fft_length * (0, )

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

        self.nco = gr.frequency_modulator_fc(
            nco_sensitivity
        )  # generate a signal proportional to frequency error of sync block
        self.sigmix = gr.multiply_cc()
        self.sampler = digital_swig.ofdm_sampler(fft_length,
                                                 fft_length + cp_length)
        self.fft_demod = gr.fft_vcc(fft_length, True, win, True)

        self.connect(self, self.chan_filt)  # filter the input channel
        self.connect(self.chan_filt,
                     self.ofdm_sync)  # into the synchronization alg.

        self.connect(
            (self.ofdm_sync, 0), self.nco,
            (self.sigmix,
             1))  # use sync freq. offset output to derotate input signal
        self.connect(self.chan_filt,
                     (self.sigmix, 0))  # signal to be derotated

        self.connect(
            self.sigmix,
            (self.sampler, 0))  # sample off timing signal detected in sync alg
        #self.connect(self.chan_filt, (self.sampler,0))                   # sample off timing signal detected in sync alg

        self.connect((self.ofdm_sync, 1),
                     (self.sampler, 1))  # timing signal to sample at
        self.connect((self.sampler, 0),
                     self.fft_demod)  # send derotated sampled signal to FFT
        self.connect(self.fft_demod,
                     (self, 0))  # frequency domain signal sent to output 0
        self.connect((self.sampler, 1), (self, 1))  # timing sent to output 1
        print "setup OK"

        logging = 0

        if logging:
            self.connect(
                self.chan_filt,
                gr.file_sink(gr.sizeof_gr_complex,
                             "ofdm_receiver-chan_filt_c.dat"))
            self.connect((self.ofdm_sync, 0),
                         gr.file_sink(gr.sizeof_float,
                                      "ofdm_receiver-sync_0.dat"))
            self.connect((self.ofdm_sync, 1),
                         gr.file_sink(gr.sizeof_char,
                                      "ofdm_receiver-sync_1.dat"))
            self.connect(
                self.nco,
                gr.file_sink(gr.sizeof_gr_complex, "ofdm_receiver-nco_c.dat"))
            self.connect(
                self.sigmix,
                gr.file_sink(gr.sizeof_gr_complex,
                             "ofdm_receiver-sigmix_c.dat"))
            self.connect((self.sampler, 0),
                         gr.file_sink(gr.sizeof_gr_complex * fft_length,
                                      "ofdm_receiver-sampler_0.dat"))
            self.connect((self.sampler, 1),
                         gr.file_sink(gr.sizeof_char * fft_length,
                                      "ofdm_receiver-sampler_1.dat"))
            self.connect(
                self.fft_demod,
                gr.file_sink(gr.sizeof_gr_complex * fft_length,
                             "ofdm_receiver-fft_out_c.dat"))
Example #54
0
    def __init__(
        self,
        alpha=0.35,
        baud=45.45,
        decimation=1,
        mark_freq=2295,
        samp_rate=48000,
        space_freq=2125,
    ):
        gr.hier_block2.__init__(
            self,
            "RTTY Demod",
            gr.io_signature(1, 1, gr.sizeof_gr_complex),
            gr.io_signature2(4, 4, gr.sizeof_char, gr.sizeof_float),
        )

        ##################################################
        # Parameters
        ##################################################
        self.alpha = alpha
        self.baud = baud
        self.decimation = decimation
        self.mark_freq = mark_freq
        self.samp_rate = samp_rate
        self.space_freq = space_freq

        ##################################################
        # Blocks
        ##################################################
        self._threshold = blocks.threshold_ff(0, 0, 0)
        self._subtract = blocks.sub_ff(1)
        self._float_to_char = blocks.float_to_char(1, 1)

        self._space_tone_detector = tone_detector_cf(decimation, space_freq,
                                                     samp_rate, baud, 0.35)

        self._mark_tone_detector = tone_detector_cf(decimation, mark_freq,
                                                    samp_rate, baud, 0.35)

        self._baudot_decode = baudot_decode_bb()

        self._word_extractor = async_word_extractor_bb(5,
                                                       samp_rate / decimation,
                                                       baud)

        ##################################################
        # Connections
        ##################################################
        self.connect(self._word_extractor, self._baudot_decode, self)

        self.connect(self, self._mark_tone_detector, self._subtract)
        self.connect(self, self._space_tone_detector, (self._subtract, 1))

        self.connect(
            self._subtract,
            self._threshold,
            self._float_to_char,
            self._word_extractor,
        )

        self.connect(self._subtract, (self, 1))
        self.connect(self._mark_tone_detector, (self, 2))
        self.connect(self._space_tone_detector, (self, 3))