From e07cf513d0ef4f6b05e91ee68a6bf1d6405172c8 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Mon, 30 Nov 2020 18:00:24 +0100 Subject: [PATCH] Improved NR blind search and DL test --- .../srslte/phy/ch_estimation/dmrs_pdcch.h | 9 + lib/include/srslte/phy/common/phy_common_nr.h | 5 + lib/include/srslte/phy/enb/enb_dl_nr.h | 2 + lib/include/srslte/phy/ue/ue_dl_nr.h | 1 + lib/src/phy/ch_estimation/dmrs_pdcch.c | 89 +++++- lib/src/phy/enb/enb_dl_nr.c | 15 + lib/src/phy/phch/pdcch_nr.c | 38 ++- lib/src/phy/ue/ue_dl_nr.c | 41 ++- lib/test/phy/phy_dl_nr_test.c | 259 +++++++++++------- 9 files changed, 338 insertions(+), 121 deletions(-) diff --git a/lib/include/srslte/phy/ch_estimation/dmrs_pdcch.h b/lib/include/srslte/phy/ch_estimation/dmrs_pdcch.h index fbcb0fdf5..66ed51cea 100644 --- a/lib/include/srslte/phy/ch_estimation/dmrs_pdcch.h +++ b/lib/include/srslte/phy/ch_estimation/dmrs_pdcch.h @@ -71,6 +71,10 @@ typedef struct SRSLTE_API { /// Channel estimates, size coreset_sz cf_t* ce; + + /// Frequency domain smoothing filter + float* filter; + uint32_t filter_len; } srslte_dmrs_pdcch_estimator_t; /** @@ -121,9 +125,14 @@ SRSLTE_API int srslte_dmrs_pdcch_estimate(srslte_dmrs_pdcch_estimator_t* q, typedef struct SRSLTE_API { /// Linear reference signal received power (RSRP). Measure correlation float rsrp; + float rsrp_dBfs; /// Energy per resource element (EPRE) float epre; + float epre_dBfs; + + /// Normalized Correlation (RSRP / EPRE) + float norm_corr; /// CFO Measure in Hz (only available for CORESET durations 2 and 3) float cfo_hz; diff --git a/lib/include/srslte/phy/common/phy_common_nr.h b/lib/include/srslte/phy/common/phy_common_nr.h index 67237fc25..ceaa2acc9 100644 --- a/lib/include/srslte/phy/common/phy_common_nr.h +++ b/lib/include/srslte/phy/common/phy_common_nr.h @@ -54,6 +54,11 @@ extern "C" { */ #define SRSLTE_NSLOTS_PER_FRAME_NR(NUM) (SRSLTE_NSLOTS_PER_SF_NR(NUM) * SRSLTE_NOF_SF_X_FRAME) +/** + * @brief Bounds slot index into the frame + */ +#define SRSLTE_SLOT_NR_MOD(NUM, N) ((N) % SRSLTE_NSLOTS_PER_FRAME_NR(NUM)) + /** * @brief Maximum Carrier identification value. Defined by TS 38.331 v15.10.0 as PhysCellId from 0 to 1007. */ diff --git a/lib/include/srslte/phy/enb/enb_dl_nr.h b/lib/include/srslte/phy/enb/enb_dl_nr.h index 4eae55cb5..45e28120c 100644 --- a/lib/include/srslte/phy/enb/enb_dl_nr.h +++ b/lib/include/srslte/phy/enb/enb_dl_nr.h @@ -53,6 +53,8 @@ SRSLTE_API int srslte_enb_dl_nr_set_coreset(srslte_enb_dl_nr_t* q, const srslte_ SRSLTE_API void srslte_enb_dl_nr_free(srslte_enb_dl_nr_t* q); +SRSLTE_API int srslte_enb_dl_nr_base_zero(srslte_enb_dl_nr_t* q); + SRSLTE_API void srslte_enb_dl_nr_gen_signal(srslte_enb_dl_nr_t* q); SRSLTE_API int srslte_enb_dl_nr_pdcch_put(srslte_enb_dl_nr_t* q, diff --git a/lib/include/srslte/phy/ue/ue_dl_nr.h b/lib/include/srslte/phy/ue/ue_dl_nr.h index b41e0cba0..960a649bc 100644 --- a/lib/include/srslte/phy/ue/ue_dl_nr.h +++ b/lib/include/srslte/phy/ue/ue_dl_nr.h @@ -36,6 +36,7 @@ typedef struct SRSLTE_API { uint32_t max_prb; uint32_t nof_rx_antennas; float pdcch_dmrs_corr_thr; + float pdcch_dmrs_epre_thr; srslte_carrier_nr_t carrier; srslte_coreset_t coreset; diff --git a/lib/src/phy/ch_estimation/dmrs_pdcch.c b/lib/src/phy/ch_estimation/dmrs_pdcch.c index 69e326d6c..481cd3a15 100644 --- a/lib/src/phy/ch_estimation/dmrs_pdcch.c +++ b/lib/src/phy/ch_estimation/dmrs_pdcch.c @@ -16,6 +16,12 @@ /// per frequency resource. #define NOF_PILOTS_X_FREQ_RES 18 +#define DMRS_PDCCH_INFO_TX(...) INFO("PDCCH DMRS Tx: " __VA_ARGS__) +#define DMRS_PDCCH_INFO_RX(...) INFO("PDCCH DMRS Rx: " __VA_ARGS__) + +/// @brief Enables interpolation at CCE frequency bandwidth to avoid interference with adjacent PDCCH DMRS +#define DMRS_PDCCH_INTERPOLATE_GROUP 1 + static uint32_t dmrs_pdcch_get_cinit(uint32_t slot_idx, uint32_t symbol_idx, uint32_t n_id) { return (uint32_t)((((SRSLTE_NSYMB_PER_SLOT_NR * slot_idx + symbol_idx + 1UL) << 17UL) * (2 * n_id + 1) + 2 * n_id) & @@ -130,9 +136,14 @@ int srslte_dmrs_pdcch_put(const srslte_carrier_nr_t* carrier, n_id = coreset->dmrs_scrambling_id; } + // Bound slot index + uint32_t slot_idx = SRSLTE_SLOT_NR_MOD(carrier->numerology, slot_cfg->idx); + for (uint32_t l = 0; l < coreset->duration; l++) { // Get Cin - uint32_t cinit = dmrs_pdcch_get_cinit(slot_cfg->idx, l, n_id); + uint32_t cinit = dmrs_pdcch_get_cinit(slot_idx, l, n_id); + + DMRS_PDCCH_INFO_TX("n=%d; l=%d; cinit=%08x\n", slot_idx, l, cinit); // Put data dmrs_pdcch_put_symbol_noninterleaved( @@ -178,7 +189,11 @@ int srslte_dmrs_pdcch_estimator_init(srslte_dmrs_pdcch_estimator_t* q, uint32_t coreset_bw = srslte_coreset_get_bw(coreset); uint32_t coreset_sz = srslte_coreset_get_sz(coreset); +#if DMRS_PDCCH_INTERPOLATE_GROUP + if (srslte_interp_linear_init(&q->interpolator, NOF_PILOTS_X_FREQ_RES / q->coreset.duration, 4)) { +#else if (srslte_interp_linear_init(&q->interpolator, coreset_bw * 3, 4)) { +#endif ERROR("Initiating interpolator\n"); return SRSLTE_ERROR; } @@ -206,6 +221,17 @@ int srslte_dmrs_pdcch_estimator_init(srslte_dmrs_pdcch_estimator_t* q, q->ce = srslte_vec_cf_malloc(coreset_sz); } + if (q->filter == NULL) { + q->filter_len = 5U; + + q->filter = srslte_vec_f_malloc(q->filter_len); + if (q->filter == NULL) { + return SRSLTE_ERROR; + } + + srslte_chest_set_smooth_filter_gauss(q->filter, q->filter_len - 1, 2); + } + // Save new calculated values q->coreset_bw = coreset_bw; q->coreset_sz = coreset_sz; @@ -229,9 +255,13 @@ void srslte_dmrs_pdcch_estimator_free(srslte_dmrs_pdcch_estimator_t* q) } } + if (q->filter) { + free(q->filter); + } + srslte_interp_linear_free(&q->interpolator); - memset(q, 0, sizeof(srslte_dmrs_pdcch_estimator_t)); + SRSLTE_MEM_ZERO(q, srslte_dmrs_pdcch_estimator_t, 1); } static void @@ -246,8 +276,10 @@ srslte_dmrs_pdcch_extract(srslte_dmrs_pdcch_estimator_t* q, uint32_t cinit, cons // Counts enabled frequency domain resources uint32_t rb_coreset_idx = 0; + // Iterate over all possible frequency resources - for (uint32_t i = 0; i < SRSLTE_CORESET_FREQ_DOMAIN_RES_SIZE; i++) { + uint32_t freq_domain_res_size = SRSLTE_MIN(q->carrier.nof_prb / 6, SRSLTE_CORESET_FREQ_DOMAIN_RES_SIZE); + for (uint32_t i = 0; i < freq_domain_res_size; i++) { // Skip disabled frequency resources if (!q->coreset.freq_resources[i]) { sequence_skip += NOF_PILOTS_X_FREQ_RES; @@ -300,10 +332,15 @@ int srslte_dmrs_pdcch_estimate(srslte_dmrs_pdcch_estimator_t* q, n_id = q->coreset.dmrs_scrambling_id; } + // Bound slot index + uint32_t slot_idx = SRSLTE_SLOT_NR_MOD(q->carrier.numerology, slot_cfg->idx); + // Extract pilots for (uint32_t l = 0; l < q->coreset.duration; l++) { // Calculate PRN sequence initial state - uint32_t cinit = dmrs_pdcch_get_cinit(slot_cfg->idx, l, n_id); + uint32_t cinit = dmrs_pdcch_get_cinit(slot_idx, l, n_id); + + DMRS_PDCCH_INFO_RX("n=%d; l=%d; cinit=%08x\n", slot_idx, l, cinit); // Extract pilots least square estimates srslte_dmrs_pdcch_extract(q, cinit, &sf_symbols[l * q->carrier.nof_prb * SRSLTE_NRE], q->lse[l]); @@ -312,10 +349,26 @@ int srslte_dmrs_pdcch_estimate(srslte_dmrs_pdcch_estimator_t* q, // Time averaging and smoothing should be implemented here // ... - // Interpolation, it assumes all frequency domain resources are contiguous + // Interpolation in groups +#if DMRS_PDCCH_INTERPOLATE_GROUP + uint32_t group_count = (q->coreset.duration * q->coreset_bw * 3) / NOF_PILOTS_X_FREQ_RES; + uint32_t group_size = NOF_PILOTS_X_FREQ_RES / q->coreset.duration; + for (uint32_t l = 0; l < q->coreset.duration; l++) { + for (uint32_t j = 0; j < group_count; j++) { + cf_t tmp[NOF_PILOTS_X_FREQ_RES]; + + // Smoothing filter group + srslte_conv_same_cf(&q->lse[l][j * group_size], q->filter, tmp, group_size, q->filter_len); + + srslte_interp_linear_offset( + &q->interpolator, tmp, &q->ce[SRSLTE_NRE * q->coreset_bw * l + j * group_size * 4], 1, 3); + } + } +#else for (uint32_t l = 0; l < q->coreset.duration; l++) { srslte_interp_linear_offset(&q->interpolator, q->lse[l], &q->ce[SRSLTE_NRE * q->coreset_bw * l], 1, 3); } +#endif return SRSLTE_SUCCESS; } @@ -350,11 +403,16 @@ int srslte_dmrs_pdcch_get_measure(const srslte_dmrs_pdcch_estimator_t* q, float sync_err = 0.0f; cf_t corr[SRSLTE_CORESET_DURATION_MAX] = {}; for (uint32_t l = 0; l < q->coreset.duration; l++) { + if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) { + DMRS_PDCCH_INFO_RX("Measuring PDCCH l=%d; lse=", l); + srslte_vec_fprint_c(stdout, &q->lse[l][pilot_idx], nof_pilots); + } + // Correlate DMRS corr[l] = srslte_vec_acc_cc(&q->lse[l][pilot_idx], nof_pilots) / (float)nof_pilots; // Measure symbol RSRP - rsrp += cabsf(corr[l]); + rsrp += __real__ corr[l] * __real__ corr[l] + __imag__ corr[l] * __imag__ corr[l]; // Measure symbol EPRE epre += srslte_vec_avg_power_cf(&q->lse[l][pilot_idx], nof_pilots); @@ -381,6 +439,22 @@ int srslte_dmrs_pdcch_get_measure(const srslte_dmrs_pdcch_estimator_t* q, measure->sync_error_us = (float)SRSLTE_SUBC_SPACING_NR(q->carrier.numerology) * sync_err / (4.0e-6f * (float)q->coreset.duration); + measure->rsrp_dBfs = srslte_convert_power_to_dB(measure->rsrp); + measure->epre_dBfs = srslte_convert_power_to_dB(measure->epre); + + if (isnormal(measure->rsrp) && isnormal(measure->epre)) { + measure->norm_corr = measure->rsrp / measure->epre; + } else { + measure->norm_corr = 0.0f; + } + + DMRS_PDCCH_INFO_RX("Measure L=%d; ncce=%d; RSRP=%+.1f dBfs; EPRE=%+.1f dBfs; Corr=%.3f\n", + dci_location->L, + dci_location->ncce, + measure->rsrp_dBfs, + measure->epre_dBfs, + measure->norm_corr); + return SRSLTE_SUCCESS; } @@ -424,5 +498,8 @@ int srslte_dmrs_pdcch_get_ce(const srslte_dmrs_pdcch_estimator_t* q, ERROR("Incorrect number of extracted resources (%d != %d)\n", count, ce->nof_re); } + // At the moment Noise is not calculated + ce->noise_var = 0.0f; + return SRSLTE_SUCCESS; } diff --git a/lib/src/phy/enb/enb_dl_nr.c b/lib/src/phy/enb/enb_dl_nr.c index de72d0de8..3e4b8ca36 100644 --- a/lib/src/phy/enb/enb_dl_nr.c +++ b/lib/src/phy/enb/enb_dl_nr.c @@ -154,6 +154,19 @@ void srslte_enb_dl_nr_gen_signal(srslte_enb_dl_nr_t* q) } } +int srslte_enb_dl_nr_base_zero(srslte_enb_dl_nr_t* q) +{ + if (q == NULL) { + return SRSLTE_ERROR_INVALID_INPUTS; + } + + for (uint32_t i = 0; i < q->nof_tx_antennas; i++) { + srslte_vec_cf_zero(q->sf_symbols[i], SRSLTE_SLOT_LEN_RE_NR(q->carrier.nof_prb)); + } + + return SRSLTE_SUCCESS; +} + int srslte_enb_dl_nr_pdcch_put(srslte_enb_dl_nr_t* q, const srslte_dl_slot_cfg_t* slot_cfg, const srslte_search_space_t* search_space, @@ -195,6 +208,8 @@ int srslte_enb_dl_nr_pdcch_put(srslte_enb_dl_nr_t* q, return SRSLTE_ERROR; } + INFO("DCI DL NR: L=%d; ncce=%d;\n", dci_location->L, dci_location->ncce); + return SRSLTE_SUCCESS; } diff --git a/lib/src/phy/phch/pdcch_nr.c b/lib/src/phy/phch/pdcch_nr.c index 531dc9439..0ee6900ca 100644 --- a/lib/src/phy/phch/pdcch_nr.c +++ b/lib/src/phy/phch/pdcch_nr.c @@ -17,6 +17,9 @@ #define PDCCH_NR_POLAR_RM_IBIL 0 +#define PDCCH_INFO_TX(...) INFO("PDCCH Tx: " __VA_ARGS__) +#define PDCCH_INFO_RX(...) INFO("PDCCH Rx: " __VA_ARGS__) + /** * @brief Recursive Y_p_n function */ @@ -345,7 +348,7 @@ int srslte_pdcch_nr_encode(srslte_pdcch_nr_t* q, const srslte_dci_msg_nr_t* dci_ if (srslte_polar_code_get(&q->code, q->K, q->E, 9U) < SRSLTE_SUCCESS) { return SRSLTE_ERROR; } - INFO("PDCCH NR TX: K=%d; E=%d; M=%d; n=%d;\n", q->K, q->E, q->M, q->code.n); + PDCCH_INFO_TX("K=%d; E=%d; M=%d; n=%d;\n", q->K, q->E, q->M, q->code.n); // Copy DCI message srslte_vec_u8_copy(q->c, dci_msg->payload, dci_msg->nof_bits); @@ -353,7 +356,7 @@ int srslte_pdcch_nr_encode(srslte_pdcch_nr_t* q, const srslte_dci_msg_nr_t* dci_ // Append CRC srslte_crc_attach(&q->crc24c, q->c, dci_msg->nof_bits); - INFO("PDCCH NR TX: Append CRC %06x\n", (uint32_t)srslte_crc_checksum_get(&q->crc24c)); + PDCCH_INFO_TX("Append CRC %06x\n", (uint32_t)srslte_crc_checksum_get(&q->crc24c)); // Unpack RNTI uint8_t unpacked_rnti[16] = {}; @@ -365,7 +368,7 @@ int srslte_pdcch_nr_encode(srslte_pdcch_nr_t* q, const srslte_dci_msg_nr_t* dci_ // Print c if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) { - INFO("PDCCH NR TX: c="); + PDCCH_INFO_TX("c="); srslte_vec_fprint_hex(stdout, q->c, q->K); } @@ -379,7 +382,7 @@ int srslte_pdcch_nr_encode(srslte_pdcch_nr_t* q, const srslte_dci_msg_nr_t* dci_ // Print d if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) { - INFO("PDCCH NR TX: d="); + PDCCH_INFO_TX("d="); srslte_vec_fprint_byte(stdout, q->d, q->K); } @@ -408,7 +411,7 @@ int srslte_pdcch_nr_encode(srslte_pdcch_nr_t* q, const srslte_dci_msg_nr_t* dci_ if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) { char str[128] = {}; srslte_pdcch_nr_info(q, NULL, str, sizeof(str)); - INFO("PDCCH NR TX: %s\n", str); + PDCCH_INFO_TX("%s\n", str); } return SRSLTE_SUCCESS; @@ -444,7 +447,7 @@ int srslte_pdcch_nr_decode(srslte_pdcch_nr_t* q, if (srslte_polar_code_get(&q->code, q->K, q->E, 9U) < SRSLTE_SUCCESS) { return SRSLTE_ERROR; } - INFO("PDCCH NR RX: K=%d; E=%d; M=%d; n=%d;\n", q->K, q->E, q->M, q->code.n); + PDCCH_INFO_RX("K=%d; E=%d; M=%d; n=%d;\n", q->K, q->E, q->M, q->code.n); // Get symbols from grid uint32_t m = pdcch_nr_cp(q, &dci_msg->location, slot_symbols, q->symbols, false); @@ -453,9 +456,21 @@ int srslte_pdcch_nr_decode(srslte_pdcch_nr_t* q, return SRSLTE_ERROR; } + // Print channel estimates if enabled + if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) { + PDCCH_INFO_RX("ce="); + srslte_vec_fprint_c(stdout, ce->ce, q->M); + } + // Equalise srslte_predecoding_single(q->symbols, ce->ce, q->symbols, NULL, q->M, 1.0f, ce->noise_var); + // Print symbols if enabled + if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) { + PDCCH_INFO_RX("symbols="); + srslte_vec_fprint_c(stdout, q->symbols, q->M); + } + // Demodulation int8_t* llr = (int8_t*)q->f; srslte_demod_soft_demodulate_b(SRSLTE_MOD_QPSK, q->symbols, llr, q->M); @@ -483,7 +498,7 @@ int srslte_pdcch_nr_decode(srslte_pdcch_nr_t* q, // Print d if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) { - INFO("PDCCH NR RX: d="); + PDCCH_INFO_RX("d="); srslte_vec_fprint_bs(stdout, d, q->K); } @@ -498,7 +513,7 @@ int srslte_pdcch_nr_decode(srslte_pdcch_nr_t* q, // Print c if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) { - INFO("PDCCH NR RX: c="); + PDCCH_INFO_RX("c="); srslte_vec_fprint_hex(stdout, q->c, q->K); } @@ -516,7 +531,10 @@ int srslte_pdcch_nr_decode(srslte_pdcch_nr_t* q, uint32_t checksum2 = srslte_bit_pack(&ptr, 24); res->crc = checksum1 == checksum2; - INFO("PDCCH NR RX: CRC={%06x, %06x}\n", checksum1, checksum2); + if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) { + PDCCH_INFO_RX("CRC={%06x, %06x}; msg=", checksum1, checksum2); + srslte_vec_fprint_hex(stdout, q->c, dci_msg->nof_bits); + } // Copy DCI message srslte_vec_u8_copy(dci_msg->payload, q->c, dci_msg->nof_bits); @@ -530,7 +548,7 @@ int srslte_pdcch_nr_decode(srslte_pdcch_nr_t* q, if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) { char str[128] = {}; srslte_pdcch_nr_info(q, res, str, sizeof(str)); - INFO("PDCCH NR RX: %s\n", str); + PDCCH_INFO_RX("%s\n", str); } return SRSLTE_SUCCESS; diff --git a/lib/src/phy/ue/ue_dl_nr.c b/lib/src/phy/ue/ue_dl_nr.c index be5218ec9..072e95d6b 100644 --- a/lib/src/phy/ue/ue_dl_nr.c +++ b/lib/src/phy/ue/ue_dl_nr.c @@ -13,6 +13,7 @@ #include "srslte/phy/ue/ue_dl_nr.h" #define UE_DL_NR_PDCCH_CORR_DEFAULT_THR 0.5f +#define UE_DL_NR_PDCCH_EPRE_DEFAULT_THR -10.0f static int ue_dl_nr_alloc_prb(srslte_ue_dl_nr_t* q, uint32_t new_nof_prb) { @@ -189,18 +190,42 @@ static int ue_dl_nr_find_dci_ncce(srslte_ue_dl_nr_t* q, srslte_dci_msg_nr_t* dci return SRSLTE_ERROR; } - // If measured RSRP and EPRE is invalid, early return - if (!isnormal(m.rsrp) || !isnormal(m.epre)) { + // If measured correlation is invalid, early return + if (!isnormal(m.norm_corr)) { + INFO("Discarded PDCCH candidate L=%d;ncce=%d; Invalid measurement;\n", dci_msg->location.L, dci_msg->location.ncce); return SRSLTE_SUCCESS; } - // Compare DMRS correlation with threshold - float thr = q->pdcch_dmrs_corr_thr; - if (!isnormal(thr)) { - thr = UE_DL_NR_PDCCH_CORR_DEFAULT_THR; //< Load default threshold if not provided + // Compare EPRE with threshold + { + float thr = q->pdcch_dmrs_epre_thr; + if (!isnormal(thr)) { + thr = UE_DL_NR_PDCCH_EPRE_DEFAULT_THR; //< Load default threshold if not provided + } + if (m.epre_dBfs < thr) { + INFO("Discarded PDCCH candidate L=%d;ncce=%d; EPRE is too weak (%.1f<%.1f);\n", + dci_msg->location.L, + dci_msg->location.ncce, + m.epre_dBfs, + thr); + return SRSLTE_SUCCESS; + } } - if (m.rsrp / m.epre < thr) { - return SRSLTE_SUCCESS; + + // Compare DMRS correlation with threshold + { + float thr = q->pdcch_dmrs_corr_thr; + if (!isnormal(thr)) { + thr = UE_DL_NR_PDCCH_CORR_DEFAULT_THR; //< Load default threshold if not provided + } + if (m.norm_corr < thr) { + INFO("Discarded PDCCH candidate L=%d;ncce=%d; Correlation is too low (%.1f<%.1f);\n", + dci_msg->location.L, + dci_msg->location.ncce, + m.norm_corr, + thr); + return SRSLTE_SUCCESS; + } } // Extract PDCCH channel estimates diff --git a/lib/test/phy/phy_dl_nr_test.c b/lib/test/phy/phy_dl_nr_test.c index 12b86922b..b06ee569d 100644 --- a/lib/test/phy/phy_dl_nr_test.c +++ b/lib/test/phy/phy_dl_nr_test.c @@ -35,11 +35,14 @@ static uint32_t mcs = 30; // Set to 30 for steering static srslte_pdsch_cfg_nr_t pdsch_cfg = {}; static srslte_pdsch_grant_nr_t pdsch_grant = {}; static uint16_t rnti = 0x1234; +static uint32_t nof_slots = 10; void usage(char* prog) { printf("Usage: %s [pTL] \n", prog); + printf("\t-P Number of BWP (Carrier) PRB [Default %d]\n", carrier.nof_prb); printf("\t-p Number of grant PRB, set to 0 for steering [Default %d]\n", n_prb); + printf("\t-n Number of slots to simulate [Default %d]\n", nof_slots); printf("\t-m MCS PRB, set to >28 for steering [Default %d]\n", mcs); printf("\t-T Provide MCS table (64qam, 256qam, 64qamLowSE) [Default %s]\n", srslte_mcs_table_to_str(pdsch_cfg.sch_cfg.mcs_table)); @@ -50,11 +53,17 @@ void usage(char* prog) int parse_args(int argc, char** argv) { int opt; - while ((opt = getopt(argc, argv, "pmTLv")) != -1) { + while ((opt = getopt(argc, argv, "PpmnTLv")) != -1) { switch (opt) { + case 'P': + carrier.nof_prb = (uint32_t)strtol(argv[optind], NULL, 10); + break; case 'p': n_prb = (uint32_t)strtol(argv[optind], NULL, 10); break; + case 'n': + nof_slots = (uint32_t)strtol(argv[optind], NULL, 10); + break; case 'm': mcs = (uint32_t)strtol(argv[optind], NULL, 10); break; @@ -76,6 +85,62 @@ int parse_args(int argc, char** argv) return SRSLTE_SUCCESS; } +int work_gnb_dl(srslte_enb_dl_nr_t* enb_dl, + srslte_dl_slot_cfg_t* slot, + srslte_search_space_t* search_space, + srslte_dci_dl_nr_t* dci_dl, + srslte_dci_location_t* dci_location, + uint8_t** data_tx) +{ + if (srslte_enb_dl_nr_base_zero(enb_dl) < SRSLTE_SUCCESS) { + ERROR("Error setting base to zero\n"); + return SRSLTE_ERROR; + } + + // Put actual DCI + if (srslte_enb_dl_nr_pdcch_put(enb_dl, slot, search_space, dci_dl, dci_location, rnti) < SRSLTE_SUCCESS) { + ERROR("Error putting PDCCH\n"); + return SRSLTE_ERROR; + } + + // Put PDSCH transmission + if (srslte_enb_dl_nr_pdsch_put(enb_dl, slot, &pdsch_cfg, &pdsch_grant, data_tx) < SRSLTE_SUCCESS) { + ERROR("Error putting PDSCH\n"); + return SRSLTE_ERROR; + } + + srslte_enb_dl_nr_gen_signal(enb_dl); + + return SRSLTE_SUCCESS; +} + +int work_ue_dl(srslte_ue_dl_nr_t* ue_dl, + srslte_dl_slot_cfg_t* slot, + srslte_search_space_t* search_space, + srslte_pdsch_res_nr_t* pdsch_res) +{ + srslte_ue_dl_nr_estimate_fft(ue_dl, slot); + + srslte_dci_dl_nr_t dci_dl_rx = {}; + int nof_found_dci = srslte_ue_dl_nr_find_dl_dci(ue_dl, search_space, slot, rnti, &dci_dl_rx, 1); + if (nof_found_dci < SRSLTE_SUCCESS) { + ERROR("Error decoding\n"); + return SRSLTE_ERROR; + } + + if (nof_found_dci < 1) { + ERROR("Error DCI not found\n"); + return SRSLTE_ERROR; + } + + if (srslte_ue_dl_nr_pdsch_get(ue_dl, slot, &pdsch_cfg, &pdsch_grant, pdsch_res) < SRSLTE_SUCCESS) { + ERROR("Error decoding\n"); + return SRSLTE_ERROR; + } + + return SRSLTE_SUCCESS; +} + int main(int argc, char** argv) { int ret = SRSLTE_ERROR; @@ -84,6 +149,10 @@ int main(int argc, char** argv) srslte_pdsch_res_nr_t pdsch_res[SRSLTE_MAX_TB] = {}; srslte_random_t rand_gen = srslte_random_init(1234); srslte_dl_slot_cfg_t slot = {}; + struct timeval t[3] = {}; + uint64_t pdsch_encode_us = 0; + uint64_t pdsch_decode_us = 0; + uint64_t nof_bits = 0; uint8_t* data_tx[SRSLTE_MAX_TB] = {}; uint8_t* data_rx[SRSLTE_MAX_CODEWORDS] = {}; @@ -95,17 +164,18 @@ int main(int argc, char** argv) goto clean_exit; } - srslte_ue_dl_nr_args_t ue_dl_args = {}; - ue_dl_args.nof_rx_antennas = 1; - ue_dl_args.nof_max_prb = MAX_PRB; - ue_dl_args.pdsch.sch.disable_simd = true; - ue_dl_args.pdsch.measure_evm = true; - ue_dl_args.pdsch.measure_time = true; + srslte_ue_dl_nr_args_t ue_dl_args = {}; + ue_dl_args.nof_rx_antennas = 1; + ue_dl_args.pdsch.sch.disable_simd = false; + ue_dl_args.pdsch.sch.decoder_use_flooded = false; + ue_dl_args.pdsch.measure_evm = true; + ue_dl_args.pdcch.disable_simd = false; + ue_dl_args.pdcch.measure_evm = true; srslte_enb_dl_nr_args_t enb_dl_args = {}; enb_dl_args.nof_tx_antennas = 1; - enb_dl_args.nof_max_prb = MAX_PRB; - enb_dl_args.pdsch.sch.disable_simd = true; + enb_dl_args.pdsch.sch.disable_simd = false; + enb_dl_args.pdcch.disable_simd = false; // Set default PDSCH configuration pdsch_cfg.sch_cfg.mcs_table = srslte_mcs_table_64qam; @@ -113,21 +183,17 @@ int main(int argc, char** argv) goto clean_exit; } - srslte_pdsch_nr_args_t pdsch_args = {}; - pdsch_args.sch.disable_simd = true; - pdsch_args.measure_evm = true; - // Configure CORESET srslte_coreset_t coreset = {}; coreset.duration = 2; for (uint32_t i = 0; i < SRSLTE_CORESET_FREQ_DOMAIN_RES_SIZE; i++) { - coreset.freq_resources[i] = i < carrier.nof_prb; + coreset.freq_resources[i] = i < carrier.nof_prb / 6; } // Configure Search Space srslte_search_space_t search_space = {}; search_space.type = srslte_search_space_type_ue; - for (uint32_t L = 0; L < SRSLTE_SEARCH_SPACE_MAX_NOF_CANDIDATES_NR; L++) { + for (uint32_t L = 0; L < SRSLTE_SEARCH_SPACE_NOF_AGGREGATION_LEVELS_NR; L++) { search_space.nof_candidates[L] = srslte_pdcch_nr_max_candidates_coreset(&coreset, L); } @@ -210,109 +276,108 @@ int main(int argc, char** argv) mcs_end = SRSLTE_MIN(mcs + 1, mcs_end); } - for (n_prb = n_prb_start; n_prb < n_prb_end; n_prb++) { - for (mcs = mcs_start; mcs < mcs_end; mcs++) { + uint64_t slot_count = 0; + for (slot.idx = 0; slot.idx < nof_slots; slot.idx++) { + for (n_prb = n_prb_start; n_prb < n_prb_end; n_prb++) { + for (mcs = mcs_start; mcs < mcs_end; mcs++, slot_count++) { - for (uint32_t n = 0; n < SRSLTE_MAX_PRB_NR; n++) { - pdsch_grant.prb_idx[n] = (n < n_prb); - } - - if (srslte_ra_nr_fill_tb(&pdsch_cfg, &pdsch_grant, mcs, &pdsch_grant.tb[0]) < SRSLTE_SUCCESS) { - ERROR("Error filing tb\n"); - goto clean_exit; - } - - for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) { - // Skip TB if no allocated - if (data_tx[tb] == NULL) { - continue; + for (uint32_t n = 0; n < SRSLTE_MAX_PRB_NR; n++) { + pdsch_grant.prb_idx[n] = (n < n_prb); } - for (uint32_t i = 0; i < pdsch_grant.tb[tb].tbs; i++) { - data_tx[tb][i] = (uint8_t)srslte_random_uniform_int_dist(rand_gen, 0, UINT8_MAX); + if (srslte_ra_nr_fill_tb(&pdsch_cfg, &pdsch_grant, mcs, &pdsch_grant.tb[0]) < SRSLTE_SUCCESS) { + ERROR("Error filing tb\n"); + goto clean_exit; } - pdsch_grant.tb[tb].softbuffer.tx = &softbuffer_tx; - } - - // Compute PDCCH candidate locations - uint32_t L = 0; - uint32_t ncce_candidates[SRSLTE_SEARCH_SPACE_MAX_NOF_CANDIDATES_NR] = {}; - int nof_candidates = - srslte_pdcch_nr_locations_coreset(&coreset, &search_space, rnti, L, slot.idx, ncce_candidates); - if (nof_candidates < SRSLTE_SUCCESS) { - ERROR("Error getting PDCCH candidates\n"); - goto clean_exit; - } - // Setup DCI location - srslte_dci_location_t dci_location = {}; - dci_location.ncce = ncce_candidates[0]; - dci_location.L = L; + for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) { + // Skip TB if no allocated + if (data_tx[tb] == NULL) { + continue; + } - // Setup DCI - srslte_dci_dl_nr_t dci_dl = {}; + for (uint32_t i = 0; i < pdsch_grant.tb[tb].tbs; i++) { + data_tx[tb][i] = (uint8_t)srslte_random_uniform_int_dist(rand_gen, 0, UINT8_MAX); + } + pdsch_grant.tb[tb].softbuffer.tx = &softbuffer_tx; + } - // Put actual DCI - if (srslte_enb_dl_nr_pdcch_put(&enb_dl, &slot, &search_space, &dci_dl, &dci_location, rnti) < SRSLTE_SUCCESS) { - ERROR("Error putting PDCCH\n"); - goto clean_exit; - } + // Compute PDCCH candidate locations + uint32_t L = 0; + uint32_t ncce_candidates[SRSLTE_SEARCH_SPACE_MAX_NOF_CANDIDATES_NR] = {}; + int nof_candidates = + srslte_pdcch_nr_locations_coreset(&coreset, &search_space, rnti, L, slot.idx, ncce_candidates); + if (nof_candidates < SRSLTE_SUCCESS) { + ERROR("Error getting PDCCH candidates\n"); + goto clean_exit; + } - // Put PDSCH transmission - if (srslte_enb_dl_nr_pdsch_put(&enb_dl, &slot, &pdsch_cfg, &pdsch_grant, data_tx) < SRSLTE_SUCCESS) { - ERROR("Error putting PDSCH\n"); - goto clean_exit; - } + // Setup DCI location + srslte_dci_location_t dci_location = {}; + dci_location.ncce = ncce_candidates[0]; + dci_location.L = L; - srslte_enb_dl_nr_gen_signal(&enb_dl); + // Setup DCI + srslte_dci_dl_nr_t dci_dl = {}; - for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) { - pdsch_grant.tb[tb].softbuffer.rx = &softbuffer_rx; - srslte_softbuffer_rx_reset(pdsch_grant.tb[tb].softbuffer.rx); - } + gettimeofday(&t[1], NULL); + if (work_gnb_dl(&enb_dl, &slot, &search_space, &dci_dl, &dci_location, data_tx) < SRSLTE_ERROR) { + ERROR("Error running eNb DL\n"); + goto clean_exit; + } + gettimeofday(&t[2], NULL); + get_time_interval(t); + pdsch_encode_us += (size_t)(t[0].tv_sec * 1e6 + t[0].tv_usec); - srslte_ue_dl_nr_estimate_fft(&ue_dl, &slot); + for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) { + pdsch_grant.tb[tb].softbuffer.rx = &softbuffer_rx; + srslte_softbuffer_rx_reset(pdsch_grant.tb[tb].softbuffer.rx); + } - srslte_dci_dl_nr_t dci_dl_rx = {}; - int nof_found_dci = srslte_ue_dl_nr_find_dl_dci(&ue_dl, &search_space, &slot, rnti, &dci_dl_rx, 1); - if (nof_found_dci < SRSLTE_SUCCESS) { - ERROR("Error decoding\n"); - goto clean_exit; - } + gettimeofday(&t[1], NULL); + if (work_ue_dl(&ue_dl, &slot, &search_space, pdsch_res) < SRSLTE_SUCCESS) { + ERROR("Error running UE DL\n"); + goto clean_exit; + } + gettimeofday(&t[2], NULL); + get_time_interval(t); + pdsch_decode_us += (size_t)(t[0].tv_sec * 1e6 + t[0].tv_usec); - if (nof_found_dci < 1) { - ERROR("Error DCI not found\n"); - goto clean_exit; - } + if (pdsch_res->evm > 0.001f) { + ERROR("Error PDSCH EVM is too high %f\n", pdsch_res->evm); + goto clean_exit; + } - if (srslte_ue_dl_nr_pdsch_get(&ue_dl, &slot, &pdsch_cfg, &pdsch_grant, pdsch_res) < SRSLTE_SUCCESS) { - ERROR("Error decoding\n"); - goto clean_exit; - } + if (!pdsch_res[0].crc) { + ERROR("Failed to match CRC; n_prb=%d; mcs=%d; TBS=%d;\n", n_prb, mcs, pdsch_grant.tb[0].tbs); + goto clean_exit; + } - if (pdsch_res->evm > 0.001f) { - ERROR("Error PDSCH EVM is too high %f\n", pdsch_res->evm); - goto clean_exit; - } + if (memcmp(data_tx[0], data_rx[0], pdsch_grant.tb[0].tbs / 8) != 0) { + ERROR("Failed to match Tx/Rx data; n_prb=%d; mcs=%d; TBS=%d;\n", n_prb, mcs, pdsch_grant.tb[0].tbs); + printf("Tx data: "); + srslte_vec_fprint_byte(stdout, data_tx[0], pdsch_grant.tb[0].tbs / 8); + printf("Rx data: "); + srslte_vec_fprint_byte(stdout, data_rx[0], pdsch_grant.tb[0].tbs / 8); + goto clean_exit; + } - if (!pdsch_res[0].crc) { - ERROR("Failed to match CRC; n_prb=%d; mcs=%d; TBS=%d;\n", n_prb, mcs, pdsch_grant.tb[0].tbs); - goto clean_exit; - } + INFO("n_prb=%d; mcs=%d; TBS=%d; EVM=%f; PASSED!\n", n_prb, mcs, pdsch_grant.tb[0].tbs, pdsch_res[0].evm); - if (memcmp(data_tx[0], data_rx[0], pdsch_grant.tb[0].tbs / 8) != 0) { - ERROR("Failed to match Tx/Rx data; n_prb=%d; mcs=%d; TBS=%d;\n", n_prb, mcs, pdsch_grant.tb[0].tbs); - printf("Tx data: "); - srslte_vec_fprint_byte(stdout, data_tx[0], pdsch_grant.tb[0].tbs / 8); - printf("Rx data: "); - srslte_vec_fprint_byte(stdout, data_rx[0], pdsch_grant.tb[0].tbs / 8); - goto clean_exit; + // Count the Tx/Rx'd number of bits + nof_bits += pdsch_grant.tb[0].tbs; } - - printf("n_prb=%d; mcs=%d; TBS=%d; EVM=%f; PASSED!\n", n_prb, mcs, pdsch_grant.tb[0].tbs, pdsch_res[0].evm); } } + printf("[Rates in Mbps] Granted Processed\n"); + printf(" eNb: %5.1f %5.1f\n", + (double)nof_bits / (double)slot_count / 1000.0f, + (double)nof_bits / pdsch_encode_us); + printf(" UE: %5.1f %5.1f\n", + (double)nof_bits / (double)slot_count / 1000.0f, + (double)nof_bits / pdsch_decode_us); + ret = SRSLTE_SUCCESS; clean_exit: