import numpy as np import pytest from galileo_rx.acquisition.acquisition_manager import AcquisitionManager from galileo_rx.config import AcquisitionConfig, FrontendConfig, RfConfig from galileo_rx.frontend.frontend_chain import FrontendChain from galileo_rx.signal_profiles import galileo_e1_profile from galileo_rx.signals.code_provider import SyntheticCodeProvider from galileo_rx.signals.signal_generator import ChannelModelConfig, SatelliteSignalConfig, SyntheticSignalGenerator def make_signal(fs: float, delay_chips: float, doppler_hz: float, periods: int = 2, real_if: bool = False): profile = galileo_e1_profile() provider = SyntheticCodeProvider() if_hz = 2.0e6 if real_if else 0.0 generator = SyntheticSignalGenerator( profile, provider, fs, if_hz, real_if, [SatelliteSignalConfig(prn=5, component="E1C", code_delay_chips=delay_chips, doppler_hz=doppler_hz, cn0_db_hz=48.0)], ChannelModelConfig(seed=22), ) samples, _ = generator.generate(int(round(periods * 0.004 * fs))) if real_if: rf = RfConfig(sample_format="float64", input_is_real_if=True, sampling_frequency_hz=fs, intermediate_frequency_hz=if_hz) samples = FrontendChain(rf, FrontendConfig()).process(samples) return samples, profile, provider @pytest.mark.parametrize("doppler_hz", [-1250.0, 1750.0]) def test_pcps_detects_doppler_and_code(doppler_hz: float) -> None: fs = 4.092e6 delay_chips = 37.0 samples, profile, provider = make_signal(fs, delay_chips, doppler_hz) config = AcquisitionConfig( doppler_min_hz=-2500, doppler_max_hz=2500, doppler_step_hz=250, coherent_integration_ms=4, noncoherent_accumulations=2, detection_threshold=2.0, zero_padding_mode="none", parabolic_interpolation=False, ) result, _ = AcquisitionManager(profile, provider, fs, config).acquire_one(samples, "E1C", 5) assert result.detected assert result.raw_doppler_hz == doppler_hz assert abs(result.code_phase_chips - delay_chips) <= 0.26 def test_pcps_noninteger_samples_per_chip_and_boundary() -> None: fs = 4.5e6 delay_chips = 4091.2 samples, profile, provider = make_signal(fs, delay_chips, 500.0) config = AcquisitionConfig( doppler_min_hz=0, doppler_max_hz=1000, doppler_step_hz=250, coherent_integration_ms=4, noncoherent_accumulations=2, detection_threshold=1.8, zero_padding_mode="none", parabolic_interpolation=False, ) result, _ = AcquisitionManager(profile, provider, fs, config).acquire_one(samples, "E1C", 5) circular_error = min(abs(result.code_phase_chips - delay_chips), 4092 - abs(result.code_phase_chips - delay_chips)) assert result.detected and circular_error < 0.6 def test_real_if_acquisition() -> None: fs = 8.0e6 samples, profile, provider = make_signal(fs, 21.0, 750.0, real_if=True) config = AcquisitionConfig( doppler_min_hz=250, doppler_max_hz=1250, doppler_step_hz=250, coherent_integration_ms=4, noncoherent_accumulations=2, detection_threshold=1.7, zero_padding_mode="none", parabolic_interpolation=False, ) result, _ = AcquisitionManager(profile, provider, fs, config).acquire_one(samples, "E1C", 5) assert result.detected and result.raw_doppler_hz == 750.0