Beispiel #1
0
    def _playback_step(self):
        if not self._playback_file:
            self._playback_started = False
            return

        QtCore.QTimer.singleShot(PLAYBACK_STEP_MSEC, self._playback_step)

        while True:
            pkt = self._playback_vrt()

            if pkt.is_context_packet():
                if 'speca' in pkt.fields:
                    self._playback_sweep_data = None
                    state_json = pkt.fields['speca']
                    self._apply_complete_settings(state_json, playback=True)
                else:
                    self._playback_context.update(pkt.fields)
                continue

            if self._state.sweeping():
                if not self._playback_sweep_step(pkt):
                    continue
                return
            break

        usable_bins = compute_usable_bins(
            self._dut.properties,
            self._state.rfe_mode(),
            len(pkt.data),
            self._state.decimation,
            self._state.fshift)

        usable_bins, fstart, fstop = adjust_usable_fstart_fstop(
            self._dut.properties,
            self._state.rfe_mode(),
            len(pkt.data),
            self._state.decimation,
            self._state.center,
            pkt.spec_inv,
            usable_bins)

        pow_data = compute_fft(
            self._dut,
            pkt,
            self._playback_context,
            **self._dsp_options)

        if not self._options.get('show_attenuated_edges'):
            pow_data, usable_bins, fstart, fstop = (
                trim_to_usable_fstart_fstop(
                    pow_data, usable_bins, fstart, fstop))

        self.capture_receive.emit(
            self._state,
            fstart,
            fstop,
            pkt,
            pow_data,
            usable_bins,
            None)
Beispiel #2
0
    def _playback_sweep_step(self, pkt):
        """
        process one data packet from a recorded sweep and
        plot collected data after receiving complete sweep.

        returns True if data was plotted on this step.
        """
        if self._playback_sweep_data is None:
            self._playback_sweep_start()
            last_center = None
        else:
            last_center = self._playback_sweep_last_center

        sweep_start = float(self._state.center - self._state.span / 2)
        sweep_stop = float(self._state.center + self._state.span / 2)
        step_center = self._playback_context['rffreq']
        updated_plot = False
        if last_center is not None and last_center >= step_center:
            # starting a new sweep, plot the data we have
            self.capture_receive.emit(self._state, sweep_start, sweep_stop,
                                      None, self._playback_sweep_data, None,
                                      None)
            updated_plot = True
            self._playback_sweep_start()
        self._playback_sweep_last_center = step_center

        usable_bins = compute_usable_bins(self._dut.properties,
                                          self._state.rfe_mode(),
                                          len(pkt.data),
                                          self._state.decimation,
                                          self._state.fshift)

        usable_bins, fstart, fstop = adjust_usable_fstart_fstop(
            self._dut.properties, self._state.rfe_mode(), len(pkt.data),
            self._state.decimation, step_center, pkt.spec_inv, usable_bins)

        pow_data = compute_fft(self._dut, pkt, self._playback_context,
                               **self._dsp_options)

        pow_data, usable_bins, fstart, fstop = (trim_to_usable_fstart_fstop(
            pow_data, usable_bins, fstart, fstop))

        clip_left = max(sweep_start, fstart)
        clip_right = min(sweep_stop, fstop)
        sweep_points = len(self._playback_sweep_data)
        point_left = int((clip_left - sweep_start) * sweep_points /
                         (sweep_stop - sweep_start))
        point_right = int((clip_right - sweep_start) * sweep_points /
                          (sweep_stop - sweep_start))
        xvalues = np.linspace(clip_left, clip_right, point_right - point_left)

        if point_left >= point_right:
            logger.info('received sweep step outside sweep: %r, %r' %
                        ((fstart, fstop), (sweep_start, sweep_stop)))
        else:
            self._playback_sweep_data[point_left:point_right] = np.interp(
                xvalues, np.linspace(fstart, fstop, len(pow_data)), pow_data)

        return updated_plot
