Project 10: The Space Compass (GPS L1 C/A Tracker)

Build a GPS L1 C/A acquisition and tracking pipeline that detects visible satellites and reports PRN, Doppler, and code phase from raw IQ data.

Quick Reference

Attribute Value
Difficulty Level 5: Master
Time Estimate 6-8 weeks
Main Programming Language C (Alternatives: Rust, Python for slow prototypes)
Alternative Programming Languages C++, Julia
Coolness Level Extreme
Business Potential 7/10 (GNSS tooling, navigation research)
Prerequisites DSP, complex numbers, FFTs, basic estimation theory
Key Topics PRN generation, correlation, acquisition search, DLL/PLL tracking

1. Learning Objectives

By completing this project, you will:

  1. Generate GPS C/A PRN codes and understand their correlation properties.
  2. Implement acquisition using coherent and non-coherent integration across Doppler bins.
  3. Build tracking loops (DLL/PLL) to maintain code and carrier lock.
  4. Output stable PRN, code phase, and Doppler estimates from real IQ captures.
  5. Construct deterministic tests using synthetic GPS signals.

2. All Theory Needed (Per-Concept Breakdown)

2.1 GPS L1 C/A Signal Structure and PRN Codes

Fundamentals

GPS L1 C/A is a spread-spectrum signal centered at 1575.42 MHz. Each satellite transmits a unique PRN (Pseudo-Random Noise) code at 1.023 Mcps. The PRN code repeats every 1 ms and spreads the energy of the signal across a wide band so it appears below the noise floor. A 50 bps navigation message is XORed with the PRN, meaning each data bit lasts 20 ms. To detect a satellite, you must generate the same PRN code locally, align it in time, and correlate with the incoming samples. If the code alignment and Doppler are correct, the correlation produces a strong peak. Understanding the structure of the PRN code and its repetition is the foundation for acquisition and tracking.

Deep Dive into the Concept

The GPS L1 C/A signal is a BPSK(1) modulation of the carrier using a 1.023 Mcps spreading code. The C/A code is a Gold code generated by XORing two 10-bit LFSRs (G1 and G2) with specific tap selections per PRN. The resulting 1023-chip sequence has excellent auto-correlation properties: it correlates strongly with itself at the correct alignment and weakly elsewhere. This property is what allows detection of signals below the noise floor. In practice, the received signal is the product of three components: the carrier (with Doppler shift), the PRN code, and the navigation data bit. The navigation data bit flips every 20 ms, which can invert the correlation sign if you integrate too long without bit compensation.

The PRN code period is exactly 1 ms. This means acquisition can be done in 1 ms coherent blocks, which simplifies correlation. However, to improve SNR, you may integrate multiple milliseconds either coherently (phase-sensitive) or non-coherently (magnitude-squared). Coherent integration is more efficient but is limited by navigation bit transitions and by residual carrier phase error. Non-coherent integration can span many milliseconds by summing magnitudes, improving detection at the cost of some sensitivity.

The signal structure also imposes precise timing. The GPS chip period is about 977.5 ns. At a 5 MHz sample rate, you get roughly 4.89 samples per chip, which is not an integer. This requires fractional resampling or a code NCO (numerically controlled oscillator) that generates the PRN at fractional chip phases. A tracking loop will continuously adjust the code phase to stay aligned. If your code phase drifts by even half a chip, the correlation peak degrades significantly.

The navigation message is framed into 30-bit words with parity and grouped into 1500-bit subframes lasting 6 seconds. While full navigation decoding is beyond the core acquisition task, the presence of the nav data affects correlation. You must either limit coherent integration to 20 ms or use data wipe-off after bit synchronization. Many acquisition pipelines start with short (1-10 ms) coherent integration to avoid bit flips.

PRN generation itself is an important engineering task. The G1 and G2 LFSRs run at 1.023 MHz with specific tap feedback. Each PRN uses a unique phase tap pair from G2. You must verify that your PRN implementation matches official tables because any mismatch yields no correlation peak. A good practice is to generate a PRN and compute its autocorrelation to confirm the sharp peak at zero lag and low sidelobes elsewhere.

Finally, the received signal experiences Doppler shifts up to about +/- 5 kHz due to satellite motion and receiver clock error. This shifts the carrier and slightly stretches the code. The effect on code rate is small but non-negligible. Acquisition typically handles Doppler by mixing with candidate Doppler bins and searching for the peak. A correct understanding of the signal structure guides the design of your acquisition grid and tracking loops.

How this fits on projects

  • You will generate PRN codes in Section 4.3 and Section 5.10 Phase 1.
  • PRN properties are used again in P04 ADS-B Decoder as a contrast to non-spread signals.

Definitions & key terms

  • PRN code: Pseudo-random sequence used to spread the signal.
  • Chip: One element of the PRN code.
  • Gold code: PRN generated by XORing two maximal-length sequences.
  • Navigation data: 50 bps message modulating the PRN.
  • Doppler: Frequency shift due to motion and clock error.

Mental model diagram (ASCII)

Carrier * PRN code * Nav data -> Received IQ -> Correlate with local PRN

How it works (step-by-step, with invariants and failure modes)

  1. Generate PRN code sequence for a given satellite.
  2. Repeat the code every 1023 chips (1 ms).
  3. Multiply the incoming baseband with the local PRN (correlation).
  4. Search for a strong correlation peak.

Invariants:

  • PRN length is 1023 chips.
  • C/A chip rate is 1.023 Mcps.

Failure modes:

  • Wrong PRN tap selection yields no correlation peak.
  • Misinterpreted sample rate causes code phase drift.

Minimal concrete example

import numpy as np

# Minimal PRN1 generator (G1/G2 LFSRs)
def ca_prn1():
    g1 = [1]*10
    g2 = [1]*10
    code = []
    for _ in range(1023):
        g1_out = g1[-1]
        g2_out = g2[-2] ^ g2[-6]  # PRN1 taps (2,6)
        code.append(g1_out ^ g2_out)
        g1_fb = g1[2] ^ g1[9]      # taps 3,10
        g2_fb = g2[1] ^ g2[2] ^ g2[5] ^ g2[7] ^ g2[8] ^ g2[9]  # taps 2,3,6,8,9,10
        g1 = [g1_fb] + g1[:-1]
        g2 = [g2_fb] + g2[:-1]
    return np.array(code)*2-1  # map {0,1} -> {-1,+1}

prn1 = ca_prn1()
print(prn1[:20])

Common misconceptions

  • “GPS signals are visible on a waterfall.” They are below the noise floor.
  • “Any PRN is fine.” Each satellite has a specific PRN code.
  • “You can integrate forever.” Navigation bit flips limit coherent integration.

Check-your-understanding questions

  1. Why does the C/A code repeat every 1 ms?
  2. What happens if you correlate with the wrong PRN?
  3. Why is coherent integration limited by navigation data bits?

Check-your-understanding answers

  1. The PRN sequence length is 1023 chips at 1.023 Mcps.
  2. You get no correlation peak because the code is uncorrelated.
  3. Bit flips invert the signal, cancelling coherent sums.

Real-world applications

  • GNSS receivers for navigation and timing.
  • Spoofing detection and signal authentication research.

Where you’ll apply it

  • This project: Section 4.1 (Architecture), Section 5.10 Phase 1.
  • Also used in: P01 Spectrum Eye for IQ handling techniques.

References

  • IS-GPS-200 (GPS Interface Specification)
  • “Understanding GPS/GNSS” by Kaplan and Hegarty, Chapters 3-5

Key insights

GPS acquisition is possible only because the PRN code has near-ideal correlation properties.

Summary

You learned how PRN codes define satellite identity, how the code repeats, and why correlation reveals signals below the noise floor.

Homework/Exercises to practice the concept

  1. Generate PRN 1 and compute its autocorrelation peak.
  2. Plot 1 ms of PRN chips and verify it repeats.
  3. Simulate a nav bit flip and observe its effect on correlation.

Solutions to the homework/exercises

  1. The autocorrelation should have a large peak at zero lag and low sidelobes.
  2. The sequence repeats after 1023 chips.
  3. A bit flip inverts the correlation sign for that interval.

Fundamentals

GPS signals are below the noise floor, so you cannot detect them with a simple FFT. Instead, you multiply the incoming samples by a local PRN code and sum the result. This correlation process spreads the noise while collapsing the signal, producing processing gain. The processing gain is approximately 10*log10(1.023e6 / 50) which is about 43 dB, enough to lift the signal above the noise after integration. Acquisition searches over code phase and Doppler frequency. You mix the signal with candidate Doppler bins, correlate with the PRN for each code phase, and look for the peak. If the peak exceeds a threshold, the satellite is acquired.

Deep Dive into the Concept

Correlation is the mathematical engine of GNSS. For each PRN, you compute the inner product between the received signal and a locally generated code. If the code phase is aligned, the contributions add coherently. If not, they cancel. The result is a sharp peak at the correct code phase. This peak is the detection statistic. In practice, you perform this correlation for many candidate Doppler frequencies because the carrier is shifted by satellite motion and receiver clock error. A standard approach is to mix the input with a complex exponential for each Doppler bin, then correlate.

The search space is two-dimensional: code phase (0 to 1022 chips) and Doppler (e.g., -5000 to +5000 Hz in 500 Hz steps). A brute-force correlation for every phase and Doppler is expensive, but FFT-based techniques can accelerate it. You can compute circular correlation by taking the FFT of the received 1 ms block and the FFT of the PRN, multiplying one by the conjugate of the other, and taking the inverse FFT. This yields correlation values for all code phases at once. Repeat for each Doppler bin. This reduces the complexity from O(N^2) to O(N log N) per Doppler bin.

Processing gain depends on coherent integration time. A 1 ms coherent integration yields 1023 chips of correlation. If you integrate for 10 ms, you gain 10x in SNR, but you risk nav bit transitions. Non-coherent integration can overcome this by summing the magnitude of multiple 1 ms correlation results. For example, you can compute 10 separate 1 ms correlations, square their magnitudes, and sum. This provides additional gain without sign cancellation. The trade-off is more computation and slightly lower theoretical gain compared to coherent integration.

Acquisition thresholding is another subtlety. If the threshold is too low, you get false alarms due to noise peaks. If too high, you miss weak satellites. A common practice is to compare the peak to the average or second-highest correlation value and require a ratio (e.g., peak > 2.5x mean). Another practice is to use a CFAR (constant false alarm rate) detector. The correct threshold depends on integration time and noise statistics. A deterministic test harness with simulated signals is invaluable for tuning this.

Doppler bin spacing is linked to coherent integration time. If you integrate for 1 ms, the coherent Doppler resolution is about 1 kHz. If you integrate for 10 ms, resolution improves to 100 Hz. This affects how fine your Doppler grid should be. A typical approach is to use 500 Hz spacing for 1-2 ms integration and refine later during tracking. Once a satellite is acquired, you pass the coarse estimates into the tracking loops, which refine Doppler and code phase continuously.

In practical SDR captures, the sample rate may not align with an integer number of chips per millisecond. This creates a fractional code phase. You can handle this by using a code NCO that generates code samples at the exact sample rate. The correlation then uses a sampled version of the PRN at the same rate as the input. This is more complex than a simple chip-based correlation but is necessary for precise acquisition and tracking.

How this fits on projects

  • Acquisition is implemented in Section 4.4 and Section 5.10 Phase 2.
  • The correlation logic is conceptually similar to preamble detection in P04 ADS-B Decoder.

Definitions & key terms

  • Correlation: Measure of similarity between two sequences.
  • Processing gain: SNR improvement from spreading and despreading.
  • Doppler bin: Candidate carrier frequency offset in the search.
  • CFAR: Constant false alarm rate thresholding technique.

Mental model diagram (ASCII)

IQ -> mix Doppler -> correlate with PRN -> peak search -> acquisition

How it works (step-by-step, with invariants and failure modes)

  1. Choose Doppler bin and mix the IQ to baseband.
  2. Generate PRN samples at the same sample rate.
  3. Compute correlation over 1 ms.
  4. Find the peak and compare to threshold.
  5. Repeat across Doppler bins and PRNs.

Invariants:

  • Code phase is within 0..1022 chips.
  • Doppler search range is bounded by receiver dynamics.

Failure modes:

  • Too coarse Doppler grid misses the peak.
  • Wrong sample rate produces smeared correlation.

Minimal concrete example

# FFT-based circular correlation (outline)
R = np.fft.fft(rx_block)
C = np.fft.fft(prn_block)
cor = np.fft.ifft(R * np.conj(C))
peak = np.max(np.abs(cor))

Common misconceptions

  • “A strong FFT peak means GPS.” GPS does not show as a narrowband peak.
  • “Acquisition and tracking are the same.” Acquisition is coarse; tracking is fine.
  • “One Doppler bin is enough.” Doppler shifts are several kHz wide.

Check-your-understanding questions

  1. Why do we need a 2D search over code phase and Doppler?
  2. What limits coherent integration time?
  3. Why is FFT-based correlation more efficient than brute force?

Check-your-understanding answers

  1. Both code alignment and carrier frequency must be correct to see a peak.
  2. Navigation bit flips and residual carrier error.
  3. It computes all code phases simultaneously in O(N log N).

Real-world applications

  • GNSS receivers for navigation and timing.
  • Signal acquisition in weak-signal environments.

Where you’ll apply it

  • This project: Section 3.4 (Example Usage), Section 5.10 Phase 2.
  • Also used in: P01 Spectrum Eye for FFT efficiency insights.

References

  • “Understanding GPS/GNSS” by Kaplan and Hegarty, Chapters 6-7
  • “A Software-Defined GPS and Galileo Receiver” by Borre et al.

Key insights

Acquisition is a large search problem; FFT correlation and careful thresholds make it practical.

Summary

You learned how correlation yields processing gain, how acquisition searches Doppler and code phase, and why FFT acceleration is essential.

Homework/Exercises to practice the concept

  1. Simulate a PRN-coded signal and test correlation peak height vs SNR.
  2. Implement a Doppler search with 500 Hz spacing.
  3. Compare coherent vs non-coherent integration for weak signals.

Solutions to the homework/exercises

  1. Peak height increases as SNR improves and as integration length increases.
  2. The best bin yields the highest correlation peak.
  3. Non-coherent integration improves detection without sign cancellations.

2.3 Tracking Loops: DLL/PLL and Navigation Bit Sync

Fundamentals

Once a satellite is acquired, you must track it. Tracking means continuously adjusting the code phase and carrier frequency so the local replica stays aligned with the incoming signal. This is done with feedback loops: a DLL (Delay Lock Loop) tracks code phase, and a PLL (Phase Lock Loop) tracks carrier phase. The loops use discriminators that compare early, prompt, and late correlations to generate error signals. Proper loop bandwidth selection balances noise rejection and dynamic responsiveness. With stable tracking, you can also recover the 50 bps navigation data by wiping off the PRN and integrating over 20 ms to detect bit transitions.

Deep Dive into the Concept

Tracking is the stage where GPS transitions from detection to continuous measurement. The DLL works by correlating the incoming signal with three versions of the PRN: early, prompt, and late. The early and late codes are offset by a small fraction of a chip (e.g., 0.5 chips). The difference between early and late correlation magnitudes forms the code error. If early is stronger than late, the local code is lagging; if late is stronger, the local code is leading. This error drives a loop filter and a code NCO that adjusts the PRN timing. The DLL effectively locks the code phase so the prompt correlator stays at maximum.

Carrier tracking uses a PLL or a Costas loop. A Costas loop is common for BPSK because it can lock without needing to know the navigation data bits. The PLL produces a carrier phase error that drives a carrier NCO. The carrier NCO both removes residual Doppler and provides a reference for coherent integration. The loop bandwidth must be chosen carefully: too narrow and the loop cannot follow dynamics or oscillator drift; too wide and noise passes through, degrading tracking. A typical PLL bandwidth might be 15-25 Hz for static receivers, wider for dynamic scenarios.

Because GPS signals are weak, tracking loops often combine a PLL with an FLL (Frequency Lock Loop) during initial pull-in. The FLL can tolerate larger frequency errors and then hand off to the PLL for fine phase tracking. Similarly, a narrowband DLL can be aided by a wider one initially. This staged approach improves robustness.

Navigation data recovery happens after code and carrier are aligned. You multiply the received signal by the prompt PRN and carrier replica to wipe off both. The result is a low-rate BPSK data stream at 50 bps. You integrate over 20 ms to form a data bit. But you must detect the bit boundaries; otherwise integration windows can straddle a bit transition and cancel. A simple approach is to compute the sign of 20 ms sums over multiple offsets and pick the offset with maximum magnitude consistency. Once bit sync is achieved, you can detect the 8-bit preamble of the navigation message and then parse words and parity. For this project, full navigation decode is optional, but bit sync provides a strong validation of tracking.

Tracking loops also provide quality metrics. The carrier-to-noise density ratio (C/N0) can be estimated from prompt correlator power and noise floor. Monitoring C/N0 helps you decide whether to trust a satellite’s measurements. Tracking stability can also be observed by the jitter of the code phase and the residual Doppler estimates. These metrics are essential in real receivers and provide a strong learning opportunity.

Finally, practical loop implementation depends on sample rate. The loop updates at a measurement interval (often 1 ms). You accumulate correlator values over that interval, compute errors, run them through loop filters, and update NCOs. The design of the loop filter (often a second-order filter) determines the stability and responsiveness. You must be careful with units: code phase in chips, carrier phase in radians, NCO frequencies in Hz. Unit mistakes are a common source of unstable tracking.

How this fits on projects

  • Tracking loops are built in Section 5.10 Phase 3 and validated in Section 6.2.
  • Loop concepts mirror PLL usage in P05 RDS Decoder.

Definitions & key terms

  • DLL: Delay Lock Loop for code phase tracking.
  • PLL: Phase Lock Loop for carrier phase tracking.
  • Costas loop: PLL variant for BPSK without data wipe-off.
  • NCO: Numerically Controlled Oscillator.
  • C/N0: Carrier-to-noise density ratio metric.

Mental model diagram (ASCII)

Prompt/Early/Late correlators -> error -> loop filter -> NCO updates

How it works (step-by-step, with invariants and failure modes)

  1. Correlate with early, prompt, late codes each millisecond.
  2. Compute code error and update DLL NCO.
  3. Compute carrier phase error and update PLL NCO.
  4. Wipe off code and carrier to recover navigation data.

Invariants:

  • Early and late spacing stays constant (e.g., 0.5 chips).
  • Loop update period stays fixed (e.g., 1 ms).

Failure modes:

  • Too wide bandwidth causes noisy jitter and loss of lock.
  • Too narrow bandwidth loses lock during dynamics.

Minimal concrete example

code_error = (E - L) / (E + L + 1e-6)
carrier_error = np.arctan2(Qp, Ip)  # Costas discriminator

Common misconceptions

  • “Once acquired, tracking is easy.” Tracking is the hardest stability problem.
  • “PLL alone is enough.” You need both code and carrier tracking.
  • “Bit sync is automatic.” You must explicitly detect bit boundaries.

Check-your-understanding questions

  1. Why are early and late correlators needed in a DLL?
  2. What is the advantage of a Costas loop for GPS?
  3. How do you detect navigation bit boundaries?

Check-your-understanding answers

  1. Their difference provides a code phase error signal.
  2. It locks to BPSK without requiring data bit knowledge.
  3. By testing multiple integration offsets and choosing the most consistent sign.

Real-world applications

  • GNSS receivers in smartphones, aviation, and timing systems.
  • High-precision timing for telecom and power grids.

Where you’ll apply it

  • This project: Section 3.7 (Real World Outcome), Section 5.10 Phase 3.
  • Also used in: P03 FM Receiver for loop filter intuition.

References

  • “Understanding GPS/GNSS” by Kaplan and Hegarty, Chapters 8-9
  • “Global Positioning System: Signals, Measurements, and Performance” by Misra and Enge

