# End-to-End DVB-S2X Simulation with RF Impairments and Corrections for VL-SNR Frames

This example shows how to measure the bit error rate (BER) and packet error rate (PER) of a single stream Digital Video Broadcasting Satellite Second Generation extended (DVB-S2X) link that has constant coding and modulation for very low signal to noise ratio (VL-SNR) frames. The example describes the symbol timing, frame and carrier synchronization strategies in detail emphasizing on how to estimate the RF front-end impairments under severe noise conditions. The single stream signal adds RF front-end impairments and then passes the waveform through an additive white Gaussian noise (AWGN) channel.

### Introduction

An increasing number of DVB-S2X terminals are being used on trains, buses, boats, and airplanes. Many applications, such as sensor networks, remote infrastructure monitoring, and emergency services, require ubiquitous coverage, and low data rates. Support for these applications was therefore included in the design of DVB-S2X, introducing VL-SNR configurations to increase the operating range to cover current and emerging applications that can benefit from operation at very low SNR. The DVB-S2X standard added nine additional modulation and coding schemes (MODCODs) in the QPSK and BPSK range. These MODCODs enable the satellite networks to deal with heavy atmospheric fading and to enable use of smaller antennas for applications in motion (land, sea, and air).

These figures show the two formats used for VL-SNR frames.

This example designs the synchronization aspects of a DVB-S2X receiver used for VL-SNR applications. The example supports all the nine MODCODs defined by the standard.

ETSI EN 302 307-2 Section 6 Table 20a, Table 20b, and Table 20c [1] summarizes the Quasi-Error-Free (QEF) performance requirement over an AWGN channel for different modulation schemes and code rates. The operating ${\mathit{E}}_{\mathit{s}}/{\mathit{N}}_{\mathit{o}}$ range for VL-SNR applications is considered from -2 dB to -10 dB. Because the operating ${\mathit{E}}_{\mathit{s}}/{\mathit{N}}_{\mathit{o}}$ range is low, the carrier, frame, and symbol timing synchronization strategies are challenging design problems.

This diagram summarizes the example workflow.

#### Main Processing Loop

The example processes 20 physical layer (PL) frames of data with the ${\mathit{E}}_{\mathit{s}}/{\mathit{N}}_{\mathit{o}}$ set to 5 dB, and then computes the BER and PER. Carrier frequency offset, frequency drift, symbol timing offset, sampling clock offset, and phase noise impairments are applied to the modulated signal, and AWGN is added to the signal. ETSI EN 302 307-2 Section 4.4.4 describes the typical RF impairment ranges used under VL-SNR conditions.

To extract PL frames, the receiver processes the distorted waveform through various timing and carrier recovery strategies. The fine frequency and carrier phase recovery algorithms are pilot-aided. To decode the data frames, the physical layer transmission parameters, such as VL-SNR set type, MODCOD, and FEC frame type are recovered from the VL-SNR header. To regenerate the input bit stream, the baseband (BB) header is decoded.

Because the DVB-S2X standard supports packetized and continuous modes of transmission, the BB frame can be either a concatenation of user packets or a stream of bits. The BB header is recovered to determine the mode of transmission. If the BB frame is a concatenation of user packets, the packet cyclic redundancy check (CRC) status of each packet is returned along with the decoded bits, and then the PER and BER are measured.

These block diagrams show the synchronization and input bit recovery workflows.

This example loads a MAT-file with DVB-S2X LDPC parity matrices. If the MAT-file is not available on the MATLAB® path, use these commands to download and unzip the MAT-file.

if ~exist('dvbs2xLDPCParityMatrices.mat','file')
if ~exist('s2xLDPCParityMatrices.zip','file')
url = 'https://ssd.mathworks.com/supportfiles/spc/satcom/DVB/s2xLDPCParityMatrices.zip';
websave('s2xLDPCParityMatrices.zip',url);
unzip('s2xLDPCParityMatrices.zip');
end
end

### DVB-S2X Configuration

Specify the cfgDVBS2X structure to define DVB-S2X transmission configuration parameters. PLSDecimalCode 129 and 131 are the only supported formats because they are used for generating VL-SNR frames.

cfgDVBS2X.StreamFormat = "TS";
cfgDVBS2X.PLSDecimalCode = 129;
cfgDVBS2X.CanonicalMODCODName = "QPSK 2/9";
cfgDVBS2X.DFL = 14128;
cfgDVBS2X.RolloffFactor = 0.35;
cfgDVBS2X.SamplesPerSymbol = 2
cfgDVBS2X = struct with fields:
StreamFormat: "TS"
PLSDecimalCode: 129
CanonicalMODCODName: "QPSK 2/9"
DFL: 14128
RolloffFactor: 0.3500
SamplesPerSymbol: 2

### Simulation Parameters

The DVB-S2X standard supports flexible channel bandwidths. Use a typical channel bandwidth such as 36 MHz. The channel bandwidth can be varied from 10MHz to 72MHz. The coarse frequency synchronization algorithm implemented in this example can track carrier frequency offsets up to 20% of the input symbol rate. The symbol rate is calculated as B/(1+R), where B is the channel bandwidth, and R is the transmit filter roll-off factor. The algorithms implemented in this example can correct the sampling clock offset up to 10 ppm.

This table defines the phase noise mask (dBc/Hz) used to generate the phase noise that is applied to the transmitted signal. These noise masks are specified in ETSI TR 102 376-1 Section 4.3 [2]. The peak doppler and frequency drift supported are specified in ETSI TR 102 376-1 Section 4.4.4.

simParams.sps = cfgDVBS2X.SamplesPerSymbol;    % Samples per symbol
simParams.numFrames = 20;                      % Number of frames to be processed
simParams.chanBW = 36e6;                       % Channel bandwidth in Hertz
simParams.cfo = 3e6;                           % Carrier frequency offset in Hertz due
% to oscillator instabilities
simParams.dopplerRate = 3e3;                   % Doppler rate in Hertz/sec
simParams.peakDoppler = 20e3;                  % Peak doppler shift due to receiver motion
simParams.sco = 10;                            % Sampling clock offset in parts per
% million
simParams.phNoiseLevel = "Level-1";            % Phase noise level
simParams.EsNodB = 5;                          % Energy per symbol to noise ratio

### Generate DVB-S2X VL-SNR Waveform Distorted with RF Impairments

To create a DVB-S2X waveform, use the HelperDVBS2XVLSNRRxInputGenerate helper function with the simParams and cfgDVBS2X structures as inputs. The function returns the data signal, transmitted, and received waveforms, physical layer configuration parameters as a structure, and a receiver processing structure. The received waveform is impaired with carrier frequency, frequency drift, symbol timing, sampling clock offsets, and phase noise and then passed through an AWGN channel. The receiver processing parameters structure, rxParams, includes the reference pilot fields, pilot indices, counters, and buffers. Plot the constellation of the received symbols and the spectrum of the transmitted and received waveforms.

[data,txOut,rxIn,phyConfig,rxParams] = ...
HelperDVBS2XVLSNRRxInputGenerate(cfgDVBS2X,simParams);
disp(phyConfig)
FECFrame: "normal"
ModulationScheme: "QPSK"
LDPCCodeIdentifier: "2/9"
'XLimits',[-1 1],'YLimits',[-1 1], ...
'ShowReferenceConstellation',false, ...
'SamplesPerSymbol',simParams.sps);
rxConst(rxIn(1:rxParams.plFrameSize*simParams.sps))

% Transmitted and received signal spectrum visualization
Rsymb = simParams.chanBW/(1 + cfgDVBS2X.RolloffFactor);
Fsamp = Rsymb*simParams.sps;
specAn = dsp.SpectrumAnalyzer('SampleRate',Fsamp, ...
'ShowLegend',true);
specAn([txOut,rxIn(1:length(txOut))]);

At the receiver, coarse frequency synchronization is performed on the received data and is then followed by matched filtering and symbol timing synchronization. The coarse frequency and symbol timing estimators are non-data aided. The coarse frequency estimation algorithm can track carrier frequency offsets up to 20% of the input symbol rate. The coarse frequency estimation, implemented as a first order frequency locked loop (FLL), reduces the frequency offset to a level that the fine frequency estimator can track. The preferred loop bandwidth for symbol timing and coarse frequency compensation depends on the ${\mathit{E}}_{\mathit{s}}/{\mathit{N}}_{\mathit{o}}$ setting.

When you decrease the ${\mathit{E}}_{\mathit{s}}/{\mathit{N}}_{\mathit{o}}$, reduce the loop bandwidth to filter out more noise during acquisition. The number of frames required for the symbol synchronizer and coarse FLL to converge depends on the loop bandwidth setting.

Symbol timing synchronization is followed by frame synchronization and MODCOD format detection. The frame synchronization uses the VL-SNR header. Because the fine frequency and carrier phase synchronization are data-aided, the frame synchronization must detect the start of frame accurately.

The fine frequency estimation can track carrier frequency offsets up to 3.5% of the input symbol rate. The fine frequency estimation must process multiple pilot blocks for the residual carrier frequency offset to be reduced to levels acceptable for the phase estimation algorithm. The phase estimation algorithm can handle residual carrier frequency error less than 0.05% of the input symbol rate.

These settings are assigned in the rxParams structure for synchronization processing. For details on how to set these parameters for low ${\mathit{E}}_{\mathit{s}}/{\mathit{N}}_{\mathit{o}}$ values, see the Further Exploration section.

rxParams.carrSyncLoopBW = 1e-4;          % Coarse frequency estimator loop bandwidth
% normalized by symbol rate
rxParams.symbSyncLoopBW = 1e-4;          % Symbol timing synchronizer loop bandwidth
% normalized by symbol rate
rxParams.initialTimeFreqSync = 5;        % Number of frames required for coarse frequency
% and symbol timing error convergence
rxParams.fineFreqLock = 4;               % Number of frames required for fine
% frequency estimation
rxParams.NeedSmoothening = false;        % Smoothen the phase estimate

% Total frames used for overall synchronization
rxParams.totalSyncFrames = rxParams.initialTimeFreqSync + rxParams.fineFreqLock;

% Create coarse frequency synchronization System object by using
% HelperDVBS2XVLSNRCoarseFreqSynchronizer helper object
freqSync = HelperDVBS2XVLSNRCoarseFreqSynchronizer('SamplesPerSymbol',simParams.sps, ...
'NormalizedLoopBandwidth',rxParams.carrSyncLoopBW);

% Create symbol timing synchronization System object by using
% comm.SymbolSynchronizer object
symSync = comm.SymbolSynchronizer('TimingErrorDetector','Gardner (non-data-aided)', ...
'NormalizedLoopBandwidth',rxParams.symbSyncLoopBW);

% Create matched filter System object by using
if simParams.sps == 2
decFac = 1;
else
decFac = simParams.sps/(simParams.sps/2);
end
'RolloffFactor',0.35, ...
'InputSamplesPerSymbol',simParams.sps,'DecimationFactor',decFac);
b = rxFilter.coeffs;
rxFilter.Gain = sum(b.Numerator);

% Initialize error computing parameters
[numFramesLost,pktsErr,bitsErr,pktsRec] = deal(0);

% Initialize data indexing variables
stIdx = 0;
dataSize = rxParams.inputFrameSize;
plFrameSize = rxParams.plFrameSize;
isLastFrame = false;
rxParams.fineFreqCorrVal = zeros(rxParams.fineFreqLock,1);
[formatIdx,formatIdxTemp] = deal(1);
vlsnrSyncStIdx = 93;
vlSNRFrameLen = plFrameSize - vlsnrSyncStIdx + 1;

### Timing and Carrier Synchronization and Data Recovery

To synchronize the received data and recover the input bit stream, process the distorted DVB-S2X waveform samples one frame at a time by following these steps.

1. Apply coarse frequency synchronization using a balanced quadricorrelator frequency error detector (BQ-FED) in an FLL [5].

2. Apply matched filtering, outputting at the rate of two samples per symbol.

3. Apply symbol timing synchronization using the Gardner timing error detector with an output generated at the symbol rate.

4. Apply frame synchronization to detect the start of frame and MODCOD format to identify the pilot positions.

5. Estimate and apply fine frequency offset correction.

6. Estimate and compensate for residual carrier frequency and phase noise.

7. Demodulate and decode the VL-SNR frames.

8. Perform CRC check on the BB header, if the check passes, recover the header parameters.

9. Regenerate the input stream of data or packets from BB frames.

while stIdx < length(rxIn)

% Use one DVB-S2X PL frame for each iteration.
endIdx = stIdx + rxParams.plFrameSize*simParams.sps;

% In the last iteration, all the remaining samples in the received
% waveform are considered.
isLastFrame = endIdx > length(rxIn);
endIdx(isLastFrame) = length(rxIn);
rxData = rxIn(stIdx+1:endIdx);

% After coarse frequency offset loop is converged, the FLL works with
% previous frequency estimate.
if rxParams.frameCount < rxParams.initialTimeFreqSync
coarseFreqLock = false;
else
coarseFreqLock = true;
end

% Retrieve the last frame samples.
if isLastFrame
resSampCnt = plFrameSize*rxParams.sps - length(rxData);
% Inadequate number of samples to fill last frame
syncIn = [rxData; zeros(resSampCnt,1)];
else
syncIn = rxData;
end

% Apply coarse frequency offset compensation.
[coarseFreqSyncOut,phEst] = freqSync(syncIn,coarseFreqLock);

% Perform matched filtering and downsample the signal to 2 samples per
% symbol.
filtOut = rxFilter(coarseFreqSyncOut);

% Apply symbol timing synchronization.
symSyncOut = symSync(filtOut);

% Apply frame synchronization and identify the MODCOD format. VL-SNR
% sync frame is detected. PL header preceding the VL-SNR header is
% ignored.
if rxParams.frameCount > rxParams.initialTimeFreqSync && ~isLastFrame
[~,rxParams.syncIndex,formatIdx] = ...
HelperDVBS2XVLSNRFrameSync(symSyncOut,rxParams.SegLength);
% MODCOD format identification failure verification
formatFail = formatIdxTemp ~= rxParams.refFormat;
if formatFail && ~isLastFrame
% Update the counters, state variables, and buffers
stIdx = endIdx;
rxParams.frameCount = rxParams.frameCount + 1;
formatIdxTemp = formatIdx;
rxParams.cfBuffer = symSyncOut(rxParams.syncIndex:end);
fprintf('%s\n','MODCOD format detection failed')
continue;
else
fprintf('%s\n','MODCOD format detection passed')
[setNum,phyParams] = getVLSNRParams(formatIdxTemp);
end
end

% The PL frame start index lies somewhere in the middle of the data
% being processed. From fine frequency estimation onwards, the
% processing happens as a PL frame. A buffer is used to store symbols
% required to fill one PL frame. PL frame is considered from
% the start of VL-SNR header, precisely from the start of the 896 bit
% length, and 2 accounts for the two zeros appended before the WH sequence.
fineFreqIn = [rxParams.cfBuffer;...
symSyncOut(1:vlSNRFrameLen-length(rxParams.cfBuffer))];

% Estimate the fine frequency error by using the HelperDVBS2FineFreqEst
% helper function.
% Add 1 to the conditional check because the buffer used to get one PL
% frame introduces a delay of one to the loop count.
if (rxParams.frameCount > rxParams.initialTimeFreqSync + 1)

% Get the correlation estimate from the regular 36 length pilot blocks.
est1 = HelperDVBS2FineFreqEst( ...
rxParams.regPilotSeq,rxParams.fineFreqState,36,rxParams.NumLags);

% Get the correlation estimate from the VL-SNR extra pilot blocks.
% vlSNRPilotBlk1Params contains the VL-SNR type 1 pilot block
% length and number of blocks in one frame.
Lp = rxParams.vlSNRPilotBlk1Params(1);
est2 = HelperDVBS2FineFreqEst( ...
rxParams.vlSNRPilotSeq1,rxParams.fineFreqState,Lp,rxParams.NumLags);

