Ejemplo n.º 1
0
    def __init__(self, frame, panel, vbox, argv):
        stdgui2.std_top_block.__init__(self, frame, panel, vbox, argv)

        self.frame = frame
        self.panel = panel

        parser = OptionParser(option_class=eng_option)
        parser.add_option("-R",
                          "--rx-subdev-spec",
                          type="subdev",
                          default=(0, 0),
                          help="select USRP Rx side A or B (default=A)")
        parser.add_option(
            "-d",
            "--decim",
            type="int",
            default=16,
            help="set fgpa decimation rate to DECIM [default=%default]")
        parser.add_option("-f",
                          "--freq",
                          type="eng_float",
                          default=None,
                          help="set frequency to FREQ",
                          metavar="FREQ")
        parser.add_option("-Q",
                          "--observing",
                          type="eng_float",
                          default=0.0,
                          help="set observing frequency to FREQ")
        parser.add_option("-a",
                          "--avg",
                          type="eng_float",
                          default=1.0,
                          help="set spectral averaging alpha")
        parser.add_option("-V",
                          "--favg",
                          type="eng_float",
                          default=2.0,
                          help="set folder averaging alpha")
        parser.add_option("-g",
                          "--gain",
                          type="eng_float",
                          default=None,
                          help="set gain in dB (default is midpoint)")
        parser.add_option("-l",
                          "--reflevel",
                          type="eng_float",
                          default=30.0,
                          help="Set pulse display reference level")
        parser.add_option("-L",
                          "--lowest",
                          type="eng_float",
                          default=1.5,
                          help="Lowest valid frequency bin")
        parser.add_option("-e",
                          "--longitude",
                          type="eng_float",
                          default=-76.02,
                          help="Set Observer Longitude")
        parser.add_option("-c",
                          "--latitude",
                          type="eng_float",
                          default=44.85,
                          help="Set Observer Latitude")
        parser.add_option("-F",
                          "--fft_size",
                          type="eng_float",
                          default=1024,
                          help="Size of FFT")

        parser.add_option("-t",
                          "--threshold",
                          type="eng_float",
                          default=2.5,
                          help="pulsar threshold")
        parser.add_option("-p",
                          "--lowpass",
                          type="eng_float",
                          default=100,
                          help="Pulse spectra cutoff freq")
        parser.add_option("-P", "--prefix", default="./", help="File prefix")
        parser.add_option("-u",
                          "--pulsefreq",
                          type="eng_float",
                          default=0.748,
                          help="Observation pulse rate")
        parser.add_option("-D",
                          "--dm",
                          type="eng_float",
                          default=1.0e-5,
                          help="Dispersion Measure")
        parser.add_option("-O",
                          "--doppler",
                          type="eng_float",
                          default=1.0,
                          help="Doppler ratio")
        parser.add_option("-B",
                          "--divbase",
                          type="eng_float",
                          default=20,
                          help="Y/Div menu base")
        parser.add_option("-I",
                          "--division",
                          type="eng_float",
                          default=100,
                          help="Y/Div")
        parser.add_option("-A",
                          "--audio_source",
                          default="plughw:0,0",
                          help="Audio input device spec")
        parser.add_option("-N",
                          "--num_pulses",
                          default=1,
                          type="eng_float",
                          help="Number of display pulses")
        (options, args) = parser.parse_args()
        if len(args) != 0:
            parser.print_help()
            sys.exit(1)

        self.show_debug_info = True

        self.reflevel = options.reflevel
        self.divbase = options.divbase
        self.division = options.division
        self.audiodev = options.audio_source
        self.mult = int(options.num_pulses)

        # Low-pass cutoff for post-detector filter
        # Set to 100Hz usually, since lots of pulsars fit in this
        #   range
        self.lowpass = options.lowpass

        # What is lowest valid frequency bin in post-detector FFT?
        # There's some pollution very close to DC
        self.lowest_freq = options.lowest

        # What (dB) threshold to use in determining spectral candidates
        self.threshold = options.threshold

        # Filename prefix for recording file
        self.prefix = options.prefix

        # Dispersion Measure (DM)
        self.dm = options.dm

        # Doppler shift, as a ratio
        #  1.0 == no doppler shift
        #  1.005 == a little negative shift
        #  0.995 == a little positive shift
        self.doppler = options.doppler

        #
        # Input frequency and observing frequency--not necessarily the
        #   same thing, if we're looking at the IF of some downconverter
        #   that's ahead of the USRP and daughtercard.  This distinction
        #   is important in computing the correct de-dispersion filter.
        #
        self.frequency = options.freq
        if options.observing <= 0:
            self.observing_freq = options.freq
        else:
            self.observing_freq = options.observing

        # build the graph
        self.u = usrp.source_c(decim_rate=options.decim)
        self.u.set_mux(
            usrp.determine_rx_mux_value(self.u, options.rx_subdev_spec))

        #
        # Recording file, in case we ever need to record baseband data
        #
        self.recording = gr.file_sink(gr.sizeof_char, "/dev/null")
        self.recording_state = False

        self.pulse_recording = gr.file_sink(gr.sizeof_short, "/dev/null")
        self.pulse_recording_state = False

        #
        # We come up with recording turned off, but the user may
        #  request recording later on
        self.recording.close()
        self.pulse_recording.close()

        #
        # Need these two for converting 12-bit baseband signals to 8-bit
        #
        self.tofloat = gr.complex_to_float()
        self.tochar = gr.float_to_char()

        # Need this for recording pulses (post-detector)
        self.toshort = gr.float_to_short()

        #
        # The spectral measurer sets this when it has a valid
        #   average spectral peak-to-peak distance
        # We can then use this to program the parameters for the epoch folder
        #
        # We set a sentimental value here
        self.pulse_freq = options.pulsefreq

        # Folder runs at this raw sample rate
        self.folder_input_rate = 20000

        # Each pulse in the epoch folder is sampled at 128 times the nominal
        #  pulse rate
        self.folding = 128

        #
        # Try to find candidate parameters for rational resampler
        #
        save_i = 0
        candidates = []
        for i in range(20, 300):
            input_rate = self.folder_input_rate
            output_rate = int(self.pulse_freq * i)
            interp = gru.lcm(input_rate, output_rate) / input_rate
            decim = gru.lcm(input_rate, output_rate) / output_rate
            if (interp < 500 and decim < 250000):
                candidates.append(i)

        # We didn't find anything, bail!
        if (len(candidates) < 1):
            print "Couldn't converge on resampler parameters"
            sys.exit(1)

        #
        # Now try to find candidate with the least sampling error
        #
        mindiff = 999.999
        for i in candidates:
            diff = self.pulse_freq * i
            diff = diff - int(diff)
            if (diff < mindiff):
                mindiff = diff
                save_i = i

        # Recompute rates
        input_rate = self.folder_input_rate
        output_rate = int(self.pulse_freq * save_i)

        # Compute new interp and decim, based on best candidate
        interp = gru.lcm(input_rate, output_rate) / input_rate
        decim = gru.lcm(input_rate, output_rate) / output_rate

        # Save optimized folding parameters, used later
        self.folding = save_i
        self.interp = int(interp)
        self.decim = int(decim)

        # So that we can view N pulses in the pulse viewer window
        FOLD_MULT = self.mult

        # determine the daughterboard subdevice we're using
        self.subdev = usrp.selected_subdev(self.u, options.rx_subdev_spec)
        self.cardtype = self.u.daughterboard_id(0)

        # Compute raw input rate
        input_rate = self.u.adc_freq() / self.u.decim_rate()

        # BW==input_rate for complex data
        self.bw = input_rate

        #
        # Set baseband filter bandwidth if DBS_RX:
        #
        if self.cardtype == usrp_dbid.DBS_RX:
            lbw = input_rate / 2
            if lbw < 1.0e6:
                lbw = 1.0e6
            self.subdev.set_bw(lbw)

        #
        # We use this as a crude volume control for the audio output
        #
        #self.volume = gr.multiply_const_ff(10**(-1))

        #
        # Create location data for ephem package
        #
        self.locality = ephem.Observer()
        self.locality.long = str(options.longitude)
        self.locality.lat = str(options.latitude)

        #
        # What is the post-detector LPF cutoff for the FFT?
        #
        PULSAR_MAX_FREQ = int(options.lowpass)

        # First low-pass filters down to input_rate/FIRST_FACTOR
        #   and decimates appropriately
        FIRST_FACTOR = int(input_rate / (self.folder_input_rate / 2))
        first_filter = gr.firdes.low_pass(1.0, input_rate,
                                          input_rate / FIRST_FACTOR,
                                          input_rate / (FIRST_FACTOR * 20),
                                          gr.firdes.WIN_HAMMING)

        # Second filter runs at the output rate of the first filter,
        #  And low-pass filters down to PULSAR_MAX_FREQ*10
        #
        second_input_rate = int(input_rate / (FIRST_FACTOR / 2))
        second_filter = gr.firdes.band_pass(1.0, second_input_rate, 0.10,
                                            PULSAR_MAX_FREQ * 10,
                                            PULSAR_MAX_FREQ * 1.5,
                                            gr.firdes.WIN_HAMMING)

        # Third filter runs at PULSAR_MAX_FREQ*20
        #   and filters down to PULSAR_MAX_FREQ
        #
        third_input_rate = PULSAR_MAX_FREQ * 20
        third_filter = gr.firdes_band_pass(1.0, third_input_rate, 0.10,
                                           PULSAR_MAX_FREQ,
                                           PULSAR_MAX_FREQ / 10.0,
                                           gr.firdes.WIN_HAMMING)

        #
        # Create the appropriate FFT scope
        #
        self.scope = ra_fftsink.ra_fft_sink_f(panel,
                                              fft_size=int(options.fft_size),
                                              sample_rate=PULSAR_MAX_FREQ * 2,
                                              title="Post-detector spectrum",
                                              ofunc=self.pulsarfunc,
                                              xydfunc=self.xydfunc,
                                              fft_rate=200)

        #
        # Tell scope we're looking from DC to PULSAR_MAX_FREQ
        #
        self.scope.set_baseband_freq(0.0)

        #
        # Setup stripchart for showing pulse profiles
        #
        hz = "%5.3fHz " % self.pulse_freq
        per = "(%5.3f sec)" % (1.0 / self.pulse_freq)
        sr = "%d sps" % (int(self.pulse_freq * self.folding))
        times = " %d Pulse Intervals" % self.mult
        self.chart = ra_stripchartsink.stripchart_sink_f(
            panel,
            sample_rate=1,
            stripsize=self.folding * FOLD_MULT,
            parallel=True,
            title="Pulse Profiles: " + hz + per + times,
            xlabel="Seconds @ " + sr,
            ylabel="Level",
            autoscale=True,
            divbase=self.divbase,
            scaling=1.0 / (self.folding * self.pulse_freq))
        self.chart.set_ref_level(self.reflevel)
        self.chart.set_y_per_div(self.division)

        # De-dispersion filter setup
        #
        # Do this here, just before creating the filter
        #  that will use the taps.
        #
        ntaps = self.compute_disp_ntaps(self.dm, self.bw, self.observing_freq)

        # Taps for the de-dispersion filter
        self.disp_taps = Numeric.zeros(ntaps, Numeric.Complex64)

        # Compute the de-dispersion filter now
        self.compute_dispfilter(self.dm, self.doppler, self.bw,
                                self.observing_freq)

        #
        # Call constructors for receive chains
        #

        #
        # Now create the FFT filter using the computed taps
        self.dispfilt = gr.fft_filter_ccc(1, self.disp_taps)

        #
        # Audio sink
        #
        #print "input_rate ", second_input_rate, "audiodev ", self.audiodev
        #self.audio = audio.sink(second_input_rate, self.audiodev)

        #
        # The three post-detector filters
        # Done this way to allow an audio path (up to 10Khz)
        # ...and also because going from xMhz down to ~100Hz
        # In a single filter doesn't seem to work.
        #
        self.first = gr.fir_filter_fff(FIRST_FACTOR / 2, first_filter)

        p = second_input_rate / (PULSAR_MAX_FREQ * 20)
        self.second = gr.fir_filter_fff(int(p), second_filter)
        self.third = gr.fir_filter_fff(10, third_filter)

        # Detector
        self.detector = gr.complex_to_mag_squared()

        self.enable_comb_filter = False
        # Epoch folder comb filter
        if self.enable_comb_filter == True:
            bogtaps = Numeric.zeros(512, Numeric.Float64)
            self.folder_comb = gr.fft_filter_ccc(1, bogtaps)

        # Rational resampler
        self.folder_rr = blks2.rational_resampler_fff(self.interp, self.decim)

        # Epoch folder bandpass
        bogtaps = Numeric.zeros(1, Numeric.Float64)
        self.folder_bandpass = gr.fir_filter_fff(1, bogtaps)

        # Epoch folder F2C/C2F
        self.folder_f2c = gr.float_to_complex()
        self.folder_c2f = gr.complex_to_float()

        # Epoch folder S2P
        self.folder_s2p = gr.serial_to_parallel(gr.sizeof_float,
                                                self.folding * FOLD_MULT)

        # Epoch folder IIR Filter (produces average pulse profiles)
        self.folder_iir = gr.single_pole_iir_filter_ff(
            1.0 / options.favg, self.folding * FOLD_MULT)

        #
        # Set all the epoch-folder goop up
        #
        self.set_folding_params()

        #
        # Start connecting configured modules in the receive chain
        #

        # Connect raw USRP to de-dispersion filter, detector
        self.connect(self.u, self.dispfilt, self.detector)

        # Connect detector output to FIR LPF
        #  in two stages, followed by the FFT scope
        self.connect(self.detector, self.first, self.second, self.third,
                     self.scope)

        # Connect audio output
        #self.connect(self.first, self.volume)
        #self.connect(self.volume, (self.audio, 0))
        #self.connect(self.volume, (self.audio, 1))

        # Connect epoch folder
        if self.enable_comb_filter == True:
            self.connect(self.first, self.folder_bandpass, self.folder_rr,
                         self.folder_f2c, self.folder_comb, self.folder_c2f,
                         self.folder_s2p, self.folder_iir, self.chart)

        else:
            self.connect(self.first, self.folder_bandpass, self.folder_rr,
                         self.folder_s2p, self.folder_iir, self.chart)

        # Connect baseband recording file (initially /dev/null)
        self.connect(self.u, self.tofloat, self.tochar, self.recording)

        # Connect pulse recording file (initially /dev/null)
        self.connect(self.first, self.toshort, self.pulse_recording)

        #
        # Build the GUI elements
        #
        self._build_gui(vbox)

        # Make GUI agree with command-line
        self.myform['average'].set_value(int(options.avg))
        self.myform['foldavg'].set_value(int(options.favg))

        # Make spectral averager agree with command line
        if options.avg != 1.0:
            self.scope.set_avg_alpha(float(1.0 / options.avg))
            self.scope.set_average(True)

        # set initial values

        if options.gain is None:
            # if no gain was specified, use the mid-point in dB
            g = self.subdev.gain_range()
            options.gain = float(g[0] + g[1]) / 2

        if options.freq is None:
            # if no freq was specified, use the mid-point
            r = self.subdev.freq_range()
            options.freq = float(r[0] + r[1]) / 2

        self.set_gain(options.gain)
        #self.set_volume(-10.0)

        if not (self.set_freq(options.freq)):
            self._set_status_msg("Failed to set initial frequency")

        self.myform['decim'].set_value(self.u.decim_rate())
        self.myform['fs@usb'].set_value(self.u.adc_freq() /
                                        self.u.decim_rate())
        self.myform['dbname'].set_value(self.subdev.name())
        self.myform['DM'].set_value(self.dm)
        self.myform['Doppler'].set_value(self.doppler)

        #
        # Start the timer that shows current LMST on the GUI
        #
        self.lmst_timer.Start(1000)
