Main Content

End-to-End CCSDS Telemetry Synchronization and Channel Coding Simulation with RF Impairments and Corrections

This example shows how to measure the bit error rate (BER) of the end-to-end chain of the Consultative Committee for Space Data Systems (CCSDS) telemetry (TM) system. The simulation chain follows the coding and modulation schemes that are specified by these two standards:

  • TM Synchronization and Channel Coding - CCSDS 131.0-B-3 for channel coding schemes [1]

  • Radio Frequency and Modulation Systems - part 1 Earth Stations and Spacecraft - CCSDS 401.0-B-30 for modulation schemes [2]


Data from various instruments is generated on board the satellite. This data collectively is called TM data. CCSDS specifies the coding and modulation schemes for the transmission of TM data from the satellite to an Earth station. This example shows the end-to-end simulation of the satellite to the Earth station communication link. The example shows how to generate a complex baseband CCSDS TM waveform from the randomly generated transfer frames (TFs), introduce radio frequency (RF) impairments to the baseband signal, and add additive white Gaussian noise (AWGN) to the impaired signal. Then, the example shows the synchronization, demodulation, and decoding of this impaired noisy signal to get the final bits in the form of TFs. The example also shows how to measure the BER with respect to the signal-to-noise ratio (SNR) for one configuration of the CCSDS TM signal. This figure shows the end-to-end simulation chain.

This example models these RF impairments:

  • Carrier frequency offset (CFO)

  • Carrier phase offset (CPO)

  • Symbol timing offset (STO)

This figure shows the receiver side operations.

The frame synchronization and channel decoding processing step performs these three tasks.

  1. Perform phase ambiguity resolution

  2. Correctly synchronize the frame to the starting of the attached sync marker (ASM)

  3. Perform channel decoding of the synchronized frame to get the recovered TF

This figure shows these three tasks. To start, form a bank of ASM sequences. Each sequence corresponds to the original ASM value in which phase ambiguity is introduced. Correlate each of these sequences with the demodulated symbols. Choose the phase ambiguity value that has the highest correlation peak. Perform the frame synchronization with this correlation process. The process to perform correlation is illustrated in section 9.3.7 in [3]. This example adopts the simplified Massey algorithm for frame synchronization. Resolve the phase ambiguity on the complete set of demodulated symbols after the frame synchronization process is complete. Finally, perform channel decoding on these symbols to obtain the recovered TFs.

Simulation Parameters

This example uses a quadrature phase shift keying (QPSK) modulation scheme for signal generation and reception and a rate-1/2 convolutional coding scheme for channel coding. The end-to-end chain this example shows can also be used for the channel coding schemes that are specified in [1]: Reed-Solomon (RS) codes and concatenated codes. For convolutional and concatenated codes, this example supports rates of 1/2 and 2/3 along with pulse code modulation (PCM)-format of non-return to zero-line (NRZ-L). The supported modulation schemes in this example are binary phase shift keying (BPSK) and QPSK.

seeConstellation = true;         % Flag to toggle the visualization of constellation
channelCoding = "convolutional"; % Channel coding scheme
transferFrameLength = 1115;      % In bytes corresponding to 223*5
modScheme = "QPSK";              % Modulation scheme
alpha = 0.35;                    % Root raised cosine filter roll-off factor
sps = 8;                         % Samples per symbol

Set the frequencies that are used for signal generation and the RF impairment values.

fSym = 2e6; % Symbol rate or Baud rate in Hz
cfo = 2e5;  % In Hz

Initialize the energy per bit to noise power ratio (Eb/N0), which is used to calculate the SNR using system parameters.

EbN0 = 10; % To see a proper BER result, run the simulation for 3.2:0.2:5

Initialize the parameters to terminate the simulation. The parameters are set to small values in this example to get quick results. Increase these parameters value to get a smoother BER curve.

maxNumErrors = 1e2;  % Simulation stops after maxNumErrors bit errors
maxNumBits = 1e5;    % Simulation stops after processing maxNumBits
                     % Set maxNumBits = 1e8 for a smoother BER curve
maxFramesLost = 1e2; % Simulation stops after maxFramesLost frames are lost

System Parameters

Initialize all of the objects that are required for the proper functioning of the end-to-end chain.

Create a CCSDS TM waveform generator with these parameters by using the ccsdsTMWaveformGenerator System object™. Display the properties of the object.

