Main Content

Joint Sampling Clock and Carrier Frequency Offset Tracking

This example demonstrates joint sampling clock and carrier frequency offset tracking in a WLAN receiver.


A WLAN radio typically uses a single oscillator to derive clocks for sampling and modulation. The oscillators in the transmitter and receiver radios do not run at the exact same frequency. Due to this mismatch, carrier frequency offset (CFO) exists between the receiver and transmitter and the sampling instants at the receiver shift relative to the transmitter. This shift of sampling instants between receiver and transmitter is described as sampling clock offset (SCO). When the sampling clock at the receiver is running slower than the transmitter, this results in a larger sampling period and a positive sampling clock offset. The inclusion of pilot subcarriers in the IEEE® 802.11™ standard allows for tracking and correction of SCO and CFO impairments.

In OFDM systems SCO manifests itself as a subcarrier- and symbol-dependent phase rotation and inter-carrier interference (ICI) [ 1 ]. When the SCO is large, and a packet is long, subcarriers far away from DC will experience a substantial impairment. CFO manifests itself as ICI and a symbol-dependent phase rotation common to all subcarriers. This figure illustrates the phase rotation on subcarriers from one OFDM symbol to the next due to these impairments. Φk is the phase error for subcarrier index k, K is the number of subcarriers, ζ is the SCO, Δf is the carrier frequency offset, Tu is the period of the symbol, δ is the phase error gradient (PEG), and ω is the common phase error (CPE). The PEG and CPE can be used to estimate SCO and residual CFO.


This example shows how to demonstrate an IEEE 802.11ac™ VHT waveform with fixed SCO and CFO impairments [2], and shows the equalized constellation of the demodulated impaired waveform with and without joint timing and phase tracking to correct for SCO and CFO to demonstrate the effectiveness of tracking.

Generate a Baseband Waveform

Create a VHT configuration object to parameterize the transmission. Use a data payload with only 500 bytes and 16-point quadrature amplitude modulation (16-QAM) to produce a small number of OFDM symbols and make the impairment easy to visualize.

cfgVHT = wlanVHTConfig;
cfgVHT.ChannelBandwidth = 'CBW20';
cfgVHT.NumTransmitAntennas = 1;
cfgVHT.NumSpaceTimeStreams = 1;
cfgVHT.MCS = 4;          % 16-QAM and 3/4 coding rate
cfgVHT.APEPLength = 500; % Bytes

Create a random PSDU.

s = rng(10); % Seed the random number generator
psdu = randi([0 1],cfgVHT.PSDULength*8,1,'int8');

Generate a VHT packet.

tx = wlanWaveformGenerator(psdu,cfgVHT);

Model Impairments

Model -100 parts per million (PPM) sampling clock offset between the transmitter and receiver using comm.SampleRateOffset.

sco = -100; % Sampling clock offset in PPM

Use comm.SampleRateOffset by specifying the desired sample rate offset. Sample rate offset is the relative offset between the sample rate of transmitter and receiver. Sampling clock offset is the relative offset between the sampling period of transmitter and receiver.

sro = -sco/(1+sco/1e6); % Sample rate offset in PPM

Model sampling clock offset, appending zeros to the waveform to allow for filter delay.

samplingClockoffset = comm.SampleRateOffset(sro);
rx = samplingClockoffset([tx; zeros(100,cfgVHT.NumTransmitAntennas)]);

Add residual carrier frequency offset to the waveform. This example assumes the same oscillator is used for sampling and modulation, so that the CFO depends on the SCO and carrier frequency.

fc = 5.25e9;         % Carrier frequency, Hertz
cfo = (sco*1e-6)*fc; % Carrier frequency offset, Hertz
fs = wlanSampleRate(cfgVHT);           % Baseband sample rate
rx = frequencyOffset(rx,fs,cfo); % Add frequency offset

Add noise to the waveform with 30 dBW variance.

awgnChannel = comm.AWGNChannel('NoiseMethod','Variance','Variance',10^(-30/10));
rx = awgnChannel(rx);

Front-End Synchronization and Receiver Processing

To synchronize the packet, in preparation for recovering the data field, the example performs these processing steps.

  1. Detect the packet

  2. Perform coarse carrier frequency offset estimation and correction

  3. Establish symbol timing synchronization

  4. Perform fine carrier frequency offset estimation and correction

  5. Demodulate the L-LTF and estimate the noise power

  6. Demodulate the VHT-LTF and estimate the channel response

Generate field indices and perform packet detection.

ind = wlanFieldIndices(cfgVHT);
tOff = wlanPacketDetect(rx,cfgVHT.ChannelBandwidth);

Perform coarse frequency offset correction.

lstf = rx(tOff+(ind.LSTF(1):ind.LSTF(2)),:);
coarseCFOEst = wlanCoarseCFOEstimate(lstf,cfgVHT.ChannelBandwidth);
rx = frequencyOffset(rx,fs,-coarseCFOEst);

Perform symbol timing synchronization.

nonhtPreamble = rx(tOff+(ind.LSTF(1):ind.LSIG(2)),:);
symOff = wlanSymbolTimingEstimate(nonhtPreamble,cfgVHT.ChannelBandwidth);
tOff = tOff+symOff;

Perform fine frequency offset correction.

lltf = rx(tOff+(ind.LLTF(1):ind.LLTF(2)),:);
fineCFOEst = wlanFineCFOEstimate(lltf,cfgVHT.ChannelBandwidth);
rx = frequencyOffset(rx,fs,-fineCFOEst);

Perform channel estimation.

vhtltf = rx(tOff+(ind.VHTLTF(1):ind.VHTLTF(2)),:);
vhtltfDemod = wlanVHTLTFDemodulate(vhtltf,cfgVHT);
[chanEst,chanEstSSPilots] = wlanVHTLTFChannelEstimate(vhtltfDemod,cfgVHT);

Recovery Without Sampling Clock Offset or Residual CFO Tracking

The coarse and fine frequency offset estimation and correction removes the majority of CFO, but residual CFO remains due to the presence of impairments in the waveform. The receiver must track and correct this offset.

disp('Front-end impairment correction:');
Front-end impairment correction:
frontEndCFOEst = coarseCFOEst+fineCFOEst;
disp(['  Estimated CFO: ' num2str(frontEndCFOEst,'%.1f') ' Hz']);
  Estimated CFO: -525209.0 Hz
residualCFO = cfo-frontEndCFOEst;
disp(['  Residual CFO after initial correction: ' num2str(residualCFO,'%.1f') ' Hz']);
  Residual CFO after initial correction: 209.0 Hz

Use the trackingVHTDataRecover function to recover the VHT data field with optional pilot tracking to correct for timing and phase errors due to SCO and CFO. Control pilot tracking using the trackingRecoveryConfig object.

First, recover the data field is without pilot tracking. Extract the data field from the waveform using the start and end sample indices of the field at the baseband rate. If the receiver sampling rate is higher than the transmitter rate, the receiver requires more samples than the transmitter produces. To allow for this, extract Ne additional samples from the waveform and pass to the recovery function. The maximum number of additional samples required depends on the expected SCO, baseband sampling rate, and maximum packet duration.

Create a recovery configuration with pilot tracking disabled.

cfgRec = trackingRecoveryConfig;
cfgRec.PilotTracking = 'None';

Extract data field with Ne additional samples to allow for negative SCO.

maxDuration = 5.484e-3; % Maximum packet duration in seconds
maxSCO = 120;           % PPM
Ne = ceil(fs*maxDuration*maxSCO*1e-6); % Number of extra samples
dataInd = tOff+(ind.VHTData(1):ind.VHTData(2)+Ne);
dataInd = dataInd(dataInd<=length(rx)); % Only use indices within waveform
data = rx(dataInd,:); 

Perform demodulation and decoding.

[rxPSDUNoTrack,~,eqSymNoTrack] = trackingVHTDataRecover(data,chanEst,chanEstSSPilots,cfgVHT,cfgRec);

Plot the equalized constellation. This plot shows a rotation of all constellation points caused by residual CFO, and a spreading of constellation points due to SCO. Despite the modest AWGN added to the waveform, the impairments cause bit errors within the decoded PSDU.

ConstNoTrack = comm.ConstellationDiagram;
ConstNoTrack.Title = 'Equalized symbols with no pilot tracking';
ConstNoTrack.ReferenceConstellation = wlanReferenceSymbols(cfgVHT);

[~,berNoTrack] = biterr(rxPSDUNoTrack,psdu);
disp('Bit error rate:');
Bit error rate:
disp(['  Without tracking: ' num2str(berNoTrack)]);
  Without tracking: 0.073909