% vlSNRPilotBlk2Params contains the VL-SNR type 2 pilot block
% length and number of blocks in one frame.
Lp = rxParams.vlSNRPilotBlk2Params(1);
est3 = HelperDVBS2FineFreqEst( ...
rxParams.vlSNRPilotSeq2,rxParams.fineFreqState,Lp,rxParams.NumLags);

estVal = est1 + est2 + est3;
% Use the correlation values calculated over pilot fields spanning over
% multiple frames to calculate the fine frequency error estimate.
% The estimation uses a sliding window technique.
rxParams.fineFreqCorrVal = [rxParams.fineFreqCorrVal(2:end);estVal];
end

if rxParams.frameCount >= rxParams.totalSyncFrames
fineFreqLock = true;
else
fineFreqLock = false;
end

if fineFreqLock
freqEst = angle(sum(rxParams.fineFreqCorrVal))/(pi*(rxParams.NumLags+1));
ind = (rxParams.frameCount-2)*plFrameSize:(rxParams.frameCount-1)*plFrameSize-1;
phErr = exp(-1j*2*pi*freqEst*ind).';
% 92 accounts for the PL header (90), and 2 for zeros appended before the WH
% sequence.
fineFreqOut = fineFreqIn(1:vlSNRFrameLen).*phErr(vlsnrSyncStIdx:end);
% 898 accounts for the 896 length WH sequence, and 2 zeros padded to the
phErrEst = HelperDVBS2PhaseEst(rxPilots,rxParams.pilotSeq, ...
rxParams.phErrState,rxParams.IsVLSNR,setNum,rxParams.Alpha);
if rxParams.NeedSmoothening
phErrEst =  smoothenEstimate(phErrEst);
end
phErrEst,rxParams.pilotInd,setNum,rxParams.IsVLSNR);
end

% Recover the input bit stream.
if rxParams.frameCount >= rxParams.totalSyncFrames
isValid = true;
syncOut = phaseCompOut;
else
isValid = false;
syncOut = [];
end

% Update the buffers and counters.
rxParams.cfBuffer = symSyncOut(rxParams.syncIndex:end);

if isValid  % Data valid signal
% Estimate noise variance by using
% HelperDVBS2NoiseVarEstimate helper function.
nVar = HelperDVBS2NoiseVarEstimate(syncOut,rxParams.pilotInd, ...
rxParams.pilotSeq,false);
% Recover the BB frame by using HelperDVBS2XBBFrameRecover
% helper function.
rxBBFrame = HelperDVBS2XBBFrameRecover(syncOut,phyParams, ...
rxParams.plScramblingIndex,rxParams.regNumPilotBlks,nVar,true,setNum);
% Recover the input bit stream by using
% HelperDVBS2StreamRecover helper function.
if strcmpi(cfgDVBS2X.StreamFormat,'GS') && ~rxParams.UPL
[decBits,isFrameLost] = HelperDVBS2StreamRecover(rxBBFrame);
if ~isFrameLost && length(decBits) ~= dataSize
isFrameLost = true;
end
else
[decBits,isFrameLost,pktCRC] = HelperDVBS2StreamRecover(rxBBFrame);
if ~isFrameLost && length(decBits) ~= dataSize
isFrameLost = true;
pktCRC = zeros(0,1,'logical');
end
% Compute the PER for TS or GS packetized
% mode.
pktsErr = pktsErr + numel(pktCRC) - sum(pktCRC);
pktsRec = pktsRec + numel(pktCRC);
end
if ~isFrameLost
ts = sprintf('%s','BB header decoding passed.');
else
ts = sprintf('%s','BB header decoding failed.');
end
% Compute the number of frames lost. CRC failure of the
% baseband header is considered a frame loss.
numFramesLost = isFrameLost + numFramesLost;
fprintf('%s(Number of frames lost = %1d)\n',ts,numFramesLost)
% Compute the bits in error.
if ~isFrameLost
dataInd = (rxParams.frameCount-2)*dataSize+1:(rxParams.frameCount-1)*dataSize;
errs = sum(data(dataInd) ~= decBits);
bitsErr = bitsErr + errs;
end
end