Beispiel #3
0
    def capture_time_domain(self, rfe_mode, freq, rbw, device_settings=None,
            min_points=128, force_change = False):
        """
        Initiate a capture of raw time domain IQ or I-only data

        :param rfe_mode: radio front end mode, e.g. 'ZIF', 'SH', ...
        :param freq: center frequency
        :param rbw: requested RBW in Hz (output RBW may be smaller than
                    requested)
        :type rbw: float
        :param device_settings: attenuator, decimation frequency shift
                                and other device settings
        :type dict:
        :param min_points: smallest number of points per capture from real_device
        :type min_points: int
        """
        prop = self.real_device.properties

        self.configure_device(dict(
            freq=freq,
            rfe_mode=rfe_mode,
            **(device_settings if device_settings else {})), force_change) 

        full_bw = prop.FULL_BW[rfe_mode]
        self.packets_per_block = 1
        self.real_device.abort()
        self.real_device.flush()
        self.real_device.request_read_perm()
        self._vrt_context = {}
        self._data_packets = []

        self.points = round(max(min_points, full_bw / rbw))

        self.points = 2 ** math.ceil(math.log(self.points, 2))
        if prop.DEFAULT_SAMPLE_TYPE[rfe_mode] == I_ONLY:
            self.points  *= 2
            
        if self.points > prop.MAX_SPP:
            self.packets_per_block = self.points / prop.MAX_SPP
            self.points = prop.MAX_SPP

        fshift = self._device_set.get('fshift', 0)
        decimation = self._device_set.get('decimation', 1)
        self.usable_bins = compute_usable_bins(prop, rfe_mode, (self.points * self.packets_per_block),
            decimation, fshift)
        if self.async_callback:
            self.real_device.set_async_callback(self.read_data)
            self.real_device.capture(self.points, self.packets_per_block)

            return

        self.real_device.capture(self.points, self._data_packets)

        result = None
        while result is None:
            result = self.read_data(self.real_device.read())
        return result
Beispiel #4
0
    def capture_time_domain(self, rfe_mode, freq, rbw, device_settings=None,
            min_points=256, force_change = False):
        """
        Initiate a capture of raw time domain IQ or I-only data

        :param str rfe_mode: radio front end mode, e.g. 'ZIF', 'SH', ...
        :param int freq: center frequency in Hz to set
        :param float rbw: the resolution bandwidth (RBW) in Hz of the data to be captured
                    (output RBW may be smaller than requested)
        :param device_settings: rfe_mode, freq, decimation, fshift and other device settings
        :type device_settings: dict or None
        :param int min_points: smallest number of data points per capture from the device
        :param bool force_change: force the configuration to apply device_settings changes or not
        :returns: (fstart, fstop, data) where fstart & fstop are frequencies in Hz & data is a list
        """

        prop = self.real_device.properties
        self.real_device.abort()
        self.real_device.flush()
        self.device_settings = device_settings
        self.real_device.request_read_perm()
        self.configure_device(dict(
            freq=freq,
            rfe_mode=rfe_mode,
            **(device_settings if device_settings else {})), force_change)

        full_bw = prop.FULL_BW[rfe_mode]

        self._vrt_context = {}
        self._data_packets = []

        self.points = round(full_bw / rbw)

        if prop.DEFAULT_SAMPLE_TYPE[rfe_mode] == I_ONLY:
            self.points  *= 2

        self.points = round(max(min_points, self.points))

        self.points, self.packets_per_block = compute_spp_ppb(self.points, prop)

        fshift = self._device_set.get('fshift', 0)
        decimation = self._device_set.get('decimation', 1)
        self.usable_bins = compute_usable_bins(prop, rfe_mode, (self.points * self.packets_per_block),
            decimation, fshift)
        if self.async_callback:
            self.real_device.set_async_callback(self.read_data)
            self.real_device.capture(self.points, self.packets_per_block)

            return

        self.real_device.capture(self.points, self._data_packets)

        result = None
        while result is None:
            result = self.read_data(self.real_device.read())
        return result
Beispiel #5
0
    def capture_time_domain(self, rfe_mode, freq, rbw, device_settings=None,
            min_points=128):
        """
        Initiate a capture of raw time domain IQ or I-only data

        :param rfe_mode: radio front end mode, e.g. 'ZIF', 'SH', ...
        :param freq: center frequency
        :param rbw: requested RBW in Hz (output RBW may be smaller than
                    requested)
        :type rbw: float
        :param device_settings: attenuator, decimation frequency shift
                                and other device settings
        :type dict:
        :param min_points: smallest number of points per capture from real_device
        :type min_points: int
        """
        prop = self.real_device.properties

        self.configure_device(dict(
            freq=freq,
            rfe_mode=rfe_mode,
            **(device_settings if device_settings else {}))) 

        if self._configure_device_flag:
            self.real_device.apply_device_settings(self._device_set)
            self._configure_device_flag = False

        full_bw = prop.FULL_BW[rfe_mode]

        self.real_device.abort()
        self.real_device.flush()
        self.real_device.request_read_perm()
        self._vrt_context = {}

        points = round(max(min_points, full_bw / rbw))
        points = 2 ** math.ceil(math.log(points, 2))

        fshift = self._device_set.get('fshift', 0)
        decimation = self._device_set.get('decimation', 1)
        self.usable_bins = compute_usable_bins(prop, rfe_mode, points,
            decimation, fshift)

        if self.async_callback:
            self.real_device.set_async_callback(self.read_data)
            self.real_device.capture(points, 1)
            return

        self.real_device.capture(points, 1)
        result = None
        while result is None:
            result = self.read_data(self.real_device.read())
        return result
Beispiel #6
0
    def _playback_step(self, single=False):

        if not (self._plot_options['cont_cap_mode'] or self._single_capture):
            return
        if not self._playback_file:
            self._playback_started = False
            return

        QtCore.QTimer.singleShot(PLAYBACK_STEP_MSEC, self._playback_step)
        while True:

            pkt = self._playback_vrt()

            if pkt.is_context_packet():
                if 'speca' in pkt.fields:
                    self._playback_sweep_data = None
                    state_json = pkt.fields['speca']
                    self._apply_complete_settings(state_json, playback=True)
                else:
                    self._playback_context.update(pkt.fields)
                continue

            if self._state.sweeping():
                if not self._playback_sweep_step(pkt):
                    continue
                self._single_capture = False
                return
            break

        usable_bins = compute_usable_bins(self._dut.properties,
                                          self._state.rfe_mode(),
                                          len(pkt.data),
                                          self._state.decimation,
                                          self._state.fshift)

        usable_bins, fstart, fstop = adjust_usable_fstart_fstop(
            self._dut.properties, self._state.rfe_mode(), len(pkt.data),
            self._state.decimation, self._state.center, pkt.spec_inv,
            usable_bins)

        pow_data = compute_fft(self._dut, pkt, self._playback_context,
                               **self._dsp_options)

        if not self._options.get('show_attenuated_edges'):
            pow_data, usable_bins, fstart, fstop = (
                trim_to_usable_fstart_fstop(pow_data, usable_bins, fstart,
                                            fstop))
        if self._export_csv:
            self._export_csv_file(self._state.rfe_mode(), fstart, fstop,
                                  pow_data)
        self.capture_receive.emit(self._state, fstart, fstop, pkt, pow_data,
                                  usable_bins, None)
Beispiel #7
0
    def _playback_sweep_step(self, pkt):
        """
        process one data packet from a recorded sweep and
        plot collected data after receiving complete sweep.

        returns True if data was plotted on this step.
        """
        if self._playback_sweep_data is None:
            self._playback_sweep_start()
            last_center = None
        else:
            last_center = self._playback_sweep_last_center

        sweep_start = float(self._state.center - self._state.span / 2)
        sweep_stop = float(self._state.center + self._state.span / 2)
        step_center = self._playback_context['rffreq']
        updated_plot = False
        if last_center is not None and last_center >= step_center:
            # starting a new sweep, plot the data we have
            self.capture_receive.emit(
                self._state,
                sweep_start,
                sweep_stop,
                None,
                self._playback_sweep_data,
                None,
                None)
            updated_plot = True
            self._playback_sweep_start()
        self._playback_sweep_last_center = step_center

        usable_bins = compute_usable_bins(
            self._dut.properties,
            self._state.rfe_mode(),
            len(pkt.data),
            self._state.decimation,
            self._state.fshift)

        usable_bins, fstart, fstop = adjust_usable_fstart_fstop(
            self._dut.properties,
            self._state.rfe_mode(),
            len(pkt.data),
            self._state.decimation,
            step_center,
            pkt.spec_inv,
            usable_bins)

        pow_data = compute_fft(
            self._dut,
            pkt,
            self._playback_context,
            **self._dsp_options)

        pow_data, usable_bins, fstart, fstop = (
            trim_to_usable_fstart_fstop(
                pow_data, usable_bins, fstart, fstop))

        clip_left = max(sweep_start, fstart)
        clip_right = min(sweep_stop, fstop)
        sweep_points = len(self._playback_sweep_data)
        point_left = int((clip_left - sweep_start) * sweep_points / (
            sweep_stop - sweep_start))
        point_right = int((clip_right - sweep_start) * sweep_points / (
            sweep_stop - sweep_start))
        xvalues = np.linspace(clip_left, clip_right, point_right - point_left)

        if point_left >= point_right:
            logger.info('received sweep step outside sweep: %r, %r' %
                ((fstart, fstop), (sweep_start, sweep_stop)))
        else:
            self._playback_sweep_data[point_left:point_right] = np.interp(
                xvalues, np.linspace(fstart, fstop, len(pow_data)), pow_data)

        return updated_plot
Beispiel #8
0
    def capture_time_domain(self,
                            rfe_mode,
                            freq,
                            rbw,
                            device_settings=None,
                            min_points=256,
                            force_change=False):
        """
        Initiate a capture of raw time domain IQ or I-only data

        :param rfe_mode: radio front end mode, e.g. 'ZIF', 'SH', ...
        :param freq: center frequency
        :param rbw: requested RBW in Hz (output RBW may be smaller than
                    requested)
        :type rbw: float
        :param device_settings: attenuator, decimation frequency shift
                                and other device settings
        :type dict:
        :param min_points: smallest number of points per capture from real_device
        :type min_points: int
        """

        prop = self.real_device.properties
        self.real_device.abort()
        self.real_device.flush()
        self.device_settings = device_settings
        self.real_device.request_read_perm()
        self.configure_device(
            dict(freq=freq,
                 rfe_mode=rfe_mode,
                 **(device_settings if device_settings else {})), force_change)

        full_bw = prop.FULL_BW[rfe_mode]

        self._vrt_context = {}
        self._data_packets = []

        self.points = round(full_bw / rbw)

        if prop.DEFAULT_SAMPLE_TYPE[rfe_mode] == I_ONLY:
            self.points *= 2

        self.points = round(max(min_points, self.points))

        self.points, self.packets_per_block = compute_spp_ppb(
            self.points, prop)

        fshift = self._device_set.get('fshift', 0)
        decimation = self._device_set.get('decimation', 1)
        self.usable_bins = compute_usable_bins(
            prop, rfe_mode, (self.points * self.packets_per_block), decimation,
            fshift)
        if self.async_callback:
            self.real_device.set_async_callback(self.read_data)
            self.real_device.capture(self.points, self.packets_per_block)

            return

        self.real_device.capture(self.points, self._data_packets)

        result = None
        while result is None:
            result = self.read_data(self.real_device.read())
        return result
Beispiel #9
0
    def capture_time_domain(self,
                            rfe_mode,
                            freq,
                            rbw,
                            device_settings=None,
                            min_points=256,
                            force_change=False):
        """
        Initiate a capture of raw time domain IQ or I-only data

        :param str rfe_mode: radio front end mode, e.g. 'ZIF', 'SH', ...
        :param int freq: center frequency in Hz to set
        :param float rbw: the resolution bandwidth (RBW) in Hz of the data to be captured
                    (output RBW may be smaller than requested)
        :param device_settings: rfe_mode, freq, decimation, fshift and other device settings
        :type device_settings: dict or None
        :param int min_points: smallest number of data points per capture from the device
        :param bool force_change: force the configuration to apply device_settings changes or not
        :returns: (fstart, fstop, data) where fstart & fstop are frequencies in Hz & data is a list
        """

        prop = self.real_device.properties
        self.real_device.abort()
        self.real_device.flush()
        self.device_settings = device_settings
        self.real_device.request_read_perm()
        self.configure_device(
            dict(freq=freq,
                 rfe_mode=rfe_mode,
                 **(device_settings if device_settings else {})), force_change)

        full_bw = prop.FULL_BW[rfe_mode]

        self._vrt_context = {}
        self._data_packets = []

        self.points = round(full_bw / rbw)

        if prop.DEFAULT_SAMPLE_TYPE[rfe_mode] == I_ONLY:
            self.points *= 2

        self.points = round(max(min_points, self.points))

        self.points, self.packets_per_block = compute_spp_ppb(
            self.points, prop)

        fshift = self._device_set.get('fshift', 0)
        decimation = self._device_set.get('decimation', 1)
        self.usable_bins = compute_usable_bins(
            prop, rfe_mode, (self.points * self.packets_per_block), decimation,
            fshift)
        if self.async_callback:
            self.real_device.set_async_callback(self.read_data)
            self.real_device.capture(self.points, self.packets_per_block)

            return

        self.real_device.capture(self.points, self._data_packets)

        result = None
        while result is None:
            result = self.read_data(self.real_device.read())
        return result
Beispiel #10
0
    def _vrt_receive(self, packet):

        # context packet just update our context dictionary
        if packet.is_context_packet():
            # look for any geolocation info
            geo = { }
            for field in [ 'latitude', 'longitude', 'altitude', 'speedoverground', 'heading', 'track', 'magneticvariation' ]:
                if field in packet.fields:
                    geo[field] = packet.fields[field]
            if geo and self._geo_callback_func:
                # execute callback
                func = self._geo_callback_func
                func(self._geo_callback_data, geo)

            self._vrt_context.update(packet.fields)
            self.log(packet)
            return

        # check to see if we recieved our sweep ID
        if not ('sweepid' in self._vrt_context):
            return

        # make sure we are receiving packets for the right sweep
        if not (self._vrt_context['sweepid'] == self._next_sweep_id):
            raise SweepDeviceError("data packets received before start of sweep received!  cur = %d, next = %d" % (self._vrt_context['sweepid'], self._next_sweep_id))

        # increment the packet count
        self.packet_count += 1
        self.log("#%d of %d - %s" % (self.packet_count, self._sweep_settings.step_count, packet))

        # retrieve the frequency and usable BW of the packet
        packet_freq = self._vrt_context['rffreq']
        usable_bw = self.dev_properties.USABLE_BW[self._sweep_settings.rfe_mode]

        # compute the fft
        pow_data = compute_fft(self.real_device, packet, self._vrt_context)

        # calc rbw for this packet
        rbw = float(self.dev_properties.FULL_BW[self._sweep_settings.rfe_mode]) / len(pow_data)
        self.log("rbw = %f, %f" % (rbw, self._sweep_settings.rbw))
        if self._flattening_enabled:
            # Check if we are above 50 MHz and in SH mode
            if packet_freq >= 50e6 and self._sweep_settings.rfe_mode == "SH":
                number_of_points = len(pow_data)
                # check if we have correction vectors (Noise)
                if self.nf_corr_obj is not None:
                    # if so grab them
                    nf_cal = \
                            self.nf_corr_obj.get_correction_vector(packet_freq,
                                                                   number_of_points)
                else:
                    # if no set it to 0
                    nf_cal = np.zeros(number_of_points)

                # check if we have corrrection vectors (Spectrum)
                if self.sp_corr_obj is not None:
                    # if so grab them
                    sp_cal = \
                            self.sp_corr_obj.get_correction_vector(packet_freq,
                                                                   number_of_points)
                else:
                    # if not set it to 0
                    sp_cal = np.zeros(number_of_points)

                # if the data is spectraly inverted, invert the vectors
                if packet.spec_inv:
                    nf_cal = np.flipud(nf_cal)
                    sp_cal = np.flipud(sp_cal)

                # calculate the correction threshold
                correction_thresh = (-135.0 + ((10.0 * packet_freq / 1e6)
                                               / 27000.0) + 10.0
                                     * np.log10(rbw)
                                     + self._sweep_settings.attenuation)
                # creat the spectrum. per bin, if the ampltitude is above
                # correction threshold do pow_data - sp_cal else do pow_data -
                # nf_cal
                pow_data = np.where(pow_data < correction_thresh,
                                    pow_data - nf_cal, pow_data - sp_cal)

        # check if DD mode was used in this sweep
        if self.packet_count == 1 and self._sweep_settings.dd_mode:
            # copy the data into the result array
            self._copy_data(0, self.dev_properties.FULL_BW['DD'], pow_data, self._sweep_settings.bandstart, self._sweep_settings.bandstop, self.spectral_data);

            if self._sweep_settings.beyond_dd:
                return
            else:
                return self._emit_data()


        # determine the usable bins in this config
        self.log("===> compute_usable_bins()", self._sweep_settings.rfe_mode, self._sweep_settings.spp, 1, 0)
        usable_bins = compute_usable_bins(self.dev_properties,
                                          self._sweep_settings.rfe_mode,
                                          self._sweep_settings.spp,
                                          1,
                                          0)
        self.log("<--- usable_bins", usable_bins)

        # adjust the usable range based on spectral inversion
        self.log("===> adjust_usable_fstart_fstop()", "self.dev_properties", self._sweep_settings.rfe_mode, len(pow_data) * 2, 1, packet_freq, packet.spec_inv, usable_bins)
        usable_bins, packet_start, packet_stop = adjust_usable_fstart_fstop(self.dev_properties,
                                                              self._sweep_settings.rfe_mode,
                                                              len(pow_data) * 2,
                                                              1,
                                                              packet_freq,
                                                              packet.spec_inv,
                                                              usable_bins)
        self.log("<--- adjust_usable_fstart_fstop", packet_start, packet_stop, usable_bins)
        #
        # WARNING: the start and stop returned from this function are HIGHLY sketchy
        #

        # calculate packet frequency range
        #packet_start = packet_freq - (self.dev_properties.FULL_BW[self._sweep_settings.rfe_mode] / 2)
        #packet_stop = packet_freq + (self.dev_properties.FULL_BW[self._sweep_settings.rfe_mode] / 2)
        #print "packet start/stop", packet_start, packet_stop

        #trim the FFT data, note decimation is 1, fshift is 0
        self.log("===> trim_to_usable_fstart_fstop()", "pow_data", usable_bins, packet_start, packet_stop)
        trimmed_spectrum, edge_data, usable_start, usable_stop = trim_to_usable_fstart_fstop(pow_data,
                                                                                 usable_bins,
                                                                                 packet_start,
                                                                                 packet_stop)
        self.log("<--- trim_to_usable_fstart_fstop", usable_start, usable_stop, "trimmed_spectrum", edge_data)

        # copy the data
        self._copy_data(usable_start, usable_stop, trimmed_spectrum, self._sweep_settings.bandstart, self._sweep_settings.bandstop, self.spectral_data);

        # if there's no more packets, emit result
        if self.packet_count == self._sweep_settings.step_count:
            return self._emit_data()

        # all done
        return
