Skip to content

feat(estimator): add carrier_doppler_pull_in_range interface#193

Closed
giove-a wants to merge 1 commit into
masterfrom
sc/get-pull-in-range
Closed

feat(estimator): add carrier_doppler_pull_in_range interface#193
giove-a wants to merge 1 commit into
masterfrom
sc/get-pull-in-range

Conversation

@giove-a

@giove-a giove-a commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator

What

Adds carrier_doppler_pull_in_range(estimator, signal) — a doppler-estimator
interface function returning the maximum absolute carrier-Doppler error a
freshly-acquired satellite can carry and still be pulled into carrier lock.

A GNSS receiver can use it to choose the Doppler resolution for the Acquisition.

How

  • Interface: bare-stub forward declaration + docstring in sat_state.jl,
    beside init_estimator_state (the analogous mandatory per-estimator hook).
    Unimplemented estimators raise a MethodError, matching the existing
    convention.
  • ConventionalPLLAndDLL (FLL-assisted, the default): returns 1/(4·T),
    the range over which the FLL atan(cross/dot) discriminator is unambiguous
    (inter-prompt phase within ±π/2). → 250 Hz for GPS L1 C/A & L5I (T = 1 ms),
    62.5 Hz for Galileo E1B (T = 4 ms), 25 Hz for L1C-D/L1C-P (T = 10 ms).
  • ConventionalPLLAndDLL (pure PLL): returns the fast lock-in
    approximation min(B_L, 1/(2·T)) (Gardner/Best), B_L taken from the
    estimator config (auto-resolved via default_carrier_loop_filter_bandwidth
    when unset). Documented as an order-of-magnitude estimate, not a hard bound.
  • handover_coherent_integration_time(signal) helper in
    sample_parameters.jl, beside calc_num_code_blocks_to_integrate: derives
    the start-of-tracking integration time from the loop's own machinery
    (pre-sync, secondary_code_or_bit_found = false) rather than assuming a
    fixed length — so it tracks any change to the pre-sync integration policy.

The returned value is a hard ceiling (one-sided): an acquisition Doppler-bin
width of 2·range is the theoretical maximum, not a safe target — size narrower
for margin. Documented accordingly.

Notes

  • Zero-allocation and type-stable (verified); it's a cold-path query, never
    called inside track!.
  • Docs: new API entries + a "custom doppler estimator" guide section.

Testing

  • New tests in test/conventional_pll_and_dll.jl covering the FLL values, the
    pure-PLL approximation + bandwidth cap, and the required-interface MethodError.
  • Full test/runtests.jl passes locally (exit 0; Flexiband integration test
    skipped as usual — it needs the 1.6 GB capture download).

🤖 Generated with Claude Code

@siebc
siebc requested a review from zsoerenm July 8, 2026 13:29
@giove-a
giove-a force-pushed the sc/get-pull-in-range branch from c7872ac to 7a5f408 Compare July 8, 2026 13:38
@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Benchmark Results (minimum time) — macos-14

Reporting the minimum over all samples (robust to shared-runner contention), not the median.

Alternative backends vs Float32 (track!, PR head)

Legend — backends: F32 Float32 (default) · I16 Int16 · 1b OneBit · 2b TwoBit (2-bit measurement + 2-bit carrier). Time columns are the minimum track! time; ×B = F32 / B (so >1 ⇒ backend B is faster than Float32), ✅ ≥ 5 % faster, ⚠️ ≥ 5 % slower. 1b/2b are BPSK-only, so their cells are blank for CBOC (Galileo E1B) scenarios.

Scenario F32 I16 1b 2b ×I16 ×1b ×2b
4-antenna @ 5 MHz 11.9 μs 6.28 μs 4.3 μs 8.64 μs 1.89 ✅ 2.76 ✅ 1.37 ✅
GPS L1CA, 8 sats @ 40 MHz 367.0 μs 118.0 μs 60.8 μs 112.0 μs 3.13 ✅ 6.05 ✅ 3.27 ✅
GPS L1CA, 8 sats @ 5 MHz 56.5 μs 22.9 μs 17.0 μs 25.5 μs 2.47 ✅ 3.32 ✅ 2.21 ✅
Galileo E1B, 4 sats @ 25 MHz 141.0 μs 58.5 μs 2.41 ✅
dynamic taps @ 5 MHz (kernel) 6.68 μs 2.38 μs 1.48 μs 2.65 μs 2.81 ✅ 4.51 ✅ 2.52 ✅
multi-signal N=3 @ 5 MHz 11.2 μs 5.11 μs 3.74 μs 6.31 μs 2.2 ✅ 3.0 ✅ 1.78 ✅
Time benchmarks (base vs PR head)

