def acquisition(self, prns=range(32), start_doppler=-7000, stop_doppler=7000, doppler_step=None, threshold=DEFAULT_THRESHOLD, show_progress=True): """ Perform an acquisition for a given list of PRNs. Perform an acquisition for a given list of PRNs across a range of Doppler frequencies. This function returns :class:`AcquisitionResult` objects contatining the location of the acquisition peak for PRNs that have an acquisition Signal-to-Noise ratio (SNR) greater than `threshold`. This calls `acquire` to find the precise code phase and a carrier frequency estimate to within `doppler_step` Hz and then uses interpolation to refine the carrier frequency estimate. Parameters ---------- prns : iterable List of PRNs to acquire. start_doppler : float, optional Start of Doppler frequency search range in Hz. This value is included in the search. stop_doppler : float, optional End of Doppler frequency search range in Hz. This value is not included in the search. doppler_step : float, optional Doppler frequency step to use when performing the coarse Doppler frequency search. threshold : float, optional Threshold SNR value for a satellite to be considered acquired. show_progress : bool, optional When `True` a progress bar will be printed showing acquisition status and estimated time remaining. Returns ------- out : [AcquisitionResult] A list of :class:`AcquisitionResult` objects, one per PRN in `prns`. """ logger.info("Acquisition starting") # If the Doppler step is not specified, compute it from the coarse # acquisition length. if doppler_step is None: # TODO: Work out the best frequency bin spacing. # This is slightly sub-optimal if power is split between two bins, # perhaps you could peak fit or look at pairs of bins to get true peak # magnitude. doppler_step = self.sampling_freq / self.n_coarse freqs = np.arange(start_doppler, stop_doppler, doppler_step) + self.IF # If progressbar is not available, disable show_progress. if show_progress and not _progressbar_available: show_progress = False logger.warning( "show_progress = True but progressbar module not found.") # Setup our progress bar if we need it if show_progress: widgets = [ ' Acquisition ', progressbar.Attribute('prn', '(PRN: %02d)', '(PRN --)'), ' ', progressbar.Percentage(), ' ', progressbar.ETA(), ' ', progressbar.Bar() ] pbar = progressbar.ProgressBar(widgets=widgets, maxval=len(prns) * len(freqs)) pbar.start() else: pbar = None acq_results = [] for n, prn in enumerate(prns): if pbar: def progress_callback(freq_num, num_freqs): pbar.update(n * len(freqs) + freq_num, attr={'prn': prn + 1}) else: progress_callback = None coarse_results = self.acquire(caCodes[prn], freqs, progress_callback=progress_callback) code_phase, carr_freq, snr = self.find_peak(freqs, coarse_results) # If the result is above the threshold, then we have acquired the # satellite. status = '-' if (snr > threshold): status = 'A' # Save properties of the detected satellite signal acq_result = AcquisitionResult(prn, carr_freq, carr_freq - self.IF, code_phase, snr, status) acq_results.append(acq_result) # If the acquisition was successful, log it if (snr > threshold): logger.debug("Acquired %s" % acq_result) # Acquisition is finished # Stop printing progress bar if pbar: pbar.finish() logger.info("Acquisition finished") acquired_prns = [ar.prn + 1 for ar in acq_results if ar.status == 'A'] logger.info("Acquired %d satellites, PRNs: %s.", len(acquired_prns), acquired_prns) return acq_results
def track(signal, channel, settings, show_progress=True, trk=swiftnav.correlate.track_correlate, loop_filter=default_loop_filter): logger.info("Tracking starting") logger.debug("Tracking %d channels, PRNs %s" % (len(channel), [chan.prn+1 for chan in channel])) # Create list of tracking channels results (correlations, freqs, etc) track_results = [] # If progressbar is not available, disable show_progress. if show_progress and not _progressbar_available: show_progress = False logger.warning("show_progress = True but progressbar module not found.") # Setup our progress bar if we need it if show_progress: widgets = [' Tracking ', progressbar.Attribute(['chan', 'nchan'], '(CH: %d/%d)', '(CH: -/-)'), ' ', progressbar.Percentage(), ' ', progressbar.ETA(), ' ', progressbar.Bar()] pbar = progressbar.ProgressBar(widgets=widgets, maxval=len(channel)*settings.msToProcess, attr={'nchan': len(channel)}) pbar.start() else: pbar = None #Do tracking for each channel for channelNr in range(len(channel)): track_result = TrackResults(settings.msToProcess) track_result.PRN = channel[channelNr].prn # Convert acquisition SNR to C/N0 cn0_0 = 10*np.log10(channel[channelNr].snr) cn0_0 += 10*np.log10(1000) # Channel bandwidth cn0_est = swiftnav.track.CN0Estimator(1e3, cn0_0, 10, 1e3) loop_filter.start(0, channel[channelNr].carr_freq-settings.IF) remCodePhase = 0.0 remCarrPhase = 0.0 # Get a vector with the C/A code sampled 1x/chip caCode = caCodes[channel[channelNr].prn] # Add wrapping to either end to be able to do early/late caCode = np.concatenate(([caCode[1022]],caCode,[caCode[0]])) blksize_ = int(settings.samplingFreq * 1e-3 + 10) #number of samples to seek ahead in file samplesPerCodeChip = int(round(settings.samplingFreq / settings.codeFreqBasis)) numSamplesToSkip = settings.skipNumberOfBytes + channel[channelNr].code_phase*samplesPerCodeChip #Process the specified number of ms for loopCnt in range(settings.msToProcess): if pbar: pbar.update(loopCnt + channelNr*settings.msToProcess, attr={'chan': channelNr+1}) rawSignal = signal[numSamplesToSkip:]#[:blksize_] I_E, Q_E, I_P, Q_P, I_L, Q_L, blksize, remCodePhase, remCarrPhase = trk(rawSignal, loop_filter.code_freq+settings.codeFreqBasis, remCodePhase, loop_filter.carr_freq+settings.IF, remCarrPhase, caCode, settings) numSamplesToSkip += blksize E = I_E + Q_E*1.j P = I_P + Q_P*1.j L = I_L + Q_L*1.j loop_filter.update(E, P, L) track_result.carrPhase[loopCnt] = remCarrPhase track_result.carrFreq[loopCnt] = loop_filter.carr_freq+settings.IF track_result.codePhase[loopCnt] = remCodePhase track_result.codeFreq[loopCnt] = loop_filter.code_freq+settings.codeFreqBasis #Record stuff for postprocessing track_result.absoluteSample[loopCnt] = numSamplesToSkip track_result.I_E[loopCnt] = I_E track_result.I_P[loopCnt] = I_P track_result.I_L[loopCnt] = I_L track_result.Q_E[loopCnt] = Q_E track_result.Q_P[loopCnt] = Q_P track_result.Q_L[loopCnt] = Q_L track_result.cn0[loopCnt] = cn0_est.update(I_P) #Possibility for lock-detection later track_result.status = 'T' track_results += [track_result] if pbar: pbar.finish() logger.info("Tracking finished") return track_results
def __init__(self, samples, channels, ms_to_track, sampling_freq, check_l2c_mask=False, l2c_handover=True, progress_bar_output='none', loop_filter_class=AidedTrackingLoop, correlator=track_correlate, stage2_coherent_ms=None, stage2_loop_filter_params=None, multi=False, tracker_options=None, output_file=None): """ Set up tracking environment. 1. Check if multy CPU tracking is possible 2. Set up progress bar 3. Create tracking channels based on the provided acquistion results Parameters ---------- samples : dictionary Samples data for all one or more data channels channels : list A list of acquisition results ms_to_track : float How many milliseconds to track [ms]. If set to '-1', then use all samples. sampling_freq : float Data sampling frequency [Hz] l2c_handover : bool Instructs if L1C/A to L2C handover is to be done progress_bar_output : string Where the progress bar updates are forwarded. loop_filter_class : class The type of the loop filter class to be used by tracker channels correlator : class The correlator class to be used by tracker channels stage2_coherent_ms : dictionary Stage 2 coherent integration parameters set. stage2_loop_filter_params : dictionary Stage 2 loop filter parameters set. multi : bool Enable multi core CPU utilization tracker_options : dictionary Enable piplining or short/long cycles tracking to simulate HW output_file : string The name of the output file, where the tracking results are stored. The actual file name is a mangled version of this file name and reflects the signal name and PRN number for which the tracking results are generated. """ self.samples = samples self.sampling_freq = sampling_freq self.ms_to_track = ms_to_track self.tracker_options = tracker_options self.output_file = output_file self.l2c_handover = l2c_handover self.check_l2c_mask = check_l2c_mask self.correlator = correlator self.stage2_coherent_ms = stage2_coherent_ms self.stage2_loop_filter_params = stage2_loop_filter_params if mp.cpu_count() > 1: self.multi = multi else: self.multi = False self.loop_filter_class = loop_filter_class if self.ms_to_track >= 0: self.samples_to_track = self.ms_to_track * sampling_freq / 1e3 if samples['samples_total'] < self.samples_to_track: logger.warning( "Samples set too short for requested tracking length (%.4fs)" % (self.ms_to_track * 1e-3)) self.samples_to_track = samples['samples_total'] else: self.samples_to_track = samples['samples_total'] if progress_bar_output == 'stdout': self.show_progress = True progress_fd = sys.stdout elif progress_bar_output == 'stderr': self.show_progress = True progress_fd = sys.stderr else: self.show_progress = False progress_fd = -1 # If progressbar is not available, disable show_progress. if self.show_progress and not _progressbar_available: self.show_progress = False logger.warning("show_progress = True but progressbar module not found.") self.init_sample_index = samples['sample_index'] # Setup our progress bar if we need it if self.show_progress: widgets = [' Tracking ', progressbar.Attribute(['sample', 'samples'], '(sample: %d/%d)', '(sample: -/-)'), ' ', progressbar.Percentage(), ' ', progressbar.ETA(), ' ', progressbar.Bar()] self.pbar = progressbar.ProgressBar( widgets=widgets, maxval=samples['samples_total'], attr={'samples': self.samples['samples_total'], 'sample': 0l}, fd=progress_fd) else: self.pbar = None self.tracking_channels = map(self._create_channel, channels)
def acquisition(self, prns=range(32), doppler_priors=None, doppler_search=7000, doppler_step=None, threshold=DEFAULT_THRESHOLD, progress_bar_output='none', multi=True): """ Perform an acquisition for a given list of PRNs. Perform an acquisition for a given list of PRNs across a range of Doppler frequencies. This function returns :class:`AcquisitionResult` objects containing the location of the acquisition peak for PRNs that have an acquisition Signal-to-Noise ratio (SNR) greater than `threshold`. This calls `acquire` to find the precise code phase and a carrier frequency estimate to within `doppler_step` Hz and then uses interpolation to refine the carrier frequency estimate. Parameters ---------- prns : iterable, optional List of PRNs to acquire. Default: 0..31 (0-indexed) doppler_prior: list of floats, optional List of expected Doppler frequencies in Hz (one per PRN). Search will be centered about these. If None, will search around 0 for all PRNs. doppler_search: float, optional Maximum frequency away from doppler_prior to search. Default: 7000 doppler_step : float, optional Doppler frequency step to use when performing the coarse Doppler frequency search. threshold : float, optional Threshold SNR value for a satellite to be considered acquired. show_progress : bool, optional When `True` a progress bar will be printed showing acquisition status and estimated time remaining. Returns ------- out : [AcquisitionResult] A list of :class:`AcquisitionResult` objects, one per PRN in `prns`. """ logger.info("Acquisition starting") from peregrine.parallel_processing import parmap # If the Doppler step is not specified, compute it from the coarse # acquisition length. if doppler_step is None: # TODO: Work out the best frequency bin spacing. # This is slightly sub-optimal if power is split between two bins, # perhaps you could peak fit or look at pairs of bins to get true peak # magnitude. doppler_step = self.sampling_freq / self.n_integrate if doppler_priors is None: doppler_priors = np.zeros_like(prns) if progress_bar_output == 'stdout': show_progress = True progress_fd = sys.stdout elif progress_bar_output == 'stderr': show_progress = True progress_fd = sys.stderr else: show_progress = False progress_fd = -1 # If progressbar is not available, disable show_progress. if show_progress and not _progressbar_available: show_progress = False logger.warning( "show_progress = True but progressbar module not found.") # Setup our progress bar if we need it if show_progress and not multi: widgets = [ ' Acquisition ', progressbar.Attribute('prn', '(PRN: %02d)', '(PRN --)'), ' ', progressbar.Percentage(), ' ', progressbar.ETA(), ' ', progressbar.Bar() ] pbar = progressbar.ProgressBar( widgets=widgets, maxval=int( len(prns) * (2 * doppler_search / doppler_step + 1)), fd=progress_fd) pbar.start() else: pbar = None def do_acq(n): prn = prns[n] doppler_prior = doppler_priors[n] freqs = np.arange(doppler_prior - doppler_search, doppler_prior + doppler_search, doppler_step) + self.IF if pbar: def progress_callback(freq_num, num_freqs): pbar.update(n * len(freqs) + freq_num, attr={'prn': prn + 1}) else: progress_callback = None coarse_results = self.acquire(caCodes[prn], freqs, progress_callback=progress_callback) code_phase, carr_freq, snr = self.find_peak( freqs, coarse_results, interpolation='gaussian') # If the result is above the threshold, then we have acquired the # satellite. status = '-' if (snr > threshold): status = 'A' # Save properties of the detected satellite signal acq_result = AcquisitionResult(prn, carr_freq, carr_freq - self.IF, code_phase, snr, status, self.signal) # If the acquisition was successful, log it if (snr > threshold): logger.debug("Acquired %s" % acq_result) return acq_result if multi: acq_results = parmap(do_acq, range(len(prns)), show_progress=show_progress) else: acq_results = map(do_acq, range(len(prns))) # Acquisition is finished # Stop printing progress bar if pbar: pbar.finish() logger.info("Acquisition finished") acquired_prns = [ar.prn + 1 for ar in acq_results if ar.status == 'A'] logger.info("Acquired %d satellites, PRNs: %s.", len(acquired_prns), acquired_prns) return acq_results