def __init__(self, dab_params, verbose=False, debug=False): """ Hierarchical block for OFDM modulation @param dab_params DAB parameter object (dab.parameters.dab_parameters) @param debug enables debug output to files """ dp = dab_params gr.hier_block2.__init__(self,"ofdm_mod", gr.io_signature2(2, 2, gr.sizeof_char*dp.num_carriers/4, gr.sizeof_char), # input signature gr.io_signature (1, 1, gr.sizeof_gr_complex)) # output signature # symbol mapping self.mapper = dab_swig.qpsk_mapper_vbc(dp.num_carriers) # add pilot symbol self.insert_pilot = dab_swig.ofdm_insert_pilot_vcc(dp.prn) # phase sum self.sum_phase = dab_swig.sum_phasor_trig_vcc(dp.num_carriers) # frequency interleaving self.interleave = dab_swig.frequency_interleaver_vcc(dp.frequency_interleaving_sequence_array) # add central carrier & move to middle self.move_and_insert_carrier = dab_swig.ofdm_move_and_insert_zero(dp.fft_length, dp.num_carriers) # ifft self.ifft = gr.fft_vcc(dp.fft_length, False, [], True) # cyclic prefixer self.prefixer = gr.ofdm_cyclic_prefixer(dp.fft_length, dp.symbol_length) # convert back to vectors self.s2v = gr.stream_to_vector(gr.sizeof_gr_complex, dp.symbol_length) # add null symbol self.insert_null = dab_swig.insert_null_symbol(dp.ns_length, dp.symbol_length) # # connect it all # # data self.connect((self,0), self.mapper, (self.insert_pilot,0), (self.sum_phase,0), self.interleave, self.move_and_insert_carrier, self.ifft, self.prefixer, self.s2v, (self.insert_null,0)) self.connect(self.insert_null, self) # control signal (frame start) self.connect((self,1), (self.insert_pilot,1), (self.sum_phase,1), (self.insert_null,1)) if debug: self.connect(self.mapper, gr.file_sink(gr.sizeof_gr_complex*dp.num_carriers, "debug/generated_signal_mapper.dat")) self.connect(self.insert_pilot, gr.file_sink(gr.sizeof_gr_complex*dp.num_carriers, "debug/generated_signal_insert_pilot.dat")) self.connect(self.sum_phase, gr.file_sink(gr.sizeof_gr_complex*dp.num_carriers, "debug/generated_signal_sum_phase.dat")) self.connect(self.interleave, gr.file_sink(gr.sizeof_gr_complex*dp.num_carriers, "debug/generated_signal_interleave.dat")) self.connect(self.move_and_insert_carrier, gr.file_sink(gr.sizeof_gr_complex*dp.fft_length, "debug/generated_signal_move_and_insert_carrier.dat")) self.connect(self.ifft, gr.file_sink(gr.sizeof_gr_complex*dp.fft_length, "debug/generated_signal_ifft.dat")) self.connect(self.prefixer, gr.file_sink(gr.sizeof_gr_complex, "debug/generated_signal_prefixer.dat")) self.connect(self.insert_null, gr.file_sink(gr.sizeof_gr_complex, "debug/generated_signal.dat"))
def __init__(self, options, msgq_limit=2, pad_for_usrp=True): """ 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._pad_for_usrp = pad_for_usrp self._modulation = options.modulation self._fft_length = options.fft_length self._occupied_tones = options.occupied_tones self._cp_length = options.cp_length win = [] #[1 for i in range(self._fft_length)] # Use freq domain to get doubled-up known symbol for correlation in time domain zeros_on_left = int( math.ceil((self._fft_length - self._occupied_tones) / 2.0)) ksfreq = known_symbols_4512_3[0:self._occupied_tones] for i in range(len(ksfreq)): if ((zeros_on_left + i) & 1): ksfreq[i] = 0 # hard-coded known symbols preambles = (ksfreq, ) padded_preambles = list() for pre in preambles: padded = self._fft_length * [ 0, ] padded[zeros_on_left:zeros_on_left + self._occupied_tones] = pre padded_preambles.append(padded) symbol_length = options.fft_length + options.cp_length mods = { "bpsk": 2, "qpsk": 4, "8psk": 8, "qam8": 8, "qam16": 16, "qam64": 64, "qam256": 256 } arity = mods[self._modulation] rot = 1 if self._modulation == "qpsk": rot = (0.707 + 0.707j) if (self._modulation.find("psk") >= 0): rotated_const = map(lambda pt: pt * rot, psk.gray_constellation[arity]) elif (self._modulation.find("qam") >= 0): rotated_const = map(lambda pt: pt * rot, qam.constellation[arity]) #print rotated_const self._pkt_input = gr.ofdm_mapper_bcv(rotated_const, msgq_limit, options.occupied_tones, options.fft_length) self.preambles = gr.ofdm_insert_preamble(self._fft_length, padded_preambles) self.ifft = gr.fft_vcc(self._fft_length, False, win, True) self.cp_adder = gr.ofdm_cyclic_prefixer(self._fft_length, symbol_length) self.scale = gr.multiply_const_cc(1.0 / math.sqrt(self._fft_length)) self.connect((self._pkt_input, 0), (self.preambles, 0)) self.connect((self._pkt_input, 1), (self.preambles, 1)) self.connect(self.preambles, self.ifft, self.cp_adder, self.scale, self) if options.verbose: self._print_verbage() if options.log: self.connect( self._pkt_input, gr.file_sink(gr.sizeof_gr_complex * options.fft_length, "ofdm_mapper_c.dat")) self.connect( self.preambles, gr.file_sink(gr.sizeof_gr_complex * options.fft_length, "ofdm_preambles.dat")) self.connect( self.ifft, gr.file_sink(gr.sizeof_gr_complex * options.fft_length, "ofdm_ifft_c.dat")) self.connect( self.cp_adder, gr.file_sink(gr.sizeof_gr_complex, "ofdm_cp_adder_c.dat"))
def __init__(self, options, msgq_limit=2, pad_for_usrp=True): """ 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._pad_for_usrp = pad_for_usrp self._modulation = options.modulation self._fft_length = options.fft_length self._occupied_tones = options.occupied_tones self._cp_length = options.cp_length win = [] #[1 for i in range(self._fft_length)] # Use freq domain to get doubled-up known symbol for correlation in time domain zeros_on_left = int(math.ceil((self._fft_length - self._occupied_tones)/2.0)) ksfreq = known_symbols_4512_3[0:self._occupied_tones] for i in range(len(ksfreq)): if((zeros_on_left + i) & 1): ksfreq[i] = 0 # hard-coded known symbols preambles = (ksfreq,) padded_preambles = list() for pre in preambles: padded = self._fft_length*[0,] padded[zeros_on_left : zeros_on_left + self._occupied_tones] = pre padded_preambles.append(padded) symbol_length = options.fft_length + options.cp_length mods = {"bpsk": 2, "qpsk": 4, "8psk": 8, "qam8": 8, "qam16": 16, "qam64": 64, "qam256": 256} arity = mods[self._modulation] rot = 1 if self._modulation == "qpsk": rot = (0.707+0.707j) if(self._modulation.find("psk") >= 0): rotated_const = map(lambda pt: pt * rot, psk.gray_constellation[arity]) elif(self._modulation.find("qam") >= 0): rotated_const = map(lambda pt: pt * rot, qam.constellation[arity]) #print rotated_const self._pkt_input = gr.ofdm_mapper_bcv(rotated_const, msgq_limit, options.occupied_tones, options.fft_length) self.preambles = gr.ofdm_insert_preamble(self._fft_length, padded_preambles) self.ifft = gr.fft_vcc(self._fft_length, False, win, True) self.cp_adder = gr.ofdm_cyclic_prefixer(self._fft_length, symbol_length) self.scale = gr.multiply_const_cc(1.0 / math.sqrt(self._fft_length)) self.connect((self._pkt_input, 0), (self.preambles, 0)) self.connect((self._pkt_input, 1), (self.preambles, 1)) self.connect(self.preambles, self.ifft, self.cp_adder, self.scale, self) if options.verbose: self._print_verbage() if options.log: self.connect(self._pkt_input, gr.file_sink(gr.sizeof_gr_complex*options.fft_length, "ofdm_mapper_c.dat")) self.connect(self.preambles, gr.file_sink(gr.sizeof_gr_complex*options.fft_length, "ofdm_preambles.dat")) self.connect(self.ifft, gr.file_sink(gr.sizeof_gr_complex*options.fft_length, "ofdm_ifft_c.dat")) self.connect(self.cp_adder, gr.file_sink(gr.sizeof_gr_complex, "ofdm_cp_adder_c.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), gr.io_signature(1, 1, gr.sizeof_gr_complex) # Input signature ) # 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 = 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 self.pilot = ftw.ofdm_pilot_cc(self._data_subcarriers) # 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) # add cyclic prefix self.cp_adder = gr.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 info = ofdm_packet_utils.get_info(payload, options.regime, self._symbol_time) N_sym = info["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 = ftw.repetition(80, 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!) 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)) # 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"))