Skip to content
This repository has been archived by the owner on Apr 13, 2021. It is now read-only.

Track profile switching logic + Glonass support #55

Closed
wants to merge 61 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
d9e5629
Remove call to start() which was done for debugging purposes
Jun 16, 2016
4b59d6e
Fix L1CA and L2C alias lock detectors
Jun 21, 2016
da7eaab
Fix code formatting
Jun 21, 2016
f9c7ef9
Address code review comments
Jun 21, 2016
8ea1d21
Add GLO acquisition support
Apr 18, 2016
0ed5bb3
glonass: added file formats with GLO signals for acquisition
valeri-atamaniouk Aug 1, 2016
011be82
iqgen: Added support for explicit file encoding types
valeri-atamaniouk Aug 3, 2016
31b3a6a
Add GLO tracking support
Apr 21, 2016
89ace5d
iqgen: fixes for GLO signal generation.
valeri-atamaniouk Aug 2, 2016
0ca3c2f
tracking: fixed GLONASS result file name mangling
valeri-atamaniouk Aug 3, 2016
7af2714
tracking: added support for tracking GLONASS SVs
valeri-atamaniouk Aug 3, 2016
0f8ae7c
Updated unit tests
valeri-atamaniouk Aug 3, 2016
75d3709
Add script for computing controlled-root parameters
Paakkit Jul 14, 2016
1fa8ff4
Added comments
Paakkit Jul 14, 2016
407c777
Extend performance simulation scripts with L1CA band option
psalmela Jun 5, 2016
1e153b9
Add 3rd order loop PLL
Jul 13, 2016
eff359d
Add MM CN0 estimator
Jul 15, 2016
1d6cd6b
Adjusted to track with non-zero doppler
Jul 15, 2016
58b2e91
WIP
Jul 18, 2016
2c83767
WIP 2
Jul 25, 2016
ff1f63a
Add BL CN0 estimator
Jul 25, 2016
2ef738e
Add new FSM (WIP)
Jul 26, 2016
2728863
Add numbers to samples distribution utility
Jul 28, 2016
0c368f0
Add more FSM states to cover 2,4,5 and 10 ms integration times
Jul 29, 2016
59e3c94
Add profile switching logic
Aug 3, 2016
954de15
Add more debug output
Aug 3, 2016
d94c4fa
Fix DLL initialization
Aug 3, 2016
fabad6c
Static dopplers work!
Aug 4, 2016
e9a70d3
5g doppler works!
Aug 4, 2016
63acde8
Draft version of tracking profile algorithm is ready
Aug 5, 2016
0d9ef86
Clean up
Aug 5, 2016
8212ce0
Lost fast lock causes PLL bw set to index 1
Aug 5, 2016
0712cb1
Fix bit sync processing handling
Aug 10, 2016
e25fee6
Fix controlled root 3rd order tracking loop
Aug 10, 2016
8cb4be2
Add 40 & 80 ms integration
Aug 10, 2016
3cf99a0
Fix bugs in controlled root 3rd order loop
Aug 10, 2016
aa9fc2d
Clear track profile switching history if it is too old
Aug 10, 2016
55b126c
Change tracker stabilization time to 50ms
Aug 10, 2016
7563695
Change PLL BW values order
Aug 10, 2016
588895e
Add dynamics detector to tracking profile switching logic
Aug 10, 2016
21ec892
Add subplots support to print_track_res script
Aug 11, 2016
3ecf81e
Use different fast lock detector params for different PLL BW
Aug 12, 2016
b45910b
Fix code formatting
Aug 12, 2016
243e55b
Do not wait for bit sync if candidates profile list has 1ms options
Aug 12, 2016
f55936b
Refactor profile history handling
Aug 12, 2016
945c5fd
Fefactor dynamics handling
Aug 12, 2016
17698e2
Remove no_bit_sync options from >1ms integration time FSM tables
Aug 12, 2016
3ab0881
Remove alias_acc_length_ms and t_diff_s from FSM tables
Aug 12, 2016
ed72cc7
Remove duplicate coherent_ms parameters from FSM tables
Aug 12, 2016
8f9660f
Fix alias lock detector
Aug 12, 2016
5e209ea
Remove references to stages and pipelining
Aug 12, 2016
37ac293
Add unit test for alias detector
Aug 12, 2016
a33e3f1
Fix unit tests
Aug 12, 2016
c663de3
Change background colour to white in print_track_res.py script
Aug 12, 2016
93b8446
Update libswiftnav SHA1 to match master head
Aug 12, 2016
b371610
Fix GLO changes to match profile switching logic changes
Aug 17, 2016
e2ee044
Fix formatting + add comments. No functional changes
Aug 17, 2016
012dca3
Remove history support
Aug 21, 2016
4577ed5
Fix print_track_result to match new csv fields naming
Aug 22, 2016
1c9a0af
Change pessimistic and optimistic lock delays
Aug 23, 2016
a94a72b
Remove 2ms and 4ms integration times from recovery stage
Aug 23, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion libswiftnav
130 changes: 93 additions & 37 deletions peregrine/acquisition.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@
import numpy as np
import pyfftw
import cPickle
import defaults

