API Reference
Acquisition Functions
Acquisition.acquire — Function
acquire(system, signal, sampling_freq, prns; kwargs...) -> Vector{AcquisitionResults}Convenience wrapper: calls plan_acquire then acquire!.
Arguments
system: GNSS system (e.g.GPSL1())signal: Complex baseband signal samplessampling_freq: Sampling frequencyprns: PRN numbers to search
Keyword Arguments forwarded to plan_acquire:
min_doppler_coverage: Minimum one-sided Doppler coverage (default:7000Hz)num_coherently_integrated_code_periods: Code periods per coherent block (default:1)bit_edge_search_steps: Bit edge search positions (default:1)num_noncoherent_accumulations: Non-coherent integration steps (default:1)fft_flag: FFTW planning flag (default:FFTW.MEASURE)
Keyword Arguments forwarded to acquire!:
interm_freq: Intermediate frequency (default:0.0Hz)subsample_interpolation: Enable parabolic interpolation (default:false)store_power_bins: Retain the full correlation power surface in each result for plotting (default:false)
Returns
Vector{AcquisitionResults}, one per PRN.
See also
acquire(system, signal, sampling_freq, prn::Integer; kwargs...) -> AcquisitionResultsSingle-PRN convenience method. Returns a single AcquisitionResults.
Acquisition.acquire! — Function
acquire!(plan::AcquisitionPlan, signal, prns; interm_freq=0.0Hz, subsample_interpolation=false, store_power_bins=false) -> Vector{AcquisitionResults}Perform FM-DBZP acquisition using a pre-computed AcquisitionPlan.
Reuses all pre-allocated buffers in plan. Multiple PRNs are processed in a single pass.
Arguments
plan: Pre-computedAcquisitionPlan(fromplan_acquire)signal: Complex baseband signal samplesprns: PRN numbers to search (must be a subset ofplan.avail_prns)
Keyword Arguments
interm_freq: Intermediate frequency (default:0.0Hz)subsample_interpolation: Whentrue, apply parabolic interpolation to refine the code phase and Doppler estimates below the grid resolution (default:false)store_power_bins: Whentrue, copy the full Doppler × code-phase correlation power matrix into each result'spower_binsfield (required for plotting). Whenfalse,power_binsisnothingand no extra copy is made (default:false)
Returns
Vector{AcquisitionResults}, one entry per PRN in prns.
See also
acquire!(plan::AcquisitionPlan, signal, prn::Integer; kwargs...) -> AcquisitionResultsSingle-PRN convenience method. Calls the multi-PRN acquire! and returns the single result.
Acquisition.plan_acquire — Function
plan_acquire(system, sampling_freq, prns; kwargs...) -> AcquisitionPlanPre-compute an acquisition plan for FM-DBZP acquisition.
Allocates all buffers, computes FFT plans, and pre-computes conjugated PRN FFTs. The returned plan can be passed to acquire! repeatedly without re-allocating. Per-thread scratch buffers are sized for Threads.maxthreadid() at the time of the call; start Julia with -t N before calling plan_acquire to enable multi-threaded acquisition.
Arguments
system: GNSS system (e.g.GPSL1())sampling_freq: Sampling frequencyprns: PRN numbers to pre-compute (e.g.1:32)
Keyword Arguments
min_doppler_coverage: Minimum guaranteed one-sided Doppler reach (default:7000Hz). Both ends of the searched grid will be at least±min_doppler_coverage. Controlsnum_blocks— see Algorithm Constraints and Trade-offs for details.num_coherently_integrated_code_periods: Number of code periods per coherent integration block (default:1). Determines Doppler resolution:bin_spacing = 1 / (num_coherently_integrated_code_periods × T_code).bit_edge_search_steps: Number of bit-edge alignment candidates to search (default:1, disabled). Must dividebit_period_codes. Only valid whennum_coherently_integrated_code_periods > 1.num_noncoherent_accumulations: Number of successive incoherent integration steps (default:1). Signal passed toacquire!must contain at leastnum_noncoherent_accumulationsfull segments.fft_flag: FFTW planning flag (default:FFTW.MEASURE).
See also
Acquisition.cfar_threshold — Function
cfar_threshold(pfa, num_cells; num_noncoherent_integrations=1)Compute the CFAR (Constant False Alarm Rate) detection threshold for a given probability of false alarm.
The threshold is computed so that the probability of any noise-only cell in the search grid exceeding the threshold equals pfa. This accounts for the multiple hypothesis testing across all num_cells search cells (code phases × Doppler bins) using a Bonferroni-like correction.
The test statistic is peak_power / noise_power (the peak_to_noise_ratio field of AcquisitionResults).
Arguments
pfa: Target probability of false alarm (e.g.,0.01). Must be in(0, 1).num_cells: Total number of search cells (typicallynum_code_phases * num_doppler_bins).
Keyword Arguments
num_noncoherent_integrations: Number of non-coherent integration dwells (default:1). More dwells increase the degrees of freedom of the chi-squared distribution.
Returns
Threshold value to compare against result.peak_to_noise_ratio.
Example
using Acquisition, GNSSSignals
system = GPSL1()
(; signal, sampling_freq, interm_freq) = generate_test_signal(system, 1)
results = acquire(system, signal, sampling_freq, 1:32; interm_freq)
detected = filter(is_detected, results)Mathematical Background
Under the null hypothesis (noise only), each power bin |I|² + |Q|² is χ²(2)-distributed with mean 2 (Springer Handbook of GNSS, Eq. 14.26). After M non-coherent integrations the raw power S_nc ~ χ²(2M) (Eq. 14.28). The test statistic peak_to_noise_ratio = S_nc / noise_power where noise_power ≈ 2M, so peak_to_noise_ratio ~ Gamma(M, 1/M) with mean 1 under H0.
The per-cell false alarm probability is adjusted for multiple testing: pfa_per_cell = 1 - (1 - pfa)^(1/num_cells).
The threshold is then the inverse CDF (quantile) of the chi-squared distribution at 1 - pfa_per_cell.
References
- Springer Handbook of GNSS, Section 14.3.1 "Test Statistics", Eq. 14.28–14.30
- GNSS-SDR PCPS Acquisition:
pcps_acquisition::calculate_threshold() - Kay Borre et al., "A Software-Defined GPS and Galileo Receiver", Birkhäuser, 2007
See also
Acquisition.is_detected — Function
is_detected(result::AcquisitionResults; pfa=0.01) -> BoolReturn true if the satellite signal is detected at the given probability of false alarm. Compares result.peak_to_noise_ratio against cfar_threshold, using the number of search cells and non-coherent integrations stored in the result.
Acquisition.get_num_cells — Function
get_num_cells(result::AcquisitionResults) -> IntReturn the number of search cells (Doppler bins × code phases) in the acquisition result. This is the num_cells argument expected by cfar_threshold.
Acquisition.generate_test_signal — Function
generate_test_signal(system, prn; kwargs...) -> NamedTupleGenerate a synthetic noisy GNSS signal. Useful for testing acquisition and demonstrating the API.
Returns a NamedTuple with fields: signal, code, carrier, num_samples, doppler, code_phase, sampling_freq, interm_freq, CN0, prn.
Keywords
seed=2345: Random seed for reproducibilitynum_samples=60000: Number of signal samplesdoppler=1234Hz: Carrier Doppler frequencycode_phase=110.613261: True code phase in chipssampling_freq=15e6Hz - 1Hz: Sampling frequencyinterm_freq=243.0Hz: Intermediate frequencyCN0=45: Carrier-to-noise density ratio (dB-Hz)phase_offset=π/8: Carrier phase offsetunit_noise_power=false: When true, scale so noise power ≈ 1; when false, scale so signal power corresponds directly to CN0
Example
using Acquisition, GNSSSignals
(; signal, prn, sampling_freq, interm_freq) = generate_test_signal(GPSL1(), 1)
result = acquire(GPSL1(), signal, sampling_freq, prn; interm_freq)
is_detected(result) # trueAcquisition.recommend_sampling_freqs — Function
recommend_sampling_freqs(code_length, code_freq;
fs_min = code_freq,
fs_max = 1.5 * fs_min,
min_doppler_coverage = 7000Hz,
num_coherently_integrated_code_periods = 1,
num_alternatives = 5,
max_prime = 7,
sort_by = :cost,
fs_step = 1000Hz,
sdr_clock_plan = nothing,
) -> Vector{SamplingFreqRecommendation}Search the range [fs_min, fs_max] for sampling frequencies with smooth-prime factorizations and return the num_alternatives best candidates.
The smallest valid num_blocks (the one plan_acquire would pick) is computed for every candidate, and candidates are ranked by either FFT cost or factorization smoothness. Candidates with the same samples_per_code are deduplicated — the first matching sampling_freq is reported.
Arguments
code_length: Number of chips per PRN code periodcode_freq: Code chipping rate (a frequency, e.g.1.023e6Hz)
Keyword Arguments
fs_min,fs_max: Sweep bounds for the sampling frequencymin_doppler_coverage: Minimum guaranteed one-sided Doppler reach. The recommender mirrorsplan_acquire— both ends of the searched grid will be at least±min_doppler_coverage.num_coherently_integrated_code_periods: Number of code periods per coherent integration block. Affectsnum_doppler_binsand therefore the column-FFT cost.num_alternatives: Maximum number of candidates to return (default5)max_prime: Reject candidates whosesamples_per_code,inner_fft_size, ornum_doppler_binscontain a prime factor larger than this value (default7— FFTW's "fast" regime)sort_by::cost(default) ranks by estimated FFT FLOPs;:smoothnessranks by largest prime factor ofinner_fft_size(ties broken by cost)fs_step: Sampling-frequency sweep step (default1000Hz)sdr_clock_plan: OptionalAbstractSDRClockPlandescribing hardware sample-rate constraints. When provided, the sweep range is intersected withsample_rate_range(plan)and every candidate must satisfyis_valid_sample_rate(plan, fs). Defaultnothing— no hardware filtering.
Cost Model
Both FFT stages of FM-DBZP are accounted for:
inner_fft_cost = 2 × num_blocks × inner_fft_size × log₂(inner_fft_size)
column_fft_cost = samples_per_code × num_doppler_bins × log₂(num_doppler_bins)
cost = inner_fft_cost + column_fft_costThis mirrors the per-PRN per coherent-step work, ignoring constant factors.
See also
recommend_sampling_freqs(system::AbstractGNSS; kwargs...) -> Vector{SamplingFreqRecommendation}Convenience method that derives code_length and code_freq from system via get_code_length(system) and get_code_frequency(system).
All keyword arguments are forwarded to recommend_sampling_freqs(::Integer, ::Any).
Acquisition.is_valid_sample_rate — Function
is_valid_sample_rate(plan::AbstractSDRClockPlan, fs_hz::Real) -> BoolReturn true if fs_hz is reachable by the SDR described by plan.
Acquisition.sample_rate_range — Function
sample_rate_range(plan::AbstractSDRClockPlan) -> Tuple{Float64,Float64}Return (fs_min_hz, fs_max_hz), the inclusive sample-rate envelope of the SDR. Used by recommend_sampling_freqs to clamp the sweep range. The default fallback returns (0.0, Inf) so concrete plans only need to override it when there's a meaningful envelope.
Types
Acquisition.AcquisitionResults — Type
AcquisitionResults{S,T}Results from GNSS signal acquisition for a single PRN.
Fields
system::S: GNSS system used for acquisitionprn::Int: PRN number of the satellitesampling_frequency: Sampling frequency of the signalcarrier_doppler: Estimated carrier Doppler frequencycode_phase::Float64: Estimated code phase in chipsCN0::Float64: Carrier-to-noise density ratio in dB-Hznoise_power::T: Estimated noise powerpeak_to_noise_ratio::T: Ratio of peak correlation power to estimated noise power (peak_power / noise_power). Compare againstcfar_thresholdto decide if a satellite is present.num_noncoherent_integrations::Int: Number of non-coherent integrations performedpower_bins::Matrix{T}: Correlation power over Doppler × code phase (for plotting)dopplers: Doppler frequencies searchednum_blocks::Int: FM-DBZP number of blocks per code periodblock_size::Int: FM-DBZP samples per block
Plotting
AcquisitionResults can be plotted directly using Plots.jl:
using Plots
plot(result) # heatmap of correlation power (chip-axis sorted)
plot(result, true) # Use log scale (dB)See also
Acquisition.AcquisitionPlan — Type
AcquisitionPlanPre-computed acquisition plan for FM-DBZP (Heckler & Garrison 2009).
See plan_acquire and acquire.
Acquisition.SamplingFreqRecommendation — Type
SamplingFreqRecommendationA single sampling-frequency candidate from recommend_sampling_freqs.
Fields
sampling_freq::typeof(1.0Hz): Sampling frequencysamples_per_code::Int: Samples per PRN code period at thissampling_freqnum_blocks::Int: Smallest validnum_blocksthat meetsmin_doppler_coverage(= the valueplan_acquirewould pick)block_size::Int:samples_per_code ÷ num_blocksinner_fft_size::Int: Inner double-block FFT length (2 × block_size)num_doppler_bins::Int: Column-FFT length (num_coherently_integrated_code_periods × num_blocks)doppler_coverage::typeof(1.0Hz): Total Doppler coverage at this configurationinner_max_prime::Int: Largest prime factor ofinner_fft_size— smaller is better for FFTWnum_doppler_bins_max_prime::Int: Largest prime factor ofnum_doppler_binscost::Float64: Estimated combined FFT cost (inner_fft_cost + column_fft_cost, seerecommend_sampling_freqs)
Acquisition.AbstractSDRClockPlan — Type
AbstractSDRClockPlanHardware constraints that decide which sampling frequencies an SDR can produce.
Concrete subtypes implement is_valid_sample_rate. They may also override sample_rate_range to narrow the sweep range.
See AD9361ClockPlan for an example implementation.
Acquisition.AD9361ClockPlan — Type
AD9361ClockPlan(; ref_clk = 38.4e6, adc_clk_min = 25e6, adc_clk_max = 640e6,
fs_min = 0.55e6, fs_max = 61.44e6,
bbpll_min = 715e6, bbpll_max = 1430e6,
bbpll_div_min = 2, bbpll_div_max = 64,
dividers = [12, 8, 6, 4, 3, 2, 1])Sample-rate validation for the Analog Devices AD9361 RFIC, as used by the LiteX-M2SDR and many other SDR boards.
A sample rate fs is reachable when some divider d ∈ dividers makes adc_clk = fs × d land in [adc_clk_min, adc_clk_max], and that adc_clk can be reached from the BBPLL: adc_clk × bbpll_div ∈ [bbpll_min, bbpll_max] for some power-of-two bbpll_div ∈ [bbpll_div_min, bbpll_div_max].
The defaults reproduce the limits in the AD9361 driver shipped with litex_m2sdr (see software/user/ad9361/ad9361.h).
Index
Acquisition.AD9361ClockPlanAcquisition.AbstractSDRClockPlanAcquisition.AcquisitionPlanAcquisition.AcquisitionResultsAcquisition.SamplingFreqRecommendationAcquisition.acquireAcquisition.acquire!Acquisition.cfar_thresholdAcquisition.generate_test_signalAcquisition.get_num_cellsAcquisition.is_detectedAcquisition.is_valid_sample_rateAcquisition.plan_acquireAcquisition.recommend_sampling_freqsAcquisition.sample_rate_range