Example #1
0
    def __init__(self, options):
        gr.hier_block2.__init__(
            self, "fbmc_transmit_path", gr.io_signature(0, 0, 0), gr.io_signature(1, 1, gr.sizeof_gr_complex)
        )

        common_options.defaults(options)

        config = self.config = station_configuration()

        config.data_subcarriers = options.subcarriers
        config.cp_length = 0
        config.frame_data_blocks = options.data_blocks
        config._verbose = options.verbose
        config.fft_length = options.fft_length
        config.dc_null = options.dc_null
        config.training_data = default_block_header(config.data_subcarriers, config.fft_length, config.dc_null, options)
        config.coding = options.coding
        config.fbmc = options.fbmc
        config.adaptive_fbmc = options.adaptive_fbmc

        config.frame_id_blocks = 1  # FIXME

        # digital rms amplitude sent to USRP
        rms_amp = options.rms_amplitude
        self._options = copy.copy(options)

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

        # default values if parameters not set
        if rms_amp is None:
            rms_amp = math.sqrt(config.subcarriers)
        config.rms_amplitude = rms_amp

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

        ## shortcuts
        blen = config.block_length
        flen = config.frame_length
        dsubc = config.data_subcarriers
        vsubc = config.virtual_subcarriers

        # Adaptive Transmitter Concept

        used_id_bits = config.used_id_bits = 8  # TODO: no constant in source code
        rep_id_bits = config.rep_id_bits = config.data_subcarriers / used_id_bits  # BPSK
        if config.data_subcarriers % used_id_bits <> 0:
            raise SystemError, "Data subcarriers need to be multiple of %d" % (used_id_bits)

        ## Allocation Control
        self.allocation_src = allocation_src(
            config.data_subcarriers,
            config.frame_data_blocks,
            config.coding,
            "tcp://*:3333",
            "tcp://" + options.rx_hostname + ":3322",
        )
        if options.static_allocation:  # DEBUG
            # how many bits per subcarrier

            if options.coding:
                mode = 1  # Coding mode 1-9
                bitspermode = [0.5, 1, 1.5, 2, 3, 4, 4.5, 5, 6]  # Information bits per mode
                modulbitspermode = [1, 2, 2, 4, 4, 6, 6, 6, 8]  # Coding bits per mode
                bitcount_vec = [(int)(config.data_subcarriers * config.frame_data_blocks * bitspermode[mode - 1])]
                modul_bitcount_vec = [config.data_subcarriers * config.frame_data_blocks * modulbitspermode[mode - 1]]
                bitcount_src = blocks.vector_source_i(bitcount_vec, True, 1)
                modul_bitcount_src = blocks.vector_source_i(modul_bitcount_vec, True, 1)
                bitloading = mode
            else:
                bitloading = 1
                bitcount_vec = [config.data_subcarriers * config.frame_data_blocks * bitloading]
                bitcount_src = blocks.vector_source_i(bitcount_vec, True, 1)
                modul_bitcount_src = bitcount_src
            # id's for frames
            id_vec = range(0, 256)
            id_src = blocks.vector_source_s(id_vec, True, 1)
            # bitloading for ID symbol and then once for data symbols
            # bitloading_vec = [1]*dsubc+[0]*(dsubc/2)+[2]*(dsubc/2)

            test_allocation = (
                [bitloading] * (int)(config.data_subcarriers / 8)
                + [0] * (int)(config.data_subcarriers / 4 * 3)
                + [bitloading] * (int)(config.data_subcarriers / 8)
            )
            # bitloading_vec = [1]*dsubc+[bitloading]*dsubc
            bitloading_vec = [1] * dsubc + test_allocation
            bitloading_src = blocks.vector_source_b(bitloading_vec, True, dsubc)
            # bitcount for frames
            # bitcount_vec = [config.data_subcarriers*config.frame_data_blocks*bitloading]
            bitcount_vec = [config.frame_data_blocks * sum(test_allocation)]
            bitcount_src = blocks.vector_source_i(bitcount_vec, True, 1)
            # power loading, here same for all symbols
            power_vec = (
                [1] * (int)(config.data_subcarriers / 8)
                + [0] * (int)(config.data_subcarriers / 4 * 3)
                + [1] * (int)(config.data_subcarriers / 8)
            )
            power_src = blocks.vector_source_f(power_vec, True, dsubc)
            # mux control stream to mux id and data bits
            mux_vec = [0] * dsubc + [1] * bitcount_vec[0]
            mux_ctrl = blocks.vector_source_b(mux_vec, True, 1)
        else:
            id_src = (self.allocation_src, 0)
            bitcount_src = (self.allocation_src, 4)
            bitloading_src = (self.allocation_src, 2)
            power_src = (self.allocation_src, 1)
            if options.coding:
                modul_bitcount_src = (self.allocation_src, 5)
            else:
                modul_bitcount_src = bitcount_src
            mux_ctrl = ofdm.tx_mux_ctrl(dsubc)
            self.connect(modul_bitcount_src, mux_ctrl)
            # Initial allocation
            self.allocation_src.set_allocation([4] * config.data_subcarriers, [1] * config.data_subcarriers)
            if options.benchmarking:
                self.allocation_src.set_allocation([4] * config.data_subcarriers, [1] * config.data_subcarriers)

        if options.lab_special_case:
            self.allocation_src.set_allocation(
                [0] * (config.data_subcarriers / 4)
                + [2] * (config.data_subcarriers / 2)
                + [0] * (config.data_subcarriers / 4),
                [1] * config.data_subcarriers,
            )

        if options.log:
            log_to_file(self, id_src, "data/id_src.short")
            log_to_file(self, bitcount_src, "data/bitcount_src.int")
            log_to_file(self, bitloading_src, "data/bitloading_src.char")
            log_to_file(self, power_src, "data/power_src.cmplx")

        ## GUI probe output
        zmq_probe_bitloading = zeromq.pub_sink(gr.sizeof_char, dsubc, "tcp://*:4445")
        # also skip ID symbol bitloading with keep_one_in_n (side effect)
        # factor 2 for bitloading because we have two vectors per frame, one for id symbol and one for all payload/data symbols
        # factor config.frame_data_part for power because there is one vector per ofdm symbol per frame
        self.connect(bitloading_src, blocks.keep_one_in_n(gr.sizeof_char * dsubc, 2 * 40), zmq_probe_bitloading)
        zmq_probe_power = zeromq.pub_sink(gr.sizeof_float, dsubc, "tcp://*:4444")
        # self.connect(power_src, blocks.keep_one_in_n(gr.sizeof_gr_complex*dsubc,40), blocks.complex_to_real(dsubc), zmq_probe_power)
        self.connect(power_src, blocks.keep_one_in_n(gr.sizeof_float * dsubc, 40), zmq_probe_power)

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

        ## ID Encoder
        id_enc = self._id_encoder = repetition_encoder_sb(used_id_bits, rep_id_bits, whitener_pn)
        self.connect(id_src, id_enc)

        if options.log:
            id_enc_f = gr.char_to_float()
            self.connect(id_enc, id_enc_f)
            log_to_file(self, id_enc_f, "data/id_enc_out.float")

        ## Reference Data Source
        ber_ref_src = ber_reference_source(self._options)
        self.connect(id_src, (ber_ref_src, 0))
        self.connect(bitcount_src, (ber_ref_src, 1))

        if options.log:
            log_to_file(self, ber_ref_src, "data/ber_rec_src_tx.char")

        if options.log:
            log_to_file(self, btrig, "data/bitmap_trig.char")

        ## Frame Trigger
        ftrig_stream = [1] + [0] * (config.frame_data_part - 1)
        ftrig = self._frame_trigger = blocks.vector_source_b(ftrig_stream, True)

        ## Data Multiplexer
        # Input 0: control stream
        # Input 1: encoded ID stream
        # Inputs 2..n: data streams
        dmux = self._data_multiplexer = stream_controlled_mux_b()
        self.connect(mux_ctrl, (dmux, 0))
        self.connect(id_enc, (dmux, 1))

        if options.coding:
            fo = trellis.fsm(1, 2, [91, 121])
            encoder = self._encoder = trellis.encoder_bb(fo, 0)
            unpack = self._unpack = blocks.unpack_k_bits_bb(2)
            self.connect(ber_ref_src, encoder, unpack)

            if options.interleave:
                int_object = trellis.interleaver(2000, 666)
                interlv = trellis.permutation(int_object.K(), int_object.INTER(), 1, gr.sizeof_char)

            if not options.nopunct:
                bmaptrig_stream_puncturing = [1] + [0] * (config.frame_data_blocks / 2 - 1)
                btrig_puncturing = self._bitmap_trigger_puncturing = blocks.vector_source_b(
                    bmaptrig_stream_puncturing, True
                )
                puncturing = self._puncturing = puncture_bb(config.data_subcarriers)
                self.connect(bitloading_src, (puncturing, 1))
                self.connect(self._bitmap_trigger_puncturing, (puncturing, 2))
                self.connect(unpack, puncturing)
                last_block = puncturing

                if options.interleave:
                    self.connect(last_block, interlv)
                    last_block = interlv

                if options.benchmarking:
                    self.connect(last_block, blocks.head(gr.sizeof_char, options.N), (dmux, 2))
                else:
                    self.connect(last_block, (dmux, 2))
            else:
                if options.benchmarking:
                    self.connect(unpack, blocks.head(gr.sizeof_char, options.N), (dmux, 2))
                else:
                    self.connect(unpack, (dmux, 2))

        else:
            if options.benchmarking:
                self.connect(ber_ref_src, blocks.head(gr.sizeof_char, options.N), (dmux, 2))
            else:
                self.connect(ber_ref_src, (dmux, 2))

        if options.log:
            dmux_f = gr.char_to_float()
            self.connect(dmux, dmux_f)
            log_to_file(self, dmux_f, "data/dmux_out.float")

        ## Modulator
        mod = self._modulator = generic_mapper_bcv(config.data_subcarriers, config.coding, config.frame_data_part)
        self.connect(dmux, (mod, 0))
        self.connect(bitloading_src, (mod, 1))

        if options.log:
            log_to_file(self, mod, "data/mod_out.compl")
            modi = blocks.complex_to_imag(config.data_subcarriers)
            modr = blocks.complex_to_real(config.data_subcarriers)
            self.connect(mod, modi)
            self.connect(mod, modr)
            log_to_file(self, modi, "data/mod_imag_out.float")
            log_to_file(self, modr, "data/mod_real_out.float")

        ## Power allocator
        pa = self._power_allocator = multiply_frame_fc(config.frame_data_part, config.data_subcarriers)
        self.connect(mod, (pa, 0))
        self.connect(power_src, (pa, 1))

        if options.log:
            log_to_file(self, pa, "data/pa_out.compl")

        if options.fbmc:
            psubc = pa
        else:
            psubc = self._pilot_subcarrier_inserter = pilot_subcarrier_inserter()
            self.connect(pa, psubc)

            if options.log:
                log_to_file(self, psubc, "data/psubc_out.compl")

        subcarriers = config.subcarriers

        # fbmc_pblocks_timing = self._fbmc_timing_pilot_block_inserter = fbmc_timing_pilot_block_inserter(5,False)

        oqam_prep = self._oqam_prep = fbmc_oqam_preprocessing_vcvc(config.subcarriers, 0, 0)
        self.connect(psubc, oqam_prep)

        fbmc_pblocks = self._fbmc_pilot_block_inserter = fbmc_pilot_block_inserter(5, False)
        self.connect(oqam_prep, fbmc_pblocks)
        # log_to_file(self, fbmc_pblocks, "data/fbmc_pblocks_out.compl")
        # fbmc_insert_pream = self._fbmc_insert_pream = fbmc_insert_preamble_vcvc(M, syms_per_frame, preamble)
        # log_to_file(self, oqam_prep, "data/oqam_prep.compl")
        # log_to_file(self, psubc, "data/psubc_out.compl")
        # fbmc_pblocks = fbmc_pblocks_timing
        # log_to_file(self, fbmc_pblocks, "data/fbmc_pblocks_out.compl")

        beta_mult = self._beta_mult = fbmc_beta_multiplier_vcvc(config.subcarriers, 4, 4 * config.fft_length - 1, 0)
        self.connect(fbmc_pblocks, beta_mult)
        log_to_file(self, beta_mult, "data/beta_mult.compl")

        ## Add virtual subcarriers
        if config.fft_length > subcarriers:
            vsubc = self._virtual_subcarrier_extender = vector_padding_dc_null(
                config.subcarriers, config.fft_length, config.dc_null
            )
            self.connect(beta_mult, vsubc)
        else:
            vsubc = self._virtual_subcarrier_extender = beta_mult

        if options.log:
            log_to_file(self, vsubc, "data/vsubc_out.compl")

        ## IFFT, no window, block shift
        ifft = self._ifft = fft_blocks.fft_vcc(config.fft_length, False, [], True)
        self.connect(vsubc, ifft)

        if options.log:
            log_to_file(self, ifft, "data/ifft_out.compl")

        # FBMC separate stream + filterbanks
        separate_oqam = self._separate_oqam = fbmc_separate_vcvc(config.fft_length, 2)
        poly_netw_1 = self._poly_netw_1 = fbmc_polyphase_network_vcvc(
            config.fft_length, 4, 4 * config.fft_length - 1, False
        )
        poly_netw_2 = self._poly_netw_2 = fbmc_polyphase_network_vcvc(
            config.fft_length, 4, 4 * config.fft_length - 1, False
        )
        overlap_p2s = self._overlap_p2s = fbmc_overlapping_parallel_to_serial_vcc(config.fft_length)

        self.connect(ifft, (separate_oqam, 0), poly_netw_1)
        self.connect((separate_oqam, 1), poly_netw_2)
        self.connect(poly_netw_1, (overlap_p2s, 0))
        self.connect(poly_netw_2, (overlap_p2s, 1))

        ## Pilot blocks (preambles)
        # pblocks = self._pilot_block_inserter = pilot_block_inserter2(5,False)
        # self.connect( overlap_p2s, blocks.stream_to_vector(gr.sizeof_gr_complex,config.fft_length/2),  pblocks )

        # log_to_file(self, pblocks, "data/fbmc_pilot_block_ins_out.compl")

        if options.log:
            log_to_file(self, pblocks, "data/pilot_block_ins_out.compl")

        ## Cyclic Prefix
        # cp = self._cyclic_prefixer = cyclic_prefixer(config.fft_length,
        # config.block_length)

        # cp= blocks.vector_to_stream(gr.sizeof_gr_complex, config.fft_length/2)
        # self.connect(pblocks, cp )
        # self.connect( overlap_p2s,blocks.stream_to_vector(gr.sizeof_gr_complex,config.fft_length/2), cp )

        lastblock = overlap_p2s

        if options.log:
            log_to_file(self, overlap_p2s, "data/overlap_p2s_out.compl")

        # Digital Amplifier for resource allocation
        if config.adaptive_fbmc:
            rep = blocks.repeat(gr.sizeof_gr_complex, config.frame_length * config.block_length)
            amp = blocks.multiply_cc()
            self.connect(lastblock, (amp, 0))
            self.connect((self.allocation_src, 3), rep, (amp, 1))
            lastblock = amp
        else:
            self.connect((self.allocation_src, 3), blocks.null_sink(gr.sizeof_gr_complex))

        ## Digital Amplifier
        # amp = self._amplifier = gr.multiply_const_cc(1)
        amp = self._amplifier = ofdm.multiply_const_ccf(1.0)
        self.connect(lastblock, amp)
        self.set_rms_amplitude(rms_amp)
        # log_to_file(self, amp, "data/amp_tx_out.compl")

        if options.log:
            log_to_file(self, amp, "data/amp_tx_out.compl")

        ## Tx parameters
        bandwidth = options.bandwidth or 2e6
        bits = 8 * config.data_subcarriers * config.frame_data_blocks  # max. QAM256
        samples_per_frame = config.frame_length * config.block_length
        tb = samples_per_frame / bandwidth
        # set dummy carrier frequency if none available due to baseband mode
        if options.tx_freq is None:
            options.tx_freq = 0.0
        self.tx_parameters = {
            "carrier_frequency": options.tx_freq / 1e9,
            "fft_size": config.fft_length,
            "cp_size": config.cp_length,
            "subcarrier_spacing": options.bandwidth / config.fft_length / 1e3,
            "data_subcarriers": config.data_subcarriers,
            "bandwidth": options.bandwidth / 1e6,
            "frame_length": config.frame_length,
            "symbol_time": (config.cp_length + config.fft_length) / options.bandwidth * 1e6,
            "max_data_rate": (bits / tb) / 1e6,
        }

        ## Setup Output
        self.connect(amp, self)

        # Display some information about the setup
        if config._verbose:
            self._print_verbage()
