NR Synchronization Procedures

This example demonstrates how to construct a waveform containing a synchronization signal burst (SS burst), pass the waveform through a fading channel with AWGN, and then blindly synchronize to the received waveform to decode the master information block (MIB).

Introduction

Before a User Terminal (UT) can communicate with the network it must perform cell search and selection procedures and obtain initial system information. The first few steps in that process are acquiring frame synchronization, finding out the cell identity and decoding the Master Information Block (MIB). This example demonstrates how those steps can be performed with 5G Toolbox (TM).

The figure below shows the main steps in the processing chain.

  • Burst generation: A structure burst is created which configures an SS burst, and the function hSSBurst is used to create an OFDM resource grid containing the SS burst.

  • Beam sweep: The OFDM resource grid for the SS burst is beamformed onto a set of physical transmission antennas, with each SS/PBCH block in the burst having a different beamforming vector.

  • Propagation channel: The transmitted waveform is passed through a TDL propagation channel model.

  • AWGN: Additive White Gaussian Noise is applied to the receive antennas.

  • Receiver: Various synchronization and demodulation processes are applied to the received waveform in order to establish the cell identity and to decode the Master Information Block (MIB).

The figure below shows the processing steps inside the receiver.

These processing steps are explained in detail below.

Burst Configuration

A structure burst is created which configures an SS burst, including configuration of the pattern of SS/PBCH blocks within the burst and the content of the Master Information Block (MIB).

% Burst configuration related to the burst structure itself:
burst.BlockPattern = 'Case B';
burst.SSBPeriodicity = 20;
burst.NFrame = 4;
burst.SSBTransmitted = [1 1 1 1 1 1 1 1];
burst.NCellID = 102;

% Burst configuration related to carrier (10 MHz, see TS 38.104 Table
% 5.3.2-1):
gnb.SubcarrierSpacing = 15;
gnb.NDLRB = 52;
gnb.CyclicPrefix = 'Normal';
carrierInfo = hOFDMInfo(gnb);
burst.SampleRate = carrierInfo.SamplingRate;
K = carrierInfo.NSubcarriers;
burst.FrequencyPointA = -K/2 * gnb.SubcarrierSpacing * 1e3;

% Burst configuration related to MIB content:
burst.DL_DMRS_typeA_pos = 2;
burst.PDCCHConfigSIB1 = 17;
burst.CellBarred = 0;
burst.IntraFreqReselection = 0;
burst.SubcarrierSpacingCommon = carrierInfo.SubcarrierSpacing;
burst.DisplayBurst = true;

Channel Configuration

A Tapped Delay Line (TDL) propagation channel channel is configured, as well as the SNR for AWGN added at the receiver.

% Configure number of transmit and receive antennas
ntxants = 8;
nrxants = 2;

% Configure channel
velocity = 30.0;
fc = 4e9;
c = physconst('lightspeed');
fd = (velocity*1000/3600)/c*fc;
channel = nrTDLChannel;
channel.Seed = 24;
channel.DelayProfile = 'TDL-C';
channel.DelaySpread = 300e-9;
channel.MaximumDopplerShift = fd;
channel.MIMOCorrelation = 'Medium';
channel.Polarization = 'Cross-Polar';
channel.NumTransmitAntennas = ntxants;
channel.NumReceiveAntennas = nrxants;

% Configure SNR for AWGN
SNRdB = 10;

Burst Generation

The function hSSBurst is used to create an OFDM resource grid containing the SS burst. The resource grid is sized such that the corresponding OFDM modulated waveform has a sample rate equal to that specified by burst.SampleRate, which allows it to be easily added to a waveform carrying PDCCH and PDSCH. Time domain combining of the waveforms is required in the case that the SS/PBCH block and PDCCH/PDSCH have different subcarrier spacings.

% Display burst
disp(burst);

% Create and display burst information
burstInfo = hSSBurstInfo(burst);
disp(burstInfo);

