feat(estimator): add carrier_doppler_pull_in_range interface#193
feat(estimator): add carrier_doppler_pull_in_range interface#193giove-a wants to merge 1 commit into
Conversation
c7872ac to
7a5f408
Compare
Benchmark Results (minimum time) — macos-14Reporting the minimum over all samples (robust to shared-runner contention), not the median. Alternative backends vs Float32 (
|
| 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,
| 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 |
Benchmark Results (minimum time) — ubuntu-latestReporting the minimum over all samples (robust to shared-runner contention), not the median. Alternative backends vs Float32 (
|
| 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,
| 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>
7a5f408 to
fba140b
Compare
Codecov Report✅ All modified and coverable lines are covered by tests. 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. 🚀 New features to boost your workflow:
|
|
This feature can also be implemented directly in a GNSS receiver using Tracking.jl. |
What
Adds
carrier_doppler_pull_in_range(estimator, signal)— a doppler-estimatorinterface 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
sat_state.jl,beside
init_estimator_state(the analogous mandatory per-estimator hook).Unimplemented estimators raise a
MethodError, matching the existingconvention.
ConventionalPLLAndDLL(FLL-assisted, the default): returns1/(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-inapproximation
min(B_L, 1/(2·T))(Gardner/Best),B_Ltaken from theestimator config (auto-resolved via
default_carrier_loop_filter_bandwidthwhen unset). Documented as an order-of-magnitude estimate, not a hard bound.
handover_coherent_integration_time(signal)helper insample_parameters.jl, besidecalc_num_code_blocks_to_integrate: derivesthe start-of-tracking integration time from the loop's own machinery
(pre-sync,
secondary_code_or_bit_found = false) rather than assuming afixed 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·rangeis the theoretical maximum, not a safe target — size narrowerfor margin. Documented accordingly.
Notes
called inside
track!.Testing
test/conventional_pll_and_dll.jlcovering the FLL values, thepure-PLL approximation + bandwidth cap, and the required-interface
MethodError.test/runtests.jlpasses locally (exit 0; Flexiband integration testskipped as usual — it needs the 1.6 GB capture download).
🤖 Generated with Claude Code