stIdx = endIdx;
rxParams.frameCount = rxParams.frameCount + 1;
formatIdxTemp = formatIdx;
end
MODCOD format detection passed
MODCOD format detection passed
MODCOD format detection passed
MODCOD format detection passed
BB header decoding passed.(Number of frames lost = 0)
MODCOD format detection passed
BB header decoding passed.(Number of frames lost = 0)
MODCOD format detection passed
BB header decoding passed.(Number of frames lost = 0)
MODCOD format detection passed
BB header decoding passed.(Number of frames lost = 0)
MODCOD format detection passed
BB header decoding passed.(Number of frames lost = 0)
MODCOD format detection passed
BB header decoding passed.(Number of frames lost = 0)
MODCOD format detection passed
BB header decoding passed.(Number of frames lost = 0)
MODCOD format detection passed
BB header decoding passed.(Number of frames lost = 0)
MODCOD format detection passed
BB header decoding passed.(Number of frames lost = 0)
MODCOD format detection passed
BB header decoding passed.(Number of frames lost = 0)
MODCOD format detection passed
BB header decoding passed.(Number of frames lost = 0)
MODCOD format detection passed
BB header decoding passed.(Number of frames lost = 0)
BB header decoding passed.(Number of frames lost = 0)

### Visualization and Error Logs

Plot the constellation of the synchronized data and compute the BER and PER.

% Synchronized data constellation plot
syncConst = comm.ConstellationDiagram('Title','Synchronized data', ...
'XLimits',[-1.7 1.7],'YLimits',[-1.7 1.7], ...
'ShowReferenceConstellation',false);
syncConst(syncOut)

pause(0.5)
% Error metrics display
% For GS continuous streams
if strcmpi(cfgDVBS2X.StreamFormat,'GS') && ~rxParams.UPL
if (simParams.numFrames-rxParams.totalSyncFrames == numFramesLost)
else
numFramesRec = simParams.numFrames - rxParams.totalSyncFrames - numFramesLost;
ber = bitsErr/(numFramesRec*dataSize);
fprintf('BER           : %1.2e\n',ber)
end
else
% For GS and TS packetized streams
if pktsRec == 0
else
if strcmpi(cfgDVBS2X.StreamFormat,'TS')
pktLen = 1504;
else
pktLen = cfgDVBS2X.UPL;      % UP length including sync byte
end
ber = bitsErr/(pktsRec*pktLen);
per = pktsErr/pktsRec;
fprintf('PER: %1.2e\n',per)
fprintf('BER: %1.2e\n',ber)
end
end
PER: 0.00e+00
BER: 0.00e+00

### Further Exploration

The operating ${\mathit{E}}_{\mathit{s}}/{\mathit{N}}_{\mathit{o}}$ range of the VL-SNR mode being very low requires the normalized loop bandwidth of the symbol synchronizer and coarse FLL to be very small for accurate estimation. Set these parameters using the rxParams.symbSyncLoopBW and rxParams.carrSyncLoopBW.

#### Configure Coarse Carrier Synchronization Parameters

Initialize HelperDVBS2XVLSNRCoarseFreqSynchronizer System object with rxParams.carrSyncLoopBW set as 2e-5 and then run the simulation.

When you set the PLSDecimalCode property to 129, set the rxParams.initialTimeFreqSync property to 15. When you set the PLSDecimalCode property to 131, set the rxParams.coarseFreqLock property to 30. Set simParams.EsNodB to the lowest ${\mathit{E}}_{\mathit{s}}/{\mathit{N}}_{\mathit{o}}$ for the chosen modulation scheme from ETSI EN 302 307-1 Section 6 [1].

Replace the code in the coarse frequency synchronization section with these lines of code. Run the simulation for different carrier frequency offset (CFO) values. After coarse frequency compensation, view the plot and the residual CFO value (resCoarseCFO) over each frame to observe the performance of the coarse frequency estimation algorithm. Ideally, the coarse frequency compensation reduces the error to 2% of the symbol rate. If the residual CFO error is not reduced to less than 2% of the symbol rate, try decreasing the loop bandwidth and increasing the rxParams.initialTimeFreqSync. The coarse frequency is a first order FLL, and it can only detect the static carrier frequency offset. It cannot track Doppler rate changes.

% [coarseFreqSyncOut,phEst] = freqSync(syncIn,false);
% Frequency offset estimate normalized by symbol rate
% freqOffEst = diff(phEst(1:simParams.sps:end))/(2*pi);
% plot(freqOffEst)
% Rsym = simParams.chanBW/(1+cfgDVBS2X.RolloffFactor);
% actFreqOff = (simParams.cfo + simParams.peakDoppler)/Rsym;
% resCoarseCFO = abs(actFreqOff-freqOffEst(end));

When the residual carrier frequency offset value (resCoarseCFO) is reduced to approximately 0.02, set the rxParams.frameCount as the rxParams.initialTimeFreqSync value.

#### Configure Symbol Timing Synchronization Parameters

Try running the simulation using the symbol timing synchronizer configured with a normalized loop bandwidth of 1e-4. To achieve convergence of the timing loop, the ratio rxParams.symbSyncLoopBW/simParams.sps must be greater than 1e-5. If the symbol timing loop doesn't converge, try decreasing the rxParams.symbSyncLoopBW.

#### Configure Frame Synchronization Parameters

Proper frame synchronization depends on the segment length, rxParams.SegLength, which is used to divide the reference VL-SNR header symbols into smaller segments to perform segment coherent correlation. rxParams.SegLength depends on the residual CFO that is present after coarse frequency synchronization and must be less than round(3/(8*resCoarseCFO)). Prefer using a value that is an integer multiple of 896 (length of VL-SNR WH sequence). If CFO is absent, perform correlation using rxParams.SegLength as 896.

#### Configure Fine Frequency Synchronization Parameters

When you set the PLSDecimalCode property to 129, set the rxParams.fineFreqLock property to 10. When you set the PLSDecimalCode property to 131, set the rxParams.coarseFreqLock property to 20. Set simParams.EsNodB to the lowest ${\mathit{E}}_{\mathit{s}}/{\mathit{N}}_{\mathit{o}}$ for the chosen modulation scheme from ETSI EN 302 307-1 Section 6 [1].

Replace the code in the fine frequency error estimation section with this code. Fine frequency estimator tracks the Doppler rate changes. To estimate the residual CFO error, include the sinusoidal variation of the Doppler shift included in the actFreqOff estimate. For an easy workaround, do not introduce Doppler rate in impairment. Instead, add only static CFO and analyze the number of frames required to generate an accurate estimate. Typically, those number of frames are sufficient to estimate CFO changes due to Doppler rate. As the Doppler rate changes are handled by the fine frequency estimator, 2*simParams.peakDoppler must be less than the estimation range of the fine frequency estimator. The estimation range depends on the rxParams.NumLags parameter and the normalized CFO that can be estimated is given by 1/(rxParams.NumLags+1). To increase the estimation range, try reducing the rxParams.NumLags . You might need more pilot blocks because the estimation accuracy drops.

% fineFreqEst = angle(sum(rxParams.fineFreqCorrVal))/(pi*(rxParams.NumLags+1));
% resFineCFO = abs(actFreqOff-freqOffEst(end)-fineFreqEst);

Repeat the simulation process and observe the residual CFO value (resFineCFO) over each frame. If the fine frequency estimator does not reduce the residual carrier frequency error to approximately 0.03% of the symbol rate, try increasing the rxParams.fineFreqLock property value.

When the residual CFO value (resFineCFO) is reduced to approximately 0.0003, update rxParams.totalSyncFrames based on rxParams.initialTimeFreqSyncrxParams and rxParams.fineFreqLock values.

#### Configure Phase Synchronization Parameters