Key insights

Tracking loops turn a weak, drifting signal into a stable, measurable data stream.

Summary

You learned how DLL and PLL keep code and carrier aligned, how bit sync is achieved, and why loop tuning is critical.

Homework/Exercises to practice the concept

  1. Simulate a DLL with early/late spacing and plot error vs code phase.
  2. Implement a simple Costas loop on a noisy BPSK signal.
  3. Create a bit sync detector using 20 ms integration windows.

Solutions to the homework/exercises

  1. The error curve should cross zero at correct alignment.
  2. The loop converges to zero phase error after a transient.
  3. The best offset yields consistent bit signs across time.

3. Project Specification

3.1 What You Will Build

A GPS L1 C/A acquisition and tracking tool that reads IQ samples (from a file or live SDR), searches for visible satellites, and reports PRN, code phase, Doppler, and C/N0. The project focuses on detection and tracking, not full position solution. It must be deterministic for a given input IQ file.

3.2 Functional Requirements

  1. Input Handling: Read interleaved IQ with configurable sample rate and center frequency.
  2. Acquisition: Search PRNs 1-32 across Doppler bins and code phases.
  3. Detection Threshold: Declare acquisition only when peak metric exceeds threshold.
  4. Tracking: Run DLL and PLL for acquired satellites.
  5. Output: Report PRN, Doppler, code phase, C/N0, and lock status.
  6. Optional: Recover navigation bit stream for verification.

3.3 Non-Functional Requirements

  • Performance: Acquire at least 4 satellites from a 5 MHz capture within 30 seconds on a laptop.
  • Reliability: Maintain lock for at least 10 seconds in a stable capture.
  • Usability: CLI flags for sample rate, IF, and integration time.

3.4 Example Usage / Output

$ ./gps_tracker --iq gps_l1.iq --fs 5e6 --if 0
[GPS] PRN 3  | Doppler -2450 Hz | Code phase 512 | C/N0 38.2 dB-Hz | LOCK
[GPS] PRN 11 | Doppler +1250 Hz | Code phase 834 | C/N0 35.1 dB-Hz | LOCK

3.5 Data Formats / Schemas / Protocols

IQ Input (interleaved int16 IQ):

I0 Q0 I1 Q1 ...

Output JSON:

{
  "prn": 3,
  "doppler_hz": -2450,
  "code_phase": 512,
  "cn0_dbhz": 38.2,
  "lock": true
}

3.6 Edge Cases

  • Low SNR capture yields no acquisition peaks.
  • Incorrect sample rate produces smeared correlation.
  • Navigation bit flip during long coherent integration cancels signal.

3.7 Real World Outcome

You will run the tracker on a known GPS L1 capture and see consistent PRN and Doppler estimates.

3.7.1 How to Run (Copy/Paste)

./gps_tracker --iq samples/gps_l1.iq --fs 5e6 --if 0 --int-ms 1

3.7.2 Golden Path Demo (Deterministic)

  • Use samples/gps_l1.iq with fixed options.
  • Expect the same PRNs and Doppler bins every run.

3.7.3 CLI Transcript (Exact)

$ ./gps_tracker --iq samples/gps_l1.iq --fs 5e6 --if 0
[GPS] PRN 3  | Doppler -2450 Hz | Code phase 512 | C/N0 38.2 dB-Hz | LOCK
[GPS] PRN 11 | Doppler +1250 Hz | Code phase 834 | C/N0 35.1 dB-Hz | LOCK
[OK] 2 satellites tracked for 12.0 s

3.7.4 Failure Demo (Bad Input)

$ ./gps_tracker --iq samples/noise.iq --fs 5e6 --if 0
[ERROR] No acquisition peaks above threshold
$ echo $?
3

4. Solution Architecture

4.1 High-Level Design

IQ Input -> Preprocess -> Acquisition Engine -> Tracking Loops -> Reporter
                         |                          |
                         v                          v
                    PRN Generator              C/N0 Estimator

4.2 Key Components

