mirror of https://github.com/PentHertz/srsLTE.git
Rearanged PDCCH NR functions structures
This commit is contained in:
parent
452eb2dbbf
commit
775692f461
|
@ -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);
|
||||
|
||||
/**
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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 <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 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);
|
||||
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] = {};
|
||||
|
||||
TESTASSERT(srslte_dmrs_pdcch_put(cfg, slot_idx, sf_symbols) == SRSLTE_SUCCESS);
|
||||
int nof_locations = srslte_pdcch_nr_locations_ncce(
|
||||
&cfg->coreset, &cfg->search_space, cfg->rnti, cfg->aggregation_level, slot_idx, locations);
|
||||
|
||||
TESTASSERT(srslte_dmrs_pdcch_estimate(estimator, slot_idx, sf_symbols) == SRSLTE_SUCCESS);
|
||||
TESTASSERT(nof_locations == cfg->search_space.nof_candidates[cfg->aggregation_level]);
|
||||
|
||||
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);
|
||||
for (uint32_t candidate = 0; candidate < nof_locations; candidate++) {
|
||||
cfg->n_cce = locations[candidate];
|
||||
|
||||
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);
|
||||
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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <srslte/phy/common/phy_common_nr.h>
|
||||
#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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
Loading…
Reference in New Issue