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

Commit ab2609b

Browse files
author
Pasi Miettinen
committed
Add acquisition support for Glonass
Depends on #26
1 parent 0bbfb03 commit ab2609b

File tree

6 files changed

+153
-47
lines changed

6 files changed

+153
-47
lines changed

peregrine/acquisition.py

Lines changed: 94 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
import defaults
2121

2222
from include.generateCAcode import caCodes
23+
from include.glo_ca_code import value as glo_ca_code
24+
from peregrine.gps_constants import L1CA, GLO_L1, glo_l1_step
2325

2426
import logging
2527
logger = logging.getLogger(__name__)
@@ -188,13 +190,15 @@ def interpolate(self, S_0, S_1, S_2, interpolation='gaussian'):
188190
189191
**Parabolic interpolation:**
190192
191-
.. math:: \Delta = \\frac{1}{2} \\frac{S[k+1] - S[k-1]}{2S[k] - S[k-1] - S[k+1]}
193+
.. math:: \Delta = \\frac{1}{2} \\frac{S[k+1] -
194+
S[k-1]}{2S[k] - S[k-1] - S[k+1]}
192195
193196
Where :math:`S[n]` is the magnitude of FFT bin :math:`n`.
194197
195198
**Gaussian interpolation:**
196199
197-
.. 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])}
200+
.. math:: \Delta = \\frac{1}{2} \\frac{\ln(S[k+1]) -
201+
\ln(S[k-1])}{2\ln(S[k]) - \ln(S[k-1]) - \ln(S[k+1])}
198202
199203
The Gaussian interpolation method gives better results, especially when
200204
used with a Gaussian window function, at the expense of computational
@@ -363,7 +367,9 @@ def find_peak(self, freqs, results, interpolation='gaussian'):
363367
return (code_phase, freq, snr)
364368

365369
def acquisition(self,
366-
prns=range(32),
370+
bandcode=L1CA,
371+
prns=xrange(32),
372+
channels=[x - 7 for x in xrange(14)],
367373
doppler_priors=None,
368374
doppler_search=7000,
369375
doppler_step=None,
@@ -372,10 +378,10 @@ def acquisition(self,
372378
multi=True
373379
):
374380
"""
375-
Perform an acquisition for a given list of PRNs.
381+
Perform an acquisition for a given list of PRNs/channels.
376382
377-
Perform an acquisition for a given list of PRNs across a range of Doppler
378-
frequencies.
383+
Perform an acquisition for a given list of PRNs/channels across a range of
384+
Doppler frequencies.
379385
380386
This function returns :class:`AcquisitionResult` objects containing the
381387
location of the acquisition peak for PRNs that have an acquisition
@@ -387,8 +393,13 @@ def acquisition(self,
387393
388394
Parameters
389395
----------
396+
bandcode : optional
397+
String defining the acquisition code. Default: L1CA
398+
choices: L1CA, GLO_L1 (in gps_constants.py)
390399
prns : iterable, optional
391400
List of PRNs to acquire. Default: 0..31 (0-indexed)
401+
channels : iterable, optional
402+
List of channels to acquire. Default: -7..6
392403
doppler_prior: list of floats, optional
393404
List of expected Doppler frequencies in Hz (one per PRN). Search will be
394405
centered about these. If None, will search around 0 for all PRNs.
@@ -406,10 +417,15 @@ def acquisition(self,
406417
Returns
407418
-------
408419
out : [AcquisitionResult]
409-
A list of :class:`AcquisitionResult` objects, one per PRN in `prns`.
420+
A list of :class:`AcquisitionResult` objects, one per PRN in `prns` or
421+
channel in 'channels'.
410422
411423
"""
412-
logger.info("Acquisition starting")
424+
if bandcode != L1CA and bandcode != GLO_L1:
425+
logger.critical("Unkown/Unsupported code " + bandcode)
426+
return
427+
428+
logger.info("Acquisition starting for " + bandcode)
413429
from peregrine.parallel_processing import parmap
414430

415431
# If the Doppler step is not specified, compute it from the coarse
@@ -421,9 +437,6 @@ def acquisition(self,
421437
# magnitude.
422438
doppler_step = self.sampling_freq / self.n_integrate
423439

424-
if doppler_priors is None:
425-
doppler_priors = np.zeros_like(prns)
426-
427440
if progress_bar_output == 'stdout':
428441
show_progress = True
429442
progress_fd = sys.stdout
@@ -439,33 +452,55 @@ def acquisition(self,
439452
show_progress = False
440453
logger.warning("show_progress = True but progressbar module not found.")
441454

455+
if bandcode == L1CA:
456+
input_len = len(prns)
457+
offset = 1
458+
pb_attr = progressbar.Attribute('prn', '(PRN: %02d)', '(PRN --)')
459+
if doppler_priors is None:
460+
doppler_priors = np.zeros_like(prns)
461+
else:
462+
input_len = len(channels)
463+
offset = 0
464+
pb_attr = progressbar.Attribute('ch', '(CH: %02d)', '(CH --)')
465+
if doppler_priors is None:
466+
doppler_priors = np.zeros_like(channels)
467+
442468
# Setup our progress bar if we need it
443469
if show_progress and not multi:
444470
widgets = [' Acquisition ',
445-
progressbar.Attribute('prn', '(PRN: %02d)', '(PRN --)'), ' ',
471+
pb_attr, ' ',
446472
progressbar.Percentage(), ' ',
447473
progressbar.ETA(), ' ',
448474
progressbar.Bar()]
449475
pbar = progressbar.ProgressBar(widgets=widgets,
450476
maxval=int(len(prns) *
451-
(2 * doppler_search / doppler_step + 1)),
477+
(2 * doppler_search / doppler_step + 1)),
452478
fd=progress_fd)
453479
pbar.start()
454480
else:
455481
pbar = None
456482

457483
def do_acq(n):
458-
prn = prns[n]
484+
if bandcode == L1CA:
485+
obj = prns[n]
486+
code = caCodes[obj]
487+
int_f = self.IF
488+
attr = {'prn': obj + 1}
489+
else:
490+
obj = channels[n]
491+
code = glo_ca_code
492+
int_f = self.IF + obj * glo_l1_step
493+
attr = {'ch': obj}
459494
doppler_prior = doppler_priors[n]
460495
freqs = np.arange(doppler_prior - doppler_search,
461-
doppler_prior + doppler_search, doppler_step) + self.IF
496+
doppler_prior + doppler_search, doppler_step) + int_f
462497
if pbar:
463498
def progress_callback(freq_num, num_freqs):
464-
pbar.update(n * len(freqs) + freq_num, attr={'prn': prn + 1})
499+
pbar.update(n * len(freqs) + freq_num, attr=attr)
465500
else:
466501
progress_callback = None
467502

468-
coarse_results = self.acquire(caCodes[prn], freqs,
503+
coarse_results = self.acquire(code, freqs,
469504
progress_callback=progress_callback)
470505

471506
code_phase, carr_freq, snr = self.find_peak(freqs, coarse_results,
@@ -478,13 +513,23 @@ def progress_callback(freq_num, num_freqs):
478513
status = 'A'
479514

480515
# Save properties of the detected satellite signal
481-
acq_result = AcquisitionResult(prn,
482-
carr_freq,
483-
carr_freq - self.IF,
484-
code_phase,
485-
snr,
486-
status,
487-
'l1ca')
516+
if bandcode == L1CA:
517+
acq_result = AcquisitionResult(obj,
518+
carr_freq,
519+
carr_freq - self.IF,
520+
code_phase,
521+
snr,
522+
status,
523+
L1CA)
524+
else:
525+
acq_result = GloAcquisitionResult(obj,
526+
carr_freq,
527+
carr_freq -
528+
self.IF - obj * glo_l1_step,
529+
code_phase,
530+
snr,
531+
status,
532+
GLO_L1)
488533

489534
# If the acquisition was successful, log it
490535
if (snr > threshold):
@@ -494,9 +539,9 @@ def progress_callback(freq_num, num_freqs):
494539

495540
if multi:
496541
acq_results = parmap(
497-
do_acq, range(len(prns)), show_progress=show_progress)
542+
do_acq, xrange(input_len), show_progress=show_progress)
498543
else:
499-
acq_results = map(do_acq, range(len(prns)))
544+
acq_results = map(do_acq, xrange(input_len))
500545

501546
# Acquisition is finished
502547

@@ -505,9 +550,11 @@ def progress_callback(freq_num, num_freqs):
505550
pbar.finish()
506551

507552
logger.info("Acquisition finished")
508-
acquired_prns = [ar.prn + 1 for ar in acq_results if ar.status == 'A']
509-
logger.info("Acquired %d satellites, PRNs: %s.",
510-
len(acquired_prns), acquired_prns)
553+
acq = [ar.prn + offset for ar in acq_results if ar.status == 'A']
554+
if bandcode == L1CA:
555+
logger.info("Acquired %d satellites, PRNs: %s.", len(acq), acq)
556+
else:
557+
logger.info("Acquired %d channels: %s.", len(acq), acq)
511558

512559
return acq_results
513560

@@ -524,7 +571,7 @@ def save_wisdom(self, wisdom_file=DEFAULT_WISDOM_FILE):
524571
pyfftw.export_wisdom(), f, protocol=cPickle.HIGHEST_PROTOCOL)
525572

526573

527-
class AcquisitionResult:
574+
class AcquisitionResult(object):
528575
"""
529576
Stores the acquisition parameters of a single satellite.
530577
@@ -553,7 +600,7 @@ class AcquisitionResult:
553600
"""
554601

555602
__slots__ = ('prn', 'carr_freq', 'doppler',
556-
'code_phase', 'snr', 'status', 'signal')
603+
'code_phase', 'snr', 'status', 'signal', 'sample_index')
557604

