API Reference

Acquisition Functions

Acquisition.acquireFunction
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 samples
  • sampling_freq: Sampling frequency
  • prns: 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

plan_acquire, acquire!

source
acquire(system, signal, sampling_freq, prn::Integer; kwargs...) -> AcquisitionResults

Single-PRN convenience method. Returns a single AcquisitionResults.

source
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-computed AcquisitionPlan (from plan_acquire)
  • signal: Complex baseband signal samples
  • prns: PRN numbers to search (must be a subset of plan.avail_prns)

Keyword Arguments

  • interm_freq: Intermediate frequency (default: 0.0Hz)
  • subsample_interpolation: When true, apply parabolic interpolation to refine the code phase and Doppler estimates below the grid resolution (default: false)
  • store_power_bins: When true, copy the full Doppler × code-phase correlation power matrix into each result's power_bins field (required for plotting). When false, power_bins is nothing and no extra copy is made (default: false)

Returns

Vector{AcquisitionResults}, one entry per PRN in prns.

See also

acquire, plan_acquire

source
acquire!(plan::AcquisitionPlan, signal, prn::Integer; kwargs...) -> AcquisitionResults

Single-PRN convenience method. Calls the multi-PRN acquire! and returns the single result.

source
Acquisition.plan_acquireFunction
plan_acquire(system, sampling_freq, prns; kwargs...) -> AcquisitionPlan

Pre-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 frequency
  • prns: 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. Controls num_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 divide bit_period_codes. Only valid when num_coherently_integrated_code_periods > 1.
  • num_noncoherent_accumulations: Number of successive incoherent integration steps (default: 1). Signal passed to acquire! must contain at least num_noncoherent_accumulations full segments.
  • fft_flag: FFTW planning flag (default: FFTW.MEASURE).

See also

acquire!, acquire

source
Acquisition.cfar_thresholdFunction
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 (typically num_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

AcquisitionResults, acquire

source
Acquisition.is_detectedFunction
is_detected(result::AcquisitionResults; pfa=0.01) -> Bool

Return 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.

source
Acquisition.get_num_cellsFunction
get_num_cells(result::AcquisitionResults) -> Int

Return the number of search cells (Doppler bins × code phases) in the acquisition result. This is the num_cells argument expected by cfar_threshold.

source
Acquisition.generate_test_signalFunction
generate_test_signal(system, prn; kwargs...) -> NamedTuple

Generate 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 reproducibility
  • num_samples=60000: Number of signal samples
  • doppler=1234Hz: Carrier Doppler frequency
  • code_phase=110.613261: True code phase in chips
  • sampling_freq=15e6Hz - 1Hz: Sampling frequency
  • interm_freq=243.0Hz: Intermediate frequency
  • CN0=45: Carrier-to-noise density ratio (dB-Hz)
  • phase_offset=π/8: Carrier phase offset
  • unit_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)  # true
source
Acquisition.recommend_sampling_freqsFunction
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 period
  • code_freq: Code chipping rate (a frequency, e.g. 1.023e6Hz)

Keyword Arguments

  • fs_min, fs_max: Sweep bounds for the sampling frequency
  • min_doppler_coverage: Minimum guaranteed one-sided Doppler reach. The recommender mirrors plan_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. Affects num_doppler_bins and therefore the column-FFT cost.
  • num_alternatives: Maximum number of candidates to return (default 5)
  • max_prime: Reject candidates whose samples_per_code, inner_fft_size, or num_doppler_bins contain a prime factor larger than this value (default 7 — FFTW's "fast" regime)
  • sort_by: :cost (default) ranks by estimated FFT FLOPs; :smoothness ranks by largest prime factor of inner_fft_size (ties broken by cost)
  • fs_step: Sampling-frequency sweep step (default 1000Hz)
  • sdr_clock_plan: Optional AbstractSDRClockPlan describing hardware sample-rate constraints. When provided, the sweep range is intersected with sample_rate_range(plan) and every candidate must satisfy is_valid_sample_rate(plan, fs). Default nothing — 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_cost

This mirrors the per-PRN per coherent-step work, ignoring constant factors.

See also

recommend_sampling_freqs(::AbstractGNSS), plan_acquire

source
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).

source
Acquisition.sample_rate_rangeFunction
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.

source

Types

Acquisition.AcquisitionResultsType
AcquisitionResults{S,T}

Results from GNSS signal acquisition for a single PRN.

Fields

  • system::S: GNSS system used for acquisition
  • prn::Int: PRN number of the satellite
  • sampling_frequency: Sampling frequency of the signal
  • carrier_doppler: Estimated carrier Doppler frequency
  • code_phase::Float64: Estimated code phase in chips
  • CN0::Float64: Carrier-to-noise density ratio in dB-Hz
  • noise_power::T: Estimated noise power
  • peak_to_noise_ratio::T: Ratio of peak correlation power to estimated noise power (peak_power / noise_power). Compare against cfar_threshold to decide if a satellite is present.
  • num_noncoherent_integrations::Int: Number of non-coherent integrations performed
  • power_bins::Matrix{T}: Correlation power over Doppler × code phase (for plotting)
  • dopplers: Doppler frequencies searched
  • num_blocks::Int: FM-DBZP number of blocks per code period
  • block_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

acquire, plan_acquire

source
Acquisition.SamplingFreqRecommendationType
SamplingFreqRecommendation

A single sampling-frequency candidate from recommend_sampling_freqs.

Fields

  • sampling_freq::typeof(1.0Hz): Sampling frequency
  • samples_per_code::Int: Samples per PRN code period at this sampling_freq
  • num_blocks::Int: Smallest valid num_blocks that meets min_doppler_coverage (= the value plan_acquire would pick)
  • block_size::Int: samples_per_code ÷ num_blocks
  • inner_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 configuration
  • inner_max_prime::Int: Largest prime factor of inner_fft_size — smaller is better for FFTW
  • num_doppler_bins_max_prime::Int: Largest prime factor of num_doppler_bins
  • cost::Float64: Estimated combined FFT cost (inner_fft_cost + column_fft_cost, see recommend_sampling_freqs)
source
Acquisition.AD9361ClockPlanType
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).

source

Index