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

Commit 08239ec

Browse files
Pasi Miettinenvaleri-atamaniouk
Pasi Miettinen
authored andcommitted
Add GLO tracking support
1 parent 2fe69a0 commit 08239ec

File tree

4 files changed

+211
-9
lines changed

4 files changed

+211
-9
lines changed

peregrine/alias_detector.py

+14
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
from swiftnav.track import AliasDetector as AD
1313
from peregrine import defaults
1414
from peregrine import gps_constants
15+
from peregrine import glo_constants
1516

1617

1718
class AliasDetector(object):
@@ -134,3 +135,16 @@ def __init__(self, coherent_ms):
134135
(defaults.alias_detect_slice_ms * 2)
135136

136137
self.alias_detect = AD(acc_len=self.integration_rounds, time_diff=2e-3)
138+
139+
140+
class AliasDetectorGLO(AliasDetector):
141+
142+
def __init__(self, coherent_ms):
143+
144+
super(AliasDetectorGLO, self).__init__(coherent_ms)
145+
146+
self.chips_num = glo_constants.glo_code_len
147+
self.integration_rounds = defaults.alias_detect_interval_ms / \
148+
(defaults.alias_detect_slice_ms * 2)
149+
150+
self.alias_detect = AD(acc_len=self.integration_rounds, time_diff=2e-3)

peregrine/defaults.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@
131131
'GPS_L1_IF': 10263750.0,
132132
'GPS_L2_IF': 7.4e6,
133133
'GLO_L1_IF': 12e6,
134-
'GLO_L2_IF': 12e6,
134+
'GLO_L2_IF': 5.6e6,
135135
'sampling_freq': 24.84375e6}
136136

137137
# 'high_rate' frequencies profile
@@ -150,6 +150,7 @@
150150

151151
L1CA_CHANNEL_BANDWIDTH_HZ = 1000
152152
L2C_CHANNEL_BANDWIDTH_HZ = 1000
153+
GLOL1_CHANNEL_BANDWIDTH_HZ = 1000
153154

154155
l1ca_stage1_loop_filter_params = {
155156
"loop_freq": 1e3, # loop frequency [Hz]

peregrine/samples.py

+53-8
Original file line numberDiff line numberDiff line change
@@ -368,10 +368,58 @@ def __get_samples_total(filename, file_format, sample_index):
368368
return samples_total
369369

370370

371+
def __update_dict(samples, sample_key, signal, signal_key):
372+
'''
373+
Helper to populate sample map. The method attaches decoded signals from
374+
a signal source into the result. Also the method removes unused result
375+
entries.
376+
377+
Parameters
378+
----------
379+
samples : map
380+
Resulting map with bands
381+
sample_key : string
382+
Band name
383+
signal : map
384+
Map with decoded band id as keys and samples as entries.
385+
signal_key : int
386+
Band identifier key, which corresponds to band name.
387+
'''
388+
389+
if sample_key in samples:
390+
if signal_key in signal:
391+
samples[sample_key]['samples'] = signal[signal_key]
392+
else:
393+
del samples[sample_key]
394+
395+
371396
def load_samples(samples,
372397
filename,
373398
num_samples=defaults.processing_block_size,
374399
file_format='piksi'):
400+
'''
401+
Loads a block of samples according to parameters.
402+
403+
Parameters
404+
----------
405+
samples : map
406+
Map of band name as a key and a map of band parameters as values. The
407+
following parameters must be present:
408+
- 'samples_total' : long -- Total number of samples in file.
409+
- Any combination of 'l1ca', 'l2c', 'glo_l1' and 'glo_l2' -- The band names
410+
to load.
411+
filename : string
412+
Input file path.
413+
num_samples : int
414+
Number of samples to load.
415+
file_format : string
416+
Type of input file.
417+
418+
Returns
419+
-------
420+
samples : map
421+
Updated band map.
422+
'''
375423

376424
if samples['samples_total'] == -1:
377425
samples['samples_total'] = __get_samples_total(filename,
@@ -381,14 +429,11 @@ def load_samples(samples,
381429
num_samples,
382430
samples['sample_index'],
383431
file_format)
384-
if L1CA in samples and defaults.sample_channel_GPS_L1 in signal:
385-
samples[L1CA]['samples'] = signal[defaults.sample_channel_GPS_L1]
386-
if L2C in samples and defaults.sample_channel_GPS_L2 in signal:
387-
samples[L2C]['samples'] = signal[defaults.sample_channel_GPS_L2]
388-
if GLO_L1 in samples and defaults.sample_channel_GLO_L1 in signal:
389-
samples[GLO_L1]['samples'] = signal[defaults.sample_channel_GLO_L1]
390-
if GLO_L2 in samples and defaults.sample_channel_GLO_L2 in signal:
391-
samples[GLO_L2]['samples'] = signal[defaults.sample_channel_GLO_L2]
432+
433+
__update_dict(samples, L1CA, signal, defaults.sample_channel_GPS_L1)
434+
__update_dict(samples, L2C, signal, defaults.sample_channel_GPS_L2)
435+
__update_dict(samples, GLO_L1, signal, defaults.sample_channel_GLO_L1)
436+
__update_dict(samples, GLO_L2, signal, defaults.sample_channel_GLO_L2)
392437

393438
return samples
394439

peregrine/tracking.py

+142
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,13 @@
2525
from swiftnav.signal import signal_from_code_index
2626
from peregrine import defaults
2727
from peregrine import gps_constants
28+
from peregrine import glo_constants
2829
from peregrine import alias_detector
2930
from peregrine.acquisition import AcquisitionResult
31+
from peregrine.acquisition import GloAcquisitionResult
3032
from peregrine.include.generateCAcode import caCodes
3133
from peregrine.include.generateL2CMcode import L2CMCodes
34+
from peregrine.include.generateGLOcode import GLOCode
3235
from peregrine.tracking_file_utils import createTrackingOutputFileNames
3336

3437
import logging
@@ -120,6 +123,8 @@ def _tracking_channel_factory(parameters):
120123
return TrackingChannelL1CA(parameters)
121124
if parameters['acq'].signal == gps_constants.L2C:
122125
return TrackingChannelL2C(parameters)
126+
if parameters['acq'].signal == glo_constants.GLO_L1:
127+
return TrackingChannelGLOL1(parameters)
123128

124129

125130
class TrackingChannel(object):
@@ -686,6 +691,7 @@ def _run_postprocess(self):
686691

687692
# Handover to L2C if possible
688693
if self.l2c_handover and not self.l2c_handover_acq and \
694+
gps_constants.L2C in self.samples and \
689695
'samples' in self.samples[gps_constants.L2C] and sync:
690696
chan_snr = self.track_result.cn0[self.i]
691697
chan_snr -= 10 * np.log10(defaults.L1CA_CHANNEL_BANDWIDTH_HZ)
@@ -808,6 +814,139 @@ def _run_postprocess(self):
808814
self.coherent_ms
809815

810816

817+
class TrackingChannelGLOL1(TrackingChannel):
818+
"""
819+
GLO L1 tracking channel.
820+
"""
821+
822+
def __init__(self, params):
823+
"""
824+
Initialize GLO L1 tracking channel with GLO L1 specific data.
825+
826+
Parameters
827+
----------
828+
params : dictionary
829+
GLO L1 tracking initialization parameters
830+
831+
"""
832+
# Convert acquisition SNR to C/N0
833+
cn0_0 = 10 * np.log10(params['acq'].snr)
834+
cn0_0 += 10 * np.log10(defaults.GLOL1_CHANNEL_BANDWIDTH_HZ)
835+
params['cn0_0'] = cn0_0
836+
params['coherent_ms'] = 1
837+
params['coherent_iter'] = 1
838+
params['loop_filter_params'] = defaults.l1ca_stage1_loop_filter_params
839+
params['lock_detect_params'] = defaults.l1ca_lock_detect_params_opt
840+
params['IF'] = params['samples'][glo_constants.GLO_L1]['IF']
841+
params['prn_code'] = GLOCode
842+
params['code_freq_init'] = params['acq'].doppler * \
843+
glo_constants.glo_chip_rate / glo_constants.glo_l1
844+
params['chipping_rate'] = glo_constants.glo_chip_rate
845+
params['sample_index'] = 0
846+
params['alias_detector'] = \
847+
alias_detector.AliasDetectorGLO(params['coherent_ms'])
848+
849+
TrackingChannel.__init__(self, params)
850+
851+
self.glol2_handover_acq = None
852+
self.glol2_handover_done = False
853+
854+
# TODO add nav msg decoder (GLO L1)
855+
856+
def is_pickleable(self):
857+
"""
858+
GLO L1 tracking channel object is not pickleable due to complexity
859+
of serializing cnav_msg_decoder Cython object.
860+
861+
out : bool
862+
False - the GLO L1 tracking object is not pickleable
863+
"""
864+
return False
865+
866+
def _get_result(self):
867+
"""
868+
Get GLO L1 tracking results.
869+
The possible outcome of GLO L1 tracking operation is
870+
the GLO L1 handover to GLO L2 in the form of an GloAcquisitionResult object.
871+
872+
Returns
873+
-------
874+
out : AcquisitionResult
875+
GLO L2 acquisition result or None
876+
877+
"""
878+
879+
if self.glol2_handover_acq and not self.glol2_handover_done:
880+
self.glol2_handover_done = True
881+
return self.glol2_handover_acq
882+
return None
883+
884+
def _run_preprocess(self):
885+
"""
886+
Run GLONASS tracking loop preprocessor operation.
887+
It runs before every coherent integration round.
888+
889+
"""
890+
891+
self.coherent_iter = self.coherent_ms
892+
893+
def _short_n_long_preprocess(self):
894+
if self.stage1:
895+
self.E = self.P = self.L = 0.j
896+
else:
897+
# When simulating short and long cycles, short step resets EPL
898+
# registers, and long one adds up to them
899+
if self.short_step:
900+
self.E = self.P = self.L = 0.j
901+
self.coherent_iter = 1
902+
else:
903+
self.coherent_iter = self.coherent_ms - 1
904+
905+
self.code_chips_to_integrate = glo_constants.glo_code_len
906+
907+
return self.coherent_iter, self.code_chips_to_integrate
908+
909+
def _short_n_long_postprocess(self):
910+
more_integration_needed = False
911+
if not self.stage1:
912+
if self.short_step:
913+
# In case of short step - go to next integration period
914+
self.short_step = False
915+
more_integration_needed = True
916+
else:
917+
# Next step is short cycle
918+
self.short_step = True
919+
return more_integration_needed
920+
921+
def _run_postprocess(self):
922+
"""
923+
Run GLO L1 coherent integration postprocessing.
924+
Runs navigation bit sync decoding operation and
925+
GLO L1 to GLO L2 handover.
926+
"""
927+
928+
# Handover to L2C if possible
929+
if self.glol2_handover and not self.glol2_handover_acq and \
930+
glo_constants.GLO_L2 in self.samples and \
931+
'samples' in self.samples[glo_constants.GLO_L2]: # and sync:
932+
chan_snr = self.track_result.cn0[self.i]
933+
# chan_snr -= 10 * np.log10(defaults.GLOL1_CHANNEL_BANDWIDTH_HZ)
934+
chan_snr = np.power(10, chan_snr / 10)
935+
glol2_doppler = self.loop_filter.to_dict()['carr_freq'] * \
936+
glo_constants.glo_l2 / glo_constants.glo_l1
937+
self.glol2_handover_acq = \
938+
GloAcquisitionResult(self.prn,
939+
self.samples[glo_constants.GLO_L2]['IF'] +
940+
glol2_doppler,
941+
glol2_doppler, # carrier doppler
942+
self.track_result.code_phase[
943+
self.i],
944+
chan_snr,
945+
'A',
946+
glo_constants.GLO_L2,
947+
self.track_result.absolute_sample[self.i])
948+
949+
811950
class Tracker(object):
812951
"""
813952
Tracker class.
@@ -822,6 +961,7 @@ def __init__(self,
822961
sampling_freq,
823962
check_l2c_mask=False,
824963
l2c_handover=True,
964+
glol2_handover=True,
825965
progress_bar_output='none',
826966
loop_filter_class=AidedTrackingLoop,
827967
correlator=track_correlate,
@@ -877,6 +1017,7 @@ def __init__(self,
8771017
self.tracker_options = tracker_options
8781018
self.output_file = output_file
8791019
self.l2c_handover = l2c_handover
1020+
self.glol2_handover = glol2_handover
8801021
self.check_l2c_mask = check_l2c_mask
8811022
self.correlator = correlator
8821023
self.stage2_coherent_ms = stage2_coherent_ms
@@ -1021,6 +1162,7 @@ def _create_channel(self, acq):
10211162
'samples_to_track': self.samples_to_track,
10221163
'sampling_freq': self.sampling_freq,
10231164
'l2c_handover': l2c_handover,
1165+
'glol2_handover': self.glol2_handover,
10241166
'show_progress': self.show_progress,
10251167
'correlator': self.correlator,
10261168
'stage2_coherent_ms': self.stage2_coherent_ms,

0 commit comments

Comments
 (0)