Component Responsibility Key Decisions
PRN Generator Produce C/A codes LFSR implementation and tap table
Acquisition Engine Correlate and detect FFT-based vs time-domain
Tracking Loops Maintain lock DLL/PLL bandwidth
Navigation Bit Sync Optional verification 20 ms integration window
Reporter Output results JSON vs CLI

4.3 Data Structures (No Full Code)

struct AcqResult {
    int prn;
    float doppler_hz;
    int code_phase;
    float peak_metric;
};

struct TrackState {
    int prn;
    float code_nco;
    float carrier_nco;
    float cn0;
    int lock;
};

4.4 Algorithm Overview

Key Algorithm: Acquisition and Tracking

  1. Generate PRN codes.
  2. For each PRN and Doppler bin, correlate and detect peaks.
  3. Initialize tracking loops from acquisition results.
  4. Run DLL/PLL, update NCOs, and compute C/N0.
  5. Output lock status and estimates.

Complexity Analysis:

  • Time: O(P * D * N log N) for acquisition, O(N) per tracking update
  • Space: O(N) for FFT buffers and correlator

5. Implementation Guide

5.1 Development Environment Setup

# C build
mkdir build && cd build
cmake ..
make

5.2 Project Structure

project-root/
+-- src/
|   +-- gps_tracker.c
|   +-- prn.c
|   +-- acquisition.c
|   +-- tracking.c
|   +-- nav_bits.c
+-- tests/
|   +-- test_prn.c
|   +-- test_acq.c
|   +-- test_tracking.c
+-- samples/
|   +-- gps_l1.iq
+-- README.md

5.3 The Core Question You’re Answering

“How do you detect and track a signal that is literally buried under noise?”

5.4 Concepts You Must Understand First

Stop and research these before coding:

  1. Correlation and processing gain
    • Why does correlation lift a weak signal above noise?
  2. PRN generation
    • How do G1 and G2 registers form unique codes?
  3. Tracking loop basics
    • What does a DLL/PLL actually control?

5.5 Questions to Guide Your Design

  1. What Doppler range and bin size will you search?
  2. How many milliseconds will you integrate for acquisition?
  3. How will you detect and handle navigation bit flips?

5.6 Thinking Exercise

Compute the processing gain for a 1 ms coherent integration and compare it to a 10 ms non-coherent integration. Which is more robust to bit flips?

5.7 The Interview Questions They’ll Ask

  1. Why is GPS considered a spread-spectrum system?
  2. What is the purpose of the delay lock loop?
  3. How does Doppler shift affect acquisition?

5.8 Hints in Layers

  1. Start with a synthetic GPS signal to validate correlation.
  2. Implement FFT-based correlation before optimizing tracking.
  3. Use short coherent integrations to avoid bit flips.
  4. Add DLL/PLL only after acquisition works consistently.

5.9 Books That Will Help

Topic Book Chapter
GPS signals “Understanding GPS/GNSS” Ch. 3-7
Tracking loops “Global Positioning System” (Misra, Enge) Ch. 6-7
DSP fundamentals “Understanding Digital Signal Processing” (Lyons) Ch. 9-10

5.10 Implementation Phases

Phase 1: PRN + Acquisition Prototype (2-3 weeks)

Goals:

  • Generate PRN codes correctly.
  • Detect peaks on synthetic data.

Tasks:

  1. Implement PRN generator and verify autocorrelation.
  2. Build FFT-based correlator for 1 ms blocks.
  3. Add Doppler bin search and detection threshold.

Checkpoint: You can detect a simulated PRN at -20 dB SNR.

Phase 2: Real Capture Acquisition (2 weeks)

Goals:

  • Acquire satellites from a real IQ capture.
  • Estimate Doppler and code phase.

Tasks:

  1. Add input parsing for IQ files.
  2. Calibrate sample rate and IF handling.
  3. Implement non-coherent integration over multiple ms.

Checkpoint: You can detect at least two satellites in a known capture.

Phase 3: Tracking Loops and Output (2-3 weeks)

Goals:

  • Maintain lock and output stable estimates.
  • Optionally recover navigation bits.