Ratio = 99d37e1… / fba140b…: >1 means the PR is faster. ✅ ≥ 5 % faster, ⚠️ ≥ 5 % slower. A blank cell means the benchmark exists on only one revision (🆕 = new on the PR, 🗑 = removed).

99d37e1 fba140b 99d37e1… / fba140b
downconvert and correlate/CPU/Float32 2.48 μs 2.46 μs 1.01
downconvert and correlate/CPU/Float32 4ant 4.87 μs 4.86 μs 1.0
downconvert and correlate/CPU/Float64 2.68 μs 2.68 μs 1.0
downconvert and correlate/CPU/Int16 2.62 μs 2.61 μs 1.0
downconvert and correlate/CPU/Int16 4ant 4.82 μs 4.8 μs 1.0
downconvert and correlate/CPU/Int32 2.54 μs 2.53 μs 1.01
fused kernel/1-ant dynamic taps 2.56 μs 2.74 μs 0.932 ⚠️
fused kernel/1-ant static taps 2.06 μs 2.21 μs 0.931 ⚠️
fused kernel/4-ant dynamic taps 7.78 μs 8.33 μs 0.934 ⚠️
fused kernel/4-ant static taps 4.43 μs 4.75 μs 0.934 ⚠️
fused tuple kernel/1-ant N=2 3.27 μs 3.51 μs 0.932 ⚠️
fused tuple kernel/1-ant N=3 3.4 μs 3.65 μs 0.932 ⚠️
fused tuple kernel/2-ant N=2 6.31 μs 6.77 μs 0.932 ⚠️
fused tuple kernel/2-ant N=3 5.61 μs 6.03 μs 0.931 ⚠️
fused tuple kernel/4-ant N=2 11.5 μs 12.4 μs 0.93 ⚠️
fused tuple kernel/4-ant N=3 10.1 μs 10.8 μs 0.931 ⚠️
track/1. Float32/2K – track 2.65 μs 2.75 μs 0.961
track/1. Float32/2K – track! 2.74 μs 2.71 μs 1.01
track/2. L1 8sat/5K – track 49.6 μs 49.3 μs 1.01
track/2. L1 8sat/5K – track! 49.2 μs 49.0 μs 1.0
track/2. L1 8sat/5K – track! Int16 20.5 μs 21.2 μs 0.965
track/2. L1 8sat/5K – track! OneBit 14.8 μs 16.1 μs 0.922 ⚠️
track/2. L1 8sat/5K – track!-threaded 49.7 μs 49.3 μs 1.01
track/2. L1 8sat/5K – track-threaded 49.9 μs 49.6 μs 1.01
track/3. E1B 4sat/25K – track 136.0 μs 136.0 μs 1.0
track/3. E1B 4sat/25K – track! 135.0 μs 135.0 μs 1.0
track/3. E1B 4sat/25K – track! Int16 58.4 μs 58.1 μs 1.01
track/3. E1B 4sat/25K – track!-threaded 135.0 μs 135.0 μs 1.0
track/3. E1B 4sat/25K – track-threaded 136.0 μs 136.0 μs 0.999
track/4. 8L1+8E1B/25K – track 490.0 μs 489.0 μs 1.0
track/4. 8L1+8E1B/25K – track! 489.0 μs 489.0 μs 1.0
track/4. 8L1+8E1B/25K – track!-threaded 489.0 μs 488.0 μs 1.0
track/4. 8L1+8E1B/25K – track-threaded 490.0 μs 489.0 μs 1.0
track/5. multi-signal N=1/5K – track 6.39 μs 6.87 μs 0.931 ⚠️
track/5. multi-signal N=1/5K – track! 6.36 μs 6.38 μs 0.996
track/6. multi-signal N=2/5K – track 10.4 μs 10.5 μs 0.988
track/6. multi-signal N=2/5K – track! 10.4 μs 10.4 μs 1.0
track/7. multi-signal N=3/5K – track 11.6 μs 11.5 μs 1.0
track/7. multi-signal N=3/5K – track! 11.7 μs 11.6 μs 1.01
track/8. L1CA presync 2 blk – track! 12.4 μs 12.3 μs 1.0
track/8. L1CA presync 20 blk – track! 120.0 μs 120.0 μs 1.0
track/8. L1CA synced 2 blk – track! 12.2 μs 12.2 μs 1.0
track/8. L1CA synced 20 blk – track! 118.0 μs 118.0 μs 1.0
time_to_load 153.0 μs 151.0 μs 1.01
Memory benchmarks (base vs PR head)
99d37e1 fba140b
downconvert and correlate/CPU/Float32 2 allocs: 576 B 2 allocs: 576 B
downconvert and correlate/CPU/Float32 4ant 2 allocs: 848 B 2 allocs: 848 B
downconvert and correlate/CPU/Float64 2 allocs: 576 B 2 allocs: 576 B
downconvert and correlate/CPU/Int16 2 allocs: 576 B 2 allocs: 576 B
downconvert and correlate/CPU/Int16 4ant 2 allocs: 848 B 2 allocs: 848 B
downconvert and correlate/CPU/Int32 2 allocs: 576 B 2 allocs: 576 B
fused kernel/1-ant dynamic taps 0 allocs: 0 B 0 allocs: 0 B
fused kernel/1-ant static taps 0 allocs: 0 B 0 allocs: 0 B
fused kernel/4-ant dynamic taps 0 allocs: 0 B 0 allocs: 0 B
fused kernel/4-ant static taps 0 allocs: 0 B 0 allocs: 0 B
fused tuple kernel/1-ant N=2 0 allocs: 0 B 0 allocs: 0 B
fused tuple kernel/1-ant N=3 0 allocs: 0 B 0 allocs: 0 B
fused tuple kernel/2-ant N=2 0 allocs: 0 B 0 allocs: 0 B
fused tuple kernel/2-ant N=3 0 allocs: 0 B 0 allocs: 0 B
fused tuple kernel/4-ant N=2 0 allocs: 0 B 0 allocs: 0 B
fused tuple kernel/4-ant N=3 0 allocs: 0 B 0 allocs: 0 B
track/1. Float32/2K – track 9 allocs: 944 B 9 allocs: 944 B
track/1. Float32/2K – track! 0 allocs: 0 B 0 allocs: 0 B
track/2. L1 8sat/5K – track 10 allocs: 4656 B 10 allocs: 4656 B
track/2. L1 8sat/5K – track! 0 allocs: 0 B 0 allocs: 0 B
track/2. L1 8sat/5K – track! Int16 13 allocs: 1056 B 13 allocs: 1056 B
track/2. L1 8sat/5K – track! OneBit 45 allocs: 2736 B 45 allocs: 2736 B
track/2. L1 8sat/5K – track!-threaded 0 allocs: 0 B 0 allocs: 0 B
track/2. L1 8sat/5K – track-threaded 10 allocs: 4656 B 10 allocs: 4656 B
track/3. E1B 4sat/25K – track 10 allocs: 3056 B 10 allocs: 3056 B
track/3. E1B 4sat/25K – track! 0 allocs: 0 B 0 allocs: 0 B
track/3. E1B 4sat/25K – track! Int16 5 allocs: 416 B 5 allocs: 416 B
track/3. E1B 4sat/25K – track!-threaded 0 allocs: 0 B 0 allocs: 0 B
track/3. E1B 4sat/25K – track-threaded 10 allocs: 3056 B 10 allocs: 3056 B
track/4. 8L1+8E1B/25K – track 26 allocs: 10464 B 26 allocs: 10464 B
track/4. 8L1+8E1B/25K – track! 0 allocs: 0 B 0 allocs: 0 B
track/4. 8L1+8E1B/25K – track!-threaded 0 allocs: 0 B 0 allocs: 0 B
track/4. 8L1+8E1B/25K – track-threaded 26 allocs: 10464 B 26 allocs: 10464 B
track/5. multi-signal N=1/5K – track 9 allocs: 944 B 9 allocs: 944 B
track/5. multi-signal N=1/5K – track! 0 allocs: 0 B 0 allocs: 0 B
track/6. multi-signal N=2/5K – track 9 allocs: 1408 B 9 allocs: 1408 B
track/6. multi-signal N=2/5K – track! 0 allocs: 0 B 0 allocs: 0 B
track/7. multi-signal N=3/5K – track 9 allocs: 1760 B 9 allocs: 1760 B
track/7. multi-signal N=3/5K – track! 0 allocs: 0 B 0 allocs: 0 B
track/8. L1CA presync 2 blk – track! 7 allocs: 320 B 7 allocs: 320 B
track/8. L1CA presync 20 blk – track! 7 allocs: 320 B 7 allocs: 320 B
track/8. L1CA synced 2 blk – track! 7 allocs: 320 B 7 allocs: 320 B
track/8. L1CA synced 20 blk – track! 7 allocs: 320 B 7 allocs: 320 B
time_to_load 196 allocs: 13984 B 200 allocs: 14176 B

