Main Content

Introduction to 5G NR Signal Detection

This example shows how to implement PSS detection and SSB grid recovery for HDL code generation.


This example introduces 5G NR signal detection, and a workflow for developing a design for HDL code generation. It uses a simplified version of the algorithm implemented in the NR HDL Cell Search reference application. The NR HDL Cell Search reference application is highly configurable and extensible, resulting in a complex design. This example focusses on the core concepts of the signal detection algorithm by reducing the complexity and flexibility of the design, in order to introduce the workflow used to develop an HDL implementation.

5G downlink signals contain a synchronization signal block (SSB), also referred to as the synchronization signal / physical broadcast channel (SS/PBCH block), which can be used by a receiver to synchronize to the signal, and to decode some parameters of the cell. An SSB consists of the primary and secondary synchronization signals (PSS and SSS), and the physical broadcast channel (PBCH) with its demodulation reference signals (DMRS). The PSS and SSS sequence numbers are used to calculate the cell identification number, and the PBCH carries the master information block (MIB). For frequency range 1 (FR1, carrier frequencies < 6 GHz) the SSB will use a subcarrier spacing (SCS) of either 15 or 30 kHz. More information on the contents of the SSB can be found in the tutorial Synchronization Signal Blocks and Bursts (5G Toolbox).

This example uses the PSS for signal detection and timing synchronization and the SSB is OFDM demodulated using the timing information from the PSS. The SSS and PBCH are decoded from the OFDM demodulated data to verify the data recovered by the signal detection and demodulation algorithm.

Example Structure

The signal detection and demodulation algorithm is implemented in both floating point MATLAB code and a fixed-point Simulink model. Developing the first version of the design in MATLAB allows for a focus on the high level algorithm without including the additional complexity of hardware implementation details. Once the MATLAB reference algorithm is proven to work this is used as the basis for a Simulink model that supports HDL code generation. The MATLAB reference can be used to verify the output of the Simulink model.

The Simulink model supports HDL code generation and includes hardware implementation details such as fixed-point data types, control signals, buffering, delay balancing and serialization for reducing resource use. The output from the Simulink model matches the output from the MATLAB reference code, with some small quantization error on the data signals due to the fixed-point data types used in the Simulink model.

When you run this example, the script loads a test waveform from a file and defines variables used by the signal detection and demodulation algorithm. The MATLAB reference code performs signal detection and SSB demodulation, and then the script simulates the Simulink model to perform the same operations on the test waveform. The outputs from the MATLAB reference and the Simulink model are compared to verify the behavior. The MIB message is decoded from the SSB grid recovered by the Simulink model to confirm the SSB grid data is correct.

Signal Detection and Demodulation Algorithm Overview

The PSS in the received signal is detected using three correlators, one for each of the three possible PSS sequences defined by the 5G standard. A strong correlation between the received signal and one of the expected PSS sequences indicates that a signal has been detected. The signal power is measured over the correlation length, and is used to calculate a threshold for the correlation output. A signal is detected when one of the correlator outputs exceeds the threshold. The scaling factor is used to set the sensitivity of the detector and help to avoid false positive detections. A minimum threshold value is also defined to prevent noise triggering the detector where no signal is present.

The PSS detector selects the first occasion that the output of any of the three PSS correlators exceeds the threshold. The index of the PSS correlator that exceeded the threshold gives nCellID2 for the cell, which is part of the physical layer cell identity. The location of the correlation peak is used to determine the timing of the start of the SSB. The SSB timing information is used to OFDM demodulate the SSB resource grid. This resource grid contains the PSS, SSS, PBCH and BCH-DMRS. The information contained in the grid can be verified by decoding the MIB information using 5G Toolbox functions.

The detector requires an input sampling rate of 7.68 MSPS. It supports FR1 SSB configurations, and OFDM demodulates the SSB from the first PSS that exceeds the threshold. For 30 kHz SSB subcarrier spacing the PSS correlator uses the 7.68 MSPS input signal. For the 15 kHz SSB subcarrier spacing a halfband decimator is used to downsample the signal to 3.84 MSPS. The recovered SSB grid consists of 4 OFDM symbols, each with 240 subcarriers.

Setup Test Waveform and Workspace Variables

Load the test waveform from waveformIntroSignalDetection.mat. The waveform was generated using 5G Toolbox. For more information on generating 5G waveforms refer to the 5G NR Downlink Vector Waveform Generation (5G Toolbox) example. The waveform is a FR1, 5 ms in duration, with SSB Pattern Case C and a subcarrier spacing of 30 kHz. The signal is normalized to have a maximum absolute value of 0.95.