Tasks:

  1. Implement DLL and PLL with configurable bandwidths.
  2. Compute C/N0 estimates from prompt correlator.
  3. Output PRN, Doppler, code phase, and lock status.

Checkpoint: You can track a satellite for 10+ seconds without loss.

5.11 Key Implementation Decisions

Decision Options Recommendation Rationale
Acquisition method brute force vs FFT FFT Faster and scalable across PRNs
Integration time 1 ms vs 10 ms 1-5 ms + non-coherent Avoid nav bit flips
Loop bandwidth narrow vs wide moderate Balances noise and dynamics

6. Testing Strategy

6.1 Test Categories

Category Purpose Examples
Unit Tests Verify PRN generator Autocorrelation peak tests
Integration Tests Acquisition on synthetic data Known PRN with known Doppler
Field Tests Real capture Compare PRN list with known satellites

6.2 Critical Test Cases

  1. PRN Autocorrelation: Peak at zero lag, low sidelobes.
  2. Acquisition Threshold: Detect PRN at -20 dB SNR with 10 ms non-coherent.
  3. Tracking Stability: Maintain lock for 10 seconds without cycle slips.

6.3 Test Data

Synthetic PRN IQ, Real GPS L1 capture, Noise-only capture

7. Common Pitfalls & Debugging

7.1 Frequent Mistakes

Pitfall Symptom Solution
Wrong PRN taps No peaks Verify G2 tap table
Bad sample rate Smeared peaks Validate capture metadata
Loop instability Loss of lock Tune bandwidth and damping

7.2 Debugging Strategies

  • Plot Correlation Surface: Visualize Doppler vs code phase peaks.
  • Check PRN Autocorrelation: Validate generator before acquisition.
  • Monitor C/N0: Sudden drops indicate loss of lock.

7.3 Performance Traps

  • Searching too many Doppler bins without pruning.
  • Using long coherent integration without bit wipe-off.

8. Extensions & Challenges

8.1 Beginner Extensions

  • Add CSV output for PRN and Doppler estimates.
  • Plot correlation peaks over time.

8.2 Intermediate Extensions

  • Recover navigation bits and detect preamble.
  • Implement FLL-assisted PLL for faster pull-in.

8.3 Advanced Extensions

  • Multi-satellite tracking with shared buffers.
  • Integrate a position solution from pseudoranges.

9. Real-World Connections

9.1 Industry Applications

  • GNSS receivers in consumer and aviation devices.
  • Precision timing for telecom and power grids.
  • gnss-sdr: Open-source GNSS receiver.
  • gr-gnss: GNU Radio GNSS blocks.

9.3 Interview Relevance

  • Spread-spectrum and correlation.
  • Feedback control loops in DSP.

10. Resources

10.1 Essential Reading

  • IS-GPS-200 GPS Interface Specification
  • “Understanding GPS/GNSS” by Kaplan and Hegarty

10.2 Video Resources

  • GNSS signal processing lectures (university DSP courses)
  • SDR tutorials on correlation and acquisition

10.3 Tools & Documentation

  • rtl-sdr or bladeRF for IQ capture
  • FFTW for high-performance FFTs

11. Self-Assessment Checklist

11.1 Understanding

  • I can explain PRN generation and correlation properties.
  • I can explain the acquisition search over Doppler and code phase.
  • I understand DLL/PLL loop behavior and tuning.

11.2 Implementation

  • Acquisition detects at least two satellites in a known capture.
  • Tracking loops maintain lock for 10 seconds.
  • Output includes PRN, Doppler, and code phase.

11.3 Growth

  • I can describe how I validated my PRN generator.
  • I documented loop tuning experiments.

12. Submission / Completion Criteria

Minimum Viable Completion:

  • Generate PRN codes correctly and verify autocorrelation.
  • Acquire at least one satellite from a known capture.
  • Output PRN and Doppler estimates.

Full Completion:

  • Track two satellites for 10+ seconds and output C/N0.
  • Demonstrate stable code phase estimates.

Excellence (Going Above & Beyond):

  • Recover navigation preamble and implement basic pseudorange solution.
  • Track 4+ satellites simultaneously.