Ejemplo n.º 2
0
	def __init__(self, frame, panel, vbox, argv):
		stdgui2.std_top_block.__init__(self, frame, panel, vbox, argv)

		self.frame = frame
		self.panel = panel
		
		parser = OptionParser(option_class=eng_option)
		parser.add_option("-R", "--rx-subdev-spec", type="subdev", default=(0, 0),
			help="select USRP Rx side A or B (default=A)")
		parser.add_option("-d", "--decim", type="int", default=16,
			help="set fgpa decimation rate to DECIM [default=%default]")
		parser.add_option("-f", "--freq", type="eng_float", default=None,
			help="set frequency to FREQ", metavar="FREQ")
		parser.add_option("-a", "--avg", type="eng_float", default=1.0,
			help="set spectral averaging alpha")
		parser.add_option("-i", "--integ", type="eng_float", default=1.0,
			help="set integration time")
		parser.add_option("-g", "--gain", type="eng_float", default=None,
			help="set gain in dB (default is midpoint)")
		parser.add_option("-l", "--reflevel", type="eng_float", default=30.0,
			help="Set Total power reference level")
		parser.add_option("-y", "--division", type="eng_float", default=0.5,
			help="Set Total power Y division size")
		parser.add_option("-e", "--longitude", type="eng_float", default=-76.02,help="Set Observer Longitude")
		parser.add_option("-c", "--latitude", type="eng_float", default=44.85,help="Set Observer Latitude")
		parser.add_option("-o", "--observing", type="eng_float", default=0.0,
			help="Set observing frequency")
		parser.add_option("-x", "--ylabel", default="dB", help="Y axis label") 
		parser.add_option("-z", "--divbase", type="eng_float", default=0.025, help="Y Division increment base") 
		parser.add_option("-v", "--stripsize", type="eng_float", default=2400, help="Size of stripchart, in 2Hz samples") 
		parser.add_option("-F", "--fft_size", type="eng_float", default=1024, help="Size of FFT")
		parser.add_option("-N", "--decln", type="eng_float", default=999.99, help="Observing declination")
		parser.add_option("-X", "--prefix", default="./")
		parser.add_option("-M", "--fft_rate", type="eng_float", default=8.0, help="FFT Rate")
		parser.add_option("-A", "--calib_coeff", type="eng_float", default=1.0, help="Calibration coefficient")
		parser.add_option("-B", "--calib_offset", type="eng_float", default=0.0, help="Calibration coefficient")
		parser.add_option("-W", "--waterfall", action="store_true", default=False, help="Use Waterfall FFT display")
		parser.add_option("-S", "--setimode", action="store_true", default=False, help="Enable SETI processing of spectral data")
		parser.add_option("-K", "--setik", type="eng_float", default=1.5, help="K value for SETI analysis")
		parser.add_option("-T", "--setibandwidth", type="eng_float", default=12500, help="Instantaneous SETI observing bandwidth--must be divisor of 250Khz")
		parser.add_option("-Q", "--seti_range", type="eng_float", default=1.0e6, help="Total scan width, in Hz for SETI scans")
		parser.add_option("-Z", "--dual_mode", action="store_true",
			default=False, help="Dual-polarization mode")
		parser.add_option("-I", "--interferometer", action="store_true", default=False, help="Interferometer mode")
		parser.add_option("-D", "--switch_mode", action="store_true", default=False, help="Dicke Switching mode")
		parser.add_option("-P", "--reference_divisor", type="eng_float", default=1.0, help="Reference Divisor")
		parser.add_option("-U", "--ref_fifo", default=None)
		parser.add_option("-k", "--notch_taps", type="int", default=64, help="Number of notch taps")
		parser.add_option("-n", "--notches", action="store_true", 
		    default=False, help="Notch frequencies after all other args")
		parser.add_option("-Y", "--interface", default=None)
		parser.add_option("-H", "--mac_addr", default=None)

		# Added this documentation
		
		(options, args) = parser.parse_args()

		self.setimode = options.setimode
		self.dual_mode = options.dual_mode
		self.interferometer = options.interferometer
		self.normal_mode = False
		self.switch_mode = options.switch_mode
		self.switch_state = 0
		self.reference_divisor = options.reference_divisor
		self.ref_fifo = options.ref_fifo
		self.usrp2 = False
		self.decim = options.decim
		self.rx_subdev_spec = options.rx_subdev_spec
		
		if (options.interface != None and options.mac_addr != None):
			self.mac_addr = options.mac_addr
			self.interface = options.interface
			self.usrp2 = True
		
		self.NOTCH_TAPS = options.notch_taps
		self.notches = Numeric.zeros(self.NOTCH_TAPS,Numeric.Float64)
		# Get notch locations
		j = 0
		for i in args:
			self.notches[j] = float(i)
			j = j + 1
		
		self.use_notches = options.notches
		
		if (self.ref_fifo != None):
			self.ref_fifo_file = open (self.ref_fifo, "r")
		
		modecount = 0
		for modes in (self.dual_mode, self.interferometer):
			if (modes == True):
				modecount = modecount + 1
				
		if (modecount > 1):
			print "must select only 1 of --dual_mode, or --interferometer"
			sys.exit(1)
			
		self.chartneeded = True
		
		if (self.setimode == True):
			self.chartneeded = False
			
		if (self.setimode == True and self.interferometer == True):
			print "can't pick both --setimode and --interferometer"
			sys.exit(1)
			
		if (self.setimode == True and self.switch_mode == True):
			print "can't pick both --setimode and --switch_mode"
			sys.exit(1)
		
		if (self.interferometer == True and self.switch_mode == True):
			print "can't pick both --interferometer and --switch_mode"
			sys.exit(1)
		
		if (modecount == 0):
			self.normal_mode = True

		self.show_debug_info = True
		
		# Pick up waterfall option
		self.waterfall = options.waterfall

		# SETI mode stuff
		self.setimode = options.setimode
		self.seticounter = 0
		self.setik = options.setik
		self.seti_fft_bandwidth = int(options.setibandwidth)

		# Calculate binwidth
		binwidth = self.seti_fft_bandwidth / options.fft_size

		# Use binwidth, and knowledge of likely chirp rates to set reasonable
		#  values for SETI analysis code.	We assume that SETI signals will
		#  chirp at somewhere between 0.10Hz/sec and 0.25Hz/sec.
		#
		# upper_limit is the "worst case"--that is, the case for which we have
		#  to wait the longest to actually see any drift, due to the quantizing
		#  on FFT bins.
		upper_limit = binwidth / 0.10
		self.setitimer = int(upper_limit * 2.00)
		self.scanning = True

		# Calculate the CHIRP values based on Hz/sec
		self.CHIRP_LOWER = 0.10 * self.setitimer
		self.CHIRP_UPPER = 0.25 * self.setitimer

		# Reset hit counters to 0
		self.hitcounter = 0
		self.s1hitcounter = 0
		self.s2hitcounter = 0
		self.avgdelta = 0
		# We scan through 2Mhz of bandwidth around the chosen center freq
		self.seti_freq_range = options.seti_range
		# Calculate lower edge
		self.setifreq_lower = options.freq - (self.seti_freq_range/2)
		self.setifreq_current = options.freq
		# Calculate upper edge
		self.setifreq_upper = options.freq + (self.seti_freq_range/2)

		# Maximum "hits" in a line
		self.nhits = 20

		# Number of lines for analysis
		self.nhitlines = 4

		# We change center frequencies based on nhitlines and setitimer
		self.setifreq_timer = self.setitimer * (self.nhitlines * 5)

		# Create actual timer
		self.seti_then = time.time()

		# The hits recording array
		self.hits_array = Numeric.zeros((self.nhits,self.nhitlines), Numeric.Float64)
		self.hit_intensities = Numeric.zeros((self.nhits,self.nhitlines), Numeric.Float64)
		# Calibration coefficient and offset
		self.calib_coeff = options.calib_coeff
		self.calib_offset = options.calib_offset
		if self.calib_offset < -750:
			self.calib_offset = -750
		if self.calib_offset > 750:
			self.calib_offset = 750

		if self.calib_coeff < 1:
			self.calib_coeff = 1
		if self.calib_coeff > 100:
			self.calib_coeff = 100

		self.integ = options.integ
		self.avg_alpha = options.avg
		self.gain = options.gain
		self.decln = options.decln

		# Set initial values for datalogging timed-output
		self.continuum_then = time.time()
		self.spectral_then = time.time()
		
	  
		# build the graph

		self.subdev = [(0, 0), (0,0)]
		
		#
		# If SETI mode, we always run at maximum USRP decimation
		#
		if (self.setimode):
			options.decim = 256
		
		if (self.dual_mode == True and self.decim <= 4):
			print "Cannot use decim <= 4 with dual_mode"
			sys.exit(1)
		
		self.setup_usrp()
		
		# Set initial declination
		self.decln = options.decln

		input_rate = self.u.adc_freq() / self.u.decim_rate()
		self.bw = input_rate
		#
		# Set prefix for data files
		#
		self.prefix = options.prefix

		#
		# The lower this number, the fewer sample frames are dropped
		#  in computing the FFT.  A sampled approach is taken to
		#  computing the FFT of the incoming data, which reduces
		#  sensitivity.	 Increasing sensitivity inreases CPU loading.
		#
		self.fft_rate = options.fft_rate

		self.fft_size = int(options.fft_size)

		# This buffer is used to remember the most-recent FFT display
		#	values.	 Used later by self.write_spectral_data() to write
		#	spectral data to datalogging files, and by the SETI analysis
		#	function.
		#
		self.fft_outbuf = Numeric.zeros(self.fft_size, Numeric.Float64)

		#
		# If SETI mode, only look at seti_fft_bandwidth
		#	at a time.
		#
		if (self.setimode):
			self.fft_input_rate = self.seti_fft_bandwidth

			#
			# Build a decimating bandpass filter
			#
			self.fft_input_taps = gr.firdes.complex_band_pass (1.0,
			   input_rate,
			   -(int(self.fft_input_rate/2)), int(self.fft_input_rate/2), 200,
			   gr.firdes.WIN_HAMMING, 0)

			#
			# Compute required decimation factor
			#
			decimation = int(input_rate/self.fft_input_rate)
			self.fft_bandpass = gr.fir_filter_ccc (decimation, 
				self.fft_input_taps)
		else:
			self.fft_input_rate = input_rate

		# Set up FFT display
		if self.waterfall == False:
		   self.scope = ra_fftsink.ra_fft_sink_c (panel, 
			   fft_size=int(self.fft_size), sample_rate=self.fft_input_rate,
			   fft_rate=int(self.fft_rate), title="Spectral",  
			   ofunc=self.fft_outfunc, xydfunc=self.xydfunc)
		else:
			self.scope = ra_waterfallsink.waterfall_sink_c (panel,
				fft_size=int(self.fft_size), sample_rate=self.fft_input_rate,
				fft_rate=int(self.fft_rate), title="Spectral", ofunc=self.fft_outfunc, size=(1100, 600), xydfunc=self.xydfunc, ref_level=0, span=10)

		# Set up ephemeris data
		self.locality = ephem.Observer()
		self.locality.long = str(options.longitude)
		self.locality.lat = str(options.latitude)
		
		# We make notes about Sunset/Sunrise in Continuum log files
		self.sun = ephem.Sun()
		self.sunstate = "??"

		# Set up stripchart display
		tit = "Continuum"
		if (self.dual_mode != False):
			tit = "H+V Continuum"
		if (self.interferometer != False):
			tit = "East x West Correlation"
		self.stripsize = int(options.stripsize)
		if self.chartneeded == True:
			self.chart = ra_stripchartsink.stripchart_sink_f (panel,
				stripsize=self.stripsize,
				title=tit,
				xlabel="LMST Offset (Seconds)",
				scaling=1.0, ylabel=options.ylabel,
				divbase=options.divbase)

		# Set center frequency
		self.centerfreq = options.freq

		# Set observing frequency (might be different from actual programmed
		#	 RF frequency)
		if options.observing == 0.0:
			self.observing = options.freq
		else:
			self.observing = options.observing

		# Remember our input bandwidth
		self.bw = input_rate
		
		#
		# 
		# The strip chart is fed at a constant 1Hz rate
		#

		#
		# Call constructors for receive chains
		#
		
		if (self.dual_mode == True):
			self.setup_dual (self.setimode)
			
		if (self.interferometer == True):
			self.setup_interferometer(self.setimode)
				
		if (self.normal_mode == True):
			self.setup_normal(self.setimode)
			
		if (self.setimode == True):
			self.setup_seti()

		self._build_gui(vbox)

		# Make GUI agree with command-line
		self.integ = options.integ
		if self.setimode == False:
			self.myform['integration'].set_value(int(options.integ))
			self.myform['offset'].set_value(self.calib_offset)
			self.myform['dcgain'].set_value(self.calib_coeff)
		self.myform['average'].set_value(int(options.avg))


		if self.setimode == False:
			# Make integrator agree with command line
			self.set_integration(int(options.integ))

		self.avg_alpha = options.avg

		# Make spectral averager agree with command line
		if options.avg != 1.0:
			self.scope.set_avg_alpha(float(1.0/options.avg))
			self.scope.set_average(True)

		if self.setimode == False:
			# Set division size
			self.chart.set_y_per_div(options.division)
			# Set reference(MAX) level
			self.chart.set_ref_level(options.reflevel)

		# set initial values

		if options.gain is None:
			# if no gain was specified, use the mid-point in dB
			g = self.subdev[0].gain_range()
			options.gain = float(g[0]+g[1])/2

		if options.freq is None:
			# if no freq was specified, use the mid-point
			r = self.subdev[0].freq_range()
			options.freq = float(r[0]+r[1])/2

		# Set the initial gain control
		self.set_gain(options.gain)

		if not(self.set_freq(options.freq)):
			self._set_status_msg("Failed to set initial frequency")

		# Set declination
		self.set_decln (self.decln)


		# RF hardware information
		self.myform['decim'].set_value(self.u.decim_rate())
		self.myform['USB BW'].set_value(self.u.adc_freq() / self.u.decim_rate())
		if (self.dual_mode == True):
			self.myform['dbname'].set_value(self.subdev[0].name()+'/'+self.subdev[1].name())
		else:
			self.myform['dbname'].set_value(self.subdev[0].name())

		# Set analog baseband filtering, if DBS_RX
		if self.cardtype == usrp_dbid.DBS_RX:
			lbw = (self.u.adc_freq() / self.u.decim_rate()) / 2
			if lbw < 1.0e6:
				lbw = 1.0e6
			self.subdev[0].set_bw(lbw)
			self.subdev[1].set_bw(lbw)
			
		# Start the timer for the LMST display and datalogging
		self.lmst_timer.Start(1000)
		if (self.switch_mode == True):
			self.other_timer.Start(330)
