From 5181a9d64c75ad55b761a8f7bc6df1d0a14ba910 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Thu, 27 May 2021 13:28:20 +0200 Subject: [PATCH] Implemented PBCH blind decode --- .../srsran/phy/ch_estimation/dmrs_pbch.h | 17 +- lib/include/srsran/phy/phch/pbch_nr.h | 13 +- lib/include/srsran/phy/sync/ssb.h | 33 ++- lib/src/phy/ch_estimation/dmrs_pbch.c | 62 ++++-- lib/src/phy/phch/pbch_nr.c | 8 +- lib/src/phy/sync/ssb.c | 191 +++++++++++++++--- lib/src/phy/sync/test/ssb_decode_test.c | 30 ++- lib/src/phy/sync/test/ssb_measure_test.c | 2 +- srsue/test/phy/nr_cell_search_test.cc | 2 +- 9 files changed, 275 insertions(+), 83 deletions(-) diff --git a/lib/include/srsran/phy/ch_estimation/dmrs_pbch.h b/lib/include/srsran/phy/ch_estimation/dmrs_pbch.h index 588c11787..8abf29b19 100644 --- a/lib/include/srsran/phy/ch_estimation/dmrs_pbch.h +++ b/lib/include/srsran/phy/ch_estimation/dmrs_pbch.h @@ -21,7 +21,7 @@ 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 ssb_idx; ///< SSB candidate index, up to 3 LSB are significant 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 @@ -46,17 +46,26 @@ typedef struct SRSRAN_API { */ SRSRAN_API int srsran_dmrs_pbch_put(const srsran_dmrs_pbch_cfg_t* cfg, cf_t ssb_grid[SRSRAN_SSB_NOF_RE]); +/** + * @brief Measures NR PBCH DMRS + * @param cfg PBCH DMRS configuration + * @param ssb_grid SSB resource grid + * @param[out] meas Measurement + * @return SRSRAN_SUCCESS if the inputs and configuration are valid, SRSRAN_ERROR code otherwise + */ +SRSRAN_API int srsran_dmrs_pbch_measure(const srsran_dmrs_pbch_cfg_t* cfg, + const cf_t ssb_grid[SRSRAN_SSB_NOF_RE], + srsran_dmrs_pbch_meas_t* meas); + /** * @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); + cf_t ce[SRSRAN_SSB_NOF_RE]); #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 65d22a7a3..c91f68bdf 100644 --- a/lib/include/srsran/phy/phch/pbch_nr.h +++ b/lib/include/srsran/phy/phch/pbch_nr.h @@ -39,11 +39,11 @@ typedef struct SRSRAN_API { * @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 + 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, up to 4 LSB significant + 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 } srsran_pbch_nr_cfg_t; /** @@ -102,15 +102,12 @@ SRSRAN_API int srsran_pbch_nr_encode(srsran_pbch_nr_t* q, * @brief Decodes an NR PBCH message in the SSB resource grid * @param q NR PBCH object * @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, 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); diff --git a/lib/include/srsran/phy/sync/ssb.h b/lib/include/srsran/phy/sync/ssb.h index bf05901d9..26f2f9c1c 100644 --- a/lib/include/srsran/phy/sync/ssb.h +++ b/lib/include/srsran/phy/sync/ssb.h @@ -105,6 +105,16 @@ typedef struct SRSRAN_API { cf_t* pss_seq[SRSRAN_NOF_NID_2_NR]; ///< Possible frequency domain PSS for find } srsran_ssb_t; +/** + * @brief Describes an SSB search result + * @note if pbch.crc is true, SSB transmission is found and decoded. Otherwise, no SSB transmission has been decoded + */ +typedef struct { + uint32_t N_id; ///< Most suitable physical cell identifier + uint32_t t_offset; ///< Time offset in the input samples + srsran_pbch_msg_nr_t pbch_msg; ///< Physical broadcast channel message of the most suitable SSB candidate +} srsran_ssb_search_res_t; + /** * @brief Initialises configures NR SSB with the given arguments * @param q SSB object @@ -131,18 +141,28 @@ SRSRAN_API int srsran_ssb_set_cfg(srsran_ssb_t* q, const srsran_ssb_cfg_t* cfg); * @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 ssb_idx SSB candidate index * @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, uint32_t n_hf, + uint32_t ssb_idx, const cf_t* in, srsran_pbch_msg_nr_t* msg); +/** + * @brief Searches for an SSB transmission and decodes the PBCH message + * @param q SSB object + * @param in Input baseband buffer + * @param nof_samples Number of samples available in the buffer + * @param res SSB Search result + * @return SRSRAN_SUCCESS if the parameters are valid, SRSRAN_ERROR code otherwise + */ +SRSRAN_API int srsran_ssb_search(srsran_ssb_t* q, const cf_t* in, uint32_t nof_samples, srsran_ssb_search_res_t* res); + /** * @brief Decides if the SSB object is configured and a given subframe is configured for SSB transmission * @param q SSB object @@ -155,16 +175,11 @@ SRSRAN_API bool srsran_ssb_send(srsran_ssb_t* q, uint32_t sf_idx); * @brief Adds SSB to a given signal in time domain * @param q SSB object * @param N_id Physical Cell Identifier - * @param ssb_idx SSB candidate index * @param msg NR PBCH message to transmit * @return SRSRAN_SUCCESS if the parameters are valid, SRSRAN_ERROR code otherwise */ -SRSRAN_API int srsran_ssb_add(srsran_ssb_t* q, - uint32_t N_id, - uint32_t ssb_idx, - const srsran_pbch_msg_nr_t* msg, - const cf_t* in, - cf_t* out); +SRSRAN_API int +srsran_ssb_add(srsran_ssb_t* q, uint32_t N_id, const srsran_pbch_msg_nr_t* msg, const cf_t* in, cf_t* out); /** * @brief Perform cell search and measurement diff --git a/lib/src/phy/ch_estimation/dmrs_pbch.c b/lib/src/phy/ch_estimation/dmrs_pbch.c index c6d38862b..c208aff73 100644 --- a/lib/src/phy/ch_estimation/dmrs_pbch.c +++ b/lib/src/phy/ch_estimation/dmrs_pbch.c @@ -137,16 +137,11 @@ int dmrs_pbch_extract_lse(const srsran_dmrs_pbch_cfg_t* cfg, 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) +static int dmrs_pbch_meas_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) { @@ -201,18 +196,47 @@ int srsran_dmrs_pbch_estimate(const srsran_dmrs_pbch_cfg_t* cfg, 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; + if (meas != NULL) { + 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); + // Generate estimated grid + if (ce != NULL) { + // 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; +} + +int srsran_dmrs_pbch_measure(const srsran_dmrs_pbch_cfg_t* cfg, + const cf_t ssb_grid[SRSRAN_SSB_NOF_RE], + srsran_dmrs_pbch_meas_t* meas) +{ + // Validate inputs + if (cfg == NULL || ssb_grid == NULL || meas == NULL) { + return SRSRAN_ERROR_INVALID_INPUTS; + } + + return dmrs_pbch_meas_estimate(cfg, ssb_grid, NULL, meas); +} + +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]) +{ + // Validate inputs + if (cfg == NULL || ssb_grid == NULL || ce == NULL) { + return SRSRAN_ERROR_INVALID_INPUTS; + } + + return dmrs_pbch_meas_estimate(cfg, ssb_grid, ce, NULL); } \ 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 1a34ab903..bc4e28c9a 100644 --- a/lib/src/phy/phch/pbch_nr.c +++ b/lib/src/phy/phch/pbch_nr.c @@ -245,6 +245,7 @@ pbch_nr_pbch_msg_unpack(const srsran_pbch_nr_cfg_t* cfg, const uint8_t a[PBCH_NR msg->hrf = (a[G[10]] == 1); // Put SSB related in a_hat[A_hat + 5] to a_hat[A_hat + 7] + msg->ssb_idx = cfg->ssb_idx; // Load 4 LSB if (cfg->Lmax == 64) { msg->ssb_idx = msg->ssb_idx & 0b111; msg->ssb_idx |= (uint8_t)(a[G[11]] << 5U); // 6th bit of SSB index @@ -427,9 +428,9 @@ static void pbch_nr_scramble_rx(const srsran_pbch_nr_cfg_t* cfg, uint32_t M_bit = PBCH_NR_E; // Select value v - uint32_t v = (ssb_idx & 0x7U); + uint32_t v = (ssb_idx & 0b111U); if (cfg->Lmax == 4) { - v = ssb_idx & 0x3U; + v = ssb_idx & 0b11U; } // Advance sequence @@ -594,7 +595,6 @@ int srsran_pbch_nr_encode(srsran_pbch_nr_t* q, 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) @@ -623,7 +623,7 @@ int srsran_pbch_nr_decode(srsran_pbch_nr_t* q, // TS 38.211 7.3.3 Physical broadcast channel // 7.3.3.1 Scrambling - pbch_nr_scramble_rx(cfg, ssb_idx, llr, llr); + pbch_nr_scramble_rx(cfg, cfg->ssb_idx, llr, llr); // 7.1.5 Rate matching int8_t d[PBCH_NR_N]; diff --git a/lib/src/phy/sync/ssb.c b/lib/src/phy/sync/ssb.c index 75dcb0b45..72746f4ad 100644 --- a/lib/src/phy/sync/ssb.c +++ b/lib/src/phy/sync/ssb.c @@ -510,12 +510,7 @@ bool srsran_ssb_send(srsran_ssb_t* q, uint32_t sf_idx) return (sf_idx % q->cfg.periodicity_ms == 0); } -int srsran_ssb_add(srsran_ssb_t* q, - uint32_t N_id, - uint32_t ssb_idx, - const srsran_pbch_msg_nr_t* msg, - const cf_t* in, - cf_t* out) +int srsran_ssb_add(srsran_ssb_t* q, uint32_t N_id, const srsran_pbch_msg_nr_t* msg, const cf_t* in, cf_t* out) { // Verify input parameters if (q == NULL || N_id >= SRSRAN_NOF_NID_NR || msg == NULL || in == NULL || out == NULL) { @@ -558,7 +553,6 @@ int srsran_ssb_add(srsran_ssb_t* q, // 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"); @@ -566,7 +560,7 @@ int srsran_ssb_add(srsran_ssb_t* q, } // Select start symbol from SSB candidate index - int t_offset = ssb_get_t_offset(q, ssb_idx); + int t_offset = ssb_get_t_offset(q, msg->ssb_idx); if (t_offset < SRSRAN_SUCCESS) { ERROR("Invalid SSB candidate index"); return SRSRAN_ERROR; @@ -905,10 +899,100 @@ int srsran_ssb_csi_measure(srsran_ssb_t* q, return SRSRAN_SUCCESS; } -int srsran_ssb_decode_pbch(srsran_ssb_t* q, +static int ssb_select_pbch(srsran_ssb_t* q, + uint32_t N_id, + const cf_t ssb_grid[SRSRAN_SSB_NOF_RE], + uint32_t* found_n_hf, + uint32_t* found_ssb_idx_4lsb) +{ + // Prepare PBCH DMRS configuration + srsran_dmrs_pbch_cfg_t pbch_dmrs_cfg = {}; + pbch_dmrs_cfg.N_id = N_id; + pbch_dmrs_cfg.n_hf = 0; // Parameter to guess + pbch_dmrs_cfg.ssb_idx = 0; // Parameter to guess + pbch_dmrs_cfg.L_max = q->Lmax; + pbch_dmrs_cfg.beta = 0.0f; + pbch_dmrs_cfg.scs = q->cfg.scs; + + // Initialise best values + srsran_dmrs_pbch_meas_t best_meas = {}; + uint32_t best_n_hf = 0; + uint32_t best_ssb_idx = 0; + + // Iterate over all the parameters to guess and select the most suitable + for (uint32_t n_hf = 0; n_hf < 2; n_hf++) { + for (uint32_t ssb_idx = 0; ssb_idx < SRSRAN_MIN(8, q->Lmax); ssb_idx++) { + // Set parameters + pbch_dmrs_cfg.n_hf = n_hf; + pbch_dmrs_cfg.ssb_idx = ssb_idx; + + // Measure + srsran_dmrs_pbch_meas_t meas = {}; + if (srsran_dmrs_pbch_measure(&pbch_dmrs_cfg, ssb_grid, &meas) < SRSRAN_SUCCESS) { + ERROR("Error measure for n_hf=%d ssb_idx=%d", n_hf, ssb_idx); + return SRSRAN_ERROR; + } + + // Select the result with highest correlation (most suitable) + if (meas.corr > best_meas.corr) { + best_meas = meas; + best_n_hf = n_hf; + best_ssb_idx = ssb_idx; + } + } + } + + // Save findings + *found_n_hf = best_n_hf; + *found_ssb_idx_4lsb = best_ssb_idx; + + return SRSRAN_SUCCESS; +} + +static int ssb_decode_pbch(srsran_ssb_t* q, uint32_t N_id, + uint32_t n_hf, uint32_t ssb_idx, + const cf_t ssb_grid[SRSRAN_SSB_NOF_RE], + srsran_pbch_msg_nr_t* msg) +{ + // 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 + cf_t ce[SRSRAN_SSB_NOF_RE] = {}; + if (srsran_dmrs_pbch_estimate(&pbch_dmrs_cfg, ssb_grid, ce) < SRSRAN_SUCCESS) { + ERROR("Error estimating channel"); + return SRSRAN_ERROR; + } + + // Prepare PBCH configuration + srsran_pbch_nr_cfg_t pbch_cfg = {}; + pbch_cfg.N_id = N_id; + pbch_cfg.n_hf = n_hf; + pbch_cfg.ssb_idx = ssb_idx; + pbch_cfg.Lmax = q->Lmax; + pbch_cfg.beta = 0.0f; + + // Decode + if (srsran_pbch_nr_decode(&q->pbch, &pbch_cfg, ssb_grid, ce, msg) < SRSRAN_SUCCESS) { + ERROR("Error decoding PBCH"); + return SRSRAN_ERROR; + } + + return SRSRAN_SUCCESS; +} + +int srsran_ssb_decode_pbch(srsran_ssb_t* q, + uint32_t N_id, uint32_t n_hf, + uint32_t ssb_idx, const cf_t* in, srsran_pbch_msg_nr_t* msg) { @@ -935,40 +1019,81 @@ int srsran_ssb_decode_pbch(srsran_ssb_t* q, return SRSRAN_ERROR; } - // 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; + // Decode PBCH + if (ssb_decode_pbch(q, N_id, n_hf, ssb_idx, ssb_grid, msg) < SRSRAN_SUCCESS) { + ERROR("Error decoding"); + return SRSRAN_ERROR; + } - // 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_SUCCESS; +} + +int srsran_ssb_search(srsran_ssb_t* q, const cf_t* in, uint32_t nof_samples, srsran_ssb_search_res_t* res) +{ + // Verify inputs + if (q == NULL || in == NULL || res == NULL || !isnormal(q->scs_hz)) { + return SRSRAN_ERROR_INVALID_INPUTS; + } + + if (!q->args.enable_search || !q->args.enable_decode) { + ERROR("SSB is not configured to search (%c) and decode (%c)", + q->args.enable_search ? 'y' : 'n', + q->args.enable_decode ? 'y' : 'n'); return SRSRAN_ERROR; } - // Compare measurement with threshold - if (meas.corr < q->args.pbch_dmrs_thr) { - msg->crc = false; - return SRSRAN_SUCCESS; + // Search for PSS in time domain + uint32_t N_id_2 = 0; + uint32_t t_offset = 0; + if (ssb_pss_search(q, in, nof_samples, &N_id_2, &t_offset) < SRSRAN_SUCCESS) { + ERROR("Error searching for N_id_2"); + return SRSRAN_ERROR; } - // 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; + // Remove CP offset prior demodulation + if (t_offset >= q->cp_sz) { + t_offset -= q->cp_sz; + } else { + t_offset = 0; + } - // Decode - if (srsran_pbch_nr_decode(&q->pbch, &pbch_cfg, ssb_idx, ssb_grid, ce, msg) < SRSRAN_SUCCESS) { + // Demodulate + cf_t ssb_grid[SRSRAN_SSB_NOF_RE] = {}; + if (ssb_demodulate(q, in, t_offset, ssb_grid) < SRSRAN_SUCCESS) { + ERROR("Error demodulating"); + return SRSRAN_ERROR; + } + + // Find best N_id_1 + uint32_t N_id_1 = 0; + float sss_corr = 0.0f; + if (srsran_sss_nr_find(ssb_grid, N_id_2, &sss_corr, &N_id_1) < SRSRAN_SUCCESS) { + ERROR("Error searching for N_id_2"); + return SRSRAN_ERROR; + } + + // Select N_id + uint32_t N_id = SRSRAN_NID_NR(N_id_1, N_id_2); + + // Select the most suitable SSB candidate + uint32_t n_hf = 0; + uint32_t ssb_idx = 0; + if (ssb_select_pbch(q, N_id, ssb_grid, &n_hf, &ssb_idx) < SRSRAN_SUCCESS) { + ERROR("Error selecting PBCH"); + return SRSRAN_ERROR; + } + + // Compute PBCH channel estimates + srsran_pbch_msg_nr_t pbch_msg = {}; + if (ssb_decode_pbch(q, N_id, n_hf, ssb_idx, ssb_grid, &pbch_msg) < SRSRAN_SUCCESS) { ERROR("Error decoding PBCH"); return SRSRAN_ERROR; } + // Save result + res->N_id = N_id; + res->t_offset = t_offset; + res->pbch_msg = pbch_msg; + return SRSRAN_SUCCESS; } diff --git a/lib/src/phy/sync/test/ssb_decode_test.c b/lib/src/phy/sync/test/ssb_decode_test.c index 181beb33b..26e529de3 100644 --- a/lib/src/phy/sync/test/ssb_decode_test.c +++ b/lib/src/phy/sync/test/ssb_decode_test.c @@ -85,6 +85,7 @@ static void gen_pbch_msg(srsran_pbch_msg_nr_t* pbch_msg, uint32_t ssb_idx) srsran_random_bit_vector(random_gen, pbch_msg->payload, SRSRAN_PBCH_NR_PAYLOAD_SZ); pbch_msg->ssb_idx = ssb_idx; + pbch_msg->crc = true; } static int test_case_1(srsran_ssb_t* ssb) @@ -92,6 +93,7 @@ static int test_case_1(srsran_ssb_t* ssb) // For benchmarking purposes uint64_t t_encode_usec = 0; uint64_t t_decode_usec = 0; + uint64_t t_search_usec = 0; // SSB configuration srsran_ssb_cfg_t ssb_cfg = {}; @@ -123,7 +125,7 @@ static int test_case_1(srsran_ssb_t* ssb) // Add the SSB base-band gettimeofday(&t[1], NULL); - TESTASSERT(srsran_ssb_add(ssb, pci, ssb_idx, &pbch_msg_tx, buffer, buffer) == SRSRAN_SUCCESS); + TESTASSERT(srsran_ssb_add(ssb, pci, &pbch_msg_tx, buffer, buffer) == SRSRAN_SUCCESS); gettimeofday(&t[2], NULL); get_time_interval(t); t_encode_usec += t[0].tv_usec + t[0].tv_sec * 1000000UL; @@ -134,7 +136,8 @@ 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, 0, buffer, &pbch_msg_rx) == SRSRAN_SUCCESS); + TESTASSERT(srsran_ssb_decode_pbch(ssb, pci, pbch_msg_tx.hrf, pbch_msg_tx.ssb_idx, 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; @@ -145,12 +148,30 @@ static int test_case_1(srsran_ssb_t* ssb) // Assert PBCH message CRC TESTASSERT(pbch_msg_rx.crc); + TESTASSERT(memcmp(&pbch_msg_rx, &pbch_msg_tx, sizeof(srsran_pbch_msg_nr_t)) == 0); + + // Search + srsran_ssb_search_res_t res = {}; + gettimeofday(&t[1], NULL); + TESTASSERT(srsran_ssb_search(ssb, buffer, hf_len, &res) == SRSRAN_SUCCESS); + gettimeofday(&t[2], NULL); + get_time_interval(t); + t_search_usec += t[0].tv_usec + t[0].tv_sec * 1000000UL; + + // Print decoded PBCH message + srsran_pbch_msg_info(&res.pbch_msg, str, sizeof(str)); + INFO("test_case_1 - found pci=%d %s crc=%s", res.N_id, str, res.pbch_msg.crc ? "OK" : "KO"); + + // Assert PBCH message CRC + TESTASSERT(res.pbch_msg.crc); + TESTASSERT(memcmp(&res.pbch_msg, &pbch_msg_tx, sizeof(srsran_pbch_msg_nr_t)) == 0); } } - INFO("test_case_1 - %.1f usec/encode; %.1f usec/decode;", + INFO("test_case_1 - %.1f usec/encode; %.1f usec/decode; %.1f usec/decode;", (double)t_encode_usec / (double)(count), - (double)t_decode_usec / (double)(count)); + (double)t_decode_usec / (double)(count), + (double)t_search_usec / (double)(count)); return SRSRAN_SUCCESS; } @@ -169,6 +190,7 @@ int main(int argc, char** argv) srsran_ssb_args_t ssb_args = {}; ssb_args.enable_encode = true; ssb_args.enable_decode = true; + ssb_args.enable_search = true; if (buffer == NULL) { ERROR("Malloc"); diff --git a/lib/src/phy/sync/test/ssb_measure_test.c b/lib/src/phy/sync/test/ssb_measure_test.c index b13815415..e6c328d59 100644 --- a/lib/src/phy/sync/test/ssb_measure_test.c +++ b/lib/src/phy/sync/test/ssb_measure_test.c @@ -116,7 +116,7 @@ static int test_case_1(srsran_ssb_t* ssb) // Add the SSB base-band gettimeofday(&t[1], NULL); - TESTASSERT(srsran_ssb_add(ssb, pci, 0, &pbch_msg, buffer, buffer) == SRSRAN_SUCCESS); + TESTASSERT(srsran_ssb_add(ssb, pci, &pbch_msg, buffer, buffer) == SRSRAN_SUCCESS); gettimeofday(&t[2], NULL); get_time_interval(t); t_add_usec += t[0].tv_usec + t[0].tv_sec * 1000000UL; diff --git a/srsue/test/phy/nr_cell_search_test.cc b/srsue/test/phy/nr_cell_search_test.cc index c203db08a..9fe02296d 100644 --- a/srsue/test/phy/nr_cell_search_test.cc +++ b/srsue/test/phy/nr_cell_search_test.cc @@ -105,7 +105,7 @@ public: srsran_pbch_msg_nr_t msg = {}; // Add SSB - if (srsran_ssb_add(&ssb, pci, 0, &msg, buffer.data(), buffer.data()) < SRSRAN_SUCCESS) { + if (srsran_ssb_add(&ssb, pci, &msg, buffer.data(), buffer.data()) < SRSRAN_SUCCESS) { logger.error("Error adding SSB"); return SRSRAN_ERROR; }