Initial NR PBCH encoding

This commit is contained in:
Xavier Arteaga 2021-05-19 18:30:47 +02:00 committed by Andre Puschmann
parent d66dac0ab2
commit 0aa5b14145
6 changed files with 603 additions and 41 deletions

View File

@ -13,13 +13,102 @@
#ifndef SRSRAN_PBCH_NR_H
#define SRSRAN_PBCH_NR_H
#include "srsran/config.h"
#include "srsran/phy/common/phy_common_nr.h"
#include "srsran/phy/fec/crc.h"
#include "srsran/phy/fec/polar/polar_code.h"
#include "srsran/phy/fec/polar/polar_decoder.h"
#include "srsran/phy/fec/polar/polar_encoder.h"
#include "srsran/phy/fec/polar/polar_rm.h"
#include "srsran/phy/modem/modem_table.h"
/**
* @brief Descibes the NR PBCH message
* @brief NR PBCH payload size generated by higher layers, deduced from TS 38.331 MIB description
*/
#define SRSRAN_PBCH_NR_PAYLOAD_SZ 24
/**
* @brief Describes the NR PBCH object initialisation arguments
*/
typedef struct SRSRAN_API {
void* TBD;
bool enable_encode; ///< Enable encoder
bool enable_decode; ///< Enable decoder
bool disable_simd; ///< Disable SIMD polar encoder/decoder
} srsran_pbch_nr_args_t;
/**
* @brief Describes the NR PBCH configuration
*/
typedef struct SRSRAN_API {
uint32_t N_id; ///< Physical cell identifier
srsran_subcarrier_spacing_t ssb_scs; ///< SSB Subcarrier spacing
uint32_t Lmax; ///< Number of SSB opportunities, described in TS 38.213 4.1 ...
float beta; ///< Scaling factor for PBCH symbols, set to zero for default
float beta_dmrs; ///< Scaling factor for PBCH DM-RS, set to zero for default
} srsran_pbch_nr_cfg_t;
/**
* @brief Describes the NR PBCH object initialisation arguments
*/
typedef struct SRSRAN_API {
srsran_polar_code_t code;
srsran_polar_encoder_t polar_encoder;
srsran_polar_decoder_t polar_decoder;
srsran_polar_rm_t polar_rm_tx;
srsran_polar_rm_t polar_rm_rx;
srsran_crc_t crc;
srsran_modem_table_t qpsk;
} srsran_pbch_nr_t;
/**
* @brief Describes the PBCH message
*/
typedef struct SRSRAN_API {
uint8_t payload[SRSRAN_PBCH_NR_PAYLOAD_SZ]; ///< Actual PBCH payload provided by higher layers
uint32_t sfn_4lsb; ///< SFN 4 LSB
uint32_t ssb_idx; ///< SS/PBCH blocks index described in TS 38.213 4.1
uint32_t k_ssb_msb; ///< Subcarrier offset MSB described in TS 38.211 7.4.3.1
uint32_t hrf; ///< Half Radio Frame bit
bool crc; ///< Decoder only, it is true only if the received CRC matches
} srsran_pbch_msg_nr_t;
/**
* @brief Initialises an NR PBCH object with the provided arguments
* @param q NR PBCH object
* @param args Arguments providing the desired configuration
* @return SRSRAN_SUCCESS if initialization is successful, SRSLTE_ERROR code otherwise
*/
SRSRAN_API int srsran_pbch_nr_init(srsran_pbch_nr_t* q, const srsran_pbch_nr_args_t* args);
/**
* @brief Deallocates an NR PBCH object
* @param q NR PBCH object
*/
SRSRAN_API void srsran_pbch_nr_free(srsran_pbch_nr_t* q);
/**
* @brief Encodes an NR PBCH message into a SSB resource grid
* @param q NR PBCH object
* @param cfg NR PBCH configuration
* @param msg NR PBCH message to transmit
* @param[out] ssb_grid SSB resource grid
* @return SRSRAN_SUCCESS if encoding is successful, SRSLTE_ERROR code otherwise
*/
SRSRAN_API int srsran_pbch_nr_encode(srsran_pbch_nr_t* q,
const srsran_pbch_nr_cfg_t* cfg,
const srsran_pbch_msg_nr_t* msg,
cf_t ssb_grid[SRSRAN_SSB_NOF_RE]);
/**
* @brief Decodes an NR PBCH message in the SSB resource grid
* @param q NR PBCH object
* @param cfg NR PBCH configuration
* @param[in] ssb_grid SSB resource grid
* @param msg NR PBCH message received
* @return SRSRAN_SUCCESS if decoding is successful, SRSLTE_ERROR code otherwise
*/
SRSRAN_API int srsran_pbch_nr_decode(srsran_pbch_nr_t* q,
const srsran_pbch_nr_cfg_t* cfg,
const cf_t ssb_grid[SRSRAN_SSB_NOF_RE],
srsran_pbch_msg_nr_t* msg);
#endif // SRSRAN_PBCH_NR_H

