Initial implementation of the 5G NR PDCCH DMRS encoding

This commit is contained in:
Xavier Arteaga 2020-09-28 16:48:24 +02:00 committed by Xavier Arteaga
parent 579526f1fe
commit 29ad2427d9
5 changed files with 523 additions and 0 deletions

View File

@ -0,0 +1,39 @@
/*
* 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/.
*
*/
#ifndef SRSLTE_DMRS_PDCCH_H
#define SRSLTE_DMRS_PDCCH_H
#ifdef __cplusplus
extern "C" {
#endif
#include "srslte/phy/common/phy_common_nr.h"
#include "srslte/srslte.h"
SRSLTE_API int
srslte_dmrs_pdcch_put(const srslte_nr_pdcch_cfg_t* cfg, const srslte_dl_sf_cfg_t* dl_sf, cf_t* sf_symbols);
#ifdef __cplusplus
}
#endif
#endif // SRSLTE_DMRS_PDCCH_H

View File

@ -0,0 +1,147 @@
/*
* 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/.
*
*/
#ifndef SRSLTE_PHY_COMMON_NR_H
#define SRSLTE_PHY_COMMON_NR_H
#include "phy_common.h"
#include <inttypes.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @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
/**
* @brief Defines the maximum numerology supported. Defined by TS 38.211 v15.8.0 Table 4.3.2-1.
*/
#define SRSLTE_NR_MAX_NUMEROLOGY 4
/**
* @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))
/**
* @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)
/**
* @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
/**
* @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_NR_MAX_START 2199
/**
* Common carrier parameters
*/
typedef struct {
uint32_t id;
uint32_t numerology;
uint32_t nof_prb;
uint32_t start;
} srslte_nr_carrier_t;
/**
* CORESET related constants
*/
#define SRSLTE_CORESET_DURATION_MIN 1
#define SRSLTE_CORESET_DURATION_MAX 3
#define SRSLTE_CORESET_FREQ_DOMAIN_RES_SIZE 45
#define SRSLTE_CORESET_SHIFT_INDEX_MAX (SRSLTE_CORESET_NOF_PRB_MAX - 1)
typedef enum {
srslte_coreset_mapping_type_interleaved = 0,
srslte_coreset_mapping_type_non_interleaved,
} srslte_coreset_mapping_type_t;
typedef enum {
srslte_coreset_bundle_size_n2 = 0,
srslte_coreset_bundle_size_n3,
srslte_coreset_bundle_size_n6,
} srslte_coreset_bundle_size_t;
typedef enum {
srslte_coreset_precoder_granularity_contiguous = 0,
srslte_coreset_precoder_granularity_reg_bundle
} srslte_coreset_precoder_granularity_t;
/**
* CORESET structure
*
* Fields follow the same order than described in 3GPP 38.331 R15 - ControlResourceSet
*
*/
typedef struct {
srslte_coreset_mapping_type_t mapping_type;
uint32_t id;
uint32_t duration;
bool freq_domain_resources[SRSLTE_CORESET_FREQ_DOMAIN_RES_SIZE];
srslte_coreset_bundle_size_t interleaver_size;
bool dmrs_scrambling_id_present;
uint32_t dmrs_scrambling_id;
srslte_coreset_precoder_granularity_t precoder_granularity;
srslte_coreset_bundle_size_t reg_bundle_size;
uint32_t shift_index;
/** Missing TCI parameters */
} srslte_coreset_t;
typedef enum {
srslte_search_space_type_common = 0,
srslte_search_space_type_ue,
} srslte_search_space_type_t;
#define SRSLTE_SEARCH_SPACE_NOF_AGGREGATION_LEVELS 5
typedef struct {
uint32_t start; // start symbol within slot
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_nr_carrier_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;
#ifdef __cplusplus
}
#endif
#endif // SRSLTE_PHY_COMMON_NR_H

View File

