diff --git a/lib/include/srsran/phy/ch_estimation/dmrs_pbch.h b/lib/include/srsran/phy/ch_estimation/dmrs_pbch.h new file mode 100644 index 000000000..588c11787 --- /dev/null +++ b/lib/include/srsran/phy/ch_estimation/dmrs_pbch.h @@ -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 diff --git a/lib/include/srsran/phy/phch/pbch_nr.h b/lib/include/srsran/phy/phch/pbch_nr.h index f849f4285..65d22a7a3 100644 --- a/lib/include/srsran/phy/phch/pbch_nr.h +++ b/lib/include/srsran/phy/phch/pbch_nr.h @@ -75,7 +75,7 @@ typedef struct SRSRAN_API { * @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 + * @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); @@ -91,7 +91,7 @@ SRSRAN_API void srsran_pbch_nr_free(srsran_pbch_nr_t* q); * @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 + * @return SRSRAN_SUCCESS if encoding is successful, SRSRAN_ERROR code otherwise */ SRSRAN_API int srsran_pbch_nr_encode(srsran_pbch_nr_t* q, 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 ssb_idx SSB candidate index * @param[in] ssb_grid SSB resource grid + * @param[in] ce Channel estimates for the SSB resource grid * @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, const srsran_pbch_nr_cfg_t* cfg, uint32_t ssb_idx, const cf_t ssb_grid[SRSRAN_SSB_NOF_RE], + const cf_t ce[SRSRAN_SSB_NOF_RE], 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); diff --git a/lib/include/srsran/phy/sync/ssb.h b/lib/include/srsran/phy/sync/ssb.h index 033d670a6..bf05901d9 100644 --- a/lib/include/srsran/phy/sync/ssb.h +++ b/lib/include/srsran/phy/sync/ssb.h @@ -50,6 +50,7 @@ typedef struct SRSRAN_API { bool enable_encode; ///< Enables PBCH Encoder bool enable_decode; ///< Enables PBCH Decoder 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; /** @@ -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); /** * @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 N_id Physical Cell Identifier * @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 */ -SRSRAN_API 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); +SRSRAN_API 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); /** * @brief Decides if the SSB object is configured and a given subframe is configured for SSB transmission diff --git a/lib/src/phy/ch_estimation/dmrs_pbch.c b/lib/src/phy/ch_estimation/dmrs_pbch.c new file mode 100644 index 000000000..c6d38862b --- /dev/null +++ b/lib/src/phy/ch_estimation/dmrs_pbch.c @@ -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 +#include + +/* + * 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; +} \ No newline at end of file diff --git a/lib/src/phy/phch/pbch_nr.c b/lib/src/phy/phch/pbch_nr.c index d6ab4a288..1a34ab903 100644 --- a/lib/src/phy/phch/pbch_nr.c +++ b/lib/src/phy/phch/pbch_nr.c @@ -14,9 +14,11 @@ #include "srsran/phy/common/sequence.h" #include "srsran/phy/fec/polar/polar_chanalloc.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/mod.h" #include "srsran/phy/utils/debug.h" +#include "srsran/phy/utils/simd.h" #include "srsran/phy/utils/vector.h" #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, uint32_t ssb_idx, const cf_t ssb_grid[SRSRAN_SSB_NOF_RE], + const cf_t ce_grid[SRSRAN_SSB_NOF_RE], srsran_pbch_msg_nr_t* msg) { 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.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); + 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 int8_t llr[PBCH_NR_E]; srsran_demod_soft_demodulate_b(SRSRAN_MOD_QPSK, symbols, llr, PBCH_NR_M); diff --git a/lib/src/phy/sync/ssb.c b/lib/src/phy/sync/ssb.c index 106f0f85b..3c64282b4 100644 --- a/lib/src/phy/sync/ssb.c +++ b/lib/src/phy/sync/ssb.c @@ -11,6 +11,7 @@ */ #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/sss_nr.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) +/* + * 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) { // 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; // 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 = SRSRAN_SSB_DEFAULT_MAX_SRATE_HZ; - } + q->args.max_srate_hz = (!isnormal(q->args.max_srate_hz)) ? SRSRAN_SSB_DEFAULT_MAX_SRATE_HZ : q->args.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->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 - // ... + 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 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_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 sss_lse[SRSRAN_SSS_NR_LEN]; 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; } -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 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; } - // 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 = {}; pbch_cfg.N_id = N_id; pbch_cfg.ssb_scs = q->cfg.scs; pbch_cfg.Lmax = q->Lmax; // 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"); return SRSRAN_ERROR; } diff --git a/lib/src/phy/sync/test/ssb_decode_test.c b/lib/src/phy/sync/test/ssb_decode_test.c index e85898b9a..181beb33b 100644 --- a/lib/src/phy/sync/test/ssb_decode_test.c +++ b/lib/src/phy/sync/test/ssb_decode_test.c @@ -15,6 +15,7 @@ #include "srsran/phy/sync/ssb.h" #include "srsran/phy/utils/debug.h" #include "srsran/phy/utils/vector.h" +#include #include #include #include @@ -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; // Channel parameters -static int32_t delay_n = 0; -static float cfo_hz = 0.0f; -static float n0_dB = -300.0f; +static cf_t wideband_gain = 1.0f + 0.5 * I; +static int32_t delay_n = 1; +static float cfo_hz = 1000.0f; +static float n0_dB = -10.0f; // Test context static srsran_random_t random_gen = NULL; @@ -69,6 +71,9 @@ static void run_channel() // AWGN 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) @@ -129,7 +134,7 @@ static int test_case_1(srsran_ssb_t* ssb) // Decode gettimeofday(&t[1], NULL); 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); get_time_interval(t); t_decode_usec += t[0].tv_usec + t[0].tv_sec * 1000000UL;