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).
Contents
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