View File

@ -43,12 +43,13 @@
* @brief Describes SSB object initialization arguments
*/
typedef struct SRSRAN_API {
double max_srate_hz; ///< Maximum sampling rate in Hz, set to zero to use default
srsran_subcarrier_spacing_t min_scs; ///< Minimum subcarrier spacing
bool enable_search; ///< Enables PSS/SSS blind search
bool enable_measure; ///< Enables PSS/SSS CSI measurements and frequency domain search
bool enable_encode; ///< Enables PBCH Encoder
bool enable_decode; ///< Enables PBCH Decoder
double max_srate_hz; ///< Maximum sampling rate in Hz, set to zero to use default
srsran_subcarrier_spacing_t min_scs; ///< Minimum subcarrier spacing
bool enable_search; ///< Enables PSS/SSS blind search
bool enable_measure; ///< Enables PSS/SSS CSI measurements and frequency domain search
bool enable_encode; ///< Enables PBCH Encoder
bool enable_decode; ///< Enables PBCH Decoder
bool disable_polar_simd; ///< Disables polar encoder/decoder SIMD acceleration
} srsran_ssb_args_t;
/**
@ -87,11 +88,15 @@ typedef struct SRSRAN_API {
uint32_t t_offset; ///< Current SSB integer time offset (number of samples)
uint32_t cp_sz[SRSRAN_SSB_DURATION_NSYMB]; ///< CP length for each SSB symbol
/// Other parameters
uint32_t Lmax; ///< Number of SSB candidates
/// Internal Objects
srsran_dft_plan_t ifft; ///< IFFT object for modulating the SSB
srsran_dft_plan_t fft; ///< FFT object for demodulate the SSB.
srsran_dft_plan_t fft_corr; ///< FFT for correlation
srsran_dft_plan_t ifft_corr; ///< IFFT for correlation
srsran_pbch_nr_t pbch; ///< PBCH encoder and decoder
/// Frequency/Time domain temporal data
cf_t* tmp_freq; ///< Temporal frequency domain buffer

View File

@ -86,6 +86,7 @@ extern "C" {
#include "srsran/phy/phch/dci.h"
#include "srsran/phy/phch/dci_nr.h"
#include "srsran/phy/phch/pbch.h"
#include "srsran/phy/phch/pbch_nr.h"
#include "srsran/phy/phch/pcfich.h"
#include "srsran/phy/phch/pdcch.h"
#include "srsran/phy/phch/pdcch_nr.h"

View File

@ -380,7 +380,6 @@ int srsran_polar_rm_tx_init(srsran_polar_rm_t* p)
int srsran_polar_rm_rx_init_f(srsran_polar_rm_t* p)
{
if (p == NULL) {
return -1;
}
@ -405,7 +404,6 @@ int srsran_polar_rm_rx_init_f(srsran_polar_rm_t* p)
int srsran_polar_rm_rx_init_s(srsran_polar_rm_t* p)
{
if (p == NULL) {
return -1;
}
@ -430,7 +428,6 @@ int srsran_polar_rm_rx_init_s(srsran_polar_rm_t* p)
int srsran_polar_rm_rx_init_c(srsran_polar_rm_t* p)
{
if (p == NULL) {
return -1;
}
@ -455,41 +452,74 @@ int srsran_polar_rm_rx_init_c(srsran_polar_rm_t* p)
void srsran_polar_rm_tx_free(srsran_polar_rm_t* q)
{
if (q != NULL) {
struct pRM_tx* qq = q->ptr;
free(qq->y_e);
free(qq);
if (q == NULL) {
return;
}
struct pRM_tx* qq = q->ptr;
if (qq == NULL) {
return;
}
if (qq->y_e) {
free(qq->y_e);
}
free(qq);
}
void srsran_polar_rm_rx_free_f(srsran_polar_rm_t* q)
{
if (q != NULL) {
struct pRM_rx_f* qq = q->ptr;
free(qq->y_e);
// free(qq->indices);
free(qq);
if (q == NULL) {
return;
}
struct pRM_rx_f* qq = q->ptr;
if (qq == NULL) {
return;
}
if (qq->y_e) {
free(qq->y_e);
}
free(qq);
}
void srsran_polar_rm_rx_free_s(srsran_polar_rm_t* q)
{
if (q != NULL) {
struct pRM_rx_s* qq = q->ptr;
free(qq->y_e);
// free(qq->indices);
free(qq);
if (q == NULL) {
return;
}
struct pRM_rx_s* qq = q->ptr;
if (qq == NULL) {
return;
}
if (qq->y_e) {
free(qq->y_e);
}
free(qq);
}
void srsran_polar_rm_rx_free_c(srsran_polar_rm_t* q)
{
if (q != NULL) {
struct pRM_rx_c* qq = q->ptr;
free(qq->y_e);
// free(qq->indices);
free(qq);
if (q == NULL) {
return;
}
struct pRM_rx_c* qq = q->ptr;
if (qq == NULL) {
return;
}
if (qq->y_e) {
free(qq->y_e);
}
free(qq);
}
int srsran_polar_rm_tx(srsran_polar_rm_t* q,
@ -529,7 +559,6 @@ int srsran_polar_rm_rx_f(srsran_polar_rm_t* q,
const uint32_t K,
const uint8_t ibil)
{
struct pRM_rx_f* pp = q->ptr;
float* y = NULL;
float* e = pp->e; // length E
@ -557,7 +586,6 @@ int srsran_polar_rm_rx_s(srsran_polar_rm_t* q,
const uint32_t K,
const uint8_t ibil)
{
struct pRM_rx_s* pp = q->ptr;
int16_t* y = NULL;
int16_t* e = pp->e;
@ -585,7 +613,6 @@ int srsran_polar_rm_rx_c(srsran_polar_rm_t* q,
const uint32_t K,
const uint8_t ibil)
{
struct pRM_rx_c* pp = q->ptr;
int8_t* y = NULL;
int8_t* e = pp->e;

404
lib/src/phy/phch/pbch_nr.c Normal file
View File

@ -0,0 +1,404 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2021 Software Radio Systems Limited
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the distribution.
*
*/
#include "srsran/phy/phch/pbch_nr.h"
#include "srsran/phy/common/sequence.h"
#include "srsran/phy/fec/polar/polar_chanalloc.h"
#include "srsran/phy/modem/mod.h"
#include "srsran/phy/utils/debug.h"
#include "srsran/phy/utils/vector.h"
/*
* CRC Parameters
*/
#define PBCH_NR_CRC SRSRAN_LTE_CRC24C
#define PBCH_NR_CRC_LEN 24
/*
* Polar code N_max
*/
#define PBCH_NR_POLAR_N_MAX 9U
/*
* Polar rate matching I_BIL
*/
#define pbch_nr_polar_rm_tx_IBIL 0
/*
* Number of generated payload bits, called A
*/
#define PBCH_NR_A (SRSRAN_PBCH_NR_PAYLOAD_SZ + 8)
/*
* Number of payload bits plus CRC
*/
#define PBCH_NR_K (PBCH_NR_A + PBCH_NR_CRC_LEN)
/*
* Number of Polar encoded bits
*/
#define PBCH_NR_N (1U << PBCH_NR_POLAR_N_MAX)
/*
* Number of RM bits
*/
#define PBCH_NR_E (864)
/*
* Number of symbols
*/
#define PBCH_NR_M (PBCH_NR_E / 2)
/*
* Number of DMRS
*/
#define PBCH_NR_NOF_DMRS (143)
static int pbch_nr_init_encoder(srsran_pbch_nr_t* q, const srsran_pbch_nr_args_t* args)
{
// Skip encoder init if not requested
if (!args->enable_encode) {
return SRSRAN_SUCCESS;
}
srsran_polar_encoder_type_t encoder_type = SRSRAN_POLAR_ENCODER_PIPELINED;
#ifdef LV_HAVE_AVX2
if (!args->disable_simd) {
encoder_type = SRSRAN_POLAR_ENCODER_AVX2;
}
#endif /* LV_HAVE_AVX2 */
if (srsran_polar_encoder_init(&q->polar_encoder, encoder_type, PBCH_NR_POLAR_N_MAX) < SRSRAN_SUCCESS) {
ERROR("Error initiating polar encoder");
return SRSRAN_ERROR;
}
if (srsran_polar_rm_tx_init(&q->polar_rm_tx) < SRSRAN_SUCCESS) {
ERROR("Error initiating polar RM");
return SRSRAN_ERROR;
}
if (srsran_modem_table_lte(&q->qpsk, SRSRAN_MOD_QPSK) < SRSRAN_SUCCESS) {
return SRSRAN_ERROR;
}
return SRSRAN_SUCCESS;
}
static int pbch_nr_init_decoder(srsran_pbch_nr_t* q, const srsran_pbch_nr_args_t* args)
{
// Skip decoder init if not requested
if (!args->enable_decode) {
return SRSRAN_SUCCESS;
}
srsran_polar_decoder_type_t decoder_type = SRSRAN_POLAR_DECODER_SSC_C;
#ifdef LV_HAVE_AVX2
if (!args->disable_simd) {
decoder_type = SRSRAN_POLAR_DECODER_SSC_C_AVX2;
}
#endif /* LV_HAVE_AVX2 */
if (srsran_polar_decoder_init(&q->polar_decoder, decoder_type, PBCH_NR_POLAR_N_MAX) < SRSRAN_SUCCESS) {
ERROR("Error initiating polar decoder");
return SRSRAN_ERROR;
}
if (srsran_polar_rm_rx_init_c(&q->polar_rm_rx) < SRSRAN_SUCCESS) {
ERROR("Error initiating polar RM");
return SRSRAN_ERROR;
}
return SRSRAN_SUCCESS;
}
int srsran_pbch_nr_init(srsran_pbch_nr_t* q, const srsran_pbch_nr_args_t* args)
{
if (q == NULL || args == NULL) {
return SRSRAN_ERROR_INVALID_INPUTS;
}
if (!args->enable_encode && !args->enable_decode) {
ERROR("Encoder and decoder are disabled, at least one of them shall be active");
return SRSRAN_ERROR;
}
if (pbch_nr_init_encoder(q, args) < SRSRAN_SUCCESS) {
return SRSRAN_ERROR;
}
if (pbch_nr_init_decoder(q, args) < SRSRAN_SUCCESS) {
return SRSRAN_ERROR;
}
if (srsran_crc_init(&q->crc, PBCH_NR_CRC, PBCH_NR_CRC_LEN) < SRSRAN_SUCCESS) {
return SRSRAN_ERROR;
}
if (srsran_polar_code_init(&q->code) < SRSRAN_SUCCESS) {
return SRSRAN_ERROR;
}
if (srsran_polar_code_get(&q->code, PBCH_NR_K, PBCH_NR_E, PBCH_NR_POLAR_N_MAX) < SRSRAN_SUCCESS) {
ERROR("Error Getting polar code");
return SRSRAN_ERROR;
}
return SRSRAN_SUCCESS;
}
void srsran_pbch_nr_free(srsran_pbch_nr_t* q)
{
if (q == NULL) {
return;
}
srsran_polar_encoder_free(&q->polar_encoder);
srsran_polar_decoder_free(&q->polar_decoder);
srsran_polar_rm_rx_free_c(&q->polar_rm_rx);
srsran_polar_rm_tx_free(&q->polar_rm_tx);
srsran_polar_code_free(&q->code);
srsran_modem_table_free(&q->qpsk);
SRSRAN_MEM_ZERO(q, srsran_pbch_nr_t, 1);
}
/*
* Implements TS 38.212 Table 7.1.1-1: Value of PBCH payload interleaver pattern G ( j )
*/
static const uint32_t G[PBCH_NR_A] = {16, 23, 18, 17, 8, 30, 10, 6, 24, 7, 0, 5, 3, 2, 1, 4,
9, 11, 12, 13, 14, 15, 19, 20, 21, 22, 25, 26, 27, 28, 29, 31};
static void
pbch_nr_pbch_msg_pack(const srsran_pbch_nr_cfg_t* cfg, const srsran_pbch_msg_nr_t* msg, uint8_t a[PBCH_NR_A])
{
// Extract actual payload size
uint32_t A_hat = SRSRAN_PBCH_NR_PAYLOAD_SZ;
// Put SFN in a_hat[A_hat] to a_hat[A_hat + 3]
uint32_t j_sfn = 0;
a[G[j_sfn++]] = (uint8_t)((msg->sfn_4lsb >> 3U) & 1U); // 4th LSB of SFN
a[G[j_sfn++]] = (uint8_t)((msg->sfn_4lsb >> 2U) & 1U); // 3th LSB of SFN
a[G[j_sfn++]] = (uint8_t)((msg->sfn_4lsb >> 1U) & 1U); // 2th LSB of SFN
a[G[j_sfn++]] = (uint8_t)((msg->sfn_4lsb >> 0U) & 1U); // 1th LSB of SFN
// Put HRF in a_hat[A_hat + 4]
a[G[10]] = (msg->hrf ? 1 : 0);
// Put SSB related in a_hat[A_hat + 5] to a_hat[A_hat + 7]
if (cfg->Lmax == 64) {
a[G[11]] = (uint8_t)((msg->ssb_idx >> 5U) & 1U); // 6th bit of SSB index
a[G[12]] = (uint8_t)((msg->ssb_idx >> 4U) & 1U); // 5th bit of SSB index
a[G[13]] = (uint8_t)((msg->ssb_idx >> 3U) & 1U); // 4th bit of SSB index
} else {
a[G[11]] = (uint8_t)msg->k_ssb_msb; // 6th bit of SSB index
a[G[12]] = 0; // Reserved
a[G[13]] = 0; // Reserved
}
// Put actual payload
uint32_t j_other = 14;
for (uint32_t i = 0; i < A_hat; i++) {
if (i > 0 && i < 7) {
a[G[j_sfn++]] = msg->payload[i];
} else {
a[G[j_other++]] = msg->payload[i];
}
}
}
static void pbch_nr_scramble(const srsran_pbch_nr_cfg_t* cfg, const uint8_t a[PBCH_NR_A], uint8_t a_prime[PBCH_NR_A])
{
uint32_t i = 0;
uint32_t j = 0;
// Initialise sequence
srsran_sequence_state_t sequence_state = {};
srsran_sequence_state_init(&sequence_state, SRSRAN_SEQUENCE_MOD(cfg->N_id));
// Select value M
uint32_t M = PBCH_NR_A - 3;
if (cfg->Lmax == 64) {
M = PBCH_NR_A - 6;
}
// Select value v
uint32_t v = 2 * a[G[1]] + a[G[2]];
// Advance sequence
srsran_sequence_state_advance(&sequence_state, M * v);
// Generate actual sequence
uint8_t c[PBCH_NR_A] = {};
srsran_sequence_state_apply_bit(&sequence_state, c, c, PBCH_NR_A);
while (i < PBCH_NR_A) {
// a i corresponds to any one of the bits belonging to the SS/PBCH block index, the half frame index, and 2 nd and 3
// rd least significant bits of the system frame number
uint8_t s_i = c[j];
// else
if (i == G[11] || i == G[12] || i == G[13] || i == G[10] || i == G[1] || i == G[2]) {
s_i = 0;
} else {
j++;
}
a_prime[i] = a[i] ^ s_i;
i++;
}
}
static int pbch_nr_polar_encode(srsran_pbch_nr_t* q, const uint8_t c[PBCH_NR_K], uint8_t d[PBCH_NR_K])
{
// Allocate channel
uint8_t allocated[PBCH_NR_N];
srsran_polar_chanalloc_tx(c, allocated, q->code.N, q->code.K, q->code.nPC, q->code.K_set, q->code.PC_set);
// Encode bits
if (srsran_polar_encoder_encode(&q->polar_encoder, allocated, d, q->code.n) < SRSRAN_SUCCESS) {
return SRSRAN_ERROR;
}
return SRSRAN_SUCCESS;
}
static int pbch_nr_polar_rm_tx(srsran_pbch_nr_t* q, const uint8_t d[PBCH_NR_K], uint8_t o[PBCH_NR_E])
{
if (srsran_polar_rm_tx(&q->polar_rm_tx, d, o, q->code.n, PBCH_NR_E, PBCH_NR_K, pbch_nr_polar_rm_tx_IBIL) <
SRSRAN_SUCCESS) {
return SRSRAN_ERROR;
}
return SRSRAN_SUCCESS;
}
static void pbch_nr_scramble_tx(const srsran_pbch_nr_cfg_t* cfg,
uint32_t ssb_idx,
const uint8_t b[PBCH_NR_E],
uint8_t b_hat[PBCH_NR_E])
{
// Initialise sequence
srsran_sequence_state_t sequence_state = {};
srsran_sequence_state_init(&sequence_state, SRSRAN_SEQUENCE_MOD(cfg->N_id));
// Select value M
uint32_t M_bit = PBCH_NR_E;
// Select value v
uint32_t v = (ssb_idx & 0x7U);
if (cfg->Lmax == 4) {
v = ssb_idx & 0x3U;
}
// Advance sequence
srsran_sequence_state_advance(&sequence_state, v * M_bit);
// Apply sequence
srsran_sequence_state_apply_bit(&sequence_state, b, b_hat, PBCH_NR_E);
}
static void
pbch_nr_mapping(const srsran_pbch_nr_cfg_t* cfg, const cf_t symbols[PBCH_NR_E], cf_t ssb_grid[SRSRAN_SSB_NOF_RE])
{
uint32_t count = 0;
// PBCH DMRS shift
uint32_t v = cfg->N_id % 4;
// Symbol 1
for (uint32_t k = 0; k < SRSRAN_SSB_BW_SUBC; k++) {
// Skip DMRS
if (k % 4 == v) {
continue;
}
ssb_grid[1 * SRSRAN_SSB_BW_SUBC + k] = symbols[count++];
}
// Symbol 2
for (uint32_t k = 0; k < 48; k++) {
// Skip DMRS
if (k % 4 == v) {
continue;
}
ssb_grid[2 * SRSRAN_SSB_BW_SUBC + k] = symbols[count++];
}
for (uint32_t k = 192; k < SRSRAN_SSB_BW_SUBC; k++) {
// Skip DMRS
if (k % 4 == v) {
continue;
}
ssb_grid[2 * SRSRAN_SSB_BW_SUBC + k] = symbols[count++];
}
// Symbol 3
for (uint32_t k = 0; k < SRSRAN_SSB_BW_SUBC; k++) {
// Skip DMRS
if (k % 4 == v) {
continue;
}
ssb_grid[3 * SRSRAN_SSB_BW_SUBC + k] = symbols[count++];
}
}
int srsran_pbch_nr_encode(srsran_pbch_nr_t* q,
const srsran_pbch_nr_cfg_t* cfg,
const srsran_pbch_msg_nr_t* msg,
cf_t ssb_grid[SRSRAN_SSB_NOF_RE])
{
if (q == NULL || cfg == NULL || msg == NULL || ssb_grid == NULL) {
return SRSRAN_ERROR_INVALID_INPUTS;
}
// TS 38.212 7.1 Broadcast channel
// 7.1.1 PBCH payload generation
uint8_t a[PBCH_NR_A];
pbch_nr_pbch_msg_pack(cfg, msg, a);
// 7.1.2 Scrambling
uint8_t b[PBCH_NR_K];
pbch_nr_scramble(cfg, a, b);
// 7.1.3 Transport block CRC attachment
uint32_t checksum = srsran_crc_attach(&q->crc, b, PBCH_NR_A);
INFO("NR-PBCH: checksum=%06x", checksum);
// 7.1.4 Channel coding
uint8_t d[PBCH_NR_K];
if (pbch_nr_polar_encode(q, b, d) < SRSRAN_SUCCESS) {
return SRSRAN_ERROR;
}
// 7.1.5 Rate matching
uint8_t f[PBCH_NR_E];
if (pbch_nr_polar_rm_tx(q, d, f) < SRSRAN_SUCCESS) {
return SRSRAN_ERROR;
}
// TS 38.211 7.3.3 Physical broadcast channel
// 7.3.3.1 Scrambling
pbch_nr_scramble_tx(cfg, msg->ssb_idx, f, f);
// 7.3.3.2 Modulation
cf_t symbols[PBCH_NR_M];
srsran_mod_modulate(&q->qpsk, f, symbols, PBCH_NR_E);
// 7.3.3.3 Mapping to physical resources
// 7.4.3.1.3 Mapping of PBCH and DM-RS within an SS/PBCH block
pbch_nr_mapping(cfg, symbols, ssb_grid);
return SRSRAN_SUCCESS;
}