HelperDVBS2PhaseEstimate estimates the residual CFO and phase error appropriately up to -8 dB of ${\mathit{E}}_{\mathit{s}}/{\mathit{N}}_{\mathit{o}}$. For ${\mathit{E}}_{\mathit{s}}/{\mathit{N}}_{\mathit{o}}$ less than -8 dB, set rxParams.Alpha to less than 0.5 if data that passed through HelperDVBS2PhaseEstimate has only phase error. If the data has residual CFO along with phase error, keep rxParams.Alpha as 1 and set rxParams.NeedSmoothening as true. Smoothening improves the phaseEst obtained from HelperDVBS2PhaseEstimate.

After refining the synchronization parameters set in the rxParams structure, perform the BER simulation for the updated configuration.

### Appendix

The example uses these helper functions:

### Bibliography

1. ETSI Standard EN 302 307-2 V1.1.1(2015-11). Digital Video Broadcasting (DVB); Second Generation Framing Structure, Channel Coding and Modulation Systems for Broadcasting, Interactive Services, News Gathering and other Broadband Satellite Applications; Part 2: DVB-S2 extensions (DVB-S2X).

2. ETSI Standard TR 102 376-2 V1.2.1(2015-11). Digital Video Broadcasting (DVB); Implementation Guidelines for the Second Generation System for Broadcasting, Interactive Services, News Gathering and other Broadband Satellite Applications; Part 2: S2 extensions (DVB-S2X).

3. ETSI Standard TR 102 376-1 V1.2.1(2015-11). Digital Video Broadcasting (DVB); Implementation Guidelines for the Second Generation System for Broadcasting, Interactive Services, News Gathering and other Broadband Satellite Applications (DVB-S2).

4. Mengali, Umberto, and Aldo N.D'Andrea. Synchronization Techniques for Digital Receivers. New York: Plenum Press,1997.

5. D’Andrea, A. N., and U. Mengali. “Design of Quadricorrelators for Automatic Frequency Control Systems.” IEEE Transactions on Communications, vol. 41, no. 6, June 1993, pp. 988–97.

6. Casini, E., et al. “DVB-S2 Modem Algorithms Design and Performance over Typical Satellite Channels.” International Journal of Satellite Communications and Networking, vol. 22, no. 3, May 2004, pp. 281–318.

7. Michael Rice, Digital Communications: A Discrete-Time Approach. New York: Prentice Hall, 2008.

### Local Functions

function [setNum,phyParams] = getVLSNRParams(formatIdx)

tableVLSNR = [4 64800 2/9 0; ...
2 32400 1/5 0; ...
2 32400 11/45 0; ...
2 32400 1/3 0; ...
2 16200 1/5 1; ...
2 16200 11/45 1; ...
2 16200 1/5 0; ...
2 16200 4/15 0; ...
2 16200 1/3 0];

params = tableVLSNR(formatIdx,:);
phyParams.ModOrder = params(1);
phyParams.FECFrameLen = params(2);
phyParams.CodeRate = params(3);
[n, d] = rat(phyParams.CodeRate);
phyParams.CodeIDF = [sprintf('%0.0f',n) '/' sprintf('%0.0f',d)];
phyParams.HasPilots = true;

if formatIdx > 6
setNum = 2;
else
setNum = 1;
end
end
% Smoothen the phase estimate using moving average filter
errDiff = diff(est(2:end));
thres = -2*sign(mean(errDiff));
width = 5;
if thres > 0
index = find(errDiff > thres);
else
index = find(errDiff < thres);
end
if ~isempty(index)
for k = 1:length(index)
est(index(k)+2:end) = est(index(k)+2:end)-sign(thres)*2*pi;
end
end
temp = est(2:end);
n = length(temp);
c = filter(ones(width,1)/width,1,temp);
cbegin = cumsum(temp(1:width-2));
cbegin = cbegin(1:2:end)./(1:2:(width-2))';
cend = cumsum(temp(n:-1:n-width+3));
cend = cend(end:-2:1)./(width-2:-2:1)';
c = [cbegin;c(width:end);cend];
end