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)
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
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
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
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
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)
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
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
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
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
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