rx = load('waveformIntroSignalDetection.mat');
rxWaveform = rx.waveform;
Fs_rxWaveform = rx.sampleRate;
ssbPattern = rx.ssbBlockPattern;
Lmax = rx.L_max;

Plot spectrogram of rxWaveform.

title('Signal Spectrogram');

Set SSB subcarrier spacing (scsSSB) based on the SSB pattern (ssbPattern). SSB pattern Case A uses 15 kHz subcarrier spacing. SSB patterns Case B and Case C use 30 kHz subcarrier spacing.

if strcmp(ssbPattern,"Case A")
    scsSSB = 15;
    scsSSB = 30;

Resample the signal to 7.68e6, the sampling rate required at the input to the detector.

Fs_in = 7.68e6;
signalIn = resample(rxWaveform,Fs_in,Fs_rxWaveform);

Define constants for detector implementation.

Fs_30 = 7.68e6;  % Sampling frequency for 30 kHz subcarrier spacing (=Fs_in)
Fs_15 = 3.84e6;  % Sampling frequency for 15 kHz subcarrier spacing
Nfft = 256;      % FFT size (SSB occupies 240 subcarriers)

Get correlation filter coefficients for the 3 PSS sequences.

pssCorrelationCoeffs = getCorrelationCoeffs(Nfft);

The detector uses a halfband filter to reduce sample rate from the input sampling rate of 7.68 MHz to 3.84 MHz. The detector uses the sample rate 7.68 MHz for subcarrier spacing 30 kHz, and 3.84 MHz for subcarrier spacing 15 kHz.

Fc_15 = 120 * 15e3;
scs15halfband = dsp.FIRHalfbandDecimator(...
    'Specification',       'Transition width and stopband attenuation', ...
    'TransitionWidth',     Fs_15 - 2*Fc_15, ...
    'StopbandAttenuation', 60, ...
    'SampleRate',          Fs_in);
halfband_grpDelay = grpdelay(scs15halfband,2);
halfband_transient = ceil(halfband_grpDelay(2)/2);

MATLAB Reference Implementation of Signal Detection and Demodulation

Run the MATLAB implementation of the signal detection and demodulation algorithm and display the locations of the PSS peaks located in the waveform.

fprintf('Running MATLAB signal detection and demodulation code\n');
Running MATLAB signal detection and demodulation code

If the subcarrier spacing of the SSB is 15 kHz the input signal is downsampled by 2 using a halfband filter to reduce the sampling rate from 7.68 MSPS (Fs_30) to 3.84 MSPS (Fs_15). For 30 kHz subcarrier spacing no sampling rate change is required as the sample rate of the input signal (Fs_in) matches the sample rate required to process the signal (Fs_30). This functionality is implemented by the nrhdlSignalDetection/SSB Detect and Demod/scsSelection subsystem in the Simulink model.

if scsSSB == 15
    Fs_correlator = Fs_15;
    halfbandOut = scs15halfband(signalIn);
    correlatorIn = halfbandOut(halfband_transient:end);
    Fs_correlator = Fs_30;      % Fs_30 == Fs_in
    correlatorIn = signalIn;

Correlate signal with all 3 PSS sequences. Each of the PSS sequences is Nfft coefficients in length. This functionality is implemented by the blocks PSS Correlator 0, PSS Correlator 1 and PSS Correlator 2 in the nrhdlSignalDetection/SSB Detect and Demod/PSS Detector subsystem.

psscorr      = zeros(length(correlatorIn),3);
psscorr(:,1) = filter(pssCorrelationCoeffs(:,1),1,correlatorIn);
psscorr(:,2) = filter(pssCorrelationCoeffs(:,2),1,correlatorIn);
psscorr(:,3) = filter(pssCorrelationCoeffs(:,3),1,correlatorIn);

Calculate the magnitude squared of each of the PSS correlator outputs. This functionality is implemented by the blocks xCorrMag0, xCorrMag1 and xCorrMag2 in the nrhdlSignalDetection/SSB Detect and Demod/PSS Detector subsystem.

psscorr_mag_sq = abs(psscorr).^2;

Calculate signal energy at the PSS correlators using a moving average filter. PSS correlations are calculated over Nfft samples, so the signal energy is measured over the same window. This calculation is implemented by the blocks signalMag and signalMagAverage in the nrhdlSignalDetection/SSB Detect and Demod/PSS Detector subsystem.