@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Benchmark Results (minimum time) — ubuntu-latest

Reporting the minimum over all samples (robust to shared-runner contention), not the median.

Alternative backends vs Float32 (track!, PR head)

Legend — backends: F32 Float32 (default) · I16 Int16 · 1b OneBit · 2b TwoBit (2-bit measurement + 2-bit carrier). Time columns are the minimum track! time; ×B = F32 / B (so >1 ⇒ backend B is faster than Float32), ✅ ≥ 5 % faster, ⚠️ ≥ 5 % slower. 1b/2b are BPSK-only, so their cells are blank for CBOC (Galileo E1B) scenarios.

Scenario F32 I16 1b 2b ×I16 ×1b ×2b
4-antenna @ 5 MHz 12.2 μs 6.07 μs 5.2 μs 9.72 μs 2.01 ✅ 2.35 ✅ 1.26 ✅
GPS L1CA, 8 sats @ 40 MHz 331.0 μs 133.0 μs 70.6 μs 119.0 μs 2.48 ✅ 4.69 ✅ 2.77 ✅
GPS L1CA, 8 sats @ 5 MHz 49.1 μs 28.1 μs 20.0 μs 28.7 μs 1.75 ✅ 2.45 ✅ 1.71 ✅
Galileo E1B, 4 sats @ 25 MHz 122.0 μs 54.6 μs 2.24 ✅
dynamic taps @ 5 MHz (kernel) 5.77 μs 3.38 μs 2.07 μs 2.79 μs 1.71 ✅ 2.78 ✅ 2.07 ✅
multi-signal N=3 @ 5 MHz 9.51 μs 5.95 μs 5.42 μs 7.03 μs 1.6 ✅ 1.75 ✅ 1.35 ✅
Time benchmarks (base vs PR head)

