mirror of https://github.com/PentHertz/srsLTE.git
Initial NR PBCH encoding
This commit is contained in:
parent
d66dac0ab2
commit
0aa5b14145
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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];
|
||||
|
|
Loading…
Reference in New Issue