energyFilt  = ones(Nfft,1);
sig_mag_sq  = abs(correlatorIn).^2;
sigEnergy   = filter(energyFilt,1,sig_mag_sq);

% Calculate threshold for correlation values from signal energy.
minimumThreshold  = Nfft*(2^-12)^2;          % Set minimumThreshold to avoid triggering on noise
PSSThreshold_dB  = -6;                       % Strength threshold in dBs (0 is least sensitive).
thresholdScaling = 10^(PSSThreshold_dB/10);  % Threshold scaling factor
threshold = sigEnergy.*thresholdScaling;     % Calculate the threshold using the signal power and threshold scaling factor
threshold(threshold<minimumThreshold) = minimumThreshold; % Apply minimum threshold value where calculated threshold is lower than the minimum

Find correlation values that exceed the threshold, and pick maximum value within window_length samples of each peak to ensure local maximum is selected. This is implemented in the nrhdlSignalDetection/SSB Detect and Demod/PSS Detector/Find Peak subsystem in the Simulink model.

[locations_1] = peakPicker(psscorr_mag_sq(:,1),threshold,window_length);
[locations_2] = peakPicker(psscorr_mag_sq(:,2),threshold,window_length);
[locations_3] = peakPicker(psscorr_mag_sq(:,3),threshold,window_length);

Combine all of the locations into a single vector and check that some peaks were found.

ml_locations = [locations_1 locations_2 locations_3];
if isempty(ml_locations)
    fprintf('No correlation peaks found \n');

Select the first correlation peak found. The PSS sequence number of the filter producing the peak gives nCellID2 for the signal. This function is performed by nrhdlSignalDetection/SSB Detect and Demod/PSS Detector/Find Peak/register PSS ID in the Simulink model.

selectedPeak = min(ml_locations);
[~,pssCorrNumber] = max(psscorr(selectedPeak,:));
ml_nCellID2 = pssCorrNumber-1;

Calculate sample offset from PSS peak to start of SSB. The correlation peak occurs at the end of the OFDM symbol containing the PSS. To find the start of the OFDM symbol carrying the PSS the FFT length is added to the cyclic prefix length to give the sample offset. The cyclic prefix length for the SSB OFDM symbols is 18 samples. This functionality is implemented by the delay to symbol start and OFDM Demod Controller blocks in the nrhdlSignalDetection/SSB Detect and Demod/OFDM Demodulator subsystem.

pssSymbolStart = selectedPeak-(Nfft+18-1); % Jump back to start of OFDM symbol containing PSS (FFT length + cyclic prefix length)
nrDemodSymbolEnd = pssSymbolStart + 4*(Nfft+18); % SSB is 4 OFDM symbols long

The nrOFDMDemodulate function requires input data starting at a slot boundary, which is one OFDM symbol before the start of the SSB. The first OFDM symbol in the slot has a different cyclic prefix length of either 20 for SSB subcarrier spacing of 15 kHz, or 22 for SSB subcarrier spacing of 30 kHz. The starting point of demodulation is adjusted to account for this. This additional offset is not required in the Simulink implementation as OFDM Demodulator block does not have the requirement to start on a slot boundary.

if scsSSB == 15
    slotFirstCyclicPrefix = 20;
    slotFirstCyclicPrefix = 22;
nrDemodSymbolStart = pssSymbolStart-(Nfft+slotFirstCyclicPrefix);

OFDM Demodulate the SSB. In the Simulink model this functionality is performed by the OFDM Demodulator block in the subsystem nrhdlSignalDetection/SSB Detect and Demod/OFDM Demodulator.

carrier = nrCarrierConfig('SubcarrierSpacing',scsSSB,'NSizeGrid',20);
nrDemodSignalIn = correlatorIn(nrDemodSymbolStart:nrDemodSymbolEnd-1);
grid = nrOFDMDemodulate(carrier,nrDemodSignalIn,'SampleRate',Fs_correlator,'Nfft',256);

Discard first OFDM symbol to get SSB from grid. The ml_SSBGrid signal is equivalent to output from the OFDM Demodulator in the Simulink model, sl_SSBGrid.

ml_SSBGrid = grid(:,2:5);

Get the IQ samples that cover the SSB region, prior to OFDM demodulation. This is equivalent to the input to the OFDM Demodulator in the Simulink model, sl_SSBRawIQ.

ml_SSBRawIQ = nrDemodSignalIn(Nfft+slotFirstCyclicPrefix+1:end);

fprintf('MATLAB signal detection and demodulation complete\n');
MATLAB signal detection and demodulation complete

Display MATLAB peak locations and nCellID2.

fprintf('MATLAB Peak Location(s) \n');
fprintf('    %i \n',ml_locations);

fprintf('MATLAB nCellID2 = %i\n', ml_nCellID2);
MATLAB Peak Location(s) 
MATLAB nCellID2 = 0

Simulink Model of Signal Detection and Demodulation

The Simulink model implements the signal detection and demodulation algorithm using a hardware modelling style and uses blocks that support HDL code generation. It uses fixed-point arithmetic and includes control signals to control the flow of data through the model. The Simulink model also uses a clock rate that is higher than the sample rate of the input signal, which makes it possible to share resources within the correlation filters to reduce the resource requirements of the design. The variable sl_in.cyclesPerSample is used to set the number of clock cycles per input sample. With this variable set to 8 the clock rate used in the model is 61.44 MHz, which is 8x larger than the input sampling rate Fs_in (7.68 MHz). To implement this in the Simulink model the input signal, sl_in.signalIn, has seven zeros inserted between each data sample and an input valid signal, sl_in.validIn, is created to indicate which of the input signal samples contains a valid data sample.

The input data signal is converted to a 16 bit signed fixed-point value, with 15 fractional bits. A boolean value is used to specify the subcarrier spacing for the SSB, with the value 0 representing 15 kHz, and 1 representing 30 kHz. The demodulated SSB grid output is a 24 bit signed fixed-point value with 15 fractional bits. The PSS ID output is an unsigned 2 bit integer number.

fprintf('Opening Simulink model\n');
Opening Simulink model

There are 4 subsystems inside the SSB Detect and Demod subsystem, as shown in the diagram. The scsSelection subsystem performs a halfband decimation on the input signal and uses the scsSSB input to select between the 7.68 MSPS signal at the input for 30 kHz SCS and the 3.84 MSPS signal from the halfband decimator for 15 kHz SCS. The output from the scsSelection subsystem is equivalent to the correlatorIn signal in the MATLAB code. The PSS Detector subsystem implements the PSS correlation filters and threshold calculation, generating a strobe, strobeOut, a valid signal, strobeValid, and outputting the pssID when a PSS signal exceeds the threshold. The Stream Synchronizer subsystem uses a RAM FIFO to balance the delays introduced by the PSS Detector. The OFDM Demodulator subsystem generates the control signals for the OFDM demodulation from the first pssDetected strobe and performs OFDM demodulation.

open_system('nrhdlSignalDetection/SSB Detect and Demod','window');

close_system('nrhdlSignalDetection/SSB Detect and Demod');

Initialize constants required by Simulink model.

sl_in.scsSSB = isequal(scsSSB,30); % Convert scsSSB to boolean 0=15kHz, 1=30kHz
sl_in.Nfft = Nfft;
sl_in.thresholdScaling = fi(thresholdScaling,0,16,16);
sl_in.minimumThreshold = fi(minimumThreshold,0,16,20);
sl_in.halfbandCoeffs = [0 scs15halfband.coeffs.Numerator];
sl_in.halfbandTransient = halfband_transient-1;
sl_in.pssCorrelationCoeffs = pssCorrelationCoeffs;
sl_in.windowLength = window_length;

Set the simulation duration to 4 ms. The spectrogram of the input waveform shows all of the SSB data in the first 4 ms of the signal.

sl_in.stopTime = 4e-3;

Set the number of clock cycles per input data sample.

sl_in.cyclesPerSample = 8;

Set the Simulink sample time based on Fs_in and sl_in.cyclesPerSample to allow for resource sharing.

sl_in.sampleTime = 1/(Fs_in*sl_in.cyclesPerSample);

Set input data valid high for 1 in every sl_in.cyclesPerSample, and pad input data signal with zeros.

sl_in.signalIn = upsample(signalIn,sl_in.cyclesPerSample);
sl_in.validIn = upsample(ones(1,length(signalIn)),sl_in.cyclesPerSample);

Run Simulink model.

fprintf('Starting Simulink simulation\n');
sl_out = sim('nrhdlSignalDetection');
fprintf('Simulink simulation finished\n');
Starting Simulink simulation
Simulink simulation finished

Process Simulink output signals.

sl_correlatorIn = sl_out.correlatorIn(sl_out.correlatorInValid);
sl_demod = sl_out.demodData(sl_out.demodValid);
sl_SSBGrid = reshape(sl_demod(1:240*4),240,[]);
sl_locationPeaks = sl_out.locationPeaks(sl_out.locationPeaksValid);
sl_locations = find(sl_locationPeaks);
sl_correlationOut = sl_out.correlationOutput(sl_out.correlationValid,:);
sl_thresholdOut = sl_out.threshold(sl_out.correlationValid,:);
sl_SSBRawIQ = sl_out.ofdmInputData(sl_out.ofdmInputValid);
sl_nCellID2 = sl_out.PSSID(end);

Display and compare results

Display simulation results when both MATLAB and Simulink simulations are complete.

Plot PSS correlation peaks and PSS threshold from Simulink output signals.

hold on;

% Zoom in on first PSS peak and surrounding area.
xlim([min(sl_locations)-500 min(sl_locations)+15000]);
legend('PSS 0','PSS 1','PSS 2','Threshold');
title('Simulink PSS Correlation Results')

Display Simulink peak locations and nCellID2.

fprintf('Simulink Peak Location(s) \n');
fprintf('    %i \n',sl_locations);

fprintf('Simulink nCellID2 = %i \n', sl_nCellID2);
Simulink Peak Location(s) 
Simulink nCellID2 = 0 

Plot demodulated SSB grid from Simulink output signals.

title('Simulink SSB Grid')
xlabel('OFDM Symbol');

Calculate relative mean-squared error between MATLAB and Simulink IQ samples for the SSB grid before OFDM demodulation.

SSBIQ_MSE = 10*log10(sum(abs(ml_SSBRawIQ-sl_SSBRawIQ).^2)/sum(abs(ml_SSBRawIQ).^2));
fprintf('Relative mean-squared error between MATLAB and Simulink IQ samples for SSB grid at input to OFDM Demod:\n   %.1f dB\n',SSBIQ_MSE);
Relative mean-squared error between MATLAB and Simulink IQ samples for SSB grid at input to OFDM Demod:
   -80.5 dB

Calculate relative mean-squared error between MATLAB and Simulink SSB grids.

SSBGrid_MSE = 10*log10(sum(abs(ml_SSBGrid(:)-sl_SSBGrid(:)).^2)/sum(abs(ml_SSBGrid(:)).^2));
fprintf('Relative mean-squared error between MATLAB and Simulink SSB grids:\n   %.1f dB\n',SSBGrid_MSE);
Relative mean-squared error between MATLAB and Simulink SSB grids:
   -79.3 dB

Decode the MIB from the Simulink SSB grid to further verify data recovered from the signal. If the bchCRC returned is 0 this indicates no errors were found.

fprintf('Decoding MIB from Simulink SSB grid \n');
[mibStruct, nCellID, ssbIndex, bchCRC] = mibDecode(sl_SSBGrid, sl_nCellID2, Lmax);

if bchCRC == 0
    fprintf('MIB decode successful\n');
    disp([' Cell identity: ' num2str(nCellID)]);
    fprintf('MIB decode failed, bchCRC was non-zero\n')
Decoding MIB from Simulink SSB grid 
MIB decode successful
 Cell identity: 249

HDL Code Generation

You can generate HDL code and an HDL testbench for the nrhdlSignalDetection/SSB Detect and Demod subsystem in the Simulink model using the makehdl and makehdltb commands. An HDL Coder™ license is required for HDL code generation. The resulting HDL code was synthesized for a Xilinx® Zynq®-7000 ZC706 evaluation board. The table shows the post place and route resource utilization results. The design meets timing with a clock frequency of 100 MHz.

T = table(...
    categorical({'Slice Registers'; 'Slice LUTs'; 'RAMB18'; 'RAMB36'; 'DSP48'}),...
    [29217; 14222; 9; 1; 313],...

       Resource        Usage
    _______________    _____

    Slice Registers    29217
    Slice LUTs         14222
    RAMB18                 9
    RAMB36                 1
    DSP48                313

Further Exploration

  1. You can use 5G Toolbox to generate different signals to test the detector. The Synchronization Signal Blocks and Bursts (5G Toolbox) example and the 5G NR Downlink Vector Waveform Generation (5G Toolbox) example.

  2. You can try adding impairments to the signal, such as noise or a frequency offset.

Related Topics