From 775692f46155c5e9df95fd5f85f20aad957fc475 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Fri, 16 Oct 2020 09:52:55 +0200 Subject: [PATCH] Rearanged PDCCH NR functions structures --- .../srslte/phy/ch_estimation/dmrs_pdcch.h | 10 +- lib/include/srslte/phy/common/phy_common_nr.h | 39 +++-- lib/include/srslte/phy/phch/pdcch_nr.h | 57 ++++++++ lib/src/phy/ch_estimation/dmrs_pdcch.c | 137 +++++------------- .../phy/ch_estimation/test/dmrs_pdcch_test.c | 96 ++++++------ lib/src/phy/common/phy_common_nr.c | 4 +- lib/src/phy/phch/pdcch_nr.c | 111 ++++++++++++++ 7 files changed, 285 insertions(+), 169 deletions(-) create mode 100644 lib/include/srslte/phy/phch/pdcch_nr.h create mode 100644 lib/src/phy/phch/pdcch_nr.c diff --git a/lib/include/srslte/phy/ch_estimation/dmrs_pdcch.h b/lib/include/srslte/phy/ch_estimation/dmrs_pdcch.h index 3e89e342c..08e361088 100644 --- a/lib/include/srslte/phy/ch_estimation/dmrs_pdcch.h +++ b/lib/include/srslte/phy/ch_estimation/dmrs_pdcch.h @@ -35,14 +35,14 @@ extern "C" { * * @remark: Implemented as specified by TS 38.211 V15.8.0 Section 7.1.4.3 * - * @attention it expects sf_symbols to be size SRSLTE_NR_SLOT_LEN_RE(cfg->carrier.nof_prb) + * @attention it expects sf_symbols to be size SRSLTE_SLOT_LEN_RE_NR(cfg->carrier.nof_prb) * * @param cfg Configuration that includes Carrier, CORESET, Search Space and PDCCH candidate * @param slot_idx Slot index in the frame * @param sf_symbols is the resource grid where the DMRS resource elements will be written * @return SRSLTE_SUCCESS if the configurations are valid, otherwise it returns an SRSLTE_ERROR code */ -SRSLTE_API int srslte_dmrs_pdcch_put(const srslte_nr_pdcch_cfg_t* cfg, uint32_t slot_idx, cf_t* sf_symbols); +SRSLTE_API int srslte_dmrs_pdcch_put(const srslte_pdcch_cfg_nr_t* cfg, uint32_t slot_idx, cf_t* sf_symbols); /** * @brief PDCCH DMRS channel estimator object @@ -54,7 +54,7 @@ SRSLTE_API int srslte_dmrs_pdcch_put(const srslte_nr_pdcch_cfg_t* cfg, uint32_t */ typedef struct SRSLTE_API { /// Current estimator carrier configuration - srslte_nr_carrier_t carrier; + srslte_carrier_nr_t carrier; /// Current estimator CORESET configuration srslte_coreset_t coreset; @@ -66,7 +66,7 @@ typedef struct SRSLTE_API { uint32_t coreset_sz; /// Object for interpolating, it shall be initialised only once - srslte_resampler_fft_t interpolator; + srslte_interp_lin_t interpolator; /// Pilots least square estimates, one vector for each possible symbol. Since there are one pilot every 4 sub-carriers /// , each vector is three times the CORESEt band-width @@ -92,7 +92,7 @@ typedef struct SRSLTE_API { * @return SRSLTE_SUCCESS if the configurations are valid, otherwise it returns an SRSLTE_ERROR code */ SRSLTE_API int srslte_dmrs_pdcch_estimator_init(srslte_dmrs_pdcch_estimator_t* q, - const srslte_nr_carrier_t* carrier, + const srslte_carrier_nr_t* carrier, const srslte_coreset_t* coreset); /** diff --git a/lib/include/srslte/phy/common/phy_common_nr.h b/lib/include/srslte/phy/common/phy_common_nr.h index 7dfa9d09d..6b17abd8d 100644 --- a/lib/include/srslte/phy/common/phy_common_nr.h +++ b/lib/include/srslte/phy/common/phy_common_nr.h @@ -32,12 +32,12 @@ extern "C" { /** * @brief Defines the number of symbols per slot. Defined by TS 38.211 v15.8.0 Table 4.3.2-1. */ -#define SRSLTE_NR_NSYMB_PER_SLOT 14 +#define SRSLTE_NSYMB_PER_SLOT_NR 14 /** * @brief Defines the resource grid size in physical resource elements (frequency and time domain) */ -#define SRSLTE_NR_SLOT_LEN_RE(nof_prb) (nof_prb * SRSLTE_NRE * SRSLTE_NR_NSYMB_PER_SLOT) +#define SRSLTE_SLOT_LEN_RE_NR(nof_prb) (nof_prb * SRSLTE_NRE * SRSLTE_NSYMB_PER_SLOT_NR) /** * @brief Defines the maximum numerology supported. Defined by TS 38.211 v15.8.0 Table 4.3.2-1. @@ -47,40 +47,40 @@ extern "C" { /** * @brief Defines the symbol duration, including cyclic prefix */ -#define SRSLTE_SUBC_SPACING(NUM) (15000U << (NUM)) +#define SRSLTE_SUBC_SPACING_NR(NUM) (15000U << (NUM)) /** * @brief Defines the number of slots per SF. Defined by TS 38.211 v15.8.0 Table 4.3.2-1. */ -#define SRSLTE_NR_NSLOTS_PER_SF(NUM) (1U << (NUM)) +#define SRSLTE_NSLOTS_PER_SF_NR(NUM) (1U << (NUM)) /** * @brief Defines the number of slots per frame. Defined by TS 38.211 v15.8.0 Table 4.3.2-1. */ -#define SRSLTE_NR_NSLOTS_PER_FRAME(NUM) (SRSLTE_NR_NSLOTS_PER_SF(NUM) * SRSLTE_NOF_SF_X_FRAME) +#define SRSLTE_NSLOTS_PER_FRAME_NR(NUM) (SRSLTE_NSLOTS_PER_SF_NR(NUM) * SRSLTE_NOF_SF_X_FRAME) /** * @brief Maximum Carrier identification value. Defined by TS 38.331 v15.10.0 as PhysCellId from 0 to 1007. */ -#define SRSLTE_NR_MAX_ID 1007 +#define SRSLTE_MAX_ID_NR 1007 /** * @brief Maximum number of physical resource blocks (PRB) that a 5G NR can have. This is defined by TS 38.331 v15.10.0 * as maxNrofPhysicalResourceBlocks */ -#define SRSLTE_NR_MAX_PRB 275 +#define SRSLTE_MAX_PRB_NR 275 -#define SRSLTE_NR_MAX_START 2199 +#define SRSLTE_MAX_START_NR 2199 /** - * Common carrier parameters + * @brief NR carrier parameters */ typedef struct { uint32_t id; uint32_t numerology; uint32_t nof_prb; uint32_t start; -} srslte_nr_carrier_t; +} srslte_carrier_nr_t; /** * CORESET related constants @@ -132,23 +132,34 @@ typedef enum SRSLTE_API { srslte_search_space_type_ue, } srslte_search_space_type_t; +/** + * @brief defines the maximum number of Aggregation levels: 1, 2, 4, 8 and 16 + */ #define SRSLTE_SEARCH_SPACE_NOF_AGGREGATION_LEVELS 5 +/** + * @brief defines the maximum number of candidates for a given Aggregation level + */ +#define SRSLTE_SEARCH_SPACE_MAX_NOF_CANDIDATES 8 + +/** + * @brief SearchSpace parameters as defined in TS 38.331 v15.10.0 SearchSpace sequence + */ typedef struct SRSLTE_API { - uint32_t start; // start symbol within slot + uint32_t id; uint32_t duration; // in slots srslte_search_space_type_t type; uint32_t nof_candidates[SRSLTE_SEARCH_SPACE_NOF_AGGREGATION_LEVELS]; } srslte_search_space_t; typedef struct SRSLTE_API { - srslte_nr_carrier_t carrier; + srslte_carrier_nr_t carrier; uint16_t rnti; srslte_coreset_t coreset; srslte_search_space_t search_space; - uint32_t candidate; uint32_t aggregation_level; -} srslte_nr_pdcch_cfg_t; + uint32_t n_cce; +} srslte_pdcch_cfg_nr_t; /** * @brief Calculates the bandwidth of a given CORESET in physical resource blocks (PRB) . This function uses the diff --git a/lib/include/srslte/phy/phch/pdcch_nr.h b/lib/include/srslte/phy/phch/pdcch_nr.h new file mode 100644 index 000000000..3db2cbbf6 --- /dev/null +++ b/lib/include/srslte/phy/phch/pdcch_nr.h @@ -0,0 +1,57 @@ +/* + * Copyright 2013-2020 Software Radio Systems Limited + * + * This file is part of srsLTE. + * + * srsLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +/****************************************************************************** + * File: pdcch.h + * + * Description: Physical downlink control channel. + * + * Reference: 3GPP TS 36.211 version 10.0.0 Release 10 Sec. 6.8 + *****************************************************************************/ + +#ifndef SRSLTE_PDCCH_NR_H +#define SRSLTE_PDCCH_NR_H + +#include "srslte/config.h" +#include "srslte/phy/common/phy_common_nr.h" + +/** + * @brief Function for generating NR PDCCH candidate locations n_cce for a given CORESET, search space, aggregation + * level and slot. + * + * @see srslte_pdcch_ue_locations_ncce + * @see srslte_pdcch_common_locations_ncce + * + * @param coreset is the coreset configuration provided from higher layers + * @param search_space is the Search Space configuration provided from higher layers + * @param RNTI UE temporal identifier, unused for common search spaces + * @param aggregation_level aggregation level in logarithm range (0,1,2,3,4) + * @param slot_idx Slot index within the radio frame + * @param locations is the destination array with the possible candidate locations n_cce + */ +int srslte_pdcch_nr_locations_ncce(const srslte_coreset_t* coreset, + const srslte_search_space_t* search_space, + uint16_t rnti, + uint32_t aggregation_level, + uint32_t slot_idx, + uint32_t locations[SRSLTE_SEARCH_SPACE_MAX_NOF_CANDIDATES]); + +#endif // SRSLTE_PDCCH_NR_H diff --git a/lib/src/phy/ch_estimation/dmrs_pdcch.c b/lib/src/phy/ch_estimation/dmrs_pdcch.c index 68eab6263..75d77cc92 100644 --- a/lib/src/phy/ch_estimation/dmrs_pdcch.c +++ b/lib/src/phy/ch_estimation/dmrs_pdcch.c @@ -25,75 +25,13 @@ /// per frequency resource. #define NOF_PILOTS_X_FREQ_RES 18 -uint32_t srslte_pdcch_calculate_Y_p_n(uint32_t coreset_id, uint16_t rnti, int n) -{ - const uint32_t A_p[3] = {39827, 39829, 39839}; - const uint32_t D = 65537; - - if (n < 0) { - return rnti; - } - - return (A_p[coreset_id % 3] * srslte_pdcch_calculate_Y_p_n(coreset_id, rnti, n - 1)) % D; -} - -/** - * Calculates the Control Channnel Element As described in 3GPP 38.213 R15 10.1 UE procedure for determining physical - * downlink control channel assignment - * - */ -static int srslte_pdcch_get_ncce(const srslte_coreset_t* coreset, - const srslte_search_space_t* search_space, - uint16_t rnti, - uint32_t aggregation_level, - uint32_t candidate, - const uint32_t slot_idx) -{ - if (aggregation_level >= SRSLTE_SEARCH_SPACE_NOF_AGGREGATION_LEVELS) { - ERROR("Invalid aggregation level %d;\n", aggregation_level); - return SRSLTE_ERROR; - } - - uint32_t L = 1U << aggregation_level; // Aggregation level - uint32_t n_ci = 0; // Carrier indicator field - uint32_t m = candidate; // Selected PDDCH candidate - uint32_t M = search_space->nof_candidates[aggregation_level]; // Number of aggregation levels - - if (M == 0) { - ERROR("Invalid number of candidates %d for aggregation level %d\n", M, aggregation_level); - return SRSLTE_ERROR; - } - - // Count number of REG - uint32_t N_cce = 0; - for (uint32_t i = 0; i < SRSLTE_CORESET_FREQ_DOMAIN_RES_SIZE; i++) { - // Every frequency domain resource is 6 PRB, a REG is 1PRB wide and a CCE is 6 REG. So, for every frequency domain - // resource there is one CCE. - N_cce += coreset->freq_resources[i] ? coreset->duration : 0; - } - - if (N_cce < L) { - ERROR("Error number of CCE %d is lower than the aggregation level %d\n", N_cce, L); - return SRSLTE_ERROR; - } - - // Calculate Y_p_n - uint32_t Y_p_n = 0; - if (search_space->type == srslte_search_space_type_ue) { - Y_p_n = srslte_pdcch_calculate_Y_p_n(coreset->id, rnti, slot_idx); - } - - return (int)(L * ((Y_p_n + (m * N_cce) / (L * M) + n_ci) % (N_cce / L))); -} - static uint32_t dmrs_pdcch_get_cinit(uint32_t slot_idx, uint32_t symbol_idx, uint32_t n_id) { - return (uint32_t)((((SRSLTE_NR_NSYMB_PER_SLOT * slot_idx + symbol_idx + 1UL) << 17UL) * (2 * n_id + 1) + 2 * n_id) & + return (uint32_t)((((SRSLTE_NSYMB_PER_SLOT_NR * slot_idx + symbol_idx + 1UL) << 17UL) * (2 * n_id + 1) + 2 * n_id) & (uint64_t)INT32_MAX); } -static void -dmrs_pdcch_put_symbol_noninterleaved(const srslte_nr_pdcch_cfg_t* cfg, uint32_t cinit, uint32_t ncce, cf_t* sf_symbol) +static void dmrs_pdcch_put_symbol_noninterleaved(const srslte_pdcch_cfg_nr_t* cfg, uint32_t cinit, cf_t* sf_symbol) { uint32_t L = 1U << cfg->aggregation_level; uint32_t nof_freq_res = SRSLTE_MIN(cfg->carrier.nof_prb / 6, SRSLTE_CORESET_FREQ_DOMAIN_RES_SIZE); @@ -104,8 +42,8 @@ dmrs_pdcch_put_symbol_noninterleaved(const srslte_nr_pdcch_cfg_t* cfg, uint32_t uint32_t sequence_skip = 0; // Accumulates pilot locations to skip // Calculate Resource block indexes range, every CCE is 6 REG, 1 REG is 6 RE in resource blocks - uint32_t rb_coreset_idx_begin = (ncce * 6) / cfg->coreset.duration; - uint32_t rb_coreset_idx_end = ((ncce + L) * 6) / cfg->coreset.duration; + uint32_t rb_coreset_idx_begin = (cfg->n_cce * 6) / cfg->coreset.duration; + uint32_t rb_coreset_idx_end = ((cfg->n_cce + L) * 6) / cfg->coreset.duration; // CORESET Resource Block counter uint32_t rb_coreset_idx = 0; @@ -168,12 +106,10 @@ dmrs_pdcch_put_symbol_noninterleaved(const srslte_nr_pdcch_cfg_t* cfg, uint32_t } } -int srslte_dmrs_pdcch_put(const srslte_nr_pdcch_cfg_t* cfg, uint32_t slot_idx, cf_t* sf_symbols) +int srslte_dmrs_pdcch_put(const srslte_pdcch_cfg_nr_t* cfg, uint32_t slot_idx, cf_t* sf_symbols) { - int ncce = srslte_pdcch_get_ncce( - &cfg->coreset, &cfg->search_space, cfg->rnti, cfg->aggregation_level, cfg->candidate, slot_idx); - if (ncce < SRSLTE_SUCCESS) { - return SRSLTE_ERROR; + if (cfg == NULL || sf_symbols == NULL) { + return SRSLTE_ERROR_INVALID_INPUTS; } if (cfg->coreset.mapping_type == srslte_coreset_mapping_type_interleaved) { @@ -200,16 +136,20 @@ int srslte_dmrs_pdcch_put(const srslte_nr_pdcch_cfg_t* cfg, uint32_t slot_idx, c uint32_t cinit = dmrs_pdcch_get_cinit(slot_idx, l, n_id); // Put data - dmrs_pdcch_put_symbol_noninterleaved(cfg, cinit, ncce, &sf_symbols[cfg->carrier.nof_prb * SRSLTE_NRE * l]); + dmrs_pdcch_put_symbol_noninterleaved(cfg, cinit, &sf_symbols[cfg->carrier.nof_prb * SRSLTE_NRE * l]); } return SRSLTE_SUCCESS; } int srslte_dmrs_pdcch_estimator_init(srslte_dmrs_pdcch_estimator_t* q, - const srslte_nr_carrier_t* carrier, + const srslte_carrier_nr_t* carrier, const srslte_coreset_t* coreset) { + if (q == NULL || carrier == NULL || coreset == NULL) { + return SRSLTE_ERROR_INVALID_INPUTS; + } + if (coreset->duration < SRSLTE_CORESET_DURATION_MIN || coreset->duration > SRSLTE_CORESET_DURATION_MAX) { ERROR("Error CORESET duration %d is out-of-bounds (%d,%d)\n", coreset->duration, @@ -230,7 +170,11 @@ int srslte_dmrs_pdcch_estimator_init(srslte_dmrs_pdcch_estimator_t* q, q->coreset = *coreset; // The interpolator may return without reconfiguring after the first call - if (srslte_resampler_fft_init(&q->interpolator, SRSLTE_RESAMPLER_MODE_INTERPOLATE, 4)) { + if (q->interpolator.M != 0) { + srslte_interp_linear_free(&q->interpolator); + } + + if (srslte_interp_linear_init(&q->interpolator, srslte_coreset_get_bw(coreset) * 3, 4)) { ERROR("Initiating interpolator\n"); return SRSLTE_ERROR; } @@ -271,6 +215,10 @@ int srslte_dmrs_pdcch_estimator_init(srslte_dmrs_pdcch_estimator_t* q, void srslte_dmrs_pdcch_estimator_free(srslte_dmrs_pdcch_estimator_t* q) { + if (q == NULL) { + return; + } + if (q->ce) { free(q->ce); } @@ -281,7 +229,7 @@ void srslte_dmrs_pdcch_estimator_free(srslte_dmrs_pdcch_estimator_t* q) } } - srslte_resampler_fft_free(&q->interpolator); + srslte_interp_linear_free(&q->interpolator); memset(q, 0, sizeof(srslte_dmrs_pdcch_estimator_t)); } @@ -340,6 +288,10 @@ srslte_dmrs_pdcch_extract(srslte_dmrs_pdcch_estimator_t* q, uint32_t cinit, cons int srslte_dmrs_pdcch_estimate(srslte_dmrs_pdcch_estimator_t* q, uint32_t slot_idx, const cf_t* sf_symbols) { + if (q == NULL || sf_symbols == NULL) { + return SRSLTE_ERROR_INVALID_INPUTS; + } + // Saves slot index for posterior use q->slot_idx = slot_idx; @@ -358,32 +310,12 @@ int srslte_dmrs_pdcch_estimate(srslte_dmrs_pdcch_estimator_t* q, uint32_t slot_i srslte_dmrs_pdcch_extract(q, cinit, &sf_symbols[l * q->carrier.nof_prb * SRSLTE_NRE], q->lse[l]); } - // Time averaging should be implemented here + // Time averaging and smoothing should be implemented here // ... - // Interpolator impulse response - uint32_t interpolation_delay = srslte_resampler_fft_get_delay(&q->interpolator) / 4; - // Interpolation, it assumes all frequency domain resources are contiguous for (uint32_t l = 0; l < q->coreset.duration; l++) { - cf_t* ce_ptr = &q->ce[SRSLTE_NRE * q->coreset_bw * l]; - - srslte_resampler_fft_reset_state(&q->interpolator); - - // Feed inital samples - uint32_t discard_initial = SRSLTE_MIN(interpolation_delay, q->coreset_bw * 3); - srslte_resampler_fft_run(&q->interpolator, q->lse[l], NULL, discard_initial); - uint32_t n = 0; - - // Pad zeroes until impulsional response is covered - if (discard_initial < interpolation_delay) { - srslte_resampler_fft_run(&q->interpolator, NULL, NULL, interpolation_delay - discard_initial); - } else { - n = q->coreset_bw * 3 - discard_initial; - srslte_resampler_fft_run(&q->interpolator, q->lse[l], ce_ptr, n); - } - - srslte_resampler_fft_run(&q->interpolator, NULL, &ce_ptr[n * 4], q->coreset_bw * 3 - n); + srslte_interp_linear_offset(&q->interpolator, q->lse[l], &q->ce[SRSLTE_NRE * q->coreset_bw * l], 1, 3); } return SRSLTE_SUCCESS; @@ -393,16 +325,15 @@ int srslte_dmrs_pdcch_get_measure(srslte_dmrs_pdcch_estimator_t* q, const srslte_search_space_t* search_space, uint32_t slot_idx, uint32_t aggregation_level, - uint32_t candidate, + uint32_t ncce, uint16_t rnti, srslte_dmrs_pdcch_measure_t* measure) { - uint32_t L = 1U << aggregation_level; - int ncce = srslte_pdcch_get_ncce(&q->coreset, search_space, rnti, aggregation_level, candidate, slot_idx); - if (ncce < SRSLTE_SUCCESS) { - return SRSLTE_ERROR; + if (q == NULL || search_space == NULL || measure == NULL) { + return SRSLTE_ERROR_INVALID_INPUTS; } + uint32_t L = 1U << aggregation_level; if (q->coreset.mapping_type == srslte_coreset_mapping_type_interleaved) { ERROR("Error interleaved mapping not implemented\n"); return SRSLTE_ERROR; @@ -453,7 +384,7 @@ int srslte_dmrs_pdcch_get_measure(srslte_dmrs_pdcch_estimator_t* q, measure->epre = epre / (float)q->coreset.duration; measure->cfo_hz = cfo / (2.0f * (float)M_PI * Ts); measure->sync_error_us = - (float)SRSLTE_SUBC_SPACING(q->carrier.numerology) * sync_err / (4.0e-6f * (float)q->coreset.duration); + (float)SRSLTE_SUBC_SPACING_NR(q->carrier.numerology) * sync_err / (4.0e-6f * (float)q->coreset.duration); return SRSLTE_SUCCESS; } \ No newline at end of file diff --git a/lib/src/phy/ch_estimation/test/dmrs_pdcch_test.c b/lib/src/phy/ch_estimation/test/dmrs_pdcch_test.c index 7b2eaba69..866abb981 100644 --- a/lib/src/phy/ch_estimation/test/dmrs_pdcch_test.c +++ b/lib/src/phy/ch_estimation/test/dmrs_pdcch_test.c @@ -20,17 +20,15 @@ */ #include "srslte/common/test_common.h" -#include "srslte/srslte.h" +#include "srslte/phy/ch_estimation/dmrs_pdcch.h" +#include "srslte/phy/phch/pdcch_nr.h" #include -#include #include #include #include #include -static srslte_nr_carrier_t carrier = { - .nof_prb = 50, -}; +static srslte_carrier_nr_t carrier = {}; static uint16_t rnti = 0x1234; @@ -46,7 +44,7 @@ void usage(char* prog) printf("\t-v increase verbosity\n"); } -void parse_args(int argc, char** argv) +static void parse_args(int argc, char** argv) { int opt; while ((opt = getopt(argc, argv, "recov")) != -1) { @@ -67,34 +65,44 @@ void parse_args(int argc, char** argv) } } -static int -run_test(srslte_dmrs_pdcch_estimator_t* estimator, const srslte_nr_pdcch_cfg_t* cfg, cf_t* sf_symbols, cf_t* h) +static int run_test(srslte_dmrs_pdcch_estimator_t* estimator, srslte_pdcch_cfg_nr_t* cfg, cf_t* sf_symbols, cf_t* h) { - for (uint32_t slot_idx = 0; slot_idx < SRSLTE_NR_NSLOTS_PER_SF(cfg->carrier.numerology); slot_idx++) { - uint32_t nof_re = carrier.nof_prb * SRSLTE_NRE * SRSLTE_NR_NSYMB_PER_SLOT; - srslte_vec_cf_zero(sf_symbols, nof_re); - - TESTASSERT(srslte_dmrs_pdcch_put(cfg, slot_idx, sf_symbols) == SRSLTE_SUCCESS); - - TESTASSERT(srslte_dmrs_pdcch_estimate(estimator, slot_idx, sf_symbols) == SRSLTE_SUCCESS); - - srslte_dmrs_pdcch_measure_t measure = {}; - TESTASSERT( - srslte_dmrs_pdcch_get_measure( - estimator, &cfg->search_space, slot_idx, cfg->aggregation_level, cfg->candidate, cfg->rnti, &measure) == - SRSLTE_SUCCESS); - - if (fabsf(measure.rsrp - 1.0f) > 1e-2) { - printf("EPRE=%f; RSRP=%f; CFO=%f; SYNC_ERR=%f;\n", - measure.epre, - measure.rsrp, - measure.cfo_hz, - measure.sync_error_us); + for (uint32_t slot_idx = 0; slot_idx < SRSLTE_NSLOTS_PER_FRAME_NR(cfg->carrier.numerology); slot_idx++) { + uint32_t locations[SRSLTE_SEARCH_SPACE_MAX_NOF_CANDIDATES] = {}; + + int nof_locations = srslte_pdcch_nr_locations_ncce( + &cfg->coreset, &cfg->search_space, cfg->rnti, cfg->aggregation_level, slot_idx, locations); + + TESTASSERT(nof_locations == cfg->search_space.nof_candidates[cfg->aggregation_level]); + + for (uint32_t candidate = 0; candidate < nof_locations; candidate++) { + cfg->n_cce = locations[candidate]; + + uint32_t nof_re = carrier.nof_prb * SRSLTE_NRE * SRSLTE_NSYMB_PER_SLOT_NR; + srslte_vec_cf_zero(sf_symbols, nof_re); + + TESTASSERT(srslte_dmrs_pdcch_put(cfg, slot_idx, sf_symbols) == SRSLTE_SUCCESS); + + TESTASSERT(srslte_dmrs_pdcch_estimate(estimator, slot_idx, sf_symbols) == SRSLTE_SUCCESS); + + srslte_dmrs_pdcch_measure_t measure = {}; + TESTASSERT( + srslte_dmrs_pdcch_get_measure( + estimator, &cfg->search_space, slot_idx, cfg->aggregation_level, cfg->n_cce, cfg->rnti, &measure) == + SRSLTE_SUCCESS); + + if (fabsf(measure.rsrp - 1.0f) > 1e-2) { + printf("EPRE=%f; RSRP=%f; CFO=%f; SYNC_ERR=%f;\n", + measure.epre, + measure.rsrp, + measure.cfo_hz, + measure.sync_error_us); + } + TESTASSERT(fabsf(measure.epre - 1.0f) < 1e-3f); + TESTASSERT(fabsf(measure.rsrp - 1.0f) < 1e-3f); + TESTASSERT(fabsf(measure.cfo_hz) < 1e-3f); + TESTASSERT(fabsf(measure.sync_error_us) < 1e-3f); } - TESTASSERT(fabsf(measure.epre - 1.0f) < 1e-3f); - TESTASSERT(fabsf(measure.rsrp - 1.0f) < 1e-3f); - TESTASSERT(fabsf(measure.cfo_hz) < 1e-3f); - TESTASSERT(fabsf(measure.sync_error_us) < 1e-3f); } return SRSLTE_SUCCESS; @@ -104,12 +112,14 @@ int main(int argc, char** argv) { int ret = SRSLTE_ERROR; + carrier.nof_prb = 50; + parse_args(argc, argv); - srslte_nr_pdcch_cfg_t cfg = {}; + srslte_pdcch_cfg_nr_t cfg = {}; srslte_dmrs_pdcch_estimator_t estimator = {}; - uint32_t nof_re = carrier.nof_prb * SRSLTE_NRE * SRSLTE_NR_NSYMB_PER_SLOT; + uint32_t nof_re = carrier.nof_prb * SRSLTE_NRE * SRSLTE_NSYMB_PER_SLOT_NR; cf_t* sf_symbols = srslte_vec_cf_malloc(nof_re); cf_t* h = srslte_vec_cf_malloc(nof_re); @@ -139,24 +149,20 @@ int main(int argc, char** argv) uint32_t L = 1 << i; uint32_t nof_reg = cfg.coreset.duration * nof_freq_resources * 6; uint32_t nof_cce = nof_reg / 6; - cfg.search_space.nof_candidates[i] = nof_cce / L; + cfg.search_space.nof_candidates[i] = SRSLTE_MIN(nof_cce / L, SRSLTE_SEARCH_SPACE_MAX_NOF_CANDIDATES); } for (cfg.aggregation_level = 0; cfg.aggregation_level < SRSLTE_SEARCH_SPACE_NOF_AGGREGATION_LEVELS; cfg.aggregation_level++) { - for (cfg.candidate = 0; cfg.candidate < cfg.search_space.nof_candidates[cfg.aggregation_level]; - cfg.candidate++) { - - srslte_dmrs_pdcch_estimator_init(&estimator, &cfg.carrier, &cfg.coreset); + srslte_dmrs_pdcch_estimator_init(&estimator, &cfg.carrier, &cfg.coreset); - if (run_test(&estimator, &cfg, sf_symbols, h)) { - ERROR("Test %d failed\n", test_counter); - } else { - test_passed++; - } - test_counter++; + if (run_test(&estimator, &cfg, sf_symbols, h)) { + ERROR("Test %d failed\n", test_counter); + } else { + test_passed++; } + test_counter++; } } } diff --git a/lib/src/phy/common/phy_common_nr.c b/lib/src/phy/common/phy_common_nr.c index 163ed551b..0be023b8d 100644 --- a/lib/src/phy/common/phy_common_nr.c +++ b/lib/src/phy/common/phy_common_nr.c @@ -19,7 +19,7 @@ * */ -#include +#include "srslte/phy/common/phy_common_nr.h" uint32_t srslte_coreset_get_bw(const srslte_coreset_t* coreset) { @@ -27,7 +27,7 @@ uint32_t srslte_coreset_get_bw(const srslte_coreset_t* coreset) // Iterate all the frequency domain resources bit-map... for (uint32_t i = 0; i < SRSLTE_CORESET_FREQ_DOMAIN_RES_SIZE; i++) { - // ... and count 6 PRB for everu frequency domain resource that it is enabled + // ... and count 6 PRB for every frequency domain resource that it is enabled if (coreset->freq_resources[i]) { prb_count += 6; } diff --git a/lib/src/phy/phch/pdcch_nr.c b/lib/src/phy/phch/pdcch_nr.c new file mode 100644 index 000000000..17b399bbc --- /dev/null +++ b/lib/src/phy/phch/pdcch_nr.c @@ -0,0 +1,111 @@ +/* + * Copyright 2013-2020 Software Radio Systems Limited + * + * This file is part of srsLTE. + * + * srsLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#include "srslte/phy/phch/pdcch_nr.h" +#include "srslte/phy/utils/debug.h" +#include "srslte/phy/utils/vector.h" + +/** + * @brief Recursive Y_p_n function + */ +static uint32_t srslte_pdcch_calculate_Y_p_n(uint32_t coreset_id, uint16_t rnti, int n) +{ + static const uint32_t A_p[3] = {39827, 39829, 39839}; + const uint32_t D = 65537; + + if (n < 0) { + return rnti; + } + + return (A_p[coreset_id % 3] * srslte_pdcch_calculate_Y_p_n(coreset_id, rnti, n - 1)) % D; +} + +/** + * Calculates the Control Channnel Element As described in 3GPP 38.213 R15 10.1 UE procedure for determining physical + * downlink control channel assignment + * + */ +static int srslte_pdcch_nr_get_ncce(const srslte_coreset_t* coreset, + const srslte_search_space_t* search_space, + uint16_t rnti, + uint32_t aggregation_level, + uint32_t slot_idx, + uint32_t candidate) +{ + if (aggregation_level >= SRSLTE_SEARCH_SPACE_NOF_AGGREGATION_LEVELS) { + ERROR("Invalid aggregation level %d;\n", aggregation_level); + return SRSLTE_ERROR; + } + + uint32_t L = 1U << aggregation_level; // Aggregation level + uint32_t n_ci = 0; // Carrier indicator field + uint32_t m = candidate; // Selected PDDCH candidate + uint32_t M = search_space->nof_candidates[aggregation_level]; // Number of aggregation levels + + if (M == 0) { + ERROR("Invalid number of candidates %d for aggregation level %d\n", M, aggregation_level); + return SRSLTE_ERROR; + } + + // Every REG is 1PRB wide and a CCE is 6 REG. So, the number of N_CCE is a sixth of the bandwidth times the number of + // symbols + uint32_t N_cce = srslte_coreset_get_bw(coreset) * coreset->duration / 6; + + if (N_cce < L) { + ERROR("Error number of CCE %d is lower than the aggregation level %d\n", N_cce, L); + return SRSLTE_ERROR; + } + + // Calculate Y_p_n for UE search space only + uint32_t Y_p_n = 0; + if (search_space->type == srslte_search_space_type_ue) { + Y_p_n = srslte_pdcch_calculate_Y_p_n(coreset->id, rnti, slot_idx); + } + + return (int)(L * ((Y_p_n + (m * N_cce) / (L * M) + n_ci) % (N_cce / L))); +} + +int srslte_pdcch_nr_locations_ncce(const srslte_coreset_t* coreset, + const srslte_search_space_t* search_space, + uint16_t rnti, + uint32_t aggregation_level, + uint32_t slot_idx, + uint32_t locations[SRSLTE_SEARCH_SPACE_MAX_NOF_CANDIDATES]) +{ + if (coreset == NULL || search_space == NULL) { + return SRSLTE_ERROR_INVALID_INPUTS; + } + + uint32_t nof_candidates = search_space->nof_candidates[aggregation_level]; + + nof_candidates = SRSLTE_MIN(nof_candidates, SRSLTE_SEARCH_SPACE_MAX_NOF_CANDIDATES); + + for (uint32_t candidate = 0; candidate < nof_candidates; candidate++) { + int ret = srslte_pdcch_nr_get_ncce(coreset, search_space, rnti, aggregation_level, slot_idx, candidate); + if (ret < SRSLTE_SUCCESS) { + return ret; + } + + locations[candidate] = ret; + } + + return nof_candidates; +}