Commit Graph
11188 Commits
Author SHA1 Message Date
Carles Fernandez 190979945d Fix reading of GNSS-SDR.SUPL_MNC config parameter 2026-10-01 21:25:53 +02:00
Carles Fernandez 17ca85235e Merge branch 'next' of https://github.com/carlesfernandez/gnss-sdr into next 2026-10-01 15:25:57 +02:00
Carles Fernandez 064ab6bfb9 Merge branch 'joebre-fix-pcps-acquisition-sample-truncation' into next 2026-10-01 15:25:39 +02:00
Carles Fernandez b23a2af572 Fix building 2026-10-01 11:57:15 +02:00
Carles Fernandez 3c256e991b Compute PCPS dwell length with integer arithmetic
Replace std::clamp with std::min/std::max for C++11/14 compatibility
2026-10-01 10:58:13 +02:00
Carles Fernandez 2185dc647d Merge branch 'fix-pcps-acquisition-sample-truncation' of https://github.com/joebre/gnss-sdr into joebre-fix-pcps-acquisition-sample-truncation 2026-10-01 09:58:08 +02:00
joebre 9bd56d4cfe Add a unit test for pcps_acquisition's per-dwell sample-count fix
Covers the exact configuration the fix is for: GNSS-SDR.internal_fs_sps
not a multiple of 1 kHz (4000123 Hz), coherent_integration_time_ms (4)
spanning more than one code period (GPS L1 C/A's own code period is
1 ms), and max_dwells (5) > 1. Asserts a successful acquisition and
checks the reported Doppler/delay against the known synthetic signal's
truth, with tolerances the dwell-boundary drift this fix addresses
would clearly exceed.

Registering it in acq_test (tests/CMakeLists.txt) surfaced that the
target had apparently never actually linked successfully in this
environment before: it links FirFilter/SignalGenerator/GenSignalSource
but was missing input_filter_adapters/signal_generator_adapters/
signal_source_adapters, and separately hit a Linux-only undefined
libboost_thread symbol inside the system's packaged
libgnuradio-runtime.so, fixed with the standard
--copy-dt-needed-entries linker workaround (guarded to Linux only).
Neither is specific to this new test; fixing them was necessary to
build and run the suite at all, and the rest of acq_test (20 tests
total) now passes too.
2026-10-01 08:18:17 +02:00
joebre 3d16234434 Fix PCPS acquisition sample-count truncation when samples_per_code is non-integer
d_samples_to_consume (pcps_acquisition_adapter.cc) is floor(sampled_ms *
samples_per_ms), truncating to an integer. When the configured internal_fs_sps
does not divide evenly into a dwell (any decimation ratio leaving a fractional
number of samples per dwell), every dwell is silently shorter than the true
dwell length by a fixed residual, and that residual compounds linearly across
non-coherent dwells: the true code epoch drifts within the accumulation grid
instead of landing on the same index every time, and the sample stamp handed
to tracking drifts out of sync with it. Tracking then reconstructs the wrong
code phase at pull-in. Only shows up for short, high-chip-rate codes (Galileo
E5a, GPS L5) accumulated over several dwells -- low chip rate codes (GPS L1,
Galileo E1) absorb the same absolute drift as a much smaller fraction of a
chip.

Fix: keep each dwell's FFT/correlation window at the existing fixed
d_samples_to_consume size (so none of the buffer/FFT-plan sizing set up at
construction needs to change), but let the actual stream consumption between
dwells track the true dwell boundary with a standard DDA/Bresenham
accumulator -- skip one extra sample (discarded, never buffered) whenever the
accumulated residual reaches a full sample. This keeps every dwell's window
within half a sample of the true boundary permanently, so the drift this fix
is about never accumulates in the first place. The residual itself is
computed once, in the constructor, directly from the integer resampled_fs
(not through the lossy intermediate float samples_per_ms), and is always in
[0, 1) by construction, so there is no signed/unsigned wraparound risk.

This lives entirely in the sample-consumption state machine in general_work(),
upstream of doppler_grid_cpu()/doppler_grid_cuda()/update_synchro(), so CUDA
builds and bit_transition_flag mode need no special-casing -- they share the
same corrected consumption automatically. It is also correct for
coherent_integration_time_ms spanning more than one code period, since the
residual is derived from the same sampled_ms used for d_samples_to_consume,
not from a single code period.

A no-op whenever samples_per_code is already an integer (any internal_fs_sps
dividing evenly into one dwell): the residual is then exactly 0, so the skip
counter never fires.

Verified against a real EVK1029 dual-band capture (Galileo E1+E5a, GPS
L1+L5): the untouched case (samples/dwell already integer) stayed at ~2
spurious loss-of-lock events per 90s; a case with 0.5 samples/dwell of
truncation error went from 50+ loss-of-lock events per 4 minutes (tracking's
own frequency-error-reduction diagnostic scan showing no discernible
correlation peak at all) down to 1 event per ~41s -- the same order as the
untouched case -- with sharp, correct correlation peaks and CN0 estimates
jumping from ~20-30 dB-Hz (meaningless, noise-floor) to ~42-52 dB-Hz (genuine
lock).
2026-10-01 08:01:14 +02:00
Carles Fernandez 15c3c812c6 CI: do not wxlude volk_gnsssdr kernels 2026-09-30 19:50:41 +02:00
Carles Fernandez 7efe85e2ca Merge branch 'joebre-f_error-dump-opt-in' into next 2026-09-30 19:43:45 +02:00
Carles Fernandez 033227d133 Fix f_error dump Octave/MATLAB tools and update CHANGELOG
- CHANGELOG: document Tracking_<Sig>.f_error_dump (default: false) and the
  new Octave/MATLAB scripts
- f_error_sim.m: match cn0_m2m4_estimator when sqrt argument is negative,
  seed with rng() (fallback for Octave < 7), fix stale comments
- plot_all_f_error_scans.m: do not require gnuplot, restore the previous
  graphics toolkit on exit
- Use fprintf instead of printf for MATLAB compatibility
2026-09-30 19:32:21 +02:00
Carles Fernandez 943ef814ab Merge branch 'f_error-dump-opt-in' of https://github.com/joebre/gnss-sdr into joebre-f_error-dump-opt-in 2026-09-30 18:44:29 +02:00
Carles Fernandez 94e32f8a13 Merge branch 'vladisslav2011-b1c_enable_sumproduct' into next 2026-09-30 15:07:13 +02:00
Carles Fernandez c6405d824a Improve BeiDou B-CNAV1 decoding sensitivity 2026-09-30 12:08:49 +02:00
Carles Fernandez 28e14a3c7c Merge branch 'b1c_enable_sumproduct' of https://github.com/vladisslav2011/gnss-sdr into vladisslav2011-b1c_enable_sumproduct 2026-09-30 09:10:53 +00:00
joebre 5c24058459 Add Octave tooling to load, plot and simulate f_error dump scans
load_f_error_dump/find_f_error_scans/plot_f_error_scan (utils/matlab/libs)
read and visualize the per-bin CSV written by the tracking f_error_dump
diagnostic, and plot_all_f_error_scans (utils/matlab) batches
plot_f_error_scan over every scan in a dump, optionally saving PNGs.
f_error_sim (utils/matlab/libs) is a self-contained Monte Carlo
simulation of the same bin-scan/CN0-estimator logic, useful for sizing
f_error_step_num/f_error_accumulation/f_error_doppler_step without a
live capture.
2026-09-30 07:42:39 +02:00
joebre cd4f643a20 Make the f_error CSV dump opt-in via Tracking_<sig>.f_error_dump
Dll_Pll_Conf::f_error_dump_filename has a non-empty default, so the
frequency-error-reduction scan's per-bin CSV dump was effectively
always on with no clean way to disable it. Add a new f_error_dump
boolean (default false), matching the existing dump/Tracking_<sig>.dump
convention, and gate the dump call on it.
2026-09-30 07:42:39 +02:00
Vladislav P 543fe28ae9 Fix BeiDou CNAV1 test
And generalize B-CNAV1/B-CNAV2 LDPC encoder.

Signed-off-by: Vladislav P <vladisslav2011@gmail.com>
2026-09-30 02:18:44 +03:00
Vladislav P b24f930abc BeiDou B1C: Enable sum-product algorithm in LDPC decoder
This reduces minimum CN0 for stable telemetry decoding from ~28 dB*Hz to
~21 dB*Hz.

Signed-off-by: Vladislav P <vladisslav2011@gmail.com>
2026-09-29 23:27:47 +03:00
Carles Fernandez e50403b89b Bump local Armadillo and Protocol Buffers versions 2026-09-29 19:03:26 +02:00
Carles Fernandez 6c1e01e0b3 Fix data race in test 2026-09-29 18:44:34 +02:00
Carles Fernandez 2e682cce8e Update to new BeiDou PRN assignments
See http://www.beidou.gov.cn/yw/xwzx/202603/t20260320_29266.html
2026-09-29 13:01:30 +02:00
Carles Fernandez ef928a5e1f Merge branch 'vladisslav2011-enable_B2a_PRN6_18' into next 2026-09-29 10:11:25 +02:00
Carles Fernandez d971f6080e Merge branch 'enable_B2a_PRN6_18' of https://github.com/vladisslav2011/gnss-sdr into vladisslav2011-enable_B2a_PRN6_18 2026-09-29 10:11:04 +02:00
Carles Fernandez 09f143fe07 Summarize comments 2026-09-29 10:10:24 +02:00
Carles Fernandez f34c297a8e Merge branch 'joebre-alm-ephe-secondary-doppler-aiding' into next 2026-09-29 10:07:51 +02:00
Carles Fernandez 88fea3099a Harden pre-fix Doppler prediction bounds and grid sizing 2026-09-29 10:07:18 +02:00
Vladislav P b27cf0a1d5 Enable BeiDou B2a PRN6...PRN18
Contrary to ICD, these satellites actually broadcast B2a (OTA upgraded
in the orbit).
Verified by decoding live signal in realtime configuration.

Signed-off-by: Vladislav P <vladisslav2011@gmail.com>
2026-09-29 03:55:05 +03:00
Carles Fernandez 6f108b7497 Merge branch 'alm-ephe-secondary-doppler-aiding' of https://github.com/joebre/gnss-sdr into joebre-alm-ephe-secondary-doppler-aiding 2026-09-28 23:50:19 +02:00
Carles Fernandez 90fd53a4a9 Merge branch 'joebre-fix-gps-l5-assistance-gating' into next 2026-09-28 23:49:41 +02:00
Carles Fernandez 7050b48564 Add loading of QZSS L5 assistance 2026-09-28 23:44:52 +02:00
joebre f74ed54ee9 Extend almanac/ephemeris Doppler prediction to secondary signals and to before a fix
SatelliteVisibility::PredictedDopplerHz() previously required a live PVT
fix and was only used for a satellite's primary signal
(GNSSFlowgraph::acquisition_manager()). Two extensions:

1. Secondary signals (e.g. GPS L5, Galileo E5a) can now use the same
   geometric prediction, opt-in per acquisition role via
   <acq role>.alm_ephe_assisted_doppler_narrowing (default false). It's
   only reached at all when dual-frequency assist is unavailable or
   disabled (GNSS-SDR.assist_dual_frequency_acq=false), and is a distinct,
   less-proven Doppler source than that dual-frequency projection, hence
   opt-in rather than defaulted on.

2. Before a live fix exists, PredictedDopplerHz() can now predict from the
   AGNSS reference position (zero assumed velocity) and the configured
   nominal clock offset, opt-in via GNSS-SDR.doppler_prediction_before_fix
   (default false). A new PredictedDopplerUncertaintyHz() reports the
   Doppler spread implied by GNSS-SDR.receiver_max_velocity_m_s and
   GNSS-SDR.clock_frequency_max_error_ppm for this pre-fix case (zero once
   a fix exists, since position/velocity/clock are all solved then, not
   assumed) -- the caller widens its acquisition Doppler-bin search by this
   amount instead of trusting a single, possibly-wrong bin.

