mirror of
https://github.com/gnss-sdr/gnss-sdr
synced 2026-10-17 04:52:36 +00:00
Fix local carrier generation in PCPS acquisition
The Doppler wipeoff replicas were generated with volk_gnsssdr_s32f_sincos_32fc, which accumulates the phase in single precision over the whole vector without wrapping it. With a large frequency offset, such as the GLONASS FDMA channel bias (several rad per sample), the accumulated phase reaches 1e5 rad over a coherent block and its float resolution drops to 0.01-0.06 rad, so the effective frequency of the local carrier was off by hundreds of Hz to kHz, changing at every power-of-two boundary of the accumulator. In GLONASS L1/L2 C/A receivers this corrupted the Doppler grid: the noise estimate taken from the opposite Doppler row no longer represented the grid, satellites absent from the signal passed the pfa threshold on every dwell (tracked for ~11 s at ~30 dB-Hz with no carrier lock, then dropped and re-acquired, periodically), and the acquisition Doppler of the satellites actually present was biased by up to one bin, which could push the tracking loop into a false lock. Generate the carrier with a complex rotator instead, renormalized every 512 samples. The residual frequency error is below 0.1 Hz.
This commit is contained in:
@@ -308,9 +308,21 @@ bool pcps_acquisition::is_fdma()
|
||||
void pcps_acquisition::update_local_carrier(own::span<gr_complex> carrier_vector, float freq) const
|
||||
{
|
||||
const auto fs_in = d_acq_parameters.use_automatic_resampler ? d_acq_parameters.resampled_fs : d_acq_parameters.fs_in;
|
||||
const auto phase_step_rad = static_cast<float>(TWO_PI) * freq / static_cast<float>(fs_in);
|
||||
std::array<float, 1> _phase{};
|
||||
volk_gnsssdr_s32f_sincos_32fc(carrier_vector.data(), -phase_step_rad, _phase.data(), carrier_vector.size());
|
||||
const double phase_step_rad = TWO_PI * static_cast<double>(freq) / static_cast<double>(fs_in);
|
||||
const gr_complex phase_inc(static_cast<float>(std::cos(phase_step_rad)), static_cast<float>(-std::sin(phase_step_rad)));
|
||||
gr_complex phase(1.0F, 0.0F);
|
||||
auto* out = carrier_vector.data();
|
||||
const auto num_samples = carrier_vector.size();
|
||||
for (std::size_t i = 0; i < num_samples; i++)
|
||||
{
|
||||
out[i] = phase;
|
||||
phase *= phase_inc;
|
||||
if ((i & 511U) == 511U)
|
||||
{
|
||||
// keep the rotator on the unit circle
|
||||
phase /= std::abs(phase);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user