@ -0,0 +1,163 @@
/*
* 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/ch_estimation/dmrs_pdcch.h"
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
*
*/
int srslte_pdcch_get_ncce(const srslte_nr_pdcch_cfg_t* cfg, const srslte_dl_sf_cfg_t* dl_sf)
{
if (cfg->aggregation_level >= SRSLTE_SEARCH_SPACE_NOF_AGGREGATION_LEVELS) {
ERROR("Invalid aggregation level %d;\n", cfg->aggregation_level);
return SRSLTE_ERROR;
}
uint32_t L = 1U << cfg->aggregation_level; // Aggregation level
uint32_t n_ci = 0; // Carrier indicator field
uint32_t m = cfg->candidate; // Selected PDDCH candidate
uint32_t M = cfg->search_space.nof_candidates[cfg->aggregation_level]; // Number of aggregation levels
if (M == 0) {
ERROR("Invalid number of candidates %d for aggregation level %d\n", M, cfg->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++) {
N_cce += cfg->coreset.freq_domain_resources[i] ? cfg->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 (cfg->search_space.type == srslte_search_space_type_ue) {
Y_p_n = srslte_pdcch_calculate_Y_p_n(
cfg->coreset.id, cfg->rnti, dl_sf->tti % SRSLTE_NR_NSLOTS_PER_FRAME(cfg->carrier.numerology));
}
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) &
(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)
{
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);
// Initialise sequence for this symbol
srslte_sequence_state_t sequence_state = {};
srslte_sequence_state_init(&sequence_state, cinit);
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;
// CORESET Resource Block counter
uint32_t rb_coreset_idx = 0;
for (uint32_t i = 0; i < nof_freq_res; i++) {
// Every frequency resource is 6 Resource blocks, every resource block carries 3 pilots. So 18 possible pilots per
// frequency resource.
const uint32_t nof_pilots_x_resource = 18;
// Skip frequency resource if outside of the CORESET
if (!cfg->coreset.freq_domain_resources[i]) {
// Skip possible DMRS locations in this region
sequence_skip += nof_pilots_x_resource;
continue;
}
// Skip if the frequency resource highest RB is lower than the first CCE resource block.
if ((rb_coreset_idx + 6) <= rb_coreset_idx_begin) {
// Skip possible DMRS locations in this region
sequence_skip += nof_pilots_x_resource;
// Since this is part of the CORESET, count the RB as CORESET
rb_coreset_idx += 6;
continue;
}
// Return if the first RB of the frequency resource is greater than the last CCE resource block
if (rb_coreset_idx > rb_coreset_idx_end) {
return;
}
// Skip all discarded possible pilot locations
srslte_sequence_state_advance(&sequence_state, 2 * sequence_skip);
sequence_skip = 0;
// Generate pilots
cf_t rl[nof_pilots_x_resource];
srslte_sequence_state_gen_f(&sequence_state, M_SQRT1_2, (float*)rl, nof_pilots_x_resource * 2);
// For each RB in the frequency resource
for (uint32_t j = 0; j < 6; j++) {
// Calculate absolute RB index
uint32_t n = i * 6 + j;
// Skip if lower than begin
if (rb_coreset_idx < rb_coreset_idx_begin) {
rb_coreset_idx++;
continue;
}
// Return if greater than end
if (rb_coreset_idx >= rb_coreset_idx_end) {
return;
}
// Write pilots in the symbol
for (uint32_t k_prime = 0; k_prime < 3; k_prime++) {
// Calculate sub-carrier index
uint32_t k = n * SRSLTE_NRE + 4 * k_prime + 1;
sf_symbol[k] = rl[(3 * n + k_prime) % nof_pilots_x_resource];
}
rb_coreset_idx++;
}
}
}

View File

@ -89,3 +89,14 @@ add_executable(dmrs_pdsch_test dmrs_pdsch_test.c)
target_link_libraries(dmrs_pdsch_test srslte_phy)
add_test(dmrs_pdsch_test dmrs_pdsch_test)
########################################################################
# NR PDSCH DMRS Channel Estimation TEST
########################################################################
add_executable(dmrs_pdcch_test dmrs_pdcch_test.c)
target_link_libraries(dmrs_pdcch_test srslte_phy)
add_test(dmrs_pdcch_test dmrs_pdcch_test)

View File

@ -0,0 +1,163 @@
/*
* 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/common/test_common.h"
#include "srslte/srslte.h"
#include <complex.h>
#include <srslte/phy/ch_estimation/dmrs_pdcch.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <unistd.h>
static srslte_nr_carrier_t carrier = {
.nof_prb = 50,
};
static uint16_t rnti = 0x1234;
void usage(char* prog)
{
printf("Usage: %s [recov]\n", prog);
printf("\t-r nof_prb [Default %d]\n", carrier.nof_prb);
printf("\t-e extended cyclic prefix [Default normal]\n");
printf("\t-c cell_id [Default %d]\n", carrier.id);
printf("\t-v increase verbosity\n");
}
void parse_args(int argc, char** argv)
{
int opt;
while ((opt = getopt(argc, argv, "recov")) != -1) {
switch (opt) {
case 'r':
carrier.nof_prb = (uint32_t)strtol(argv[optind], NULL, 10);
break;
case 'c':
carrier.id = (uint32_t)strtol(argv[optind], NULL, 10);
break;
case 'v':
srslte_verbose++;
break;
default:
usage(argv[0]);
exit(-1);
}
}
}
static int run_test(const srslte_nr_pdcch_cfg_t* cfg, cf_t* sf_symbols, cf_t* h)
{
srslte_dl_sf_cfg_t dl_sf = {};
for (dl_sf.tti = 0; dl_sf.tti < SRSLTE_NOF_SF_X_FRAME; dl_sf.tti++) {
TESTASSERT(srslte_dmrs_pdcch_put(cfg, &dl_sf, sf_symbols) == SRSLTE_SUCCESS);
/*srslte_dmrs_pdsch_get_sf(cfg, &dl_sf, sf_symbols, h);
float mse = 0.0f;
for (uint32_t i = 0; i < dmrs_pdsch->nof_symbols * dmrs_pdsch->nof_sc * SRSLTE_NRE; i++) {
cf_t err = h[i] - 1.0f;
mse += cabsf(err);
}
mse /= (float)dmrs_pdsch->nof_symbols * dmrs_pdsch->nof_sc;
TESTASSERT(!isnan(mse));
TESTASSERT(mse < 1e-6f);*/
}
return SRSLTE_SUCCESS;
}
int main(int argc, char** argv)
{
int ret = SRSLTE_ERROR;
parse_args(argc, argv);
srslte_nr_pdcch_cfg_t cfg = {};
uint32_t nof_re = carrier.nof_prb * SRSLTE_NRE * SRSLTE_NOF_SLOTS_PER_SF * SRSLTE_MAX_NSYMB;
cf_t* sf_symbols = srslte_vec_cf_malloc(nof_re);
cf_t* h = srslte_vec_cf_malloc(nof_re);
uint32_t test_counter = 0;
uint32_t test_passed = 0;
cfg.carrier = carrier;
cfg.rnti = rnti;
cfg.coreset.mapping_type = srslte_coreset_mapping_type_non_interleaved;
uint32_t nof_frequency_resource = SRSLTE_MIN(SRSLTE_CORESET_FREQ_DOMAIN_RES_SIZE, carrier.nof_prb / 6);
for (uint32_t frequency_resources = 1; frequency_resources < (1U << nof_frequency_resource); frequency_resources++) {
uint32_t nof_freq_resources = 0;
for (uint32_t i = 0; i < nof_frequency_resource; i++) {
uint32_t mask = ((frequency_resources >> i) & 1U);
cfg.coreset.freq_domain_resources[i] = (mask == 1);
nof_freq_resources += mask;
}
for (cfg.coreset.duration = 1; cfg.coreset.duration <= 3; cfg.coreset.duration++) {
for (cfg.search_space.type = srslte_search_space_type_common;
cfg.search_space.type <= srslte_search_space_type_ue;
cfg.search_space.type++) {
for (uint32_t i = 0; i < SRSLTE_SEARCH_SPACE_NOF_AGGREGATION_LEVELS; i++) {
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;
}
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++) {
if (run_test(&cfg, sf_symbols, h)) {
ERROR("Test %d failed\n", test_counter);
} else {
test_passed++;
}
test_counter++;
}
}
}
}
}
if (sf_symbols) {
free(sf_symbols);
}
if (h) {
free(h);
}
ret = test_passed == test_counter ? SRSLTE_SUCCESS : SRSLTE_ERROR;
printf("%s, %d of %d test passed successfully.\n", ret ? "Failed" : "Passed", test_passed, test_counter);
return ret;
}