def __call__(self, schedule_entry_json, task_id, sensor_definition): """This is the entrypoint function called by the scheduler.""" self.test_required_components() start_time = utils.get_datetime_str_now() measurement_result = self.acquire_data() end_time = utils.get_datetime_str_now() sigmf_builder = SigMFBuilder() self.set_base_sigmf_global( sigmf_builder, schedule_entry_json, sensor_definition, measurement_result, task_id, is_complex=False, ) sigmf_builder.set_measurement( start_time, end_time, domain=Domain.FREQUENCY, measurement_type=MeasurementType.SINGLE_FREQUENCY, frequency=measurement_result["frequency"], ) self.add_sigmf_capture(sigmf_builder, measurement_result) self.add_base_sigmf_annotations(sigmf_builder, measurement_result) self.add_fft_annotations(sigmf_builder, measurement_result) measurement_action_completed.send( sender=self.__class__, task_id=task_id, data=measurement_result["data"], metadata=sigmf_builder.metadata, )
def status(request, version, format=None): """The status overview of the sensor.""" return Response( { "scheduler": scheduler.thread.status, "location": serialize_location(), "system_time": get_datetime_str_now(), "last_calibration_time": last_calibration_time(), } )
def __call__(self, schedule_entry_json, task_id, sensor_definition): """This is the entrypoint function called by the scheduler.""" self.test_required_components() for recording_id, measurement_params in enumerate( self.sorted_measurement_parameters, start=1): start_time = utils.get_datetime_str_now() measurement_result = super().acquire_data(measurement_params) end_time = utils.get_datetime_str_now() received_samples = len(measurement_result["data"]) sigmf_builder = SigMFBuilder() self.set_base_sigmf_global( sigmf_builder, schedule_entry_json, sensor_definition, measurement_result, task_id, recording_id, ) sigmf_builder.set_measurement( start_time, end_time, domain=Domain.TIME, measurement_type=MeasurementType.SINGLE_FREQUENCY, frequency=measurement_result["frequency"], ) self.add_sigmf_capture(sigmf_builder, measurement_result) self.add_base_sigmf_annotations(sigmf_builder, measurement_result) sigmf_builder.add_time_domain_detection( start_index=0, num_samples=received_samples, detector="sample_iq", units="volts", reference="preselector input", ) measurement_action_completed.send( sender=self.__class__, task_id=task_id, data=measurement_result["data"], metadata=sigmf_builder.metadata, )
def acquire_time_domain_samples(self, num_samples, num_samples_skip=0, retries=5): self.sigan_overload = False self._capture_time = None self._num_samples_skip = num_samples_skip # Try to acquire the samples max_retries = retries data = [] while True: if self.times_failed_recv < self.times_to_fail_recv: self.times_failed_recv += 1 data = np.ones(0, dtype=np.complex64) else: self._capture_time = get_datetime_str_now() if self.randomize_values: i = np.random.normal(0.5, 0.5, num_samples) q = np.random.normal(0.5, 0.5, num_samples) rand_iq = np.empty(num_samples, dtype=np.complex64) rand_iq.real = i rand_iq.imag = q data = rand_iq else: data = np.ones(num_samples, dtype=np.complex64) data_len = len(data) if not len(data) == num_samples: if retries > 0: msg = "USRP error: requested {} samples, but got {}." logger.warning( msg.format(num_samples + num_samples_skip, data_len)) logger.warning("Retrying {} more times.".format(retries)) retries = retries - 1 else: err = "Failed to acquire correct number of samples " err += "{} times in a row.".format(max_retries) raise RuntimeError(err) else: logger.debug( "Successfully acquired {} samples.".format(num_samples)) return { "data": data, "overload": self._overload, "frequency": self._frequency, "gain": self._gain, "sample_rate": self._sample_rate, "capture_time": self._capture_time, "calibration_annotation": self.create_calibration_annotation(), }
def last_calibration_time(self): return get_datetime_str_now()
def acquire_time_domain_samples(self, num_samples, num_samples_skip=0, retries=5): """Acquire num_samples_skip+num_samples samples and return the last num_samples :type num_samples: int :param num_samples: Number of samples to acquire :type num_samples_skip: int :param num_samples_skip: Skip samples to allow signal analyzer DC offset and IQ imbalance algorithms to take effect :type retries: int :param retries: The number of retries to attempt when failing to acquire samples :rtype: dictionary containing the following: data - (list) measurement data overload - (boolean) True if overload occurred, otherwise False frequency - (float) Measurement center frequency in hertz gain - (float) Measurement signal analyzer gain setting in dB sample_rate - (float) Measurement sample rate in samples per second capture_time - (string) Measurement capture time calibration_annotation - (dict) SigMF calibration annotation """ self._sigan_overload = False self._capture_time = None # Get the calibration data for the acquisition self.recompute_calibration_data() nsamps = int(num_samples) nskip = int(num_samples_skip) # Compute the linear gain db_gain = self.sensor_calibration_data["gain_sensor"] linear_gain = 10**(db_gain / 20.0) # Try to acquire the samples max_retries = retries while True: # No need to skip initial samples when simulating the radio if not settings.RUNNING_TESTS and not settings.MOCK_RADIO: nsamps += nskip self._capture_time = utils.get_datetime_str_now() samples = self.usrp.recv_num_samps( nsamps, # number of samples self.frequency, # center frequency in Hz self.sample_rate, # sample rate in samples per second [0], # channel list self.gain, # gain in dB ) # usrp.recv_num_samps returns a numpy array of shape # (n_channels, n_samples) and dtype complex64 assert samples.dtype == np.complex64 assert len(samples.shape) == 2 and samples.shape[0] == 1 data = samples[0] # isolate data for channel 0 data_len = len(data) if not settings.RUNNING_TESTS and not settings.MOCK_RADIO: data = data[nskip:] if not len(data) == num_samples: if retries > 0: msg = "USRP error: requested {} samples, but got {}." logger.warning( msg.format(num_samples + num_samples_skip, data_len)) logger.warning("Retrying {} more times.".format(retries)) retries = retries - 1 else: err = "Failed to acquire correct number of samples " err += "{} times in a row.".format(max_retries) raise RuntimeError(err) else: logger.debug( "Successfully acquired {} samples.".format(num_samples)) # Check IQ values versus ADC max for sigan compression self._sigan_overload = False i_samples = np.abs(np.real(data)) q_samples = np.abs(np.imag(data)) i_over_threshold = np.sum( i_samples > self.ADC_FULL_RANGE_THRESHOLD) q_over_threshold = np.sum( q_samples > self.ADC_FULL_RANGE_THRESHOLD) total_over_threshold = i_over_threshold + q_over_threshold ratio_over_threshold = float( total_over_threshold) / num_samples if ratio_over_threshold > self.ADC_OVERLOAD_THRESHOLD: self._sigan_overload = True # Scale the data back to RF power and return it data /= linear_gain self.check_sensor_overload(data) measurement_result = { "data": data, "overload": self.overload, "frequency": self.frequency, "gain": self.gain, "sample_rate": self.sample_rate, "capture_time": self._capture_time, "calibration_annotation": self.create_calibration_annotation(), } return measurement_result