Recovery With Sampling Clock Offset Tracking and Residual CFO Tracking

Now recover the data field with joint timing and phase pilot tracking to correct for SCO and residual CFO.

The tracking algorithm in this example estimates absolute values of δ and ω per OFDM symbol and applies a per subcarrier and symbol phase correction to the demodulated symbols to reverse the phase errors caused by SCO and CFO. The algorithm calculates the phase error between each received pilot subcarrier and the expected value per symbol averaged over PilotTrackingWindow OFDM symbols. From this value, the algorithm calculates least-square estimates of δ and ω per symbol, and uses these estimates to apply a phase correction to each symbol and subcarrier [3,4] .

Create a recovery configuration with pilot tracking enabled.

cfgRec = trackingRecoveryConfig;
cfgRec.PilotTracking = 'Joint'; % Joint timing and phase tracking
cfgRec.PilotTrackingWindow = 9; % Averaging window in OFDM symbols

Perform demodulation and decoding.

[rxPSDU,~,eqSymTrack,cpe,peg] = trackingVHTDataRecover(data,chanEst,chanEstSSPilots,cfgVHT,cfgRec);

Plot the equalized constellation. This shows a clear 16-QAM constellation with no spreading or rotation. The decoded PSDU contains no bit errors.

ConstTrack = comm.ConstellationDiagram;
ConstTrack.Title = 'Equalized symbols with joint pilot tracking';
ConstTrack.ReferenceConstellation = wlanReferenceSymbols(cfgVHT);

[~,berTrack] = biterr(rxPSDU,psdu);
disp(['  With tracking: ' num2str(berTrack)]);
  With tracking: 0

The trackingVHTDataRecover function returns measurements from which the residual CFO, and SCO can be estimated:

  • cpe - The common phase error (radians) per symbol

  • peg - The phase error gradient (radians per subcarrier) per symbol

Estimate the SCO and residual CFO from these measurements using a linear least-square fit of the rate of change. The trackingPlotSCOCFOEstimates function performs these measurements and plot the results.

[residualCFOEst,scoEst] = trackingPlotSCOCFOEstimates(cpe,peg,cfgVHT);

fprintf('Tracked impairments:\n');
Tracked impairments:
fprintf('  Estimated residual CFO: %3.1f Hz (%.1f Hz error)\n', ...
  Estimated residual CFO: 198.9 Hz (-10.1 Hz error)
fprintf('  Estimated SCO: %3.1f PPM (%.1f PPM error)\n',scoEst,scoEst-sco);
  Estimated SCO: -98.3 PPM (1.7 PPM error)
cfoEst = frontEndCFOEst+residualCFOEst; % Initial + tracked CFO estimate
fprintf('Estimated CFO (initial + tracked): %.1f Hz (%.1f Hz error)\n',cfoEst,cfoEst-cfo);
Estimated CFO (initial + tracked): -525010.1 Hz (-10.1 Hz error)
rng(s); % Restore the state of the random number generator


This example shows how you can track and correct sampling clock and carrier frequency offsets when recovering the data field of a WLAN waveform.

This example uses data field recovery functions with joint pilot tracking for VHT, HT-MF and non-HT formats, and an object to configure the recovery algorithms.

To see an example of pilot tracking for HE format packets see the Recovery Procedure for an 802.11ax Packet example.


  1. Speth, M., S.A. Fechtel, G. Fock, and H. Meyr. “Optimum Receiver Design for Wireless Broad-Band Systems Using OFDM. I.” IEEE Transactions on Communications 47, no. 11 (November 1999): 1668–77.

  2. IEEE Std 802.11™-2020. IEEE Standard for Information Technology - Telecommunications and Information Exchange between Systems - Local and Metropolitan Area Networks - Specific Requirements - Part 11: Wireless LAN Medium Access Control (MAC) and Physical Layer (PHY) Specifications.

  3. Chiueh, Tzi-Dar, Pei-Yun Tsai, Lai. I-Wei, and Tzi-Dar Chiueh. Baseband Receiver Design for Wireless MIMO-OFDM Communications. 2nd ed. Hoboken, N.J: J. Wiley & Sons, 2012.

  4. Horlin, François, and André Bourdoux. Digital Compensation for Analog Front-Ends: A New Approach to Wireless Transceiver Design. Chichester, West Sussex ; Hoboken, NJ: J. Wiley & Sons, 2008.