def __init__(self): gr.top_block.__init__(self, "Affinity Set Test") ################################################## # Variables ################################################## self.samp_rate = samp_rate = 32000 ################################################## # Blocks ################################################## vec_len = 1 self.gr_throttle_0 = gr.throttle(gr.sizeof_gr_complex*vec_len, samp_rate) self.gr_null_source_0 = gr.null_source(gr.sizeof_gr_complex*vec_len) self.gr_null_sink_0 = gr.null_sink(gr.sizeof_gr_complex*vec_len) self.gr_filt_0 = gr.fir_filter_ccc(1, 40000*[0.2+0.3j,]) self.gr_filt_1 = gr.fir_filter_ccc(1, 40000*[0.2+0.3j,]) self.gr_filt_0.set_processor_affinity([0,]) self.gr_filt_1.set_processor_affinity([0,1]) ################################################## # Connections ################################################## self.connect((self.gr_null_source_0, 0), (self.gr_throttle_0, 0)) self.connect((self.gr_throttle_0, 0), (self.gr_filt_0, 0)) self.connect((self.gr_filt_0, 0), (self.gr_filt_1, 0)) self.connect((self.gr_filt_1, 0), (self.gr_null_sink_0, 0))
def __init__(self, options): gr.hier_block2.__init__(self, "transmit_path", gr.io_signature(0, 0, 0), gr.io_signature(0, 0, 0)) #Set up usrp block self.u = usrp.source_c() adc_rate = self.u.adc_rate() # 64 MS/s usrp_decim = 16 gain = 65 self.u.set_decim_rate(usrp_decim) usrp_rate = adc_rate / usrp_decim # 320 kS/s print usrp_rate #subdev_spec = usrp.pick_subdev(self.u) subdev_spec = (0, 0) mux_value = usrp.determine_rx_mux_value(self.u, subdev_spec) self.u.set_mux(mux_value) self.subdev = usrp.selected_subdev(self.u, subdev_spec) self.subdev.set_gain(gain) self.subdev.set_auto_tr(False) self.subdev.set_enable(True) if not (self.set_freq(915e6)): print "Failed to set initial frequency" #set up the rest of the path deci = 1 self.agc = gr.agc_cc(rate=1e-7, reference=1.0, gain=0.001, max_gain=0.5) matchtaps = [complex(-1, -1)] * 8 + [complex( 1, 1)] * 8 + [complex(-1, -1)] * 8 + [complex(1, 1)] * 8 #matchtaps = [complex(-1,-1)] * 8 + [complex(1,1)] * 8 self.matchfilter = gr.fir_filter_ccc(1, matchtaps) reverse = [complex(1, 1)] * (8 / deci) + [complex( -1, -1)] * (8 / deci) + [complex( 1, 1)] * (8 / deci) + [complex(-1, -1)] * (8 / deci) #pretaps = matchtaps * 3 + reverse * 4 + matchtaps * 4 + reverse * 8 + matchtaps * 6 + matchtaps * 62 pretaps = matchtaps * 2 + reverse * 2 + matchtaps * 2 + reverse * 4 + matchtaps * 3 + matchtaps * 31 #pretaps = matchtaps * 3 + reverse * 8 + matchtaps * 6 + matchtaps * 64 self.preamble_filter = gr.fir_filter_ccc(1, pretaps) self.c_f = gr.complex_to_real() self.c_f2 = gr.complex_to_real() self.lock = howto.lock_time(32, 5, 32) self.pd = howto.find_pre_ff(55, 200) self.dec = symbols_decoder() self.vect = gr.vector_sink_f() #self.connect(self.u, self.agc, self.matchfilter, self.c_f, (self.lock, 0), self.dec, self.vect) #self.connect(self.agc, self.preamble_filter, self.c_f2, self.pd, (self.lock, 1)) self.connect(self.u, self.agc, self.matchfilter, self.c_f, self.vect)
def __init__(self, options): gr.hier_block2.__init__(self, "transmit_path", gr.io_signature(0, 0, 0), gr.io_signature(0, 0, 0)) #Set up usrp block self.u = usrp.source_c() adc_rate = self.u.adc_rate() # 64 MS/s usrp_decim = 16 gain = 65 self.u.set_decim_rate(usrp_decim) usrp_rate = adc_rate / usrp_decim # 320 kS/s print usrp_rate #subdev_spec = usrp.pick_subdev(self.u) subdev_spec = (0,0) mux_value = usrp.determine_rx_mux_value(self.u, subdev_spec) self.u.set_mux(mux_value) self.subdev = usrp.selected_subdev(self.u, subdev_spec) self.subdev.set_gain(gain) self.subdev.set_auto_tr(False) self.subdev.set_enable(True) if not(self.set_freq(915e6)): print "Failed to set initial frequency" #set up the rest of the path deci = 1 self.agc = gr.agc_cc( rate = 1e-7, reference = 1.0, gain = 0.001, max_gain = 0.5) matchtaps = [complex(-1,-1)] * 8 + [complex(1,1)] * 8 + [complex(-1,-1)]* 8 + [complex(1,1)]* 8 #matchtaps = [complex(-1,-1)] * 8 + [complex(1,1)] * 8 self.matchfilter = gr.fir_filter_ccc(1, matchtaps) reverse = [complex(1,1)] * (8 / deci) + [complex(-1,-1)] * (8 / deci) + [complex(1,1)]* (8 / deci) + [complex(-1,-1)]* (8 / deci) #pretaps = matchtaps * 3 + reverse * 4 + matchtaps * 4 + reverse * 8 + matchtaps * 6 + matchtaps * 62 pretaps = matchtaps * 2 + reverse * 2 + matchtaps * 2 + reverse * 4 + matchtaps * 3 + matchtaps * 31 #pretaps = matchtaps * 3 + reverse * 8 + matchtaps * 6 + matchtaps * 64 self.preamble_filter = gr.fir_filter_ccc(1, pretaps) self.c_f = gr.complex_to_real() self.c_f2 = gr.complex_to_real() self.lock = howto.lock_time(32, 5, 32) self.pd = howto.find_pre_ff(55, 200) self.dec = symbols_decoder() self.vect = gr.vector_sink_f() #self.connect(self.u, self.agc, self.matchfilter, self.c_f, (self.lock, 0), self.dec, self.vect) #self.connect(self.agc, self.preamble_filter, self.c_f2, self.pd, (self.lock, 1)) self.connect(self.u, self.agc, self.matchfilter, self.c_f, self.vect)
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 __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 __init__(self, uhd_address, options): gr.top_block.__init__(self) self.uhd_addr = uhd_address self.freq = options.freq self.samp_rate = options.samp_rate self.gain = options.gain self.threshold = options.threshold self.trigger = options.trigger self.uhd_src = uhd.single_usrp_source( device_addr=self.uhd_addr, stream_args=uhd.stream_args('fc32')) self.uhd_src.set_samp_rate(self.samp_rate) self.uhd_src.set_center_freq(self.freq, 0) self.uhd_src.set_gain(self.gain, 0) taps = firdes.low_pass_2(1, 1, 0.4, 0.1, 60) self.chanfilt = gr.fir_filter_ccc(10, taps) self.tagger = gr.burst_tagger(gr.sizeof_gr_complex) # Dummy signaler to collect a burst on known periods data = 1000 * [ 0, ] + 1000 * [ 1, ] self.signal = gr.vector_source_s(data, True) # Energy detector to get signal burst ## use squelch to detect energy self.det = gr.simple_squelch_cc(self.threshold, 0.01) ## convert to mag squared (float) self.c2m = gr.complex_to_mag_squared() ## average to debounce self.avg = gr.single_pole_iir_filter_ff(0.01) ## rescale signal for conversion to short self.scale = gr.multiply_const_ff(2**16) ## signal input uses shorts self.f2s = gr.float_to_short() # Use file sink burst tagger to capture bursts self.fsnk = gr.tagged_file_sink(gr.sizeof_gr_complex, self.samp_rate) ################################################## # Connections ################################################## self.connect((self.uhd_src, 0), (self.tagger, 0)) self.connect((self.tagger, 0), (self.fsnk, 0)) if self.trigger: # Connect a dummy signaler to the burst tagger self.connect((self.signal, 0), (self.tagger, 1)) else: # Connect an energy detector signaler to the burst tagger self.connect(self.uhd_src, self.det) self.connect(self.det, self.c2m, self.avg, self.scale, self.f2s) self.connect(self.f2s, (self.tagger, 1))
def __init__(self, uhd_address, options): gr.top_block.__init__(self) self.uhd_addr = uhd_address self.freq = options.freq self.samp_rate = options.samp_rate self.gain = options.gain self.threshold = options.threshold self.trigger = options.trigger self.uhd_src = uhd.single_usrp_source( device_addr=self.uhd_addr, io_type=uhd.io_type_t.COMPLEX_FLOAT32, num_channels=1, ) self.uhd_src.set_samp_rate(self.samp_rate) self.uhd_src.set_center_freq(self.freq, 0) self.uhd_src.set_gain(self.gain, 0) taps = firdes.low_pass_2(1, 1, 0.4, 0.1, 60) self.chanfilt = gr.fir_filter_ccc(10, taps) self.tagger = gr.burst_tagger(gr.sizeof_gr_complex) # Dummy signaler to collect a burst on known periods data = 1000*[0,] + 1000*[1,] self.signal = gr.vector_source_s(data, True) # Energy detector to get signal burst ## use squelch to detect energy self.det = gr.simple_squelch_cc(self.threshold, 0.01) ## convert to mag squared (float) self.c2m = gr.complex_to_mag_squared() ## average to debounce self.avg = gr.single_pole_iir_filter_ff(0.01) ## rescale signal for conversion to short self.scale = gr.multiply_const_ff(2**16) ## signal input uses shorts self.f2s = gr.float_to_short() # Use file sink burst tagger to capture bursts self.fsnk = gr.tagged_file_sink(gr.sizeof_gr_complex, self.samp_rate) ################################################## # Connections ################################################## self.connect((self.uhd_src, 0), (self.tagger, 0)) self.connect((self.tagger, 0), (self.fsnk, 0)) if self.trigger: # Connect a dummy signaler to the burst tagger self.connect((self.signal, 0), (self.tagger, 1)) else: # Connect an energy detector signaler to the burst tagger self.connect(self.uhd_src, self.det) self.connect(self.det, self.c2m, self.avg, self.scale, self.f2s) self.connect(self.f2s, (self.tagger, 1))
def build_graph (input, output, coeffs, mag): # Initialize empty flow graph fg = gr.top_block () # Set up file source src = gr.file_source (gr.sizeof_gr_complex, input) # Read coefficients for 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) # If the output is magnitude, it is float, else its complex if mag: magnitude = gr.complex_to_mag(1) dst = gr.file_sink (gr.sizeof_float, output) fg.connect(src, mfilter, magnitude, dst) else: dst = gr.file_sink (gr.sizeof_gr_complex, output) fg.connect(src, mfilter, dst) return fg
def __init__(self, rx, reader, tx): gr.top_block.__init__(self) samp_freq = (64 / dec_rate) * 1e6 amplitude = 33000 num_taps = int( 64000 / (dec_rate * up_link_freq * 2)) #Matched filter for 1/2 cycle taps = [complex(1, 1)] * num_taps print num_taps filt = gr.fir_filter_ccc(sw_dec, taps) to_mag = gr.complex_to_mag() amp = gr.multiply_const_cc(amplitude) c_gate = rfid.cmd_gate(dec_rate * sw_dec, reader.STATE_PTR) zc = rfid.clock_recovery_zc_ff(samples_per_pulse, 2) dummy = gr.null_sink(gr.sizeof_float) to_complex = gr.float_to_complex() r = gr.enable_realtime_scheduling() if r != gr.RT_OK: print "Warning: failed to enable realtime scheduling" self.connect(rx, filt, to_mag, c_gate, zc, reader, amp, tx)
def __init__(self, tx, zc, reader, rx, matched_filter, reader_monitor_cmd_gate, cr, tag_monitor, amplitude): gr.top_block.__init__(self) # ASK/PSK demodulators to_mag_L = gr.complex_to_mag() to_mag_R = gr.complex_to_mag() # Others blocks for Buettner's reader samp_freq = (64 / dec_rate) * 1e6 num_taps = int(64000 / (dec_rate * up_link_freq * 4)) taps = [complex(1, 1)] * num_taps filt = gr.fir_filter_ccc(sw_dec, taps) # Matched filter amp = gr.multiply_const_cc(amplitude) c_gate = rfid.cmd_gate(dec_rate * sw_dec, reader.STATE_PTR) # Null sink for terminating the Listener graph null_sink = gr.null_sink(gr.sizeof_float * 1) # Deinterleaver to separate FPGA channels di = gr.deinterleave(gr.sizeof_gr_complex) # Enable real-time scheduling r = gr.enable_realtime_scheduling() if r != gr.RT_OK: print "Warning: failed to enable realtime scheduling" # Create flow-graph self.connect(rx, di) self.connect((di, 0), filt, to_mag_R, c_gate, zc, reader, amp, tx) self.connect((di, 1), matched_filter, to_mag_L, reader_monitor_cmd_gate, cr, tag_monitor, null_sink)
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, rx, reader, tx): gr.top_block.__init__(self) samp_freq = (64 / dec_rate) * 1e6 amplitude = 33000 num_taps = int(64000 / (dec_rate * up_link_freq * 2)) #Matched filter for 1/2 cycle taps = [complex(1,1)] * num_taps print num_taps filt = gr.fir_filter_ccc(sw_dec, taps) to_mag = gr.complex_to_mag() amp = gr.multiply_const_cc(amplitude) c_gate = rfid.cmd_gate(dec_rate * sw_dec, reader.STATE_PTR) zc = rfid.clock_recovery_zc_ff(samples_per_pulse, 2); dummy = gr.null_sink(gr.sizeof_float) to_complex = gr.float_to_complex() r = gr.enable_realtime_scheduling() if r != gr.RT_OK: print "Warning: failed to enable realtime scheduling" self.connect(rx, filt, to_mag, c_gate, zc, reader, amp, tx);
def __init__(self, options, args, queue): gr.top_block.__init__(self) self.options = options self.args = args rate = int(options.rate) if options.filename is None: self.u = uhd.single_usrp_source("", uhd.io_type_t.COMPLEX_FLOAT32, 1) if(options.rx_subdev_spec is None): options.rx_subdev_spec = "" self.u.set_subdev_spec(options.rx_subdev_spec) if not options.antenna is None: self.u.set_antenna(options.antenna) self.u.set_samp_rate(rate) rate = int(self.u.get_samp_rate()) #retrieve actual if options.gain is None: #set to halfway g = self.u.get_gain_range() options.gain = (g.start()+g.stop()) / 2.0 if not(self.tune(options.freq)): print "Failed to set initial frequency" print "Setting gain to %i" % (options.gain,) self.u.set_gain(options.gain) print "Gain is %i" % (self.u.get_gain(),) else: self.u = gr.file_source(gr.sizeof_gr_complex, options.filename) print "Rate is %i" % (rate,) pass_all = 0 if options.output_all : pass_all = 1 self.demod = gr.complex_to_mag() self.avg = gr.moving_average_ff(100, 1.0/100, 400) #the DBSRX especially tends to be spur-prone; the LPF keeps out the #spur multiple that shows up at 2MHz self.lpfiltcoeffs = gr.firdes.low_pass(1, rate, 1.8e6, 200e3) self.lpfilter = gr.fir_filter_ccc(1, self.lpfiltcoeffs) self.preamble = air.modes_preamble(rate, options.threshold) #self.framer = air.modes_framer(rate) self.slicer = air.modes_slicer(rate, queue) self.connect(self.u, self.lpfilter, self.demod) self.connect(self.demod, self.avg) self.connect(self.demod, (self.preamble, 0)) self.connect(self.avg, (self.preamble, 1)) self.connect((self.preamble, 0), (self.slicer, 0))
def reference_filter_ccc(dec, taps, input): """ compute result using conventional fir filter """ tb = gr.top_block() #src = gr.vector_source_c(((0,) * (len(taps) - 1)) + input) src = gr.vector_source_c(input) op = gr.fir_filter_ccc(dec, taps) dst = gr.vector_sink_c() tb.connect(src, op, dst) tb.run() return dst.data()
def __init__(self, filename="usrp.dat", output="frames.dat", decim=16, pll_alpha=0.05, sync_alpha=0.05): gr.top_block.__init__(self, "USRP HRPT Receiver") ################################################## # Parameters ################################################## self.filename = filename self.output = output self.decim = decim self.pll_alpha = pll_alpha self.sync_alpha = sync_alpha ################################################## # Variables ################################################## self.sym_rate = sym_rate = 600*1109 self.sample_rate = sample_rate = 64e6/decim self.sps = sps = sample_rate/sym_rate self.hs = hs = int(sps/2.0) self.mf_taps = mf_taps = [-0.5/hs,]*hs+[0.5/hs,]*hs self.max_sync_offset = max_sync_offset = 0.01 self.max_carrier_offset = max_carrier_offset = 2*math.pi*100e3/sample_rate ################################################## # Blocks ################################################## self.decoder = noaa.hrpt_decoder() self.deframer = noaa.hrpt_deframer() self.deinterleave = gr.deinterleave(gr.sizeof_float*1) self.f2c = gr.float_to_complex(1) self.file_sink = gr.file_sink(gr.sizeof_short*1, output) self.file_source = gr.file_source(gr.sizeof_short*1, filename, False) self.gr_fir_filter_xxx_0 = gr.fir_filter_ccc(1, (mf_taps)) self.pll = noaa.hrpt_pll_cf(pll_alpha, pll_alpha**2/4.0, max_carrier_offset) self.s2f = gr.short_to_float() self.sync = noaa.hrpt_sync_fb(sync_alpha, sync_alpha**2/4.0, sps, max_sync_offset) ################################################## # Connections ################################################## self.connect((self.deframer, 0), (self.file_sink, 0)) self.connect((self.sync, 0), (self.deframer, 0)) self.connect((self.pll, 0), (self.sync, 0)) self.connect((self.deinterleave, 1), (self.f2c, 1)) self.connect((self.deinterleave, 0), (self.f2c, 0)) self.connect((self.deframer, 0), (self.decoder, 0)) self.connect((self.gr_fir_filter_xxx_0, 0), (self.pll, 0)) self.connect((self.f2c, 0), (self.gr_fir_filter_xxx_0, 0)) self.connect((self.s2f, 0), (self.deinterleave, 0)) self.connect((self.file_source, 0), (self.s2f, 0))
def build_graph(input, output, acq_coeffs, sync_coeffs, sync_thresh, sync_window): # Initialize our top block fg = gr.top_block() # Source is a file src = gr.file_source (gr.sizeof_gr_complex, input) # Read coefficients for the acquisition filter (FIR filter) dfile = open(acq_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) # Our matched filter! # Read coefficients for the sync block dfile = open(sync_coeffs, 'r') data = [] for line in dfile: data.append(complex(*map(float,line.strip().strip("()").split(" "))).conjugate()) dfile.close() sync = cmusdrg.mf_sync_ccf(data) # Sync block! # Delay component, to sync the original complex with MF output delay = gr.delay(gr.sizeof_gr_complex, len(data)-1) # Acquisition filter with threshold and window acq = cmusdrg.acquisition_filter_ccc(sync_thresh, sync_window) # Connect complex input to matched filter and delay fg.connect(src, mfilter) fg.connect(src, delay) # Connect the mfilter and delay to the acquisition filter fg.connect(mfilter, (acq, 0)) fg.connect(delay, (acq, 1)) # Connect the acquisition filter to the sync block fg.connect((acq, 0), (sync, 0)) fg.connect((acq, 1), (sync, 1)) # Two file sinks for the output fsink = gr.file_sink (gr.sizeof_char, output+"_sync") fsink2 = gr.file_sink (gr.sizeof_gr_complex, output+"_acq") fg.connect((acq,0), fsink2) fg.connect(sync, fsink) return fg
def __init__(self, noise_dB=-20., fir_taps=[1]): gr.hier_block2.__init__(self, 'my_channel', gr.io_signature(1,1,gr.sizeof_gr_complex), gr.io_signature(1,1,gr.sizeof_gr_complex)) noise_adder = gr.add_cc() noise = gr.noise_source_c(gr.GR_GAUSSIAN, 10**(noise_dB/20.), random.randint(0,2**30)) # normalize taps firtabsum = float(sum(map(abs,fir_taps))) fir_taps = [ i / firtabsum for i in fir_taps] multipath = gr.fir_filter_ccc(1,fir_taps) self.connect(noise, (noise_adder,1)) self.connect(self, noise_adder, multipath, self) self.__dict__.update(locals()) # didn't feel like using self all over the place
def __init__(self, noise_dB=-20., fir_taps=[1]): gr.hier_block2.__init__(self, 'my_channel', gr.io_signature(1, 1, gr.sizeof_gr_complex), gr.io_signature(1, 1, gr.sizeof_gr_complex)) noise_adder = gr.add_cc() noise = gr.noise_source_c(gr.GR_GAUSSIAN, 10**(noise_dB / 20.), random.randint(0, 2**30)) # normalize taps firtabsum = float(sum(map(abs, fir_taps))) fir_taps = [i / firtabsum for i in fir_taps] multipath = gr.fir_filter_ccc(1, fir_taps) self.connect(noise, (noise_adder, 1)) self.connect(self, noise_adder, multipath, self) self.__dict__.update( locals()) # didn't feel like using self all over the place
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 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): gr.hier_block2.__init__(self, "multipath_channel", gr.io_signature(1, 1, gr.sizeof_gr_complex), gr.io_signature(1, 1, gr.sizeof_gr_complex)) #self.taps = [1.0, .2, 0.0, .1, .08, -.4, .12, -.2, 0, 0, 0, .3] self.length = 8 a = 24.0 / 10 / (8 - 1) * log(10.0) x = [exp(-a * i) for i in range(self.length)] # i.i.d. in [0.0,1.0) y = [ 0.27599478430000000, 0.34303317230500000, 0.24911284691022517, 0.19471409268935069, 0.98794533144803298, 0.36772813703828844, 0.008240459082489604, 0.26629172049386607, 0.3308407474924715, 0.17198856343625069, 0.30433761100062451, 0.55081856590567013, 0.41045093976820779, 0.28842125692731335, 0.54050922175406835, 0.419704078137786185, 0.23368258618886051, 0.78509149901607134, 0.29433609371058278, 0.60536839932433595 ] tapsize = 4 self.taps = numpy.array([0.0j] * (self.length * tapsize)) for i in range(self.length): self.taps[i * tapsize] = x[i] * exp(1j * 2 * pi * y[i]) gain = sqrt(sum(absolute(self.taps)**2)) self.taps /= gain self.chan = gr.fir_filter_ccc(1, self.taps) self.connect(self, self.chan, self) try: gr.hier_block.update_var_names(self, "multipath_channel", vars()) gr.hier_block.update_var_names(self, "multipath_channel", vars(self)) except: pass
def build_graph(input, output, acq_coeffs, sync_thresh, sync_window): # Initialize our top block fg = gr.top_block() # Source is a file src = gr.file_source (gr.sizeof_gr_complex, input) # Read coefficients for the acquisition filter (FIR filter) dfile = open(acq_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) # Our matched filter! # delay = gr.delay(gr.sizeof_gr_complex, len(data)-1) acq = cmusdrg.acquisition_filter_ccc(sync_thresh, sync_window) power = gr.complex_to_mag(1) # Connect complex input to matched filter and delay fg.connect(src, mfilter) # fg.connect(src, delay) # Connect the mfilter and delay to the acquisition filter fg.connect(mfilter, (acq, 0)) fg.connect(src, (acq, 1)) # Connect the delay component to compute the power fg.connect((acq,1), power) # Two file sinks for the output fsink = gr.file_sink (gr.sizeof_float, output+"_power") fsink2 = gr.file_sink (gr.sizeof_gr_complex, output+"_acq") fg.connect(power, fsink) fg.connect((acq,0), fsink2) return fg
def __init__(self): gr.hier_block2.__init__(self, "multipath_channel", gr.io_signature(1,1,gr.sizeof_gr_complex), gr.io_signature(1,1,gr.sizeof_gr_complex)) #self.taps = [1.0, .2, 0.0, .1, .08, -.4, .12, -.2, 0, 0, 0, .3] self.length = 8 a = 24.0/10 / (8-1) * log(10.0) x = [exp(-a*i) for i in range(self.length)] # i.i.d. in [0.0,1.0) y = [0.27599478430000000, 0.34303317230500000, 0.24911284691022517, 0.19471409268935069, 0.98794533144803298, 0.36772813703828844, 0.008240459082489604, 0.26629172049386607, 0.3308407474924715, 0.17198856343625069, 0.30433761100062451, 0.55081856590567013, 0.41045093976820779, 0.28842125692731335, 0.54050922175406835, 0.419704078137786185, 0.23368258618886051, 0.78509149901607134, 0.29433609371058278, 0.60536839932433595] tapsize = 4 self.taps = numpy.array([0.0j]*(self.length*tapsize)) for i in range(self.length): self.taps[i*tapsize] = x[i] * exp(1j*2*pi*y[i]) gain = sqrt(sum(absolute(self.taps)**2)) self.taps /= gain self.chan = gr.fir_filter_ccc(1, self.taps) self.connect(self, self.chan, self) try: gr.hier_block.update_var_names(self, "multipath_channel", vars()) gr.hier_block.update_var_names(self, "multipath_channel", vars(self)) except: pass
def __init__(self, options): gr.hier_block2.__init__( self, "ais_demod", gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature gr.io_signature(1, 1, gr.sizeof_char), ) # Output signature self._samples_per_symbol = options.samples_per_symbol self._bits_per_sec = options.bits_per_sec self._samplerate = self._samples_per_symbol * self._bits_per_sec self._gain_mu = options.gain_mu self._mu = options.mu self._omega_relative_limit = options.omega_relative_limit self.fftlen = options.fftlen # right now we are going to hardcode the different options for VA mode here. later on we can use configurable options samples_per_symbol_viterbi = 2 bits_per_symbol = 2 samples_per_symbol = 6 samples_per_symbol_clockrec = samples_per_symbol / bits_per_symbol BT = 0.4 data_rate = 9600.0 samp_rate = options.samp_rate self.gmsk_sync = gmsk_sync.square_and_fft_sync(self._samplerate, self._bits_per_sec, self.fftlen) if options.viterbi is True: # calculate the required decimation and interpolation to achieve the desired samples per symbol denom = gcd(data_rate * samples_per_symbol, samp_rate) cr_interp = int(data_rate * samples_per_symbol / denom) cr_decim = int(samp_rate / denom) self.resample = blks2.rational_resampler_ccc(cr_interp, cr_decim) # here we take a different tack and use A.A.'s CPM decomposition technique self.clockrec = gr.clock_recovery_mm_cc( samples_per_symbol_clockrec, 0.005 * 0.005 * 0.25, 0.5, 0.005, 0.0005 ) # might have to futz with the max. deviation (fsm, constellation, MF, N, f0T) = make_gmsk( samples_per_symbol_viterbi, BT ) # calculate the decomposition required for demodulation self.costas = gr.costas_loop_cc( 0.015, 0.015 * 0.015 * 0.25, 100e-6, -100e-6, 4 ) # does fine freq/phase synchronization. should probably calc the coeffs instead of hardcode them. self.streams2stream = gr.streams_to_stream(int(gr.sizeof_gr_complex * 1), int(N)) self.mf0 = gr.fir_filter_ccc( samples_per_symbol_viterbi, MF[0].conjugate() ) # two matched filters for decomposition self.mf1 = gr.fir_filter_ccc(samples_per_symbol_viterbi, MF[1].conjugate()) self.fo = gr.sig_source_c( samples_per_symbol_viterbi, gr.GR_COS_WAVE, -f0T, 1, 0 ) # the memoryless modulation component of the decomposition self.fomult = gr.multiply_cc(1) self.trellis = trellis.viterbi_combined_cb( fsm, int(data_rate), -1, -1, int(N), constellation, trellis.TRELLIS_EUCLIDEAN ) # the actual Viterbi decoder else: # this is probably not optimal and someone who knows what they're doing should correct me self.datafiltertaps = gr.firdes.root_raised_cosine( 10, # gain self._samplerate * 32, # sample rate self._bits_per_sec, # symbol rate 0.4, # alpha, same as BT? 50 * 32, ) # no. of taps self.datafilter = gr.fir_filter_fff(1, self.datafiltertaps) sensitivity = (math.pi / 2) / self._samples_per_symbol self.demod = gr.quadrature_demod_cf(sensitivity) # param is gain # self.clockrec = digital.clock_recovery_mm_ff(self._samples_per_symbol,0.25*self._gain_mu*self._gain_mu,self._mu,self._gain_mu,self._omega_relative_limit) self.clockrec = gr.pfb_clock_sync_ccf(self._samples_per_symbol, 0.04, self.datafiltertaps, 32, 0, 1.15) self.tcslicer = digital.digital.binary_slicer_fb() # self.dfe = digital.digital.lms_dd_equalizer_cc( # 32, # 0.005, # 1, # digital.digital.constellation_bpsk() # ) # self.delay = gr.delay(gr.sizeof_float, 64 + 16) #the correlator delays 64 bits, and the LMS delays some as well. self.slicer = digital.digital.binary_slicer_fb() # self.training_correlator = digital.correlate_access_code_bb("1100110011001100", 0) # self.cma = digital.cma_equalizer_cc # just a note here: a complex combined quad demod/slicer could be based on if's rather than an actual quad demod, right? # in fact all the constellation decoders up to QPSK could operate on complex data w/o doing the whole atan thing self.diff = gr.diff_decoder_bb(2) self.invert = ais.invert() # NRZI signal diff decoded and inverted should give original signal self.connect(self, self.gmsk_sync) if options.viterbi is False: self.connect(self.gmsk_sync, self.clockrec, self.demod, self.slicer, self.diff, self.invert, self) # self.connect(self.gmsk_sync, self.demod, self.clockrec, self.tcslicer, self.training_correlator) # self.connect(self.clockrec, self.delay, (self.dfe, 0)) # self.connect(self.training_correlator, (self.dfe, 1)) # self.connect(self.dfe, self.slicer, self.diff, self.invert, self) else: self.connect(self.gmsk_sync, self.costas, self.resample, self.clockrec) self.connect(self.clockrec, (self.fomult, 0)) self.connect(self.fo, (self.fomult, 1)) self.connect(self.fomult, self.mf0) self.connect(self.fomult, self.mf1) self.connect(self.mf0, (self.streams2stream, 0)) self.connect(self.mf1, (self.streams2stream, 1)) self.connect(self.streams2stream, self.trellis, self.diff, self.invert, self)
def run_test(seed, blocksize): tb = gr.top_block() ################################################## # Variables ################################################## M = 2 K = 1 P = 2 h = (1.0 * K) / P L = 3 Q = 4 frac = 0.99 f = trellis.fsm(P, M, L) # CPFSK signals #p = numpy.ones(Q)/(2.0) #q = numpy.cumsum(p)/(1.0*Q) # GMSK signals BT = 0.3 tt = numpy.arange(0, L * Q) / (1.0 * Q) - L / 2.0 #print tt p = (0.5 * scipy.stats.erfc(2 * math.pi * BT * (tt - 0.5) / math.sqrt( math.log(2.0)) / math.sqrt(2.0)) - 0.5 * scipy.stats.erfc( 2 * math.pi * BT * (tt + 0.5) / math.sqrt(math.log(2.0)) / math.sqrt(2.0))) / 2.0 p = p / sum(p) * Q / 2.0 #print p q = numpy.cumsum(p) / Q q = q / q[-1] / 2.0 #print q (f0T, SS, S, F, Sf, Ff, N) = fsm_utils.make_cpm_signals(K, P, M, L, q, frac) #print N #print Ff Ffa = numpy.insert(Ff, Q, numpy.zeros(N), axis=0) #print Ffa MF = numpy.fliplr(numpy.transpose(Ffa)) #print MF E = numpy.sum(numpy.abs(Sf)**2, axis=0) Es = numpy.sum(E) / f.O() #print Es constellation = numpy.reshape(numpy.transpose(Sf), N * f.O()) #print Ff #print Sf #print constellation #print numpy.max(numpy.abs(SS - numpy.dot(Ff , Sf))) EsN0_db = 10.0 N0 = Es * 10.0**(-(1.0 * EsN0_db) / 10.0) #N0 = 0.0 #print N0 head = 4 tail = 4 numpy.random.seed(seed * 666) data = numpy.random.randint(0, M, head + blocksize + tail + 1) #data = numpy.zeros(blocksize+1+head+tail,'int') for i in range(head): data[i] = 0 for i in range(tail + 1): data[-i] = 0 ################################################## # Blocks ################################################## random_source_x_0 = gr.vector_source_b(data.tolist(), False) gr_chunks_to_symbols_xx_0 = gr.chunks_to_symbols_bf((-1, 1), 1) gr_interp_fir_filter_xxx_0 = gr.interp_fir_filter_fff(Q, p) gr_frequency_modulator_fc_0 = gr.frequency_modulator_fc(2 * math.pi * h * (1.0 / Q)) gr_add_vxx_0 = gr.add_vcc(1) gr_noise_source_x_0 = gr.noise_source_c(gr.GR_GAUSSIAN, (N0 / 2.0)**0.5, -long(seed)) gr_multiply_vxx_0 = gr.multiply_vcc(1) gr_sig_source_x_0 = gr.sig_source_c(Q, gr.GR_COS_WAVE, -f0T, 1, 0) # only works for N=2, do it manually for N>2... gr_fir_filter_xxx_0_0 = gr.fir_filter_ccc(Q, MF[0].conjugate()) gr_fir_filter_xxx_0_0_0 = gr.fir_filter_ccc(Q, MF[1].conjugate()) gr_streams_to_stream_0 = gr.streams_to_stream(gr.sizeof_gr_complex * 1, int(N)) gr_skiphead_0 = gr.skiphead(gr.sizeof_gr_complex * 1, int(N * (1 + 0))) viterbi = trellis.viterbi_combined_cb(f, head + blocksize + tail, 0, -1, int(N), constellation, digital.TRELLIS_EUCLIDEAN) gr_vector_sink_x_0 = gr.vector_sink_b() ################################################## # Connections ################################################## tb.connect((random_source_x_0, 0), (gr_chunks_to_symbols_xx_0, 0)) tb.connect((gr_chunks_to_symbols_xx_0, 0), (gr_interp_fir_filter_xxx_0, 0)) tb.connect((gr_interp_fir_filter_xxx_0, 0), (gr_frequency_modulator_fc_0, 0)) tb.connect((gr_frequency_modulator_fc_0, 0), (gr_add_vxx_0, 0)) tb.connect((gr_noise_source_x_0, 0), (gr_add_vxx_0, 1)) tb.connect((gr_add_vxx_0, 0), (gr_multiply_vxx_0, 0)) tb.connect((gr_sig_source_x_0, 0), (gr_multiply_vxx_0, 1)) tb.connect((gr_multiply_vxx_0, 0), (gr_fir_filter_xxx_0_0, 0)) tb.connect((gr_multiply_vxx_0, 0), (gr_fir_filter_xxx_0_0_0, 0)) tb.connect((gr_fir_filter_xxx_0_0, 0), (gr_streams_to_stream_0, 0)) tb.connect((gr_fir_filter_xxx_0_0_0, 0), (gr_streams_to_stream_0, 1)) tb.connect((gr_streams_to_stream_0, 0), (gr_skiphead_0, 0)) tb.connect((gr_skiphead_0, 0), (viterbi, 0)) tb.connect((viterbi, 0), (gr_vector_sink_x_0, 0)) tb.run() dataest = gr_vector_sink_x_0.data() #print data #print numpy.array(dataest) perr = 0 err = 0 for i in range(blocksize): if data[head + i] != dataest[head + i]: #print i err += 1 if err != 0: perr = 1 return (err, perr)
def __init__(self): grc_wxgui.top_block_gui.__init__(self, title="USRP HRPT Receiver") ################################################## # Variables ################################################## self.config_filename = config_filename = 'usrp_rx_hrpt.cfg' self._decim_config = ConfigParser.ConfigParser() self._decim_config.read(config_filename) try: decim = self._decim_config.getfloat('usrp', 'decim') except: decim = 16 self.decim = decim self.sym_rate = sym_rate = 600*1109 self.sample_rate = sample_rate = 64e6/decim self.sps = sps = sample_rate/sym_rate self._side_config = ConfigParser.ConfigParser() self._side_config.read(config_filename) try: side = self._side_config.get('usrp', 'side') except: side = 'A' self.side = side self._saved_sync_alpha_config = ConfigParser.ConfigParser() self._saved_sync_alpha_config.read(config_filename) try: saved_sync_alpha = self._saved_sync_alpha_config.getfloat('demod', 'sync_alpha') except: saved_sync_alpha = 0.05 self.saved_sync_alpha = saved_sync_alpha self._saved_pll_alpha_config = ConfigParser.ConfigParser() self._saved_pll_alpha_config.read(config_filename) try: saved_pll_alpha = self._saved_pll_alpha_config.getfloat('demod', 'pll_alpha') except: saved_pll_alpha = 0.05 self.saved_pll_alpha = saved_pll_alpha self._saved_gain_config = ConfigParser.ConfigParser() self._saved_gain_config.read(config_filename) try: saved_gain = self._saved_gain_config.getfloat('usrp', 'gain') except: saved_gain = 35 self.saved_gain = saved_gain self._saved_freq_config = ConfigParser.ConfigParser() self._saved_freq_config.read(config_filename) try: saved_freq = self._saved_freq_config.getfloat('usrp', 'freq') except: saved_freq = 1698e6 self.saved_freq = saved_freq self.hs = hs = int(sps/2.0) self.sync_alpha = sync_alpha = saved_sync_alpha self.side_text = side_text = side self.pll_alpha = pll_alpha = saved_pll_alpha self._output_filename_config = ConfigParser.ConfigParser() self._output_filename_config.read(config_filename) try: output_filename = self._output_filename_config.get('output', 'filename') except: output_filename = 'frames.dat' self.output_filename = output_filename self.mf_taps = mf_taps = [-0.5/hs,]*hs+[0.5/hs,]*hs self.max_sync_offset = max_sync_offset = 0.01 self.max_carrier_offset = max_carrier_offset = 2*math.pi*100e3/sample_rate self.gain = gain = saved_gain self.freq = freq = saved_freq self.decim_text = decim_text = decim ################################################## # Controls ################################################## _sync_alpha_sizer = wx.BoxSizer(wx.VERTICAL) self._sync_alpha_text_box = forms.text_box( parent=self.GetWin(), sizer=_sync_alpha_sizer, value=self.sync_alpha, callback=self.set_sync_alpha, label="SYNC Alpha", converter=forms.float_converter(), proportion=0, ) self._sync_alpha_slider = forms.slider( parent=self.GetWin(), sizer=_sync_alpha_sizer, value=self.sync_alpha, callback=self.set_sync_alpha, minimum=0.0, maximum=0.5, num_steps=100, style=wx.SL_HORIZONTAL, cast=float, proportion=1, ) self.GridAdd(_sync_alpha_sizer, 0, 3, 1, 1) self._side_text_static_text = forms.static_text( parent=self.GetWin(), value=self.side_text, callback=self.set_side_text, label="USRP Side", converter=forms.str_converter(), ) self.GridAdd(self._side_text_static_text, 1, 0, 1, 1) _pll_alpha_sizer = wx.BoxSizer(wx.VERTICAL) self._pll_alpha_text_box = forms.text_box( parent=self.GetWin(), sizer=_pll_alpha_sizer, value=self.pll_alpha, callback=self.set_pll_alpha, label="PLL Alpha", converter=forms.float_converter(), proportion=0, ) self._pll_alpha_slider = forms.slider( parent=self.GetWin(), sizer=_pll_alpha_sizer, value=self.pll_alpha, callback=self.set_pll_alpha, minimum=0.0, maximum=0.5, num_steps=100, style=wx.SL_HORIZONTAL, cast=float, proportion=1, ) self.GridAdd(_pll_alpha_sizer, 0, 2, 1, 1) _gain_sizer = wx.BoxSizer(wx.VERTICAL) self._gain_text_box = forms.text_box( parent=self.GetWin(), sizer=_gain_sizer, value=self.gain, callback=self.set_gain, label="RX Gain", converter=forms.float_converter(), proportion=0, ) self._gain_slider = forms.slider( parent=self.GetWin(), sizer=_gain_sizer, value=self.gain, callback=self.set_gain, minimum=0, maximum=100, num_steps=100, style=wx.SL_HORIZONTAL, cast=float, proportion=1, ) self.GridAdd(_gain_sizer, 0, 1, 1, 1) self._freq_text_box = forms.text_box( parent=self.GetWin(), value=self.freq, callback=self.set_freq, label="Frequency", converter=forms.float_converter(), ) self.GridAdd(self._freq_text_box, 0, 0, 1, 1) self._decim_text_static_text = forms.static_text( parent=self.GetWin(), value=self.decim_text, callback=self.set_decim_text, label="Decimation", converter=forms.float_converter(), ) self.GridAdd(self._decim_text_static_text, 1, 1, 1, 1) ################################################## # Blocks ################################################## self.agc = gr.agc_cc(1e-6, 1.0, 1.0, 1.0) self.decoder = noaa.hrpt_decoder() self.deframer = noaa.hrpt_deframer() self.frame_sink = gr.file_sink(gr.sizeof_short*1, output_filename) self.gr_fir_filter_xxx_0 = gr.fir_filter_ccc(1, (mf_taps)) self.pll = noaa.hrpt_pll_cf(pll_alpha, pll_alpha**2/4.0, max_carrier_offset) self.pll_scope = scopesink2.scope_sink_f( self.GetWin(), title="Demod Waveform", sample_rate=sample_rate, v_scale=0.5, t_scale=20.0/sample_rate, ac_couple=False, xy_mode=False, num_inputs=1, ) self.GridAdd(self.pll_scope.win, 2, 0, 1, 4) self.sync = noaa.hrpt_sync_fb(sync_alpha, sync_alpha**2/4.0, sps, max_sync_offset) self.usrp_source = grc_usrp.simple_source_c(which=0, side=side, rx_ant="RXA") self.usrp_source.set_decim_rate(decim) self.usrp_source.set_frequency(freq, verbose=True) self.usrp_source.set_gain(gain) ################################################## # Connections ################################################## self.connect((self.gr_fir_filter_xxx_0, 0), (self.pll, 0)) self.connect((self.agc, 0), (self.gr_fir_filter_xxx_0, 0)) self.connect((self.usrp_source, 0), (self.agc, 0)) self.connect((self.deframer, 0), (self.decoder, 0)) self.connect((self.pll, 0), (self.pll_scope, 0)) self.connect((self.pll, 0), (self.sync, 0)) self.connect((self.sync, 0), (self.deframer, 0)) self.connect((self.deframer, 0), (self.frame_sink, 0))
def __init__(self, options): gr.hier_block2.__init__(self, "ais_demod", gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature gr.io_signature(1, 1, gr.sizeof_char)) # Output signature self._samples_per_symbol = options.samples_per_symbol self._bits_per_sec = options.bits_per_sec self._samplerate = self._samples_per_symbol * self._bits_per_sec self._gain_mu = options.gain_mu self._mu = options.mu self._omega_relative_limit = options.omega_relative_limit self.fftlen = options.fftlen #right now we are going to hardcode the different options for VA mode here. later on we can use configurable options samples_per_symbol_viterbi = 2 bits_per_symbol = 2 samples_per_symbol = 6 samples_per_symbol_clockrec = samples_per_symbol / bits_per_symbol BT = 0.4 data_rate = 9600.0 samp_rate = options.samp_rate self.gmsk_sync = gmsk_sync.square_and_fft_sync(self._samplerate, self._bits_per_sec, self.fftlen) if(options.viterbi is True): #calculate the required decimation and interpolation to achieve the desired samples per symbol denom = gcd(data_rate*samples_per_symbol, samp_rate) cr_interp = int(data_rate*samples_per_symbol/denom) cr_decim = int(samp_rate/denom) self.resample = blks2.rational_resampler_ccc(cr_interp, cr_decim) #here we take a different tack and use A.A.'s CPM decomposition technique self.clockrec = gr.clock_recovery_mm_cc(samples_per_symbol_clockrec, 0.005*0.005*0.25, 0.5, 0.005, 0.0005) #might have to futz with the max. deviation (fsm, constellation, MF, N, f0T) = make_gmsk(samples_per_symbol_viterbi, BT) #calculate the decomposition required for demodulation self.costas = gr.costas_loop_cc(0.015, 0.015*0.015*0.25, 100e-6, -100e-6, 4) #does fine freq/phase synchronization. should probably calc the coeffs instead of hardcode them. self.streams2stream = gr.streams_to_stream(int(gr.sizeof_gr_complex*1), int(N)) self.mf0 = gr.fir_filter_ccc(samples_per_symbol_viterbi, MF[0].conjugate()) #two matched filters for decomposition self.mf1 = gr.fir_filter_ccc(samples_per_symbol_viterbi, MF[1].conjugate()) self.fo = gr.sig_source_c(samples_per_symbol_viterbi, gr.GR_COS_WAVE, -f0T, 1, 0) #the memoryless modulation component of the decomposition self.fomult = gr.multiply_cc(1) self.trellis = trellis.viterbi_combined_cb(fsm, int(data_rate), -1, -1, int(N), constellation, trellis.TRELLIS_EUCLIDEAN) #the actual Viterbi decoder else: #this is probably not optimal and someone who knows what they're doing should correct me self.datafiltertaps = gr.firdes.root_raised_cosine(10, #gain self._samplerate*32, #sample rate self._bits_per_sec, #symbol rate 0.4, #alpha, same as BT? 50*32) #no. of taps self.datafilter = gr.fir_filter_fff(1, self.datafiltertaps) sensitivity = (math.pi / 2) / self._samples_per_symbol self.demod = gr.quadrature_demod_cf(sensitivity) #param is gain #self.clockrec = digital.clock_recovery_mm_ff(self._samples_per_symbol,0.25*self._gain_mu*self._gain_mu,self._mu,self._gain_mu,self._omega_relative_limit) self.clockrec = gr.pfb_clock_sync_ccf(self._samples_per_symbol, 0.04, self.datafiltertaps, 32, 0, 1.15) self.tcslicer = digital.digital.binary_slicer_fb() # self.dfe = digital.digital.lms_dd_equalizer_cc( # 32, # 0.005, # 1, # digital.digital.constellation_bpsk() # ) # self.delay = gr.delay(gr.sizeof_float, 64 + 16) #the correlator delays 64 bits, and the LMS delays some as well. self.slicer = digital.digital.binary_slicer_fb() # self.training_correlator = digital.correlate_access_code_bb("1100110011001100", 0) # self.cma = digital.cma_equalizer_cc #just a note here: a complex combined quad demod/slicer could be based on if's rather than an actual quad demod, right? #in fact all the constellation decoders up to QPSK could operate on complex data w/o doing the whole atan thing self.diff = gr.diff_decoder_bb(2) self.invert = ais.invert() #NRZI signal diff decoded and inverted should give original signal self.connect(self, self.gmsk_sync) if(options.viterbi is False): self.connect(self.gmsk_sync, self.clockrec, self.demod, self.slicer, self.diff, self.invert, self) #self.connect(self.gmsk_sync, self.demod, self.clockrec, self.tcslicer, self.training_correlator) #self.connect(self.clockrec, self.delay, (self.dfe, 0)) #self.connect(self.training_correlator, (self.dfe, 1)) #self.connect(self.dfe, self.slicer, self.diff, self.invert, self) else: self.connect(self.gmsk_sync, self.costas, self.resample, self.clockrec) self.connect(self.clockrec, (self.fomult, 0)) self.connect(self.fo, (self.fomult, 1)) self.connect(self.fomult, self.mf0) self.connect(self.fomult, self.mf1) self.connect(self.mf0, (self.streams2stream, 0)) self.connect(self.mf1, (self.streams2stream, 1)) self.connect(self.streams2stream, self.trellis, self.diff, self.invert, self)
def __init__ (self, options): gr.top_block.__init__(self, "ofdm_benchmark") ##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._verbose = options.verbose ##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 = 1.0/self._interpolation tb = bw/5 if self._interpolation > 1: self.tx_filter = gr.hier_block2("filter", gr.io_signature(1,1,gr.sizeof_gr_complex), gr.io_signature(1,1,gr.sizeof_gr_complex)) self.tx_filter2 = gr.hier_block2("filter", gr.io_signature(1,1,gr.sizeof_gr_complex), gr.io_signature(1,1,gr.sizeof_gr_complex)) self.tx_filter.connect( self.tx_filter, gr.interp_fir_filter_ccf(2,f1), gr.interp_fir_filter_ccf(2,f1), self.tx_filter ) self.tx_filter2.connect( self.tx_filter2, gr.interp_fir_filter_ccf(2,f1), gr.interp_fir_filter_ccf(2,f1), self.tx_filter2 ) print "New" else: self.tx_filter = None self.tx_filter2 = None self.decimation = 1 if self.decimation > 1: bw = 0.5/self.decimation * 1 tb = bw/5 # gain, sampling rate, passband cutoff, stopband cutoff # passband ripple in dB, stopband attenuation in dB # extra taps filt_coeff = optfir.low_pass(1.0, 1.0, bw, bw+tb, 0.1, 60.0, 1) print "Software decimation filter length: %d" % (len(filt_coeff)) self.rx_filter = gr.fir_filter_ccf(self.decimation,filt_coeff) self.rx_filter2 = gr.fir_filter_ccf(self.decimation,filt_coeff) else: self.rx_filter = None self.rx_filter2 = 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) self._setup_rx_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") if options.disable_equalization or options.ideal: #print "CHANGE set_k" self.rxpath.enable_estim_power_adjust("estim_power") #self.rxpath.publish_estim_power("txpower_info") #self.enable_txfreq_adjust("txfreq") if options.imgxfer: self.rxpath.setup_imgtransfer_sink() if not options.no_decoding: self.rxpath.publish_rx_performance_measure() self.dst = (self.rxpath,0) self.dst2 = (self.rxpath,1) if options.force_rx_filter: print "Forcing rx filter usage" self.connect( self.rx_filter, self.dst ) self.connect( self.rx_filter2, self.dst2 ) self.dst = self.rx_filter self.dst2 = self.rx_filter2 if options.measure: self.m = throughput_measure(gr.sizeof_gr_complex) self.m2 = throughput_measure(gr.sizeof_gr_complex) self.connect( self.m, self.dst ) self.connect( self.m2, self.dst2 ) self.dst = self.m self.dst2 = self.m2 if options.snr is not None: if options.berm is not False: 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 = blocks.add_cc() awgn_chan2 = blocks.add_cc() awgn_noise_src = ofdm.complex_white_noise( 0.0, noise_sigma ) awgn_noise_src2 = ofdm.complex_white_noise( 0.0, noise_sigma ) self.connect( awgn_chan, self.dst ) self.connect( awgn_chan2, self.dst2 ) self.connect( awgn_noise_src, (awgn_chan,1) ) self.connect( awgn_noise_src2, (awgn_chan2,1) ) self.dst = awgn_chan self.dst2 = awgn_chan2 if options.freqoff is not None: freq_shift = blocks.multiply_cc() freq_shift2 = blocks.multiply_cc() norm_freq = options.freqoff / config.fft_length freq_off_src = analog.sig_source_c(1.0, analog.GR_SIN_WAVE, norm_freq, 1.0, 0.0 ) freq_off_src2 = analog.sig_source_c(1.0, analog.GR_SIN_WAVE, norm_freq, 1.0, 0.0 ) self.connect( freq_off_src, ( freq_shift, 1 ) ) self.connect( freq_off_src2, ( freq_shift2, 1 ) ) dst = self.dst dst2 = self.dst2 self.connect( freq_shift, dst ) self.connect( freq_shift2, dst2 ) self.dst = freq_shift self.dst2 = freq_shift2 if options.multipath: if options.itu_channel: 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_chan2 = itpp.tdl_channel( ) fad_chan.set_channel_profile( itpp.ITU_Pedestrian_A, 5e-8 ) fad_chan.set_norm_doppler( 1e-8 ) fad_chan2.set_channel_profile( itpp.ITU_Pedestrian_A, 5e-8 ) fad_chan2.set_norm_doppler( 1e-8 ) else: fad_chan = gr.fir_filter_ccc(1,[1.0,0.0,2e-1+0.1j,1e-4-0.04j]) fad_chan2 = gr.fir_filter_ccc(1,[1.0,0.0,2e-1+0.1j,1e-4-0.04j]) self.connect( fad_chan, self.dst ) self.connect( fad_chan2, self.dst2 ) self.dst = fad_chan self.dst2 = fad_chan2 if options.samplingoffset is not None: soff = options.samplingoffset interp = moms(1000000+soff,1000000) interp2 = moms(1000000+soff,1000000) self.connect( interp, self.dst ) self.connect( interp2, self.dst2 ) self.dst = interp self.dst2 = interp2 if options.record: log_to_file( self, interp, "data/interp_out.compl" ) log_to_file( self, interp2, "data/interp2_out.compl" ) tmm =blocks.throttle(gr.sizeof_gr_complex,self._bandwidth) tmm2 =blocks.throttle(gr.sizeof_gr_complex,self._bandwidth) tmm_add = blocks.add_cc() tmm2_add = blocks.add_cc() self.connect( tmm, tmm_add ) self.connect( tmm2, (tmm_add,1) ) self.connect( tmm, tmm2_add ) self.connect( tmm2, (tmm2_add,1) ) self.connect( tmm_add, self.dst ) self.connect( tmm2_add, self.dst2 ) self.dst = tmm self.dst2 = tmm2 inter = blocks.interleave(gr.sizeof_gr_complex) deinter = blocks.deinterleave(gr.sizeof_gr_complex) self.connect(inter, deinter) self.connect((deinter,0),self.dst) self.connect((deinter,1),self.dst2) self.dst = inter self.dst2 = (inter,1) if options.force_tx_filter: print "Forcing tx filter usage" self.connect( self.tx_filter, self.dst ) self.connect( self.tx_filter2, self.dst2 ) self.dst = self.tx_filter self.dst2 = self.tx_filter2 if options.record: log_to_file( self, self.txpath, "data/txpath_out.compl" ) log_to_file( self, self.txpath2, "data/txpath2_out.compl" ) if options.nullsink: self.connect(gr.null_source(gr.sizeof_gr_complex), self.dst) self.connect(gr.null_source(gr.sizeof_gr_complex), self.dst2) self.dst = gr.null_sink(gr.sizeof_gr_complex) self.dst2 = gr.null_sink(gr.sizeof_gr_complex) self.connect( self.txpath,self.dst ) self.connect( (self.txpath,1),self.dst2 ) if options.cheat: self.txpath.enable_channel_cheating("channelcheat") print "Hit Strg^C to terminate" if options.event_rxbaseband: self.publish_rx_baseband_measure() if options.with_old_gui: self.publish_spectrum(256) self.rxpath.publish_ctf("ctf_display") self.rxpath.publish_ber_measurement(["ber"]) self.rxpath.publish_average_snr(["totalsnr"]) if options.sinr_est: self.rxpath.publish_sinrsc("sinrsc_display") print "Hit Strg^C to terminate" # Display some information about the setup if self._verbose: self._print_verbage()
def __init__(self): # GUI setup grc_wxgui.top_block_gui.__init__(self, title="Grc Wisp Reader") self.wxgui_scopesink2_0 = scopesink2.scope_sink_f( self.GetWin(), title="Scope Plot", sample_rate=1e6, v_scale=0, v_offset=0, t_scale=0, ac_couple=False, xy_mode=False, num_inputs=1, trig_mode=gr.gr_TRIG_MODE_AUTO, y_axis_label="Counts", ) self.Add(self.wxgui_scopesink2_0.win) # Constants amplitude = 1 interp_rate = 128 dec_rate = 16 # dec_rate = 8 sw_dec = 2 # sw_dec = 4 num_taps = int(64000 / (( dec_rate * 4) * 256 )) #Filter matched to 1/4 of the 256 kHz tag cycle # num_taps = int(64000 / ( (dec_rate * 4) * 40 )) #Filter matched to 1/4 of the 40 kHz tag cycle #--------------------------- #num_taps==3 #taps =[complex(1,1)] * num_taps = [(1+1j)]*3 = [(1+1j),(1+1j),(1+1j)] # #"complex" creates complex numbers # complex(x,y) = x+yj (x are the real part of the number and y are the complex part of the number) # #[complex(x,y)]*size = size tells how many complex numbers will be created #[complex(1,1)]*3 = [(1+1j),(1+1j),(1+1j)] #--------------------------- taps = [complex(1, 1)] * num_taps matched_filt = gr.fir_filter_ccc(sw_dec, taps); to_mag = gr.complex_to_mag() center = rfid.center_ff(4) # center = rfid.center_ff(10) mm = rfid.clock_recovery_zc_ff(4, 1); self.reader = rfid.reader_f(int(128e6 / interp_rate)); tag_decoder = rfid.tag_decoder_f() command_gate = rfid.command_gate_cc(12, 60, 64000000 / dec_rate / sw_dec) # command_gate = rfid.command_gate_cc(12, 250, 64000000 / dec_rate / sw_dec) to_complex = gr.float_to_complex() amp = gr.multiply_const_ff(amplitude) ################################################## # Blocks ################################################## freq = 915e6 rx_gain = 1 # Transmitter setup tx = uhd.usrp_sink( device_addr="", io_type=uhd.io_type.COMPLEX_FLOAT32, num_channels=1, ) tx.set_samp_rate(128e6 / interp_rate) tx.set_center_freq(freq, 0) # Receiver setup rx = uhd.usrp_source( device_addr="", io_type=uhd.io_type.COMPLEX_FLOAT32, num_channels=1, ) rx.set_samp_rate(64e6 / dec_rate) rx.set_center_freq(freq, 0) rx.set_gain(rx_gain, 0) # Command gate command_gate.set_ctrl_out(self.reader.ctrl_q()) # Tag decoder tag_decoder.set_ctrl_out(self.reader.ctrl_q()) #########Build Graph self.connect(rx, matched_filt) self.connect(matched_filt, command_gate) self.connect(command_gate, to_mag) # self.connect(command_gate, agc) # agc = gr.agc2_cc(0.3, 1e-3, 1, 1, 100) # self.connect(agc, to_mag) self.connect(to_mag, center, mm, tag_decoder) # self.connect(to_mag, center, matched_filt_tag_decode, tag_decoder) self.connect(tag_decoder, self.reader) self.connect(self.reader, amp) self.connect(amp, to_complex) self.connect(to_complex, tx)
def __init__(self, fft_length, cp_length, kstime, threshold, threshold_type, threshold_gap, logging=False): """ OFDM synchronization using PN Correlation: T. M. Schmidl and D. C. Cox, "Robust Frequency and Timing Synchonization for OFDM," IEEE Trans. Communications, vol. 45, no. 12, 1997. """ gr.hier_block2.__init__( self, "ofdm_sync_pn", gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature gr.io_signature2(2, 2, gr.sizeof_float, gr.sizeof_char)) # Output signature self.input = gr.add_const_cc(0) # PN Sync # Create a delay line self.delay = gr.delay(gr.sizeof_gr_complex, fft_length / 2) # Correlation from ML Sync self.conjg = gr.conjugate_cc() self.corr = gr.multiply_cc() # Create a moving sum filter for the corr output if 1: moving_sum_taps = [1.0 for i in range(fft_length // 2)] self.moving_sum_filter = gr.fir_filter_ccf(1, moving_sum_taps) else: moving_sum_taps = [ complex(1.0, 0.0) for i in range(fft_length // 2) ] self.moving_sum_filter = gr.fft_filter_ccc(1, moving_sum_taps) # Create a moving sum filter for the input self.inputmag2 = gr.complex_to_mag_squared() movingsum2_taps = [1.0 for i in range(fft_length // 2)] #movingsum2_taps = [0.5 for i in range(fft_length*4)] #apurv - implementing Veljo's suggestion, when pause b/w packets if 1: self.inputmovingsum = gr.fir_filter_fff(1, movingsum2_taps) else: self.inputmovingsum = gr.fft_filter_fff(1, movingsum2_taps) self.square = gr.multiply_ff() self.normalize = gr.divide_ff() # Get magnitude (peaks) and angle (phase/freq error) self.c2mag = gr.complex_to_mag_squared() self.angle = gr.complex_to_arg() self.sample_and_hold = gr.sample_and_hold_ff() #ML measurements input to sampler block and detect self.sub1 = gr.add_const_ff(-1) self.pk_detect = gr.peak_detector_fb( 0.20, 0.20, 30, 0.001 ) #apurv - implementing Veljo's suggestion, when pause b/w packets self.connect(self, self.input) # Calculate the frequency offset from the correlation of the preamble self.connect(self.input, self.delay) self.connect(self.input, (self.corr, 0)) self.connect(self.delay, self.conjg) self.connect(self.conjg, (self.corr, 1)) self.connect(self.corr, self.moving_sum_filter) #self.connect(self.moving_sum_filter, self.c2mag) self.connect(self.moving_sum_filter, self.angle) self.connect(self.angle, (self.sample_and_hold, 0)) # apurv-- #self.connect(self.angle, gr.delay(gr.sizeof_float, offset), (self.sample_and_hold, 0)) #apurv++ cross_correlate = 1 if cross_correlate == 1: # cross-correlate with the known symbol kstime = [k.conjugate() for k in kstime] kstime.reverse() self.crosscorr_filter = gr.fir_filter_ccc(1, kstime) # get the magnitude # self.corrmag = gr.complex_to_mag_squared() self.f2b = gr.float_to_char() self.threshold_factor = threshold #0.0012 #0.012 #0.0015 if 0: self.slice = gr.threshold_ff(self.threshold_factor, self.threshold_factor, 0, fft_length) else: #thresholds = [self.threshold_factor, 9e-5] self.slice = gr.threshold_ff(threshold, threshold, 0, fft_length, threshold_type, threshold_gap) self.connect(self.input, self.crosscorr_filter, self.corrmag, self.slice, self.f2b) # some debug dump # self.connect(self.corrmag, gr.file_sink(gr.sizeof_float, "ofdm_corrmag.dat")) #self.connect(self.f2b, gr.file_sink(gr.sizeof_char, "ofdm_f2b.dat")) self.connect(self.f2b, (self.sample_and_hold, 1)) # Set output signals # Output 0: fine frequency correction value # Output 1: timing signal self.connect(self.sample_and_hold, (self, 0)) #self.connect(self.pk_detect, (self,1)) #removed #self.connect(self.f2b, gr.delay(gr.sizeof_char, 1), (self, 1)) self.connect(self.f2b, (self, 1)) if logging: self.connect( self.matched_filter, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-mf_f.dat")) self.connect( self.normalize, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-theta_f.dat")) self.connect( self.angle, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-epsilon_f.dat")) self.connect( self.pk_detect, gr.file_sink(gr.sizeof_char, "ofdm_sync_pn-peaks_b.dat")) self.connect( self.sample_and_hold, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-sample_and_hold_f.dat")) self.connect( self.input, gr.file_sink(gr.sizeof_gr_complex, "ofdm_sync_pn-input_c.dat"))
def __init__(self, demodulator, rx_callback0, rx_callback1, options): gr.top_block.__init__(self) use_source = None if(options.rx_freq is not None): # Work-around to get the modulation's bits_per_symbol args = demodulator.extract_kwargs_from_options(options) symbol_rate = options.bitrate / demodulator(**args).bits_per_symbol() self.source = uhd_receiver(options.args, symbol_rate, options.samples_per_symbol, options.rx_freq, options.rx_gain, options.spec, options.antenna, options.verbose) options.samples_per_symbol = self.source._sps use_source = self.source elif(options.from_file is not None): sys.stderr.write(("Reading samples from '%s'.\n\n" % (options.from_file))) self.source = gr.file_source(gr.sizeof_gr_complex, options.from_file) self.throttle = gr.throttle(gr.sizeof_gr_complex*1, options.file_samp_rate) self.connect(self.source, self.throttle) use_source = self.throttle else: sys.stderr.write("No source defined, pulling samples from null source.\n\n") self.source = gr.null_source(gr.sizeof_gr_complex) # Set up receive path # do this after for any adjustments to the options that may # occur in the sinks (specifically the UHD sink) self.rxpath = [ ] self.rxpath.append(receive_path(demodulator, rx_callback0, options)) self.rxpath.append(receive_path(demodulator, rx_callback1, options)) samp_rate = 0 if(options.rx_freq is not None): samp_rate = self.source.get_sample_rate() else: samp_rate = options.file_samp_rate print "SAMP RATE " + str(samp_rate) band_transition = options.band_trans_width low_transition = options.low_trans_width guard_width = options.guard_width self.band_pass_filter_qv0 = gr.fir_filter_ccc(1, firdes.complex_band_pass( 1, samp_rate, 0e3+guard_width, samp_rate/2-guard_width, band_transition, firdes.WIN_HAMMING, 6.76)) self.freq_translate_qv0 = filter.freq_xlating_fir_filter_ccc(1, (options.num_taps, ), samp_rate/4, samp_rate) self.low_pass_filter_qv0 = gr.fir_filter_ccf(2, firdes.low_pass( 1, samp_rate, samp_rate/4-guard_width/2, low_transition, firdes.WIN_HAMMING, 6.76)) self.band_pass_filter_qv1 = gr.fir_filter_ccc(1, firdes.complex_band_pass( 1, samp_rate, (-samp_rate/2)+guard_width, 0e3-guard_width, band_transition, firdes.WIN_HAMMING, 6.76)) self.freq_translate_qv1 = filter.freq_xlating_fir_filter_ccc(1, (options.num_taps, ), -samp_rate/4, samp_rate) self.low_pass_filter_qv1 = gr.fir_filter_ccf(2, firdes.low_pass( 1, samp_rate, samp_rate/4-guard_width/2, low_transition, firdes.WIN_HAMMING, 6.76)) self.connect(use_source, self.band_pass_filter_qv0) self.connect((self.band_pass_filter_qv0, 0), (self.freq_translate_qv0, 0)) self.connect((self.freq_translate_qv0, 0), (self.low_pass_filter_qv0, 0)) self.connect((self.low_pass_filter_qv0, 0), (self.rxpath[0], 0)) self.connect(use_source, self.band_pass_filter_qv1) self.connect((self.band_pass_filter_qv1, 0), (self.freq_translate_qv1, 0)) self.connect((self.freq_translate_qv1, 0), (self.low_pass_filter_qv1, 0)) self.connect((self.low_pass_filter_qv1, 0), (self.rxpath[1], 0))
def __init__(self, options): gr.hier_block2.__init__(self, "transmit_path", gr.io_signature(0, 0, 0), gr.io_signature(2, 2, gr.sizeof_gr_complex)) common_options.defaults(options) config = self.config = station_configuration() config.data_subcarriers = options.subcarriers config.cp_length = options.cp_length config.frame_data_blocks = options.data_blocks config._verbose = options.verbose config.fft_length = options.fft_length config.training_data = default_block_header(config.data_subcarriers, config.fft_length, options) config.tx_station_id = options.station_id config.coding = options.coding if config.tx_station_id is None: raise SystemError, "Station ID not set" config.frame_id_blocks = 1 # FIXME # digital rms amplitude sent to USRP rms_amp = options.rms_amplitude self._options = copy.copy(options) self.servants = [] # FIXME config.block_length = config.fft_length + config.cp_length config.frame_data_part = config.frame_data_blocks + config.frame_id_blocks config.frame_length = config.frame_data_part + \ config.training_data.no_pilotsyms config.subcarriers = config.data_subcarriers + \ config.training_data.pilot_subcarriers config.virtual_subcarriers = config.fft_length - config.subcarriers # default values if parameters not set if rms_amp is None: rms_amp = math.sqrt(config.subcarriers) config.rms_amplitude = rms_amp # check some bounds if config.fft_length < config.subcarriers: raise SystemError, "Subcarrier number must be less than FFT length" if config.fft_length < config.cp_length: raise SystemError, "Cyclic prefix length must be less than FFT length" ## shortcuts blen = config.block_length flen = config.frame_length dsubc = config.data_subcarriers vsubc = config.virtual_subcarriers # ------------------------------------------------------------------------ # # Adaptive Transmitter Concept used_id_bits = config.used_id_bits = 8 #TODO: no constant in source code rep_id_bits = config.rep_id_bits = config.data_subcarriers / used_id_bits #BPSK if config.data_subcarriers % used_id_bits <> 0: raise SystemError, "Data subcarriers need to be multiple of %d" % ( used_id_bits) ## Control Part if options.debug: self._control = ctrl = static_tx_control(options) print "Statix TX Control used" else: self._control = ctrl = corba_tx_control(options) print "CORBA TX Control used" id_src = (ctrl, 0) mux_src = (ctrl, 1) map_src = self._map_src = (ctrl, 2) pa_src = (ctrl, 3) if options.log: id_src_f = gr.short_to_float() self.connect(id_src, id_src_f) log_to_file(self, id_src_f, "data/id_src_out.float") mux_src_f = gr.short_to_float() self.connect(mux_src, mux_src_f) log_to_file(self, mux_src_f, "data/mux_src_out.float") map_src_s = blocks.vector_to_stream(gr.sizeof_char, config.data_subcarriers) map_src_f = gr.char_to_float() self.connect(map_src, map_src_s, map_src_f) ##log_to_file(self, map_src_f, "data/map_src.float") ##log_to_file(self, pa_src, "data/pa_src_out.float") ## Workaround to avoid periodic structure seed(1) whitener_pn = [ randint(0, 1) for i in range(used_id_bits * rep_id_bits) ] ## ID Encoder id_enc = self._id_encoder = repetition_encoder_sb( used_id_bits, rep_id_bits, whitener_pn) self.connect(id_src, id_enc) if options.log: id_enc_f = gr.char_to_float() self.connect(id_enc, id_enc_f) log_to_file(self, id_enc_f, "data/id_enc_out.float") ## Bitmap Update Trigger # TODO #bmaptrig_stream = concatenate([[1, 2],[0]*(config.frame_data_part-7)]) bmaptrig_stream = concatenate([[1, 1], [0] * (config.frame_data_part - 2)]) print "bmaptrig_stream = ", bmaptrig_stream btrig = self._bitmap_trigger = blocks.vector_source_b( bmaptrig_stream.tolist(), True) if options.log: log_to_file(self, btrig, "data/bitmap_trig.char") ## Bitmap Update Trigger for puncturing # TODO if not options.nopunct: #bmaptrig_stream_puncturing = concatenate([[1],[0]*(config.frame_data_part-2)]) bmaptrig_stream_puncturing = concatenate( [[1], [0] * (config.frame_data_blocks / 2 - 1)]) btrig_puncturing = self._bitmap_trigger_puncturing = blocks.vector_source_b( bmaptrig_stream_puncturing.tolist(), True) bmapsrc_stream_puncturing = concatenate([[1] * dsubc, [2] * dsubc]) bsrc_puncturing = self._bitmap_src_puncturing = blocks.vector_source_b( bmapsrc_stream_puncturing.tolist(), True, dsubc) if options.log and options.coding and not options.nopunct: log_to_file(self, btrig_puncturing, "data/bitmap_trig_puncturing.char") ## Frame Trigger # TODO ftrig_stream = concatenate([[1], [0] * (config.frame_data_part - 1)]) ftrig = self._frame_trigger = blocks.vector_source_b( ftrig_stream.tolist(), True) ## Data Multiplexer # Input 0: control stream # Input 1: encoded ID stream # Inputs 2..n: data streams dmux = self._data_multiplexer = stream_controlled_mux_b() self.connect(mux_src, (dmux, 0)) self.connect(id_enc, (dmux, 1)) self._data_multiplexer_nextport = 2 if options.log: dmux_f = gr.char_to_float() self.connect(dmux, dmux_f) log_to_file(self, dmux_f, "data/dmux_out.float") ## Modulator mod = self._modulator = generic_mapper_bcv(config.data_subcarriers, options.coding) self.connect(dmux, (mod, 0)) self.connect(map_src, (mod, 1)) self.connect(btrig, (mod, 2)) if options.log: log_to_file(self, mod, "data/mod_out.compl") modi = gr.complex_to_imag(config.data_subcarriers) modr = gr.complex_to_real(config.data_subcarriers) self.connect(mod, modi) self.connect(mod, modr) log_to_file(self, modi, "data/mod_imag_out.float") log_to_file(self, modr, "data/mod_real_out.float") ## Power allocator if options.debug: ## static pa = self._power_allocator = power_allocator( config.data_subcarriers) self.connect(mod, (pa, 0)) self.connect(pa_src, (pa, 1)) else: ## with CORBA control event channel ns_ip = ctrl.ns_ip ns_port = ctrl.ns_port evchan = ctrl.evchan pa = self._power_allocator = corba_power_allocator(dsubc, \ evchan, ns_ip, ns_port, True) self.connect(mod, (pa, 0)) self.connect(id_src, (pa, 1)) self.connect(ftrig, (pa, 2)) if options.log: log_to_file(self, pa, "data/pa_out.compl") ## Pilot subcarriers psubc = self._pilot_subcarrier_inserter = pilot_subcarrier_inserter() self.connect(pa, psubc) pilot_subc = config.training_data.shifted_pilot_tones print "pilot_subc", pilot_subc stc = stc_encoder(config.subcarriers, config.frame_data_blocks, pilot_subc) self.connect(psubc, stc) if options.log: log_to_file(self, psubc, "data/psubc_out.compl") log_to_file(self, psubc_2, "data/psubc2_out.compl") log_to_file(self, pa, "data/pa.compl") log_to_file(self, (stc, 0), "data/stc_0.compl") log_to_file(self, (stc, 1), "data/stc_1.compl") ## Add virtual subcarriers if config.fft_length > config.subcarriers: vsubc = self._virtual_subcarrier_extender = \ vector_padding(config.subcarriers, config.fft_length) self.connect(stc, vsubc) vsubc_2 = self._virtual_subcarrier_extender_2 = \ vector_padding(config.subcarriers, config.fft_length) self.connect((stc, 1), vsubc_2) else: vsubc = self._virtual_subcarrier_extender = psubc vsubc_2 = self._virtual_subcarrier_extender_2 = psubc_2 log_to_file(self, psubc, "data/psubc.compl") log_to_file(self, stc, "data/stc1.compl") log_to_file(self, (stc, 1), "data/stc2.compl") if options.log: log_to_file(self, vsubc, "data/vsubc_out.compl") log_to_file(self, vsubc_2, "data/vsubc2_out.compl") ## IFFT, no window, block shift ifft = self._ifft = fft_blocks.fft_vcc(config.fft_length, False, [], True) self.connect(vsubc, ifft) ifft_2 = self._ifft_2 = fft_blocks.fft_vcc(config.fft_length, False, [], True) self.connect(vsubc_2, ifft_2) if options.log: log_to_file(self, ifft, "data/ifft_out.compl") log_to_file(self, ifft_2, "data/ifft2_out.compl") ## Pilot blocks (preambles) pblocks = self._pilot_block_inserter = pilot_block_inserter(1, False) self.connect(ifft, pblocks) pblocks_2 = self._pilot_block_inserter_2 = pilot_block_inserter( 2, False) self.connect(ifft_2, pblocks_2) if options.log: log_to_file(self, pblocks, "data/pilot_block_ins_out.compl") log_to_file(self, pblocks_2, "data/pilot_block_ins2_out.compl") ## Cyclic Prefix cp = self._cyclic_prefixer = cyclic_prefixer(config.fft_length, config.block_length) self.connect(pblocks, cp) cp_2 = self._cyclic_prefixer_2 = cyclic_prefixer( config.fft_length, config.block_length) self.connect(pblocks_2, cp_2) lastblock = cp lastblock_2 = cp_2 if options.log: log_to_file(self, cp, "data/cp_out.compl") log_to_file(self, cp_2, "data/cp2_out.compl") if options.cheat: ## Artificial Channel # kept to compare with previous system achan_ir = concatenate([[1.0], [0.0] * (config.cp_length - 1)]) achan = self._artificial_channel = gr.fir_filter_ccc(1, achan_ir) self.connect(lastblock, achan) lastblock = achan achan_2 = self._artificial_channel_2 = gr.fir_filter_ccc( 1, achan_ir) self.connect(lastblock_2, achan_2) lastblock_2 = achan_2 ## Digital Amplifier amp = self._amplifier = ofdm.multiply_const_ccf(1.0 / math.sqrt(2)) self.connect(lastblock, amp) amp_2 = self._amplifier_2 = ofdm.multiply_const_ccf(1.0 / math.sqrt(2)) self.connect(lastblock_2, amp_2) self.set_rms_amplitude(rms_amp) if options.log: log_to_file(self, amp, "data/amp_tx_out.compl") log_to_file(self, amp_2, "data/amp_tx2_out.compl") ## Setup Output self.connect(amp, (self, 0)) self.connect(amp_2, (self, 1)) # ------------------------------------------------------------------------ # # Display some information about the setup if config._verbose: self._print_verbage()
def __init__(self, fft_length, cp_length, half_sync, kstime, ks1time, threshold, 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) # offset by -1 phi = gr.sample_and_hold_ff() self.corrmag = gr.complex_to_mag_squared() P_d_angle = gr.complex_to_arg() self.connect(P_d, P_d_angle, (phi, 0)) cross_correlate = 1 if cross_correlate == 1: # cross-correlate with the known symbol kstime = [k.conjugate() for k in kstime] kstime.reverse() self.crosscorr_filter = gr.fir_filter_ccc(1, kstime) """ self.f2b = gr.float_to_char() self.slice = gr.threshold_ff(threshold, threshold, 0, fft_length) #self.connect(self, self.crosscorr_filter, self.corrmag, self.slice, self.f2b) self.connect(self.f2b, (phi,1)) self.connect(self.f2b, (self,2)) self.connect(self.f2b, gr.file_sink(gr.sizeof_char, "ofdm_f2b.dat")) """ # new method starts here - only crosscorrelate and use peak_detect block # peak_detect = gr.peak_detector_fb(100, 100, 30, 0.001) self.corrmag1 = gr.complex_to_mag_squared() self.connect(self, self.crosscorr_filter, self.corrmag, peak_detect) self.connect(peak_detect, (phi, 1)) self.connect(peak_detect, (self, 2)) self.connect(peak_detect, gr.file_sink(gr.sizeof_char, "sync-peaks_b.dat")) self.connect(self.corrmag, gr.file_sink(gr.sizeof_float, "ofdm_corrmag.dat")) self.connect(self, gr.delay(gr.sizeof_gr_complex, (fft_length)), (self, 0)) else: # 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 matched_filter = gr.moving_average_ff(cp_length, 1.0 / cp_length) peak_detect = gr.peak_detector_fb(0.25, 0.25, 30, 0.001) self.connect(M_d, matched_filter, gr.add_const_ff(-1), peak_detect) offset = cp_length / 2 # cp_length/2 self.connect(peak_detect, (phi, 1)) self.connect(peak_detect, (self, 2)) self.connect(P_d_angle, gr.delay(gr.sizeof_float, offset), (phi, 0)) self.connect( self, gr.delay(gr.sizeof_gr_complex, (fft_length + offset)), (self, 0) ) # delay the input to follow the freq offset self.connect(peak_detect, gr.delay(gr.sizeof_char, (fft_length + offset)), (self, 2)) self.connect(peak_detect, gr.file_sink(gr.sizeof_char, "sync-peaks_b.dat")) self.connect(matched_filter, gr.file_sink(gr.sizeof_float, "sync-mf.dat")) self.connect(phi, (self, 1)) 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 run_test(seed,blocksize): tb = gr.top_block() ################################################## # Variables ################################################## M = 2 K = 1 P = 2 h = (1.0*K)/P L = 3 Q = 4 frac = 0.99 f = trellis.fsm(P,M,L) # CPFSK signals #p = numpy.ones(Q)/(2.0) #q = numpy.cumsum(p)/(1.0*Q) # GMSK signals BT=0.3; tt=numpy.arange(0,L*Q)/(1.0*Q)-L/2.0; #print tt p=(0.5*scipy.stats.erfc(2*math.pi*BT*(tt-0.5)/math.sqrt(math.log(2.0))/math.sqrt(2.0))-0.5*scipy.stats.erfc(2*math.pi*BT*(tt+0.5)/math.sqrt(math.log(2.0))/math.sqrt(2.0)))/2.0; p=p/sum(p)*Q/2.0; #print p q=numpy.cumsum(p)/Q; q=q/q[-1]/2.0; #print q (f0T,SS,S,F,Sf,Ff,N) = fsm_utils.make_cpm_signals(K,P,M,L,q,frac) #print N #print Ff Ffa = numpy.insert(Ff,Q,numpy.zeros(N),axis=0) #print Ffa MF = numpy.fliplr(numpy.transpose(Ffa)) #print MF E = numpy.sum(numpy.abs(Sf)**2,axis=0) Es = numpy.sum(E)/f.O() #print Es constellation = numpy.reshape(numpy.transpose(Sf),N*f.O()) #print Ff #print Sf #print constellation #print numpy.max(numpy.abs(SS - numpy.dot(Ff , Sf))) EsN0_db = 10.0 N0 = Es * 10.0**(-(1.0*EsN0_db)/10.0) #N0 = 0.0 #print N0 head = 4 tail = 4 numpy.random.seed(seed*666) data = numpy.random.randint(0, M, head+blocksize+tail+1) #data = numpy.zeros(blocksize+1+head+tail,'int') for i in range(head): data[i]=0 for i in range(tail+1): data[-i]=0 ################################################## # Blocks ################################################## random_source_x_0 = gr.vector_source_b(data, False) gr_chunks_to_symbols_xx_0 = gr.chunks_to_symbols_bf((-1, 1), 1) gr_interp_fir_filter_xxx_0 = gr.interp_fir_filter_fff(Q, p) gr_frequency_modulator_fc_0 = gr.frequency_modulator_fc(2*math.pi*h*(1.0/Q)) gr_add_vxx_0 = gr.add_vcc(1) gr_noise_source_x_0 = gr.noise_source_c(gr.GR_GAUSSIAN, (N0/2.0)**0.5, -long(seed)) gr_multiply_vxx_0 = gr.multiply_vcc(1) gr_sig_source_x_0 = gr.sig_source_c(Q, gr.GR_COS_WAVE, -f0T, 1, 0) # only works for N=2, do it manually for N>2... gr_fir_filter_xxx_0_0 = gr.fir_filter_ccc(Q, MF[0].conjugate()) gr_fir_filter_xxx_0_0_0 = gr.fir_filter_ccc(Q, MF[1].conjugate()) gr_streams_to_stream_0 = gr.streams_to_stream(gr.sizeof_gr_complex*1, N) gr_skiphead_0 = gr.skiphead(gr.sizeof_gr_complex*1, N*(1+0)) viterbi = trellis.viterbi_combined_cb(f, head+blocksize+tail, 0, -1, N, constellation, trellis.TRELLIS_EUCLIDEAN) gr_vector_sink_x_0 = gr.vector_sink_b() ################################################## # Connections ################################################## tb.connect((random_source_x_0, 0), (gr_chunks_to_symbols_xx_0, 0)) tb.connect((gr_chunks_to_symbols_xx_0, 0), (gr_interp_fir_filter_xxx_0, 0)) tb.connect((gr_interp_fir_filter_xxx_0, 0), (gr_frequency_modulator_fc_0, 0)) tb.connect((gr_frequency_modulator_fc_0, 0), (gr_add_vxx_0, 0)) tb.connect((gr_noise_source_x_0, 0), (gr_add_vxx_0, 1)) tb.connect((gr_add_vxx_0, 0), (gr_multiply_vxx_0, 0)) tb.connect((gr_sig_source_x_0, 0), (gr_multiply_vxx_0, 1)) tb.connect((gr_multiply_vxx_0, 0), (gr_fir_filter_xxx_0_0, 0)) tb.connect((gr_multiply_vxx_0, 0), (gr_fir_filter_xxx_0_0_0, 0)) tb.connect((gr_fir_filter_xxx_0_0, 0), (gr_streams_to_stream_0, 0)) tb.connect((gr_fir_filter_xxx_0_0_0, 0), (gr_streams_to_stream_0, 1)) tb.connect((gr_streams_to_stream_0, 0), (gr_skiphead_0, 0)) tb.connect((gr_skiphead_0, 0), (viterbi, 0)) tb.connect((viterbi, 0), (gr_vector_sink_x_0, 0)) tb.run() dataest = gr_vector_sink_x_0.data() #print data #print numpy.array(dataest) perr = 0 err = 0 for i in range(blocksize): if data[head+i] != dataest[head+i]: #print i err += 1 if err != 0 : perr = 1 return (err,perr)
def __init__(self): grc_wxgui.top_block_gui.__init__(self, title="Grc Wisp Reader") _icon_path = "/usr/share/icons/hicolor/32x32/apps/gnuradio-grc.png" self.SetIcon(wx.Icon(_icon_path, wx.BITMAP_TYPE_ANY)) self.wxgui_scopesink2_0 = scopesink2.scope_sink_f( self.GetWin(), title="Scope Plot", sample_rate=1e6, v_scale=0, v_offset=0, t_scale=0, ac_couple=False, xy_mode=False, num_inputs=1, trig_mode=gr.gr_TRIG_MODE_AUTO, y_axis_label="Counts", ) self.Add(self.wxgui_scopesink2_0.win) amplitude = 1 interp_rate = 128 # dec_rate = 8 # sw_dec = 4 dec_rate = 16 sw_dec = 2 # num_taps = int(64000 / ( (dec_rate * 4) * 40 )) #Filter matched to 1/4 of the 40 kHz tag cycle num_taps = int(64000 / ( (dec_rate * 4) * 256 )) #Filter matched to 1/4 of the 256 kHz tag cycle taps = [complex(1,1)] * num_taps matched_filt = gr.fir_filter_ccc(sw_dec, taps); agc = gr.agc2_cc(0.3, 1e-3, 1, 1, 100) to_mag = gr.complex_to_mag() # center = rfid.center_ff(10) center = rfid.center_ff(4) omega = 5 mu = 0.25 gain_mu = 0.25 gain_omega = .25 * gain_mu * gain_mu omega_relative_limit = .05 # mm = digital.clock_recovery_mm_ff(omega, gain_omega, mu, gain_mu, omega_relative_limit) mm = rfid.clock_recovery_zc_ff(4,1); self.reader = rfid.reader_f(int(128e6/interp_rate)); tag_decoder = rfid.tag_decoder_f() # command_gate = rfid.command_gate_cc(12, 250, 64000000 / dec_rate / sw_dec) command_gate = rfid.command_gate_cc(12, 60, 64000000 / dec_rate / sw_dec) to_complex = gr.float_to_complex() amp = gr.multiply_const_ff(amplitude) ################################################## # Blocks ################################################## freq = 915e6 rx_gain = 1 tx = uhd.usrp_sink( device_addr="", io_type=uhd.io_type.COMPLEX_FLOAT32, num_channels=1, ) print "tx: get sample rate:" print (tx.get_samp_rate()) tx.set_samp_rate(128e6/interp_rate) print "tx: get sample rate:" print (tx.get_samp_rate()) r = tx.set_center_freq(freq, 0) rx = uhd.usrp_source( device_addr="", io_type=uhd.io_type.COMPLEX_FLOAT32, num_channels=1, ) print "rx: get samp rate" print (rx.get_samp_rate()) r = rx.set_samp_rate(64e6/dec_rate) print "rx: get samp rate" print (rx.get_samp_rate()) r = rx.set_center_freq(freq, 0) print "rx: get gain " print (rx.get_gain_range()) r = rx.set_gain(rx_gain, 0) print "rx: get gain " print (rx.get_gain()) command_gate.set_ctrl_out(self.reader.ctrl_q()) tag_decoder.set_ctrl_out(self.reader.ctrl_q()) #########Build Graph self.connect(rx, matched_filt) self.connect(matched_filt, command_gate) self.connect(command_gate, to_mag) # self.connect(command_gate, agc) # self.connect(agc, to_mag) self.connect(to_mag, center, mm, tag_decoder) # self.connect(to_mag, center, matched_filt_tag_decode, tag_decoder) self.connect(tag_decoder, self.reader) self.connect(self.reader, amp) self.connect(amp, to_complex) self.connect(to_complex, tx)
def __init__(self, modulator, options): gr.top_block.__init__(self) self.txpath = [] use_sink = None if options.tx_freq is not None: # Work-around to get the modulation's bits_per_symbol args = modulator.extract_kwargs_from_options(options) symbol_rate = options.bitrate / modulator(**args).bits_per_symbol() self.sink = uhd_transmitter( options.args, symbol_rate, options.samples_per_symbol, options.tx_freq, options.tx_gain, options.spec, options.antenna, options.verbose, ) sample_rate = self.sink.get_sample_rate() options.samples_per_symbol = self.sink._sps use_sink = self.sink elif options.to_file is not None: sys.stderr.write(("Saving samples to '%s'.\n\n" % (options.to_file))) self.sink = gr.file_sink(gr.sizeof_gr_complex, options.to_file) self.throttle = gr.throttle(gr.sizeof_gr_complex * 1, options.file_samp_rate) self.connect(self.throttle, self.sink) use_sink = self.throttle else: sys.stderr.write("No sink defined, dumping samples to null sink.\n\n") self.sink = gr.null_sink(gr.sizeof_gr_complex) # do this after for any adjustments to the options that may # occur in the sinks (specifically the UHD sink) self.txpath.append(transmit_path(modulator, options)) self.txpath.append(transmit_path(modulator, options)) samp_rate = 0 if options.tx_freq is not None: samp_rate = self.sink.get_sample_rate() else: samp_rate = options.file_samp_rate volume = options.split_amplitude band_transition = options.band_trans_width low_transition = options.low_trans_width guard_width = options.guard_width self.low_pass_filter_qv0 = gr.interp_fir_filter_ccf( 2, firdes.low_pass(1, samp_rate, samp_rate / 4 - guard_width / 2, low_transition, firdes.WIN_HAMMING, 6.76) ) self.freq_translate_qv0 = filter.freq_xlating_fir_filter_ccc(1, (options.num_taps,), samp_rate / 4, samp_rate) self.band_pass_filter_qv0 = gr.fir_filter_ccc( 1, firdes.complex_band_pass( 1, samp_rate, -samp_rate / 2 + guard_width, 0 - guard_width, band_transition, firdes.WIN_HAMMING, 6.76 ), ) self.low_pass_filter_qv1 = gr.interp_fir_filter_ccf( 2, firdes.low_pass(1, samp_rate, samp_rate / 4 - guard_width / 2, low_transition, firdes.WIN_HAMMING, 6.76) ) self.freq_translate_qv1 = filter.freq_xlating_fir_filter_ccc(1, (options.num_taps,), -samp_rate / 4, samp_rate) self.band_pass_filter_qv1 = gr.fir_filter_ccc( 1, firdes.complex_band_pass( 1, samp_rate, 0 + guard_width, samp_rate / 2 - guard_width, band_transition, firdes.WIN_HAMMING, 6.76 ), ) self.combiner = gr.add_vcc(1) self.volume_multiply = blocks.multiply_const_vcc((volume,)) self.connect((self.txpath[0], 0), (self.low_pass_filter_qv0, 0)) self.connect((self.txpath[1], 0), (self.low_pass_filter_qv1, 0)) self.connect((self.low_pass_filter_qv0, 0), (self.freq_translate_qv0, 0)) self.connect((self.freq_translate_qv0, 0), (self.band_pass_filter_qv0, 0)) self.connect((self.low_pass_filter_qv1, 0), (self.freq_translate_qv1, 0)) self.connect((self.freq_translate_qv1, 0), (self.band_pass_filter_qv1, 0)) self.connect((self.band_pass_filter_qv0, 0), (self.combiner, 0)) self.connect((self.band_pass_filter_qv1, 0), (self.combiner, 1)) self.connect((self.combiner, 0), (self.volume_multiply, 0)) self.connect(self.volume_multiply, use_sink)
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_1 = wx.Slider(self, ID_SLIDER_1, 0, -15799, 15799, style=wx.SL_HORIZONTAL | wx.SL_LABELS) self.button_6 = wx.ToggleButton(self, ID_BUTTON_6, "Lower") self.slider_2 = wx.Slider(self, ID_SLIDER_2, 0, -15799, 15799, 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( "-c", "--ddc-freq", type="eng_float", default=3.9e6, help="set Rx DDC frequency to FREQ", metavar="FREQ" ) 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("-d", "--decim", type="int", default=250, help="USRP decimation") parser.add_option( "-R", "--rx-subdev-spec", type="subdev", default=None, help="select USRP Rx side A or B (default=first one with a daughterboard)", ) (options, args) = parser.parse_args() self.usrp_center = options.ddc_freq usb_rate = 64e6 / options.decim self.slider_range = usb_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(usb_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 / options.decim 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 = usrp.source_s(decim_rate=options.decim) if options.rx_subdev_spec is None: options.rx_subdev_spec = pick_subdevice(self.src) self.src.set_mux(usrp.determine_rx_mux_value(self.src, options.rx_subdev_spec)) self.subdev = usrp.selected_subdev(self.src, options.rx_subdev_spec) self.src.tune(0, self.subdev, self.usrp_center) self.tune_offset = 0 # -self.usrp_center - self.src.rx_freq(0) else: self.src = gr.file_source(gr.sizeof_short, options.input_file) self.tune_offset = 2200 # 2200 works for 3.5-4Mhz band # save radio data to a file if SAVE_RADIO_TO_FILE: file = gr.file_sink(gr.sizeof_short, options.radio_file) self.tb.connect(self.src, file) # 2nd DDC xlate_taps = gr.firdes.low_pass(1.0, usb_rate, 16e3, 4e3, gr.firdes.WIN_HAMMING) self.xlate = gr.freq_xlating_fir_filter_ccf(fir_decim, xlate_taps, self.tune_offset, usb_rate) # 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)) # 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_1.SetValue(0) self.slider_2.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( 0.5, 0.0625, (2.0 * math.pi * 7.5e3 / self.af_sample_rate), (2.0 * 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([0.004, 0], [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)) 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 em.eventManager.Register(self.Mouse, wx.EVT_MOTION, self.fft.win) # and left click to re-tune em.eventManager.Register(self.Click, wx.EVT_LEFT_DOWN, self.fft.win) # 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, kstime, logging=False): """ OFDM synchronization using PN Correlation and initial cross-correlation: F. Tufvesson, O. Edfors, and M. Faulkner, "Time and Frequency Synchronization for OFDM using PN-Sequency Preambles," IEEE Proc. VTC, 1999, pp. 2203-2207. This implementation is meant to be a more robust version of the Schmidl and Cox receiver design. By correlating against the preamble and using that as the input to the time-delayed correlation, this circuit produces a very clean timing signal at the end of the preamble. The timing is more accurate and does not have the problem associated with determining the timing from the plateau structure in the Schmidl and Cox. This implementation appears to require that the signal is received with a normalized power or signal scalling factor to reduce ambiguities intorduced from partial correlation of the cyclic prefix and the peak detection. A better peak detection block might fix this. Also, the cross-correlation falls apart as the frequency offset gets larger and completely fails when an integer offset is introduced. Another thing to look at. """ gr.hier_block2.__init__( self, "ofdm_sync_pnac", gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature gr.io_signature2(2, 2, gr.sizeof_float, gr.sizeof_char)) # Output signature self.input = gr.add_const_cc(0) symbol_length = fft_length + cp_length # PN Sync with cross-correlation input # cross-correlate with the known symbol kstime = [k.conjugate() for k in kstime[0:fft_length // 2]] kstime.reverse() self.crosscorr_filter = gr.fir_filter_ccc(1, kstime) # Create a delay line self.delay = gr.delay(gr.sizeof_gr_complex, fft_length / 2) # Correlation from ML Sync self.conjg = gr.conjugate_cc() self.corr = gr.multiply_cc() # Create a moving sum filter for the input self.mag = gr.complex_to_mag_squared() movingsum_taps = (fft_length // 1) * [ 1.0, ] self.power = gr.fir_filter_fff(1, movingsum_taps) # Get magnitude (peaks) and angle (phase/freq error) self.c2mag = gr.complex_to_mag_squared() self.angle = gr.complex_to_arg() self.compare = gr.sub_ff() self.sample_and_hold = gr.sample_and_hold_ff() #ML measurements input to sampler block and detect self.threshold = gr.threshold_ff( 0, 0, 0) # threshold detection might need to be tweaked self.peaks = gr.float_to_char() self.connect(self, self.input) # Cross-correlate input signal with known preamble self.connect(self.input, self.crosscorr_filter) # use the output of the cross-correlation as input time-shifted correlation self.connect(self.crosscorr_filter, self.delay) self.connect(self.crosscorr_filter, (self.corr, 0)) self.connect(self.delay, self.conjg) self.connect(self.conjg, (self.corr, 1)) self.connect(self.corr, self.c2mag) self.connect(self.corr, self.angle) self.connect(self.angle, (self.sample_and_hold, 0)) # Get the power of the input signal to compare against the correlation self.connect(self.crosscorr_filter, self.mag, self.power) # Compare the power to the correlator output to determine timing peak # When the peak occurs, it peaks above zero, so the thresholder detects this self.connect(self.c2mag, (self.compare, 0)) self.connect(self.power, (self.compare, 1)) self.connect(self.compare, self.threshold) self.connect(self.threshold, self.peaks, (self.sample_and_hold, 1)) # Set output signals # Output 0: fine frequency correction value # Output 1: timing signal self.connect(self.sample_and_hold, (self, 0)) self.connect(self.peaks, (self, 1)) if logging: self.connect( self.compare, gr.file_sink(gr.sizeof_float, "ofdm_sync_pnac-compare_f.dat")) self.connect( self.c2mag, gr.file_sink(gr.sizeof_float, "ofdm_sync_pnac-theta_f.dat")) self.connect( self.power, gr.file_sink(gr.sizeof_float, "ofdm_sync_pnac-inputpower_f.dat")) self.connect( self.angle, gr.file_sink(gr.sizeof_float, "ofdm_sync_pnac-epsilon_f.dat")) self.connect( self.threshold, gr.file_sink(gr.sizeof_float, "ofdm_sync_pnac-threshold_f.dat")) self.connect( self.peaks, gr.file_sink(gr.sizeof_char, "ofdm_sync_pnac-peaks_b.dat")) self.connect( self.sample_and_hold, gr.file_sink(gr.sizeof_float, "ofdm_sync_pnac-sample_and_hold_f.dat")) self.connect( self.input, gr.file_sink(gr.sizeof_gr_complex, "ofdm_sync_pnac-input_c.dat"))
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): grc_wxgui.top_block_gui.__init__(self, title="USRP HRPT Receiver") ################################################## # Variables ################################################## self.config_filename = config_filename = "usrp_rx_hrpt.cfg" self._decim_config = ConfigParser.ConfigParser() self._decim_config.read(config_filename) try: decim = self._decim_config.getfloat("usrp", "decim") except: decim = 16 self.decim = decim self.sym_rate = sym_rate = 600 * 1109 self.sample_rate = sample_rate = 64e6 / decim self.sps = sps = sample_rate / sym_rate self._side_config = ConfigParser.ConfigParser() self._side_config.read(config_filename) try: side = self._side_config.get("usrp", "side") except: side = "A" self.side = side self._saved_sync_alpha_config = ConfigParser.ConfigParser() self._saved_sync_alpha_config.read(config_filename) try: saved_sync_alpha = self._saved_sync_alpha_config.getfloat("demod", "sync_alpha") except: saved_sync_alpha = 0.05 self.saved_sync_alpha = saved_sync_alpha self._saved_pll_alpha_config = ConfigParser.ConfigParser() self._saved_pll_alpha_config.read(config_filename) try: saved_pll_alpha = self._saved_pll_alpha_config.getfloat("demod", "pll_alpha") except: saved_pll_alpha = 0.05 self.saved_pll_alpha = saved_pll_alpha self._saved_gain_config = ConfigParser.ConfigParser() self._saved_gain_config.read(config_filename) try: saved_gain = self._saved_gain_config.getfloat("usrp", "gain") except: saved_gain = 35 self.saved_gain = saved_gain self._saved_freq_config = ConfigParser.ConfigParser() self._saved_freq_config.read(config_filename) try: saved_freq = self._saved_freq_config.getfloat("usrp", "freq") except: saved_freq = 1698e6 self.saved_freq = saved_freq self.hs = hs = int(sps / 2.0) self.sync_alpha = sync_alpha = saved_sync_alpha self.side_text = side_text = side self.pll_alpha = pll_alpha = saved_pll_alpha self._output_filename_config = ConfigParser.ConfigParser() self._output_filename_config.read(config_filename) try: output_filename = self._output_filename_config.get("output", "filename") except: output_filename = "frames.dat" self.output_filename = output_filename self.mf_taps = mf_taps = [-0.5 / hs] * hs + [0.5 / hs] * hs self.max_sync_offset = max_sync_offset = 0.01 self.max_carrier_offset = max_carrier_offset = 2 * math.pi * 100e3 / sample_rate self.gain = gain = saved_gain self.freq = freq = saved_freq self.decim_text = decim_text = decim ################################################## # Notebooks ################################################## self.displays = wx.Notebook(self.GetWin(), style=wx.NB_TOP) self.displays.AddPage(grc_wxgui.Panel(self.displays), "RX") self.displays.AddPage(grc_wxgui.Panel(self.displays), "Demod") self.GridAdd(self.displays, 2, 0, 1, 4) ################################################## # Controls ################################################## _sync_alpha_sizer = wx.BoxSizer(wx.VERTICAL) self._sync_alpha_text_box = forms.text_box( parent=self.GetWin(), sizer=_sync_alpha_sizer, value=self.sync_alpha, callback=self.set_sync_alpha, label="SYNC Alpha", converter=forms.float_converter(), proportion=0, ) self._sync_alpha_slider = forms.slider( parent=self.GetWin(), sizer=_sync_alpha_sizer, value=self.sync_alpha, callback=self.set_sync_alpha, minimum=0.0, maximum=0.5, num_steps=100, style=wx.SL_HORIZONTAL, cast=float, proportion=1, ) self.GridAdd(_sync_alpha_sizer, 0, 3, 1, 1) self._side_text_static_text = forms.static_text( parent=self.GetWin(), value=self.side_text, callback=self.set_side_text, label="USRP Side", converter=forms.str_converter(), ) self.GridAdd(self._side_text_static_text, 1, 0, 1, 1) _pll_alpha_sizer = wx.BoxSizer(wx.VERTICAL) self._pll_alpha_text_box = forms.text_box( parent=self.GetWin(), sizer=_pll_alpha_sizer, value=self.pll_alpha, callback=self.set_pll_alpha, label="PLL Alpha", converter=forms.float_converter(), proportion=0, ) self._pll_alpha_slider = forms.slider( parent=self.GetWin(), sizer=_pll_alpha_sizer, value=self.pll_alpha, callback=self.set_pll_alpha, minimum=0.0, maximum=0.5, num_steps=100, style=wx.SL_HORIZONTAL, cast=float, proportion=1, ) self.GridAdd(_pll_alpha_sizer, 0, 2, 1, 1) _gain_sizer = wx.BoxSizer(wx.VERTICAL) self._gain_text_box = forms.text_box( parent=self.GetWin(), sizer=_gain_sizer, value=self.gain, callback=self.set_gain, label="RX Gain", converter=forms.float_converter(), proportion=0, ) self._gain_slider = forms.slider( parent=self.GetWin(), sizer=_gain_sizer, value=self.gain, callback=self.set_gain, minimum=0, maximum=100, num_steps=100, style=wx.SL_HORIZONTAL, cast=float, proportion=1, ) self.GridAdd(_gain_sizer, 0, 1, 1, 1) self._freq_text_box = forms.text_box( parent=self.GetWin(), value=self.freq, callback=self.set_freq, label="Frequency", converter=forms.float_converter(), ) self.GridAdd(self._freq_text_box, 0, 0, 1, 1) self._decim_text_static_text = forms.static_text( parent=self.GetWin(), value=self.decim_text, callback=self.set_decim_text, label="Decimation", converter=forms.float_converter(), ) self.GridAdd(self._decim_text_static_text, 1, 1, 1, 1) ################################################## # Blocks ################################################## self.agc = gr.agc_cc(1e-6, 1.0, 1.0, 1.0) self.decoder = noaa.hrpt_decoder() self.deframer = noaa.hrpt_deframer() self.frame_sink = gr.file_sink(gr.sizeof_short * 1, output_filename) self.gr_fir_filter_xxx_0 = gr.fir_filter_ccc(1, (mf_taps)) self.pll = noaa.hrpt_pll_cf(pll_alpha, pll_alpha ** 2 / 4.0, max_carrier_offset) self.pll_scope = scopesink2.scope_sink_f( self.displays.GetPage(1).GetWin(), title="Demod Waveform", sample_rate=sample_rate, v_scale=0.5, t_scale=20.0 / sample_rate, ac_couple=False, xy_mode=False, num_inputs=1, ) self.displays.GetPage(1).GridAdd(self.pll_scope.win, 0, 0, 1, 1) self.rx_fft = fftsink2.fft_sink_c( self.displays.GetPage(0).GetWin(), baseband_freq=freq, y_per_div=5, y_divs=8, ref_level=-5, ref_scale=2.0, sample_rate=sample_rate, fft_size=1024, fft_rate=15, average=True, avg_alpha=0.1, title="RX Spectrum", peak_hold=False, ) self.displays.GetPage(0).GridAdd(self.rx_fft.win, 0, 0, 1, 1) self.rx_scope = scopesink2.scope_sink_c( self.displays.GetPage(0).GetWin(), title="RX Waveform", sample_rate=sample_rate, v_scale=0, t_scale=20.0 / sample_rate, ac_couple=False, xy_mode=False, num_inputs=1, ) self.displays.GetPage(0).GridAdd(self.rx_scope.win, 1, 0, 1, 1) self.sync = noaa.hrpt_sync_fb(sync_alpha, sync_alpha ** 2 / 4.0, sps, max_sync_offset) self.usrp_source = grc_usrp.simple_source_c(which=0, side=side, rx_ant="RXA") self.usrp_source.set_decim_rate(decim) self.usrp_source.set_frequency(freq, verbose=True) self.usrp_source.set_gain(gain) ################################################## # Connections ################################################## self.connect((self.deframer, 0), (self.frame_sink, 0)) self.connect((self.sync, 0), (self.deframer, 0)) self.connect((self.pll, 0), (self.sync, 0)) self.connect((self.pll, 0), (self.pll_scope, 0)) self.connect((self.agc, 0), (self.rx_scope, 0)) self.connect((self.agc, 0), (self.rx_fft, 0)) self.connect((self.deframer, 0), (self.decoder, 0)) self.connect((self.agc, 0), (self.gr_fir_filter_xxx_0, 0)) self.connect((self.gr_fir_filter_xxx_0, 0), (self.pll, 0)) self.connect((self.usrp_source, 0), (self.agc, 0))
def main(): # Parsing command line parameter parser = OptionParser(option_class=eng_option) parser.add_option( "-f", "--freq", type="eng_float", dest="freq", default=866.5, help="set USRP center frequency (provide frequency in MHz)") parser.add_option("-m", "--miller", type="int", dest="miller", default=2, help="set number of Miller subcarriers (2,4 or 8)") (options, args) = parser.parse_args() which_usrp = 0 fpga = "gen2_reader_2ch_mod_pwr.rbf" # Modified firmware --> you can set TX amplitude directly from Python (see below) freq = options.freq # Default value = 866.5 --> center frequency of 2 MHz European RFID Band freq = freq * 1e6 miller = options.miller deviation_corr = 1 # Maximum deviation for Early/Late gate correlator in Buettner's reader amplitude = 30000 # Amplitude of READER TX signal. 30000 is the maximum allowed. rx_gain = 20 us_per_sample = float(1 / (64.0 / (dec_rate * sw_dec))) samp_freq = (64 / dec_rate) * 1e6 # BUETTNER'S READER HARDWARE SUB-SYSTEM for TX SIDE tx = usrp.sink_c(which_usrp, fusb_block_size=1024, fusb_nblocks=4, fpga_filename=fpga) tx.set_interp_rate(interp) tx_subdev = (0, 0) # TX/RX port of RFX900 daugtherboard on SIDE A tx.set_mux(usrp.determine_tx_mux_value(tx, tx_subdev)) subdev = usrp.selected_subdev(tx, tx_subdev) subdev.set_enable(True) subdev.set_gain(subdev.gain_range()[2]) t = tx.tune(subdev.which(), subdev, freq) # Tuning TX Daughterboard @ Center Frequency if not t: print "Couldn't set READER TX frequency" tx._write_fpga_reg(usrp.FR_USER_1, int( amplitude)) # SET FPGA register value with the desired tx amplitude # END BUETTNER'S READER HARDWARE SUB-SYSTEM for TX SIDE # BUETTNER'S READER HARDWARE SUB-SYSTEM for RX SIDE rx = usrp.source_c( which_usrp, dec_rate, nchan=2, fusb_block_size=512, fusb_nblocks=16, fpga_filename=fpga) # USRP source: 2 channels (reader + listener) rx.set_mux(rx.determine_rx_mux_value( (0, 0), (1, 0) )) # 2 channel mux --> rx from (0,0) to reader - rx from (1,0) to listener rx_reader_subdev_spec = (0, 0) # Reader RFX900 daugtherboard on SIDE A rx_reader_subdev = rx.selected_subdev(rx_reader_subdev_spec) rx_reader_subdev.set_gain(rx_gain) rx_reader_subdev.set_auto_tr(False) rx_reader_subdev.set_enable(True) rx_reader_subdev.select_rx_antenna( 'RX2' ) # RX2 port of RFX900 on side A --> RX antenna of Buettner's reader r = usrp.tune(rx, 0, rx_reader_subdev, freq) # Tuning READER RX Daughterboard @ Center Frequency if not r: print "Couldn't set READER RX frequency" # END BUETTNER'S READER HARDWARE SUB-SYSTEM for TX SIDE # LISTENER HARDWARE SUB-SYSTEM rx_listener_subdev_spec = (1, 0) # Listener DB RFX900 on side B rx_listener_subdev = rx.selected_subdev(rx_listener_subdev_spec) rx_listener_subdev.set_gain(rx_gain) rx_listener_subdev.set_auto_tr(False) rx_listener_subdev.set_enable(True) rx_listener_subdev.select_rx_antenna( 'RX2' ) # RX Antenna on RX2 Connector of side B RFX900 (comment this line if you want TX/RX connector) r = usrp.tune(rx, 1, rx_listener_subdev, freq) # Tuning Listener Daughterboard @ Center Frequency if not r: print "Couldn't set LISTENER RX frequency" # END LISTENER HARDWARE SUB-SYSTEM print "" print "********************************************************" print "************ Gen2 RFID Monitoring Platform *************" print "********* Reader and Listener on the same USRP *********" print "********************************************************\n" print "USRP center frequency: %s MHz" % str(freq / 1e6) print "Sampling Frequency: " + str( samp_freq / 1e6) + " MHz" + " --- microsec. per Sample: " + str(us_per_sample) # BUETTNER's READER SOFTWARE SUB-SYSTEM (GNU-Radio flow-graph) gen2_reader = rfid.gen2_reader(dec_rate * sw_dec * samples_per_pulse, interp, int(miller), True, int(deviation_corr)) zc = rfid.clock_recovery_zc_ff(samples_per_pulse, 1, float(us_per_sample), float(up_link_freq), True) # END BUETTNER's READER SOFTWARE SUB-SYSTEM (GNU-Radio flow-graph) # LISTENER SOFTWARE SUB-SYSTEM (GNU-Radio flow-graph) # MATCHED FILTER num_taps = int( 64000 / (dec_rate * up_link_freq * 4)) #Matched filter for 1/4 cycle taps = [complex(1, 1)] * num_taps matched_filter = gr.fir_filter_ccc(sw_dec, taps) # Tag Decoding Block --> the boolean value in input indicate if real-time output of EPC is enabled or not tag_monitor = listener.tag_monitor(True, int(miller), float(up_link_freq)) # Clock recovery cr = listener.clock_recovery(samples_per_pulse, us_per_sample, tag_monitor.STATE_PTR, float(up_link_freq)) # Reader Decoding Block and Command gate--> the boolean value indicate if real-time output of reader commands is enabled or not reader_monitor_cmd_gate = listener.reader_monitor_cmd_gate( False, us_per_sample, tag_monitor.STATE_PTR, float(up_link_freq), float(rtcal)) # END LISTENER SOFTWARE SUB-SYSTEM (GNU-Radio flow-graph) # Create GNU-Radio flow-graph tb = my_top_block(tx, zc, gen2_reader, rx, matched_filter, reader_monitor_cmd_gate, cr, tag_monitor, amplitude) # Start application tb.start() # GETTING LOGs from BUETTNER's READER video_output = False # Set as True if you want real time video output of Buettner's reader logs log_reader_buettner_file = open("log_reader_buettner.log", "w") finish = 0 succ_reads = 0 epc_errors = 0 while 1: log_reader_buettner = gen2_reader.get_log() i = log_reader_buettner.count() for k in range(0, i): msg = log_reader_buettner.delete_head_nowait() print_msg(msg, log_reader_buettner_file, video_output) if msg.type() == 99: # All cycles are terminated finish = 1 if msg.type() == LOG_EPC: # EPC if msg.arg2() == LOG_ERROR: epc_errors = epc_errors + 1 # CRC Error on EPC else: succ_reads = succ_reads + 1 # Successful EPc if finish: break # Stop application tb.stop() log_reader_buettner_file.close() rec_frames = succ_reads + epc_errors print "\nReader --> Total Received Frames: " + str(rec_frames) print "Reader --> Successful reads: " + str(succ_reads) print "Reader --> CRC error frames: " + str(epc_errors) print "" # GETTING LOGs from LISTENER log_READER = reader_monitor_cmd_gate.get_reader_log() log_TAG = tag_monitor.get_tag_log() print "Listener collected %s Entries for READER LOG" % str( log_READER.count()) print "Listener collected %s Entries for TAG LOG" % str(log_TAG.count()) c = raw_input("PRESS 'f' to write LOG files, 'q' to QUIT\n") if c == "q": print "\n Shutting Down...\n" return if c == "f": print "\n Writing READER LOG on file...\n\n" reader_file = open("reader_log.out", "w") reader_file.close() reader_file = open("reader_log.out", "a") i = log_READER.count() for k in range(0, i): decode_reader_log_msg(log_READER.delete_head_nowait(), reader_file) k = k + 1 reader_file.close() print "\n Writing TAG LOG on file...\n" tag_file = open("tag_log.out", "w") tag_file.close() tag_file = open("tag_log.out", "a") i = log_TAG.count() for k in range(0, i): decode_tag_log_msg(log_TAG.delete_head_nowait(), tag_file) k = k + 1 tag_file.close()
def __init__(self): gr.top_block.__init__(self) amplitude = 5000 interp_rate = 256 dec_rate = 16 sw_dec = 5 num_taps = int(64000 / ( (dec_rate * 4) * 40 )) #Filter matched to 1/4 of the 40 kHz tag cycle taps = [complex(1,1)] * num_taps matched_filt = gr.fir_filter_ccc(sw_dec, taps); agc = gr.agc2_cc(0.3, 1e-3, 1, 1, 100) to_mag = gr.complex_to_mag() center = rfid.center_ff(10) omega = 5 mu = 0.25 gain_mu = 0.25 gain_omega = .25 * gain_mu * gain_mu omega_relative_limit = .05 mm = gr.clock_recovery_mm_ff(omega, gain_omega, mu, gain_mu, omega_relative_limit) self.reader = rfid.reader_f(int(128e6/interp_rate)); tag_decoder = rfid.tag_decoder_f() command_gate = rfid.command_gate_cc(12, 250, 64000000 / dec_rate / sw_dec) to_complex = gr.float_to_complex() amp = gr.multiply_const_ff(amplitude) #output the TX and RX signals only f_txout = gr.file_sink(gr.sizeof_gr_complex, 'f_txout.out'); f_rxout = gr.file_sink(gr.sizeof_gr_complex, 'f_rxout.out'); #TX # working frequency at 915 MHz by default and RX Gain of 20 freq = options.center_freq #915e6 rx_gain = options.rx_gain #20 tx = usrp.sink_c(fusb_block_size = 512, fusb_nblocks=4) tx.set_interp_rate(256) tx_subdev = (0,0) tx.set_mux(usrp.determine_tx_mux_value(tx, tx_subdev)) subdev = usrp.selected_subdev(tx, tx_subdev) subdev.set_enable(True) subdev.set_gain(subdev.gain_range()[2]) t = tx.tune(subdev.which(), subdev, freq) if not t: print "Couldn't set tx freq" #End TX #RX rx = usrp.source_c(0, dec_rate, fusb_block_size = 512, fusb_nblocks = 4) rx_subdev_spec = (1,0) rx.set_mux(usrp.determine_rx_mux_value(rx, rx_subdev_spec)) rx_subdev = usrp.selected_subdev(rx, rx_subdev_spec) rx_subdev.set_gain(rx_gain) rx_subdev.set_auto_tr(False) rx_subdev.set_enable(True) r = usrp.tune(rx, 0, rx_subdev, freq) self.rx = rx if not r: print "Couldn't set rx freq" #End RX command_gate.set_ctrl_out(self.reader.ctrl_q()) tag_decoder.set_ctrl_out(self.reader.ctrl_q()) #########Build Graph self.connect(rx, matched_filt) self.connect(matched_filt, command_gate) self.connect(command_gate, agc) self.connect(agc, to_mag) self.connect(to_mag, center, mm, tag_decoder) self.connect(tag_decoder, self.reader, amp, to_complex, tx); ################# #Output dumps for debug self.connect(rx, f_rxout); self.connect(to_complex, f_txout);
def __init__(self): gr.top_block.__init__(self) amplitude = 30000 filt_out = gr.file_sink(gr.sizeof_gr_complex, "./filt.out") filt2_out = gr.file_sink(gr.sizeof_gr_complex, "./filt2.out") ffilt_out = gr.file_sink(gr.sizeof_float, "./ffilt.out") ffilt2_out = gr.file_sink(gr.sizeof_float, "./ffilt2.out") interp_rate = 128 dec_rate = 8 sw_dec = 4 num_taps = int(64000 / ( (dec_rate * 4) * 256 )) #Filter matched to 1/4 of the 256 kHz tag cycle taps = [complex(1,1)] * num_taps matched_filt = gr.fir_filter_ccc(sw_dec, taps); agc = gr.agc2_cc(0.3, 1e-3, 1, 1, 100) to_mag = gr.complex_to_mag() center = rfid.center_ff(4) omega = 2 mu = 0.25 gain_mu = 0.25 gain_omega = .25 * gain_mu * gain_mu omega_relative_limit = .05 mm = gr.clock_recovery_mm_ff(omega, gain_omega, mu, gain_mu, omega_relative_limit) self.reader = rfid.reader_f(int(128e6/interp_rate)); tag_decoder = rfid.tag_decoder_f() command_gate = rfid.command_gate_cc(12, 60, 64000000 / dec_rate / sw_dec) to_complex = gr.float_to_complex() amp = gr.multiply_const_ff(amplitude) f_sink = gr.file_sink(gr.sizeof_gr_complex, 'f_sink.out'); f_sink2 = gr.file_sink(gr.sizeof_gr_complex, 'f_sink2.out'); #TX freq = 915e6 rx_gain = 20 tx = usrp.sink_c(fusb_block_size = 1024, fusb_nblocks=8) tx.set_interp_rate(interp_rate) tx_subdev = (0,0) tx.set_mux(usrp.determine_tx_mux_value(tx, tx_subdev)) subdev = usrp.selected_subdev(tx, tx_subdev) subdev.set_enable(True) subdev.set_gain(subdev.gain_range()[2]) t = tx.tune(subdev.which(), subdev, freq) if not t: print "Couldn't set tx freq" #End TX #RX rx = usrp.source_c(0, dec_rate, fusb_block_size = 512 * 4, fusb_nblocks = 16) rx_subdev_spec = (1,0) rx.set_mux(usrp.determine_rx_mux_value(rx, rx_subdev_spec)) rx_subdev = usrp.selected_subdev(rx, rx_subdev_spec) rx_subdev.set_gain(rx_gain) rx_subdev.set_auto_tr(False) rx_subdev.set_enable(True) r = usrp.tune(rx, 0, rx_subdev, freq) self.rx = rx if not r: print "Couldn't set rx freq" #End RX command_gate.set_ctrl_out(self.reader.ctrl_q()) tag_decoder.set_ctrl_out(self.reader.ctrl_q()) agc2 = gr.agc2_ff(0.3, 1e-3, 1, 1, 100) #########Build Graph self.connect(rx, matched_filt) self.connect(matched_filt, command_gate) self.connect(command_gate, agc) self.connect(agc, to_mag) self.connect(to_mag, center, agc2, mm, tag_decoder) self.connect(tag_decoder, self.reader, amp, to_complex, tx); ################# self.connect(matched_filt, filt_out)
def __init__(self, fft_length, cp_length, snr, kstime, logging): ''' Maximum Likelihood OFDM synchronizer: J. van de Beek, M. Sandell, and P. O. Borjesson, "ML Estimation of Time and Frequency Offset in OFDM Systems," IEEE Trans. Signal Processing, vol. 45, no. 7, pp. 1800-1805, 1997. ''' gr.hier_block2.__init__(self, "ofdm_sync_ml", gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature gr.io_signature2(2, 2, gr.sizeof_float, gr.sizeof_char)) # Output signature self.input = gr.add_const_cc(0) SNR = 10.0**(snr/10.0) rho = SNR / (SNR + 1.0) symbol_length = fft_length + cp_length # ML Sync # Energy Detection from ML Sync self.connect(self, self.input) # Create a delay line self.delay = gr.delay(gr.sizeof_gr_complex, fft_length) self.connect(self.input, self.delay) # magnitude squared blocks self.magsqrd1 = gr.complex_to_mag_squared() self.magsqrd2 = gr.complex_to_mag_squared() self.adder = gr.add_ff() moving_sum_taps = [rho/2 for i in range(cp_length)] self.moving_sum_filter = gr.fir_filter_fff(1,moving_sum_taps) self.connect(self.input,self.magsqrd1) self.connect(self.delay,self.magsqrd2) self.connect(self.magsqrd1,(self.adder,0)) self.connect(self.magsqrd2,(self.adder,1)) self.connect(self.adder,self.moving_sum_filter) # Correlation from ML Sync self.conjg = gr.conjugate_cc(); self.mixer = gr.multiply_cc(); movingsum2_taps = [1.0 for i in range(cp_length)] self.movingsum2 = gr.fir_filter_ccf(1,movingsum2_taps) # Correlator data handler self.c2mag = gr.complex_to_mag() self.angle = gr.complex_to_arg() self.connect(self.input,(self.mixer,1)) self.connect(self.delay,self.conjg,(self.mixer,0)) self.connect(self.mixer,self.movingsum2,self.c2mag) self.connect(self.movingsum2,self.angle) # ML Sync output arg, need to find maximum point of this self.diff = gr.sub_ff() self.connect(self.c2mag,(self.diff,0)) self.connect(self.moving_sum_filter,(self.diff,1)) #ML measurements input to sampler block and detect self.f2c = gr.float_to_complex() self.pk_detect = gr.peak_detector_fb(0.2, 0.25, 30, 0.0005) self.sample_and_hold = gr.sample_and_hold_ff() # use the sync loop values to set the sampler and the NCO # self.diff = theta # self.angle = epsilon self.connect(self.diff, self.pk_detect) # The DPLL corrects for timing differences between CP correlations use_dpll = 0 if use_dpll: self.dpll = gr.dpll_bb(float(symbol_length),0.01) self.connect(self.pk_detect, self.dpll) self.connect(self.dpll, (self.sample_and_hold,1)) else: self.connect(self.pk_detect, (self.sample_and_hold,1)) self.connect(self.angle, (self.sample_and_hold,0)) ################################ # correlate against known symbol # This gives us the same timing signal as the PN sync block only on the preamble # we don't use the signal generated from the CP correlation because we don't want # to readjust the timing in the middle of the packet or we ruin the equalizer settings. kstime = [k.conjugate() for k in kstime] kstime.reverse() self.kscorr = gr.fir_filter_ccc(1, kstime) self.corrmag = gr.complex_to_mag_squared() self.div = gr.divide_ff() # The output signature of the correlation has a few spikes because the rest of the # system uses the repeated preamble symbol. It needs to work that generically if # anyone wants to use this against a WiMAX-like signal since it, too, repeats. # The output theta of the correlator above is multiplied with this correlation to # identify the proper peak and remove other products in this cross-correlation self.threshold_factor = 0.1 self.slice = gr.threshold_ff(self.threshold_factor, self.threshold_factor, 0) self.f2b = gr.float_to_char() self.b2f = gr.char_to_float() self.mul = gr.multiply_ff() # Normalize the power of the corr output by the energy. This is not really needed # and could be removed for performance, but it makes for a cleaner signal. # if this is removed, the threshold value needs adjustment. self.connect(self.input, self.kscorr, self.corrmag, (self.div,0)) self.connect(self.moving_sum_filter, (self.div,1)) self.connect(self.div, (self.mul,0)) self.connect(self.pk_detect, self.b2f, (self.mul,1)) self.connect(self.mul, self.slice) # Set output signals # Output 0: fine frequency correction value # Output 1: timing signal self.connect(self.sample_and_hold, (self,0)) self.connect(self.slice, self.f2b, (self,1)) if logging: self.connect(self.moving_sum_filter, gr.file_sink(gr.sizeof_float, "ofdm_sync_ml-energy_f.dat")) self.connect(self.diff, gr.file_sink(gr.sizeof_float, "ofdm_sync_ml-theta_f.dat")) self.connect(self.angle, gr.file_sink(gr.sizeof_float, "ofdm_sync_ml-epsilon_f.dat")) self.connect(self.corrmag, gr.file_sink(gr.sizeof_float, "ofdm_sync_ml-corrmag_f.dat")) self.connect(self.kscorr, gr.file_sink(gr.sizeof_gr_complex, "ofdm_sync_ml-kscorr_c.dat")) self.connect(self.div, gr.file_sink(gr.sizeof_float, "ofdm_sync_ml-div_f.dat")) self.connect(self.mul, gr.file_sink(gr.sizeof_float, "ofdm_sync_ml-mul_f.dat")) self.connect(self.slice, gr.file_sink(gr.sizeof_float, "ofdm_sync_ml-slice_f.dat")) self.connect(self.pk_detect, gr.file_sink(gr.sizeof_char, "ofdm_sync_ml-peaks_b.dat")) if use_dpll: self.connect(self.dpll, gr.file_sink(gr.sizeof_char, "ofdm_sync_ml-dpll_b.dat")) self.connect(self.sample_and_hold, gr.file_sink(gr.sizeof_float, "ofdm_sync_ml-sample_and_hold_f.dat")) self.connect(self.input, gr.file_sink(gr.sizeof_gr_complex, "ofdm_sync_ml-input_c.dat"))
def __init__(self): gr.top_block.__init__(self) amplitude = 30000 # 1 2150 10000 rx_out = gr.file_sink(gr.sizeof_gr_complex, "./rx.out") interp_rate = 128 # tx_samprate = 1M # dec_rate = 8 # rx_samprate = 8M dec_rate = 16 #16 # rx_samprate = 4M sw_dec = 4 #2 # num_taps = int(64000 / ( (dec_rate * 4) * 40 )) #Filter matched to 1/4 of the 40 kHz tag cycle num_taps = int(64000 / ( (dec_rate * 4) * 256 )) #Filter matched to 1/4 of the 256 kHz tag cycle taps = [complex(1,1)] * num_taps matched_filt = gr.fir_filter_ccc(sw_dec, taps); to_mag = gr.complex_to_mag() center = rfid.center_ff(4) mm = rfid.clock_recovery_zc_ff(4,1); self.reader = rfid.reader_f(int(128e6/interp_rate)); tag_decoder = rfid.tag_decoder_f() command_gate = rfid.command_gate_cc(12, 60, 64000000 / dec_rate / sw_dec) to_complex = gr.float_to_complex() amp = gr.multiply_const_ff(amplitude) ################################################## # Blocks ################################################## freq = 915e6 #915e6 rx_gain = 24 #xjtu tx = uhd.usrp_sink( device_addr="", io_type=uhd.io_type.COMPLEX_FLOAT32, num_channels=1, ) tx.set_samp_rate(128e6/interp_rate) p = tx.get_gain_range() tx.set_gain(float(p.start() + p.stop()) / 4) #r = tx.set_center_freq(freq, 0) t = tx.set_samp_rate(64e6/dec_rate) tune_req_tx = uhd.tune_request_t(freq,128e6/interp_rate/2) tt = tx.set_center_freq(tune_req_tx) rx = uhd.usrp_source( options.args, io_type=uhd.io_type.COMPLEX_FLOAT32, num_channels=1, ) r = rx.set_samp_rate(64e6/dec_rate) tune_req = uhd.tune_request_t(freq,64e6/dec_rate) x = rx.set_center_freq(tune_req) if not x: print "Couldn't set rx freq" #g = rx.get_gain_range() rx.set_gain(rx_gain) print "***************Info******************" print "-----tx: get sample rate:" print (tx.get_samp_rate()) print "tx: get freq:" print (tx.get_center_freq()) print "-----rx.detail" print rx.detail() print "rx: get samp rate" print (rx.get_samp_rate()) print "rx: get freq " print (rx.get_center_freq()) print "rx: get gain " print (rx.get_gain()) print "***************END******************" command_gate.set_ctrl_out(self.reader.ctrl_q()) tag_decoder.set_ctrl_out(self.reader.ctrl_q()) #########Build Graph self.connect(rx, matched_filt) self.connect(matched_filt, command_gate) self.connect(command_gate, to_mag) #self.connect(command_gate, agc) #self.connect(agc, to_mag) self.connect(to_mag, center, mm, tag_decoder) #self.connect(to_mag, center, matched_filt_tag_decode, tag_decoder) self.connect(tag_decoder, self.reader) self.connect(self.reader, amp) self.connect(amp, to_complex) self.connect(to_complex, tx) ################# #self.connect(command_gate, commandGate_out) self.connect(rx, rx_out)
def __init__(self, frequency, sample_rate, uhd_address="192.168.10.2", trigger=False): gr.top_block.__init__(self) self.freq = frequency self.samp_rate = sample_rate self.uhd_addr = uhd_address self.gain = 32 self.trigger = trigger self.uhd_src = uhd.single_usrp_source( device_addr=self.uhd_addr, io_type=uhd.io_type_t.COMPLEX_FLOAT32, num_channels=1, ) self.uhd_src.set_samp_rate(self.samp_rate) self.uhd_src.set_center_freq(self.freq, 0) self.uhd_src.set_gain(self.gain, 0) taps = firdes.low_pass_2(1, 1, 0.4, 0.1, 60) self.chanfilt = gr.fir_filter_ccc(10, taps) self.ann0 = gr.annotator_alltoall(100000, gr.sizeof_gr_complex) self.tagger = gr.burst_tagger(gr.sizeof_gr_complex) # Dummy signaler to collect a burst on known periods data = 1000 * [ 0, ] + 1000 * [ 1, ] self.signal = gr.vector_source_s(data, True) # Energy detector to get signal burst self.c2m = gr.complex_to_mag_squared() self.iir = gr.single_pole_iir_filter_ff(0.0001) self.sub = gr.sub_ff() self.mult = gr.multiply_const_ff(32768) self.f2s = gr.float_to_short() self.fsnk = gr.tagged_file_sink(gr.sizeof_gr_complex, self.samp_rate) ################################################## # Connections ################################################## self.connect((self.uhd_src, 0), (self.tagger, 0)) self.connect((self.tagger, 0), (self.fsnk, 0)) if self.trigger: # Connect a dummy signaler to the burst tagger self.connect((self.signal, 0), (self.tagger, 1)) else: # Connect an energy detector signaler to the burst tagger self.connect((self.uhd_src, 0), (self.c2m, 0)) self.connect((self.c2m, 0), (self.sub, 0)) self.connect((self.c2m, 0), (self.iir, 0)) self.connect((self.iir, 0), (self.sub, 1)) self.connect((self.sub, 0), (self.mult, 0)) self.connect((self.mult, 0), (self.f2s, 0)) self.connect((self.f2s, 0), (self.tagger, 1))