mirror of https://github.com/PentHertz/srsLTE.git
Initial NR-PBCH-DMRS integration
This commit is contained in:
parent
997f7db23a
commit
a245039cf3
|
@ -0,0 +1,62 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* \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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SRSRAN_DMRS_PBCH_H
|
||||||
|
#define SRSRAN_DMRS_PBCH_H
|
||||||
|
|
||||||
|
#include "srsran/phy/common/phy_common_nr.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Describes the DeModulation Reference Signals (DMRS) for NR PBCH configuration
|
||||||
|
*/
|
||||||
|
typedef struct SRSRAN_API {
|
||||||
|
uint32_t N_id; ///< Physical cell identifier
|
||||||
|
uint32_t n_hf; ///< Number of half radio frame, 0 or 1
|
||||||
|
uint32_t ssb_idx; ///< SSB candidate index
|
||||||
|
uint32_t L_max; ///< Number of SSB opportunities in half radio frame
|
||||||
|
float beta; ///< Power allocation specified in TS 38.213
|
||||||
|
srsran_subcarrier_spacing_t scs; ///< SSB configured subcarrier spacing
|
||||||
|
} srsran_dmrs_pbch_cfg_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Describes an NR PBCH DMRS based measurement
|
||||||
|
*/
|
||||||
|
typedef struct SRSRAN_API {
|
||||||
|
float corr; ///< Normalised correlation
|
||||||
|
float epre; ///< Linear energy per resource element
|
||||||
|
float rsrp; ///< Linear RSRP
|
||||||
|
float cfo_hz; ///< CFO in Hz
|
||||||
|
float avg_delay_us; ///< Average delay in us
|
||||||
|
} srsran_dmrs_pbch_meas_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Put NR PBCH DMRS in the SSB resource grid
|
||||||
|
* @param cfg PBCH DMRS configuration
|
||||||
|
* @param[out] ssb_grid SSB resource grid
|
||||||
|
* @return SRSRAN_SUCCESS if the inputs and configuration are valid, SRSRAN_ERROR code otherwise
|
||||||
|
*/
|
||||||
|
SRSRAN_API int srsran_dmrs_pbch_put(const srsran_dmrs_pbch_cfg_t* cfg, cf_t ssb_grid[SRSRAN_SSB_NOF_RE]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Estimates NR PBCH DMRS
|
||||||
|
* @param cfg PBCH DMRS configuration
|
||||||
|
* @param ssb_grid Demodulated SSB resource grid
|
||||||
|
* @param[out] ce Estimated channel
|
||||||
|
* @param[out] meas Estimated channel measurements
|
||||||
|
* @return SRSRAN_SUCCESS if the inputs and configuration are valid, SRSRAN_ERROR code otherwise
|
||||||
|
*/
|
||||||
|
SRSRAN_API int srsran_dmrs_pbch_estimate(const srsran_dmrs_pbch_cfg_t* cfg,
|
||||||
|
const cf_t ssb_grid[SRSRAN_SSB_NOF_RE],
|
||||||
|
cf_t ce[SRSRAN_SSB_NOF_RE],
|
||||||
|
srsran_dmrs_pbch_meas_t* meas);
|
||||||
|
|
||||||
|
#endif // SRSRAN_DMRS_PBCH_H
|
|
@ -75,7 +75,7 @@ typedef struct SRSRAN_API {
|
||||||
* @brief Initialises an NR PBCH object with the provided arguments
|
* @brief Initialises an NR PBCH object with the provided arguments
|
||||||
* @param q NR PBCH object
|
* @param q NR PBCH object
|
||||||
* @param args Arguments providing the desired configuration
|
* @param args Arguments providing the desired configuration
|
||||||
* @return SRSRAN_SUCCESS if initialization is successful, SRSLTE_ERROR code otherwise
|
* @return SRSRAN_SUCCESS if initialization is successful, SRSRAN_ERROR code otherwise
|
||||||
*/
|
*/
|
||||||
SRSRAN_API int srsran_pbch_nr_init(srsran_pbch_nr_t* q, const srsran_pbch_nr_args_t* args);
|
SRSRAN_API int srsran_pbch_nr_init(srsran_pbch_nr_t* q, const srsran_pbch_nr_args_t* args);
|
||||||
|
|
||||||
|
@ -91,7 +91,7 @@ SRSRAN_API void srsran_pbch_nr_free(srsran_pbch_nr_t* q);
|
||||||
* @param cfg NR PBCH configuration
|
* @param cfg NR PBCH configuration
|
||||||
* @param msg NR PBCH message to transmit
|
* @param msg NR PBCH message to transmit
|
||||||
* @param[out] ssb_grid SSB resource grid
|
* @param[out] ssb_grid SSB resource grid
|
||||||
* @return SRSRAN_SUCCESS if encoding is successful, SRSLTE_ERROR code otherwise
|
* @return SRSRAN_SUCCESS if encoding is successful, SRSRAN_ERROR code otherwise
|
||||||
*/
|
*/
|
||||||
SRSRAN_API int srsran_pbch_nr_encode(srsran_pbch_nr_t* q,
|
SRSRAN_API int srsran_pbch_nr_encode(srsran_pbch_nr_t* q,
|
||||||
const srsran_pbch_nr_cfg_t* cfg,
|
const srsran_pbch_nr_cfg_t* cfg,
|
||||||
|
@ -104,13 +104,15 @@ SRSRAN_API int srsran_pbch_nr_encode(srsran_pbch_nr_t* q,
|
||||||
* @param cfg NR PBCH configuration
|
* @param cfg NR PBCH configuration
|
||||||
* @param ssb_idx SSB candidate index
|
* @param ssb_idx SSB candidate index
|
||||||
* @param[in] ssb_grid SSB resource grid
|
* @param[in] ssb_grid SSB resource grid
|
||||||
|
* @param[in] ce Channel estimates for the SSB resource grid
|
||||||
* @param msg NR PBCH message received
|
* @param msg NR PBCH message received
|
||||||
* @return SRSRAN_SUCCESS if decoding is successful, SRSLTE_ERROR code otherwise
|
* @return SRSRAN_SUCCESS if decoding is successful, SRSRAN_ERROR code otherwise
|
||||||
*/
|
*/
|
||||||
SRSRAN_API int srsran_pbch_nr_decode(srsran_pbch_nr_t* q,
|
SRSRAN_API int srsran_pbch_nr_decode(srsran_pbch_nr_t* q,
|
||||||
const srsran_pbch_nr_cfg_t* cfg,
|
const srsran_pbch_nr_cfg_t* cfg,
|
||||||
uint32_t ssb_idx,
|
uint32_t ssb_idx,
|
||||||
const cf_t ssb_grid[SRSRAN_SSB_NOF_RE],
|
const cf_t ssb_grid[SRSRAN_SSB_NOF_RE],
|
||||||
|
const cf_t ce[SRSRAN_SSB_NOF_RE],
|
||||||
srsran_pbch_msg_nr_t* msg);
|
srsran_pbch_msg_nr_t* msg);
|
||||||
|
|
||||||
SRSRAN_API uint32_t srsran_pbch_msg_info(const srsran_pbch_msg_nr_t* msg, char* str, uint32_t str_len);
|
SRSRAN_API uint32_t srsran_pbch_msg_info(const srsran_pbch_msg_nr_t* msg, char* str, uint32_t str_len);
|
||||||
|
|
|
@ -50,6 +50,7 @@ typedef struct SRSRAN_API {
|
||||||
bool enable_encode; ///< Enables PBCH Encoder
|
bool enable_encode; ///< Enables PBCH Encoder
|
||||||
bool enable_decode; ///< Enables PBCH Decoder
|
bool enable_decode; ///< Enables PBCH Decoder
|
||||||
bool disable_polar_simd; ///< Disables polar encoder/decoder SIMD acceleration
|
bool disable_polar_simd; ///< Disables polar encoder/decoder SIMD acceleration
|
||||||
|
float pbch_dmrs_thr; ///< NR-PBCH DMRS threshold for blind decoding, set to 0 for default
|
||||||
} srsran_ssb_args_t;
|
} srsran_ssb_args_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -127,13 +128,20 @@ SRSRAN_API void srsran_ssb_free(srsran_ssb_t* q);
|
||||||
SRSRAN_API int srsran_ssb_set_cfg(srsran_ssb_t* q, const srsran_ssb_cfg_t* cfg);
|
SRSRAN_API int srsran_ssb_set_cfg(srsran_ssb_t* q, const srsran_ssb_cfg_t* cfg);
|
||||||
/**
|
/**
|
||||||
* @brief Decodes PBCH in the given time domain signal
|
* @brief Decodes PBCH in the given time domain signal
|
||||||
|
* @note It currently expects an input buffer of half radio frame
|
||||||
* @param q SSB object
|
* @param q SSB object
|
||||||
* @param N_id Physical Cell Identifier
|
* @param N_id Physical Cell Identifier
|
||||||
* @param ssb_idx SSB candidate index
|
* @param ssb_idx SSB candidate index
|
||||||
|
* @param n_hf Number of hald radio frame, 0 or 1
|
||||||
|
* @param in Input baseband buffer
|
||||||
* @return SRSRAN_SUCCESS if the parameters are valid, SRSRAN_ERROR code otherwise
|
* @return SRSRAN_SUCCESS if the parameters are valid, SRSRAN_ERROR code otherwise
|
||||||
*/
|
*/
|
||||||
SRSRAN_API int
|
SRSRAN_API int srsran_ssb_decode_pbch(srsran_ssb_t* q,
|
||||||
srsran_ssb_decode_pbch(srsran_ssb_t* q, uint32_t N_id, uint32_t ssb_idx, const cf_t* in, srsran_pbch_msg_nr_t* msg);
|
uint32_t N_id,
|
||||||
|
uint32_t ssb_idx,
|
||||||
|
uint32_t n_hf,
|
||||||
|
const cf_t* in,
|
||||||
|
srsran_pbch_msg_nr_t* msg);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Decides if the SSB object is configured and a given subframe is configured for SSB transmission
|
* @brief Decides if the SSB object is configured and a given subframe is configured for SSB transmission
|
||||||
|
|
|
@ -0,0 +1,218 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* \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/ch_estimation/dmrs_pbch.h"
|
||||||
|
#include "srsran/phy/common/sequence.h"
|
||||||
|
#include "srsran/phy/utils/debug.h"
|
||||||
|
#include "srsran/phy/utils/vector.h"
|
||||||
|
#include <complex.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Number of NR PBCH DMRS resource elements present in an SSB resource grid
|
||||||
|
*/
|
||||||
|
#define DMRS_PBCH_NOF_RE 144
|
||||||
|
|
||||||
|
static uint32_t dmrs_pbch_cinit(const srsran_dmrs_pbch_cfg_t* cfg)
|
||||||
|
{
|
||||||
|
// Default values for L_max == 4
|
||||||
|
uint64_t i_ssb = (cfg->ssb_idx & 0b11U) + 4UL * cfg->n_hf; // Least 2 significant bits
|
||||||
|
|
||||||
|
if (cfg->L_max == 8 || cfg->L_max == 64) {
|
||||||
|
i_ssb = cfg->ssb_idx & 0b111U; // Least 3 significant bits
|
||||||
|
}
|
||||||
|
|
||||||
|
return SRSRAN_SEQUENCE_MOD(((i_ssb + 1UL) * (SRSRAN_FLOOR(cfg->N_id, 4UL) + 1UL) << 11UL) + ((i_ssb + 1UL) << 6UL) +
|
||||||
|
(cfg->N_id % 4));
|
||||||
|
}
|
||||||
|
|
||||||
|
int srsran_dmrs_pbch_put(const srsran_dmrs_pbch_cfg_t* cfg, cf_t ssb_grid[SRSRAN_SSB_NOF_RE])
|
||||||
|
{
|
||||||
|
// Validate inputs
|
||||||
|
if (cfg == NULL || ssb_grid == NULL) {
|
||||||
|
return SRSRAN_ERROR_INVALID_INPUTS;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate index shift
|
||||||
|
uint32_t v = cfg->N_id % 4;
|
||||||
|
|
||||||
|
// Calculate power allocation
|
||||||
|
float beta = M_SQRT1_2;
|
||||||
|
if (isnormal(cfg->beta)) {
|
||||||
|
beta = cfg->beta;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialise sequence
|
||||||
|
uint32_t cinit = dmrs_pbch_cinit(cfg);
|
||||||
|
srsran_sequence_state_t sequence_state = {};
|
||||||
|
srsran_sequence_state_init(&sequence_state, cinit);
|
||||||
|
|
||||||
|
// Generate sequence
|
||||||
|
cf_t r[DMRS_PBCH_NOF_RE];
|
||||||
|
srsran_sequence_state_gen_f(&sequence_state, beta, (float*)r, DMRS_PBCH_NOF_RE * 2);
|
||||||
|
|
||||||
|
// r sequence read index
|
||||||
|
uint32_t r_idx = 0;
|
||||||
|
|
||||||
|
// Put sequence in symbol 1
|
||||||
|
for (uint32_t k = v; k < SRSRAN_SSB_BW_SUBC; k += 4) {
|
||||||
|
ssb_grid[SRSRAN_SSB_BW_SUBC * 1 + k] = r[r_idx++];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Put sequence in symbol 2, lower section
|
||||||
|
for (uint32_t k = v; k < 48; k += 4) {
|
||||||
|
ssb_grid[SRSRAN_SSB_BW_SUBC * 2 + k] = r[r_idx++];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Put sequence in symbol 2, upper section
|
||||||
|
for (uint32_t k = 192 + v; k < SRSRAN_SSB_BW_SUBC; k += 4) {
|
||||||
|
ssb_grid[SRSRAN_SSB_BW_SUBC * 2 + k] = r[r_idx++];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Put sequence in symbol 3
|
||||||
|
for (uint32_t k = v; k < SRSRAN_SSB_BW_SUBC; k += 4) {
|
||||||
|
ssb_grid[SRSRAN_SSB_BW_SUBC * 3 + k] = r[r_idx++];
|
||||||
|
}
|
||||||
|
|
||||||
|
return SRSRAN_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dmrs_pbch_extract_lse(const srsran_dmrs_pbch_cfg_t* cfg,
|
||||||
|
const cf_t ssb_grid[SRSRAN_SSB_NOF_RE],
|
||||||
|
cf_t lse[DMRS_PBCH_NOF_RE])
|
||||||
|
{
|
||||||
|
// Calculate index shift
|
||||||
|
uint32_t v = cfg->N_id % 4;
|
||||||
|
|
||||||
|
// Calculate power allocation
|
||||||
|
float beta = M_SQRT1_2;
|
||||||
|
if (isnormal(cfg->beta)) {
|
||||||
|
beta = cfg->beta;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialise sequence
|
||||||
|
uint32_t cinit = dmrs_pbch_cinit(cfg);
|
||||||
|
srsran_sequence_state_t sequence_state = {};
|
||||||
|
srsran_sequence_state_init(&sequence_state, cinit);
|
||||||
|
|
||||||
|
// Generate sequence
|
||||||
|
cf_t r[DMRS_PBCH_NOF_RE];
|
||||||
|
srsran_sequence_state_gen_f(&sequence_state, beta, (float*)r, DMRS_PBCH_NOF_RE * 2);
|
||||||
|
|
||||||
|
// r sequence read index
|
||||||
|
uint32_t r_idx = 0;
|
||||||
|
|
||||||
|
// Put sequence in symbol 1
|
||||||
|
for (uint32_t k = v; k < SRSRAN_SSB_BW_SUBC; k += 4) {
|
||||||
|
lse[r_idx++] = ssb_grid[SRSRAN_SSB_BW_SUBC * 1 + k];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Put sequence in symbol 2, lower section
|
||||||
|
for (uint32_t k = v; k < 48; k += 4) {
|
||||||
|
lse[r_idx++] = ssb_grid[SRSRAN_SSB_BW_SUBC * 2 + k];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Put sequence in symbol 2, upper section
|
||||||
|
for (uint32_t k = 192 + v; k < SRSRAN_SSB_BW_SUBC; k += 4) {
|
||||||
|
lse[r_idx++] = ssb_grid[SRSRAN_SSB_BW_SUBC * 2 + k];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Put sequence in symbol 3
|
||||||
|
for (uint32_t k = v; k < SRSRAN_SSB_BW_SUBC; k += 4) {
|
||||||
|
lse[r_idx++] = ssb_grid[SRSRAN_SSB_BW_SUBC * 3 + k];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate actual least square estimates
|
||||||
|
srsran_vec_prod_conj_ccc(lse, r, lse, DMRS_PBCH_NOF_RE);
|
||||||
|
|
||||||
|
return SRSRAN_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int srsran_dmrs_pbch_estimate(const srsran_dmrs_pbch_cfg_t* cfg,
|
||||||
|
const cf_t ssb_grid[SRSRAN_SSB_NOF_RE],
|
||||||
|
cf_t ce[SRSRAN_SSB_NOF_RE],
|
||||||
|
srsran_dmrs_pbch_meas_t* meas)
|
||||||
|
{
|
||||||
|
// Validate inputs
|
||||||
|
if (cfg == NULL || ssb_grid == NULL || ce == NULL || meas == NULL) {
|
||||||
|
return SRSRAN_ERROR_INVALID_INPUTS;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract least square estimates
|
||||||
|
cf_t lse[DMRS_PBCH_NOF_RE];
|
||||||
|
if (dmrs_pbch_extract_lse(cfg, ssb_grid, lse) < SRSRAN_SUCCESS) {
|
||||||
|
return SRSRAN_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
float scs_hz = SRSRAN_SUBC_SPACING_NR(cfg->scs);
|
||||||
|
if (!isnormal(scs_hz)) {
|
||||||
|
ERROR("Invalid SCS");
|
||||||
|
return SRSRAN_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute average delay in microseconds from the symbols 1 and 3 (symbol 2 does not carry PBCH in all the grid)
|
||||||
|
float avg_delay1_norm = srsran_vec_estimate_frequency(&lse[0], 60) / 4.0f;
|
||||||
|
float avg_delay3_norm = srsran_vec_estimate_frequency(&lse[84], 60) / 4.0f;
|
||||||
|
float avg_delay_norm = (avg_delay1_norm + avg_delay3_norm) / 2.0f;
|
||||||
|
float avg_delay_us = avg_delay_norm / scs_hz;
|
||||||
|
|
||||||
|
// Generate a second SSB grid with the corrected average delay
|
||||||
|
cf_t ssb_grid_corrected[SRSRAN_SSB_NOF_RE];
|
||||||
|
for (uint32_t l = 0; l < SRSRAN_SSB_DURATION_NSYMB; l++) {
|
||||||
|
srsran_vec_apply_cfo(&ssb_grid[SRSRAN_SSB_BW_SUBC * l],
|
||||||
|
avg_delay_norm,
|
||||||
|
&ssb_grid_corrected[SRSRAN_SSB_BW_SUBC * l],
|
||||||
|
SRSRAN_SSB_BW_SUBC);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract LSE from corrected grid
|
||||||
|
if (dmrs_pbch_extract_lse(cfg, ssb_grid_corrected, lse) < SRSRAN_SUCCESS) {
|
||||||
|
return SRSRAN_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute correlation of symbols 1 and 3
|
||||||
|
cf_t corr1 = srsran_vec_acc_cc(&lse[0], 60) / 60.0f;
|
||||||
|
cf_t corr3 = srsran_vec_acc_cc(&lse[84], 60) / 60.0f;
|
||||||
|
|
||||||
|
// Estimate CFO from correlation
|
||||||
|
float distance_s = srsran_symbol_distance_s(1, 3, cfg->scs);
|
||||||
|
float cfo_hz = 0.0f;
|
||||||
|
if (isnormal(distance_s)) {
|
||||||
|
cfo_hz = cargf(corr1 * conjf(corr3)) / (2.0f * (float)M_PI * distance_s);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Estimate wideband gain at symbol 0
|
||||||
|
cf_t wideband_gain = (srsran_vec_acc_cc(lse, DMRS_PBCH_NOF_RE) / DMRS_PBCH_NOF_RE) *
|
||||||
|
cexpf(I * 2.0f * M_PI * srsran_symbol_offset_s(2, cfg->scs) * cfo_hz);
|
||||||
|
|
||||||
|
// Compute RSRP from correlation
|
||||||
|
float rsrp = SRSRAN_CSQABS((corr1 + corr3) / 2.0f);
|
||||||
|
|
||||||
|
// Compute EPRE
|
||||||
|
float epre = srsran_vec_avg_power_cf(lse, DMRS_PBCH_NOF_RE);
|
||||||
|
|
||||||
|
// Write measurements
|
||||||
|
meas->corr = rsrp / epre;
|
||||||
|
meas->epre = epre;
|
||||||
|
meas->rsrp = rsrp;
|
||||||
|
meas->cfo_hz = cfo_hz;
|
||||||
|
meas->avg_delay_us = avg_delay_us;
|
||||||
|
|
||||||
|
// Compute channel estimates
|
||||||
|
for (uint32_t l = 0; l < SRSRAN_SSB_DURATION_NSYMB; l++) {
|
||||||
|
float t_s = srsran_symbol_offset_s(l, cfg->scs);
|
||||||
|
cf_t symbol_wideband_gain = cexpf(-I * 2.0f * M_PI * cfo_hz * t_s) * wideband_gain;
|
||||||
|
srsran_vec_gen_sine(symbol_wideband_gain, -avg_delay_norm, &ce[l * SRSRAN_SSB_BW_SUBC], SRSRAN_SSB_BW_SUBC);
|
||||||
|
}
|
||||||
|
|
||||||
|
return SRSRAN_SUCCESS;
|
||||||
|
}
|
|
@ -14,9 +14,11 @@
|
||||||
#include "srsran/phy/common/sequence.h"
|
#include "srsran/phy/common/sequence.h"
|
||||||
#include "srsran/phy/fec/polar/polar_chanalloc.h"
|
#include "srsran/phy/fec/polar/polar_chanalloc.h"
|
||||||
#include "srsran/phy/fec/polar/polar_interleaver.h"
|
#include "srsran/phy/fec/polar/polar_interleaver.h"
|
||||||
|
#include "srsran/phy/mimo/precoding.h"
|
||||||
#include "srsran/phy/modem/demod_soft.h"
|
#include "srsran/phy/modem/demod_soft.h"
|
||||||
#include "srsran/phy/modem/mod.h"
|
#include "srsran/phy/modem/mod.h"
|
||||||
#include "srsran/phy/utils/debug.h"
|
#include "srsran/phy/utils/debug.h"
|
||||||
|
#include "srsran/phy/utils/simd.h"
|
||||||
#include "srsran/phy/utils/vector.h"
|
#include "srsran/phy/utils/vector.h"
|
||||||
|
|
||||||
#define PBCH_NR_DEBUG_TX(...) DEBUG("PBCH-NR Tx: " __VA_ARGS__)
|
#define PBCH_NR_DEBUG_TX(...) DEBUG("PBCH-NR Tx: " __VA_ARGS__)
|
||||||
|
@ -594,6 +596,7 @@ int srsran_pbch_nr_decode(srsran_pbch_nr_t* q,
|
||||||
const srsran_pbch_nr_cfg_t* cfg,
|
const srsran_pbch_nr_cfg_t* cfg,
|
||||||
uint32_t ssb_idx,
|
uint32_t ssb_idx,
|
||||||
const cf_t ssb_grid[SRSRAN_SSB_NOF_RE],
|
const cf_t ssb_grid[SRSRAN_SSB_NOF_RE],
|
||||||
|
const cf_t ce_grid[SRSRAN_SSB_NOF_RE],
|
||||||
srsran_pbch_msg_nr_t* msg)
|
srsran_pbch_msg_nr_t* msg)
|
||||||
{
|
{
|
||||||
if (q == NULL || cfg == NULL || msg == NULL || ssb_grid == NULL) {
|
if (q == NULL || cfg == NULL || msg == NULL || ssb_grid == NULL) {
|
||||||
|
@ -602,9 +605,18 @@ int srsran_pbch_nr_decode(srsran_pbch_nr_t* q,
|
||||||
|
|
||||||
// 7.3.3.3 Mapping to physical resources
|
// 7.3.3.3 Mapping to physical resources
|
||||||
// 7.4.3.1.3 Mapping of PBCH and DM-RS within an SS/PBCH block
|
// 7.4.3.1.3 Mapping of PBCH and DM-RS within an SS/PBCH block
|
||||||
cf_t symbols[PBCH_NR_M];
|
srsran_simd_aligned cf_t symbols[PBCH_NR_M];
|
||||||
pbch_nr_demapping(cfg, ssb_grid, symbols);
|
pbch_nr_demapping(cfg, ssb_grid, symbols);
|
||||||
|
|
||||||
|
srsran_simd_aligned cf_t ce[PBCH_NR_M];
|
||||||
|
pbch_nr_demapping(cfg, ce_grid, ce);
|
||||||
|
|
||||||
|
// Channel equalizer
|
||||||
|
if (srsran_predecoding_single(symbols, ce, symbols, NULL, PBCH_NR_M, 1.0f, 0.0f) < SRSRAN_SUCCESS) {
|
||||||
|
ERROR("Error in predecoder");
|
||||||
|
return SRSRAN_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
// 7.3.3.2 Modulation
|
// 7.3.3.2 Modulation
|
||||||
int8_t llr[PBCH_NR_E];
|
int8_t llr[PBCH_NR_E];
|
||||||
srsran_demod_soft_demodulate_b(SRSRAN_MOD_QPSK, symbols, llr, PBCH_NR_M);
|
srsran_demod_soft_demodulate_b(SRSRAN_MOD_QPSK, symbols, llr, PBCH_NR_M);
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "srsran/phy/sync/ssb.h"
|
#include "srsran/phy/sync/ssb.h"
|
||||||
|
#include "srsran/phy/ch_estimation/dmrs_pbch.h"
|
||||||
#include "srsran/phy/sync/pss_nr.h"
|
#include "srsran/phy/sync/pss_nr.h"
|
||||||
#include "srsran/phy/sync/sss_nr.h"
|
#include "srsran/phy/sync/sss_nr.h"
|
||||||
#include "srsran/phy/utils/debug.h"
|
#include "srsran/phy/utils/debug.h"
|
||||||
|
@ -33,6 +34,11 @@
|
||||||
*/
|
*/
|
||||||
#define SSB_CORR_SZ(SYMB_SZ) SRSRAN_MIN(1U << (uint32_t)ceil(log2((double)(SYMB_SZ)) + 3.0), 1U << 13U)
|
#define SSB_CORR_SZ(SYMB_SZ) SRSRAN_MIN(1U << (uint32_t)ceil(log2((double)(SYMB_SZ)) + 3.0), 1U << 13U)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Default NR-PBCH DMRS normalised correlation (RSRP/EPRE) threshold
|
||||||
|
*/
|
||||||
|
#define SSB_PBCH_DMRS_DEFAULT_CORR_THR 0.6f
|
||||||
|
|
||||||
static int ssb_init_corr(srsran_ssb_t* q)
|
static int ssb_init_corr(srsran_ssb_t* q)
|
||||||
{
|
{
|
||||||
// Initialise correlation only if it is enabled
|
// Initialise correlation only if it is enabled
|
||||||
|
@ -83,9 +89,8 @@ int srsran_ssb_init(srsran_ssb_t* q, const srsran_ssb_args_t* args)
|
||||||
q->args = *args;
|
q->args = *args;
|
||||||
|
|
||||||
// Check if the maximum sampling rate is in range, force default otherwise
|
// Check if the maximum sampling rate is in range, force default otherwise
|
||||||
if (!isnormal(q->args.max_srate_hz) || q->args.max_srate_hz < 0.0) {
|
q->args.max_srate_hz = (!isnormal(q->args.max_srate_hz)) ? SRSRAN_SSB_DEFAULT_MAX_SRATE_HZ : q->args.max_srate_hz;
|
||||||
q->args.max_srate_hz = SRSRAN_SSB_DEFAULT_MAX_SRATE_HZ;
|
q->args.pbch_dmrs_thr = (!isnormal(q->args.pbch_dmrs_thr)) ? SSB_PBCH_DMRS_DEFAULT_CORR_THR : q->args.pbch_dmrs_thr;
|
||||||
}
|
|
||||||
|
|
||||||
q->scs_hz = (float)SRSRAN_SUBC_SPACING_NR(q->args.min_scs);
|
q->scs_hz = (float)SRSRAN_SUBC_SPACING_NR(q->args.min_scs);
|
||||||
q->max_symbol_sz = (uint32_t)round(q->args.max_srate_hz / q->scs_hz);
|
q->max_symbol_sz = (uint32_t)round(q->args.max_srate_hz / q->scs_hz);
|
||||||
|
@ -539,7 +544,16 @@ int srsran_ssb_add(srsran_ssb_t* q,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Put PBCH DMRS
|
// Put PBCH DMRS
|
||||||
// ...
|
srsran_dmrs_pbch_cfg_t pbch_dmrs_cfg = {};
|
||||||
|
pbch_dmrs_cfg.N_id = N_id;
|
||||||
|
pbch_dmrs_cfg.n_hf = msg->hrf ? 0 : 1;
|
||||||
|
pbch_dmrs_cfg.ssb_idx = msg->ssb_idx;
|
||||||
|
pbch_dmrs_cfg.L_max = q->Lmax;
|
||||||
|
pbch_dmrs_cfg.beta = 0.0f;
|
||||||
|
if (srsran_dmrs_pbch_put(&pbch_dmrs_cfg, ssb_grid) < SRSRAN_SUCCESS) {
|
||||||
|
ERROR("Error putting PBCH DMRS");
|
||||||
|
return SRSRAN_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
// Put PBCH payload
|
// Put PBCH payload
|
||||||
srsran_pbch_nr_cfg_t pbch_cfg = {};
|
srsran_pbch_nr_cfg_t pbch_cfg = {};
|
||||||
|
@ -630,7 +644,7 @@ ssb_measure(srsran_ssb_t* q, const cf_t ssb_grid[SRSRAN_SSB_NOF_RE], uint32_t N_
|
||||||
uint32_t N_id_1 = SRSRAN_NID_1_NR(N_id);
|
uint32_t N_id_1 = SRSRAN_NID_1_NR(N_id);
|
||||||
uint32_t N_id_2 = SRSRAN_NID_2_NR(N_id);
|
uint32_t N_id_2 = SRSRAN_NID_2_NR(N_id);
|
||||||
|
|
||||||
// Extract PSS LSE
|
// Extract PSS and SSS LSE
|
||||||
cf_t pss_lse[SRSRAN_PSS_NR_LEN];
|
cf_t pss_lse[SRSRAN_PSS_NR_LEN];
|
||||||
cf_t sss_lse[SRSRAN_SSS_NR_LEN];
|
cf_t sss_lse[SRSRAN_SSS_NR_LEN];
|
||||||
if (srsran_pss_nr_extract_lse(ssb_grid, N_id_2, pss_lse) < SRSRAN_SUCCESS ||
|
if (srsran_pss_nr_extract_lse(ssb_grid, N_id_2, pss_lse) < SRSRAN_SUCCESS ||
|
||||||
|
@ -882,7 +896,12 @@ int srsran_ssb_csi_measure(srsran_ssb_t* q,
|
||||||
return SRSRAN_SUCCESS;
|
return SRSRAN_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
int srsran_ssb_decode_pbch(srsran_ssb_t* q, uint32_t N_id, uint32_t ssb_idx, const cf_t* in, srsran_pbch_msg_nr_t* msg)
|
int srsran_ssb_decode_pbch(srsran_ssb_t* q,
|
||||||
|
uint32_t N_id,
|
||||||
|
uint32_t ssb_idx,
|
||||||
|
uint32_t n_hf,
|
||||||
|
const cf_t* in,
|
||||||
|
srsran_pbch_msg_nr_t* msg)
|
||||||
{
|
{
|
||||||
// Verify inputs
|
// Verify inputs
|
||||||
if (q == NULL || N_id >= SRSRAN_NOF_NID_NR || in == NULL || msg == NULL || !isnormal(q->scs_hz)) {
|
if (q == NULL || N_id >= SRSRAN_NOF_NID_NR || in == NULL || msg == NULL || !isnormal(q->scs_hz)) {
|
||||||
|
@ -907,14 +926,37 @@ int srsran_ssb_decode_pbch(srsran_ssb_t* q, uint32_t N_id, uint32_t ssb_idx, con
|
||||||
return SRSRAN_ERROR;
|
return SRSRAN_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prepare configuration
|
// Prepare PBCH DMRS configuration
|
||||||
|
srsran_dmrs_pbch_cfg_t pbch_dmrs_cfg = {};
|
||||||
|
pbch_dmrs_cfg.N_id = N_id;
|
||||||
|
pbch_dmrs_cfg.n_hf = n_hf;
|
||||||
|
pbch_dmrs_cfg.ssb_idx = ssb_idx;
|
||||||
|
pbch_dmrs_cfg.L_max = q->Lmax;
|
||||||
|
pbch_dmrs_cfg.beta = 0.0f;
|
||||||
|
pbch_dmrs_cfg.scs = q->cfg.scs;
|
||||||
|
|
||||||
|
// Compute PBCH channel estimates
|
||||||
|
srsran_dmrs_pbch_meas_t meas = {};
|
||||||
|
cf_t ce[SRSRAN_SSB_NOF_RE] = {};
|
||||||
|
if (srsran_dmrs_pbch_estimate(&pbch_dmrs_cfg, ssb_grid, ce, &meas) < SRSRAN_SUCCESS) {
|
||||||
|
ERROR("Error estimating channel");
|
||||||
|
return SRSRAN_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compare measurement with threshold
|
||||||
|
if (meas.corr < q->args.pbch_dmrs_thr) {
|
||||||
|
msg->crc = false;
|
||||||
|
return SRSRAN_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare PBCH configuration
|
||||||
srsran_pbch_nr_cfg_t pbch_cfg = {};
|
srsran_pbch_nr_cfg_t pbch_cfg = {};
|
||||||
pbch_cfg.N_id = N_id;
|
pbch_cfg.N_id = N_id;
|
||||||
pbch_cfg.ssb_scs = q->cfg.scs;
|
pbch_cfg.ssb_scs = q->cfg.scs;
|
||||||
pbch_cfg.Lmax = q->Lmax;
|
pbch_cfg.Lmax = q->Lmax;
|
||||||
|
|
||||||
// Decode
|
// Decode
|
||||||
if (srsran_pbch_nr_decode(&q->pbch, &pbch_cfg, ssb_idx, ssb_grid, msg) < SRSRAN_SUCCESS) {
|
if (srsran_pbch_nr_decode(&q->pbch, &pbch_cfg, ssb_idx, ssb_grid, ce, msg) < SRSRAN_SUCCESS) {
|
||||||
ERROR("Error decoding PBCH");
|
ERROR("Error decoding PBCH");
|
||||||
return SRSRAN_ERROR;
|
return SRSRAN_ERROR;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include "srsran/phy/sync/ssb.h"
|
#include "srsran/phy/sync/ssb.h"
|
||||||
#include "srsran/phy/utils/debug.h"
|
#include "srsran/phy/utils/debug.h"
|
||||||
#include "srsran/phy/utils/vector.h"
|
#include "srsran/phy/utils/vector.h"
|
||||||
|
#include <complex.h>
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
#include <srsran/phy/utils/random.h>
|
#include <srsran/phy/utils/random.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
@ -25,9 +26,10 @@ static srsran_subcarrier_spacing_t carrier_scs = srsran_subcarrier_spacing_1
|
||||||
static srsran_subcarrier_spacing_t ssb_scs = srsran_subcarrier_spacing_30kHz;
|
static srsran_subcarrier_spacing_t ssb_scs = srsran_subcarrier_spacing_30kHz;
|
||||||
|
|
||||||
// Channel parameters
|
// Channel parameters
|
||||||
static int32_t delay_n = 0;
|
static cf_t wideband_gain = 1.0f + 0.5 * I;
|
||||||
static float cfo_hz = 0.0f;
|
static int32_t delay_n = 1;
|
||||||
static float n0_dB = -300.0f;
|
static float cfo_hz = 1000.0f;
|
||||||
|
static float n0_dB = -10.0f;
|
||||||
|
|
||||||
// Test context
|
// Test context
|
||||||
static srsran_random_t random_gen = NULL;
|
static srsran_random_t random_gen = NULL;
|
||||||
|
@ -69,6 +71,9 @@ static void run_channel()
|
||||||
|
|
||||||
// AWGN
|
// AWGN
|
||||||
srsran_channel_awgn_run_c(&awgn, buffer, buffer, hf_len);
|
srsran_channel_awgn_run_c(&awgn, buffer, buffer, hf_len);
|
||||||
|
|
||||||
|
// Wideband gain
|
||||||
|
srsran_vec_sc_prod_ccc(buffer, wideband_gain, buffer, hf_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gen_pbch_msg(srsran_pbch_msg_nr_t* pbch_msg, uint32_t ssb_idx)
|
static void gen_pbch_msg(srsran_pbch_msg_nr_t* pbch_msg, uint32_t ssb_idx)
|
||||||
|
@ -129,7 +134,7 @@ static int test_case_1(srsran_ssb_t* ssb)
|
||||||
// Decode
|
// Decode
|
||||||
gettimeofday(&t[1], NULL);
|
gettimeofday(&t[1], NULL);
|
||||||
srsran_pbch_msg_nr_t pbch_msg_rx = {};
|
srsran_pbch_msg_nr_t pbch_msg_rx = {};
|
||||||
TESTASSERT(srsran_ssb_decode_pbch(ssb, pci, ssb_idx, buffer, &pbch_msg_rx) == SRSRAN_SUCCESS);
|
TESTASSERT(srsran_ssb_decode_pbch(ssb, pci, ssb_idx, 0, buffer, &pbch_msg_rx) == SRSRAN_SUCCESS);
|
||||||
gettimeofday(&t[2], NULL);
|
gettimeofday(&t[2], NULL);
|
||||||
get_time_interval(t);
|
get_time_interval(t);
|
||||||
t_decode_usec += t[0].tv_usec + t[0].tv_sec * 1000000UL;
|
t_decode_usec += t[0].tv_usec + t[0].tv_sec * 1000000UL;
|
||||||
|
|
Loading…
Reference in New Issue