Example #2
0
    def __init__(self,
                 M=1024,
                 K=4,
                 qam_size=16,
                 syms_per_frame=10,
                 carriers=924,
                 theta_sel=0,
                 exclude_preamble=0,
                 sel_preamble=0,
                 zero_pads=1,
                 extra_pad=False):
        gr.hier_block2.__init__(
            self,
            "fbmc_transmitter_demo",
            gr.io_signature(1, 1, gr.sizeof_gr_complex * M),
            gr.io_signature(1, 1, gr.sizeof_gr_complex * 1),
        )

        ##################################################
        # Parameters
        ##################################################
        self.syms_per_frame = syms_per_frame
        self.qam_size = qam_size
        self.K = K
        self.M = M
        self.exclude_preamble = exclude_preamble
        self.theta_sel = theta_sel
        self.zero_pads = zero_pads

        ##################################################
        # Variables
        ##################################################

        # Assertions
        assert (M > 0 and K > 0
                and qam_size > 0), "M, K and qam_size should be bigger than 0"
        assert ((math.log(M) / math.log(2)) == int(
            math.log(M) / math.log(2))), "M shouldbe a power of 2"
        assert (K == 4), "for now only K=4 s supported."
        assert (qam_size == 4 or qam_size == 16 or qam_size == 64
                or qam_size == 256
                ), "Only 4-,16-,64-,256-qam constellations are supported."
        assert (theta_sel == 0 or theta_sel == 1)
        assert (exclude_preamble == 0 or exclude_preamble == 1)

        ##################################################
        # Blocks
        ##################################################
        self.fft_vxx_0_0 = fft.fft_vcc(M, False, (), True, 1)
        self.blocks_multiply_const_vxx_0 = blocks.multiply_const_vcc(
            ([1.0 / (M * 0.6863)] * M))
        # self.fbmc_symbol_creation_bvc_0 = ofdm.fbmc_symbol_creation_bvc(carriers, qam_size)
        self.vector_padding_0 = ofdm.vector_padding(carriers, M, -1)
        self.fbmc_separate_vcvc_0 = ofdm.fbmc_separate_vcvc(M, 2)
        self.fbmc_polyphase_network_vcvc_0_0 = ofdm.fbmc_polyphase_network_vcvc(
            M, K, K * M - 1, False)
        self.fbmc_polyphase_network_vcvc_0 = ofdm.fbmc_polyphase_network_vcvc(
            M, K, K * M - 1, False)
        self.fbmc_overlapping_parallel_to_serial_vcc_0 = ofdm.fbmc_overlapping_parallel_to_serial_vcc(
            M)
        self.fbmc_oqam_preprocessing_vcvc_0 = ofdm.fbmc_oqam_preprocessing_vcvc(
            M, 0, theta_sel)
        self.fbmc_insert_preamble_vcvc_0 = ofdm.fbmc_insert_preamble_vcvc(
            M, syms_per_frame, sel_preamble, zero_pads, extra_pad)
        self.fbmc_beta_multiplier_vcvc_0 = ofdm.fbmc_beta_multiplier_vcvc(
            M, K, K * M - 1, 0)
        self.blks2_selector_0 = grc_blks2.selector(
            item_size=gr.sizeof_gr_complex * M,
            num_inputs=2,
            num_outputs=1,
            input_index=exclude_preamble,
            output_index=0,
        )

        ##################################################
        # Connections
        ##################################################
        self.connect((self, 0), (self.vector_padding_0, 0))
        self.connect((self.vector_padding_0, 0),
                     (self.fbmc_oqam_preprocessing_vcvc_0, 0))
        # self.connect(, (self.fbmc_symbol_creation_bvc_0, 0))
        self.connect((self.fbmc_beta_multiplier_vcvc_0, 0),
                     (self.fft_vxx_0_0, 0))
        self.connect((self.fft_vxx_0_0, 0),
                     (self.blocks_multiply_const_vxx_0, 0))
        self.connect((self.blocks_multiply_const_vxx_0, 0),
                     (self.fbmc_separate_vcvc_0, 0))
        self.connect((self.fbmc_polyphase_network_vcvc_0, 0),
                     (self.fbmc_overlapping_parallel_to_serial_vcc_0, 0))
        self.connect((self.fbmc_polyphase_network_vcvc_0_0, 0),
                     (self.fbmc_overlapping_parallel_to_serial_vcc_0, 1))
        self.connect((self.fbmc_separate_vcvc_0, 1),
                     (self.fbmc_polyphase_network_vcvc_0_0, 0))
        self.connect((self.fbmc_separate_vcvc_0, 0),
                     (self.fbmc_polyphase_network_vcvc_0, 0))
        self.connect((self.fbmc_overlapping_parallel_to_serial_vcc_0, 0),
                     (self, 0))
        self.connect((self.fbmc_oqam_preprocessing_vcvc_0, 0),
                     (self.blks2_selector_0, 1))
        self.connect((self.fbmc_oqam_preprocessing_vcvc_0, 0),
                     (self.fbmc_insert_preamble_vcvc_0, 0))
        self.connect((self.fbmc_insert_preamble_vcvc_0, 0),
                     (self.blks2_selector_0, 0))
        self.connect((self.blks2_selector_0, 0),
                     (self.fbmc_beta_multiplier_vcvc_0, 0))