Ratio = 99d37e1… / fba140b…: >1 means the PR is faster. ✅ ≥ 5 % faster, ⚠️ ≥ 5 % slower. A blank cell means the benchmark exists on only one revision (🆕 = new on the PR, 🗑 = removed).

99d37e1 fba140b 99d37e1… / fba140b
downconvert and correlate/CPU/Float32 2.33 μs 2.34 μs 0.999
downconvert and correlate/CPU/Float32 4ant 4.73 μs 4.72 μs 1.0
downconvert and correlate/CPU/Float64 2.75 μs 2.75 μs 1.0
downconvert and correlate/CPU/Int16 2.41 μs 2.41 μs 1.0
downconvert and correlate/CPU/Int16 4ant 5.17 μs 5.18 μs 0.997
downconvert and correlate/CPU/Int32 2.4 μs 2.39 μs 1.0
fused kernel/1-ant dynamic taps 2.16 μs 2.16 μs 1.0
fused kernel/1-ant static taps 1.88 μs 1.87 μs 1.0
fused kernel/4-ant dynamic taps 5.41 μs 5.43 μs 0.996
fused kernel/4-ant static taps 4.15 μs 4.14 μs 1.0
fused tuple kernel/1-ant N=2 2.35 μs 2.36 μs 0.996
fused tuple kernel/1-ant N=3 2.82 μs 2.81 μs 1.0
fused tuple kernel/2-ant N=2 3.59 μs 3.6 μs 0.999
fused tuple kernel/2-ant N=3 4.57 μs 4.54 μs 1.01
fused tuple kernel/4-ant N=2 6.04 μs 5.98 μs 1.01
fused tuple kernel/4-ant N=3 9.74 μs 9.76 μs 0.998
track/1. Float32/2K – track 2.57 μs 2.54 μs 1.01
track/1. Float32/2K – track! 2.64 μs 2.64 μs 1.0
track/2. L1 8sat/5K – track 47.8 μs 47.6 μs 1.0
track/2. L1 8sat/5K – track! 47.6 μs 47.1 μs 1.01
track/2. L1 8sat/5K – track! Int16 28.1 μs 27.8 μs 1.01
track/2. L1 8sat/5K – track! OneBit 20.0 μs 21.1 μs 0.947 ⚠️
track/2. L1 8sat/5K – track!-threaded 47.2 μs 47.2 μs 1.0
track/2. L1 8sat/5K – track-threaded 47.7 μs 47.7 μs 1.0
track/3. E1B 4sat/25K – track 117.0 μs 118.0 μs 0.999
track/3. E1B 4sat/25K – track! 117.0 μs 117.0 μs 0.998
track/3. E1B 4sat/25K – track! Int16 54.4 μs 54.8 μs 0.993
track/3. E1B 4sat/25K – track!-threaded 117.0 μs 117.0 μs 0.999
track/3. E1B 4sat/25K – track-threaded 117.0 μs 118.0 μs 0.999
track/4. 8L1+8E1B/25K – track 433.0 μs 433.0 μs 1.0
track/4. 8L1+8E1B/25K – track! 432.0 μs 432.0 μs 0.999
track/4. 8L1+8E1B/25K – track!-threaded 431.0 μs 431.0 μs 0.999
track/4. 8L1+8E1B/25K – track-threaded 434.0 μs 435.0 μs 0.998
track/5. multi-signal N=1/5K – track 6.14 μs 6.1 μs 1.01
track/5. multi-signal N=1/5K – track! 6.12 μs 6.13 μs 0.999
track/6. multi-signal N=2/5K – track 8.42 μs 8.34 μs 1.01
track/6. multi-signal N=2/5K – track! 8.53 μs 8.51 μs 1.0
track/7. multi-signal N=3/5K – track 10.7 μs 10.6 μs 1.0
track/7. multi-signal N=3/5K – track! 10.9 μs 10.8 μs 1.01
track/8. L1CA presync 2 blk – track! 11.6 μs 11.7 μs 0.996
track/8. L1CA presync 20 blk – track! 113.0 μs 113.0 μs 1.0
track/8. L1CA synced 2 blk – track! 11.5 μs 11.6 μs 0.992
track/8. L1CA synced 20 blk – track! 111.0 μs 111.0 μs 0.999
time_to_load 101.0 μs 104.0 μs 0.974
Memory benchmarks (base vs PR head)
99d37e1 fba140b
downconvert and correlate/CPU/Float32 2 allocs: 576 B 2 allocs: 576 B
downconvert and correlate/CPU/Float32 4ant 2 allocs: 848 B 2 allocs: 848 B
downconvert and correlate/CPU/Float64 2 allocs: 576 B 2 allocs: 576 B
downconvert and correlate/CPU/Int16 2 allocs: 576 B 2 allocs: 576 B
downconvert and correlate/CPU/Int16 4ant 2 allocs: 848 B 2 allocs: 848 B
downconvert and correlate/CPU/Int32 2 allocs: 576 B 2 allocs: 576 B
fused kernel/1-ant dynamic taps 0 allocs: 0 B 0 allocs: 0 B
fused kernel/1-ant static taps 0 allocs: 0 B 0 allocs: 0 B
fused kernel/4-ant dynamic taps 0 allocs: 0 B 0 allocs: 0 B
fused kernel/4-ant static taps 0 allocs: 0 B 0 allocs: 0 B
fused tuple kernel/1-ant N=2 0 allocs: 0 B 0 allocs: 0 B
fused tuple kernel/1-ant N=3 0 allocs: 0 B 0 allocs: 0 B
fused tuple kernel/2-ant N=2 0 allocs: 0 B 0 allocs: 0 B
fused tuple kernel/2-ant N=3 0 allocs: 0 B 0 allocs: 0 B
fused tuple kernel/4-ant N=2 0 allocs: 0 B 0 allocs: 0 B
fused tuple kernel/4-ant N=3 0 allocs: 0 B 0 allocs: 0 B
track/1. Float32/2K – track 9 allocs: 944 B 9 allocs: 944 B
track/1. Float32/2K – track! 0 allocs: 0 B 0 allocs: 0 B
track/2. L1 8sat/5K – track 10 allocs: 4536 B 10 allocs: 4536 B
track/2. L1 8sat/5K – track! 0 allocs: 0 B 0 allocs: 0 B
track/2. L1 8sat/5K – track! Int16 13 allocs: 1056 B 13 allocs: 1056 B
track/2. L1 8sat/5K – track! OneBit 45 allocs: 2736 B 45 allocs: 2736 B
track/2. L1 8sat/5K – track!-threaded 0 allocs: 0 B 0 allocs: 0 B
track/2. L1 8sat/5K – track-threaded 10 allocs: 4536 B 10 allocs: 4536 B
track/3. E1B 4sat/25K – track 10 allocs: 2808 B 10 allocs: 2808 B
track/3. E1B 4sat/25K – track! 0 allocs: 0 B 0 allocs: 0 B
track/3. E1B 4sat/25K – track! Int16 5 allocs: 416 B 5 allocs: 416 B
track/3. E1B 4sat/25K – track!-threaded 0 allocs: 0 B 0 allocs: 0 B
track/3. E1B 4sat/25K – track-threaded 10 allocs: 2808 B 10 allocs: 2808 B
track/4. 8L1+8E1B/25K – track 26 allocs: 10352 B 26 allocs: 10352 B
track/4. 8L1+8E1B/25K – track! 0 allocs: 0 B 0 allocs: 0 B
track/4. 8L1+8E1B/25K – track!-threaded 0 allocs: 0 B 0 allocs: 0 B
track/4. 8L1+8E1B/25K – track-threaded 26 allocs: 10352 B 26 allocs: 10352 B
track/5. multi-signal N=1/5K – track 9 allocs: 944 B 9 allocs: 944 B
track/5. multi-signal N=1/5K – track! 0 allocs: 0 B 0 allocs: 0 B
track/6. multi-signal N=2/5K – track 9 allocs: 1408 B 9 allocs: 1408 B
track/6. multi-signal N=2/5K – track! 0 allocs: 0 B 0 allocs: 0 B
track/7. multi-signal N=3/5K – track 9 allocs: 1760 B 9 allocs: 1760 B
track/7. multi-signal N=3/5K – track! 0 allocs: 0 B 0 allocs: 0 B
track/8. L1CA presync 2 blk – track! 7 allocs: 320 B 7 allocs: 320 B
track/8. L1CA presync 20 blk – track! 7 allocs: 320 B 7 allocs: 320 B
track/8. L1CA synced 2 blk – track! 7 allocs: 320 B 7 allocs: 320 B
track/8. L1CA synced 20 blk – track! 7 allocs: 320 B 7 allocs: 320 B
time_to_load 145 allocs: 11216 B 145 allocs: 11216 B

