def __init__(self,delay_num,delay_denom): gr.hier_block2.__init__(self,"moms_block", gr.io_signature(1,1,gr.sizeof_gr_complex), gr.io_signature(1,1,gr.sizeof_gr_complex)) cmplx_to_real = gr.complex_to_real() cmplx_to_img = gr.complex_to_imag() iirf_real = gr.iir_filter_ffd([1.5],[1, -0.5]) self.moms_real = moms_ff() self.moms_real.set_init_ip_fraction(delay_num,delay_denom) iirf_imag = gr.iir_filter_ffd([1.5],[1, -0.5]) self.moms_imag = moms_ff() self.moms_imag.set_init_ip_fraction(delay_num,delay_denom) float_to_cmplx = gr.float_to_complex() self.connect((self,0), (cmplx_to_real,0)) self.connect((self,0), (cmplx_to_img,0)) self.connect((cmplx_to_real,0), (iirf_real,0)) self.connect((cmplx_to_img,0), (iirf_imag,0)) self.connect((iirf_real,0), (self.moms_real,0)) self.connect((iirf_imag,0), (self.moms_imag,0)) self.connect((self.moms_real,0), (float_to_cmplx,0)) self.connect((self.moms_imag,0), (float_to_cmplx,1)) self.connect((float_to_cmplx,0), (self,0))
def test_complex_to_imag(self): src_data = (0, 1, -1, 3 + 4j, -3 - 4j, -3 + 4j) expected_result = (0, 0, 0, 4, -4, 4) src = gr.vector_source_c(src_data) op = gr.complex_to_imag() dst = gr.vector_sink_f() self.tb.connect(src, op) self.tb.connect(op, dst) self.tb.run() actual_result = dst.data() self.assertFloatTuplesAlmostEqual(expected_result, actual_result, 5)
def test_complex_to_imag (self): src_data = (0, 1, -1, 3+4j, -3-4j, -3+4j) expected_result = (0, 0, 0, 4, -4, 4) src = gr.vector_source_c (src_data) op = gr.complex_to_imag () dst = gr.vector_sink_f () self.tb.connect (src, op) self.tb.connect (op, dst) self.tb.run () actual_result = dst.data () self.assertFloatTuplesAlmostEqual (expected_result, actual_result,5)
def complex_to_imag(N): op = gr.complex_to_imag() tb = helper(N, op, gr.sizeof_gr_complex, gr.sizeof_float, 1, 1) return tb
def __init__(self, options): gr.hier_block2.__init__(self, "transmit_path", gr.io_signature(0, 0, 0), gr.io_signature(2, 2, gr.sizeof_gr_complex)) common_options.defaults(options) config = self.config = station_configuration() config.data_subcarriers = options.subcarriers config.cp_length = options.cp_length config.frame_data_blocks = options.data_blocks config._verbose = options.verbose config.fft_length = options.fft_length config.training_data = default_block_header(config.data_subcarriers, config.fft_length, options) config.tx_station_id = options.station_id config.coding = options.coding if config.tx_station_id is None: raise SystemError, "Station ID not set" config.frame_id_blocks = 1 # FIXME # digital rms amplitude sent to USRP rms_amp = options.rms_amplitude self._options = copy.copy(options) self.servants = [] # FIXME 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.frame_data_part + \ config.training_data.no_pilotsyms config.subcarriers = config.data_subcarriers + \ config.training_data.pilot_subcarriers config.virtual_subcarriers = config.fft_length - config.subcarriers # 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) ## Control Part if options.debug: self._control = ctrl = static_tx_control(options) print "Statix TX Control used" else: self._control = ctrl = corba_tx_control(options) print "CORBA TX Control used" id_src = (ctrl, 0) mux_src = (ctrl, 1) map_src = self._map_src = (ctrl, 2) pa_src = (ctrl, 3) if options.log: id_src_f = gr.short_to_float() self.connect(id_src, id_src_f) log_to_file(self, id_src_f, "data/id_src_out.float") mux_src_f = gr.short_to_float() self.connect(mux_src, mux_src_f) log_to_file(self, mux_src_f, "data/mux_src_out.float") map_src_s = blocks.vector_to_stream(gr.sizeof_char, config.data_subcarriers) map_src_f = gr.char_to_float() self.connect(map_src, map_src_s, map_src_f) ##log_to_file(self, map_src_f, "data/map_src.float") ##log_to_file(self, pa_src, "data/pa_src_out.float") ## 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") ## Bitmap Update Trigger # TODO #bmaptrig_stream = concatenate([[1, 2],[0]*(config.frame_data_part-7)]) bmaptrig_stream = concatenate([[1, 1], [0] * (config.frame_data_part - 2)]) print "bmaptrig_stream = ", bmaptrig_stream btrig = self._bitmap_trigger = blocks.vector_source_b( bmaptrig_stream.tolist(), True) if options.log: log_to_file(self, btrig, "data/bitmap_trig.char") ## Bitmap Update Trigger for puncturing # TODO if not options.nopunct: #bmaptrig_stream_puncturing = concatenate([[1],[0]*(config.frame_data_part-2)]) bmaptrig_stream_puncturing = concatenate( [[1], [0] * (config.frame_data_blocks / 2 - 1)]) btrig_puncturing = self._bitmap_trigger_puncturing = blocks.vector_source_b( bmaptrig_stream_puncturing.tolist(), True) bmapsrc_stream_puncturing = concatenate([[1] * dsubc, [2] * dsubc]) bsrc_puncturing = self._bitmap_src_puncturing = blocks.vector_source_b( bmapsrc_stream_puncturing.tolist(), True, dsubc) if options.log and options.coding and not options.nopunct: log_to_file(self, btrig_puncturing, "data/bitmap_trig_puncturing.char") ## Frame Trigger # TODO ftrig_stream = concatenate([[1], [0] * (config.frame_data_part - 1)]) ftrig = self._frame_trigger = blocks.vector_source_b( ftrig_stream.tolist(), 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_src, (dmux, 0)) self.connect(id_enc, (dmux, 1)) self._data_multiplexer_nextport = 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, options.coding) self.connect(dmux, (mod, 0)) self.connect(map_src, (mod, 1)) self.connect(btrig, (mod, 2)) if options.log: log_to_file(self, mod, "data/mod_out.compl") modi = gr.complex_to_imag(config.data_subcarriers) modr = gr.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 if options.debug: ## static pa = self._power_allocator = power_allocator( config.data_subcarriers) self.connect(mod, (pa, 0)) self.connect(pa_src, (pa, 1)) else: ## with CORBA control event channel ns_ip = ctrl.ns_ip ns_port = ctrl.ns_port evchan = ctrl.evchan pa = self._power_allocator = corba_power_allocator(dsubc, \ evchan, ns_ip, ns_port, True) self.connect(mod, (pa, 0)) self.connect(id_src, (pa, 1)) self.connect(ftrig, (pa, 2)) if options.log: log_to_file(self, pa, "data/pa_out.compl") ## Pilot subcarriers psubc = self._pilot_subcarrier_inserter = pilot_subcarrier_inserter() self.connect(pa, psubc) pilot_subc = config.training_data.shifted_pilot_tones print "pilot_subc", pilot_subc stc = stc_encoder(config.subcarriers, config.frame_data_blocks, pilot_subc) self.connect(psubc, stc) if options.log: log_to_file(self, psubc, "data/psubc_out.compl") log_to_file(self, psubc_2, "data/psubc2_out.compl") log_to_file(self, pa, "data/pa.compl") log_to_file(self, (stc, 0), "data/stc_0.compl") log_to_file(self, (stc, 1), "data/stc_1.compl") ## Add virtual subcarriers if config.fft_length > config.subcarriers: vsubc = self._virtual_subcarrier_extender = \ vector_padding(config.subcarriers, config.fft_length) self.connect(stc, vsubc) vsubc_2 = self._virtual_subcarrier_extender_2 = \ vector_padding(config.subcarriers, config.fft_length) self.connect((stc, 1), vsubc_2) else: vsubc = self._virtual_subcarrier_extender = psubc vsubc_2 = self._virtual_subcarrier_extender_2 = psubc_2 log_to_file(self, psubc, "data/psubc.compl") log_to_file(self, stc, "data/stc1.compl") log_to_file(self, (stc, 1), "data/stc2.compl") if options.log: log_to_file(self, vsubc, "data/vsubc_out.compl") log_to_file(self, vsubc_2, "data/vsubc2_out.compl") ## IFFT, no window, block shift ifft = self._ifft = fft_blocks.fft_vcc(config.fft_length, False, [], True) self.connect(vsubc, ifft) ifft_2 = self._ifft_2 = fft_blocks.fft_vcc(config.fft_length, False, [], True) self.connect(vsubc_2, ifft_2) if options.log: log_to_file(self, ifft, "data/ifft_out.compl") log_to_file(self, ifft_2, "data/ifft2_out.compl") ## Pilot blocks (preambles) pblocks = self._pilot_block_inserter = pilot_block_inserter(1, False) self.connect(ifft, pblocks) pblocks_2 = self._pilot_block_inserter_2 = pilot_block_inserter( 2, False) self.connect(ifft_2, pblocks_2) if options.log: log_to_file(self, pblocks, "data/pilot_block_ins_out.compl") log_to_file(self, pblocks_2, "data/pilot_block_ins2_out.compl") ## Cyclic Prefix cp = self._cyclic_prefixer = cyclic_prefixer(config.fft_length, config.block_length) self.connect(pblocks, cp) cp_2 = self._cyclic_prefixer_2 = cyclic_prefixer( config.fft_length, config.block_length) self.connect(pblocks_2, cp_2) lastblock = cp lastblock_2 = cp_2 if options.log: log_to_file(self, cp, "data/cp_out.compl") log_to_file(self, cp_2, "data/cp2_out.compl") if options.cheat: ## Artificial Channel # kept to compare with previous system achan_ir = concatenate([[1.0], [0.0] * (config.cp_length - 1)]) achan = self._artificial_channel = gr.fir_filter_ccc(1, achan_ir) self.connect(lastblock, achan) lastblock = achan achan_2 = self._artificial_channel_2 = gr.fir_filter_ccc( 1, achan_ir) self.connect(lastblock_2, achan_2) lastblock_2 = achan_2 ## Digital Amplifier amp = self._amplifier = ofdm.multiply_const_ccf(1.0 / math.sqrt(2)) self.connect(lastblock, amp) amp_2 = self._amplifier_2 = ofdm.multiply_const_ccf(1.0 / math.sqrt(2)) self.connect(lastblock_2, amp_2) self.set_rms_amplitude(rms_amp) if options.log: log_to_file(self, amp, "data/amp_tx_out.compl") log_to_file(self, amp_2, "data/amp_tx2_out.compl") ## Setup Output self.connect(amp, (self, 0)) self.connect(amp_2, (self, 1)) # ------------------------------------------------------------------------ # # Display some information about the setup if config._verbose: self._print_verbage()
def __init__(self, options, payload='', msgq_limit=2, pad_for_usrp=False): """ Hierarchical block for sending packets Packets to be sent are enqueued by calling send_pkt. The output is the complex modulated signal at baseband. @param options: pass modulation options from higher layers (fft length, occupied tones, etc.) @param msgq_limit: maximum number of messages in message queue @type msgq_limit: int @param pad_for_usrp: If true, packets are padded such that they end up a multiple of 128 samples """ gr.hier_block2.__init__(self, "ofdm_mod", gr.io_signature(0, 0, 0), # Input signature gr.io_signature(1, 1, gr.sizeof_gr_complex)) # Output signature self._fft_length = 64 self._total_sub_carriers = 53 self._data_subcarriers = 48 self._cp_length = 16 self._regime = options.regime self._symbol_length = self._fft_length + self._cp_length self._role = options.role # assuming we have 100Ms/s going to the USRP2 and 80 samples per symbol # we can calculate the OFDM symboltime (in microseconds) # depending on the interpolation factor self._symbol_time = options.interp*(self._fft_length+self._cp_length)/100 win = [] if(self._regime == "1" or self._regime == "2"): rotated_const = ofdm_packet_utils.bpsk(self) elif (self._regime == "3" or self._regime == "4"): rotated_const = ofdm_packet_utils.qpsk(self) elif(self._regime == "5" or self._regime == "6"): rotated_const = ofdm_packet_utils.qam16(self) elif(self._regime == "7" or self._regime == "8"): rotated_const = ofdm_packet_utils.qam64(self) # map groups of bits to complex symbols self._pkt_input = ftw.ofdm_mapper(rotated_const, msgq_limit, self._data_subcarriers, self._fft_length) # insert pilot symbols (use pnc block * by lzyou) if self._role == 'A': print " >>> [FPNC]: *A* Insert Pilot" self.pilot = ftw.pnc_ofdm_pilot_cc(self._data_subcarriers, 1) elif self._role == 'B': print " >>> [FPNC]: *B* Insert Pilot" self.pilot = ftw.pnc_ofdm_pilot_cc(self._data_subcarriers, 2) else: print " >>> [FTW ]: Insert Pilot" self.pilot = ftw.ofdm_pilot_cc(self._data_subcarriers) # just for test #self.pilot = ftw.pnc_ofdm_pilot_cc(self._data_subcarriers, 1) #self.pilot = ftw.pnc_ofdm_pilot_cc(self._data_subcarriers, 2) # move subcarriers to their designated place and insert DC self.cmap = ftw.ofdm_cmap_cc(self._fft_length, self._total_sub_carriers) # inverse fast fourier transform self.ifft = gr.fft_vcc(self._fft_length, False, win, False) # add cyclic prefix from gnuradio import digital self.cp_adder = digital.ofdm_cyclic_prefixer(self._fft_length, self._symbol_length) self.connect(gr.null_source(gr.sizeof_char), (self.cp_adder, 1)) # Note: dirty modification to accomdate the API change # scale accordingly self.scale = gr.multiply_const_cc(1.0 / math.sqrt(self._fft_length)) # we need to know the number of OFDM data symbols for preamble and zerogap info = ofdm_packet_utils.get_info(payload, options.regime, self._symbol_time) N_sym = info["N_sym"] # add training sequence (modify by lzyou) if self._role == 'A': print " >>> [FPNC]: *A* Insert Preamble" self.preamble= ofdm_packet_utils.insert_preamble(self._symbol_length, N_sym, 'A') elif self._role == 'B': print " >>> [FPNC]: *B* Insert Preamble" self.preamble= ofdm_packet_utils.insert_preamble(self._symbol_length, N_sym, 'B') else: print " >>> [FTW ]: Insert Preamble" self.preamble= ofdm_packet_utils.insert_preamble(self._symbol_length, N_sym) # append zero samples at the end (receiver needs that to decode) if self._role == None: print " >>> [FTW ]: Insert Zerogap" self.zerogap = ofdm_packet_utils.insert_zerogap(self._symbol_length, N_sym) else: print " >>> [FPNC]: Insert Zerogap" self.zerogap = ofdm_packet_utils.insert_zerogap(self._symbol_length, N_sym, 'FPNC') self.s2v = gr.stream_to_vector(gr.sizeof_gr_complex , self._symbol_length) self.v2s = gr.vector_to_stream(gr.sizeof_gr_complex , self._symbol_length) # swap real and immaginary component before sending (GNURadio/USRP2 bug!) if options.swapIQ == True: self.gr_complex_to_imag_0 = gr.complex_to_imag(1) self.gr_complex_to_real_0 = gr.complex_to_real(1) self.gr_float_to_complex_0 = gr.float_to_complex(1) self.connect((self.v2s, 0), (self.gr_complex_to_imag_0, 0)) self.connect((self.v2s, 0), (self.gr_complex_to_real_0, 0)) self.connect((self.gr_complex_to_real_0, 0), (self.gr_float_to_complex_0, 1)) self.connect((self.gr_complex_to_imag_0, 0), (self.gr_float_to_complex_0, 0)) self.connect((self.gr_float_to_complex_0, 0), (self)) elif options.swapIQ == False: self.gr_complex_to_imag_0 = gr.complex_to_imag(1) self.gr_complex_to_real_0 = gr.complex_to_real(1) self.gr_float_to_complex_0 = gr.float_to_complex(1) self.connect((self.v2s, 0), (self.gr_complex_to_imag_0, 0)) self.connect((self.v2s, 0), (self.gr_complex_to_real_0, 0)) self.connect((self.gr_complex_to_imag_0, 0), (self.gr_float_to_complex_0, 1)) self.connect((self.gr_complex_to_real_0, 0), (self.gr_float_to_complex_0, 0)) self.connect((self.gr_float_to_complex_0, 0), (self)) # connect the blocks self.connect((self._pkt_input, 0), (self.pilot, 0)) self.connect((self._pkt_input,1), (self.preamble, 1)) self.connect((self.preamble,1), (self.zerogap, 1)) self.connect(self.pilot, self.cmap, self.ifft, self.cp_adder, self.scale, self.s2v, self.preamble, self.zerogap, self.v2s) if options.log: self.connect((self._pkt_input), gr.file_sink(gr.sizeof_gr_complex * self._data_subcarriers, "ofdm_mapper.dat")) self.connect(self.pilot, gr.file_sink(gr.sizeof_gr_complex * (5 + self._data_subcarriers), "ofdm_pilot.dat")) self.connect(self.cmap, gr.file_sink(gr.sizeof_gr_complex * self._fft_length, "ofdm_cmap.dat")) self.connect(self.ifft, gr.file_sink(gr.sizeof_gr_complex * self._fft_length, "ofdm_ifft.dat")) self.connect(self.cp_adder, gr.file_sink(gr.sizeof_gr_complex, "ofdm_cp_adder.dat")) self.connect(self.scale, gr.file_sink(gr.sizeof_gr_complex, "ofdm_scale.dat")) self.connect(self.preamble, gr.file_sink(gr.sizeof_gr_complex * self._symbol_length, "ofdm_preamble.dat")) self.connect(self.zerogap, gr.file_sink(gr.sizeof_gr_complex * self._symbol_length, "ofdm_zerogap.dat"))
def __init__(self, options, msgq_limit=2, pad_for_usrp=False): """ Hierarchical block for sending packets Packets to be sent are enqueued by calling send_pkt. The output is the complex modulated signal at baseband. @param options: pass modulation options from higher layers (fft length, occupied tones, etc.) @param msgq_limit: maximum number of messages in message queue @type msgq_limit: int @param pad_for_usrp: If true, packets are padded such that they end up a multiple of 128 samples """ gr.hier_block2.__init__(self, "ofdm_mod", gr.io_signature(0, 0, 0), # Input signature gr.io_signature(1, 1, gr.sizeof_gr_complex)) # Output signature self._fft_length = 64 self._total_sub_carriers = 53 self._data_subcarriers = 48 self._cp_length = 16 self._regime = options.regime self._symbol_length = self._fft_length + self._cp_length # assuming we have 100Ms/s going to the USRP2 and 80 samples per symbol # we can calculate the OFDM symboltime (in microseconds) # depending on the interpolation factor self._symbol_time = 100000000*(self._symbol_length )/(100*options.bandwidth) self._n_sym = options.nsym win = [] self._modulation = options.modulation if self._modulation == "bpsk": rotated_const = ofdm_packet_utils.bpsk(self) elif self._modulation == "qpsk": rotated_const = ofdm_packet_utils.qpsk(self) elif self._modulation == "qam16": rotated_const = ofdm_packet_utils.qam16(self) elif self._modulation == "qam64": rotated_const = ofdm_packet_utils.qam64(self) # if(self._regime == "1" or self._regime == "2"): # rotated_const = ofdm_packet_utils.bpsk(self) # # elif (self._regime == "3" or self._regime == "4"): # rotated_const = ofdm_packet_utils.qpsk(self) # # elif(self._regime == "5" or self._regime == "6"): # rotated_const = ofdm_packet_utils.qam16(self) # # elif(self._regime == "7" or self._regime == "8"): # rotated_const = ofdm_packet_utils.qam64(self) # map groups of bits to complex symbols self._pkt_input = gr_ieee802_11.ofdm_symbol_mapper(rotated_const, msgq_limit, self._data_subcarriers, self._fft_length) # insert pilot symbols self.pilot = gr_ieee802_11.ofdm_pilot_insert(self._data_subcarriers) # move subcarriers to their designated place and insert DC self.cmap = gr_ieee802_11.ofdm_carrier_mapper(self._fft_length, self._total_sub_carriers) # inverse fast fourier transform self.ifft = gr.fft_vcc(self._fft_length, False, win, False) # add cyclic prefix self.cp_adder = digital_swig.ofdm_cyclic_prefixer(self._fft_length, self._symbol_length) # scale accordingly self.scale = gr.multiply_const_cc(1.0 / math.sqrt(self._fft_length)) # we need to know the number of OFDM data symbols for preamble and zerogap # MODIFIED FROM ORIGINAL # Instead of having the OFDM data symbols recorded in a python dictionary, the value of N_sym is updated when the class ofdm_mod invoked. N_sym = self._n_sym # add training sequence self.preamble= ofdm_packet_utils.insert_preamble(self._symbol_length, N_sym) # append zero samples at the end (receiver needs that to decode) self.zerogap = ofdm_packet_utils.insert_zerogap(self._symbol_length, N_sym) # repeat the frame a number of times self.repeat = gr_ieee802_11.ofdm_symbol_repeater(self._symbol_length, options.repetition, N_sym) self.s2v = gr.stream_to_vector(gr.sizeof_gr_complex , self._symbol_length) self.v2s = gr.vector_to_stream(gr.sizeof_gr_complex , self._symbol_length) # swap real and immaginary component before sending (GNURadio/USRP2 bug!) self.gr_complex_to_imag_0 = gr.complex_to_imag(1) self.gr_complex_to_real_0 = gr.complex_to_real(1) self.gr_float_to_complex_0 = gr.float_to_complex(1) self.connect((self.v2s, 0), (self.gr_complex_to_imag_0, 0)) self.connect((self.v2s, 0), (self.gr_complex_to_real_0, 0)) self.connect((self.gr_complex_to_imag_0, 0), (self.gr_float_to_complex_0, 1)) self.connect((self.gr_complex_to_real_0, 0), (self.gr_float_to_complex_0, 0)) self.connect((self.gr_float_to_complex_0, 0), (self)) # connect the blocks self.connect((self._pkt_input, 0), (self.pilot, 0)) self.connect((self._pkt_input,1), (self.preamble, 1)) self.connect((self.preamble,1), (self.zerogap, 1)) #if options.repetition == 1: self.connect(self.pilot, self.cmap, self.ifft, self.cp_adder, self.scale, self.s2v, \ self.preamble, self.zerogap, self.v2s) #elif options.repetition > 1: #self.connect(self.pilot, self.cmap, self.ifft, self.cp_adder, self.scale, self.s2v, self.preamble, self.zerogap, self.repeat, self.v2s) #else: # print"Error: repetiton must be a integer number >= 1 \n" # sys.exit(1) if options.log: self.connect((self._pkt_input), gr.file_sink(gr.sizeof_gr_complex * self._data_subcarriers, "ofdm_mapper.dat")) self.connect(self.pilot, gr.file_sink(gr.sizeof_gr_complex * (5 + self._data_subcarriers), "ofdm_pilot.dat")) self.connect(self.cmap, gr.file_sink(gr.sizeof_gr_complex * self._fft_length, "ofdm_cmap.dat")) self.connect(self.ifft, gr.file_sink(gr.sizeof_gr_complex * self._fft_length, "ofdm_ifft.dat")) self.connect(self.cp_adder, gr.file_sink(gr.sizeof_gr_complex, "ofdm_cp_adder.dat")) self.connect(self.scale, gr.file_sink(gr.sizeof_gr_complex, "ofdm_scale.dat")) self.connect(self.preamble, gr.file_sink(gr.sizeof_gr_complex * self._symbol_length, "ofdm_preamble.dat")) self.connect(self.zerogap, gr.file_sink(gr.sizeof_gr_complex * self._symbol_length, "ofdm_zerogap.dat"))
def __init__(self, options, payload='', msgq_limit=2, pad_for_usrp=False): """ Hierarchical block for sending packets Packets to be sent are enqueued by calling send_pkt. The output is the complex modulated signal at baseband. @param options: pass modulation options from higher layers (fft length, occupied tones, etc.) @param msgq_limit: maximum number of messages in message queue @type msgq_limit: int @param pad_for_usrp: If true, packets are padded such that they end up a multiple of 128 samples """ gr.hier_block2.__init__( self, "ofdm_mod", gr.io_signature(0, 0, 0), # Input signature gr.io_signature(1, 1, gr.sizeof_gr_complex)) # Output signature self._fft_length = 64 self._total_sub_carriers = 53 self._data_subcarriers = 48 self._cp_length = 16 self._regime = options.regime self._symbol_length = self._fft_length + self._cp_length self._role = options.role # assuming we have 100Ms/s going to the USRP2 and 80 samples per symbol # we can calculate the OFDM symboltime (in microseconds) # depending on the interpolation factor self._symbol_time = options.interp * (self._fft_length + self._cp_length) / 100 win = [] if (self._regime == "1" or self._regime == "2"): rotated_const = ofdm_packet_utils.bpsk(self) elif (self._regime == "3" or self._regime == "4"): rotated_const = ofdm_packet_utils.qpsk(self) elif (self._regime == "5" or self._regime == "6"): rotated_const = ofdm_packet_utils.qam16(self) elif (self._regime == "7" or self._regime == "8"): rotated_const = ofdm_packet_utils.qam64(self) # map groups of bits to complex symbols self._pkt_input = ftw.ofdm_mapper(rotated_const, msgq_limit, self._data_subcarriers, self._fft_length) # insert pilot symbols (use pnc block * by lzyou) if self._role == 'A': print " >>> [FPNC]: *A* Insert Pilot" self.pilot = ftw.pnc_ofdm_pilot_cc(self._data_subcarriers, 1) elif self._role == 'B': print " >>> [FPNC]: *B* Insert Pilot" self.pilot = ftw.pnc_ofdm_pilot_cc(self._data_subcarriers, 2) else: print " >>> [FTW ]: Insert Pilot" self.pilot = ftw.ofdm_pilot_cc(self._data_subcarriers) # just for test #self.pilot = ftw.pnc_ofdm_pilot_cc(self._data_subcarriers, 1) #self.pilot = ftw.pnc_ofdm_pilot_cc(self._data_subcarriers, 2) # move subcarriers to their designated place and insert DC self.cmap = ftw.ofdm_cmap_cc(self._fft_length, self._total_sub_carriers) # inverse fast fourier transform self.ifft = gr.fft_vcc(self._fft_length, False, win, False) # add cyclic prefix from gnuradio import digital self.cp_adder = digital.ofdm_cyclic_prefixer(self._fft_length, self._symbol_length) self.connect( gr.null_source(gr.sizeof_char), (self.cp_adder, 1)) # Note: dirty modification to accomdate the API change # scale accordingly self.scale = gr.multiply_const_cc(1.0 / math.sqrt(self._fft_length)) # we need to know the number of OFDM data symbols for preamble and zerogap info = ofdm_packet_utils.get_info(payload, options.regime, self._symbol_time) N_sym = info["N_sym"] # add training sequence (modify by lzyou) if self._role == 'A': print " >>> [FPNC]: *A* Insert Preamble" self.preamble = ofdm_packet_utils.insert_preamble( self._symbol_length, N_sym, 'A') elif self._role == 'B': print " >>> [FPNC]: *B* Insert Preamble" self.preamble = ofdm_packet_utils.insert_preamble( self._symbol_length, N_sym, 'B') else: print " >>> [FTW ]: Insert Preamble" self.preamble = ofdm_packet_utils.insert_preamble( self._symbol_length, N_sym) # append zero samples at the end (receiver needs that to decode) if self._role == None: print " >>> [FTW ]: Insert Zerogap" self.zerogap = ofdm_packet_utils.insert_zerogap( self._symbol_length, N_sym) else: print " >>> [FPNC]: Insert Zerogap" self.zerogap = ofdm_packet_utils.insert_zerogap( self._symbol_length, N_sym, 'FPNC') self.s2v = gr.stream_to_vector(gr.sizeof_gr_complex, self._symbol_length) self.v2s = gr.vector_to_stream(gr.sizeof_gr_complex, self._symbol_length) # swap real and immaginary component before sending (GNURadio/USRP2 bug!) if options.swapIQ == True: self.gr_complex_to_imag_0 = gr.complex_to_imag(1) self.gr_complex_to_real_0 = gr.complex_to_real(1) self.gr_float_to_complex_0 = gr.float_to_complex(1) self.connect((self.v2s, 0), (self.gr_complex_to_imag_0, 0)) self.connect((self.v2s, 0), (self.gr_complex_to_real_0, 0)) self.connect((self.gr_complex_to_real_0, 0), (self.gr_float_to_complex_0, 1)) self.connect((self.gr_complex_to_imag_0, 0), (self.gr_float_to_complex_0, 0)) self.connect((self.gr_float_to_complex_0, 0), (self)) elif options.swapIQ == False: self.gr_complex_to_imag_0 = gr.complex_to_imag(1) self.gr_complex_to_real_0 = gr.complex_to_real(1) self.gr_float_to_complex_0 = gr.float_to_complex(1) self.connect((self.v2s, 0), (self.gr_complex_to_imag_0, 0)) self.connect((self.v2s, 0), (self.gr_complex_to_real_0, 0)) self.connect((self.gr_complex_to_imag_0, 0), (self.gr_float_to_complex_0, 1)) self.connect((self.gr_complex_to_real_0, 0), (self.gr_float_to_complex_0, 0)) self.connect((self.gr_float_to_complex_0, 0), (self)) # connect the blocks self.connect((self._pkt_input, 0), (self.pilot, 0)) self.connect((self._pkt_input, 1), (self.preamble, 1)) self.connect((self.preamble, 1), (self.zerogap, 1)) self.connect(self.pilot, self.cmap, self.ifft, self.cp_adder, self.scale, self.s2v, self.preamble, self.zerogap, self.v2s) if options.log: self.connect( (self._pkt_input), gr.file_sink(gr.sizeof_gr_complex * self._data_subcarriers, "ofdm_mapper.dat")) self.connect( self.pilot, gr.file_sink( gr.sizeof_gr_complex * (5 + self._data_subcarriers), "ofdm_pilot.dat")) self.connect( self.cmap, gr.file_sink(gr.sizeof_gr_complex * self._fft_length, "ofdm_cmap.dat")) self.connect( self.ifft, gr.file_sink(gr.sizeof_gr_complex * self._fft_length, "ofdm_ifft.dat")) self.connect( self.cp_adder, gr.file_sink(gr.sizeof_gr_complex, "ofdm_cp_adder.dat")) self.connect(self.scale, gr.file_sink(gr.sizeof_gr_complex, "ofdm_scale.dat")) self.connect( self.preamble, gr.file_sink(gr.sizeof_gr_complex * self._symbol_length, "ofdm_preamble.dat")) self.connect( self.zerogap, gr.file_sink(gr.sizeof_gr_complex * self._symbol_length, "ofdm_zerogap.dat"))
def __init__(self, options): gr.hier_block2.__init__(self, "transmit_path", gr.io_signature(0,0,0), gr.io_signature(2,2,gr.sizeof_gr_complex)) common_options.defaults(options) config = self.config = station_configuration() config.data_subcarriers = options.subcarriers config.cp_length = options.cp_length config.frame_data_blocks = options.data_blocks config._verbose = options.verbose config.fft_length = options.fft_length config.training_data = default_block_header(config.data_subcarriers, config.fft_length,options) config.tx_station_id = options.station_id config.coding = options.coding if config.tx_station_id is None: raise SystemError, "Station ID not set" config.frame_id_blocks = 1 # FIXME # digital rms amplitude sent to USRP rms_amp = options.rms_amplitude self._options = copy.copy(options) self.servants = [] # FIXME 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.frame_data_part + \ config.training_data.no_pilotsyms config.subcarriers = config.data_subcarriers + \ config.training_data.pilot_subcarriers config.virtual_subcarriers = config.fft_length - config.subcarriers # 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) ## Control Part if options.debug: self._control = ctrl = static_tx_control(options) print "Statix TX Control used" else: self._control = ctrl = corba_tx_control(options) print "CORBA TX Control used" id_src = (ctrl,0) mux_src = (ctrl,1) map_src = self._map_src = (ctrl,2) pa_src = (ctrl,3) if options.log: id_src_f = gr.short_to_float() self.connect(id_src,id_src_f) log_to_file(self, id_src_f, "data/id_src_out.float") mux_src_f = gr.short_to_float() self.connect(mux_src,mux_src_f) log_to_file(self, mux_src_f, "data/mux_src_out.float") map_src_s = blocks.vector_to_stream(gr.sizeof_char,config.data_subcarriers) map_src_f = gr.char_to_float() self.connect(map_src,map_src_s,map_src_f) ##log_to_file(self, map_src_f, "data/map_src.float") ##log_to_file(self, pa_src, "data/pa_src_out.float") ## 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") ## Bitmap Update Trigger # TODO #bmaptrig_stream = concatenate([[1, 2],[0]*(config.frame_data_part-7)]) bmaptrig_stream = concatenate([[1, 1],[0]*(config.frame_data_part-2)]) print"bmaptrig_stream = ",bmaptrig_stream btrig = self._bitmap_trigger = blocks.vector_source_b(bmaptrig_stream.tolist(), True) if options.log: log_to_file(self, btrig, "data/bitmap_trig.char") ## Bitmap Update Trigger for puncturing # TODO if not options.nopunct: #bmaptrig_stream_puncturing = concatenate([[1],[0]*(config.frame_data_part-2)]) bmaptrig_stream_puncturing = concatenate([[1],[0]*(config.frame_data_blocks/2-1)]) btrig_puncturing = self._bitmap_trigger_puncturing = blocks.vector_source_b(bmaptrig_stream_puncturing.tolist(), True) bmapsrc_stream_puncturing = concatenate([[1]*dsubc,[2]*dsubc]) bsrc_puncturing = self._bitmap_src_puncturing = blocks.vector_source_b(bmapsrc_stream_puncturing.tolist(), True, dsubc) if options.log and options.coding and not options.nopunct: log_to_file(self, btrig_puncturing, "data/bitmap_trig_puncturing.char") ## Frame Trigger # TODO ftrig_stream = concatenate([[1],[0]*(config.frame_data_part-1)]) ftrig = self._frame_trigger = blocks.vector_source_b(ftrig_stream.tolist(),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_src,(dmux,0)) self.connect(id_enc,(dmux,1)) self._data_multiplexer_nextport = 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,options.coding) self.connect(dmux,(mod,0)) self.connect(map_src,(mod,1)) self.connect(btrig,(mod,2)) if options.log: log_to_file(self, mod, "data/mod_out.compl") modi = gr.complex_to_imag(config.data_subcarriers) modr = gr.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 if options.debug: ## static pa = self._power_allocator = power_allocator(config.data_subcarriers) self.connect(mod,(pa,0)) self.connect(pa_src,(pa,1)) else: ## with CORBA control event channel ns_ip = ctrl.ns_ip ns_port = ctrl.ns_port evchan = ctrl.evchan pa = self._power_allocator = corba_power_allocator(dsubc, \ evchan, ns_ip, ns_port, True) self.connect(mod,(pa,0)) self.connect(id_src,(pa,1)) self.connect(ftrig,(pa,2)) if options.log: log_to_file(self, pa, "data/pa_out.compl") ## Pilot subcarriers psubc = self._pilot_subcarrier_inserter = pilot_subcarrier_inserter() self.connect( pa ,psubc ) pilot_subc = config.training_data.shifted_pilot_tones; print "pilot_subc", pilot_subc stc = stc_encoder( config.subcarriers, config.frame_data_blocks, pilot_subc ) self.connect(psubc, stc) if options.log: log_to_file(self, psubc, "data/psubc_out.compl") log_to_file(self, psubc_2, "data/psubc2_out.compl") log_to_file(self, pa, "data/pa.compl") log_to_file(self, ( stc, 0 ), "data/stc_0.compl") log_to_file(self, ( stc, 1 ), "data/stc_1.compl") ## Add virtual subcarriers if config.fft_length > config.subcarriers: vsubc = self._virtual_subcarrier_extender = \ vector_padding(config.subcarriers, config.fft_length) self.connect(stc,vsubc) vsubc_2 = self._virtual_subcarrier_extender_2 = \ vector_padding(config.subcarriers, config.fft_length) self.connect((stc,1),vsubc_2) else: vsubc = self._virtual_subcarrier_extender = psubc vsubc_2 = self._virtual_subcarrier_extender_2 = psubc_2 log_to_file(self, psubc, "data/psubc.compl") log_to_file(self, stc, "data/stc1.compl") log_to_file(self, (stc,1), "data/stc2.compl") if options.log: log_to_file(self, vsubc, "data/vsubc_out.compl") log_to_file(self, vsubc_2, "data/vsubc2_out.compl") ## IFFT, no window, block shift ifft = self._ifft = fft_blocks.fft_vcc(config.fft_length,False,[],True) self.connect(vsubc,ifft) ifft_2 = self._ifft_2 = fft_blocks.fft_vcc(config.fft_length,False,[],True) self.connect(vsubc_2,ifft_2) if options.log: log_to_file(self, ifft, "data/ifft_out.compl") log_to_file(self, ifft_2, "data/ifft2_out.compl") ## Pilot blocks (preambles) pblocks = self._pilot_block_inserter = pilot_block_inserter(1, False) self.connect( ifft, pblocks ) pblocks_2 = self._pilot_block_inserter_2 = pilot_block_inserter( 2, False) self.connect( ifft_2, pblocks_2 ) if options.log: log_to_file(self, pblocks, "data/pilot_block_ins_out.compl") log_to_file(self, pblocks_2, "data/pilot_block_ins2_out.compl") ## Cyclic Prefix cp = self._cyclic_prefixer = cyclic_prefixer(config.fft_length, config.block_length) self.connect( pblocks, cp ) cp_2 = self._cyclic_prefixer_2 = cyclic_prefixer(config.fft_length, config.block_length) self.connect( pblocks_2, cp_2 ) lastblock = cp lastblock_2 = cp_2 if options.log: log_to_file(self, cp, "data/cp_out.compl") log_to_file(self, cp_2, "data/cp2_out.compl") if options.cheat: ## Artificial Channel # kept to compare with previous system achan_ir = concatenate([[1.0],[0.0]*(config.cp_length-1)]) achan = self._artificial_channel = gr.fir_filter_ccc(1,achan_ir) self.connect( lastblock, achan ) lastblock = achan achan_2 = self._artificial_channel_2 = gr.fir_filter_ccc(1,achan_ir) self.connect( lastblock_2, achan_2 ) lastblock_2 = achan_2 ## Digital Amplifier amp = self._amplifier = ofdm.multiply_const_ccf( 1.0/math.sqrt(2) ) self.connect( lastblock, amp ) amp_2 = self._amplifier_2 = ofdm.multiply_const_ccf( 1.0/math.sqrt(2) ) self.connect( lastblock_2, amp_2 ) self.set_rms_amplitude(rms_amp) if options.log: log_to_file(self, amp, "data/amp_tx_out.compl") log_to_file(self, amp_2, "data/amp_tx2_out.compl") ## Setup Output self.connect(amp,(self,0)) self.connect(amp_2,(self,1)) # ------------------------------------------------------------------------ # # Display some information about the setup if config._verbose: self._print_verbage()