Example #3
0
    def __init__(self,
                 M=1024,
                 K=4,
                 qam_size=16,
                 syms_per_frame=10,
                 carriers=924,
                 theta_sel=0,
                 sel_eq=0,
                 exclude_preamble=0,
                 sel_preamble=0,
                 zero_pads=1,
                 extra_pad=False):
        gr.hier_block2.__init__(
            self,
            "fbmc_receiver_demo",
            gr.io_signature(1, 1, gr.sizeof_gr_complex * 1),
            gr.io_signature(1, 1, gr.sizeof_gr_complex * M),
        )

        ##################################################
        # Parameters
        ##################################################
        self.theta_sel = theta_sel
        self.exclude_preamble = exclude_preamble
        self.sel_eq = sel_eq
        self.M = M
        self.K = K
        self.qam_size = qam_size
        self.syms_per_frame = syms_per_frame

        ##################################################
        # Variables
        ##################################################
        if self.exclude_preamble == 1 and self.sel_eq != 3:
            self.sel_eq = sel_eq = 3
            warnings.warn(
                "Since exclude_preamble is set as 1, sel_eq is forced to be 3 (no equalizer)"
            )

        self.skip = skip = 0
        if exclude_preamble == 1 or sel_eq == 3 or sel_eq == 0:
            self.skip = skip = 0
        else:
            self.skip = skip = 1

        # Assertions
        assert (M > 0 and K > 0
                and qam_size > 0), "M, K and qam_size should be bigger than 0"
        assert ((math.log(M) / math.log(2)) == int(
            math.log(M) / math.log(2))), "M should be a power of 2"
        assert (K == 4), "for now only K=4 s supported."
        assert (qam_size == 4 or qam_size == 16 or qam_size == 64
                or qam_size == 128 or qam_size == 256
                ), "Only 4-,16-,64-,128-,256-qam constellations are supported."
        assert (theta_sel == 0 or theta_sel == 1)
        assert (exclude_preamble == 0 or exclude_preamble == 1)

        ##################################################
        # Blocks
        ##################################################
        self.ofdm_vector_mask_0 = ofdm.vector_mask(M, (M - carriers) / 2,
                                                   carriers, [])
        # self.ofdm_fbmc_symbol_estimation_vcb_0 = ofdm.fbmc_symbol_estimation_vcb(carriers, qam_size)
        # unsigned int M, unsigned int syms_per_frame, int sel_preamble, int zero_pads, bool extra_pad, int sel_eq
        self.ofdm_fbmc_subchannel_processing_vcvc_0 = ofdm.fbmc_subchannel_processing_vcvc(
            M, syms_per_frame, sel_preamble, zero_pads, extra_pad, sel_eq)
        self.ofdm_fbmc_separate_vcvc_0 = ofdm.fbmc_separate_vcvc(M, 2)
        self.ofdm_fbmc_remove_preamble_vcvc_0 = ofdm.fbmc_remove_preamble_vcvc(
            M, syms_per_frame, sel_preamble, zero_pads, extra_pad)
        self.ofdm_fbmc_polyphase_network_vcvc_3 = ofdm.fbmc_polyphase_network_vcvc(
            M, K, K * M - 1, True)
        self.ofdm_fbmc_polyphase_network_vcvc_2 = ofdm.fbmc_polyphase_network_vcvc(
            M, K, K * M - 1, True)
        self.ofdm_fbmc_overlapping_serial_to_parallel_cvc_0 = ofdm.fbmc_overlapping_serial_to_parallel_cvc(
            M)
        self.ofdm_fbmc_oqam_postprocessing_vcvc_0 = ofdm.fbmc_oqam_postprocessing_vcvc(
            M, 0, theta_sel)
        self.ofdm_fbmc_junction_vcvc_0 = ofdm.fbmc_junction_vcvc(M, 2)
        self.ofdm_fbmc_beta_multiplier_vcvc_1 = ofdm.fbmc_beta_multiplier_vcvc(
            M, K, K * M - 1, 0)
        self.fft_vxx_1 = fft.fft_vcc(M, True, ([]), True, 1)
        self.blocks_skiphead_0_0 = blocks.skiphead(gr.sizeof_gr_complex * M,
                                                   skip)
        self.blocks_skiphead_0 = blocks.skiphead(gr.sizeof_gr_complex * M,
                                                 2 * K - 1 - 1)
        self.blocks_null_sink_0 = blocks.null_sink(gr.sizeof_gr_complex * M)
        self.blks2_selector_0_0 = grc_blks2.selector(
            item_size=gr.sizeof_gr_complex * M,
            num_inputs=2,
            num_outputs=1,
            input_index=exclude_preamble,
            output_index=0,
        )

        ##################################################
        # Connections
        ##################################################
        self.connect((self.blks2_selector_0_0, 0),
                     (self.ofdm_fbmc_oqam_postprocessing_vcvc_0, 0))
        self.connect((self.ofdm_fbmc_remove_preamble_vcvc_0, 0),
                     (self.blks2_selector_0_0, 0))
        self.connect((self.blocks_skiphead_0_0, 0),
                     (self.blks2_selector_0_0, 1))
        self.connect((self.blocks_skiphead_0_0, 0),
                     (self.ofdm_fbmc_remove_preamble_vcvc_0, 0))
        self.connect((self.ofdm_fbmc_beta_multiplier_vcvc_1, 0),
                     (self.blocks_skiphead_0, 0))
        self.connect((self.fft_vxx_1, 0),
                     (self.ofdm_fbmc_beta_multiplier_vcvc_1, 0))
        self.connect((self.blocks_skiphead_0, 0),
                     (self.ofdm_fbmc_subchannel_processing_vcvc_0, 0))
        self.connect((self.ofdm_fbmc_junction_vcvc_0, 0), (self.fft_vxx_1, 0))
        # self.connect((self.ofdm_fbmc_symbol_estimation_vcb_0, 0), )
        self.connect((self.ofdm_fbmc_subchannel_processing_vcvc_0, 1),
                     (self.blocks_null_sink_0, 0))
        self.connect((self.ofdm_vector_mask_0, 0), (self, 0))
        self.connect((self.ofdm_fbmc_oqam_postprocessing_vcvc_0, 0),
                     (self.ofdm_vector_mask_0, 0))
        self.connect((self.ofdm_fbmc_subchannel_processing_vcvc_0, 0),
                     (self.blocks_skiphead_0_0, 0))
        self.connect((self, 0),
                     (self.ofdm_fbmc_overlapping_serial_to_parallel_cvc_0, 0))
        self.connect((self.ofdm_fbmc_separate_vcvc_0, 0),
                     (self.ofdm_fbmc_polyphase_network_vcvc_2, 0))
        self.connect((self.ofdm_fbmc_separate_vcvc_0, 1),
                     (self.ofdm_fbmc_polyphase_network_vcvc_3, 0))
        self.connect((self.ofdm_fbmc_overlapping_serial_to_parallel_cvc_0, 0),
                     (self.ofdm_fbmc_separate_vcvc_0, 0))
        self.connect((self.ofdm_fbmc_polyphase_network_vcvc_2, 0),
                     (self.ofdm_fbmc_junction_vcvc_0, 0))
        self.connect((self.ofdm_fbmc_polyphase_network_vcvc_3, 0),
                     (self.ofdm_fbmc_junction_vcvc_0, 1))
Example #4
0
    def __init__(self):
        gr.top_block.__init__(self, "Top Block")
        Qt.QWidget.__init__(self)
        self.setWindowTitle("Top Block")
        try:
             self.setWindowIcon(Qt.QIcon.fromTheme('gnuradio-grc'))
        except:
             pass
        self.top_scroll_layout = Qt.QVBoxLayout()
        self.setLayout(self.top_scroll_layout)
        self.top_scroll = Qt.QScrollArea()
        self.top_scroll.setFrameStyle(Qt.QFrame.NoFrame)
        self.top_scroll_layout.addWidget(self.top_scroll)
        self.top_scroll.setWidgetResizable(True)
        self.top_widget = Qt.QWidget()
        self.top_scroll.setWidget(self.top_widget)
        self.top_layout = Qt.QVBoxLayout(self.top_widget)
        self.top_grid_layout = Qt.QGridLayout()
        self.top_layout.addLayout(self.top_grid_layout)

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


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

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

        ##################################################
        # Connections
        ##################################################
        self.connect((self.ofdm_fbmc_polyphase_network_vcvc_0, 0), (self.ofdm_fbmc_overlapping_parallel_to_serial_vcc_0, 0))
        self.connect((self.ofdm_fbmc_polyphase_network_vcvc_1, 0), (self.ofdm_fbmc_overlapping_parallel_to_serial_vcc_0, 1))
        self.connect((self.ofdm_fbmc_separate_vcvc_1, 1), (self.ofdm_fbmc_polyphase_network_vcvc_1, 0))
        self.connect((self.ofdm_fbmc_oqam_preprocessing_vcvc_0, 0), (self.ofdm_fbmc_pilot_block_inserter_0, 0))
        self.connect((self.ofdm_fbmc_pilot_block_inserter_0, 0), (self.ofdm_vector_padding_0, 0))
        self.connect((self.ofdm_fbmc_beta_multiplier_vcvc_0, 0), (self.fft_vxx_1, 0))
        self.connect((self.fft_vxx_1, 0), (self.ofdm_fbmc_separate_vcvc_1, 0))
        self.connect((self.tigr_transmit_control_0, 0), (self.ofdm_fbmc_oqam_preprocessing_vcvc_0, 0))
        self.connect((self.single_pole_iir_filter_xx_0, 0), (self.blocks_keep_one_in_n_1, 0))
        self.connect((self.ofdm_fbmc_frame_sampler_0, 1), (self.ofdm_fbmc_pilot_block_filter_0, 1))
        self.connect((self.ofdm_fbmc_frame_sampler_0, 0), (self.ofdm_fbmc_pilot_block_filter_0, 0))
        self.connect((self.ofdm_fbmc_pilot_block_filter_0, 1), (self.ofdm_vector_sampler_0, 1))
        self.connect((self.ofdm_vector_sampler_0, 0), (self.ofdm_coded_bpsk_soft_decoder_0, 0))
        self.connect((self.ofdm_coded_bpsk_soft_decoder_0, 0), (self.ofdm_allocation_buffer_0, 0))
        self.connect((self.ofdm_allocation_buffer_0, 1), (self.ofdm_generic_softdemapper_vcf_0, 1))
        self.connect((self.single_pole_iir_filter_xx_0, 0), (self.ofdm_generic_softdemapper_vcf_0, 2))
        self.connect((self.ofdm_generic_softdemapper_vcf_0, 0), (self.trellis_permutation_0, 0))
        self.connect((self.ofdm_depuncture_ff_0, 0), (self.ofdm_viterbi_combined_fb_0, 0))
        self.connect((self.ofdm_allocation_buffer_0, 1), (self.ofdm_depuncture_ff_0, 1))
        self.connect((self.blocks_vector_source_x_0, 0), (self.ofdm_depuncture_ff_0, 2))
        self.connect((self.ofdm_allocation_buffer_0, 0), (self.ofdm_multiply_const_ii_0, 0))
        self.connect((self.ofdm_multiply_const_ii_0, 0), (self.ofdm_viterbi_combined_fb_0, 1))
        self.connect((self.ofdm_fbmc_separate_vcvc_1, 0), (self.ofdm_fbmc_polyphase_network_vcvc_0, 0))
        self.connect((self.ofdm_viterbi_combined_fb_0, 0), (self.tigr_ber_measurement_0, 2))
        self.connect((self.ofdm_dynamic_trigger_ib_0, 0), (self.tigr_ber_measurement_0, 3))
        self.connect((self.ofdm_fbmc_frame_sampler_0, 0), (self.tigr_fbmc_snr_estimator_0, 0))
        self.connect((self.ofdm_fbmc_frame_sampler_0, 1), (self.tigr_fbmc_snr_estimator_0, 1))
        self.connect((self.tigr_fbmc_inner_receiver_0, 1), (self.ofdm_fbmc_frame_sampler_0, 1))
        self.connect((self.tigr_fbmc_inner_receiver_0, 2), (self.ofdm_fbmc_frame_sampler_0, 0))
        self.connect((self.rms, 0), (self.blocks_throttle_0, 0))
        self.connect((self.tigr_fbmc_inner_receiver_0, 3), (self.zeromq_pub_sink_0, 0))
        self.connect((self.blocks_keep_one_in_n_1, 0), (self.zeromq_pub_sink_1, 0))
        self.connect((self.ofdm_vector_padding_0, 0), (self.ofdm_fbmc_beta_multiplier_vcvc_0, 0))
        self.connect((self.tigr_fbmc_inner_receiver_0, 0), (self.single_pole_iir_filter_xx_0, 0))
        self.connect((self.ofdm_fbmc_overlapping_parallel_to_serial_vcc_0, 0), (self.rms, 0))
        self.connect((self.ofdm_allocation_buffer_0, 0), (self.ofdm_dynamic_trigger_ib_0, 0))
        self.connect((self.ofdm_coded_bpsk_soft_decoder_0, 0), (self.tigr_ber_measurement_0, 0))
        self.connect((self.ofdm_allocation_buffer_0, 0), (self.tigr_ber_measurement_0, 1))
        self.connect((self.blks2_selector_0, 0), (self.ofdm_depuncture_ff_0, 0))
        self.connect((self.trellis_permutation_0, 0), (self.blks2_selector_0, 1))
        self.connect((self.ofdm_generic_softdemapper_vcf_0, 0), (self.blks2_selector_0, 0))
        self.connect((self.blocks_throttle_0, 0), (self.channels_channel_model_0, 0))
        self.connect((self.channels_channel_model_0, 0), (self.tigr_fbmc_inner_receiver_0, 0))
        self.connect((self.ofdm_fbmc_pilot_block_filter_0, 0), (self.ofdm_vector_sampler_0, 0))
        self.connect((self.ofdm_allocation_buffer_0, 2), (self.ofdm_multiply_frame_fc_0, 1))
        self.connect((self.ofdm_fbmc_pilot_block_filter_0, 0), (self.ofdm_multiply_frame_fc_0, 0))
        self.connect((self.ofdm_multiply_frame_fc_0, 0), (self.tigr_scatterplot_0, 0))
        self.connect((self.ofdm_multiply_frame_fc_0, 0), (self.ofdm_generic_softdemapper_vcf_0, 0))
    def __init__(self, M=1024, K=4, qam_size=16, syms_per_frame=10, start=10, end=29, theta_sel=0, exclude_preamble=0, sel_preamble=0, zero_pads=1, extra_pad=False):
        gr.hier_block2.__init__(self,
            "fbmc_transmitter_multiuser_bc",
            gr.io_signature(1, 1, gr.sizeof_char*1),
            gr.io_signature(1, 1, gr.sizeof_gr_complex*1),
        )

        ##################################################
        # Parameters
        ##################################################
        self.syms_per_frame = syms_per_frame
        self.qam_size = qam_size
        self.K = K
        self.M = M
        self.exclude_preamble = exclude_preamble
        self.theta_sel = theta_sel
        self.zero_pads = zero_pads
        self.allocation = allocation = end-start+1

        ##################################################
        # Variables
        ##################################################

        # Assertions
        assert(M>0 and K>0 and qam_size>0), "M, K and qam_size should be bigger than 0"
        assert((math.log(M)/math.log(2))==int(math.log(M)/math.log(2))), "M shouldbe a power of 2"
        assert(K==4), "for now only K=4 s supported."
        assert(qam_size==4 or qam_size==16 or qam_size==64 or qam_size==256 ), "Only 4-,16-,64-,256-qam constellations are supported."
        assert(theta_sel==0 or theta_sel==1)
        assert(exclude_preamble==0 or exclude_preamble==1)

        ##################################################
        # Blocks
        ##################################################
        self.fft_vxx_0_0 = fft.fft_vcc(M, False, (), True, 1)
        self.blocks_multiply_const_vxx_0 = blocks.multiply_const_vcc(([1.0/(M*0.6863)]*M))
        self.fbmc_symbol_creation_bvc_0 = ofdm.fbmc_symbol_creation_bvc(allocation, qam_size)
        self.vector_padding_0 = ofdm.fbmc_asymmetrical_vector_padding_vcvc(start,end,M,-1)
        self.fbmc_separate_vcvc_0 = ofdm.fbmc_separate_vcvc(M, 2)
        self.fbmc_polyphase_network_vcvc_0_0 = ofdm.fbmc_polyphase_network_vcvc(M, K, K*M-1, False)
        self.fbmc_polyphase_network_vcvc_0 = ofdm.fbmc_polyphase_network_vcvc(M, K, K*M-1, False)
        self.fbmc_overlapping_parallel_to_serial_vcc_0 = ofdm.fbmc_overlapping_parallel_to_serial_vcc(M)
        self.fbmc_oqam_preprocessing_vcvc_0 = ofdm.fbmc_oqam_preprocessing_vcvc(M, 0, theta_sel)
        self.fbmc_insert_preamble_vcvc_0 = ofdm.fbmc_insert_preamble_vcvc(M, syms_per_frame, sel_preamble, zero_pads,extra_pad)
        self.fbmc_beta_multiplier_vcvc_0 = ofdm.fbmc_beta_multiplier_vcvc(M, K, K*M-1, 0)
        self.blks2_selector_0 = grc_blks2.selector(
            item_size=gr.sizeof_gr_complex*M,
            num_inputs=2,
            num_outputs=1,
            input_index=exclude_preamble,
            output_index=0,
        )

        ##################################################
        # Connections
        ##################################################
        self.connect((self.fbmc_symbol_creation_bvc_0, 0), (self.vector_padding_0,0))
        self.connect((self.vector_padding_0,0),(self.fbmc_oqam_preprocessing_vcvc_0, 0))
        self.connect((self, 0), (self.fbmc_symbol_creation_bvc_0, 0))
        self.connect((self.fbmc_beta_multiplier_vcvc_0, 0), (self.fft_vxx_0_0, 0))
        self.connect((self.fft_vxx_0_0, 0), (self.blocks_multiply_const_vxx_0,0))
        self.connect((self.blocks_multiply_const_vxx_0,0), (self.fbmc_separate_vcvc_0, 0))
        self.connect((self.fbmc_polyphase_network_vcvc_0, 0), (self.fbmc_overlapping_parallel_to_serial_vcc_0, 0))
        self.connect((self.fbmc_polyphase_network_vcvc_0_0, 0), (self.fbmc_overlapping_parallel_to_serial_vcc_0, 1))
        self.connect((self.fbmc_separate_vcvc_0, 1), (self.fbmc_polyphase_network_vcvc_0_0, 0))
        self.connect((self.fbmc_separate_vcvc_0, 0), (self.fbmc_polyphase_network_vcvc_0, 0))
        self.connect((self.fbmc_overlapping_parallel_to_serial_vcc_0, 0), (self, 0))
        self.connect((self.fbmc_oqam_preprocessing_vcvc_0, 0), (self.blks2_selector_0, 1))
        self.connect((self.fbmc_oqam_preprocessing_vcvc_0, 0), (self.fbmc_insert_preamble_vcvc_0, 0))
        self.connect((self.fbmc_insert_preamble_vcvc_0, 0), (self.blks2_selector_0, 0))
        self.connect((self.blks2_selector_0, 0), (self.fbmc_beta_multiplier_vcvc_0, 0))
    def __init__(self, M=1024, K=4, qam_size=16, syms_per_frame=10, carriers=924, theta_sel=0, sel_eq=0, exclude_preamble=0, sel_preamble=0, zero_pads=1, extra_pad=False):
        gr.hier_block2.__init__(self,
            "fbmc_receiver_hier_cb",
            gr.io_signature(1, 1, gr.sizeof_gr_complex*1),
            gr.io_signature(1, 1, gr.sizeof_char*1),
        )

        ##################################################
        # Parameters
        ##################################################
        self.theta_sel = theta_sel
        self.exclude_preamble = exclude_preamble
        self.sel_eq = sel_eq
        self.M = M
        self.K = K
        self.qam_size = qam_size
        self.syms_per_frame = syms_per_frame

        ##################################################
        # Variables
        ##################################################
        if self.exclude_preamble == 1 and self.sel_eq != 3:
            self.sel_eq = sel_eq = 3
            warnings.warn("Since exclude_preamble is set as 1, sel_eq is forced to be 3 (no equalizer)")

        self.skip = skip = 0
        if exclude_preamble == 1 or sel_eq == 3 or sel_eq== 0:
            self.skip = skip = 0
        else:
            self.skip = skip = 1

        # Assertions
        assert(M>0 and K>0 and qam_size>0), "M, K and qam_size should be bigger than 0"
        assert((math.log(M)/math.log(2))==int(math.log(M)/math.log(2))), "M should be a power of 2"
        assert(K==4), "for now only K=4 s supported."
        assert(qam_size==4 or qam_size==16 or qam_size==64 or qam_size==128 or qam_size==256 ), "Only 4-,16-,64-,128-,256-qam constellations are supported."
        assert(theta_sel==0 or theta_sel==1)
        assert(exclude_preamble==0 or exclude_preamble==1)
        


        ##################################################
        # Blocks
        ##################################################
        self.ofdm_vector_mask_0 = ofdm.vector_mask(M, (M-carriers)/2, carriers, [])
        self.ofdm_fbmc_symbol_estimation_vcb_0 = ofdm.fbmc_symbol_estimation_vcb(carriers, qam_size)
        # unsigned int M, unsigned int syms_per_frame, int sel_preamble, int zero_pads, bool extra_pad, int sel_eq
        self.ofdm_fbmc_subchannel_processing_vcvc_0 = ofdm.fbmc_subchannel_processing_vcvc(M, syms_per_frame, sel_preamble, zero_pads, extra_pad, sel_eq)
        self.ofdm_fbmc_separate_vcvc_0 = ofdm.fbmc_separate_vcvc(M, 2)
        self.ofdm_fbmc_remove_preamble_vcvc_0 = ofdm.fbmc_remove_preamble_vcvc(M, syms_per_frame, sel_preamble, zero_pads, extra_pad)
        self.ofdm_fbmc_polyphase_network_vcvc_3 = ofdm.fbmc_polyphase_network_vcvc(M, K, K*M-1, True)
        self.ofdm_fbmc_polyphase_network_vcvc_2 = ofdm.fbmc_polyphase_network_vcvc(M, K, K*M-1, True)
        self.ofdm_fbmc_overlapping_serial_to_parallel_cvc_0 = ofdm.fbmc_overlapping_serial_to_parallel_cvc(M)
        self.ofdm_fbmc_oqam_postprocessing_vcvc_0 = ofdm.fbmc_oqam_postprocessing_vcvc(M, 0, theta_sel)
        self.ofdm_fbmc_junction_vcvc_0 = ofdm.fbmc_junction_vcvc(M, 2)
        self.ofdm_fbmc_beta_multiplier_vcvc_1 = ofdm.fbmc_beta_multiplier_vcvc(M, K, K*M-1, 0)
        self.fft_vxx_1 = fft.fft_vcc(M, True, ([]), True, 1)
        self.blocks_skiphead_0_0 = blocks.skiphead(gr.sizeof_gr_complex*M, skip)
        self.blocks_skiphead_0 = blocks.skiphead(gr.sizeof_gr_complex*M, 2*K-1-1)
        self.blocks_null_sink_0 = blocks.null_sink(gr.sizeof_gr_complex*M)
        self.blks2_selector_0_0 = grc_blks2.selector(
            item_size=gr.sizeof_gr_complex*M,
            num_inputs=2,
            num_outputs=1,
            input_index=exclude_preamble,
            output_index=0,
        )

        ##################################################
        # Connections
        ##################################################
        self.connect((self.blks2_selector_0_0, 0), (self.ofdm_fbmc_oqam_postprocessing_vcvc_0, 0))
        self.connect((self.ofdm_fbmc_remove_preamble_vcvc_0, 0), (self.blks2_selector_0_0, 0))
        self.connect((self.blocks_skiphead_0_0, 0), (self.blks2_selector_0_0, 1))
        self.connect((self.blocks_skiphead_0_0, 0), (self.ofdm_fbmc_remove_preamble_vcvc_0, 0))
        self.connect((self.ofdm_fbmc_beta_multiplier_vcvc_1, 0), (self.blocks_skiphead_0, 0))
        self.connect((self.fft_vxx_1, 0), (self.ofdm_fbmc_beta_multiplier_vcvc_1, 0))
        self.connect((self.blocks_skiphead_0, 0), (self.ofdm_fbmc_subchannel_processing_vcvc_0, 0))
        self.connect((self.ofdm_fbmc_junction_vcvc_0, 0), (self.fft_vxx_1, 0))
        self.connect((self.ofdm_fbmc_symbol_estimation_vcb_0, 0), (self, 0))
        self.connect((self.ofdm_fbmc_subchannel_processing_vcvc_0, 1), (self.blocks_null_sink_0, 0))
        self.connect((self.ofdm_vector_mask_0, 0), (self.ofdm_fbmc_symbol_estimation_vcb_0, 0))
        self.connect((self.ofdm_fbmc_oqam_postprocessing_vcvc_0, 0), (self.ofdm_vector_mask_0, 0))
        self.connect((self.ofdm_fbmc_subchannel_processing_vcvc_0, 0), (self.blocks_skiphead_0_0, 0))
        self.connect((self, 0), (self.ofdm_fbmc_overlapping_serial_to_parallel_cvc_0, 0))
        self.connect((self.ofdm_fbmc_separate_vcvc_0, 0), (self.ofdm_fbmc_polyphase_network_vcvc_2, 0))
        self.connect((self.ofdm_fbmc_separate_vcvc_0, 1), (self.ofdm_fbmc_polyphase_network_vcvc_3, 0))
        self.connect((self.ofdm_fbmc_overlapping_serial_to_parallel_cvc_0, 0), (self.ofdm_fbmc_separate_vcvc_0, 0))
        self.connect((self.ofdm_fbmc_polyphase_network_vcvc_2, 0), (self.ofdm_fbmc_junction_vcvc_0, 0))
        self.connect((self.ofdm_fbmc_polyphase_network_vcvc_3, 0), (self.ofdm_fbmc_junction_vcvc_0, 1))