558605
def __init__(self, prn, carr_freq, doppler, code_phase, snr, status, signal,
559606
sample_index=0):
@@ -608,6 +655,20 @@ def _equal(self, other):
608655
return True
609656

610657

658+
class GloAcquisitionResult(AcquisitionResult):
659+
660+
def __init__(self, channel, carr_freq, doppler, code_phase, snr, status,
661+
signal, sample_index=0):
662+
super(GloAcquisitionResult, self).__init__(channel, carr_freq, doppler,
663+
code_phase, snr, status,
664+
signal, sample_index)
665+
666+
def __str__(self):
667+
return "CH %2d (%s) SNR %6.2f @ CP %6.1f, %+8.2f Hz %s" % \
668+
(self.prn, self.signal, self.snr, self.code_phase, self.doppler,
669+
self.status)
670+
671+
611672
def save_acq_results(filename, acq_results):
612673
"""
613674
Save a set of acquisition results to a file.
@@ -669,4 +730,5 @@ def print_scores(acq_results, pred, pred_dopp=None):
669730

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

peregrine/defaults.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,18 @@
1111
ms_to_track = 37 * 1e3
1212
skip_samples = 1000
1313
file_format = 'piksi'
14-
processing_block_size = 20e6 # [samples]
14+
processing_block_size = 20e6 # [samples]
1515

1616
chipping_rate = 1.023e6 # Hz
1717
code_length = 1023 # chips
1818

1919
code_period = code_length / chipping_rate
2020

21+
glo_chipping_rate = 0.511e6 # Hz
22+
glo_code_length = 511 # chips
23+
24+
glo_code_period = glo_code_length / glo_chipping_rate
25+
2126
# original
2227
sample_channel_GPS_L1 = 0
2328
sample_channel_GPS_L2 = 1
@@ -80,12 +85,14 @@
8085
freq_profile_normal_rate = {
8186
'GPS_L1_IF': 14.58e6,
8287
'GPS_L2_IF': 7.4e6,
88+
'GLO_L1_IF': 12e6,
8389
'sampling_freq': 24.84375e6}
8490

85-
# 'normal_rate' frequencies profile
91+
# 'high_rate' frequencies profile
8692
freq_profile_high_rate = {
8793
'GPS_L1_IF': freq_profile_normal_rate['GPS_L1_IF'],
8894
'GPS_L2_IF': freq_profile_normal_rate['GPS_L2_IF'],
95+
'GLO_L1_IF': freq_profile_normal_rate['GLO_L1_IF'],
8996
'sampling_freq': 99.375e6}
9097

9198
L1CA_CHANNEL_BANDWIDTH_HZ = 1000

peregrine/gps_constants.py

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,33 @@
22

33
# Some fundamental constants have specific numeric definitions to ensure
44
# consistent results in curve fits:
5-
c = 2.99792458e8 # m/s
5+
c = 2.99792458e8 # m/s
66
pi = 3.1415926535898
77

88
# Physical parameters of the Earth
9-
earth_gm = 3.986005e14 # m^3/s^2 (WGS84 earth's gravitational constant)
10-
omegae_dot = 7.2921151467e-005 # rad/s (WGS84 earth rotation rate)
9+
earth_gm = 3.986005e14 # m^3/s^2 (WGS84 earth's gravitational constant)
10+
omegae_dot = 7.2921151467e-005 # rad/s (WGS84 earth rotation rate)
1111

1212
# GPS system parameters:
13-
l1 = 1.57542e9 # Hz
14-
l2 = 1.22760e9 # Hz
13+
l1 = 1.57542e9 # Hz
14+
l2 = 1.22760e9 # Hz
1515
chips_per_code = 1023
16-
chip_rate = 1.023e6 # Hz
17-
nominal_range = 26000e3 # m
16+
chip_rate = 1.023e6 # Hz
17+
nominal_range = 26000e3 # m
18+
19+
# GLO system parameters
20+
glo_l1 = 1.602e9 # Hz
21+
glo_l2 = 1.246e9 # Hz
22+
glo_chips_per_code = 511
23+
glo_chip_rate = 0.511e6 # Hz
24+
glo_l1_step = 0.5625e6 # Hz
1825

1926
# Useful derived quantities:
2027
code_period = chips_per_code / chip_rate
2128
code_wavelength = code_period * c
29+
glo_code_period = glo_chips_per_code / glo_chip_rate
30+
glo_code_wavelength = glo_code_period * c
2231

2332
L1CA = 'l1ca'
2433
L2C = 'l2c'
34+
GLO_L1 = 'glo_l1'

peregrine/initSettings.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,12 @@ def __init__(self, freq_profile):
1515
self.skipNumberOfBytes = 0 # Skip bytes in sample file before loading samples for acquisition (bytes)
1616
self.L1_IF = freq_profile['GPS_L1_IF'] # L1 intermediate frequency of signal in sample file (Hz)
1717
self.L2_IF = freq_profile['GPS_L2_IF'] # L2 intermediate frequency of signal in sample file (Hz)
18+
self.GLO_L1_IF = freq_profile['GLO_L1_IF'] # GLO L1 intermediate frequency of signal in sample file (Hz)
1819
self.samplingFreq = freq_profile['sampling_freq'] # Sampling frequency of sample file (Hz)
1920
self.codeFreqBasis = defaults.chipping_rate # Frequency of chipping code (Hz)
2021
self.codeLength = defaults.code_length # Length of chipping code (chips)
22+
self.gloCodeFreqBasis = defaults.glo_chipping_rate # GLO frequency of chipping code (Hz)
23+
self.gloCodeLength = defaults.glo_code_length # GLO length of chipping code (chips)
2124
self.acqThreshold = 21.0 # SNR (unitless)
2225
self.acqSanityCheck = True # Check for sats known to be below the horizon
2326
self.navSanityMaxResid = 25.0 # meters per SV, normalized nav residuals

0 commit comments

Comments
 (0)