Main Content

GPS Receiver Acquisition and Tracking

This example shows how to acquire and track Global Positioning System (GPS) signals. The example supports these signals.

  • GPS L1 C/A [1]

  • GPS L1C [2]

  • GPS L5 [3]

Introduction

All the GPS signals that work on the principle of code division multiple access (CDMA) use similar acquisition and tracking algorithms. Acquisition is a process that detects all visible satellites and estimates the coarse values of frequency offset (that includes Doppler shift) and code phase offset for these visible satellites. Using the values from acquisition, a tracking module fine-tunes the frequency offset and code-phase offset for the visible satellites. Acquisition is typically the first step in a GPS receiver. Use the information from acquisition to perform parallel receiver operations on each of the visible satellites, as shown in the figure. For a given visible satellite, acquisition is a one-time operation, unless some signal loss occurs, whereas tracking is a continuous process to keep a track of changes to frequency offset and code phase offset.

In the example, generate GPS baseband waveform for satellites of your choice, perform acquisition to search for visible satellites in the signal, and track the visible satellites as shown in this figure.

gpsacqTrack.png

For detailed information on the acquisition and tracking algorithm, see the GPS Receiver Acquisition and Tracking Using C/A-Code example.

Set Initial Parameters

Specify all the parameters that control the example workflow.

First, specify the signal type.

signalType = "GPS L1CD"
signalType = 
"GPS L1CD"

Optionally, you can write the generated waveform and tracking output to a file by specifying writeWaveformToFile and writeTrackedSignalToFile, respectively, as true.

writeWaveformToFile      = false;
writeTrackedSignalToFile = false;

Specify that you want to perform acquisition on only visible satellites. To instead perform acquisition on all GPS satellites, specify acquireActiveSatellitesOnly as false, but note that choosing to acquire all GPS satellites can cause memory issues, depending on your available system memory.

acquireActiveSatellitesOnly = true;

Specify the number of visible satellites.

numSat = 4;

Specify the pseudo-random noise (PRN) numbers of the visible satellites.

PRNIDs = [7; 11; 20; 28];

Specify the number of data bits to process in this example. For a long-running simulation, set numDataBits to an appropriate higher value. For example, transmitting all of the information for a GPS L1C signal requires 8 frames of 1800 bits each, which is a total of 14400 bits. Because running such a simulation takes a long time, set this parameter to a smaller value to validate the example results.

numDataBits = 300;

Specify the Doppler, delay, and signal-to-noise ratio (SNR) for each of the visible satellites.

frequencyOffset = [-3589; 4256; -1563; 2666];       % In Hz
sigdelay        = [300.34; 587.21; 425.89; 312.88]; % Number of code chips delay
SNRs            = [-25; -25.5; -26.5; -26];         % In dB

Set the intermediate frequency and sampling rate of the signal.

IntermediateFrequency = 0;                          % In Hz
SampleRate            = 20e6;                       % In samples/sec

While performing acquisition, set the frequency step size to a real positive number. When you set this value to -1, the example considers these default frequency step size, depending on the signal type.

  • "GPS C/A", "GPS L5I", "GPS L5Q" — 500 Hz

  • "GPS L1CD" — 50 Hz

acquisitionFrequencyStep = -1;    % Default

Set the loop noise bandwidths of the phase-locked loop (PLL), frequency-locked loop (FLL), and delay-locked loop (DLL). Higher bandwidth allows more noise through a loop, but enables it to track fast-varying parameters. Lower bandwidth allows less noise through the loop, but the lock will be lost if tracking parameters vary quickly. For open sky environments where the receiver is moving at high speeds, you can expect low noise and fast changing parameters, so set the noise bandwidths to higher values. In high-noise environments, such as indoors, reduce the noise bandwidths to increase receiver sensitivity. In this example, use moderate values of loop bandwidths because the noise is moderate in the default setting of the example.

PLLNoiseBandwidth = 90;                             % In Hz
FLLNoiseBandwidth = 4;                              % In Hz
DLLNoiseBandwidth = 1;                              % In Hz

Set the seed for generating reproducible waveform.

Seed = 73;

Configure Simulation

Configure the simulation by using the parameters specified in the previous section.

First, configure initial set of parameters.

isl1c = strcmp(signalType,"GPS L1CD");
% Configure various parameters based on the signalType.
switch(signalType)
    case "GPS C/A"
        numBitsPerStep = 1;
        numCodeBlocksPerBit = 20;
        chipRate = 1.023e6;
        samplesPerCodeBlock = SampleRate*1e-3;
        ibranch = "P+D";
        qbranch = "C/A+D";
        navDataType = "LNAV";
        defaultAcqFqyStep = 500;
    case "GPS L1CD"
        numBitsPerStep = 2;
        numCodeBlocksPerBit = 1;
        chipRate = 1.023e6;
        samplesPerCodeBlock = SampleRate*10e-3;
        ibranch = "l1C";
        qbranch = "None";
        navDataType = "CNAV2";
        defaultAcqFqyStep = 50;
    case {"GPS L5I" "GPS L5Q"}
        numBitsPerStep = 1;
        numCodeBlocksPerBit = 10;
        chipRate = 10.23e6;
        samplesPerCodeBlock = SampleRate*1e-3;
        ibranch = "I5-of-L5";
        qbranch = "Q5-of-L5";
        navDataType = "L5";
        defaultAcqFqyStep = 500;
    otherwise
        error("Invalid signalType.")
end
numCodeBlocks = numDataBits*numCodeBlocksPerBit;
numSteps = numDataBits/numBitsPerStep;
numCodeBlocksPerStep = numCodeBlocksPerBit*numBitsPerStep;
if acquisitionFrequencyStep == -1 % Set default value
    acqfqystep = defaultAcqFqyStep;
else
    acqfqystep = acquisitionFrequencyStep;
end

if writeWaveformToFile == true
    % Initialize the baseband file writer object
    bbwriter = comm.BasebandFileWriter("gpsWaveform.bb",SampleRate,IntermediateFrequency);
end

Initialize the waveform generation object based on the initial configuration.

gpswavegen = HelperGPSWaveformGenerator(PRNID=PRNIDs, ...
    InPhaseSignalType=ibranch,QuadraturePhaseSignalType=qbranch, ...
    SignalToNoiseRatio=SNRs,SignalDelay=sigdelay/chipRate, ...
    FrequencyOffset=frequencyOffset,IntermediateFrequency=IntermediateFrequency, ...
    SampleRate=SampleRate,RandomStream="mt19937ar with seed",Seed=Seed)
gpswavegen = 
  HelperGPSWaveformGenerator with properties:

   Transmitter Properties
                        PRNID: [4x1 double]
            InPhaseSignalType: "L1C"
    QuadraturePhaseSignalType: "None"
                  InitialTime: 0

   Signal Properties
                   SampleRate: 20000000
        IntermediateFrequency: 0

   Channel Properties
           DisableImpairments: false
           SignalToNoiseRatio: [4x1 double]
                  SignalDelay: [4x1 double]
              FrequencyOffset: [4x1 double]
                 RandomStream: "mt19937ar with seed"
                         Seed: 73

Configure the receiver acquisition object

gsa = gnssSignalAcquirer(GNSSSignalType=signalType, ...
    FrequencyResolution=acqfqystep, ...
    IntermediateFrequency=IntermediateFrequency, ...
    SampleRate=SampleRate)
gsa = 
  gnssSignalAcquirer with properties:

              GNSSSignalType: "GPS L1CD"
                  SampleRate: 20000000
       IntermediateFrequency: 0
              FrequencyRange: [-10000 10000]
         FrequencyResolution: 50
    DetectionThresholdFactor: 1.9000

% If CNAV, encode it with convolutional encoder
% Initialize the trellis for convolutional encoder
trellis = poly2trellis(7,["1+x+x^2+x^3+x^6" "1+x^2+x^3+x^5+x^6"]);
cenc = comm.ConvolutionalEncoder(TrellisStructure = trellis, ...
    TerminationMethod = "Continuous");

cfg = cell(numSat,1);
cfg{1} = HelperGPSNavigationConfig(SignalType=navDataType, ...
        L1CTOI=60);
tempData = HelperGPSNAVDataEncode(cfg{1});
if any(strcmp(navDataType,["CNAV" "L5"]))
    tempData = cenc(tempData);
    reset(cenc);
end
transmittedBits = [tempData zeros(size(tempData,1),numSat-1)];