Example #7
0
  def __init__(self, options):
    gr.hier_block2.__init__(self, "fbmc_transmit_path",
        gr.io_signature(0,0,0),
        gr.io_signature(1,1,gr.sizeof_gr_complex))

    common_options.defaults(options)

    config = self.config = station_configuration()

    config.data_subcarriers    = options.subcarriers
    config.cp_length           = 0
    config.frame_data_blocks   = options.data_blocks
    config._verbose            = options.verbose
    config.fft_length          = options.fft_length
    config.dc_null             = options.dc_null
    config.training_data       = default_block_header(config.data_subcarriers,
                                          config.fft_length,config.dc_null,options)
    config.coding              = options.coding
    config.fbmc                = options.fbmc
    config.adaptive_fbmc       = options.adaptive_fbmc


    config.frame_id_blocks     = 1 # FIXME

    # digital rms amplitude sent to USRP
    rms_amp                    = options.rms_amplitude
    self._options              = copy.copy(options)


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

    # default values if parameters not set
    if rms_amp is None:
      rms_amp = math.sqrt(config.subcarriers)
    config.rms_amplitude = rms_amp

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

    ## shortcuts
    blen = config.block_length
    flen = config.frame_length
    dsubc = config.data_subcarriers
    vsubc = config.virtual_subcarriers

    # Adaptive Transmitter Concept

    used_id_bits = config.used_id_bits = 8 #TODO: no constant in source code
    rep_id_bits = config.rep_id_bits = config.data_subcarriers/used_id_bits #BPSK
    if config.data_subcarriers % used_id_bits <> 0:
      raise SystemError,"Data subcarriers need to be multiple of %d" % (used_id_bits)

    ## Allocation Control
    self.allocation_src = allocation_src(config.data_subcarriers, config.frame_data_blocks, config.coding, "tcp://*:3333", "tcp://"+options.rx_hostname+":3322")
    if options.static_allocation: #DEBUG
        # how many bits per subcarrier
         
        if options.coding:
            mode = 1 # Coding mode 1-9
            bitspermode= [0.5,1,1.5,2,3,4,4.5,5,6] # Information bits per mode
            modulbitspermode = [1,2,2,4,4,6,6,6,8] # Coding bits per mode
            bitcount_vec = [(int)(config.data_subcarriers*config.frame_data_blocks*bitspermode[mode-1])]
            modul_bitcount_vec = [config.data_subcarriers*config.frame_data_blocks*modulbitspermode[mode-1]]
            bitcount_src = blocks.vector_source_i(bitcount_vec,True,1)
            modul_bitcount_src = blocks.vector_source_i(modul_bitcount_vec,True,1)
            bitloading = mode
        else:
            bitloading = 1
            bitcount_vec = [config.data_subcarriers*config.frame_data_blocks*bitloading]
            bitcount_src = blocks.vector_source_i(bitcount_vec,True,1)
            modul_bitcount_src = bitcount_src
        # id's for frames
        id_vec = range(0,256)
        id_src = blocks.vector_source_s(id_vec,True,1)
        # bitloading for ID symbol and then once for data symbols
        #bitloading_vec = [1]*dsubc+[0]*(dsubc/2)+[2]*(dsubc/2)
        
        test_allocation = [bitloading]*(int)(config.data_subcarriers/8)+ [0]*(int)(config.data_subcarriers/4*3) + [bitloading]*(int)(config.data_subcarriers/8)
        #bitloading_vec = [1]*dsubc+[bitloading]*dsubc
        bitloading_vec = [1]*dsubc+test_allocation
        bitloading_src = blocks.vector_source_b(bitloading_vec,True,dsubc)
        # bitcount for frames
        #bitcount_vec = [config.data_subcarriers*config.frame_data_blocks*bitloading]
        bitcount_vec = [config.frame_data_blocks*sum(test_allocation)]
        bitcount_src = blocks.vector_source_i(bitcount_vec,True,1)
        # power loading, here same for all symbols
        power_vec = [1]*(int)(config.data_subcarriers/8)+ [0]*(int)(config.data_subcarriers/4*3) + [1]*(int)(config.data_subcarriers/8)
        power_src = blocks.vector_source_f(power_vec,True,dsubc)
        # mux control stream to mux id and data bits
        mux_vec = [0]*dsubc+[1]*bitcount_vec[0]
        mux_ctrl = blocks.vector_source_b(mux_vec,True,1)
    else:
        id_src = (self.allocation_src,0)
        bitcount_src = (self.allocation_src,4)
        bitloading_src = (self.allocation_src,2)
        power_src = (self.allocation_src,1)
        if options.coding: 
            modul_bitcount_src = (self.allocation_src,5)
        else:
            modul_bitcount_src = bitcount_src
        mux_ctrl = ofdm.tx_mux_ctrl(dsubc)
        self.connect(modul_bitcount_src,mux_ctrl)
        #Initial allocation
        self.allocation_src.set_allocation([4]*config.data_subcarriers,[1]*config.data_subcarriers)   
        if options.benchmarking:
            self.allocation_src.set_allocation([4]*config.data_subcarriers,[1]*config.data_subcarriers)        


    if options.lab_special_case:
        self.allocation_src.set_allocation([0]*(config.data_subcarriers/4)+[2]*(config.data_subcarriers/2)+[0]*(config.data_subcarriers/4),[1]*config.data_subcarriers)

    if options.log:
        log_to_file(self, id_src, "data/id_src.short")
        log_to_file(self, bitcount_src, "data/bitcount_src.int")
        log_to_file(self, bitloading_src, "data/bitloading_src.char")
        log_to_file(self, power_src, "data/power_src.cmplx")
         

    ## GUI probe output
    zmq_probe_bitloading = zeromq.pub_sink(gr.sizeof_char,dsubc, "tcp://*:4445")
    # also skip ID symbol bitloading with keep_one_in_n (side effect)
    # factor 2 for bitloading because we have two vectors per frame, one for id symbol and one for all payload/data symbols
    # factor config.frame_data_part for power because there is one vector per ofdm symbol per frame
    self.connect(bitloading_src, blocks.keep_one_in_n(gr.sizeof_char*dsubc,2*40), zmq_probe_bitloading)
    zmq_probe_power = zeromq.pub_sink(gr.sizeof_float,dsubc, "tcp://*:4444")
    #self.connect(power_src, blocks.keep_one_in_n(gr.sizeof_gr_complex*dsubc,40), blocks.complex_to_real(dsubc), zmq_probe_power)
    self.connect(power_src, blocks.keep_one_in_n(gr.sizeof_float*dsubc,40), zmq_probe_power)

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

    ## ID Encoder
    id_enc = self._id_encoder = repetition_encoder_sb(used_id_bits,rep_id_bits,whitener_pn)
    self.connect(id_src,id_enc)

    if options.log:
      id_enc_f = gr.char_to_float()
      self.connect(id_enc,id_enc_f)
      log_to_file(self, id_enc_f, "data/id_enc_out.float")

    ## Reference Data Source
    ber_ref_src = ber_reference_source(self._options)
    self.connect(id_src,(ber_ref_src,0))
    self.connect(bitcount_src,(ber_ref_src,1))

    if options.log:
      log_to_file(self, ber_ref_src, "data/ber_rec_src_tx.char")

    if options.log:
      log_to_file(self, btrig, "data/bitmap_trig.char")

    ## Frame Trigger
    ftrig_stream = [1]+[0]*(config.frame_data_part-1)
    ftrig = self._frame_trigger = blocks.vector_source_b(ftrig_stream,True)

    ## Data Multiplexer
    # Input 0: control stream
    # Input 1: encoded ID stream
    # Inputs 2..n: data streams
    dmux = self._data_multiplexer = stream_controlled_mux_b()
    self.connect(mux_ctrl,(dmux,0))
    self.connect(id_enc,(dmux,1))

    if options.coding:
        fo=trellis.fsm(1,2,[91,121])       
        encoder = self._encoder = trellis.encoder_bb(fo,0)
        unpack = self._unpack = blocks.unpack_k_bits_bb(2)
        self.connect(ber_ref_src,encoder,unpack)
        
        if options.interleave:
            int_object=trellis.interleaver(2000,666)
            interlv = trellis.permutation(int_object.K(),int_object.INTER(),1,gr.sizeof_char)
        
        if not options.nopunct:
            bmaptrig_stream_puncturing = [1]+[0]*(config.frame_data_blocks/2-1)
            btrig_puncturing = self._bitmap_trigger_puncturing = blocks.vector_source_b(bmaptrig_stream_puncturing, True)
            puncturing = self._puncturing = puncture_bb(config.data_subcarriers)
            self.connect(bitloading_src,(puncturing,1))
            self.connect(self._bitmap_trigger_puncturing,(puncturing,2))
            self.connect(unpack,puncturing)
            last_block=puncturing
            
            if options.interleave:
                self.connect(last_block,interlv)
                last_block = interlv
            
            if options.benchmarking:
                self.connect(last_block,blocks.head(gr.sizeof_char, options.N),(dmux,2))
            else:
                self.connect(last_block,(dmux,2))
        else:
            if options.benchmarking:
                self.connect(unpack,blocks.head(gr.sizeof_char, options.N),(dmux,2))
            else:
                self.connect(unpack,(dmux,2))
        
    else:
        if options.benchmarking:
            self.connect(ber_ref_src,blocks.head(gr.sizeof_char, options.N),(dmux,2))
        else:
            self.connect(ber_ref_src,(dmux,2))
        
    

    if options.log:
      dmux_f = gr.char_to_float()
      self.connect(dmux,dmux_f)
      log_to_file(self, dmux_f, "data/dmux_out.float")

    ## Modulator
    mod = self._modulator = generic_mapper_bcv(config.data_subcarriers,config.coding, config.frame_data_part)
    self.connect(dmux,(mod,0))
    self.connect(bitloading_src,(mod,1))

    if options.log:
      log_to_file(self, mod, "data/mod_out.compl")
      modi = blocks.complex_to_imag(config.data_subcarriers)
      modr = blocks.complex_to_real(config.data_subcarriers)
      self.connect(mod,modi)
      self.connect(mod,modr)
      log_to_file(self, modi, "data/mod_imag_out.float")
      log_to_file(self, modr, "data/mod_real_out.float")

    ## Power allocator
    pa = self._power_allocator = multiply_frame_fc(config.frame_data_part, config.data_subcarriers)
    self.connect(mod,(pa,0))
    self.connect(power_src,(pa,1))

    if options.log:
      log_to_file(self, pa, "data/pa_out.compl")
      

    if options.fbmc:
        psubc = pa
    else:
        psubc = self._pilot_subcarrier_inserter = pilot_subcarrier_inserter()
        self.connect(pa,psubc)
        
        if options.log:
            log_to_file(self, psubc, "data/psubc_out.compl")
        
    subcarriers = config.subcarriers
    
    #fbmc_pblocks_timing = self._fbmc_timing_pilot_block_inserter = fbmc_timing_pilot_block_inserter(5,False)
    
    oqam_prep = self._oqam_prep = fbmc_oqam_preprocessing_vcvc(config.subcarriers, 0, 0)
    self.connect(psubc,oqam_prep)
    
    
    fbmc_pblocks = self._fbmc_pilot_block_inserter = fbmc_pilot_block_inserter(5,False)
    self.connect(oqam_prep, fbmc_pblocks)
    #log_to_file(self, fbmc_pblocks, "data/fbmc_pblocks_out.compl")
    #fbmc_insert_pream = self._fbmc_insert_pream = fbmc_insert_preamble_vcvc(M, syms_per_frame, preamble)
    #log_to_file(self, oqam_prep, "data/oqam_prep.compl")
    #log_to_file(self, psubc, "data/psubc_out.compl")
    #fbmc_pblocks = fbmc_pblocks_timing
    #log_to_file(self, fbmc_pblocks, "data/fbmc_pblocks_out.compl")
    



      
    beta_mult = self._beta_mult = fbmc_beta_multiplier_vcvc(config.subcarriers, 4, 4*config.fft_length-1, 0)
    self.connect(fbmc_pblocks, beta_mult)
    log_to_file(self, beta_mult, "data/beta_mult.compl")
    
        ## Add virtual subcarriers
    if config.fft_length > subcarriers:
      vsubc = self._virtual_subcarrier_extender = \
              vector_padding_dc_null(config.subcarriers, config.fft_length,config.dc_null)
      self.connect(beta_mult,vsubc)
    else:
      vsubc = self._virtual_subcarrier_extender = beta_mult

    if options.log:
      log_to_file(self, vsubc, "data/vsubc_out.compl")

    ## IFFT, no window, block shift
    ifft = self._ifft = fft_blocks.fft_vcc(config.fft_length,False,[],True)
    self.connect(vsubc,ifft)

    if options.log:
      log_to_file(self, ifft, "data/ifft_out.compl")
      
      
    #FBMC separate stream + filterbanks
    separate_oqam = self._separate_oqam = fbmc_separate_vcvc(config.fft_length, 2)
    poly_netw_1 = self._poly_netw_1 = fbmc_polyphase_network_vcvc(config.fft_length, 4, 4*config.fft_length-1, False)
    poly_netw_2 = self._poly_netw_2 = fbmc_polyphase_network_vcvc(config.fft_length, 4, 4*config.fft_length-1, False)
    overlap_p2s = self._overlap_p2s = fbmc_overlapping_parallel_to_serial_vcc(config.fft_length)
      
    self.connect(ifft,(separate_oqam,0),poly_netw_1)
    self.connect((separate_oqam,1),poly_netw_2)
    self.connect(poly_netw_1,(overlap_p2s,0))
    self.connect(poly_netw_2,(overlap_p2s,1))
    

    ## Pilot blocks (preambles)
    #pblocks = self._pilot_block_inserter = pilot_block_inserter2(5,False)
    #self.connect( overlap_p2s, blocks.stream_to_vector(gr.sizeof_gr_complex,config.fft_length/2),  pblocks )
    
    #log_to_file(self, pblocks, "data/fbmc_pilot_block_ins_out.compl")

    if options.log:
      log_to_file(self, pblocks, "data/pilot_block_ins_out.compl")

    ## Cyclic Prefix
    #cp = self._cyclic_prefixer = cyclic_prefixer(config.fft_length,
                                               # config.block_length)

    #cp= blocks.vector_to_stream(gr.sizeof_gr_complex, config.fft_length/2)
    #self.connect(pblocks, cp )
    #self.connect( overlap_p2s,blocks.stream_to_vector(gr.sizeof_gr_complex,config.fft_length/2), cp )


    lastblock = overlap_p2s

    if options.log:
      log_to_file(self, overlap_p2s, "data/overlap_p2s_out.compl")


    #Digital Amplifier for resource allocation
    if config.adaptive_fbmc:
        rep = blocks.repeat(gr.sizeof_gr_complex, config.frame_length * config.block_length)
        amp = blocks.multiply_cc()
        self.connect( lastblock, (amp,0) )
        self.connect((self.allocation_src,3), rep , (amp,1) )
        lastblock = amp
    else:
        self.connect((self.allocation_src,3), blocks.null_sink(gr.sizeof_gr_complex) )

    ## Digital Amplifier
    #amp = self._amplifier = gr.multiply_const_cc(1)
    amp = self._amplifier = ofdm.multiply_const_ccf( 1.0 )
    self.connect( lastblock, amp )
    self.set_rms_amplitude(rms_amp)
    #log_to_file(self, amp, "data/amp_tx_out.compl")

    if options.log:
      log_to_file(self, amp, "data/amp_tx_out.compl")



    ## Tx parameters
    bandwidth = options.bandwidth or 2e6
    bits = 8*config.data_subcarriers*config.frame_data_blocks # max. QAM256
    samples_per_frame = config.frame_length*config.block_length
    tb = samples_per_frame/bandwidth
    # set dummy carrier frequency if none available due to baseband mode
    if(options.tx_freq is None):
        options.tx_freq = 0.0
    self.tx_parameters = {'carrier_frequency':options.tx_freq/1e9,'fft_size':config.fft_length, 'cp_size':config.cp_length \
                          , 'subcarrier_spacing':options.bandwidth/config.fft_length/1e3 \
                          ,'data_subcarriers':config.data_subcarriers, 'bandwidth':options.bandwidth/1e6 \
                          , 'frame_length':config.frame_length  \
                          , 'symbol_time':(config.cp_length + config.fft_length)/options.bandwidth*1e6, 'max_data_rate':(bits/tb)/1e6}

    ## Setup Output
    self.connect(amp,self)

    # Display some information about the setup
    if config._verbose:
      self._print_verbage()
    def __init__(self, M=1024, K=4, qam_size=16, syms_per_frame=10, boundaries=[], theta_sel=0, sel_eq=0, exclude_preamble=0, sel_preamble=0, zero_pads=1, extra_pad=False):
        # for now, following assumption should be made:
        # each user should be allocated with same number of subchannels.
        lb = len(boundaries)

        assert(lb>0), "The array that defines user boundaries cannot be passed as empty."
        assert(lb%2 == 0), "Unbalanced boundary definition."

        allocated = list()
        for i in range(1,(lb/2)+1):
            allocated.append(boundaries[2*i-1]-boundaries[2*i-2]+1)
            if i>=2:
                assert(allocated[i-2] == allocated[i-1]), "Each user should be allocated with same number of subchannels."

        output_signature = list()
        for i in range(lb/2):
            output_signature.append(gr.sizeof_gr_complex*(boundaries[2*i+1]-boundaries[2*i]+1))

        # print(output_signature)
        gr.hier_block2.__init__(self,
            "fbmc_receiver_multiuser_cb",
            gr.io_signature(1, 1, gr.sizeof_gr_complex*1),  # Input signature
            gr.io_signature(lb/2, lb/2, gr.sizeof_char*1))  # Output signature

        ##################################################
        # Parameters
        ##################################################
        self.theta_sel = theta_sel
        self.exclude_preamble = exclude_preamble
        self.sel_eq = sel_eq
        self.M = M
        self.K = K
        self.qam_size = qam_size
        self.syms_per_frame = syms_per_frame

        ##################################################
        # Variables
        ##################################################
        if self.exclude_preamble == 1 and self.sel_eq != 3:
            self.sel_eq = sel_eq = 3
            warnings.warn("Since exclude_preamble is set as 1, sel_eq is forced to be 3 (no equalizer)")

        self.skip = skip = 0
        if exclude_preamble == 1 or sel_eq == 3 or sel_eq== 0:
            self.skip = skip = 0
        else:
            self.skip = skip = 1

        # Assertions
        assert(M>0 and K>0 and qam_size>0), "M, K and qam_size should be bigger than 0"
        assert((math.log(M)/math.log(2))==int(math.log(M)/math.log(2))), "M should be a power of 2"
        assert(K==4), "for now only K=4 s supported."
        assert(qam_size==4 or qam_size==16 or qam_size==64 or qam_size==128 or qam_size==256 ), "Only 4-,16-,64-,128-,256-qam constellations are supported."
        assert(theta_sel==0 or theta_sel==1)
        assert(exclude_preamble==0 or exclude_preamble==1)
        


        ##################################################
        # Blocks
        ##################################################
        self.ofdm_fbmc_subchannel_processing_mu_vcvc_0 = ofdm.fbmc_subchannel_processing_mu_vcvc(M=M,syms_per_frame=syms_per_frame,indices=boundaries,sel_preamble=sel_preamble,zero_pads=zero_pads,extra_pad=extra_pad,sel_eq=sel_eq)
        self.ofdm_fbmc_separate_vcvc_0 = ofdm.fbmc_separate_vcvc(M, 2)
        self.ofdm_fbmc_remove_preamble_vcvc_0 = ofdm.fbmc_remove_preamble_vcvc(M, syms_per_frame, sel_preamble, zero_pads, extra_pad)
        self.ofdm_fbmc_polyphase_network_vcvc_3 = ofdm.fbmc_polyphase_network_vcvc(M, K, K*M-1, True)
        self.ofdm_fbmc_polyphase_network_vcvc_2 = ofdm.fbmc_polyphase_network_vcvc(M, K, K*M-1, True)
        self.ofdm_fbmc_overlapping_serial_to_parallel_cvc_0 = ofdm.fbmc_overlapping_serial_to_parallel_cvc(M)
        self.ofdm_fbmc_oqam_postprocessing_vcvc_0 = ofdm.fbmc_oqam_postprocessing_vcvc(M, 0, theta_sel)
        self.ofdm_fbmc_junction_vcvc_0 = ofdm.fbmc_junction_vcvc(M, 2)
        self.ofdm_fbmc_beta_multiplier_vcvc_1 = ofdm.fbmc_beta_multiplier_vcvc(M, K, K*M-1, 0)
        self.fft_vxx_1 = fft.fft_vcc(M, True, ([]), True, 1)
        self.blocks_skiphead_0_0 = blocks.skiphead(gr.sizeof_gr_complex*M, skip)
        self.blocks_skiphead_0 = blocks.skiphead(gr.sizeof_gr_complex*M, 2*K-1-1)
        self.blocks_null_sink_0 = blocks.null_sink(gr.sizeof_gr_complex*M)
        self.blks2_selector_0_0 = grc_blks2.selector(
            item_size=gr.sizeof_gr_complex*M,
            num_inputs=2,
            num_outputs=1,
            input_index=exclude_preamble,
            output_index=0,
        )

        ##################################################
        # Connections
        ##################################################
        self.connect((self.blks2_selector_0_0, 0), (self.ofdm_fbmc_oqam_postprocessing_vcvc_0, 0))
        self.connect((self.ofdm_fbmc_remove_preamble_vcvc_0, 0), (self.blks2_selector_0_0, 0))
        self.connect((self.blocks_skiphead_0_0, 0), (self.blks2_selector_0_0, 1))
        self.connect((self.blocks_skiphead_0_0, 0), (self.ofdm_fbmc_remove_preamble_vcvc_0, 0))
        self.connect((self.ofdm_fbmc_beta_multiplier_vcvc_1, 0), (self.blocks_skiphead_0, 0))
        self.connect((self.fft_vxx_1, 0), (self.ofdm_fbmc_beta_multiplier_vcvc_1, 0))
        self.connect((self.blocks_skiphead_0, 0), (self.ofdm_fbmc_subchannel_processing_mu_vcvc_0, 0))
        self.connect((self.ofdm_fbmc_junction_vcvc_0, 0), (self.fft_vxx_1, 0))
        self.connect((self.ofdm_fbmc_subchannel_processing_mu_vcvc_0, 1), (self.blocks_null_sink_0, 0))
        self.connect((self.ofdm_fbmc_subchannel_processing_mu_vcvc_0, 0), (self.blocks_skiphead_0_0, 0))
        self.connect((self, 0), (self.ofdm_fbmc_overlapping_serial_to_parallel_cvc_0, 0))
        self.connect((self.ofdm_fbmc_separate_vcvc_0, 0), (self.ofdm_fbmc_polyphase_network_vcvc_2, 0))
        self.connect((self.ofdm_fbmc_separate_vcvc_0, 1), (self.ofdm_fbmc_polyphase_network_vcvc_3, 0))
        self.connect((self.ofdm_fbmc_overlapping_serial_to_parallel_cvc_0, 0), (self.ofdm_fbmc_separate_vcvc_0, 0))
        self.connect((self.ofdm_fbmc_polyphase_network_vcvc_2, 0), (self.ofdm_fbmc_junction_vcvc_0, 0))
        self.connect((self.ofdm_fbmc_polyphase_network_vcvc_3, 0), (self.ofdm_fbmc_junction_vcvc_0, 1))
        # blocks
        # self.ofdm_fbmc_receiver_demo_0 = ofdm.fbmc_receiver_demo(M, K, qam_size, syms_per_frame, M, theta_sel, sel_eq, exclude_preamble, sel_preamble, zero_pads, extra_pad)
        # instead of calling receiver_demo block we copy the content of that block and change subchannel processing part. 10.03.2015
        # this way receiver_demo file will stay as original, multiuser case not implemented.




        asymms = list()
        for i in range(lb/2):
            asymms.append(ofdm.fbmc_asymmetrical_vector_mask_vcvc(M,boundaries[2*i],boundaries[2*i+1]))
            # print(str(i))

        sym_est = list()
        for i in range(lb/2):
            sym_est.append(ofdm.fbmc_symbol_estimation_vcb(allocated[i], qam_size))

        # connections
        for i in range(lb/2):
            self.connect((self.ofdm_fbmc_oqam_postprocessing_vcvc_0, 0), (asymms[i], 0))
            self.connect((asymms[i], 0),(sym_est[i], 0))
            self.connect((sym_est[i], 0),(self,i))