Add a required AbstractDopplerEstimator interface function reporting the
maximum acquisition carrier-Doppler error a freshly-acquired satellite can
carry and still be pulled into carrier lock. A GNSS receiver can use it to
pick the smallest satellite acquisition Doppler resolution needed to lock.

The integration length is derived from the loop's own
calc_num_code_blocks_to_integrate in the pre-sync state, so only the signal
is needed. ConventionalPLLAndDLL implements two methods:
- FLL-assisted: crisp 1/(4T) FLL-discriminator bound
- pure PLL: min(B_L, 1/(2T)) fast lock-in approximation

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@giove-a
giove-a force-pushed the sc/get-pull-in-range branch from 7a5f408 to fba140b Compare July 9, 2026 04:58
@codecov

codecov Bot commented Jul 9, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 97.64%. Comparing base (99d37e1) to head (fba140b).

Additional details and impacted files
@@            Coverage Diff             @@
##           master     #193      +/-   ##
==========================================
- Coverage   97.87%   97.64%   -0.24%     
==========================================
  Files          32       32              
  Lines        3296     3306      +10     
==========================================
+ Hits         3226     3228       +2     
- Misses         70       78       +8     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@siebc

siebc commented Jul 14, 2026

Copy link
Copy Markdown
Member

This feature can also be implemented directly in a GNSS receiver using Tracking.jl.

@siebc siebc closed this Jul 14, 2026
@siebc
siebc deleted the sc/get-pull-in-range branch July 14, 2026 06:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants