GPS Data Decode
This example shows how to perform bit and frame synchronization and decode the legacy GPS navigation (LNAV) data as per IS-GPS-200 .
This figure shows the various operations in a typical GPS receiver. The GPS Receiver Acquisition and Tracking Using C/A-Code example describes the operations shown in red blocks in this figure. This example focuses on the green blocks. The GPS LNAV data transmits at a rate of 50 bits per second. In other words, each bit takes 20 milliseconds for transmission. The tracking module in the receiver tracks the phase shift, frequency offset, and delay between the visible GPS satellites and the receiver. For tracking, the received baseband signal is integrated to calculate the tracking metrics . During tracking, if the integration happens over a bit transition, then the effective integrated value decreases because the bit values vary. Hence, the first step in data decoding is to find the exact bit transition boundary. Next, use the frame synchronization module to calculate the frame boundaries, which are required for navigation data decoding. Once the frame boundary is known, perform data decoding to get the received navigation data from a satellite. Data decoding from each tracking output channel must be done independently. This example shows how to decode data for a single satellite.
This example is divided into three parts.
To perform any of these steps, tracking results (time and frequency synchronized waveforms) are required. For this example, use 125 subframes of data from satellite PRN ID 7, which are stored in
trackedSignal.mat, attached to this example as a supporting file. The samples are collected at a signal to noise ratio (SNR) of -23 dB. For more information on acquiring and tracking a GPS signal, see GPS Receiver Acquisition and Tracking Using C/A-Code.
Load the samples that the tracking loops output. Each sample in this array has a duration of 1 millisecond. The data type of the tracking loop output is floating-point double precision. To conserve storage, the MAT file stores the data in fixed point format with 1 sign bit, 1 bit for the integer part, and 6 bits for the fractional value. Convert the fixed-point data back into floating-point double format.
load trackedSignal.mat trackedSignal = double(trackedSignal)/(2^6); % Convert fixed-point number to real value
Load the transmitted data bits to compare them with the decoded data bits. The GPS Waveform Generation example shows how to generate these bits.
For the LNAV data, once tracking of the C/A-codes is complete, each code block with a C/A-code boundary of 1 millisecond duration is known. Each data bit consists of 20 such code blocks. To get the bit boundary in each block of 20 milliseconds, flag the location (within this 20 millisecond block) that has the maximum number of transition .
Initialize the bit synchronization System object, which estimates the data transition and gives the index of maximum number of transitions. The
NumAveragingBits property controls the length of the window to search for the data transitions. Because each data bit is 20 milliseconds long and each code block is 1 millisecond long, when you set
NumAveragingBits to 100, then the bit synchronization module considers a window of 20*100 = 2000 samples to decide the bit transition boundary.
bitsync = HelperGPSBitSynchronizer('NumAveragingBits',100)
bitsync = HelperGPSBitSynchronizer with properties: NumAveragingBits: 100
Call the bit synchronization System object to find where the bit transition occurs in 20 millisecond period. Because C/A-codes sit on the quadrature branch of the waveform, consider only the imaginary part of the signal.
numCACodeBlocksPerBit = 20; numAveragingSamples = numCACodeBlocksPerBit*bitsync.NumAveragingBits; [maxTransitionLocation, transitionValues] = ... bitsync(imag(trackedSignal(1:numAveragingSamples,1))); maxTransitionLocation
maxTransitionLocation = 7
bar(transitionValues) xlabel('Sample Index') ylabel('Number of Transitions') title('Bit Transitions Chart')
In the above figure, observe that the highest number of transitions occur at the location of bit transition.
Consider block of 20 samples from the location of the bit transition and integrate every 20 samples to generate soft log-likelihood ratios (LLRs). Get the bit values from the soft LLR values.
[samples,leftout] = buffer(trackedSignal(maxTransitionLocation:end,1),numCACodeBlocksPerBit); softbits = mean(samples).'; bits = imag(softbits)<0; rxconstellation = comm.ConstellationDiagram(1,"ShowReferenceConstellation",false); rxconstellation.Title = "Constellation of Received Data After Bit Synchronization"; rxconstellation(softbits(:))
Frame synchronization, which determines the exact starting and ending points of a subframe. This information is necessary for the data decoder to process data.
Each subframe begins with a known 8-bit preamble. The frame synchronization module searches for this 8-bit sequence. Because an 8-bit sequence is small, the same sequence can occur somewhere else within the data. After detecting the 8-bit preamble, decode the first and second words of the subframe. If the parity checks pass, then decode the time of week present in the handover word  and the subframe ID. If the time of week and the subframe ID agree, declare a successful frame boundary detection. Cycle slip in the tracking loops is possible, so continuous processing of the frame synchronization ensures that the decoder always works with an exact subframe . This figure shows the telemetry word and handover word in a GPS LNAV data subframe.
Initialize the frame synchronization System object. This object returns the frame synchronized subframes in each column. Send all of the data through this object. This object also works when each subframe of data is passed through it iteratively.
framesync = HelperGPSLNAVFrameSynchronizer; [syncidx, rxsubframes, subframeIDs] = framesync(bits); syncidx
syncidx = 251
numSubframes = size(rxsubframes,2)
numSubframes = 123
subframeIDs = 1×123 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1
% Get the index of the synchronized subframes allidx = 1:125; % There are 125 sub-frames in 25 frames of data offsetidx = 0; lostIdx = zeros(size(allidx)); % Pre-allocation subframeIDs = [subframeIDs,0]; % To allow searching for all elements for idx = allidx if mod(allidx(idx)-1,5)+1~=subframeIDs(idx-offsetidx) offsetidx = offsetidx + 1; lostIdx(offsetidx) = idx; end end lostIdx = lostIdx(1:offsetidx)
lostIdx = 1×2 1 125
availableIdx = allidx(~ismember(allidx,lostIdx));
Check how many data bits differ between the frame synchronized data and transmitted data.
[transmittedSubframes,remainingBits] = ... buffer(transmittedBits,300); % Each subframe is of 300 bits numBitsInError = nnz(transmittedSubframes(:,availableIdx) - rxsubframes)
numBitsInError = 0
Decode GPS LNAV Data
The GPS LNAV data is transmitted in 1500-bit length frames. Each frame consists of five subframes of 300 bits each. Because the data rate is 50 bits per second, transmitting each subframe takes 6 seconds and transmitting each frame takes 30 seconds. Each subframe consists of 10 words with 30 bits (24 data bits and 6 parity bits) in each word. The GPS data contains information regarding the clock and the position of the satellites. This figure shows the frame structure of the LNAV data.
This example processes each subframe independently.
cfg = struct; accuParityChecks = zeros(numSubframes,10); for isubframe = 1:numSubframes [cfg,parityChecks] = HelperGPSLNAVDataDecode(rxsubframes(:,isubframe),cfg); accuParityChecks(isubframe,:) = parityChecks; end numWordsInError = numel(accuParityChecks) - nnz(accuParityChecks)
numWordsInError = 0
The transmitted configuration properties and the decoded configuration properties must have same values. These are the decoded configuration parameters.
cfg = struct with fields: DataType: "LNAV" Preamble: 139 TLMMessage: 0 HOWTOW: 124 AntiSpoofFlag: 0 CodesOnL2: "P-code" L2PDataFlag: 0 CEIDataSet: [1x1 struct] AgeOfDataOffset: 0 NMCTAvailabilityIndicator: 0 NMCTERD: [30x1 double] Ionosphere: [1x1 struct] UTC: [1x1 struct] TextMessage: 'This content is part o' SubframeID: 4 DataID: [2x1 double] SVPageID: 63 Almanac: [1x1 struct] ReferenceTimeUTCData: 0 TimeDataReferenceWeekNumber: 101 PastLeapSecondCount: 18 LeapSecondReferenceWeekNumber: 101 LeapSecondReferenceDayNumber: 1 FutureLeapSecondCount: 18 AlmanacSVHealth: [0 0 0 0 0 0 0 0]
ans = struct with fields: SVHealth: 0 IssueOfDataClock: 0 URAID: 0 WeekNumber: 101 GroupDelayDifferential: 0 SVClockCorrectionCoefficients: [3x1 double] ReferenceTimeOfClock: 0 SemiMajorAxisLength: 2.6560e+04 MeanMotionDifference: 0 FitIntervalFlag: 0 Eccentricity: 0.0200 MeanAnomaly: 0 ReferenceTimeOfEphemeris: 0 HarmonicCorrectionTerms: [6x1 double] IssueOfDataEphemeris: 0 IntegrityStatusFlag: 0 ArgumentOfPerigee: -0.5200 RateOfRightAscension: 0 LongitudeOfAscendingNode: -0.8400 Inclination: 0.3000 InclinationRate: 0 AlertFlag: 0
This example performs frame synchronization, considering all subframes at a time. In practice, each subframe processing occurs in a loop whenever any new data is received. You can perform frame synchronization on every subframe independently. Also, this example does not update the bit synchronization status back to the tracking loop. You can also use the bit synchronization value to increase the phase locked loop (PLL) integration time to enhance the PLL performance at low SNR values.
This example uses these helper files:
This example uses these data files:
trackedSignal.mat — Output of the tracking loop in the GPS Receiver Acquisition and Tracking Using C/A-Code example for satellite PRNID 7
transmittedBits.mat — Transmitted bits from the GPS satellite PRNID 7, consisting of 125 subframes of data
 IS-GPS-200, Rev: L. NAVSTAR GPS Space Segment/Navigation User Segment Interfaces. May 14, 2020; Code Ident: 66RP1.
 Elliott D. Kaplan and C. Hegarty, eds., Understanding GPS/GNSS: Principles and Applications, Third edition, GNSS Technology and Applications Series (Boston ; London: Artech House, 2017).