% Create burst resource grid
[~,burstGrid] = hSSBurst(burst);
               BlockPattern: 'Case B'
             SSBPeriodicity: 20
                     NFrame: 4
             SSBTransmitted: [1 1 1 1 1 1 1 1]
                    NCellID: 102
                 SampleRate: 15360000
            FrequencyPointA: -4680000
          DL_DMRS_typeA_pos: 2
            PDCCHConfigSIB1: 17
                 CellBarred: 0
       IntraFreqReselection: 0
    SubcarrierSpacingCommon: 15
               DisplayBurst: 1

      SubcarrierSpacing: 30
               NCRB_SSB: 6
                  k_SSB: 0
     FrequencyOffsetSSB: 0
                    MIB: [24×1 double]
                      L: 8
               SSBIndex: [0 1 2 3 4 5 6 7]
                  i_SSB: [0 1 2 3 4 5 6 7]
               ibar_SSB: [0 1 2 3 4 5 6 7]
             SampleRate: 15360000
                   Nfft: 512
                  NDLRB: 36
           CyclicPrefix: 'Normal'
    OccupiedSubcarriers: [240×1 double]
        OccupiedSymbols: [8×4 double]

Beam Sweep

The OFDM resource grid for the SS burst is beamformed onto a set of physical transmission antennas, with each SS/PBCH block in the burst having a different beamforming vector. The beamformed OFDM resource grid is then OFDM modulated to give a time domain waveform.

% Configure beamforming weights
W = fft(eye(ntxants)) / sqrt(ntxants);

% Beamform the OFDM symbols correpsonding to each burst
beamformedGrid = zeros([size(burstGrid) ntxants]);
blockSubcarriers = burstInfo.OccupiedSubcarriers;
for ssb = 1:length(burstInfo.SSBIndex)

    blockSymbols = burstInfo.OccupiedSymbols(ssb,:);
    block = burstGrid(blockSubcarriers,blockSymbols);
    Wssb = W(mod(ssb-1,ntxants)+1,:);
    beamformedBlock = reshape(block(:) * Wssb,[size(block) ntxants]);
    beamformedGrid(blockSubcarriers,blockSymbols,:) = beamformedBlock;

end

% Perform OFDM modulation
beamformedGrid = beamformedGrid(:,1:max(burstInfo.OccupiedSymbols(:))+1,:);
ofdmConfig.SubcarrierSpacing = burstInfo.SubcarrierSpacing;
ofdmConfig.NDLRB = burstInfo.NDLRB;
ofdmConfig.CyclicPrefix = burstInfo.CyclicPrefix;
ofdmConfig.Windowing = 0;
[burstWaveform,ofdmInfo] = hOFDMModulate(ofdmConfig,beamformedGrid);

Propagation Channel

The transmitted waveform is passed through a TDL propagation channel model resulting in a received waveform for the configured number of antennas.

rxWaveform = channel(burstWaveform);

AWGN

Additive White Gaussian Noise is applied to the receive antennas.

rng('default');
rxWaveform = awgn(rxWaveform,SNRdB,-10*log10(double(ofdmInfo.Nfft)));

PSS Search

PSS search is performed, which consists of correlating the received waveform (across all SS/PBCH blocks) with each of the three possible PSS sequences and extracting the strongest correlation peak. The SS/PBCH block with the strongest correlation peak indicates which beam in the beam sweep was most effective at directing the signal towards the receiver.

pssIndices = nrPSSIndices;
pssGrid = zeros([240 4]);
refGrid = zeros([ofdmInfo.NSubcarriers ofdmInfo.SymbolsPerSlot]);
k = burstInfo.OccupiedSubcarriers;
l = burstInfo.OccupiedSymbols(1,:);

figure;
hold on;
peak_value = zeros(1,3);
peak_index = zeros(1,3);
for NID2 = [0 1 2]

    pssRef = nrPSS(NID2);
    pssGrid(pssIndices) = pssRef;
    refGrid(k,l) = pssGrid;
    refWaveform = hOFDMModulate(ofdmConfig,refGrid);
    refWaveform = refWaveform(refWaveform~=0);

    corr = zeros(size(rxWaveform));
    for r = 1:size(rxWaveform,2)
        antcorr = xcorr(rxWaveform(:,r),refWaveform);
        corr(:,r) = antcorr(size(rxWaveform,1):end);
    end
    corr = sum(abs(corr),2);
    [peak_value(NID2+1),peak_index(NID2+1)] = max(corr);
    plot(corr);

end

% Plot PSS correlations
axis([1 length(rxWaveform(:,1)) 0 max(peak_value)*1.1]);
title('PSS Correlations (time domain)');
ylabel('Magnitude');
xlabel('Sample Index');

% Determine NID2 by finding the strongest correlation
NID2 = find(peak_value==max(peak_value)) - 1;

% Determine timing offset
offset = peak_index(NID2+1) - 1;

% Plot selected NID2
plot(offset+1,peak_value(NID2+1),'kx','LineWidth',2,'MarkerSize',8);
lgd = legend;
lgd.Interpreter = 'latex';
legends = "$N_{ID}^{(2)}$ = " + num2cell(0:2);
legend([legends "$N_{ID}^{(2)}$ = " + num2str(NID2)]);

% Extract strongest burst
offset = offset - ofdmInfo.SymbolLengths(1);
rxGrid = hOFDMDemodulate(ofdmConfig,rxWaveform(1+offset:end,:));
rxGrid = rxGrid(burstInfo.OccupiedSubcarriers,2:5,:);

SSS Search

The timing of the PSS correlation peak is used to synchronize the waveform and OFDM demodulation is performed. The subcarriers associated with the SSS are extracted and correlated with each possible SSS sequence. The indices of the strongest PSS and SSS sequences are combined to give the physical layer cell identity, which is required for PBCH DM-RS and PBCH processing.

% Extract the received SSS symbols from the SS/PBCH block
sssIndices = nrSSSIndices;
sssRx = nrExtractResources(sssIndices,rxGrid);

% Correlate received SSS symbols with each possible SSS sequence
sssEst = zeros(1,336);
for NID1 = 0:335

    ncellid = (3*NID1) + NID2;
    sssRef = nrSSS(ncellid);
    sssEst(NID1+1) = sum(abs(mean(sssRx .* conj(sssRef),1)).^2);

end

% Plot SSS correlations
figure;
stem(0:335,sssEst,'o');
title('SSS Correlations (frequency domain)');
xlabel('$N_{ID}^{(1)}$','Interpreter','latex');
ylabel('Magnitude');
axis([-1 336 0 max(sssEst)*1.1]);

% Determine NID1 by finding the strongest correlation
NID1 = find(sssEst==max(sssEst)) - 1;

% Plot selected NID1
hold on;
plot(NID1,max(sssEst),'kx','LineWidth',2,'MarkerSize',8);
lgd = legend;
lgd.Interpreter = 'latex';
legend(["correlations" "$N_{ID}^{(1)}$ = " + num2str(NID1)]);

% Form overall cell identity from NID1 and NID2
ncellid = (3*NID1) + NID2;

PBCH DM-RS search

In a process similar to SSS search, the subcarriers corresponding to the PBCH DM-RS are extracted and correlated with each possible PBCH DM-RS sequence. The index of the strongest PBCH DM-RS determines the LSBs of the SS/PBCH block index, required for PBCH scrambling initialization.

% Extract the received PBCH DM-RS symbols from the SS/PBCH block
dmrsIndices = nrPBCHDMRSIndices(ncellid);
[dmrsRx,dmrsRxIndices] = nrExtractResources(dmrsIndices,rxGrid);

% Correlate received DM-RS symbols with each possible DM-RS sequence
dmrsEst = zeros(1,8);
for ibar_SSB = 0:7

    dmrsRef = nrPBCHDMRS(ncellid,ibar_SSB);
    dmrsEst(ibar_SSB+1) = sum(abs(mean(dmrsRx .* conj(dmrsRef),1)).^2);

end

% Plot PBCH DM-RS correlations
figure;
stem(0:7,dmrsEst,'o');
title('PBCH DM-RS Correlations (frequency domain)');
xlabel('$\overline{i}_{SSB}$','Interpreter','latex');
xticks(0:7);
ylabel('Magnitude');
axis([-1 8 0 max(dmrsEst)*1.1]);

% Record ibar_SSB for the strongest correlation
ibar_SSB = find(dmrsEst==max(dmrsEst)) - 1;

% Plot selected ibar_SSB
hold on;
plot(ibar_SSB,max(dmrsEst),'kx','LineWidth',2,'MarkerSize',8);
lgd = legend;
lgd.Interpreter = 'latex';
legend(["correlations" "$\overline{i}_{SSB}$ = " + num2str(ibar_SSB)]);

Channel Estimation using PBCH DM-RS

Now that the PBCH DM-RS sequence is known, a channel estimate for the SS/PBCH block can be created by estimating the channel in each PBCH DM-RS resource element location and interpolating across the SS/PBCH block. An estimate of the additive noise on the PBCH DM-RS is also performed.

% Channel estimation, using linear interpolation of the PBCH DM-RS
dmrsRef = nrPBCHDMRS(ncellid,ibar_SSB);
dmrsSubs = double(nrPBCHDMRSIndices(ncellid,'IndexStyle','subscript'));
hest = zeros([240 4 nrxants 1]);
[l_hest,k_hest] = meshgrid(1:size(hest,2),1:size(hest,1));
dmrsEsts = dmrsRx .* conj(dmrsRef);
for r = 1:nrxants
    f = scatteredInterpolant(dmrsSubs(:,2),dmrsSubs(:,1),dmrsEsts(:,r));
    hest(:,:,r) = f(l_hest,k_hest);
end

% Noise estimation, based on the difference between the PBCH DM-RS in
% symbols 2 and 4 (1-based) of the SS/PBCH block. This technique assumes
% that the channel itself does not change between the two symbols
dmrsEstsSym2 = dmrsEsts(dmrsSubs(:,2)==2,:);
dmrsEstsSym4 = dmrsEsts(dmrsSubs(:,2)==4,:);
dmrsEstsSym2and4 = [dmrsEstsSym2(:) dmrsEstsSym4(:)];
dmrsNoise = mean(dmrsEstsSym2and4,2) - dmrsEstsSym2and4;
nest = var(dmrsNoise(:)) * 2;

PBCH Demodulation

The subcarriers associated with the PBCH are extracted and the channel and noise estimates are used to perform MMSE equalization. The equalized PBCH symbols are then demodulated and descrambled to give bit estimates for the coded BCH block.

% Extract the received PBCH symbols from the SS/PBCH block
[pbchIndices,pbchIndicesInfo] = nrPBCHIndices(ncellid);
pbchRx = nrExtractResources(pbchIndices,rxGrid);

% Plot received PBCH constellation before equalization
figure;
plot(pbchRx,'o');
title('Received PBCH constellation');
m = max(abs([real(pbchRx(:)); imag(pbchRx(:))])) * 1.1;
axis([-m m -m m]);

% Configure 'v' for PBCH scrambling according to TS 38.211 Section 7.3.3.1
% 'v' is also the 2 LSBs of the SS/PBCH block index for L=4, or the 3 LSBs
% for L=8 or 64
if (burstInfo.L==4)
    v = mod(ibar_SSB,4);
else
    v = ibar_SSB;
end
ssbIndex = v;

% PBCH equalization and CSI calculation
pbchHest = nrExtractResources(pbchIndices,hest);
[pbchEq,csi] = nrEqualizeMMSE(pbchRx,pbchHest,nest);
Qm = pbchIndicesInfo.G / pbchIndicesInfo.Gd;
csi = repmat(csi.',Qm,1);
csi = reshape(csi,[],1);

% Plot received PBCH constellation after equalization
figure;
plot(pbchEq,'o');
title('Equalized PBCH constellation');
m = max(abs([real(pbchEq(:)); imag(pbchEq(:))])) * 1.1;
axis([-m m -m m]);

% PBCH demodulation
pbchBits = nrPBCHDecode(pbchEq,ncellid,v,nest);

% Calculate RMS PBCH EVM
pbchRef = nrPBCH(pbchBits<0,ncellid,v);
evm = comm.EVM;
evm_rms = evm(pbchEq,pbchRef);

% Display calculated EVM
disp(['RMS PBCH EVM = ' num2str(evm_rms,'%0.3f') '%']);
RMS PBCH EVM = 34.058%

BCH Decoding

The BCH bit estimates are weighted with Channel State Information (CSI) from the MMSE equalizer then BCH decoding is performed, consisting of rate recovery, polar decoding, CRC decoding, descrambling and separating the 24 MIB bits from the 8 additional timing-related payload bits.

% Apply CSI
pbchBits = pbchBits .* csi;

% Perform BCH decoding including rate recovery, polar decoding and CRC
% decoding. PBCH descrambling and separation of the MIB bits from 8
% additional payload bits A...A+7 is also performed:
%   A ... A+3: 4 LSBs of System Frame Number
%         A+4: half frame number
% A+5 ... A+7: for L=64, 3 MSBs of the SS/PBCH block index
%              for L=4 or 8, A+5 is the MSB of the subcarrier offset k_SSB
polarListLength = 8;
[~,err,mibbits,sfn4lsb,nHalfFrame,msbidxoffset] = ...
    nrBCHDecode(pbchBits,polarListLength,burstInfo.L,ncellid);

% Use 'msbidxoffset' value to set bits of 'k_SSB' or 'ssbIndex', depending
% on the number of SS/PBCH blocks in the burst
if (burstInfo.L==64)
    ssbIndex = ssbIndex + (bi2de(msbidxoffset.','left-msb') * 8);
    k_SSB = 0;
else
    k_SSB = msbidxoffset * 16;
end

% Display the BCH CRC
disp(['BCH CRC = ' num2str(err)]);

% Displaying the SSB index
disp(['SSB index = ' num2str(ssbIndex)]);
BCH CRC = 0
SSB index = 1

MIB Parsing

Finally the 24 decoded MIB bits are parsed into a structure which represents the MIB message fields. This includes reconstituting the 10-bit System Frame Number (SFN) NFrame from the 6 MSBs in the MIB and the 4 LSBs in the PBCH payload bits. It also includes incorporating the MSB of the subcarrier offset k_SSB from the PBCH payload bits in the case of L=4 or 8 SS/PBCH blocks per burst.

% Create set of subcarrier spacings signaled by the 7th bit of the decoded
% MIB, the set is different for FR1 (L=4 or 8) and FR2 (L=64)
if (burstInfo.L==64)
    commonSCSs = [60 120];
else
    commonSCSs = [15 30];
end

% Create a structure of MIB fields from the decoded MIB bits
mib.NFrame = bi2de([mibbits(1:6); sfn4lsb] .','left-msb');
mib.SubcarrierSpacingCommon = commonSCSs(mibbits(7) + 1);
mib.k_SSB = k_SSB + bi2de(mibbits(8:11).','left-msb');
mib.DL_DMRS_typeA_pos = 2 + mibbits(12);
mib.PDCCHConfigSIB1 = bi2de(mibbits(13:20).','left-msb');
mib.CellBarred = mibbits(21);
mib.IntraFreqReselection = mibbits(22);

% Display the MIB structure
disp(mib);
                     NFrame: 4
    SubcarrierSpacingCommon: 15
                      k_SSB: 0
          DL_DMRS_typeA_pos: 2
            PDCCHConfigSIB1: 17
                 CellBarred: 0
       IntraFreqReselection: 0

See Also

System Objects

Functions

Related Topics