from include.generateCAcode import caCodes
from include.generateGLOcode import GLOCode
from peregrine.gps_constants import L1CA
from peregrine.glo_constants import GLO_L1, glo_l1_step

import logging
logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -191,13 +193,15 @@ def interpolate(self, S_0, S_1, S_2, interpolation='gaussian'):

**Parabolic interpolation:**

.. math:: \Delta = \\frac{1}{2} \\frac{S[k+1] - S[k-1]}{2S[k] - S[k-1] - S[k+1]}
.. math:: \Delta = \\frac{1}{2} \\frac{S[k+1] -
S[k-1]}{2S[k] - S[k-1] - S[k+1]}

Where :math:`S[n]` is the magnitude of FFT bin :math:`n`.

**Gaussian interpolation:**

.. math:: \Delta = \\frac{1}{2} \\frac{\ln(S[k+1]) - \ln(S[k-1])}{2\ln(S[k]) - \ln(S[k-1]) - \ln(S[k+1])}
.. math:: \Delta = \\frac{1}{2} \\frac{\ln(S[k+1]) -
\ln(S[k-1])}{2\ln(S[k]) - \ln(S[k-1]) - \ln(S[k+1])}

The Gaussian interpolation method gives better results, especially when
used with a Gaussian window function, at the expense of computational
Expand Down Expand Up @@ -342,6 +346,8 @@ def find_peak(self, freqs, results, interpolation='gaussian'):
freq_index, cp_samples = np.unravel_index(results.argmax(),
results.shape)

code_phase = float(cp_samples) / self.samples_per_chip

