def make_prs(sample_rate=2048000): dp = parameters.dab_parameters(1, sample_rate) prs = dp.prn def write(file_name, signal): if type(signal) != numpy.complex64: signal = numpy.asarray(signal, dtype=numpy.complex64) signal.tofile(file_name) def interleave(symbol): return [symbol[i] for i in dp.frequency_interleaving_sequence_array] def pad(symbol): zeros_on_left = (dp.fft_length - dp.num_carriers) / 2 zeros_on_right = dp.fft_length - zeros_on_left - dp.num_carriers - 1 return [0] * zeros_on_left + symbol[0:dp.num_carriers / 2] + [ 0 ] + symbol[dp.num_carriers / 2:] + [0] * zeros_on_right #print prs interleaved_prs = interleave(prs) #padded_prs = pad(interleaved_prs) padded_prs = pad(prs) return padded_prs
def __init__(self): gr.top_block.__init__(self) usage = "%prog: [options] samples_file" parser = OptionParser(option_class=eng_option, usage=usage) (options, args) = parser.parse_args () if len(args)<1: # print "using gaussian noise as source" # self.sigsrc = gr.noise_source_c(gr.GR_GAUSSIAN,10e6) print "using repeating random vector as source" self.sigsrc = blocks.vector_source_c([10e6*(random.random() + 1j*random.random()) for i in range(0,100000)],True) self.src = blocks.throttle( gr.sizeof_gr_complex,2048000) self.connect(self.sigsrc, self.src) else: filename = args[0] print "using samples from file " + filename self.src = blocks.file_source(gr.sizeof_gr_complex, filename, False) dp = parameters.dab_parameters(1) rp = parameters.receiver_parameters(1) self.sync_dab = ofdm_sync_dab(dp, rp, False) self.nop0 = blocks.nop(gr.sizeof_gr_complex) self.nop1 = blocks.nop(gr.sizeof_char) self.connect(self.src, self.sync_dab, self.nop0) self.connect((self.sync_dab,1), self.nop1)
def __init__(self): gr.sync_block.__init__(self, name="dab_sync", in_sig=[numpy.complex64], out_sig=[numpy.complex64]) self.sample_rate = 2048000 self.step = 1 self.dp = parameters.dab_parameters(1, self.sample_rate) self.prs = make_prs.modulate_prs(self.sample_rate, True) self.frame_length = int(self.sample_rate * 96e-3) self.prs_len = len(self.prs) print "PRS length", self.prs_len self.correlator = correlate.Correlator(self.prs, self.sample_rate) self.P = 0.2 * 3 self.I = 0.2 * 3 self.fract = 1000 self.integer_offset = 0 self.fract_offset = 0 self.state = INIT self.set_history(self.prs_len + 1)
def __init__(self): gr.top_block.__init__(self) usage = "%prog: [options] samples_file" parser = OptionParser(option_class=eng_option, usage=usage) (options, args) = parser.parse_args() if len(args) < 1: # print "using gaussian noise as source" # self.sigsrc = gr.noise_source_c(gr.GR_GAUSSIAN,10e6) print "using repeating random vector as source" self.sigsrc = blocks.vector_source_c([ 10e6 * (random.random() + 1j * random.random()) for i in range(0, 100000) ], True) self.src = blocks.throttle(gr.sizeof_gr_complex, 2048000) self.connect(self.sigsrc, self.src) else: filename = args[0] print "using samples from file " + filename self.src = blocks.file_source(gr.sizeof_gr_complex, filename, False) dp = parameters.dab_parameters(1) rp = parameters.receiver_parameters(1) self.sync_dab = ofdm_sync_dab(dp, rp, False) self.nop0 = blocks.nop(gr.sizeof_gr_complex) self.nop1 = blocks.nop(gr.sizeof_char) self.connect(self.src, self.sync_dab, self.nop0) self.connect((self.sync_dab, 1), self.nop1)
def test_001_t (self): self.symbol_length = 32*4 self.dab_params = dab_parameters(1, 208.064e6, True) # source self.dp = dab_parameters(1, 208.064e6, True) self.fib_src = dab.fib_source_b_make(1, 1, 1, "ensemble1", "service1 ", "musicmix", 4, [2], [15], [1]) # encoder self.fib_enc = fic_encode(self.dab_params) self.unpack = blocks.packed_to_unpacked_bb_make(1, gr.GR_MSB_FIRST) # mapper self.map = dab.mapper_bc_make(self.dp.num_carriers) # demapper self.s2v = blocks.stream_to_vector_make(gr.sizeof_gr_complex, self.dp.num_carriers) self.soft_interleaver = dab.complex_to_interleaved_float_vcf_make(self.dp.num_carriers) # decode self.fic_decoder = fic_decode(self.dab_params) # control stream self.trigger_src = blocks.vector_source_b([1] + [0]*74, True) self.tb.connect(self.fib_src, blocks.head_make(gr.sizeof_char, 100000), self.fib_enc, self.unpack, self.map, self.s2v, self.soft_interleaver, self.fic_decoder ) self.tb.connect(self.trigger_src, (self.fic_decoder, 1)) self.tb.run () pass
def __init__(self): gr.top_block.__init__(self) usage = "%prog: [options] samples_file" parser = OptionParser(option_class=eng_option, usage=usage) parser.add_option("-m", "--dab-mode", type="int", default=1, help="DAB mode [default=%default]") parser.add_option("-F", "--filter-input", action="store_true", default=False, help="Enable FFT filter at input") parser.add_option("-s", "--resample-fixed", type="float", default=1, help="resample by a fixed factor (fractional interpolation)") parser.add_option("-S", "--autocorrect-sample-rate", action="store_true", default=False, help="Estimate sample rate offset and resample (dynamic fractional interpolation)") parser.add_option('-r', '--sample-rate', type="int", default=2048000, help="Use non-standard sample rate (default=%default)") parser.add_option('-e', '--equalize-magnitude', action="store_true", default=False, help="Enable individual carrier magnitude equalizer") parser.add_option('-d', '--debug', action="store_true", default=False, help="Write output to files") parser.add_option('-v', '--verbose', action="store_true", default=False, help="Print status messages") (options, args) = parser.parse_args () dp = parameters.dab_parameters(options.dab_mode, verbose=options.verbose, sample_rate=options.sample_rate) rp = parameters.receiver_parameters(options.dab_mode, input_fft_filter=options.filter_input, autocorrect_sample_rate=options.autocorrect_sample_rate, sample_rate_correction_factor=options.resample_fixed, equalize_magnitude=options.equalize_magnitude, verbose=options.verbose) if len(args)<1: if options.verbose: print "-> using repeating random vector as source" self.sigsrc = gr.vector_source_c([10e6*(random.random() + 1j*random.random()) for i in range(0,100000)],True) self.ns_simulate = gr.vector_source_c([0.01]*dp.ns_length+[1]*dp.symbols_per_frame*dp.symbol_length,1) self.mult = gr.multiply_cc() # simulate null symbols ... self.src = gr.throttle( gr.sizeof_gr_complex,2048000) self.connect(self.sigsrc, (self.mult, 0)) self.connect(self.ns_simulate, (self.mult, 1)) self.connect(self.mult, self.src) else: filename = args[0] if options.verbose: print "-> using samples from file " + filename self.src = gr.file_source(gr.sizeof_gr_complex, filename, False) self.dab_demod = ofdm.ofdm_demod(dp, rp, debug=options.debug, verbose=options.verbose) self.connect(self.src, self.dab_demod) # sink output to nowhere self.nop0 = gr.nop(gr.sizeof_char*dp.num_carriers/4) self.nop1 = gr.nop(gr.sizeof_char) self.connect((self.dab_demod,0),self.nop0) self.connect((self.dab_demod,1),self.nop1)
def init(self): self.sample_rate = 2048000 self.step = 1 self.dp = parameters.dab_parameters(1, self.sample_rate) self.prs = make_prs.modulate_prs(self.sample_rate, True) self.frame_length = int(self.sample_rate * 96e-3) self.prs_len = len(self.prs) self.P = 0.2 * 3 self.I = 0.2 * 3 self.fract = 1000 self.integer_offset = 0 self.fract_offset = 0 self.state = get_samples self.get_samples_count = self.frame_length self.next_state = find_start
def modulate_prs(sample_rate=2048000, cp=True): dp = parameters.dab_parameters(1, sample_rate) padded_prs = make_prs(sample_rate) #plt.plot(numpy.abs(padded_prs)) #plt.show() #plt.plot(numpy.angle(padded_prs)) #plt.show() shifted_prs = numpy.fft.fftshift(padded_prs) #plt.plot(numpy.abs(shifted_prs)) #plt.show() ifft_prs = numpy.fft.ifft(shifted_prs) if cp: print "CP length", dp.cp_length cycled_prs = numpy.concatenate((ifft_prs[-dp.cp_length:], ifft_prs)) return cycled_prs else: return ifft_prs
if __name__ == "__main__": #sample_rate = 2048000 sample_rate = 2000000 cycled_prs = modulate_prs(sample_rate) iq.write("/tmp/generated.cfile", cycled_prs) signal = numpy.concatenate(([0] * 2048, cycled_prs)) #signal = numpy.concatenate(([0] * 2048, cycled_prs, [0] * 2048, cycled_prs)) #signal = numpy.concatenate(([0] * 2048, prs, [0] * 2048, prs)) iq.write("/tmp/foo.cfile", signal) #print dp.frequency_interleaving_sequence_array dp = parameters.dab_parameters(1, sample_rate) Tu = dp.fft_length offset = 600 shift_signal = numpy.exp( complex(0, -1) * numpy.arange(len(signal)) * 2 * numpy.pi * offset / float(sample_rate)) signal = signal * shift_signal time_shifted_signal = signal[Tu:] auto_correlated = [0] * len(time_shifted_signal) for i in range(len(time_shifted_signal)): auto_correlated[i] = numpy.angle(signal[i] * numpy.conj( time_shifted_signal[i])) / 2 / 3.14 / (2048. / sample_rate)
def __init__(self): gr.top_block.__init__(self) usage = "%prog: [options] samples_file" parser = OptionParser(option_class=eng_option, usage=usage) parser.add_option("-m", "--dab-mode", type="int", default=1, help="DAB mode [default=%default]") parser.add_option("-F", "--filter-input", action="store_true", default=False, help="Enable FFT filter at input") parser.add_option( "-s", "--resample-fixed", type="float", default=1, help="resample by a fixed factor (fractional interpolation)") parser.add_option( "-S", "--autocorrect-sample-rate", action="store_true", default=False, help= "Estimate sample rate offset and resample (dynamic fractional interpolation)" ) parser.add_option( '-r', '--sample-rate', type="int", default=2048000, help="Use non-standard sample rate (default=%default)") parser.add_option('-e', '--equalize-magnitude', action="store_true", default=False, help="Enable individual carrier magnitude equalizer") parser.add_option('-d', '--debug', action="store_true", default=False, help="Write output to files") parser.add_option('-v', '--verbose', action="store_true", default=False, help="Print status messages") (options, args) = parser.parse_args() dp = parameters.dab_parameters(options.dab_mode, verbose=options.verbose, sample_rate=options.sample_rate) rp = parameters.receiver_parameters( options.dab_mode, input_fft_filter=options.filter_input, autocorrect_sample_rate=options.autocorrect_sample_rate, sample_rate_correction_factor=options.resample_fixed, equalize_magnitude=options.equalize_magnitude, verbose=options.verbose) if len(args) < 1: if options.verbose: print "-> using repeating random vector as source" self.sigsrc = blocks.vector_source_c([ 10e6 * (random.random() + 1j * random.random()) for i in range(0, 100000) ], True) self.ns_simulate = blocks.vector_source_c( [0.01] * dp.ns_length + [1] * dp.symbols_per_frame * dp.symbol_length, 1) self.mult = blocks.multiply_cc() # simulate null symbols ... self.src = blocks.throttle(gr.sizeof_gr_complex, 2048000) self.connect(self.sigsrc, (self.mult, 0)) self.connect(self.ns_simulate, (self.mult, 1)) self.connect(self.mult, self.src) else: filename = args[0] if options.verbose: print "-> using samples from file " + filename self.src = blocks.file_source(gr.sizeof_gr_complex, filename, False) self.dab_demod = ofdm.ofdm_demod(dp, rp, debug=options.debug, verbose=options.verbose) self.connect(self.src, self.dab_demod) # sink output to nowhere self.nop0 = blocks.nop(gr.sizeof_char * dp.num_carriers / 4) self.nop1 = blocks.nop(gr.sizeof_char) self.connect((self.dab_demod, 0), self.nop0) self.connect((self.dab_demod, 1), self.nop1)
def __init__(self, mode, debug=False): """ OFDM time and coarse frequency synchronisation for DAB @param mode DAB mode (1-4) @param debug if True: write data streams out to files """ if mode < 1 or mode > 4: raise ValueError, "Invalid DAB mode: " + str( mode) + " (modes 1-4 exist)" # get the correct DAB parameters dp = parameters.dab_parameters(mode) rp = parameters.receiver_parameters(mode) gr.hier_block2.__init__( self, "ofdm_sync_dab", gr.io_signature(1, 1, gr.sizeof_gr_complex), # input signature gr.io_signature2(2, 2, gr.sizeof_gr_complex, gr.sizeof_char)) # output signature # workaround for a problem that prevents connecting more than one block directly (see trac ticket #161) self.input = gr.kludge_copy(gr.sizeof_gr_complex) self.connect(self, self.input) # # null-symbol detection # # (outsourced to detect_zero.py) self.ns_detect = detect_null.detect_null(dp.ns_length, debug) self.connect(self.input, self.ns_detect) # # fine frequency synchronisation # # the code for fine frequency synchronisation is adapted from # ofdm_sync_ml.py; it abuses the cyclic prefix to find the fine # frequency error, as suggested in "ML Estimation of Timing and # Frequency Offset in OFDM Systems", by Jan-Jaap van de Beek, # Magnus Sandell, Per Ola Börjesson, see # http://www.sm.luth.se/csee/sp/research/report/bsb96r.html self.ffs_delay = gr.delay(gr.sizeof_gr_complex, dp.fft_length) self.ffs_conj = gr.conjugate_cc() self.ffs_mult = gr.multiply_cc() # self.ffs_moving_sum = gr.fir_filter_ccf(1, [1]*dp.cp_length) self.ffs_moving_sum = dab_swig.moving_sum_cc(dp.cp_length) self.ffs_angle = gr.complex_to_arg() self.ffs_angle_scale = gr.multiply_const_ff(1. / dp.fft_length) self.ffs_delay_sample_and_hold = gr.delay( gr.sizeof_char, dp.symbol_length) # sample the value at the end of the symbol .. self.ffs_sample_and_hold = gr.sample_and_hold_ff() self.ffs_delay_input_for_correction = gr.delay( gr.sizeof_gr_complex, dp.symbol_length ) # by delaying the input, we can use the ff offset estimation from the first symbol to correct the first symbol itself self.ffs_nco = gr.frequency_modulator_fc( 1) # ffs_sample_and_hold directly outputs phase error per sample self.ffs_mixer = gr.multiply_cc() # calculate fine frequency error self.connect(self.input, self.ffs_conj, self.ffs_mult) self.connect(self.input, self.ffs_delay, (self.ffs_mult, 1)) self.connect(self.ffs_mult, self.ffs_moving_sum, self.ffs_angle) # only use the value from the first half of the first symbol self.connect(self.ffs_angle, self.ffs_angle_scale, (self.ffs_sample_and_hold, 0)) self.connect(self.ns_detect, self.ffs_delay_sample_and_hold, (self.ffs_sample_and_hold, 1)) # do the correction self.connect(self.ffs_sample_and_hold, self.ffs_nco, (self.ffs_mixer, 0)) self.connect(self.input, self.ffs_delay_input_for_correction, (self.ffs_mixer, 1)) # output - corrected signal and start of DAB frames self.connect(self.ffs_mixer, (self, 0)) self.connect(self.ffs_delay_sample_and_hold, (self, 1)) if debug: self.connect( self.ffs_angle, gr.file_sink(gr.sizeof_float, "debug/ofdm_sync_dab_ffs_angle.dat")) self.connect( self.ffs_sample_and_hold, gr.multiply_const_ff(1. / (dp.T * 2 * pi)), gr.file_sink(gr.sizeof_float, "debug/ofdm_sync_dab_fine_freq_err_f.dat")) self.connect( self.ffs_mixer, gr.file_sink(gr.sizeof_gr_complex, "debug/ofdm_sync_dab_fine_freq_corrected_c.dat"))
def __init__(self, mode, debug=False): """ OFDM time and coarse frequency synchronisation for DAB @param mode DAB mode (1-4) @param debug if True: write data streams out to files """ if mode<1 or mode>4: raise ValueError, "Invalid DAB mode: "+str(mode)+" (modes 1-4 exist)" # get the correct DAB parameters dp = parameters.dab_parameters(mode) rp = parameters.receiver_parameters(mode) gr.hier_block2.__init__(self,"ofdm_sync_dab", gr.io_signature(1, 1, gr.sizeof_gr_complex), # input signature gr.io_signature2(2, 2, gr.sizeof_gr_complex, gr.sizeof_char)) # output signature # workaround for a problem that prevents connecting more than one block directly (see trac ticket #161) self.input = gr.kludge_copy(gr.sizeof_gr_complex) self.connect(self, self.input) # # null-symbol detection # # (outsourced to detect_zero.py) self.ns_detect = detect_null.detect_null(dp.ns_length, debug) self.connect(self.input, self.ns_detect) # # fine frequency synchronisation # # the code for fine frequency synchronisation is adapted from # ofdm_sync_ml.py; it abuses the cyclic prefix to find the fine # frequency error, as suggested in "ML Estimation of Timing and # Frequency Offset in OFDM Systems", by Jan-Jaap van de Beek, # Magnus Sandell, Per Ola Börjesson, see # http://www.sm.luth.se/csee/sp/research/report/bsb96r.html self.ffs_delay = gr.delay(gr.sizeof_gr_complex, dp.fft_length) self.ffs_conj = gr.conjugate_cc() self.ffs_mult = gr.multiply_cc() # self.ffs_moving_sum = gr.fir_filter_ccf(1, [1]*dp.cp_length) self.ffs_moving_sum = dab_swig.moving_sum_cc(dp.cp_length) self.ffs_angle = gr.complex_to_arg() self.ffs_angle_scale = gr.multiply_const_ff(1./dp.fft_length) self.ffs_delay_sample_and_hold = gr.delay(gr.sizeof_char, dp.symbol_length) # sample the value at the end of the symbol .. self.ffs_sample_and_hold = gr.sample_and_hold_ff() self.ffs_delay_input_for_correction = gr.delay(gr.sizeof_gr_complex, dp.symbol_length) # by delaying the input, we can use the ff offset estimation from the first symbol to correct the first symbol itself self.ffs_nco = gr.frequency_modulator_fc(1) # ffs_sample_and_hold directly outputs phase error per sample self.ffs_mixer = gr.multiply_cc() # calculate fine frequency error self.connect(self.input, self.ffs_conj, self.ffs_mult) self.connect(self.input, self.ffs_delay, (self.ffs_mult, 1)) self.connect(self.ffs_mult, self.ffs_moving_sum, self.ffs_angle) # only use the value from the first half of the first symbol self.connect(self.ffs_angle, self.ffs_angle_scale, (self.ffs_sample_and_hold, 0)) self.connect(self.ns_detect, self.ffs_delay_sample_and_hold, (self.ffs_sample_and_hold, 1)) # do the correction self.connect(self.ffs_sample_and_hold, self.ffs_nco, (self.ffs_mixer, 0)) self.connect(self.input, self.ffs_delay_input_for_correction, (self.ffs_mixer, 1)) # output - corrected signal and start of DAB frames self.connect(self.ffs_mixer, (self, 0)) self.connect(self.ffs_delay_sample_and_hold, (self, 1)) if debug: self.connect(self.ffs_angle, gr.file_sink(gr.sizeof_float, "debug/ofdm_sync_dab_ffs_angle.dat")) self.connect(self.ffs_sample_and_hold, gr.multiply_const_ff(1./(dp.T*2*pi)), gr.file_sink(gr.sizeof_float, "debug/ofdm_sync_dab_fine_freq_err_f.dat")) self.connect(self.ffs_mixer, gr.file_sink(gr.sizeof_gr_complex, "debug/ofdm_sync_dab_fine_freq_corrected_c.dat"))