Added PDCCH NR interleaved mapping

master
Xavier Arteaga 3 years ago committed by Xavier Arteaga
parent d61d6aa59f
commit f5f18054eb

@ -405,18 +405,19 @@ typedef struct SRSRAN_API {
* @brief CORESET parameters as defined in TS 38.331 V15.10.0 - ControlResourceSet
*/
typedef struct SRSRAN_API {
uint32_t id;
srsran_coreset_mapping_type_t mapping_type;
uint32_t duration;
bool freq_resources[SRSRAN_CORESET_FREQ_DOMAIN_RES_SIZE];
srsran_coreset_bundle_size_t interleaver_size;
uint32_t offset_rb; ///< Integer offset in resource blocks from the pointA (lowest subcarrier of resource grid) to the
///< lowest resource block of the CORESET region (used by CORESET Zero only)
uint32_t id;
srsran_coreset_mapping_type_t mapping_type;
uint32_t duration;
bool freq_resources[SRSRAN_CORESET_FREQ_DOMAIN_RES_SIZE];
bool dmrs_scrambling_id_present;
uint32_t dmrs_scrambling_id;
srsran_coreset_precoder_granularity_t precoder_granularity;
srsran_coreset_bundle_size_t reg_bundle_size;
srsran_coreset_bundle_size_t interleaver_size; ///< Referenced in TS 38.211 section 7.3.2.2 as R
srsran_coreset_bundle_size_t reg_bundle_size; ///< Referenced in TS 38.211 section 7.3.2.2 as L
uint32_t shift_index;
uint32_t offset_rb; ///< Integer offset in resource blocks from the pointA (lowest subcarrier of resource grid) to the
///< lowest resource block of the CORESET region (used by CORESET Zero only)
/** Missing TCI parameters */
} srsran_coreset_t;
@ -622,14 +623,16 @@ SRSRAN_API void srsran_combine_csi_trs_measurements(const srsran_csi_trs_measure
/**
* @brief Setup CORESET Zero from a configuration index
* @remark Defined by TS 38.213 tables 13-1, 13-2, 13-3, 13-4, 13-5, 13-6, 13-7, 13-8, 13-9, 13-10
* @param n_cell_id Physical Cell identifier
* @param ssb_pointA_freq_offset_Hz Integer frequency offset in Hz between the SS/PBCH block center and pointA
* @param ssb_scs SS/PBCH block subcarrier spacing
* @param pdcch_scs PDCCH subcarrier spacing
* @param idx CORESET Zero configuration index
* @param[out] coreset Points to the resultant CORESET
* @return SRSLTE_SUCCESS if the given inputs lead to a valid CORESET configuration, otherise SRSLTE_ERROR code
* @return SRSRAN_SUCCESS if the given inputs lead to a valid CORESET configuration, otherise SRSRAN_ERROR code
*/
SRSRAN_API int srsran_coreset_zero(uint32_t ssb_pointA_freq_offset_Hz,
SRSRAN_API int srsran_coreset_zero(uint32_t n_cell_id,
uint32_t ssb_pointA_freq_offset_Hz,
srsran_subcarrier_spacing_t ssb_scs,
srsran_subcarrier_spacing_t pdcch_scs,
uint32_t idx,

@ -98,6 +98,17 @@ int srsran_pdcch_nr_locations_coreset(const srsran_coreset_t* coreset,
SRSRAN_API int srsran_pdcch_nr_max_candidates_coreset(const srsran_coreset_t* coreset, uint32_t aggregation_level);
/**
* @brief Function for generating a RB mask indicating the CCE-to-REG mapping
* @param coreset A given CORESET
* @param dci_location The DCI location for the PDCCH transmission
* @param[out] rb_mask The resultant mask indicating the locations of PDCCH payload
* @return SRSRAN_SUCCESS if the provided parameters are valid, SRSRAN_ERROR code otherwise
*/
SRSRAN_API int srsran_pdcch_nr_cce_to_reg_mapping(const srsran_coreset_t* coreset,
const srsran_dci_location_t* dci_location,
bool rb_mask[SRSRAN_MAX_PRB_NR]);
SRSRAN_API int srsran_pdcch_nr_init_tx(srsran_pdcch_nr_t* q, const srsran_pdcch_nr_args_t* args);
SRSRAN_API int srsran_pdcch_nr_init_rx(srsran_pdcch_nr_t* q, const srsran_pdcch_nr_args_t* args);

@ -478,7 +478,8 @@ static const coreset_zero_entry_t coreset_zero_30_15[16] = {
{},
};
int srsran_coreset_zero(uint32_t ssb_pointA_freq_offset_Hz,
int srsran_coreset_zero(uint32_t n_cell_id,
uint32_t ssb_pointA_freq_offset_Hz,
srsran_subcarrier_spacing_t ssb_scs,
srsran_subcarrier_spacing_t pdcch_scs,
uint32_t idx,
@ -545,10 +546,16 @@ int srsran_coreset_zero(uint32_t ssb_pointA_freq_offset_Hz,
// Set CORESET fields
coreset->id = 0;
coreset->dmrs_scrambling_id_present = false;
coreset->mapping_type = srsran_coreset_mapping_type_non_interleaved;
coreset->duration = entry->nof_symb;
coreset->offset_rb = offset_rb;
// Set CCE-to-REG mapping according to TS 38.211 section 7.3.2.2
coreset->mapping_type = srsran_coreset_mapping_type_interleaved;
coreset->reg_bundle_size = srsran_coreset_bundle_size_n6;
coreset->interleaver_size = srsran_coreset_bundle_size_n2;
coreset->precoder_granularity = srsran_coreset_precoder_granularity_reg_bundle;
coreset->shift_index = n_cell_id;
// Set CORESET frequency resource mask
for (uint32_t i = 0; i < SRSRAN_CORESET_FREQ_DOMAIN_RES_SIZE; i++) {
coreset->freq_resources[i] = (i < (entry->nof_prb / 6));

@ -304,6 +304,106 @@ int srsran_pdcch_nr_set_carrier(srsran_pdcch_nr_t* q,
return SRSRAN_SUCCESS;
}
static uint32_t pdcch_nr_bundle_size(srsran_coreset_bundle_size_t x)
{
switch (x) {
case srsran_coreset_bundle_size_n2:
return 2;
case srsran_coreset_bundle_size_n3:
return 3;
case srsran_coreset_bundle_size_n6:
return 6;
}
return 0;
}
static int pdcch_nr_cce_to_reg_mapping_non_interleaved(const srsran_coreset_t* coreset,
const srsran_dci_location_t* dci_location,
bool rb_mask[SRSRAN_MAX_PRB_NR])
{
uint32_t nof_cce = 1U << dci_location->L;
uint32_t L = 6;
uint32_t nof_reg_bundle = 6 / L;
// For each CCE j in the PDCCH transmission
for (uint32_t j = dci_location->ncce; j < dci_location->ncce + nof_cce; j++) {
// For each REG bundle i in the CCE j
for (uint32_t reg_bundle = 0; reg_bundle < nof_reg_bundle; reg_bundle++) {
// Calculate x variable
uint32_t x = (6 * j) / L + reg_bundle;
// For non interleaved f(x) = x
uint32_t i = x;
// For each REG in the REG bundle
for (uint32_t reg = 0; reg < L; reg++) {
rb_mask[(i * L + reg) / coreset->duration] = true;
}
}
}
return SRSRAN_SUCCESS;
}
static int pdcch_nr_cce_to_reg_mapping_interleaved(const srsran_coreset_t* coreset,
const srsran_dci_location_t* dci_location,
bool rb_mask[SRSRAN_MAX_PRB_NR])
{
// Calculate CORESET constants
uint32_t N_CORESET_REG = coreset->duration * srsran_coreset_get_bw(coreset);
uint32_t L = pdcch_nr_bundle_size(coreset->reg_bundle_size);
uint32_t R = pdcch_nr_bundle_size(coreset->interleaver_size);
uint32_t C = N_CORESET_REG / (L * R);
uint32_t n_shift = coreset->shift_index;
// Validate
if (N_CORESET_REG == 0 || N_CORESET_REG % (L * R) != 0 || L % coreset->duration != 0) {
ERROR("Invalid CORESET configuration N=%d; L=%d; R=%d;", N_CORESET_REG, L, R);
return 0;
}
uint32_t nof_cce = 1U << dci_location->L;
uint32_t nof_reg_bundle = 6 / L;
// For each CCE j in the PDCCH transmission
for (uint32_t j = dci_location->ncce; j < dci_location->ncce + nof_cce; j++) {
// For each REG bundle i in the CCE j
for (uint32_t reg_bundle = 0; reg_bundle < nof_reg_bundle; reg_bundle++) {
// Calculate x variable
uint32_t x = (6 * j) / L + reg_bundle;
// For non interleaved f(x) = x
uint32_t r = x % R;
uint32_t c = x / R;
uint32_t i = (r * C + c + n_shift) % (N_CORESET_REG / L);
// For each REG in the REG bundle i
for (uint32_t reg = 0; reg < L; reg++) {
rb_mask[(i * L + reg) / coreset->duration] = true;
}
}
}
return SRSRAN_SUCCESS;
}
int srsran_pdcch_nr_cce_to_reg_mapping(const srsran_coreset_t* coreset,
const srsran_dci_location_t* dci_location,
bool rb_mask[SRSRAN_MAX_PRB_NR])
{
if (coreset == NULL || dci_location == NULL) {
return SRSRAN_ERROR_INVALID_INPUTS;
}
// Non-interleaved case
if (coreset->mapping_type == srsran_coreset_mapping_type_non_interleaved) {
return pdcch_nr_cce_to_reg_mapping_non_interleaved(coreset, dci_location, rb_mask);
}
// Interleaved case
return pdcch_nr_cce_to_reg_mapping_interleaved(coreset, dci_location, rb_mask);
}
static uint32_t pdcch_nr_cp(const srsran_pdcch_nr_t* q,
const srsran_dci_location_t* dci_location,
cf_t* slot_grid,
@ -311,27 +411,44 @@ static uint32_t pdcch_nr_cp(const srsran_pdcch_nr_t* q,
bool put)
{
uint32_t offset_k = q->coreset.offset_rb * SRSRAN_NRE;
uint32_t L = 1U << dci_location->L;
// Calculate begin and end sub-carrier index for the selected candidate
uint32_t k_begin = (dci_location->ncce * SRSRAN_NRE * 6) / q->coreset.duration;
uint32_t k_end = k_begin + (L * 6 * SRSRAN_NRE) / q->coreset.duration;
// Compute REG list
bool rb_mask[SRSRAN_MAX_PRB_NR] = {};
if (srsran_pdcch_nr_cce_to_reg_mapping(&q->coreset, dci_location, rb_mask) < SRSRAN_SUCCESS) {
return 0;
}
uint32_t count = 0;
// Iterate over symbols
for (uint32_t l = 0; l < q->coreset.duration; l++) {
// Iterate over frequency resource groups
uint32_t k = 0;
uint32_t rb = 0;
for (uint32_t r = 0; r < SRSRAN_CORESET_FREQ_DOMAIN_RES_SIZE; r++) {
if (q->coreset.freq_resources[r]) {
for (uint32_t i = r * 6 * SRSRAN_NRE; i < (r + 1) * 6 * SRSRAN_NRE; i++, k++) {
if (k >= k_begin && k < k_end && k % 4 != 1) {
if (put) {
slot_grid[q->carrier.nof_prb * SRSRAN_NRE * l + i + offset_k] = symbols[count++];
} else {
symbols[count++] = slot_grid[q->carrier.nof_prb * SRSRAN_NRE * l + i + offset_k];
}
// Skip frequency resource if not set
if (!q->coreset.freq_resources[r]) {
continue;
}
// For each RB in the frequency resource
for (uint32_t i = r * 6; i < (r + 1) * 6; i++, rb++) {
// Skip if this RB is not marked as mapped
if (!rb_mask[rb]) {
continue;
}
// For each RE in the RB
for (uint32_t k = i * SRSRAN_NRE; k < (i + 1) * SRSRAN_NRE; k++) {
// Skip if it is a DMRS
if (k % 4 == 1) {
continue;
}
// Read or write in the grid
if (put) {
slot_grid[q->carrier.nof_prb * SRSRAN_NRE * l + k + offset_k] = symbols[count++];
} else {
symbols[count++] = slot_grid[q->carrier.nof_prb * SRSRAN_NRE * l + k + offset_k];
}
}
}

@ -663,4 +663,5 @@ add_nr_test(pusch_nr_ack20_csi4_test pusch_nr_test -p 50 -m 20 -A 20 -C 4)
add_executable(pdcch_nr_test pdcch_nr_test.c)
target_link_libraries(pdcch_nr_test srsran_phy)
add_nr_test(pdcch_nr_test pdcch_nr_test)
add_nr_test(pdcch_nr_test_non_interleaved pdcch_nr_test)
add_nr_test(pdcch_nr_test_interleaved pdcch_nr_test -I)

@ -26,8 +26,9 @@ static srsran_carrier_nr_t carrier = {
1 // max_mimo_layers
};
static uint16_t rnti = 0x1234;
static bool fast_sweep = true;
static uint16_t rnti = 0x1234;
static bool fast_sweep = true;
static bool interleaved = false;
typedef struct {
uint64_t time_us;
@ -69,16 +70,17 @@ static int test(srsran_pdcch_nr_t* tx,
static void usage(char* prog)
{
printf("Usage: %s [pFv] \n", prog);
printf("Usage: %s [pFIv] \n", prog);
printf("\t-p Number of carrier PRB [Default %d]\n", carrier.nof_prb);
printf("\t-F Fast CORESET frequency resource sweeping [Default %s]\n", fast_sweep ? "Enabled" : "Disabled");
printf("\t-I Enable interleaved CCE-to-REG [Default %s]\n", interleaved ? "Enabled" : "Disabled");
printf("\t-v [set srsran_verbose to debug, default none]\n");
}
static int parse_args(int argc, char** argv)
{
int opt;
while ((opt = getopt(argc, argv, "pFv")) != -1) {
while ((opt = getopt(argc, argv, "pFIv")) != -1) {
switch (opt) {
case 'p':
carrier.nof_prb = (uint32_t)strtol(argv[optind], NULL, 10);
@ -86,6 +88,9 @@ static int parse_args(int argc, char** argv)
case 'F':
fast_sweep ^= true;
break;
case 'I':
interleaved ^= true;
break;
case 'v':
srsran_verbose++;
break;
@ -135,16 +140,34 @@ int main(int argc, char** argv)
goto clean_exit;
}
srsran_coreset_t coreset = {};
uint32_t nof_frequency_resource = SRSRAN_MIN(SRSRAN_CORESET_FREQ_DOMAIN_RES_SIZE, carrier.nof_prb / 6);
srsran_coreset_t coreset = {};
if (interleaved) {
coreset.mapping_type = srsran_coreset_mapping_type_interleaved;
coreset.reg_bundle_size = srsran_coreset_bundle_size_n6;
coreset.interleaver_size = srsran_coreset_bundle_size_n2;
coreset.precoder_granularity = srsran_coreset_precoder_granularity_reg_bundle;
coreset.shift_index = carrier.pci;
carrier.nof_prb = 52;
carrier.pci = 500;
}
uint32_t nof_frequency_resource = SRSRAN_MIN(SRSRAN_CORESET_FREQ_DOMAIN_RES_SIZE, carrier.nof_prb / 6);
for (uint32_t frequency_resources = 1; frequency_resources < (1U << nof_frequency_resource);
frequency_resources = (fast_sweep) ? ((frequency_resources << 1U) | 1U) : (frequency_resources + 1)) {
for (uint32_t i = 0; i < nof_frequency_resource; i++) {
uint32_t mask = ((frequency_resources >> i) & 1U);
coreset.freq_resources[i] = (mask == 1);
}
for (coreset.duration = SRSRAN_CORESET_DURATION_MIN; coreset.duration <= SRSRAN_CORESET_DURATION_MAX;
coreset.duration++) {
// Skip case if CORESET bandwidth is not enough
uint32_t N = srsran_coreset_get_bw(&coreset) * coreset.duration;
if (interleaved && N % 12 != 0) {
continue;
}
srsran_search_space_t search_space = {};
search_space.type = srsran_search_space_type_ue;
search_space.formats[search_space.nof_formats++] = srsran_dci_format_nr_0_0;

Loading…
Cancel
Save