for isat = 2:numSat
    cfg{isat} = HelperGPSNavigationConfig(SignalType=navDataType, ...
        L1CTOI=60);
    navdata = HelperGPSNAVDataEncode(cfg{isat});
    if any(strcmp(navDataType,["CNAV" "L5"]))
        transmittedBits(:,isat) = cenc(navdata);
        reset(cenc);
    else
        transmittedBits(:,isat) = navdata;
    end
end

Acquire GPS Signals

Generate a waveform that is adequate for acquisition, and use the receiver acquisition object to acquire it.

% Initialize data bits for the waveform
b = transmittedBits(1:numBitsPerStep,:);
% Generate waveform for those data bits
w = gpswavegen(b);
if writeWaveformToFile == true
    bbwriter(w)
end
% Perform acquisition
if acquireActiveSatellitesOnly == true
    prntable = gsa(w(end-2*samplesPerCodeBlock+1:end),PRNIDs)
else
    % Searching for all satellites requires more system memory
    prntable = gsa(w(end-2*samplesPerCodeBlock+1:end),1:32)
end
prntable=4×4 table
    PRNID    FrequencyOffset    CodePhaseOffset    IsDetected
    _____    _______________    _______________    __________

      7           -3600             300.35           true    
     11            4250              587.2           true    
     28            2650             312.88           true    
     20           -1550             425.87           true    

PRNIDsToSearch = prntable(prntable(:,4).IsDetected==1,1).PRNID.';         % Get row vector
doppleroffsets = prntable(prntable(:,4).IsDetected==1,2).FrequencyOffset;
codephoffsets  = prntable(prntable(:,4).IsDetected==1,3).CodePhaseOffset;

numdetectsat = length(PRNIDsToSearch);

disp("The detected satellite PRN IDs: " + num2str(PRNIDsToSearch))
The detected satellite PRN IDs: 7  11  28  20

Track GPS Signals

Create and configure the signal tracking object. Continue to generate the waveform and track the signal in a loop after acquisition is complete. Because this example assumes that the satellites do not change while the simulation is in progress, the signal tracking object can handle multiple satellites.

if isempty(PRNIDsToSearch)
    % Because no satellites are detected, stop the simulation
    return
end
carrierCodeTrack                        = gnssSignalTracker;
carrierCodeTrack.GNSSSignalType         = signalType;
carrierCodeTrack.SampleRate             = SampleRate;
carrierCodeTrack.IntermediateFrequency  = IntermediateFrequency;
carrierCodeTrack.PLLNoiseBandwidth      = PLLNoiseBandwidth;
carrierCodeTrack.FLLNoiseBandwidth      = FLLNoiseBandwidth;
carrierCodeTrack.DLLNoiseBandwidth      = DLLNoiseBandwidth;
carrierCodeTrack.PRNID                  = PRNIDsToSearch;
carrierCodeTrack.InitialFrequencyOffset = doppleroffsets;
carrierCodeTrack.InitialCodePhaseOffset = codephoffsets;
longDisplay(carrierCodeTrack)
  gnssSignalTracker with properties:

            GNSSSignalType: "GPS L1CD"
                SampleRate: 20000000
     IntermediateFrequency: 0

   Initialization from acquisition
                     PRNID: [7 11 28 20]
    InitialCodePhaseOffset: [4x1 double]
    InitialFrequencyOffset: [4x1 double]

   Phase Locked Loop (PLL)
                DisablePLL: 0
                  PLLOrder: 2
         PLLNoiseBandwidth: 90

   Frequency Locked Loop (FLL)
                DisableFLL: 0
                  FLLOrder: 1
         FLLNoiseBandwidth: 4

   Delay Locked Loop (DLL)
                  DLLOrder: 1
         DLLNoiseBandwidth: 1

Initialize variables for storing the output from the tracking object.

% Initialize all the properties which must be accumulated.
[accuph, accufqy, accufqyerr, accupherr, ...
    accudelay, accudelayerr, accuintegwave] = ...
    deal(zeros(numCodeBlocks,numdetectsat));           % Each column represents data from a satellite

Perform initial tracking of the generated waveform, and store the values.

[trackedWave,trackinfo] = carrierCodeTrack(w);
tridx = 1:numCodeBlocksPerStep;
accuintegwave(tridx,:) = trackedWave;
accuph(tridx,:)        = trackinfo.PhaseEstimate;
accupherr(tridx,:)     = trackinfo.PhaseError;
accufqy(tridx,:)       = trackinfo.FrequencyEstimate;
accufqyerr(tridx,:)    = trackinfo.FrequencyError;
accudelay(tridx,:)     = trackinfo.DelayEstimate;
accudelayerr(tridx,:)  = trackinfo.DelayError;

Track the signals in a loop.

for ii = 2:numSteps
    % Waveform generation
    b = transmittedBits((ii-1)*numBitsPerStep+1:ii*numBitsPerStep,:);
    w = gpswavegen(b);

    if writeWaveformToFile == true
        bbwriter(w);
    end

    % Track at receiver
    [trackedWave,trackinfo] = carrierCodeTrack(w);
    
    % Store tracking output
    tridx = (ii-1)*numCodeBlocksPerStep + (1:numCodeBlocksPerStep);
    accuintegwave(tridx,:) = trackedWave;
    accuph(tridx,:)        = trackinfo.PhaseEstimate;
    accupherr(tridx,:)     = trackinfo.PhaseError;
    accufqy(tridx,:)       = trackinfo.FrequencyEstimate;
    accufqyerr(tridx,:)    = trackinfo.FrequencyError;
    accudelay(tridx,:)     = trackinfo.DelayEstimate;
    accudelayerr(tridx,:)  = trackinfo.DelayError;
end
trackedOutput = accuintegwave(1:tridx(end),:);
trackedOutput = trackedOutput/rms(trackedOutput(:));    % Normalize tracking output

if writeWaveformToFile == 1
    release(bbwriter);
end

% Plot constellation after tracking is complete
scatterplot(trackedOutput(:))

Figure Scatter Plot contains an axes object. The axes object with title Scatter plot, xlabel In-Phase, ylabel Quadrature contains a line object which displays its values using only markers. This object represents Channel 1.

Further Exploration

Using this example, you can store the generated waveform to a file and use those samples in your receiver chain to test your receiver.

You can also write the output of the tracker to a file for further processing. Store the tracker output as a signed, fixed-point number.

if writeTrackedSignalToFile == true
    % Initialize the number of bits for the integer (a) and fractional (b)
    % parts of the fixed point number. Ensure that a+b is always 7, so as
    % to store the signal in int8 format.
    a = 1; % Number of bits for integer part
    b = 6; % Number of bits for fractional part
    % Convert the tracked output to integer values.
    intTrackedOutput = round(trackedOutput*2^b);

    % Store the real and imaginary components of the integer-tracked signal
    % as different matrices for the purpose of converting them to
    % fixed-point numbers independently.
    tempTrackedSignal = zeros(size(intTrackedOutput,1),size(intTrackedOutput,2),2);
    tempTrackedSignal(:,:,1) = real(intTrackedOutput);
    tempTrackedSignal(:,:,2) = imag(intTrackedOutput);
    signOfTrackedSignal = int8(sign(tempTrackedSignal));

    % Store only the LSBs of the absolute value. Handle the sign separately.
    lsbOfTrackedSignal = bitand(int32(abs(tempTrackedSignal)),2^(a+b)-1);

    % Apply the sign to the signal.
    tempFixedPointSignal = int8(lsbOfTrackedSignal).*signOfTrackedSignal;

    % Create a fixed-point, complex signal in int8 format.
    trackedSignal = complex(tempFixedPointSignal(:,:,1),tempFixedPointSignal(:,:,2));
    save trackedSignal trackedSignal
end

Supporting Files

This example uses these data and helper files.

References

[1] IS-GPS-200, Rev: N. NAVSTAR GPS Space Segment/Navigation User Segment Interfaces. Aug 22, 2022; Code Ident: 66RP1.

[2] IS-GPS-800, Rev: J. NAVSTAR GPS Space Segment/User segment L1C Interfaces. Aug 22, 2022; Code Ident: 66RP1.

[3] IS-GPS-705, Rev: J. NAVSTAR GPS Space Segment/User segment L1C Interfaces. Aug 22, 2022; Code Ident: 66RP1.

See Also

Functions

Objects

Related Topics