Ejemplo n.º 3
0
    def __init__(self, frame, panel, vbox, argv):
        stdgui2.std_top_block.__init__(self, frame, panel, vbox, argv)

        self.frame = frame
        self.panel = panel
        
        parser = OptionParser(option_class=eng_option)
        parser.add_option("-R", "--rx-subdev-spec", type="subdev", default=(0, 0),
                          help="select USRP Rx side A or B (default=A)")
        parser.add_option("-d", "--decim", type="int", default=16,
                          help="set fgpa decimation rate to DECIM [default=%default]")
        parser.add_option("-f", "--freq", type="eng_float", default=None,
                          help="set frequency to FREQ", metavar="FREQ")
        parser.add_option("-Q", "--observing", type="eng_float", default=0.0,
                          help="set observing frequency to FREQ")
        parser.add_option("-a", "--avg", type="eng_float", default=1.0,
		help="set spectral averaging alpha")
        parser.add_option("-V", "--favg", type="eng_float", default=2.0,
                help="set folder averaging alpha")
        parser.add_option("-g", "--gain", type="eng_float", default=None,
                          help="set gain in dB (default is midpoint)")
        parser.add_option("-l", "--reflevel", type="eng_float", default=30.0,
                          help="Set pulse display reference level")
        parser.add_option("-L", "--lowest", type="eng_float", default=1.5,
                          help="Lowest valid frequency bin")
        parser.add_option("-e", "--longitude", type="eng_float", default=-76.02,                          help="Set Observer Longitude")
        parser.add_option("-c", "--latitude", type="eng_float", default=44.85,                          help="Set Observer Latitude")
        parser.add_option("-F", "--fft_size", type="eng_float", default=1024, help="Size of FFT")

        parser.add_option ("-t", "--threshold", type="eng_float", default=2.5, help="pulsar threshold")
        parser.add_option("-p", "--lowpass", type="eng_float", default=100, help="Pulse spectra cutoff freq")
        parser.add_option("-P", "--prefix", default="./", help="File prefix")
        parser.add_option("-u", "--pulsefreq", type="eng_float", default=0.748, help="Observation pulse rate")
        parser.add_option("-D", "--dm", type="eng_float", default=1.0e-5, help="Dispersion Measure")
        parser.add_option("-O", "--doppler", type="eng_float", default=1.0, help="Doppler ratio")
        parser.add_option("-B", "--divbase", type="eng_float", default=20, help="Y/Div menu base")
        parser.add_option("-I", "--division", type="eng_float", default=100, help="Y/Div")
        parser.add_option("-A", "--audio_source", default="plughw:0,0", help="Audio input device spec")
        parser.add_option("-N", "--num_pulses", default=1, type="eng_float", help="Number of display pulses")
        (options, args) = parser.parse_args()
        if len(args) != 0:
            parser.print_help()
            sys.exit(1)

        self.show_debug_info = True

        self.reflevel = options.reflevel
        self.divbase = options.divbase
        self.division = options.division
        self.audiodev = options.audio_source
        self.mult = int(options.num_pulses)

        # Low-pass cutoff for post-detector filter
        # Set to 100Hz usually, since lots of pulsars fit in this
        #   range
        self.lowpass = options.lowpass

        # What is lowest valid frequency bin in post-detector FFT?
        # There's some pollution very close to DC
        self.lowest_freq = options.lowest

        # What (dB) threshold to use in determining spectral candidates
        self.threshold = options.threshold

        # Filename prefix for recording file
        self.prefix = options.prefix

        # Dispersion Measure (DM)
        self.dm = options.dm

        # Doppler shift, as a ratio
        #  1.0 == no doppler shift
        #  1.005 == a little negative shift
        #  0.995 == a little positive shift
        self.doppler = options.doppler

        #
        # Input frequency and observing frequency--not necessarily the
        #   same thing, if we're looking at the IF of some downconverter
        #   that's ahead of the USRP and daughtercard.  This distinction
        #   is important in computing the correct de-dispersion filter.
        #
        self.frequency = options.freq
        if options.observing <= 0:
            self.observing_freq = options.freq
        else:
            self.observing_freq = options.observing
        
        # build the graph
        self.u = usrp.source_c(decim_rate=options.decim)
        self.u.set_mux(usrp.determine_rx_mux_value(self.u, options.rx_subdev_spec))

        #
        # Recording file, in case we ever need to record baseband data
        #
        self.recording = gr.file_sink(gr.sizeof_char, "/dev/null")
        self.recording_state = False

        self.pulse_recording = gr.file_sink(gr.sizeof_short, "/dev/null")
        self.pulse_recording_state = False

        #
        # We come up with recording turned off, but the user may
        #  request recording later on
        self.recording.close()
        self.pulse_recording.close()

        #
        # Need these two for converting 12-bit baseband signals to 8-bit
        #
        self.tofloat = gr.complex_to_float()
        self.tochar = gr.float_to_char()

        # Need this for recording pulses (post-detector)
        self.toshort = gr.float_to_short()


        #
        # The spectral measurer sets this when it has a valid
        #   average spectral peak-to-peak distance
        # We can then use this to program the parameters for the epoch folder
        #
        # We set a sentimental value here
        self.pulse_freq = options.pulsefreq

        # Folder runs at this raw sample rate
        self.folder_input_rate = 20000

        # Each pulse in the epoch folder is sampled at 128 times the nominal
        #  pulse rate
        self.folding = 128

 
        #
        # Try to find candidate parameters for rational resampler
        #
        save_i = 0
        candidates = []
        for i in range(20,300):
            input_rate = self.folder_input_rate
            output_rate = int(self.pulse_freq * i)
            interp = gru.lcm(input_rate, output_rate) / input_rate
            decim = gru.lcm(input_rate, output_rate) / output_rate
            if (interp < 500 and decim < 250000):
                 candidates.append(i)

        # We didn't find anything, bail!
        if (len(candidates) < 1):
            print "Couldn't converge on resampler parameters"
            sys.exit(1)

        #
        # Now try to find candidate with the least sampling error
        #
        mindiff = 999.999
        for i in candidates:
            diff = self.pulse_freq * i
            diff = diff - int(diff)
            if (diff < mindiff):
                mindiff = diff
                save_i = i

        # Recompute rates
        input_rate = self.folder_input_rate
        output_rate = int(self.pulse_freq * save_i)

        # Compute new interp and decim, based on best candidate
        interp = gru.lcm(input_rate, output_rate) / input_rate
        decim = gru.lcm(input_rate, output_rate) / output_rate

        # Save optimized folding parameters, used later
        self.folding = save_i
        self.interp = int(interp)
        self.decim = int(decim)

        # So that we can view N pulses in the pulse viewer window
        FOLD_MULT=self.mult

        # determine the daughterboard subdevice we're using
        self.subdev = usrp.selected_subdev(self.u, options.rx_subdev_spec)
        self.cardtype = self.u.daughterboard_id(0)

        # Compute raw input rate
        input_rate = self.u.adc_freq() / self.u.decim_rate()

        # BW==input_rate for complex data
        self.bw = input_rate

        #
        # Set baseband filter bandwidth if DBS_RX:
        #
        if self.cardtype == usrp_dbid.DBS_RX:
            lbw = input_rate / 2
            if lbw < 1.0e6:
                lbw = 1.0e6
            self.subdev.set_bw(lbw)

        #
        # We use this as a crude volume control for the audio output
        #
        #self.volume = gr.multiply_const_ff(10**(-1))
        

        #
        # Create location data for ephem package
        #
        self.locality = ephem.Observer()
        self.locality.long = str(options.longitude)
        self.locality.lat = str(options.latitude)

        #
        # What is the post-detector LPF cutoff for the FFT?
        #
        PULSAR_MAX_FREQ=int(options.lowpass)

        # First low-pass filters down to input_rate/FIRST_FACTOR
        #   and decimates appropriately
        FIRST_FACTOR=int(input_rate/(self.folder_input_rate/2))
        first_filter = gr.firdes.low_pass (1.0,
                                          input_rate,
                                          input_rate/FIRST_FACTOR,
                                          input_rate/(FIRST_FACTOR*20),         
                                          gr.firdes.WIN_HAMMING)

        # Second filter runs at the output rate of the first filter,
        #  And low-pass filters down to PULSAR_MAX_FREQ*10
        #
        second_input_rate =  int(input_rate/(FIRST_FACTOR/2))
        second_filter = gr.firdes.band_pass(1.0, second_input_rate,
                                          0.10,
                                          PULSAR_MAX_FREQ*10,
                                          PULSAR_MAX_FREQ*1.5,
                                          gr.firdes.WIN_HAMMING)

        # Third filter runs at PULSAR_MAX_FREQ*20
        #   and filters down to PULSAR_MAX_FREQ
        #
        third_input_rate = PULSAR_MAX_FREQ*20
        third_filter = gr.firdes_band_pass(1.0, third_input_rate,
                                           0.10, PULSAR_MAX_FREQ,
                                           PULSAR_MAX_FREQ/10.0,
                                           gr.firdes.WIN_HAMMING)


        #
        # Create the appropriate FFT scope
        #
        self.scope = ra_fftsink.ra_fft_sink_f (panel, 
           fft_size=int(options.fft_size), sample_rate=PULSAR_MAX_FREQ*2,
           title="Post-detector spectrum",  
           ofunc=self.pulsarfunc, xydfunc=self.xydfunc, fft_rate=200)

        #
        # Tell scope we're looking from DC to PULSAR_MAX_FREQ
        #
        self.scope.set_baseband_freq (0.0)


        #
        # Setup stripchart for showing pulse profiles
        #
        hz = "%5.3fHz " % self.pulse_freq
        per = "(%5.3f sec)" % (1.0/self.pulse_freq)
        sr = "%d sps" % (int(self.pulse_freq*self.folding))
        times = " %d Pulse Intervals" % self.mult
        self.chart = ra_stripchartsink.stripchart_sink_f (panel,
               sample_rate=1,
               stripsize=self.folding*FOLD_MULT, parallel=True, title="Pulse Profiles: "+hz+per+times, 
               xlabel="Seconds @ "+sr, ylabel="Level", autoscale=True,
               divbase=self.divbase, scaling=1.0/(self.folding*self.pulse_freq))
        self.chart.set_ref_level(self.reflevel)
        self.chart.set_y_per_div(self.division)

        # De-dispersion filter setup
        #
        # Do this here, just before creating the filter
        #  that will use the taps.
        #
        ntaps = self.compute_disp_ntaps(self.dm,self.bw,self.observing_freq)

        # Taps for the de-dispersion filter
        self.disp_taps = Numeric.zeros(ntaps,Numeric.Complex64)

        # Compute the de-dispersion filter now
        self.compute_dispfilter(self.dm,self.doppler,
            self.bw,self.observing_freq)

        #
        # Call constructors for receive chains
        #

        #
        # Now create the FFT filter using the computed taps
        self.dispfilt = gr.fft_filter_ccc(1, self.disp_taps)

        #
        # Audio sink
        #
        #print "input_rate ", second_input_rate, "audiodev ", self.audiodev
        #self.audio = audio.sink(second_input_rate, self.audiodev)

        #
        # The three post-detector filters
        # Done this way to allow an audio path (up to 10Khz)
        # ...and also because going from xMhz down to ~100Hz
        # In a single filter doesn't seem to work.
        #
        self.first = gr.fir_filter_fff (FIRST_FACTOR/2, first_filter)

        p = second_input_rate / (PULSAR_MAX_FREQ*20)
        self.second = gr.fir_filter_fff (int(p), second_filter)
        self.third = gr.fir_filter_fff (10, third_filter)

        # Detector
        self.detector = gr.complex_to_mag_squared()

        self.enable_comb_filter = False
        # Epoch folder comb filter
        if self.enable_comb_filter == True:
            bogtaps = Numeric.zeros(512, Numeric.Float64)
            self.folder_comb = gr.fft_filter_ccc(1,bogtaps)

        # Rational resampler
        self.folder_rr = blks2.rational_resampler_fff(self.interp, self.decim)

        # Epoch folder bandpass
        bogtaps = Numeric.zeros(1, Numeric.Float64)
        self.folder_bandpass = gr.fir_filter_fff (1, bogtaps)

        # Epoch folder F2C/C2F
        self.folder_f2c = gr.float_to_complex()
        self.folder_c2f = gr.complex_to_float()

        # Epoch folder S2P
        self.folder_s2p = gr.serial_to_parallel (gr.sizeof_float, 
             self.folding*FOLD_MULT)

        # Epoch folder IIR Filter (produces average pulse profiles)
        self.folder_iir = gr.single_pole_iir_filter_ff(1.0/options.favg,
             self.folding*FOLD_MULT)

        #
        # Set all the epoch-folder goop up
        #
        self.set_folding_params()

        # 
        # Start connecting configured modules in the receive chain
        #

        # Connect raw USRP to de-dispersion filter, detector
        self.connect(self.u, self.dispfilt, self.detector)

        # Connect detector output to FIR LPF
        #  in two stages, followed by the FFT scope
        self.connect(self.detector, self.first,
            self.second, self.third, self.scope)

        # Connect audio output
        #self.connect(self.first, self.volume)
        #self.connect(self.volume, (self.audio, 0))
        #self.connect(self.volume, (self.audio, 1))

        # Connect epoch folder
        if self.enable_comb_filter == True:
            self.connect (self.first, self.folder_bandpass, self.folder_rr,
                self.folder_f2c,
                self.folder_comb, self.folder_c2f,
                self.folder_s2p, self.folder_iir,
                self.chart)

        else:
            self.connect (self.first, self.folder_bandpass, self.folder_rr,
                self.folder_s2p, self.folder_iir, self.chart)

        # Connect baseband recording file (initially /dev/null)
        self.connect(self.u, self.tofloat, self.tochar, self.recording)

        # Connect pulse recording file (initially /dev/null)
        self.connect(self.first, self.toshort, self.pulse_recording)

        #
        # Build the GUI elements
        #
        self._build_gui(vbox)

        # Make GUI agree with command-line
        self.myform['average'].set_value(int(options.avg))
        self.myform['foldavg'].set_value(int(options.favg))


        # Make spectral averager agree with command line
        if options.avg != 1.0:
            self.scope.set_avg_alpha(float(1.0/options.avg))
            self.scope.set_average(True)


        # set initial values

        if options.gain is None:
            # if no gain was specified, use the mid-point in dB
            g = self.subdev.gain_range()
            options.gain = float(g[0]+g[1])/2

        if options.freq is None:
            # if no freq was specified, use the mid-point
            r = self.subdev.freq_range()
            options.freq = float(r[0]+r[1])/2

        self.set_gain(options.gain)
        #self.set_volume(-10.0)

        if not(self.set_freq(options.freq)):
            self._set_status_msg("Failed to set initial frequency")

        self.myform['decim'].set_value(self.u.decim_rate())
        self.myform['fs@usb'].set_value(self.u.adc_freq() / self.u.decim_rate())
        self.myform['dbname'].set_value(self.subdev.name())
        self.myform['DM'].set_value(self.dm)
        self.myform['Doppler'].set_value(self.doppler)

        #
        # Start the timer that shows current LMST on the GUI
        #
        self.lmst_timer.Start(1000)
    def __init__(self, frame, panel, vbox, argv):
        stdgui.gui_flow_graph.__init__(self)

        self.frame = frame
        self.panel = panel
        
        parser = OptionParser(option_class=eng_option)
        parser.add_option("-R", "--rx-subdev-spec", type="subdev", default=(0, 0),
                          help="select USRP Rx side A or B (default=A)")
        parser.add_option("-d", "--decim", type="int", default=16,
                          help="set fgpa decimation rate to DECIM [default=%default]")
        parser.add_option("-f", "--freq", type="eng_float", default=None,
                          help="set frequency to FREQ", metavar="FREQ")
	parser.add_option("-a", "--avg", type="eng_float", default=1.0,
		help="set spectral averaging alpha")
	parser.add_option("-i", "--integ", type="eng_float", default=1.0,
		help="set integration time")
        parser.add_option("-g", "--gain", type="eng_float", default=None,
                          help="set gain in dB (default is midpoint)")
        parser.add_option("-l", "--reflevel", type="eng_float", default=30.0,
                          help="Set Total power reference level")
        parser.add_option("-y", "--division", type="eng_float", default=0.5,
                          help="Set Total power Y division size")
        parser.add_option("-e", "--longitude", type="eng_float", default=-76.02,                          help="Set Observer Longitude")
        parser.add_option("-c", "--latitude", type="eng_float", default=44.85,                          help="Set Observer Latitude")
        parser.add_option("-o", "--observing", type="eng_float", default=0.0,
                        help="Set observing frequency")
        parser.add_option("-x", "--ylabel", default="dB", help="Y axis label") 
        parser.add_option("-z", "--divbase", type="eng_float", default=0.025, help="Y Division increment base") 
        parser.add_option("-v", "--stripsize", type="eng_float", default=2400, help="Size of stripchart, in 2Hz samples") 
        parser.add_option("-F", "--fft_size", type="eng_float", default=1024, help="Size of FFT")

        parser.add_option("-N", "--decln", type="eng_float", default=999.99, help="Observing declination")
        parser.add_option("-X", "--prefix", default="./")
        parser.add_option("-M", "--fft_rate", type="eng_float", default=8.0, help="FFT Rate")
        parser.add_option("-A", "--calib_coeff", type="eng_float", default=1.0, help="Calibration coefficient")
        parser.add_option("-B", "--calib_offset", type="eng_float", default=0.0, help="Calibration coefficient")
        parser.add_option("-W", "--waterfall", action="store_true", default=False, help="Use Waterfall FFT display")
        parser.add_option("-S", "--setimode", action="store_true", default=False, help="Enable SETI processing of spectral data")
        parser.add_option("-K", "--setik", type="eng_float", default=1.5, help="K value for SETI analysis")
        parser.add_option("-T", "--setibandwidth", type="eng_float", default=12500, help="Instantaneous SETI observing bandwidth--must be divisor of 250Khz")
        parser.add_option("-n", "--notches", action="store_true", default=False,
            help="Notches appear after all other arguments")
        parser.add_option("-Q", "--seti_range", type="eng_float", default=1.0e6, help="Total scan width, in Hz for SETI scans")
        (options, args) = parser.parse_args()

        self.notches = Numeric.zeros(64,Numeric.Float64)
        if len(args) != 0 and options.notches == False:
            parser.print_help()
            sys.exit(1)

        if len(args) == 0 and options.notches != False:
            parser.print_help()
            sys.exit()

        self.use_notches = options.notches

        # Get notch locations
        j = 0
        for i in args:
            self.notches[j] = float(i)
            j = j+1

        self.notch_count = j

        self.show_debug_info = True

        # Pick up waterfall option
        self.waterfall = options.waterfall

        # SETI mode stuff
        self.setimode = options.setimode
        self.seticounter = 0
        self.setik = options.setik
        self.seti_fft_bandwidth = int(options.setibandwidth)

        # Calculate binwidth
        binwidth = self.seti_fft_bandwidth / options.fft_size

        # Use binwidth, and knowledge of likely chirp rates to set reasonable
        #  values for SETI analysis code.   We assume that SETI signals will
        #  chirp at somewhere between 0.10Hz/sec and 0.25Hz/sec.
        #
        # upper_limit is the "worst case"--that is, the case for which we have
        #  to wait the longest to actually see any drift, due to the quantizing
        #  on FFT bins.
        upper_limit = binwidth / 0.10
        self.setitimer = int(upper_limit * 2.00)
        self.scanning = True

        # Calculate the CHIRP values based on Hz/sec
        self.CHIRP_LOWER = 0.10 * self.setitimer
        self.CHIRP_UPPER = 0.25 * self.setitimer

        # Reset hit counters to 0
        self.hitcounter = 0
        self.s1hitcounter = 0
        self.s2hitcounter = 0
        self.avgdelta = 0
        # We scan through 2Mhz of bandwidth around the chosen center freq
        self.seti_freq_range = options.seti_range
        # Calculate lower edge
        self.setifreq_lower = options.freq - (self.seti_freq_range/2)
        self.setifreq_current = options.freq
        # Calculate upper edge
        self.setifreq_upper = options.freq + (self.seti_freq_range/2)

        # Maximum "hits" in a line
        self.nhits = 20

        # Number of lines for analysis
        self.nhitlines = 4

        # We change center frequencies based on nhitlines and setitimer
        self.setifreq_timer = self.setitimer * (self.nhitlines * 5)

        # Create actual timer
        self.seti_then = time.time()

        # The hits recording array
        self.hits_array = Numeric.zeros((self.nhits,self.nhitlines), Numeric.Float64)
        self.hit_intensities = Numeric.zeros((self.nhits,self.nhitlines), Numeric.Float64)
        # Calibration coefficient and offset
        self.calib_coeff = options.calib_coeff
        self.calib_offset = options.calib_offset
        if self.calib_offset < -750:
            self.calib_offset = -750
        if self.calib_offset > 750:
            self.calib_offset = 750

        if self.calib_coeff < 1:
            self.calib_coeff = 1
        if self.calib_coeff > 100:
            self.calib_coeff = 100

        self.integ = options.integ
        self.avg_alpha = options.avg
        self.gain = options.gain
        self.decln = options.decln

        # Set initial values for datalogging timed-output
        self.continuum_then = time.time()
        self.spectral_then = time.time()
      
        # build the graph

        #
        # If SETI mode, we always run at maximum USRP decimation
        #
        if (self.setimode):
            options.decim = 256

        self.u = usrp.source_c(decim_rate=options.decim)
        self.u.set_mux(usrp.determine_rx_mux_value(self.u, options.rx_subdev_spec))
        # Set initial declination
        self.decln = options.decln

        # determine the daughterboard subdevice we're using
        self.subdev = usrp.selected_subdev(self.u, options.rx_subdev_spec)
        self.cardtype = self.subdev.dbid()

        input_rate = self.u.adc_freq() / self.u.decim_rate()

        #
        # Set prefix for data files
        #
        self.prefix = options.prefix

        #
        # The lower this number, the fewer sample frames are dropped
        #  in computing the FFT.  A sampled approach is taken to
        #  computing the FFT of the incoming data, which reduces
        #  sensitivity.  Increasing sensitivity inreases CPU loading.
        #
        self.fft_rate = options.fft_rate

        self.fft_size = int(options.fft_size)

        # This buffer is used to remember the most-recent FFT display
        #   values.  Used later by self.write_spectral_data() to write
        #   spectral data to datalogging files, and by the SETI analysis
        #   function.
        #
        self.fft_outbuf = Numeric.zeros(self.fft_size, Numeric.Float64)

        #
        # If SETI mode, only look at seti_fft_bandwidth
        #   at a time.
        #
        if (self.setimode):
            self.fft_input_rate = self.seti_fft_bandwidth

            #
            # Build a decimating bandpass filter
            #
            self.fft_input_taps = gr.firdes.complex_band_pass (1.0,
               input_rate,
               -(int(self.fft_input_rate/2)), int(self.fft_input_rate/2), 200,
               gr.firdes.WIN_HAMMING, 0)

            #
            # Compute required decimation factor
            #
            decimation = int(input_rate/self.fft_input_rate)
            self.fft_bandpass = gr.fir_filter_ccc (decimation, 
                self.fft_input_taps)
        else:
            self.fft_input_rate = input_rate

        # Set up FFT display
        if self.waterfall == False:
           self.scope = ra_fftsink.ra_fft_sink_c (self, panel, 
               fft_size=int(self.fft_size), sample_rate=self.fft_input_rate,
               fft_rate=int(self.fft_rate), title="Spectral",  
               ofunc=self.fft_outfunc, xydfunc=self.xydfunc)
        else:
            self.scope = ra_waterfallsink.waterfall_sink_c (self, panel,
                fft_size=int(self.fft_size), sample_rate=self.fft_input_rate,
                fft_rate=int(self.fft_rate), title="Spectral", ofunc=self.fft_outfunc, size=(1100, 600), xydfunc=self.xydfunc, ref_level=0, span=10)

        # Set up ephemeris data
        self.locality = ephem.Observer()
        self.locality.long = str(options.longitude)
        self.locality.lat = str(options.latitude)
        # We make notes about Sunset/Sunrise in Continuum log files
        self.sun = ephem.Sun()
        self.sunstate = "??"

        # Set up stripchart display
        self.stripsize = int(options.stripsize)
        if self.setimode == False:
            self.chart = ra_stripchartsink.stripchart_sink_f (self, panel,
                stripsize=self.stripsize,
                title="Continuum",
                xlabel="LMST Offset (Seconds)",
                scaling=1.0, ylabel=options.ylabel,
                divbase=options.divbase)

        # Set center frequency
        self.centerfreq = options.freq

        # Set observing frequency (might be different from actual programmed
        #    RF frequency)
        if options.observing == 0.0:
            self.observing = options.freq
        else:
            self.observing = options.observing

        self.bw = input_rate

        # We setup the first two integrators to produce a fixed integration
        # Down to 1Hz, with output at 1 samples/sec
        N = input_rate/5000

        # Second stage runs on decimated output of first
        M = (input_rate/N)

        # Create taps for first integrator
        t = range(0,N-1)
        tapsN = []
        for i in t:
             tapsN.append(1.0/N)

        # Create taps for second integrator
        t = range(0,M-1)
        tapsM = []
        for i in t:
            tapsM.append(1.0/M)

        #
        # The 3rd integrator is variable, and user selectable at runtime
        # This integrator doesn't decimate, but is used to set the
        #  final integration time based on the constant 1Hz input samples
        # The strip chart is fed at a constant 1Hz rate as a result
        #

        #
        # Call constructors for receive chains
        #

        if self.setimode == False:
            # The three integrators--two FIR filters, and an IIR final filter
            self.integrator1 = gr.fir_filter_fff (N, tapsN)
            self.integrator2 = gr.fir_filter_fff (M, tapsM)
            self.integrator3 = gr.single_pole_iir_filter_ff(1.0)
    
            # The detector
            self.detector = gr.complex_to_mag_squared()

    
            # Signal probe
            self.probe = gr.probe_signal_f();
    
            #
            # Continuum calibration stuff
            #
            x = self.calib_coeff/100.0
            self.cal_mult = gr.multiply_const_ff(self.calib_coeff/100.0);
            self.cal_offs = gr.add_const_ff(self.calib_offset*(x*8000));

            if self.use_notches == True:
                self.compute_notch_taps(self.notches)
                self.notch_filt = gr.fft_filter_ccc(1, self.notch_taps)

        #
        # Start connecting configured modules in the receive chain
        #

        # The scope--handle SETI mode
        if (self.setimode == False):
            if (self.use_notches == True):
                self.connect(self.u, self.notch_filt, self.scope)
            else:
                self.connect(self.u, self.scope)
        else:
            if (self.use_notches == True):
                self.connect(self.u, self.notch_filt, 
                    self.fft_bandpass, self.scope)
            else:
                self.connect(self.u, self.fft_bandpass, self.scope)

        if self.setimode == False:
            if (self.use_notches == True):
                self.connect(self.notch_filt, self.detector, 
                    self.integrator1, self.integrator2,
                    self.integrator3, self.cal_mult, self.cal_offs, self.chart)
            else:
                self.connect(self.u, self.detector, 
                    self.integrator1, self.integrator2,
                    self.integrator3, self.cal_mult, self.cal_offs, self.chart)
    
            #  current instantaneous integrated detector value
            self.connect(self.cal_offs, self.probe)

        self._build_gui(vbox)

        # Make GUI agree with command-line
        self.integ = options.integ
        if self.setimode == False:
            self.myform['integration'].set_value(int(options.integ))
            self.myform['offset'].set_value(self.calib_offset)
            self.myform['dcgain'].set_value(self.calib_coeff)
        self.myform['average'].set_value(int(options.avg))


        if self.setimode == False:
            # Make integrator agree with command line
            self.set_integration(int(options.integ))

        self.avg_alpha = options.avg

        # Make spectral averager agree with command line
        if options.avg != 1.0:
            self.scope.set_avg_alpha(float(1.0/options.avg))
            self.scope.set_average(True)

        if self.setimode == False:
            # Set division size
            self.chart.set_y_per_div(options.division)
            # Set reference(MAX) level
            self.chart.set_ref_level(options.reflevel)

        # set initial values

        if options.gain is None:
            # if no gain was specified, use the mid-point in dB
            g = self.subdev.gain_range()
            options.gain = float(g[0]+g[1])/2

        if options.freq is None:
            # if no freq was specified, use the mid-point
            r = self.subdev.freq_range()
            options.freq = float(r[0]+r[1])/2

        # Set the initial gain control
        self.set_gain(options.gain)

        if not(self.set_freq(options.freq)):
            self._set_status_msg("Failed to set initial frequency")

        # Set declination
        self.set_decln (self.decln)


        # RF hardware information
        self.myform['decim'].set_value(self.u.decim_rate())
        self.myform['fs@usb'].set_value(self.u.adc_freq() / self.u.decim_rate())
        self.myform['dbname'].set_value(self.subdev.name())

        # Set analog baseband filtering, if DBS_RX
        if self.cardtype in (usrp_dbid.DBS_RX, usrp_dbid.DBS_RX_REV_2_1):
            lbw = (self.u.adc_freq() / self.u.decim_rate()) / 2
            if lbw < 1.0e6:
                lbw = 1.0e6
            self.subdev.set_bw(lbw)

        # Start the timer for the LMST display and datalogging
        self.lmst_timer.Start(1000)