Beispiel #11
0
    def _vrt_receive(self, packet):

        # context packet just update our context dictionary
        if packet.is_context_packet():
            self._vrt_context.update(packet.fields)
            self.log(packet)
            return

        # check to see if we recieved our sweep ID
        if not ('sweepid' in self._vrt_context):
            return

        # make sure we are receiving packets for the right sweep
        if not (self._vrt_context['sweepid'] == self._next_sweep_id):
            raise SweepDeviceError(
                "data packets received before start of sweep received!  cur = %d, next = %d"
                % (self._vrt_context['sweepid'], self._next_sweep_id))

        # increment the packet count
        self.packet_count += 1
        self.log("#%d of %d - %s" %
                 (self.packet_count, self._sweep_settings.step_count, packet))

        # compute the fft
        pow_data = compute_fft(self.real_device, packet, self._vrt_context)

        # check if DD mode was used in this sweep
        if self.packet_count == 1 and self._sweep_settings.dd_mode:
            # copy the data into the result array
            self._copy_data(0, self.dev_properties.FULL_BW['DD'], pow_data,
                            self._sweep_settings.bandstart,
                            self._sweep_settings.bandstop, self.spectral_data)

            if self._sweep_settings.beyond_dd:
                return
            else:
                return self._emit_data()

        # retrieve the frequency and usable BW of the packet
        packet_freq = self._vrt_context['rffreq']
        usable_bw = self.dev_properties.USABLE_BW[
            self._sweep_settings.rfe_mode]

        # calc rbw for this packet
        rbw = float(self.dev_properties.FULL_BW[
            self._sweep_settings.rfe_mode]) / len(pow_data)
        self.log("rbw = %f, %f" % (rbw, self._sweep_settings.rbw))

        # determine the usable bins in this config
        self.log("===> compute_usable_bins()", self._sweep_settings.rfe_mode,
                 self._sweep_settings.spp, 1, 0)
        usable_bins = compute_usable_bins(self.dev_properties,
                                          self._sweep_settings.rfe_mode,
                                          self._sweep_settings.spp, 1, 0)
        self.log("<--- usable_bins", usable_bins)

        # adjust the usable range based on spectral inversion
        self.log("===> adjust_usable_fstart_fstop()", "self.dev_properties",
                 self._sweep_settings.rfe_mode,
                 len(pow_data) * 2, 1, packet_freq, packet.spec_inv,
                 usable_bins)
        usable_bins, packet_start, packet_stop = adjust_usable_fstart_fstop(
            self.dev_properties, self._sweep_settings.rfe_mode,
            len(pow_data) * 2, 1, packet_freq, packet.spec_inv, usable_bins)
        self.log("<--- adjust_usable_fstart_fstop", packet_start, packet_stop,
                 usable_bins)
        #
        # WARNING: the start and stop returned from this function are HIGHLY sketchy
        #

        # calculate packet frequency range
        #packet_start = packet_freq - (self.dev_properties.FULL_BW[self._sweep_settings.rfe_mode] / 2)
        #packet_stop = packet_freq + (self.dev_properties.FULL_BW[self._sweep_settings.rfe_mode] / 2)
        #print "packet start/stop", packet_start, packet_stop

        #trim the FFT data, note decimation is 1, fshift is 0
        self.log("===> trim_to_usable_fstart_fstop()", "pow_data", usable_bins,
                 packet_start, packet_stop)
        trimmed_spectrum, edge_data, usable_start, usable_stop = trim_to_usable_fstart_fstop(
            pow_data, usable_bins, packet_start, packet_stop)
        self.log("<--- trim_to_usable_fstart_fstop", usable_start, usable_stop,
                 "trimmed_spectrum", edge_data)

        # copy the data
        self._copy_data(usable_start, usable_stop, trimmed_spectrum,
                        self._sweep_settings.bandstart,
                        self._sweep_settings.bandstop, self.spectral_data)

        # if there's no more packets, emit result
        if self.packet_count == self._sweep_settings.step_count:
            return self._emit_data()

        # all done
        return