Example #9
0
    def __init__(self, options, log=False):

        ## Read configuration
        config = station_configuration()

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

        L = block_header.mm_periodic_parts

        cp_length = config.cp_length

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

            print "Disabled time synchronization stage"

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        #ofdm_blocks = (inner_pb_filt,0)

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

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

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

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

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

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

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

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

        #terminate_stream(self, help2)

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

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

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

        self.connect(ofdm_blocks, self.beta_multiplier_vcvc)

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

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

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

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

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

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

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

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

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

            if not options.disable_ctf_enhancer:

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

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

                estimated_CTF = ctf_mse_enhancer
                print "Disabled CTF MSE enhancer"

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

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

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

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


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

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

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

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

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

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

        if options.scatter_plot_before_phase_tracking:
            self.before_phase_tracking = equalizer

        ## Output connections

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

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

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

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

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

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

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

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

            log_to_file(self, phase_tracking, "data/phase_tracking.compl")
Example #10
0
  def __init__( self, options, log = False ):
    
    ## Read configuration
    config = station_configuration()
    
    fft_length    = config.fft_length
    #cp_length     = config.cp_length
    block_header  = config.training_data
    data_subc     = config.data_subcarriers
    virtual_subc  = config.virtual_subcarriers
    total_subc    = config.subcarriers
    block_length  = config.block_length
    frame_length  = config.frame_length
    
    L             = block_header.mm_periodic_parts
    
        
    cp_length     = config.cp_length


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

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

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

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

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

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

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

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

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

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

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

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

    ## Output connections

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

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