if freq_index > 1 and freq_index < len(freqs) - 1:
delta = self.interpolate(
results[freq_index - 1][cp_samples],
Expand All @@ -358,8 +364,6 @@ def find_peak(self, freqs, results, interpolation='gaussian'):
else:
freq = freqs[freq_index]

code_phase = float(cp_samples) / self.samples_per_chip

# Calculate SNR for the peak.
results_mean = np.mean(results)
if results_mean != 0:
Expand All @@ -370,7 +374,8 @@ def find_peak(self, freqs, results, interpolation='gaussian'):
return (code_phase, freq, snr)

def acquisition(self,
prns=range(32),
prns=xrange(32),
channels=[x - 7 for x in xrange(14)],
doppler_priors=None,
doppler_search=7000,
doppler_step=None,
Expand All @@ -379,10 +384,10 @@ def acquisition(self,
multi=True
):
"""
Perform an acquisition for a given list of PRNs.
Perform an acquisition for a given list of PRNs/channels.

Perform an acquisition for a given list of PRNs across a range of Doppler
frequencies.
Perform an acquisition for a given list of PRNs/channels 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
Expand All @@ -394,8 +399,13 @@ def acquisition(self,

Parameters
----------
bandcode : optional
String defining the acquisition code. Default: L1CA
choices: L1CA, GLO_L1 (in gps_constants.py)
prns : iterable, optional
List of PRNs to acquire. Default: 0..31 (0-indexed)
channels : iterable, optional
List of channels to acquire. Default: -7..6
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.
Expand All @@ -413,10 +423,11 @@ def acquisition(self,
Returns
-------
out : [AcquisitionResult]
A list of :class:`AcquisitionResult` objects, one per PRN in `prns`.
A list of :class:`AcquisitionResult` objects, one per PRN in `prns` or
channel in 'channels'.

"""
logger.info("Acquisition starting")
logger.info("Acquisition starting for " + self.signal)
from peregrine.parallel_processing import parmap

# If the Doppler step is not specified, compute it from the coarse
Expand All @@ -428,9 +439,6 @@ def acquisition(self,
# 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
Expand All @@ -446,33 +454,55 @@ def acquisition(self,
show_progress = False
logger.warning("show_progress = True but progressbar module not found.")

if self.signal == L1CA:
input_len = len(prns)
offset = 1
pb_attr = progressbar.Attribute('prn', '(PRN: %02d)', '(PRN --)')
if doppler_priors is None:
doppler_priors = np.zeros_like(prns)
else:
input_len = len(channels)
offset = 0
pb_attr = progressbar.Attribute('ch', '(CH: %02d)', '(CH --)')
if doppler_priors is None:
doppler_priors = np.zeros_like(channels)

# Setup our progress bar if we need it
if show_progress and not multi:
widgets = [' Acquisition ',
progressbar.Attribute('prn', '(PRN: %02d)', '(PRN --)'), ' ',
pb_attr, ' ',
progressbar.Percentage(), ' ',
progressbar.ETA(), ' ',
progressbar.Bar()]
pbar = progressbar.ProgressBar(widgets=widgets,
maxval=int(len(prns) *
(2 * doppler_search / doppler_step + 1)),
maxval=int(input_len *
(2 * doppler_search / doppler_step + 1)),
fd=progress_fd)
pbar.start()
else:
pbar = None

def do_acq(n):
prn = prns[n]
if self.signal == L1CA:
prn = prns[n]
code = caCodes[prn]
int_f = self.IF
attr = {'prn': prn + 1}
else:
ch = channels[n]
code = GLOCode
int_f = self.IF + ch * glo_l1_step
attr = {'ch': ch}
doppler_prior = doppler_priors[n]
freqs = np.arange(doppler_prior - doppler_search,
doppler_prior + doppler_search, doppler_step) + self.IF
doppler_prior + doppler_search, doppler_step) + int_f
if pbar:
def progress_callback(freq_num, num_freqs):
pbar.update(n * len(freqs) + freq_num, attr={'prn': prn + 1})
pbar.update(n * len(freqs) + freq_num, attr=attr)
else:
progress_callback = None

coarse_results = self.acquire(caCodes[prn], freqs,
coarse_results = self.acquire(code, freqs,
progress_callback=progress_callback)

code_phase, carr_freq, snr = self.find_peak(freqs, coarse_results,
Expand All @@ -485,13 +515,22 @@ def progress_callback(freq_num, num_freqs):
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 self.signal == L1CA:
acq_result = AcquisitionResult(prn,
carr_freq,
carr_freq - int_f,
code_phase,
snr,
status,
L1CA)
else:
acq_result = GloAcquisitionResult(ch,
carr_freq,
carr_freq - int_f,
code_phase,
snr,
status,
GLO_L1)

# If the acquisition was successful, log it
if (snr > threshold):
Expand All @@ -501,9 +540,9 @@ def progress_callback(freq_num, num_freqs):

if multi:
acq_results = parmap(
do_acq, range(len(prns)), show_progress=show_progress)
do_acq, xrange(input_len), show_progress=show_progress)
else:
acq_results = map(do_acq, range(len(prns)))
acq_results = map(do_acq, xrange(input_len))

# Acquisition is finished

Expand All @@ -512,9 +551,11 @@ def progress_callback(freq_num, num_freqs):
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)
acq = [ar.prn + offset for ar in acq_results if ar.status == 'A']
if self.signal == L1CA:
logger.info("Acquired %d satellites, PRNs: %s.", len(acq), acq)
else:
logger.info("Acquired %d channels: %s.", len(acq), acq)

return acq_results

Expand All @@ -531,7 +572,7 @@ def save_wisdom(self, wisdom_file=DEFAULT_WISDOM_FILE):
pyfftw.export_wisdom(), f, protocol=cPickle.HIGHEST_PROTOCOL)


class AcquisitionResult:
class AcquisitionResult(object):
"""
Stores the acquisition parameters of a single satellite.

Expand Down Expand Up @@ -560,7 +601,7 @@ class AcquisitionResult:
"""

__slots__ = ('prn', 'carr_freq', 'doppler',
'code_phase', 'snr', 'status', 'signal')
'code_phase', 'snr', 'status', 'signal', 'sample_index')

def __init__(self, prn, carr_freq, doppler, code_phase, snr, status, signal,
sample_index=0):
Expand All @@ -574,7 +615,7 @@ def __init__(self, prn, carr_freq, doppler, code_phase, snr, status, signal,
self.sample_index = sample_index

def __str__(self):
return "PRN %2d (%s) SNR %6.2f @ CP %6.1f, %+8.2f Hz %s" % \
return "PRN %2d (%s) SNR %6.2f @ CP %6.3f, %+8.2f Hz %s" % \
(self.prn + 1, self.signal, self.snr, self.code_phase,
self.doppler, self.status)

Expand Down Expand Up @@ -615,6 +656,20 @@ def _equal(self, other):
return True


class GloAcquisitionResult(AcquisitionResult):

def __init__(self, channel, carr_freq, doppler, code_phase, snr, status,
signal, sample_index=0):
super(GloAcquisitionResult, self).__init__(channel, carr_freq, doppler,
code_phase, snr, status,
signal, sample_index)

def __str__(self):
return "CH %2d (%s) SNR %6.2f @ CP %6.3f, %+8.2f Hz %s" % \
(self.prn, self.signal, self.snr, self.code_phase, self.doppler,
self.status)


def save_acq_results(filename, acq_results):
"""
Save a set of acquisition results to a file.
Expand Down Expand Up @@ -676,4 +731,5 @@ def print_scores(acq_results, pred, pred_dopp=None):

print "Found %d of %d, mean doppler error = %+5.0f Hz, mean abs err = %4.0f Hz, worst = %+5.0f Hz"\
% (n_match, len(pred),
sum_dopp_err / max(1, n_match), sum_abs_dopp_err / max(1, n_match), worst_dopp_err)
sum_dopp_err / max(1, n_match), sum_abs_dopp_err /
max(1, n_match), worst_dopp_err)
Loading