tmWaveGen = ccsdsTMWaveformGenerator("ChannelCoding",channelCoding, ...
    "NumBytesInTransferFrame",transferFrameLength, ...
    "Modulation",modScheme, ...
    "RolloffFactor",alpha, ...
  ccsdsTMWaveformGenerator with properties:

             WaveformSource: "synchronization and channel coding"
    NumBytesInTransferFrame: 1115
              HasRandomizer: true
                     HasASM: true
                  PCMFormat: "NRZ-L"

   Channel coding
              ChannelCoding: "convolutional"
      ConvolutionalCodeRate: "1/2"
              InvertCCPath2: true

   Digital modulation and filter
                 Modulation: "QPSK"
         PulseShapingFilter: "root raised cosine"
              RolloffFactor: 0.3500
        FilterSpanInSymbols: 10
           SamplesPerSymbol: 8

  Use get to show all properties

Calculate the SNR from the Eb/N0 and initialize the parameters related to the calculation of BER.

rate =;
M =;
numBitsInTF = tmWaveGen.NumInputBits;
snr = EbN0 + 10*log10(rate) + ...
    10*log10(M) - 10*log10(sps);      % As signal power is scaled to one while introducing noise, 
                                      % SNR value should be reduced by a factor of SPS
numSNR = length(snr);
ber = zeros(numSNR,1);                % Initialize the BER parameter
bercalc = comm.ErrorRate; 

Create a receive filter object by using the comm.RaisedCosineReceiveFilter System object.

b = rcosdesign(alpha,tmWaveGen.FilterSpanInSymbols,sps);
% |H(f)| = 1  for |f| < fN(1-alpha) - Annex 1 in Section 2.4.17A in [2]
Gain =  sum(b);
rxFilterDecimationFactor = sps/2;
rxfilter = comm.RaisedCosineReceiveFilter( ...
    "DecimationFactor",rxFilterDecimationFactor, ...
    "InputSamplesPerSymbol",sps, ...
    "RolloffFactor",alpha, ...

Model frequency and phase offsets by using the comm.PhaseFrequencyOffset System object. Compensate for frequency and phase offset at the receiver in two steps.

  1. Compensate for the coarse frequency offset by using the comm.CoarseFrequencyCompensator System object.

  2. Compensate for the fine frequency offset and the phase offset by using the comm.CarrierSynchronizer System object.

phaseOffset = pi/8;
fqyoffsetobj = comm.PhaseFrequencyOffset( ...
    "FrequencyOffset",cfo, ...
    "PhaseOffset",phaseOffset, ...
coarseFreqSync = comm.CoarseFrequencyCompensator( ...
    "Modulation",modScheme, ...
    "FrequencyResolution",100, ...
fineFreqSync = comm.CarrierSynchronizer("DampingFactor",1/sqrt(2), ...
    "NormalizedLoopBandwidth",0.0007, ...
    "SamplesPerSymbol",1, ...

Create a variable fractional delay object by using the dsp.VariableFractionalDelay System object, which introduces the fractional delay in the transmitted waveform. Create a symbol synchronization object by using the comm.SymbolSynchronizer System object, which performs symbol timing synchronization.

varDelay = dsp.VariableFractionalDelay("InterpolationMethod","Farrow");
fixedDelayVal = 10.2;
Kp = 1/(pi*(1-((alpha^2)/4)))*cos(pi*alpha/2);
symsyncobj = comm.SymbolSynchronizer( ...
    "DampingFactor",1/sqrt(2), ...
    "DetectorGain",Kp, ...
    "TimingErrorDetector","Gardner (non-data-aided)", ...
    "Modulation","PAM/PSK/QAM", ...
    "NormalizedLoopBandwidth",0.0001, ...

Demodulate and decode the received signal by using the HelperCCSDSTMDemodulator and HelperCCSDSTMDecoder helper files, respectively. Display the properties of the resulting objects.

demodobj = HelperCCSDSTMDemodulator("Modulation",modScheme,"ChannelCoding",channelCoding)
demodobj = 
  HelperCCSDSTMDemodulator with properties:

       Modulation: "QPSK"
        PCMFormat: "NRZ-L"
    ChannelCoding: "convolutional"

decoderobj = HelperCCSDSTMDecoder("ChannelCoding",channelCoding, ...
    "NumBytesInTransferFrame",transferFrameLength, ...
decoderobj = 
  HelperCCSDSTMDecoder with properties:

                      ChannelCoding: "convolutional"
                      HasRandomizer: true
                             HasASM: true
        DisableFrameSynchronization: 0
    DisablePhaseAmbiguityResolution: 0
            NumBytesInTransferFrame: 1115
              ConvolutionalCodeRate: "1/2"
              ViterbiTraceBackDepth: 60
                     ViterbiTrellis: [1x1 struct]
                  ViterbiWordLength: 8
                         Modulation: "QPSK"
                          PCMFormat: "NRZ-L"

Initialize the constellation diagram object by using the comm.ConstellationDiagram System object to visualize how the constellation evolves as the synchronizers converge.

costellationobj = comm.ConstellationDiagram; % Default view is for QPSK
if strcmp(modScheme,'BPSK')
    costellationobj.ReferenceConstellation = [1, -1]

Processing Chain

To simulate the end-to-end chain and measure the BER of the CCSDS TM system, follow these steps.

  1. Generate random bits to form a TF.

  2. Generate the TM waveform by passing the TF through the ccsdsTMWaveformGenerator System object.

  3. Introduce RF impairments, such as CFO and symbol delay.

  4. Add AWGN to the RF-impaired signal. This noisy signal is considered the received signal.

  5. Pass the received signal through coarse frequency correction, which performs the initial coarse carrier frequency synchronization. Coarse frequency estimation is done using the "FFT-based" algorithm.

  6. Use a matched filter (root raised cosine filter) with the same configuration that is applied at the transmitter end. Because the symbol timing synchronization module works at a sampling rate that is higher than the symbol rate, the complex baseband samples are not down sampled to the symbol rate after filtering. It is down sampled such that at least 2 samples per symbol exist.

  7. Perform symbol timing synchronization by using the Gardner timing error detector (TED) to remove the timing offset that is present in the signal.

  8. Perform carrier frequency and phase tracking by using the comm.CarrierSynchronizer System object, which has a type 2 phase locked loop (PLL). This System object can track a stationary carrier frequency offset. The System object also introduces phase ambiguity, which is then removed by the frame synchronization module.

  9. Visualize the constellation after symbol timing and carrier frequency synchronization is complete. Observe how the constellation evolves over multiple iterations.

  10. Demodulate the received signal and verify that the signal is at the symbol rate (that is, the samples per symbol is 1).

  11. Perform frame synchronization and channel decoding to resolve the phase ambiguity, synchronize the frame to the start of the ASM, and then decode the synchronized frame to recover the TF.

numBitsForBER = 8; % For detecting which frame is synchronized
numMessagesInBlock = 2^numBitsForBER;
for isnr = 1:numSNR
    rng default;                         % Reset to get repeatable results
    berinfo = bercalc(int8(1), int8(1)); % Initialize berinfo before BER is calculated
    tfidx = 1;
    numFramesLost = 0;
    prevdectfidx = 0;
    inputBuffer = zeros(numBitsInTF, 256,"int8");
    while((berinfo(2) < maxNumErrors) && ...
            (berinfo(3) < maxNumBits) && ...
            (numFramesLost < maxFramesLost))
        seed = randi([0 2^32-1],1,1);    % Generate seed for repeatable simulation

        % Transmitter side processing
        bits = int8(randi([0 1],numBitsInTF-numBitsForBER,1));
        % The first 8 bits correspond to the TF index modulo 256. When
        % synchronization modules are included, there can be a few frames
        % where synchronization is lost temporarily and then locks again.
        % In such cases, to calculate the BER, these 8 bits aid in
        % identifying which TF is decoded. If an error in these 8 bits
        % exists, then this error is detected by looking at the difference
        % between consecutive decoded bits. If an error is detected, then
        % that frame is considered lost. Even though the data link layer is
        % out of scope of this example, the data link layer has a similar
        % mechanism. In this example, only for calculating the BER, this
        % mechanism is adopted. The mechanism that is adopted in this
        % example is not as specified in the data link layer of the CCSDS
        % standard. And this mechanism is not specified in the physical
        % layer of the CCSDS standard.
        msg = [de2bi(mod(tfidx-1,numMessagesInBlock),numBitsForBER,"left-msb").';bits];
        inputBuffer(:,mod(tfidx-1,numMessagesInBlock)+1) = msg;
        tx = tmWaveGen(msg);

        % Introduce RF impairments
        cfoInroduced = fqyoffsetobj(tx);                % Introduce CFO
        delayed = varDelay(cfoInroduced,fixedDelayVal); % Introduce timing offset
        rx = awgn(delayed, snr(isnr),'measured',seed);  % Add AWGN

        % Receiver-side processing
        coarseSynced = coarseFreqSync(rx);     % Apply coarse frequency synchronization
        filtered = rxfilter(coarseSynced);     % Filter received samples through RRC filter
        TimeSynced = symsyncobj(filtered);     % Apply symbol timing synchronization
        fineSynced = fineFreqSync(TimeSynced); % Track frequency and phase
        % Visualize constellation
        if seeConstellation
            % Plot constellation of first 1000 symbols in a TF so
            % that variable size of fineSynced does not impede the
            % requirement of constant input size for the
            % comm.ConstellationDiagram System object.

        demodData = demodobj(fineSynced); % Demodulate
        decoded = decoderobj(demodData);  % Perform phase ambiguity resolution,
                                          % frame synchronization, and channel decoding

        % Calculate BER and adjust all buffers accordingly
        dectfidx = bi2de(double(decoded(1:8).'), ...
            "left-msb")+1;                % See the value of first 8 bits
        if tfidx > 30 % Consider to calculate BER only after 30 TFs are processed
            % As the value of first 8 bits is increased by one in each
            % iteration, if the difference between the current decoded
            % decimal value of first 8 bits is not equal to the previously
            % decoded one, then it indicates a frame loss.
            if dectfidx - prevdectfidx ~= 1
                numFramesLost = numFramesLost + 1;
                disp(['Frame lost at tfidx: ' num2str(tfidx) ...
                    '. Total frames lost: ' num2str(numFramesLost)]);
                berinfo = bercalc(inputBuffer(:,dectfidx),decoded);
                if nnz(inputBuffer(:,dectfidx)-decoded)
                    disp(['Errors occurred at tfidx: ' num2str(tfidx) ...
                        '. Num errors: ' num2str(nnz(inputBuffer(:,dectfidx) - decoded))])
        prevdectfidx = dectfidx;
        % Update tfidx
        tfidx = tfidx + 1;
    currentBer = berinfo(1);
    ber(isnr) = currentBer;
    disp(['Eb/N0: ' num2str(EbN0(isnr)) '. BER: ' num2str(currentBer) ...
        '. Num frames lost: ' num2str(numFramesLost)]);
    % Reset objects

Eb/N0: 10. BER: 0. Num frames lost: 0

Further Exploration

This example demonstrates BER simulation for convolutional codes with QPSK modulation in the presence of several RF impairments. To observe the end-to-end simulation chain for different scenarios, change the properties related to the channel coding and modulation schemes. The modulation schemes that are supported by the receiver in this example are BPSK and QPSK. The channel coding schemes that are supported by the receiver in this example are none (that is, no channel coding), RS, convolutional, and concatenated codes.

Run a full BER simulation by setting the Eb/N0 value to 3.2:0.2:5 and observe the BER by setting maxNumBits to 1e8. Uncomment this code to plot the BER results.

% semilogy(EbN0,ber);
% grid on;
% xlabel('E_b/N_0 (dB)');
% ylabel('BER');
% title('BER plot');

Always reserve the initial few TFs for the symbol timing and carrier frequency synchronizers to lock. This example discards the first 30 TFs. This number can vary based on the SNR at which the receiver is operating and the parameters of the synchronization loops, such as loop bandwidth and damping factor. If you operate the receiver at low SNR and observe large errors in the initial values of tfidx, then the synchronizers are not yet locked. For the given simulation parameters, discard the initial TFs as appropriate. The second output arguments of comm.CoarseFrequencyCompensator and comm.CarrierSynchronizer System objects contain the information related to the estimated CFO, which can be used to assess whether the synchronization loops are locked or not.


The example uses the following helper files:


[1] TM Synchronization and Channel Coding. Recommendation for Space Data System Standards, CCSDS 131.0-B-3. Blue Book. Issue 3. Washington, D.C.: CCSDS, September 2017.

[2] Radio Frequency and Modulation Systems--Part 1: Earth Stations and Spacecraft. Recommendation for Space Data System Standards, CCSDS 401.0-B-30. Blue Book. Issue 30. Washington, D.C.: CCSDS, February 2020.

[3] TM Synchronization and Channel Coding - Summary of Concept and Rationale. Report Concerning Space Data System Standards, CCSDS 130.1-G-3. Green Book. Issue 3. Washington, D.C.: CCSDS, June 2020.

See Also


Related Topics