From d9e56292f8fd35d37aa045bfed61d60ad13aba20 Mon Sep 17 00:00:00 2001 From: Pasi Miettinen Date: Thu, 16 Jun 2016 12:38:10 +0300 Subject: [PATCH 01/61] Remove call to start() which was done for debugging purposes --- peregrine/tracking.py | 1 - 1 file changed, 1 deletion(-) diff --git a/peregrine/tracking.py b/peregrine/tracking.py index 3c4389f..7934ea8 100644 --- a/peregrine/tracking.py +++ b/peregrine/tracking.py @@ -363,7 +363,6 @@ def run(self, samples): which can be redefined in subclasses """ - self.start() self.samples = samples if self.sample_index < samples['sample_index']: From 4b59d6e847ed993c444e89db78d8cb1484ee5e87 Mon Sep 17 00:00:00 2001 From: Adel Mamin Date: Tue, 21 Jun 2016 12:09:23 +0300 Subject: [PATCH 02/61] Fix L1CA and L2C alias lock detectors --- libswiftnav | 2 +- peregrine/alias_detector.py | 136 +++++++++++++++++++++++++++++++ peregrine/defaults.py | 13 ++- peregrine/tracking.py | 158 +++++++++++++++++++----------------- 4 files changed, 230 insertions(+), 79 deletions(-) create mode 100644 peregrine/alias_detector.py diff --git a/libswiftnav b/libswiftnav index 8bbc35e..d3e254c 160000 --- a/libswiftnav +++ b/libswiftnav @@ -1 +1 @@ -Subproject commit 8bbc35e7292b639c7f4be636ef3ccb1227312c8b +Subproject commit d3e254cf0db3e0b6d3fadd0b1fb15304acff9ef3 diff --git a/peregrine/alias_detector.py b/peregrine/alias_detector.py new file mode 100644 index 0000000..f348727 --- /dev/null +++ b/peregrine/alias_detector.py @@ -0,0 +1,136 @@ +# Copyright (C) 2016 Swift Navigation Inc. +# Contact: Adel Mamin +# +# This source is subject to the license found in the file 'LICENSE' which must +# be be distributed together with this source. All other rights reserved. +# +# THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, +# EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. + +import numpy as np +from swiftnav.track import AliasDetector as AD +from peregrine import defaults +from peregrine import gps_constants + + +class AliasDetector(object): + + def __init__(self, coherent_ms): + """ + Initialize the parameters, which are common across different + types of tracking channels. + + Parameters + ---------- + coherent_ms : int + Coherent integration time [ms]. + + + """ + self.first_step = True + self.err_hz = 0. + self.coherent_ms = coherent_ms + self.iterations_num = coherent_ms / defaults.alias_detect_slice_ms + + def reinit(self, coherent_ms): + """ + Customize the alias detect reinitialization in a subclass. + The method can be optionally redefined in a subclass to perform + a subclass specific actions to happen when alias detect + reinitialization procedure happens. + + Parameters + ---------- + coherent_ms : int + Coherent integration time [ms]. + + """ + self.err_hz = 0 + self.coherent_ms = coherent_ms + self.alias_detect.reinit(self.integration_rounds, time_diff=2e-3) + + def preprocess(self): + """ + Customize the alias detect procedure in a subclass. + The method can be optionally redefined in a subclass to perform + a subclass specific actions to happen before correlator runs + next integration round. + + """ + self.first_step = True + return self.iterations_num, self.chips_num + + def postprocess(self, P): + """ + Customize the alias detect run procedure in a subclass. + The method can be optionally redefined in a subclass to perform + a subclass specific actions to happen after correlator runs + next integration round. + + Parameters + ---------- + P : prompt I/Q + The prompt I/Q samples from correlator. + code_phase : current code phase [chips] + + """ + + def postprocess(self, P): + if self.first_step: + self.alias_detect.first(P.real, P.imag) + else: + self.err_hz = self.alias_detect.second(P.real, P.imag) + abs_err_hz = abs(self.err_hz) + err_sign = np.sign(self.err_hz) + # The expected frequency errors are +-(25 + N * 50) Hz + # For the reference, see: + # https://swiftnav.hackpad.com/Alias-PLL-lock-detector-in-L2C-4fWUJWUNnOE + if abs_err_hz > 25.: + self.err_hz = 25 + self.err_hz += 50 * int((abs_err_hz - 25) / 50) + abs_err_hz -= self.err_hz + if abs_err_hz + 25. > 50.: + self.err_hz += 50 + elif abs_err_hz > 25 / 2.: + self.err_hz = 25 + else: + self.err_hz = 0 + self.err_hz *= err_sign + + self.first_step = not self.first_step + + return self.chips_num + + def get_err_hz(self): + """ + Customize the alias detect get error procedure in a subclass. + + """ + return self.err_hz + + +class AliasDetectorL1CA(AliasDetector): + + def __init__(self, coherent_ms): + + AliasDetector.__init__(self, coherent_ms) + + self.chips_num = gps_constants.chips_per_code + self.integration_rounds = defaults.alias_detect_interval_ms / \ + (defaults.alias_detect_slice_ms * 2) + + self.alias_detect = AD(acc_len=self.integration_rounds, time_diff=2e-3) + + +class AliasDetectorL2C(AliasDetector): + + def __init__(self, coherent_ms): + + AliasDetector.__init__(self, coherent_ms) + + self.chips_num = 2 * gps_constants.l2_cm_chips_per_code / coherent_ms + self.integration_rounds = defaults.alias_detect_interval_ms / \ + (defaults.alias_detect_slice_ms * 2) + + self.alias_detect = AD(acc_len=self.integration_rounds, time_diff=2e-3) diff --git a/peregrine/defaults.py b/peregrine/defaults.py index 3620e9c..7caf99d 100644 --- a/peregrine/defaults.py +++ b/peregrine/defaults.py @@ -1,4 +1,4 @@ -# Copyright (C) 2014 Swift Navigation Inc. +# Copyright (C) 2014,2016 Swift Navigation Inc. # Contact: Adel Mamin # # This source is subject to the license found in the file 'LICENSE' which must @@ -21,7 +21,7 @@ # used to simulate real HW # [0..10230] -l2c_short_step_chips = 500 # used to simulate real HW +l2c_short_step_chips = 300 # used to simulate real HW chipping_rate = 1.023e6 # Hz code_length = 1023 # chips @@ -264,7 +264,16 @@ 'lp': 50, # 1000ms worth of I/Q samples to reach pessimistic lock 'lo': 240} # 4800ms worth of I/Q samples to lower optimistic lock +# The time interval, over which the alias detection is done. +# The alias detect algorithm averages the phase angle over this time [ms] alias_detect_interval_ms = 500 +# The correlator intermediate results are read with this timeout in [ms]. +# The intermediate results are the input for the alias lock detector. +alias_detect_slice_ms = 1 + # Default pipelining prediction coefficient pipelining_k = .9549 + +# Default coherent integration time for L2C tracker +l2c_coherent_integration_time_ms = 20 diff --git a/peregrine/tracking.py b/peregrine/tracking.py index 7934ea8..fb5755b 100644 --- a/peregrine/tracking.py +++ b/peregrine/tracking.py @@ -16,7 +16,6 @@ from swiftnav.track import LockDetector from swiftnav.track import CN0Estimator -from swiftnav.track import AliasDetector from swiftnav.track import AidedTrackingLoop from swiftnav.correlate import track_correlate from swiftnav.nav_msg import NavMsg @@ -26,6 +25,7 @@ from swiftnav.signal import signal_from_code_index from peregrine import defaults from peregrine import gps_constants +from peregrine import alias_detector from peregrine.acquisition import AcquisitionResult from peregrine.include.generateCAcode import caCodes from peregrine.include.generateL2CMcode import L2CMCodes @@ -172,10 +172,6 @@ def __init__(self, params): lp=self.lock_detect_params["lp"], lo=self.lock_detect_params["lo"]) - self.alias_detect = AliasDetector( - acc_len=defaults.alias_detect_interval_ms / self.coherent_ms, - time_diff=1) - self.cn0_est = CN0Estimator( bw=1e3 / self.coherent_ms, cn0_0=self.cn0_0, @@ -203,7 +199,6 @@ def __init__(self, params): self.track_result = TrackResults(self.results_num, self.acq.prn, self.acq.signal) - self.alias_detect_init = 1 self.code_phase = 0.0 self.carr_phase = 0.0 self.samples_per_chip = int(round(self.sampling_freq / self.chipping_rate)) @@ -215,6 +210,9 @@ def __init__(self, params): self.code_phase_acc = 0.0 self.samples_tracked = 0 self.i = 0 + self.started = False + self.lock_detect_outo = 0 + self.lock_detect_outp = 0 self.pipelining = False # Flag if pipelining is used self.pipelining_k = 0. # Error prediction coefficient for pipelining @@ -249,6 +247,11 @@ def start(self): """ + if self.started: + return + + self.started = True + logger.info("[PRN: %d (%s)] Tracking is started. " "IF: %.1f, Doppler: %.1f, code phase: %.1f, " "sample index: %d" % @@ -412,18 +415,26 @@ def run(self, samples): corr_code_freq = self.next_code_freq corr_carr_freq = self.next_carr_freq - coherent_iter, code_chips_to_integrate = self._short_n_long_preprocess() + if self.short_n_long: + coherent_iter, code_chips_to_integrate = self._short_n_long_preprocess() + else: + coherent_iter, code_chips_to_integrate = \ + self.alias_detector.preprocess() + self.E = self.P = self.L = 0.j - for _ in range(self.coherent_iter): + # Estimated blksize might change as a result of a change of + # the coherent integration time. + estimated_blksize = self.coherent_ms * self.sampling_freq / 1e3 + if (sample_index + 2 * estimated_blksize) > samples_total: + continue - if (sample_index + 2 * estimated_blksize) >= samples_total: - break + for _ in range(coherent_iter): samples_ = samples[self.signal]['samples'][sample_index:] E_, P_, L_, blksize, self.code_phase, self.carr_phase = self.correlator( samples_, - code_chips_to_integrate, + self.code_phase + code_chips_to_integrate, corr_code_freq + self.chipping_rate, self.code_phase, corr_carr_freq + self.IF, self.carr_phase, self.prn_code, @@ -431,9 +442,6 @@ def run(self, samples): self.signal ) - if blksize > estimated_blksize: - estimated_blksize = blksize - sample_index += blksize samples_processed += blksize self.carr_phase_acc += corr_carr_freq * blksize / self.sampling_freq @@ -443,34 +451,35 @@ def run(self, samples): self.P += P_ self.L += L_ - more_integration_needed = self._short_n_long_postprocess() - if more_integration_needed: - continue + if self.short_n_long: + continue + + if self.lock_detect_outo: + code_chips_to_integrate = self.alias_detector.postprocess(P_) + else: + self.alias_detector.reinit(self.coherent_ms) + + if self.short_n_long: + more_integration_needed = self._short_n_long_postprocess() + if more_integration_needed: + continue + + err_hz = self.alias_detector.get_err_hz() + if abs(err_hz) > 0: + logger.info("[PRN: %d (%s)] False lock detected. " + "Error: %.1f Hz. Correcting..." % + (self.prn + 1, self.signal, -err_hz)) + self.loop_filter.adjust_freq(err_hz) # Update PLL lock detector - lock_detect_outo, \ - lock_detect_outp, \ - lock_detect_pcount1, \ - lock_detect_pcount2, \ - lock_detect_lpfi, \ - lock_detect_lpfq = self.lock_detect.update(self.P.real, - self.P.imag, - coherent_iter) - - if lock_detect_outo: - if self.alias_detect_init: - self.alias_detect_init = 0 - self.alias_detect.reinit(defaults.alias_detect_interval_ms / - self.coherent_iter, - time_diff=1) - self.alias_detect.first(self.P.real, self.P.imag) - alias_detect_err_hz = \ - self.alias_detect.second(self.P.real, self.P.imag) * np.pi * \ - (1e3 / defaults.alias_detect_interval_ms) - self.alias_detect.first(self.P.real, self.P.imag) - else: - self.alias_detect_init = 1 - alias_detect_err_hz = 0 + self.lock_detect_outo, \ + self.lock_detect_outp, \ + lock_detect_pcount1, \ + lock_detect_pcount2, \ + lock_detect_lpfi, \ + lock_detect_lpfq = self.lock_detect.update(self.P.real, + self.P.imag, + coherent_iter) self.loop_filter.update(self.E, self.P, self.L) self.track_result.coherent_ms[self.i] = self.coherent_ms @@ -497,14 +506,14 @@ def run(self, samples): self.track_result.cn0[self.i] = self.cn0_est.update( self.P.real, self.P.imag) - self.track_result.lock_detect_outo[self.i] = lock_detect_outo - self.track_result.lock_detect_outp[self.i] = lock_detect_outp + self.track_result.lock_detect_outo[self.i] = self.lock_detect_outo + self.track_result.lock_detect_outp[self.i] = self.lock_detect_outp self.track_result.lock_detect_pcount1[self.i] = lock_detect_pcount1 self.track_result.lock_detect_pcount2[self.i] = lock_detect_pcount2 self.track_result.lock_detect_lpfi[self.i] = lock_detect_lpfi self.track_result.lock_detect_lpfq[self.i] = lock_detect_lpfq - self.track_result.alias_detect_err_hz[self.i] = alias_detect_err_hz + self.track_result.alias_detect_err_hz[self.i] = err_hz self._run_postprocess() @@ -555,6 +564,8 @@ def __init__(self, params): params['lock_detect_params'] = defaults.l1ca_lock_detect_params_opt params['chipping_rate'] = gps_constants.l1ca_chip_rate params['sample_index'] = params['samples']['sample_index'] + params['alias_detector'] = \ + alias_detector.AliasDetectorL1CA(params['coherent_ms']) TrackingChannel.__init__(self, params) @@ -581,6 +592,8 @@ def _run_preprocess(self): self.stage1 = False self.coherent_ms = self.stage2_coherent_ms + self.alias_detector.reinit(self.coherent_ms) + self.loop_filter.retune(**self.stage2_loop_filter_params) self.lock_detect.reinit( k1=self.lock_detect_params["k1"] * self.coherent_ms, @@ -613,7 +626,9 @@ def _get_result(self): return None def _short_n_long_preprocess(self): - if self.short_n_long and not self.stage1: + if self.stage1: + self.E = self.P = self.L = 0.j + else: # When simulating short and long cycles, short step resets EPL # registers, and long one adds up to them if self.short_step: @@ -621,8 +636,6 @@ def _short_n_long_preprocess(self): self.coherent_iter = 1 else: self.coherent_iter = self.coherent_ms - 1 - else: - self.E = self.P = self.L = 0.j self.code_chips_to_integrate = gps_constants.chips_per_code @@ -630,11 +643,10 @@ def _short_n_long_preprocess(self): def _short_n_long_postprocess(self): more_integration_needed = False - if not self.stage1 and self.short_n_long: + if not self.stage1: if self.short_step: # In case of short step - go to next integration period self.short_step = False - self.alias_detect.first(self.P.real, self.P.imag) more_integration_needed = True else: # Next step is short cycle @@ -711,7 +723,7 @@ def __init__(self, params): cn0_0 = 10 * np.log10(params['acq'].snr) cn0_0 += 10 * np.log10(defaults.L2C_CHANNEL_BANDWIDTH_HZ) params['cn0_0'] = cn0_0 - params['coherent_ms'] = 20 + params['coherent_ms'] = defaults.l2c_coherent_integration_time_ms params['coherent_iter'] = 1 params['loop_filter_params'] = defaults.l2c_loop_filter_params params['lock_detect_params'] = defaults.l2c_lock_detect_params_20ms @@ -721,6 +733,8 @@ def __init__(self, params): gps_constants.l2c_chip_rate / gps_constants.l2 params['chipping_rate'] = gps_constants.l2c_chip_rate params['sample_index'] = 0 + params['alias_detector'] = \ + alias_detector.AliasDetectorL2C(params['coherent_ms']) TrackingChannel.__init__(self, params) @@ -738,39 +752,31 @@ def is_pickleable(self): return False def _short_n_long_preprocess(self): - if self.short_n_long: - # When simulating short and long cycles, short step resets EPL - # registers, and long one adds up to them - if self.short_step: - self.E = self.P = self.L = 0.j - # L2C CM code is only half of the PRN code length. - # The other half is CL code. Thus multiply by 2. - self.code_chips_to_integrate = \ - int(2 * defaults.l2c_short_step_chips) - else: - # L2C CM code is only half of the PRN code length. - # The other half is CL code. Thus multiply by 2. - self.code_chips_to_integrate = \ - 2 * gps_constants.l2_cm_chips_per_code - \ - self.code_chips_to_integrate + self.code_phase - code_chips_to_integrate = self.code_chips_to_integrate - else: + # When simulating short and long cycles, short step resets EPL + # registers, and long one adds up to them + if self.short_step: self.E = self.P = self.L = 0.j - code_chips_to_integrate = 2 * gps_constants.l2_cm_chips_per_code + # L2C CM code is only half of the PRN code length. + # The other half is CL code. Thus multiply by 2. + self.code_chips_to_integrate = \ + int(2 * defaults.l2c_short_step_chips) + else: + # L2C CM code is only half of the PRN code length. + # The other half is CL code. Thus multiply by 2. + self.code_chips_to_integrate = \ + 2 * gps_constants.l2_cm_chips_per_code - \ + self.code_chips_to_integrate + code_chips_to_integrate = self.code_chips_to_integrate return self.coherent_iter, code_chips_to_integrate def _short_n_long_postprocess(self): more_integration_needed = False - if self.short_n_long: - if self.short_step: - # In case of short step - go to next integration period - self.short_step = False - self.alias_detect.first(self.P.real, self.P.imag) - more_integration_needed = True - else: - # Next step is short cycle - self.short_step = True + if self.short_step: + self.short_step = False + more_integration_needed = True + else: + self.short_step = True return more_integration_needed From da7eaaba0bf495cea415b77d36174d6b6e130f4f Mon Sep 17 00:00:00 2001 From: Adel Mamin Date: Tue, 21 Jun 2016 14:10:07 +0300 Subject: [PATCH 03/61] Fix code formatting --- peregrine/tracking.py | 46 +++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/peregrine/tracking.py b/peregrine/tracking.py index fb5755b..e2dc838 100644 --- a/peregrine/tracking.py +++ b/peregrine/tracking.py @@ -419,7 +419,7 @@ def run(self, samples): coherent_iter, code_chips_to_integrate = self._short_n_long_preprocess() else: coherent_iter, code_chips_to_integrate = \ - self.alias_detector.preprocess() + self.alias_detector.preprocess() self.E = self.P = self.L = 0.j # Estimated blksize might change as a result of a change of @@ -473,13 +473,13 @@ def run(self, samples): # Update PLL lock detector self.lock_detect_outo, \ - self.lock_detect_outp, \ - lock_detect_pcount1, \ - lock_detect_pcount2, \ - lock_detect_lpfi, \ - lock_detect_lpfq = self.lock_detect.update(self.P.real, - self.P.imag, - coherent_iter) + self.lock_detect_outp, \ + lock_detect_pcount1, \ + lock_detect_pcount2, \ + lock_detect_lpfi, \ + lock_detect_lpfq = self.lock_detect.update(self.P.real, + self.P.imag, + coherent_iter) self.loop_filter.update(self.E, self.P, self.L) self.track_result.coherent_ms[self.i] = self.coherent_ms @@ -565,7 +565,7 @@ def __init__(self, params): params['chipping_rate'] = gps_constants.l1ca_chip_rate params['sample_index'] = params['samples']['sample_index'] params['alias_detector'] = \ - alias_detector.AliasDetectorL1CA(params['coherent_ms']) + alias_detector.AliasDetectorL1CA(params['coherent_ms']) TrackingChannel.__init__(self, params) @@ -759,13 +759,13 @@ def _short_n_long_preprocess(self): # L2C CM code is only half of the PRN code length. # The other half is CL code. Thus multiply by 2. self.code_chips_to_integrate = \ - int(2 * defaults.l2c_short_step_chips) + int(2 * defaults.l2c_short_step_chips) else: # L2C CM code is only half of the PRN code length. # The other half is CL code. Thus multiply by 2. self.code_chips_to_integrate = \ - 2 * gps_constants.l2_cm_chips_per_code - \ - self.code_chips_to_integrate + 2 * gps_constants.l2_cm_chips_per_code - \ + self.code_chips_to_integrate code_chips_to_integrate = self.code_chips_to_integrate return self.coherent_iter, code_chips_to_integrate @@ -893,8 +893,8 @@ def __init__(self, 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)) + "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'] @@ -974,8 +974,8 @@ def stop(self): if self.pbar: self.pbar.finish() res = map(lambda chan: chan.track_result.makeOutputFileNames( - chan.output_file), - self.tracking_channels) + chan.output_file), + self.tracking_channels) fn_analysis = map(lambda x: x[0], res) fn_results = map(lambda x: x[1], res) @@ -1196,13 +1196,13 @@ def dump(self, output_file, size): with open(fn_analysis, mode) as f1: if self.print_start: f1.write( - "sample_index,ms_tracked,coherent_ms,IF,doppler_phase,carr_doppler," - "code_phase,code_freq," - "CN0,E_I,E_Q,P_I,P_Q,L_I,L_Q," - "lock_detect_outp,lock_detect_outo," - "lock_detect_pcount1,lock_detect_pcount2," - "lock_detect_lpfi,lock_detect_lpfq,alias_detect_err_hz," - "code_phase_acc\n") + "sample_index,ms_tracked,coherent_ms,IF,doppler_phase,carr_doppler," + "code_phase,code_freq," + "CN0,E_I,E_Q,P_I,P_Q,L_I,L_Q," + "lock_detect_outp,lock_detect_outo," + "lock_detect_pcount1,lock_detect_pcount2," + "lock_detect_lpfi,lock_detect_lpfq,alias_detect_err_hz," + "code_phase_acc\n") for i in range(size): f1.write("%s," % int(self.absolute_sample[i])) f1.write("%s," % self.ms_tracked[i]) From f9c7ef99fb1e0adcf05cb5049d5c7383a571af7d Mon Sep 17 00:00:00 2001 From: Adel Mamin Date: Tue, 21 Jun 2016 21:15:47 +0300 Subject: [PATCH 04/61] Address code review comments --- libswiftnav | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libswiftnav b/libswiftnav index d3e254c..8bbc35e 160000 --- a/libswiftnav +++ b/libswiftnav @@ -1 +1 @@ -Subproject commit d3e254cf0db3e0b6d3fadd0b1fb15304acff9ef3 +Subproject commit 8bbc35e7292b639c7f4be636ef3ccb1227312c8b From 8ea1d215d29a6eb30450d670f2a910ebb2a37abc Mon Sep 17 00:00:00 2001 From: Pasi Miettinen Date: Mon, 18 Apr 2016 10:48:20 +0300 Subject: [PATCH 05/61] Add GLO acquisition support Conflicts: peregrine/defaults.py peregrine/gps_constants.py peregrine/run.py tests/test_run.py --- peregrine/acquisition.py | 130 +++++++++++++++++------- peregrine/defaults.py | 7 +- peregrine/glo_constants.py | 13 +++ peregrine/run.py | 40 +++++--- peregrine/samples.py | 3 + tests/test_run.py | 196 ++++++++++++++++++++++++++++++++----- 6 files changed, 312 insertions(+), 77 deletions(-) create mode 100644 peregrine/glo_constants.py diff --git a/peregrine/acquisition.py b/peregrine/acquisition.py index 9d4cc56..57ddbb3 100644 --- a/peregrine/acquisition.py +++ b/peregrine/acquisition.py @@ -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__) @@ -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 @@ -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], @@ -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: @@ -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, @@ -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 @@ -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. @@ -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 @@ -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 @@ -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, @@ -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): @@ -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 @@ -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 @@ -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. @@ -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): @@ -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) @@ -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. @@ -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) diff --git a/peregrine/defaults.py b/peregrine/defaults.py index 7caf99d..80e9b83 100644 --- a/peregrine/defaults.py +++ b/peregrine/defaults.py @@ -84,18 +84,21 @@ freq_profile_low_rate = { 'GPS_L1_IF': 1026375.0, 'GPS_L2_IF': 7.4e5, + 'GLO_L1_IF': 12e5, 'sampling_freq': 24.84375e5} # 'normal_rate' frequencies profile freq_profile_normal_rate = { 'GPS_L1_IF': 10263750.0, 'GPS_L2_IF': 7.4e6, + 'GLO_L1_IF': 12e6, 'sampling_freq': 24.84375e6} # 'high_rate' frequencies profile freq_profile_high_rate = { - 'GPS_L1_IF': 14.58e6, - 'GPS_L2_IF': 7.4e6, + 'GPS_L1_IF': freq_profile_normal_rate['GPS_L1_IF'], + 'GPS_L2_IF': freq_profile_normal_rate['GPS_L2_IF'], + 'GLO_L1_IF': freq_profile_normal_rate['GLO_L1_IF'], 'sampling_freq': 99.375e6} freq_profile_lookup = { diff --git a/peregrine/glo_constants.py b/peregrine/glo_constants.py new file mode 100644 index 0000000..d35319d --- /dev/null +++ b/peregrine/glo_constants.py @@ -0,0 +1,13 @@ +# -*- coding: utf-8 -*- +from gps_constants import c +# GLO system parameters +glo_l1 = 1.602e9 # Hz +glo_l2 = 1.246e9 # Hz +glo_code_len = 511 +glo_chip_rate = 0.511e6 # Hz +glo_l1_step = 0.5625e6 # Hz + +glo_code_period = glo_code_len / glo_chip_rate +glo_code_wavelength = glo_code_period * c + +GLO_L1 = 'glo_l1' diff --git a/peregrine/run.py b/peregrine/run.py index e99a06e..d47dc56 100755 --- a/peregrine/run.py +++ b/peregrine/run.py @@ -18,7 +18,8 @@ from operator import attrgetter from peregrine.samples import load_samples -from peregrine.acquisition import Acquisition, load_acq_results, save_acq_results +from peregrine.acquisition import Acquisition, load_acq_results,\ + save_acq_results from peregrine.navigation import navigation import peregrine.tracking as tracking from peregrine.log import default_logging_config @@ -27,6 +28,7 @@ from peregrine.tracking_file_utils import removeTrackingOutputFiles from peregrine.tracking_file_utils import TrackingResults from peregrine.tracking_file_utils import createTrackingDumpOutputFileName +import peregrine.glo_constants as glo class SaveConfigAction(argparse.Action): @@ -54,6 +56,7 @@ def __call__(self, parser, namespace, file_hnd, option_string=None): file_hnd.close() + def populate_peregrine_cmd_line_arguments(parser): if sys.stdout.isatty(): progress_bar_default = 'stdout' @@ -183,6 +186,9 @@ def main(): parser.add_argument("-n", "--skip-navigation", help="use previously saved navigation results", action="store_true") + parser.add_argument("--skip-glonass", + help="skip glonass", + action="store_true") populate_peregrine_cmd_line_arguments(parser) @@ -229,6 +235,7 @@ def main(): samples = {gps.L1CA: {'IF': freq_profile['GPS_L1_IF']}, gps.L2C: {'IF': freq_profile['GPS_L2_IF']}, + glo.GLO_L1: {'IF': freq_profile['GLO_L1_IF']}, 'samples_total': -1, 'sample_index': skip_samples} @@ -243,10 +250,22 @@ def main(): acq_results_file) sys.exit(1) else: - for signal in [gps.L1CA]: - - samplesPerCode = int(round(freq_profile['sampling_freq'] / - (gps.l1ca_chip_rate / gps.l1ca_code_length))) + acq_results = [] + for signal in [gps.L1CA, glo.GLO_L1]: + if signal == gps.L1CA: + code_period = gps.l1ca_code_period + code_len = gps.l1ca_code_length + i_f = freq_profile['GPS_L1_IF'] + samplesPerCode = int(round(freq_profile['sampling_freq'] / + (gps.l1ca_chip_rate / gps.l1ca_code_length))) + else: + if args.skip_glonass: + continue + code_period = glo.glo_code_period + code_len = glo.glo_code_len + i_f = freq_profile['GLO_L1_IF'] + samplesPerCode = int(round(freq_profile['sampling_freq'] / + (glo.glo_chip_rate / glo.glo_code_len))) # Get 11ms of acquisition samples for fine frequency estimation load_samples(samples=samples, @@ -257,13 +276,10 @@ def main(): acq = Acquisition(signal, samples[signal]['samples'], freq_profile['sampling_freq'], - freq_profile['GPS_L1_IF'], - gps.l1ca_code_period * freq_profile['sampling_freq'], - gps.l1ca_code_length) - # only one signal - L1CA is expected to be acquired at the moment - # TODO: add handling of acquisition results from GLONASS once GLONASS - # acquisition is supported. - acq_results = acq.acquisition(progress_bar_output=args.progress_bar) + i_f, + code_period * freq_profile['sampling_freq'], + code_len) + acq_results += acq.acquisition(progress_bar_output=args.progress_bar) print "Acquisition is over!" diff --git a/peregrine/samples.py b/peregrine/samples.py index f2b077d..972e024 100644 --- a/peregrine/samples.py +++ b/peregrine/samples.py @@ -14,6 +14,7 @@ import math import defaults from peregrine.gps_constants import L1CA, L2C +from peregrine.glo_constants import GLO_L1 __all__ = ['load_samples', 'save_samples'] @@ -369,6 +370,8 @@ def load_samples(samples, samples[L1CA]['samples'] = signal[defaults.sample_channel_GPS_L1] if len(signal) > 1: samples[L2C]['samples'] = signal[defaults.sample_channel_GPS_L2] + if len(signal) > 2: + samples[GLO_L1]['samples'] = signal[defaults.sample_channel_GLO_L1] return samples diff --git a/tests/test_run.py b/tests/test_run.py index 53128fa..d9d5bab 100644 --- a/tests/test_run.py +++ b/tests/test_run.py @@ -7,34 +7,178 @@ # EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED # WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. +import peregrine.run +import peregrine.iqgen.iqgen_main as iqgen +import sys import os +import peregrine.acquisition as acq +import peregrine.gps_constants as gps +import peregrine.glo_constants as glo -from test_common import generate_sample_file, \ - run_peregrine +from mock import patch +SAMPLES_PATH = 'tests/test_data/' +# todo: the gpsl1ca_ci_samples.piksi_format.acq_results +# should replace the old file with the same name at the +# remote server, where the script takes it from. +# For now, let's use the local version. +#RES_PATH = SAMPLES_PATH + '/results/' +RES_PATH = 'tests/' -def test_tracking(): - prn = 15 - init_doppler = 1234 - init_code_phase = 0 - file_format = '2bits_x2' +SAMPLES_FNAME = 'gpsl1ca_ci_samples.piksi_format' + +SAMPLES = SAMPLES_PATH + SAMPLES_FNAME + +OLD_TRK_RES = RES_PATH + SAMPLES_FNAME + '.track_results' +OLD_NAV_RES = RES_PATH + SAMPLES_FNAME + '.nav_results' + +# run.py deposits results in same location as samples +NEW_TRK_RES = SAMPLES_PATH + SAMPLES_FNAME + '.track_results' +NEW_NAV_RES = SAMPLES_PATH + SAMPLES_FNAME + '.nav_results' + + +def generate_sample_file(gps_sv_prn, glo_ch, init_doppler, init_code_phase): + sample_file = 'iqgen-data-samples.bin' freq_profile = 'low_rate' - skip_param = '--skip-ms' - skip_val = 0 - samples_filename = generate_sample_file(prn, init_doppler, - init_code_phase, - file_format, freq_profile) - - run_peregrine(samples_filename, file_format, freq_profile, - skip_param, skip_val, False) - - # Comparison not working on Travis at the moment, needs further debugging. - # Simply make sure tracking runs successfully for now. - #with open(NEW_TRK_RES, 'rb') as f: - # new_trk_results = cPickle.load(f) - #with open(OLD_TRK_RES, 'rb') as f: - # old_trk_results = cPickle.load(f) - #assert new_trk_results == old_trk_results - - # Clean-up. - os.remove(samples_filename) + params = ['iqgen_main'] + # GPS + params += ['--gps-sv', str(gps_sv_prn)] + params += ['--bands', 'l1ca'] + params += ['--doppler-type', 'const'] + params += ['--doppler-value', str(init_doppler)] + params += ['--tec', '0'] + params += ['--distance', '0'] + params += ['--chip-delay', str(init_code_phase)] + params += ['--amplitude-type', 'poly'] + params += ['--amplitude-units', 'snr-db'] + params += ['--amplitude-a0', '-17'] + # GLO + params += ['--glo-sv', str(glo_ch)] + params += ['--bands', 'l1'] + params += ['--doppler-type', 'const'] + params += ['--doppler-value', str(init_doppler)] + params += ['--tec', '0'] + params += ['--distance', '0'] + params += ['--message-type', 'crc'] + params += ['--chip-delay', str(init_code_phase)] + params += ['--amplitude-type', 'poly'] + params += ['--amplitude-units', 'snr-db'] + params += ['--amplitude-a0', '-17'] + # common + params += ['--generate', '1'] + params += ['--encoder', '2bits'] + params += ['--output', sample_file] + params += ['--profile', freq_profile] + params += ['-j', '4'] + print params + with patch.object(sys, 'argv', params): + iqgen.main() + + return {'sample_file': sample_file, + 'file_format': '2bits_x4', + 'freq_profile': 'low_rate'} + + +def get_acq_result_file_name(sample_file): + return sample_file + '.acq_results' + + +def run_acq_test(init_doppler, init_code_phase): + for ch in [-1, 0, 1]: + prn = (ch + 8) * 2 + + samples = generate_sample_file(prn, ch, init_doppler, init_code_phase) + + # Replace argv with args to skip tracking and navigation. + with patch.object(sys, 'argv', + ['peregrine', + '--file', samples['sample_file'], + '--file-format', samples['file_format'], + '--profile', samples['freq_profile'], + '-t', '-n']): + + try: + peregrine.run.main() + except SystemExit: + # Thrown if track and nav results files are not present and we + # supplied command line args to skip tracking and navigation. + pass + + acq_results = acq.load_acq_results( + get_acq_result_file_name(samples['sample_file'])) + + glo_res = [] + gps_res = [] + for res in acq_results: + if isinstance(res, acq.GloAcquisitionResult): + glo_res.append(res) + else: + gps_res.append(res) + glo_res = sorted(glo_res, lambda x, y: -1 if x.snr > y.snr else 1) + gps_res = sorted(gps_res, lambda x, y: -1 if x.snr > y.snr else 1) + + def check_result(res): + assert len(res) != 0 + + result = res[0] + print "result = ", result + if isinstance(result, acq.GloAcquisitionResult): + assert (result.prn) == ch + code_length = glo.glo_code_len + else: + assert (result.prn + 1) == prn + code_length = gps.l1ca_code_length + + # check doppler phase estimation + doppler_diff = abs(abs(result.doppler) - abs(init_doppler)) + print "doppler_diff = ", doppler_diff + assert doppler_diff < 200.0 + + # check code phase estimation + code_phase = result.code_phase + if code_phase > code_length / 2: + code_phase = code_phase - code_length + code_phase_diff = abs(abs(code_phase) - abs(init_code_phase)) + print "code_phase_diff = ", code_phase_diff + assert code_phase_diff < 1.0 + + check_result(glo_res) + check_result(gps_res) + + # Clean-up. + os.remove(get_acq_result_file_name(samples['sample_file'])) + os.remove(samples['sample_file']) + + +def test_acquisition(): + run_acq_test(775, 0) + +# def test_tracking(): + +# # Replace argv with args to skip acquisition and navigation. +# with patch.object(sys, 'argv', ['peregrine', SAMPLES, '-a', '-n']): + +# # Copy reference acq results to use in order to skip acquisition. +# copyfile(OLD_ACQ_RES, NEW_ACQ_RES) + +# try: +# peregrine.run.main() +# except SystemExit: +# # Thrown if nav results file is not present and we supplied +# # command line arg to skip navigation. +# pass + +# # Comparison not working on Travis at the moment, needs further debugging. +# # Simply make sure tracking runs successfully for now. +# #with open(NEW_TRK_RES, 'rb') as f: +# # new_trk_results = cPickle.load(f) +# #with open(OLD_TRK_RES, 'rb') as f: +# # old_trk_results = cPickle.load(f) +# #assert new_trk_results == old_trk_results + +# # Clean-up. +# os.remove(NEW_ACQ_RES) +# #os.remove(NEW_TRK_RES) + +# if __name__ == '__main__': +# test_acquisition() From 0ed5bb32a741243e37954fa0fd5db0994b2bbba1 Mon Sep 17 00:00:00 2001 From: Valeri Atamaniouk Date: Mon, 1 Aug 2016 17:15:50 +0300 Subject: [PATCH 06/61] glonass: added file formats with GLO signals for acquisition Added GLONASS-specific file formats for processing. --- peregrine/analysis/tracking_loop.py | 3 + peregrine/defaults.py | 82 +++++++++++++++-- peregrine/glo_constants.py | 1 + peregrine/run.py | 27 +++--- peregrine/samples.py | 135 ++++++++++++++++------------ 5 files changed, 172 insertions(+), 76 deletions(-) diff --git a/peregrine/analysis/tracking_loop.py b/peregrine/analysis/tracking_loop.py index 1832821..6cc7329 100755 --- a/peregrine/analysis/tracking_loop.py +++ b/peregrine/analysis/tracking_loop.py @@ -18,6 +18,7 @@ from peregrine.log import default_logging_config from peregrine.tracking import Tracker from peregrine.gps_constants import L1CA, L2C +from peregrine.glo_constants import GLO_L1, GLO_L2 from peregrine.run import populate_peregrine_cmd_line_arguments @@ -129,6 +130,8 @@ def main(): samples = {L1CA: {'IF': freq_profile['GPS_L1_IF']}, L2C: {'IF': freq_profile['GPS_L2_IF']}, + GLO_L1: {'IF': freq_profile['GLO_L1_IF']}, + GLO_L2: {'IF': freq_profile['GLO_L2_IF']}, 'samples_total': -1, 'sample_index': skip_samples} diff --git a/peregrine/defaults.py b/peregrine/defaults.py index 80e9b83..34daeae 100644 --- a/peregrine/defaults.py +++ b/peregrine/defaults.py @@ -34,11 +34,25 @@ sample_channel_GLO_L1 = 2 sample_channel_GLO_L2 = 3 -file_encoding_1bit_x2 = [ +file_encoding_x1_gpsl1 = [ + sample_channel_GPS_L1] # GPS L1 + +file_encoding_x1_gpsl2 = [ + sample_channel_GPS_L2] # GPS L2 + +file_encoding_x1_glol1 = [ + sample_channel_GLO_L1] # GLO L1 + +file_encoding_x1_glol2 = [ + sample_channel_GLO_L2] # GLO L2 + +file_encoding_x2_gpsl1l2 = [ sample_channel_GPS_L1, # GPS L1 sample_channel_GPS_L2] # GPS L2 -file_encoding_2bits_x2 = file_encoding_1bit_x2 +file_encoding_x2_glol1l2 = [ + sample_channel_GLO_L1, # GLO L1 + sample_channel_GLO_L2] # GLO L2 # encoding is taken from here: # https://swiftnav.hackpad.com/MicroZed-Sample-Grabber-IFgt5DbAunD @@ -63,21 +77,74 @@ # GPS L2 @ 7.4MHz (1227.6MHz) # Galileo E5b-I/Q @ 27.86MHz (1207.14MHz) # Beidou B2 @ 27.86MHz (1207.14MHz) -file_encoding_2bits_x4 = [ +file_encoding_x4_gps_glo = [ sample_channel_GPS_L2, # RF4 sample_channel_GLO_L2, # RF3 sample_channel_GLO_L1, # RF2 sample_channel_GPS_L1] # RF1 +# Some of the format names for use with other components +# The format has the following pattern: _x. +FORMAT_PIKSI_X1_GPS_L1 = 'piksi_x1.gpsl1' +FORMAT_PIKSI_X1_GPS_L2 = 'piksi_x1.gpsl2' +FORMAT_PIKSI_X1_GLO_L1 = 'piksi_x1.glol1' +FORMAT_PIKSI_X1_GLO_L2 = 'piksi_x1.glol2' + +FORMAT_1BIT_X1_GPS_L1 = '1bit_x1.gpsl1' +FORMAT_1BIT_X1_GPS_L2 = '1bit_x1.gpsl2' +FORMAT_1BIT_X2_GPS_L1L2 = '1bit_x2.gps' +FORMAT_1BIT_X1_GLO_L1 = '1bit_x1.glol1' +FORMAT_1BIT_X1_GLO_L2 = '1bit_x1.glol2' +FORMAT_1BIT_X2_GLO_L1L2 = '1bit_x2.glo' +FORMAT_1BIT_X4_GPS_L1L2_GLO_L1L2 = '1bit_x4' + +FORMAT_2BITS_X1_GPS_L1 = '2bits_x1.gpsl1' +FORMAT_2BITS_X1_GPS_L2 = '2bits_x1.gpsl2' +FORMAT_2BITS_X2_GPS_L1L2 = '2bits_x2.gps' +FORMAT_2BITS_X1_GLO_L1 = '2bits_x1.glol1' +FORMAT_2BITS_X1_GLO_L2 = '2bits_x1.glol2' +FORMAT_2BITS_X2_GLO_L1L2 = '2bits_x2.glo' +FORMAT_2BITS_X4_GPS_L1L2_GLO_L1L2 = '2bits_x4' + +# All supported file formats +# The map contains encoding name as a key and value as a list of channels in +# the file. file_encoding_profile = { - '1bit_x2': file_encoding_1bit_x2, - '2bits_x2': file_encoding_2bits_x2, - '2bits_x4': file_encoding_2bits_x4} + 'piksi': file_encoding_x1_gpsl1, + FORMAT_PIKSI_X1_GPS_L1: file_encoding_x1_gpsl1, + FORMAT_PIKSI_X1_GPS_L2: file_encoding_x1_gpsl2, + FORMAT_PIKSI_X1_GLO_L1: file_encoding_x1_glol1, + FORMAT_PIKSI_X1_GLO_L2: file_encoding_x1_glol2, + 'piksinew': file_encoding_x1_gpsl1, + 'int8': file_encoding_x1_gpsl1, + 'c8c8': file_encoding_x2_gpsl1l2, + '1bit': file_encoding_x1_gpsl1, + '1bitrev': file_encoding_x1_gpsl1, + '1bit_x1': file_encoding_x1_gpsl1, + FORMAT_1BIT_X1_GPS_L1: file_encoding_x1_gpsl1, + FORMAT_1BIT_X1_GPS_L2: file_encoding_x1_gpsl2, + FORMAT_1BIT_X1_GLO_L1: file_encoding_x1_glol1, + FORMAT_1BIT_X1_GLO_L2: file_encoding_x1_glol2, + '1bit_x2': file_encoding_x2_gpsl1l2, + FORMAT_1BIT_X2_GPS_L1L2: file_encoding_x2_gpsl1l2, + FORMAT_1BIT_X2_GLO_L1L2: file_encoding_x2_glol1l2, + FORMAT_1BIT_X4_GPS_L1L2_GLO_L1L2: file_encoding_x4_gps_glo, + '2bits': file_encoding_x1_gpsl1, + '2bits_x2': file_encoding_x2_gpsl1l2, + FORMAT_2BITS_X1_GPS_L1: file_encoding_x1_gpsl1, + FORMAT_2BITS_X1_GPS_L2: file_encoding_x1_gpsl2, + FORMAT_2BITS_X1_GLO_L1: file_encoding_x1_glol1, + FORMAT_2BITS_X1_GLO_L2: file_encoding_x1_glol2, + FORMAT_2BITS_X2_GPS_L1L2: file_encoding_x2_gpsl1l2, + FORMAT_2BITS_X2_GLO_L1L2: file_encoding_x2_glol1l2, + FORMAT_2BITS_X4_GPS_L1L2_GLO_L1L2: file_encoding_x4_gps_glo} # 'peregrine' frequencies profile freq_profile_peregrine = { 'GPS_L1_IF': 4.092e6, 'GPS_L2_IF': 4.092e6, + 'GLO_L1_IF': 6e6, + 'GLO_L2_IF': 6e6, 'sampling_freq': 16.368e6} # 'low_rate' frequencies profile @@ -85,6 +152,7 @@ 'GPS_L1_IF': 1026375.0, 'GPS_L2_IF': 7.4e5, 'GLO_L1_IF': 12e5, + 'GLO_L2_IF': 12e5, 'sampling_freq': 24.84375e5} # 'normal_rate' frequencies profile @@ -92,6 +160,7 @@ 'GPS_L1_IF': 10263750.0, 'GPS_L2_IF': 7.4e6, 'GLO_L1_IF': 12e6, + 'GLO_L2_IF': 12e6, 'sampling_freq': 24.84375e6} # 'high_rate' frequencies profile @@ -99,6 +168,7 @@ 'GPS_L1_IF': freq_profile_normal_rate['GPS_L1_IF'], 'GPS_L2_IF': freq_profile_normal_rate['GPS_L2_IF'], 'GLO_L1_IF': freq_profile_normal_rate['GLO_L1_IF'], + 'GLO_L2_IF': freq_profile_normal_rate['GLO_L2_IF'], 'sampling_freq': 99.375e6} freq_profile_lookup = { diff --git a/peregrine/glo_constants.py b/peregrine/glo_constants.py index d35319d..176af07 100644 --- a/peregrine/glo_constants.py +++ b/peregrine/glo_constants.py @@ -11,3 +11,4 @@ glo_code_wavelength = glo_code_period * c GLO_L1 = 'glo_l1' +GLO_L2 = 'glo_l2' diff --git a/peregrine/run.py b/peregrine/run.py index d47dc56..1d6fa9a 100755 --- a/peregrine/run.py +++ b/peregrine/run.py @@ -19,7 +19,7 @@ from peregrine.samples import load_samples from peregrine.acquisition import Acquisition, load_acq_results,\ - save_acq_results + save_acq_results from peregrine.navigation import navigation import peregrine.tracking as tracking from peregrine.log import default_logging_config @@ -56,7 +56,6 @@ def __call__(self, parser, namespace, file_hnd, option_string=None): file_hnd.close() - def populate_peregrine_cmd_line_arguments(parser): if sys.stdout.isatty(): progress_bar_default = 'stdout' @@ -115,12 +114,10 @@ def populate_peregrine_cmd_line_arguments(parser): help="How many milliseconds to skip") inputCtrl.add_argument("-f", "--file-format", - choices=['piksi', 'int8', '1bit', '1bitrev', - '1bit_x2', '2bits', '2bits_x2', '2bits_x4'], + choices=defaults.file_encoding_profile.keys(), metavar='FORMAT', help="The format of the sample data file " - "('piksi', 'int8', '1bit', '1bitrev', " - "'1bit_x2', '2bits', '2bits_x2', '2bits_x4')") + "(%s)" % defaults.file_encoding_profile.keys()) inputCtrl.add_argument("--ms-to-process", metavar='MS', @@ -236,6 +233,7 @@ def main(): samples = {gps.L1CA: {'IF': freq_profile['GPS_L1_IF']}, gps.L2C: {'IF': freq_profile['GPS_L2_IF']}, glo.GLO_L1: {'IF': freq_profile['GLO_L1_IF']}, + glo.GLO_L2: {'IF': freq_profile['GLO_L2_IF']}, 'samples_total': -1, 'sample_index': skip_samples} @@ -250,22 +248,29 @@ def main(): acq_results_file) sys.exit(1) else: + encoding_profile = defaults.file_encoding_profile[args.file_format] + acq_results = [] - for signal in [gps.L1CA, glo.GLO_L1]: - if signal == gps.L1CA: + for channel in encoding_profile: + if channel == defaults.sample_channel_GPS_L1: + signal = gps.L1CA code_period = gps.l1ca_code_period code_len = gps.l1ca_code_length i_f = freq_profile['GPS_L1_IF'] samplesPerCode = int(round(freq_profile['sampling_freq'] / - (gps.l1ca_chip_rate / gps.l1ca_code_length))) - else: + (gps.l1ca_chip_rate / gps.l1ca_code_length))) + elif channel == defaults.sample_channel_GLO_L1: if args.skip_glonass: continue + signal = glo.GLO_L1 code_period = glo.glo_code_period code_len = glo.glo_code_len i_f = freq_profile['GLO_L1_IF'] samplesPerCode = int(round(freq_profile['sampling_freq'] / - (glo.glo_chip_rate / glo.glo_code_len))) + (glo.glo_chip_rate / glo.glo_code_len))) + else: + # No acquisition for other signals + continue # Get 11ms of acquisition samples for fine frequency estimation load_samples(samples=samples, diff --git a/peregrine/samples.py b/peregrine/samples.py index 972e024..c2043d8 100644 --- a/peregrine/samples.py +++ b/peregrine/samples.py @@ -14,7 +14,7 @@ import math import defaults from peregrine.gps_constants import L1CA, L2C -from peregrine.glo_constants import GLO_L1 +from peregrine.glo_constants import GLO_L1, GLO_L2 __all__ = ['load_samples', 'save_samples'] @@ -67,8 +67,7 @@ def __load_samples_n_bits(filename, num_samples, num_skip, n_bits, rounded_len = num_samples * sample_block_size bits = np.unpackbits(s_file) - samples = np.empty((n_rx, num_samples - sample_offset), - dtype=value_lookup.dtype) + samples = {} for rx in range(n_rx): # Construct multi-bit sample values @@ -79,7 +78,9 @@ def __load_samples_n_bits(filename, num_samples, num_skip, n_bits, # Generate sample values using value_lookup table chan = value_lookup[tmp] chan = chan[sample_offset:] - samples[channel_lookup[rx]][:] = chan + copy = np.empty(num_samples - sample_offset, dtype=value_lookup.dtype) + copy[:] = chan + samples[channel_lookup[rx]] = copy return samples @@ -140,9 +141,9 @@ def __load_samples_two_bits(filename, num_samples, num_skip, channel_lookup): def _load_samples(filename, - num_samples=defaults.processing_block_size, - num_skip=0, - file_format='piksi'): + num_samples=defaults.processing_block_size, + num_skip=0, + file_format='piksi'): """ Load sample data from a file. @@ -185,43 +186,55 @@ def _load_samples(filename, If `file_format` is unrecognised. """ - if file_format == 'int8': + + encoding_profile = defaults.file_encoding_profile[file_format] + + if file_format.startswith('int8'): with open(filename, 'rb') as f: f.seek(num_skip) - samples = np.zeros((1, num_samples), dtype=np.int8) - samples[:] = np.fromfile(f, dtype=np.int8, count=num_samples) - elif file_format == 'c8c8': + copy = np.empty(num_samples, dtype=np.int8) + copy[:] = np.fromfile(f, dtype=np.int8, count=num_samples) + samples = {} + samples[encoding_profile[0]] = copy + elif file_format.startswith('c8c8') and not file_format.startswith('c8c8_tayloe'): # Interleaved complex samples from two receivers, i.e. first four bytes are # I0 Q0 I1 Q1 s_file = np.memmap(filename, offset=num_skip, dtype=np.int8, mode='r') n_rx = 2 if num_samples > 0: s_file = s_file[:num_samples * 2 * n_rx] - samples = np.empty([n_rx, len(s_file) / (2 * n_rx)], dtype=np.complex64) + samples = {} for rx in range(n_rx): - samples[rx] = s_file[2 * rx::2 * n_rx] + s_file[2 * rx + 1::2 * n_rx] * 1j - elif file_format == 'c8c8_tayloe': + copy = np.empty(len(s_file) / (2 * n_rx), dtype=np.complex64) + copy[:] = s_file[2 * rx::2 * n_rx] + s_file[2 * rx + 1::2 * n_rx] * 1j + samples[encoding_profile[rx]] = copy + elif file_format.startswith('c8c8_tayloe'): # Interleaved complex samples from two receivers, i.e. first four bytes are - # I0 Q0 I1 Q1. Tayloe-upconverted to become purely real with fs=4fs0,fi=fs0 + # I0 Q0 I1 Q1. Tayloe-upconverted to become purely real with + # fs=4fs0,fi=fs0 s_file = np.memmap(filename, offset=num_skip, dtype=np.int8, mode='r') n_rx = 2 if num_samples > 0: s_file = s_file[:num_samples * 2 * n_rx] - samples = np.empty([n_rx, 4 * len(s_file) / (2 * n_rx)], dtype=np.int8) + samples = {} for rx in range(n_rx): - samples[rx][0::4] = s_file[2 * rx::2 * n_rx] - samples[rx][1::4] = -s_file[2 * rx + 1::2 * n_rx] - samples[rx][2::4] = -s_file[2 * rx::2 * n_rx] - samples[rx][3::4] = s_file[2 * rx + 1::2 * n_rx] - - elif file_format == 'piksinew': + copy = np.empty(4 * len(s_file) / (2 * n_rx), dtype=np.int8) + copy[0::4] = s_file[2 * rx::2 * n_rx] + copy[1::4] = -s_file[2 * rx + 1::2 * n_rx] + copy[2::4] = -s_file[2 * rx::2 * n_rx] + copy[3::4] = s_file[2 * rx + 1::2 * n_rx] + samples[encoding_profile[rx]] = copy + + elif file_format.startswith('piksinew'): packed = np.memmap(filename, offset=num_skip, dtype=np.uint8, mode='r') if num_samples > 0: packed = packed[:num_samples] - samples = np.empty((1, len(packed)), dtype=np.int8) - samples[0][:] = (packed >> 6) - 1 + copy = np.empty(len(packed), dtype=np.int8) + copy[:] = (packed >> 6) - 1 + samples = {} + samples[encoding_profile[0]] = copy - elif file_format == 'piksi': + elif file_format.startswith('piksi'): """ Piksi format is packed 3-bit sign-magnitude samples, 2 samples per byte. @@ -261,11 +274,13 @@ def _load_samples(filename, samples = samples[num_skip_samples:] if num_samples > 0: samples = samples[:num_samples] - tmp = np.ndarray((1, len(samples)), dtype=np.int8) - tmp[0][:] = samples - samples = tmp + copy = np.ndarray(len(samples), dtype=np.int8) + copy[:] = samples + result = {} + result[encoding_profile[0]] = copy + samples = result - elif file_format == '1bit' or file_format == '1bitrev': + elif file_format == '1bitrev': if num_samples > 0: num_skip_bytes = num_skip / 8 num_skip_samples = num_skip % 8 @@ -287,25 +302,20 @@ def _load_samples(filename, samples = samples[num_skip_samples:] if num_samples > 0: samples = samples[:num_samples] - tmp = np.ndarray((1, len(samples)), dtype=np.int8) - tmp[0][:] = samples - samples = tmp - - elif file_format == '1bit_x2': - # Interleaved single bit samples from two receivers: -1, +1 + result = {} + copy = np.ndarray(len(samples), dtype=np.int8) + copy[:] = samples + result[encoding_profile[0]] = copy + samples = result + + elif file_format.startswith('1bit'): + # Interleaved single bit samples from one, two or four receivers: -1, +1 samples = __load_samples_one_bit(filename, num_samples, num_skip, - defaults.file_encoding_1bit_x2) - elif file_format == '2bits': - # Two bit samples from one receiver: -3, -1, +1, +3 - samples = __load_samples_two_bits(filename, num_samples, num_skip, [0]) - elif file_format == '2bits_x2': - # Interleaved two bit samples from two receivers: -3, -1, +1, +3 - samples = __load_samples_two_bits(filename, num_samples, num_skip, - defaults.file_encoding_2bits_x2) - elif file_format == '2bits_x4': - # Interleaved two bit samples from four receivers: -3, -1, +1, +3 + encoding_profile) + elif file_format.startswith('2bits'): + # Two bit samples from one, two or four receivers: -3, -1, +1, +3 samples = __load_samples_two_bits(filename, num_samples, num_skip, - defaults.file_encoding_2bits_x4) + encoding_profile) else: raise ValueError("Unknown file type '%s'" % file_format) @@ -313,6 +323,7 @@ def _load_samples(filename, def __get_samples_total(filename, file_format, sample_index): + if file_format == 'int8': samples_block_size = 8 elif file_format == 'piksi': @@ -328,20 +339,23 @@ def __get_samples_total(filename, file_format, sample_index): """ samples_block_size = 4 - elif file_format == '1bit' or file_format == '1bitrev': - samples_block_size = 1 - elif file_format == '1bit_x2': + elif file_format.startswith('1bit_x4'): + # Interleaved single bit samples from four receivers: -1, +1 + samples_block_size = 4 + elif file_format.startswith('1bit_x2'): # Interleaved single bit samples from two receivers: -1, +1 samples_block_size = 2 - elif file_format == '2bits': - # Two bit samples from one receiver: -3, -1, +1, +3 - samples_block_size = 2 - elif file_format == '2bits_x2': - # Interleaved two bit samples from two receivers: -3, -1, +1, +3 - samples_block_size = 4 - elif file_format == '2bits_x4': + elif file_format.startswith('1bit'): + samples_block_size = 1 + elif file_format.startswith('2bits_x4'): # Interleaved two bit samples from four receivers: -3, -1, +1, +3 samples_block_size = 8 + elif file_format.startswith('2bits_x2'): + # Interleaved two bit samples from two receivers: -3, -1, +1, +3 + samples_block_size = 4 + elif file_format.startswith('2bits'): + # Two bit samples from one receiver: -3, -1, +1, +3 + samples_block_size = 2 else: raise ValueError("Unknown file type '%s'" % file_format) @@ -367,11 +381,14 @@ def load_samples(samples, num_samples, samples['sample_index'], file_format) - samples[L1CA]['samples'] = signal[defaults.sample_channel_GPS_L1] - if len(signal) > 1: + if L1CA in samples and defaults.sample_channel_GPS_L1 in signal: + samples[L1CA]['samples'] = signal[defaults.sample_channel_GPS_L1] + if L2C in samples and defaults.sample_channel_GPS_L2 in signal: samples[L2C]['samples'] = signal[defaults.sample_channel_GPS_L2] - if len(signal) > 2: + if GLO_L1 in samples and defaults.sample_channel_GLO_L1 in signal: samples[GLO_L1]['samples'] = signal[defaults.sample_channel_GLO_L1] + if GLO_L2 in samples and defaults.sample_channel_GLO_L2 in signal: + samples[GLO_L2]['samples'] = signal[defaults.sample_channel_GLO_L2] return samples From 011be82d58630c88772d08803605303483e413c5 Mon Sep 17 00:00:00 2001 From: Valeri Atamaniouk Date: Wed, 3 Aug 2016 14:50:42 +0300 Subject: [PATCH 07/61] iqgen: Added support for explicit file encoding types Added support for file encoding types compatible with main peregrine tools. --- peregrine/iqgen/iqgen_main.py | 53 +++++++++++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 3 deletions(-) diff --git a/peregrine/iqgen/iqgen_main.py b/peregrine/iqgen/iqgen_main.py index 5dd5852..f96647c 100755 --- a/peregrine/iqgen/iqgen_main.py +++ b/peregrine/iqgen/iqgen_main.py @@ -85,6 +85,7 @@ from peregrine.iqgen.bits.tcxo_factory import factoryObject as tcxoFO from peregrine.log import default_logging_config +from peregrine import defaults logger = logging.getLogger(__name__) @@ -666,7 +667,22 @@ def __call__(self, parser, namespace, values, option_string=None): help="Amount of data to generate, in seconds") parser.add_argument('--encoder', default="2bits", - choices=["1bit", "2bits"], + choices=["1bit", "2bits", + defaults.FORMAT_1BIT_X1_GPS_L1, + defaults.FORMAT_1BIT_X1_GPS_L2, + defaults.FORMAT_1BIT_X1_GLO_L1, + defaults.FORMAT_1BIT_X1_GLO_L2, + defaults.FORMAT_1BIT_X2_GPS_L1L2, + defaults.FORMAT_1BIT_X2_GLO_L1L2, + defaults.FORMAT_1BIT_X4_GPS_L1L2_GLO_L1L2, + defaults.FORMAT_2BITS_X1_GPS_L1, + defaults.FORMAT_2BITS_X1_GPS_L2, + defaults.FORMAT_2BITS_X1_GLO_L1, + defaults.FORMAT_2BITS_X1_GLO_L2, + defaults.FORMAT_2BITS_X2_GPS_L1L2, + defaults.FORMAT_2BITS_X2_GLO_L1L2, + defaults.FORMAT_2BITS_X4_GPS_L1L2_GLO_L1L2 + ], help="Output data format") parser.add_argument('--output', type=argparse.FileType('wb'), @@ -801,8 +817,39 @@ def selectEncoder(encoderType, outputConfig, enabledBands): enabledGPS = enabledGPSL1 or enabledGPSL2 enabledGLONASS = enabledGLONASSL1 or enabledGLONASSL2 - # Configure data encoder - if encoderType == "1bit": + + # Explicitly defined encoders + if encoderType == defaults.FORMAT_1BIT_X1_GPS_L1: + encoder = GPSL1BitEncoder(outputConfig) + elif encoderType == defaults.FORMAT_1BIT_X1_GPS_L2: + encoder = GPSL2BitEncoder(outputConfig) + elif encoderType == defaults.FORMAT_1BIT_X2_GPS_L1L2: + encoder = GPSL1L2BitEncoder(outputConfig) + elif encoderType == defaults.FORMAT_1BIT_X1_GLO_L1: + encoder = GLONASSL1BitEncoder(outputConfig) + elif encoderType == defaults.FORMAT_1BIT_X1_GLO_L2: + encoder = GLONASSL2BitEncoder(outputConfig) + elif encoderType == defaults.FORMAT_1BIT_X2_GLO_L1L2: + encoder = GLONASSL1L2BitEncoder(outputConfig) + elif encoderType == defaults.FORMAT_1BIT_X4_GPS_L1L2_GLO_L1L2: + encoder = GPSGLONASSBitEncoder(outputConfig) + elif encoderType == defaults.FORMAT_2BITS_X1_GPS_L1: + encoder = GPSL1TwoBitsEncoder(outputConfig) + elif encoderType == defaults.FORMAT_2BITS_X1_GPS_L2: + encoder = GPSL2TwoBitsEncoder(outputConfig) + elif encoderType == defaults.FORMAT_2BITS_X2_GPS_L1L2: + encoder = GPSL1L2TwoBitsEncoder(outputConfig) + elif encoderType == defaults.FORMAT_2BITS_X1_GLO_L1: + encoder = GLONASSL1TwoBitsEncoder(outputConfig) + elif encoderType == defaults.FORMAT_2BITS_X1_GLO_L2: + encoder = GLONASSL2TwoBitsEncoder(outputConfig) + elif encoderType == defaults.FORMAT_2BITS_X2_GLO_L1L2: + encoder = GLONASSL1L2TwoBitsEncoder(outputConfig) + elif encoderType == defaults.FORMAT_2BITS_X4_GPS_L1L2_GLO_L1L2: + encoder = GPSGLONASSTwoBitsEncoder(outputConfig) + + # Encoder auto-detection + elif encoderType == "1bit": if enabledGPS and enabledGLONASS: encoder = GPSGLONASSBitEncoder(outputConfig) elif enabledGPS: From 31b3a6a5a8bbd984f02ae18314e54f364db311ca Mon Sep 17 00:00:00 2001 From: Pasi Miettinen Date: Thu, 21 Apr 2016 10:11:42 +0300 Subject: [PATCH 08/61] Add GLO tracking support --- peregrine/alias_detector.py | 14 ++++ peregrine/defaults.py | 3 +- peregrine/samples.py | 61 ++++++++++++++-- peregrine/tracking.py | 142 ++++++++++++++++++++++++++++++++++++ 4 files changed, 211 insertions(+), 9 deletions(-) diff --git a/peregrine/alias_detector.py b/peregrine/alias_detector.py index f348727..e809c74 100644 --- a/peregrine/alias_detector.py +++ b/peregrine/alias_detector.py @@ -12,6 +12,7 @@ from swiftnav.track import AliasDetector as AD from peregrine import defaults from peregrine import gps_constants +from peregrine import glo_constants class AliasDetector(object): @@ -134,3 +135,16 @@ def __init__(self, coherent_ms): (defaults.alias_detect_slice_ms * 2) self.alias_detect = AD(acc_len=self.integration_rounds, time_diff=2e-3) + + +class AliasDetectorGLO(AliasDetector): + + def __init__(self, coherent_ms): + + super(AliasDetectorGLO, self).__init__(coherent_ms) + + self.chips_num = glo_constants.glo_code_len + self.integration_rounds = defaults.alias_detect_interval_ms / \ + (defaults.alias_detect_slice_ms * 2) + + self.alias_detect = AD(acc_len=self.integration_rounds, time_diff=2e-3) diff --git a/peregrine/defaults.py b/peregrine/defaults.py index 34daeae..e02a8e9 100644 --- a/peregrine/defaults.py +++ b/peregrine/defaults.py @@ -160,7 +160,7 @@ 'GPS_L1_IF': 10263750.0, 'GPS_L2_IF': 7.4e6, 'GLO_L1_IF': 12e6, - 'GLO_L2_IF': 12e6, + 'GLO_L2_IF': 5.6e6, 'sampling_freq': 24.84375e6} # 'high_rate' frequencies profile @@ -179,6 +179,7 @@ L1CA_CHANNEL_BANDWIDTH_HZ = 1000 L2C_CHANNEL_BANDWIDTH_HZ = 1000 +GLOL1_CHANNEL_BANDWIDTH_HZ = 1000 l1ca_stage1_loop_filter_params = { "loop_freq": 1e3, # loop frequency [Hz] diff --git a/peregrine/samples.py b/peregrine/samples.py index c2043d8..154ae99 100644 --- a/peregrine/samples.py +++ b/peregrine/samples.py @@ -368,10 +368,58 @@ def __get_samples_total(filename, file_format, sample_index): return samples_total +def __update_dict(samples, sample_key, signal, signal_key): + ''' + Helper to populate sample map. The method attaches decoded signals from + a signal source into the result. Also the method removes unused result + entries. + + Parameters + ---------- + samples : map + Resulting map with bands + sample_key : string + Band name + signal : map + Map with decoded band id as keys and samples as entries. + signal_key : int + Band identifier key, which corresponds to band name. + ''' + + if sample_key in samples: + if signal_key in signal: + samples[sample_key]['samples'] = signal[signal_key] + else: + del samples[sample_key] + + def load_samples(samples, filename, num_samples=defaults.processing_block_size, file_format='piksi'): + ''' + Loads a block of samples according to parameters. + + Parameters + ---------- + samples : map + Map of band name as a key and a map of band parameters as values. The + following parameters must be present: + - 'samples_total' : long -- Total number of samples in file. + - Any combination of 'l1ca', 'l2c', 'glo_l1' and 'glo_l2' -- The band names + to load. + filename : string + Input file path. + num_samples : int + Number of samples to load. + file_format : string + Type of input file. + + Returns + ------- + samples : map + Updated band map. + ''' if samples['samples_total'] == -1: samples['samples_total'] = __get_samples_total(filename, @@ -381,14 +429,11 @@ def load_samples(samples, num_samples, samples['sample_index'], file_format) - if L1CA in samples and defaults.sample_channel_GPS_L1 in signal: - samples[L1CA]['samples'] = signal[defaults.sample_channel_GPS_L1] - if L2C in samples and defaults.sample_channel_GPS_L2 in signal: - samples[L2C]['samples'] = signal[defaults.sample_channel_GPS_L2] - if GLO_L1 in samples and defaults.sample_channel_GLO_L1 in signal: - samples[GLO_L1]['samples'] = signal[defaults.sample_channel_GLO_L1] - if GLO_L2 in samples and defaults.sample_channel_GLO_L2 in signal: - samples[GLO_L2]['samples'] = signal[defaults.sample_channel_GLO_L2] + + __update_dict(samples, L1CA, signal, defaults.sample_channel_GPS_L1) + __update_dict(samples, L2C, signal, defaults.sample_channel_GPS_L2) + __update_dict(samples, GLO_L1, signal, defaults.sample_channel_GLO_L1) + __update_dict(samples, GLO_L2, signal, defaults.sample_channel_GLO_L2) return samples diff --git a/peregrine/tracking.py b/peregrine/tracking.py index e2dc838..8fa85a3 100644 --- a/peregrine/tracking.py +++ b/peregrine/tracking.py @@ -25,10 +25,13 @@ from swiftnav.signal import signal_from_code_index from peregrine import defaults from peregrine import gps_constants +from peregrine import glo_constants from peregrine import alias_detector from peregrine.acquisition import AcquisitionResult +from peregrine.acquisition import GloAcquisitionResult from peregrine.include.generateCAcode import caCodes from peregrine.include.generateL2CMcode import L2CMCodes +from peregrine.include.generateGLOcode import GLOCode from peregrine.tracking_file_utils import createTrackingOutputFileNames import logging @@ -120,6 +123,8 @@ def _tracking_channel_factory(parameters): return TrackingChannelL1CA(parameters) if parameters['acq'].signal == gps_constants.L2C: return TrackingChannelL2C(parameters) + if parameters['acq'].signal == glo_constants.GLO_L1: + return TrackingChannelGLOL1(parameters) class TrackingChannel(object): @@ -686,6 +691,7 @@ def _run_postprocess(self): # Handover to L2C if possible if self.l2c_handover and not self.l2c_handover_acq and \ + gps_constants.L2C in self.samples and \ 'samples' in self.samples[gps_constants.L2C] and sync: chan_snr = self.track_result.cn0[self.i] chan_snr -= 10 * np.log10(defaults.L1CA_CHANNEL_BANDWIDTH_HZ) @@ -808,6 +814,139 @@ def _run_postprocess(self): self.coherent_ms +class TrackingChannelGLOL1(TrackingChannel): + """ + GLO L1 tracking channel. + """ + + def __init__(self, params): + """ + Initialize GLO L1 tracking channel with GLO L1 specific data. + + Parameters + ---------- + params : dictionary + GLO L1 tracking initialization parameters + + """ + # Convert acquisition SNR to C/N0 + cn0_0 = 10 * np.log10(params['acq'].snr) + cn0_0 += 10 * np.log10(defaults.GLOL1_CHANNEL_BANDWIDTH_HZ) + params['cn0_0'] = cn0_0 + params['coherent_ms'] = 1 + params['coherent_iter'] = 1 + params['loop_filter_params'] = defaults.l1ca_stage1_loop_filter_params + params['lock_detect_params'] = defaults.l1ca_lock_detect_params_opt + params['IF'] = params['samples'][glo_constants.GLO_L1]['IF'] + params['prn_code'] = GLOCode + params['code_freq_init'] = params['acq'].doppler * \ + glo_constants.glo_chip_rate / glo_constants.glo_l1 + params['chipping_rate'] = glo_constants.glo_chip_rate + params['sample_index'] = 0 + params['alias_detector'] = \ + alias_detector.AliasDetectorGLO(params['coherent_ms']) + + TrackingChannel.__init__(self, params) + + self.glol2_handover_acq = None + self.glol2_handover_done = False + + # TODO add nav msg decoder (GLO L1) + + def is_pickleable(self): + """ + GLO L1 tracking channel object is not pickleable due to complexity + of serializing cnav_msg_decoder Cython object. + + out : bool + False - the GLO L1 tracking object is not pickleable + """ + return False + + def _get_result(self): + """ + Get GLO L1 tracking results. + The possible outcome of GLO L1 tracking operation is + the GLO L1 handover to GLO L2 in the form of an GloAcquisitionResult object. + + Returns + ------- + out : AcquisitionResult + GLO L2 acquisition result or None + + """ + + if self.glol2_handover_acq and not self.glol2_handover_done: + self.glol2_handover_done = True + return self.glol2_handover_acq + return None + + def _run_preprocess(self): + """ + Run GLONASS tracking loop preprocessor operation. + It runs before every coherent integration round. + + """ + + self.coherent_iter = self.coherent_ms + + def _short_n_long_preprocess(self): + if self.stage1: + self.E = self.P = self.L = 0.j + else: + # When simulating short and long cycles, short step resets EPL + # registers, and long one adds up to them + if self.short_step: + self.E = self.P = self.L = 0.j + self.coherent_iter = 1 + else: + self.coherent_iter = self.coherent_ms - 1 + + self.code_chips_to_integrate = glo_constants.glo_code_len + + return self.coherent_iter, self.code_chips_to_integrate + + def _short_n_long_postprocess(self): + more_integration_needed = False + if not self.stage1: + if self.short_step: + # In case of short step - go to next integration period + self.short_step = False + more_integration_needed = True + else: + # Next step is short cycle + self.short_step = True + return more_integration_needed + + def _run_postprocess(self): + """ + Run GLO L1 coherent integration postprocessing. + Runs navigation bit sync decoding operation and + GLO L1 to GLO L2 handover. + """ + + # Handover to L2C if possible + if self.glol2_handover and not self.glol2_handover_acq and \ + glo_constants.GLO_L2 in self.samples and \ + 'samples' in self.samples[glo_constants.GLO_L2]: # and sync: + chan_snr = self.track_result.cn0[self.i] + # chan_snr -= 10 * np.log10(defaults.GLOL1_CHANNEL_BANDWIDTH_HZ) + chan_snr = np.power(10, chan_snr / 10) + glol2_doppler = self.loop_filter.to_dict()['carr_freq'] * \ + glo_constants.glo_l2 / glo_constants.glo_l1 + self.glol2_handover_acq = \ + GloAcquisitionResult(self.prn, + self.samples[glo_constants.GLO_L2]['IF'] + + glol2_doppler, + glol2_doppler, # carrier doppler + self.track_result.code_phase[ + self.i], + chan_snr, + 'A', + glo_constants.GLO_L2, + self.track_result.absolute_sample[self.i]) + + class Tracker(object): """ Tracker class. @@ -822,6 +961,7 @@ def __init__(self, sampling_freq, check_l2c_mask=False, l2c_handover=True, + glol2_handover=True, progress_bar_output='none', loop_filter_class=AidedTrackingLoop, correlator=track_correlate, @@ -877,6 +1017,7 @@ def __init__(self, self.tracker_options = tracker_options self.output_file = output_file self.l2c_handover = l2c_handover + self.glol2_handover = glol2_handover self.check_l2c_mask = check_l2c_mask self.correlator = correlator self.stage2_coherent_ms = stage2_coherent_ms @@ -1021,6 +1162,7 @@ def _create_channel(self, acq): 'samples_to_track': self.samples_to_track, 'sampling_freq': self.sampling_freq, 'l2c_handover': l2c_handover, + 'glol2_handover': self.glol2_handover, 'show_progress': self.show_progress, 'correlator': self.correlator, 'stage2_coherent_ms': self.stage2_coherent_ms, From 89ace5d44b83e8ce069553f4e073a0669018a7c6 Mon Sep 17 00:00:00 2001 From: Valeri Atamaniouk Date: Tue, 2 Aug 2016 13:47:05 +0300 Subject: [PATCH 09/61] iqgen: fixes for GLO signal generation. Updated GLONASS C/N0 estimation and parameter handling. --- peregrine/iqgen/generate.py | 13 ++++++------- peregrine/iqgen/iqgen_main.py | 14 ++++++-------- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/peregrine/iqgen/generate.py b/peregrine/iqgen/generate.py index 7f236e3..94d9d28 100644 --- a/peregrine/iqgen/generate.py +++ b/peregrine/iqgen/generate.py @@ -25,7 +25,6 @@ import sys import traceback import logging -import scipy import scipy.constants import numpy import time @@ -434,8 +433,8 @@ def printSvInfo(sv_list, outputConfig, lpfFA_db, noiseParams, encoder): elif isinstance(_sv, GLOSatellite): band1 = outputConfig.GLONASS.L1 band2 = outputConfig.GLONASS.L2 - band1IncreaseDb = 60. - lpfFA_db[band1.INDEX] # GLONASS L1 - band2IncreaseDb = 60. - lpfFA_db[band2.INDEX] # GLONASS L2 + band1IncreaseDb = 57. - lpfFA_db[band1.INDEX] # GLONASS L1 + band2IncreaseDb = 57. - lpfFA_db[band2.INDEX] # GLONASS L2 signal1 = signals.GLONASS.L1S[_sv.prn] signal2 = signals.GLONASS.L2S[_sv.prn] _msg1 = _sv.getL1Message() @@ -546,8 +545,8 @@ def generateSamples(outputFile, # Print out parameters # logger.info( - "Generating samples, sample rate={} Hz, interval={} seconds".format( - outputConfig.SAMPLE_RATE_HZ, nSamples / outputConfig.SAMPLE_RATE_HZ)) + "Generating samples, sample rate={} Hz, interval={} seconds".format( + outputConfig.SAMPLE_RATE_HZ, nSamples / outputConfig.SAMPLE_RATE_HZ)) logger.debug("Jobs: %d" % threadCount) _count = 0l @@ -602,8 +601,8 @@ def generateSamples(outputFile, # Print out parameters logger.info( - "Generating samples, sample rate={} Hz, interval={} seconds".format( - outputConfig.SAMPLE_RATE_HZ, nSamples / outputConfig.SAMPLE_RATE_HZ)) + "Generating samples, sample rate={} Hz, interval={} seconds".format( + outputConfig.SAMPLE_RATE_HZ, nSamples / outputConfig.SAMPLE_RATE_HZ)) logger.debug("Jobs: %d" % threadCount) # Print out SV parameters printSvInfo(sv_list, outputConfig, lpfFA_db, noiseParams, encoder) diff --git a/peregrine/iqgen/iqgen_main.py b/peregrine/iqgen/iqgen_main.py index f96647c..ce0144a 100755 --- a/peregrine/iqgen/iqgen_main.py +++ b/peregrine/iqgen/iqgen_main.py @@ -273,9 +273,9 @@ def doUpdate(self, sv, parser, namespace, values, option_string): raise ValueError("Signal band must be specified before doppler") elif isinstance(sv, GLOSatellite): if sv.isL1Enabled(): - frequency_hz = signals.GLONASS.L1S[sv.prn].CENTER_FREQUENCY_HZ + signal = signals.GLONASS.L1S[sv.prn] elif sv.isL2Enabled(): - frequency_hz = signals.GLONASS.L2S[sv.prn].CENTER_FREQUENCY_HZ + signal = signals.GLONASS.L2S[sv.prn] else: raise ValueError("Signal band must be specified before doppler") else: @@ -571,8 +571,7 @@ def __call__(self, parser, namespace, values, option_string=None): amplitudeGrp.add_argument('--amplitude-type', default="poly", choices=["poly", "sine"], - help= - "Configure amplitude type: polynomial or sine.", + help="Configure amplitude type: polynomial or sine.", action=UpdateAmplitudeType) amplitudeGrp.add_argument('--amplitude-units', default="snr-db", @@ -656,8 +655,7 @@ def __call__(self, parser, namespace, values, option_string=None): action=UpdateTcxoType) parser.add_argument('--group-delays', type=bool, - help= - "Enable/disable group delays simulation between bands") + help="Enable/disable group delays simulation between bands") parser.add_argument('--debug', type=argparse.FileType('wb'), help="Debug output file") @@ -755,9 +753,9 @@ def printOutputConfig(outputConfig, args): print " GPS L1 IF: ", outputConfig.GPS.L1.INTERMEDIATE_FREQUENCY_HZ print " GPS L2 IF: ", outputConfig.GPS.L2.INTERMEDIATE_FREQUENCY_HZ print " GLONASS L1[0] IF:",\ - outputConfig.GLONASS.L1.INTERMEDIATE_FREQUENCIES_HZ[0] + outputConfig.GLONASS.L1.INTERMEDIATE_FREQUENCIES_HZ[0] print " GLONASS L2[0] IF:",\ - outputConfig.GLONASS.L2.INTERMEDIATE_FREQUENCIES_HZ[0] + outputConfig.GLONASS.L2.INTERMEDIATE_FREQUENCIES_HZ[0] print "Other parameters:" print " TCXO: ", args.tcxo print " noise sigma: ", args.noise_sigma From 0ca3c2fa2f2e4b1398d927ad46bfc3fb5f5346e6 Mon Sep 17 00:00:00 2001 From: Valeri Atamaniouk Date: Wed, 3 Aug 2016 15:58:28 +0300 Subject: [PATCH 10/61] tracking: fixed GLONASS result file name mangling Fixed handling of GLONASS tracking result file names. --- peregrine/glo_constants.py | 1 + peregrine/tracking.py | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/peregrine/glo_constants.py b/peregrine/glo_constants.py index 176af07..65ece04 100644 --- a/peregrine/glo_constants.py +++ b/peregrine/glo_constants.py @@ -6,6 +6,7 @@ glo_code_len = 511 glo_chip_rate = 0.511e6 # Hz glo_l1_step = 0.5625e6 # Hz +glo_l2_step = 0.4375e6 # Hz glo_code_period = glo_code_len / glo_chip_rate glo_code_wavelength = glo_code_period * c diff --git a/peregrine/tracking.py b/peregrine/tracking.py index 8fa85a3..154797d 100644 --- a/peregrine/tracking.py +++ b/peregrine/tracking.py @@ -1376,8 +1376,11 @@ def dump(self, output_file, size): def makeOutputFileNames(self, outputFileName): # mangle the output file names with the tracked signal name + prn = self.prn + if self.signal == gps_constants.L1CA or self.signal == gps_constants.L2C: + prn += 1 fn_analysis, fn_results = createTrackingOutputFileNames(outputFileName, - self.prn + 1, + prn, self.signal) return fn_analysis, fn_results From 7af2714ff275cf423f2a16695436e9e62ebe0b65 Mon Sep 17 00:00:00 2001 From: Valeri Atamaniouk Date: Wed, 3 Aug 2016 15:59:13 +0300 Subject: [PATCH 11/61] tracking: added support for tracking GLONASS SVs Added support for tracking analysys of GLONASS signals. --- peregrine/analysis/tracking_loop.py | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/peregrine/analysis/tracking_loop.py b/peregrine/analysis/tracking_loop.py index 6cc7329..e639679 100755 --- a/peregrine/analysis/tracking_loop.py +++ b/peregrine/analysis/tracking_loop.py @@ -18,7 +18,7 @@ from peregrine.log import default_logging_config from peregrine.tracking import Tracker from peregrine.gps_constants import L1CA, L2C -from peregrine.glo_constants import GLO_L1, GLO_L2 +from peregrine.glo_constants import GLO_L1, GLO_L2, glo_l1_step, glo_l2_step from peregrine.run import populate_peregrine_cmd_line_arguments @@ -41,9 +41,9 @@ def main(): help="carrier Doppler frequency [Hz]. ") signalParam.add_argument("-S", "--signal", - choices=[L1CA, L2C], + choices=[L1CA, L2C, GLO_L1, GLO_L2], metavar='BAND', - help="Signal type (l1ca / l2c)") + help="Signal type (l1ca, l2c, glo_l1, glo_l2)") signalParam.add_argument("--l2c-handover", action='store_true', help="Perform L2C handover", @@ -79,13 +79,25 @@ def main(): isL1CA = (args.signal == L1CA) isL2C = (args.signal == L2C) + isGLO_L1 = (args.signal == GLO_L1) + isGLO_L2 = (args.signal == GLO_L2) if isL1CA: signal = L1CA IF = freq_profile['GPS_L1_IF'] + prn = int(args.prn) - 1 elif isL2C: signal = L2C IF = freq_profile['GPS_L2_IF'] + prn = int(args.prn) - 1 + elif isGLO_L1: + signal = GLO_L1 + IF = freq_profile['GLO_L1_IF'] + glo_l1_step * int(args.prn) + prn = int(args.prn) + elif isGLO_L2: + signal = GLO_L2 + IF = freq_profile['GLO_L2_IF'] + glo_l2_step * int(args.prn) + prn = int(args.prn) else: raise NotImplementedError() @@ -98,7 +110,6 @@ def main(): carr_doppler = float(args.carr_doppler) code_phase = float(args.code_phase) - prn = int(args.prn) - 1 ms_to_process = int(args.ms_to_process) @@ -148,8 +159,10 @@ def main(): print "File format: %s" % args.file_format print "PRN to track [1-32]: %s" % args.prn print "Time to process [s]: %s" % (ms_to_process / 1e3) - print "L1 IF [Hz]: %f" % freq_profile['GPS_L1_IF'] - print "L2 IF [Hz]: %f" % freq_profile['GPS_L2_IF'] + print "GPS L1 IF [Hz]: %f" % freq_profile['GPS_L1_IF'] + print "GPS L2 IF [Hz]: %f" % freq_profile['GPS_L2_IF'] + print "GLO L1 IF [Hz]: %f" % freq_profile['GLO_L1_IF'] + print "GLO L2 IF [Hz]: %f" % freq_profile['GLO_L2_IF'] print "Sampling frequency [Hz]: %f" % sampling_freq print "Initial carrier Doppler frequency [Hz]: %s" % carr_doppler print "Initial code phase [chips]: %s" % code_phase From 0f8ae7c19b529c83450bef9bb5a26a1d2d2402c3 Mon Sep 17 00:00:00 2001 From: Valeri Atamaniouk Date: Wed, 3 Aug 2016 14:36:59 +0300 Subject: [PATCH 12/61] Updated unit tests Updated hanlding of encoding names, added GLONASS tracking test. --- tests/test_acquisition.py | 29 ++++----- tests/test_common.py | 120 +++++++++++++++++++++++------------- tests/test_file_format.py | 14 ++--- tests/test_freq_profiles.py | 11 ++-- tests/test_tracking.py | 89 ++++++++++++++++++-------- 5 files changed, 166 insertions(+), 97 deletions(-) diff --git a/tests/test_acquisition.py b/tests/test_acquisition.py index 3c0d526..49bcc56 100644 --- a/tests/test_acquisition.py +++ b/tests/test_acquisition.py @@ -8,12 +8,13 @@ # WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. from test_common import generate_sample_file, \ - run_peregrine,\ - propagate_code_phase, \ - get_sampling_freq + run_peregrine,\ + propagate_code_phase, \ + get_sampling_freq import os import peregrine.acquisition as acq +from peregrine import defaults def get_acq_result_file_name(sample_file): @@ -37,15 +38,15 @@ def run_acq_test(init_doppler, init_code_phase, for prn in prns: samples_filename = generate_sample_file(prn, init_doppler, - init_code_phase, - file_format, freq_profile) + init_code_phase, + file_format, freq_profile) run_peregrine(samples_filename, file_format, freq_profile, skip_param, skip_val) code_phase = propagate_code_phase(init_code_phase, - get_sampling_freq(freq_profile), - skip_param, skip_val) + get_sampling_freq(freq_profile), + skip_param, skip_val) if skip_val == 0: check_acq_results(samples_filename, prn, init_doppler, code_phase) @@ -57,7 +58,7 @@ def run_acq_test(init_doppler, init_code_phase, def check_acq_results(filename, prn, doppler, code_phase): acq_results = acq.load_acq_results( - get_acq_result_file_name(filename)) + get_acq_result_file_name(filename)) acq_results = sorted(acq_results, lambda x, y: -1 if x.snr > y.snr else 1) @@ -79,7 +80,7 @@ def check_acq_results(filename, prn, doppler, code_phase): assert code_phase_diff < 1.0 -#def test_acquisition(): +# def test_acquisition(): # """ # Test GPS L1C/A acquisition # """ @@ -97,21 +98,21 @@ def test_acqusition_prn1_m1000(): """ Test GPS L1C/A acquisition """ - run_acq_test(-1000., 0., [1], '2bits') + run_acq_test(-1000., 0., [1], defaults.FORMAT_2BITS_X1_GPS_L1) def test_acqusition_prn32_0(): """ Test GPS L1C/A acquisition """ - run_acq_test(0., 0., [32], '2bits') + run_acq_test(0., 0., [32], defaults.FORMAT_2BITS_X1_GPS_L1) def test_acqusition_prn5_p1000(): """ Test GPS L1C/A acquisition """ - run_acq_test(1000., 0., [5], '2bits') + run_acq_test(1000., 0., [5], defaults.FORMAT_2BITS_X1_GPS_L1) def test_skip_params(): @@ -122,5 +123,5 @@ def test_skip_params(): --skip_ms """ - run_acq_test(1000, 0, [1], '1bit', skip_samples=1000) - run_acq_test(1000, 0, [1], '1bit', skip_ms=50) + run_acq_test(1000, 0, [1], defaults.FORMAT_1BIT_X1_GPS_L1, skip_samples=1000) + run_acq_test(1000, 0, [1], defaults.FORMAT_1BIT_X1_GPS_L1, skip_ms=50) diff --git a/tests/test_common.py b/tests/test_common.py index 135e309..6166df7 100644 --- a/tests/test_common.py +++ b/tests/test_common.py @@ -12,22 +12,24 @@ import peregrine.iqgen.iqgen_main as iqgen import peregrine.defaults as defaults import peregrine.gps_constants as gps +import peregrine.glo_constants as glo import numpy as np from mock import patch def fileformat_to_bands(file_format): - if file_format == '1bit': - bands = ['l1ca'] - elif file_format == '1bit_x2': - bands = ['l1ca', 'l2c'] - elif file_format == '2bits': - bands = ['l1ca'] - elif file_format == '2bits_x2': - bands = ['l1ca', 'l2c'] - elif file_format == '2bits_x4': - bands = ['l1ca', 'l2c'] + profile = defaults.file_encoding_profile[file_format] + bands = [] + for p in profile: + if p == defaults.sample_channel_GPS_L1: + bands += [gps.L1CA] + elif p == defaults.sample_channel_GPS_L2: + bands += [gps.L2C] + elif p == defaults.sample_channel_GLO_L1: + bands += [glo.GLO_L1] + elif p == defaults.sample_channel_GLO_L2: + bands += [glo.GLO_L2] return bands @@ -67,8 +69,8 @@ def generate_2bits_x4_sample_file(filename): samples[channel_lookup[rx]][:] = chan # Store the result back to the same file packed = np.zeros(num_samples, dtype=np.uint8) - packed = samples[3][::] << 6 - packed |= samples[0][::] & 3 + packed[:] = samples[3] << 6 + packed |= samples[0] & 3 with open(filename, 'wb') as f: packed.tofile(f) @@ -77,17 +79,17 @@ def generate_2bits_x4_sample_file(filename): def generate_piksi_sample_file(filename): samples_lookup = [ - 0b11111100, - 0b11011000, - 0b10110100, - 0b10010000, - 0b00000000, - 0b00100100, - 0b01001000, - 0b01101100 + 0b11111100, + 0b11011000, + 0b10110100, + 0b10010000, + 0b00000000, + 0b00100100, + 0b01001000, + 0b01101100 ] samples_lookup_values = [ - -7, -7, -5, -5, -3, -3, -1, -1, 1, 1, 3, 3, 5, 5, 7, 7 + -7, -7, -5, -5, -3, -3, -1, -1, 1, 1, 3, 3, 5, 5, 7, 7 ] num_samples = int(1e6) packed = np.zeros(num_samples, dtype=np.uint8) @@ -104,23 +106,53 @@ def generate_sample_file(gps_sv_prn, init_doppler, freq_profile, generate=.1): sample_file = 'iqgen-data-samples.bin' params = ['iqgen_main'] - params += ['--gps-sv', str(gps_sv_prn)] - - if file_format == '1bit': - encoder = '1bit' - params += ['--bands', 'l1ca'] - elif file_format == '1bit_x2': - encoder = '1bit' - params += ['--bands', 'l1ca+l2c'] - elif file_format == '2bits': - encoder = '2bits' - params += ['--bands', 'l1ca'] - elif file_format == '2bits_x2': - encoder = '2bits' - params += ['--bands', 'l1ca+l2c'] - elif file_format == '2bits_x4': - encoder = '2bits' - params += ['--bands', 'l1ca+l2c'] + bands = fileformat_to_bands(file_format) + + if gps.L1CA in bands or gps.L2C in bands: + params += ['--gps-sv', str(gps_sv_prn)] + + if file_format == defaults.FORMAT_1BIT_X1_GPS_L1: + encoder = '1bit' + params += ['--bands', 'l1ca'] + elif file_format == defaults.FORMAT_1BIT_X2_GPS_L1L2: + encoder = '1bit' + params += ['--bands', 'l1ca+l2c'] + elif file_format == defaults.FORMAT_2BITS_X1_GPS_L1: + encoder = '2bits' + params += ['--bands', 'l1ca'] + elif file_format == defaults.FORMAT_2BITS_X2_GPS_L1L2: + encoder = '2bits' + params += ['--bands', 'l1ca+l2c'] + elif file_format == defaults.FORMAT_2BITS_X4_GPS_L1L2_GLO_L1L2: + encoder = '2bits' + params += ['--bands', 'l1ca+l2c'] + else: + assert False + elif glo.GLO_L1 in bands or glo.GLO_L2 in bands: + params += ['--glo-sv', str(gps_sv_prn)] + + if file_format == defaults.FORMAT_1BIT_X1_GLO_L1: + encoder = '1bit' + params += ['--bands', 'l1'] + elif file_format == defaults.FORMAT_1BIT_X1_GLO_L2: + encoder = '1bit' + params += ['--bands', 'l2'] + elif file_format == defaults.FORMAT_1BIT_X2_GLO_L1L2: + encoder = '1bit' + params += ['--bands', 'l1+l2'] + elif file_format == defaults.FORMAT_2BITS_X1_GLO_L1: + encoder = '2bits' + params += ['--bands', 'l1'] + elif file_format == defaults.FORMAT_2BITS_X2_GLO_L1L2: + encoder = '2bits' + params += ['--bands', 'l1+l2'] + elif file_format == defaults.FORMAT_2BITS_X4_GPS_L1L2_GLO_L1L2: + encoder = '2bits' + params += ['--bands', 'l1+l2'] + else: + assert False + else: + assert False params += ['--encoder', encoder] params += ['--doppler-type', 'const'] @@ -153,12 +185,12 @@ def run_peregrine(file_name, file_format, freq_profile, short_long_cycles=None): parameters = [ - 'peregrine', - '--file', file_name, - '--file-format', file_format, - '--profile', freq_profile, - skip_param, str(skip_val), - '--progress-bar', 'stdout' + 'peregrine', + '--file', file_name, + '--file-format', file_format, + '--profile', freq_profile, + skip_param, str(skip_val), + '--progress-bar', 'stdout' ] if skip_tracking: parameters += ['-t'] diff --git a/tests/test_file_format.py b/tests/test_file_format.py index 36f7a95..a94794c 100644 --- a/tests/test_file_format.py +++ b/tests/test_file_format.py @@ -13,28 +13,28 @@ def test_file_format_1bit(): """ Test different file formats: '1bit' """ - run_acq_test(1000, 0, [1], '1bit') + run_acq_test(1000, 0, [1], defaults.FORMAT_1BIT_X1_GPS_L1) def test_file_format_2bits(): """ Test different file formats: '2bits' """ - run_acq_test(1000, 0, [1], '2bits') + run_acq_test(1000, 0, [1], defaults.FORMAT_2BITS_X1_GPS_L1) def test_file_format_1bitx2(): """ Test different file formats: '1bit_x2' """ - run_acq_test(1000, 0, [1], '1bit_x2') + run_acq_test(1000, 0, [1], defaults.FORMAT_1BIT_X2_GPS_L1L2) def test_file_format_2bitsx2(): """ Test different file formats: '2bits_x2' """ - run_acq_test(1000, 0, [1], '2bits_x2') + run_acq_test(1000, 0, [1], defaults.FORMAT_2BITS_X2_GPS_L1L2) def test_file_formats(): @@ -45,9 +45,9 @@ def test_file_formats(): # test 'piksi' format val = generate_piksi_sample_file(SAMPLE_FILE_NAME) samples = { - 'samples_total': -1, - 'sample_index': 0, - L1CA: {} + 'samples_total': -1, + 'sample_index': 0, + L1CA: {} } for num in [-1, defaults.processing_block_size]: load_samples(samples, SAMPLE_FILE_NAME, num, 'piksi') diff --git a/tests/test_freq_profiles.py b/tests/test_freq_profiles.py index b343c19..7786935 100644 --- a/tests/test_freq_profiles.py +++ b/tests/test_freq_profiles.py @@ -8,21 +8,22 @@ # WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. from test_acquisition import run_acq_test +from peregrine import defaults def test_custom_rate(): - run_acq_test(-4000, 0, [1], '2bits', 'custom_rate') + run_acq_test(-4000, 0, [1], defaults.FORMAT_2BITS_X1_GPS_L1, 'custom_rate') def test_low_rate(): - run_acq_test(-2000, 0, [2], '2bits', 'low_rate') + run_acq_test(-2000, 0, [2], defaults.FORMAT_2BITS_X1_GPS_L1, 'low_rate') def test_normal_rate(): - run_acq_test(2000, 0, [3], '2bits', 'normal_rate') + run_acq_test(2000, 0, [3], defaults.FORMAT_2BITS_X1_GPS_L1, 'normal_rate') # Takes long time to complete in Travis CI test and # therefore fails -#def test_high_rate(): -# run_acq_test(2000, 0, [4], '2bits', 'high_rate') +# def test_high_rate(): +# run_acq_test(2000, 0, [4], defaults.FORMAT_2BITS_X1_GPS_L1, 'high_rate') diff --git a/tests/test_tracking.py b/tests/test_tracking.py index c1709a6..c58776e 100644 --- a/tests/test_tracking.py +++ b/tests/test_tracking.py @@ -10,13 +10,15 @@ # WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. from peregrine.gps_constants import l1, l2, L1CA, L2C +from peregrine.glo_constants import GLO_L1 from test_common import generate_sample_file, fileformat_to_bands,\ - get_skip_params, run_peregrine + get_skip_params, run_peregrine from test_acquisition import get_acq_result_file_name from peregrine.analysis import tracking_loop from peregrine.tracking import TrackingLoop, NavBitSync, NavBitSyncSBAS,\ - NBSLibSwiftNav, NBSSBAS, NBSMatchBit,\ - NBSHistogram, NBSMatchEdge + NBSLibSwiftNav, NBSSBAS, NBSMatchBit,\ + NBSHistogram, NBSMatchEdge +from peregrine import defaults import cPickle import csv @@ -30,15 +32,15 @@ def run_tracking_loop(prn, signal, dopp, phase, file_name, file_format, freq_profile, skip_val, norun=False, l2chandover=False, pipelining=None, short_long_cycles=None): parameters = [ - 'tracking_loop', - '-P', str(prn), - '-p', str(phase), - '-d', str(dopp), - '-S', signal, - '--file', file_name, - '--file-format', file_format, - '--profile', freq_profile, - '--skip-samples', str(skip_val) + 'tracking_loop', + '-P', str(prn), + '-p', str(phase), + '-d', str(dopp), + '-S', signal, + '--file', file_name, + '--file-format', file_format, + '--profile', freq_profile, + '--skip-samples', str(skip_val) ] if pipelining: @@ -61,17 +63,17 @@ def run_tracking_loop(prn, signal, dopp, phase, file_name, file_format, def get_track_result_file_name(sample_file, prn, band): sample_file, sample_file_extension = os.path.splitext(sample_file) return (sample_file + (".PRN-%d.%s" % (prn, band)) + - sample_file_extension + '.track_results', - "track.PRN-%d.%s.csv" % (prn, band)) + sample_file_extension + '.track_results', + "track.PRN-%d.%s.csv" % (prn, band)) def get_peregrine_tr_res_file_name(sample_file, prn, band): - per_fn, tr_loop_fn = get_track_result_file_name(sample_file, prn, band) + per_fn, _ = get_track_result_file_name(sample_file, prn, band) return per_fn def get_tr_loop_res_file_name(sample_file, prn, band): - per_fn, tr_loop_fn = get_track_result_file_name(sample_file, prn, band) + _, tr_loop_fn = get_track_result_file_name(sample_file, prn, band) return tr_loop_fn @@ -97,9 +99,9 @@ def run_track_test(samples_file, expected_lock_ratio, init_doppler, pipelining=pipelining, short_long_cycles=short_long_cycles) - #code_phase = propagate_code_phase(init_code_phase, - #get_sampling_freq(freq_profile), - #skip_param, skip_val) + # code_phase = propagate_code_phase(init_code_phase, + # get_sampling_freq(freq_profile), + # skip_param, skip_val) check_per_track_results(expected_lock_ratio, samples_file, prn, bands, pipelining, short_long_cycles) @@ -126,7 +128,10 @@ def check_per_track_results(expected_lock_ratio, filename, prn, bands, while True: try: track_results = cPickle.load(f) - assert (track_results.prn + 1) == prn + if band == L1CA or band == L2C: + assert (track_results.prn + 1) == prn + else: + assert (track_results.prn) == prn assert track_results.status == 'T' assert track_results == track_results lock_detect_outp_sum += (track_results.lock_detect_outp == 1).sum() @@ -167,7 +172,7 @@ def check_tr_loop_track(expected_lock_ratio, filename, prn, bands, return ret -def test_tracking(): +def test_tracking_gps(): """ Test GPS L1C/A and L2C tracking """ @@ -175,7 +180,7 @@ def test_tracking(): prn = 1 init_doppler = 555 init_code_phase = 0 - file_format = '2bits_x2' + file_format = defaults.FORMAT_2BITS_X2_GPS_L1L2 freq_profile = 'low_rate' samples = generate_sample_file(prn, init_doppler, @@ -183,16 +188,16 @@ def test_tracking(): file_format, freq_profile, generate=5) run_track_test(samples, 0.6, init_doppler, init_code_phase, prn, file_format, - freq_profile) + freq_profile) run_track_test(samples, 0.3, init_doppler, init_code_phase, prn, file_format, - freq_profile, pipelining=0.5) + freq_profile, pipelining=0.5) run_track_test(samples, 0.3, init_doppler, init_code_phase, prn, file_format, - freq_profile, short_long_cycles=0.5) + freq_profile, short_long_cycles=0.5) os.remove(samples) # test --no-run - run_tracking_loop(1, L1CA, 0, 0, 'dummy', '2bits_x2', 'low_rate', 0, + run_tracking_loop(1, L1CA, 0, 0, 'dummy', file_format, 'low_rate', 0, norun=True) # Test with different initial code phases @@ -233,5 +238,35 @@ def test_tracking(): assert NBSMatchEdge() +def test_tracking_glo(): + """ + Test GLO L1 tracking + """ + + prn = 0 + init_doppler = 555 + init_code_phase = 0 + file_format = defaults.FORMAT_2BITS_X1_GLO_L1 + freq_profile = 'low_rate' + + samples = generate_sample_file(prn, init_doppler, + init_code_phase, + file_format, freq_profile, generate=5) + + run_track_test(samples, 0.6, init_doppler, init_code_phase, prn, file_format, + freq_profile) + run_track_test(samples, 0.3, init_doppler, init_code_phase, prn, file_format, + freq_profile, pipelining=0.5) + run_track_test(samples, 0.3, init_doppler, init_code_phase, prn, file_format, + freq_profile, short_long_cycles=0.5) + + os.remove(samples) + + # test --no-run + run_tracking_loop(0, GLO_L1, 0, 0, 'dummy', file_format, 'low_rate', 0, + norun=True) + + if __name__ == '__main__': - test_tracking() + test_tracking_gps() + test_tracking_glo() From 75d3709c035b127c0660a1c1960e5103eb70684a Mon Sep 17 00:00:00 2001 From: Tommi Paakki Date: Thu, 14 Jul 2016 17:48:50 +0300 Subject: [PATCH 13/61] Add script for computing controlled-root parameters --- peregrine/include/controlled_root.py | 110 +++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 peregrine/include/controlled_root.py diff --git a/peregrine/include/controlled_root.py b/peregrine/include/controlled_root.py new file mode 100644 index 0000000..412678c --- /dev/null +++ b/peregrine/include/controlled_root.py @@ -0,0 +1,110 @@ +# -*- coding: utf-8 -*- +""" +Created on Thu Jul 14 14:29:34 2016 + +@author: tpaakki + +This script generates controlled-root loop parameters, based on +"Stephens, S. A., and J. C. Thomas, "Controlled-Root Formulation for +Digital Phase-Locked Loops," IEEE Trans. on Aerospace and Electronics + Systems, January 1995" + +""" +from math import factorial, exp +import cmath + +def controlled_root(N, T, BW): + # Input Parameters + # N [-] Loop Order + # T [s] Integration Time + # BW [Hz] Loop Bandwidth + # Output Parameters + # K [-] Loop constants + + K = [] + tol = 1.e-6 # Error tolerance + goal = BW*T # This is the BLT we want to solve + + # Few precomputed factorial parameters + if N > 1: + fac1 = factorial(N)/(factorial(1)*factorial(N-1)) + if N > 2: + fac2 = factorial(N)/(factorial(2)*factorial(N-2)) + fac3 = factorial(N-1)/(factorial(1)*factorial(N-1-1)) + fac4 = factorial(N-2)/(factorial(1)*factorial(N-2-1)) + + beta = 0.5 + step = 0.25 + done = True + ii = 1 + if N == 1: + while done: + z1 = exp(-beta) + K1 = 1.-z1 + blt = K1/(2.*(2.-K1)) + err = goal-blt + if abs(err) <= tol: + K = [K1] + done = False + if err > 0.: + beta = beta + step + step = step / 2. + if err < 0.: + beta = beta - step + step = step / 2. + if ii > 30: + 'Error - did not converge' + done = False + ii = ii + 1; + if N == 2: + while done: + z1 = cmath.exp(-beta*(1.+1.j)) + z2 = cmath.exp(-beta*(1.-1.j)) + K1 = 1.-z1*z2 + K1 = K1.real + K2 = fac1-K1-z1-z2 + K2 = K2.real + blt = (2.*K1*K1+2.*K2+K1*K2)/(2.*K1*(4.-2*K1-K2)) + err = goal-blt + if abs(err) <= tol: + K = K1, K2 + done = False + if err > 0.: + beta = beta + step + step = step / 2. + if err < 0.: + beta = beta - step + step = step / 2. + if ii > 30: + 'Error - did not converge' + done = False + ii = ii + 1; + if N == 3: + while done: + z1 = exp(-beta) + z2 = cmath.exp(-beta*(1.+1.j)) + z3 = cmath.exp(-beta*(1.-1.j)) + K1 = 1-z1*z2*z3 + K1 = K1.real + summ = z1*z2+z1*z3+z2*z3; + K2 = (fac2-fac3*K1-summ)/fac4 + K2 = K2.real + K3 = fac1-K1-K2-z1-z2-z3 + K3 = K3.real + blt = (4.*K1*K1*K2-4.*K1*K3+4.*K2*K2+2.*K1*K2*K2+4.*K1*K1*K3+4.*K2*K3+3*K1*K2*K3+K3*K3+K1*K3*K3)/(2.*(K1*K2-K3+K1*K3)*(8.-4.*K1-2.*K2-K3)) + err = goal-blt + if abs(err) <= tol: + K = K1, K2, K3 + done = False + if err > 0.: + beta = beta + step + step = step / 2. + if err < 0.: + beta = beta - step + step = step / 2. + if ii > 30: + 'Error - did not converge' + done = False + ii = ii + 1; + + return K From 1fa8ff496cca443e6e46711113636e3228e6149a Mon Sep 17 00:00:00 2001 From: Tommi Paakki Date: Thu, 14 Jul 2016 18:17:55 +0300 Subject: [PATCH 14/61] Added comments --- peregrine/include/controlled_root.py | 186 ++++++++++++++------------- 1 file changed, 94 insertions(+), 92 deletions(-) diff --git a/peregrine/include/controlled_root.py b/peregrine/include/controlled_root.py index 412678c..466a5e2 100644 --- a/peregrine/include/controlled_root.py +++ b/peregrine/include/controlled_root.py @@ -14,97 +14,99 @@ import cmath def controlled_root(N, T, BW): - # Input Parameters - # N [-] Loop Order - # T [s] Integration Time - # BW [Hz] Loop Bandwidth - # Output Parameters - # K [-] Loop constants + # Input Parameters + # N [-] Loop Order + # T [s] Integration Time + # BW [Hz] Loop Bandwidth + # Output Parameters + # K [-] Loop constants - K = [] - tol = 1.e-6 # Error tolerance - goal = BW*T # This is the BLT we want to solve - - # Few precomputed factorial parameters - if N > 1: - fac1 = factorial(N)/(factorial(1)*factorial(N-1)) - if N > 2: - fac2 = factorial(N)/(factorial(2)*factorial(N-2)) - fac3 = factorial(N-1)/(factorial(1)*factorial(N-1-1)) - fac4 = factorial(N-2)/(factorial(1)*factorial(N-2-1)) - - beta = 0.5 - step = 0.25 - done = True - ii = 1 - if N == 1: - while done: - z1 = exp(-beta) - K1 = 1.-z1 - blt = K1/(2.*(2.-K1)) - err = goal-blt - if abs(err) <= tol: - K = [K1] - done = False - if err > 0.: - beta = beta + step - step = step / 2. - if err < 0.: - beta = beta - step - step = step / 2. - if ii > 30: - 'Error - did not converge' - done = False - ii = ii + 1; - if N == 2: - while done: - z1 = cmath.exp(-beta*(1.+1.j)) - z2 = cmath.exp(-beta*(1.-1.j)) - K1 = 1.-z1*z2 - K1 = K1.real - K2 = fac1-K1-z1-z2 - K2 = K2.real - blt = (2.*K1*K1+2.*K2+K1*K2)/(2.*K1*(4.-2*K1-K2)) - err = goal-blt - if abs(err) <= tol: - K = K1, K2 - done = False - if err > 0.: - beta = beta + step - step = step / 2. - if err < 0.: - beta = beta - step - step = step / 2. - if ii > 30: - 'Error - did not converge' - done = False - ii = ii + 1; - if N == 3: - while done: - z1 = exp(-beta) - z2 = cmath.exp(-beta*(1.+1.j)) - z3 = cmath.exp(-beta*(1.-1.j)) - K1 = 1-z1*z2*z3 - K1 = K1.real - summ = z1*z2+z1*z3+z2*z3; - K2 = (fac2-fac3*K1-summ)/fac4 - K2 = K2.real - K3 = fac1-K1-K2-z1-z2-z3 - K3 = K3.real - blt = (4.*K1*K1*K2-4.*K1*K3+4.*K2*K2+2.*K1*K2*K2+4.*K1*K1*K3+4.*K2*K3+3*K1*K2*K3+K3*K3+K1*K3*K3)/(2.*(K1*K2-K3+K1*K3)*(8.-4.*K1-2.*K2-K3)) - err = goal-blt - if abs(err) <= tol: - K = K1, K2, K3 - done = False - if err > 0.: - beta = beta + step - step = step / 2. - if err < 0.: - beta = beta - step - step = step / 2. - if ii > 30: - 'Error - did not converge' - done = False - ii = ii + 1; + K = [] + tol = 1.e-6 # Error tolerance + goal = BW*T # This is the BLT we want to solve - return K + # Few precomputed factorial parameters + if N > 1: + fac1 = factorial(N)/(factorial(1)*factorial(N-1)) # eq.(45) + if N > 2: + fac2 = factorial(N)/(factorial(2)*factorial(N-2)) # eq.(46) + fac3 = factorial(N-1)/(factorial(1)*factorial(N-1-1)) # eq.(46) + fac4 = factorial(N-2)/(factorial(1)*factorial(N-2-1)) # eq.(46) + + beta = 0.5 + step = 0.25 + done = True + ii = 1 + if N == 1: + while done: + z1 = exp(-beta) # eq.(50) + K1 = 1.-z1 # eq.(49) + blt = K1/(2.*(2.-K1)) # Table IV + err = goal-blt + if abs(err) <= tol: + K = [K1] + done = False + if err > 0.: + beta = beta + step + step = step / 2. + if err < 0.: + beta = beta - step + step = step / 2. + if ii > 30: + 'Error - did not converge' + done = False + ii = ii + 1; + if N == 2: + while done: + z1 = cmath.exp(-beta*(1.+1.j)) # eq.(50) + z2 = cmath.exp(-beta*(1.-1.j)) # eq.(50) + K1 = 1.-z1*z2 # eq.(49) + K1 = K1.real + K2 = fac1-K1-z1-z2 # eq.(45) + K2 = K2.real + blt = (2.*K1*K1+2.*K2+K1*K2)/(2.*K1*(4.-2*K1-K2)) # Table IV + err = goal-blt + if abs(err) <= tol: + K = K1, K2 + done = False + if err > 0.: + beta = beta + step + step = step / 2. + if err < 0.: + beta = beta - step + step = step / 2. + if ii > 30: + 'Error - did not converge' + done = False + ii = ii + 1; + if N == 3: + while done: + z1 = exp(-beta) # eq.(50) + z2 = cmath.exp(-beta*(1.+1.j)) # eq.(50) + z3 = cmath.exp(-beta*(1.-1.j)) # eq.(50) + K1 = 1-z1*z2*z3 # eq.(49) + K1 = K1.real + summ = z1*z2+z1*z3+z2*z3; + K2 = (fac2-fac3*K1-summ)/fac4 # eq.(46) + K2 = K2.real + K3 = fac1-K1-K2-z1-z2-z3 # eq.(45) + K3 = K3.real + blt = (4.*K1*K1*K2-4.*K1*K3+4.*K2*K2+2.*K1*K2*K2+4.*K1*K1*K3+4.*K2*K3 + +3*K1*K2*K3+K3*K3+K1*K3*K3)/(2.*(K1*K2-K3+K1*K3)*(8. + -4.*K1-2.*K2-K3)) # Table IV + err = goal-blt + if abs(err) <= tol: + K = K1, K2, K3 + done = False + if err > 0.: + beta = beta + step + step = step / 2. + if err < 0.: + beta = beta - step + step = step / 2. + if ii > 30: + 'Error - did not converge' + done = False + ii = ii + 1; + + return K From 407c77727febfd69fef5d2f1c90354bed67ff1c8 Mon Sep 17 00:00:00 2001 From: Perttu Salmela Date: Sun, 5 Jun 2016 20:44:33 +0300 Subject: [PATCH 15/61] Extend performance simulation scripts with L1CA band option --- peregrine/analysis/README-sim.txt | 20 ++- peregrine/analysis/plt_res.py | 56 +++++-- peregrine/analysis/run_sim.py | 233 +++++++++++++++++++++--------- 3 files changed, 220 insertions(+), 89 deletions(-) diff --git a/peregrine/analysis/README-sim.txt b/peregrine/analysis/README-sim.txt index c210db4..d62f87c 100644 --- a/peregrine/analysis/README-sim.txt +++ b/peregrine/analysis/README-sim.txt @@ -1,14 +1,14 @@ -Running L2C Performance Simulations +Running L1CA/L2C Performance Simulations =================================== Performance simulations are run with run_sim.py tool which invokes iqgen_main.py and tracking_loop.py. The tool stores all the simulation results (including commands -for generating iq data and tracking l2c signal) in json file. Data is always appended +for generating iq data and tracking l1ca/l2c signal) in json file. Data is always appended in given json file. Thereafter, results are illustrated with plt_res.py which reads data from json file. -The json file contains following data for each iqgen and L2C tracking run: +The json file contains following data for each iqgen and L1CA/L2C tracking run: { "acc": # Acceleration (L1CA Hz / s) "avgcn0": # Average of all tracker CN0 estimates @@ -18,9 +18,9 @@ The json file contains following data for each iqgen and L2C tracking run: "dopSigma3": # 3-sigma Doppler error (99.7% of errors is less than this) "duration": # Length of simulation in seconds "iqgencmd": # Command line for iqgen - "iqgencn0": # L2C CN0 reported by iqgen - "l2chip": # Initial L2C code phase reported by iqgen - "l2dop": # Initial L2C Doppler frequency reported by iqgen + "iqgencn0": # L1CA/L2C CN0 reported by iqgen + "l_chip": # Initial L1CA/L2C code phase reported by iqgen + "l_dop": # Initial L1CA/L2C Doppler frequency reported by iqgen "lockrate": # PLL lock rate "snr": # SNR argument for iqgen "stamp": # Wall clock time stamp of simulation run @@ -52,6 +52,13 @@ Performance data can be generated with following commands: $ ./plt_res.py -e -f result_3.json +Band selection +============== +By default simulation is run for L2C band. The L1CA is selected with command line option: +-b l1ca (--band) +FPGA delay control simulation option --short-long-cycles can be given for L1CA band simulation with option: +-s (--short-long-cycles) + Varying simulation parameters ============================= Changing values in the python file is as easy as value in configuration file @@ -89,3 +96,4 @@ Changing CN0 estimator of plt_res.py In plt_res.py there is a string which defines which CN0 estimate is used: CN0STRING="avgcn0" # CN0 from tracking #CN0STRING="iqgencn0" # CN0 from iqgen + diff --git a/peregrine/analysis/plt_res.py b/peregrine/analysis/plt_res.py index cc47c06..c4c4c47 100755 --- a/peregrine/analysis/plt_res.py +++ b/peregrine/analysis/plt_res.py @@ -16,9 +16,22 @@ import json import numpy import matplotlib.pyplot as plt +import peregrine.gps_constants -CN0STRING = "avgcn0" # CN0 from tracking -# CN0STRING="iqgencn0" # CN0 from iqgen + +class CfgClass: + + def __init__(self): + # self.CN0STRING = "avgcn0" # CN0 from tracking + self.CN0STRING = "iqgencn0" # CN0 from iqgen + self.BAND = "l2c" + + def isL1CA(self): + if "l1ca" == self.BAND: + return True + return False + +cfg = CfgClass() def sigmaFreqPlot(filename): @@ -30,7 +43,7 @@ def sigmaFreqPlot(filename): jsarray = json.loads(s) r = [] for j in jsarray: - r.append((j["dopSigma1"], j[CN0STRING])) + r.append((j["dopSigma1"], j[cfg.CN0STRING])) r = sorted(r, key=lambda x: x[1]) dopSigma1 = map(lambda x: x[0], r) @@ -40,6 +53,7 @@ def sigmaFreqPlot(filename): plt.plot(avgcn0, dopSigma1, 'o-') plt.xlabel('CN0') plt.ylabel('Doppler sigma-1 error (Hz)') + plt.grid(True) plt.show() @@ -52,7 +66,7 @@ def lockrateCn0Plot(filename): jsarray = json.loads(s) r = [] for j in jsarray: - r.append((j["lockrate"], j[CN0STRING])) + r.append((j["lockrate"], j[cfg.CN0STRING])) r = sorted(r, key=lambda x: x[1]) lockrate = map(lambda x: x[0], r) @@ -63,10 +77,14 @@ def lockrateCn0Plot(filename): plt.xlabel('CN0') plt.ylabel('PLL lock rate') #plt.scatter(avgcn0, lockrate) + plt.grid(True) plt.show() def dynamicAccPlot(filename, mode): + GRAV_G = 9.80665 # m/s^2 + HzToMps = (peregrine.gps_constants.c / peregrine.gps_constants.l1) + HzToG = HzToMps / GRAV_G fp = open(filename, "r") s = fp.read() fp.close() @@ -78,8 +96,8 @@ def dynamicAccPlot(filename, mode): maxCN0 = 0.0 r = [] for j in jsarray: - minCN0 = min(minCN0, j[CN0STRING]) - maxCN0 = max(maxCN0, j[CN0STRING]) + minCN0 = min(minCN0, j[cfg.CN0STRING]) + maxCN0 = max(maxCN0, j[cfg.CN0STRING]) #r.append( (float(j["acc"]),j[CN0STRING]) ) #accVecAll = map(lambda x:x[0], r) #cn0VecAll = map(lambda x:x[1], r) @@ -89,23 +107,28 @@ def dynamicAccPlot(filename, mode): fig = plt.figure() r = [] + if cfg.isL1CA(): + Tcoh = 0.005 # Integration time 5 ms + else: + Tcoh = 0.02 # Integration time 20 ms + for cn0bin in cn0Range: bestAcc = -1000.0 bestCN0 = 0 print "BIN", cn0bin, for j in jsarray: - cn0 = j[CN0STRING] + cn0 = j[cfg.CN0STRING] lockrate = j["lockrate"] doperr = j["dopSigma1"] - acc = float(j["acc"]) + acc = float(j["acc"]) * HzToG if cn0bin - 0.5 <= cn0 and cn0 < cn0bin + 0.5: if acc > bestAcc: if mode == "lockrate" and lockrate >= 0.68: bestAcc = acc bestCN0 = cn0 plt.plot(bestCN0, bestAcc, 'bo') - # 1/12T, Tcoh=20 ms - elif mode == "doperr" and doperr <= 1.0 / (12 * 0.02): + # 1/12T, Tcoh=20 ms, Tcoh=5 ms + elif mode == "doperr" and doperr <= 1.0 / (12 * Tcoh): bestAcc = acc bestCN0 = cn0 plt.plot(bestCN0, bestAcc, 'bo') @@ -122,12 +145,15 @@ def dynamicAccPlot(filename, mode): #plt.plot(cn0VecAll, accVecAll, 'bo') plt.plot(bestCN0, bestAcc, 'r.-') plt.xlabel('CN0') - plt.ylabel('Acceleration Hz/s') - plt.grid() + plt.ylabel('Acceleration (g)') + plt.grid(True) if mode == "lockrate": plt.title("PLL lock rate >= 0.68 (1-sigma)") elif mode == "doperr": - plt.title("Doppler 1-sigma error <= 1/(12*0.02) = 4.2 Hz") + if cfg.isL1CA(): + plt.title("Doppler 1-sigma error <= 1/(12*0.005) = 16.7 Hz") + else: + plt.title("Doppler 1-sigma error <= 1/(12*0.02) = 4.2 Hz") plt.show() @@ -147,8 +173,12 @@ def main(): parser.add_argument("-e", "--dyn-acc-dop", help="x-sigma Doppler error acceleration tolerance vs. CN0", action="store_true") + parser.add_argument("-b", "--band", + help="l1ca or l2c (default)") args = parser.parse_args() + if args.band: + cfg.BAND = args.band if args.lockrate: lockrateCn0Plot(args.filename) elif args.dyn_acc_lockrate: diff --git a/peregrine/analysis/run_sim.py b/peregrine/analysis/run_sim.py index 9929cb7..a5a6dc1 100755 --- a/peregrine/analysis/run_sim.py +++ b/peregrine/analysis/run_sim.py @@ -20,81 +20,153 @@ import peregrine.iqgen.bits.signals as signals import numpy as np -IQ_DATA = "iqdata.bin" -TRACK_DATA = "track_res" -TRACK_RES_DATA = "track_res.json" + +class CfgClass: + + def __init__(self): + self.IQ_DATA = "iqdata.bin" + self.TRACK_DATA = "track_res" + self.TRACK_RES_DATA = "track_res.json" + self.BAND = "l2c" # "l1ca" + self.fpgaSim = " " # "--short-long-cycles " + + def isL1CA(self): + if "l1ca" == self.BAND: + return True + return False + + def __str__(self): + s = "band:" + self.BAND + "\n" + s = s + "fpga delay control simulation: " + self.fpgaSim + return s + + +cfg = CfgClass() def runCmd(cmd): print cmd # Do not use shell=True for untrusted input! - out = subprocess.check_output(cmd, shell=True) + try: + out = subprocess.check_output(cmd, shell=True) + except subprocess.CalledProcessError as e: + # Peregrine exits with failure if acquisition fails. + # Therefore handle error case + print e.output + return e.output, False + print out - return out + return out, True def runIqGen(lens, snr, dop, acc): cmd = "python " + peregrinePath() + "/peregrine/iqgen/iqgen_main.py" - cmd = cmd + " --gps-sv 1 --encoder 1bit --bands l1ca+l2c --message-type crc --profile low_rate" + if cfg.isL1CA(): + cmd = cmd + " --gps-sv 1 --encoder 1bit --bands l1ca --message-type crc --profile low_rate" + else: + cmd = cmd + " --gps-sv 1 --encoder 1bit --bands l1ca+l2c --message-type crc --profile low_rate" + if float(acc) != 0.0: cmd = cmd + " --doppler-type linear --doppler-speed " + acc + " " elif float(dop) != 0.0: cmd = cmd + " --doppler-type const " + dop + " " else: cmd = cmd + " --doppler-type zero " - cmd = cmd + " --snr " + snr + " --generate " + lens + " " - cmd = cmd + " --output " + IQ_DATA + " " - out = runCmd(cmd) + cmd = cmd + "--amplitude-type poly --amplitude-units snr-db --amplitude-a0 " + snr + cmd = cmd + " --generate " + lens + " " + + cmd = cmd + " --output " + cfg.IQ_DATA + " " + out, success = runCmd(cmd) + if not success: + print "iqgen failed" + sys.exit(1) + lines = out.split('\n') cn0 = None - l2dop = None - l2chip = None + l_dop = None + l_chip = None for ln in lines: words = ln.split() if len(words) == 0: continue - if words[0] == ".L2": - cn0 = words[2] - if words[0] == ".l2_doppler:": - l2dop = words[1] - if words[0] == ".l2_chip:": - l2chip = words[1] + if cfg.isL1CA(): + if words[0] == ".l1": + cn0 = words[2] + if words[0] == ".l1_doppler:": + l_dop = words[1] + if words[0] == ".l1_chip:": + l_chip = words[1] + else: + if words[0] == ".l2": + cn0 = words[2] + if words[0] == ".l2_doppler:": + l_dop = words[1] + if words[0] == ".l2_chip:": + l_chip = words[1] + if words[0] == ".SNR": if float(words[2]) != float(snr): print "snr unexpected" sys.exit(1) - if cn0 is None or l2dop is None or l2chip is None: + if cn0 is None or l_dop is None or l_chip is None: print "iqgen output parse error" sys.exit(1) - return lens, snr, l2dop, acc, l2chip, cn0, cmd + return lens, snr, l_dop, acc, l_chip, cn0, cmd def runTracker(dopp, cp, lens): - cmd = "python " + peregrinePath() + \ - "/peregrine/analysis/tracking_loop.py -f 1bit_x2 -P 1 --profile low_rate " - cmd = cmd + "-p " + cp + " -d " + dopp - cmd = cmd + " -o " + TRACK_DATA + " " - cmd = cmd + " -S l2c " - cmd = cmd + IQ_DATA + " " - out = runCmd(cmd) + if cfg.isL1CA(): + cmd = "python " + peregrinePath() + \ + "/peregrine/analysis/tracking_loop.py -f 1bit -P 1 --profile low_rate --l1ca-profile med --ms-to-process -1 " + # "--short-long-cycles " tracking loop corrections are taken in use in FPGA with a delay of 1 ms + cmd = cmd + cfg.fpgaSim + cmd = cmd + "-p " + cp + " -d " + dopp + cmd = cmd + " -o " + cfg.TRACK_DATA + " " + cmd = cmd + " -S l1ca " + cmd = cmd + " --file " + cfg.IQ_DATA + " " + + else: + cmd = "python " + peregrinePath() + \ + "/peregrine/analysis/tracking_loop.py -f 1bit_x2 -P 1 --profile low_rate --ms-to-process -1 " + cmd = cmd + "-p " + cp + " -d " + dopp + cmd = cmd + " -o " + cfg.TRACK_DATA + " " + cmd = cmd + " -S l2c " + cmd = cmd + " --file " + cfg.IQ_DATA + " " + + out, success = runCmd(cmd) lines = out.split('\n') + # This is usefull if acquisition is run instead of + # running tracking_loop.py directly + if not success: + for ln in lines: + if ln.find("No satellites acquired"): + # Acceptable failure + return cmd, False + # Unacceptable failure + print "Acquisition/tracking failed unexpectedly" + sys.exit(1) + durationOk = False for ln in lines: words = ln.split() if len(words) == 0: continue if words[0] == "Time" and words[1] == "to" and words[2] == "process": - if int(words[4]) / 1000 == int(lens): + if round(float(words[4])) == int(lens): durationOk = True if not durationOk: print "Data duration mismatch" sys.exit(1) - return cmd + return cmd, True def processTrackResults(acc): - data = np.genfromtxt(TRACK_DATA + ".PRN-1.l2c", - dtype=float, delimiter=',', names=True) + if cfg.isL1CA(): + data = np.genfromtxt(cfg.TRACK_DATA + ".PRN-1.l1ca", + dtype=float, delimiter=',', names=True) + else: + data = np.genfromtxt(cfg.TRACK_DATA + ".PRN-1.l2c", + dtype=float, delimiter=',', names=True) CN0 = data['CN0'] dopp = data['carr_doppler'] lock = data['lock_detect_outp'] @@ -105,10 +177,15 @@ def processTrackResults(acc): lockRate = np.sum(lock) / nsamples dopErr = np.ndarray(shape=(1, len(dopp)), dtype=float) - i = np.linspace(1, len(dopp), len(dopp), dtype=float) - # Doppler - (i * 20 ms * acc Hz/s * L2/L1 Hz relation) - dopErr = np.abs(dopp - i * 0.02 * acc * - (signals.GPS.L2C.CENTER_FREQUENCY_HZ / signals.GPS.L1CA.CENTER_FREQUENCY_HZ)) + + if cfg.isL1CA(): + ms_tracked = data['ms_tracked'] + dopErr = np.abs(dopp - ms_tracked / 1000.0 * acc) + else: + i = np.linspace(1, len(dopp), len(dopp), dtype=float) + # Doppler - (i * 20 ms * acc Hz/s * L2/L1 Hz relation) + dopErr = np.abs(dopp - i * 0.02 * acc * + (signals.GPS.L2C.CENTER_FREQUENCY_HZ / signals.GPS.L1CA.CENTER_FREQUENCY_HZ)) maxDopErr = np.max(dopErr) sortedDopErr = np.sort(dopErr) ix1 = int(0.5 + 0.6827 * (len(sortedDopErr) - 1)) @@ -126,33 +203,35 @@ def produce(lens, snr, dop, acc): snr = str(float(snr)) dop = str(float(dop)) acc = str(float(acc)) - lens, snr, l2dop, acc, l2chip, cn0, iqgenCmd = runIqGen(lens, snr, dop, acc) - trackerCmd = runTracker(l2dop, l2chip, lens) - avgCN0, lockRate, dopSigma1, dopSigma2, dopSigma3, maxDopErr = processTrackResults( - acc) - fpout = open(TRACK_RES_DATA, "a") - d = datetime.datetime(2000, 1, 1) - js = json.dumps({"stamp": d.utcnow().isoformat(), - "snr": snr, - "duration": float(lens), - "iqgencn0": float(cn0), - "l2dop": float(l2dop), - "l2chip": float(l2chip), - "acc": float(acc), - "avgcn0": avgCN0, - "lockrate": lockRate, - "dopSigma1": dopSigma1, - "dopSigma2": dopSigma2, - "dopSigma3": dopSigma3, - "dopMaxErr": maxDopErr, - "iqgencmd": iqgenCmd, - "trackcmd": trackerCmd}, - sort_keys=True, indent=4, separators=(',', ': ')) - print js - fpout.write(js + ',') - fpout.close() - - return lockRate, dopSigma1, dopSigma2 + lens, snr, l_dop, acc, l_chip, cn0, iqgenCmd = runIqGen(lens, snr, dop, acc) + trackerCmd, trackSuccess = runTracker(l_dop, l_chip, lens) + if trackSuccess: + avgCN0, lockRate, dopSigma1, dopSigma2, dopSigma3, maxDopErr = processTrackResults( + acc) + fpout = open(cfg.TRACK_RES_DATA, "a") + d = datetime.datetime(2000, 1, 1) + js = json.dumps({"stamp": d.utcnow().isoformat(), + "snr": snr, + "duration": float(lens), + "iqgencn0": float(cn0), + "l_dop": float(l_dop), + "l_chip": float(l_chip), + "acc": float(acc), + "avgcn0": avgCN0, + "lockrate": lockRate, + "dopSigma1": dopSigma1, + "dopSigma2": dopSigma2, + "dopSigma3": dopSigma3, + "dopMaxErr": maxDopErr, + "iqgencmd": iqgenCmd, + "trackcmd": trackerCmd}, + sort_keys=True, indent=4, separators=(',', ': ')) + print js + fpout.write(js + ',') + fpout.close() + return lockRate, dopSigma1, dopSigma2, trackSuccess + else: + return 0, 0, 0, trackSuccess def runCn0Range(): @@ -161,7 +240,7 @@ def runCn0Range(): doppler = 0 # Hz acceleration = 0.0 # Hz / s for snr in snrRng: - lockRate, dopSigma1, dopSigma2 = produce( + lockRate, dopSigma1, dopSigma2, success = produce( length, snr / 10.0, doppler, acceleration) @@ -188,10 +267,10 @@ def runDynamicLockRate(): bestLockRate = lockRate bestAcc = acc - lockRate, dopSigma1, dopSigma2 = produce( + lockRate, dopSigma1, dopSigma2, success = produce( length, snr / 10.0, doppler, acc) print "SNR", snr / 10.0, "ACC", acc, "LOCKRATE", lockRate - if lockRate >= lockRateThreshold: + if lockRate >= lockRateThreshold and success: acc = acc + accStep else: print "BEST ACC", bestAcc, "LOCKRATE", bestLockRate @@ -205,7 +284,12 @@ def runDynamicFreq(): # Must run from low CN0 to high CN0 doppler = 0 # Hz accStep = 10 # Size of single acceleration step (L1CA Hz/s) - freqErrThreshold = 1.0 / (12 * 0.02) # 1/12T, Tcoh=20 ms. Failure threshold. + if cfg.isL1CA(): + # 1/12T, Tcoh=5 ms. Failure threshold. + freqErrThreshold = 1.0 / (12 * 0.005) + else: + # 1/12T, Tcoh=20 ms. Failure threshold. + freqErrThreshold = 1.0 / (12 * 0.02) # When it is reached, the next CN0 bin is tried freqErr = 0.0 # 1-sigma @@ -220,11 +304,11 @@ def runDynamicFreq(): bestFreqErr = freqErr bestAcc = acc - lockRate, dopSigma1, dopSigma2 = produce( + lockRate, dopSigma1, dopSigma2, trackSuccess = produce( length, snr / 10.0, doppler, acc) freqErr = dopSigma1 print "SNR", snr / 10.0, "ACC", acc, "1-SIGMA", freqErr - if freqErr <= freqErrThreshold: + if freqErr <= freqErrThreshold and trackSuccess: acc = acc + accStep else: print "BEST ACC", bestAcc, "1-SIGMA", bestFreqErr @@ -237,23 +321,32 @@ def peregrinePath(): def main(): - global TRACK_RES_DATA parser = argparse.ArgumentParser() parser.add_argument("-l", "--lockrate", help="Simple lockrate vs. CN0", action="store_true") parser.add_argument("-f", "--filename", - help="Output file which is appended. Default " + TRACK_RES_DATA) + help="Output file which is appended. Default " + cfg.TRACK_RES_DATA) parser.add_argument("-d", "--dyn-lockrate", help="Lockrate, acceleration, CN0", action="store_true") parser.add_argument("-e", "--dyn-freq", help="Fequency error, acceleration, CN0", action="store_true") + parser.add_argument("-b", "--band", + help="l1ca or l2c (default)") + parser.add_argument("-s", "--short-long-cycles", + help="FPGA delay control simulation", + action="store_true") args = parser.parse_args() if args.filename: - TRACK_RES_DATA = args.filename + cfg.TRACK_RES_DATA = args.filename + if args.band: + cfg.BAND = args.band + if args.short_long_cycles: + cfg.fpgaSim = "--short-long-cycles " + if args.lockrate: runCn0Range() elif args.dyn_lockrate: From 1e153b906afcf8757784b1b83e06951561966803 Mon Sep 17 00:00:00 2001 From: Adel Mamin Date: Wed, 13 Jul 2016 17:40:02 +0300 Subject: [PATCH 16/61] Add 3rd order loop PLL --- peregrine/analysis/plt_res.py | 7 +- peregrine/analysis/run_sim.py | 15 +-- peregrine/analysis/tracking_loop.py | 4 +- peregrine/defaults.py | 34 +++--- peregrine/tracking_loop.py | 165 ++++++++++++++++++++++++++++ 5 files changed, 198 insertions(+), 27 deletions(-) create mode 100644 peregrine/tracking_loop.py diff --git a/peregrine/analysis/plt_res.py b/peregrine/analysis/plt_res.py index c4c4c47..f16aa2a 100755 --- a/peregrine/analysis/plt_res.py +++ b/peregrine/analysis/plt_res.py @@ -14,7 +14,7 @@ import sys import argparse import json -import numpy +import numpy as np import matplotlib.pyplot as plt import peregrine.gps_constants @@ -72,8 +72,11 @@ def lockrateCn0Plot(filename): lockrate = map(lambda x: x[0], r) avgcn0 = map(lambda x: x[1], r) + x, y = zip(*sorted((xVal, np.mean([yVal for a, yVal in zip(avgcn0, lockrate) if xVal==a])) for xVal in set(avgcn0))) + fig = plt.figure() - plt.plot(avgcn0, lockrate, 'o-') + plt.plot(avgcn0, lockrate, 'o') + plt.plot(x, y, '-') plt.xlabel('CN0') plt.ylabel('PLL lock rate') #plt.scatter(avgcn0, lockrate) diff --git a/peregrine/analysis/run_sim.py b/peregrine/analysis/run_sim.py index a5a6dc1..4fb6d02 100755 --- a/peregrine/analysis/run_sim.py +++ b/peregrine/analysis/run_sim.py @@ -27,8 +27,9 @@ def __init__(self): self.IQ_DATA = "iqdata.bin" self.TRACK_DATA = "track_res" self.TRACK_RES_DATA = "track_res.json" - self.BAND = "l2c" # "l1ca" - self.fpgaSim = " " # "--short-long-cycles " + self.BAND = 'l1ca' # "l2c" + #self.fpgaSim = " " # "--short-long-cycles " + self.fpgaSim = "--short-long-cycles " def isL1CA(self): if "l1ca" == self.BAND: @@ -62,9 +63,9 @@ def runCmd(cmd): def runIqGen(lens, snr, dop, acc): cmd = "python " + peregrinePath() + "/peregrine/iqgen/iqgen_main.py" if cfg.isL1CA(): - cmd = cmd + " --gps-sv 1 --encoder 1bit --bands l1ca --message-type crc --profile low_rate" + cmd = cmd + " --gps-sv 1 --encoder 1bit --bands l1ca --message-type zero+one --profile low_rate" else: - cmd = cmd + " --gps-sv 1 --encoder 1bit --bands l1ca+l2c --message-type crc --profile low_rate" + cmd = cmd + " --gps-sv 1 --encoder 1bit --bands l1ca+l2c --message-type zero+one --profile low_rate" if float(acc) != 0.0: cmd = cmd + " --doppler-type linear --doppler-speed " + acc + " " @@ -117,7 +118,7 @@ def runIqGen(lens, snr, dop, acc): def runTracker(dopp, cp, lens): if cfg.isL1CA(): cmd = "python " + peregrinePath() + \ - "/peregrine/analysis/tracking_loop.py -f 1bit -P 1 --profile low_rate --l1ca-profile med --ms-to-process -1 " + "/peregrine/analysis/tracking_loop.py -f 1bit -P 1 --profile low_rate --l1ca-profile med " # "--short-long-cycles " tracking loop corrections are taken in use in FPGA with a delay of 1 ms cmd = cmd + cfg.fpgaSim cmd = cmd + "-p " + cp + " -d " + dopp @@ -170,11 +171,11 @@ def processTrackResults(acc): CN0 = data['CN0'] dopp = data['carr_doppler'] lock = data['lock_detect_outp'] - nsamples = len(CN0) + coherent_ms = data['coherent_ms'] acc = float(acc) avgCN0 = np.mean(CN0) - lockRate = np.sum(lock) / nsamples + lockRate = np.sum([a * b for a, b in zip(lock, coherent_ms)]) / np.sum(coherent_ms) dopErr = np.ndarray(shape=(1, len(dopp)), dtype=float) diff --git a/peregrine/analysis/tracking_loop.py b/peregrine/analysis/tracking_loop.py index e639679..67d1f5e 100755 --- a/peregrine/analysis/tracking_loop.py +++ b/peregrine/analysis/tracking_loop.py @@ -20,6 +20,7 @@ from peregrine.gps_constants import L1CA, L2C from peregrine.glo_constants import GLO_L1, GLO_L2, glo_l1_step, glo_l2_step from peregrine.run import populate_peregrine_cmd_line_arguments +from peregrine.tracking_loop import TrackingLoop3 def main(): @@ -181,7 +182,8 @@ def main(): stage2_loop_filter_params=stage2_params, tracker_options=tracker_options, output_file=args.output_file, - progress_bar_output=args.progress_bar) + progress_bar_output=args.progress_bar, + loop_filter_class=TrackingLoop3) tracker.start() condition = True while condition: diff --git a/peregrine/defaults.py b/peregrine/defaults.py index e02a8e9..d61f01a 100644 --- a/peregrine/defaults.py +++ b/peregrine/defaults.py @@ -201,7 +201,7 @@ "carr_bw": 13, # Carrier loop NBW "carr_zeta": 0.707, # Carrier loop zeta "carr_k": 1, # Carrier loop k - "carr_freq_b1": 5} # Carrier loop aiding_igain + "carr_freq_b1": 1} # Carrier loop aiding_igain # Tracking stages. See track.c for more details. @@ -211,15 +211,15 @@ 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k 'carr_params': (10., 0.7, 1.), # NBW, zeta, k 'loop_freq': 1000., # 1000/coherent_ms - 'carr_freq_igain': 5., # fll_aid + 'carr_freq_b1': 5., # fll_aid 'carr_to_code': 1540. # carr_to_code } }, {'coherent_ms': 20, 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k - 'carr_params': (12., 0.7, 1.), # NBW, zeta, k + 'carr_params': (2., 0.7, 1.), # NBW, zeta, k 'loop_freq': 1000. / 20, # 1000/coherent_ms - 'carr_freq_igain': 0., # fll_aid + 'carr_freq_b1': 0., # fll_aid 'carr_to_code': 1540. # carr_to_code } } @@ -230,7 +230,7 @@ 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k 'carr_params': (10., 0.7, 1.), # NBW, zeta, k 'loop_freq': 1000., # 1000/coherent_ms - 'carr_freq_igain': 5., # fll_aid + 'carr_freq_b1': 5., # fll_aid 'carr_to_code': 1540. # carr_to_code } }, @@ -238,7 +238,7 @@ 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k 'carr_params': (12., 0.7, 1.), # NBW, zeta, k 'loop_freq': 1000. / 10, # 1000/coherent_ms - 'carr_freq_igain': 0., # fll_aid + 'carr_freq_b1': 0., # fll_aid 'carr_to_code': 1540. # carr_to_code } } @@ -247,19 +247,19 @@ # 1;5 ms stages l1ca_stage_params_med = \ ({'coherent_ms': 1, - 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k - 'carr_params': (10., 0.7, 1.), # NBW, zeta, k + 'loop_filter_params': {'code_params': (5., 0.7, 1.), # NBW, zeta, k + 'carr_params': (13., 0.7, 1.), # NBW, zeta, k 'loop_freq': 1000., # 1000/coherent_ms - 'carr_freq_igain': 5., # fll_aid + 'carr_freq_b1': 1., # fll_aid 'carr_to_code': 1540. # carr_to_code } }, - {'coherent_ms': 5, + {'coherent_ms': 4, 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k - 'carr_params': (50., 0.7, 1.), # NBW, zeta, k - 'loop_freq': 1000. / 5, # 1000/coherent_ms - 'carr_freq_igain': 0., # fll_aid + 'carr_params': (2., 0.7, 1.), # NBW, zeta, k + 'loop_freq': 1000./4, # 1000/coherent_ms + 'carr_freq_b1': 1., # fll_aid 'carr_to_code': 1540. # carr_to_code } } @@ -271,7 +271,7 @@ 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k 'carr_params': (10., 0.7, 1.), # NBW, zeta, k 'loop_freq': 1000., # 1000/coherent_ms - 'carr_freq_igain': 5., # fll_aid + 'carr_freq_b1': 5., # fll_aid 'carr_to_code': 1540. # carr_to_code } }, @@ -279,7 +279,7 @@ 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k 'carr_params': (62., 0.7, 1.), # NBW, zeta, k 'loop_freq': 1000. / 4, # 1000/coherent_ms - 'carr_freq_igain': 0., # fll_aid + 'carr_freq_b1': 0., # fll_aid 'carr_to_code': 1540. # carr_to_code } } @@ -291,7 +291,7 @@ 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k 'carr_params': (10., 0.7, 1.), # NBW, zeta, k 'loop_freq': 1000., # 1000/coherent_ms - 'carr_freq_igain': 5., # fll_aid + 'carr_freq_b1': 5., # fll_aid 'carr_to_code': 1540. # carr_to_code } }, @@ -299,7 +299,7 @@ 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k 'carr_params': (100., 0.7, 1.), # NBW, zeta, k 'loop_freq': 1000. / 2, # 1000/coherent_ms - 'carr_freq_igain': 0., # fll_aid + 'carr_freq_b1': 0., # fll_aid 'carr_to_code': 1540. # carr_to_code } } diff --git a/peregrine/tracking_loop.py b/peregrine/tracking_loop.py new file mode 100644 index 0000000..5af2eec --- /dev/null +++ b/peregrine/tracking_loop.py @@ -0,0 +1,165 @@ +# Copyright (C) 2016 Swift Navigation Inc. +# Contact: Adel Mamin +# +# This source is subject to the license found in the file 'LICENSE' which must +# be be distributed together with this source. All other rights reserved. +# +# THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, +# EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. + +import numpy as np + +def costas_discriminator(I, Q): + if I == 0: + # Technically, it should be +/- 0.25, but then we'd have to keep track + # of the previous sign do it right, so it's simple enough to just return + # the average of 0.25 and -0.25 in the face of that ambiguity, so zero. + return 0 + + return np.arctan(Q / I) / (2 * np.pi) + +def frequency_discriminator(I, Q, prev_I, prev_Q): + dot = np.absolute(I * prev_I) + np.absolute(Q * prev_Q) + cross = prev_I * Q - I * prev_Q + return np.arctan2(cross, dot) / (2 * np.pi) + +def dll_discriminator(E, P, L): + E_mag = np.absolute(E) + L_mag = np.absolute(L) + + return 0.5 * (E_mag - L_mag) / (E_mag + L_mag) + +class TrackingLoop3: + """ + Third order tracking loop initialization. + + For a full description of the loop filter parameters, see + :libswiftnav:`calc_loop_gains`. + + """ + + def __init__(self, **kwargs): + # Initial state + self.carr_freq = kwargs['carr_freq'] + self.code_freq = kwargs['code_freq'] + + self.code_vel = kwargs['code_freq'] + self.phase_acc = 0 + self.phase_vel = kwargs['carr_freq'] + + self.P_prev = 1+0j + + self.retune( (kwargs['code_bw'], kwargs['code_zeta'], kwargs['code_k']), + (kwargs['carr_bw'], kwargs['carr_zeta'], kwargs['carr_k']), + kwargs['loop_freq'], + kwargs['carr_freq_b1'], + kwargs['carr_to_code'] ) + + def retune(self, code_params, carr_params, loop_freq, carr_freq_b1, carr_to_code): + """ + Retune the tracking loop. + + Parameters + ---------- + code_params : (float, float, float) + Code tracking loop parameter tuple, `(bw, zeta, k)`. + carr_params : (float, float, float) + Carrier tracking loop parameter tuple, `(bw, zeta, k)`. + loop_freq : float + The frequency with which loop updates are performed. + carr_freq_b1 : float + FLL aiding gain + carr_to_code : float + PLL to DLL aiding gain + + """ + code_bw, code_zeta, code_k = code_params + carr_bw, carr_zeta, carr_k = carr_params + + # Common parameters + self.T = 1 / loop_freq + + # FLL constants + freq_omega_0 = carr_freq_b1 / 0.53 + freq_a2 = 1.414 + + # a_2 * omega_0f + self.freq_c1 = freq_a2 * freq_omega_0 + self.freq_c2 = freq_omega_0 * freq_omega_0 + + # PLL constants + phase_omega_0 = carr_bw / 0.7845 + phase_a3 = 1.1 + phase_b3 = 2.4 + + self.phase_c1 = phase_b3 * phase_omega_0 + self.phase_c2 = phase_a3 * phase_omega_0 * phase_omega_0 + self.phase_c3 = phase_omega_0 * phase_omega_0 * phase_omega_0 + + # DLL constants + code_omega_0 = code_bw / 0.53 + code_a2 = 1.414 + + self.code_c1 = code_a2 * code_omega_0 + self.code_c2 = code_omega_0 * code_omega_0 + + self.carr_to_code = carr_to_code + + def update(self, E, P, L): + """ + Tracking loop update + + Parameters + ---------- + E : [complex], :math:`I_E + Q_E j` + Complex Early Correlation + P : [complex], :math:`I_P + Q_P j` + Complex Prompt Correlation + L : [complex], :math:`I_L + Q_L j` + Complex Late Correlation + + Returns + ------- + out : (float, float) + The tuple (code_freq, carrier_freq). + + """ + + # Carrier loop + phase_error = costas_discriminator(P.real, P.imag) + freq_error = 0 + if self.freq_c1 != 0: + freq_error = frequency_discriminator(P.real, P.imag, self.P_prev.real, self.P_prev.imag) / self.T + + self.P_prev = P + + prev = self.phase_acc + self.phase_acc += freq_error * self.freq_c2 * self.T + phase_error * self.phase_c3 * self.T + + sum = (self.phase_acc + prev) * 0.5 + sum += freq_error * self.freq_c1 + phase_error * self.phase_c2 + prev = self.phase_vel + self.phase_vel += sum * self.T + sum = (self.phase_vel + prev) * 0.5 + phase_error * self.phase_c1 + self.carr_freq = sum + + # Code loop + code_error = -dll_discriminator(E, P, L) + + prev = self.code_vel + self.code_vel += self.code_c2 * code_error * self.T + sum = (prev + self.code_vel) * 0.5 + self.code_c1 * code_error + + self.code_freq = sum + if self.carr_to_code > 0: + self.code_freq += self.carr_freq / self.carr_to_code + + return (self.code_freq, self.carr_freq) + + def adjust_freq(self, corr): + self.carr_freq += corr + + def to_dict(self): + return { k:v for k, v in self.__dict__.items() \ + if not (k.startswith('__') and k.endswith('__')) } From eff359d389bcded4e0b2bf60408a16e94c88134c Mon Sep 17 00:00:00 2001 From: Adel Mamin Date: Fri, 15 Jul 2016 12:23:04 +0300 Subject: [PATCH 17/61] Add MM CN0 estimator --- peregrine/analysis/run_sim.py | 4 +- peregrine/cn0.py | 118 ++++++++++++++++++++++++++++++++++ peregrine/defaults.py | 12 ++-- peregrine/tracking.py | 5 +- peregrine/tracking_loop.py | 4 ++ 5 files changed, 133 insertions(+), 10 deletions(-) create mode 100644 peregrine/cn0.py diff --git a/peregrine/analysis/run_sim.py b/peregrine/analysis/run_sim.py index 4fb6d02..c7c7984 100755 --- a/peregrine/analysis/run_sim.py +++ b/peregrine/analysis/run_sim.py @@ -236,8 +236,8 @@ def produce(lens, snr, dop, acc): def runCn0Range(): - length = 6 # Duration (s) - snrRng = range(-270, -350, -10) # SNR for iqgen command. Unit 0.1 dBHz + length = 30 # Duration (s) + snrRng = range(-200, -350, -10) # SNR for iqgen command. Unit 0.1 dBHz doppler = 0 # Hz acceleration = 0.0 # Hz / s for snr in snrRng: diff --git a/peregrine/cn0.py b/peregrine/cn0.py new file mode 100644 index 0000000..ca2fbd1 --- /dev/null +++ b/peregrine/cn0.py @@ -0,0 +1,118 @@ +# Copyright (C) 2016 Swift Navigation Inc. +# Contact: Adel Mamin +# +# This source is subject to the license found in the file 'LICENSE' which must +# be be distributed together with this source. All other rights reserved. +# +# THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, +# EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. + +import numpy as np + +# Multiplier for checking out-of bounds NSR +CN0_MM_NSR_MIN_MULTIPLIER = 1e-6 + +# Maximum supported NSR value (1/CN0_MM_NSR_MIN_MULTIPLIER) +CN0_MM_NSR_MIN = 1e6 + +CN0_MOVING_AVG_WINDOW_SIZE = 200 + +class CN0_Est_MM(object): + + def __init__(self, bw, cn0_0, cutoff_freq, loop_freq): + """ + Initialize the C/N0 estimator state. + + Initializes Moment method C/N0 estimator. + + The method uses the function for SNR computation: + + \frac{C}{N_0}(n) = \frac{P_d}{P_n}, + where P_n(n) = M2(n) - P_d(n), + where P_d(n) = \sqrt{2# M2(n)^2 - M4(n)}, + where + M2(n) = \frac{1}{2}(I(n)^2 + I(n-1)^2 + Q(n)^2 + Q(n-1)^2) + M4(n) = \frac{1}{2}(I(n)^4 + I(n-1)^4 + Q(n)^4 + Q(n-1)^4) + + Parameters + ---------- +\param s The estimator state struct to initialize. +\param p Common C/N0 estimator parameters. +\param cn0_0 The initial value of \f$ C / N_0 \f$ in dBHz. + +\return None + + Parameters + ---------- + coherent_ms : int + Coherent integration time [ms]. + + + """ + self.cn0_db = cn0_0 + self.M2_arr = np.ndarray(CN0_MOVING_AVG_WINDOW_SIZE, dtype=np.double) + self.M4_arr = np.ndarray(CN0_MOVING_AVG_WINDOW_SIZE, dtype=np.double) + self.index = 0 + self.log_bw = 10 * np.log10(loop_freq) + + + def _compute_cn0(self, M_2, M_4): + tmp = 2 * M_2 * M_2 - M_4 + + if tmp < 0: + snr = 1 / CN0_MM_NSR_MIN + else: + P_d = np.sqrt(tmp) + P_n = M_2 - P_d + + # Ensure the NSR is within the limit + if P_d < P_n * CN0_MM_NSR_MIN_MULTIPLIER: + return 60 + elif P_n == 0: + return 10 + else: + snr = P_d / P_n + + snr_db = 10 * np.log10(snr) + + # Compute CN0 + x= self.log_bw + snr_db + if x < 10: + return 10 + if x > 60: + return 60 + + return x + + + def _moving_average(self, arr, x): + if self.index < CN0_MOVING_AVG_WINDOW_SIZE: + arr[self.index] = x + return np.average(arr[:self.index + 1]) + else: + arr[:-1] = arr[1:] + arr[-1] = x + return np.average(arr) + + # Computes \f$ C / N_0 \f$ with Moment method. + # + # s Initialized estimator object. + # I In-phase signal component + # Q Quadrature phase signal component. + # + # Computed \f$ C / N_0 \f$ value + def update(self, I, Q): + m_2 = I * I + Q * Q + m_4 = m_2 * m_2 + + M_2 = self._moving_average(self.M2_arr, m_2) + M_4 = self._moving_average(self.M4_arr, m_4) + + if self.index < CN0_MOVING_AVG_WINDOW_SIZE: + self.index += 1 + + # Compute and store updated CN0 + self.cn0_db = self._compute_cn0(M_2, M_4) + + return self.cn0_db diff --git a/peregrine/defaults.py b/peregrine/defaults.py index d61f01a..470b597 100644 --- a/peregrine/defaults.py +++ b/peregrine/defaults.py @@ -247,19 +247,19 @@ # 1;5 ms stages l1ca_stage_params_med = \ ({'coherent_ms': 1, - 'loop_filter_params': {'code_params': (5., 0.7, 1.), # NBW, zeta, k - 'carr_params': (13., 0.7, 1.), # NBW, zeta, k + 'loop_filter_params': {'code_params': (3., 0.7, 1.), # NBW, zeta, k + 'carr_params': (15., 0.7, 1.), # NBW, zeta, k 'loop_freq': 1000., # 1000/coherent_ms - 'carr_freq_b1': 1., # fll_aid + 'carr_freq_b1': 5., # fll_aid 'carr_to_code': 1540. # carr_to_code } }, - {'coherent_ms': 4, + {'coherent_ms': 20, 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k - 'carr_params': (2., 0.7, 1.), # NBW, zeta, k + 'carr_params': (1., 0.7, 1.), # NBW, zeta, k 'loop_freq': 1000./4, # 1000/coherent_ms - 'carr_freq_b1': 1., # fll_aid + 'carr_freq_b1': 0, # fll_aid 'carr_to_code': 1540. # carr_to_code } } diff --git a/peregrine/tracking.py b/peregrine/tracking.py index 154797d..d8b2061 100644 --- a/peregrine/tracking.py +++ b/peregrine/tracking.py @@ -33,6 +33,7 @@ from peregrine.include.generateL2CMcode import L2CMCodes from peregrine.include.generateGLOcode import GLOCode from peregrine.tracking_file_utils import createTrackingOutputFileNames +from peregrine.cn0 import CN0_Est_MM import logging import sys @@ -177,7 +178,7 @@ def __init__(self, params): lp=self.lock_detect_params["lp"], lo=self.lock_detect_params["lo"]) - self.cn0_est = CN0Estimator( + self.cn0_est = CN0_Est_MM( bw=1e3 / self.coherent_ms, cn0_0=self.cn0_0, cutoff_freq=0.1, @@ -605,7 +606,7 @@ def _run_preprocess(self): k2=self.lock_detect_params["k2"], lp=self.lock_detect_params["lp"], lo=self.lock_detect_params["lo"]) - self.cn0_est = CN0Estimator(bw=1e3 / self.stage2_coherent_ms, + self.cn0_est = CN0_Est_MM(bw=1e3 / self.stage2_coherent_ms, cn0_0=self.track_result.cn0[self.i - 1], cutoff_freq=10, loop_freq=1e3 / self.stage2_coherent_ms) diff --git a/peregrine/tracking_loop.py b/peregrine/tracking_loop.py index 5af2eec..84f94a0 100644 --- a/peregrine/tracking_loop.py +++ b/peregrine/tracking_loop.py @@ -106,6 +106,10 @@ def retune(self, code_params, carr_params, loop_freq, carr_freq_b1, carr_to_code self.carr_to_code = carr_to_code + self.code_vel = 0 + self.phase_acc = 0 + self.phase_vel = 0 + def update(self, E, P, L): """ Tracking loop update From 1d6cd6b09b2aaa08e4b7a93b55974ac3dea94578 Mon Sep 17 00:00:00 2001 From: Adel Mamin Date: Fri, 15 Jul 2016 14:33:01 +0300 Subject: [PATCH 18/61] Adjusted to track with non-zero doppler --- peregrine/defaults.py | 6 +++--- peregrine/tracking_loop.py | 13 ++++++++++--- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/peregrine/defaults.py b/peregrine/defaults.py index 470b597..16038e2 100644 --- a/peregrine/defaults.py +++ b/peregrine/defaults.py @@ -187,7 +187,7 @@ "code_zeta": 0.7, # Code loop zeta "code_k": 1, # Code loop k "carr_to_code": 1540, # Carrier-to-code freq ratio (carrier aiding) - "carr_bw": 10, # Carrier loop NBW + "carr_bw": 15, # Carrier loop NBW "carr_zeta": 0.7, # Carrier loop zeta "carr_k": 1, # Carrier loop k "carr_freq_b1": 5} # Carrier loop aiding_igain @@ -257,8 +257,8 @@ {'coherent_ms': 20, 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k - 'carr_params': (1., 0.7, 1.), # NBW, zeta, k - 'loop_freq': 1000./4, # 1000/coherent_ms + 'carr_params': (15., 0.7, 1.), # NBW, zeta, k + 'loop_freq': 1000./20, # 1000/coherent_ms 'carr_freq_b1': 0, # fll_aid 'carr_to_code': 1540. # carr_to_code } diff --git a/peregrine/tracking_loop.py b/peregrine/tracking_loop.py index 84f94a0..7ba9eaa 100644 --- a/peregrine/tracking_loop.py +++ b/peregrine/tracking_loop.py @@ -9,6 +9,7 @@ # WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. import numpy as np +from peregrine.include.controlled_root import controlled_root def costas_discriminator(I, Q): if I == 0: @@ -96,6 +97,12 @@ def retune(self, code_params, carr_params, loop_freq, carr_freq_b1, carr_to_code self.phase_c1 = phase_b3 * phase_omega_0 self.phase_c2 = phase_a3 * phase_omega_0 * phase_omega_0 self.phase_c3 = phase_omega_0 * phase_omega_0 * phase_omega_0 + # self.phase_c1, self.phase_c2, self.phase_c3 = controlled_root(3, 1 / loop_freq, carr_bw) + # print "T = ", 1 / loop_freq, " BW = ", carr_bw + + # self.phase_c1 = 0.00013553072504812747 + # self.phase_c2 = 0.006445479093110773 + # self.phase_c3 = 0.11739536416734386 # DLL constants code_omega_0 = code_bw / 0.53 @@ -106,9 +113,9 @@ def retune(self, code_params, carr_params, loop_freq, carr_freq_b1, carr_to_code self.carr_to_code = carr_to_code - self.code_vel = 0 - self.phase_acc = 0 - self.phase_vel = 0 + # self.code_vel = 0 + # self.phase_acc = 0 + # self.phase_vel = 0 def update(self, E, P, L): """ From 58b2e912e72333f7fa4899f9726b65b177941b91 Mon Sep 17 00:00:00 2001 From: Adel Mamin Date: Mon, 18 Jul 2016 14:30:04 +0300 Subject: [PATCH 19/61] WIP --- peregrine/analysis/run_sim.py | 2 +- peregrine/analysis/tracking_loop.py | 6 +- peregrine/defaults.py | 39 +++- peregrine/tracking.py | 1 + peregrine/tracking_loop.py | 274 ++++++++++++++++++++++++++++ 5 files changed, 309 insertions(+), 13 deletions(-) diff --git a/peregrine/analysis/run_sim.py b/peregrine/analysis/run_sim.py index c7c7984..fed63c7 100755 --- a/peregrine/analysis/run_sim.py +++ b/peregrine/analysis/run_sim.py @@ -237,7 +237,7 @@ def produce(lens, snr, dop, acc): def runCn0Range(): length = 30 # Duration (s) - snrRng = range(-200, -350, -10) # SNR for iqgen command. Unit 0.1 dBHz + snrRng = range(-330, -370, -1) # SNR for iqgen command. Unit 0.1 dBHz doppler = 0 # Hz acceleration = 0.0 # Hz / s for snr in snrRng: diff --git a/peregrine/analysis/tracking_loop.py b/peregrine/analysis/tracking_loop.py index 67d1f5e..d4d8cce 100755 --- a/peregrine/analysis/tracking_loop.py +++ b/peregrine/analysis/tracking_loop.py @@ -20,7 +20,7 @@ from peregrine.gps_constants import L1CA, L2C from peregrine.glo_constants import GLO_L1, GLO_L2, glo_l1_step, glo_l2_step from peregrine.run import populate_peregrine_cmd_line_arguments -from peregrine.tracking_loop import TrackingLoop3 +from peregrine.tracking_loop import TrackingLoop3, TrackingLoop3b, TrackingLoop2b def main(): @@ -182,8 +182,8 @@ def main(): stage2_loop_filter_params=stage2_params, tracker_options=tracker_options, output_file=args.output_file, - progress_bar_output=args.progress_bar, - loop_filter_class=TrackingLoop3) + progress_bar_output=args.progress_bar) +# loop_filter_class=TrackingLoop2b) tracker.start() condition = True while condition: diff --git a/peregrine/defaults.py b/peregrine/defaults.py index 16038e2..704c45b 100644 --- a/peregrine/defaults.py +++ b/peregrine/defaults.py @@ -190,7 +190,7 @@ "carr_bw": 15, # Carrier loop NBW "carr_zeta": 0.7, # Carrier loop zeta "carr_k": 1, # Carrier loop k - "carr_freq_b1": 5} # Carrier loop aiding_igain + "carr_freq_b1": 0} # Carrier loop aiding_igain l2c_loop_filter_params = { "loop_freq": 50, # loop frequency [Hz] @@ -244,22 +244,43 @@ } ) +# 1;5 ms stages +# l1ca_stage_params_med = \ +# ({'coherent_ms': 1, +# 'loop_filter_params': {'code_params': (3., 0.7, 1.), # NBW, zeta, k +# 'carr_params': (15., 0.7, 1.), # NBW, zeta, k +# 'loop_freq': 1000., # 1000/coherent_ms +# 'carr_freq_b1': 5., # fll_aid +# 'carr_to_code': 1540. # carr_to_code +# } +# }, + +# {'coherent_ms': 2, +# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k +# 'carr_params': (30., 0.7, 1.), # NBW, zeta, k +# 'loop_freq': 1000./2, # 1000/coherent_ms +# 'carr_freq_b1': 0, # fll_aid +# 'carr_to_code': 1540. # carr_to_code +# } +# } +# ) + # 1;5 ms stages l1ca_stage_params_med = \ ({'coherent_ms': 1, - 'loop_filter_params': {'code_params': (3., 0.7, 1.), # NBW, zeta, k - 'carr_params': (15., 0.7, 1.), # NBW, zeta, k + 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k + 'carr_params': (10., 0.7, 1.), # NBW, zeta, k 'loop_freq': 1000., # 1000/coherent_ms - 'carr_freq_b1': 5., # fll_aid + 'carr_freq_igain': 5., # fll_aid 'carr_to_code': 1540. # carr_to_code } }, - {'coherent_ms': 20, - 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k - 'carr_params': (15., 0.7, 1.), # NBW, zeta, k - 'loop_freq': 1000./20, # 1000/coherent_ms - 'carr_freq_b1': 0, # fll_aid + {'coherent_ms': 5, + 'loop_filter_params': {'code_params': (1., 0.707, 1.), # NBW, zeta, k + 'carr_params': (7., 0.707, 1.), # NBW, zeta, k + 'loop_freq': 1000. / 5, # 1000/coherent_ms + 'carr_freq_igain': 0., # fll_aid 'carr_to_code': 1540. # carr_to_code } } diff --git a/peregrine/tracking.py b/peregrine/tracking.py index d8b2061..8c8c055 100644 --- a/peregrine/tracking.py +++ b/peregrine/tracking.py @@ -1012,6 +1012,7 @@ def __init__(self, """ + print "loop_filter_class = ", loop_filter_class self.samples = samples self.sampling_freq = sampling_freq self.ms_to_track = ms_to_track diff --git a/peregrine/tracking_loop.py b/peregrine/tracking_loop.py index 7ba9eaa..0b05db8 100644 --- a/peregrine/tracking_loop.py +++ b/peregrine/tracking_loop.py @@ -174,3 +174,277 @@ def adjust_freq(self, corr): def to_dict(self): return { k:v for k, v in self.__dict__.items() \ if not (k.startswith('__') and k.endswith('__')) } + + +class TrackingLoop3b: + """ + Third order tracking loop initialization. + + For a full description of the loop filter parameters, see + :libswiftnav:`calc_loop_gains`. + + """ + + def __init__(self, **kwargs): + # Initial state + self.retune( (kwargs['code_bw'], kwargs['code_zeta'], kwargs['code_k']), + (kwargs['carr_bw'], kwargs['carr_zeta'], kwargs['carr_k']), + kwargs['loop_freq'], + kwargs['carr_freq_b1'], + kwargs['carr_to_code'] ) + + self.carr_freq = kwargs['carr_freq'] + self.code_freq = kwargs['code_freq'] + + self.code_vel = kwargs['code_freq'] + self.phase_acc = 0 + self.phase_vel = kwargs['carr_freq'] + + self.P_prev = 1+0j + + + def retune(self, code_params, carr_params, loop_freq, carr_freq_b1, carr_to_code): + """ + Retune the tracking loop. + + Parameters + ---------- + code_params : (float, float, float) + Code tracking loop parameter tuple, `(bw, zeta, k)`. + carr_params : (float, float, float) + Carrier tracking loop parameter tuple, `(bw, zeta, k)`. + loop_freq : float + The frequency with which loop updates are performed. + carr_freq_b1 : float + FLL aiding gain + carr_to_code : float + PLL to DLL aiding gain + + """ + code_bw, code_zeta, code_k = code_params + carr_bw, carr_zeta, carr_k = carr_params + + # Common parameters + self.T = 1 / loop_freq + + # FLL constants + freq_omega_0 = carr_freq_b1 / 0.53 + freq_a2 = 1.414 + + # a_2 * omega_0f + self.freq_c1 = freq_a2 * freq_omega_0 + self.freq_c2 = freq_omega_0 * freq_omega_0 + + # PLL constants + phase_omega_0 = carr_bw / 0.7845 + phase_a3 = 1.1 + phase_b3 = 2.4 + + # self.phase_c1 = phase_b3 * phase_omega_0 + # self.phase_c2 = phase_a3 * phase_omega_0 * phase_omega_0 + # self.phase_c3 = phase_omega_0 * phase_omega_0 * phase_omega_0 + self.phase_c1, self.phase_c2, self.phase_c3 = controlled_root(3, 1 / loop_freq, carr_bw) + print "T = ", 1 / loop_freq, " BW = ", carr_bw + + # self.phase_c1 = 0.00013553072504812747 + # self.phase_c2 = 0.006445479093110773 + # self.phase_c3 = 0.11739536416734386 + + # DLL constants + code_omega_0 = code_bw / 0.53 + code_a2 = 1.414 + + self.code_c1 = code_a2 * code_omega_0 + self.code_c2 = code_omega_0 * code_omega_0 + + self.carr_to_code = carr_to_code + + # self.code_vel = 0 + # self.phase_acc = 0 + # self.phase_vel = 0 + + def update(self, E, P, L): + """ + Tracking loop update + + Parameters + ---------- + E : [complex], :math:`I_E + Q_E j` + Complex Early Correlation + P : [complex], :math:`I_P + Q_P j` + Complex Prompt Correlation + L : [complex], :math:`I_L + Q_L j` + Complex Late Correlation + + Returns + ------- + out : (float, float) + The tuple (code_freq, carrier_freq). + + """ + + # Carrier loop + phase_error = costas_discriminator(P.real, P.imag) + freq_error = 0 + if self.freq_c1 != 0: + freq_error = frequency_discriminator(P.real, P.imag, self.P_prev.real, self.P_prev.imag) / self.T + + self.P_prev = P + + self.phase_acc += freq_error * self.freq_c2 * self.T + phase_error * self.phase_c3 * self.T + + sum = self.phase_acc + freq_error * self.freq_c1 + phase_error * self.phase_c2 + self.phase_vel += sum * self.T + sum = self.phase_vel + phase_error * self.phase_c1 + self.carr_freq = sum + + # Code loop + code_error = -dll_discriminator(E, P, L) + + prev = self.code_vel + self.code_vel += self.code_c2 * code_error * self.T + sum = (prev + self.code_vel) * 0.5 + self.code_c1 * code_error + + self.code_freq = sum + if self.carr_to_code > 0: + self.code_freq += self.carr_freq / self.carr_to_code + + return (self.code_freq, self.carr_freq) + + def adjust_freq(self, corr): + self.carr_freq += corr + + def to_dict(self): + return { k:v for k, v in self.__dict__.items() \ + if not (k.startswith('__') and k.endswith('__')) } + + +class TrackingLoop2b: + """ + Second order tracking loop initialization. + + For a full description of the loop filter parameters, see + :libswiftnav:`calc_loop_gains`. + + """ + + def __init__(self, **kwargs): + # Initial state + self.carr_freq = kwargs['carr_freq'] + self.code_freq = kwargs['code_freq'] + + self.code_vel = kwargs['code_freq'] + self.phase_vel = kwargs['carr_freq'] + + self.P_prev = 1+0j + + self.retune( (kwargs['code_bw'], kwargs['code_zeta'], kwargs['code_k']), + (kwargs['carr_bw'], kwargs['carr_zeta'], kwargs['carr_k']), + kwargs['loop_freq'], + kwargs['carr_freq_b1'], + kwargs['carr_to_code'] ) + + def retune(self, code_params, carr_params, loop_freq, carr_freq_b1, carr_to_code): + """ + Retune the tracking loop. + + Parameters + ---------- + code_params : (float, float, float) + Code tracking loop parameter tuple, `(bw, zeta, k)`. + carr_params : (float, float, float) + Carrier tracking loop parameter tuple, `(bw, zeta, k)`. + loop_freq : float + The frequency with which loop updates are performed. + carr_freq_b1 : float + FLL aiding gain + carr_to_code : float + PLL to DLL aiding gain + + """ + code_bw, code_zeta, code_k = code_params + carr_bw, carr_zeta, carr_k = carr_params + + # Common parameters + self.T = 1 / loop_freq + + # FLL constants + freq_omega_0 = carr_freq_b1 / 0.53 + freq_a2 = 1.414 + + # a_2 * omega_0f + self.freq_c1 = freq_a2 * freq_omega_0 + self.freq_c2 = freq_omega_0 * freq_omega_0 + + # PLL constants + phase_omega_0 = carr_bw / 0.53 + phase_a2 = 1.414 + + self.phase_c1 = phase_a2 * phase_omega_0 + self.phase_c2 = phase_omega_0 * phase_omega_0 + # self.phase_c1, self.phase_c2 = controlled_root(2, 1 / loop_freq, carr_bw) + # print "T = ", 1 / loop_freq, " BW = ", carr_bw + + # DLL constants + code_omega_0 = code_bw / 0.53 + code_a2 = 1.414 + + self.code_c1 = code_a2 * code_omega_0 + self.code_c2 = code_omega_0 * code_omega_0 + + self.carr_to_code = carr_to_code + + # self.code_vel = 0 + # self.phase_vel = 0 + + def update(self, E, P, L): + """ + Tracking loop update + + Parameters + ---------- + E : [complex], :math:`I_E + Q_E j` + Complex Early Correlation + P : [complex], :math:`I_P + Q_P j` + Complex Prompt Correlation + L : [complex], :math:`I_L + Q_L j` + Complex Late Correlation + + Returns + ------- + out : (float, float) + The tuple (code_freq, carrier_freq). + + """ + + # Carrier loop + phase_error = costas_discriminator(P.real, P.imag) + freq_error = 0 + if self.freq_c1 != 0: + freq_error = frequency_discriminator(P.real, P.imag, self.P_prev.real, self.P_prev.imag) / self.T + + self.P_prev = P + + self.phase_vel += freq_error * self.freq_c2 * self.T + phase_error * self.phase_c2 * self.T + + self.carr_freq = self.phase_vel + freq_error * self.freq_c1 + phase_error * self.phase_c1 + + # Code loop + code_error = -dll_discriminator(E, P, L) + + prev = self.code_vel + self.code_vel += self.code_c2 * code_error * self.T + sum = (prev + self.code_vel) * 0.5 + self.code_c1 * code_error + + self.code_freq = sum + if self.carr_to_code > 0: + self.code_freq += self.carr_freq / self.carr_to_code + + return (self.code_freq, self.carr_freq) + + def adjust_freq(self, corr): + self.carr_freq += corr + + def to_dict(self): + return { k:v for k, v in self.__dict__.items() \ + if not (k.startswith('__') and k.endswith('__')) } From 2c83767c88e3ab22abf9dc7b2091f4132a328595 Mon Sep 17 00:00:00 2001 From: Adel Mamin Date: Mon, 25 Jul 2016 11:34:30 +0300 Subject: [PATCH 20/61] WIP 2 --- peregrine/analysis/tracking_loop.py | 4 +- peregrine/cn0.py | 36 ++-- peregrine/defaults.py | 12 +- peregrine/run.py | 4 +- peregrine/tracking.py | 19 ++- peregrine/tracking_loop.py | 251 +++++++++++++++++++++++++--- 6 files changed, 270 insertions(+), 56 deletions(-) diff --git a/peregrine/analysis/tracking_loop.py b/peregrine/analysis/tracking_loop.py index d4d8cce..1fdcca4 100755 --- a/peregrine/analysis/tracking_loop.py +++ b/peregrine/analysis/tracking_loop.py @@ -182,8 +182,8 @@ def main(): stage2_loop_filter_params=stage2_params, tracker_options=tracker_options, output_file=args.output_file, - progress_bar_output=args.progress_bar) -# loop_filter_class=TrackingLoop2b) + progress_bar_output=args.progress_bar, + loop_filter_class=TrackingLoop3) tracker.start() condition = True while condition: diff --git a/peregrine/cn0.py b/peregrine/cn0.py index ca2fbd1..18ac6ec 100644 --- a/peregrine/cn0.py +++ b/peregrine/cn0.py @@ -28,25 +28,19 @@ def __init__(self, bw, cn0_0, cutoff_freq, loop_freq): The method uses the function for SNR computation: - \frac{C}{N_0}(n) = \frac{P_d}{P_n}, + C/N0(n) = P_d / P_n, where P_n(n) = M2(n) - P_d(n), - where P_d(n) = \sqrt{2# M2(n)^2 - M4(n)}, + where P_d(n) = sqrt(2 * M2(n)^2 - M4(n)), where - M2(n) = \frac{1}{2}(I(n)^2 + I(n-1)^2 + Q(n)^2 + Q(n-1)^2) - M4(n) = \frac{1}{2}(I(n)^4 + I(n-1)^4 + Q(n)^4 + Q(n-1)^4) - - Parameters - ---------- -\param s The estimator state struct to initialize. -\param p Common C/N0 estimator parameters. -\param cn0_0 The initial value of \f$ C / N_0 \f$ in dBHz. - -\return None + M2(n) = sum(1,N)(I(n)^2 + I(n-1)^2 + Q(n)^2 + Q(n-1)^2) / N + M4(n) = sum(1,N)(I(n)^4 + I(n-1)^4 + Q(n)^4 + Q(n-1)^4) / N Parameters ---------- coherent_ms : int Coherent integration time [ms]. + cn0_0 + The initial value of C/N_0 in dBHz. """ @@ -55,29 +49,31 @@ def __init__(self, bw, cn0_0, cutoff_freq, loop_freq): self.M4_arr = np.ndarray(CN0_MOVING_AVG_WINDOW_SIZE, dtype=np.double) self.index = 0 self.log_bw = 10 * np.log10(loop_freq) + self.snr_db = 0 + self.snr = 0 def _compute_cn0(self, M_2, M_4): tmp = 2 * M_2 * M_2 - M_4 if tmp < 0: - snr = 1 / CN0_MM_NSR_MIN + self.snr = 1 / CN0_MM_NSR_MIN else: P_d = np.sqrt(tmp) P_n = M_2 - P_d - # Ensure the NSR is within the limit + # Ensure the SNR is within the limit if P_d < P_n * CN0_MM_NSR_MIN_MULTIPLIER: return 60 elif P_n == 0: return 10 else: - snr = P_d / P_n + self.snr = P_d / P_n - snr_db = 10 * np.log10(snr) + self.snr_db = 10 * np.log10(self.snr) # Compute CN0 - x= self.log_bw + snr_db + x= self.log_bw + self.snr_db if x < 10: return 10 if x > 60: @@ -95,13 +91,13 @@ def _moving_average(self, arr, x): arr[-1] = x return np.average(arr) - # Computes \f$ C / N_0 \f$ with Moment method. + # Computes C/N0 with Moment method. # # s Initialized estimator object. # I In-phase signal component # Q Quadrature phase signal component. # - # Computed \f$ C / N_0 \f$ value + # Computed C/N0 & SNR values def update(self, I, Q): m_2 = I * I + Q * Q m_4 = m_2 * m_2 @@ -115,4 +111,4 @@ def update(self, I, Q): # Compute and store updated CN0 self.cn0_db = self._compute_cn0(M_2, M_4) - return self.cn0_db + return (self.cn0_db, self.snr, self.snr_db) diff --git a/peregrine/defaults.py b/peregrine/defaults.py index 704c45b..b267e4b 100644 --- a/peregrine/defaults.py +++ b/peregrine/defaults.py @@ -190,7 +190,7 @@ "carr_bw": 15, # Carrier loop NBW "carr_zeta": 0.7, # Carrier loop zeta "carr_k": 1, # Carrier loop k - "carr_freq_b1": 0} # Carrier loop aiding_igain + "carr_freq_b1": 1} # Carrier loop aiding_igain l2c_loop_filter_params = { "loop_freq": 50, # loop frequency [Hz] @@ -271,16 +271,16 @@ 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k 'carr_params': (10., 0.7, 1.), # NBW, zeta, k 'loop_freq': 1000., # 1000/coherent_ms - 'carr_freq_igain': 5., # fll_aid + 'carr_freq_b1': 5., # fll_aid 'carr_to_code': 1540. # carr_to_code } }, - {'coherent_ms': 5, + {'coherent_ms': 20, 'loop_filter_params': {'code_params': (1., 0.707, 1.), # NBW, zeta, k - 'carr_params': (7., 0.707, 1.), # NBW, zeta, k - 'loop_freq': 1000. / 5, # 1000/coherent_ms - 'carr_freq_igain': 0., # fll_aid + 'carr_params': (3, 0.707, 1.), # NBW, zeta, k + 'loop_freq': 1000. / 20, # 1000/coherent_ms + 'carr_freq_b1': 0., # fll_aid 'carr_to_code': 1540. # carr_to_code } } diff --git a/peregrine/run.py b/peregrine/run.py index 1d6fa9a..570144b 100755 --- a/peregrine/run.py +++ b/peregrine/run.py @@ -29,6 +29,7 @@ from peregrine.tracking_file_utils import TrackingResults from peregrine.tracking_file_utils import createTrackingDumpOutputFileName import peregrine.glo_constants as glo +from peregrine.tracking_loop import TrackingLoop3, TrackingLoop3b, TrackingLoop2b class SaveConfigAction(argparse.Action): @@ -329,7 +330,8 @@ def main(): tracker_options=tracker_options, output_file=args.file, progress_bar_output=args.progress_bar, - check_l2c_mask=args.check_l2c_mask) + check_l2c_mask=args.check_l2c_mask, + loop_filter_class=TrackingLoop3) # The tracking channels are designed to support batch processing. # In the batch processing mode the data samples are provided in # batches (chunks) of 'defaults.processing_block_size' bytes size. diff --git a/peregrine/tracking.py b/peregrine/tracking.py index 8c8c055..b323d62 100644 --- a/peregrine/tracking.py +++ b/peregrine/tracking.py @@ -501,6 +501,9 @@ def run(self, samples): self.track_result.code_freq[self.i] = \ self.loop_filter.to_dict()['code_freq'] + self.chipping_rate + self.track_result.phase_err[self.i] = \ + self.loop_filter.to_dict()['phase_err'] + # Record stuff for postprocessing self.track_result.absolute_sample[self.i] = self.sample_index + \ samples_processed @@ -509,8 +512,10 @@ def run(self, samples): self.track_result.P[self.i] = self.P self.track_result.L[self.i] = self.L - self.track_result.cn0[self.i] = self.cn0_est.update( - self.P.real, self.P.imag) + self.track_result.cn0[self.i], \ + self.track_result.snr[self.i], \ + self.track_result.snr_db[self.i] = \ + self.cn0_est.update(self.P.real, self.P.imag) self.track_result.lock_detect_outo[self.i] = self.lock_detect_outo self.track_result.lock_detect_outp[self.i] = self.lock_detect_outp @@ -1290,6 +1295,8 @@ def __init__(self, n_points, prn, signal): self.P = np.zeros(n_points, dtype=np.complex128) self.L = np.zeros(n_points, dtype=np.complex128) self.cn0 = np.zeros(n_points) + self.snr = np.zeros(n_points) + self.snr_db = np.zeros(n_points) self.lock_detect_outp = np.zeros(n_points) self.lock_detect_outo = np.zeros(n_points) self.lock_detect_pcount1 = np.zeros(n_points) @@ -1297,6 +1304,7 @@ def __init__(self, n_points, prn, signal): self.lock_detect_lpfi = np.zeros(n_points) self.lock_detect_lpfq = np.zeros(n_points) self.alias_detect_err_hz = np.zeros(n_points) + self.phase_err = np.zeros(n_points) self.nav_msg = NavMsg() self.nav_msg_bit_phase_ref = np.zeros(n_points) self.nav_bit_sync = NBSMatchBit() if prn < 32 else NBSSBAS() @@ -1342,11 +1350,11 @@ def dump(self, output_file, size): f1.write( "sample_index,ms_tracked,coherent_ms,IF,doppler_phase,carr_doppler," "code_phase,code_freq," - "CN0,E_I,E_Q,P_I,P_Q,L_I,L_Q," + "CN0,SNR,SNR_DB,E_I,E_Q,P_I,P_Q,L_I,L_Q," "lock_detect_outp,lock_detect_outo," "lock_detect_pcount1,lock_detect_pcount2," "lock_detect_lpfi,lock_detect_lpfq,alias_detect_err_hz," - "code_phase_acc\n") + "phase_err,code_phase_acc\n") for i in range(size): f1.write("%s," % int(self.absolute_sample[i])) f1.write("%s," % self.ms_tracked[i]) @@ -1358,6 +1366,8 @@ def dump(self, output_file, size): f1.write("%s," % self.code_phase[i]) f1.write("%s," % self.code_freq[i]) f1.write("%s," % self.cn0[i]) + f1.write("%s," % self.snr[i]) + f1.write("%s," % self.snr_db[i]) f1.write("%s," % self.E[i].real) f1.write("%s," % self.E[i].imag) f1.write("%s," % self.P[i].real) @@ -1371,6 +1381,7 @@ def dump(self, output_file, size): f1.write("%s," % self.lock_detect_lpfi[i]) f1.write("%s," % self.lock_detect_lpfq[i]) f1.write("%s," % self.alias_detect_err_hz[i]) + f1.write("%s," % self.phase_err[i]) f1.write("%s\n" % self.code_phase_acc[i]) self.print_start = 0 diff --git a/peregrine/tracking_loop.py b/peregrine/tracking_loop.py index 0b05db8..f9634af 100644 --- a/peregrine/tracking_loop.py +++ b/peregrine/tracking_loop.py @@ -18,16 +18,18 @@ def costas_discriminator(I, Q): # the average of 0.25 and -0.25 in the face of that ambiguity, so zero. return 0 - return np.arctan(Q / I) / (2 * np.pi) + return np.arctan(Q / I)# / (2 * np.pi) def frequency_discriminator(I, Q, prev_I, prev_Q): dot = np.absolute(I * prev_I) + np.absolute(Q * prev_Q) cross = prev_I * Q - I * prev_Q - return np.arctan2(cross, dot) / (2 * np.pi) + return np.arctan2(cross, dot)# / (2 * np.pi) def dll_discriminator(E, P, L): E_mag = np.absolute(E) L_mag = np.absolute(L) + if E_mag + L_mag == 0: + return 0 return 0.5 * (E_mag - L_mag) / (E_mag + L_mag) @@ -48,6 +50,7 @@ def __init__(self, **kwargs): self.code_vel = kwargs['code_freq'] self.phase_acc = 0 self.phase_vel = kwargs['carr_freq'] + self.phase_err = 0 self.P_prev = 1+0j @@ -79,7 +82,7 @@ def retune(self, code_params, carr_params, loop_freq, carr_freq_b1, carr_to_code carr_bw, carr_zeta, carr_k = carr_params # Common parameters - self.T = 1 / loop_freq + self.T = 1. / loop_freq # FLL constants freq_omega_0 = carr_freq_b1 / 0.53 @@ -98,7 +101,7 @@ def retune(self, code_params, carr_params, loop_freq, carr_freq_b1, carr_to_code self.phase_c2 = phase_a3 * phase_omega_0 * phase_omega_0 self.phase_c3 = phase_omega_0 * phase_omega_0 * phase_omega_0 # self.phase_c1, self.phase_c2, self.phase_c3 = controlled_root(3, 1 / loop_freq, carr_bw) - # print "T = ", 1 / loop_freq, " BW = ", carr_bw + print "T = ", 1 / loop_freq, " BW = ", carr_bw # self.phase_c1 = 0.00013553072504812747 # self.phase_c2 = 0.006445479093110773 @@ -112,9 +115,10 @@ def retune(self, code_params, carr_params, loop_freq, carr_freq_b1, carr_to_code self.code_c2 = code_omega_0 * code_omega_0 self.carr_to_code = carr_to_code + print "phase_acc = ", self.phase_acc, " phase_vel = ", self.phase_vel # self.code_vel = 0 - # self.phase_acc = 0 + self.phase_acc = 0 # self.phase_vel = 0 def update(self, E, P, L): @@ -138,21 +142,21 @@ def update(self, E, P, L): """ # Carrier loop - phase_error = costas_discriminator(P.real, P.imag) + self.phase_err = costas_discriminator(P.real, P.imag) freq_error = 0 - if self.freq_c1 != 0: + if self.freq_c1 != 0 and self.T != 0: freq_error = frequency_discriminator(P.real, P.imag, self.P_prev.real, self.P_prev.imag) / self.T self.P_prev = P prev = self.phase_acc - self.phase_acc += freq_error * self.freq_c2 * self.T + phase_error * self.phase_c3 * self.T + self.phase_acc += freq_error * self.freq_c2 * self.T + self.phase_err * self.phase_c3 * self.T sum = (self.phase_acc + prev) * 0.5 - sum += freq_error * self.freq_c1 + phase_error * self.phase_c2 + sum += freq_error * self.freq_c1 + self.phase_err * self.phase_c2 prev = self.phase_vel self.phase_vel += sum * self.T - sum = (self.phase_vel + prev) * 0.5 + phase_error * self.phase_c1 + sum = (self.phase_vel + prev) * 0.5 + self.phase_err * self.phase_c1 self.carr_freq = sum # Code loop @@ -243,12 +247,75 @@ def retune(self, code_params, carr_params, loop_freq, carr_freq_b1, carr_to_code # self.phase_c1 = phase_b3 * phase_omega_0 # self.phase_c2 = phase_a3 * phase_omega_0 * phase_omega_0 # self.phase_c3 = phase_omega_0 * phase_omega_0 * phase_omega_0 - self.phase_c1, self.phase_c2, self.phase_c3 = controlled_root(3, 1 / loop_freq, carr_bw) - print "T = ", 1 / loop_freq, " BW = ", carr_bw - # self.phase_c1 = 0.00013553072504812747 - # self.phase_c2 = 0.006445479093110773 - # self.phase_c3 = 0.11739536416734386 + # self.phase_c1 = 0.2532 + # self.phase_c2 = 0.03710 + # self.phase_c3 = 0.002344 + + # BL*T = 0.015 no delay + # self.phase_c1 = 0.03742 + # self.phase_c2 = 6.356e-04 + # self.phase_c3 = 4.084e-06 + + # BL*T = 0.015 with delay + # self.phase_c1 = 0.03575 + # self.phase_c2 = 5.859e-04 + # self.phase_c3 = 3.646e-06 + + # BL*T = 0.050 with delay + # self.phase_c1 = 0.09928 + # self.phase_c2 = 0.004802 + # self.phase_c3 = 9.066e-05 + + if carr_bw / loop_freq == 0.1: + # BL*T = 0.100 with delay + self.phase_c1 = 0.1599 + self.phase_c2 = 0.01333 + self.phase_c3 = 4.494e-04 + # BL*T = 0.100 without delay + # self.phase_c1 = 0.1991 + # self.phase_c2 = 0.01995 + # self.phase_c3 = 7.924e-04 + elif carr_bw / loop_freq == 0.050: + self.phase_c1 = 0.09928 + self.phase_c2 = 0.004802 + self.phase_c3 = 9.066e-05 + elif carr_bw / loop_freq == 0.070: + self.phase_c1 = 0.1268 + self.phase_c2 = 0.008066 + self.phase_c3 = 2.032-04 + elif carr_bw / loop_freq == 0.15: + self.phase_c1 = 0.2003 + self.phase_c2 = 0.02203 + self.phase_c3 = 0.001012 + elif carr_bw / loop_freq == 0.2: + # without delay + self.phase_c1 = 0.3183 + self.phase_c2 = 0.05595 + self.phase_c3 = 0.004103 + # with delay + # self.phase_c1 = 0.2290 + # self.phase_c2 = 0.02994 + # self.phase_c3 = 0.001683 + # BL*T = 0.400 without delay + # self.phase_c1 = 0.4499 + # self.phase_c2 = 0.1253 + # self.phase_c3 = 0.01584 + + # BL*T = 0.300 without delay + # self.phase_c1 = 0.3951 + # self.phase_c2 = 0.09238 + # self.phase_c3 = 0.009451 + + # BL*T = 0.250 without delay + # self.phase_c1 = 0.3606 + # self.phase_c2 = 0.07452 + # self.phase_c3 = 0.006583 + + else: + self.phase_c1, self.phase_c2, self.phase_c3 = controlled_root(3, 1 / loop_freq, carr_bw) + print "T = ", 1 / loop_freq, " BW = ", carr_bw, "BL*T = ", carr_bw / loop_freq + print "c1, c2, c3: ", self.phase_c1, self.phase_c2, self.phase_c3 # DLL constants code_omega_0 = code_bw / 0.53 @@ -284,18 +351,25 @@ def update(self, E, P, L): """ # Carrier loop - phase_error = costas_discriminator(P.real, P.imag) + self.phase_err = costas_discriminator(P.real, P.imag) freq_error = 0 if self.freq_c1 != 0: freq_error = frequency_discriminator(P.real, P.imag, self.P_prev.real, self.P_prev.imag) / self.T self.P_prev = P - self.phase_acc += freq_error * self.freq_c2 * self.T + phase_error * self.phase_c3 * self.T + # self.phase_acc += freq_error * self.freq_c2 * 1 / self.T + self.phase_err * self.phase_c3# * 1 / self.T - sum = self.phase_acc + freq_error * self.freq_c1 + phase_error * self.phase_c2 - self.phase_vel += sum * self.T - sum = self.phase_vel + phase_error * self.phase_c1 + # sum = self.phase_acc + freq_error * self.freq_c1 + self.phase_err * self.phase_c2 + # self.phase_vel += sum * 1 / self.T + # sum = self.phase_vel + self.phase_err * self.phase_c1 + # self.carr_freq = sum #* self.T + + self.phase_acc += self.phase_err * self.phase_c3 / self.T + + sum = self.phase_acc + self.phase_err * self.phase_c2 / self.T + self.phase_vel += sum + sum = self.phase_vel + self.phase_err * self.phase_c1 / self.T self.carr_freq = sum # Code loop @@ -418,16 +492,147 @@ def update(self, E, P, L): """ # Carrier loop - phase_error = costas_discriminator(P.real, P.imag) + self.phase_err = costas_discriminator(P.real, P.imag) + freq_error = 0 + if self.freq_c1 != 0: + freq_error = frequency_discriminator(P.real, P.imag, self.P_prev.real, self.P_prev.imag) / self.T + + self.P_prev = P + + self.phase_vel += freq_error * self.freq_c2 * self.T + self.phase_err * self.phase_c2 * self.T + + self.carr_freq = self.phase_vel + freq_error * self.freq_c1 + self.phase_err * self.phase_c1 + + # Code loop + code_error = -dll_discriminator(E, P, L) + + prev = self.code_vel + self.code_vel += self.code_c2 * code_error * self.T + sum = (prev + self.code_vel) * 0.5 + self.code_c1 * code_error + + self.code_freq = sum + if self.carr_to_code > 0: + self.code_freq += self.carr_freq / self.carr_to_code + + return (self.code_freq, self.carr_freq) + + def adjust_freq(self, corr): + self.carr_freq += corr + + def to_dict(self): + return { k:v for k, v in self.__dict__.items() \ + if not (k.startswith('__') and k.endswith('__')) } + + +class TrackingLoop3Optimal: + """ + Third order optimal tracking loop initialization. + + For a full description of the loop filter parameters, see + :libswiftnav:`calc_loop_gains`. + + """ + + def __init__(self, **kwargs): + # Initial state + self.carr_freq = kwargs['carr_freq'] + self.code_freq = kwargs['code_freq'] + + self.code_vel = kwargs['code_freq'] + self.phase_vel = kwargs['carr_freq'] + + self.P_prev = 1+0j + + self.retune( (kwargs['code_bw'], kwargs['code_zeta'], kwargs['code_k']), + (kwargs['carr_bw'], kwargs['carr_zeta'], kwargs['carr_k']), + kwargs['loop_freq'], + kwargs['carr_freq_b1'], + kwargs['carr_to_code'] ) + + def retune(self, code_params, carr_params, loop_freq, carr_freq_b1, carr_to_code): + """ + Retune the tracking loop. + + Parameters + ---------- + code_params : (float, float, float) + Code tracking loop parameter tuple, `(bw, zeta, k)`. + carr_params : (float, float, float) + Carrier tracking loop parameter tuple, `(bw, zeta, k)`. + loop_freq : float + The frequency with which loop updates are performed. + carr_freq_b1 : float + FLL aiding gain + carr_to_code : float + PLL to DLL aiding gain + + """ + code_bw, code_zeta, code_k = code_params + carr_bw, carr_zeta, carr_k = carr_params + + # Common parameters + self.T = 1 / loop_freq + + # FLL constants + freq_omega_0 = carr_freq_b1 / 0.53 + freq_a2 = 1.414 + + # a_2 * omega_0f + self.freq_c1 = freq_a2 * freq_omega_0 + self.freq_c2 = freq_omega_0 * freq_omega_0 + + # PLL constants + phase_omega_0 = carr_bw / 0.53 + phase_a2 = 1.414 + + self.phase_c1 = phase_a2 * phase_omega_0 + self.phase_c2 = phase_omega_0 * phase_omega_0 + # self.phase_c1, self.phase_c2 = controlled_root(2, 1 / loop_freq, carr_bw) + # print "T = ", 1 / loop_freq, " BW = ", carr_bw + + # DLL constants + code_omega_0 = code_bw / 0.53 + code_a2 = 1.414 + + self.code_c1 = code_a2 * code_omega_0 + self.code_c2 = code_omega_0 * code_omega_0 + + self.carr_to_code = carr_to_code + + # self.code_vel = 0 + # self.phase_vel = 0 + + def update(self, E, P, L): + """ + Tracking loop update + + Parameters + ---------- + E : [complex], :math:`I_E + Q_E j` + Complex Early Correlation + P : [complex], :math:`I_P + Q_P j` + Complex Prompt Correlation + L : [complex], :math:`I_L + Q_L j` + Complex Late Correlation + + Returns + ------- + out : (float, float) + The tuple (code_freq, carrier_freq). + + """ + + # Carrier loop + self.phase_err = costas_discriminator(P.real, P.imag) freq_error = 0 if self.freq_c1 != 0: freq_error = frequency_discriminator(P.real, P.imag, self.P_prev.real, self.P_prev.imag) / self.T self.P_prev = P - self.phase_vel += freq_error * self.freq_c2 * self.T + phase_error * self.phase_c2 * self.T + self.phase_vel += freq_error * self.freq_c2 * self.T + self.phase_err * self.phase_c2 * self.T - self.carr_freq = self.phase_vel + freq_error * self.freq_c1 + phase_error * self.phase_c1 + self.carr_freq = self.phase_vel + freq_error * self.freq_c1 + self.phase_err * self.phase_c1 # Code loop code_error = -dll_discriminator(E, P, L) From ff1f63abebd00d50b05f4e1978cabcfaed0fbc47 Mon Sep 17 00:00:00 2001 From: Adel Mamin Date: Mon, 25 Jul 2016 17:20:04 +0300 Subject: [PATCH 21/61] Add BL CN0 estimator --- peregrine/cn0.py | 86 ++++++++++++++++++++++++++++++++++++++++++- peregrine/tracking.py | 2 +- 2 files changed, 86 insertions(+), 2 deletions(-) diff --git a/peregrine/cn0.py b/peregrine/cn0.py index 18ac6ec..55569e4 100644 --- a/peregrine/cn0.py +++ b/peregrine/cn0.py @@ -16,7 +16,7 @@ # Maximum supported NSR value (1/CN0_MM_NSR_MIN_MULTIPLIER) CN0_MM_NSR_MIN = 1e6 -CN0_MOVING_AVG_WINDOW_SIZE = 200 +CN0_MOVING_AVG_WINDOW_SIZE = 500 class CN0_Est_MM(object): @@ -112,3 +112,87 @@ def update(self, I, Q): self.cn0_db = self._compute_cn0(M_2, M_4) return (self.cn0_db, self.snr, self.snr_db) + + +class CN0_Est_BL(object): + + def __init__(self, bw, cn0_0, cutoff_freq, loop_freq): + """ + Initialize the C/N0 estimator state. + + Initializes Moment method C/N0 estimator. + + The method uses the function for SNR computation: + + C/N0(n) = P_d / P_n, + where P_n(n) = M2(n) - P_d(n), + where P_d(n) = sqrt(2 * M2(n)^2 - M4(n)), + where + M2(n) = sum(1,N)(I(n)^2 + I(n-1)^2 + Q(n)^2 + Q(n-1)^2) / N + M4(n) = sum(1,N)(I(n)^4 + I(n-1)^4 + Q(n)^4 + Q(n-1)^4) / N + + Parameters + ---------- + coherent_ms : int + Coherent integration time [ms]. + cn0_0 + The initial value of C/N_0 in dBHz. + + + """ + # self.cn0_db = cn0_0 + # self.M2_arr = np.ndarray(CN0_MOVING_AVG_WINDOW_SIZE, dtype=np.double) + # self.M4_arr = np.ndarray(CN0_MOVING_AVG_WINDOW_SIZE, dtype=np.double) + # self.index = 0 + # self.log_bw = 10 * np.log10(loop_freq) + # self.snr_db = 0 + # self.snr = 0 + + self.nsr_arr = np.ndarray(CN0_MOVING_AVG_WINDOW_SIZE, dtype=np.double) + self.snr_arr = np.ndarray(CN0_MOVING_AVG_WINDOW_SIZE, dtype=np.double) + self.index = 0 + self.log_bw = 10. * np.log10(loop_freq) + self.I_prev_abs = -1. + self.Q_prev_abs = -1. + self.nsr = 10. ** (0.1 * (self.log_bw - cn0_0)) + self.snr = 0 + + def _moving_average(self, arr, x): + if self.index < CN0_MOVING_AVG_WINDOW_SIZE: + arr[self.index] = x + return np.average(arr[:self.index + 1]) + else: + arr[:-1] = arr[1:] + arr[-1] = x + return np.average(arr) + + # Computes C/N0 with Moment method. + # + # s Initialized estimator object. + # I In-phase signal component + # Q Quadrature phase signal component. + # + # Computed C/N0 & SNR values + def update(self, I, Q): + if self.I_prev_abs < 0.: + # This is the first iteration, just update the prev state. + self.I_prev_abs = np.absolute(I) + self.Q_prev_abs = np.absolute(Q) + else: + P_n = np.absolute(I) - self.I_prev_abs + P_n = P_n * P_n + + P_s = 0.5 * (I * I + self.I_prev_abs * self.I_prev_abs) + + self.I_prev_abs = np.absolute(I) + self.Q_prev_abs = np.absolute(Q) + + self.nsr = self._moving_average(self.nsr_arr, P_n / P_s) + self.snr = self._moving_average(self.snr_arr, I ** 2 / (2 * Q ** 2)) + if self.index < CN0_MOVING_AVG_WINDOW_SIZE: + self.index += 1 + + cn0 = self.log_bw - 10.*np.log10(self.nsr) + + return (cn0, self.snr, 10 * np.log10(self.snr)) + diff --git a/peregrine/tracking.py b/peregrine/tracking.py index b323d62..aa46871 100644 --- a/peregrine/tracking.py +++ b/peregrine/tracking.py @@ -33,7 +33,7 @@ from peregrine.include.generateL2CMcode import L2CMCodes from peregrine.include.generateGLOcode import GLOCode from peregrine.tracking_file_utils import createTrackingOutputFileNames -from peregrine.cn0 import CN0_Est_MM +from peregrine.cn0 import CN0_Est_MM, CN0_Est_BL import logging import sys From 2ef738e9776342fbc35434255d804729e3af72de Mon Sep 17 00:00:00 2001 From: Adel Mamin Date: Tue, 26 Jul 2016 09:17:55 +0300 Subject: [PATCH 22/61] Add new FSM (WIP) --- peregrine/alias_detector.py | 104 ++++-------- peregrine/defaults.py | 228 +++++++++++++++++++++++++++ peregrine/tracking.py | 305 +++++++++++++++--------------------- 3 files changed, 388 insertions(+), 249 deletions(-) diff --git a/peregrine/alias_detector.py b/peregrine/alias_detector.py index e809c74..8834ac5 100644 --- a/peregrine/alias_detector.py +++ b/peregrine/alias_detector.py @@ -27,12 +27,13 @@ def __init__(self, coherent_ms): coherent_ms : int Coherent integration time [ms]. - """ - self.first_step = True self.err_hz = 0. self.coherent_ms = coherent_ms - self.iterations_num = coherent_ms / defaults.alias_detect_slice_ms + self.integration_rounds = defaults.alias_detect_interval_ms / \ + (defaults.alias_detect_slice_ms * 2) + + self.alias_detect = AD(acc_len=self.integration_rounds, time_diff=2e-3) def reinit(self, coherent_ms): """ @@ -51,57 +52,51 @@ def reinit(self, coherent_ms): self.coherent_ms = coherent_ms self.alias_detect.reinit(self.integration_rounds, time_diff=2e-3) - def preprocess(self): + def first(self, P): """ Customize the alias detect procedure in a subclass. The method can be optionally redefined in a subclass to perform a subclass specific actions to happen before correlator runs next integration round. + Parameters + ---------- + P : prompt I/Q + The prompt I/Q samples from correlator. + """ - self.first_step = True - return self.iterations_num, self.chips_num + self.alias_detect.first(P.real, P.imag) - def postprocess(self, P): + def second(self, P): """ - Customize the alias detect run procedure in a subclass. + Customize the alias detect procedure in a subclass. The method can be optionally redefined in a subclass to perform - a subclass specific actions to happen after correlator runs + a subclass specific actions to happen before correlator runs next integration round. Parameters ---------- P : prompt I/Q The prompt I/Q samples from correlator. - code_phase : current code phase [chips] """ - - def postprocess(self, P): - if self.first_step: - self.alias_detect.first(P.real, P.imag) + self.err_hz = self.alias_detect.second(P.real, P.imag) + abs_err_hz = abs(self.err_hz) + err_sign = np.sign(self.err_hz) + # The expected frequency errors are +-(25 + N * 50) Hz + # For the reference, see: + # https://swiftnav.hackpad.com/Alias-PLL-lock-detector-in-L2C-4fWUJWUNnOE + if abs_err_hz > 25.: + self.err_hz = 25 + self.err_hz += 50 * int((abs_err_hz - 25) / 50) + abs_err_hz -= self.err_hz + if abs_err_hz + 25. > 50.: + self.err_hz += 50 + elif abs_err_hz > 25 / 2.: + self.err_hz = 25 else: - self.err_hz = self.alias_detect.second(P.real, P.imag) - abs_err_hz = abs(self.err_hz) - err_sign = np.sign(self.err_hz) - # The expected frequency errors are +-(25 + N * 50) Hz - # For the reference, see: - # https://swiftnav.hackpad.com/Alias-PLL-lock-detector-in-L2C-4fWUJWUNnOE - if abs_err_hz > 25.: - self.err_hz = 25 - self.err_hz += 50 * int((abs_err_hz - 25) / 50) - abs_err_hz -= self.err_hz - if abs_err_hz + 25. > 50.: - self.err_hz += 50 - elif abs_err_hz > 25 / 2.: - self.err_hz = 25 - else: - self.err_hz = 0 - self.err_hz *= err_sign - - self.first_step = not self.first_step - - return self.chips_num + self.err_hz = 0 + self.err_hz *= err_sign def get_err_hz(self): """ @@ -109,42 +104,3 @@ def get_err_hz(self): """ return self.err_hz - - -class AliasDetectorL1CA(AliasDetector): - - def __init__(self, coherent_ms): - - AliasDetector.__init__(self, coherent_ms) - - self.chips_num = gps_constants.chips_per_code - self.integration_rounds = defaults.alias_detect_interval_ms / \ - (defaults.alias_detect_slice_ms * 2) - - self.alias_detect = AD(acc_len=self.integration_rounds, time_diff=2e-3) - - -class AliasDetectorL2C(AliasDetector): - - def __init__(self, coherent_ms): - - AliasDetector.__init__(self, coherent_ms) - - self.chips_num = 2 * gps_constants.l2_cm_chips_per_code / coherent_ms - self.integration_rounds = defaults.alias_detect_interval_ms / \ - (defaults.alias_detect_slice_ms * 2) - - self.alias_detect = AD(acc_len=self.integration_rounds, time_diff=2e-3) - - -class AliasDetectorGLO(AliasDetector): - - def __init__(self, coherent_ms): - - super(AliasDetectorGLO, self).__init__(coherent_ms) - - self.chips_num = glo_constants.glo_code_len - self.integration_rounds = defaults.alias_detect_interval_ms / \ - (defaults.alias_detect_slice_ms * 2) - - self.alias_detect = AD(acc_len=self.integration_rounds, time_diff=2e-3) diff --git a/peregrine/defaults.py b/peregrine/defaults.py index b267e4b..ea16d40 100644 --- a/peregrine/defaults.py +++ b/peregrine/defaults.py @@ -8,6 +8,8 @@ # EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED # WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. +import gps_constants + acqThreshold = 21.0 # SNR (unitless) acqSanityCheck = True # Check for sats known to be below the horizon navSanityMaxResid = 25.0 # meters per SV, normalized nav residuals @@ -333,6 +335,232 @@ 'fast': l1ca_stage_params_fast, 'extrafast': l1ca_stage_params_extrafast} +ALIAS_DETECT_1ST = 1 +ALIAS_DETECT_2ND = 2 +ALIAS_DETECT_BOTH = 3 +RUN_LD = 4 +APPLY_CORR_1 = 5 +APPLY_CORR_2 = 6 +GET_CORR_1 = 7 +GET_CORR_2 = 8 + +fsm_states = \ + { '1ms': + { 'no_bit_sync': + { 'short_n_long': + { 'coherent_ms': 1, + 't_diff_s': 1023 * 1 / gps_constants.l1ca_chip_rate, + 'alias_acc_length_ms': 500, + 0: (1023, 1, {'pre': (APPLY_CORR_1,), 'post': (RUN_LD, GET_CORR_1)}), + 1: (1023, 0, {'pre': (APPLY_CORR_2,), 'post': (RUN_LD, GET_CORR_2)}) }, + + 'ideal': + { 'coherent_ms': 1, + 't_diff_s': 1023 * 1 / gps_constants.l1ca_chip_rate, + 'alias_acc_length_ms': 500, + 0: (1023, 1, {'pre': (APPLY_CORR_1,), 'post': (RUN_LD, GET_CORR_2)}), + 1: (1023, 0, {'pre': (APPLY_CORR_2,), 'post': (RUN_LD, GET_CORR_1)}) } + }, + 'bit_sync': + { 'short_n_long': + { 'coherent_ms': 1, + 't_diff_s': 1023 * 1 / gps_constants.l1ca_chip_rate, + 'alias_acc_length_ms': 500, + + # start-up + 0: (1023, 2, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_1ST, GET_CORR_1) }), + + # normal + 1: (1023, 2, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_1ST, GET_CORR_1) }), + 2: (1023, 3, {'pre': (APPLY_CORR_2,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_2) }), + 3: (1023, 4, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), + 4: (1023, 5, {'pre': (APPLY_CORR_2,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_2) }), + 5: (1023, 6, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), + 6: (1023, 7, {'pre': (APPLY_CORR_2,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_2) }), + 7: (1023, 8, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), + 8: (1023, 9, {'pre': (APPLY_CORR_2,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_2) }), + 9: (1023, 10, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), + 10: (1023, 11, {'pre': (APPLY_CORR_2,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_2) }), + 11: (1023, 12, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), + 12: (1023, 13, {'pre': (APPLY_CORR_2,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_2) }), + 13: (1023, 14, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), + 14: (1023, 15, {'pre': (APPLY_CORR_2,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_2) }), + 15: (1023, 16, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), + 16: (1023, 17, {'pre': (APPLY_CORR_2,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_2) }), + 17: (1023, 18, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), + 18: (1023, 19, {'pre': (APPLY_CORR_2,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_2) }), + 19: (1023, 20, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), + 20: (1023, 1, {'pre': (APPLY_CORR_2,), + 'post': (RUN_LD, ALIAS_DETECT_2ND, GET_CORR_2) }) }, + 'ideal': + { 'coherent_ms': 1, + 't_diff_s': 1023 * 1 / gps_constants.l1ca_chip_rate, + 'alias_acc_length_ms': 500, + + # start-up + 0: (1023, 2, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_1ST, GET_CORR_2) }), + + # normal + 1: (1023, 2, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_1ST, GET_CORR_2) }), + 2: (1023, 3, {'pre': (APPLY_CORR_2,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), + 3: (1023, 4, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_2) }), + 4: (1023, 5, {'pre': (APPLY_CORR_2,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), + 5: (1023, 6, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_2) }), + 6: (1023, 7, {'pre': (APPLY_CORR_2,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), + 7: (1023, 8, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_2) }), + 8: (1023, 9, {'pre': (APPLY_CORR_2,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), + 9: (1023, 10, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_2) }), + 10: (1023, 11, {'pre': (APPLY_CORR_2,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), + 11: (1023, 12, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_2) }), + 12: (1023, 13, {'pre': (APPLY_CORR_2,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), + 13: (1023, 14, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_2) }), + 14: (1023, 15, {'pre': (APPLY_CORR_2,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), + 15: (1023, 16, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_2) }), + 16: (1023, 17, {'pre': (APPLY_CORR_2,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), + 17: (1023, 18, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_2) }), + 18: (1023, 19, {'pre': (APPLY_CORR_2,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), + 19: (1023, 20, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_2) }), + 20: (1023, 1, {'pre': (APPLY_CORR_2,), + 'post': (RUN_LD, ALIAS_DETECT_2ND, GET_CORR_1) }) }, + } + }, + + '20ms': + { 'bit_sync': + { 'short_n_long': + { 'coherent_ms': 20, + 't_diff_s': 1023 * 1 / gps_constants.l1ca_chip_rate, + 'alias_acc_length_ms': 500, + + 0: (1023, 1, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_1ST,) }), + 1: (1023, 2, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 2: (1023, 3, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 3: (1023, 4, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 4: (1023, 5, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 5: (1023, 6, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 6: (1023, 7, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 7: (1023, 8, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 8: (1023, 9, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 9: (1023, 10, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 10: (1023, 11, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 11: (1023, 12, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 12: (1023, 13, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 13: (1023, 14, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 14: (1023, 15, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 15: (1023, 16, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 16: (1023, 17, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 17: (1023, 18, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 18: (1023, 19, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 19: (1023, 0, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_2ND, GET_CORR_1) }) }, + 'ideal': + { 'coherent_ms': 20, + 't_diff_s': 1023 * 1 / gps_constants.l1ca_chip_rate, + 'alias_acc_length_ms': 500, + + 0: (1023, 1, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_1ST,) }), + 1: (1023, 2, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 2: (1023, 3, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 3: (1023, 4, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 4: (1023, 5, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 5: (1023, 6, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 6: (1023, 7, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 7: (1023, 8, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 8: (1023, 9, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 9: (1023, 10, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 10: (1023, 11, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 11: (1023, 12, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 12: (1023, 13, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 13: (1023, 14, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 14: (1023, 15, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 15: (1023, 16, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 16: (1023, 17, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 17: (1023, 18, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 18: (1023, 19, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 19: (1023, 0, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_2ND, GET_CORR_1) }) } + } + } + } + # pessimistic set l1ca_lock_detect_params_pess = {"k1": 0.10, "k2": 1.4, "lp": 200, "lo": 50} diff --git a/peregrine/tracking.py b/peregrine/tracking.py index aa46871..9594d97 100644 --- a/peregrine/tracking.py +++ b/peregrine/tracking.py @@ -127,6 +127,24 @@ def _tracking_channel_factory(parameters): if parameters['acq'].signal == glo_constants.GLO_L1: return TrackingChannelGLOL1(parameters) +def get_fsm_states(ms, short_n_long, bit_sync): + if ms == 1: + ms = '1ms' + if ms == 20: + ms = '20ms' + + if short_n_long: + mode = 'short_n_long' + else: + mode = 'ideal' + + if bit_sync: + bit_sync_status = 'bit_sync' + else: + bit_sync_status = 'no_bit_sync' + + return defaults.fsm_states[ms][bit_sync_status][mode] + class TrackingChannel(object): """ @@ -199,8 +217,11 @@ def __init__(self, params): carr_freq_b1=self.loop_filter_params['carr_freq_b1'], ) - self.next_code_freq = self.loop_filter.to_dict()['code_freq'] - self.next_carr_freq = self.loop_filter.to_dict()['carr_freq'] + self.code_freq_1 = self.code_freq_2 = self.corr_code_freq = \ + self.loop_filter.to_dict()['code_freq'] + + self.carr_freq_1 = self.carr_freq_2 = self.corr_carr_freq = \ + self.loop_filter.to_dict()['carr_freq'] self.track_result = TrackResults(self.results_num, self.acq.prn, @@ -212,6 +233,8 @@ def __init__(self, params): self.sample_index += self.acq.sample_index self.sample_index += self.acq.code_phase * self.samples_per_chip self.sample_index = int(math.floor(self.sample_index)) + self.fsm_states = params['fsm_states'] + self.fsm_step = 0 self.carr_phase_acc = 0.0 self.code_phase_acc = 0.0 self.samples_tracked = 0 @@ -219,22 +242,7 @@ def __init__(self, params): self.started = False self.lock_detect_outo = 0 self.lock_detect_outp = 0 - - self.pipelining = False # Flag if pipelining is used - self.pipelining_k = 0. # Error prediction coefficient for pipelining - self.short_n_long = False # Short/Long cycle simulation - self.short_step = True # Short cycle - if self.tracker_options: - mode = self.tracker_options['mode'] - if mode == 'pipelining': - self.pipelining = True - self.pipelining_k = self.tracker_options['k'] - elif mode == 'short-long-cycles': - self.short_n_long = True - self.pipelining = True - self.pipelining_k = self.tracker_options['k'] - else: - raise ValueError("Invalid tracker mode %s" % str(mode)) + self.E = self.P = self.L = 0.j def dump(self): """ @@ -319,12 +327,6 @@ def _get_result(self): """ return None - def _short_n_long_preprocess(self): - pass - - def _short_n_long_postprocess(self): - pass - def is_pickleable(self): """ Check if object is pickleable. @@ -381,94 +383,70 @@ def run(self, samples): samples_processed = 0 samples_total = len(samples[self.signal]['samples']) - estimated_blksize = self.coherent_ms * self.sampling_freq / 1e3 + coherent_ms = self.fsm_states['coherent_ms'] + estimated_blksize = coherent_ms * self.sampling_freq / 1e3 self.track_result.status = 'T' while self.samples_tracked < self.samples_to_track and \ (sample_index + 2 * estimated_blksize) < samples_total: - self._run_preprocess() - - if self.pipelining: - # Pipelining and prediction - corr_code_freq = self.next_code_freq - corr_carr_freq = self.next_carr_freq - - self.next_code_freq = self.loop_filter.to_dict()['code_freq'] - self.next_carr_freq = self.loop_filter.to_dict()['carr_freq'] - - if self.short_n_long and not self.stage1 and not self.short_step: - # In case of short/long cycles, the correction applicable for the - # long cycle is smaller proportionally to the actual cycle size - pipelining_k = self.pipelining_k / (self.coherent_ms - 1) - else: - pipelining_k = self.pipelining_k - - # There is an error between target frequency and actual one. Affect - # the target frequency according to the computed error - carr_freq_error = self.next_carr_freq - corr_carr_freq - self.next_carr_freq += carr_freq_error * pipelining_k - - code_freq_error = self.next_code_freq - corr_code_freq - self.next_code_freq += code_freq_error * pipelining_k - - else: - # Immediate correction simulation - self.next_code_freq = self.loop_filter.to_dict()['code_freq'] - self.next_carr_freq = self.loop_filter.to_dict()['carr_freq'] - - corr_code_freq = self.next_code_freq - corr_carr_freq = self.next_carr_freq - - if self.short_n_long: - coherent_iter, code_chips_to_integrate = self._short_n_long_preprocess() + cur_fsm_state = self.fsm_states[self.fsm_step] + flags_pre = cur_fsm_state[2]['pre'] + + if defaults.APPLY_CORR_1 in flags_pre: + self.corr_code_freq = self.code_freq_1 + self.corr_carr_freq = self.carr_freq_1 + elif defaults.APPLY_CORR_2 in flags_pre: + self.corr_code_freq = self.code_freq_2 + self.corr_carr_freq = self.carr_freq_2 + + samples_ = samples[self.signal]['samples'][sample_index:] + + E_, P_, L_, blksize, self.code_phase, self.carr_phase = self.correlator( + samples_, + self.code_phase + cur_fsm_state[0], + self.corr_code_freq + self.chipping_rate, self.code_phase, + self.corr_carr_freq + self.IF, self.carr_phase, + self.prn_code, + self.sampling_freq, + self.signal + ) + + sample_index += blksize + samples_processed += blksize + self.carr_phase_acc += self.corr_carr_freq * blksize / self.sampling_freq + self.code_phase_acc += self.corr_code_freq * blksize / self.sampling_freq + estimated_blksize -= blksize + + self.E += E_ + self.P += P_ + self.L += L_ + + flags_post = cur_fsm_state[2]['post'] + self.fsm_step = cur_fsm_state[1] + + if defaults.RUN_LD in flags_post: + # Update PLL lock detector + self.lock_detect_outo, \ + self.lock_detect_outp, \ + lock_detect_pcount1, \ + lock_detect_pcount2, \ + lock_detect_lpfi, \ + lock_detect_lpfq = self.lock_detect.update(self.P.real, + self.P.imag, + 1) + + if self.lock_detect_outo: + if defaults.ALIAS_DETECT_1ST in flags_post or \ + defaults.ALIAS_DETECT_BOTH in flags_post: + self.alias_detector.first(P_) + + if defaults.ALIAS_DETECT_2ND in flags_post or \ + defaults.ALIAS_DETECT_BOTH in flags_post: + self.alias_detector.second(P_) else: - coherent_iter, code_chips_to_integrate = \ - self.alias_detector.preprocess() - self.E = self.P = self.L = 0.j - - # Estimated blksize might change as a result of a change of - # the coherent integration time. - estimated_blksize = self.coherent_ms * self.sampling_freq / 1e3 - if (sample_index + 2 * estimated_blksize) > samples_total: - continue - - for _ in range(coherent_iter): - - samples_ = samples[self.signal]['samples'][sample_index:] - - E_, P_, L_, blksize, self.code_phase, self.carr_phase = self.correlator( - samples_, - self.code_phase + code_chips_to_integrate, - corr_code_freq + self.chipping_rate, self.code_phase, - corr_carr_freq + self.IF, self.carr_phase, - self.prn_code, - self.sampling_freq, - self.signal - ) - - sample_index += blksize - samples_processed += blksize - self.carr_phase_acc += corr_carr_freq * blksize / self.sampling_freq - self.code_phase_acc += corr_code_freq * blksize / self.sampling_freq - - self.E += E_ - self.P += P_ - self.L += L_ - - if self.short_n_long: - continue - - if self.lock_detect_outo: - code_chips_to_integrate = self.alias_detector.postprocess(P_) - else: - self.alias_detector.reinit(self.coherent_ms) - - if self.short_n_long: - more_integration_needed = self._short_n_long_postprocess() - if more_integration_needed: - continue + self.alias_detector.reinit(self.coherent_ms) err_hz = self.alias_detector.get_err_hz() if abs(err_hz) > 0: @@ -477,17 +455,20 @@ def run(self, samples): (self.prn + 1, self.signal, -err_hz)) self.loop_filter.adjust_freq(err_hz) - # Update PLL lock detector - self.lock_detect_outo, \ - self.lock_detect_outp, \ - lock_detect_pcount1, \ - lock_detect_pcount2, \ - lock_detect_lpfi, \ - lock_detect_lpfq = self.lock_detect.update(self.P.real, - self.P.imag, - coherent_iter) + if not (defaults.GET_CORR_1 in flags_post) and \ + not (defaults.GET_CORR_2 in flags_post): + continue + # run tracking loop self.loop_filter.update(self.E, self.P, self.L) + + if defaults.GET_CORR_1 in flags_post: + self.code_freq_1 = self.loop_filter.to_dict()['code_freq'] + self.carr_freq_1 = self.loop_filter.to_dict()['carr_freq'] + elif defaults.GET_CORR_2 in flags_post: + self.code_freq_2 = self.loop_filter.to_dict()['code_freq'] + self.carr_freq_2 = self.loop_filter.to_dict()['carr_freq'] + self.track_result.coherent_ms[self.i] = self.coherent_ms self.track_result.IF = self.IF @@ -526,8 +507,14 @@ def run(self, samples): self.track_result.alias_detect_err_hz[self.i] = err_hz + self._run_preprocess() self._run_postprocess() + # Estimated blksize might change as a result of a change of + # the coherent integration time. + coherent_ms = self.fsm_states['coherent_ms'] + estimated_blksize = coherent_ms * self.sampling_freq / 1e3 + self.samples_tracked = self.sample_index + samples_processed self.track_result.ms_tracked[self.i] = self.samples_tracked * 1e3 / \ self.sampling_freq @@ -536,6 +523,9 @@ def run(self, samples): if self.i >= self.results_num: self.dump() + self.E = self.P = self.L = 0.j + + if self.i > 0: self.dump() @@ -576,7 +566,17 @@ def __init__(self, params): params['chipping_rate'] = gps_constants.l1ca_chip_rate params['sample_index'] = params['samples']['sample_index'] params['alias_detector'] = \ - alias_detector.AliasDetectorL1CA(params['coherent_ms']) + alias_detector.AliasDetector(params['coherent_ms']) + + self.short_n_long = False + if params['tracker_options']: + mode = params['tracker_options']['mode'] + if mode == 'short-long-cycles': + self.short_n_long = True + + params['fsm_states'] = get_fsm_states(ms=params['coherent_ms'], + short_n_long=self.short_n_long, + bit_sync=False) TrackingChannel.__init__(self, params) @@ -616,7 +616,10 @@ def _run_preprocess(self): cutoff_freq=10, loop_freq=1e3 / self.stage2_coherent_ms) - self.coherent_iter = self.coherent_ms + self.fsm_states = get_fsm_states(ms=self.coherent_ms, + short_n_long=self.short_n_long, + bit_sync=True) + def _get_result(self): """ @@ -636,34 +639,6 @@ def _get_result(self): return self.l2c_handover_acq return None - def _short_n_long_preprocess(self): - if self.stage1: - self.E = self.P = self.L = 0.j - else: - # When simulating short and long cycles, short step resets EPL - # registers, and long one adds up to them - if self.short_step: - self.E = self.P = self.L = 0.j - self.coherent_iter = 1 - else: - self.coherent_iter = self.coherent_ms - 1 - - self.code_chips_to_integrate = gps_constants.chips_per_code - - return self.coherent_iter, self.code_chips_to_integrate - - def _short_n_long_postprocess(self): - more_integration_needed = False - if not self.stage1: - if self.short_step: - # In case of short step - go to next integration period - self.short_step = False - more_integration_needed = True - else: - # Next step is short cycle - self.short_step = True - return more_integration_needed - def _run_postprocess(self): """ Run L1C/A coherent integration postprocessing. @@ -736,7 +711,6 @@ def __init__(self, params): cn0_0 += 10 * np.log10(defaults.L2C_CHANNEL_BANDWIDTH_HZ) params['cn0_0'] = cn0_0 params['coherent_ms'] = defaults.l2c_coherent_integration_time_ms - params['coherent_iter'] = 1 params['loop_filter_params'] = defaults.l2c_loop_filter_params params['lock_detect_params'] = defaults.l2c_lock_detect_params_20ms params['IF'] = params['samples'][gps_constants.L2C]['IF'] @@ -746,7 +720,17 @@ def __init__(self, params): params['chipping_rate'] = gps_constants.l2c_chip_rate params['sample_index'] = 0 params['alias_detector'] = \ - alias_detector.AliasDetectorL2C(params['coherent_ms']) + alias_detector.AliasDetector(params['coherent_ms']) + + short_n_long = False + if params['tracker_options']: + mode = params['tracker_options']['mode'] + if mode == 'short-long-cycles': + short_n_long = True + + params['fsm_states'] = get_fsm_states(ms=params['coherent_ms'], + short_n_long=short_n_long, + bit_sync=True) TrackingChannel.__init__(self, params) @@ -763,35 +747,6 @@ def is_pickleable(self): """ return False - def _short_n_long_preprocess(self): - # When simulating short and long cycles, short step resets EPL - # registers, and long one adds up to them - if self.short_step: - self.E = self.P = self.L = 0.j - # L2C CM code is only half of the PRN code length. - # The other half is CL code. Thus multiply by 2. - self.code_chips_to_integrate = \ - int(2 * defaults.l2c_short_step_chips) - else: - # L2C CM code is only half of the PRN code length. - # The other half is CL code. Thus multiply by 2. - self.code_chips_to_integrate = \ - 2 * gps_constants.l2_cm_chips_per_code - \ - self.code_chips_to_integrate - code_chips_to_integrate = self.code_chips_to_integrate - - return self.coherent_iter, code_chips_to_integrate - - def _short_n_long_postprocess(self): - more_integration_needed = False - if self.short_step: - self.short_step = False - more_integration_needed = True - else: - self.short_step = True - - return more_integration_needed - def _run_postprocess(self): """ Run L2C coherent integration postprocessing. From 2728863d6c5c8002e515cf413da28fbe5d81e65b Mon Sep 17 00:00:00 2001 From: Adel Mamin Date: Thu, 28 Jul 2016 16:04:19 +0300 Subject: [PATCH 23/61] Add numbers to samples distribution utility --- peregrine/analysis/samples.py | 37 ++++++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/peregrine/analysis/samples.py b/peregrine/analysis/samples.py index 0ca1821..8b0901b 100755 --- a/peregrine/analysis/samples.py +++ b/peregrine/analysis/samples.py @@ -15,6 +15,8 @@ import matplotlib import matplotlib.pyplot as plt import matplotlib.mlab as mlab +from peregrine import defaults +from peregrine.gps_constants import L1CA, L2C __all__ = ['hist', 'psd', 'summary'] @@ -77,9 +79,20 @@ def hist(samples, ax=None, value_range=None, bin_width=1.0, max_len=ANALYSIS_MAX ticks = np.linspace(min_val, max_val, n_bins) + if min_val == -3 and max_val == 3: + # taken from https://hal-enac.archives-ouvertes.fr/hal-01021721/document + expected_dist = '16.35 33.65 33.65 16.35 [%]' + total = len(samples) + have = str(100 * np.count_nonzero(samples == -3) / total) + ' ' + \ + str(100 * np.count_nonzero(samples == -1) / total) + ' ' + \ + str(100 * np.count_nonzero(samples == 1) / total) + ' ' + \ + str(100 * np.count_nonzero(samples == 3) / total) + ' [%] ' + else: + expected_dist = 'TBD' + ax.hist(samples, bins=bins, color='0.9') - ax.set_title('Histogram') + ax.set_title('Histogram: ' + have + '(expected: ' + expected_dist + ')') ax.set_xlabel('Sample value') if len(ticks) < 22: ax.set_xticks(ticks) @@ -168,12 +181,13 @@ def summary(samples, sampling_freq=None, max_len=ANALYSIS_MAX_LEN): `None` then the whole array will be used. """ + fig = plt.figure() - ax1 = fig.add_subplot(121) - ax2 = fig.add_subplot(122) + ax1 = fig.add_subplot(111) + # ax2 = fig.add_subplot(122) - hist(samples[0], ax=ax1, max_len=max_len) - psd(samples[0], sampling_freq, ax=ax2, max_len=max_len) + hist(samples, ax=ax1, max_len=max_len) + # psd(samples, sampling_freq, ax=ax2, max_len=max_len) fig.set_size_inches(10, 4, forward=True) fig.tight_layout() @@ -193,8 +207,17 @@ def main(): + "'int8', '1bit', '1bitrev' or 'piksi' (default)") args = parser.parse_args() - samples = peregrine.samples.load_samples(args.file, args.num_samples, file_format=args.format) - summary(samples) + # the actual frequency profile is irrelevant for this utility + freq_profile = defaults.freq_profile_high_rate + samples = {L1CA: {'IF': freq_profile['GPS_L1_IF']}, + L2C: {'IF': freq_profile['GPS_L2_IF']}, + 'samples_total': args.num_samples, + 'sample_index': 0} + + samples = peregrine.samples.load_samples(samples=samples, + filename=args.file, + file_format=args.format) + summary(samples['l1ca']['samples']) plt.show() From 0c368f0d59a1ac4fdb2ad0eadfa2c91508df2e14 Mon Sep 17 00:00:00 2001 From: Adel Mamin Date: Fri, 29 Jul 2016 14:55:31 +0300 Subject: [PATCH 24/61] Add more FSM states to cover 2,4,5 and 10 ms integration times --- peregrine/defaults.py | 549 +++++++++++++++++++++++++++++++++++++----- peregrine/tracking.py | 15 +- 2 files changed, 505 insertions(+), 59 deletions(-) diff --git a/peregrine/defaults.py b/peregrine/defaults.py index ea16d40..3c4f796 100644 --- a/peregrine/defaults.py +++ b/peregrine/defaults.py @@ -349,118 +349,553 @@ { 'no_bit_sync': { 'short_n_long': { 'coherent_ms': 1, - 't_diff_s': 1023 * 1 / gps_constants.l1ca_chip_rate, 'alias_acc_length_ms': 500, 0: (1023, 1, {'pre': (APPLY_CORR_1,), 'post': (RUN_LD, GET_CORR_1)}), 1: (1023, 0, {'pre': (APPLY_CORR_2,), 'post': (RUN_LD, GET_CORR_2)}) }, 'ideal': { 'coherent_ms': 1, - 't_diff_s': 1023 * 1 / gps_constants.l1ca_chip_rate, 'alias_acc_length_ms': 500, - 0: (1023, 1, {'pre': (APPLY_CORR_1,), 'post': (RUN_LD, GET_CORR_2)}), - 1: (1023, 0, {'pre': (APPLY_CORR_2,), 'post': (RUN_LD, GET_CORR_1)}) } + 0: (1023, 0, {'pre': (APPLY_CORR_1,), 'post': (RUN_LD, GET_CORR_1)}) } }, 'bit_sync': { 'short_n_long': { 'coherent_ms': 1, - 't_diff_s': 1023 * 1 / gps_constants.l1ca_chip_rate, 'alias_acc_length_ms': 500, - # start-up - 0: (1023, 2, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_1ST, GET_CORR_1) }), - - # normal - 1: (1023, 2, {'pre': (APPLY_CORR_1,), + 0: (1023, 1, {'pre': (APPLY_CORR_1,), 'post': (RUN_LD, ALIAS_DETECT_1ST, GET_CORR_1) }), - 2: (1023, 3, {'pre': (APPLY_CORR_2,), + 1: (1023, 2, {'pre': (APPLY_CORR_2,), 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_2) }), - 3: (1023, 4, {'pre': (APPLY_CORR_1,), + 2: (1023, 3, {'pre': (APPLY_CORR_1,), 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), - 4: (1023, 5, {'pre': (APPLY_CORR_2,), + 3: (1023, 4, {'pre': (APPLY_CORR_2,), 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_2) }), - 5: (1023, 6, {'pre': (APPLY_CORR_1,), + 4: (1023, 5, {'pre': (APPLY_CORR_1,), 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), - 6: (1023, 7, {'pre': (APPLY_CORR_2,), + 5: (1023, 6, {'pre': (APPLY_CORR_2,), 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_2) }), - 7: (1023, 8, {'pre': (APPLY_CORR_1,), + 6: (1023, 7, {'pre': (APPLY_CORR_1,), 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), - 8: (1023, 9, {'pre': (APPLY_CORR_2,), + 7: (1023, 8, {'pre': (APPLY_CORR_2,), 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_2) }), - 9: (1023, 10, {'pre': (APPLY_CORR_1,), + 8: (1023, 9, {'pre': (APPLY_CORR_1,), 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), - 10: (1023, 11, {'pre': (APPLY_CORR_2,), + 9: (1023, 10, {'pre': (APPLY_CORR_2,), 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_2) }), - 11: (1023, 12, {'pre': (APPLY_CORR_1,), + 10: (1023, 11, {'pre': (APPLY_CORR_1,), 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), - 12: (1023, 13, {'pre': (APPLY_CORR_2,), + 11: (1023, 12, {'pre': (APPLY_CORR_2,), 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_2) }), - 13: (1023, 14, {'pre': (APPLY_CORR_1,), + 12: (1023, 13, {'pre': (APPLY_CORR_1,), 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), - 14: (1023, 15, {'pre': (APPLY_CORR_2,), + 13: (1023, 14, {'pre': (APPLY_CORR_2,), 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_2) }), - 15: (1023, 16, {'pre': (APPLY_CORR_1,), + 14: (1023, 15, {'pre': (APPLY_CORR_1,), 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), - 16: (1023, 17, {'pre': (APPLY_CORR_2,), + 15: (1023, 16, {'pre': (APPLY_CORR_2,), 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_2) }), - 17: (1023, 18, {'pre': (APPLY_CORR_1,), + 16: (1023, 17, {'pre': (APPLY_CORR_1,), 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), - 18: (1023, 19, {'pre': (APPLY_CORR_2,), + 17: (1023, 18, {'pre': (APPLY_CORR_2,), 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_2) }), - 19: (1023, 20, {'pre': (APPLY_CORR_1,), + 18: (1023, 19, {'pre': (APPLY_CORR_1,), 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), - 20: (1023, 1, {'pre': (APPLY_CORR_2,), + 19: (1023, 0, {'pre': (APPLY_CORR_2,), 'post': (RUN_LD, ALIAS_DETECT_2ND, GET_CORR_2) }) }, 'ideal': { 'coherent_ms': 1, - 't_diff_s': 1023 * 1 / gps_constants.l1ca_chip_rate, 'alias_acc_length_ms': 500, - # start-up - 0: (1023, 2, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_1ST, GET_CORR_2) }), - - # normal + 0: (1023, 1, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_1ST, GET_CORR_1) }), 1: (1023, 2, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_1ST, GET_CORR_2) }), - 2: (1023, 3, {'pre': (APPLY_CORR_2,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), + 2: (1023, 3, {'pre': (APPLY_CORR_1,), 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), 3: (1023, 4, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_2) }), - 4: (1023, 5, {'pre': (APPLY_CORR_2,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), + 4: (1023, 5, {'pre': (APPLY_CORR_1,), 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), 5: (1023, 6, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_2) }), - 6: (1023, 7, {'pre': (APPLY_CORR_2,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), + 6: (1023, 7, {'pre': (APPLY_CORR_1,), 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), 7: (1023, 8, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_2) }), - 8: (1023, 9, {'pre': (APPLY_CORR_2,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), + 8: (1023, 9, {'pre': (APPLY_CORR_1,), 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), 9: (1023, 10, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_2) }), - 10: (1023, 11, {'pre': (APPLY_CORR_2,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), + 10: (1023, 11, {'pre': (APPLY_CORR_1,), 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), 11: (1023, 12, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_2) }), - 12: (1023, 13, {'pre': (APPLY_CORR_2,), 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), + 12: (1023, 13, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), 13: (1023, 14, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_2) }), - 14: (1023, 15, {'pre': (APPLY_CORR_2,), 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), + 14: (1023, 15, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), 15: (1023, 16, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_2) }), - 16: (1023, 17, {'pre': (APPLY_CORR_2,), 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), + 16: (1023, 17, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), 17: (1023, 18, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_2) }), - 18: (1023, 19, {'pre': (APPLY_CORR_2,), 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), - 19: (1023, 20, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_2) }), - 20: (1023, 1, {'pre': (APPLY_CORR_2,), + 18: (1023, 19, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), + 19: (1023, 0, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_2ND, GET_CORR_1) }) }, + } + }, + + '2ms': + { 'no_bit_sync': + { 'short_n_long': + { 'coherent_ms': 2, + 'alias_acc_length_ms': 500, + 0: (1023, 1, {'pre': (APPLY_CORR_1,), 'post': (RUN_LD, GET_CORR_1)}), + 1: (1023, 0, {'pre': (APPLY_CORR_2,), 'post': (RUN_LD, GET_CORR_2)}) }, + + 'ideal': + { 'coherent_ms': 2, + 'alias_acc_length_ms': 500, + 0: (1023, 1, {'pre': (APPLY_CORR_1,), 'post': (RUN_LD,)}), + 1: (1023, 0, {'pre': (), 'post': (RUN_LD, GET_CORR_1)}) } + }, + 'bit_sync': + { 'short_n_long': + { 'coherent_ms': 2, + 'alias_acc_length_ms': 500, + + 0: (1023, 1, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_1ST) }), + 1: (1023, 2, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), + 2: (1023, 3, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 3: (1023, 4, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), + 4: (1023, 5, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 5: (1023, 6, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), + 6: (1023, 7, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 7: (1023, 8, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), + 8: (1023, 9, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 9: (1023, 10, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), + 10: (1023, 11, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 11: (1023, 12, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), + 12: (1023, 13, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 13: (1023, 14, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), + 14: (1023, 15, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 15: (1023, 16, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), + 16: (1023, 17, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 17: (1023, 18, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), + 18: (1023, 19, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 19: (1023, 0, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_2ND, GET_CORR_1) }) }, + 'ideal': + { 'coherent_ms': 2, + 'alias_acc_length_ms': 500, + + 0: (1023, 1, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_1ST) }), + 1: (1023, 2, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), + 2: (1023, 3, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 3: (1023, 4, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), + 4: (1023, 5, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 5: (1023, 6, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), + 6: (1023, 7, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 7: (1023, 8, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), + 8: (1023, 9, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 9: (1023, 10, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), + 10: (1023, 11, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 11: (1023, 12, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), + 12: (1023, 13, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 13: (1023, 14, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), + 14: (1023, 15, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 15: (1023, 16, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), + 16: (1023, 17, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 17: (1023, 18, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), + 18: (1023, 19, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 19: (1023, 0, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_2ND, GET_CORR_1) }) }, + } + }, + + '4ms': + { 'no_bit_sync': + { 'short_n_long': + { 'coherent_ms': 4, + 'alias_acc_length_ms': 500, + 0: (1023, 1, {'pre': (), 'post': (RUN_LD,)}), + 1: (1023, 2, {'pre': (APPLY_CORR_1,), 'post': (RUN_LD,)}), + 2: (1023, 3, {'pre': (), 'post': (RUN_LD,)}), + 3: (1023, 0, {'pre': (), 'post': (RUN_LD, GET_CORR_1)}) }, + + 'ideal': + { 'coherent_ms': 4, + 'alias_acc_length_ms': 500, + 0: (1023, 1, {'pre': (APPLY_CORR_1,), 'post': (RUN_LD,)}), + 1: (1023, 2, {'pre': (), 'post': (RUN_LD,)}), + 2: (1023, 3, {'pre': (), 'post': (RUN_LD,)}), + 3: (1023, 0, {'pre': (), 'post': (RUN_LD, GET_CORR_1)}) } + }, + 'bit_sync': + { 'short_n_long': + { 'coherent_ms': 4, + 'alias_acc_length_ms': 500, + + 0: (1023, 1, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_1ST) }), + 1: (1023, 2, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 2: (1023, 3, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 3: (1023, 4, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), + 4: (1023, 5, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 5: (1023, 6, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 6: (1023, 7, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 7: (1023, 8, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), + 8: (1023, 9, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 9: (1023, 10, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 10: (1023, 11, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 11: (1023, 12, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), + 12: (1023, 13, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 13: (1023, 14, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 14: (1023, 15, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 15: (1023, 16, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), + 16: (1023, 17, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 17: (1023, 18, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 18: (1023, 19, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 19: (1023, 0, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_2ND, GET_CORR_1) }) }, + 'ideal': + { 'coherent_ms': 4, + 'alias_acc_length_ms': 500, + + 0: (1023, 1, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_1ST) }), + 1: (1023, 2, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 2: (1023, 3, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 3: (1023, 4, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), + 4: (1023, 5, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 5: (1023, 6, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 6: (1023, 7, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 7: (1023, 8, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), + 8: (1023, 9, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 9: (1023, 10, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 10: (1023, 11, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 11: (1023, 12, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), + 12: (1023, 13, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 13: (1023, 14, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 14: (1023, 15, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 15: (1023, 16, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), + 16: (1023, 17, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 17: (1023, 18, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 18: (1023, 19, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 19: (1023, 0, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_2ND, GET_CORR_1) }) }, + } + }, + + '5ms': + { 'no_bit_sync': + { 'short_n_long': + { 'coherent_ms': 5, + 'alias_acc_length_ms': 500, + 0: (1023, 1, {'pre': (), 'post': (RUN_LD,)}), + 1: (1023, 2, {'pre': (APPLY_CORR_1,), 'post': (RUN_LD,)}), + 2: (1023, 3, {'pre': (), 'post': (RUN_LD,)}), + 3: (1023, 4, {'pre': (), 'post': (RUN_LD,)}), + 4: (1023, 0, {'pre': (), 'post': (RUN_LD, GET_CORR_1)}) }, + + 'ideal': + { 'coherent_ms': 5, + 'alias_acc_length_ms': 500, + 0: (1023, 1, {'pre': (APPLY_CORR_1,), 'post': (RUN_LD,)}), + 1: (1023, 2, {'pre': (), 'post': (RUN_LD,)}), + 2: (1023, 3, {'pre': (), 'post': (RUN_LD,)}), + 3: (1023, 4, {'pre': (), 'post': (RUN_LD,)}), + 4: (1023, 0, {'pre': (), 'post': (RUN_LD, GET_CORR_1)}) } + }, + 'bit_sync': + { 'short_n_long': + { 'coherent_ms': 5, + 'alias_acc_length_ms': 500, + + 0: (1023, 1, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_1ST) }), + 1: (1023, 2, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 2: (1023, 3, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 3: (1023, 4, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 4: (1023, 5, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), + 5: (1023, 6, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 6: (1023, 7, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 7: (1023, 8, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 8: (1023, 9, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 9: (1023, 10, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), + 10: (1023, 11, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 11: (1023, 12, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 12: (1023, 13, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 13: (1023, 14, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 14: (1023, 15, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), + 15: (1023, 16, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 16: (1023, 17, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 17: (1023, 18, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 18: (1023, 19, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 19: (1023, 0, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_2ND, GET_CORR_1) }) }, + 'ideal': + { 'coherent_ms': 5, + 'alias_acc_length_ms': 500, + + 0: (1023, 1, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_1ST) }), + 1: (1023, 2, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 2: (1023, 3, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 3: (1023, 4, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 4: (1023, 5, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), + 5: (1023, 6, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 6: (1023, 7, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 7: (1023, 8, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 8: (1023, 9, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 9: (1023, 10, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), + 10: (1023, 11, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 11: (1023, 12, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 12: (1023, 13, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 13: (1023, 14, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 14: (1023, 15, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), + 15: (1023, 16, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 16: (1023, 17, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 17: (1023, 18, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 18: (1023, 19, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 19: (1023, 0, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_2ND, GET_CORR_1) }) }, + } + }, + + '10ms': + { 'no_bit_sync': + { 'short_n_long': + { 'coherent_ms': 10, + 'alias_acc_length_ms': 500, + 0: (1023, 1, {'pre': (), 'post': (RUN_LD,)}), + 1: (1023, 2, {'pre': (APPLY_CORR_1,), 'post': (RUN_LD,)}), + 2: (1023, 3, {'pre': (), 'post': (RUN_LD,)}), + 3: (1023, 4, {'pre': (), 'post': (RUN_LD,)}), + 4: (1023, 5, {'pre': (), 'post': (RUN_LD,)}), + 5: (1023, 6, {'pre': (), 'post': (RUN_LD,)}), + 6: (1023, 7, {'pre': (), 'post': (RUN_LD,)}), + 7: (1023, 8, {'pre': (), 'post': (RUN_LD,)}), + 8: (1023, 9, {'pre': (), 'post': (RUN_LD,)}), + 9: (1023, 0, {'pre': (), 'post': (RUN_LD, GET_CORR_1)}) }, + + 'ideal': + { 'coherent_ms': 10, + 'alias_acc_length_ms': 500, + 0: (1023, 1, {'pre': (APPLY_CORR_1,), 'post': (RUN_LD,)}), + 1: (1023, 2, {'pre': (), 'post': (RUN_LD,)}), + 2: (1023, 3, {'pre': (), 'post': (RUN_LD,)}), + 3: (1023, 4, {'pre': (), 'post': (RUN_LD,)}), + 4: (1023, 5, {'pre': (), 'post': (RUN_LD,)}), + 5: (1023, 6, {'pre': (), 'post': (RUN_LD,)}), + 6: (1023, 7, {'pre': (), 'post': (RUN_LD,)}), + 7: (1023, 8, {'pre': (), 'post': (RUN_LD,)}), + 8: (1023, 9, {'pre': (), 'post': (RUN_LD,)}), + 9: (1023, 0, {'pre': (), 'post': (RUN_LD, GET_CORR_1)}) } + }, + 'bit_sync': + { 'short_n_long': + { 'coherent_ms': 10, + 'alias_acc_length_ms': 500, + + 0: (1023, 1, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_1ST) }), + 1: (1023, 2, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 2: (1023, 3, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 3: (1023, 4, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 4: (1023, 5, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 5: (1023, 6, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 6: (1023, 7, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 7: (1023, 8, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 8: (1023, 9, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 9: (1023, 10, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 10: (1023, 11, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 11: (1023, 12, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 12: (1023, 13, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 13: (1023, 14, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 14: (1023, 15, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 15: (1023, 16, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 16: (1023, 17, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 17: (1023, 18, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 18: (1023, 19, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 19: (1023, 0, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_2ND, GET_CORR_1) }) }, + 'ideal': + { 'coherent_ms': 10, + 'alias_acc_length_ms': 500, + + 0: (1023, 1, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_1ST) }), + 1: (1023, 2, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 2: (1023, 3, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 3: (1023, 4, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 4: (1023, 5, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 5: (1023, 6, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 6: (1023, 7, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 7: (1023, 8, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 8: (1023, 9, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 9: (1023, 10, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 10: (1023, 11, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 11: (1023, 12, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 12: (1023, 13, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 13: (1023, 14, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 14: (1023, 15, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 15: (1023, 16, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 16: (1023, 17, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 17: (1023, 18, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 18: (1023, 19, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 19: (1023, 0, {'pre': (), 'post': (RUN_LD, ALIAS_DETECT_2ND, GET_CORR_1) }) }, } }, diff --git a/peregrine/tracking.py b/peregrine/tracking.py index 9594d97..f7cc149 100644 --- a/peregrine/tracking.py +++ b/peregrine/tracking.py @@ -130,8 +130,18 @@ def _tracking_channel_factory(parameters): def get_fsm_states(ms, short_n_long, bit_sync): if ms == 1: ms = '1ms' - if ms == 20: + elif ms == 2: + ms = '2ms' + elif ms == 4: + ms = '4ms' + elif ms == 5: + ms = '5ms' + elif ms == 10: + ms = '10ms' + elif ms == 20: ms = '20ms' + else: + raise ValueError("Not implemented!") if short_n_long: mode = 'short_n_long' @@ -507,8 +517,8 @@ def run(self, samples): self.track_result.alias_detect_err_hz[self.i] = err_hz - self._run_preprocess() self._run_postprocess() + self._run_preprocess() # Estimated blksize might change as a result of a change of # the coherent integration time. @@ -619,6 +629,7 @@ def _run_preprocess(self): self.fsm_states = get_fsm_states(ms=self.coherent_ms, short_n_long=self.short_n_long, bit_sync=True) + self.fsm_step = 0 def _get_result(self): From 59e3c94159354a06836b4a68dcccaa1c4ecb9159 Mon Sep 17 00:00:00 2001 From: Adel Mamin Date: Wed, 3 Aug 2016 14:43:17 +0300 Subject: [PATCH 25/61] Add profile switching logic --- peregrine/analysis/tracking_loop.py | 7 - peregrine/defaults.py | 504 +++++++++++++++++++++++++++- peregrine/tracking.py | 434 +++++++++++++++++------- peregrine/tracking_loop.py | 22 +- 4 files changed, 823 insertions(+), 144 deletions(-) diff --git a/peregrine/analysis/tracking_loop.py b/peregrine/analysis/tracking_loop.py index 1fdcca4..065a290 100755 --- a/peregrine/analysis/tracking_loop.py +++ b/peregrine/analysis/tracking_loop.py @@ -134,11 +134,6 @@ def main(): if args.l1ca_profile: profile = defaults.l1ca_stage_profiles[args.l1ca_profile] - stage2_coherent_ms = profile[1]['coherent_ms'] - stage2_params = profile[1]['loop_filter_params'] - else: - stage2_coherent_ms = None - stage2_params = None samples = {L1CA: {'IF': freq_profile['GPS_L1_IF']}, L2C: {'IF': freq_profile['GPS_L2_IF']}, @@ -178,8 +173,6 @@ def main(): ms_to_track=ms_to_process, sampling_freq=sampling_freq, # [Hz] l2c_handover=l2c_handover, - stage2_coherent_ms=stage2_coherent_ms, - stage2_loop_filter_params=stage2_params, tracker_options=tracker_options, output_file=args.output_file, progress_bar_output=args.progress_bar, diff --git a/peregrine/defaults.py b/peregrine/defaults.py index 3c4f796..2504210 100644 --- a/peregrine/defaults.py +++ b/peregrine/defaults.py @@ -205,6 +205,502 @@ "carr_k": 1, # Carrier loop k "carr_freq_b1": 1} # Carrier loop aiding_igain +l1ca_track_params = { + 'fll_bw': (0,), + 'pll_bw': (20,), #, 20, 14, 10, 8, 6, 4, 2), + 'coherent_ms': (1,) }# 2, 4, 5, 10, 20) } + +l1ca_loop_filter_params_template = { + 'code_params': (1., 0.7, 1.), # NBW, zeta, k + 'carr_params': (20., 0.7, 1.), # NBW, zeta, k + 'loop_freq': 1000., # 1000/coherent_ms + 'carr_freq_b1': 1., # FLL NBW + 'carr_to_code': 1540. # carr_to_code + } + +# l1ca_track_profiles_fll = { +# 0: ({'coherent_ms': 1, +# 'stabilization_time_ms': 50, +# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k +# 'carr_params': (20., 0.7, 1.), # NBW, zeta, k +# 'loop_freq': 1000., # 1000/coherent_ms +# 'carr_freq_b1': 1., # FLL NBW +# 'carr_to_code': 1540. # carr_to_code +# } +# }, 1), +# 1: ({'coherent_ms': 4, +# 'stabilization_time_ms': 50, +# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k +# 'carr_params': (8, 0.7, 1.), # NBW, zeta, k +# 'loop_freq': 1000./4, # 1000/coherent_ms +# 'carr_freq_b1': 0., # FLL NBW +# 'carr_to_code': 1540. # carr_to_code +# } +# }, 1) } + +# l1ca_track_response = { +# 0: ({'coherent_ms': 1, +# 'stabilization_time_ms': 50, +# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k +# 'carr_params': (20., 0.7, 1.), # NBW, zeta, k +# 'loop_freq': 1000., # 1000/coherent_ms +# 'carr_freq_b1': 1., # FLL NBW +# 'carr_to_code': 1540. # carr_to_code +# } +# }, 0 } + +# l1ca_track_recovery = { +# 0: ({'coherent_ms': 1, +# 'stabilization_time_ms': 50, +# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k +# 'carr_params': (20., 0.7, 1.), # NBW, zeta, k +# 'loop_freq': 1000., # 1000/coherent_ms +# 'carr_freq_b1': 0., # FLL NBW +# 'carr_to_code': 1540. # carr_to_code +# } +# }, 0 } + +# l1ca_track_profiles = { +# # init state +# 0: ({'coherent_ms': 1, +# 'stabilization_time_ms': 50, +# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k +# 'carr_params': (20., 0.7, 1.), # NBW, zeta, k +# 'loop_freq': 1000., # 1000/coherent_ms +# 'carr_freq_b1': 1., # FLL NBW +# 'carr_to_code': 1540. # carr_to_code +# } +# }, {'next_bw': 1, 'next_time': 1}), + +# # 1ms +# 1: ({'coherent_ms': 1, +# 'stabilization_time_ms': 50, +# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k +# 'carr_params': (20., 0.7, 1.), # NBW, zeta, k +# 'loop_freq': 1000., # 1000/coherent_ms +# 'carr_freq_b1': 0., # FLL NBW +# 'carr_to_code': 1540. # carr_to_code +# } +# }, {'next_bw': 2, 'next_time': 8}), + +# 2: ({'coherent_ms': 1, +# 'stabilization_time_ms': 50, +# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k +# 'carr_params': (14., 0.7, 1.), # NBW, zeta, k +# 'loop_freq': 1000., # 1000/coherent_ms +# 'carr_freq_b1': 0., # FLL NBW +# 'carr_to_code': 1540. # carr_to_code +# } +# }, {'next_bw': 3, 'next_time': 9}), + +# 3: ({'coherent_ms': 1, +# 'stabilization_time_ms': 50, +# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k +# 'carr_params': (10, 0.7, 1.), # NBW, zeta, k +# 'loop_freq': 1000., # 1000/coherent_ms +# 'carr_freq_b1': 0., # FLL NBW +# 'carr_to_code': 1540. # carr_to_code +# } +# }, {'next_bw': 4, 'next_time': 10}), + +# 4: ({'coherent_ms': 1, +# 'stabilization_time_ms': 50, +# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k +# 'carr_params': (8, 0.7, 1.), # NBW, zeta, k +# 'loop_freq': 1000., # 1000/coherent_ms +# 'carr_freq_b1': 0., # FLL NBW +# 'carr_to_code': 1540. # carr_to_code +# } +# }, {'next_bw': 5, 'next_time': 11}), + +# 5: ({'coherent_ms': 1, +# 'stabilization_time_ms': 50, +# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k +# 'carr_params': (6, 0.7, 1.), # NBW, zeta, k +# 'loop_freq': 1000., # 1000/coherent_ms +# 'carr_freq_b1': 0., # FLL NBW +# 'carr_to_code': 1540. # carr_to_code +# } +# }, {'next_bw': 6, 'next_time': 12}), + +# 6: ({'coherent_ms': 1, +# 'stabilization_time_ms': 50, +# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k +# 'carr_params': (4, 0.7, 1.), # NBW, zeta, k +# 'loop_freq': 1000., # 1000/coherent_ms +# 'carr_freq_b1': 0., # FLL NBW +# 'carr_to_code': 1540. # carr_to_code +# } +# }, {'next_bw': 7, 'next_time': 13}), + +# 7: ({'coherent_ms': 1, +# 'stabilization_time_ms': 50, +# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k +# 'carr_params': (2, 0.7, 1.), # NBW, zeta, k +# 'loop_freq': 1000., # 1000/coherent_ms +# 'carr_freq_b1': 0., # FLL NBW +# 'carr_to_code': 1540. # carr_to_code +# } +# }, {'next_bw': 7, 'next_time': 14}), + +# # 2ms +# 8: ({'coherent_ms': 2, +# 'stabilization_time_ms': 50, +# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k +# 'carr_params': (20., 0.7, 1.), # NBW, zeta, k +# 'loop_freq': 1000. / 2, # 1000/coherent_ms +# 'carr_freq_b1': 0., # FLL NBW +# 'carr_to_code': 1540. # carr_to_code +# } +# }, {'next_bw': 9, 'next_time': 15}), + +# 9: ({'coherent_ms': 2, +# 'stabilization_time_ms': 50, +# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k +# 'carr_params': (14., 0.7, 1.), # NBW, zeta, k +# 'loop_freq': 1000. / 2, # 1000/coherent_ms +# 'carr_freq_b1': 0., # FLL NBW +# 'carr_to_code': 1540. # carr_to_code +# } +# }, {'next_bw': 10, 'next_time': 16}), + +# 10: ({'coherent_ms': 2, +# 'stabilization_time_ms': 50, +# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k +# 'carr_params': (10, 0.7, 1.), # NBW, zeta, k +# 'loop_freq': 1000. / 2, # 1000/coherent_ms +# 'carr_freq_b1': 0., # FLL NBW +# 'carr_to_code': 1540. # carr_to_code +# } +# }, {'next_bw': 11, 'next_time': 17}), + +# 11: ({'coherent_ms': 2, +# 'stabilization_time_ms': 50, +# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k +# 'carr_params': (8, 0.7, 1.), # NBW, zeta, k +# 'loop_freq': 1000. / 2, # 1000/coherent_ms +# 'carr_freq_b1': 0., # FLL NBW +# 'carr_to_code': 1540. # carr_to_code +# } +# }, {'next_bw': 12, 'next_time': 18}), + +# 12: ({'coherent_ms': 2, +# 'stabilization_time_ms': 50, +# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k +# 'carr_params': (6, 0.7, 1.), # NBW, zeta, k +# 'loop_freq': 1000. / 2, # 1000/coherent_ms +# 'carr_freq_b1': 0., # FLL NBW +# 'carr_to_code': 1540. # carr_to_code +# } +# }, {'next_bw': 13, 'next_time': 19}), + +# 13: ({'coherent_ms':21, +# 'stabilization_time_ms': 50, +# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k +# 'carr_params': (4, 0.7, 1.), # NBW, zeta, k +# 'loop_freq': 1000. / 2, # 1000/coherent_ms +# 'carr_freq_b1': 0., # FLL NBW +# 'carr_to_code': 1540. # carr_to_code +# } +# }, {'next_bw': 14, 'next_time': 20}), + +# 14: ({'coherent_ms': 2, +# 'stabilization_time_ms': 50, +# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k +# 'carr_params': (2, 0.7, 1.), # NBW, zeta, k +# 'loop_freq': 1000. / 2, # 1000/coherent_ms +# 'carr_freq_b1': 0., # FLL NBW +# 'carr_to_code': 1540. # carr_to_code +# } +# }, {'next_bw': 14, 'next_time': 21}), + +# # 4ms + +# 15: ({'coherent_ms': 4, +# 'stabilization_time_ms': 50, +# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k +# 'carr_params': (20., 0.7, 1.), # NBW, zeta, k +# 'loop_freq': 1000. / 4, # 1000/coherent_ms +# 'carr_freq_b1': 0., # FLL NBW +# 'carr_to_code': 1540. # carr_to_code +# } +# }, {'next_bw': 16, 'next_time': 22}), + +# 16: ({'coherent_ms': 4, +# 'stabilization_time_ms': 50, +# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k +# 'carr_params': (14., 0.7, 1.), # NBW, zeta, k +# 'loop_freq': 1000. / 4, # 1000/coherent_ms +# 'carr_freq_b1': 0., # FLL NBW +# 'carr_to_code': 1540. # carr_to_code +# } +# }, {'next_bw': 17, 'next_time': 23}), + +# 17: ({'coherent_ms': 4, +# 'stabilization_time_ms': 50, +# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k +# 'carr_params': (10, 0.7, 1.), # NBW, zeta, k +# 'loop_freq': 1000. / 4, # 1000/coherent_ms +# 'carr_freq_b1': 0., # FLL NBW +# 'carr_to_code': 1540. # carr_to_code +# } +# }, {'next_bw': 18, 'next_time':24}), + +# 18: ({'coherent_ms': 4, +# 'stabilization_time_ms': 50, +# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k +# 'carr_params': (8, 0.7, 1.), # NBW, zeta, k +# 'loop_freq': 1000. / 4, # 1000/coherent_ms +# 'carr_freq_b1': 0., # FLL NBW +# 'carr_to_code': 1540. # carr_to_code +# } +# }, {'next_bw': 19, 'next_time': 25}), + +# 19: ({'coherent_ms': 4, +# 'stabilization_time_ms': 50, +# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k +# 'carr_params': (6, 0.7, 1.), # NBW, zeta, k +# 'loop_freq': 1000. / 4, # 1000/coherent_ms +# 'carr_freq_b1': 0., # FLL NBW +# 'carr_to_code': 1540. # carr_to_code +# } +# }, {'next_bw': 20, 'next_time': 26}), + +# 20: ({'coherent_ms': 4, +# 'stabilization_time_ms': 50, +# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k +# 'carr_params': (4, 0.7, 1.), # NBW, zeta, k +# 'loop_freq': 1000. / 4, # 1000/coherent_ms +# 'carr_freq_b1': 0., # FLL NBW +# 'carr_to_code': 1540. # carr_to_code +# } +# }, {'next_bw': 21, 'next_time': 27}), + +# 21: ({'coherent_ms': 4, +# 'stabilization_time_ms': 50, +# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k +# 'carr_params': (2, 0.7, 1.), # NBW, zeta, k +# 'loop_freq': 1000. / 4, # 1000/coherent_ms +# 'carr_freq_b1': 0., # FLL NBW +# 'carr_to_code': 1540. # carr_to_code +# } +# }, {'next_bw': 21, 'next_time': 28}), + +# # 5ms +# 22: ({'coherent_ms': 5, +# 'stabilization_time_ms': 50, +# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k +# 'carr_params': (20., 0.7, 1.), # NBW, zeta, k +# 'loop_freq': 1000. / 5, # 1000/coherent_ms +# 'carr_freq_b1': 0., # FLL NBW +# 'carr_to_code': 1540. # carr_to_code +# } +# }, {'next_bw': 23, 'next_time': 29}), + +# 23: ({'coherent_ms': 5, +# 'stabilization_time_ms': 50, +# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k +# 'carr_params': (14., 0.7, 1.), # NBW, zeta, k +# 'loop_freq': 1000. / 5, # 1000/coherent_ms +# 'carr_freq_b1': 0., # FLL NBW +# 'carr_to_code': 1540. # carr_to_code +# } +# }, {'next_bw': 24, 'next_time': 30}), + +# 24: ({'coherent_ms': 5, +# 'stabilization_time_ms': 50, +# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k +# 'carr_params': (10, 0.7, 1.), # NBW, zeta, k +# 'loop_freq': 1000. / 5, # 1000/coherent_ms +# 'carr_freq_b1': 0., # FLL NBW +# 'carr_to_code': 1540. # carr_to_code +# } +# }, {'next_bw': 25, 'next_time': 31}), + +# 25: ({'coherent_ms': 5, +# 'stabilization_time_ms': 50, +# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k +# 'carr_params': (8, 0.7, 1.), # NBW, zeta, k +# 'loop_freq': 1000. / 5, # 1000/coherent_ms +# 'carr_freq_b1': 0., # FLL NBW +# 'carr_to_code': 1540. # carr_to_code +# } +# }, {'next_bw': 26, 'next_time': 32}), + +# 26: ({'coherent_ms': 5, +# 'stabilization_time_ms': 50, +# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k +# 'carr_params': (6, 0.7, 1.), # NBW, zeta, k +# 'loop_freq': 1000. / 5, # 1000/coherent_ms +# 'carr_freq_b1': 0., # FLL NBW +# 'carr_to_code': 1540. # carr_to_code +# } +# }, {'next_bw': 27, 'next_time': 33}), + +# 27: ({'coherent_ms': 5, +# 'stabilization_time_ms': 50, +# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k +# 'carr_params': (4, 0.7, 1.), # NBW, zeta, k +# 'loop_freq': 1000. / 5, # 1000/coherent_ms +# 'carr_freq_b1': 0., # FLL NBW +# 'carr_to_code': 1540. # carr_to_code +# } +# }, {'next_bw': 28, 'next_time': 34}), + +# 28: ({'coherent_ms': 5, +# 'stabilization_time_ms': 50, +# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k +# 'carr_params': (2, 0.7, 1.), # NBW, zeta, k +# 'loop_freq': 1000. / 5, # 1000/coherent_ms +# 'carr_freq_b1': 0., # FLL NBW +# 'carr_to_code': 1540. # carr_to_code +# } +# }, {'next_bw': 28, 'next_time': 35}), + +# # 10ms + +# 29: ({'coherent_ms': 10, +# 'stabilization_time_ms': 50, +# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k +# 'carr_params': (20., 0.7, 1.), # NBW, zeta, k +# 'loop_freq': 1000. / 10, # 1000/coherent_ms +# 'carr_freq_b1': 0., # FLL NBW +# 'carr_to_code': 1540. # carr_to_code +# } +# }, {'next_bw': 30, 'next_time': 36}), + +# 30: ({'coherent_ms': 10, +# 'stabilization_time_ms': 50, +# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k +# 'carr_params': (14., 0.7, 1.), # NBW, zeta, k +# 'loop_freq': 1000. / 10, # 1000/coherent_ms +# 'carr_freq_b1': 0., # FLL NBW +# 'carr_to_code': 1540. # carr_to_code +# } +# }, {'next_bw': 31, 'next_time': 37}), + +# 31: ({'coherent_ms': 10, +# 'stabilization_time_ms': 50, +# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k +# 'carr_params': (10, 0.7, 1.), # NBW, zeta, k +# 'loop_freq': 1000. / 10, # 1000/coherent_ms +# 'carr_freq_b1': 0., # FLL NBW +# 'carr_to_code': 1540. # carr_to_code +# } +# }, {'next_bw': 32, 'next_time': 38}), + +# 32: ({'coherent_ms': 10, +# 'stabilization_time_ms': 50, +# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k +# 'carr_params': (8, 0.7, 1.), # NBW, zeta, k +# 'loop_freq': 1000. / 10, # 1000/coherent_ms +# 'carr_freq_b1': 0., # FLL NBW +# 'carr_to_code': 1540. # carr_to_code +# } +# }, {'next_bw': 33, 'next_time': 39}), + +# 33: ({'coherent_ms': 10, +# 'stabilization_time_ms': 50, +# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k +# 'carr_params': (6, 0.7, 1.), # NBW, zeta, k +# 'loop_freq': 1000. / 10, # 1000/coherent_ms +# 'carr_freq_b1': 0., # FLL NBW +# 'carr_to_code': 1540. # carr_to_code +# } +# }, {'next_bw': 34, 'next_time': 40}), + +# 34: ({'coherent_ms': 10, +# 'stabilization_time_ms': 50, +# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k +# 'carr_params': (4, 0.7, 1.), # NBW, zeta, k +# 'loop_freq': 1000. / 10, # 1000/coherent_ms +# 'carr_freq_b1': 0., # FLL NBW +# 'carr_to_code': 1540. # carr_to_code +# } +# }, {'next_bw': 35, 'next_time': 41}), + +# 35: ({'coherent_ms': 10, +# 'stabilization_time_ms': 50, +# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k +# 'carr_params': (2, 0.7, 1.), # NBW, zeta, k +# 'loop_freq': 1000. / 10, # 1000/coherent_ms +# 'carr_freq_b1': 0., # FLL NBW +# 'carr_to_code': 1540. # carr_to_code +# } +# }, {'next_bw': 35, 'next_time': 42}), + +# # 20ms + +# 36: ({'coherent_ms': 20, +# 'stabilization_time_ms': 50, +# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k +# 'carr_params': (20., 0.7, 1.), # NBW, zeta, k +# 'loop_freq': 1000. / 20, # 1000/coherent_ms +# 'carr_freq_b1': 0., # FLL NBW +# 'carr_to_code': 1540. # carr_to_code +# } +# }, {'next_bw': 37, 'next_time': 36}), + +# 37: ({'coherent_ms': 20, +# 'stabilization_time_ms': 50, +# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k +# 'carr_params': (14., 0.7, 1.), # NBW, zeta, k +# 'loop_freq': 1000. / 20, # 1000/coherent_ms +# 'carr_freq_b1': 0., # FLL NBW +# 'carr_to_code': 1540. # carr_to_code +# } +# }, {'next_bw': 38, 'next_time': 37}), + +# 38: ({'coherent_ms': 20, +# 'stabilization_time_ms': 50, +# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k +# 'carr_params': (10, 0.7, 1.), # NBW, zeta, k +# 'loop_freq': 1000. / 20, # 1000/coherent_ms +# 'carr_freq_b1': 0., # FLL NBW +# 'carr_to_code': 1540. # carr_to_code +# } +# }, {'next_bw': 39, 'next_time': 38}), + +# 39: ({'coherent_ms': 20, +# 'stabilization_time_ms': 50, +# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k +# 'carr_params': (8, 0.7, 1.), # NBW, zeta, k +# 'loop_freq': 1000. / 20, # 1000/coherent_ms +# 'carr_freq_b1': 0., # FLL NBW +# 'carr_to_code': 1540. # carr_to_code +# } +# }, {'next_bw': 40, 'next_time': 39}), + +# 40: ({'coherent_ms': 20, +# 'stabilization_time_ms': 50, +# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k +# 'carr_params': (6, 0.7, 1.), # NBW, zeta, k +# 'loop_freq': 1000. / 20, # 1000/coherent_ms +# 'carr_freq_b1': 0., # FLL NBW +# 'carr_to_code': 1540. # carr_to_code +# } +# }, {'next_bw': 41, 'next_time': 40}), + +# 41: ({'coherent_ms': 20, +# 'stabilization_time_ms': 50, +# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k +# 'carr_params': (4, 0.7, 1.), # NBW, zeta, k +# 'loop_freq': 1000. / 20, # 1000/coherent_ms +# 'carr_freq_b1': 0., # FLL NBW +# 'carr_to_code': 1540. # carr_to_code +# } +# }, {'next_bw': 42, 'next_time': 41}), + +# 42: ({'coherent_ms': 20, +# 'stabilization_time_ms': 50, +# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k +# 'carr_params': (2, 0.7, 1.), # NBW, zeta, k +# 'loop_freq': 1000. / 20, # 1000/coherent_ms +# 'carr_freq_b1': 0., # FLL NBW +# 'carr_to_code': 1540. # carr_to_code +# } +# }, {'next_bw': 42, 'next_time': 42}) } + # Tracking stages. See track.c for more details. # 1;20 ms stages @@ -832,10 +1328,10 @@ 8: (1023, 9, {'pre': (), 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), 9: (1023, 10, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), 10: (1023, 11, {'pre': (), 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 11: (1023, 12, {'pre': (), + 11: (1023, 12, {'pre': (APPLY_CORR_1,), 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), 12: (1023, 13, {'pre': (), 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), @@ -876,8 +1372,8 @@ 8: (1023, 9, {'pre': (), 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), 9: (1023, 10, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 10: (1023, 11, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), + 10: (1023, 11, {'pre': (APPLY_CORR_1,), 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), 11: (1023, 12, {'pre': (), 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), diff --git a/peregrine/tracking.py b/peregrine/tracking.py index f7cc149..dce5f24 100644 --- a/peregrine/tracking.py +++ b/peregrine/tracking.py @@ -27,6 +27,7 @@ from peregrine import gps_constants from peregrine import glo_constants from peregrine import alias_detector +from peregrine import dynamics_detector from peregrine.acquisition import AcquisitionResult from peregrine.acquisition import GloAcquisitionResult from peregrine.include.generateCAcode import caCodes @@ -163,8 +164,8 @@ class TrackingChannel(object): this class. See TrackingChannelL1CA or TrackingChannelL2C as examples. - Sub-classes can optionally implement :meth:'_run_preprocess', - :meth:'_run_postprocess' and :meth:'_get_result' methods. + Sub-classes can optionally implement :meth:'_run_track_profile_selection', + :meth:'_run_nav_data_decoding' and :meth:'_get_result' methods. The class is designed to support batch processing of sample data. This is to help processing of large data sample files without the need @@ -198,7 +199,42 @@ def __init__(self, params): self.signal = params['acq'].signal self.results_num = 500 - self.stage1 = True + + self.coherent_ms_index = 0 + self.fll_bw_index = 0 + self.pll_bw_index = 0 + coherent_ms = self.track_params['coherent_ms'][self.coherent_ms_index] + fll_bw = self.track_params['fll_bw'][self.fll_bw_index] + pll_bw = self.track_params['pll_bw'][self.pll_bw_index] + + loop_filter_params = self.loop_filter_params_template + carr_params = loop_filter_params['carr_params'] + loop_filter_params['carr_params'] = (pll_bw, carr_params[1], carr_params[2]) + loop_filter_params['loop_freq'] = 1000 / coherent_ms + loop_filter_params['carr_freq_b1'] = fll_bw + + self.track_profile = {'loop_filter_params': loop_filter_params, + 'coherent_ms': coherent_ms, + 'phase_err': 0} + + self.profiles_history = [] + self.track_candidates = [] + self.stabilization_time = 50 + self.coherent_ms = coherent_ms + self.alias_detector = alias_detector.AliasDetector(self.coherent_ms) + + self.dynamics_detector = dynamics_detector.DynamicsDetector() + + self.short_n_long = False + if params['tracker_options']: + mode = params['tracker_options']['mode'] + if mode == 'short-long-cycles': + self.short_n_long = True + + self.fsm_index = 0 + self.fsm_states = get_fsm_states(ms=self.coherent_ms, + short_n_long=self.short_n_long, + bit_sync=False) self.lock_detect = LockDetector( k1=self.lock_detect_params["k1"], @@ -210,32 +246,42 @@ def __init__(self, params): bw=1e3 / self.coherent_ms, cn0_0=self.cn0_0, cutoff_freq=0.1, - loop_freq=self.loop_filter_params["loop_freq"] + loop_freq=loop_filter_params["loop_freq"] ) + code_params = loop_filter_params['code_params'] + carr_params = loop_filter_params['carr_params'] + self.loop_filter = self.loop_filter_class( - loop_freq=self.loop_filter_params['loop_freq'], - code_freq=self.code_freq_init, - code_bw=self.loop_filter_params['code_bw'], - code_zeta=self.loop_filter_params['code_zeta'], - code_k=self.loop_filter_params['code_k'], - carr_to_code=self.loop_filter_params['carr_to_code'], - carr_freq=self.acq.doppler, - carr_bw=self.loop_filter_params['carr_bw'], - carr_zeta=self.loop_filter_params['carr_zeta'], - carr_k=self.loop_filter_params['carr_k'], - carr_freq_b1=self.loop_filter_params['carr_freq_b1'], + loop_freq=loop_filter_params['loop_freq'], + code_freq=params['code_freq_init'] * 2 * np.pi, + code_bw=code_params[0], # code_bw' + code_zeta=code_params[1], # code_zeta + code_k=code_params[2], # code_k + carr_to_code=loop_filter_params['carr_to_code'], + carr_freq=self.acq.doppler * 2 * np.pi, + carr_bw=carr_params[0], # carr_bw, + carr_zeta=carr_params[1], # carr_zeta + carr_k=carr_params[2], # carr_k + carr_freq_b1=loop_filter_params['carr_freq_b1'], ) - self.code_freq_1 = self.code_freq_2 = self.corr_code_freq = \ + self.code_freq_1 = self.code_freq_2 = \ self.loop_filter.to_dict()['code_freq'] - self.carr_freq_1 = self.carr_freq_2 = self.corr_carr_freq = \ + self.corr_code_freq = self.loop_filter.to_dict()['code_freq'] / (2 * np.pi) + + self.carr_freq_1 = self.carr_freq_2 = \ self.loop_filter.to_dict()['carr_freq'] + self.corr_carr_freq = self.loop_filter.to_dict()['carr_freq'] / (2 * np.pi) + + print self.corr_carr_freq, self.corr_code_freq + self.track_result = TrackResults(self.results_num, self.acq.prn, self.acq.signal) + self.track_profile_timer_ms = 0 self.code_phase = 0.0 self.carr_phase = 0.0 self.samples_per_chip = int(round(self.sampling_freq / self.chipping_rate)) @@ -243,8 +289,6 @@ def __init__(self, params): self.sample_index += self.acq.sample_index self.sample_index += self.acq.code_phase * self.samples_per_chip self.sample_index = int(math.floor(self.sample_index)) - self.fsm_states = params['fsm_states'] - self.fsm_step = 0 self.carr_phase_acc = 0.0 self.code_phase_acc = 0.0 self.samples_tracked = 0 @@ -303,7 +347,75 @@ def get_index(self): """ return self.sample_index - def _run_preprocess(self): + + def _set_track_profile(self): + coherent_ms = self.track_params['coherent_ms'][self.coherent_ms_index] + fll_bw = self.track_params['fll_bw'][self.fll_bw_index] + pll_bw = self.track_params['pll_bw'][self.pll_bw_index] + + loop_filter_params = self.loop_filter_params_template + carr_params = loop_filter_params['carr_params'] + loop_filter_params['carr_params'] = (pll_bw, carr_params[1], carr_params[2]) + loop_filter_params['loop_freq'] = 1000 / coherent_ms + loop_filter_params['carr_freq_b1'] = fll_bw + + self.track_profile = {'loop_filter_params': loop_filter_params, + 'coherent_ms': coherent_ms, + 'phase_err': 0} + + self.coherent_ms = coherent_ms + + logger.info("[PRN: %d (%s)] coherent_ms=%d and PLL bw=%f FLL bw=%f" % + (self.prn + 1, self.signal, self.coherent_ms, pll_bw, fll_bw)) + + self.alias_detector.reinit(self.coherent_ms) + + self.loop_filter.retune(**loop_filter_params) + self.lock_detect.reinit( + k1=self.lock_detect_params["k1"] * self.coherent_ms, + k2=self.lock_detect_params["k2"], + lp=self.lock_detect_params["lp"], + lo=self.lock_detect_params["lo"]) + self.cn0_est = CN0_Est_MM(bw=1e3 / self.coherent_ms, + cn0_0=self.track_result.cn0[self.i - 1], + cutoff_freq=10, + loop_freq=1e3 / self.coherent_ms) + + self.fsm_states = get_fsm_states(ms=self.coherent_ms, + short_n_long=self.short_n_long, + bit_sync=self.bit_sync) + self.fsm_index = 0 + self.track_profile_timer_ms = 0 + + + def _make_track_candidates(self): + fll_bw_index = self.fll_bw_index + if fll_bw_index == len(self.track_params['fll_bw']) - 1: + coherent_ms_index = self.coherent_ms_index + if coherent_ms_index < len(self.track_params['coherent_ms']) - 1: + coherent_ms_index += 1 + candidate = { 'fll_bw_index': self.fll_bw_index, + 'pll_bw_index': self.pll_bw_index, + 'coherent_ms_index': coherent_ms_index } + self.track_candidates.append(candidate) + + pll_bw_index = self.pll_bw_index + if pll_bw_index < len(self.track_params['pll_bw']) - 1: + pll_bw_index += 1 + candidate = { 'fll_bw_index': self.fll_bw_index, + 'pll_bw_index': pll_bw_index, + 'coherent_ms_index': self.coherent_ms_index } + self.track_candidates.append(candidate) + else: + fll_bw_index += 1 + candidate = { 'fll_bw_index': fll_bw_index, + 'pll_bw_index': self.pll_bw_index, + 'coherent_ms_index': self.coherent_ms_index } + self.track_candidates.append(candidate) + + print "New track candidates: ", self.track_candidates, " Bit sync: ", self.bit_sync + + def _run_track_profile_selection(self): """ Customize the tracking run procedure in a subclass. The method can be optionally redefined in a subclass to perform @@ -311,9 +423,91 @@ def _run_preprocess(self): next integration round. """ - pass - def _run_postprocess(self): + self.bit_sync = self.nav_bit_sync.bit_sync_acquired() + phase_err = np.absolute(self.loop_filter.to_dict()['phase_err']) + if self.track_profile['phase_err'] < phase_err: + self.track_profile['phase_err'] = phase_err + + if self.lock_detect_outp: + if len(self.profiles_history): + prev_phase_err = self.profiles_history[-1]['phase_err'] + else: + prev_phase_err = 0 + + if prev_phase_err and phase_err > prev_phase_err and \ + len(self.profiles_history) > 0: + + print "" + print "#################### Current history status history: " + for pr in self.profiles_history: + print pr + print "#####################################################" + print "" + + profile = self.profiles_history.pop() + print "High phase error, Prev: ", prev_phase_err, " Now: ", phase_err + print "Taking profile from history: ", profile + self.fll_bw_index = profile['fll_bw_index'] + self.pll_bw_index = profile['pll_bw_index'] + self.coherent_ms_index = profile['coherent_ms_index'] + self._set_track_profile() + return + + final_profile = \ + self.fll_bw_index == len(self.track_params['fll_bw']) - 1 and \ + self.pll_bw_index == len(self.track_params['pll_bw']) - 1 and \ + self.coherent_ms_index == len(self.track_params['coherent_ms']) - 1 + if final_profile: + return + + track_settled = self.track_profile_timer_ms >= self.stabilization_time + if not track_settled: + return + + if len(self.track_candidates) == 0: + self._make_track_candidates() + + track_profile = self.track_candidates.pop() + coherent_ms_index = track_profile['coherent_ms_index'] + coherent_ms = self.track_params['coherent_ms'][coherent_ms_index] + bit_sync_required = (coherent_ms != 1) + + if bit_sync_required and not self.bit_sync: + self.track_candidates.append(track_profile) + return + + print "Start using next track profile: ", track_profile + print "Track candidates in queue: ", self.track_candidates + + # switch to next track profile + history = {'fll_bw_index': self.fll_bw_index, + 'pll_bw_index': self.pll_bw_index, + 'coherent_ms_index': self.coherent_ms_index, + 'phase_err': self.track_profile['phase_err'] } + self.profiles_history.append(history) + + self.fll_bw_index = track_profile['fll_bw_index'] + self.pll_bw_index = track_profile['pll_bw_index'] + self.coherent_ms_index = track_profile['coherent_ms_index'] + + print "Switch to the next track profile" + self._set_track_profile() + + else: + if self.fll_bw_index == 0 and \ + self.pll_bw_index == 0 and \ + self.coherent_ms_index == 0: + return + + self.fll_bw_index = 0 + self.pll_bw_index = 0 + self.coherent_ms_index = 0 + self.profiles_history = [] + print "Back to init profile" + self._set_track_profile() + + def _run_nav_data_decoding(self): """ Customize the tracking run procedure in a subclass. The method can be optionally redefined in a subclass to perform @@ -370,7 +564,8 @@ def run(self, samples): Run tracking channel for the given batch of data. This method is an entry point for the tracking procedure. Subclasses normally will not redefine the method, but instead - redefine the customization methods '_run_preprocess', '_run_postprocess' + redefine the customization methods + '_run_track_profile_selection', '_run_nav_data_decoding' and '_get_result' to run signal specific tracking operations. Parameters @@ -393,23 +588,22 @@ def run(self, samples): samples_processed = 0 samples_total = len(samples[self.signal]['samples']) - coherent_ms = self.fsm_states['coherent_ms'] - estimated_blksize = coherent_ms * self.sampling_freq / 1e3 + estimated_blksize = self.coherent_ms * self.sampling_freq / 1e3 self.track_result.status = 'T' while self.samples_tracked < self.samples_to_track and \ (sample_index + 2 * estimated_blksize) < samples_total: - cur_fsm_state = self.fsm_states[self.fsm_step] + cur_fsm_state = self.fsm_states[self.fsm_index] flags_pre = cur_fsm_state[2]['pre'] if defaults.APPLY_CORR_1 in flags_pre: - self.corr_code_freq = self.code_freq_1 - self.corr_carr_freq = self.carr_freq_1 + self.corr_code_freq = self.code_freq_1 / (2 * np.pi) + self.corr_carr_freq = self.carr_freq_1 / (2 * np.pi) elif defaults.APPLY_CORR_2 in flags_pre: - self.corr_code_freq = self.code_freq_2 - self.corr_carr_freq = self.carr_freq_2 + self.corr_code_freq = self.code_freq_2 / (2 * np.pi) + self.corr_carr_freq = self.carr_freq_2 / (2 * np.pi) samples_ = samples[self.signal]['samples'][sample_index:] @@ -423,6 +617,8 @@ def run(self, samples): self.signal ) + self.track_profile_timer_ms += 1e3 * blksize / self.sampling_freq + sample_index += blksize samples_processed += blksize self.carr_phase_acc += self.corr_carr_freq * blksize / self.sampling_freq @@ -434,7 +630,7 @@ def run(self, samples): self.L += L_ flags_post = cur_fsm_state[2]['post'] - self.fsm_step = cur_fsm_state[1] + self.fsm_index = cur_fsm_state[1] if defaults.RUN_LD in flags_post: # Update PLL lock detector @@ -469,6 +665,10 @@ def run(self, samples): not (defaults.GET_CORR_2 in flags_post): continue + self.track_result.dynamics[self.i] = \ + self.loop_filter.to_dict()['phase_acc'] / (2 * np.pi) + #self.dynamics_detector.update(self.loop_filter.to_dict()['phase_acc'] / (2 * np.pi), self.coherent_ms) + # run tracking loop self.loop_filter.update(self.E, self.P, self.L) @@ -485,15 +685,26 @@ def run(self, samples): self.track_result.carr_phase[self.i] = self.carr_phase self.track_result.carr_phase_acc[self.i] = self.carr_phase_acc self.track_result.carr_freq[self.i] = \ - self.loop_filter.to_dict()['carr_freq'] + self.IF + self.loop_filter.to_dict()['carr_freq'] / (2 * np.pi) + self.IF self.track_result.code_phase[self.i] = self.code_phase self.track_result.code_phase_acc[self.i] = self.code_phase_acc self.track_result.code_freq[self.i] = \ - self.loop_filter.to_dict()['code_freq'] + self.chipping_rate + self.loop_filter.to_dict()['code_freq'] / (2 * np.pi) + \ + self.chipping_rate self.track_result.phase_err[self.i] = \ self.loop_filter.to_dict()['phase_err'] + self.track_result.phase_err_max[self.i] = self.track_profile['phase_err'] + + self.track_result.acceleration[self.i] = \ + self.loop_filter.to_dict()['phase_acc'] + + self.track_result.fll_bw[self.i] = self.loop_filter.to_dict()['fll_bw'] + self.track_result.pll_bw[self.i] = self.loop_filter.to_dict()['pll_bw'] + self.track_result.dll_bw[self.i] = self.loop_filter.to_dict()['dll_bw'] + + self.track_result.track_timer_ms[self.i] = self.track_profile_timer_ms # Record stuff for postprocessing self.track_result.absolute_sample[self.i] = self.sample_index + \ @@ -517,13 +728,19 @@ def run(self, samples): self.track_result.alias_detect_err_hz[self.i] = err_hz - self._run_postprocess() - self._run_preprocess() + self._run_nav_data_decoding() + self._run_track_profile_selection() + + self.track_result.bit_sync[self.i] = self.bit_sync # Estimated blksize might change as a result of a change of # the coherent integration time. - coherent_ms = self.fsm_states['coherent_ms'] - estimated_blksize = coherent_ms * self.sampling_freq / 1e3 + estimated_blksize = self.coherent_ms * self.sampling_freq / 1e3 + + if (sample_index + 2 * estimated_blksize) < samples_total: + self.track_result.more_samples[self.i] = 0 + else: + self.track_result.more_samples[self.i] = 1 self.samples_tracked = self.sample_index + samples_processed self.track_result.ms_tracked[self.i] = self.samples_tracked * 1e3 / \ @@ -566,27 +783,18 @@ def __init__(self, params): cn0_0 += 10 * np.log10(defaults.L1CA_CHANNEL_BANDWIDTH_HZ) params['cn0_0'] = cn0_0 - params['coherent_ms'] = 1 params['IF'] = params['samples'][gps_constants.L1CA]['IF'] params['prn_code'] = caCodes[params['acq'].prn] params['code_freq_init'] = params['acq'].doppler * \ gps_constants.l1ca_chip_rate / gps_constants.l1 - params['loop_filter_params'] = defaults.l1ca_stage1_loop_filter_params + + params['track_params'] = defaults.l1ca_track_params + params['loop_filter_params_template'] = \ + defaults.l1ca_loop_filter_params_template + params['lock_detect_params'] = defaults.l1ca_lock_detect_params_opt params['chipping_rate'] = gps_constants.l1ca_chip_rate params['sample_index'] = params['samples']['sample_index'] - params['alias_detector'] = \ - alias_detector.AliasDetector(params['coherent_ms']) - - self.short_n_long = False - if params['tracker_options']: - mode = params['tracker_options']['mode'] - if mode == 'short-long-cycles': - self.short_n_long = True - - params['fsm_states'] = get_fsm_states(ms=params['coherent_ms'], - short_n_long=self.short_n_long, - bit_sync=False) TrackingChannel.__init__(self, params) @@ -595,43 +803,6 @@ def __init__(self, params): self.l2c_handover_acq = None self.l2c_handover_done = False - def _run_preprocess(self): - """ - Run L1C/A tracking loop preprocessor operation. - It runs before every coherent integration round. - - """ - - # For L1 C/A there are coherent and non-coherent tracking options. - if self.stage1 and \ - self.stage2_coherent_ms and \ - self.nav_bit_sync.bit_phase == self.nav_bit_sync.bit_phase_ref: - - logger.info("[PRN: %d (%s)] switching to stage2, coherent_ms=%d" % - (self.prn + 1, self.signal, self.stage2_coherent_ms)) - - self.stage1 = False - self.coherent_ms = self.stage2_coherent_ms - - self.alias_detector.reinit(self.coherent_ms) - - self.loop_filter.retune(**self.stage2_loop_filter_params) - self.lock_detect.reinit( - k1=self.lock_detect_params["k1"] * self.coherent_ms, - k2=self.lock_detect_params["k2"], - lp=self.lock_detect_params["lp"], - lo=self.lock_detect_params["lo"]) - self.cn0_est = CN0_Est_MM(bw=1e3 / self.stage2_coherent_ms, - cn0_0=self.track_result.cn0[self.i - 1], - cutoff_freq=10, - loop_freq=1e3 / self.stage2_coherent_ms) - - self.fsm_states = get_fsm_states(ms=self.coherent_ms, - short_n_long=self.short_n_long, - bit_sync=True) - self.fsm_step = 0 - - def _get_result(self): """ Get L1C/A tracking results. @@ -650,7 +821,7 @@ def _get_result(self): return self.l2c_handover_acq return None - def _run_postprocess(self): + def _run_nav_data_decoding(self): """ Run L1C/A coherent integration postprocessing. Runs navigation bit sync decoding operation and @@ -689,7 +860,7 @@ def _run_postprocess(self): chan_snr -= 10 * np.log10(defaults.L1CA_CHANNEL_BANDWIDTH_HZ) chan_snr = np.power(10, chan_snr / 10) l2c_doppler = self.loop_filter.to_dict( - )['carr_freq'] * gps_constants.l2 / gps_constants.l1 + )['carr_freq'] * gps_constants.l2 / gps_constants.l1 / (2 * np.pi) self.l2c_handover_acq = \ AcquisitionResult(self.prn, self.samples[gps_constants.L2C][ @@ -721,8 +892,7 @@ def __init__(self, params): cn0_0 = 10 * np.log10(params['acq'].snr) cn0_0 += 10 * np.log10(defaults.L2C_CHANNEL_BANDWIDTH_HZ) params['cn0_0'] = cn0_0 - params['coherent_ms'] = defaults.l2c_coherent_integration_time_ms - params['loop_filter_params'] = defaults.l2c_loop_filter_params + params['track_profiles'] = defaults.l2c_track_profiles params['lock_detect_params'] = defaults.l2c_lock_detect_params_20ms params['IF'] = params['samples'][gps_constants.L2C]['IF'] params['prn_code'] = L2CMCodes[params['acq'].prn] @@ -730,18 +900,6 @@ def __init__(self, params): gps_constants.l2c_chip_rate / gps_constants.l2 params['chipping_rate'] = gps_constants.l2c_chip_rate params['sample_index'] = 0 - params['alias_detector'] = \ - alias_detector.AliasDetector(params['coherent_ms']) - - short_n_long = False - if params['tracker_options']: - mode = params['tracker_options']['mode'] - if mode == 'short-long-cycles': - short_n_long = True - - params['fsm_states'] = get_fsm_states(ms=params['coherent_ms'], - short_n_long=short_n_long, - bit_sync=True) TrackingChannel.__init__(self, params) @@ -758,10 +916,9 @@ def is_pickleable(self): """ return False - def _run_postprocess(self): + def _run_nav_data_decoding(self): """ - Run L2C coherent integration postprocessing. - Runs navigation bit sync decoding operation. + Runs L2C navigation bit sync decoding operation. """ @@ -937,8 +1094,6 @@ def __init__(self, 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): @@ -967,10 +1122,6 @@ def __init__(self, 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 @@ -993,8 +1144,6 @@ def __init__(self, self.glol2_handover = glol2_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 @@ -1138,8 +1287,6 @@ def _create_channel(self, acq): 'glol2_handover': self.glol2_handover, 'show_progress': self.show_progress, 'correlator': self.correlator, - 'stage2_coherent_ms': self.stage2_coherent_ms, - 'stage2_loop_filter_params': self.stage2_loop_filter_params, 'multi': self.multi} return _tracking_channel_factory(parameters) @@ -1271,12 +1418,25 @@ def __init__(self, n_points, prn, signal): self.lock_detect_lpfq = np.zeros(n_points) self.alias_detect_err_hz = np.zeros(n_points) self.phase_err = np.zeros(n_points) + self.phase_err_max = np.zeros(n_points) + self.acceleration = np.zeros(n_points) + self.dynamics = np.zeros(n_points) self.nav_msg = NavMsg() self.nav_msg_bit_phase_ref = np.zeros(n_points) self.nav_bit_sync = NBSMatchBit() if prn < 32 else NBSSBAS() self.tow = np.empty(n_points) self.tow[:] = np.NAN self.coherent_ms = np.zeros(n_points) + self.more_samples = np.zeros(n_points) + + self.bit_sync = np.zeros(n_points) + + self.fll_bw = np.zeros(n_points) + self.pll_bw = np.zeros(n_points) + self.dll_bw = np.zeros(n_points) + + self.track_timer_ms = np.zeros(n_points) + self.signal = signal self.ms_tracked = np.zeros(n_points) @@ -1314,24 +1474,42 @@ def dump(self, output_file, size): with open(fn_analysis, mode) as f1: if self.print_start: f1.write( - "sample_index,ms_tracked,coherent_ms,IF,doppler_phase,carr_doppler," - "code_phase,code_freq," - "CN0,SNR,SNR_DB,E_I,E_Q,P_I,P_Q,L_I,L_Q," - "lock_detect_outp,lock_detect_outo," + "sample_index,ms_tracked,coherent_ms,bit_sync,fll_bw,pll_bw,dll_bw," + "track_timer_ms," + "lock_detect_outp,lock_detect_outo,dynamics," + "phase_err,phase_err_max,CN0,IF,doppler_phase," + "carr_doppler,code_phase,code_freq," + "SNR,SNR_DB,E_I,E_Q,P_I,P_Q,L_I,L_Q," "lock_detect_pcount1,lock_detect_pcount2," "lock_detect_lpfi,lock_detect_lpfq,alias_detect_err_hz," - "phase_err,code_phase_acc\n") + "acceleration,code_phase_acc,more_samples\n") for i in range(size): f1.write("%s," % int(self.absolute_sample[i])) f1.write("%s," % self.ms_tracked[i]) f1.write("%s," % self.coherent_ms[i]) + + f1.write("%s," % self.bit_sync[i]) + + f1.write("%s," % self.fll_bw[i]) + f1.write("%s," % self.pll_bw[i]) + f1.write("%s," % self.dll_bw[i]) + + f1.write("%s," % self.track_timer_ms[i]) + + f1.write("%s," % int(self.lock_detect_outp[i])) + f1.write("%s," % int(self.lock_detect_outo[i])) + + f1.write("%s," % self.dynamics[i]) + f1.write("%s," % self.phase_err[i]) + f1.write("%s," % self.phase_err_max[i]) + f1.write("%s," % self.cn0[i]) + f1.write("%s," % self.IF) f1.write("%s," % self.carr_phase[i]) f1.write("%s," % (self.carr_freq[i] - self.IF)) f1.write("%s," % self.code_phase[i]) f1.write("%s," % self.code_freq[i]) - f1.write("%s," % self.cn0[i]) f1.write("%s," % self.snr[i]) f1.write("%s," % self.snr_db[i]) f1.write("%s," % self.E[i].real) @@ -1340,15 +1518,14 @@ def dump(self, output_file, size): f1.write("%s," % self.P[i].imag) f1.write("%s," % self.L[i].real) f1.write("%s," % self.L[i].imag) - f1.write("%s," % int(self.lock_detect_outp[i])) - f1.write("%s," % int(self.lock_detect_outo[i])) f1.write("%s," % int(self.lock_detect_pcount1[i])) f1.write("%s," % int(self.lock_detect_pcount2[i])) f1.write("%s," % self.lock_detect_lpfi[i]) f1.write("%s," % self.lock_detect_lpfq[i]) f1.write("%s," % self.alias_detect_err_hz[i]) - f1.write("%s," % self.phase_err[i]) - f1.write("%s\n" % self.code_phase_acc[i]) + f1.write("%s," % self.acceleration[i]) + f1.write("%s," % self.code_phase_acc[i]) + f1.write("%s\n" % self.more_samples[i]) self.print_start = 0 return fn_analysis, fn_results @@ -1427,6 +1604,9 @@ def update(self, corr, ms): else: return False, None + def bit_sync_acquired(self): + return self.synced + def update_bit_sync(self, corr, ms): raise NotImplementedError diff --git a/peregrine/tracking_loop.py b/peregrine/tracking_loop.py index f9634af..414d226 100644 --- a/peregrine/tracking_loop.py +++ b/peregrine/tracking_loop.py @@ -51,6 +51,9 @@ def __init__(self, **kwargs): self.phase_acc = 0 self.phase_vel = kwargs['carr_freq'] self.phase_err = 0 + self.fll_bw = kwargs['carr_freq_b1'] + self.pll_bw = kwargs['carr_bw'] + self.dll_bw = kwargs['code_bw'] self.P_prev = 1+0j @@ -84,6 +87,17 @@ def retune(self, code_params, carr_params, loop_freq, carr_freq_b1, carr_to_code # Common parameters self.T = 1. / loop_freq + # self.code_vel = 0 + # self.phase_vel = 0 + + if self.fll_bw and not carr_freq_b1: + # FLL is turned off + self.phase_acc = 0 + + self.fll_bw = carr_freq_b1 + self.pll_bw = carr_bw + self.dll_bw = code_bw + # FLL constants freq_omega_0 = carr_freq_b1 / 0.53 freq_a2 = 1.414 @@ -101,7 +115,7 @@ def retune(self, code_params, carr_params, loop_freq, carr_freq_b1, carr_to_code self.phase_c2 = phase_a3 * phase_omega_0 * phase_omega_0 self.phase_c3 = phase_omega_0 * phase_omega_0 * phase_omega_0 # self.phase_c1, self.phase_c2, self.phase_c3 = controlled_root(3, 1 / loop_freq, carr_bw) - print "T = ", 1 / loop_freq, " BW = ", carr_bw + # print "T = ", 1 / loop_freq, " BW = ", carr_bw # self.phase_c1 = 0.00013553072504812747 # self.phase_c2 = 0.006445479093110773 @@ -115,11 +129,7 @@ def retune(self, code_params, carr_params, loop_freq, carr_freq_b1, carr_to_code self.code_c2 = code_omega_0 * code_omega_0 self.carr_to_code = carr_to_code - print "phase_acc = ", self.phase_acc, " phase_vel = ", self.phase_vel - - # self.code_vel = 0 - self.phase_acc = 0 - # self.phase_vel = 0 + # print "phase_acc = ", self.phase_acc, " phase_vel = ", self.phase_vel def update(self, E, P, L): """ From 954de150635137ff3ed207ffb06fb5c48fa9e76c Mon Sep 17 00:00:00 2001 From: Adel Mamin Date: Wed, 3 Aug 2016 17:06:34 +0300 Subject: [PATCH 26/61] Add more debug output --- peregrine/defaults.py | 6 +++--- peregrine/tracking.py | 15 +++++++++------ peregrine/tracking_loop.py | 10 +++++----- 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/peregrine/defaults.py b/peregrine/defaults.py index 2504210..df09bd4 100644 --- a/peregrine/defaults.py +++ b/peregrine/defaults.py @@ -206,9 +206,9 @@ "carr_freq_b1": 1} # Carrier loop aiding_igain l1ca_track_params = { - 'fll_bw': (0,), - 'pll_bw': (20,), #, 20, 14, 10, 8, 6, 4, 2), - 'coherent_ms': (1,) }# 2, 4, 5, 10, 20) } + 'fll_bw': (1, 0), + 'pll_bw': (20, 14, 10, 8, 6, 4, 2), + 'coherent_ms': (1, 2, 4, 5, 10, 20) } l1ca_loop_filter_params_template = { 'code_params': (1., 0.7, 1.), # NBW, zeta, k diff --git a/peregrine/tracking.py b/peregrine/tracking.py index dce5f24..f254e3f 100644 --- a/peregrine/tracking.py +++ b/peregrine/tracking.py @@ -685,18 +685,20 @@ def run(self, samples): self.track_result.carr_phase[self.i] = self.carr_phase self.track_result.carr_phase_acc[self.i] = self.carr_phase_acc self.track_result.carr_freq[self.i] = \ - self.loop_filter.to_dict()['carr_freq'] / (2 * np.pi) + self.IF + self.loop_filter.to_dict()['carr_freq'] / (2 * np.pi) self.track_result.code_phase[self.i] = self.code_phase self.track_result.code_phase_acc[self.i] = self.code_phase_acc self.track_result.code_freq[self.i] = \ - self.loop_filter.to_dict()['code_freq'] / (2 * np.pi) + \ - self.chipping_rate + self.loop_filter.to_dict()['code_freq'] / (2 * np.pi) self.track_result.phase_err[self.i] = \ self.loop_filter.to_dict()['phase_err'] self.track_result.phase_err_max[self.i] = self.track_profile['phase_err'] + self.track_result.code_err[self.i] = \ + self.loop_filter.to_dict()['code_err'] + self.track_result.acceleration[self.i] = \ self.loop_filter.to_dict()['phase_acc'] @@ -1419,6 +1421,7 @@ def __init__(self, n_points, prn, signal): self.alias_detect_err_hz = np.zeros(n_points) self.phase_err = np.zeros(n_points) self.phase_err_max = np.zeros(n_points) + self.code_err = np.zeros(n_points) self.acceleration = np.zeros(n_points) self.dynamics = np.zeros(n_points) self.nav_msg = NavMsg() @@ -1477,7 +1480,7 @@ def dump(self, output_file, size): "sample_index,ms_tracked,coherent_ms,bit_sync,fll_bw,pll_bw,dll_bw," "track_timer_ms," "lock_detect_outp,lock_detect_outo,dynamics," - "phase_err,phase_err_max,CN0,IF,doppler_phase," + "phase_err,phase_err_max,code_err,CN0,IF,doppler_phase," "carr_doppler,code_phase,code_freq," "SNR,SNR_DB,E_I,E_Q,P_I,P_Q,L_I,L_Q," "lock_detect_pcount1,lock_detect_pcount2," @@ -1502,12 +1505,12 @@ def dump(self, output_file, size): f1.write("%s," % self.dynamics[i]) f1.write("%s," % self.phase_err[i]) f1.write("%s," % self.phase_err_max[i]) + f1.write("%s," % self.code_err[i]) f1.write("%s," % self.cn0[i]) f1.write("%s," % self.IF) f1.write("%s," % self.carr_phase[i]) - f1.write("%s," % (self.carr_freq[i] - - self.IF)) + f1.write("%s," % self.carr_freq[i]) f1.write("%s," % self.code_phase[i]) f1.write("%s," % self.code_freq[i]) f1.write("%s," % self.snr[i]) diff --git a/peregrine/tracking_loop.py b/peregrine/tracking_loop.py index 414d226..8de8ec1 100644 --- a/peregrine/tracking_loop.py +++ b/peregrine/tracking_loop.py @@ -51,6 +51,7 @@ def __init__(self, **kwargs): self.phase_acc = 0 self.phase_vel = kwargs['carr_freq'] self.phase_err = 0 + self.code_err = 0 self.fll_bw = kwargs['carr_freq_b1'] self.pll_bw = kwargs['carr_bw'] self.dll_bw = kwargs['code_bw'] @@ -156,8 +157,7 @@ def update(self, E, P, L): freq_error = 0 if self.freq_c1 != 0 and self.T != 0: freq_error = frequency_discriminator(P.real, P.imag, self.P_prev.real, self.P_prev.imag) / self.T - - self.P_prev = P + self.P_prev = P prev = self.phase_acc self.phase_acc += freq_error * self.freq_c2 * self.T + self.phase_err * self.phase_c3 * self.T @@ -170,11 +170,11 @@ def update(self, E, P, L): self.carr_freq = sum # Code loop - code_error = -dll_discriminator(E, P, L) + self.code_err = -dll_discriminator(E, P, L) prev = self.code_vel - self.code_vel += self.code_c2 * code_error * self.T - sum = (prev + self.code_vel) * 0.5 + self.code_c1 * code_error + self.code_vel += self.code_c2 * self.code_err * self.T + sum = (prev + self.code_vel) * 0.5 + self.code_c1 * self.code_err self.code_freq = sum if self.carr_to_code > 0: From d94c4fa94adb3516ab1810b01cbc09b3c6c127e3 Mon Sep 17 00:00:00 2001 From: Adel Mamin Date: Thu, 4 Aug 2016 00:55:04 +0300 Subject: [PATCH 27/61] Fix DLL initialization --- peregrine/tracking.py | 36 +++++++++++++++--------------------- peregrine/tracking_loop.py | 1 - 2 files changed, 15 insertions(+), 22 deletions(-) diff --git a/peregrine/tracking.py b/peregrine/tracking.py index f254e3f..2cd985e 100644 --- a/peregrine/tracking.py +++ b/peregrine/tracking.py @@ -219,7 +219,7 @@ def __init__(self, params): self.profiles_history = [] self.track_candidates = [] - self.stabilization_time = 50 + self.stabilization_time = 25 self.coherent_ms = coherent_ms self.alias_detector = alias_detector.AliasDetector(self.coherent_ms) @@ -254,7 +254,7 @@ def __init__(self, params): self.loop_filter = self.loop_filter_class( loop_freq=loop_filter_params['loop_freq'], - code_freq=params['code_freq_init'] * 2 * np.pi, + code_freq=0, code_bw=code_params[0], # code_bw' code_zeta=code_params[1], # code_zeta code_k=code_params[2], # code_k @@ -266,17 +266,11 @@ def __init__(self, params): carr_freq_b1=loop_filter_params['carr_freq_b1'], ) - self.code_freq_1 = self.code_freq_2 = \ - self.loop_filter.to_dict()['code_freq'] + self.code_freq_1 = self.code_freq_2 = self.corr_code_freq = \ + params['code_freq_init'] - self.corr_code_freq = self.loop_filter.to_dict()['code_freq'] / (2 * np.pi) - - self.carr_freq_1 = self.carr_freq_2 = \ - self.loop_filter.to_dict()['carr_freq'] - - self.corr_carr_freq = self.loop_filter.to_dict()['carr_freq'] / (2 * np.pi) - - print self.corr_carr_freq, self.corr_code_freq + self.carr_freq_1 = self.carr_freq_2 = self.corr_carr_freq = \ + self.acq.doppler self.track_result = TrackResults(self.results_num, self.acq.prn, @@ -599,11 +593,11 @@ def run(self, samples): flags_pre = cur_fsm_state[2]['pre'] if defaults.APPLY_CORR_1 in flags_pre: - self.corr_code_freq = self.code_freq_1 / (2 * np.pi) - self.corr_carr_freq = self.carr_freq_1 / (2 * np.pi) + self.corr_code_freq = self.code_freq_1 + self.corr_carr_freq = self.carr_freq_1 elif defaults.APPLY_CORR_2 in flags_pre: - self.corr_code_freq = self.code_freq_2 / (2 * np.pi) - self.corr_carr_freq = self.carr_freq_2 / (2 * np.pi) + self.corr_code_freq = self.code_freq_2 + self.corr_carr_freq = self.carr_freq_2 samples_ = samples[self.signal]['samples'][sample_index:] @@ -673,11 +667,11 @@ def run(self, samples): self.loop_filter.update(self.E, self.P, self.L) if defaults.GET_CORR_1 in flags_post: - self.code_freq_1 = self.loop_filter.to_dict()['code_freq'] - self.carr_freq_1 = self.loop_filter.to_dict()['carr_freq'] + self.code_freq_1 = self.loop_filter.to_dict()['code_freq'] / (2 * np.pi) + self.carr_freq_1 = self.loop_filter.to_dict()['carr_freq'] / (2 * np.pi) elif defaults.GET_CORR_2 in flags_post: - self.code_freq_2 = self.loop_filter.to_dict()['code_freq'] - self.carr_freq_2 = self.loop_filter.to_dict()['carr_freq'] + self.code_freq_2 = self.loop_filter.to_dict()['code_freq'] / (2 * np.pi) + self.carr_freq_2 = self.loop_filter.to_dict()['carr_freq'] / (2 * np.pi) self.track_result.coherent_ms[self.i] = self.coherent_ms @@ -690,7 +684,7 @@ def run(self, samples): self.track_result.code_phase[self.i] = self.code_phase self.track_result.code_phase_acc[self.i] = self.code_phase_acc self.track_result.code_freq[self.i] = \ - self.loop_filter.to_dict()['code_freq'] / (2 * np.pi) + self.loop_filter.to_dict()['code_freq'] self.track_result.phase_err[self.i] = \ self.loop_filter.to_dict()['phase_err'] diff --git a/peregrine/tracking_loop.py b/peregrine/tracking_loop.py index 8de8ec1..5cd3d49 100644 --- a/peregrine/tracking_loop.py +++ b/peregrine/tracking_loop.py @@ -130,7 +130,6 @@ def retune(self, code_params, carr_params, loop_freq, carr_freq_b1, carr_to_code self.code_c2 = code_omega_0 * code_omega_0 self.carr_to_code = carr_to_code - # print "phase_acc = ", self.phase_acc, " phase_vel = ", self.phase_vel def update(self, E, P, L): """ From fabad6cfbef0aceb313bcfb7fe1110efe2211fdf Mon Sep 17 00:00:00 2001 From: Adel Mamin Date: Thu, 4 Aug 2016 16:22:35 +0300 Subject: [PATCH 28/61] Static dopplers work! --- peregrine/defaults.py | 2 +- peregrine/lock_detect.py | 76 +++++++++++++++++++++++ peregrine/tracking.py | 121 +++++++++++++++++++++++-------------- peregrine/tracking_loop.py | 6 +- 4 files changed, 156 insertions(+), 49 deletions(-) create mode 100644 peregrine/lock_detect.py diff --git a/peregrine/defaults.py b/peregrine/defaults.py index df09bd4..50872b8 100644 --- a/peregrine/defaults.py +++ b/peregrine/defaults.py @@ -207,7 +207,7 @@ l1ca_track_params = { 'fll_bw': (1, 0), - 'pll_bw': (20, 14, 10, 8, 6, 4, 2), + 'pll_bw': (30, 20, 18, 16, 14, 10, 8, 6, 4, 2), 'coherent_ms': (1, 2, 4, 5, 10, 20) } l1ca_loop_filter_params_template = { diff --git a/peregrine/lock_detect.py b/peregrine/lock_detect.py new file mode 100644 index 0000000..582b9af --- /dev/null +++ b/peregrine/lock_detect.py @@ -0,0 +1,76 @@ +# Copyright (C) 2016 Swift Navigation Inc. +# Contact: Adel Mamin +# +# This source is subject to the license found in the file 'LICENSE' which must +# be be distributed together with this source. All other rights reserved. +# +# THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, +# EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. + +import numpy as np +from peregrine import defaults +from peregrine import gps_constants + + +class LockDetector(object): + """ + Wraps the `libswiftnav` PLL lock detector implementation. + + The detector state, :libswiftnav:`lock_detect_t` is maintained by + the class instance. + + """ + + def __init__(self, **kwargs): + self.lpfi = 0 + self.lpfq = 0 + self.outo = False + self.outp = False + self.pcount1 = 0 + self.pcount2 = 0 + self.reinit( kwargs['k1'], + kwargs['k2'], + kwargs['lp'], + kwargs['lo']) + + def reinit(self, k1, k2, lp, lo): + # Adjust LPF coefficient + self.k1 = k1 + self.k2 = k2 + self.lp = lp + self.lo = lo + + def lpf_update(self, y, x): + y += self.k1 * (x - y) + return y + + def update(self, I, Q, DT): + # Calculated low-pass filtered prompt correlations + self.lpfi = self.lpf_update(self.lpfi, np.absolute(I) / DT) + self.lpfq = self.lpf_update(self.lpfq, np.absolute(Q) / DT) + + a = self.lpfi / self.k2 + b = self.lpfq + if a > b: + # In-phase > quadrature, looks like we're locked + self.outo = True + self.pcount2 = 0 + # Wait before raising the pessimistic indicator + if self.pcount1 > self.lp: + self.outp = True + else: + self.pcount1 += 1 + else: + # In-phase < quadrature, looks like we're not locked + self.outp = False + self.pcount1 = 0 + # Wait before lowering the optimistic indicator + if self.pcount2 > self.lo: + self.outo = False + else: + self.pcount2 += 1 + + return (self.outo, self.outp, \ + self.pcount1, self.pcount2,\ + self.lpfi, self.lpfq) diff --git a/peregrine/tracking.py b/peregrine/tracking.py index 2cd985e..3a5f04b 100644 --- a/peregrine/tracking.py +++ b/peregrine/tracking.py @@ -14,7 +14,7 @@ import multiprocessing as mp import cPickle -from swiftnav.track import LockDetector +from peregrine import lock_detect from swiftnav.track import CN0Estimator from swiftnav.track import AidedTrackingLoop from swiftnav.correlate import track_correlate @@ -215,11 +215,11 @@ def __init__(self, params): self.track_profile = {'loop_filter_params': loop_filter_params, 'coherent_ms': coherent_ms, - 'phase_err': 0} + 'iq_ratio': 0} self.profiles_history = [] self.track_candidates = [] - self.stabilization_time = 25 + self.stabilization_time = 150 self.coherent_ms = coherent_ms self.alias_detector = alias_detector.AliasDetector(self.coherent_ms) @@ -231,12 +231,13 @@ def __init__(self, params): if mode == 'short-long-cycles': self.short_n_long = True + self.track_settled = False self.fsm_index = 0 self.fsm_states = get_fsm_states(ms=self.coherent_ms, short_n_long=self.short_n_long, bit_sync=False) - self.lock_detect = LockDetector( + self.lock_detect = lock_detect.LockDetector( k1=self.lock_detect_params["k1"], k2=self.lock_detect_params["k2"], lp=self.lock_detect_params["lp"], @@ -355,7 +356,7 @@ def _set_track_profile(self): self.track_profile = {'loop_filter_params': loop_filter_params, 'coherent_ms': coherent_ms, - 'phase_err': 0} + 'iq_ratio': 0} self.coherent_ms = coherent_ms @@ -366,7 +367,7 @@ def _set_track_profile(self): self.loop_filter.retune(**loop_filter_params) self.lock_detect.reinit( - k1=self.lock_detect_params["k1"] * self.coherent_ms, + k1=self.lock_detect_params["k1"], k2=self.lock_detect_params["k2"], lp=self.lock_detect_params["lp"], lo=self.lock_detect_params["lo"]) @@ -380,6 +381,7 @@ def _set_track_profile(self): bit_sync=self.bit_sync) self.fsm_index = 0 self.track_profile_timer_ms = 0 + self.track_settled = False def _make_track_candidates(self): @@ -409,6 +411,19 @@ def _make_track_candidates(self): print "New track candidates: ", self.track_candidates, " Bit sync: ", self.bit_sync + def _filter_track_candidates(self): + res = [] + for candidate in self.track_candidates: + pll_bw_index = candidate['pll_bw_index'] + pll_bw = self.track_params['pll_bw'][pll_bw_index] + coherent_ms_index = candidate['coherent_ms_index'] + coherent_ms = self.track_params['coherent_ms'][coherent_ms_index] + if pll_bw * coherent_ms * 1e-3 <= 0.04: + res.append(candidate) + + print "filtered candidates: ", res + return res + def _run_track_profile_selection(self): """ Customize the tracking run procedure in a subclass. @@ -419,17 +434,28 @@ def _run_track_profile_selection(self): """ self.bit_sync = self.nav_bit_sync.bit_sync_acquired() - phase_err = np.absolute(self.loop_filter.to_dict()['phase_err']) - if self.track_profile['phase_err'] < phase_err: - self.track_profile['phase_err'] = phase_err if self.lock_detect_outp: + track_settled = self.track_profile_timer_ms >= self.stabilization_time + if not track_settled: + return + + iq_ratio = np.absolute(self.lock_detect_lpfi / self.lock_detect_lpfq) + if not self.track_settled: + self.track_profile['iq_ratio'] = iq_ratio + self.track_settled = True + print "Init track profile iq ratio: ", iq_ratio + + if self.track_profile['iq_ratio'] > iq_ratio: + self.track_profile['iq_ratio'] = iq_ratio + if len(self.profiles_history): - prev_phase_err = self.profiles_history[-1]['phase_err'] + prev_iq_ratio = self.profiles_history[-1]['iq_ratio'] else: - prev_phase_err = 0 + prev_iq_ratio = 0 - if prev_phase_err and phase_err > prev_phase_err and \ + if prev_iq_ratio and iq_ratio < prev_iq_ratio and \ + iq_ratio < 2 and \ len(self.profiles_history) > 0: print "" @@ -440,7 +466,7 @@ def _run_track_profile_selection(self): print "" profile = self.profiles_history.pop() - print "High phase error, Prev: ", prev_phase_err, " Now: ", phase_err + print "Low I/Q ratio, Prev: ", prev_iq_ratio, " Now: ", iq_ratio print "Taking profile from history: ", profile self.fll_bw_index = profile['fll_bw_index'] self.pll_bw_index = profile['pll_bw_index'] @@ -455,12 +481,12 @@ def _run_track_profile_selection(self): if final_profile: return - track_settled = self.track_profile_timer_ms >= self.stabilization_time - if not track_settled: - return - if len(self.track_candidates) == 0: self._make_track_candidates() + self.track_candidates = self._filter_track_candidates() + if len(self.track_candidates) == 0: + print "=================== No candidates" + return track_profile = self.track_candidates.pop() coherent_ms_index = track_profile['coherent_ms_index'] @@ -478,7 +504,7 @@ def _run_track_profile_selection(self): history = {'fll_bw_index': self.fll_bw_index, 'pll_bw_index': self.pll_bw_index, 'coherent_ms_index': self.coherent_ms_index, - 'phase_err': self.track_profile['phase_err'] } + 'iq_ratio': self.track_profile['iq_ratio'] } self.profiles_history.append(history) self.fll_bw_index = track_profile['fll_bw_index'] @@ -494,12 +520,12 @@ def _run_track_profile_selection(self): self.coherent_ms_index == 0: return - self.fll_bw_index = 0 - self.pll_bw_index = 0 - self.coherent_ms_index = 0 - self.profiles_history = [] - print "Back to init profile" - self._set_track_profile() + # self.fll_bw_index = 0 + # self.pll_bw_index = 0 + # self.coherent_ms_index = 0 + # self.profiles_history = [] + # print "Back to init profile" + # self._set_track_profile() def _run_nav_data_decoding(self): """ @@ -626,17 +652,6 @@ def run(self, samples): flags_post = cur_fsm_state[2]['post'] self.fsm_index = cur_fsm_state[1] - if defaults.RUN_LD in flags_post: - # Update PLL lock detector - self.lock_detect_outo, \ - self.lock_detect_outp, \ - lock_detect_pcount1, \ - lock_detect_pcount2, \ - lock_detect_lpfi, \ - lock_detect_lpfq = self.lock_detect.update(self.P.real, - self.P.imag, - 1) - if self.lock_detect_outo: if defaults.ALIAS_DETECT_1ST in flags_post or \ defaults.ALIAS_DETECT_BOTH in flags_post: @@ -659,6 +674,17 @@ def run(self, samples): not (defaults.GET_CORR_2 in flags_post): continue + if defaults.RUN_LD in flags_post: + # Update PLL lock detector + self.lock_detect_outo, \ + self.lock_detect_outp, \ + lock_detect_pcount1, \ + lock_detect_pcount2, \ + self.lock_detect_lpfi, \ + self.lock_detect_lpfq = self.lock_detect.update(self.P.real, + self.P.imag, + self.coherent_ms) + self.track_result.dynamics[self.i] = \ self.loop_filter.to_dict()['phase_acc'] / (2 * np.pi) #self.dynamics_detector.update(self.loop_filter.to_dict()['phase_acc'] / (2 * np.pi), self.coherent_ms) @@ -688,7 +714,7 @@ def run(self, samples): self.track_result.phase_err[self.i] = \ self.loop_filter.to_dict()['phase_err'] - self.track_result.phase_err_max[self.i] = self.track_profile['phase_err'] + self.track_result.iq_ratio_min[self.i] = self.track_profile['iq_ratio'] self.track_result.code_err[self.i] = \ self.loop_filter.to_dict()['code_err'] @@ -719,8 +745,8 @@ def run(self, samples): self.track_result.lock_detect_outp[self.i] = self.lock_detect_outp self.track_result.lock_detect_pcount1[self.i] = lock_detect_pcount1 self.track_result.lock_detect_pcount2[self.i] = lock_detect_pcount2 - self.track_result.lock_detect_lpfi[self.i] = lock_detect_lpfi - self.track_result.lock_detect_lpfq[self.i] = lock_detect_lpfq + self.track_result.lock_detect_lpfi[self.i] = self.lock_detect_lpfi + self.track_result.lock_detect_lpfq[self.i] = self.lock_detect_lpfq self.track_result.alias_detect_err_hz[self.i] = err_hz @@ -788,7 +814,7 @@ def __init__(self, params): params['loop_filter_params_template'] = \ defaults.l1ca_loop_filter_params_template - params['lock_detect_params'] = defaults.l1ca_lock_detect_params_opt + params['lock_detect_params'] = defaults.l1ca_lock_detect_params_normal params['chipping_rate'] = gps_constants.l1ca_chip_rate params['sample_index'] = params['samples']['sample_index'] @@ -1414,7 +1440,7 @@ def __init__(self, n_points, prn, signal): self.lock_detect_lpfq = np.zeros(n_points) self.alias_detect_err_hz = np.zeros(n_points) self.phase_err = np.zeros(n_points) - self.phase_err_max = np.zeros(n_points) + self.iq_ratio_min = np.zeros(n_points) self.code_err = np.zeros(n_points) self.acceleration = np.zeros(n_points) self.dynamics = np.zeros(n_points) @@ -1473,12 +1499,14 @@ def dump(self, output_file, size): f1.write( "sample_index,ms_tracked,coherent_ms,bit_sync,fll_bw,pll_bw,dll_bw," "track_timer_ms," - "lock_detect_outp,lock_detect_outo,dynamics," - "phase_err,phase_err_max,code_err,CN0,IF,doppler_phase," + "lock_detect_outp,lock_detect_outo," + "iq_ratio,iq_ratio_min,dynamics," + "phase_err,code_err,CN0,IF,doppler_phase," "carr_doppler,code_phase,code_freq," - "SNR,SNR_DB,E_I,E_Q,P_I,P_Q,L_I,L_Q," + "SNR,SNR_DB,P_Mag,E_I,E_Q,P_I,P_Q,L_I,L_Q," "lock_detect_pcount1,lock_detect_pcount2," - "lock_detect_lpfi,lock_detect_lpfq,alias_detect_err_hz," + "lock_detect_lpfi,lock_detect_lpfq," + "alias_detect_err_hz," "acceleration,code_phase_acc,more_samples\n") for i in range(size): f1.write("%s," % int(self.absolute_sample[i])) @@ -1496,9 +1524,11 @@ def dump(self, output_file, size): f1.write("%s," % int(self.lock_detect_outp[i])) f1.write("%s," % int(self.lock_detect_outo[i])) + f1.write("%s," % (self.lock_detect_lpfi[i] / self.lock_detect_lpfq[i])) + f1.write("%s," % self.iq_ratio_min[i]) + f1.write("%s," % self.dynamics[i]) f1.write("%s," % self.phase_err[i]) - f1.write("%s," % self.phase_err_max[i]) f1.write("%s," % self.code_err[i]) f1.write("%s," % self.cn0[i]) @@ -1509,6 +1539,7 @@ def dump(self, output_file, size): f1.write("%s," % self.code_freq[i]) f1.write("%s," % self.snr[i]) f1.write("%s," % self.snr_db[i]) + f1.write("%s," % (np.absolute(self.P[i]) ** 2)) f1.write("%s," % self.E[i].real) f1.write("%s," % self.E[i].imag) f1.write("%s," % self.P[i].real) diff --git a/peregrine/tracking_loop.py b/peregrine/tracking_loop.py index 5cd3d49..d088999 100644 --- a/peregrine/tracking_loop.py +++ b/peregrine/tracking_loop.py @@ -91,9 +91,9 @@ def retune(self, code_params, carr_params, loop_freq, carr_freq_b1, carr_to_code # self.code_vel = 0 # self.phase_vel = 0 - if self.fll_bw and not carr_freq_b1: - # FLL is turned off - self.phase_acc = 0 + # if self.fll_bw and not carr_freq_b1: + # # FLL is turned off + # self.phase_acc = 0 self.fll_bw = carr_freq_b1 self.pll_bw = carr_bw From e9a70d3be21ec8f113e46c0277521442938f4ce7 Mon Sep 17 00:00:00 2001 From: Adel Mamin Date: Thu, 4 Aug 2016 16:38:26 +0300 Subject: [PATCH 29/61] 5g doppler works! --- peregrine/tracking.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/peregrine/tracking.py b/peregrine/tracking.py index 3a5f04b..36ce2ae 100644 --- a/peregrine/tracking.py +++ b/peregrine/tracking.py @@ -219,7 +219,7 @@ def __init__(self, params): self.profiles_history = [] self.track_candidates = [] - self.stabilization_time = 150 + self.stabilization_time = 200 self.coherent_ms = coherent_ms self.alias_detector = alias_detector.AliasDetector(self.coherent_ms) @@ -416,10 +416,20 @@ def _filter_track_candidates(self): for candidate in self.track_candidates: pll_bw_index = candidate['pll_bw_index'] pll_bw = self.track_params['pll_bw'][pll_bw_index] + + fll_bw_index = candidate['fll_bw_index'] + fll_bw = self.track_params['fll_bw'][fll_bw_index] + coherent_ms_index = candidate['coherent_ms_index'] coherent_ms = self.track_params['coherent_ms'][coherent_ms_index] - if pll_bw * coherent_ms * 1e-3 <= 0.04: - res.append(candidate) + + if pll_bw * coherent_ms * 1e-3 > 0.04: + continue + + if fll_bw == 0 and self.loop_filter.to_dict()['phase_acc'] / (2 * np.pi) > 100: + continue + + res.append(candidate) print "filtered candidates: ", res return res @@ -814,7 +824,7 @@ def __init__(self, params): params['loop_filter_params_template'] = \ defaults.l1ca_loop_filter_params_template - params['lock_detect_params'] = defaults.l1ca_lock_detect_params_normal + params['lock_detect_params'] = defaults.l1ca_lock_detect_params_opt params['chipping_rate'] = gps_constants.l1ca_chip_rate params['sample_index'] = params['samples']['sample_index'] From 63acde8b5e00a29fd9da810e9645cd56224456f2 Mon Sep 17 00:00:00 2001 From: Adel Mamin Date: Fri, 5 Aug 2016 18:08:59 +0300 Subject: [PATCH 30/61] Draft version of tracking profile algorithm is ready --- peregrine/defaults.py | 7 ++- peregrine/tracking.py | 138 +++++++++++++++++++++++++++++++++--------- 2 files changed, 113 insertions(+), 32 deletions(-) diff --git a/peregrine/defaults.py b/peregrine/defaults.py index 50872b8..b64e8d1 100644 --- a/peregrine/defaults.py +++ b/peregrine/defaults.py @@ -207,7 +207,7 @@ l1ca_track_params = { 'fll_bw': (1, 0), - 'pll_bw': (30, 20, 18, 16, 14, 10, 8, 6, 4, 2), + 'pll_bw': (40, 35, 30, 25, 20, 18, 16, 14, 10, 8, 6, 4, 2), 'coherent_ms': (1, 2, 4, 5, 10, 20) } l1ca_loop_filter_params_template = { @@ -1496,7 +1496,7 @@ l1ca_lock_detect_params_pess = {"k1": 0.10, "k2": 1.4, "lp": 200, "lo": 50} # normal set -l1ca_lock_detect_params_normal = {"k1": 0.05, "k2": 1.4, "lp": 150, "lo": 50} +l1ca_lock_detect_params_normal = {"k1": 0.2, "k2": .8, "lp": 150, "lo": 50} # optimal set l1ca_lock_detect_params_opt = {"k1": 0.02, "k2": 1.1, "lp": 150, "lo": 50} @@ -1507,6 +1507,9 @@ # disable lock detect l1ca_lock_detect_params_disable = {"k1": 0.02, "k2": 1e-6, "lp": 1, "lo": 1} +lock_detect_params_slow = {"k1": 0.005, "k2": 1.4, "lp": 200, "lo": 50} +lock_detect_params_fast = {"k1": 0.2, "k2": .8, "lp": 50, "lo": 50} + # L2C 20ms lock detect profile # References: # - Understanding GPS: Principles and Applications. diff --git a/peregrine/tracking.py b/peregrine/tracking.py index 36ce2ae..ca4bb5d 100644 --- a/peregrine/tracking.py +++ b/peregrine/tracking.py @@ -219,7 +219,7 @@ def __init__(self, params): self.profiles_history = [] self.track_candidates = [] - self.stabilization_time = 200 + self.stabilization_time = 100 self.coherent_ms = coherent_ms self.alias_detector = alias_detector.AliasDetector(self.coherent_ms) @@ -243,6 +243,18 @@ def __init__(self, params): lp=self.lock_detect_params["lp"], lo=self.lock_detect_params["lo"]) + self.lock_detect_fast = lock_detect.LockDetector( + k1=defaults.lock_detect_params_fast["k1"], + k2=defaults.lock_detect_params_fast["k2"], + lp=defaults.lock_detect_params_fast["lp"], + lo=defaults.lock_detect_params_fast["lo"]) + + self.lock_detect_slow = lock_detect.LockDetector( + k1=defaults.lock_detect_params_slow["k1"], + k2=defaults.lock_detect_params_slow["k2"], + lp=defaults.lock_detect_params_slow["lp"], + lo=defaults.lock_detect_params_slow["lo"]) + self.cn0_est = CN0_Est_MM( bw=1e3 / self.coherent_ms, cn0_0=self.cn0_0, @@ -366,11 +378,11 @@ def _set_track_profile(self): self.alias_detector.reinit(self.coherent_ms) self.loop_filter.retune(**loop_filter_params) - self.lock_detect.reinit( - k1=self.lock_detect_params["k1"], - k2=self.lock_detect_params["k2"], - lp=self.lock_detect_params["lp"], - lo=self.lock_detect_params["lo"]) + # self.lock_detect.reinit( + # k1=self.lock_detect_params["k1"], + # k2=self.lock_detect_params["k2"], + # lp=self.lock_detect_params["lp"], + # lo=self.lock_detect_params["lo"]) self.cn0_est = CN0_Est_MM(bw=1e3 / self.coherent_ms, cn0_0=self.track_result.cn0[self.i - 1], cutoff_freq=10, @@ -426,8 +438,8 @@ def _filter_track_candidates(self): if pll_bw * coherent_ms * 1e-3 > 0.04: continue - if fll_bw == 0 and self.loop_filter.to_dict()['phase_acc'] / (2 * np.pi) > 100: - continue + # if fll_bw == 0 and self.loop_filter.to_dict()['phase_acc'] / (2 * np.pi) > 100: + # continue res.append(candidate) @@ -446,11 +458,20 @@ def _run_track_profile_selection(self): self.bit_sync = self.nav_bit_sync.bit_sync_acquired() if self.lock_detect_outp: + if not self.lock_detect_fast_outp: + self.fll_bw_index = 1 + self.pll_bw_index = 0 + self.coherent_ms_index = 0 + self.profiles_history = [] + print "We are about to loose the lock" + self._set_track_profile() + return + track_settled = self.track_profile_timer_ms >= self.stabilization_time if not track_settled: return - iq_ratio = np.absolute(self.lock_detect_lpfi / self.lock_detect_lpfq) + iq_ratio = np.absolute(self.lock_detect_slow_lpfi / self.lock_detect_slow_lpfq) if not self.track_settled: self.track_profile['iq_ratio'] = iq_ratio self.track_settled = True @@ -459,15 +480,27 @@ def _run_track_profile_selection(self): if self.track_profile['iq_ratio'] > iq_ratio: self.track_profile['iq_ratio'] = iq_ratio + + # if prev_iq_ratio and iq_ratio < prev_iq_ratio and \ + # iq_ratio < 3 and \ + # len(self.profiles_history) > 0: + + # if prev_iq_ratio and iq_ratio < prev_iq_ratio and \ + # len(self.profiles_history) > 0: + if len(self.profiles_history): prev_iq_ratio = self.profiles_history[-1]['iq_ratio'] else: prev_iq_ratio = 0 - if prev_iq_ratio and iq_ratio < prev_iq_ratio and \ - iq_ratio < 2 and \ + if prev_iq_ratio and iq_ratio < prev_iq_ratio * 0.5 and \ len(self.profiles_history) > 0: + # if prev_iq_ratio and iq_ratio < prev_iq_ratio and \ + # len(self.profiles_history) > 0: + + # if not self.lock_detect_fast_outp and len(self.profiles_history) > 0: + print "" print "#################### Current history status history: " for pr in self.profiles_history: @@ -476,7 +509,7 @@ def _run_track_profile_selection(self): print "" profile = self.profiles_history.pop() - print "Low I/Q ratio, Prev: ", prev_iq_ratio, " Now: ", iq_ratio + #print "Low I/Q ratio, Prev: ", prev_iq_ratio, " Now: ", iq_ratio print "Taking profile from history: ", profile self.fll_bw_index = profile['fll_bw_index'] self.pll_bw_index = profile['pll_bw_index'] @@ -530,12 +563,12 @@ def _run_track_profile_selection(self): self.coherent_ms_index == 0: return - # self.fll_bw_index = 0 - # self.pll_bw_index = 0 - # self.coherent_ms_index = 0 - # self.profiles_history = [] - # print "Back to init profile" - # self._set_track_profile() + self.fll_bw_index = 0 + self.pll_bw_index = 0 + self.coherent_ms_index = 0 + self.profiles_history = [] + print "Back to init profile" + self._set_track_profile() def _run_nav_data_decoding(self): """ @@ -662,6 +695,36 @@ def run(self, samples): flags_post = cur_fsm_state[2]['post'] self.fsm_index = cur_fsm_state[1] + if defaults.RUN_LD in flags_post: + # Update PLL lock detector + self.lock_detect_outo, \ + self.lock_detect_outp, \ + lock_detect_pcount1, \ + lock_detect_pcount2, \ + self.lock_detect_lpfi, \ + self.lock_detect_lpfq = self.lock_detect.update(self.P.real, + self.P.imag, + 1) + # Update PLL fast lock detector + self.lock_detect_fast_outo, \ + self.lock_detect_fast_outp, \ + lock_detect_fast_pcount1, \ + lock_detect_fast_pcount2, \ + self.lock_detect_fast_lpfi, \ + self.lock_detect_fast_lpfq = self.lock_detect_fast.update(self.P.real, + self.P.imag, + 1) + + # Update PLL fast lock detector + self.lock_detect_slow_outo, \ + self.lock_detect_slow_outp, \ + lock_detect_slow_pcount1, \ + lock_detect_slow_pcount2, \ + self.lock_detect_slow_lpfi, \ + self.lock_detect_slow_lpfq = self.lock_detect_slow.update(self.P.real, + self.P.imag, + 1) + if self.lock_detect_outo: if defaults.ALIAS_DETECT_1ST in flags_post or \ defaults.ALIAS_DETECT_BOTH in flags_post: @@ -684,17 +747,6 @@ def run(self, samples): not (defaults.GET_CORR_2 in flags_post): continue - if defaults.RUN_LD in flags_post: - # Update PLL lock detector - self.lock_detect_outo, \ - self.lock_detect_outp, \ - lock_detect_pcount1, \ - lock_detect_pcount2, \ - self.lock_detect_lpfi, \ - self.lock_detect_lpfq = self.lock_detect.update(self.P.real, - self.P.imag, - self.coherent_ms) - self.track_result.dynamics[self.i] = \ self.loop_filter.to_dict()['phase_acc'] / (2 * np.pi) #self.dynamics_detector.update(self.loop_filter.to_dict()['phase_acc'] / (2 * np.pi), self.coherent_ms) @@ -753,11 +805,20 @@ def run(self, samples): self.track_result.lock_detect_outo[self.i] = self.lock_detect_outo self.track_result.lock_detect_outp[self.i] = self.lock_detect_outp + self.track_result.lock_detect_fast_outo[self.i] = self.lock_detect_fast_outo + self.track_result.lock_detect_fast_outp[self.i] = self.lock_detect_fast_outp self.track_result.lock_detect_pcount1[self.i] = lock_detect_pcount1 self.track_result.lock_detect_pcount2[self.i] = lock_detect_pcount2 + self.track_result.lock_detect_lpfi[self.i] = self.lock_detect_lpfi self.track_result.lock_detect_lpfq[self.i] = self.lock_detect_lpfq + self.track_result.lock_detect_fast_lpfi[self.i] = self.lock_detect_fast_lpfi + self.track_result.lock_detect_fast_lpfq[self.i] = self.lock_detect_fast_lpfq + + self.track_result.lock_detect_slow_lpfi[self.i] = self.lock_detect_slow_lpfi + self.track_result.lock_detect_slow_lpfq[self.i] = self.lock_detect_slow_lpfq + self.track_result.alias_detect_err_hz[self.i] = err_hz self._run_nav_data_decoding() @@ -1444,10 +1505,20 @@ def __init__(self, n_points, prn, signal): self.snr_db = np.zeros(n_points) self.lock_detect_outp = np.zeros(n_points) self.lock_detect_outo = np.zeros(n_points) + self.lock_detect_fast_outp = np.zeros(n_points) + self.lock_detect_fast_outo = np.zeros(n_points) self.lock_detect_pcount1 = np.zeros(n_points) self.lock_detect_pcount2 = np.zeros(n_points) + self.lock_detect_lpfi = np.zeros(n_points) self.lock_detect_lpfq = np.zeros(n_points) + + self.lock_detect_fast_lpfi = np.zeros(n_points) + self.lock_detect_fast_lpfq = np.zeros(n_points) + + self.lock_detect_slow_lpfi = np.zeros(n_points) + self.lock_detect_slow_lpfq = np.zeros(n_points) + self.alias_detect_err_hz = np.zeros(n_points) self.phase_err = np.zeros(n_points) self.iq_ratio_min = np.zeros(n_points) @@ -1510,7 +1581,8 @@ def dump(self, output_file, size): "sample_index,ms_tracked,coherent_ms,bit_sync,fll_bw,pll_bw,dll_bw," "track_timer_ms," "lock_detect_outp,lock_detect_outo," - "iq_ratio,iq_ratio_min,dynamics," + "lock_detect_fast_outp,lock_detect_fast_outo," + "iq_ratio,iq_ratio_fast,iq_ration_slow,iq_ratio_raw,iq_ratio_min,dynamics," "phase_err,code_err,CN0,IF,doppler_phase," "carr_doppler,code_phase,code_freq," "SNR,SNR_DB,P_Mag,E_I,E_Q,P_I,P_Q,L_I,L_Q," @@ -1534,7 +1606,13 @@ def dump(self, output_file, size): f1.write("%s," % int(self.lock_detect_outp[i])) f1.write("%s," % int(self.lock_detect_outo[i])) + f1.write("%s," % int(self.lock_detect_fast_outp[i])) + f1.write("%s," % int(self.lock_detect_fast_outo[i])) + f1.write("%s," % (self.lock_detect_lpfi[i] / self.lock_detect_lpfq[i])) + f1.write("%s," % (self.lock_detect_fast_lpfi[i] / self.lock_detect_fast_lpfq[i])) + f1.write("%s," % (self.lock_detect_slow_lpfi[i] / self.lock_detect_slow_lpfq[i])) + f1.write("%s," % np.absolute(self.P[i].real / self.P[i].imag)) f1.write("%s," % self.iq_ratio_min[i]) f1.write("%s," % self.dynamics[i]) From 0d9ef860ac1c2c9dd1c1fcd565d5229998650112 Mon Sep 17 00:00:00 2001 From: Adel Mamin Date: Fri, 5 Aug 2016 18:15:56 +0300 Subject: [PATCH 31/61] Clean up --- peregrine/defaults.py | 484 ------------------------------------------ peregrine/tracking.py | 45 +--- 2 files changed, 1 insertion(+), 528 deletions(-) diff --git a/peregrine/defaults.py b/peregrine/defaults.py index b64e8d1..c218f8a 100644 --- a/peregrine/defaults.py +++ b/peregrine/defaults.py @@ -218,490 +218,6 @@ 'carr_to_code': 1540. # carr_to_code } -# l1ca_track_profiles_fll = { -# 0: ({'coherent_ms': 1, -# 'stabilization_time_ms': 50, -# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k -# 'carr_params': (20., 0.7, 1.), # NBW, zeta, k -# 'loop_freq': 1000., # 1000/coherent_ms -# 'carr_freq_b1': 1., # FLL NBW -# 'carr_to_code': 1540. # carr_to_code -# } -# }, 1), -# 1: ({'coherent_ms': 4, -# 'stabilization_time_ms': 50, -# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k -# 'carr_params': (8, 0.7, 1.), # NBW, zeta, k -# 'loop_freq': 1000./4, # 1000/coherent_ms -# 'carr_freq_b1': 0., # FLL NBW -# 'carr_to_code': 1540. # carr_to_code -# } -# }, 1) } - -# l1ca_track_response = { -# 0: ({'coherent_ms': 1, -# 'stabilization_time_ms': 50, -# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k -# 'carr_params': (20., 0.7, 1.), # NBW, zeta, k -# 'loop_freq': 1000., # 1000/coherent_ms -# 'carr_freq_b1': 1., # FLL NBW -# 'carr_to_code': 1540. # carr_to_code -# } -# }, 0 } - -# l1ca_track_recovery = { -# 0: ({'coherent_ms': 1, -# 'stabilization_time_ms': 50, -# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k -# 'carr_params': (20., 0.7, 1.), # NBW, zeta, k -# 'loop_freq': 1000., # 1000/coherent_ms -# 'carr_freq_b1': 0., # FLL NBW -# 'carr_to_code': 1540. # carr_to_code -# } -# }, 0 } - -# l1ca_track_profiles = { -# # init state -# 0: ({'coherent_ms': 1, -# 'stabilization_time_ms': 50, -# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k -# 'carr_params': (20., 0.7, 1.), # NBW, zeta, k -# 'loop_freq': 1000., # 1000/coherent_ms -# 'carr_freq_b1': 1., # FLL NBW -# 'carr_to_code': 1540. # carr_to_code -# } -# }, {'next_bw': 1, 'next_time': 1}), - -# # 1ms -# 1: ({'coherent_ms': 1, -# 'stabilization_time_ms': 50, -# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k -# 'carr_params': (20., 0.7, 1.), # NBW, zeta, k -# 'loop_freq': 1000., # 1000/coherent_ms -# 'carr_freq_b1': 0., # FLL NBW -# 'carr_to_code': 1540. # carr_to_code -# } -# }, {'next_bw': 2, 'next_time': 8}), - -# 2: ({'coherent_ms': 1, -# 'stabilization_time_ms': 50, -# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k -# 'carr_params': (14., 0.7, 1.), # NBW, zeta, k -# 'loop_freq': 1000., # 1000/coherent_ms -# 'carr_freq_b1': 0., # FLL NBW -# 'carr_to_code': 1540. # carr_to_code -# } -# }, {'next_bw': 3, 'next_time': 9}), - -# 3: ({'coherent_ms': 1, -# 'stabilization_time_ms': 50, -# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k -# 'carr_params': (10, 0.7, 1.), # NBW, zeta, k -# 'loop_freq': 1000., # 1000/coherent_ms -# 'carr_freq_b1': 0., # FLL NBW -# 'carr_to_code': 1540. # carr_to_code -# } -# }, {'next_bw': 4, 'next_time': 10}), - -# 4: ({'coherent_ms': 1, -# 'stabilization_time_ms': 50, -# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k -# 'carr_params': (8, 0.7, 1.), # NBW, zeta, k -# 'loop_freq': 1000., # 1000/coherent_ms -# 'carr_freq_b1': 0., # FLL NBW -# 'carr_to_code': 1540. # carr_to_code -# } -# }, {'next_bw': 5, 'next_time': 11}), - -# 5: ({'coherent_ms': 1, -# 'stabilization_time_ms': 50, -# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k -# 'carr_params': (6, 0.7, 1.), # NBW, zeta, k -# 'loop_freq': 1000., # 1000/coherent_ms -# 'carr_freq_b1': 0., # FLL NBW -# 'carr_to_code': 1540. # carr_to_code -# } -# }, {'next_bw': 6, 'next_time': 12}), - -# 6: ({'coherent_ms': 1, -# 'stabilization_time_ms': 50, -# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k -# 'carr_params': (4, 0.7, 1.), # NBW, zeta, k -# 'loop_freq': 1000., # 1000/coherent_ms -# 'carr_freq_b1': 0., # FLL NBW -# 'carr_to_code': 1540. # carr_to_code -# } -# }, {'next_bw': 7, 'next_time': 13}), - -# 7: ({'coherent_ms': 1, -# 'stabilization_time_ms': 50, -# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k -# 'carr_params': (2, 0.7, 1.), # NBW, zeta, k -# 'loop_freq': 1000., # 1000/coherent_ms -# 'carr_freq_b1': 0., # FLL NBW -# 'carr_to_code': 1540. # carr_to_code -# } -# }, {'next_bw': 7, 'next_time': 14}), - -# # 2ms -# 8: ({'coherent_ms': 2, -# 'stabilization_time_ms': 50, -# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k -# 'carr_params': (20., 0.7, 1.), # NBW, zeta, k -# 'loop_freq': 1000. / 2, # 1000/coherent_ms -# 'carr_freq_b1': 0., # FLL NBW -# 'carr_to_code': 1540. # carr_to_code -# } -# }, {'next_bw': 9, 'next_time': 15}), - -# 9: ({'coherent_ms': 2, -# 'stabilization_time_ms': 50, -# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k -# 'carr_params': (14., 0.7, 1.), # NBW, zeta, k -# 'loop_freq': 1000. / 2, # 1000/coherent_ms -# 'carr_freq_b1': 0., # FLL NBW -# 'carr_to_code': 1540. # carr_to_code -# } -# }, {'next_bw': 10, 'next_time': 16}), - -# 10: ({'coherent_ms': 2, -# 'stabilization_time_ms': 50, -# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k -# 'carr_params': (10, 0.7, 1.), # NBW, zeta, k -# 'loop_freq': 1000. / 2, # 1000/coherent_ms -# 'carr_freq_b1': 0., # FLL NBW -# 'carr_to_code': 1540. # carr_to_code -# } -# }, {'next_bw': 11, 'next_time': 17}), - -# 11: ({'coherent_ms': 2, -# 'stabilization_time_ms': 50, -# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k -# 'carr_params': (8, 0.7, 1.), # NBW, zeta, k -# 'loop_freq': 1000. / 2, # 1000/coherent_ms -# 'carr_freq_b1': 0., # FLL NBW -# 'carr_to_code': 1540. # carr_to_code -# } -# }, {'next_bw': 12, 'next_time': 18}), - -# 12: ({'coherent_ms': 2, -# 'stabilization_time_ms': 50, -# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k -# 'carr_params': (6, 0.7, 1.), # NBW, zeta, k -# 'loop_freq': 1000. / 2, # 1000/coherent_ms -# 'carr_freq_b1': 0., # FLL NBW -# 'carr_to_code': 1540. # carr_to_code -# } -# }, {'next_bw': 13, 'next_time': 19}), - -# 13: ({'coherent_ms':21, -# 'stabilization_time_ms': 50, -# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k -# 'carr_params': (4, 0.7, 1.), # NBW, zeta, k -# 'loop_freq': 1000. / 2, # 1000/coherent_ms -# 'carr_freq_b1': 0., # FLL NBW -# 'carr_to_code': 1540. # carr_to_code -# } -# }, {'next_bw': 14, 'next_time': 20}), - -# 14: ({'coherent_ms': 2, -# 'stabilization_time_ms': 50, -# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k -# 'carr_params': (2, 0.7, 1.), # NBW, zeta, k -# 'loop_freq': 1000. / 2, # 1000/coherent_ms -# 'carr_freq_b1': 0., # FLL NBW -# 'carr_to_code': 1540. # carr_to_code -# } -# }, {'next_bw': 14, 'next_time': 21}), - -# # 4ms - -# 15: ({'coherent_ms': 4, -# 'stabilization_time_ms': 50, -# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k -# 'carr_params': (20., 0.7, 1.), # NBW, zeta, k -# 'loop_freq': 1000. / 4, # 1000/coherent_ms -# 'carr_freq_b1': 0., # FLL NBW -# 'carr_to_code': 1540. # carr_to_code -# } -# }, {'next_bw': 16, 'next_time': 22}), - -# 16: ({'coherent_ms': 4, -# 'stabilization_time_ms': 50, -# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k -# 'carr_params': (14., 0.7, 1.), # NBW, zeta, k -# 'loop_freq': 1000. / 4, # 1000/coherent_ms -# 'carr_freq_b1': 0., # FLL NBW -# 'carr_to_code': 1540. # carr_to_code -# } -# }, {'next_bw': 17, 'next_time': 23}), - -# 17: ({'coherent_ms': 4, -# 'stabilization_time_ms': 50, -# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k -# 'carr_params': (10, 0.7, 1.), # NBW, zeta, k -# 'loop_freq': 1000. / 4, # 1000/coherent_ms -# 'carr_freq_b1': 0., # FLL NBW -# 'carr_to_code': 1540. # carr_to_code -# } -# }, {'next_bw': 18, 'next_time':24}), - -# 18: ({'coherent_ms': 4, -# 'stabilization_time_ms': 50, -# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k -# 'carr_params': (8, 0.7, 1.), # NBW, zeta, k -# 'loop_freq': 1000. / 4, # 1000/coherent_ms -# 'carr_freq_b1': 0., # FLL NBW -# 'carr_to_code': 1540. # carr_to_code -# } -# }, {'next_bw': 19, 'next_time': 25}), - -# 19: ({'coherent_ms': 4, -# 'stabilization_time_ms': 50, -# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k -# 'carr_params': (6, 0.7, 1.), # NBW, zeta, k -# 'loop_freq': 1000. / 4, # 1000/coherent_ms -# 'carr_freq_b1': 0., # FLL NBW -# 'carr_to_code': 1540. # carr_to_code -# } -# }, {'next_bw': 20, 'next_time': 26}), - -# 20: ({'coherent_ms': 4, -# 'stabilization_time_ms': 50, -# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k -# 'carr_params': (4, 0.7, 1.), # NBW, zeta, k -# 'loop_freq': 1000. / 4, # 1000/coherent_ms -# 'carr_freq_b1': 0., # FLL NBW -# 'carr_to_code': 1540. # carr_to_code -# } -# }, {'next_bw': 21, 'next_time': 27}), - -# 21: ({'coherent_ms': 4, -# 'stabilization_time_ms': 50, -# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k -# 'carr_params': (2, 0.7, 1.), # NBW, zeta, k -# 'loop_freq': 1000. / 4, # 1000/coherent_ms -# 'carr_freq_b1': 0., # FLL NBW -# 'carr_to_code': 1540. # carr_to_code -# } -# }, {'next_bw': 21, 'next_time': 28}), - -# # 5ms -# 22: ({'coherent_ms': 5, -# 'stabilization_time_ms': 50, -# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k -# 'carr_params': (20., 0.7, 1.), # NBW, zeta, k -# 'loop_freq': 1000. / 5, # 1000/coherent_ms -# 'carr_freq_b1': 0., # FLL NBW -# 'carr_to_code': 1540. # carr_to_code -# } -# }, {'next_bw': 23, 'next_time': 29}), - -# 23: ({'coherent_ms': 5, -# 'stabilization_time_ms': 50, -# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k -# 'carr_params': (14., 0.7, 1.), # NBW, zeta, k -# 'loop_freq': 1000. / 5, # 1000/coherent_ms -# 'carr_freq_b1': 0., # FLL NBW -# 'carr_to_code': 1540. # carr_to_code -# } -# }, {'next_bw': 24, 'next_time': 30}), - -# 24: ({'coherent_ms': 5, -# 'stabilization_time_ms': 50, -# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k -# 'carr_params': (10, 0.7, 1.), # NBW, zeta, k -# 'loop_freq': 1000. / 5, # 1000/coherent_ms -# 'carr_freq_b1': 0., # FLL NBW -# 'carr_to_code': 1540. # carr_to_code -# } -# }, {'next_bw': 25, 'next_time': 31}), - -# 25: ({'coherent_ms': 5, -# 'stabilization_time_ms': 50, -# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k -# 'carr_params': (8, 0.7, 1.), # NBW, zeta, k -# 'loop_freq': 1000. / 5, # 1000/coherent_ms -# 'carr_freq_b1': 0., # FLL NBW -# 'carr_to_code': 1540. # carr_to_code -# } -# }, {'next_bw': 26, 'next_time': 32}), - -# 26: ({'coherent_ms': 5, -# 'stabilization_time_ms': 50, -# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k -# 'carr_params': (6, 0.7, 1.), # NBW, zeta, k -# 'loop_freq': 1000. / 5, # 1000/coherent_ms -# 'carr_freq_b1': 0., # FLL NBW -# 'carr_to_code': 1540. # carr_to_code -# } -# }, {'next_bw': 27, 'next_time': 33}), - -# 27: ({'coherent_ms': 5, -# 'stabilization_time_ms': 50, -# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k -# 'carr_params': (4, 0.7, 1.), # NBW, zeta, k -# 'loop_freq': 1000. / 5, # 1000/coherent_ms -# 'carr_freq_b1': 0., # FLL NBW -# 'carr_to_code': 1540. # carr_to_code -# } -# }, {'next_bw': 28, 'next_time': 34}), - -# 28: ({'coherent_ms': 5, -# 'stabilization_time_ms': 50, -# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k -# 'carr_params': (2, 0.7, 1.), # NBW, zeta, k -# 'loop_freq': 1000. / 5, # 1000/coherent_ms -# 'carr_freq_b1': 0., # FLL NBW -# 'carr_to_code': 1540. # carr_to_code -# } -# }, {'next_bw': 28, 'next_time': 35}), - -# # 10ms - -# 29: ({'coherent_ms': 10, -# 'stabilization_time_ms': 50, -# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k -# 'carr_params': (20., 0.7, 1.), # NBW, zeta, k -# 'loop_freq': 1000. / 10, # 1000/coherent_ms -# 'carr_freq_b1': 0., # FLL NBW -# 'carr_to_code': 1540. # carr_to_code -# } -# }, {'next_bw': 30, 'next_time': 36}), - -# 30: ({'coherent_ms': 10, -# 'stabilization_time_ms': 50, -# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k -# 'carr_params': (14., 0.7, 1.), # NBW, zeta, k -# 'loop_freq': 1000. / 10, # 1000/coherent_ms -# 'carr_freq_b1': 0., # FLL NBW -# 'carr_to_code': 1540. # carr_to_code -# } -# }, {'next_bw': 31, 'next_time': 37}), - -# 31: ({'coherent_ms': 10, -# 'stabilization_time_ms': 50, -# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k -# 'carr_params': (10, 0.7, 1.), # NBW, zeta, k -# 'loop_freq': 1000. / 10, # 1000/coherent_ms -# 'carr_freq_b1': 0., # FLL NBW -# 'carr_to_code': 1540. # carr_to_code -# } -# }, {'next_bw': 32, 'next_time': 38}), - -# 32: ({'coherent_ms': 10, -# 'stabilization_time_ms': 50, -# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k -# 'carr_params': (8, 0.7, 1.), # NBW, zeta, k -# 'loop_freq': 1000. / 10, # 1000/coherent_ms -# 'carr_freq_b1': 0., # FLL NBW -# 'carr_to_code': 1540. # carr_to_code -# } -# }, {'next_bw': 33, 'next_time': 39}), - -# 33: ({'coherent_ms': 10, -# 'stabilization_time_ms': 50, -# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k -# 'carr_params': (6, 0.7, 1.), # NBW, zeta, k -# 'loop_freq': 1000. / 10, # 1000/coherent_ms -# 'carr_freq_b1': 0., # FLL NBW -# 'carr_to_code': 1540. # carr_to_code -# } -# }, {'next_bw': 34, 'next_time': 40}), - -# 34: ({'coherent_ms': 10, -# 'stabilization_time_ms': 50, -# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k -# 'carr_params': (4, 0.7, 1.), # NBW, zeta, k -# 'loop_freq': 1000. / 10, # 1000/coherent_ms -# 'carr_freq_b1': 0., # FLL NBW -# 'carr_to_code': 1540. # carr_to_code -# } -# }, {'next_bw': 35, 'next_time': 41}), - -# 35: ({'coherent_ms': 10, -# 'stabilization_time_ms': 50, -# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k -# 'carr_params': (2, 0.7, 1.), # NBW, zeta, k -# 'loop_freq': 1000. / 10, # 1000/coherent_ms -# 'carr_freq_b1': 0., # FLL NBW -# 'carr_to_code': 1540. # carr_to_code -# } -# }, {'next_bw': 35, 'next_time': 42}), - -# # 20ms - -# 36: ({'coherent_ms': 20, -# 'stabilization_time_ms': 50, -# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k -# 'carr_params': (20., 0.7, 1.), # NBW, zeta, k -# 'loop_freq': 1000. / 20, # 1000/coherent_ms -# 'carr_freq_b1': 0., # FLL NBW -# 'carr_to_code': 1540. # carr_to_code -# } -# }, {'next_bw': 37, 'next_time': 36}), - -# 37: ({'coherent_ms': 20, -# 'stabilization_time_ms': 50, -# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k -# 'carr_params': (14., 0.7, 1.), # NBW, zeta, k -# 'loop_freq': 1000. / 20, # 1000/coherent_ms -# 'carr_freq_b1': 0., # FLL NBW -# 'carr_to_code': 1540. # carr_to_code -# } -# }, {'next_bw': 38, 'next_time': 37}), - -# 38: ({'coherent_ms': 20, -# 'stabilization_time_ms': 50, -# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k -# 'carr_params': (10, 0.7, 1.), # NBW, zeta, k -# 'loop_freq': 1000. / 20, # 1000/coherent_ms -# 'carr_freq_b1': 0., # FLL NBW -# 'carr_to_code': 1540. # carr_to_code -# } -# }, {'next_bw': 39, 'next_time': 38}), - -# 39: ({'coherent_ms': 20, -# 'stabilization_time_ms': 50, -# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k -# 'carr_params': (8, 0.7, 1.), # NBW, zeta, k -# 'loop_freq': 1000. / 20, # 1000/coherent_ms -# 'carr_freq_b1': 0., # FLL NBW -# 'carr_to_code': 1540. # carr_to_code -# } -# }, {'next_bw': 40, 'next_time': 39}), - -# 40: ({'coherent_ms': 20, -# 'stabilization_time_ms': 50, -# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k -# 'carr_params': (6, 0.7, 1.), # NBW, zeta, k -# 'loop_freq': 1000. / 20, # 1000/coherent_ms -# 'carr_freq_b1': 0., # FLL NBW -# 'carr_to_code': 1540. # carr_to_code -# } -# }, {'next_bw': 41, 'next_time': 40}), - -# 41: ({'coherent_ms': 20, -# 'stabilization_time_ms': 50, -# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k -# 'carr_params': (4, 0.7, 1.), # NBW, zeta, k -# 'loop_freq': 1000. / 20, # 1000/coherent_ms -# 'carr_freq_b1': 0., # FLL NBW -# 'carr_to_code': 1540. # carr_to_code -# } -# }, {'next_bw': 42, 'next_time': 41}), - -# 42: ({'coherent_ms': 20, -# 'stabilization_time_ms': 50, -# 'loop_filter_params': {'code_params': (1., 0.7, 1.), # NBW, zeta, k -# 'carr_params': (2, 0.7, 1.), # NBW, zeta, k -# 'loop_freq': 1000. / 20, # 1000/coherent_ms -# 'carr_freq_b1': 0., # FLL NBW -# 'carr_to_code': 1540. # carr_to_code -# } -# }, {'next_bw': 42, 'next_time': 42}) } - - # Tracking stages. See track.c for more details. # 1;20 ms stages l1ca_stage_params_slow = \ diff --git a/peregrine/tracking.py b/peregrine/tracking.py index ca4bb5d..a74ab74 100644 --- a/peregrine/tracking.py +++ b/peregrine/tracking.py @@ -27,7 +27,6 @@ from peregrine import gps_constants from peregrine import glo_constants from peregrine import alias_detector -from peregrine import dynamics_detector from peregrine.acquisition import AcquisitionResult from peregrine.acquisition import GloAcquisitionResult from peregrine.include.generateCAcode import caCodes @@ -223,8 +222,6 @@ def __init__(self, params): self.coherent_ms = coherent_ms self.alias_detector = alias_detector.AliasDetector(self.coherent_ms) - self.dynamics_detector = dynamics_detector.DynamicsDetector() - self.short_n_long = False if params['tracker_options']: mode = params['tracker_options']['mode'] @@ -378,11 +375,7 @@ def _set_track_profile(self): self.alias_detector.reinit(self.coherent_ms) self.loop_filter.retune(**loop_filter_params) - # self.lock_detect.reinit( - # k1=self.lock_detect_params["k1"], - # k2=self.lock_detect_params["k2"], - # lp=self.lock_detect_params["lp"], - # lo=self.lock_detect_params["lo"]) + self.cn0_est = CN0_Est_MM(bw=1e3 / self.coherent_ms, cn0_0=self.track_result.cn0[self.i - 1], cutoff_freq=10, @@ -421,7 +414,6 @@ def _make_track_candidates(self): 'coherent_ms_index': self.coherent_ms_index } self.track_candidates.append(candidate) - print "New track candidates: ", self.track_candidates, " Bit sync: ", self.bit_sync def _filter_track_candidates(self): res = [] @@ -438,12 +430,8 @@ def _filter_track_candidates(self): if pll_bw * coherent_ms * 1e-3 > 0.04: continue - # if fll_bw == 0 and self.loop_filter.to_dict()['phase_acc'] / (2 * np.pi) > 100: - # continue - res.append(candidate) - print "filtered candidates: ", res return res def _run_track_profile_selection(self): @@ -463,7 +451,6 @@ def _run_track_profile_selection(self): self.pll_bw_index = 0 self.coherent_ms_index = 0 self.profiles_history = [] - print "We are about to loose the lock" self._set_track_profile() return @@ -475,19 +462,10 @@ def _run_track_profile_selection(self): if not self.track_settled: self.track_profile['iq_ratio'] = iq_ratio self.track_settled = True - print "Init track profile iq ratio: ", iq_ratio if self.track_profile['iq_ratio'] > iq_ratio: self.track_profile['iq_ratio'] = iq_ratio - - # if prev_iq_ratio and iq_ratio < prev_iq_ratio and \ - # iq_ratio < 3 and \ - # len(self.profiles_history) > 0: - - # if prev_iq_ratio and iq_ratio < prev_iq_ratio and \ - # len(self.profiles_history) > 0: - if len(self.profiles_history): prev_iq_ratio = self.profiles_history[-1]['iq_ratio'] else: @@ -496,21 +474,7 @@ def _run_track_profile_selection(self): if prev_iq_ratio and iq_ratio < prev_iq_ratio * 0.5 and \ len(self.profiles_history) > 0: - # if prev_iq_ratio and iq_ratio < prev_iq_ratio and \ - # len(self.profiles_history) > 0: - - # if not self.lock_detect_fast_outp and len(self.profiles_history) > 0: - - print "" - print "#################### Current history status history: " - for pr in self.profiles_history: - print pr - print "#####################################################" - print "" - profile = self.profiles_history.pop() - #print "Low I/Q ratio, Prev: ", prev_iq_ratio, " Now: ", iq_ratio - print "Taking profile from history: ", profile self.fll_bw_index = profile['fll_bw_index'] self.pll_bw_index = profile['pll_bw_index'] self.coherent_ms_index = profile['coherent_ms_index'] @@ -528,7 +492,6 @@ def _run_track_profile_selection(self): self._make_track_candidates() self.track_candidates = self._filter_track_candidates() if len(self.track_candidates) == 0: - print "=================== No candidates" return track_profile = self.track_candidates.pop() @@ -540,9 +503,6 @@ def _run_track_profile_selection(self): self.track_candidates.append(track_profile) return - print "Start using next track profile: ", track_profile - print "Track candidates in queue: ", self.track_candidates - # switch to next track profile history = {'fll_bw_index': self.fll_bw_index, 'pll_bw_index': self.pll_bw_index, @@ -554,7 +514,6 @@ def _run_track_profile_selection(self): self.pll_bw_index = track_profile['pll_bw_index'] self.coherent_ms_index = track_profile['coherent_ms_index'] - print "Switch to the next track profile" self._set_track_profile() else: @@ -567,7 +526,6 @@ def _run_track_profile_selection(self): self.pll_bw_index = 0 self.coherent_ms_index = 0 self.profiles_history = [] - print "Back to init profile" self._set_track_profile() def _run_nav_data_decoding(self): @@ -749,7 +707,6 @@ def run(self, samples): self.track_result.dynamics[self.i] = \ self.loop_filter.to_dict()['phase_acc'] / (2 * np.pi) - #self.dynamics_detector.update(self.loop_filter.to_dict()['phase_acc'] / (2 * np.pi), self.coherent_ms) # run tracking loop self.loop_filter.update(self.E, self.P, self.L) From 8212ce02fc9edb1e0f59a7bcc07bb4fc4e1b8597 Mon Sep 17 00:00:00 2001 From: Adel Mamin Date: Fri, 5 Aug 2016 18:33:11 +0300 Subject: [PATCH 32/61] Lost fast lock causes PLL bw set to index 1 --- peregrine/tracking.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/peregrine/tracking.py b/peregrine/tracking.py index a74ab74..6a63ff9 100644 --- a/peregrine/tracking.py +++ b/peregrine/tracking.py @@ -447,8 +447,13 @@ def _run_track_profile_selection(self): if self.lock_detect_outp: if not self.lock_detect_fast_outp: + if self.fll_bw_index == 1 and \ + self.pll_bw_index == 1 and \ + self.coherent_ms_index == 0: + return + self.fll_bw_index = 1 - self.pll_bw_index = 0 + self.pll_bw_index = 1 self.coherent_ms_index = 0 self.profiles_history = [] self._set_track_profile() From 0712cb1ac1759663456c0de82f87874fd994ce3c Mon Sep 17 00:00:00 2001 From: Adel Mamin Date: Wed, 10 Aug 2016 10:17:47 +0300 Subject: [PATCH 33/61] Fix bit sync processing handling --- peregrine/tracking.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/peregrine/tracking.py b/peregrine/tracking.py index 6a63ff9..474b98e 100644 --- a/peregrine/tracking.py +++ b/peregrine/tracking.py @@ -443,7 +443,10 @@ def _run_track_profile_selection(self): """ - self.bit_sync = self.nav_bit_sync.bit_sync_acquired() + bit_sync = self.nav_bit_sync.bit_sync_acquired() + if bit_sync and not self.bit_sync: + self.track_profile_timer_ms = 0 + self.bit_sync = bit_sync if self.lock_detect_outp: if not self.lock_detect_fast_outp: @@ -463,6 +466,10 @@ def _run_track_profile_selection(self): if not track_settled: return + if int(self.track_profile_timer_ms + 0.5) % 20 != 0: + #print self.track_profile_timer_ms + return + iq_ratio = np.absolute(self.lock_detect_slow_lpfi / self.lock_detect_slow_lpfq) if not self.track_settled: self.track_profile['iq_ratio'] = iq_ratio @@ -1663,6 +1670,7 @@ def __init__(self): self.bit_phase = 0 self.bit_integrate = 0 self.synced = False + self.sync_acquired = False self.bits = [] self.bit_phase_ref = -1 # A new bit begins when bit_phase == bit_phase_ref self.count = 0 @@ -1678,12 +1686,13 @@ def update(self, corr, ms): bit = 1 if self.bit_integrate > 0 else 0 self.bits.append(bit) self.bit_integrate = 0 + self.sync_acquired = True return True, bit else: return False, None def bit_sync_acquired(self): - return self.synced + return self.sync_acquired def update_bit_sync(self, corr, ms): raise NotImplementedError From e25fee633f30c29ebade4ce7fc1de435d1f52a5d Mon Sep 17 00:00:00 2001 From: Adel Mamin Date: Wed, 10 Aug 2016 10:51:19 +0300 Subject: [PATCH 34/61] Fix controlled root 3rd order tracking loop --- peregrine/tracking_loop.py | 135 ++++++------------------------------- 1 file changed, 22 insertions(+), 113 deletions(-) diff --git a/peregrine/tracking_loop.py b/peregrine/tracking_loop.py index d088999..75bcccd 100644 --- a/peregrine/tracking_loop.py +++ b/peregrine/tracking_loop.py @@ -88,13 +88,6 @@ def retune(self, code_params, carr_params, loop_freq, carr_freq_b1, carr_to_code # Common parameters self.T = 1. / loop_freq - # self.code_vel = 0 - # self.phase_vel = 0 - - # if self.fll_bw and not carr_freq_b1: - # # FLL is turned off - # self.phase_acc = 0 - self.fll_bw = carr_freq_b1 self.pll_bw = carr_bw self.dll_bw = code_bw @@ -115,12 +108,6 @@ def retune(self, code_params, carr_params, loop_freq, carr_freq_b1, carr_to_code self.phase_c1 = phase_b3 * phase_omega_0 self.phase_c2 = phase_a3 * phase_omega_0 * phase_omega_0 self.phase_c3 = phase_omega_0 * phase_omega_0 * phase_omega_0 - # self.phase_c1, self.phase_c2, self.phase_c3 = controlled_root(3, 1 / loop_freq, carr_bw) - # print "T = ", 1 / loop_freq, " BW = ", carr_bw - - # self.phase_c1 = 0.00013553072504812747 - # self.phase_c2 = 0.006445479093110773 - # self.phase_c3 = 0.11739536416734386 # DLL constants code_omega_0 = code_bw / 0.53 @@ -200,21 +187,26 @@ class TrackingLoop3b: def __init__(self, **kwargs): # Initial state - self.retune( (kwargs['code_bw'], kwargs['code_zeta'], kwargs['code_k']), - (kwargs['carr_bw'], kwargs['carr_zeta'], kwargs['carr_k']), - kwargs['loop_freq'], - kwargs['carr_freq_b1'], - kwargs['carr_to_code'] ) - self.carr_freq = kwargs['carr_freq'] self.code_freq = kwargs['code_freq'] self.code_vel = kwargs['code_freq'] self.phase_acc = 0 self.phase_vel = kwargs['carr_freq'] + self.phase_err = 0 + self.code_err = 0 + self.fll_bw = kwargs['carr_freq_b1'] + self.pll_bw = kwargs['carr_bw'] + self.dll_bw = kwargs['code_bw'] self.P_prev = 1+0j + self.retune( (kwargs['code_bw'], kwargs['code_zeta'], kwargs['code_k']), + (kwargs['carr_bw'], kwargs['carr_zeta'], kwargs['carr_k']), + kwargs['loop_freq'], + kwargs['carr_freq_b1'], + kwargs['carr_to_code'] ) + def retune(self, code_params, carr_params, loop_freq, carr_freq_b1, carr_to_code): """ @@ -238,7 +230,11 @@ def retune(self, code_params, carr_params, loop_freq, carr_freq_b1, carr_to_code carr_bw, carr_zeta, carr_k = carr_params # Common parameters - self.T = 1 / loop_freq + self.T = 1. / loop_freq + + self.fll_bw = carr_freq_b1 + self.pll_bw = carr_bw + self.dll_bw = code_bw # FLL constants freq_omega_0 = carr_freq_b1 / 0.53 @@ -249,82 +245,7 @@ def retune(self, code_params, carr_params, loop_freq, carr_freq_b1, carr_to_code self.freq_c2 = freq_omega_0 * freq_omega_0 # PLL constants - phase_omega_0 = carr_bw / 0.7845 - phase_a3 = 1.1 - phase_b3 = 2.4 - - # self.phase_c1 = phase_b3 * phase_omega_0 - # self.phase_c2 = phase_a3 * phase_omega_0 * phase_omega_0 - # self.phase_c3 = phase_omega_0 * phase_omega_0 * phase_omega_0 - - # self.phase_c1 = 0.2532 - # self.phase_c2 = 0.03710 - # self.phase_c3 = 0.002344 - - # BL*T = 0.015 no delay - # self.phase_c1 = 0.03742 - # self.phase_c2 = 6.356e-04 - # self.phase_c3 = 4.084e-06 - - # BL*T = 0.015 with delay - # self.phase_c1 = 0.03575 - # self.phase_c2 = 5.859e-04 - # self.phase_c3 = 3.646e-06 - - # BL*T = 0.050 with delay - # self.phase_c1 = 0.09928 - # self.phase_c2 = 0.004802 - # self.phase_c3 = 9.066e-05 - - if carr_bw / loop_freq == 0.1: - # BL*T = 0.100 with delay - self.phase_c1 = 0.1599 - self.phase_c2 = 0.01333 - self.phase_c3 = 4.494e-04 - # BL*T = 0.100 without delay - # self.phase_c1 = 0.1991 - # self.phase_c2 = 0.01995 - # self.phase_c3 = 7.924e-04 - elif carr_bw / loop_freq == 0.050: - self.phase_c1 = 0.09928 - self.phase_c2 = 0.004802 - self.phase_c3 = 9.066e-05 - elif carr_bw / loop_freq == 0.070: - self.phase_c1 = 0.1268 - self.phase_c2 = 0.008066 - self.phase_c3 = 2.032-04 - elif carr_bw / loop_freq == 0.15: - self.phase_c1 = 0.2003 - self.phase_c2 = 0.02203 - self.phase_c3 = 0.001012 - elif carr_bw / loop_freq == 0.2: - # without delay - self.phase_c1 = 0.3183 - self.phase_c2 = 0.05595 - self.phase_c3 = 0.004103 - # with delay - # self.phase_c1 = 0.2290 - # self.phase_c2 = 0.02994 - # self.phase_c3 = 0.001683 - # BL*T = 0.400 without delay - # self.phase_c1 = 0.4499 - # self.phase_c2 = 0.1253 - # self.phase_c3 = 0.01584 - - # BL*T = 0.300 without delay - # self.phase_c1 = 0.3951 - # self.phase_c2 = 0.09238 - # self.phase_c3 = 0.009451 - - # BL*T = 0.250 without delay - # self.phase_c1 = 0.3606 - # self.phase_c2 = 0.07452 - # self.phase_c3 = 0.006583 - - else: - self.phase_c1, self.phase_c2, self.phase_c3 = controlled_root(3, 1 / loop_freq, carr_bw) - print "T = ", 1 / loop_freq, " BW = ", carr_bw, "BL*T = ", carr_bw / loop_freq - print "c1, c2, c3: ", self.phase_c1, self.phase_c2, self.phase_c3 + self.phase_c1, self.phase_c2, self.phase_c3 = controlled_root(3, 1 / loop_freq, carr_bw) # DLL constants code_omega_0 = code_bw / 0.53 @@ -335,10 +256,6 @@ def retune(self, code_params, carr_params, loop_freq, carr_freq_b1, carr_to_code self.carr_to_code = carr_to_code - # self.code_vel = 0 - # self.phase_acc = 0 - # self.phase_vel = 0 - def update(self, E, P, L): """ Tracking loop update @@ -362,17 +279,9 @@ def update(self, E, P, L): # Carrier loop self.phase_err = costas_discriminator(P.real, P.imag) freq_error = 0 - if self.freq_c1 != 0: + if self.freq_c1 != 0 and self.T != 0: freq_error = frequency_discriminator(P.real, P.imag, self.P_prev.real, self.P_prev.imag) / self.T - - self.P_prev = P - - # self.phase_acc += freq_error * self.freq_c2 * 1 / self.T + self.phase_err * self.phase_c3# * 1 / self.T - - # sum = self.phase_acc + freq_error * self.freq_c1 + self.phase_err * self.phase_c2 - # self.phase_vel += sum * 1 / self.T - # sum = self.phase_vel + self.phase_err * self.phase_c1 - # self.carr_freq = sum #* self.T + self.P_prev = P self.phase_acc += self.phase_err * self.phase_c3 / self.T @@ -382,11 +291,11 @@ def update(self, E, P, L): self.carr_freq = sum # Code loop - code_error = -dll_discriminator(E, P, L) + self.code_err = -dll_discriminator(E, P, L) prev = self.code_vel - self.code_vel += self.code_c2 * code_error * self.T - sum = (prev + self.code_vel) * 0.5 + self.code_c1 * code_error + self.code_vel += self.code_c2 * self.code_err * self.T + sum = (prev + self.code_vel) * 0.5 + self.code_c1 * self.code_err self.code_freq = sum if self.carr_to_code > 0: From 8cb4be2301131e7f0e2b5bec9d59f264eeb26b10 Mon Sep 17 00:00:00 2001 From: Adel Mamin Date: Wed, 10 Aug 2016 17:18:43 +0300 Subject: [PATCH 35/61] Add 40 & 80 ms integration --- peregrine/defaults.py | 326 +++++++++++++++++++++++++++++++++++++++++- peregrine/tracking.py | 27 ++++ 2 files changed, 352 insertions(+), 1 deletion(-) diff --git a/peregrine/defaults.py b/peregrine/defaults.py index c218f8a..e0f7062 100644 --- a/peregrine/defaults.py +++ b/peregrine/defaults.py @@ -355,6 +355,9 @@ APPLY_CORR_2 = 6 GET_CORR_1 = 7 GET_CORR_2 = 8 +COMPENSATE_BIT_POLARITY = 9 +USE_COMPENSATED_BIT = 10 +PREPARE_BIT_COMPENSATION = 11 fsm_states = \ { '1ms': @@ -1003,7 +1006,328 @@ 18: (1023, 19, {'pre': (), 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), 19: (1023, 0, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_2ND, GET_CORR_1) }) } + 'post': (RUN_LD, ALIAS_DETECT_2ND, GET_CORR_1) }) }, + } + }, + + '40ms': + { 'bit_sync': + { 'short_n_long': + { 'coherent_ms': 40, + 't_diff_s': 1023 * 1 / gps_constants.l1ca_chip_rate, + 'alias_acc_length_ms': 500, + + 0: (1023, 1, {'pre': (PREPARE_BIT_COMPENSATION,), + 'post': (RUN_LD, ALIAS_DETECT_1ST,) }), + 1: (1023, 2, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 2: (1023, 3, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 3: (1023, 4, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 4: (1023, 5, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 5: (1023, 6, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 6: (1023, 7, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 7: (1023, 8, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 8: (1023, 9, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 9: (1023, 10, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 10: (1023, 11, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 11: (1023, 12, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 12: (1023, 13, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 13: (1023, 14, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 14: (1023, 15, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 15: (1023, 16, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 16: (1023, 17, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 17: (1023, 18, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 18: (1023, 19, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_2ND,) }), + 19: (1023, 20, {'pre': (), + 'post': (RUN_LD, + ALIAS_DETECT_1ST, + COMPENSATE_BIT_POLARITY) }), + 20: (1023, 21, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 21: (1023, 22, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 22: (1023, 23, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 23: (1023, 24, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 24: (1023, 25, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 25: (1023, 26, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 26: (1023, 27, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 27: (1023, 28, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 28: (1023, 29, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 29: (1023, 30, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 30: (1023, 31, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 31: (1023, 32, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 32: (1023, 33, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 33: (1023, 34, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 34: (1023, 35, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 35: (1023, 36, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 36: (1023, 37, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 37: (1023, 38, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 38: (1023, 39, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 39: (1023, 0, {'pre': (), + 'post': (RUN_LD, + ALIAS_DETECT_2ND, + GET_CORR_1, + COMPENSATE_BIT_POLARITY, + USE_COMPENSATED_BIT) }) }, + 'ideal': + { 'coherent_ms': 40, + 't_diff_s': 1023 * 1 / gps_constants.l1ca_chip_rate, + 'alias_acc_length_ms': 500, + + 0: (1023, 1, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_1ST,) }), + 1: (1023, 2, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 2: (1023, 3, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 3: (1023, 4, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 4: (1023, 5, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 5: (1023, 6, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 6: (1023, 7, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 7: (1023, 8, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 8: (1023, 9, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 9: (1023, 10, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 10: (1023, 11, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 11: (1023, 12, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 12: (1023, 13, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 13: (1023, 14, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 14: (1023, 15, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 15: (1023, 16, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 16: (1023, 17, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 17: (1023, 18, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 18: (1023, 19, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 19: (1023, 0, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_2ND, GET_CORR_1) }) }, + } + }, + + '80ms': + { 'bit_sync': + { 'short_n_long': + { 'coherent_ms': 80, + 't_diff_s': 1023 * 1 / gps_constants.l1ca_chip_rate, + 'alias_acc_length_ms': 500, + + 0: (1023, 1, {'pre': (PREPARE_BIT_COMPENSATION,), + 'post': (RUN_LD, ALIAS_DETECT_1ST,) }), + 1: (1023, 2, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 2: (1023, 3, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 3: (1023, 4, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 4: (1023, 5, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 5: (1023, 6, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 6: (1023, 7, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 7: (1023, 8, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 8: (1023, 9, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 9: (1023, 10, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 10: (1023, 11, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 11: (1023, 12, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 12: (1023, 13, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 13: (1023, 14, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 14: (1023, 15, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 15: (1023, 16, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 16: (1023, 17, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 17: (1023, 18, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 18: (1023, 19, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_2ND,) }), + 19: (1023, 20, {'pre': (), + 'post': (RUN_LD, + ALIAS_DETECT_1ST, + COMPENSATE_BIT_POLARITY) }), + 20: (1023, 21, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 21: (1023, 22, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 22: (1023, 23, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 23: (1023, 24, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 24: (1023, 25, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 25: (1023, 26, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 26: (1023, 27, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 27: (1023, 28, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 28: (1023, 29, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 29: (1023, 30, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 30: (1023, 31, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 31: (1023, 32, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 32: (1023, 33, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 33: (1023, 34, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 34: (1023, 35, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 35: (1023, 36, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 36: (1023, 37, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 37: (1023, 38, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 38: (1023, 39, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 39: (1023, 40, {'pre': (), + 'post': (RUN_LD, + ALIAS_DETECT_2ND, + COMPENSATE_BIT_POLARITY,) }), + 40: (1023, 41, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_1ST,) }), + 41: (1023, 42, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 42: (1023, 43, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 43: (1023, 44, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 44: (1023, 45, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 45: (1023, 46, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 46: (1023, 47, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 47: (1023, 48, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 48: (1023, 49, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 49: (1023, 50, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 50: (1023, 51, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 51: (1023, 52, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 52: (1023, 53, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 53: (1023, 54, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 54: (1023, 55, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 55: (1023, 56, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 56: (1023, 57, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 57: (1023, 58, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 58: (1023, 59, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_2ND,) }), + 59: (1023, 60, {'pre': (), + 'post': (RUN_LD, + ALIAS_DETECT_1ST, + COMPENSATE_BIT_POLARITY) }), + 60: (1023, 61, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 61: (1023, 62, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 62: (1023, 63, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 63: (1023, 64, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 64: (1023, 65, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 65: (1023, 66, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 66: (1023, 67, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 67: (1023, 68, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 68: (1023, 69, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 69: (1023, 70, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 70: (1023, 71, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 71: (1023, 72, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 72: (1023, 73, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 73: (1023, 74, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 74: (1023, 75, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 75: (1023, 76, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 76: (1023, 77, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 77: (1023, 78, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 78: (1023, 79, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), + 79: (1023, 0, {'pre': (), + 'post': (RUN_LD, + ALIAS_DETECT_2ND, + GET_CORR_1, + COMPENSATE_BIT_POLARITY, + USE_COMPENSATED_BIT) }) }, } } } diff --git a/peregrine/tracking.py b/peregrine/tracking.py index 474b98e..49f0d65 100644 --- a/peregrine/tracking.py +++ b/peregrine/tracking.py @@ -140,6 +140,10 @@ def get_fsm_states(ms, short_n_long, bit_sync): ms = '10ms' elif ms == 20: ms = '20ms' + elif ms == 40: + ms = '40ms' + elif ms == 80: + ms = '80ms' else: raise ValueError("Not implemented!") @@ -638,6 +642,11 @@ def run(self, samples): self.corr_code_freq = self.code_freq_2 self.corr_carr_freq = self.carr_freq_2 + if defaults.PREPARE_BIT_COMPENSATION in flags_pre: + comp_bit_E = 0 + comp_bit_P = 0 + comp_bit_L = 0 + samples_ = samples[self.signal]['samples'][sample_index:] E_, P_, L_, blksize, self.code_phase, self.carr_phase = self.correlator( @@ -665,6 +674,24 @@ def run(self, samples): flags_post = cur_fsm_state[2]['post'] self.fsm_index = cur_fsm_state[1] + if defaults.COMPENSATE_BIT_POLARITY in flags_post: + if self.P.real < 0: + comp_bit_E += -self.E + comp_bit_P += -self.P + comp_bit_L += -self.L + else: + comp_bit_E += self.E + comp_bit_P += self.P + comp_bit_L += self.L + self.E = 0 + self.P = 0 + self.L = 0 + + if defaults.USE_COMPENSATED_BIT in flags_post: + self.E = comp_bit_E + self.P = comp_bit_P + self.L = comp_bit_L + if defaults.RUN_LD in flags_post: # Update PLL lock detector self.lock_detect_outo, \ From 3cf99a0ab09901474839e596e52532204c45d4a6 Mon Sep 17 00:00:00 2001 From: Adel Mamin Date: Wed, 10 Aug 2016 17:20:58 +0300 Subject: [PATCH 36/61] Fix bugs in controlled root 3rd order loop --- peregrine/tracking_loop.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/peregrine/tracking_loop.py b/peregrine/tracking_loop.py index 75bcccd..49fb74c 100644 --- a/peregrine/tracking_loop.py +++ b/peregrine/tracking_loop.py @@ -245,7 +245,7 @@ def retune(self, code_params, carr_params, loop_freq, carr_freq_b1, carr_to_code self.freq_c2 = freq_omega_0 * freq_omega_0 # PLL constants - self.phase_c1, self.phase_c2, self.phase_c3 = controlled_root(3, 1 / loop_freq, carr_bw) + self.phase_c1, self.phase_c2, self.phase_c3 = controlled_root(3, 1. / loop_freq, carr_bw) # DLL constants code_omega_0 = code_bw / 0.53 @@ -358,7 +358,7 @@ def retune(self, code_params, carr_params, loop_freq, carr_freq_b1, carr_to_code carr_bw, carr_zeta, carr_k = carr_params # Common parameters - self.T = 1 / loop_freq + self.T = 1. / loop_freq # FLL constants freq_omega_0 = carr_freq_b1 / 0.53 From aa9fc2dc1b07e64c458376a23ee6631c2b37cd47 Mon Sep 17 00:00:00 2001 From: Adel Mamin Date: Wed, 10 Aug 2016 17:23:25 +0300 Subject: [PATCH 37/61] Clear track profile switching history if it is too old --- peregrine/tracking.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/peregrine/tracking.py b/peregrine/tracking.py index 49f0d65..294ae78 100644 --- a/peregrine/tracking.py +++ b/peregrine/tracking.py @@ -470,6 +470,10 @@ def _run_track_profile_selection(self): if not track_settled: return + if self.track_profile_timer_ms > 500: + # clear history as it is too old + self.profiles_history = [] + if int(self.track_profile_timer_ms + 0.5) % 20 != 0: #print self.track_profile_timer_ms return From 55b126cde62c97a9bb91946c08285a1f555b1d43 Mon Sep 17 00:00:00 2001 From: Adel Mamin Date: Wed, 10 Aug 2016 17:25:30 +0300 Subject: [PATCH 38/61] Change tracker stabilization time to 50ms --- peregrine/tracking.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/peregrine/tracking.py b/peregrine/tracking.py index 294ae78..60b1f42 100644 --- a/peregrine/tracking.py +++ b/peregrine/tracking.py @@ -222,7 +222,7 @@ def __init__(self, params): self.profiles_history = [] self.track_candidates = [] - self.stabilization_time = 100 + self.stabilization_time = 50 self.coherent_ms = coherent_ms self.alias_detector = alias_detector.AliasDetector(self.coherent_ms) From 7563695b997560c143a461540c7d441e2ffd3d4a Mon Sep 17 00:00:00 2001 From: Adel Mamin Date: Wed, 10 Aug 2016 17:26:22 +0300 Subject: [PATCH 39/61] Change PLL BW values order --- peregrine/defaults.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/peregrine/defaults.py b/peregrine/defaults.py index e0f7062..b5af78e 100644 --- a/peregrine/defaults.py +++ b/peregrine/defaults.py @@ -207,7 +207,7 @@ l1ca_track_params = { 'fll_bw': (1, 0), - 'pll_bw': (40, 35, 30, 25, 20, 18, 16, 14, 10, 8, 6, 4, 2), + 'pll_bw': (40, 35, 30, 25, 20, 18, 16, 14, 12, 10, 8, 7, 6.5, 6, 5.5, 5), 'coherent_ms': (1, 2, 4, 5, 10, 20) } l1ca_loop_filter_params_template = { From 588895e0a97021d49f5f9254214ab232559302dd Mon Sep 17 00:00:00 2001 From: Adel Mamin Date: Wed, 10 Aug 2016 17:28:02 +0300 Subject: [PATCH 40/61] Add dynamics detector to tracking profile switching logic --- peregrine/tracking.py | 62 ++++++++++++++++++++++++++++++++----------- 1 file changed, 46 insertions(+), 16 deletions(-) diff --git a/peregrine/tracking.py b/peregrine/tracking.py index 60b1f42..91e920a 100644 --- a/peregrine/tracking.py +++ b/peregrine/tracking.py @@ -290,8 +290,11 @@ def __init__(self, params): self.acq.prn, self.acq.signal) self.track_profile_timer_ms = 0 + self.dynamics_timer_ms = 0 + self.dynamics_detected = False self.code_phase = 0.0 self.carr_phase = 0.0 + self.lock_detect_outp_prev = False self.samples_per_chip = int(round(self.sampling_freq / self.chipping_rate)) self.sample_index = params['sample_index'] self.sample_index += self.acq.sample_index @@ -432,7 +435,8 @@ def _filter_track_candidates(self): coherent_ms = self.track_params['coherent_ms'][coherent_ms_index] if pll_bw * coherent_ms * 1e-3 > 0.04: - continue + if (coherent_ms != 20 and pll_bw != 5): + continue res.append(candidate) @@ -453,15 +457,22 @@ def _run_track_profile_selection(self): self.bit_sync = bit_sync if self.lock_detect_outp: + + # dynamics in [Hz/s] + dynamics = self.loop_filter.to_dict()['phase_acc'] / (2 * np.pi) + if dynamics > 20: + self.dynamics_timer_ms = 0 + self.dynamics_detected = True + elif self.dynamics_timer_ms > 10000: + self.dynamics_detected = False + + self.lock_detect_outp_prev = True + if not self.lock_detect_fast_outp: - if self.fll_bw_index == 1 and \ - self.pll_bw_index == 1 and \ - self.coherent_ms_index == 0: + if self.fll_bw_index == 0: return - self.fll_bw_index = 1 - self.pll_bw_index = 1 - self.coherent_ms_index = 0 + self.fll_bw_index = 0 self.profiles_history = [] self._set_track_profile() return @@ -475,7 +486,7 @@ def _run_track_profile_selection(self): self.profiles_history = [] if int(self.track_profile_timer_ms + 0.5) % 20 != 0: - #print self.track_profile_timer_ms + # wait for bit edge return iq_ratio = np.absolute(self.lock_detect_slow_lpfi / self.lock_detect_slow_lpfq) @@ -537,14 +548,29 @@ def _run_track_profile_selection(self): self._set_track_profile() else: - if self.fll_bw_index == 0 and \ - self.pll_bw_index == 0 and \ - self.coherent_ms_index == 0: - return + if self.lock_detect_outp_prev: + self.track_profile_timer_ms = 0 + + self.lock_detect_outp_prev = False + + if self.dynamics_detected: + threshold = 50 + else: + threshold = 10000 + + if self.track_profile_timer_ms > threshold: + if self.fll_bw_index == 0 and \ + self.pll_bw_index == 0 and \ + self.coherent_ms_index == 0: + return + self.fll_bw_index = 0 + self.pll_bw_index = 0 + self.coherent_ms_index = 0 + else: + if self.fll_bw_index == 0: + return + self.fll_bw_index = 0 - self.fll_bw_index = 0 - self.pll_bw_index = 0 - self.coherent_ms_index = 0 self.profiles_history = [] self._set_track_profile() @@ -664,6 +690,7 @@ def run(self, samples): ) self.track_profile_timer_ms += 1e3 * blksize / self.sampling_freq + self.dynamics_timer_ms += 1e3 * blksize / self.sampling_freq sample_index += blksize samples_processed += blksize @@ -789,6 +816,7 @@ def run(self, samples): self.track_result.dll_bw[self.i] = self.loop_filter.to_dict()['dll_bw'] self.track_result.track_timer_ms[self.i] = self.track_profile_timer_ms + self.track_result.dynamics_timer_ms[self.i] = self.dynamics_timer_ms # Record stuff for postprocessing self.track_result.absolute_sample[self.i] = self.sample_index + \ @@ -1540,6 +1568,7 @@ def __init__(self, n_points, prn, signal): self.dll_bw = np.zeros(n_points) self.track_timer_ms = np.zeros(n_points) + self.dynamics_timer_ms = np.zeros(n_points) self.signal = signal self.ms_tracked = np.zeros(n_points) @@ -1579,7 +1608,7 @@ def dump(self, output_file, size): if self.print_start: f1.write( "sample_index,ms_tracked,coherent_ms,bit_sync,fll_bw,pll_bw,dll_bw," - "track_timer_ms," + "track_timer_ms,dynamics_timer_ms," "lock_detect_outp,lock_detect_outo," "lock_detect_fast_outp,lock_detect_fast_outo," "iq_ratio,iq_ratio_fast,iq_ration_slow,iq_ratio_raw,iq_ratio_min,dynamics," @@ -1602,6 +1631,7 @@ def dump(self, output_file, size): f1.write("%s," % self.dll_bw[i]) f1.write("%s," % self.track_timer_ms[i]) + f1.write("%s," % self.dynamics_timer_ms[i]) f1.write("%s," % int(self.lock_detect_outp[i])) f1.write("%s," % int(self.lock_detect_outo[i])) From 21ec892210f54aa9878b47569416226e65a56d31 Mon Sep 17 00:00:00 2001 From: Adel Mamin Date: Thu, 11 Aug 2016 11:30:38 +0300 Subject: [PATCH 41/61] Add subplots support to print_track_res script --- libswiftnav | 2 +- peregrine/analysis/print_track_res.py | 37 ++++++++++++++++++++------- 2 files changed, 29 insertions(+), 10 deletions(-) diff --git a/libswiftnav b/libswiftnav index 8bbc35e..18c8d96 160000 --- a/libswiftnav +++ b/libswiftnav @@ -1 +1 @@ -Subproject commit 8bbc35e7292b639c7f4be636ef3ccb1227312c8b +Subproject commit 18c8d96249d44a2330d35983bc1ed51ec7ed0c35 diff --git a/peregrine/analysis/print_track_res.py b/peregrine/analysis/print_track_res.py index f97b86b..a6b99ca 100755 --- a/peregrine/analysis/print_track_res.py +++ b/peregrine/analysis/print_track_res.py @@ -24,6 +24,10 @@ def main(): parser.add_argument("-p", "--par-to-print", default="CN0", help="parameter to print") + parser.add_argument("--no-toolbar", + action='store_true', + help="Disable toolbar") + parser.add_argument("--profile", choices=['peregrine', 'custom_rate', 'low_rate', 'normal_rate', 'piksi_v3', 'high_rate'], @@ -46,24 +50,39 @@ def main(): else: raise NotImplementedError() - fig = plt.figure() - plt.title(args.par_to_print.replace('_', ' ').title() + ' vs Time') - ax1 = fig.add_subplot(111) + if args.no_toolbar: + plt.rcParams['toolbar'] = 'None' + + params = [x.strip() for x in args.par_to_print.split(',')] + params_num = len(params) + if params_num == 1: + params.append('111') - plt.ylabel(args.par_to_print.replace('_', ' ').title(), color='b') - plt.xlabel('Time [s]') + params = [tuple(params[i:i+2]) for i in range(0, params_num, 2)] data = np.genfromtxt(args.file, dtype=float, delimiter=',', names=True) time_stamps = np.array(data['sample_index']) time_stamps = time_stamps - data['sample_index'][0] time_stamps = time_stamps / freq_profile['sampling_freq'] - - plt.plot(time_stamps, np.array(data[args.par_to_print]), 'r.') + time_stamp_min = min(time_stamps) + time_stamp_max = max(time_stamps) + + fig = plt.figure(figsize=(11, 15)) + plt.subplots_adjust(wspace=0.25, hspace=0.75) + + for (par_to_print,layout) in params: + sub = fig.add_subplot(layout) + sub.set_title(par_to_print.replace('_', ' ').title() + ' vs Time') + sub.grid() + sub.set_xlim([time_stamp_min, time_stamp_max]) + + sub.set_ylabel(par_to_print.replace('_', ' ').title(), color='b') + sub.set_xlabel('Time [s]') + sub.legend(loc='upper right') - plt.legend(loc='upper right') + sub.plot(time_stamps, np.array(data[par_to_print]), 'r.') - plt.grid() plt.axis('tight') plt.show() From 3ecf81e3134670f507c9dc7e844ca4459d612915 Mon Sep 17 00:00:00 2001 From: Adel Mamin Date: Fri, 12 Aug 2016 09:19:03 +0300 Subject: [PATCH 42/61] Use different fast lock detector params for different PLL BW --- peregrine/defaults.py | 12 +++++++++++- peregrine/tracking.py | 34 +++++++++++++++++++++++++++------- 2 files changed, 38 insertions(+), 8 deletions(-) diff --git a/peregrine/defaults.py b/peregrine/defaults.py index b5af78e..4516b7a 100644 --- a/peregrine/defaults.py +++ b/peregrine/defaults.py @@ -1348,7 +1348,17 @@ l1ca_lock_detect_params_disable = {"k1": 0.02, "k2": 1e-6, "lp": 1, "lo": 1} lock_detect_params_slow = {"k1": 0.005, "k2": 1.4, "lp": 200, "lo": 50} -lock_detect_params_fast = {"k1": 0.2, "k2": .8, "lp": 50, "lo": 50} +lock_detect_params_fast = ( + (40, {"k1": 0.2, "k2": .80, "lp": 50, "lo": 50}), + (35, {"k1": 0.2, "k2": .83, "lp": 50, "lo": 50}), + (30, {"k1": 0.2, "k2": .86, "lp": 50, "lo": 50}), + (25, {"k1": 0.2, "k2": .89, "lp": 50, "lo": 50}), + (20, {"k1": 0.2, "k2": .92, "lp": 50, "lo": 50}), + (15, {"k1": 0.2, "k2": .95, "lp": 50, "lo": 50}), + (10, {"k1": 0.2, "k2": .98, "lp": 50, "lo": 50}), + ( 5, {"k1": 0.2, "k2": 1.0, "lp": 50, "lo": 50}) ) + +tracking_loop_stabilization_time_ms = 50 # L2C 20ms lock detect profile # References: diff --git a/peregrine/tracking.py b/peregrine/tracking.py index 91e920a..4a9d130 100644 --- a/peregrine/tracking.py +++ b/peregrine/tracking.py @@ -9,6 +9,7 @@ # WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. import numpy as np +import scipy.constants as constants import math import parallel_processing as pp import multiprocessing as mp @@ -160,6 +161,13 @@ def get_fsm_states(ms, short_n_long, bit_sync): return defaults.fsm_states[ms][bit_sync_status][mode] +def get_lock_detector(cur_bw, lock_detect_set): + for bw, params in lock_detect_set: + if cur_bw < bw: + continue + return params + + class TrackingChannel(object): """ Tracking channel base class. @@ -244,11 +252,18 @@ def __init__(self, params): lp=self.lock_detect_params["lp"], lo=self.lock_detect_params["lo"]) + code_params = loop_filter_params['code_params'] + carr_params = loop_filter_params['carr_params'] + pll_bw = carr_params[0] + + lock_detect_params_fast = get_lock_detector(pll_bw, + defaults.lock_detect_params_fast) + self.lock_detect_fast = lock_detect.LockDetector( - k1=defaults.lock_detect_params_fast["k1"], - k2=defaults.lock_detect_params_fast["k2"], - lp=defaults.lock_detect_params_fast["lp"], - lo=defaults.lock_detect_params_fast["lo"]) + k1=lock_detect_params_fast["k1"], + k2=lock_detect_params_fast["k2"], + lp=lock_detect_params_fast["lp"], + lo=lock_detect_params_fast["lo"]) self.lock_detect_slow = lock_detect.LockDetector( k1=defaults.lock_detect_params_slow["k1"], @@ -263,9 +278,6 @@ def __init__(self, params): loop_freq=loop_filter_params["loop_freq"] ) - code_params = loop_filter_params['code_params'] - carr_params = loop_filter_params['carr_params'] - self.loop_filter = self.loop_filter_class( loop_freq=loop_filter_params['loop_freq'], code_freq=0, @@ -381,6 +393,14 @@ def _set_track_profile(self): self.alias_detector.reinit(self.coherent_ms) + lock_detect_params_fast = get_lock_detector(pll_bw, + defaults.lock_detect_params_fast) + + self.lock_detect_fast.reinit(k1=lock_detect_params_fast["k1"], + k2=lock_detect_params_fast["k2"], + lp=lock_detect_params_fast["lp"], + lo=lock_detect_params_fast["lo"]) + self.loop_filter.retune(**loop_filter_params) self.cn0_est = CN0_Est_MM(bw=1e3 / self.coherent_ms, From b45910b1e442c42884ceefb291f1bd6b2f265fa7 Mon Sep 17 00:00:00 2001 From: Adel Mamin Date: Fri, 12 Aug 2016 09:22:12 +0300 Subject: [PATCH 43/61] Fix code formatting --- peregrine/tracking.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/peregrine/tracking.py b/peregrine/tracking.py index 4a9d130..bec56bd 100644 --- a/peregrine/tracking.py +++ b/peregrine/tracking.py @@ -473,6 +473,7 @@ def _run_track_profile_selection(self): bit_sync = self.nav_bit_sync.bit_sync_acquired() if bit_sync and not self.bit_sync: + # we just got bit sync self.track_profile_timer_ms = 0 self.bit_sync = bit_sync @@ -509,7 +510,8 @@ def _run_track_profile_selection(self): # wait for bit edge return - iq_ratio = np.absolute(self.lock_detect_slow_lpfi / self.lock_detect_slow_lpfq) + iq_ratio = np.absolute(self.lock_detect_slow_lpfi / \ + self.lock_detect_slow_lpfq) if not self.track_settled: self.track_profile['iq_ratio'] = iq_ratio self.track_settled = True @@ -569,9 +571,9 @@ def _run_track_profile_selection(self): else: if self.lock_detect_outp_prev: + # we just lost the lock self.track_profile_timer_ms = 0 - - self.lock_detect_outp_prev = False + self.lock_detect_outp_prev = False if self.dynamics_detected: threshold = 50 From 243e55b7b6d4b6af307eb7e2c4db40e9140178cc Mon Sep 17 00:00:00 2001 From: Adel Mamin Date: Fri, 12 Aug 2016 09:24:58 +0300 Subject: [PATCH 44/61] Do not wait for bit sync if candidates profile list has 1ms options --- peregrine/tracking.py | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/peregrine/tracking.py b/peregrine/tracking.py index bec56bd..d477e52 100644 --- a/peregrine/tracking.py +++ b/peregrine/tracking.py @@ -547,27 +547,29 @@ def _run_track_profile_selection(self): if len(self.track_candidates) == 0: return - track_profile = self.track_candidates.pop() - coherent_ms_index = track_profile['coherent_ms_index'] - coherent_ms = self.track_params['coherent_ms'][coherent_ms_index] - bit_sync_required = (coherent_ms != 1) + for i, track_profile in reversed(list(enumerate(self.track_candidates))): + coherent_ms_index = track_profile['coherent_ms_index'] + coherent_ms = self.track_params['coherent_ms'][coherent_ms_index] + bit_sync_required = (coherent_ms != 1) - if bit_sync_required and not self.bit_sync: - self.track_candidates.append(track_profile) - return + if bit_sync_required and not self.bit_sync: + continue - # switch to next track profile - history = {'fll_bw_index': self.fll_bw_index, - 'pll_bw_index': self.pll_bw_index, - 'coherent_ms_index': self.coherent_ms_index, - 'iq_ratio': self.track_profile['iq_ratio'] } - self.profiles_history.append(history) + track_profile = self.track_candidates.pop(i) - self.fll_bw_index = track_profile['fll_bw_index'] - self.pll_bw_index = track_profile['pll_bw_index'] - self.coherent_ms_index = track_profile['coherent_ms_index'] + # switch to next track profile + history = {'fll_bw_index': self.fll_bw_index, + 'pll_bw_index': self.pll_bw_index, + 'coherent_ms_index': self.coherent_ms_index, + 'iq_ratio': self.track_profile['iq_ratio'] } + self.profiles_history.append(history) - self._set_track_profile() + self.fll_bw_index = track_profile['fll_bw_index'] + self.pll_bw_index = track_profile['pll_bw_index'] + self.coherent_ms_index = track_profile['coherent_ms_index'] + + self._set_track_profile() + break else: if self.lock_detect_outp_prev: From f55936b68a867a113ec9c2fbaeaca6b9c067faab Mon Sep 17 00:00:00 2001 From: Adel Mamin Date: Fri, 12 Aug 2016 09:26:58 +0300 Subject: [PATCH 45/61] Refactor profile history handling --- peregrine/tracking.py | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/peregrine/tracking.py b/peregrine/tracking.py index d477e52..81b1db1 100644 --- a/peregrine/tracking.py +++ b/peregrine/tracking.py @@ -521,18 +521,14 @@ def _run_track_profile_selection(self): if len(self.profiles_history): prev_iq_ratio = self.profiles_history[-1]['iq_ratio'] - else: - prev_iq_ratio = 0 - - if prev_iq_ratio and iq_ratio < prev_iq_ratio * 0.5 and \ - len(self.profiles_history) > 0: - - profile = self.profiles_history.pop() - self.fll_bw_index = profile['fll_bw_index'] - self.pll_bw_index = profile['pll_bw_index'] - self.coherent_ms_index = profile['coherent_ms_index'] - self._set_track_profile() - return + if prev_iq_ratio and iq_ratio < prev_iq_ratio * 0.5: + # revert to previous profile + profile = self.profiles_history.pop() + self.fll_bw_index = profile['fll_bw_index'] + self.pll_bw_index = profile['pll_bw_index'] + self.coherent_ms_index = profile['coherent_ms_index'] + self._set_track_profile() + return final_profile = \ self.fll_bw_index == len(self.track_params['fll_bw']) - 1 and \ From 945c5fde8ccf3a903507fe463fbd527573aecea9 Mon Sep 17 00:00:00 2001 From: Adel Mamin Date: Fri, 12 Aug 2016 09:27:53 +0300 Subject: [PATCH 46/61] Fefactor dynamics handling --- peregrine/tracking.py | 67 ++++++++++++++++++++++++++++++++----------- 1 file changed, 51 insertions(+), 16 deletions(-) diff --git a/peregrine/tracking.py b/peregrine/tracking.py index 81b1db1..497f900 100644 --- a/peregrine/tracking.py +++ b/peregrine/tracking.py @@ -455,8 +455,16 @@ def _filter_track_candidates(self): coherent_ms = self.track_params['coherent_ms'][coherent_ms_index] if pll_bw * coherent_ms * 1e-3 > 0.04: - if (coherent_ms != 20 and pll_bw != 5): - continue + if self.dynamics_detected: + if coherent_ms <= 5 and pll_bw <= 10: + pass + else: + continue + else: + if pll_bw <= 5: + pass + else: + continue res.append(candidate) @@ -479,21 +487,25 @@ def _run_track_profile_selection(self): if self.lock_detect_outp: - # dynamics in [Hz/s] - dynamics = self.loop_filter.to_dict()['phase_acc'] / (2 * np.pi) - if dynamics > 20: - self.dynamics_timer_ms = 0 - self.dynamics_detected = True - elif self.dynamics_timer_ms > 10000: - self.dynamics_detected = False - self.lock_detect_outp_prev = True if not self.lock_detect_fast_outp: - if self.fll_bw_index == 0: - return + # we lost fast lock detector + if self.dynamics_detected: + # and we are facing dynamics + if self.fll_bw_index == 0 and \ + self.pll_bw_index == 0 and \ + self.coherent_ms_index == 0: + return + self.fll_bw_index = 0 + self.pll_bw_index = 0 + self.coherent_ms_index = 0 + else: + # we are in static scenario - just add FLL + if self.fll_bw_index == 0: + return + self.fll_bw_index = 0 - self.fll_bw_index = 0 self.profiles_history = [] self._set_track_profile() return @@ -502,6 +514,18 @@ def _run_track_profile_selection(self): if not track_settled: return + # dynamics in [Hz/s] + # do no assess dynamics in FLL mode as + # the PLL phase acceleration indicator looks to be scrued + if self.fll_bw_index != 0: + dynamics = self.loop_filter.to_dict()['phase_acc'] / (2 * np.pi) + if dynamics > 30: # [hz/sec] + self.dynamics_timer_ms = 0 + self.dynamics_detected = True + + if self.dynamics_timer_ms > 2000: + self.dynamics_detected = False + if self.track_profile_timer_ms > 500: # clear history as it is too old self.profiles_history = [] @@ -795,8 +819,10 @@ def run(self, samples): not (defaults.GET_CORR_2 in flags_post): continue - self.track_result.dynamics[self.i] = \ - self.loop_filter.to_dict()['phase_acc'] / (2 * np.pi) + phase_acc_hz_per_s = self.loop_filter.to_dict()['phase_acc'] / (2 * np.pi) + self.track_result.dynamics[self.i] = phase_acc_hz_per_s + self.track_result.dynamics_g[self.i] = \ + phase_acc_hz_per_s * constants.c / (self.carrier_freq * constants.g) # run tracking loop self.loop_filter.update(self.E, self.P, self.L) @@ -837,6 +863,7 @@ def run(self, samples): self.track_result.track_timer_ms[self.i] = self.track_profile_timer_ms self.track_result.dynamics_timer_ms[self.i] = self.dynamics_timer_ms + self.track_result.dynamics_detected[self.i] = self.dynamics_detected # Record stuff for postprocessing self.track_result.absolute_sample[self.i] = self.sample_index + \ @@ -936,6 +963,7 @@ def __init__(self, params): params['lock_detect_params'] = defaults.l1ca_lock_detect_params_opt params['chipping_rate'] = gps_constants.l1ca_chip_rate params['sample_index'] = params['samples']['sample_index'] + params['carrier_freq'] = gps_constants.l1 TrackingChannel.__init__(self, params) @@ -1041,6 +1069,7 @@ def __init__(self, params): gps_constants.l2c_chip_rate / gps_constants.l2 params['chipping_rate'] = gps_constants.l2c_chip_rate params['sample_index'] = 0 + params['carrier_freq'] = gps_constants.l2 TrackingChannel.__init__(self, params) @@ -1573,6 +1602,8 @@ def __init__(self, n_points, prn, signal): self.code_err = np.zeros(n_points) self.acceleration = np.zeros(n_points) self.dynamics = np.zeros(n_points) + self.dynamics_g = np.zeros(n_points) + self.dynamics_detected = np.zeros(n_points) self.nav_msg = NavMsg() self.nav_msg_bit_phase_ref = np.zeros(n_points) self.nav_bit_sync = NBSMatchBit() if prn < 32 else NBSSBAS() @@ -1631,7 +1662,8 @@ def dump(self, output_file, size): "track_timer_ms,dynamics_timer_ms," "lock_detect_outp,lock_detect_outo," "lock_detect_fast_outp,lock_detect_fast_outo," - "iq_ratio,iq_ratio_fast,iq_ration_slow,iq_ratio_raw,iq_ratio_min,dynamics," + "iq_ratio,iq_ratio_fast,iq_ration_slow,iq_ratio_raw,iq_ratio_min," + "dynamics,dynamics_g,dynamics_detected," "phase_err,code_err,CN0,IF,doppler_phase," "carr_doppler,code_phase,code_freq," "SNR,SNR_DB,P_Mag,E_I,E_Q,P_I,P_Q,L_I,L_Q," @@ -1666,6 +1698,9 @@ def dump(self, output_file, size): f1.write("%s," % self.iq_ratio_min[i]) f1.write("%s," % self.dynamics[i]) + f1.write("%s," % self.dynamics_g[i]) + f1.write("%s," % self.dynamics_detected[i]) + f1.write("%s," % self.phase_err[i]) f1.write("%s," % self.code_err[i]) f1.write("%s," % self.cn0[i]) From 17698e2c644693381e68d511bc2b0d7e7ca07c80 Mon Sep 17 00:00:00 2001 From: Adel Mamin Date: Fri, 12 Aug 2016 09:39:19 +0300 Subject: [PATCH 47/61] Remove no_bit_sync options from >1ms integration time FSM tables --- peregrine/defaults.py | 86 ++----------------------------------------- 1 file changed, 4 insertions(+), 82 deletions(-) diff --git a/peregrine/defaults.py b/peregrine/defaults.py index 4516b7a..e3e019b 100644 --- a/peregrine/defaults.py +++ b/peregrine/defaults.py @@ -466,20 +466,7 @@ }, '2ms': - { 'no_bit_sync': - { 'short_n_long': - { 'coherent_ms': 2, - 'alias_acc_length_ms': 500, - 0: (1023, 1, {'pre': (APPLY_CORR_1,), 'post': (RUN_LD, GET_CORR_1)}), - 1: (1023, 0, {'pre': (APPLY_CORR_2,), 'post': (RUN_LD, GET_CORR_2)}) }, - - 'ideal': - { 'coherent_ms': 2, - 'alias_acc_length_ms': 500, - 0: (1023, 1, {'pre': (APPLY_CORR_1,), 'post': (RUN_LD,)}), - 1: (1023, 0, {'pre': (), 'post': (RUN_LD, GET_CORR_1)}) } - }, - 'bit_sync': + { 'bit_sync': { 'short_n_long': { 'coherent_ms': 2, 'alias_acc_length_ms': 500, @@ -572,24 +559,7 @@ }, '4ms': - { 'no_bit_sync': - { 'short_n_long': - { 'coherent_ms': 4, - 'alias_acc_length_ms': 500, - 0: (1023, 1, {'pre': (), 'post': (RUN_LD,)}), - 1: (1023, 2, {'pre': (APPLY_CORR_1,), 'post': (RUN_LD,)}), - 2: (1023, 3, {'pre': (), 'post': (RUN_LD,)}), - 3: (1023, 0, {'pre': (), 'post': (RUN_LD, GET_CORR_1)}) }, - - 'ideal': - { 'coherent_ms': 4, - 'alias_acc_length_ms': 500, - 0: (1023, 1, {'pre': (APPLY_CORR_1,), 'post': (RUN_LD,)}), - 1: (1023, 2, {'pre': (), 'post': (RUN_LD,)}), - 2: (1023, 3, {'pre': (), 'post': (RUN_LD,)}), - 3: (1023, 0, {'pre': (), 'post': (RUN_LD, GET_CORR_1)}) } - }, - 'bit_sync': + { 'bit_sync': { 'short_n_long': { 'coherent_ms': 4, 'alias_acc_length_ms': 500, @@ -682,26 +652,7 @@ }, '5ms': - { 'no_bit_sync': - { 'short_n_long': - { 'coherent_ms': 5, - 'alias_acc_length_ms': 500, - 0: (1023, 1, {'pre': (), 'post': (RUN_LD,)}), - 1: (1023, 2, {'pre': (APPLY_CORR_1,), 'post': (RUN_LD,)}), - 2: (1023, 3, {'pre': (), 'post': (RUN_LD,)}), - 3: (1023, 4, {'pre': (), 'post': (RUN_LD,)}), - 4: (1023, 0, {'pre': (), 'post': (RUN_LD, GET_CORR_1)}) }, - - 'ideal': - { 'coherent_ms': 5, - 'alias_acc_length_ms': 500, - 0: (1023, 1, {'pre': (APPLY_CORR_1,), 'post': (RUN_LD,)}), - 1: (1023, 2, {'pre': (), 'post': (RUN_LD,)}), - 2: (1023, 3, {'pre': (), 'post': (RUN_LD,)}), - 3: (1023, 4, {'pre': (), 'post': (RUN_LD,)}), - 4: (1023, 0, {'pre': (), 'post': (RUN_LD, GET_CORR_1)}) } - }, - 'bit_sync': + { 'bit_sync': { 'short_n_long': { 'coherent_ms': 5, 'alias_acc_length_ms': 500, @@ -794,36 +745,7 @@ }, '10ms': - { 'no_bit_sync': - { 'short_n_long': - { 'coherent_ms': 10, - 'alias_acc_length_ms': 500, - 0: (1023, 1, {'pre': (), 'post': (RUN_LD,)}), - 1: (1023, 2, {'pre': (APPLY_CORR_1,), 'post': (RUN_LD,)}), - 2: (1023, 3, {'pre': (), 'post': (RUN_LD,)}), - 3: (1023, 4, {'pre': (), 'post': (RUN_LD,)}), - 4: (1023, 5, {'pre': (), 'post': (RUN_LD,)}), - 5: (1023, 6, {'pre': (), 'post': (RUN_LD,)}), - 6: (1023, 7, {'pre': (), 'post': (RUN_LD,)}), - 7: (1023, 8, {'pre': (), 'post': (RUN_LD,)}), - 8: (1023, 9, {'pre': (), 'post': (RUN_LD,)}), - 9: (1023, 0, {'pre': (), 'post': (RUN_LD, GET_CORR_1)}) }, - - 'ideal': - { 'coherent_ms': 10, - 'alias_acc_length_ms': 500, - 0: (1023, 1, {'pre': (APPLY_CORR_1,), 'post': (RUN_LD,)}), - 1: (1023, 2, {'pre': (), 'post': (RUN_LD,)}), - 2: (1023, 3, {'pre': (), 'post': (RUN_LD,)}), - 3: (1023, 4, {'pre': (), 'post': (RUN_LD,)}), - 4: (1023, 5, {'pre': (), 'post': (RUN_LD,)}), - 5: (1023, 6, {'pre': (), 'post': (RUN_LD,)}), - 6: (1023, 7, {'pre': (), 'post': (RUN_LD,)}), - 7: (1023, 8, {'pre': (), 'post': (RUN_LD,)}), - 8: (1023, 9, {'pre': (), 'post': (RUN_LD,)}), - 9: (1023, 0, {'pre': (), 'post': (RUN_LD, GET_CORR_1)}) } - }, - 'bit_sync': + { 'bit_sync': { 'short_n_long': { 'coherent_ms': 10, 'alias_acc_length_ms': 500, From 3ab088171dd6a59fcd1468afe319646d3ba474a8 Mon Sep 17 00:00:00 2001 From: Adel Mamin Date: Fri, 12 Aug 2016 09:45:47 +0300 Subject: [PATCH 48/61] Remove alias_acc_length_ms and t_diff_s from FSM tables --- peregrine/defaults.py | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/peregrine/defaults.py b/peregrine/defaults.py index e3e019b..412298b 100644 --- a/peregrine/defaults.py +++ b/peregrine/defaults.py @@ -364,19 +364,16 @@ { 'no_bit_sync': { 'short_n_long': { 'coherent_ms': 1, - 'alias_acc_length_ms': 500, 0: (1023, 1, {'pre': (APPLY_CORR_1,), 'post': (RUN_LD, GET_CORR_1)}), 1: (1023, 0, {'pre': (APPLY_CORR_2,), 'post': (RUN_LD, GET_CORR_2)}) }, 'ideal': { 'coherent_ms': 1, - 'alias_acc_length_ms': 500, 0: (1023, 0, {'pre': (APPLY_CORR_1,), 'post': (RUN_LD, GET_CORR_1)}) } }, 'bit_sync': { 'short_n_long': { 'coherent_ms': 1, - 'alias_acc_length_ms': 500, 0: (1023, 1, {'pre': (APPLY_CORR_1,), 'post': (RUN_LD, ALIAS_DETECT_1ST, GET_CORR_1) }), @@ -420,7 +417,6 @@ 'post': (RUN_LD, ALIAS_DETECT_2ND, GET_CORR_2) }) }, 'ideal': { 'coherent_ms': 1, - 'alias_acc_length_ms': 500, 0: (1023, 1, {'pre': (APPLY_CORR_1,), 'post': (RUN_LD, ALIAS_DETECT_1ST, GET_CORR_1) }), @@ -469,7 +465,6 @@ { 'bit_sync': { 'short_n_long': { 'coherent_ms': 2, - 'alias_acc_length_ms': 500, 0: (1023, 1, {'pre': (), 'post': (RUN_LD, ALIAS_DETECT_1ST) }), @@ -513,7 +508,6 @@ 'post': (RUN_LD, ALIAS_DETECT_2ND, GET_CORR_1) }) }, 'ideal': { 'coherent_ms': 2, - 'alias_acc_length_ms': 500, 0: (1023, 1, {'pre': (APPLY_CORR_1,), 'post': (RUN_LD, ALIAS_DETECT_1ST) }), @@ -562,7 +556,6 @@ { 'bit_sync': { 'short_n_long': { 'coherent_ms': 4, - 'alias_acc_length_ms': 500, 0: (1023, 1, {'pre': (), 'post': (RUN_LD, ALIAS_DETECT_1ST) }), @@ -606,7 +599,6 @@ 'post': (RUN_LD, ALIAS_DETECT_2ND, GET_CORR_1) }) }, 'ideal': { 'coherent_ms': 4, - 'alias_acc_length_ms': 500, 0: (1023, 1, {'pre': (APPLY_CORR_1,), 'post': (RUN_LD, ALIAS_DETECT_1ST) }), @@ -655,7 +647,6 @@ { 'bit_sync': { 'short_n_long': { 'coherent_ms': 5, - 'alias_acc_length_ms': 500, 0: (1023, 1, {'pre': (), 'post': (RUN_LD, ALIAS_DETECT_1ST) }), @@ -699,7 +690,6 @@ 'post': (RUN_LD, ALIAS_DETECT_2ND, GET_CORR_1) }) }, 'ideal': { 'coherent_ms': 5, - 'alias_acc_length_ms': 500, 0: (1023, 1, {'pre': (APPLY_CORR_1,), 'post': (RUN_LD, ALIAS_DETECT_1ST) }), @@ -748,7 +738,6 @@ { 'bit_sync': { 'short_n_long': { 'coherent_ms': 10, - 'alias_acc_length_ms': 500, 0: (1023, 1, {'pre': (), 'post': (RUN_LD, ALIAS_DETECT_1ST) }), @@ -792,7 +781,6 @@ 'post': (RUN_LD, ALIAS_DETECT_2ND, GET_CORR_1) }) }, 'ideal': { 'coherent_ms': 10, - 'alias_acc_length_ms': 500, 0: (1023, 1, {'pre': (APPLY_CORR_1,), 'post': (RUN_LD, ALIAS_DETECT_1ST) }), @@ -841,8 +829,6 @@ { 'bit_sync': { 'short_n_long': { 'coherent_ms': 20, - 't_diff_s': 1023 * 1 / gps_constants.l1ca_chip_rate, - 'alias_acc_length_ms': 500, 0: (1023, 1, {'pre': (), 'post': (RUN_LD, ALIAS_DETECT_1ST,) }), @@ -886,8 +872,6 @@ 'post': (RUN_LD, ALIAS_DETECT_2ND, GET_CORR_1) }) }, 'ideal': { 'coherent_ms': 20, - 't_diff_s': 1023 * 1 / gps_constants.l1ca_chip_rate, - 'alias_acc_length_ms': 500, 0: (1023, 1, {'pre': (APPLY_CORR_1,), 'post': (RUN_LD, ALIAS_DETECT_1ST,) }), @@ -936,8 +920,6 @@ { 'bit_sync': { 'short_n_long': { 'coherent_ms': 40, - 't_diff_s': 1023 * 1 / gps_constants.l1ca_chip_rate, - 'alias_acc_length_ms': 500, 0: (1023, 1, {'pre': (PREPARE_BIT_COMPENSATION,), 'post': (RUN_LD, ALIAS_DETECT_1ST,) }), @@ -1027,8 +1009,6 @@ USE_COMPENSATED_BIT) }) }, 'ideal': { 'coherent_ms': 40, - 't_diff_s': 1023 * 1 / gps_constants.l1ca_chip_rate, - 'alias_acc_length_ms': 500, 0: (1023, 1, {'pre': (APPLY_CORR_1,), 'post': (RUN_LD, ALIAS_DETECT_1ST,) }), @@ -1077,8 +1057,6 @@ { 'bit_sync': { 'short_n_long': { 'coherent_ms': 80, - 't_diff_s': 1023 * 1 / gps_constants.l1ca_chip_rate, - 'alias_acc_length_ms': 500, 0: (1023, 1, {'pre': (PREPARE_BIT_COMPENSATION,), 'post': (RUN_LD, ALIAS_DETECT_1ST,) }), From ed72cc7c15d6dc34af6c755e345701d1ea1efd8b Mon Sep 17 00:00:00 2001 From: Adel Mamin Date: Fri, 12 Aug 2016 09:51:00 +0300 Subject: [PATCH 49/61] Remove duplicate coherent_ms parameters from FSM tables --- peregrine/defaults.py | 66 +++++++++++-------------------------------- 1 file changed, 17 insertions(+), 49 deletions(-) diff --git a/peregrine/defaults.py b/peregrine/defaults.py index 412298b..e89f629 100644 --- a/peregrine/defaults.py +++ b/peregrine/defaults.py @@ -363,19 +363,15 @@ { '1ms': { 'no_bit_sync': { 'short_n_long': - { 'coherent_ms': 1, - 0: (1023, 1, {'pre': (APPLY_CORR_1,), 'post': (RUN_LD, GET_CORR_1)}), + { 0: (1023, 1, {'pre': (APPLY_CORR_1,), 'post': (RUN_LD, GET_CORR_1)}), 1: (1023, 0, {'pre': (APPLY_CORR_2,), 'post': (RUN_LD, GET_CORR_2)}) }, 'ideal': - { 'coherent_ms': 1, - 0: (1023, 0, {'pre': (APPLY_CORR_1,), 'post': (RUN_LD, GET_CORR_1)}) } + { 0: (1023, 0, {'pre': (APPLY_CORR_1,), 'post': (RUN_LD, GET_CORR_1)}) } }, 'bit_sync': { 'short_n_long': - { 'coherent_ms': 1, - - 0: (1023, 1, {'pre': (APPLY_CORR_1,), + { 0: (1023, 1, {'pre': (APPLY_CORR_1,), 'post': (RUN_LD, ALIAS_DETECT_1ST, GET_CORR_1) }), 1: (1023, 2, {'pre': (APPLY_CORR_2,), 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_2) }), @@ -416,9 +412,7 @@ 19: (1023, 0, {'pre': (APPLY_CORR_2,), 'post': (RUN_LD, ALIAS_DETECT_2ND, GET_CORR_2) }) }, 'ideal': - { 'coherent_ms': 1, - - 0: (1023, 1, {'pre': (APPLY_CORR_1,), + { 0: (1023, 1, {'pre': (APPLY_CORR_1,), 'post': (RUN_LD, ALIAS_DETECT_1ST, GET_CORR_1) }), 1: (1023, 2, {'pre': (APPLY_CORR_1,), 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), @@ -464,9 +458,7 @@ '2ms': { 'bit_sync': { 'short_n_long': - { 'coherent_ms': 2, - - 0: (1023, 1, {'pre': (), + { 0: (1023, 1, {'pre': (), 'post': (RUN_LD, ALIAS_DETECT_1ST) }), 1: (1023, 2, {'pre': (APPLY_CORR_1,), 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), @@ -507,9 +499,7 @@ 19: (1023, 0, {'pre': (APPLY_CORR_1,), 'post': (RUN_LD, ALIAS_DETECT_2ND, GET_CORR_1) }) }, 'ideal': - { 'coherent_ms': 2, - - 0: (1023, 1, {'pre': (APPLY_CORR_1,), + { 0: (1023, 1, {'pre': (APPLY_CORR_1,), 'post': (RUN_LD, ALIAS_DETECT_1ST) }), 1: (1023, 2, {'pre': (), 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), @@ -555,9 +545,7 @@ '4ms': { 'bit_sync': { 'short_n_long': - { 'coherent_ms': 4, - - 0: (1023, 1, {'pre': (), + { 0: (1023, 1, {'pre': (), 'post': (RUN_LD, ALIAS_DETECT_1ST) }), 1: (1023, 2, {'pre': (APPLY_CORR_1,), 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), @@ -598,9 +586,7 @@ 19: (1023, 0, {'pre': (), 'post': (RUN_LD, ALIAS_DETECT_2ND, GET_CORR_1) }) }, 'ideal': - { 'coherent_ms': 4, - - 0: (1023, 1, {'pre': (APPLY_CORR_1,), + { 0: (1023, 1, {'pre': (APPLY_CORR_1,), 'post': (RUN_LD, ALIAS_DETECT_1ST) }), 1: (1023, 2, {'pre': (), 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), @@ -646,9 +632,7 @@ '5ms': { 'bit_sync': { 'short_n_long': - { 'coherent_ms': 5, - - 0: (1023, 1, {'pre': (), + { 0: (1023, 1, {'pre': (), 'post': (RUN_LD, ALIAS_DETECT_1ST) }), 1: (1023, 2, {'pre': (APPLY_CORR_1,), 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), @@ -689,9 +673,7 @@ 19: (1023, 0, {'pre': (), 'post': (RUN_LD, ALIAS_DETECT_2ND, GET_CORR_1) }) }, 'ideal': - { 'coherent_ms': 5, - - 0: (1023, 1, {'pre': (APPLY_CORR_1,), + { 0: (1023, 1, {'pre': (APPLY_CORR_1,), 'post': (RUN_LD, ALIAS_DETECT_1ST) }), 1: (1023, 2, {'pre': (), 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), @@ -737,9 +719,7 @@ '10ms': { 'bit_sync': { 'short_n_long': - { 'coherent_ms': 10, - - 0: (1023, 1, {'pre': (), + { 0: (1023, 1, {'pre': (), 'post': (RUN_LD, ALIAS_DETECT_1ST) }), 1: (1023, 2, {'pre': (APPLY_CORR_1,), 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), @@ -780,9 +760,7 @@ 19: (1023, 0, {'pre': (), 'post': (RUN_LD, ALIAS_DETECT_2ND, GET_CORR_1) }) }, 'ideal': - { 'coherent_ms': 10, - - 0: (1023, 1, {'pre': (APPLY_CORR_1,), + { 0: (1023, 1, {'pre': (APPLY_CORR_1,), 'post': (RUN_LD, ALIAS_DETECT_1ST) }), 1: (1023, 2, {'pre': (), 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), @@ -828,9 +806,7 @@ '20ms': { 'bit_sync': { 'short_n_long': - { 'coherent_ms': 20, - - 0: (1023, 1, {'pre': (), + { 0: (1023, 1, {'pre': (), 'post': (RUN_LD, ALIAS_DETECT_1ST,) }), 1: (1023, 2, {'pre': (APPLY_CORR_1,), 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), @@ -871,9 +847,7 @@ 19: (1023, 0, {'pre': (), 'post': (RUN_LD, ALIAS_DETECT_2ND, GET_CORR_1) }) }, 'ideal': - { 'coherent_ms': 20, - - 0: (1023, 1, {'pre': (APPLY_CORR_1,), + { 0: (1023, 1, {'pre': (APPLY_CORR_1,), 'post': (RUN_LD, ALIAS_DETECT_1ST,) }), 1: (1023, 2, {'pre': (), 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), @@ -919,9 +893,7 @@ '40ms': { 'bit_sync': { 'short_n_long': - { 'coherent_ms': 40, - - 0: (1023, 1, {'pre': (PREPARE_BIT_COMPENSATION,), + { 0: (1023, 1, {'pre': (PREPARE_BIT_COMPENSATION,), 'post': (RUN_LD, ALIAS_DETECT_1ST,) }), 1: (1023, 2, {'pre': (APPLY_CORR_1,), 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), @@ -1008,9 +980,7 @@ COMPENSATE_BIT_POLARITY, USE_COMPENSATED_BIT) }) }, 'ideal': - { 'coherent_ms': 40, - - 0: (1023, 1, {'pre': (APPLY_CORR_1,), + { 0: (1023, 1, {'pre': (APPLY_CORR_1,), 'post': (RUN_LD, ALIAS_DETECT_1ST,) }), 1: (1023, 2, {'pre': (), 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), @@ -1056,9 +1026,7 @@ '80ms': { 'bit_sync': { 'short_n_long': - { 'coherent_ms': 80, - - 0: (1023, 1, {'pre': (PREPARE_BIT_COMPENSATION,), + { 0: (1023, 1, {'pre': (PREPARE_BIT_COMPENSATION,), 'post': (RUN_LD, ALIAS_DETECT_1ST,) }), 1: (1023, 2, {'pre': (APPLY_CORR_1,), 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), From 8f9660f6ae4b8a4a25f50808740bbaf02619ecaa Mon Sep 17 00:00:00 2001 From: Adel Mamin Date: Fri, 12 Aug 2016 12:02:02 +0300 Subject: [PATCH 50/61] Fix alias lock detector --- peregrine/alias_detector.py | 50 ++++++++++++++++++++++++------------- peregrine/defaults.py | 11 +++++--- peregrine/tracking.py | 23 +++++++---------- peregrine/tracking_loop.py | 3 +++ 4 files changed, 52 insertions(+), 35 deletions(-) diff --git a/peregrine/alias_detector.py b/peregrine/alias_detector.py index 8834ac5..6d1292c 100644 --- a/peregrine/alias_detector.py +++ b/peregrine/alias_detector.py @@ -9,7 +9,6 @@ # WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. import numpy as np -from swiftnav.track import AliasDetector as AD from peregrine import defaults from peregrine import gps_constants from peregrine import glo_constants @@ -17,25 +16,19 @@ class AliasDetector(object): - def __init__(self, coherent_ms): + def __init__(self): """ Initialize the parameters, which are common across different types of tracking channels. Parameters ---------- - coherent_ms : int - Coherent integration time [ms]. + None """ - self.err_hz = 0. - self.coherent_ms = coherent_ms - self.integration_rounds = defaults.alias_detect_interval_ms / \ - (defaults.alias_detect_slice_ms * 2) - - self.alias_detect = AD(acc_len=self.integration_rounds, time_diff=2e-3) + self.reinit() - def reinit(self, coherent_ms): + def reinit(self): """ Customize the alias detect reinitialization in a subclass. The method can be optionally redefined in a subclass to perform @@ -44,13 +37,19 @@ def reinit(self, coherent_ms): Parameters ---------- - coherent_ms : int - Coherent integration time [ms]. + None """ - self.err_hz = 0 - self.coherent_ms = coherent_ms - self.alias_detect.reinit(self.integration_rounds, time_diff=2e-3) + + self.err_hz = 0. + self.first_P = 0 + 0j + self.acc_len = defaults.alias_detect_interval_ms / \ + defaults.alias_detect_slice_ms + self.dot = 0. + self.cross = 0. + self.fl_count = 0 + self.dt = defaults.alias_detect_slice_ms * 1e-3 + self.first_set = False def first(self, P): """ @@ -65,7 +64,8 @@ def first(self, P): The prompt I/Q samples from correlator. """ - self.alias_detect.first(P.real, P.imag) + self.first_P = P + self.first_set = True def second(self, P): """ @@ -80,7 +80,21 @@ def second(self, P): The prompt I/Q samples from correlator. """ - self.err_hz = self.alias_detect.second(P.real, P.imag) + if not self.first_set: + return + + self.dot += (np.absolute(P.real * self.first_P.real) + \ + np.absolute(P.imag * self.first_P.imag)) / self.acc_len + self.cross += (self.first_P.real * P.imag - P.real * self.first_P.imag) / self.acc_len + self.fl_count += 1 + if self.fl_count == self.acc_len: + self.err_hz = np.arctan2(self.cross, self.dot) / (2 * np.pi * self.dt) + self.fl_count = 0 + self.cross = 0 + self.dot = 0 + else: + self.err_hz = 0 + abs_err_hz = abs(self.err_hz) err_sign = np.sign(self.err_hz) # The expected frequency errors are +-(25 + N * 50) Hz diff --git a/peregrine/defaults.py b/peregrine/defaults.py index e89f629..5188f17 100644 --- a/peregrine/defaults.py +++ b/peregrine/defaults.py @@ -363,11 +363,16 @@ { '1ms': { 'no_bit_sync': { 'short_n_long': - { 0: (1023, 1, {'pre': (APPLY_CORR_1,), 'post': (RUN_LD, GET_CORR_1)}), - 1: (1023, 0, {'pre': (APPLY_CORR_2,), 'post': (RUN_LD, GET_CORR_2)}) }, + { 0: (1023, 1, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, GET_CORR_1, ALIAS_DETECT_1ST)}), + 1: (1023, 0, {'pre': (APPLY_CORR_2,), + 'post': (RUN_LD, GET_CORR_2, ALIAS_DETECT_2ND)}) }, 'ideal': - { 0: (1023, 0, {'pre': (APPLY_CORR_1,), 'post': (RUN_LD, GET_CORR_1)}) } + { 0: (1023, 1, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, GET_CORR_1, ALIAS_DETECT_1ST)}), + 1: (1023, 0, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, GET_CORR_1, ALIAS_DETECT_2ND)}) } }, 'bit_sync': { 'short_n_long': diff --git a/peregrine/tracking.py b/peregrine/tracking.py index 497f900..7bdba57 100644 --- a/peregrine/tracking.py +++ b/peregrine/tracking.py @@ -230,9 +230,9 @@ def __init__(self, params): self.profiles_history = [] self.track_candidates = [] - self.stabilization_time = 50 + self.stabilization_time = defaults.tracking_loop_stabilization_time_ms self.coherent_ms = coherent_ms - self.alias_detector = alias_detector.AliasDetector(self.coherent_ms) + self.alias_detector = alias_detector.AliasDetector() self.short_n_long = False if params['tracker_options']: @@ -391,8 +391,6 @@ def _set_track_profile(self): logger.info("[PRN: %d (%s)] coherent_ms=%d and PLL bw=%f FLL bw=%f" % (self.prn + 1, self.signal, self.coherent_ms, pll_bw, fll_bw)) - self.alias_detector.reinit(self.coherent_ms) - lock_detect_params_fast = get_lock_detector(pll_bw, defaults.lock_detect_params_fast) @@ -797,23 +795,20 @@ def run(self, samples): self.P.imag, 1) - if self.lock_detect_outo: - if defaults.ALIAS_DETECT_1ST in flags_post or \ - defaults.ALIAS_DETECT_BOTH in flags_post: - self.alias_detector.first(P_) + if defaults.ALIAS_DETECT_1ST in flags_post or \ + defaults.ALIAS_DETECT_BOTH in flags_post: + self.alias_detector.first(P_) - if defaults.ALIAS_DETECT_2ND in flags_post or \ - defaults.ALIAS_DETECT_BOTH in flags_post: - self.alias_detector.second(P_) - else: - self.alias_detector.reinit(self.coherent_ms) + if defaults.ALIAS_DETECT_2ND in flags_post or \ + defaults.ALIAS_DETECT_BOTH in flags_post: + self.alias_detector.second(P_) err_hz = self.alias_detector.get_err_hz() if abs(err_hz) > 0: logger.info("[PRN: %d (%s)] False lock detected. " "Error: %.1f Hz. Correcting..." % (self.prn + 1, self.signal, -err_hz)) - self.loop_filter.adjust_freq(err_hz) + self.loop_filter.adjust_freq(err_hz * 2 * np.pi) if not (defaults.GET_CORR_1 in flags_post) and \ not (defaults.GET_CORR_2 in flags_post): diff --git a/peregrine/tracking_loop.py b/peregrine/tracking_loop.py index 49fb74c..6b4819e 100644 --- a/peregrine/tracking_loop.py +++ b/peregrine/tracking_loop.py @@ -170,6 +170,9 @@ def update(self, E, P, L): def adjust_freq(self, corr): self.carr_freq += corr + self.phase_vel += corr + self.code_vel += corr / self.carr_to_code + self.code_freq += corr / self.carr_to_code def to_dict(self): return { k:v for k, v in self.__dict__.items() \ From 5e209ea68318b95b9ee65160948091a3fbc523b6 Mon Sep 17 00:00:00 2001 From: Adel Mamin Date: Fri, 12 Aug 2016 13:52:40 +0300 Subject: [PATCH 51/61] Remove references to stages and pipelining --- peregrine/analysis/tracking_loop.py | 12 ++------ peregrine/run.py | 43 ++++------------------------- peregrine/tracking.py | 4 +-- peregrine/tracking_loop.py | 2 -- 4 files changed, 10 insertions(+), 51 deletions(-) diff --git a/peregrine/analysis/tracking_loop.py b/peregrine/analysis/tracking_loop.py index 065a290..a03cf80 100755 --- a/peregrine/analysis/tracking_loop.py +++ b/peregrine/analysis/tracking_loop.py @@ -114,12 +114,8 @@ def main(): ms_to_process = int(args.ms_to_process) - if args.pipelining is not None: - tracker_options = {'mode': 'pipelining', - 'k': args.pipelining} - elif args.short_long_cycles is not None: - tracker_options = {'mode': 'short-long-cycles', - 'k': args.short_long_cycles} + if args.short_long_cycles is not None: + tracker_options = {'mode': 'short-long-cycles'} else: tracker_options = None @@ -132,9 +128,6 @@ def main(): signal=signal, sample_index=skip_samples) - if args.l1ca_profile: - profile = defaults.l1ca_stage_profiles[args.l1ca_profile] - samples = {L1CA: {'IF': freq_profile['GPS_L1_IF']}, L2C: {'IF': freq_profile['GPS_L2_IF']}, GLO_L1: {'IF': freq_profile['GLO_L1_IF']}, @@ -163,7 +156,6 @@ def main(): print "Initial carrier Doppler frequency [Hz]: %s" % carr_doppler print "Initial code phase [chips]: %s" % code_phase print "Signal: %s" % args.signal - print "L1 stage profile: %s" % args.l1ca_profile print "Tracker options: %s" % str(tracker_options) print "L2C handover: %s" % str(l2c_handover) print "======================================================================" diff --git a/peregrine/run.py b/peregrine/run.py index 570144b..18c0835 100755 --- a/peregrine/run.py +++ b/peregrine/run.py @@ -137,36 +137,15 @@ def populate_peregrine_cmd_line_arguments(parser): fpgaSim = parser.add_argument_group('FPGA simulation', 'FPGA delay control simulation') - fpgaExcl = fpgaSim.add_mutually_exclusive_group(required=False) - fpgaExcl.add_argument("--pipelining", - type=float, - nargs='?', - metavar='PIPELINING_K', - help="Use FPGA pipelining simulation. Supply optional " - " coefficient (%f)" % defaults.pipelining_k, - const=defaults.pipelining_k, - default=None) - - fpgaExcl.add_argument("--short-long-cycles", - type=float, - nargs='?', - metavar='PIPELINING_K', - help="Use FPGA short-long cycle simulation. Supply" - " optional pipelining coefficient (0.)", - const=0., - default=None) + + fpgaSim.add_argument("--short-long-cycles", + help="Use FPGA short-long cycle simulation.", + action="store_true") signalParam = parser.add_argument_group('Signal tracking', 'Parameters for satellite vehicle' ' signal') - signalParam.add_argument('--l1ca-profile', - metavar='PROFILE', - help='L1 C/A stage profile. Controls coherent' - ' integration time and tuning parameters: %s.' % - str(defaults.l1ca_stage_profiles.keys()), - choices=defaults.l1ca_stage_profiles.keys()) - return signalParam @@ -210,16 +189,8 @@ def main(): else: raise NotImplementedError() - if args.l1ca_profile: - profile = defaults.l1ca_stage_profiles[args.l1ca_profile] - stage2_coherent_ms = profile[1]['coherent_ms'] - stage2_params = profile[1]['loop_filter_params'] - else: - stage2_coherent_ms = None - stage2_params = None - - if args.pipelining is not None: - tracker_options = {'mode': 'pipelining', 'k': args.pipelining} + if args.short_long_cycles is not None: + tracker_options = {'mode': 'short-long-cycles'} else: tracker_options = None @@ -325,8 +296,6 @@ def main(): ms_to_track=ms_to_process, sampling_freq=freq_profile[ 'sampling_freq'], # [Hz] - stage2_coherent_ms=stage2_coherent_ms, - stage2_loop_filter_params=stage2_params, tracker_options=tracker_options, output_file=args.file, progress_bar_output=args.progress_bar, diff --git a/peregrine/tracking.py b/peregrine/tracking.py index 7bdba57..08b2b09 100644 --- a/peregrine/tracking.py +++ b/peregrine/tracking.py @@ -388,8 +388,8 @@ def _set_track_profile(self): self.coherent_ms = coherent_ms - logger.info("[PRN: %d (%s)] coherent_ms=%d and PLL bw=%f FLL bw=%f" % - (self.prn + 1, self.signal, self.coherent_ms, pll_bw, fll_bw)) + # logger.info("[PRN: %d (%s)] coherent_ms=%d and PLL bw=%f FLL bw=%f" % + # (self.prn + 1, self.signal, self.coherent_ms, pll_bw, fll_bw)) lock_detect_params_fast = get_lock_detector(pll_bw, defaults.lock_detect_params_fast) diff --git a/peregrine/tracking_loop.py b/peregrine/tracking_loop.py index 6b4819e..b4077fc 100644 --- a/peregrine/tracking_loop.py +++ b/peregrine/tracking_loop.py @@ -378,7 +378,6 @@ def retune(self, code_params, carr_params, loop_freq, carr_freq_b1, carr_to_code self.phase_c1 = phase_a2 * phase_omega_0 self.phase_c2 = phase_omega_0 * phase_omega_0 # self.phase_c1, self.phase_c2 = controlled_root(2, 1 / loop_freq, carr_bw) - # print "T = ", 1 / loop_freq, " BW = ", carr_bw # DLL constants code_omega_0 = code_bw / 0.53 @@ -509,7 +508,6 @@ def retune(self, code_params, carr_params, loop_freq, carr_freq_b1, carr_to_code self.phase_c1 = phase_a2 * phase_omega_0 self.phase_c2 = phase_omega_0 * phase_omega_0 # self.phase_c1, self.phase_c2 = controlled_root(2, 1 / loop_freq, carr_bw) - # print "T = ", 1 / loop_freq, " BW = ", carr_bw # DLL constants code_omega_0 = code_bw / 0.53 From 37ac29398d415d33acba115089b1d7ade84fd1f7 Mon Sep 17 00:00:00 2001 From: Adel Mamin Date: Fri, 12 Aug 2016 13:53:23 +0300 Subject: [PATCH 52/61] Add unit test for alias detector --- tests/test_alias_detector.py | 43 ++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 tests/test_alias_detector.py diff --git a/tests/test_alias_detector.py b/tests/test_alias_detector.py new file mode 100644 index 0000000..34de7dd --- /dev/null +++ b/tests/test_alias_detector.py @@ -0,0 +1,43 @@ +# Copyright (C) 2016 Swift Navigation Inc. +# +# This source is subject to the license found in the file 'LICENSE' which must +# be be distributed together with this source. All other rights reserved. +# +# THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, +# EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. + +import numpy as np +from peregrine import alias_detector + +def get_error(ad, expected_err_hz): + angle = expected_err_hz * 2 * np.pi * 0.001 + rotation = np.exp(1j * angle) + + ad.reinit() + + iq = rotation + ad.first(iq) + + for i in range(ad.acc_len): + ad.second(iq) + ad.first(iq) + iq *= rotation + iq /= abs(iq) + + return ad.get_err_hz() + +def test_alias_detect(): + ''' + Alias lock detector test + ''' + + ad_l1ca = alias_detector.AliasDetector() + ad_l2c = alias_detector.AliasDetector() + + meas_err_hz = [-75, -80, -25, -30, 0, 20, 25, 65, 75] + true_err_hz = [-75, -75, -25, -25, 0, 25, 25, 75, 75] + + for ad in [ad_l1ca, ad_l2c]: + for i, err_hz in enumerate(meas_err_hz): + assert true_err_hz[i] == get_error(ad, err_hz) From a33e3f1b1c36f5041fe3cade9a65c42aa7c2414e Mon Sep 17 00:00:00 2001 From: Adel Mamin Date: Fri, 12 Aug 2016 14:31:40 +0300 Subject: [PATCH 53/61] Fix unit tests Fix unit test rebasing error --- peregrine/analysis/tracking_loop.py | 2 +- peregrine/defaults.py | 13 +++++++++++++ peregrine/run.py | 3 ++- peregrine/tracking.py | 22 +++++++++++++++++----- tests/test_common.py | 8 ++------ tests/test_tracking.py | 29 +++++++++++++---------------- 6 files changed, 48 insertions(+), 29 deletions(-) diff --git a/peregrine/analysis/tracking_loop.py b/peregrine/analysis/tracking_loop.py index a03cf80..658200d 100755 --- a/peregrine/analysis/tracking_loop.py +++ b/peregrine/analysis/tracking_loop.py @@ -114,7 +114,7 @@ def main(): ms_to_process = int(args.ms_to_process) - if args.short_long_cycles is not None: + if args.short_long_cycles: tracker_options = {'mode': 'short-long-cycles'} else: tracker_options = None diff --git a/peregrine/defaults.py b/peregrine/defaults.py index 5188f17..0e5cce7 100644 --- a/peregrine/defaults.py +++ b/peregrine/defaults.py @@ -210,6 +210,11 @@ 'pll_bw': (40, 35, 30, 25, 20, 18, 16, 14, 12, 10, 8, 7, 6.5, 6, 5.5, 5), 'coherent_ms': (1, 2, 4, 5, 10, 20) } +l2c_track_params = { + 'fll_bw': (1, 0), + 'pll_bw': (20, 18, 16, 14, 12, 10, 8, 7, 6.5, 6, 5.5, 5), + 'coherent_ms': (20,) } + l1ca_loop_filter_params_template = { 'code_params': (1., 0.7, 1.), # NBW, zeta, k 'carr_params': (20., 0.7, 1.), # NBW, zeta, k @@ -218,6 +223,14 @@ 'carr_to_code': 1540. # carr_to_code } +l2c_loop_filter_params_template = { + 'code_params': (1., 0.7, 1.), # NBW, zeta, k + 'carr_params': (20., 0.7, 1.), # NBW, zeta, k + 'loop_freq': 1000., # 1000/coherent_ms + 'carr_freq_b1': 1., # FLL NBW + 'carr_to_code': 1200. # carr_to_code + } + # Tracking stages. See track.c for more details. # 1;20 ms stages l1ca_stage_params_slow = \ diff --git a/peregrine/run.py b/peregrine/run.py index 18c0835..d9248a9 100755 --- a/peregrine/run.py +++ b/peregrine/run.py @@ -140,6 +140,7 @@ def populate_peregrine_cmd_line_arguments(parser): fpgaSim.add_argument("--short-long-cycles", help="Use FPGA short-long cycle simulation.", + default=False, action="store_true") signalParam = parser.add_argument_group('Signal tracking', @@ -189,7 +190,7 @@ def main(): else: raise NotImplementedError() - if args.short_long_cycles is not None: + if args.short_long_cycles: tracker_options = {'mode': 'short-long-cycles'} else: tracker_options = None diff --git a/peregrine/tracking.py b/peregrine/tracking.py index 08b2b09..893d0e6 100644 --- a/peregrine/tracking.py +++ b/peregrine/tracking.py @@ -240,11 +240,13 @@ def __init__(self, params): if mode == 'short-long-cycles': self.short_n_long = True + self.bit_sync_prev = self.bit_sync + self.track_settled = False self.fsm_index = 0 self.fsm_states = get_fsm_states(ms=self.coherent_ms, short_n_long=self.short_n_long, - bit_sync=False) + bit_sync=self.bit_sync) self.lock_detect = lock_detect.LockDetector( k1=self.lock_detect_params["k1"], @@ -477,11 +479,10 @@ def _run_track_profile_selection(self): """ - bit_sync = self.nav_bit_sync.bit_sync_acquired() - if bit_sync and not self.bit_sync: + if self.bit_sync and not self.bit_sync_prev: # we just got bit sync self.track_profile_timer_ms = 0 - self.bit_sync = bit_sync + self.bit_sync_prev = self.bit_sync if self.lock_detect_outp: @@ -960,6 +961,8 @@ def __init__(self, params): params['sample_index'] = params['samples']['sample_index'] params['carrier_freq'] = gps_constants.l1 + self.bit_sync = False + TrackingChannel.__init__(self, params) self.nav_msg = NavMsg() @@ -1016,6 +1019,8 @@ def _run_nav_data_decoding(self): self.track_result.tow[self.i] = tow if tow >= 0 else ( self.track_result.tow[self.i - 1] + self.coherent_ms) + self.bit_sync = self.nav_bit_sync.bit_sync_acquired() + # Handover to L2C if possible if self.l2c_handover and not self.l2c_handover_acq and \ gps_constants.L2C in self.samples and \ @@ -1056,16 +1061,23 @@ def __init__(self, params): cn0_0 = 10 * np.log10(params['acq'].snr) cn0_0 += 10 * np.log10(defaults.L2C_CHANNEL_BANDWIDTH_HZ) params['cn0_0'] = cn0_0 - params['track_profiles'] = defaults.l2c_track_profiles + params['lock_detect_params'] = defaults.l2c_lock_detect_params_20ms params['IF'] = params['samples'][gps_constants.L2C]['IF'] params['prn_code'] = L2CMCodes[params['acq'].prn] params['code_freq_init'] = params['acq'].doppler * \ gps_constants.l2c_chip_rate / gps_constants.l2 + + params['track_params'] = defaults.l2c_track_params + params['loop_filter_params_template'] = \ + defaults.l2c_loop_filter_params_template + params['chipping_rate'] = gps_constants.l2c_chip_rate params['sample_index'] = 0 params['carrier_freq'] = gps_constants.l2 + self.bit_sync = True + TrackingChannel.__init__(self, params) self.cnav_msg = CNavMsg() diff --git a/tests/test_common.py b/tests/test_common.py index 6166df7..d2502c6 100644 --- a/tests/test_common.py +++ b/tests/test_common.py @@ -181,8 +181,7 @@ def run_peregrine(file_name, file_format, freq_profile, skip_param, skip_val, skip_tracking=True, skip_navigation=True, - pipelining=None, - short_long_cycles=None): + short_long_cycles=False): parameters = [ 'peregrine', @@ -198,11 +197,8 @@ def run_peregrine(file_name, file_format, freq_profile, if skip_navigation: parameters += ['-n'] - if pipelining: - parameters += ['--pipelining', str(pipelining)] - if short_long_cycles: - parameters += ['--short-long-cycles', str(short_long_cycles)] + parameters += ['--short-long-cycles'] # Replace argv with args to skip tracking and navigation. with patch.object(sys, 'argv', parameters): diff --git a/tests/test_tracking.py b/tests/test_tracking.py index c58776e..56c5872 100644 --- a/tests/test_tracking.py +++ b/tests/test_tracking.py @@ -30,7 +30,7 @@ def run_tracking_loop(prn, signal, dopp, phase, file_name, file_format, freq_profile, skip_val, norun=False, l2chandover=False, - pipelining=None, short_long_cycles=None): + short_long_cycles=False): parameters = [ 'tracking_loop', '-P', str(prn), @@ -43,10 +43,8 @@ def run_tracking_loop(prn, signal, dopp, phase, file_name, file_format, '--skip-samples', str(skip_val) ] - if pipelining: - parameters += ['--pipelining', str(pipelining)] - elif short_long_cycles: - parameters += ['--short-long-cycles', str(short_long_cycles)] + if short_long_cycles: + parameters += ['--short-long-cycles'] if norun: parameters.append('--no-run') @@ -80,7 +78,7 @@ def get_tr_loop_res_file_name(sample_file, prn, band): def run_track_test(samples_file, expected_lock_ratio, init_doppler, init_code_phase, prn, file_format, freq_profile, skip_samples=None, skip_ms=None, - pipelining=None, short_long_cycles=None): + short_long_cycles=False): bands = fileformat_to_bands(file_format) @@ -88,7 +86,7 @@ def run_track_test(samples_file, expected_lock_ratio, init_doppler, run_peregrine(samples_file, file_format, freq_profile, skip_param, skip_val, skip_tracking=False, - pipelining=pipelining, short_long_cycles=short_long_cycles) + short_long_cycles=short_long_cycles) for band in bands: dopp_ratio = 1 @@ -96,7 +94,6 @@ def run_track_test(samples_file, expected_lock_ratio, init_doppler, dopp_ratio = l2 / l1 run_tracking_loop(prn, band, init_doppler * dopp_ratio, init_code_phase, samples_file, file_format, freq_profile, 0, - pipelining=pipelining, short_long_cycles=short_long_cycles) # code_phase = propagate_code_phase(init_code_phase, @@ -104,10 +101,10 @@ def run_track_test(samples_file, expected_lock_ratio, init_doppler, # skip_param, skip_val) check_per_track_results(expected_lock_ratio, samples_file, prn, bands, - pipelining, short_long_cycles) + short_long_cycles) check_tr_loop_track(expected_lock_ratio, samples_file, prn, bands, - pipelining, short_long_cycles) + short_long_cycles) # Clean-up. os.remove(get_acq_result_file_name(samples_file)) @@ -117,7 +114,7 @@ def run_track_test(samples_file, expected_lock_ratio, init_doppler, def check_per_track_results(expected_lock_ratio, filename, prn, bands, - pipelining, short_long_cycles): + short_long_cycles): ret = {} print "Peregrine tracking:" for band in bands: @@ -142,14 +139,14 @@ def check_per_track_results(expected_lock_ratio, filename, prn, bands, print "band =", band lock_ratio = float(lock_detect_outp_sum) / lock_detect_outp_len print "lock_ratio =", lock_ratio - if (not short_long_cycles and not pipelining) or band != L2C: + if not short_long_cycles or band != L2C: assert lock_ratio >= expected_lock_ratio ret[band]['lock_ratio'] = lock_ratio return ret def check_tr_loop_track(expected_lock_ratio, filename, prn, bands, - pipelining, short_long_cycles): + short_long_cycles): ret = {} print "Tracking loop:" for band in bands: @@ -166,7 +163,7 @@ def check_tr_loop_track(expected_lock_ratio, filename, prn, bands, print "band =", band lock_ratio = float(lock_detect_outp_sum) / lock_detect_outp_len print "lock_ratio =", lock_ratio - if (not short_long_cycles and not pipelining) or band != L2C: + if not short_long_cycles or band != L2C: assert lock_ratio >= expected_lock_ratio ret[band]['lock_ratio'] = lock_ratio return ret @@ -190,9 +187,9 @@ def test_tracking_gps(): run_track_test(samples, 0.6, init_doppler, init_code_phase, prn, file_format, freq_profile) run_track_test(samples, 0.3, init_doppler, init_code_phase, prn, file_format, - freq_profile, pipelining=0.5) + freq_profile) run_track_test(samples, 0.3, init_doppler, init_code_phase, prn, file_format, - freq_profile, short_long_cycles=0.5) + freq_profile, short_long_cycles=True) os.remove(samples) From c663de35949ccb27f7e47ee0ef5c29475a809119 Mon Sep 17 00:00:00 2001 From: Adel Mamin Date: Fri, 12 Aug 2016 16:18:52 +0300 Subject: [PATCH 54/61] Change background colour to white in print_track_res.py script --- peregrine/analysis/print_track_res.py | 1 + 1 file changed, 1 insertion(+) diff --git a/peregrine/analysis/print_track_res.py b/peregrine/analysis/print_track_res.py index a6b99ca..28d9f51 100755 --- a/peregrine/analysis/print_track_res.py +++ b/peregrine/analysis/print_track_res.py @@ -69,6 +69,7 @@ def main(): time_stamp_max = max(time_stamps) fig = plt.figure(figsize=(11, 15)) + fig.patch.set_facecolor('white') plt.subplots_adjust(wspace=0.25, hspace=0.75) for (par_to_print,layout) in params: From 93b8446bbd80dcbce820423ee68072660ccc2de8 Mon Sep 17 00:00:00 2001 From: Adel Mamin Date: Fri, 12 Aug 2016 16:19:31 +0300 Subject: [PATCH 55/61] Update libswiftnav SHA1 to match master head --- libswiftnav | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libswiftnav b/libswiftnav index 18c8d96..da4bfcb 160000 --- a/libswiftnav +++ b/libswiftnav @@ -1 +1 @@ -Subproject commit 18c8d96249d44a2330d35983bc1ed51ec7ed0c35 +Subproject commit da4bfcb7db04021a730e9bd6b1b0781dfd69abc0 From b3716105319c088edbdda7a3065f628a14a0c4bb Mon Sep 17 00:00:00 2001 From: Adel Mamin Date: Wed, 17 Aug 2016 13:56:19 +0300 Subject: [PATCH 56/61] Fix GLO changes to match profile switching logic changes --- peregrine/defaults.py | 35 ++++++++++++++++++++++- peregrine/tracking.py | 65 ++++++++++++++++-------------------------- tests/test_tracking.py | 6 ++-- 3 files changed, 61 insertions(+), 45 deletions(-) diff --git a/peregrine/defaults.py b/peregrine/defaults.py index 0e5cce7..1c884d4 100644 --- a/peregrine/defaults.py +++ b/peregrine/defaults.py @@ -215,6 +215,11 @@ 'pll_bw': (20, 18, 16, 14, 12, 10, 8, 7, 6.5, 6, 5.5, 5), 'coherent_ms': (20,) } +glol1_track_params = { + 'fll_bw': (2, 1, 0), + 'pll_bw': (40, 20, 18, 16, 14, 12, 10, 8, 7, 6.5, 6, 5.5, 5), + 'coherent_ms': (1,) } + l1ca_loop_filter_params_template = { 'code_params': (1., 0.7, 1.), # NBW, zeta, k 'carr_params': (20., 0.7, 1.), # NBW, zeta, k @@ -231,6 +236,14 @@ 'carr_to_code': 1200. # carr_to_code } +glol1_loop_filter_params_template = { + 'code_params': (1., 0.7, 1.), # NBW, zeta, k + 'carr_params': (20., 0.7, 1.), # NBW, zeta, k + 'loop_freq': 1000., # 1000/coherent_ms + 'carr_freq_b1': 1., # FLL NBW + 'carr_to_code': 3135.0293542074364 # carr_to_code + } + # Tracking stages. See track.c for more details. # 1;20 ms stages l1ca_stage_params_slow = \ @@ -372,7 +385,25 @@ USE_COMPENSATED_BIT = 10 PREPARE_BIT_COMPENSATION = 11 -fsm_states = \ +glo_fsm_states = \ + { '1ms': + { 'no_bit_sync': + { 'short_n_long': + { 0: (511, 1, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, GET_CORR_1, ALIAS_DETECT_1ST)}), + 1: (511, 0, {'pre': (APPLY_CORR_2,), + 'post': (RUN_LD, GET_CORR_2, ALIAS_DETECT_2ND)}) }, + + 'ideal': + { 0: (511, 1, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, GET_CORR_1, ALIAS_DETECT_1ST)}), + 1: (511, 0, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, GET_CORR_1, ALIAS_DETECT_2ND)}) } + } + } + } + +gps_fsm_states = \ { '1ms': { 'no_bit_sync': { 'short_n_long': @@ -1257,6 +1288,8 @@ 'lp': 50, # 1000ms worth of I/Q samples to reach pessimistic lock 'lo': 240} # 4800ms worth of I/Q samples to lower optimistic lock +glol1_lock_detect_params = l1ca_lock_detect_params_opt + # The time interval, over which the alias detection is done. # The alias detect algorithm averages the phase angle over this time [ms] alias_detect_interval_ms = 500 diff --git a/peregrine/tracking.py b/peregrine/tracking.py index 893d0e6..6dd66c6 100644 --- a/peregrine/tracking.py +++ b/peregrine/tracking.py @@ -128,7 +128,7 @@ def _tracking_channel_factory(parameters): if parameters['acq'].signal == glo_constants.GLO_L1: return TrackingChannelGLOL1(parameters) -def get_fsm_states(ms, short_n_long, bit_sync): +def get_fsm_states(fsm_states, ms, short_n_long, bit_sync): if ms == 1: ms = '1ms' elif ms == 2: @@ -158,7 +158,7 @@ def get_fsm_states(ms, short_n_long, bit_sync): else: bit_sync_status = 'no_bit_sync' - return defaults.fsm_states[ms][bit_sync_status][mode] + return fsm_states[ms][bit_sync_status][mode] def get_lock_detector(cur_bw, lock_detect_set): @@ -244,7 +244,8 @@ def __init__(self, params): self.track_settled = False self.fsm_index = 0 - self.fsm_states = get_fsm_states(ms=self.coherent_ms, + self.fsm_states = get_fsm_states(self.fsm_states_all, + ms=self.coherent_ms, short_n_long=self.short_n_long, bit_sync=self.bit_sync) @@ -408,7 +409,8 @@ def _set_track_profile(self): cutoff_freq=10, loop_freq=1e3 / self.coherent_ms) - self.fsm_states = get_fsm_states(ms=self.coherent_ms, + self.fsm_states = get_fsm_states(self.fsm_states_all, + ms=self.coherent_ms, short_n_long=self.short_n_long, bit_sync=self.bit_sync) self.fsm_index = 0 @@ -960,6 +962,7 @@ def __init__(self, params): params['chipping_rate'] = gps_constants.l1ca_chip_rate params['sample_index'] = params['samples']['sample_index'] params['carrier_freq'] = gps_constants.l1 + params['fsm_states_all'] = defaults.gps_fsm_states self.bit_sync = False @@ -1075,6 +1078,7 @@ def __init__(self, params): params['chipping_rate'] = gps_constants.l2c_chip_rate params['sample_index'] = 0 params['carrier_freq'] = gps_constants.l2 + params['fsm_states_all'] = defaults.gps_fsm_states self.bit_sync = True @@ -1135,22 +1139,29 @@ def __init__(self, params): GLO L1 tracking initialization parameters """ + # Convert acquisition SNR to C/N0 cn0_0 = 10 * np.log10(params['acq'].snr) cn0_0 += 10 * np.log10(defaults.GLOL1_CHANNEL_BANDWIDTH_HZ) + params['cn0_0'] = cn0_0 - params['coherent_ms'] = 1 - params['coherent_iter'] = 1 - params['loop_filter_params'] = defaults.l1ca_stage1_loop_filter_params - params['lock_detect_params'] = defaults.l1ca_lock_detect_params_opt params['IF'] = params['samples'][glo_constants.GLO_L1]['IF'] params['prn_code'] = GLOCode params['code_freq_init'] = params['acq'].doppler * \ glo_constants.glo_chip_rate / glo_constants.glo_l1 + + params['track_params'] = defaults.glol1_track_params + params['loop_filter_params_template'] = \ + defaults.glol1_loop_filter_params_template + + params['lock_detect_params'] = defaults.glol1_lock_detect_params params['chipping_rate'] = glo_constants.glo_chip_rate - params['sample_index'] = 0 - params['alias_detector'] = \ - alias_detector.AliasDetectorGLO(params['coherent_ms']) + params['sample_index'] = params['samples']['sample_index'] + params['carrier_freq'] = glo_constants.glo_l1 + + params['fsm_states_all'] = defaults.glo_fsm_states + + self.bit_sync = False TrackingChannel.__init__(self, params) @@ -1196,42 +1207,14 @@ def _run_preprocess(self): self.coherent_iter = self.coherent_ms - def _short_n_long_preprocess(self): - if self.stage1: - self.E = self.P = self.L = 0.j - else: - # When simulating short and long cycles, short step resets EPL - # registers, and long one adds up to them - if self.short_step: - self.E = self.P = self.L = 0.j - self.coherent_iter = 1 - else: - self.coherent_iter = self.coherent_ms - 1 - - self.code_chips_to_integrate = glo_constants.glo_code_len - - return self.coherent_iter, self.code_chips_to_integrate - - def _short_n_long_postprocess(self): - more_integration_needed = False - if not self.stage1: - if self.short_step: - # In case of short step - go to next integration period - self.short_step = False - more_integration_needed = True - else: - # Next step is short cycle - self.short_step = True - return more_integration_needed - - def _run_postprocess(self): + def _run_nav_data_decoding(self): """ Run GLO L1 coherent integration postprocessing. Runs navigation bit sync decoding operation and GLO L1 to GLO L2 handover. """ - # Handover to L2C if possible + # Handover to L2 if possible if self.glol2_handover and not self.glol2_handover_acq and \ glo_constants.GLO_L2 in self.samples and \ 'samples' in self.samples[glo_constants.GLO_L2]: # and sync: diff --git a/tests/test_tracking.py b/tests/test_tracking.py index 56c5872..a9ad22c 100644 --- a/tests/test_tracking.py +++ b/tests/test_tracking.py @@ -187,7 +187,7 @@ def test_tracking_gps(): run_track_test(samples, 0.6, init_doppler, init_code_phase, prn, file_format, freq_profile) run_track_test(samples, 0.3, init_doppler, init_code_phase, prn, file_format, - freq_profile) + freq_profile) run_track_test(samples, 0.3, init_doppler, init_code_phase, prn, file_format, freq_profile, short_long_cycles=True) @@ -253,9 +253,9 @@ def test_tracking_glo(): run_track_test(samples, 0.6, init_doppler, init_code_phase, prn, file_format, freq_profile) run_track_test(samples, 0.3, init_doppler, init_code_phase, prn, file_format, - freq_profile, pipelining=0.5) + freq_profile) run_track_test(samples, 0.3, init_doppler, init_code_phase, prn, file_format, - freq_profile, short_long_cycles=0.5) + freq_profile, short_long_cycles=True) os.remove(samples) From e2ee04462314543a3d26153509df8ba884b3b5b7 Mon Sep 17 00:00:00 2001 From: Adel Mamin Date: Wed, 17 Aug 2016 18:03:43 +0300 Subject: [PATCH 57/61] Fix formatting + add comments. No functional changes --- peregrine/alias_detector.py | 27 +- peregrine/analysis/plt_res.py | 3 +- peregrine/analysis/print_track_res.py | 5 +- peregrine/cn0.py | 156 ++- peregrine/defaults.py | 1744 ++++++++++++------------- peregrine/lock_detect.py | 92 +- peregrine/run.py | 6 +- peregrine/tracking.py | 202 ++- peregrine/tracking_loop.py | 298 ++--- 9 files changed, 1355 insertions(+), 1178 deletions(-) diff --git a/peregrine/alias_detector.py b/peregrine/alias_detector.py index 6d1292c..1325e9e 100644 --- a/peregrine/alias_detector.py +++ b/peregrine/alias_detector.py @@ -18,8 +18,7 @@ class AliasDetector(object): def __init__(self): """ - Initialize the parameters, which are common across different - types of tracking channels. + Initialize the alias lock detector parameters. Parameters ---------- @@ -30,10 +29,7 @@ def __init__(self): def reinit(self): """ - Customize the alias detect reinitialization in a subclass. - The method can be optionally redefined in a subclass to perform - a subclass specific actions to happen when alias detect - reinitialization procedure happens. + Alias detector reinitialization. Parameters ---------- @@ -44,7 +40,7 @@ def reinit(self): self.err_hz = 0. self.first_P = 0 + 0j self.acc_len = defaults.alias_detect_interval_ms / \ - defaults.alias_detect_slice_ms + defaults.alias_detect_slice_ms self.dot = 0. self.cross = 0. self.fl_count = 0 @@ -53,10 +49,7 @@ def reinit(self): def first(self, P): """ - Customize the alias detect procedure in a subclass. - The method can be optionally redefined in a subclass to perform - a subclass specific actions to happen before correlator runs - next integration round. + Provide the first reading of prompt correlator output. Parameters ---------- @@ -69,10 +62,7 @@ def first(self, P): def second(self, P): """ - Customize the alias detect procedure in a subclass. - The method can be optionally redefined in a subclass to perform - a subclass specific actions to happen before correlator runs - next integration round. + Provide the second reading of prompt correlator output Parameters ---------- @@ -83,9 +73,10 @@ def second(self, P): if not self.first_set: return - self.dot += (np.absolute(P.real * self.first_P.real) + \ + self.dot += (np.absolute(P.real * self.first_P.real) + np.absolute(P.imag * self.first_P.imag)) / self.acc_len - self.cross += (self.first_P.real * P.imag - P.real * self.first_P.imag) / self.acc_len + self.cross += (self.first_P.real * P.imag - P.real * + self.first_P.imag) / self.acc_len self.fl_count += 1 if self.fl_count == self.acc_len: self.err_hz = np.arctan2(self.cross, self.dot) / (2 * np.pi * self.dt) @@ -114,7 +105,7 @@ def second(self, P): def get_err_hz(self): """ - Customize the alias detect get error procedure in a subclass. + Return the last detected frequency error in Hz """ return self.err_hz diff --git a/peregrine/analysis/plt_res.py b/peregrine/analysis/plt_res.py index f16aa2a..1ba5b3d 100755 --- a/peregrine/analysis/plt_res.py +++ b/peregrine/analysis/plt_res.py @@ -72,7 +72,8 @@ def lockrateCn0Plot(filename): lockrate = map(lambda x: x[0], r) avgcn0 = map(lambda x: x[1], r) - x, y = zip(*sorted((xVal, np.mean([yVal for a, yVal in zip(avgcn0, lockrate) if xVal==a])) for xVal in set(avgcn0))) + x, y = zip(*sorted((xVal, np.mean([yVal for a, yVal in zip( + avgcn0, lockrate) if xVal == a])) for xVal in set(avgcn0))) fig = plt.figure() plt.plot(avgcn0, lockrate, 'o') diff --git a/peregrine/analysis/print_track_res.py b/peregrine/analysis/print_track_res.py index 28d9f51..36a83fe 100755 --- a/peregrine/analysis/print_track_res.py +++ b/peregrine/analysis/print_track_res.py @@ -15,6 +15,7 @@ import argparse from peregrine import defaults + def main(): parser = argparse.ArgumentParser() @@ -58,7 +59,7 @@ def main(): if params_num == 1: params.append('111') - params = [tuple(params[i:i+2]) for i in range(0, params_num, 2)] + params = [tuple(params[i:i + 2]) for i in range(0, params_num, 2)] data = np.genfromtxt(args.file, dtype=float, delimiter=',', names=True) @@ -72,7 +73,7 @@ def main(): fig.patch.set_facecolor('white') plt.subplots_adjust(wspace=0.25, hspace=0.75) - for (par_to_print,layout) in params: + for (par_to_print, layout) in params: sub = fig.add_subplot(layout) sub.set_title(par_to_print.replace('_', ' ').title() + ' vs Time') sub.grid() diff --git a/peregrine/cn0.py b/peregrine/cn0.py index 55569e4..c37134a 100644 --- a/peregrine/cn0.py +++ b/peregrine/cn0.py @@ -16,8 +16,10 @@ # Maximum supported NSR value (1/CN0_MM_NSR_MIN_MULTIPLIER) CN0_MM_NSR_MIN = 1e6 +# Moving average filter window size CN0_MOVING_AVG_WINDOW_SIZE = 500 + class CN0_Est_MM(object): def __init__(self, bw, cn0_0, cutoff_freq, loop_freq): @@ -26,7 +28,7 @@ def __init__(self, bw, cn0_0, cutoff_freq, loop_freq): Initializes Moment method C/N0 estimator. - The method uses the function for SNR computation: + The method uses the following function for SNR computation: C/N0(n) = P_d / P_n, where P_n(n) = M2(n) - P_d(n), @@ -37,10 +39,14 @@ def __init__(self, bw, cn0_0, cutoff_freq, loop_freq): Parameters ---------- - coherent_ms : int - Coherent integration time [ms]. - cn0_0 - The initial value of C/N_0 in dBHz. + bw : float + Unused + cn0_0 : float + The initial value of C/N_0 in dB-Hz. + cutoff_freq : float + Unused + loop_freq : float + The estimator update rate [Hz]. """ @@ -52,8 +58,24 @@ def __init__(self, bw, cn0_0, cutoff_freq, loop_freq): self.snr_db = 0 self.snr = 0 - def _compute_cn0(self, M_2, M_4): + """ + Compute C/N0 value + + Parameters + ---------- + M_2 : float + M2 value + M_4 : float + M4 value + + Return + ------ + out : float + Computed C/N0 value + + """ + tmp = 2 * M_2 * M_2 - M_4 if tmp < 0: @@ -73,7 +95,7 @@ def _compute_cn0(self, M_2, M_4): self.snr_db = 10 * np.log10(self.snr) # Compute CN0 - x= self.log_bw + self.snr_db + x = self.log_bw + self.snr_db if x < 10: return 10 if x > 60: @@ -81,8 +103,23 @@ def _compute_cn0(self, M_2, M_4): return x - def _moving_average(self, arr, x): + """ + Moving average filter. + + Parameters + ---------- + arr : list + The list of past values + x : float + New value + + Return + ------ + out : float + Filtered value + + """ if self.index < CN0_MOVING_AVG_WINDOW_SIZE: arr[self.index] = x return np.average(arr[:self.index + 1]) @@ -91,14 +128,25 @@ def _moving_average(self, arr, x): arr[-1] = x return np.average(arr) - # Computes C/N0 with Moment method. - # - # s Initialized estimator object. - # I In-phase signal component - # Q Quadrature phase signal component. - # - # Computed C/N0 & SNR values def update(self, I, Q): + """ + Compute C/N0 with Moment method. + + Parameters + ---------- + I : int + In-phase signal component. + Q : int + Quadrature signal component. + + Return + ------ + out : tuple + cn0_db - CN0 value in dB-Hz + snr - SNR + snr_db - SNR [dB] + + """ m_2 = I * I + Q * Q m_4 = m_2 * m_2 @@ -120,34 +168,18 @@ def __init__(self, bw, cn0_0, cutoff_freq, loop_freq): """ Initialize the C/N0 estimator state. - Initializes Moment method C/N0 estimator. - - The method uses the function for SNR computation: - - C/N0(n) = P_d / P_n, - where P_n(n) = M2(n) - P_d(n), - where P_d(n) = sqrt(2 * M2(n)^2 - M4(n)), - where - M2(n) = sum(1,N)(I(n)^2 + I(n-1)^2 + Q(n)^2 + Q(n-1)^2) / N - M4(n) = sum(1,N)(I(n)^4 + I(n-1)^4 + Q(n)^4 + Q(n-1)^4) / N - Parameters ---------- - coherent_ms : int - Coherent integration time [ms]. - cn0_0 - The initial value of C/N_0 in dBHz. - + bw : float + Unused + cn0_0 : float + The initial value of C/N_0 in dB-Hz. + cutoff_freq : float + Unused + loop_freq : float + The estimator update rate [Hz]. """ - # self.cn0_db = cn0_0 - # self.M2_arr = np.ndarray(CN0_MOVING_AVG_WINDOW_SIZE, dtype=np.double) - # self.M4_arr = np.ndarray(CN0_MOVING_AVG_WINDOW_SIZE, dtype=np.double) - # self.index = 0 - # self.log_bw = 10 * np.log10(loop_freq) - # self.snr_db = 0 - # self.snr = 0 - self.nsr_arr = np.ndarray(CN0_MOVING_AVG_WINDOW_SIZE, dtype=np.double) self.snr_arr = np.ndarray(CN0_MOVING_AVG_WINDOW_SIZE, dtype=np.double) self.index = 0 @@ -158,6 +190,23 @@ def __init__(self, bw, cn0_0, cutoff_freq, loop_freq): self.snr = 0 def _moving_average(self, arr, x): + """ + Moving average filter. + + Parameters + ---------- + arr : list + The list of past values + x : float + New value + + Return + ------ + out : float + Filtered value + + """ + if self.index < CN0_MOVING_AVG_WINDOW_SIZE: arr[self.index] = x return np.average(arr[:self.index + 1]) @@ -166,14 +215,26 @@ def _moving_average(self, arr, x): arr[-1] = x return np.average(arr) - # Computes C/N0 with Moment method. - # - # s Initialized estimator object. - # I In-phase signal component - # Q Quadrature phase signal component. - # - # Computed C/N0 & SNR values def update(self, I, Q): + """ + Compute C/N0 with BL method. + + Parameters + ---------- + I : int + In-phase signal component. + Q : int + Quadrature signal component. + + Return + ------ + out : tuple + cn0_db - CN0 value in dB-Hz + snr - SNR + snr_db - SNR [dB] + + """ + if self.I_prev_abs < 0.: # This is the first iteration, just update the prev state. self.I_prev_abs = np.absolute(I) @@ -192,7 +253,6 @@ def update(self, I, Q): if self.index < CN0_MOVING_AVG_WINDOW_SIZE: self.index += 1 - cn0 = self.log_bw - 10.*np.log10(self.nsr) + cn0 = self.log_bw - 10. * np.log10(self.nsr) return (cn0, self.snr, 10 * np.log10(self.snr)) - diff --git a/peregrine/defaults.py b/peregrine/defaults.py index 1c884d4..e4d80d0 100644 --- a/peregrine/defaults.py +++ b/peregrine/defaults.py @@ -208,41 +208,41 @@ l1ca_track_params = { 'fll_bw': (1, 0), 'pll_bw': (40, 35, 30, 25, 20, 18, 16, 14, 12, 10, 8, 7, 6.5, 6, 5.5, 5), - 'coherent_ms': (1, 2, 4, 5, 10, 20) } + 'coherent_ms': (1, 2, 4, 5, 10, 20)} l2c_track_params = { 'fll_bw': (1, 0), 'pll_bw': (20, 18, 16, 14, 12, 10, 8, 7, 6.5, 6, 5.5, 5), - 'coherent_ms': (20,) } + 'coherent_ms': (20,)} glol1_track_params = { 'fll_bw': (2, 1, 0), 'pll_bw': (40, 20, 18, 16, 14, 12, 10, 8, 7, 6.5, 6, 5.5, 5), - 'coherent_ms': (1,) } + 'coherent_ms': (1,)} l1ca_loop_filter_params_template = { - 'code_params': (1., 0.7, 1.), # NBW, zeta, k - 'carr_params': (20., 0.7, 1.), # NBW, zeta, k - 'loop_freq': 1000., # 1000/coherent_ms - 'carr_freq_b1': 1., # FLL NBW - 'carr_to_code': 1540. # carr_to_code - } + 'code_params': (1., 0.7, 1.), # NBW, zeta, k + 'carr_params': (20., 0.7, 1.), # NBW, zeta, k + 'loop_freq': 1000., # 1000/coherent_ms + 'carr_freq_b1': 1., # FLL NBW + 'carr_to_code': 1540. # carr_to_code +} l2c_loop_filter_params_template = { - 'code_params': (1., 0.7, 1.), # NBW, zeta, k - 'carr_params': (20., 0.7, 1.), # NBW, zeta, k - 'loop_freq': 1000., # 1000/coherent_ms - 'carr_freq_b1': 1., # FLL NBW - 'carr_to_code': 1200. # carr_to_code - } + 'code_params': (1., 0.7, 1.), # NBW, zeta, k + 'carr_params': (20., 0.7, 1.), # NBW, zeta, k + 'loop_freq': 1000., # 1000/coherent_ms + 'carr_freq_b1': 1., # FLL NBW + 'carr_to_code': 1200. # carr_to_code +} glol1_loop_filter_params_template = { - 'code_params': (1., 0.7, 1.), # NBW, zeta, k - 'carr_params': (20., 0.7, 1.), # NBW, zeta, k - 'loop_freq': 1000., # 1000/coherent_ms - 'carr_freq_b1': 1., # FLL NBW - 'carr_to_code': 3135.0293542074364 # carr_to_code - } + 'code_params': (1., 0.7, 1.), # NBW, zeta, k + 'carr_params': (20., 0.7, 1.), # NBW, zeta, k + 'loop_freq': 1000., # 1000/coherent_ms + 'carr_freq_b1': 1., # FLL NBW + 'carr_to_code': 3135.0293542074364 # carr_to_code +} # Tracking stages. See track.c for more details. # 1;20 ms stages @@ -386,868 +386,868 @@ PREPARE_BIT_COMPENSATION = 11 glo_fsm_states = \ - { '1ms': - { 'no_bit_sync': - { 'short_n_long': - { 0: (511, 1, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, GET_CORR_1, ALIAS_DETECT_1ST)}), - 1: (511, 0, {'pre': (APPLY_CORR_2,), - 'post': (RUN_LD, GET_CORR_2, ALIAS_DETECT_2ND)}) }, - - 'ideal': - { 0: (511, 1, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, GET_CORR_1, ALIAS_DETECT_1ST)}), - 1: (511, 0, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, GET_CORR_1, ALIAS_DETECT_2ND)}) } + {'1ms': + {'no_bit_sync': + {'short_n_long': + {0: (511, 1, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, GET_CORR_1, ALIAS_DETECT_1ST)}), + 1: (511, 0, {'pre': (APPLY_CORR_2,), + 'post': (RUN_LD, GET_CORR_2, ALIAS_DETECT_2ND)})}, + + 'ideal': + {0: (511, 1, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, GET_CORR_1, ALIAS_DETECT_1ST)}), + 1: (511, 0, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, GET_CORR_1, ALIAS_DETECT_2ND)})} + } } - } - } + } gps_fsm_states = \ - { '1ms': - { 'no_bit_sync': - { 'short_n_long': - { 0: (1023, 1, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, GET_CORR_1, ALIAS_DETECT_1ST)}), - 1: (1023, 0, {'pre': (APPLY_CORR_2,), - 'post': (RUN_LD, GET_CORR_2, ALIAS_DETECT_2ND)}) }, - - 'ideal': - { 0: (1023, 1, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, GET_CORR_1, ALIAS_DETECT_1ST)}), - 1: (1023, 0, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, GET_CORR_1, ALIAS_DETECT_2ND)}) } - }, + {'1ms': + {'no_bit_sync': + {'short_n_long': + {0: (1023, 1, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, GET_CORR_1, ALIAS_DETECT_1ST)}), + 1: (1023, 0, {'pre': (APPLY_CORR_2,), + 'post': (RUN_LD, GET_CORR_2, ALIAS_DETECT_2ND)})}, + + 'ideal': + {0: (1023, 1, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, GET_CORR_1, ALIAS_DETECT_1ST)}), + 1: (1023, 0, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, GET_CORR_1, ALIAS_DETECT_2ND)})} + }, 'bit_sync': - { 'short_n_long': - { 0: (1023, 1, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_1ST, GET_CORR_1) }), - 1: (1023, 2, {'pre': (APPLY_CORR_2,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_2) }), - 2: (1023, 3, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), - 3: (1023, 4, {'pre': (APPLY_CORR_2,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_2) }), - 4: (1023, 5, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), - 5: (1023, 6, {'pre': (APPLY_CORR_2,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_2) }), - 6: (1023, 7, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), - 7: (1023, 8, {'pre': (APPLY_CORR_2,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_2) }), - 8: (1023, 9, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), - 9: (1023, 10, {'pre': (APPLY_CORR_2,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_2) }), - 10: (1023, 11, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), - 11: (1023, 12, {'pre': (APPLY_CORR_2,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_2) }), - 12: (1023, 13, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), - 13: (1023, 14, {'pre': (APPLY_CORR_2,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_2) }), - 14: (1023, 15, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), - 15: (1023, 16, {'pre': (APPLY_CORR_2,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_2) }), - 16: (1023, 17, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), - 17: (1023, 18, {'pre': (APPLY_CORR_2,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_2) }), - 18: (1023, 19, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), - 19: (1023, 0, {'pre': (APPLY_CORR_2,), - 'post': (RUN_LD, ALIAS_DETECT_2ND, GET_CORR_2) }) }, - 'ideal': - { 0: (1023, 1, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_1ST, GET_CORR_1) }), - 1: (1023, 2, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), - 2: (1023, 3, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), - 3: (1023, 4, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), - 4: (1023, 5, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), - 5: (1023, 6, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), - 6: (1023, 7, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), - 7: (1023, 8, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), - 8: (1023, 9, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), - 9: (1023, 10, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), - 10: (1023, 11, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), - 11: (1023, 12, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), - 12: (1023, 13, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), - 13: (1023, 14, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), - 14: (1023, 15, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), - 15: (1023, 16, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), - 16: (1023, 17, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), - 17: (1023, 18, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), - 18: (1023, 19, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), - 19: (1023, 0, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_2ND, GET_CORR_1) }) }, - } + {'short_n_long': + {0: (1023, 1, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_1ST, GET_CORR_1)}), + 1: (1023, 2, {'pre': (APPLY_CORR_2,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_2)}), + 2: (1023, 3, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1)}), + 3: (1023, 4, {'pre': (APPLY_CORR_2,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_2)}), + 4: (1023, 5, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1)}), + 5: (1023, 6, {'pre': (APPLY_CORR_2,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_2)}), + 6: (1023, 7, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1)}), + 7: (1023, 8, {'pre': (APPLY_CORR_2,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_2)}), + 8: (1023, 9, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1)}), + 9: (1023, 10, {'pre': (APPLY_CORR_2,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_2)}), + 10: (1023, 11, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1)}), + 11: (1023, 12, {'pre': (APPLY_CORR_2,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_2)}), + 12: (1023, 13, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1)}), + 13: (1023, 14, {'pre': (APPLY_CORR_2,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_2)}), + 14: (1023, 15, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1)}), + 15: (1023, 16, {'pre': (APPLY_CORR_2,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_2)}), + 16: (1023, 17, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1)}), + 17: (1023, 18, {'pre': (APPLY_CORR_2,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_2)}), + 18: (1023, 19, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1)}), + 19: (1023, 0, {'pre': (APPLY_CORR_2,), + 'post': (RUN_LD, ALIAS_DETECT_2ND, GET_CORR_2)})}, + 'ideal': + {0: (1023, 1, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_1ST, GET_CORR_1)}), + 1: (1023, 2, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1)}), + 2: (1023, 3, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1)}), + 3: (1023, 4, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1)}), + 4: (1023, 5, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1)}), + 5: (1023, 6, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1)}), + 6: (1023, 7, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1)}), + 7: (1023, 8, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1)}), + 8: (1023, 9, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1)}), + 9: (1023, 10, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1)}), + 10: (1023, 11, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1)}), + 11: (1023, 12, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1)}), + 12: (1023, 13, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1)}), + 13: (1023, 14, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1)}), + 14: (1023, 15, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1)}), + 15: (1023, 16, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1)}), + 16: (1023, 17, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1)}), + 17: (1023, 18, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1)}), + 18: (1023, 19, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1)}), + 19: (1023, 0, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_2ND, GET_CORR_1)})}, + } }, - '2ms': - { 'bit_sync': - { 'short_n_long': - { 0: (1023, 1, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_1ST) }), - 1: (1023, 2, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), - 2: (1023, 3, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 3: (1023, 4, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), - 4: (1023, 5, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 5: (1023, 6, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), - 6: (1023, 7, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 7: (1023, 8, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), - 8: (1023, 9, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 9: (1023, 10, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), - 10: (1023, 11, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 11: (1023, 12, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), - 12: (1023, 13, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 13: (1023, 14, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), - 14: (1023, 15, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 15: (1023, 16, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), - 16: (1023, 17, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 17: (1023, 18, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), - 18: (1023, 19, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 19: (1023, 0, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_2ND, GET_CORR_1) }) }, - 'ideal': - { 0: (1023, 1, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_1ST) }), - 1: (1023, 2, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), - 2: (1023, 3, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 3: (1023, 4, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), - 4: (1023, 5, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 5: (1023, 6, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), - 6: (1023, 7, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 7: (1023, 8, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), - 8: (1023, 9, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 9: (1023, 10, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), - 10: (1023, 11, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 11: (1023, 12, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), - 12: (1023, 13, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 13: (1023, 14, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), - 14: (1023, 15, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 15: (1023, 16, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), - 16: (1023, 17, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 17: (1023, 18, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), - 18: (1023, 19, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 19: (1023, 0, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_2ND, GET_CORR_1) }) }, - } + '2ms': + {'bit_sync': + {'short_n_long': + {0: (1023, 1, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_1ST)}), + 1: (1023, 2, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1)}), + 2: (1023, 3, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 3: (1023, 4, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1)}), + 4: (1023, 5, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 5: (1023, 6, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1)}), + 6: (1023, 7, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 7: (1023, 8, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1)}), + 8: (1023, 9, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 9: (1023, 10, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1)}), + 10: (1023, 11, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 11: (1023, 12, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1)}), + 12: (1023, 13, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 13: (1023, 14, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1)}), + 14: (1023, 15, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 15: (1023, 16, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1)}), + 16: (1023, 17, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 17: (1023, 18, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1)}), + 18: (1023, 19, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 19: (1023, 0, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_2ND, GET_CORR_1)})}, + 'ideal': + {0: (1023, 1, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_1ST)}), + 1: (1023, 2, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1)}), + 2: (1023, 3, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 3: (1023, 4, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1)}), + 4: (1023, 5, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 5: (1023, 6, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1)}), + 6: (1023, 7, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 7: (1023, 8, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1)}), + 8: (1023, 9, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 9: (1023, 10, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1)}), + 10: (1023, 11, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 11: (1023, 12, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1)}), + 12: (1023, 13, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 13: (1023, 14, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1)}), + 14: (1023, 15, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 15: (1023, 16, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1)}), + 16: (1023, 17, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 17: (1023, 18, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1)}), + 18: (1023, 19, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 19: (1023, 0, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_2ND, GET_CORR_1)})}, + } }, - '4ms': - { 'bit_sync': - { 'short_n_long': - { 0: (1023, 1, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_1ST) }), - 1: (1023, 2, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 2: (1023, 3, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 3: (1023, 4, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), - 4: (1023, 5, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 5: (1023, 6, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 6: (1023, 7, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 7: (1023, 8, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), - 8: (1023, 9, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 9: (1023, 10, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 10: (1023, 11, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 11: (1023, 12, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), - 12: (1023, 13, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 13: (1023, 14, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 14: (1023, 15, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 15: (1023, 16, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), - 16: (1023, 17, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 17: (1023, 18, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 18: (1023, 19, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 19: (1023, 0, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_2ND, GET_CORR_1) }) }, - 'ideal': - { 0: (1023, 1, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_1ST) }), - 1: (1023, 2, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 2: (1023, 3, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 3: (1023, 4, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), - 4: (1023, 5, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 5: (1023, 6, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 6: (1023, 7, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 7: (1023, 8, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), - 8: (1023, 9, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 9: (1023, 10, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 10: (1023, 11, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 11: (1023, 12, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), - 12: (1023, 13, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 13: (1023, 14, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 14: (1023, 15, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 15: (1023, 16, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), - 16: (1023, 17, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 17: (1023, 18, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 18: (1023, 19, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 19: (1023, 0, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_2ND, GET_CORR_1) }) }, - } + '4ms': + {'bit_sync': + {'short_n_long': + {0: (1023, 1, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_1ST)}), + 1: (1023, 2, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 2: (1023, 3, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 3: (1023, 4, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1)}), + 4: (1023, 5, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 5: (1023, 6, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 6: (1023, 7, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 7: (1023, 8, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1)}), + 8: (1023, 9, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 9: (1023, 10, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 10: (1023, 11, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 11: (1023, 12, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1)}), + 12: (1023, 13, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 13: (1023, 14, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 14: (1023, 15, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 15: (1023, 16, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1)}), + 16: (1023, 17, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 17: (1023, 18, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 18: (1023, 19, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 19: (1023, 0, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_2ND, GET_CORR_1)})}, + 'ideal': + {0: (1023, 1, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_1ST)}), + 1: (1023, 2, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 2: (1023, 3, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 3: (1023, 4, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1)}), + 4: (1023, 5, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 5: (1023, 6, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 6: (1023, 7, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 7: (1023, 8, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1)}), + 8: (1023, 9, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 9: (1023, 10, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 10: (1023, 11, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 11: (1023, 12, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1)}), + 12: (1023, 13, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 13: (1023, 14, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 14: (1023, 15, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 15: (1023, 16, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1)}), + 16: (1023, 17, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 17: (1023, 18, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 18: (1023, 19, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 19: (1023, 0, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_2ND, GET_CORR_1)})}, + } }, - '5ms': - { 'bit_sync': - { 'short_n_long': - { 0: (1023, 1, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_1ST) }), - 1: (1023, 2, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 2: (1023, 3, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 3: (1023, 4, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 4: (1023, 5, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), - 5: (1023, 6, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 6: (1023, 7, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 7: (1023, 8, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 8: (1023, 9, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 9: (1023, 10, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), - 10: (1023, 11, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 11: (1023, 12, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 12: (1023, 13, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 13: (1023, 14, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 14: (1023, 15, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), - 15: (1023, 16, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 16: (1023, 17, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 17: (1023, 18, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 18: (1023, 19, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 19: (1023, 0, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_2ND, GET_CORR_1) }) }, - 'ideal': - { 0: (1023, 1, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_1ST) }), - 1: (1023, 2, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 2: (1023, 3, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 3: (1023, 4, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 4: (1023, 5, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), - 5: (1023, 6, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 6: (1023, 7, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 7: (1023, 8, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 8: (1023, 9, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 9: (1023, 10, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), - 10: (1023, 11, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 11: (1023, 12, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 12: (1023, 13, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 13: (1023, 14, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 14: (1023, 15, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), - 15: (1023, 16, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 16: (1023, 17, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 17: (1023, 18, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 18: (1023, 19, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 19: (1023, 0, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_2ND, GET_CORR_1) }) }, - } + '5ms': + {'bit_sync': + {'short_n_long': + {0: (1023, 1, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_1ST)}), + 1: (1023, 2, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 2: (1023, 3, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 3: (1023, 4, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 4: (1023, 5, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1)}), + 5: (1023, 6, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 6: (1023, 7, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 7: (1023, 8, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 8: (1023, 9, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 9: (1023, 10, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1)}), + 10: (1023, 11, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 11: (1023, 12, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 12: (1023, 13, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 13: (1023, 14, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 14: (1023, 15, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1)}), + 15: (1023, 16, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 16: (1023, 17, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 17: (1023, 18, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 18: (1023, 19, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 19: (1023, 0, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_2ND, GET_CORR_1)})}, + 'ideal': + {0: (1023, 1, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_1ST)}), + 1: (1023, 2, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 2: (1023, 3, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 3: (1023, 4, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 4: (1023, 5, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1)}), + 5: (1023, 6, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 6: (1023, 7, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 7: (1023, 8, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 8: (1023, 9, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 9: (1023, 10, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1)}), + 10: (1023, 11, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 11: (1023, 12, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 12: (1023, 13, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 13: (1023, 14, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 14: (1023, 15, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1)}), + 15: (1023, 16, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 16: (1023, 17, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 17: (1023, 18, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 18: (1023, 19, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 19: (1023, 0, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_2ND, GET_CORR_1)})}, + } }, - '10ms': - { 'bit_sync': - { 'short_n_long': - { 0: (1023, 1, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_1ST) }), - 1: (1023, 2, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 2: (1023, 3, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 3: (1023, 4, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 4: (1023, 5, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 5: (1023, 6, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 6: (1023, 7, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 7: (1023, 8, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 8: (1023, 9, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 9: (1023, 10, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), - 10: (1023, 11, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 11: (1023, 12, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 12: (1023, 13, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 13: (1023, 14, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 14: (1023, 15, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 15: (1023, 16, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 16: (1023, 17, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 17: (1023, 18, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 18: (1023, 19, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 19: (1023, 0, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_2ND, GET_CORR_1) }) }, - 'ideal': - { 0: (1023, 1, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_1ST) }), - 1: (1023, 2, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 2: (1023, 3, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 3: (1023, 4, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 4: (1023, 5, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 5: (1023, 6, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 6: (1023, 7, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 7: (1023, 8, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 8: (1023, 9, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 9: (1023, 10, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1) }), - 10: (1023, 11, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 11: (1023, 12, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 12: (1023, 13, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 13: (1023, 14, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 14: (1023, 15, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 15: (1023, 16, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 16: (1023, 17, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 17: (1023, 18, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 18: (1023, 19, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH) }), - 19: (1023, 0, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_2ND, GET_CORR_1) }) }, - } + '10ms': + {'bit_sync': + {'short_n_long': + {0: (1023, 1, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_1ST)}), + 1: (1023, 2, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 2: (1023, 3, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 3: (1023, 4, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 4: (1023, 5, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 5: (1023, 6, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 6: (1023, 7, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 7: (1023, 8, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 8: (1023, 9, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 9: (1023, 10, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1)}), + 10: (1023, 11, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 11: (1023, 12, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 12: (1023, 13, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 13: (1023, 14, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 14: (1023, 15, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 15: (1023, 16, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 16: (1023, 17, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 17: (1023, 18, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 18: (1023, 19, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 19: (1023, 0, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_2ND, GET_CORR_1)})}, + 'ideal': + {0: (1023, 1, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_1ST)}), + 1: (1023, 2, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 2: (1023, 3, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 3: (1023, 4, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 4: (1023, 5, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 5: (1023, 6, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 6: (1023, 7, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 7: (1023, 8, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 8: (1023, 9, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 9: (1023, 10, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH, GET_CORR_1)}), + 10: (1023, 11, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 11: (1023, 12, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 12: (1023, 13, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 13: (1023, 14, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 14: (1023, 15, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 15: (1023, 16, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 16: (1023, 17, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 17: (1023, 18, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 18: (1023, 19, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH)}), + 19: (1023, 0, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_2ND, GET_CORR_1)})}, + } }, - '20ms': - { 'bit_sync': - { 'short_n_long': - { 0: (1023, 1, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_1ST,) }), - 1: (1023, 2, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 2: (1023, 3, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 3: (1023, 4, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 4: (1023, 5, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 5: (1023, 6, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 6: (1023, 7, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 7: (1023, 8, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 8: (1023, 9, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 9: (1023, 10, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 10: (1023, 11, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 11: (1023, 12, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 12: (1023, 13, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 13: (1023, 14, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 14: (1023, 15, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 15: (1023, 16, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 16: (1023, 17, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 17: (1023, 18, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 18: (1023, 19, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 19: (1023, 0, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_2ND, GET_CORR_1) }) }, - 'ideal': - { 0: (1023, 1, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_1ST,) }), - 1: (1023, 2, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 2: (1023, 3, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 3: (1023, 4, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 4: (1023, 5, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 5: (1023, 6, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 6: (1023, 7, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 7: (1023, 8, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 8: (1023, 9, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 9: (1023, 10, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 10: (1023, 11, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 11: (1023, 12, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 12: (1023, 13, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 13: (1023, 14, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 14: (1023, 15, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 15: (1023, 16, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 16: (1023, 17, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 17: (1023, 18, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 18: (1023, 19, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 19: (1023, 0, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_2ND, GET_CORR_1) }) }, - } + '20ms': + {'bit_sync': + {'short_n_long': + {0: (1023, 1, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_1ST,)}), + 1: (1023, 2, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 2: (1023, 3, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 3: (1023, 4, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 4: (1023, 5, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 5: (1023, 6, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 6: (1023, 7, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 7: (1023, 8, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 8: (1023, 9, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 9: (1023, 10, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 10: (1023, 11, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 11: (1023, 12, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 12: (1023, 13, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 13: (1023, 14, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 14: (1023, 15, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 15: (1023, 16, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 16: (1023, 17, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 17: (1023, 18, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 18: (1023, 19, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 19: (1023, 0, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_2ND, GET_CORR_1)})}, + 'ideal': + {0: (1023, 1, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_1ST,)}), + 1: (1023, 2, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 2: (1023, 3, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 3: (1023, 4, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 4: (1023, 5, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 5: (1023, 6, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 6: (1023, 7, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 7: (1023, 8, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 8: (1023, 9, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 9: (1023, 10, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 10: (1023, 11, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 11: (1023, 12, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 12: (1023, 13, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 13: (1023, 14, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 14: (1023, 15, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 15: (1023, 16, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 16: (1023, 17, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 17: (1023, 18, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 18: (1023, 19, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 19: (1023, 0, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_2ND, GET_CORR_1)})}, + } }, - '40ms': - { 'bit_sync': - { 'short_n_long': - { 0: (1023, 1, {'pre': (PREPARE_BIT_COMPENSATION,), - 'post': (RUN_LD, ALIAS_DETECT_1ST,) }), - 1: (1023, 2, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 2: (1023, 3, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 3: (1023, 4, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 4: (1023, 5, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 5: (1023, 6, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 6: (1023, 7, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 7: (1023, 8, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 8: (1023, 9, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 9: (1023, 10, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 10: (1023, 11, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 11: (1023, 12, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 12: (1023, 13, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 13: (1023, 14, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 14: (1023, 15, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 15: (1023, 16, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 16: (1023, 17, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 17: (1023, 18, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 18: (1023, 19, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_2ND,) }), - 19: (1023, 20, {'pre': (), - 'post': (RUN_LD, - ALIAS_DETECT_1ST, - COMPENSATE_BIT_POLARITY) }), - 20: (1023, 21, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 21: (1023, 22, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 22: (1023, 23, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 23: (1023, 24, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 24: (1023, 25, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 25: (1023, 26, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 26: (1023, 27, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 27: (1023, 28, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 28: (1023, 29, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 29: (1023, 30, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 30: (1023, 31, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 31: (1023, 32, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 32: (1023, 33, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 33: (1023, 34, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 34: (1023, 35, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 35: (1023, 36, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 36: (1023, 37, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 37: (1023, 38, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 38: (1023, 39, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 39: (1023, 0, {'pre': (), - 'post': (RUN_LD, - ALIAS_DETECT_2ND, - GET_CORR_1, - COMPENSATE_BIT_POLARITY, - USE_COMPENSATED_BIT) }) }, - 'ideal': - { 0: (1023, 1, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_1ST,) }), - 1: (1023, 2, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 2: (1023, 3, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 3: (1023, 4, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 4: (1023, 5, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 5: (1023, 6, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 6: (1023, 7, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 7: (1023, 8, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 8: (1023, 9, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 9: (1023, 10, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 10: (1023, 11, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 11: (1023, 12, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 12: (1023, 13, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 13: (1023, 14, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 14: (1023, 15, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 15: (1023, 16, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 16: (1023, 17, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 17: (1023, 18, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 18: (1023, 19, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 19: (1023, 0, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_2ND, GET_CORR_1) }) }, - } + '40ms': + {'bit_sync': + {'short_n_long': + {0: (1023, 1, {'pre': (PREPARE_BIT_COMPENSATION,), + 'post': (RUN_LD, ALIAS_DETECT_1ST,)}), + 1: (1023, 2, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 2: (1023, 3, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 3: (1023, 4, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 4: (1023, 5, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 5: (1023, 6, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 6: (1023, 7, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 7: (1023, 8, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 8: (1023, 9, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 9: (1023, 10, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 10: (1023, 11, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 11: (1023, 12, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 12: (1023, 13, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 13: (1023, 14, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 14: (1023, 15, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 15: (1023, 16, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 16: (1023, 17, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 17: (1023, 18, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 18: (1023, 19, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_2ND,)}), + 19: (1023, 20, {'pre': (), + 'post': (RUN_LD, + ALIAS_DETECT_1ST, + COMPENSATE_BIT_POLARITY)}), + 20: (1023, 21, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 21: (1023, 22, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 22: (1023, 23, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 23: (1023, 24, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 24: (1023, 25, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 25: (1023, 26, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 26: (1023, 27, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 27: (1023, 28, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 28: (1023, 29, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 29: (1023, 30, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 30: (1023, 31, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 31: (1023, 32, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 32: (1023, 33, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 33: (1023, 34, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 34: (1023, 35, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 35: (1023, 36, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 36: (1023, 37, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 37: (1023, 38, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 38: (1023, 39, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 39: (1023, 0, {'pre': (), + 'post': (RUN_LD, + ALIAS_DETECT_2ND, + GET_CORR_1, + COMPENSATE_BIT_POLARITY, + USE_COMPENSATED_BIT)})}, + 'ideal': + {0: (1023, 1, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_1ST,)}), + 1: (1023, 2, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 2: (1023, 3, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 3: (1023, 4, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 4: (1023, 5, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 5: (1023, 6, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 6: (1023, 7, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 7: (1023, 8, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 8: (1023, 9, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 9: (1023, 10, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 10: (1023, 11, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 11: (1023, 12, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 12: (1023, 13, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 13: (1023, 14, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 14: (1023, 15, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 15: (1023, 16, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 16: (1023, 17, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 17: (1023, 18, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 18: (1023, 19, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 19: (1023, 0, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_2ND, GET_CORR_1)})}, + } }, - '80ms': - { 'bit_sync': - { 'short_n_long': - { 0: (1023, 1, {'pre': (PREPARE_BIT_COMPENSATION,), - 'post': (RUN_LD, ALIAS_DETECT_1ST,) }), - 1: (1023, 2, {'pre': (APPLY_CORR_1,), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 2: (1023, 3, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 3: (1023, 4, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 4: (1023, 5, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 5: (1023, 6, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 6: (1023, 7, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 7: (1023, 8, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 8: (1023, 9, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 9: (1023, 10, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 10: (1023, 11, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 11: (1023, 12, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 12: (1023, 13, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 13: (1023, 14, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 14: (1023, 15, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 15: (1023, 16, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 16: (1023, 17, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 17: (1023, 18, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 18: (1023, 19, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_2ND,) }), - 19: (1023, 20, {'pre': (), - 'post': (RUN_LD, - ALIAS_DETECT_1ST, - COMPENSATE_BIT_POLARITY) }), - 20: (1023, 21, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 21: (1023, 22, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 22: (1023, 23, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 23: (1023, 24, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 24: (1023, 25, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 25: (1023, 26, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 26: (1023, 27, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 27: (1023, 28, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 28: (1023, 29, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 29: (1023, 30, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 30: (1023, 31, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 31: (1023, 32, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 32: (1023, 33, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 33: (1023, 34, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 34: (1023, 35, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 35: (1023, 36, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 36: (1023, 37, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 37: (1023, 38, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 38: (1023, 39, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 39: (1023, 40, {'pre': (), - 'post': (RUN_LD, - ALIAS_DETECT_2ND, - COMPENSATE_BIT_POLARITY,) }), - 40: (1023, 41, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_1ST,) }), - 41: (1023, 42, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 42: (1023, 43, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 43: (1023, 44, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 44: (1023, 45, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 45: (1023, 46, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 46: (1023, 47, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 47: (1023, 48, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 48: (1023, 49, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 49: (1023, 50, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 50: (1023, 51, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 51: (1023, 52, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 52: (1023, 53, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 53: (1023, 54, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 54: (1023, 55, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 55: (1023, 56, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 56: (1023, 57, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 57: (1023, 58, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 58: (1023, 59, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_2ND,) }), - 59: (1023, 60, {'pre': (), - 'post': (RUN_LD, - ALIAS_DETECT_1ST, - COMPENSATE_BIT_POLARITY) }), - 60: (1023, 61, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 61: (1023, 62, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 62: (1023, 63, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 63: (1023, 64, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 64: (1023, 65, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 65: (1023, 66, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 66: (1023, 67, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 67: (1023, 68, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 68: (1023, 69, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 69: (1023, 70, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 70: (1023, 71, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 71: (1023, 72, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 72: (1023, 73, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 73: (1023, 74, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 74: (1023, 75, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 75: (1023, 76, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 76: (1023, 77, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 77: (1023, 78, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 78: (1023, 79, {'pre': (), - 'post': (RUN_LD, ALIAS_DETECT_BOTH,) }), - 79: (1023, 0, {'pre': (), - 'post': (RUN_LD, - ALIAS_DETECT_2ND, - GET_CORR_1, - COMPENSATE_BIT_POLARITY, - USE_COMPENSATED_BIT) }) }, - } + '80ms': + {'bit_sync': + {'short_n_long': + {0: (1023, 1, {'pre': (PREPARE_BIT_COMPENSATION,), + 'post': (RUN_LD, ALIAS_DETECT_1ST,)}), + 1: (1023, 2, {'pre': (APPLY_CORR_1,), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 2: (1023, 3, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 3: (1023, 4, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 4: (1023, 5, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 5: (1023, 6, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 6: (1023, 7, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 7: (1023, 8, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 8: (1023, 9, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 9: (1023, 10, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 10: (1023, 11, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 11: (1023, 12, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 12: (1023, 13, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 13: (1023, 14, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 14: (1023, 15, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 15: (1023, 16, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 16: (1023, 17, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 17: (1023, 18, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 18: (1023, 19, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_2ND,)}), + 19: (1023, 20, {'pre': (), + 'post': (RUN_LD, + ALIAS_DETECT_1ST, + COMPENSATE_BIT_POLARITY)}), + 20: (1023, 21, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 21: (1023, 22, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 22: (1023, 23, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 23: (1023, 24, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 24: (1023, 25, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 25: (1023, 26, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 26: (1023, 27, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 27: (1023, 28, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 28: (1023, 29, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 29: (1023, 30, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 30: (1023, 31, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 31: (1023, 32, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 32: (1023, 33, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 33: (1023, 34, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 34: (1023, 35, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 35: (1023, 36, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 36: (1023, 37, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 37: (1023, 38, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 38: (1023, 39, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 39: (1023, 40, {'pre': (), + 'post': (RUN_LD, + ALIAS_DETECT_2ND, + COMPENSATE_BIT_POLARITY,)}), + 40: (1023, 41, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_1ST,)}), + 41: (1023, 42, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 42: (1023, 43, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 43: (1023, 44, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 44: (1023, 45, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 45: (1023, 46, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 46: (1023, 47, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 47: (1023, 48, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 48: (1023, 49, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 49: (1023, 50, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 50: (1023, 51, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 51: (1023, 52, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 52: (1023, 53, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 53: (1023, 54, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 54: (1023, 55, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 55: (1023, 56, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 56: (1023, 57, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 57: (1023, 58, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 58: (1023, 59, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_2ND,)}), + 59: (1023, 60, {'pre': (), + 'post': (RUN_LD, + ALIAS_DETECT_1ST, + COMPENSATE_BIT_POLARITY)}), + 60: (1023, 61, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 61: (1023, 62, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 62: (1023, 63, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 63: (1023, 64, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 64: (1023, 65, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 65: (1023, 66, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 66: (1023, 67, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 67: (1023, 68, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 68: (1023, 69, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 69: (1023, 70, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 70: (1023, 71, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 71: (1023, 72, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 72: (1023, 73, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 73: (1023, 74, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 74: (1023, 75, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 75: (1023, 76, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 76: (1023, 77, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 77: (1023, 78, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 78: (1023, 79, {'pre': (), + 'post': (RUN_LD, ALIAS_DETECT_BOTH,)}), + 79: (1023, 0, {'pre': (), + 'post': (RUN_LD, + ALIAS_DETECT_2ND, + GET_CORR_1, + COMPENSATE_BIT_POLARITY, + USE_COMPENSATED_BIT)})}, + } } - } + } # pessimistic set l1ca_lock_detect_params_pess = {"k1": 0.10, "k2": 1.4, "lp": 200, "lo": 50} @@ -1266,14 +1266,14 @@ lock_detect_params_slow = {"k1": 0.005, "k2": 1.4, "lp": 200, "lo": 50} lock_detect_params_fast = ( - (40, {"k1": 0.2, "k2": .80, "lp": 50, "lo": 50}), - (35, {"k1": 0.2, "k2": .83, "lp": 50, "lo": 50}), - (30, {"k1": 0.2, "k2": .86, "lp": 50, "lo": 50}), - (25, {"k1": 0.2, "k2": .89, "lp": 50, "lo": 50}), - (20, {"k1": 0.2, "k2": .92, "lp": 50, "lo": 50}), - (15, {"k1": 0.2, "k2": .95, "lp": 50, "lo": 50}), - (10, {"k1": 0.2, "k2": .98, "lp": 50, "lo": 50}), - ( 5, {"k1": 0.2, "k2": 1.0, "lp": 50, "lo": 50}) ) + (40, {"k1": 0.2, "k2": .80, "lp": 50, "lo": 50}), + (35, {"k1": 0.2, "k2": .83, "lp": 50, "lo": 50}), + (30, {"k1": 0.2, "k2": .86, "lp": 50, "lo": 50}), + (25, {"k1": 0.2, "k2": .89, "lp": 50, "lo": 50}), + (20, {"k1": 0.2, "k2": .92, "lp": 50, "lo": 50}), + (15, {"k1": 0.2, "k2": .95, "lp": 50, "lo": 50}), + (10, {"k1": 0.2, "k2": .98, "lp": 50, "lo": 50}), + (5, {"k1": 0.2, "k2": 1.0, "lp": 50, "lo": 50})) tracking_loop_stabilization_time_ms = 50 diff --git a/peregrine/lock_detect.py b/peregrine/lock_detect.py index 582b9af..7bd5eaa 100644 --- a/peregrine/lock_detect.py +++ b/peregrine/lock_detect.py @@ -15,40 +15,104 @@ class LockDetector(object): """ - Wraps the `libswiftnav` PLL lock detector implementation. - - The detector state, :libswiftnav:`lock_detect_t` is maintained by - the class instance. + PLL lock detector implementation. """ def __init__(self, **kwargs): + """ + Initialize the lock detector parameters + + Parameters + ---------- + params : dictionary + k1 - 1st order IIR I & Q filter parameter + k2 - filtered in-phase divider + lp - pessimistic lock threshold + lo - optimistic lock threshold + + """ + self.lpfi = 0 self.lpfq = 0 self.outo = False self.outp = False self.pcount1 = 0 self.pcount2 = 0 - self.reinit( kwargs['k1'], - kwargs['k2'], - kwargs['lp'], - kwargs['lo']) + self.reinit(kwargs['k1'], + kwargs['k2'], + kwargs['lp'], + kwargs['lo']) def reinit(self, k1, k2, lp, lo): - # Adjust LPF coefficient + """ + Adjust low-pass filter (LPF) coefficients + + Parameters + ---------- + params : dictionary + k1 - 1st order IIR I & Q filter parameter + k2 - filtered in-phase divider + lp - pessimistic lock threshold + lo - optimistic lock threshold + + """ + self.k1 = k1 self.k2 = k2 self.lp = lp self.lo = lo - def lpf_update(self, y, x): + def _lpf_update(self, y, x): + """ + Low-pass filter (LPF) state update. + + Parameters + ---------- + y : float + old state + x : float + new input + lo - optimistic lock threshold + + Returns + ------- + out : float + Filtered output + + """ + y += self.k1 * (x - y) return y def update(self, I, Q, DT): + """ + Lock detector update. + + Parameters + ---------- + I : int + Prompt in-phase correlator output + Q : int + Prompt quadrature correlator output + DT : float + Time difference since the last update [ms] + + Returns + ------- + out : tuple + outo - optimistic lock detector output + outp - pessimistic lock detector output + pcount1 - the counter compared against the pessimistic lock threshold + pcount2 - the counter compared against the optimistic lock threshold + lpfi - filtered in-phase prompt correlator output + lpfq - filtered quadrature prompt correlator output + + """ + # Calculated low-pass filtered prompt correlations - self.lpfi = self.lpf_update(self.lpfi, np.absolute(I) / DT) - self.lpfq = self.lpf_update(self.lpfq, np.absolute(Q) / DT) + self.lpfi = self._lpf_update(self.lpfi, np.absolute(I) / DT) + self.lpfq = self._lpf_update(self.lpfq, np.absolute(Q) / DT) a = self.lpfi / self.k2 b = self.lpfq @@ -71,6 +135,6 @@ def update(self, I, Q, DT): else: self.pcount2 += 1 - return (self.outo, self.outp, \ - self.pcount1, self.pcount2,\ + return (self.outo, self.outp, + self.pcount1, self.pcount2, self.lpfi, self.lpfq) diff --git a/peregrine/run.py b/peregrine/run.py index d9248a9..9a9e864 100755 --- a/peregrine/run.py +++ b/peregrine/run.py @@ -139,9 +139,9 @@ def populate_peregrine_cmd_line_arguments(parser): 'FPGA delay control simulation') fpgaSim.add_argument("--short-long-cycles", - help="Use FPGA short-long cycle simulation.", - default=False, - action="store_true") + help="Use FPGA short-long cycle simulation.", + default=False, + action="store_true") signalParam = parser.add_argument_group('Signal tracking', 'Parameters for satellite vehicle' diff --git a/peregrine/tracking.py b/peregrine/tracking.py index 6dd66c6..b9f6bc4 100644 --- a/peregrine/tracking.py +++ b/peregrine/tracking.py @@ -128,7 +128,32 @@ def _tracking_channel_factory(parameters): if parameters['acq'].signal == glo_constants.GLO_L1: return TrackingChannelGLOL1(parameters) + def get_fsm_states(fsm_states, ms, short_n_long, bit_sync): + """ + Tracking loop FSM operation table getter. + The right FSM operation table is chosen based on the + set of input parameters. + + Parameters + ---------- + fsm_states : dictionary + Contains FSM operation tables for different modes + ms : integer + The integration time [ms] + short_n_long : Boolean + FPGA operation simulation flag. True - the simulation + is requested. + bit_sync : Boolean + Tells if bit sync is acquired. + + Returns + ------- + out : dictionary + The relevant tracking loop FSM operation table + + """ + if ms == 1: ms = '1ms' elif ms == 2: @@ -162,6 +187,25 @@ def get_fsm_states(fsm_states, ms, short_n_long, bit_sync): def get_lock_detector(cur_bw, lock_detect_set): + """ + Selects the relevant lock detector parameter set. + The selection is done based on the current PLL bandwidth. + + Parameters + ---------- + cur_bw : float + The current PLL bandwidth + lock_detect_set : tuple + The combination of PLL bandwidth and its lock detector + parameters set + + Returns + ------- + out : dictionary + The relevant lock detector parameters set + + """ + for bw, params in lock_detect_set: if cur_bw < bw: continue @@ -220,7 +264,9 @@ def __init__(self, params): loop_filter_params = self.loop_filter_params_template carr_params = loop_filter_params['carr_params'] - loop_filter_params['carr_params'] = (pll_bw, carr_params[1], carr_params[2]) + loop_filter_params['carr_params'] = (pll_bw, + carr_params[1], + carr_params[2]) loop_filter_params['loop_freq'] = 1000 / coherent_ms loop_filter_params['carr_freq_b1'] = fll_bw @@ -260,7 +306,7 @@ def __init__(self, params): pll_bw = carr_params[0] lock_detect_params_fast = get_lock_detector(pll_bw, - defaults.lock_detect_params_fast) + defaults.lock_detect_params_fast) self.lock_detect_fast = lock_detect.LockDetector( k1=lock_detect_params_fast["k1"], @@ -284,22 +330,22 @@ def __init__(self, params): self.loop_filter = self.loop_filter_class( loop_freq=loop_filter_params['loop_freq'], code_freq=0, - code_bw=code_params[0], # code_bw' - code_zeta=code_params[1], # code_zeta - code_k=code_params[2], # code_k + code_bw=code_params[0], # code_bw' + code_zeta=code_params[1], # code_zeta + code_k=code_params[2], # code_k carr_to_code=loop_filter_params['carr_to_code'], carr_freq=self.acq.doppler * 2 * np.pi, - carr_bw=carr_params[0], # carr_bw, - carr_zeta=carr_params[1], # carr_zeta - carr_k=carr_params[2], # carr_k + carr_bw=carr_params[0], # carr_bw, + carr_zeta=carr_params[1], # carr_zeta + carr_k=carr_params[2], # carr_k carr_freq_b1=loop_filter_params['carr_freq_b1'], ) self.code_freq_1 = self.code_freq_2 = self.corr_code_freq = \ - params['code_freq_init'] + params['code_freq_init'] self.carr_freq_1 = self.carr_freq_2 = self.corr_carr_freq = \ - self.acq.doppler + self.acq.doppler self.track_result = TrackResults(self.results_num, self.acq.prn, @@ -373,15 +419,23 @@ def get_index(self): """ return self.sample_index - def _set_track_profile(self): + """ + Set the current track profile. + The current track profile determines the PLL BW, FLL BW and + the coherent integration time. + + """ + coherent_ms = self.track_params['coherent_ms'][self.coherent_ms_index] fll_bw = self.track_params['fll_bw'][self.fll_bw_index] pll_bw = self.track_params['pll_bw'][self.pll_bw_index] loop_filter_params = self.loop_filter_params_template carr_params = loop_filter_params['carr_params'] - loop_filter_params['carr_params'] = (pll_bw, carr_params[1], carr_params[2]) + loop_filter_params['carr_params'] = (pll_bw, + carr_params[1], + carr_params[2]) loop_filter_params['loop_freq'] = 1000 / coherent_ms loop_filter_params['carr_freq_b1'] = fll_bw @@ -395,19 +449,19 @@ def _set_track_profile(self): # (self.prn + 1, self.signal, self.coherent_ms, pll_bw, fll_bw)) lock_detect_params_fast = get_lock_detector(pll_bw, - defaults.lock_detect_params_fast) + defaults.lock_detect_params_fast) self.lock_detect_fast.reinit(k1=lock_detect_params_fast["k1"], - k2=lock_detect_params_fast["k2"], - lp=lock_detect_params_fast["lp"], - lo=lock_detect_params_fast["lo"]) + k2=lock_detect_params_fast["k2"], + lp=lock_detect_params_fast["lp"], + lo=lock_detect_params_fast["lo"]) self.loop_filter.retune(**loop_filter_params) self.cn0_est = CN0_Est_MM(bw=1e3 / self.coherent_ms, - cn0_0=self.track_result.cn0[self.i - 1], - cutoff_freq=10, - loop_freq=1e3 / self.coherent_ms) + cn0_0=self.track_result.cn0[self.i - 1], + cutoff_freq=10, + loop_freq=1e3 / self.coherent_ms) self.fsm_states = get_fsm_states(self.fsm_states_all, ms=self.coherent_ms, @@ -417,34 +471,52 @@ def _set_track_profile(self): self.track_profile_timer_ms = 0 self.track_settled = False - def _make_track_candidates(self): + """ + Create a list of track profile candidates. + The list content depends on the current track profile. + We are in the recovery stage, when this function is called. + See more details at + https://swiftnav.hackpad.com/High-sensitivity-tracking-FLL-PLL-profile-switching-design-HDpuFC1BygA + + """ + fll_bw_index = self.fll_bw_index if fll_bw_index == len(self.track_params['fll_bw']) - 1: coherent_ms_index = self.coherent_ms_index if coherent_ms_index < len(self.track_params['coherent_ms']) - 1: coherent_ms_index += 1 - candidate = { 'fll_bw_index': self.fll_bw_index, - 'pll_bw_index': self.pll_bw_index, - 'coherent_ms_index': coherent_ms_index } + candidate = {'fll_bw_index': self.fll_bw_index, + 'pll_bw_index': self.pll_bw_index, + 'coherent_ms_index': coherent_ms_index} self.track_candidates.append(candidate) pll_bw_index = self.pll_bw_index if pll_bw_index < len(self.track_params['pll_bw']) - 1: pll_bw_index += 1 - candidate = { 'fll_bw_index': self.fll_bw_index, - 'pll_bw_index': pll_bw_index, - 'coherent_ms_index': self.coherent_ms_index } + candidate = {'fll_bw_index': self.fll_bw_index, + 'pll_bw_index': pll_bw_index, + 'coherent_ms_index': self.coherent_ms_index} self.track_candidates.append(candidate) else: fll_bw_index += 1 - candidate = { 'fll_bw_index': fll_bw_index, - 'pll_bw_index': self.pll_bw_index, - 'coherent_ms_index': self.coherent_ms_index } + candidate = {'fll_bw_index': fll_bw_index, + 'pll_bw_index': self.pll_bw_index, + 'coherent_ms_index': self.coherent_ms_index} self.track_candidates.append(candidate) - def _filter_track_candidates(self): + """ + Filter the track candidate list. + The track candidate list is created by _make_track_candidate() + function. + + Returns + ------- + res: list + The filtered track profiles candidates list + """ + res = [] for candidate in self.track_candidates: pll_bw_index = candidate['pll_bw_index'] @@ -520,7 +592,7 @@ def _run_track_profile_selection(self): # the PLL phase acceleration indicator looks to be scrued if self.fll_bw_index != 0: dynamics = self.loop_filter.to_dict()['phase_acc'] / (2 * np.pi) - if dynamics > 30: # [hz/sec] + if dynamics > 30: # [hz/sec] self.dynamics_timer_ms = 0 self.dynamics_detected = True @@ -535,7 +607,7 @@ def _run_track_profile_selection(self): # wait for bit edge return - iq_ratio = np.absolute(self.lock_detect_slow_lpfi / \ + iq_ratio = np.absolute(self.lock_detect_slow_lpfi / self.lock_detect_slow_lpfq) if not self.track_settled: self.track_profile['iq_ratio'] = iq_ratio @@ -556,9 +628,9 @@ def _run_track_profile_selection(self): return final_profile = \ - self.fll_bw_index == len(self.track_params['fll_bw']) - 1 and \ - self.pll_bw_index == len(self.track_params['pll_bw']) - 1 and \ - self.coherent_ms_index == len(self.track_params['coherent_ms']) - 1 + self.fll_bw_index == len(self.track_params['fll_bw']) - 1 and \ + self.pll_bw_index == len(self.track_params['pll_bw']) - 1 and \ + self.coherent_ms_index == len(self.track_params['coherent_ms']) - 1 if final_profile: return @@ -582,7 +654,7 @@ def _run_track_profile_selection(self): history = {'fll_bw_index': self.fll_bw_index, 'pll_bw_index': self.pll_bw_index, 'coherent_ms_index': self.coherent_ms_index, - 'iq_ratio': self.track_profile['iq_ratio'] } + 'iq_ratio': self.track_profile['iq_ratio']} self.profiles_history.append(history) self.fll_bw_index = track_profile['fll_bw_index'] @@ -776,8 +848,8 @@ def run(self, samples): lock_detect_pcount2, \ self.lock_detect_lpfi, \ self.lock_detect_lpfq = self.lock_detect.update(self.P.real, - self.P.imag, - 1) + self.P.imag, + 1) # Update PLL fast lock detector self.lock_detect_fast_outo, \ self.lock_detect_fast_outp, \ @@ -785,8 +857,8 @@ def run(self, samples): lock_detect_fast_pcount2, \ self.lock_detect_fast_lpfi, \ self.lock_detect_fast_lpfq = self.lock_detect_fast.update(self.P.real, - self.P.imag, - 1) + self.P.imag, + 1) # Update PLL fast lock detector self.lock_detect_slow_outo, \ @@ -795,8 +867,8 @@ def run(self, samples): lock_detect_slow_pcount2, \ self.lock_detect_slow_lpfi, \ self.lock_detect_slow_lpfq = self.lock_detect_slow.update(self.P.real, - self.P.imag, - 1) + self.P.imag, + 1) if defaults.ALIAS_DETECT_1ST in flags_post or \ defaults.ALIAS_DETECT_BOTH in flags_post: @@ -817,20 +889,25 @@ def run(self, samples): not (defaults.GET_CORR_2 in flags_post): continue - phase_acc_hz_per_s = self.loop_filter.to_dict()['phase_acc'] / (2 * np.pi) + phase_acc_hz_per_s = \ + self.loop_filter.to_dict()['phase_acc'] / (2 * np.pi) self.track_result.dynamics[self.i] = phase_acc_hz_per_s self.track_result.dynamics_g[self.i] = \ - phase_acc_hz_per_s * constants.c / (self.carrier_freq * constants.g) + phase_acc_hz_per_s * constants.c / (self.carrier_freq * constants.g) # run tracking loop self.loop_filter.update(self.E, self.P, self.L) if defaults.GET_CORR_1 in flags_post: - self.code_freq_1 = self.loop_filter.to_dict()['code_freq'] / (2 * np.pi) - self.carr_freq_1 = self.loop_filter.to_dict()['carr_freq'] / (2 * np.pi) + self.code_freq_1 = \ + self.loop_filter.to_dict()['code_freq'] / (2 * np.pi) + self.carr_freq_1 = \ + self.loop_filter.to_dict()['carr_freq'] / (2 * np.pi) elif defaults.GET_CORR_2 in flags_post: - self.code_freq_2 = self.loop_filter.to_dict()['code_freq'] / (2 * np.pi) - self.carr_freq_2 = self.loop_filter.to_dict()['carr_freq'] / (2 * np.pi) + self.code_freq_2 = \ + self.loop_filter.to_dict()['code_freq'] / (2 * np.pi) + self.carr_freq_2 = \ + self.loop_filter.to_dict()['carr_freq'] / (2 * np.pi) self.track_result.coherent_ms[self.i] = self.coherent_ms @@ -872,25 +949,31 @@ def run(self, samples): self.track_result.L[self.i] = self.L self.track_result.cn0[self.i], \ - self.track_result.snr[self.i], \ - self.track_result.snr_db[self.i] = \ + self.track_result.snr[self.i], \ + self.track_result.snr_db[self.i] = \ self.cn0_est.update(self.P.real, self.P.imag) self.track_result.lock_detect_outo[self.i] = self.lock_detect_outo self.track_result.lock_detect_outp[self.i] = self.lock_detect_outp - self.track_result.lock_detect_fast_outo[self.i] = self.lock_detect_fast_outo - self.track_result.lock_detect_fast_outp[self.i] = self.lock_detect_fast_outp + self.track_result.lock_detect_fast_outo[self.i] = \ + self.lock_detect_fast_outo + self.track_result.lock_detect_fast_outp[self.i] = \ + self.lock_detect_fast_outp self.track_result.lock_detect_pcount1[self.i] = lock_detect_pcount1 self.track_result.lock_detect_pcount2[self.i] = lock_detect_pcount2 self.track_result.lock_detect_lpfi[self.i] = self.lock_detect_lpfi self.track_result.lock_detect_lpfq[self.i] = self.lock_detect_lpfq - self.track_result.lock_detect_fast_lpfi[self.i] = self.lock_detect_fast_lpfi - self.track_result.lock_detect_fast_lpfq[self.i] = self.lock_detect_fast_lpfq + self.track_result.lock_detect_fast_lpfi[self.i] = \ + self.lock_detect_fast_lpfi + self.track_result.lock_detect_fast_lpfq[self.i] = \ + self.lock_detect_fast_lpfq - self.track_result.lock_detect_slow_lpfi[self.i] = self.lock_detect_slow_lpfi - self.track_result.lock_detect_slow_lpfq[self.i] = self.lock_detect_slow_lpfq + self.track_result.lock_detect_slow_lpfi[self.i] = \ + self.lock_detect_slow_lpfi + self.track_result.lock_detect_slow_lpfq[self.i] = \ + self.lock_detect_slow_lpfq self.track_result.alias_detect_err_hz[self.i] = err_hz @@ -918,7 +1001,6 @@ def run(self, samples): self.E = self.P = self.L = 0.j - if self.i > 0: self.dump() @@ -1682,8 +1764,10 @@ def dump(self, output_file, size): f1.write("%s," % int(self.lock_detect_fast_outo[i])) f1.write("%s," % (self.lock_detect_lpfi[i] / self.lock_detect_lpfq[i])) - f1.write("%s," % (self.lock_detect_fast_lpfi[i] / self.lock_detect_fast_lpfq[i])) - f1.write("%s," % (self.lock_detect_slow_lpfi[i] / self.lock_detect_slow_lpfq[i])) + f1.write("%s," % (self.lock_detect_fast_lpfi[i] / + self.lock_detect_fast_lpfq[i])) + f1.write("%s," % (self.lock_detect_slow_lpfi[i] / + self.lock_detect_slow_lpfq[i])) f1.write("%s," % np.absolute(self.P[i].real / self.P[i].imag)) f1.write("%s," % self.iq_ratio_min[i]) diff --git a/peregrine/tracking_loop.py b/peregrine/tracking_loop.py index b4077fc..c6790d2 100644 --- a/peregrine/tracking_loop.py +++ b/peregrine/tracking_loop.py @@ -11,21 +11,72 @@ import numpy as np from peregrine.include.controlled_root import controlled_root + def costas_discriminator(I, Q): + """ + Costas discriminator implementation. + + Parameters + ---------- + I : Prompt correlator in-phase output + Q : Prompt correlator quadrature output + + Returns + ------- + out : float + Phase error [radians] + + """ + if I == 0: # Technically, it should be +/- 0.25, but then we'd have to keep track # of the previous sign do it right, so it's simple enough to just return # the average of 0.25 and -0.25 in the face of that ambiguity, so zero. return 0 - return np.arctan(Q / I)# / (2 * np.pi) + return np.arctan(Q / I) + def frequency_discriminator(I, Q, prev_I, prev_Q): + """ + FLL discriminator + + Parameters + ---------- + I : Current prompt correlator in-phase output + Q : Current prompt correlator quadrature output + prev_I : Previous prompt correlator in-phase output + prev_Q : Previous prompt correlator quadrature output + + Returns + ------- + out : float + Phase difference [radians] + + """ + dot = np.absolute(I * prev_I) + np.absolute(Q * prev_Q) cross = prev_I * Q - I * prev_Q - return np.arctan2(cross, dot)# / (2 * np.pi) + return np.arctan2(cross, dot) + def dll_discriminator(E, P, L): + """ + DLL discriminator + + Parameters + ---------- + E : Early correlator output + P : Prompt correlator output + L : Late correlator output + + Returns + ------- + out : float + Code phase error + + """ + E_mag = np.absolute(E) L_mag = np.absolute(L) if E_mag + L_mag == 0: @@ -33,6 +84,7 @@ def dll_discriminator(E, P, L): return 0.5 * (E_mag - L_mag) / (E_mag + L_mag) + class TrackingLoop3: """ Third order tracking loop initialization. @@ -43,6 +95,20 @@ class TrackingLoop3: """ def __init__(self, **kwargs): + """ + Tracking loop initialization. + + Parameters + ---------- + code_params : dictionary + carr_freq - Carrier frequency [rad/s] + code_freq - Code frequency [rad/s] + carr_freq_b1 - FLL BW + carr_bw - PLL BW + code_bw - DLL BW + carr_to_code - carrier to code scaling factor + + """ # Initial state self.carr_freq = kwargs['carr_freq'] self.code_freq = kwargs['code_freq'] @@ -56,13 +122,13 @@ def __init__(self, **kwargs): self.pll_bw = kwargs['carr_bw'] self.dll_bw = kwargs['code_bw'] - self.P_prev = 1+0j + self.P_prev = 1 + 0j - self.retune( (kwargs['code_bw'], kwargs['code_zeta'], kwargs['code_k']), - (kwargs['carr_bw'], kwargs['carr_zeta'], kwargs['carr_k']), - kwargs['loop_freq'], - kwargs['carr_freq_b1'], - kwargs['carr_to_code'] ) + self.retune((kwargs['code_bw'], kwargs['code_zeta'], kwargs['code_k']), + (kwargs['carr_bw'], kwargs['carr_zeta'], kwargs['carr_k']), + kwargs['loop_freq'], + kwargs['carr_freq_b1'], + kwargs['carr_to_code']) def retune(self, code_params, carr_params, loop_freq, carr_freq_b1, carr_to_code): """ @@ -120,7 +186,8 @@ def retune(self, code_params, carr_params, loop_freq, carr_freq_b1, carr_to_code def update(self, E, P, L): """ - Tracking loop update + Tracking loop update. + Based on the bilinear transform. Parameters ---------- @@ -142,11 +209,13 @@ def update(self, E, P, L): self.phase_err = costas_discriminator(P.real, P.imag) freq_error = 0 if self.freq_c1 != 0 and self.T != 0: - freq_error = frequency_discriminator(P.real, P.imag, self.P_prev.real, self.P_prev.imag) / self.T + freq_error = frequency_discriminator( + P.real, P.imag, self.P_prev.real, self.P_prev.imag) / self.T self.P_prev = P prev = self.phase_acc - self.phase_acc += freq_error * self.freq_c2 * self.T + self.phase_err * self.phase_c3 * self.T + self.phase_acc += freq_error * self.freq_c2 * \ + self.T + self.phase_err * self.phase_c3 * self.T sum = (self.phase_acc + prev) * 0.5 sum += freq_error * self.freq_c1 + self.phase_err * self.phase_c2 @@ -175,8 +244,8 @@ def adjust_freq(self, corr): self.code_freq += corr / self.carr_to_code def to_dict(self): - return { k:v for k, v in self.__dict__.items() \ - if not (k.startswith('__') and k.endswith('__')) } + return {k: v for k, v in self.__dict__.items() + if not (k.startswith('__') and k.endswith('__'))} class TrackingLoop3b: @@ -189,6 +258,21 @@ class TrackingLoop3b: """ def __init__(self, **kwargs): + """ + Tracking loop initialization. + + Parameters + ---------- + code_params : dictionary + carr_freq - Carrier frequency [rad/s] + code_freq - Code frequency [rad/s] + carr_freq_b1 - FLL BW + carr_bw - PLL BW + code_bw - DLL BW + carr_to_code - carrier to code scaling factor + + """ + # Initial state self.carr_freq = kwargs['carr_freq'] self.code_freq = kwargs['code_freq'] @@ -202,14 +286,13 @@ def __init__(self, **kwargs): self.pll_bw = kwargs['carr_bw'] self.dll_bw = kwargs['code_bw'] - self.P_prev = 1+0j - - self.retune( (kwargs['code_bw'], kwargs['code_zeta'], kwargs['code_k']), - (kwargs['carr_bw'], kwargs['carr_zeta'], kwargs['carr_k']), - kwargs['loop_freq'], - kwargs['carr_freq_b1'], - kwargs['carr_to_code'] ) + self.P_prev = 1 + 0j + self.retune((kwargs['code_bw'], kwargs['code_zeta'], kwargs['code_k']), + (kwargs['carr_bw'], kwargs['carr_zeta'], kwargs['carr_k']), + kwargs['loop_freq'], + kwargs['carr_freq_b1'], + kwargs['carr_to_code']) def retune(self, code_params, carr_params, loop_freq, carr_freq_b1, carr_to_code): """ @@ -248,7 +331,8 @@ def retune(self, code_params, carr_params, loop_freq, carr_freq_b1, carr_to_code self.freq_c2 = freq_omega_0 * freq_omega_0 # PLL constants - self.phase_c1, self.phase_c2, self.phase_c3 = controlled_root(3, 1. / loop_freq, carr_bw) + self.phase_c1, self.phase_c2, self.phase_c3 = controlled_root( + 3, 1. / loop_freq, carr_bw) # DLL constants code_omega_0 = code_bw / 0.53 @@ -261,7 +345,9 @@ def retune(self, code_params, carr_params, loop_freq, carr_freq_b1, carr_to_code def update(self, E, P, L): """ - Tracking loop update + Tracking loop update. + Based on the boxcar transform. + Parameters ---------- @@ -283,7 +369,8 @@ def update(self, E, P, L): self.phase_err = costas_discriminator(P.real, P.imag) freq_error = 0 if self.freq_c1 != 0 and self.T != 0: - freq_error = frequency_discriminator(P.real, P.imag, self.P_prev.real, self.P_prev.imag) / self.T + freq_error = frequency_discriminator( + P.real, P.imag, self.P_prev.real, self.P_prev.imag) / self.T self.P_prev = P self.phase_acc += self.phase_err * self.phase_c3 / self.T @@ -310,8 +397,8 @@ def adjust_freq(self, corr): self.carr_freq += corr def to_dict(self): - return { k:v for k, v in self.__dict__.items() \ - if not (k.startswith('__') and k.endswith('__')) } + return {k: v for k, v in self.__dict__.items() + if not (k.startswith('__') and k.endswith('__'))} class TrackingLoop2b: @@ -324,136 +411,21 @@ class TrackingLoop2b: """ def __init__(self, **kwargs): - # Initial state - self.carr_freq = kwargs['carr_freq'] - self.code_freq = kwargs['code_freq'] - - self.code_vel = kwargs['code_freq'] - self.phase_vel = kwargs['carr_freq'] - - self.P_prev = 1+0j - - self.retune( (kwargs['code_bw'], kwargs['code_zeta'], kwargs['code_k']), - (kwargs['carr_bw'], kwargs['carr_zeta'], kwargs['carr_k']), - kwargs['loop_freq'], - kwargs['carr_freq_b1'], - kwargs['carr_to_code'] ) - - def retune(self, code_params, carr_params, loop_freq, carr_freq_b1, carr_to_code): """ - Retune the tracking loop. + Tracking loop initialization. Parameters ---------- - code_params : (float, float, float) - Code tracking loop parameter tuple, `(bw, zeta, k)`. - carr_params : (float, float, float) - Carrier tracking loop parameter tuple, `(bw, zeta, k)`. - loop_freq : float - The frequency with which loop updates are performed. - carr_freq_b1 : float - FLL aiding gain - carr_to_code : float - PLL to DLL aiding gain + code_params : dictionary + carr_freq - Carrier frequency [rad/s] + code_freq - Code frequency [rad/s] + carr_freq_b1 - FLL BW + carr_bw - PLL BW + code_bw - DLL BW + carr_to_code - carrier to code scaling factor """ - code_bw, code_zeta, code_k = code_params - carr_bw, carr_zeta, carr_k = carr_params - - # Common parameters - self.T = 1. / loop_freq - - # FLL constants - freq_omega_0 = carr_freq_b1 / 0.53 - freq_a2 = 1.414 - # a_2 * omega_0f - self.freq_c1 = freq_a2 * freq_omega_0 - self.freq_c2 = freq_omega_0 * freq_omega_0 - - # PLL constants - phase_omega_0 = carr_bw / 0.53 - phase_a2 = 1.414 - - self.phase_c1 = phase_a2 * phase_omega_0 - self.phase_c2 = phase_omega_0 * phase_omega_0 - # self.phase_c1, self.phase_c2 = controlled_root(2, 1 / loop_freq, carr_bw) - - # DLL constants - code_omega_0 = code_bw / 0.53 - code_a2 = 1.414 - - self.code_c1 = code_a2 * code_omega_0 - self.code_c2 = code_omega_0 * code_omega_0 - - self.carr_to_code = carr_to_code - - # self.code_vel = 0 - # self.phase_vel = 0 - - def update(self, E, P, L): - """ - Tracking loop update - - Parameters - ---------- - E : [complex], :math:`I_E + Q_E j` - Complex Early Correlation - P : [complex], :math:`I_P + Q_P j` - Complex Prompt Correlation - L : [complex], :math:`I_L + Q_L j` - Complex Late Correlation - - Returns - ------- - out : (float, float) - The tuple (code_freq, carrier_freq). - - """ - - # Carrier loop - self.phase_err = costas_discriminator(P.real, P.imag) - freq_error = 0 - if self.freq_c1 != 0: - freq_error = frequency_discriminator(P.real, P.imag, self.P_prev.real, self.P_prev.imag) / self.T - - self.P_prev = P - - self.phase_vel += freq_error * self.freq_c2 * self.T + self.phase_err * self.phase_c2 * self.T - - self.carr_freq = self.phase_vel + freq_error * self.freq_c1 + self.phase_err * self.phase_c1 - - # Code loop - code_error = -dll_discriminator(E, P, L) - - prev = self.code_vel - self.code_vel += self.code_c2 * code_error * self.T - sum = (prev + self.code_vel) * 0.5 + self.code_c1 * code_error - - self.code_freq = sum - if self.carr_to_code > 0: - self.code_freq += self.carr_freq / self.carr_to_code - - return (self.code_freq, self.carr_freq) - - def adjust_freq(self, corr): - self.carr_freq += corr - - def to_dict(self): - return { k:v for k, v in self.__dict__.items() \ - if not (k.startswith('__') and k.endswith('__')) } - - -class TrackingLoop3Optimal: - """ - Third order optimal tracking loop initialization. - - For a full description of the loop filter parameters, see - :libswiftnav:`calc_loop_gains`. - - """ - - def __init__(self, **kwargs): # Initial state self.carr_freq = kwargs['carr_freq'] self.code_freq = kwargs['code_freq'] @@ -461,13 +433,13 @@ def __init__(self, **kwargs): self.code_vel = kwargs['code_freq'] self.phase_vel = kwargs['carr_freq'] - self.P_prev = 1+0j + self.P_prev = 1 + 0j - self.retune( (kwargs['code_bw'], kwargs['code_zeta'], kwargs['code_k']), - (kwargs['carr_bw'], kwargs['carr_zeta'], kwargs['carr_k']), - kwargs['loop_freq'], - kwargs['carr_freq_b1'], - kwargs['carr_to_code'] ) + self.retune((kwargs['code_bw'], kwargs['code_zeta'], kwargs['code_k']), + (kwargs['carr_bw'], kwargs['carr_zeta'], kwargs['carr_k']), + kwargs['loop_freq'], + kwargs['carr_freq_b1'], + kwargs['carr_to_code']) def retune(self, code_params, carr_params, loop_freq, carr_freq_b1, carr_to_code): """ @@ -491,7 +463,7 @@ def retune(self, code_params, carr_params, loop_freq, carr_freq_b1, carr_to_code carr_bw, carr_zeta, carr_k = carr_params # Common parameters - self.T = 1 / loop_freq + self.T = 1. / loop_freq # FLL constants freq_omega_0 = carr_freq_b1 / 0.53 @@ -523,7 +495,8 @@ def retune(self, code_params, carr_params, loop_freq, carr_freq_b1, carr_to_code def update(self, E, P, L): """ - Tracking loop update + Tracking loop update. + Uses boxcar transform. Parameters ---------- @@ -545,13 +518,16 @@ def update(self, E, P, L): self.phase_err = costas_discriminator(P.real, P.imag) freq_error = 0 if self.freq_c1 != 0: - freq_error = frequency_discriminator(P.real, P.imag, self.P_prev.real, self.P_prev.imag) / self.T + freq_error = frequency_discriminator( + P.real, P.imag, self.P_prev.real, self.P_prev.imag) / self.T self.P_prev = P - self.phase_vel += freq_error * self.freq_c2 * self.T + self.phase_err * self.phase_c2 * self.T + self.phase_vel += freq_error * self.freq_c2 * \ + self.T + self.phase_err * self.phase_c2 * self.T - self.carr_freq = self.phase_vel + freq_error * self.freq_c1 + self.phase_err * self.phase_c1 + self.carr_freq = self.phase_vel + freq_error * \ + self.freq_c1 + self.phase_err * self.phase_c1 # Code loop code_error = -dll_discriminator(E, P, L) @@ -570,5 +546,5 @@ def adjust_freq(self, corr): self.carr_freq += corr def to_dict(self): - return { k:v for k, v in self.__dict__.items() \ - if not (k.startswith('__') and k.endswith('__')) } + return {k: v for k, v in self.__dict__.items() + if not (k.startswith('__') and k.endswith('__'))} From 012dca3c09e8b3a5580aea69603f3df93c455f78 Mon Sep 17 00:00:00 2001 From: Adel Mamin Date: Sun, 21 Aug 2016 23:25:13 +0300 Subject: [PATCH 58/61] Remove history support --- peregrine/tracking.py | 229 ++++++++++++++++++++---------------------- 1 file changed, 109 insertions(+), 120 deletions(-) diff --git a/peregrine/tracking.py b/peregrine/tracking.py index b9f6bc4..d7c25b5 100644 --- a/peregrine/tracking.py +++ b/peregrine/tracking.py @@ -274,7 +274,6 @@ def __init__(self, params): 'coherent_ms': coherent_ms, 'iq_ratio': 0} - self.profiles_history = [] self.track_candidates = [] self.stabilization_time = defaults.tracking_loop_stabilization_time_ms self.coherent_ms = coherent_ms @@ -288,7 +287,6 @@ def __init__(self, params): self.bit_sync_prev = self.bit_sync - self.track_settled = False self.fsm_index = 0 self.fsm_states = get_fsm_states(self.fsm_states_all, ms=self.coherent_ms, @@ -351,8 +349,9 @@ def __init__(self, params): self.acq.prn, self.acq.signal) self.track_profile_timer_ms = 0 - self.dynamics_timer_ms = 0 - self.dynamics_detected = False + self.acc_timer_ms = 0 + self.bit_sync_timer_ms = 0 + self.acc_detected = False self.code_phase = 0.0 self.carr_phase = 0.0 self.lock_detect_outp_prev = False @@ -369,6 +368,7 @@ def __init__(self, params): self.lock_detect_outo = 0 self.lock_detect_outp = 0 self.E = self.P = self.L = 0.j + self.acc_g = 0 def dump(self): """ @@ -469,7 +469,6 @@ def _set_track_profile(self): bit_sync=self.bit_sync) self.fsm_index = 0 self.track_profile_timer_ms = 0 - self.track_settled = False def _make_track_candidates(self): """ @@ -482,7 +481,9 @@ def _make_track_candidates(self): """ fll_bw_index = self.fll_bw_index + # we try to minimize FLL BW first if fll_bw_index == len(self.track_params['fll_bw']) - 1: + # FLL is already mith minimum BW coherent_ms_index = self.coherent_ms_index if coherent_ms_index < len(self.track_params['coherent_ms']) - 1: coherent_ms_index += 1 @@ -522,23 +523,48 @@ def _filter_track_candidates(self): pll_bw_index = candidate['pll_bw_index'] pll_bw = self.track_params['pll_bw'][pll_bw_index] - fll_bw_index = candidate['fll_bw_index'] - fll_bw = self.track_params['fll_bw'][fll_bw_index] - coherent_ms_index = candidate['coherent_ms_index'] coherent_ms = self.track_params['coherent_ms'][coherent_ms_index] - if pll_bw * coherent_ms * 1e-3 > 0.04: - if self.dynamics_detected: - if coherent_ms <= 5 and pll_bw <= 10: - pass - else: - continue + bw_time = pll_bw * coherent_ms * 1e-3 + + if pll_bw < 5: + continue + + if coherent_ms == 1: + if 30 <= pll_bw: + pass + else: + continue + + elif coherent_ms == 2: + if 12 <= pll_bw and pll_bw <= 30: + pass + else: + continue + + elif coherent_ms == 4: + if 10 <= pll_bw and pll_bw <= 12: + pass + else: + continue + + elif coherent_ms == 5: + if 5 <= pll_bw and pll_bw <= 10: + pass else: - if pll_bw <= 5: + continue + + elif bw_time > 0.04: + if self.acc_detected: + if coherent_ms <= 10 and pll_bw <= 5: pass else: continue + elif pll_bw == 5: + pass + else: + continue res.append(candidate) @@ -546,25 +572,21 @@ def _filter_track_candidates(self): def _run_track_profile_selection(self): """ - Customize the tracking run procedure in a subclass. - The method can be optionally redefined in a subclass to perform - a subclass specific actions to happen before correlator runs - next integration round. + Runs tracking profile selection based on the + availability of bit sync, fast and normal locks. """ if self.bit_sync and not self.bit_sync_prev: # we just got bit sync - self.track_profile_timer_ms = 0 + self.bit_sync_timer_ms = 0 self.bit_sync_prev = self.bit_sync if self.lock_detect_outp: - self.lock_detect_outp_prev = True - if not self.lock_detect_fast_outp: # we lost fast lock detector - if self.dynamics_detected: + if self.acc_detected: # and we are facing dynamics if self.fll_bw_index == 0 and \ self.pll_bw_index == 0 and \ @@ -579,7 +601,6 @@ def _run_track_profile_selection(self): return self.fll_bw_index = 0 - self.profiles_history = [] self._set_track_profile() return @@ -587,45 +608,21 @@ def _run_track_profile_selection(self): if not track_settled: return - # dynamics in [Hz/s] - # do no assess dynamics in FLL mode as + # Detect dynamics + # do not assess dynamics in FLL mode as # the PLL phase acceleration indicator looks to be scrued - if self.fll_bw_index != 0: - dynamics = self.loop_filter.to_dict()['phase_acc'] / (2 * np.pi) - if dynamics > 30: # [hz/sec] - self.dynamics_timer_ms = 0 - self.dynamics_detected = True + fll_bw = self.track_params['fll_bw'][self.fll_bw_index] + if fll_bw == 0: + acc = self.loop_filter.to_dict()['phase_acc'] / (2 * np.pi) + self.acc_g = acc * constants.c / (self.carrier_freq * constants.g) - if self.dynamics_timer_ms > 2000: - self.dynamics_detected = False + if acc > 30: # [hz/sec] + self.acc_timer_ms = 0 + self.acc_detected = True - if self.track_profile_timer_ms > 500: - # clear history as it is too old - self.profiles_history = [] - - if int(self.track_profile_timer_ms + 0.5) % 20 != 0: - # wait for bit edge - return - - iq_ratio = np.absolute(self.lock_detect_slow_lpfi / - self.lock_detect_slow_lpfq) - if not self.track_settled: - self.track_profile['iq_ratio'] = iq_ratio - self.track_settled = True - - if self.track_profile['iq_ratio'] > iq_ratio: - self.track_profile['iq_ratio'] = iq_ratio - - if len(self.profiles_history): - prev_iq_ratio = self.profiles_history[-1]['iq_ratio'] - if prev_iq_ratio and iq_ratio < prev_iq_ratio * 0.5: - # revert to previous profile - profile = self.profiles_history.pop() - self.fll_bw_index = profile['fll_bw_index'] - self.pll_bw_index = profile['pll_bw_index'] - self.coherent_ms_index = profile['coherent_ms_index'] - self._set_track_profile() - return + if self.acc_timer_ms > 2000: + # clear acceleration flag as it is too old + self.acc_detected = False final_profile = \ self.fll_bw_index == len(self.track_params['fll_bw']) - 1 and \ @@ -640,27 +637,27 @@ def _run_track_profile_selection(self): if len(self.track_candidates) == 0: return - for i, track_profile in reversed(list(enumerate(self.track_candidates))): + for i, track_profile in list(enumerate(self.track_candidates)): coherent_ms_index = track_profile['coherent_ms_index'] coherent_ms = self.track_params['coherent_ms'][coherent_ms_index] bit_sync_required = (coherent_ms != 1) - if bit_sync_required and not self.bit_sync: - continue + if bit_sync_required: + if not self.bit_sync: + continue + if int(self.bit_sync_timer_ms + 0.5) % 20 != 0: + # wait for bit edge + continue track_profile = self.track_candidates.pop(i) # switch to next track profile - history = {'fll_bw_index': self.fll_bw_index, - 'pll_bw_index': self.pll_bw_index, - 'coherent_ms_index': self.coherent_ms_index, - 'iq_ratio': self.track_profile['iq_ratio']} - self.profiles_history.append(history) self.fll_bw_index = track_profile['fll_bw_index'] self.pll_bw_index = track_profile['pll_bw_index'] self.coherent_ms_index = track_profile['coherent_ms_index'] + self.track_candidates = [] self._set_track_profile() break @@ -668,9 +665,8 @@ def _run_track_profile_selection(self): if self.lock_detect_outp_prev: # we just lost the lock self.track_profile_timer_ms = 0 - self.lock_detect_outp_prev = False - if self.dynamics_detected: + if self.acc_detected: threshold = 50 else: threshold = 10000 @@ -688,9 +684,10 @@ def _run_track_profile_selection(self): return self.fll_bw_index = 0 - self.profiles_history = [] self._set_track_profile() + self.lock_detect_outp_prev = self.lock_detect_outp + def _run_nav_data_decoding(self): """ Customize the tracking run procedure in a subclass. @@ -807,7 +804,8 @@ def run(self, samples): ) self.track_profile_timer_ms += 1e3 * blksize / self.sampling_freq - self.dynamics_timer_ms += 1e3 * blksize / self.sampling_freq + self.bit_sync_timer_ms += 1e3 * blksize / self.sampling_freq + self.acc_timer_ms += 1e3 * blksize / self.sampling_freq sample_index += blksize samples_processed += blksize @@ -889,11 +887,8 @@ def run(self, samples): not (defaults.GET_CORR_2 in flags_post): continue - phase_acc_hz_per_s = \ - self.loop_filter.to_dict()['phase_acc'] / (2 * np.pi) - self.track_result.dynamics[self.i] = phase_acc_hz_per_s - self.track_result.dynamics_g[self.i] = \ - phase_acc_hz_per_s * constants.c / (self.carrier_freq * constants.g) + phase_acc = self.loop_filter.to_dict()['phase_acc'] / (2 * np.pi) + self.track_result.acc_g[self.i] = self.acc_g # run tracking loop self.loop_filter.update(self.E, self.P, self.L) @@ -937,8 +932,8 @@ def run(self, samples): self.track_result.dll_bw[self.i] = self.loop_filter.to_dict()['dll_bw'] self.track_result.track_timer_ms[self.i] = self.track_profile_timer_ms - self.track_result.dynamics_timer_ms[self.i] = self.dynamics_timer_ms - self.track_result.dynamics_detected[self.i] = self.dynamics_detected + self.track_result.acc_timer_ms[self.i] = self.acc_timer_ms + self.track_result.acc_detected[self.i] = self.acc_detected # Record stuff for postprocessing self.track_result.absolute_sample[self.i] = self.sample_index + \ @@ -1673,9 +1668,8 @@ def __init__(self, n_points, prn, signal): self.iq_ratio_min = np.zeros(n_points) self.code_err = np.zeros(n_points) self.acceleration = np.zeros(n_points) - self.dynamics = np.zeros(n_points) - self.dynamics_g = np.zeros(n_points) - self.dynamics_detected = np.zeros(n_points) + self.acc_g = np.zeros(n_points) + self.acc_detected = np.zeros(n_points) self.nav_msg = NavMsg() self.nav_msg_bit_phase_ref = np.zeros(n_points) self.nav_bit_sync = NBSMatchBit() if prn < 32 else NBSSBAS() @@ -1691,7 +1685,7 @@ def __init__(self, n_points, prn, signal): self.dll_bw = np.zeros(n_points) self.track_timer_ms = np.zeros(n_points) - self.dynamics_timer_ms = np.zeros(n_points) + self.acc_timer_ms = np.zeros(n_points) self.signal = signal self.ms_tracked = np.zeros(n_points) @@ -1730,12 +1724,11 @@ def dump(self, output_file, size): with open(fn_analysis, mode) as f1: if self.print_start: f1.write( - "sample_index,ms_tracked,coherent_ms,bit_sync,fll_bw,pll_bw,dll_bw," - "track_timer_ms,dynamics_timer_ms," - "lock_detect_outp,lock_detect_outo," - "lock_detect_fast_outp,lock_detect_fast_outo," - "iq_ratio,iq_ratio_fast,iq_ration_slow,iq_ratio_raw,iq_ratio_min," - "dynamics,dynamics_g,dynamics_detected," + "sample,ms,coherent_ms,bs,fll_bw,pll_bw,dll_bw," + "track_ms,acc_ms," + "plock,plock_fast," + "i/q,i/q_fast,i/q_slow,i/q_raw,i/q_min," + "acc_g,acc_flag," "phase_err,code_err,CN0,IF,doppler_phase," "carr_doppler,code_phase,code_freq," "SNR,SNR_DB,P_Mag,E_I,E_Q,P_I,P_Q,L_I,L_Q," @@ -1745,54 +1738,50 @@ def dump(self, output_file, size): "acceleration,code_phase_acc,more_samples\n") for i in range(size): f1.write("%s," % int(self.absolute_sample[i])) - f1.write("%s," % self.ms_tracked[i]) + f1.write("%.1f," % self.ms_tracked[i]) f1.write("%s," % self.coherent_ms[i]) - f1.write("%s," % self.bit_sync[i]) + f1.write("%d," % self.bit_sync[i]) f1.write("%s," % self.fll_bw[i]) f1.write("%s," % self.pll_bw[i]) f1.write("%s," % self.dll_bw[i]) - f1.write("%s," % self.track_timer_ms[i]) - f1.write("%s," % self.dynamics_timer_ms[i]) + f1.write("%d," % self.track_timer_ms[i]) + f1.write("%d," % self.acc_timer_ms[i]) f1.write("%s," % int(self.lock_detect_outp[i])) - f1.write("%s," % int(self.lock_detect_outo[i])) - f1.write("%s," % int(self.lock_detect_fast_outp[i])) - f1.write("%s," % int(self.lock_detect_fast_outo[i])) - f1.write("%s," % (self.lock_detect_lpfi[i] / self.lock_detect_lpfq[i])) - f1.write("%s," % (self.lock_detect_fast_lpfi[i] / + f1.write("%.1f," % (self.lock_detect_lpfi[i] / self.lock_detect_lpfq[i])) + f1.write("%.1f," % (self.lock_detect_fast_lpfi[i] / self.lock_detect_fast_lpfq[i])) - f1.write("%s," % (self.lock_detect_slow_lpfi[i] / + f1.write("%.1f," % (self.lock_detect_slow_lpfi[i] / self.lock_detect_slow_lpfq[i])) - f1.write("%s," % np.absolute(self.P[i].real / self.P[i].imag)) - f1.write("%s," % self.iq_ratio_min[i]) + f1.write("%.1f," % np.absolute(self.P[i].real / self.P[i].imag)) + f1.write("%.1f," % self.iq_ratio_min[i]) - f1.write("%s," % self.dynamics[i]) - f1.write("%s," % self.dynamics_g[i]) - f1.write("%s," % self.dynamics_detected[i]) + f1.write("%.1f," % self.acc_g[i]) + f1.write("%d," % self.acc_detected[i]) - f1.write("%s," % self.phase_err[i]) - f1.write("%s," % self.code_err[i]) - f1.write("%s," % self.cn0[i]) + f1.write("%.1f," % self.phase_err[i]) + f1.write("%.1f," % self.code_err[i]) + f1.write("%.1f," % self.cn0[i]) f1.write("%s," % self.IF) - f1.write("%s," % self.carr_phase[i]) - f1.write("%s," % self.carr_freq[i]) - f1.write("%s," % self.code_phase[i]) - f1.write("%s," % self.code_freq[i]) - f1.write("%s," % self.snr[i]) - f1.write("%s," % self.snr_db[i]) - f1.write("%s," % (np.absolute(self.P[i]) ** 2)) - f1.write("%s," % self.E[i].real) - f1.write("%s," % self.E[i].imag) - f1.write("%s," % self.P[i].real) - f1.write("%s," % self.P[i].imag) - f1.write("%s," % self.L[i].real) - f1.write("%s," % self.L[i].imag) + f1.write("%.1f," % self.carr_phase[i]) + f1.write("%.1f," % self.carr_freq[i]) + f1.write("%.1f," % self.code_phase[i]) + f1.write("%.1f," % self.code_freq[i]) + f1.write("%.1f," % self.snr[i]) + f1.write("%.1f," % self.snr_db[i]) + f1.write("%.1f," % (np.absolute(self.P[i]) ** 2)) + f1.write("%.1f," % self.E[i].real) + f1.write("%.1f," % self.E[i].imag) + f1.write("%.1f," % self.P[i].real) + f1.write("%.1f," % self.P[i].imag) + f1.write("%.1f," % self.L[i].real) + f1.write("%.1f," % self.L[i].imag) f1.write("%s," % int(self.lock_detect_pcount1[i])) f1.write("%s," % int(self.lock_detect_pcount2[i])) f1.write("%s," % self.lock_detect_lpfi[i]) From 4577ed50ca35c5ec2edebc12bb4f40e78f985b7b Mon Sep 17 00:00:00 2001 From: Adel Mamin Date: Mon, 22 Aug 2016 09:08:35 +0300 Subject: [PATCH 59/61] Fix print_track_result to match new csv fields naming --- peregrine/analysis/print_track_res.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/peregrine/analysis/print_track_res.py b/peregrine/analysis/print_track_res.py index 36a83fe..50b9ba9 100755 --- a/peregrine/analysis/print_track_res.py +++ b/peregrine/analysis/print_track_res.py @@ -63,8 +63,8 @@ def main(): data = np.genfromtxt(args.file, dtype=float, delimiter=',', names=True) - time_stamps = np.array(data['sample_index']) - time_stamps = time_stamps - data['sample_index'][0] + time_stamps = np.array(data['sample']) + time_stamps = time_stamps - data['sample'][0] time_stamps = time_stamps / freq_profile['sampling_freq'] time_stamp_min = min(time_stamps) time_stamp_max = max(time_stamps) From 1c9a0af6fb8425d3d7e11fd98ea5e6cf168ce4e5 Mon Sep 17 00:00:00 2001 From: Adel Mamin Date: Tue, 23 Aug 2016 16:25:41 +0300 Subject: [PATCH 60/61] Change pessimistic and optimistic lock delays --- peregrine/defaults.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/peregrine/defaults.py b/peregrine/defaults.py index e4d80d0..b58442c 100644 --- a/peregrine/defaults.py +++ b/peregrine/defaults.py @@ -1256,7 +1256,7 @@ l1ca_lock_detect_params_normal = {"k1": 0.2, "k2": .8, "lp": 150, "lo": 50} # optimal set -l1ca_lock_detect_params_opt = {"k1": 0.02, "k2": 1.1, "lp": 150, "lo": 50} +l1ca_lock_detect_params_opt = {"k1": 0.02, "k2": 1.1, "lp": 50, "lo": 150} # extra optimal set l1ca_lock_detect_params_extraopt = {"k1": 0.02, "k2": 0.8, "lp": 150, "lo": 50} From a94a72b23dd86807f5986cef27174cc427a7a24d Mon Sep 17 00:00:00 2001 From: Adel Mamin Date: Tue, 23 Aug 2016 16:26:54 +0300 Subject: [PATCH 61/61] Remove 2ms and 4ms integration times from recovery stage --- peregrine/defaults.py | 2 +- peregrine/tracking.py | 24 ++++++++++++------------ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/peregrine/defaults.py b/peregrine/defaults.py index b58442c..f7359f8 100644 --- a/peregrine/defaults.py +++ b/peregrine/defaults.py @@ -208,7 +208,7 @@ l1ca_track_params = { 'fll_bw': (1, 0), 'pll_bw': (40, 35, 30, 25, 20, 18, 16, 14, 12, 10, 8, 7, 6.5, 6, 5.5, 5), - 'coherent_ms': (1, 2, 4, 5, 10, 20)} + 'coherent_ms': (1, 5, 10, 20)} l2c_track_params = { 'fll_bw': (1, 0), diff --git a/peregrine/tracking.py b/peregrine/tracking.py index d7c25b5..e6aa04e 100644 --- a/peregrine/tracking.py +++ b/peregrine/tracking.py @@ -537,20 +537,20 @@ def _filter_track_candidates(self): else: continue - elif coherent_ms == 2: - if 12 <= pll_bw and pll_bw <= 30: - pass - else: - continue - - elif coherent_ms == 4: - if 10 <= pll_bw and pll_bw <= 12: - pass - else: - continue + # elif coherent_ms == 2: + # if 12 <= pll_bw and pll_bw <= 30: + # pass + # else: + # continue + + # elif coherent_ms == 4: + # if 10 <= pll_bw and pll_bw <= 12: + # pass + # else: + # continue elif coherent_ms == 5: - if 5 <= pll_bw and pll_bw <= 10: + if 5 <= pll_bw and pll_bw <= 30: pass else: continue