View File

@ -53,6 +53,25 @@ static int ssb_init_corr(srsran_ssb_t* q)
return SRSRAN_SUCCESS;
}
static int ssb_init_pbch(srsran_ssb_t* q)
{
srsran_pbch_nr_args_t args = {};
args.enable_encode = q->args.enable_encode;
args.enable_decode = q->args.enable_decode;
args.disable_simd = q->args.disable_polar_simd;
if (!args.enable_encode && !args.enable_decode) {
return SRSRAN_SUCCESS;
}
if (srsran_pbch_nr_init(&q->pbch, &args) < SRSRAN_SUCCESS) {
ERROR("Error init NR PBCH");
return SRSRAN_SUCCESS;
}
return SRSRAN_SUCCESS;
}
int srsran_ssb_init(srsran_ssb_t* q, const srsran_ssb_args_t* args)
{
// Verify input parameters
@ -86,6 +105,11 @@ int srsran_ssb_init(srsran_ssb_t* q, const srsran_ssb_args_t* args)
return SRSRAN_ERROR;
}
// PBCH
if (ssb_init_pbch(q) < SRSRAN_SUCCESS) {
return SRSRAN_ERROR;
}
return SRSRAN_SUCCESS;
}
@ -118,6 +142,7 @@ void srsran_ssb_free(srsran_ssb_t* q)
srsran_dft_plan_free(&q->fft);
srsran_dft_plan_free(&q->fft_corr);
srsran_dft_plan_free(&q->ifft_corr);
srsran_pbch_nr_free(&q->pbch);
SRSRAN_MEM_ZERO(q, srsran_ssb_t, 1);
}
@ -228,9 +253,8 @@ static uint32_t ssb_first_symbol_caseE(const srsran_ssb_cfg_t* cfg, uint32_t ind
return count;
}
static int ssb_first_symbol(const srsran_ssb_cfg_t* cfg, uint32_t ssb_i)
static uint32_t ssb_candidates(const srsran_ssb_cfg_t* cfg, uint32_t indexes[SRSRAN_SSB_NOF_POSITION])
{
uint32_t indexes[SRSRAN_SSB_NOF_POSITION];
uint32_t Lmax = 0;
switch (cfg->pattern) {
@ -251,12 +275,17 @@ static int ssb_first_symbol(const srsran_ssb_cfg_t* cfg, uint32_t ssb_i)
break;
case SRSRAN_SSB_PATTERN_INVALID:
ERROR("Invalid case");
return SRSRAN_ERROR;
}
return Lmax;
}
static int ssb_first_symbol(const srsran_ssb_cfg_t* cfg, uint32_t ssb_i, uint32_t* Lmax)
{
uint32_t indexes[SRSRAN_SSB_NOF_POSITION];
*Lmax = ssb_candidates(cfg, indexes);
uint32_t ssb_count = 0;
for (uint32_t i = 0; i < Lmax; i++) {
for (uint32_t i = 0; i < *Lmax; i++) {
// There is a SSB transmission opportunity
if (cfg->position[i]) {
// Return the SSB transmission in burst
@ -380,7 +409,7 @@ int srsran_ssb_set_cfg(srsran_ssb_t* q, const srsran_ssb_cfg_t* cfg)
q->scs_hz = (float)SRSRAN_SUBC_SPACING_NR(cfg->scs);
// Get first symbol
int l_begin = ssb_first_symbol(cfg, 0);
int l_begin = ssb_first_symbol(cfg, 0, &q->Lmax);
if (l_begin < SRSRAN_SUCCESS) {
// set it to 2 in case it is not selected
l_begin = 2;
@ -531,7 +560,14 @@ int srsran_ssb_add(srsran_ssb_t* q, uint32_t N_id, const srsran_pbch_msg_nr_t* m
// ...
// Put PBCH payload
// ...
srsran_pbch_nr_cfg_t pbch_cfg = {};
pbch_cfg.N_id = N_id;
pbch_cfg.ssb_scs = q->cfg.scs;
pbch_cfg.Lmax = q->Lmax;
if (srsran_pbch_nr_encode(&q->pbch, &pbch_cfg, msg, ssb_grid) < SRSRAN_SUCCESS) {
ERROR("Error encoding PBCH");
return SRSRAN_ERROR;
}
// Select input/ouput pointers considering the time offset in the slot
const cf_t* in_ptr = &in[q->t_offset];