def __init__(self, samplerate, bits_per_sec, fftlen): gr.hier_block2.__init__( self, "gmsk_sync", gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature gr.io_signature(1, 1, gr.sizeof_gr_complex)) # Output signature #this is just the old square-and-fft method #ais.freqest is simply looking for peaks spaced bits-per-sec apart self.square = gr.multiply_cc(1) self.fftvect = gr.stream_to_vector(gr.sizeof_gr_complex, fftlen) self.fft = gr.fft_vcc(fftlen, True, window.rectangular(fftlen), True) self.freqest = ais.freqest(int(samplerate), int(bits_per_sec), fftlen) self.repeat = gr.repeat(gr.sizeof_float, fftlen) self.fm = gr.frequency_modulator_fc(-1.0 / (float(samplerate) / (2 * pi))) self.mix = gr.multiply_cc(1) self.connect(self, (self.square, 0)) self.connect(self, (self.square, 1)) #this is the feedforward branch self.connect(self, (self.mix, 0)) #this is the feedback branch self.connect(self.square, self.fftvect, self.fft, self.freqest, self.repeat, self.fm, (self.mix, 1)) #and this is the output self.connect(self.mix, self)
def __init__ ( self, noise_power, coherence_time, taps ): gr.hier_block2.__init__(self, "fading_channel", gr.io_signature( 1, 1, gr.sizeof_gr_complex ), gr.io_signature( 1, 1, gr.sizeof_gr_complex ) ) inp = gr.kludge_copy( gr.sizeof_gr_complex ) self.connect( self, inp ) tap1_delay = gr.delay( gr.sizeof_gr_complex, 1 ) tap2_delay = gr.delay( gr.sizeof_gr_complex, 2 ) self.connect( inp, tap1_delay ) self.connect( inp, tap2_delay ) fd = 100 z = numpy.arange(-fd+0.1,fd,0.1) t = numpy.sqrt(1. / ( pi * fd * numpy.sqrt( 1. - (z/fd)**2 ) ) ) tap1_noise = ofdm.complex_white_noise( 0.0, taps[0] ) tap1_filter = gr.fft_filter_ccc(1, t) self.connect( tap1_noise, tap1_filter ) tap1_mult = gr.multiply_cc() self.connect( tap1_filter, (tap1_mult,0) ) self.connect( tap1_delay, (tap1_mult,1) ) tap2_noise = ofdm.complex_white_noise( 0.0, taps[1] ) tap2_filter = gr.fft_filter_ccc(1, t) self.connect( tap2_noise, tap2_filter ) tap2_mult = gr.multiply_cc() self.connect( tap2_filter, (tap2_mult,0) ) self.connect( tap2_delay, (tap2_mult,1) ) noise_src = ofdm.complex_white_noise( 0.0, sqrt( noise_power ) ) chan = gr.add_cc() self.connect( inp, (chan,0) ) self.connect( tap1_mult, (chan,1) ) self.connect( tap2_mult, (chan,2) ) self.connect( noise_src, (chan,3) ) self.connect( chan, self ) log_to_file( self, tap1_filter, "data/tap1_filter.compl") log_to_file( self, tap1_filter, "data/tap1_filter.float", mag=True) log_to_file( self, tap2_filter, "data/tap2_filter.compl") log_to_file( self, tap2_filter, "data/tap2_filter.float", mag=True)
def __init__(self, noise_power, coherence_time, taps): gr.hier_block2.__init__(self, "fading_channel", gr.io_signature(1, 1, gr.sizeof_gr_complex), gr.io_signature(1, 1, gr.sizeof_gr_complex)) inp = gr.kludge_copy(gr.sizeof_gr_complex) self.connect(self, inp) tap1_delay = gr.delay(gr.sizeof_gr_complex, 1) tap2_delay = gr.delay(gr.sizeof_gr_complex, 2) self.connect(inp, tap1_delay) self.connect(inp, tap2_delay) fd = 100 z = numpy.arange(-fd + 0.1, fd, 0.1) t = numpy.sqrt(1. / (pi * fd * numpy.sqrt(1. - (z / fd)**2))) tap1_noise = ofdm.complex_white_noise(0.0, taps[0]) tap1_filter = gr.fft_filter_ccc(1, t) self.connect(tap1_noise, tap1_filter) tap1_mult = gr.multiply_cc() self.connect(tap1_filter, (tap1_mult, 0)) self.connect(tap1_delay, (tap1_mult, 1)) tap2_noise = ofdm.complex_white_noise(0.0, taps[1]) tap2_filter = gr.fft_filter_ccc(1, t) self.connect(tap2_noise, tap2_filter) tap2_mult = gr.multiply_cc() self.connect(tap2_filter, (tap2_mult, 0)) self.connect(tap2_delay, (tap2_mult, 1)) noise_src = ofdm.complex_white_noise(0.0, sqrt(noise_power)) chan = gr.add_cc() self.connect(inp, (chan, 0)) self.connect(tap1_mult, (chan, 1)) self.connect(tap2_mult, (chan, 2)) self.connect(noise_src, (chan, 3)) self.connect(chan, self) log_to_file(self, tap1_filter, "data/tap1_filter.compl") log_to_file(self, tap1_filter, "data/tap1_filter.float", mag=True) log_to_file(self, tap2_filter, "data/tap2_filter.compl") log_to_file(self, tap2_filter, "data/tap2_filter.float", mag=True)
def __init__(self, filename, lo_freq, audio_rate, if_rate): gr.hier_block2.__init__(self, "pipeline", gr.io_signature(0, 0, 0), gr.io_signature(1, 1, gr.sizeof_gr_complex)) try: src = gr.file_source (gr.sizeof_float, filename, True) except RuntimeError: sys.stderr.write(("\nError: Could not open file '%s'\n\n" % \ filename)) sys.exit(1) print audio_rate, if_rate fmtx = blks2.nbfm_tx (audio_rate, if_rate, max_dev=5e3, tau=75e-6) # Local oscillator lo = gr.sig_source_c (if_rate, # sample rate gr.GR_SIN_WAVE, # waveform type lo_freq, #frequency 1.0, # amplitude 0) # DC Offset mixer = gr.multiply_cc () self.connect (src, fmtx, (mixer, 0)) self.connect (lo, (mixer, 1)) self.connect (mixer, self)
def test_002_freq (self): """ Add a fine frequency offset and see if that get's detected properly """ fft_len = 32 cp_len = 4 # This frequency offset is normalized to rads, i.e. \pi == f_s/2 max_freq_offset = 2*numpy.pi/fft_len # Otherwise, it's coarse freq_offset = ((2 * random.random()) - 1) * max_freq_offset sig_len = (fft_len + cp_len) * 10 sync_symbol = [(random.randint(0, 1)*2)-1 for x in range(fft_len/2)] * 2 tx_signal = sync_symbol[-cp_len:] + \ sync_symbol + \ [(random.randint(0, 1)*2)-1 for x in range(sig_len)] mult = gr.multiply_cc() add = gr.add_cc() sync = digital.ofdm_sync_sc_cfb(fft_len, cp_len, True) channel = gr.channel_model(0.005, freq_offset / 2.0 / numpy.pi) sink_freq = gr.vector_sink_f() sink_detect = gr.vector_sink_b() self.tb.connect(gr.vector_source_c(tx_signal), channel, sync) self.tb.connect((sync, 0), sink_freq) self.tb.connect((sync, 1), sink_detect) self.tb.run() phi_hat = sink_freq.data()[sink_detect.data().index(1)] est_freq_offset = 2 * phi_hat / fft_len self.assertAlmostEqual(est_freq_offset, freq_offset, places=2)
def __init__(self): gr.top_block.__init__(self) parser = OptionParser(option_class=eng_option) parser.add_option("-c", "--calibration", type="eng_float", default=0, help="freq offset") parser.add_option("-g", "--gain", type="eng_float", default=1) parser.add_option("-i", "--input-file", type="string", default="in.dat", help="specify the input file") parser.add_option("-o", "--output-file", type="string", default="out.dat", help="specify the output file") parser.add_option("-r", "--new-sample-rate", type="int", default=96000, help="output sample rate") parser.add_option("-s", "--sample-rate", type="int", default=48000, help="input sample rate") (options, args) = parser.parse_args() sample_rate = options.sample_rate new_sample_rate = options.new_sample_rate IN = gr.file_source(gr.sizeof_gr_complex, options.input_file) OUT = gr.file_sink(gr.sizeof_gr_complex, options.output_file) LO = gr.sig_source_c(sample_rate, gr.GR_COS_WAVE, options.calibration, 1.0, 0) MIXER = gr.multiply_cc() AMP = gr.multiply_const_cc(options.gain) nphases = 32 frac_bw = 0.05 p1 = frac_bw p2 = frac_bw rs_taps = gr.firdes.low_pass(nphases, nphases, p1, p2) #RESAMP = blks2.pfb_arb_resampler_ccf(float(sample_rate) / float(new_sample_rate), (rs_taps), nphases, ) RESAMP = blks2.pfb_arb_resampler_ccf(float(new_sample_rate) / float(sample_rate), (rs_taps), nphases, ) self.connect(IN, (MIXER, 0)) self.connect(LO, (MIXER, 1)) self.connect(MIXER, AMP, RESAMP, OUT)
def test_002_freq (self): """ Add a fine frequency offset and see if that get's detected properly """ fft_len = 32 cp_len = 4 freq_offset = 0.1 # Must stay < 2*pi/fft_len = 0.196 (otherwise, it's coarse) sig_len = (fft_len + cp_len) * 10 sync_symbol = [(random.randint(0, 1)*2)-1 for x in range(fft_len/2)] * 2 tx_signal = sync_symbol[-cp_len:] + \ sync_symbol + \ [(random.randint(0, 1)*2)-1 for x in range(sig_len)] mult = gr.multiply_cc() add = gr.add_cc() sync = digital.ofdm_sync_sc_cfb(fft_len, cp_len) sink_freq = gr.vector_sink_f() sink_detect = gr.vector_sink_b() self.tb.connect(gr.vector_source_c(tx_signal), (mult, 0), (add, 0)) self.tb.connect(gr.sig_source_c(2 * numpy.pi, gr.GR_SIN_WAVE, freq_offset, 1.0), (mult, 1)) self.tb.connect(gr.noise_source_c(gr.GR_GAUSSIAN, .01), (add, 1)) self.tb.connect(add, sync) self.tb.connect((sync, 0), sink_freq) self.tb.connect((sync, 1), sink_detect) self.tb.run() phi_hat = sink_freq.data()[sink_detect.data().index(1)] est_freq_offset = 2 * phi_hat / fft_len self.assertAlmostEqual(est_freq_offset, freq_offset, places=2)
def __init__(self, sample_rate, noise_voltage, frequency_offset, seed=False): gr.hier_block2.__init__(self, "awgn_channel", gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature gr.io_signature(1, 1, gr.sizeof_gr_complex)) # Output signature # Create the Gaussian noise source if not seed: self.noise = gr.noise_source_c(gr.GR_GAUSSIAN, noise_voltage) else: rseed = int(time.time()) self.noise = gr.noise_source_c(gr.GR_GAUSSIAN, noise_voltage, rseed) self.adder = gr.add_cc() # Create the frequency offset self.offset = gr.sig_source_c(1, gr.GR_SIN_WAVE, frequency_offset, 1.0, 0.0) self.mixer = gr.multiply_cc() # Connect the components self.connect(self, (self.mixer, 0)) self.connect(self.offset, (self.mixer, 1)) self.connect(self.mixer, (self.adder, 0)) self.connect(self.noise, (self.adder, 1)) self.connect(self.adder, self)
def __init__(self, noise_voltage=0.0, frequency_offset=0.0, epsilon=1.0, taps=[1.0,0.0], noise_seed=3021): ''' Creates a channel model that includes: - AWGN noise power in terms of noise voltage - A frequency offest in the channel in ratio - A timing offset ratio to model clock difference (epsilon) - Multipath taps ''' gr.hier_block2.__init__(self, "channel_model", gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature gr.io_signature(1, 1, gr.sizeof_gr_complex)) # Output signature #print epsilon self.timing_offset = gr.fractional_interpolator_cc(0, epsilon) self.multipath = gr.fir_filter_ccc(1, taps) self.noise_adder = gr.add_cc() self.noise = gr.noise_source_c(gr.GR_GAUSSIAN, noise_voltage, noise_seed) self.freq_offset = gr.sig_source_c(1, gr.GR_SIN_WAVE, frequency_offset, 1.0, 0.0) self.mixer_offset = gr.multiply_cc() self.connect(self, self.timing_offset, self.multipath) self.connect(self.multipath, (self.mixer_offset,0)) self.connect(self.freq_offset,(self.mixer_offset,1)) self.connect(self.mixer_offset, (self.noise_adder,1)) self.connect(self.noise, (self.noise_adder,0)) self.connect(self.noise_adder, self)
def build_graph (input, raw, snr, freq_offset, coeffs, mag): # Initialize empty flow graph fg = gr.top_block () # Set up file source src = gr.file_source (1, input) # Set up GMSK modulator, 2 samples per symbol mod = gmsk_mod(2) # Amplify the signal tx_amp = 1 amp = gr.multiply_const_cc(1) amp.set_k(tx_amp) # Compute proper noise voltage based on SNR SNR = 10.0**(snr/10.0) power_in_signal = abs(tx_amp)**2 noise_power = power_in_signal/SNR noise_voltage = math.sqrt(noise_power) # Generate noise rseed = int(time.time()) noise = gr.noise_source_c(gr.GR_GAUSSIAN, noise_voltage, rseed) adder = gr.add_cc() fg.connect(noise, (adder, 1)) # Create the frequency offset, 0 for now offset = gr.sig_source_c(1, gr.GR_SIN_WAVE, freq_offset, 1.0, 0.0) mixer = gr.multiply_cc() fg.connect(offset, (mixer, 1)) # Pass the noisy data to the matched filter dfile = open(coeffs, 'r') data = [] for line in dfile: data.append(complex(*map(float,line.strip().strip("()").split(" "))).conjugate()) dfile.close() data.reverse() mfilter = gr.fir_filter_ccc(1, data) # Connect the flow graph fg.connect(src, mod) fg.connect(mod, (mixer, 0)) fg.connect(mixer, (adder, 0)) if mag: raw_dst = gr.file_sink (gr.sizeof_float, raw) magnitude = gr.complex_to_mag(1) fg.connect(adder, mfilter, magnitude, raw_dst) else: raw_dst = gr.file_sink (gr.sizeof_gr_complex, raw) fg.connect(adder, mfilter, raw_dst) print "SNR(db): " + str(snr) print "Frequency Offset: " + str(freq_offset) return fg
def __init__(self, fftl): """ docstring """ gr.hier_block2.__init__(self, "hier_freq_estimate_cc", gr.io_signature(1,1, gr.sizeof_gr_complex), # Input signature gr.io_signature(1,1, gr.sizeof_gr_complex)) # Output signature # Define blocks waveform = gr.GR_COS_WAVE wave_freq = 0.0 ampl = 1.0 offset = 0.0 cpl = 144 * fftl / 2048 cpl0 = 160 * fftl / 2048 slotl = 7 * fftl + 6 * cpl + cpl0 samp_rate = slotl / 0.0005 #print fftl #print cpl #print cpl0 #print slotl #print samp_rate self.sig = gr.sig_source_c(samp_rate, waveform,wave_freq,ampl,offset) self.multi = gr.multiply_cc(1) self.est = lte_swig.freq_estimate_c(self.sig,fftl) self.connect(self,(self.multi,0),self) self.connect(self.sig,(self.multi,1) ) self.connect(self.multi,self.est )
def __init__(self, port, gain, usrp_rate, lo_freq): gr.hier_block2.__init__(self, "tx_channel_usrp", gr.io_signature(0, 0, 0), gr.io_signature(1, 1, gr.sizeof_gr_complex)) msg_queue = gr.msg_queue(2) do_imbe = 1 do_float = 0 do_complex = 1 decim = MAX_COMPLEX_RATE / usrp_rate # per-channel GR source block including these steps: # - receive audio chunks from asterisk via UDP # - imbe encode # - generate phase-modulated complex output stream (table lookup method) # - generates no power while no input received self.chan = repeater.chan_usrp(port, do_imbe, do_complex, do_float, gain, int(decim), msg_queue) # Local oscillator lo = gr.sig_source_c( usrp_rate, # sample rate gr.GR_SIN_WAVE, # waveform type lo_freq, #frequency 1.0, # amplitude 0) # DC Offset self.mixer = gr.multiply_cc() self.connect(self.chan, (self.mixer, 0)) self.connect(lo, (self.mixer, 1)) self.connect(self.mixer, self)
def __init__(self, port, gain, usrp_rate, lo_freq): gr.hier_block2.__init__(self, "tx_channel_usrp", gr.io_signature(0, 0, 0), gr.io_signature(1, 1, gr.sizeof_gr_complex)) msg_queue = gr.msg_queue(2) do_imbe = 1 do_float = 0 do_complex = 1 decim = MAX_COMPLEX_RATE / usrp_rate # per-channel GR source block including these steps: # - receive audio chunks from asterisk via UDP # - imbe encode # - generate phase-modulated complex output stream (table lookup method) # - generates no power while no input received self.chan = repeater.chan_usrp(port, do_imbe, do_complex, do_float, gain, int(decim), msg_queue) # Local oscillator lo = gr.sig_source_c (usrp_rate, # sample rate gr.GR_SIN_WAVE, # waveform type lo_freq, #frequency 1.0, # amplitude 0) # DC Offset self.mixer = gr.multiply_cc () self.connect (self.chan, (self.mixer, 0)) self.connect (lo, (self.mixer, 1)) self.connect (self.mixer, self)
def test_002_freq(self): """ Add a fine frequency offset and see if that get's detected properly """ fft_len = 32 cp_len = 4 # This frequency offset is normalized to rads, i.e. \pi == f_s/2 max_freq_offset = 2 * numpy.pi / fft_len # Otherwise, it's coarse freq_offset = ((2 * random.random()) - 1) * max_freq_offset sig_len = (fft_len + cp_len) * 10 sync_symbol = [(random.randint(0, 1) * 2) - 1 for x in range(fft_len / 2)] * 2 tx_signal = sync_symbol[-cp_len:] + \ sync_symbol + \ [(random.randint(0, 1)*2)-1 for x in range(sig_len)] mult = gr.multiply_cc() add = gr.add_cc() sync = digital.ofdm_sync_sc_cfb(fft_len, cp_len, True) channel = gr.channel_model(0.005, freq_offset / 2.0 / numpy.pi) sink_freq = gr.vector_sink_f() sink_detect = gr.vector_sink_b() self.tb.connect(gr.vector_source_c(tx_signal), channel, sync) self.tb.connect((sync, 0), sink_freq) self.tb.connect((sync, 1), sink_detect) self.tb.run() phi_hat = sink_freq.data()[sink_detect.data().index(1)] est_freq_offset = 2 * phi_hat / fft_len self.assertAlmostEqual(est_freq_offset, freq_offset, places=2)
def __init__(self, fft_length, pn_weights): gr.hier_block2.__init__(self, "modified_timing_metric", gr.io_signature(1,1,gr.sizeof_gr_complex), gr.io_signature(1,1,gr.sizeof_float)) assert(len(pn_weights) == fft_length) self.input = gr.kludge_copy(gr.sizeof_gr_complex) self.connect(self,self.input) # P(d) = sum(0 to L-1, conj(delayed(r)) * r) conj = gr.conjugate_cc() mixer = gr.multiply_cc() nominator = gr.fir_filter_ccf(1,[pn_weights[fft_length-i-1]*pn_weights[fft_length/2-i-1] for i in range(fft_length/2)]) self.connect(self.input, delay(gr.sizeof_gr_complex,fft_length/2), conj, (mixer,0)) self.connect(self.input, (mixer,1)) self.connect(mixer, nominator) # moving_avg = P(d) # R(d) denominator = schmidl_denominator(fft_length) # |P(d)| ** 2 / (R(d)) ** 2 p_mag_sqrd = gr.complex_to_mag_squared() r_sqrd = gr.multiply_ff() self.timing_metric = gr.divide_ff() self.connect(nominator, p_mag_sqrd, (self.timing_metric,0)) self.connect(self.input, denominator, (r_sqrd,0)) self.connect(denominator, (r_sqrd,1)) self.connect(r_sqrd, (self.timing_metric,1)) self.connect(self.timing_metric, self)
def __init__(self, vocoder, lo_freq, audio_rate, if_rate): gr.hier_block2.__init__(self, "pipeline", gr.io_signature(0, 0, 0), # Input signature gr.io_signature(1, 1, gr.sizeof_gr_complex)) # Output signature c4fm = op25_c4fm_mod.p25_mod_bf(output_sample_rate=audio_rate, log=False, verbose=True) interp_factor = if_rate / audio_rate low_pass = 2.88e3 interp_taps = gr.firdes.low_pass(1.0, if_rate, low_pass, low_pass * 0.1, gr.firdes.WIN_HANN) interpolator = gr.interp_fir_filter_fff (int(interp_factor), interp_taps) max_dev = 12.5e3 k = 2 * math.pi * max_dev / if_rate adjustment = 1.5 # adjust for proper c4fm deviation level modulator = gr.frequency_modulator_fc (k * adjustment) # Local oscillator lo = gr.sig_source_c (if_rate, # sample rate gr.GR_SIN_WAVE, # waveform type lo_freq, #frequency 1.0, # amplitude 0) # DC Offset mixer = gr.multiply_cc () self.connect (vocoder, c4fm, interpolator, modulator, (mixer, 0)) self.connect (lo, (mixer, 1)) self.connect (mixer, self)
def __init__(self, fg, noise_voltage=0.0, frequency_offset=0.0, epsilon=1.0, taps=[1.0,0.0]): ''' Creates a channel model that includes: - AWGN noise power in terms of noise voltage - A frequency offest in the channel in ratio - A timing offset ratio to model clock difference (epsilon) - Multipath taps ''' print epsilon self.timing_offset = gr.fractional_interpolator_cc(0, epsilon) self.multipath = gr.fir_filter_ccc(1, taps) self.noise_adder = gr.add_cc() self.noise = gr.noise_source_c(gr.GR_GAUSSIAN,noise_voltage) self.freq_offset = gr.sig_source_c(1, gr.GR_SIN_WAVE, frequency_offset, 1.0, 0.0) self.mixer_offset = gr.multiply_cc() fg.connect(self.timing_offset, self.multipath) fg.connect(self.multipath, (self.mixer_offset,0)) fg.connect(self.freq_offset,(self.mixer_offset,1)) fg.connect(self.mixer_offset, (self.noise_adder,1)) fg.connect(self.noise, (self.noise_adder,0)) gr.hier_block.__init__(self, fg, self.timing_offset, self.noise_adder)
def test_mult_cc (self): src1_data = (1+1j, 2+2j, 3+3j, 4+4j, 5+5j) src2_data = (8, -3, 4, 8, 2) expected_result = (8+8j, -6-6j, 12+12j, 32+32j, 10+10j) op = gr.multiply_cc () self.help_cc ((src1_data, src2_data), expected_result, op)
def __init__(self): gr.hier_block2.__init__( self, "s", gr.io_signature(2, 2, gr.sizeof_gr_complex), gr.io_signature(1, 1, gr.sizeof_gr_complex)) conj = gr.conjugate_cc() mult = gr.multiply_cc() self.connect((self, 0), (mult, 0)) self.connect((self, 1), conj, (mult, 1)) self.connect(mult, self)
def __init__(self): gr.hier_block2.__init__(self, "s", gr.io_signature(2, 2, gr.sizeof_gr_complex), gr.io_signature(1, 1, gr.sizeof_gr_complex)) conj = gr.conjugate_cc() mult = gr.multiply_cc() self.connect((self,0), (mult,0)) self.connect((self,1), conj, (mult,1)) self.connect(mult, self)
def test_mult_cc (self): # Note: the GNUHawk multiply_ff only outputs data in multiples of 8, # so this test has been modified accordingly src1_data = (1+1j, 2+2j, 3+3j, 4+4j, 5+5j, 6+6j, 7+7j, 8+8j) src2_data = ( complex(8), complex(-3), complex(4), complex(8), complex(2), complex(1), complex(2), complex(5) ) expected_result = (8+8j, -6-6j, 12+12j, 32+32j, 10+10j, 6+6j, 14+14j, 40+40j ) op = gr.multiply_cc () self.help_cc ((src1_data, src2_data), expected_result, op)
def __init__(self, fd, M, sample_rate): gr.hier_block2.__init__(self, "Rayleigh Channel", gr.io_signature(1, 1, gr.sizeof_gr_complex), gr.io_signature(1, 1, gr.sizeof_gr_complex)) self.M = M self.sample_rate = sample_rate n = range(1, M + 1) N = 4 * M + 2 f_n = [fd * math.cos(2 * math.pi * x / N) for x in n] beta_n = [math.pi / M * x for x in n] a_n = [2 * math.cos(x) for x in beta_n] a_n.append(math.sqrt(2) * math.cos(math.pi / 4)) a_n = [x * 2 / math.sqrt(N) for x in a_n] b_n = [2 * math.sin(x) for x in beta_n] b_n.append(math.sqrt(2) * math.sin(math.pi / 4)) b_n = [x * 2 / math.sqrt(N) for x in b_n] f_n.append(fd) self.sin_real = [ gr.sig_source_f(self.sample_rate, gr.GR_COS_WAVE, f_n[i], a_n[i]) for i in range(M + 1) ] self.sin_imag = [ gr.sig_source_f(self.sample_rate, gr.GR_COS_WAVE, f_n[i], b_n[i]) for i in range(M + 1) ] self.add_real = gr.add_ff(1) self.add_imag = gr.add_ff(1) for i in range(M + 1): self.connect(self.sin_real[i], (self.add_real, i)) for i in range(M + 1): self.connect(self.sin_imag[i], (self.add_imag, i)) self.ftoc = gr.float_to_complex(1) self.connect(self.add_real, (self.ftoc, 0)) self.connect(self.add_imag, (self.ftoc, 1)) self.mulc = gr.multiply_const_cc((0.5)) #self.divide = gr.divide_cc(1) #self.connect(self,(self.divide,0)) #self.connect(self.ftoc,(self.divide,1)) #self.connect(self.divide, self) self.prod = gr.multiply_cc(1) self.connect(self, (self.prod, 0)) self.connect(self.ftoc, self.mulc, (self.prod, 1)) self.connect(self.prod, self)
def test_mult_cc(self): # Note: the GNUHawk multiply_ff only outputs data in multiples of 8, # so this test has been modified accordingly src1_data = (1 + 1j, 2 + 2j, 3 + 3j, 4 + 4j, 5 + 5j, 6 + 6j, 7 + 7j, 8 + 8j) src2_data = (complex(8), complex(-3), complex(4), complex(8), complex(2), complex(1), complex(2), complex(5)) expected_result = (8 + 8j, -6 - 6j, 12 + 12j, 32 + 32j, 10 + 10j, 6 + 6j, 14 + 14j, 40 + 40j) op = gr.multiply_cc() self.help_cc((src1_data, src2_data), expected_result, op)
def __init__(self,fd,M,sample_rate): gr.hier_block2.__init__(self,"Rayleigh Channel", gr.io_signature(1,1,gr.sizeof_gr_complex), gr.io_signature(1,1,gr.sizeof_gr_complex)) self.M = M self.sample_rate = sample_rate n=range(1,M+1) N = 4*M+2 f_n= [fd*math.cos(2*math.pi*x/N) for x in n] beta_n = [math.pi/M*x for x in n] a_n = [2*math.cos(x) for x in beta_n] a_n.append(math.sqrt(2)*math.cos(math.pi/4)) a_n = [x*2/math.sqrt(N) for x in a_n] b_n= [2*math.sin(x) for x in beta_n] b_n.append(math.sqrt(2)*math.sin(math.pi/4)) b_n = [x*2/math.sqrt(N) for x in b_n] f_n.append(fd) self.sin_real = [gr.sig_source_f(self.sample_rate,gr.GR_COS_WAVE,f_n[i],a_n[i]) for i in range(M+1)] self.sin_imag = [gr.sig_source_f(self.sample_rate,gr.GR_COS_WAVE,f_n[i],b_n[i]) for i in range(M+1)] self.add_real = gr.add_ff(1) self.add_imag = gr.add_ff(1) for i in range (M+1): self.connect(self.sin_real[i],(self.add_real,i)) for i in range (M+1): self.connect(self.sin_imag[i],(self.add_imag,i)) self.ftoc = gr.float_to_complex(1) self.connect(self.add_real,(self.ftoc,0)) self.connect(self.add_imag,(self.ftoc,1)) self.mulc = gr.multiply_const_cc((0.5)) #self.divide = gr.divide_cc(1) #self.connect(self,(self.divide,0)) #self.connect(self.ftoc,(self.divide,1)) #self.connect(self.divide, self) self.prod = gr.multiply_cc(1) self.connect(self,(self.prod,0)) self.connect(self.ftoc,self.mulc,(self.prod,1)) self.connect(self.prod, self)
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, frame, panel, vbox, argv): stdgui2.std_top_block.__init__(self, frame, panel, vbox, argv) parser = OptionParser (option_class=eng_option) (options, args) = parser.parse_args () sample_rate = 16e3 mpoints = 4 ampl = 1000 freq = 0 lo_freq = 1e6 lo_ampl = 1 vbox.Add(slider.slider(panel, -sample_rate/2, sample_rate/2, self.set_lo_freq), 0, wx.ALIGN_CENTER) src = gr.sig_source_c(sample_rate, gr.GR_CONST_WAVE, freq, ampl, 0) self.lo = gr.sig_source_c(sample_rate, gr.GR_SIN_WAVE, lo_freq, lo_ampl, 0) mixer = gr.multiply_cc() self.connect(src, (mixer, 0)) self.connect(self.lo, (mixer, 1)) # We add these throttle blocks so that this demo doesn't # suck down all the CPU available. Normally you wouldn't use these. thr = gr.throttle(gr.sizeof_gr_complex, sample_rate) taps = gr.firdes.low_pass(1, # gain 1, # rate 1.0/mpoints * 0.4, # cutoff 1.0/mpoints * 0.1, # trans width gr.firdes.WIN_HANN) print len(taps) analysis = blks2.analysis_filterbank(mpoints, taps) self.connect(mixer, thr) self.connect(thr, analysis) for i in range(mpoints): fft = fftsink2.fft_sink_c(frame, fft_size=128, sample_rate=sample_rate/mpoints, fft_rate=5, title="Ch %d" % (i,)) self.connect((analysis, i), fft) vbox.Add(fft.win, 1, wx.EXPAND)
def __init__(self, samplerate, bits_per_sec, fftlen): gr.hier_block2.__init__(self, "gmsk_sync", gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature gr.io_signature(1, 1, gr.sizeof_gr_complex)) # Output signature #this is just the old square-and-fft method #ais.freqest is simply looking for peaks spaced bits-per-sec apart self.square = gr.multiply_cc(1) self.fftvect = gr.stream_to_vector(gr.sizeof_gr_complex, fftlen) self.fft = gr.fft_vcc(fftlen, True, window.rectangular(fftlen), True) self.freqest = ais.freqest(int(samplerate), int(bits_per_sec), fftlen) self.repeat = gr.repeat(gr.sizeof_float, fftlen) self.fm = gr.frequency_modulator_fc(-1.0/(float(samplerate)/(2*pi))) self.mix = gr.multiply_cc(1) self.connect(self, (self.square, 0)) self.connect(self, (self.square, 1)) #this is the feedforward branch self.connect(self, (self.mix, 0)) #this is the feedback branch self.connect(self.square, self.fftvect, self.fft, self.freqest, self.repeat, self.fm, (self.mix, 1)) #and this is the output self.connect(self.mix, self)
def test01(self): sps = 4 rolloff = 0.35 bw = 2 * math.pi / 100.0 ntaps = 45 # Create pulse shape filter #rrc_taps = gr.firdes.root_raised_cosine( # sps, sps, 1.0, rolloff, ntaps) rrc_taps = taps # The frequency offset to correct foffset = 0.2 / (2.0 * math.pi) # Create a set of 1's and -1's, pulse shape and interpolate to sps random.seed(0) data = [2.0 * random.randint(0, 2) - 1.0 for i in xrange(200)] self.src = gr.vector_source_c(data, False) self.rrc = gr.interp_fir_filter_ccf(sps, rrc_taps) # Mix symbols with a complex sinusoid to spin them self.nco = gr.sig_source_c(1, gr.GR_SIN_WAVE, foffset, 1) self.mix = gr.multiply_cc() # FLL will despin the symbols to an arbitrary phase self.fll = digital_swig.fll_band_edge_cc(sps, rolloff, ntaps, bw) # Create sinks for all outputs of the FLL # we will only care about the freq and error outputs self.vsnk_frq = gr.vector_sink_f() self.nsnk_fll = gr.null_sink(gr.sizeof_gr_complex) self.nsnk_phs = gr.null_sink(gr.sizeof_float) self.nsnk_err = gr.null_sink(gr.sizeof_float) # Connect the blocks self.tb.connect(self.nco, (self.mix, 1)) self.tb.connect(self.src, self.rrc, (self.mix, 0)) self.tb.connect(self.mix, self.fll, self.nsnk_fll) self.tb.connect((self.fll, 1), self.vsnk_frq) self.tb.connect((self.fll, 2), self.nsnk_phs) self.tb.connect((self.fll, 3), self.nsnk_err) self.tb.run() N = 700 dst_data = self.vsnk_frq.data()[N:] expected_result = len(dst_data) * [ -0.20, ] self.assertFloatTuplesAlmostEqual(expected_result, dst_data, 4)
def __init__(self, noise_voltage, sensitivity): gr.hier_block2.__init__(self, "variable_awgn_channel", gr.io_signature(1,1,gr.sizeof_gr_complex), gr.io_signature(1,1,gr.sizeof_gr_complex)) self.noise_adder = gr.add_cc() self.noise = gr.noise_source_c(gr.GR_GAUSSIAN,noise_voltage) self.noise_amp = gr.multiply_cc() self.offset = gr.frequency_modulator_fc(sensitivity) self.mixer_offset = gr.multiply_cc() self.connect(self, (self.mixer_offset,0)) self.connect(self.offset,(self.mixer_offset,1)) self.connect(self.mixer_offset, (self.noise_adder,1)) self.connect(self.noise, (self.noise_amp,0)) self.connect(self.noise_amp, (self.noise_adder,0)) self.connect(self.noise_adder, self) try: gr.hier_block.update_var_names(self, "var_awgn_channel", vars()) gr.hier_block.update_var_names(self, "var_awgn_channel", vars(self)) except: pass
def test_004_connect (self): """ Advanced test: - Allocator -> IFFT -> Frequency offset -> FFT -> Serializer - FFT does shift (moves DC to middle) - Make sure input == output - Frequency offset is -2 carriers """ fft_len = 8 n_syms = 1 carr_offset = -2 freq_offset = 1.0 / fft_len * carr_offset # Normalized frequency occupied_carriers = ((-2, -1, 1, 2),) pilot_carriers = ((3,),(5,)) pilot_symbols = ((1j,),(-1j,)) tx_data = (1, 1, 1, 1) tag_name = "len" tag = gr.gr_tag_t() tag.offset = 0 tag.key = pmt.pmt_string_to_symbol(tag_name) tag.value = pmt.pmt_from_long(len(tx_data)) offsettag = gr.gr_tag_t() offsettag.offset = 0 offsettag.key = pmt.pmt_string_to_symbol("ofdm_sync_carr_offset") offsettag.value = pmt.pmt_from_long(carr_offset) src = gr.vector_source_c(tx_data, False, 1, (tag, offsettag)) alloc = digital.ofdm_carrier_allocator_cvc(fft_len, occupied_carriers, pilot_carriers, pilot_symbols, tag_name) tx_ifft = fft.fft_vcc(fft_len, False, (1.0/fft_len,)*fft_len) oscillator = gr.sig_source_c(1.0, gr.GR_COS_WAVE, freq_offset, 1.0/fft_len) mixer = gr.multiply_cc() rx_fft = fft.fft_vcc(fft_len, True, (), True) serializer = digital.ofdm_serializer_vcc( alloc, "", 0, "ofdm_sync_carr_offset" ) sink = gr.vector_sink_c() self.tb.connect( src, alloc, tx_ifft, gr.vector_to_stream(gr.sizeof_gr_complex, fft_len), (mixer, 0), gr.stream_to_vector(gr.sizeof_gr_complex, fft_len), rx_fft, serializer, sink ) self.tb.connect(oscillator, (mixer, 1)) self.tb.run () self.assertComplexTuplesAlmostEqual(sink.data(), tx_data, places=5)
def __init__(self, noise_voltage, sensitivity): gr.hier_block2.__init__(self, "variable_awgn_channel", gr.io_signature(1, 1, gr.sizeof_gr_complex), gr.io_signature(1, 1, gr.sizeof_gr_complex)) self.noise_adder = gr.add_cc() self.noise = gr.noise_source_c(gr.GR_GAUSSIAN, noise_voltage) self.noise_amp = gr.multiply_cc() self.offset = gr.frequency_modulator_fc(sensitivity) self.mixer_offset = gr.multiply_cc() self.connect(self, (self.mixer_offset, 0)) self.connect(self.offset, (self.mixer_offset, 1)) self.connect(self.mixer_offset, (self.noise_adder, 1)) self.connect(self.noise, (self.noise_amp, 0)) self.connect(self.noise_amp, (self.noise_adder, 0)) self.connect(self.noise_adder, self) try: gr.hier_block.update_var_names(self, "var_awgn_channel", vars()) gr.hier_block.update_var_names(self, "var_awgn_channel", vars(self)) except: pass
def test01 (self): sps = 4 rolloff = 0.35 bw = 2*math.pi/100.0 ntaps = 45 # Create pulse shape filter #rrc_taps = gr.firdes.root_raised_cosine( # sps, sps, 1.0, rolloff, ntaps) rrc_taps = taps # The frequency offset to correct foffset = 0.2 / (2.0*math.pi) # Create a set of 1's and -1's, pulse shape and interpolate to sps random.seed(0) data = [2.0*random.randint(0, 2) - 1.0 for i in xrange(200)] self.src = gr.vector_source_c(data, False) self.rrc = gr.interp_fir_filter_ccf(sps, rrc_taps) # Mix symbols with a complex sinusoid to spin them self.nco = gr.sig_source_c(1, gr.GR_SIN_WAVE, foffset, 1) self.mix = gr.multiply_cc() # FLL will despin the symbols to an arbitrary phase self.fll = digital_swig.fll_band_edge_cc(sps, rolloff, ntaps, bw) # Create sinks for all outputs of the FLL # we will only care about the freq and error outputs self.vsnk_frq = gr.vector_sink_f() self.nsnk_fll = gr.null_sink(gr.sizeof_gr_complex) self.nsnk_phs = gr.null_sink(gr.sizeof_float) self.nsnk_err = gr.null_sink(gr.sizeof_float) # Connect the blocks self.tb.connect(self.nco, (self.mix,1)) self.tb.connect(self.src, self.rrc, (self.mix,0)) self.tb.connect(self.mix, self.fll, self.nsnk_fll) self.tb.connect((self.fll,1), self.vsnk_frq) self.tb.connect((self.fll,2), self.nsnk_phs) self.tb.connect((self.fll,3), self.nsnk_err) self.tb.run() N = 700 dst_data = self.vsnk_frq.data()[N:] expected_result = len(dst_data)* [-0.20,] self.assertFloatTuplesAlmostEqual (expected_result, dst_data, 4)
def test_004_connect (self): """ Advanced test: - Allocator -> IFFT -> Frequency offset -> FFT -> Serializer - FFT does shift (moves DC to middle) - Make sure input == output - Frequency offset is -2 carriers """ fft_len = 8 n_syms = 2 carr_offset = -2 freq_offset = 2 * numpy.pi * carr_offset / fft_len # If the sampling rate == 1 occupied_carriers = ((1, 2, -2, -1),) pilot_carriers = ((3,),(5,)) pilot_symbols = ((1j,),(-1j,)) tx_data = tuple([numpy.random.randint(0, 10) for x in range(4 * n_syms)]) #tx_data = (1,) * occupied_carriers[0] * n_syms tag_name = "len" tag = gr.gr_tag_t() tag.offset = 0 tag.key = pmt.pmt_string_to_symbol(tag_name) tag.value = pmt.pmt_from_long(len(tx_data)) offsettag = gr.gr_tag_t() offsettag.offset = 0 offsettag.key = pmt.pmt_string_to_symbol("ofdm_sync_carr_offset") offsettag.value = pmt.pmt_from_long(carr_offset) src = gr.vector_source_c(tx_data, False, 1, (tag, offsettag)) alloc = digital.ofdm_carrier_allocator_cvc(fft_len, occupied_carriers, pilot_carriers, pilot_symbols, tag_name) tx_ifft = fft.fft_vcc(fft_len, False, ()) offset_sig = gr.sig_source_c(1.0, gr.GR_COS_WAVE, freq_offset, 1.0) mixer = gr.multiply_cc() rx_fft = fft.fft_vcc(fft_len, True, (), True) serializer = digital.ofdm_serializer_vcc(alloc) sink = gr.vector_sink_c() self.tb.connect( src, alloc, tx_ifft, gr.vector_to_stream(gr.sizeof_gr_complex, fft_len), (mixer, 0), gr.stream_to_vector(gr.sizeof_gr_complex, fft_len), rx_fft, serializer, sink ) self.tb.connect(offset_sig, (mixer, 1)) self.tb.run ()
def test_004_connect(self): """ Advanced test: - Allocator -> IFFT -> Frequency offset -> FFT -> Serializer - FFT does shift (moves DC to middle) - Make sure input == output - Frequency offset is -2 carriers """ fft_len = 8 n_syms = 1 carr_offset = -2 freq_offset = 1.0 / fft_len * carr_offset # Normalized frequency occupied_carriers = ((-2, -1, 1, 2), ) pilot_carriers = ((3, ), (5, )) pilot_symbols = ((1j, ), (-1j, )) tx_data = (1, 1, 1, 1) tag_name = "len" tag = gr.gr_tag_t() tag.offset = 0 tag.key = pmt.pmt_string_to_symbol(tag_name) tag.value = pmt.pmt_from_long(len(tx_data)) offsettag = gr.gr_tag_t() offsettag.offset = 0 offsettag.key = pmt.pmt_string_to_symbol("ofdm_sync_carr_offset") offsettag.value = pmt.pmt_from_long(carr_offset) src = gr.vector_source_c(tx_data, False, 1, (tag, offsettag)) alloc = digital.ofdm_carrier_allocator_cvc(fft_len, occupied_carriers, pilot_carriers, pilot_symbols, tag_name) tx_ifft = fft.fft_vcc(fft_len, False, (1.0 / fft_len, ) * fft_len) oscillator = gr.sig_source_c(1.0, gr.GR_COS_WAVE, freq_offset, 1.0 / fft_len) mixer = gr.multiply_cc() rx_fft = fft.fft_vcc(fft_len, True, (), True) serializer = digital.ofdm_serializer_vcc(alloc, "", 0, "ofdm_sync_carr_offset") sink = gr.vector_sink_c() self.tb.connect(src, alloc, tx_ifft, gr.vector_to_stream(gr.sizeof_gr_complex, fft_len), (mixer, 0), gr.stream_to_vector(gr.sizeof_gr_complex, fft_len), rx_fft, serializer, sink) self.tb.connect(oscillator, (mixer, 1)) self.tb.run() self.assertComplexTuplesAlmostEqual(sink.data(), tx_data, places=5)
def test_100(self): vlen = 256 N = int( 5e5 ) soff=40 taps = [1.0,0.0,2e-1+0.1j,1e-4-0.04j] freqoff = 0.0 snr_db = 10 rms_amplitude = 8000 data = [1 + 1j] * vlen #data2 = [2] * vlen src = gr.vector_source_c( data, True, vlen ) v2s = gr.vector_to_stream(gr.sizeof_gr_complex,vlen) #interp = gr.fractional_interpolator_cc(0.0,soff) interp = moms(1000000,1000000+soff) fad_chan = gr.fir_filter_ccc(1,taps) freq_shift = gr.multiply_cc() norm_freq = freqoff / vlen freq_off_src = gr.sig_source_c(1.0, gr.GR_SIN_WAVE, norm_freq, 1.0, 0.0 ) snr = 10.0**(snr_db/10.0) noise_sigma = sqrt( rms_amplitude**2 / snr) awgn_chan = gr.add_cc() awgn_noise_src = ofdm.complex_white_noise( 0.0, noise_sigma ) dst = gr.null_sink( gr.sizeof_gr_complex ) limit = gr.head( gr.sizeof_gr_complex * vlen, N ) self.tb.connect( src, limit, v2s, interp, fad_chan,freq_shift, awgn_chan, dst ) self.tb.connect( freq_off_src,(freq_shift,1)) self.tb.connect( awgn_noise_src,(awgn_chan,1)) r = time_it( self.tb ) print "Rate: %s Samples/second" \ % eng_notation.num_to_str( float(N) * vlen / r )
def __init__(self, lo_freq, audio_rate, if_rate): gr.hier_block2.__init__(self, "build_fm", gr.io_signature(1, 1, gr.sizeof_float), # Input signature gr.io_signature(1, 1, gr.sizeof_gr_complex)) # Output signature fmtx = blks2.nbfm_tx (audio_rate, if_rate, max_dev=5e3, tau=75e-6) # Local oscillator lo = gr.sig_source_c (if_rate, # sample rate gr.GR_SIN_WAVE, # waveform type lo_freq, #frequency 1.0, # amplitude 0) # DC Offset mixer = gr.multiply_cc () self.connect (self, fmtx, (mixer, 0)) self.connect (lo, (mixer, 1)) self.connect (mixer, self)
def test_100(self): vlen = 256 N = int(5e5) soff = 40 taps = [1.0, 0.0, 2e-1 + 0.1j, 1e-4 - 0.04j] freqoff = 0.0 snr_db = 10 rms_amplitude = 8000 data = [1 + 1j] * vlen #data2 = [2] * vlen src = gr.vector_source_c(data, True, vlen) v2s = gr.vector_to_stream(gr.sizeof_gr_complex, vlen) #interp = gr.fractional_interpolator_cc(0.0,soff) interp = moms(1000000, 1000000 + soff) fad_chan = gr.fir_filter_ccc(1, taps) freq_shift = gr.multiply_cc() norm_freq = freqoff / vlen freq_off_src = gr.sig_source_c(1.0, gr.GR_SIN_WAVE, norm_freq, 1.0, 0.0) snr = 10.0**(snr_db / 10.0) noise_sigma = sqrt(rms_amplitude**2 / snr) awgn_chan = gr.add_cc() awgn_noise_src = ofdm.complex_white_noise(0.0, noise_sigma) dst = gr.null_sink(gr.sizeof_gr_complex) limit = gr.head(gr.sizeof_gr_complex * vlen, N) self.tb.connect(src, limit, v2s, interp, fad_chan, freq_shift, awgn_chan, dst) self.tb.connect(freq_off_src, (freq_shift, 1)) self.tb.connect(awgn_noise_src, (awgn_chan, 1)) r = time_it(self.tb) print "Rate: %s Samples/second" \ % eng_notation.num_to_str( float(N) * vlen / r )
def __init__ ( self, fft_length ): gr.hier_block2.__init__(self, "recursive_timing_metric", gr.io_signature(1,1,gr.sizeof_gr_complex), gr.io_signature(1,1,gr.sizeof_float)) self.input = gr.kludge_copy(gr.sizeof_gr_complex) self.connect(self, self.input) # P(d) = sum(0 to L-1, conj(delayed(r)) * r) conj = gr.conjugate_cc() mixer = gr.multiply_cc() mix_delay = delay(gr.sizeof_gr_complex,fft_length/2+1) mix_diff = gr.sub_cc() nominator = accumulator_cc() inpdelay = delay(gr.sizeof_gr_complex,fft_length/2) self.connect(self.input, inpdelay, conj, (mixer,0)) self.connect(self.input, (mixer,1)) self.connect(mixer,(mix_diff,0)) self.connect(mixer, mix_delay, (mix_diff,1)) self.connect(mix_diff,nominator) rmagsqrd = gr.complex_to_mag_squared() rm_delay = delay(gr.sizeof_float,fft_length+1) rm_diff = gr.sub_ff() denom = accumulator_ff() self.connect(self.input,rmagsqrd,rm_diff,gr.multiply_const_ff(0.5),denom) self.connect(rmagsqrd,rm_delay,(rm_diff,1)) ps = gr.complex_to_mag_squared() rs = gr.multiply_ff() self.connect(nominator,ps) self.connect(denom,rs) self.connect(denom,(rs,1)) div = gr.divide_ff() self.connect(ps,div) self.connect(rs,(div,1)) self.connect(div,self)
def __init__(self, fft_length): gr.hier_block2.__init__(self, "recursive_timing_metric", gr.io_signature(1, 1, gr.sizeof_gr_complex), gr.io_signature(1, 1, gr.sizeof_float)) self.input = gr.kludge_copy(gr.sizeof_gr_complex) self.connect(self, self.input) # P(d) = sum(0 to L-1, conj(delayed(r)) * r) conj = gr.conjugate_cc() mixer = gr.multiply_cc() mix_delay = delay(gr.sizeof_gr_complex, fft_length / 2 + 1) mix_diff = gr.sub_cc() nominator = accumulator_cc() inpdelay = delay(gr.sizeof_gr_complex, fft_length / 2) self.connect(self.input, inpdelay, conj, (mixer, 0)) self.connect(self.input, (mixer, 1)) self.connect(mixer, (mix_diff, 0)) self.connect(mixer, mix_delay, (mix_diff, 1)) self.connect(mix_diff, nominator) rmagsqrd = gr.complex_to_mag_squared() rm_delay = delay(gr.sizeof_float, fft_length + 1) rm_diff = gr.sub_ff() denom = accumulator_ff() self.connect(self.input, rmagsqrd, rm_diff, gr.multiply_const_ff(0.5), denom) self.connect(rmagsqrd, rm_delay, (rm_diff, 1)) ps = gr.complex_to_mag_squared() rs = gr.multiply_ff() self.connect(nominator, ps) self.connect(denom, rs) self.connect(denom, (rs, 1)) div = gr.divide_ff() self.connect(ps, div) self.connect(rs, (div, 1)) self.connect(div, self)
def __init__(self, fft_length): gr.hier_block2.__init__(self, "schmidl_nominator", gr.io_signature(1,1,gr.sizeof_gr_complex), gr.io_signature(1,1,gr.sizeof_gr_complex)) self.input=gr.kludge_copy(gr.sizeof_gr_complex) # P(d) = sum(0 to L-1, conj(delayed(r)) * r) conj = gr.conjugate_cc() mixer = gr.multiply_cc() moving_avg = gr.fir_filter_ccf(1,[1.0 for i in range(fft_length/2)]) self.connect(self, self.input, delay(gr.sizeof_gr_complex,fft_length/2), conj, (mixer,0)) self.connect(self.input, (mixer,1)) self.connect(mixer, moving_avg, self) # moving_avg = P(d) try: gr.hier_block.update_var_names(self, "schmidl_nom", vars()) gr.hier_block.update_var_names(self, "schmidl_nom", vars(self)) except: pass
def __init__(self, noise_voltage, frequency_offset): gr.hier_block2.__init__(self, "awgn_channel", gr.io_signature(1,1,gr.sizeof_gr_complex), gr.io_signature(1,1,gr.sizeof_gr_complex)) self.noise_adder = gr.add_cc() self.noise = gr.noise_source_c(gr.GR_GAUSSIAN,noise_voltage) self.offset = gr.sig_source_c(1, gr.GR_SIN_WAVE, frequency_offset, 1.0, 0.0) self.mixer_offset = gr.multiply_cc() self.connect(self, (self.mixer_offset,0)) self.connect(self.offset,(self.mixer_offset,1)) self.connect(self.mixer_offset, (self.noise_adder,1)) self.connect(self.noise, (self.noise_adder,0)) self.connect(self.noise_adder, self) try: gr.hier_block.update_var_names(self, "awgn_channel", vars()) gr.hier_block.update_var_names(self, "awgn_channel", vars(self)) except: pass
def __init__(self, noise_voltage, frequency_offset): gr.hier_block2.__init__(self, "awgn_channel", gr.io_signature(1, 1, gr.sizeof_gr_complex), gr.io_signature(1, 1, gr.sizeof_gr_complex)) self.noise_adder = gr.add_cc() self.noise = gr.noise_source_c(gr.GR_GAUSSIAN, noise_voltage) self.offset = gr.sig_source_c(1, gr.GR_SIN_WAVE, frequency_offset, 1.0, 0.0) self.mixer_offset = gr.multiply_cc() self.connect(self, (self.mixer_offset, 0)) self.connect(self.offset, (self.mixer_offset, 1)) self.connect(self.mixer_offset, (self.noise_adder, 1)) self.connect(self.noise, (self.noise_adder, 0)) self.connect(self.noise_adder, self) try: gr.hier_block.update_var_names(self, "awgn_channel", vars()) gr.hier_block.update_var_names(self, "awgn_channel", vars(self)) except: pass
def __init__(self, vocoder, lo_freq, audio_rate, if_rate): gr.hier_block2.__init__( self, "pipeline", gr.io_signature(0, 0, 0), # Input signature gr.io_signature(1, 1, gr.sizeof_gr_complex)) # Output signature c4fm = op25_c4fm_mod.p25_mod_bf(output_sample_rate=audio_rate, log=False, verbose=True) interp_factor = if_rate / audio_rate low_pass = 2.88e3 interp_taps = gr.firdes.low_pass(1.0, if_rate, low_pass, low_pass * 0.1, gr.firdes.WIN_HANN) interpolator = gr.interp_fir_filter_fff(int(interp_factor), interp_taps) max_dev = 12.5e3 k = 2 * math.pi * max_dev / if_rate adjustment = 1.5 # adjust for proper c4fm deviation level modulator = gr.frequency_modulator_fc(k * adjustment) # Local oscillator lo = gr.sig_source_c( if_rate, # sample rate gr.GR_SIN_WAVE, # waveform type lo_freq, #frequency 1.0, # amplitude 0) # DC Offset mixer = gr.multiply_cc() self.connect(vocoder, c4fm, interpolator, modulator, (mixer, 0)) self.connect(lo, (mixer, 1)) self.connect(mixer, self)
def __init__(self, fft_length): gr.hier_block2.__init__(self, "schmidl_nominator", gr.io_signature(1, 1, gr.sizeof_gr_complex), gr.io_signature(1, 1, gr.sizeof_gr_complex)) self.input = gr.kludge_copy(gr.sizeof_gr_complex) # P(d) = sum(0 to L-1, conj(delayed(r)) * r) conj = gr.conjugate_cc() mixer = gr.multiply_cc() moving_avg = gr.fir_filter_ccf(1, [1.0 for i in range(fft_length / 2)]) self.connect(self, self.input, delay(gr.sizeof_gr_complex, fft_length / 2), conj, (mixer, 0)) self.connect(self.input, (mixer, 1)) self.connect(mixer, moving_avg, self) # moving_avg = P(d) try: gr.hier_block.update_var_names(self, "schmidl_nom", vars()) gr.hier_block.update_var_names(self, "schmidl_nom", vars(self)) except: pass
def setup_interferometer(self, setimode): self.setup_radiometer_common(2) self.di = gr.deinterleave(gr.sizeof_gr_complex) self.connect (self.u, self.di) self.corr = gr.multiply_cc() self.c2f = gr.complex_to_float() self.shead = (self.di, 0) # Channel 0 to multiply port 0 # Channel 1 to multiply port 1 if (self.use_notches == False): self.connect((self.di, 0), (self.corr, 0)) self.connect((self.di, 1), (self.corr, 1)) else: self.connect((self.di, 0), self.notch_filt1, (self.corr, 0)) self.connect((self.di, 1), self.notch_filt2, (self.corr, 0)) # # Multiplier (correlator) to complex-to-float, followed by integrator, etc # self.connect(self.corr, self.c2f, self.integrator, self.keepn, self.cal_mult, self.cal_offs, self.chart) # # FFT scope gets only 1 channel # FIX THIS, by cross-correlating the *outputs* of two different FFTs, then display # Funky! # self.connect(self.shead, self.scope) # # Output of correlator/integrator chain to probe # self.connect(self.cal_offs, self.probe) return
def __init__(self, fft_length, pn_weights): gr.hier_block2.__init__(self, "modified_timing_metric", gr.io_signature(1, 1, gr.sizeof_gr_complex), gr.io_signature(1, 1, gr.sizeof_float)) assert (len(pn_weights) == fft_length) self.input = gr.kludge_copy(gr.sizeof_gr_complex) self.connect(self, self.input) # P(d) = sum(0 to L-1, conj(delayed(r)) * r) conj = gr.conjugate_cc() mixer = gr.multiply_cc() nominator = gr.fir_filter_ccf(1, [ pn_weights[fft_length - i - 1] * pn_weights[fft_length / 2 - i - 1] for i in range(fft_length / 2) ]) self.connect(self.input, delay(gr.sizeof_gr_complex, fft_length / 2), conj, (mixer, 0)) self.connect(self.input, (mixer, 1)) self.connect(mixer, nominator) # moving_avg = P(d) # R(d) denominator = schmidl_denominator(fft_length) # |P(d)| ** 2 / (R(d)) ** 2 p_mag_sqrd = gr.complex_to_mag_squared() r_sqrd = gr.multiply_ff() self.timing_metric = gr.divide_ff() self.connect(nominator, p_mag_sqrd, (self.timing_metric, 0)) self.connect(self.input, denominator, (r_sqrd, 0)) self.connect(denominator, (r_sqrd, 1)) self.connect(r_sqrd, (self.timing_metric, 1)) self.connect(self.timing_metric, self)
def __init__(self, tx_id, rx_id, sample_rate, fmax): """ Paramters: sample_rate: int or float fmax: int or float maximum Doppler shift of the Jakes PSD. """ gr.hier_block2.__init__(self, "Rayleigh Channel", gr.io_signature(1, 1, gr.sizeof_gr_complex), gr.io_signature(1, 1, gr.sizeof_gr_complex)) self.sample_rate = sample_rate self.channel_opts = {'N': 2001, 'fmax': fmax} self.rayleigh = gauss_rand_proc_c(self.sample_rate, "cost207:jakes", "mea", 12, self.channel_opts) self.multiply = gr.multiply_cc() self.connect(self, (self.multiply, 0)) self.connect(self.rayleigh, (self.multiply, 1)) self.connect(self.multiply, self)
def __init__(self, fft_length, cp_length, occupied_tones, snr, logging=False): """ Hierarchical block for receiving OFDM symbols. The input is the complex modulated signal at baseband. Synchronized packets are sent back to the demodulator. @param fft_length: total number of subcarriers @type fft_length: int @param cp_length: length of cyclic prefix as specified in subcarriers (<= fft_length) @type cp_length: int @param occupied_tones: number of subcarriers used for data @type occupied_tones: int @param snr: estimated signal to noise ratio used to guide cyclic prefix synchronizer @type snr: float @param logging: turn file logging on or off @type logging: bool """ gr.hier_block2.__init__( self, "ofdm_receiver", gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature gr.io_signature2(2, 2, gr.sizeof_gr_complex * fft_length, gr.sizeof_char * fft_length)) # Output signature bw = (float(occupied_tones) / float(fft_length)) / 2.0 tb = bw * 0.08 chan_coeffs = gr.firdes.low_pass( 1.0, # gain 1.0, # sampling rate bw + tb, # midpoint of trans. band tb, # width of trans. band gr.firdes.WIN_HAMMING) # filter type #self.chan_filt = gr.fft_filter_ccc(1, chan_coeffs) self.chan_filt = gr.multiply_cc(1) win = [1 for i in range(fft_length)] ks0time = fft_length * (0, ) SYNC = "ml" if SYNC == "ml": #TODO -1.0/... nco_sensitivity = -1.0 / fft_length # correct for fine frequency self.ofdm_sync = ofdm_sync_ml.ofdm_sync_ml(fft_length, cp_length, snr, ks0time, logging) elif SYNC == "pn": nco_sensitivity = -2.0 / fft_length # correct for fine frequency self.ofdm_sync = ofdm_sync_pn.ofdm_sync_pn(fft_length, cp_length, logging) elif SYNC == "pnac": nco_sensitivity = -2.0 / fft_length # correct for fine frequency self.ofdm_sync = ofdm_sync_pnac.ofdm_sync_pnac( fft_length, cp_length, ks0time, logging) # for testing only; do not user over the air # remove filter and filter delay for this elif SYNC == "fixed": self.chan_filt = gr.multiply_const_cc(1.0) nsymbols = 18 # enter the number of symbols per packet freq_offset = 0.0 # if you use a frequency offset, enter it here nco_sensitivity = -2.0 / fft_length # correct for fine frequency self.ofdm_sync = ofdm_sync_fixed.ofdm_sync_fixed( fft_length, cp_length, nsymbols, freq_offset, logging) # Set up blocks #self.grnull = gr.null_sink(4); self.nco = gr.frequency_modulator_fc( nco_sensitivity ) # generate a signal proportional to frequency error of sync block self.sigmix = gr.multiply_cc() self.sampler = digital_swig.ofdm_sampler(fft_length, fft_length + cp_length) self.fft_demod = gr.fft_vcc(fft_length, True, win, True) self.connect(self, self.chan_filt) # filter the input channel self.connect(self.chan_filt, self.ofdm_sync) # into the synchronization alg. self.connect( (self.ofdm_sync, 0), self.nco, (self.sigmix, 1)) # use sync freq. offset output to derotate input signal self.connect(self.chan_filt, (self.sigmix, 0)) # signal to be derotated self.connect( self.sigmix, (self.sampler, 0)) # sample off timing signal detected in sync alg #self.connect(self.chan_filt, (self.sampler,0)) # sample off timing signal detected in sync alg self.connect((self.ofdm_sync, 1), (self.sampler, 1)) # timing signal to sample at self.connect((self.sampler, 0), self.fft_demod) # send derotated sampled signal to FFT self.connect(self.fft_demod, (self, 0)) # frequency domain signal sent to output 0 self.connect((self.sampler, 1), (self, 1)) # timing sent to output 1 print "setup OK" logging = 0 if logging: self.connect( self.chan_filt, gr.file_sink(gr.sizeof_gr_complex, "ofdm_receiver-chan_filt_c.dat")) self.connect((self.ofdm_sync, 0), gr.file_sink(gr.sizeof_float, "ofdm_receiver-sync_0.dat")) self.connect((self.ofdm_sync, 1), gr.file_sink(gr.sizeof_char, "ofdm_receiver-sync_1.dat")) self.connect( self.nco, gr.file_sink(gr.sizeof_gr_complex, "ofdm_receiver-nco_c.dat")) self.connect( self.sigmix, gr.file_sink(gr.sizeof_gr_complex, "ofdm_receiver-sigmix_c.dat")) self.connect((self.sampler, 0), gr.file_sink(gr.sizeof_gr_complex * fft_length, "ofdm_receiver-sampler_0.dat")) self.connect((self.sampler, 1), gr.file_sink(gr.sizeof_char * fft_length, "ofdm_receiver-sampler_1.dat")) self.connect( self.fft_demod, gr.file_sink(gr.sizeof_gr_complex * fft_length, "ofdm_receiver-fft_out_c.dat"))
def __init__(self, bandwidth, fft_length, cp_length, occupied_tones, snr, ks, logging=False, mode='benchmark'): """ Hierarchical block for receiving OFDM symbols. The input is the complex modulated signal at baseband. Synchronized packets are sent back to the demodulator. @param fft_length: total number of subcarriers @type fft_length: int @param cp_length: length of cyclic prefix as specified in subcarriers (<= fft_length) @type cp_length: int @param occupied_tones: number of subcarriers used for data @type occupied_tones: int @param snr: estimated signal to noise ratio used to guide cyclic prefix synchronizer @type snr: float @param ks: known symbols used as preambles to each packet @type ks: list of lists @param logging: turn file logging on or off @type logging: bool """ gr.hier_block2.__init__(self, "ofdm_receiver", gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature gr.io_signature2(2, 2, gr.sizeof_gr_complex*occupied_tones, gr.sizeof_char)) # Output signature bw = (float(occupied_tones) / float(fft_length)) / 2.0 tb = bw*0.08 chan_coeffs = gr.firdes.low_pass (1.0, # gain 1.0, # sampling rate bw+tb, # midpoint of trans. band tb, # width of trans. band gr.firdes.WIN_HAMMING) # filter type self.chan_filt = gr.fft_filter_ccc(1, chan_coeffs) win = [1 for i in range(fft_length)] zeros_on_left = int(math.ceil((fft_length - occupied_tones)/2.0)) ks0 = fft_length*[0,] ks0[zeros_on_left : zeros_on_left + occupied_tones] = ks[0] ks0 = fft.ifftshift(ks0) ks0time = fft.ifft(ks0) # ADD SCALING FACTOR ks0time = ks0time.tolist() SYNC = "pn" if SYNC == "ml": nco_sensitivity = -1.0/fft_length # correct for fine frequency self.ofdm_sync = ofdm_sync_ml(fft_length, cp_length, snr, ks0time, logging) elif SYNC == "pn": nco_sensitivity = -2.0/fft_length # correct for fine frequency self.ofdm_sync = ofdm_sync_pn(fft_length, cp_length, logging, mode) elif SYNC == "pnac": nco_sensitivity = -2.0/fft_length # correct for fine frequency self.ofdm_sync = ofdm_sync_pnac(fft_length, cp_length, ks0time, logging) # for testing only; do not user over the air # remove filter and filter delay for this elif SYNC == "fixed": self.chan_filt = gr.multiply_const_cc(1.0) nsymbols = 18 # enter the number of symbols per packet freq_offset = 0.0 # if you use a frequency offset, enter it here nco_sensitivity = -2.0/fft_length # correct for fine frequency self.ofdm_sync = ofdm_sync_fixed(fft_length, cp_length, nsymbols, freq_offset, logging) # Set up blocks self.nco = gr.frequency_modulator_fc(nco_sensitivity) # generate a signal proportional to frequency error of sync block self.sigmix = gr.multiply_cc() self.sampler = digital_swig.ofdm_sampler(fft_length, fft_length+cp_length, long(bandwidth)) self.fft_demod = gr.fft_vcc(fft_length, True, win, True) self.ofdm_frame_acq = digital_swig.ofdm_frame_acquisition(occupied_tones, fft_length, cp_length, ks[0]) self.connect(self, self.chan_filt) # filter the input channel self.connect(self.chan_filt, self.ofdm_sync) # into the synchronization alg. self.connect((self.ofdm_sync,0), self.nco, (self.sigmix,1)) # use sync freq. offset output to derotate input signal self.connect(self.chan_filt, (self.sigmix,0)) # signal to be derotated self.connect(self.sigmix, (self.sampler,0)) # sample off timing signal detected in sync alg self.connect((self.ofdm_sync,1), (self.sampler,1)) # timing signal to sample at self.connect((self.sampler,0), self.fft_demod) # send derotated sampled signal to FFT self.connect(self.fft_demod, (self.ofdm_frame_acq,0)) # find frame start and equalize signal self.connect((self.sampler,1), (self.ofdm_frame_acq,1)) # send timing signal to signal frame start self.connect((self.ofdm_frame_acq,0), (self,0)) # finished with fine/coarse freq correction, self.connect((self.ofdm_frame_acq,1), (self,1)) # frame and symbol timing, and equalization # for debugging self.connect(self.chan_filt, gr.file_sink(gr.sizeof_gr_complex, "ofdm_receiver-chan_filt_c.dat")) if logging: self.connect(self.chan_filt, gr.file_sink(gr.sizeof_gr_complex, "ofdm_receiver-chan_filt_c.dat")) self.connect(self.fft_demod, gr.file_sink(gr.sizeof_gr_complex*fft_length, "ofdm_receiver-fft_out_c.dat")) self.connect(self.ofdm_frame_acq, gr.file_sink(gr.sizeof_gr_complex*occupied_tones, "ofdm_receiver-frame_acq_c.dat")) self.connect((self.ofdm_frame_acq,1), gr.file_sink(1, "ofdm_receiver-found_corr_b.dat")) self.connect(self.sampler, gr.file_sink(gr.sizeof_gr_complex*fft_length, "ofdm_receiver-sampler_c.dat")) self.connect(self.sigmix, gr.file_sink(gr.sizeof_gr_complex, "ofdm_receiver-sigmix_c.dat")) self.connect(self.nco, gr.file_sink(gr.sizeof_gr_complex, "ofdm_receiver-nco_c.dat"))
def __init__(self): gr.top_block.__init__(self) parser = OptionParser(option_class=eng_option) parser.add_option("-1", "--one-channel", action="store_true", default=False, help="software synthesized Q channel") parser.add_option("-a", "--agc", action="store_true", default=False, help="automatic gain control (overrides --gain)") parser.add_option("-c", "--calibration", type="eng_float", default=0, help="freq offset") parser.add_option("-d", "--debug", action="store_true", default=False, help="allow time at init to attach gdb") parser.add_option("-C", "--costas-alpha", type="eng_float", default=0.125, help="Costas alpha") parser.add_option("-g", "--gain", type="eng_float", default=1.0) parser.add_option("-i", "--input-file", type="string", default="in.dat", help="specify the input file") parser.add_option("-I", "--imbe", action="store_true", default=False, help="output IMBE codewords") parser.add_option("-L", "--low-pass", type="eng_float", default=6.5e3, help="low pass cut-off", metavar="Hz") parser.add_option("-o", "--output-file", type="string", default="out.dat", help="specify the output file") parser.add_option("-p", "--polarity", action="store_true", default=False, help="use reversed polarity") parser.add_option("-r", "--raw-symbols", type="string", default=None, help="dump decoded symbols to file") parser.add_option("-s", "--sample-rate", type="int", default=96000, help="input sample rate") parser.add_option("-t", "--tone-detect", action="store_true", default=False, help="use experimental tone detect algorithm") parser.add_option("-v", "--verbose", action="store_true", default=False, help="additional output") parser.add_option("-6", "--k6k", action="store_true", default=False, help="use 6K symbol rate") (options, args) = parser.parse_args() sample_rate = options.sample_rate if options.k6k: symbol_rate = 6000 else: symbol_rate = 4800 samples_per_symbol = sample_rate // symbol_rate IN = gr.file_source(gr.sizeof_gr_complex, options.input_file) if options.one_channel: C2F = gr.complex_to_float() F2C = gr.float_to_complex() # osc./mixer for mixing signal down to approx. zero IF LO = gr.sig_source_c(sample_rate, gr.GR_COS_WAVE, options.calibration, 1.0, 0) MIXER = gr.multiply_cc() # get signal into normalized range (-1.0 - +1.0) if options.agc: AMP = gr.feedforward_agc_cc(16, 1.0) else: AMP = gr.multiply_const_cc(options.gain) lpf_taps = gr.firdes.low_pass(1.0, sample_rate, options.low_pass, options.low_pass * 0.1, gr.firdes.WIN_HANN) decim_amt = 1 if options.tone_detect: if sample_rate != 96000: print "warning, only 96K has been tested." print "other rates may require theta to be reviewed/adjusted." step_size = 7.5e-8 theta = -4 # optimum timing sampling point cic_length = 48 DEMOD = repeater.tdetect_cc(samples_per_symbol, step_size, theta, cic_length) else: # decim by 2 to get 48k rate samples_per_symbol /= 2 # for DECIM sample_rate /= 2 # for DECIM decim_amt = 2 # create Gardner/Costas loop # the loop will not work if the sample levels aren't normalized (above) timing_error_gain = 0.025 # loop error gain gain_omega = 0.25 * timing_error_gain * timing_error_gain alpha = options.costas_alpha beta = 0.125 * alpha * alpha fmin = -0.025 # fmin and fmax are in radians/s fmax = 0.025 DEMOD = repeater.gardner_costas_cc(samples_per_symbol, timing_error_gain, gain_omega, alpha, beta, fmax, fmin) DECIM = gr.fir_filter_ccf(decim_amt, lpf_taps) # probably too much phase noise etc to attempt coherent demodulation # so we use differential DIFF = gr.diff_phasor_cc() # take angle of the phase difference (in radians) TOFLOAT = gr.complex_to_arg() # convert from radians such that signal is in [-3, -1, +1, +3] RESCALE = gr.multiply_const_ff(1 / (pi / 4.0)) # optional polarity reversal (should be unnec. - now autodetected) p = 1.0 if options.polarity: p = -1.0 POLARITY = gr.multiply_const_ff(p) # hard decision at specified points levels = [-2.0, 0.0, 2.0, 4.0] SLICER = repeater.fsk4_slicer_fb(levels) # assemble received frames and route to Wireshark via UDP hostname = "127.0.0.1" port = 23456 debug = 0 if options.verbose: debug = 255 do_imbe = False if options.imbe: do_imbe = True do_output = True # enable block's output stream do_msgq = False # msgq output not yet implemented msgq = gr.msg_queue(2) DECODER = repeater.p25_frame_assembler(hostname, port, debug, do_imbe, do_output, do_msgq, msgq) OUT = gr.file_sink(gr.sizeof_char, options.output_file) if options.one_channel: self.connect(IN, C2F, F2C, (MIXER, 0)) else: self.connect(IN, (MIXER, 0)) self.connect(LO, (MIXER, 1)) self.connect(MIXER, AMP, DECIM, DEMOD, DIFF, TOFLOAT, RESCALE, POLARITY, SLICER, DECODER, OUT) if options.raw_symbols: SINKC = gr.file_sink(gr.sizeof_char, options.raw_symbols) self.connect(SLICER, SINKC) if options.debug: print 'Ready for GDB to attach (pid = %d)' % (os.getpid(), ) raw_input("Press 'Enter' to continue...")
def __init__(self, *args, **kwds): # begin wxGlade: MyFrame.__init__ kwds["style"] = wx.DEFAULT_FRAME_STYLE wx.Frame.__init__(self, *args, **kwds) # Menu Bar self.frame_1_menubar = wx.MenuBar() self.SetMenuBar(self.frame_1_menubar) wxglade_tmp_menu = wx.Menu() self.Exit = wx.MenuItem(wxglade_tmp_menu, ID_EXIT, "Exit", "Exit", wx.ITEM_NORMAL) wxglade_tmp_menu.AppendItem(self.Exit) self.frame_1_menubar.Append(wxglade_tmp_menu, "File") # Menu Bar end self.panel_1 = wx.Panel(self, -1) self.button_1 = wx.Button(self, ID_BUTTON_1, "LSB") self.button_2 = wx.Button(self, ID_BUTTON_2, "USB") self.button_3 = wx.Button(self, ID_BUTTON_3, "AM") self.button_4 = wx.Button(self, ID_BUTTON_4, "CW") self.button_5 = wx.ToggleButton(self, ID_BUTTON_5, "Upper") self.slider_fcutoff_hi = wx.Slider(self, ID_SLIDER_1, 0, -15798, 15799, style=wx.SL_HORIZONTAL | wx.SL_LABELS) self.button_6 = wx.ToggleButton(self, ID_BUTTON_6, "Lower") self.slider_fcutoff_lo = wx.Slider(self, ID_SLIDER_2, 0, -15799, 15798, style=wx.SL_HORIZONTAL | wx.SL_LABELS) self.panel_5 = wx.Panel(self, -1) self.label_1 = wx.StaticText(self, -1, " Band\nCenter") self.text_ctrl_1 = wx.TextCtrl(self, ID_TEXT_1, "") self.panel_6 = wx.Panel(self, -1) self.panel_7 = wx.Panel(self, -1) self.panel_2 = wx.Panel(self, -1) self.button_7 = wx.ToggleButton(self, ID_BUTTON_7, "Freq") self.slider_3 = wx.Slider(self, ID_SLIDER_3, 3000, 0, 6000) self.spin_ctrl_1 = wx.SpinCtrl(self, ID_SPIN_1, "", min=0, max=100) self.button_8 = wx.ToggleButton(self, ID_BUTTON_8, "Vol") self.slider_4 = wx.Slider(self, ID_SLIDER_4, 0, 0, 500) self.slider_5 = wx.Slider(self, ID_SLIDER_5, 0, 0, 20) self.button_9 = wx.ToggleButton(self, ID_BUTTON_9, "Time") self.button_11 = wx.Button(self, ID_BUTTON_11, "Rew") self.button_10 = wx.Button(self, ID_BUTTON_10, "Fwd") self.panel_3 = wx.Panel(self, -1) self.label_2 = wx.StaticText(self, -1, "PGA ") self.panel_4 = wx.Panel(self, -1) self.panel_8 = wx.Panel(self, -1) self.panel_9 = wx.Panel(self, -1) self.label_3 = wx.StaticText(self, -1, "AM Sync\nCarrier") self.slider_6 = wx.Slider(self, ID_SLIDER_6, 50, 0, 200, style=wx.SL_HORIZONTAL | wx.SL_LABELS) self.label_4 = wx.StaticText(self, -1, "Antenna Tune") self.slider_7 = wx.Slider(self, ID_SLIDER_7, 1575, 950, 2200, style=wx.SL_HORIZONTAL | wx.SL_LABELS) self.panel_10 = wx.Panel(self, -1) self.button_12 = wx.ToggleButton(self, ID_BUTTON_12, "Auto Tune") self.button_13 = wx.Button(self, ID_BUTTON_13, "Calibrate") self.button_14 = wx.Button(self, ID_BUTTON_14, "Reset") self.panel_11 = wx.Panel(self, -1) self.panel_12 = wx.Panel(self, -1) self.__set_properties() self.__do_layout() # end wxGlade parser = OptionParser(option_class=eng_option) parser.add_option("", "--address", type="string", default="addr=192.168.10.2", help="Address of UHD device, [default=%default]") parser.add_option("-c", "--ddc-freq", type="eng_float", default=3.9e6, help="set Rx DDC frequency to FREQ", metavar="FREQ") parser.add_option( "-s", "--samp-rate", type="eng_float", default=256e3, help="set sample rate (bandwidth) [default=%default]") parser.add_option("-a", "--audio_file", default="", help="audio output file", metavar="FILE") parser.add_option("-r", "--radio_file", default="", help="radio output file", metavar="FILE") parser.add_option("-i", "--input_file", default="", help="radio input file", metavar="FILE") parser.add_option( "-O", "--audio-output", type="string", default="", help="audio output device name. E.g., hw:0,0, /dev/dsp, or pulse") (options, args) = parser.parse_args() self.usrp_center = options.ddc_freq input_rate = options.samp_rate self.slider_range = input_rate * 0.9375 self.f_lo = self.usrp_center - (self.slider_range / 2) self.f_hi = self.usrp_center + (self.slider_range / 2) self.af_sample_rate = 32000 fir_decim = long(input_rate / self.af_sample_rate) # data point arrays for antenna tuner self.xdata = [] self.ydata = [] self.tb = gr.top_block() # radio variables, initial conditions self.frequency = self.usrp_center # these map the frequency slider (0-6000) to the actual range self.f_slider_offset = self.f_lo self.f_slider_scale = 10000 self.spin_ctrl_1.SetRange(self.f_lo, self.f_hi) self.text_ctrl_1.SetValue(str(int(self.usrp_center))) self.slider_5.SetValue(0) self.AM_mode = False self.slider_3.SetValue( (self.frequency - self.f_slider_offset) / self.f_slider_scale) self.spin_ctrl_1.SetValue(int(self.frequency)) POWERMATE = True try: self.pm = powermate.powermate(self) except: sys.stderr.write("Unable to find PowerMate or Contour Shuttle\n") POWERMATE = False if POWERMATE: powermate.EVT_POWERMATE_ROTATE(self, self.on_rotate) powermate.EVT_POWERMATE_BUTTON(self, self.on_pmButton) self.active_button = 7 # command line options if options.audio_file == "": SAVE_AUDIO_TO_FILE = False else: SAVE_AUDIO_TO_FILE = True if options.radio_file == "": SAVE_RADIO_TO_FILE = False else: SAVE_RADIO_TO_FILE = True if options.input_file == "": self.PLAY_FROM_USRP = True else: self.PLAY_FROM_USRP = False if self.PLAY_FROM_USRP: self.src = uhd.usrp_source(device_addr=options.address, io_type=uhd.io_type.COMPLEX_FLOAT32, num_channels=1) self.src.set_samp_rate(input_rate) input_rate = self.src.get_samp_rate() self.src.set_center_freq(self.usrp_center, 0) self.tune_offset = 0 else: self.src = gr.file_source(gr.sizeof_short, options.input_file) self.tune_offset = 2200 # 2200 works for 3.5-4Mhz band # convert rf data in interleaved short int form to complex s2ss = gr.stream_to_streams(gr.sizeof_short, 2) s2f1 = gr.short_to_float() s2f2 = gr.short_to_float() src_f2c = gr.float_to_complex() self.tb.connect(self.src, s2ss) self.tb.connect((s2ss, 0), s2f1) self.tb.connect((s2ss, 1), s2f2) self.tb.connect(s2f1, (src_f2c, 0)) self.tb.connect(s2f2, (src_f2c, 1)) # save radio data to a file if SAVE_RADIO_TO_FILE: radio_file = gr.file_sink(gr.sizeof_short, options.radio_file) self.tb.connect(self.src, radio_file) # 2nd DDC xlate_taps = gr.firdes.low_pass ( \ 1.0, input_rate, 16e3, 4e3, gr.firdes.WIN_HAMMING ) self.xlate = gr.freq_xlating_fir_filter_ccf ( \ fir_decim, xlate_taps, self.tune_offset, input_rate ) # Complex Audio filter audio_coeffs = gr.firdes.complex_band_pass( 1.0, # gain self.af_sample_rate, # sample rate -3000, # low cutoff 0, # high cutoff 100, # transition gr.firdes.WIN_HAMMING) # window self.slider_fcutoff_hi.SetValue(0) self.slider_fcutoff_lo.SetValue(-3000) self.audio_filter = gr.fir_filter_ccc(1, audio_coeffs) # Main +/- 16Khz spectrum display self.fft = fftsink2.fft_sink_c(self.panel_2, fft_size=512, sample_rate=self.af_sample_rate, average=True, size=(640, 240)) # AM Sync carrier if AM_SYNC_DISPLAY: self.fft2 = fftsink.fft_sink_c(self.tb, self.panel_9, y_per_div=20, fft_size=512, sample_rate=self.af_sample_rate, average=True, size=(640, 240)) c2f = gr.complex_to_float() # AM branch self.sel_am = gr.multiply_const_cc(0) # the following frequencies turn out to be in radians/sample # gr.pll_refout_cc(alpha,beta,min_freq,max_freq) # suggested alpha = X, beta = .25 * X * X pll = gr.pll_refout_cc(.5, .0625, (2. * math.pi * 7.5e3 / self.af_sample_rate), (2. * math.pi * 6.5e3 / self.af_sample_rate)) self.pll_carrier_scale = gr.multiply_const_cc(complex(10, 0)) am_det = gr.multiply_cc() # these are for converting +7.5kHz to -7.5kHz # for some reason gr.conjugate_cc() adds noise ?? c2f2 = gr.complex_to_float() c2f3 = gr.complex_to_float() f2c = gr.float_to_complex() phaser1 = gr.multiply_const_ff(1) phaser2 = gr.multiply_const_ff(-1) # filter for pll generated carrier pll_carrier_coeffs = gr.firdes.complex_band_pass( 2.0, # gain self.af_sample_rate, # sample rate 7400, # low cutoff 7600, # high cutoff 100, # transition gr.firdes.WIN_HAMMING) # window self.pll_carrier_filter = gr.fir_filter_ccc(1, pll_carrier_coeffs) self.sel_sb = gr.multiply_const_ff(1) combine = gr.add_ff() #AGC sqr1 = gr.multiply_ff() intr = gr.iir_filter_ffd([.004, 0], [0, .999]) offset = gr.add_const_ff(1) agc = gr.divide_ff() self.scale = gr.multiply_const_ff(0.00001) dst = audio.sink(long(self.af_sample_rate), options.audio_output) if self.PLAY_FROM_USRP: self.tb.connect(self.src, self.xlate, self.fft) else: self.tb.connect(src_f2c, self.xlate, self.fft) self.tb.connect(self.xlate, self.audio_filter, self.sel_am, (am_det, 0)) self.tb.connect(self.sel_am, pll, self.pll_carrier_scale, self.pll_carrier_filter, c2f3) self.tb.connect((c2f3, 0), phaser1, (f2c, 0)) self.tb.connect((c2f3, 1), phaser2, (f2c, 1)) self.tb.connect(f2c, (am_det, 1)) self.tb.connect(am_det, c2f2, (combine, 0)) self.tb.connect(self.audio_filter, c2f, self.sel_sb, (combine, 1)) if AM_SYNC_DISPLAY: self.tb.connect(self.pll_carrier_filter, self.fft2) self.tb.connect(combine, self.scale) self.tb.connect(self.scale, (sqr1, 0)) self.tb.connect(self.scale, (sqr1, 1)) self.tb.connect(sqr1, intr, offset, (agc, 1)) self.tb.connect(self.scale, (agc, 0)) self.tb.connect(agc, dst) if SAVE_AUDIO_TO_FILE: f_out = gr.file_sink(gr.sizeof_short, options.audio_file) sc1 = gr.multiply_const_ff(64000) f2s1 = gr.float_to_short() self.tb.connect(agc, sc1, f2s1, f_out) self.tb.start() # for mouse position reporting on fft display self.fft.win.Bind(wx.EVT_LEFT_UP, self.Mouse) # and left click to re-tune self.fft.win.Bind(wx.EVT_LEFT_DOWN, self.Click) # start a timer to check for web commands if WEB_CONTROL: self.timer = UpdateTimer(self, 1000) # every 1000 mSec, 1 Sec wx.EVT_BUTTON(self, ID_BUTTON_1, self.set_lsb) wx.EVT_BUTTON(self, ID_BUTTON_2, self.set_usb) wx.EVT_BUTTON(self, ID_BUTTON_3, self.set_am) wx.EVT_BUTTON(self, ID_BUTTON_4, self.set_cw) wx.EVT_BUTTON(self, ID_BUTTON_10, self.fwd) wx.EVT_BUTTON(self, ID_BUTTON_11, self.rew) wx.EVT_BUTTON(self, ID_BUTTON_13, self.AT_calibrate) wx.EVT_BUTTON(self, ID_BUTTON_14, self.AT_reset) wx.EVT_TOGGLEBUTTON(self, ID_BUTTON_5, self.on_button) wx.EVT_TOGGLEBUTTON(self, ID_BUTTON_6, self.on_button) wx.EVT_TOGGLEBUTTON(self, ID_BUTTON_7, self.on_button) wx.EVT_TOGGLEBUTTON(self, ID_BUTTON_8, self.on_button) wx.EVT_TOGGLEBUTTON(self, ID_BUTTON_9, self.on_button) wx.EVT_SLIDER(self, ID_SLIDER_1, self.set_filter) wx.EVT_SLIDER(self, ID_SLIDER_2, self.set_filter) wx.EVT_SLIDER(self, ID_SLIDER_3, self.slide_tune) wx.EVT_SLIDER(self, ID_SLIDER_4, self.set_volume) wx.EVT_SLIDER(self, ID_SLIDER_5, self.set_pga) wx.EVT_SLIDER(self, ID_SLIDER_6, self.am_carrier) wx.EVT_SLIDER(self, ID_SLIDER_7, self.antenna_tune) wx.EVT_SPINCTRL(self, ID_SPIN_1, self.spin_tune) wx.EVT_MENU(self, ID_EXIT, self.TimeToQuit)
def __init__(self, fft_length, cp_length, half_sync, logging=False): gr.hier_block2.__init__( self, "ofdm_sync_pn", gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature gr.io_signature3( 3, 3, # Output signature gr.sizeof_gr_complex, # delayed input gr.sizeof_float, # fine frequency offset gr.sizeof_char # timing indicator )) if half_sync: period = fft_length / 2 window = fft_length / 2 else: # full symbol period = fft_length + cp_length window = fft_length # makes the plateau cp_length long # Calculate the frequency offset from the correlation of the preamble x_corr = gr.multiply_cc() self.connect(self, gr.conjugate_cc(), (x_corr, 0)) self.connect(self, gr.delay(gr.sizeof_gr_complex, period), (x_corr, 1)) P_d = gr.moving_average_cc(window, 1.0) self.connect(x_corr, P_d) P_d_angle = gr.complex_to_arg() self.connect(P_d, P_d_angle) # Get the power of the input signal to normalize the output of the correlation R_d = gr.moving_average_ff(window, 1.0) self.connect(self, gr.complex_to_mag_squared(), R_d) R_d_squared = gr.multiply_ff() # this is retarded self.connect(R_d, (R_d_squared, 0)) self.connect(R_d, (R_d_squared, 1)) M_d = gr.divide_ff() self.connect(P_d, gr.complex_to_mag_squared(), (M_d, 0)) self.connect(R_d_squared, (M_d, 1)) # Now we need to detect peak of M_d # NOTE: replaced fir_filter with moving_average for clarity # the peak is up to cp_length long, but noisy, so average it out #matched_filter_taps = [1.0/cp_length for i in range(cp_length)] #matched_filter = gr.fir_filter_fff(1, matched_filter_taps) matched_filter = gr.moving_average_ff(cp_length, 1.0 / cp_length) # NOTE: the look_ahead parameter doesn't do anything # these parameters are kind of magic, increase 1 and 2 (==) to be more tolerant #peak_detect = raw.peak_detector_fb(0.55, 0.55, 30, 0.001) peak_detect = raw.peak_detector_fb(0.25, 0.25, 30, 0.001) # NOTE: gr.peak_detector_fb is broken! #peak_detect = gr.peak_detector_fb(0.55, 0.55, 30, 0.001) #peak_detect = gr.peak_detector_fb(0.45, 0.45, 30, 0.001) #peak_detect = gr.peak_detector_fb(0.30, 0.30, 30, 0.001) # offset by -1 self.connect(M_d, matched_filter, gr.add_const_ff(-1), peak_detect) # peak_detect indicates the time M_d is highest, which is the end of the symbol. # We should try to sample in the middle of the plateau!! # FIXME until we figure out how to do this, just offset by cp_length/2 offset = 6 #cp_length/2 # nco(t) = P_d_angle(t-offset) sampled at peak_detect(t) # modulate input(t - fft_length) by nco(t) # signal to sample input(t) at t-offset # # We can't delay by < 0 so instead: # input is delayed by fft_length # P_d_angle is delayed by offset # signal to sample is delayed by fft_length - offset # phi = gr.sample_and_hold_ff() self.connect(peak_detect, (phi, 1)) self.connect(P_d_angle, gr.delay(gr.sizeof_float, offset), (phi, 0)) #self.connect(P_d_angle, matched_filter2, (phi,0)) # why isn't this better?!? # FIXME: we add fft_length delay so that the preamble is nco corrected too # BUT is this buffering worth it? consider implementing sync as a proper block # delay the input signal to follow the frequency offset signal self.connect(self, gr.delay(gr.sizeof_gr_complex, (fft_length + offset)), (self, 0)) self.connect(phi, (self, 1)) self.connect(peak_detect, (self, 2)) if logging: self.connect(matched_filter, gr.file_sink(gr.sizeof_float, "sync-mf.dat")) self.connect(M_d, gr.file_sink(gr.sizeof_float, "sync-M.dat")) self.connect(P_d_angle, gr.file_sink(gr.sizeof_float, "sync-angle.dat")) self.connect(peak_detect, gr.file_sink(gr.sizeof_char, "sync-peaks.datb")) self.connect(phi, gr.file_sink(gr.sizeof_float, "sync-phi.dat"))
def __init__(self, p, logging=False): """ Hierarchical block for receiving OFDM symbols. The input is the complex modulated signal at baseband. Synchronized packets are sent back to the demodulator. @param params: Raw OFDM parameters @type params: ofdm_params @param logging: turn file logging on or off @type logging: bool """ from numpy import fft gr.hier_block2.__init__( self, "ofdm_receiver", gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature gr.io_signature2(2, 2, gr.sizeof_gr_complex * p.occupied_tones, gr.sizeof_char)) # Output signature # low-pass filter the input channel bw = (float(p.occupied_tones) / float(p.fft_length)) / 2.0 tb = bw * 0.08 lpf_coeffs = gr.firdes.low_pass( 1.0, # gain 1.0, # sampling rate bw + tb, # midpoint of trans. band tb, # width of trans. band gr.firdes.WIN_HAMMING) # filter type lpf = gr.fft_filter_ccc(1, lpf_coeffs) #lpf = gr.add_const_cc(0.0) ## no-op low-pass-filter self.connect(self, lpf) # to the synchronization algorithm #from gnuradio import blks2impl #from gnuradio.blks2impl.ofdm_sync_pn import ofdm_sync_pn sync = ofdm_sync(p.fft_length, p.cp_length, p.half_sync, logging) self.connect(lpf, sync) # correct for fine frequency offset computed in sync (up to +-pi/fft_length) # NOTE: frame_acquisition can correct coarse freq offset (i.e. kpi/fft_length) if p.half_sync: nco_sensitivity = 2.0 / p.fft_length else: nco_sensitivity = 1.0 / (p.fft_length + p.cp_length) #nco_sensitivity = 0 nco = gr.frequency_modulator_fc(nco_sensitivity) sigmix = gr.multiply_cc() self.connect((sync, 0), (sigmix, 0)) self.connect((sync, 1), nco, (sigmix, 1)) # sample at symbol boundaries # NOTE: (sync,2) indicates the first sample of the symbol! sampler = raw.ofdm_sampler(p.fft_length, p.fft_length + p.cp_length, timeout=100) self.connect(sigmix, (sampler, 0)) self.connect((sync, 2), (sampler, 1)) # timing signal to sample at # fft on the symbols win = [1 for i in range(p.fft_length)] # see gr_fft_vcc_fftw that it works differently if win = [] fft = gr.fft_vcc(p.fft_length, True, win, True) self.connect((sampler, 0), fft) # use the preamble to correct the coarse frequency offset and initial equalizer frame_acq = raw.ofdm_frame_acquisition(p.fft_length, p.cp_length, p.preambles) self.frame_acq = frame_acq self.connect(fft, (frame_acq, 0)) self.connect((sampler, 1), (frame_acq, 1)) self.connect((frame_acq, 0), (self, 0)) # finished with fine/coarse freq correction self.connect((frame_acq, 1), (self, 1)) # frame and symbol timing if logging: self.connect(lpf, gr.file_sink(gr.sizeof_gr_complex, "rx-filt.dat")) self.connect( fft, gr.file_sink(gr.sizeof_gr_complex * p.fft_length, "rx-fft.dat")) self.connect((frame_acq, 0), gr.file_sink(gr.sizeof_gr_complex * p.occupied_tones, "rx-acq.dat")) self.connect((frame_acq, 1), gr.file_sink(1, "rx-detect.datb")) self.connect( sampler, gr.file_sink(gr.sizeof_gr_complex * p.fft_length, "rx-sampler.dat")) self.connect(sigmix, gr.file_sink(gr.sizeof_gr_complex, "rx-sigmix.dat")) self.connect(nco, gr.file_sink(gr.sizeof_gr_complex, "rx-nco.dat"))
def test_mult_cc(self): src1_data = (1 + 1j, 2 + 2j, 3 + 3j, 4 + 4j, 5 + 5j) src2_data = (8, -3, 4, 8, 2) expected_result = (8 + 8j, -6 - 6j, 12 + 12j, 32 + 32j, 10 + 10j) op = gr.multiply_cc() self.help_cc((src1_data, src2_data), expected_result, op)
def __init__(self, demod_rate, audio_decimation): """ Hierarchical block for demodulating a broadcast FM signal. The input is the downconverted complex baseband signal (gr_complex). The output is two streams of the demodulated audio (float) 0=Left, 1=Right. @param demod_rate: input sample rate of complex baseband input. @type demod_rate: float @param audio_decimation: how much to decimate demod_rate to get to audio. @type audio_decimation: integer """ gr.hier_block2.__init__( self, "wfm_rcv_fmdet", gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature gr.io_signature(2, 2, gr.sizeof_float)) # Output signature lowfreq = -125e3 / demod_rate highfreq = 125e3 / demod_rate audio_rate = demod_rate / audio_decimation # We assign to self so that outsiders can grab the demodulator # if they need to. E.g., to plot its output. # # input: complex; output: float self.fm_demod = gr.fmdet_cf(demod_rate, lowfreq, highfreq, 0.05) # input: float; output: float self.deemph_Left = fm_deemph(audio_rate) self.deemph_Right = fm_deemph(audio_rate) # compute FIR filter taps for audio filter width_of_transition_band = audio_rate / 32 audio_coeffs = gr.firdes.low_pass( 1.0, # gain demod_rate, # sampling rate 15000, width_of_transition_band, gr.firdes.WIN_HAMMING) # input: float; output: float self.audio_filter = gr.fir_filter_fff(audio_decimation, audio_coeffs) if 1: # Pick off the stereo carrier/2 with this filter. It # attenuated 10 dB so apply 10 dB gain We pick off the # negative frequency half because we want to base band by # it! ## NOTE THIS WAS HACKED TO OFFSET INSERTION LOSS DUE TO ## DEEMPHASIS stereo_carrier_filter_coeffs = gr.firdes.complex_band_pass( 10.0, demod_rate, -19020, -18980, width_of_transition_band, gr.firdes.WIN_HAMMING) #print "len stereo carrier filter = ",len(stereo_carrier_filter_coeffs) #print "stereo carrier filter ", stereo_carrier_filter_coeffs #print "width of transition band = ",width_of_transition_band, " audio rate = ", audio_rate # Pick off the double side band suppressed carrier # Left-Right audio. It is attenuated 10 dB so apply 10 dB # gain stereo_dsbsc_filter_coeffs = gr.firdes.complex_band_pass( 20.0, demod_rate, 38000 - 15000 / 2, 38000 + 15000 / 2, width_of_transition_band, gr.firdes.WIN_HAMMING) #print "len stereo dsbsc filter = ",len(stereo_dsbsc_filter_coeffs) #print "stereo dsbsc filter ", stereo_dsbsc_filter_coeffs # construct overlap add filter system from coefficients # for stereo carrier self.stereo_carrier_filter = gr.fir_filter_fcc( audio_decimation, stereo_carrier_filter_coeffs) # carrier is twice the picked off carrier so arrange to do # a commplex multiply self.stereo_carrier_generator = gr.multiply_cc() # Pick off the rds signal stereo_rds_filter_coeffs = gr.firdes.complex_band_pass( 30.0, demod_rate, 57000 - 1500, 57000 + 1500, width_of_transition_band, gr.firdes.WIN_HAMMING) #print "len stereo dsbsc filter = ",len(stereo_dsbsc_filter_coeffs) #print "stereo dsbsc filter ", stereo_dsbsc_filter_coeffs # construct overlap add filter system from coefficients for stereo carrier self.rds_signal_filter = gr.fir_filter_fcc( audio_decimation, stereo_rds_filter_coeffs) self.rds_carrier_generator = gr.multiply_cc() self.rds_signal_generator = gr.multiply_cc() self_rds_signal_processor = gr.null_sink(gr.sizeof_gr_complex) loop_bw = 2 * math.pi / 100.0 max_freq = -2.0 * math.pi * 18990 / audio_rate min_freq = -2.0 * math.pi * 19010 / audio_rate self.stereo_carrier_pll_recovery = gr.pll_refout_cc( loop_bw, max_freq, min_freq) #self.stereo_carrier_pll_recovery.squelch_enable(False) ##pll_refout does not have squelch yet, so disabled for #now # set up mixer (multiplier) to get the L-R signal at # baseband self.stereo_basebander = gr.multiply_cc() # pick off the real component of the basebanded L-R # signal. The imaginary SHOULD be zero self.LmR_real = gr.complex_to_real() self.Make_Left = gr.add_ff() self.Make_Right = gr.sub_ff() self.stereo_dsbsc_filter = gr.fir_filter_fcc( audio_decimation, stereo_dsbsc_filter_coeffs) if 1: # send the real signal to complex filter to pick off the # carrier and then to one side of a multiplier self.connect(self, self.fm_demod, self.stereo_carrier_filter, self.stereo_carrier_pll_recovery, (self.stereo_carrier_generator, 0)) # send the already filtered carrier to the otherside of the carrier # the resulting signal from this multiplier is the carrier # with correct phase but at -38000 Hz. self.connect(self.stereo_carrier_pll_recovery, (self.stereo_carrier_generator, 1)) # send the new carrier to one side of the mixer (multiplier) self.connect(self.stereo_carrier_generator, (self.stereo_basebander, 0)) # send the demphasized audio to the DSBSC pick off filter, the complex # DSBSC signal at +38000 Hz is sent to the other side of the mixer/multiplier # the result is BASEBANDED DSBSC with phase zero! self.connect(self.fm_demod, self.stereo_dsbsc_filter, (self.stereo_basebander, 1)) # Pick off the real part since the imaginary is # theoretically zero and then to one side of a summer self.connect(self.stereo_basebander, self.LmR_real, (self.Make_Left, 0)) #take the same real part of the DSBSC baseband signal and #send it to negative side of a subtracter self.connect(self.LmR_real, (self.Make_Right, 1)) # Make rds carrier by taking the squared pilot tone and # multiplying by pilot tone self.connect(self.stereo_basebander, (self.rds_carrier_generator, 0)) self.connect(self.stereo_carrier_pll_recovery, (self.rds_carrier_generator, 1)) # take signal, filter off rds, send into mixer 0 channel self.connect(self.fm_demod, self.rds_signal_filter, (self.rds_signal_generator, 0)) # take rds_carrier_generator output and send into mixer 1 # channel self.connect(self.rds_carrier_generator, (self.rds_signal_generator, 1)) # send basebanded rds signal and send into "processor" # which for now is a null sink self.connect(self.rds_signal_generator, self_rds_signal_processor) if 1: # pick off the audio, L+R that is what we used to have and # send it to the summer self.connect(self.fm_demod, self.audio_filter, (self.Make_Left, 1)) # take the picked off L+R audio and send it to the PLUS # side of the subtractor self.connect(self.audio_filter, (self.Make_Right, 0)) # The result of Make_Left gets (L+R) + (L-R) and results in 2*L # The result of Make_Right gets (L+R) - (L-R) and results in 2*R self.connect(self.Make_Left, self.deemph_Left, (self, 0)) self.connect(self.Make_Right, self.deemph_Right, (self, 1))
def __init__(self, options, queue): gr.top_block.__init__(self) if options.filename is not None: self.fs = gr.file_source(gr.sizeof_gr_complex, options.filename) self.rate = options.rate else: #self.u = uhd.usrp_source(options.addr, # io_type=uhd.io_type.COMPLEX_FLOAT32, # num_channels=1) self.rtl = osmosdr.source_c(args="nchan=" + str(1) + " " + "") self.rtl.set_sample_rate(options.rate) self.rate = options.rate #self.rtl.get_samp_rate() self.rtl.set_center_freq(options.centerfreq, 0) #self.rtl.set_freq_corr(options.ppm, 0) self.centerfreq = options.centerfreq print "Tuning to: %fMHz" % (self.centerfreq - options.error) if not (self.tune(options.centerfreq - options.error)): print "Failed to set initial frequency" if options.gain is None: options.gain = 10 if options.bbgain is None: options.bbgain = 25 if options.ifgain is None: options.ifgain = 25 print "Setting RF gain to %i" % options.gain print "Setting BB gain to %i" % options.bbgain print "Setting IF gain to %i" % options.ifgain self.rtl.set_gain(options.gain, 0) self.rtl.set_if_gain(options.ifgain, 0) self.rtl.set_bb_gain(options.bbgain, 0) #self.rtl.set_gain_mode(1,0) print "Samples per second is %i" % self.rate self._syms_per_sec = 3600 options.samples_per_second = self.rate options.syms_per_sec = self._syms_per_sec options.gain_mu = 0.01 options.mu = 0.5 options.omega_relative_limit = 0.3 options.syms_per_sec = self._syms_per_sec options.offset = options.centerfreq - options.freq print "Control channel offset: %f" % options.offset self.offset = gr.sig_source_c(self.rate, gr.GR_SIN_WAVE, options.offset, 1.0, 0.0) # for some reason using the xlating filter to do the offset makes thing barf with the HackRF, Multiply CC seems to work options.offset = 0 self.mixer = gr.multiply_cc() self.demod = fsk_demod(options) self.start_correlator = gr.correlate_access_code_tag_bb( "10101100", 0, "smartnet_preamble") #should mark start of packet self.smartnet_deinterleave = smartnet.deinterleave() self.smartnet_crc = smartnet.crc(queue) #rerate = float(self.rate / float(first_decim)) / float(7200) #print "resampling factor: %f\n" % rerate #if rerate.is_integer(): # print "using pfb decimator\n" # self.resamp = blks2.pfb_decimator_ccf(int(rerate)) #else: # print "using pfb resampler\n" # self.resamp = blks2.pfb_arb_resampler_ccf(1 / rerate) if options.filename is None: #self.connect(self.u, self.demod) self.connect(self.rtl, (self.mixer, 0)) self.connect(self.offset, (self.mixer, 1)) self.connect(self.mixer, self.demod) # self.connect(self.rtl, self.demod) else: self.connect(self.fs, self.demod) self.connect(self.demod, self.start_correlator, self.smartnet_deinterleave, self.smartnet_crc) #hook up the audio patch if options.audio: self.audiorate = 48000 self.audiotaps = gr.firdes.low_pass(1, self.rate, 8000, 2000, gr.firdes.WIN_HANN) self.prefilter_decim = int( self.rate / self.audiorate ) #might have to use a rational resampler for audio print "Prefilter decimation: %i" % self.prefilter_decim self.audio_prefilter = gr.freq_xlating_fir_filter_ccf( self.prefilter_decim, #decimation self.audiotaps, #taps 0, #freq offset self.rate) #sampling rate #on a trunked network where you know you will have good signal, a carrier power squelch works well. real FM receviers use a noise squelch, where #the received audio is high-passed above the cutoff and then fed to a reverse squelch. If the power is then BELOW a threshold, open the squelch. #self.squelch = gr.pwr_squelch_cc(options.squelch, #squelch point # alpha = 0.1, #wat # ramp = 10, #wat # gate = False) self.audiodemod = blks2.fm_demod_cf( self.rate / self.prefilter_decim, #rate 1, #audio decimation 4000, #deviation 3000, #audio passband 4000, #audio stopband 1, #gain 75e-6) #deemphasis constant #the filtering removes FSK data woobling from the subaudible channel (might be able to combine w/lpf above) self.audiofilttaps = gr.firdes.high_pass(1, self.audiorate, 300, 50, gr.firdes.WIN_HANN) self.audiofilt = gr.fir_filter_fff(1, self.audiofilttaps) self.audiogain = gr.multiply_const_ff(options.volume) self.audiosink = audio.sink(self.audiorate, "") # self.audiosink = gr.wavfile_sink("test.wav", 1, self.audiorate, 8) #self.mute() if options.filename is None: #self.connect(self.u, self.audio_prefilter) self.connect(self.rtl, self.audio_prefilter) else: self.connect(self.fs, self.audio_prefilter) # self.connect(self.audio_prefilter, self.squelch, self.audiodemod, self.audiofilt, self.audiogain, self.audioresamp, self.audiosink) # real self.connect(self.audio_prefilter, self.squelch, self.audiodemod, self.audiofilt, self.audiogain, self.audiosink) self.connect(self.audio_prefilter, self.audiodemod, self.audiofilt, self.audiogain, self.audiosink)
def __init__(self, options): gr.top_block.__init__(self, "ofdm_tx") self._tx_freq = options.tx_freq # tranmitter's center frequency self._tx_subdev_spec = options.tx_subdev_spec # daughterboard to use self._fusb_block_size = options.fusb_block_size # usb info for USRP self._fusb_nblocks = options.fusb_nblocks # usb info for USRP self._which = options.which_usrp self._bandwidth = options.bandwidth self.servants = [] self._interface = options.interface self._mac_addr = options.mac_addr self._options = copy.copy(options) self._interpolation = 1 f1 = numpy.array([ -107, 0, 445, 0, -1271, 0, 2959, 0, -6107, 0, 11953, 0, -24706, 0, 82359, 262144 / 2, 82359, 0, -24706, 0, 11953, 0, -6107, 0, 2959, 0, -1271, 0, 445, 0, -107 ], numpy.float64) / 262144. print "Software interpolation: %d" % (self._interpolation) bw = 0.5 / self._interpolation tb = bw / 5 if self._interpolation > 1: self.filter = gr.hier_block2( "filter", gr.io_signature(1, 1, gr.sizeof_gr_complex), gr.io_signature(1, 1, gr.sizeof_gr_complex)) self.filter.connect(self.filter, gr.interp_fir_filter_ccf(2, f1), gr.interp_fir_filter_ccf(2, f1), self.filter) print "New" # # # self.filt_coeff = optfir.low_pass(1.0, 1.0, bw, bw+tb, 0.2, 60.0, 0) # self.filter = gr.interp_fir_filter_ccf(self._interpolation,self.filt_coeff) # print "Software interpolation filter length: %d" % (len(self.filt_coeff)) else: self.filter = None if not options.from_file is None: # sent captured file to usrp self.src = gr.file_source(gr.sizeof_gr_complex, options.from_file) self._setup_usrp_sink() if hasattr(self, "filter"): self.connect(self.src, self.filter, self.u) #,self.filter else: self.connect(self.src, self.u) return self._setup_tx_path(options) config = station_configuration() self.enable_info_tx("info_tx", "pa_user") # if not options.no_cheat: # self.txpath.enable_channel_cheating("channelcheat") self.txpath.enable_txpower_adjust("txpower") self.txpath.publish_txpower("txpower_info") #self.enable_txfreq_adjust("txfreq") if options.nullsink: self.dst = gr.null_sink(gr.sizeof_gr_complex) self.dst_2 = gr.null_sink(gr.sizeof_gr_complex) else: if not options.to_file is None: # capture transmitter's stream to disk self.dst = gr.file_sink(gr.sizeof_gr_complex, options.to_file) self.dst_2 = gr.file_sink(gr.sizeof_gr_complex, options.to_file) tmp = gr.throttle(gr.sizeof_gr_complex, 1e5) tmp_2 = gr.throttle(gr.sizeof_gr_complex, 1e5) self.connect(tmp, self.dst) self.connect(tmp_2, self.dst_2) self.dst = tmp self.dst_2 = tmp_2 if options.force_filter: print "Forcing filter usage" self.connect(self.filter, self.dst) self.dst = self.filter else: # connect transmitter to usrp self._setup_usrp_sink() if options.dyn_freq: self.enable_txfreq_adjust("txfreq") if self.filter is not None: self.connect(self.filter, self.dst) self.dst = self.filter if options.record: log_to_file(self, self.txpath, "data/txpath_out.compl") #self.publish_spectrum( 256 ) if options.measure: self.m = throughput_measure(gr.sizeof_gr_complex) self.connect(self.m, self.dst) self.dst = self.m if options.samplingoffset is not None: soff = options.samplingoffset interp = gr.fractional_interpolator_cc(0.0, soff) self.connect(interp, self.dst) self.dst = interp if options.snr is not None: # if options.berm is not None: # noise_sigma = 380 #empirically given, gives the received SNR range of (1:28) for tx amp. range of (500:10000) which is set in rm_ber_measurement.py # #check for fading channel # else: snr_db = options.snr snr = 10.0**(snr_db / 10.0) noise_sigma = sqrt(config.rms_amplitude**2 / snr) print " Noise St. Dev. %d" % (noise_sigma) awgn_chan = gr.add_cc() awgn_noise_src = ofdm.complex_white_noise(0.0, noise_sigma) self.connect(awgn_noise_src, (awgn_chan, 1)) self.connect(awgn_chan, self.dst) self.dst = awgn_chan if options.berm is False: fad_chan = itpp.tdl_channel() #[0, -7, -20], [0, 2, 6] #fad_chan.set_norm_doppler( 1e-9 ) #fad_chan.set_LOS( [500.,0,0] ) fad_chan.set_channel_profile(itpp.ITU_Pedestrian_A, 5e-8) fad_chan.set_norm_doppler(1e-8) # fad_chan = gr.fir_filter_ccc(1,[1.0,0.0,2e-1+0.1j,1e-4-0.04j]) self.connect(fad_chan, self.dst) self.dst = fad_chan if options.freqoff is not None: freq_shift = gr.multiply_cc() norm_freq = options.freqoff / config.fft_length freq_off_src = gr.sig_source_c(1.0, gr.GR_SIN_WAVE, norm_freq, 1.0, 0.0) self.connect(freq_off_src, (freq_shift, 1)) dst = self.dst self.connect(freq_shift, dst) self.dst = freq_shift self.connect((self.txpath, 0), self.dst) self.connect((self.txpath, 1), self.dst_2) if options.cheat: self.txpath.enable_channel_cheating("channelcheat") print "Hit Strg^C to terminate"