79 lines
3.1 KiB
Python
79 lines
3.1 KiB
Python
from __future__ import annotations
|
|
|
|
from pathlib import Path
|
|
|
|
import numpy as np
|
|
import pytest
|
|
import yaml
|
|
|
|
from galileo_rx.acquisition.acquisition_manager import AcquisitionManager
|
|
from galileo_rx.config import AcquisitionConfig, TrackingConfig
|
|
from galileo_rx.io.signalsim_reader import SignalSimReader, SignalSimSampleSpec
|
|
from galileo_rx.signal_profiles import galileo_e1_profile
|
|
from galileo_rx.signals.signalsim_codes import SignalSimCodeProvider
|
|
from galileo_rx.tracking.pilot_aided_e1 import (
|
|
E1CPilotAidedE1TrackingChannel,
|
|
synchronize_e1c_for_tracking,
|
|
)
|
|
|
|
|
|
@pytest.mark.signalsim
|
|
def test_e1c_secondary_sync_and_pilot_aided_e1b_branch() -> None:
|
|
cfg = yaml.safe_load(Path("configs/navigation_collection.yaml").read_text(encoding="utf-8"))
|
|
source = Path(cfg["signalsim"]["path"])
|
|
vector = Path(cfg["signalsim"]["samples"])
|
|
if not source.is_dir() or not vector.is_file():
|
|
pytest.skip("SignalSim checkout or 32.2-second navigation IQ8 vector is unavailable")
|
|
fs = float(cfg["rf"]["sampling_frequency_hz"])
|
|
samples = SignalSimReader(
|
|
vector, SignalSimSampleSpec(cfg["signalsim"]["sample_format"]), memory_map=True
|
|
).read()
|
|
profile = galileo_e1_profile()
|
|
provider = SignalSimCodeProvider(source)
|
|
acquisition_config = AcquisitionConfig(
|
|
**cfg["acquisition"], parallelism="doppler_vectorized"
|
|
)
|
|
manager = AcquisitionManager(profile, provider, fs, acquisition_config)
|
|
observation_samples = (
|
|
manager.engine.coherent_samples * acquisition_config.noncoherent_accumulations
|
|
)
|
|
acquisition, _ = manager.acquire_one(
|
|
samples[:observation_samples], "E1C", 1, float(cfg["rf"]["intermediate_frequency_hz"])
|
|
)
|
|
assert acquisition.detected
|
|
synchronized = synchronize_e1c_for_tracking(
|
|
samples, profile, provider, fs, acquisition, observation_samples
|
|
)
|
|
assert synchronized.sync.normalized_correlation > 0.98
|
|
assert synchronized.sync.sign_errors == 0
|
|
|
|
channel = E1CPilotAidedE1TrackingChannel(
|
|
profile,
|
|
provider,
|
|
fs,
|
|
TrackingConfig(
|
|
integration_ms=2.0,
|
|
pull_in_duration_ms=300.0,
|
|
pll_noise_bandwidth_hz=10.0,
|
|
fll_noise_bandwidth_hz=20.0,
|
|
dll_noise_bandwidth_hz=1.0,
|
|
secondary_code_mode="wipeoff",
|
|
loss_of_lock_epochs=40,
|
|
),
|
|
synchronized.acquisition,
|
|
synchronized.tracking_start_sample,
|
|
synchronized.sync.phase,
|
|
)
|
|
count = int(round(fs * 1.0))
|
|
epochs = channel.process_pilot_aided(
|
|
samples[synchronized.tracking_start_sample : synchronized.tracking_start_sample + count]
|
|
)
|
|
pilot = [item.pilot for item in epochs]
|
|
assert len(pilot) == 500
|
|
assert sum(item.code_lock and item.carrier_lock for item in pilot[30:]) > 460
|
|
assert not any(item.cycle_slip or item.sample_discontinuity for item in pilot)
|
|
assert sum(pilot[index - 1].code_lock and not pilot[index].code_lock for index in range(1, len(pilot))) == 0
|
|
assert np.median(
|
|
np.asarray([abs(item.e1b_correlators.prompt) for item in epochs[150:]], dtype=np.float64)
|
|
) > 1.0e4
|