Verified against an EVK1029 GPS L5 capture (single-band, so every L5
channel is a secondary signal): with both flags enabled, the almanac-based
prediction narrows acquisition Doppler search before and after the fix,
logged via a new low-noise [alm_ephe_doppler] line; with them left at
their defaults, behavior is unchanged from before this change.
2026-09-28 16:00:42 +02:00
joebre 17bd8a4860 Fix stale fix-freshness check ordering in visibility-aware Doppler prediction
SatelliteVisibility::PredictedDopplerHz() gates its live-fix path on a
freshness check against last_fix_time_s_/last_fix_receiver_time_s_, both of
which are only stamped by SatelliteVisibility::Tick() (called from
GNSSFlowgraph::MaybeUpdateVisibility()).

In ControlThread::event_dispatcher(), acquisition_manager() -- which calls
PredictedDopplerHz() -- ran before MaybeUpdateVisibility() in the same
iteration. Since PVT updates roughly once per second, PredictedDopplerHz()
was therefore always comparing against a timestamp exactly one PVT epoch
stale, failing its own freshness check on every single call once a live
fix existed. The prediction only ever succeeded in the brief window right
after a periodic full visibility recompute happened to re-trigger a fresh
pick synchronously within the same call.

Reordering so MaybeUpdateVisibility() (and therefore Tick()'s stamping)
runs before acquisition_manager() each iteration fixes this: the timestamp
PredictedDopplerHz() checks is always current for the epoch it's
evaluating. acquisition_manager()'s existing "only when idle" gate is
preserved exactly (previously the implicit else of the valid_event check,
now an explicit !valid_event condition).

Verified against an EVK1029 GPS L5 capture with visibility-aware search
and almanac-based Doppler prediction enabled: before this fix, the
prediction log line never appeared after the first fix except in narrow
bursts tied to the ~120s full-recompute interval; after, it fires
continuously for every still-unlocked visible satellite each cycle.
2026-09-28 15:59:53 +02:00
Carles Fernandez 0dd0ea3681 Merge branch 'fix-gps-l5-assistance-gating' of https://github.com/joebre/gnss-sdr into joebre-fix-gps-l5-assistance-gating 2026-09-28 14:07:28 +02:00
Carles Fernandez 9e35452d19 Merge branch 'joebre-fix-galileo-fnav-preamble-confirmation' into next 2026-09-28 13:55:47 +02:00
Carles Fernandez 95c72618f8 Fix Galileo telemetry decoder races during reset and satellite changes 2026-09-28 13:19:07 +02:00
Carles Fernandez fd70179392 Fix Galileo preamble confirmation with intervening payload matches
Preserve the candidate anchor until its expected confirmation point.
Replace it only after confirmation is missed, preventing payload
correlations from repeatedly displacing a valid preamble.
2026-09-28 10:56:34 +02:00
Carles Fernandez 6ee81b93a6 Merge branch 'fix-galileo-fnav-preamble-confirmation' of https://github.com/joebre/gnss-sdr into joebre-fix-galileo-fnav-preamble-confirmation 2026-09-28 09:29:36 +02:00
joebre bf8df18ba5 Load GPS assistance XML for L5/L2C-only configurations too
GPS/QZSS UTC model, ionosphere and almanac data are broadcast system-wide
parameters, not specific to the L1 C/A signal -- L5 and L2C channels rely on
the exact same almanac (via the PRN-keyed map PVT and the visibility/
Doppler-assist logic read from) for visibility classification and Doppler
prediction just as much as L1 C/A does.

read_assistance_from_XML() gated the whole GPS ephemeris/UTC/iono/almanac
block on Channels_1C.count/Channels_J1.count alone. A configuration running
only L5 and/or L2C channels (no L1 C/A) never even attempted to load its
almanac, UTC or iono XML files -- not because those files were missing or
invalid, but because the code never asked for them, unconditionally reporting
"Error reading XML files" / "Disabling GNSS assistance" even with perfectly
valid assistance data on disk.

Broaden the gate to also fire when Channels_2S.count (L2C) or
Channels_L5.count is > 0, matching the same OR-together-all-constellation-
signals pattern already used for the Galileo block just below it. The L1 C/A
LNAV ephemeris load stays in this same block; L5/L2C use their own
separately-gated CNAV ephemeris further down, and requesting the LNAV
ephemeris is harmless when no L1 C/A channel exists to use it.
2026-09-28 09:11:02 +02:00
joebre 5ad428001f Fix Galileo frame-sync confirmation getting stuck on a false-positive anchor
case 0's preamble detection is a single 12-bit correlation match, which has
a real (if rare, ~1/2048) false-positive rate even at high CN0 -- nothing
about the page content is validated at that point, only the correlation
itself. case 1 then confirmed sync by checking only the single exact symbol
position predicted from that first hit (anchor + one page period), forever.
If the first hit was a coincidental false positive, every subsequent check
looked at the wrong symbol -- nowhere near the true 12-symbol preamble
window -- so confirmation could never succeed no matter how many periods
passed, even on an otherwise perfectly strong, cleanly-tracked signal.

case 1 now scans every symbol for a correlation hit, the same way case 0
does, and confirms sync when two genuine hits land exactly one page period
apart. A hit that does not match that spacing no longer discards the
anchor's progress outright -- it replaces the anchor with the new,
independently-found hit and keeps watching. A false-positive first
detection is now self-correcting instead of permanently poisoning
confirmation.

Also scope the existing d_setlock guard to cover case 0 and case 1's state
mutations (d_stat, d_preamble_index) and the d_symbol_history push, matching
case 2's existing pattern: reset()/set_satellite() can run on a different
thread than general_work() (ChannelFsm::start_acquisition() -> nav_->reset()),
and this state was previously unprotected there.

Verified on a EVK1029/SAPHYRION SY1029 dual-band Galileo E1+E5a setup:
strong-signal (47+ dB-Hz) E5a channels that previously hit
check_tlm_separation()'s ~50s timeout and force-restarted on essentially
every run now confirm and decode cleanly, across repeated back-to-back runs.
2026-09-28 07:57:05 +02:00
Carles Fernandez 044aee9bc2 Keep a separate logfile for each run with Abseil logging, as google-glog did 2026-09-27 18:26:57 +02:00
Carles Fernandez 20a0a69780 Fix acquisition code phase handed to tracking in GPS L1 C/A tests, restore Doppler search range in GLONASS L1 C/A acquisition test 2026-09-27 13:22:23 +02:00
Carles Fernandez 8c0dc1bff9 Update cpu_features to upstream main (f8a517f) 2026-09-27 12:39:50 +02:00
Carles Fernandez ab488fc1b4 volk_gnsssdr: fix flaky QA tests in rotator and convert kernels 2026-09-27 00:33:50 +02:00
Carles Fernandez a4fcb39d85 Restore frequency order in signals list 2026-09-26 15:44:08 +02:00
Carles Fernandez b37cc311d0 Fix race in acquisition tests 2026-09-26 12:02:38 +02:00
Carles Fernandez 28acfb7d9d Fix QuickSync acquisition 2026-09-26 11:38:18 +02:00
Carles Fernandez a967539ecb Merge branch 'mmajoral-galileo-e6-fpga' into next 2026-09-26 07:11:47 +02:00
Carles Fernandez f65096fc71 Merge branch 'galileo-e6-fpga' of https://github.com/mmajoral/gnss-sdr into mmajoral-galileo-e6-fpga 2026-09-26 07:09:59 +02:00
Marc Majoral 61d4447657 Enable FPGA acceleration for Galileo E6 2026-09-25 21:26:20 +02:00