mirror of https://github.com/PentHertz/srsLTE.git
Initial PDCCH encode/decode
This commit is contained in:
parent
159a3d84bd
commit
53f6ac118e
|
@ -28,12 +28,18 @@ extern "C" {
|
|||
*
|
||||
* @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[in] carrier Provides carrier configuration
|
||||
* @param[in] coreset Provides higher layer CORSET configuration
|
||||
* @param[in] slot_cfg Provides DL slot configuration
|
||||
* @param[in] dci_location Provides DCI location
|
||||
* @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_pdcch_cfg_nr_t* cfg, uint32_t slot_idx, cf_t* sf_symbols);
|
||||
SRSLTE_API int srslte_dmrs_pdcch_put(const srslte_carrier_nr_t* carrier,
|
||||
const srslte_coreset_t* coreset,
|
||||
const srslte_dl_slot_cfg_t* slot_cfg,
|
||||
const srslte_dci_location_t* dci_location,
|
||||
cf_t* sf_symbols);
|
||||
|
||||
/**
|
||||
* @brief PDCCH DMRS channel estimator object
|
||||
|
@ -65,9 +71,6 @@ typedef struct SRSLTE_API {
|
|||
|
||||
/// Channel estimates, size coreset_sz
|
||||
cf_t* ce;
|
||||
|
||||
/// Stores latest slot index in frame
|
||||
uint32_t slot_idx;
|
||||
} srslte_dmrs_pdcch_estimator_t;
|
||||
|
||||
/**
|
||||
|
@ -77,9 +80,9 @@ typedef struct SRSLTE_API {
|
|||
* \attention Initialization is required every time the carrier and/or CORESET changes. No free is required between
|
||||
* initializations.
|
||||
*
|
||||
* @param q provides PDCCH DMRS estimator object
|
||||
* @param carrier provides the required carrier configuration for some estimation
|
||||
* @param coreset provides the required configuration for initialising the object
|
||||
* @param[in,out] q provides PDCCH DMRS estimator object
|
||||
* @param[in] carrier Provides carrier configuration
|
||||
* @param[in] coreset Provides higher layer CORSET configuration
|
||||
* @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,
|
||||
|
@ -101,13 +104,14 @@ SRSLTE_API void srslte_dmrs_pdcch_estimator_free(srslte_dmrs_pdcch_estimator_t*
|
|||
* The channel estimate measurements are performed at PDCCH candidate level through the function
|
||||
* srslte_dmrs_pdcch_estimator_measure.
|
||||
*
|
||||
* @param cfg Configuration that includes Carrier, CORESET and the Search Space
|
||||
* @param slot_idx Slot index in the frame
|
||||
* @param sf_symbols Received resource grid.
|
||||
* @param estimates CORESET Resource grid with the estimated channel
|
||||
* @param[in,out] cfg Configuration that includes Carrier, CORESET and the Search Space
|
||||
* @param[in] slot_cfg Slot index in the frame
|
||||
* @param[in] sf_symbols Received resource grid.
|
||||
* @return SRSLTE_SUCCESS if the configurations are valid, otherwise it returns an SRSLTE_ERROR code
|
||||
*/
|
||||
SRSLTE_API int srslte_dmrs_pdcch_estimate(srslte_dmrs_pdcch_estimator_t* q, uint32_t slot_idx, const cf_t* sf_symbols);
|
||||
SRSLTE_API int srslte_dmrs_pdcch_estimate(srslte_dmrs_pdcch_estimator_t* q,
|
||||
const srslte_dl_slot_cfg_t* slot_cfg,
|
||||
const cf_t* sf_symbols);
|
||||
|
||||
/**
|
||||
* @brief PDSCH DMRS measurement results
|
||||
|
@ -129,28 +133,45 @@ typedef struct SRSLTE_API {
|
|||
} srslte_dmrs_pdcch_measure_t;
|
||||
|
||||
/**
|
||||
* @brief Performs PDCCH DMRS measurements of a given PDCCH candidate for an aggregation level
|
||||
* @brief PDSCH DMRS Channel estimates structure
|
||||
*
|
||||
* @note The measurement is useful for determining whether there is a PDCCH transmission in the given candidate.
|
||||
* @see srslte_dmrs_pdcch_get_ce
|
||||
*/
|
||||
typedef struct SRSLTE_API {
|
||||
/// Channel estimates, subtract 1 DMRS for every 4 RE, a maximum of L=16 and 6 PRB per CCE
|
||||
cf_t ce[SRSLTE_PDCCH_MAX_RE];
|
||||
uint32_t nof_re;
|
||||
float noise_var;
|
||||
} srslte_dmrs_pdcch_ce_t;
|
||||
|
||||
/**
|
||||
* @brief Performs PDCCH DMRS measurements of a given DCI location
|
||||
*
|
||||
* @note The measurement is useful for determining whether there is a PDCCH transmission in the given DCI location.
|
||||
*
|
||||
* @param[in] q provides PDCCH DMRS estimator object
|
||||
* @param[in] dci_location provides the search space
|
||||
* @param[in] location Provides the aggregation level and CCE resource
|
||||
* @param[out] measure Provides the structure for storing the channel estimate measurements
|
||||
* @return SRSLTE_SUCCESS if the configurations are valid, otherwise it returns an SRSLTE_ERROR code
|
||||
*/
|
||||
SRSLTE_API int srslte_dmrs_pdcch_get_measure(const srslte_dmrs_pdcch_estimator_t* q,
|
||||
const srslte_dci_location_t* location,
|
||||
srslte_dmrs_pdcch_measure_t* measure);
|
||||
|
||||
/**
|
||||
* @brief Extracts PDCCH DMRS channel estimates of a given PDCCH candidate for an aggregation level
|
||||
*
|
||||
* @attention The provided aggregation level and candidate need to be according to the search space.
|
||||
*
|
||||
* @param q provides PDCCH DMRS estimator object
|
||||
* @param search_space provides the search space
|
||||
* @param slot_idx Slot index in the frame
|
||||
* @param aggregation_level Indicates the aggregation level of the candidate to examine
|
||||
* @param candidate Indicates the candidate index of the available
|
||||
* @param rnti Indicates the UE RNTI (only used for UE search space type)
|
||||
* @param measure Provides the structure for storing the channel estimate measurements
|
||||
* @param[in] q provides PDCCH DMRS estimator object
|
||||
* @param[in] location Provides the aggregation level and CCE resource
|
||||
* @param[out] ce Provides the structure for storing the channel estimates
|
||||
* @return SRSLTE_SUCCESS if the configurations are valid, otherwise it returns an SRSLTE_ERROR code
|
||||
*/
|
||||
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,
|
||||
uint16_t rnti,
|
||||
srslte_dmrs_pdcch_measure_t* measure);
|
||||
SRSLTE_API int srslte_dmrs_pdcch_get_ce(const srslte_dmrs_pdcch_estimator_t* q,
|
||||
const srslte_dci_location_t* location,
|
||||
srslte_dmrs_pdcch_ce_t* ce);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -62,6 +62,7 @@ extern "C" {
|
|||
|
||||
#define SRSLTE_LTE_CRC24A 0x1864CFB
|
||||
#define SRSLTE_LTE_CRC24B 0X1800063
|
||||
#define SRSLTE_LTE_CRC24C 0X1B2B117
|
||||
#define SRSLTE_LTE_CRC16 0x11021
|
||||
#define SRSLTE_LTE_CRC8 0x19B
|
||||
|
||||
|
|
|
@ -75,6 +75,11 @@ extern "C" {
|
|||
*/
|
||||
#define SRSLTE_SEARCH_SPACE_NOF_AGGREGATION_LEVELS_NR 5
|
||||
|
||||
/**
|
||||
* @brief defines the maximum number of RE
|
||||
*/
|
||||
#define SRSLTE_PDCCH_MAX_RE ((SRSLTE_NRE - 3U) * (1U << (SRSLTE_SEARCH_SPACE_NOF_AGGREGATION_LEVELS_NR - 1U)) * 6U)
|
||||
|
||||
/**
|
||||
* @brief defines the maximum number of candidates for a given Aggregation level
|
||||
*/
|
||||
|
@ -236,18 +241,6 @@ typedef struct SRSLTE_API {
|
|||
uint32_t nof_candidates[SRSLTE_SEARCH_SPACE_NOF_AGGREGATION_LEVELS_NR];
|
||||
} srslte_search_space_t;
|
||||
|
||||
/**
|
||||
* @brief PDCCH configuration
|
||||
*/
|
||||
typedef struct SRSLTE_API {
|
||||
srslte_carrier_nr_t carrier;
|
||||
uint16_t rnti;
|
||||
srslte_coreset_t coreset;
|
||||
srslte_search_space_t search_space;
|
||||
uint32_t aggregation_level;
|
||||
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
|
||||
* frequency domain resources bit-map for counting the number of PRB.
|
||||
|
|
|
@ -44,6 +44,11 @@ static const uint16_t EMAX = 8192;
|
|||
*/
|
||||
static const uint16_t NMAX = 1024;
|
||||
|
||||
/*!
|
||||
* \brief Base 2 logarithm of maximum codeword length
|
||||
*/
|
||||
static const uint16_t NMAX_LOG = 10;
|
||||
|
||||
/*!
|
||||
* \brief \f$log_2(EMAX)\f$
|
||||
*/
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#ifndef SRSLTE_DCI_NR_H
|
||||
#define SRSLTE_DCI_NR_H
|
||||
|
||||
#include "dci.h"
|
||||
#include "srslte/phy/common/phy_common_nr.h"
|
||||
#include "srslte/phy/phch/pdsch_cfg_nr.h"
|
||||
|
||||
|
@ -25,6 +26,8 @@ typedef enum SRSLTE_API {
|
|||
} srslte_rnti_type_t;
|
||||
|
||||
typedef struct SRSLTE_API {
|
||||
srslte_dci_location_t location;
|
||||
srslte_search_space_type_t search_space;
|
||||
uint8_t payload[32];
|
||||
srslte_rnti_type_t rnti_type;
|
||||
uint32_t nof_bits;
|
||||
|
@ -59,7 +62,7 @@ typedef struct SRSLTE_API {
|
|||
// SI-RNTI specific fields
|
||||
uint32_t sii; ///< System information indicator
|
||||
|
||||
} srslte_dci_dl_t;
|
||||
} srslte_dci_dl_nr_t;
|
||||
|
||||
SRSLTE_API SRSLTE_API int srslte_dci_nr_format_1_0_sizeof(const srslte_carrier_nr_t* carrier,
|
||||
const srslte_coreset_t* coreset,
|
||||
|
@ -67,12 +70,12 @@ SRSLTE_API SRSLTE_API int srslte_dci_nr_format_1_0_sizeof(const srslte_carrier_n
|
|||
|
||||
SRSLTE_API int srslte_dci_nr_format_1_0_pack(const srslte_carrier_nr_t* carrier,
|
||||
const srslte_coreset_t* coreset,
|
||||
const srslte_dci_dl_t* dci,
|
||||
const srslte_dci_dl_nr_t* dci,
|
||||
srslte_dci_msg_nr_t* msg);
|
||||
|
||||
SRSLTE_API int srslte_dci_nr_format_1_0_unpack(const srslte_carrier_nr_t* carrier,
|
||||
const srslte_coreset_t* coreset,
|
||||
srslte_dci_msg_nr_t* msg,
|
||||
srslte_dci_dl_t* dci);
|
||||
srslte_dci_dl_nr_t* dci);
|
||||
|
||||
#endif // SRSLTE_DCI_NR_H
|
||||
|
|
|
@ -21,8 +21,51 @@
|
|||
#ifndef SRSLTE_PDCCH_NR_H
|
||||
#define SRSLTE_PDCCH_NR_H
|
||||
|
||||
#include "dci_nr.h"
|
||||
#include "srslte/config.h"
|
||||
#include "srslte/phy/ch_estimation/dmrs_pdcch.h"
|
||||
#include "srslte/phy/common/phy_common_nr.h"
|
||||
#include "srslte/phy/fec/crc.h"
|
||||
#include "srslte/phy/fec/polar/polar_code.h"
|
||||
#include "srslte/phy/fec/polar/polar_decoder.h"
|
||||
#include "srslte/phy/fec/polar/polar_encoder.h"
|
||||
#include "srslte/phy/fec/polar/polar_rm.h"
|
||||
|
||||
/**
|
||||
* @brief PDCCH configuration initialization arguments
|
||||
*/
|
||||
typedef struct {
|
||||
bool disable_simd;
|
||||
bool measure_evm;
|
||||
} srslte_pdcch_nr_args_t;
|
||||
|
||||
/**
|
||||
* @brief PDCCH Attributes and objects required to encode/decode NR PDCCH
|
||||
*/
|
||||
typedef struct SRSLTE_API {
|
||||
bool is_tx;
|
||||
srslte_polar_code_t code;
|
||||
srslte_polar_encoder_t encoder;
|
||||
srslte_polar_decoder_t decoder;
|
||||
srslte_polar_rm_t rm;
|
||||
srslte_carrier_nr_t carrier;
|
||||
srslte_coreset_t coreset;
|
||||
srslte_crc_t crc24c;
|
||||
uint8_t* c; // Message bits with attached CRC
|
||||
uint8_t* d; // encoded bits
|
||||
uint8_t* f; // bits at the Rate matching output
|
||||
cf_t* symbols;
|
||||
srslte_modem_table_t modem_table;
|
||||
srslte_evm_buffer_t* evm_buffer;
|
||||
} srslte_pdcch_nr_t;
|
||||
|
||||
/**
|
||||
* @brief NR PDCCH decoder result
|
||||
*/
|
||||
typedef struct SRSLTE_API {
|
||||
float evm;
|
||||
bool crc;
|
||||
} srslte_pdcch_nr_res_t;
|
||||
|
||||
/**
|
||||
* @brief Function for generating NR PDCCH candidate locations n_cce for a given CORESET, search space, aggregation
|
||||
|
@ -45,4 +88,32 @@ int srslte_pdcch_nr_locations_coreset(const srslte_coreset_t* coreset,
|
|||
uint32_t slot_idx,
|
||||
uint32_t locations[SRSLTE_SEARCH_SPACE_MAX_NOF_CANDIDATES_NR]);
|
||||
|
||||
SRSLTE_API int srslte_pdcch_nr_init_tx(srslte_pdcch_nr_t* q, const srslte_pdcch_nr_args_t* args);
|
||||
|
||||
SRSLTE_API int srslte_pdcch_nr_init_rx(srslte_pdcch_nr_t* q, const srslte_pdcch_nr_args_t* args);
|
||||
|
||||
SRSLTE_API void srslte_pdcch_nr_init_free(srslte_pdcch_nr_t* q);
|
||||
|
||||
SRSLTE_API int
|
||||
srslte_pdcch_nr_set_carrier(srslte_pdcch_nr_t* q, const srslte_carrier_nr_t* carrier, const srslte_coreset_t* coreset);
|
||||
|
||||
SRSLTE_API int srslte_pdcch_nr_encode(srslte_pdcch_nr_t* q, const srslte_dci_msg_nr_t* dci_msg, cf_t* slot_symbols);
|
||||
|
||||
/**
|
||||
* @brief Decodes a DCI
|
||||
*
|
||||
* @param[in,out] q provides PDCCH encoder/decoder object
|
||||
* @param[in] slot_symbols provides slot resource grid
|
||||
* @param[in] ce provides channel estimated resource elements
|
||||
* @param[in,out] dci_msg Provides with the DCI message location, RNTI, RNTI type and so on. Also, the message data
|
||||
* buffer
|
||||
* @param[out] res Provides the PDCCH result information
|
||||
* @return SRSLTE_SUCCESS if the configurations are valid, otherwise it returns an SRSLTE_ERROR code
|
||||
*/
|
||||
SRSLTE_API int srslte_pdcch_nr_decode(srslte_pdcch_nr_t* q,
|
||||
cf_t* slot_symbols,
|
||||
srslte_dmrs_pdcch_ce_t* ce,
|
||||
srslte_dci_msg_nr_t* dci_msg,
|
||||
srslte_pdcch_nr_res_t* res);
|
||||
|
||||
#endif // SRSLTE_PDCCH_NR_H
|
||||
|
|
|
@ -22,10 +22,14 @@ static uint32_t dmrs_pdcch_get_cinit(uint32_t slot_idx, uint32_t symbol_idx, uin
|
|||
(uint64_t)INT32_MAX);
|
||||
}
|
||||
|
||||
static void dmrs_pdcch_put_symbol_noninterleaved(const srslte_pdcch_cfg_nr_t* cfg, uint32_t cinit, cf_t* sf_symbol)
|
||||
static void dmrs_pdcch_put_symbol_noninterleaved(const srslte_carrier_nr_t* carrier,
|
||||
const srslte_coreset_t* coreset,
|
||||
const srslte_dci_location_t* dci_location,
|
||||
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);
|
||||
uint32_t L = 1U << dci_location->L;
|
||||
uint32_t nof_freq_res = SRSLTE_MIN(carrier->nof_prb / 6, SRSLTE_CORESET_FREQ_DOMAIN_RES_SIZE);
|
||||
|
||||
// Initialise sequence for this symbol
|
||||
srslte_sequence_state_t sequence_state = {};
|
||||
|
@ -33,14 +37,14 @@ static void dmrs_pdcch_put_symbol_noninterleaved(const srslte_pdcch_cfg_nr_t* cf
|
|||
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 = (cfg->n_cce * 6) / cfg->coreset.duration;
|
||||
uint32_t rb_coreset_idx_end = ((cfg->n_cce + L) * 6) / cfg->coreset.duration;
|
||||
uint32_t rb_coreset_idx_begin = (dci_location->ncce * 6) / coreset->duration;
|
||||
uint32_t rb_coreset_idx_end = ((dci_location->ncce + L) * 6) / coreset->duration;
|
||||
|
||||
// CORESET Resource Block counter
|
||||
uint32_t rb_coreset_idx = 0;
|
||||
for (uint32_t i = 0; i < nof_freq_res; i++) {
|
||||
// Skip frequency resource if outside of the CORESET
|
||||
if (!cfg->coreset.freq_resources[i]) {
|
||||
if (!coreset->freq_resources[i]) {
|
||||
// Skip possible DMRS locations in this region
|
||||
sequence_skip += NOF_PILOTS_X_FREQ_RES;
|
||||
continue;
|
||||
|
@ -97,37 +101,42 @@ static void dmrs_pdcch_put_symbol_noninterleaved(const srslte_pdcch_cfg_nr_t* cf
|
|||
}
|
||||
}
|
||||
|
||||
int srslte_dmrs_pdcch_put(const srslte_pdcch_cfg_nr_t* cfg, uint32_t slot_idx, cf_t* sf_symbols)
|
||||
int srslte_dmrs_pdcch_put(const srslte_carrier_nr_t* carrier,
|
||||
const srslte_coreset_t* coreset,
|
||||
const srslte_dl_slot_cfg_t* slot_cfg,
|
||||
const srslte_dci_location_t* dci_location,
|
||||
cf_t* sf_symbols)
|
||||
{
|
||||
if (cfg == NULL || sf_symbols == NULL) {
|
||||
if (carrier == NULL || coreset == NULL || slot_cfg == NULL || dci_location == NULL || sf_symbols == NULL) {
|
||||
return SRSLTE_ERROR_INVALID_INPUTS;
|
||||
}
|
||||
|
||||
if (cfg->coreset.mapping_type == srslte_coreset_mapping_type_interleaved) {
|
||||
if (coreset->mapping_type == srslte_coreset_mapping_type_interleaved) {
|
||||
ERROR("Error interleaved CORESET mapping is not currently implemented\n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
if (cfg->coreset.duration < SRSLTE_CORESET_DURATION_MIN || cfg->coreset.duration > SRSLTE_CORESET_DURATION_MAX) {
|
||||
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",
|
||||
cfg->coreset.duration,
|
||||
coreset->duration,
|
||||
SRSLTE_CORESET_DURATION_MIN,
|
||||
SRSLTE_CORESET_DURATION_MAX);
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
// Use cell id if the DMR scrambling id is not provided by higher layers
|
||||
uint32_t n_id = cfg->carrier.id;
|
||||
if (cfg->coreset.dmrs_scrambling_id_present) {
|
||||
n_id = cfg->coreset.dmrs_scrambling_id;
|
||||
uint32_t n_id = carrier->id;
|
||||
if (coreset->dmrs_scrambling_id_present) {
|
||||
n_id = coreset->dmrs_scrambling_id;
|
||||
}
|
||||
|
||||
for (uint32_t l = 0; l < cfg->coreset.duration; l++) {
|
||||
for (uint32_t l = 0; l < coreset->duration; l++) {
|
||||
// Get Cin
|
||||
uint32_t cinit = dmrs_pdcch_get_cinit(slot_idx, l, n_id);
|
||||
uint32_t cinit = dmrs_pdcch_get_cinit(slot_cfg->idx, l, n_id);
|
||||
|
||||
// Put data
|
||||
dmrs_pdcch_put_symbol_noninterleaved(cfg, cinit, &sf_symbols[cfg->carrier.nof_prb * SRSLTE_NRE * l]);
|
||||
dmrs_pdcch_put_symbol_noninterleaved(
|
||||
carrier, coreset, dci_location, cinit, &sf_symbols[carrier->nof_prb * SRSLTE_NRE * l]);
|
||||
}
|
||||
|
||||
return SRSLTE_SUCCESS;
|
||||
|
@ -165,15 +174,15 @@ int srslte_dmrs_pdcch_estimator_init(srslte_dmrs_pdcch_estimator_t* q,
|
|||
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;
|
||||
}
|
||||
|
||||
// Calculate new bandwidth and size
|
||||
uint32_t coreset_bw = srslte_coreset_get_bw(coreset);
|
||||
uint32_t coreset_sz = srslte_coreset_get_sz(coreset);
|
||||
|
||||
if (srslte_interp_linear_init(&q->interpolator, coreset_bw * 3, 4)) {
|
||||
ERROR("Initiating interpolator\n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
// Reallocate only if the CORESET size or bandwidth changed
|
||||
if (q->coreset_bw != coreset_bw || q->coreset_sz != coreset_sz) {
|
||||
// Iterate all possible symbols
|
||||
|
@ -277,15 +286,14 @@ 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)
|
||||
int srslte_dmrs_pdcch_estimate(srslte_dmrs_pdcch_estimator_t* q,
|
||||
const srslte_dl_slot_cfg_t* slot_cfg,
|
||||
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;
|
||||
|
||||
// Use cell id if the DMR scrambling id is not provided by higher layers
|
||||
uint32_t n_id = q->carrier.id;
|
||||
if (q->coreset.dmrs_scrambling_id_present) {
|
||||
|
@ -295,7 +303,7 @@ int srslte_dmrs_pdcch_estimate(srslte_dmrs_pdcch_estimator_t* q, uint32_t slot_i
|
|||
// 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_idx, l, n_id);
|
||||
uint32_t cinit = dmrs_pdcch_get_cinit(slot_cfg->idx, l, n_id);
|
||||
|
||||
// Extract pilots least square estimates
|
||||
srslte_dmrs_pdcch_extract(q, cinit, &sf_symbols[l * q->carrier.nof_prb * SRSLTE_NRE], q->lse[l]);
|
||||
|
@ -312,19 +320,15 @@ int srslte_dmrs_pdcch_estimate(srslte_dmrs_pdcch_estimator_t* q, uint32_t slot_i
|
|||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
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 ncce,
|
||||
uint16_t rnti,
|
||||
int srslte_dmrs_pdcch_get_measure(const srslte_dmrs_pdcch_estimator_t* q,
|
||||
const srslte_dci_location_t* dci_location,
|
||||
srslte_dmrs_pdcch_measure_t* measure)
|
||||
{
|
||||
if (q == NULL || search_space == NULL || measure == NULL) {
|
||||
if (q == NULL || dci_location == NULL || measure == NULL) {
|
||||
return SRSLTE_ERROR_INVALID_INPUTS;
|
||||
}
|
||||
|
||||
uint32_t L = 1U << aggregation_level;
|
||||
uint32_t L = 1U << dci_location->L;
|
||||
if (q->coreset.mapping_type == srslte_coreset_mapping_type_interleaved) {
|
||||
ERROR("Error interleaved mapping not implemented\n");
|
||||
return SRSLTE_ERROR;
|
||||
|
@ -337,7 +341,7 @@ int srslte_dmrs_pdcch_get_measure(srslte_dmrs_pdcch_estimator_t* q,
|
|||
}
|
||||
|
||||
// Get base pilot;
|
||||
uint32_t pilot_idx = (ncce * 18) / q->coreset.duration;
|
||||
uint32_t pilot_idx = (dci_location->ncce * 18) / q->coreset.duration;
|
||||
uint32_t nof_pilots = (L * 18) / q->coreset.duration;
|
||||
|
||||
float rsrp = 0.0f;
|
||||
|
@ -379,3 +383,46 @@ int srslte_dmrs_pdcch_get_measure(srslte_dmrs_pdcch_estimator_t* q,
|
|||
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
int srslte_dmrs_pdcch_get_ce(const srslte_dmrs_pdcch_estimator_t* q,
|
||||
const srslte_dci_location_t* dci_location,
|
||||
srslte_dmrs_pdcch_ce_t* ce)
|
||||
{
|
||||
if (q == NULL || dci_location == NULL || ce == NULL) {
|
||||
return SRSLTE_ERROR_INVALID_INPUTS;
|
||||
}
|
||||
|
||||
uint32_t L = 1U << dci_location->L;
|
||||
if (q->coreset.mapping_type == srslte_coreset_mapping_type_interleaved) {
|
||||
ERROR("Error interleaved mapping not implemented\n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
// Check that CORESET duration is not less than minimum
|
||||
if (q->coreset.duration < SRSLTE_CORESET_DURATION_MIN) {
|
||||
ERROR("Invalid CORESET duration\n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
// Calculate begin and end sub-carrier index for the selected candidate
|
||||
uint32_t k_begin = (dci_location->ncce * SRSLTE_NRE * 6) / q->coreset.duration;
|
||||
uint32_t k_end = k_begin + (L * 6 * SRSLTE_NRE) / q->coreset.duration;
|
||||
|
||||
// Extract CE for PDCCH
|
||||
uint32_t count = 0;
|
||||
for (uint32_t l = 0; l < q->coreset.duration; l++) {
|
||||
for (uint32_t k = k_begin; k < k_end; k++) {
|
||||
if (k % 4 != 1) {
|
||||
ce->ce[count++] = q->ce[q->coreset_bw * SRSLTE_NRE * l + k];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Double check extracted RE match ideal count
|
||||
ce->nof_re = (SRSLTE_NRE - 3) * 6 * L;
|
||||
if (count != ce->nof_re) {
|
||||
ERROR("Incorrect number of extracted resources (%d != %d)\n", count, ce->nof_re);
|
||||
}
|
||||
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
#include <unistd.h>
|
||||
|
||||
static srslte_carrier_nr_t carrier = {};
|
||||
|
||||
static srslte_dmrs_pdcch_ce_t pdcch_ce = {};
|
||||
static uint16_t rnti = 0x1234;
|
||||
|
||||
void usage(char* prog)
|
||||
|
@ -56,31 +56,38 @@ static void parse_args(int argc, char** argv)
|
|||
}
|
||||
}
|
||||
|
||||
static int run_test(srslte_dmrs_pdcch_estimator_t* estimator, srslte_pdcch_cfg_nr_t* cfg, cf_t* sf_symbols, cf_t* h)
|
||||
static int run_test(srslte_dmrs_pdcch_estimator_t* estimator,
|
||||
const srslte_coreset_t* coreset,
|
||||
const srslte_search_space_t* search_space,
|
||||
uint32_t aggregation_level,
|
||||
cf_t* sf_symbols,
|
||||
srslte_dmrs_pdcch_ce_t* ce)
|
||||
{
|
||||
for (uint32_t slot_idx = 0; slot_idx < SRSLTE_NSLOTS_PER_FRAME_NR(cfg->carrier.numerology); slot_idx++) {
|
||||
srslte_dl_slot_cfg_t slot_cfg = {};
|
||||
|
||||
srslte_dci_location_t dci_location = {};
|
||||
dci_location.L = aggregation_level;
|
||||
|
||||
for (slot_cfg.idx = 0; slot_cfg.idx < SRSLTE_NSLOTS_PER_FRAME_NR(carrier.numerology); slot_cfg.idx++) {
|
||||
uint32_t locations[SRSLTE_SEARCH_SPACE_MAX_NOF_CANDIDATES_NR] = {};
|
||||
|
||||
int nof_locations = srslte_pdcch_nr_locations_coreset(
|
||||
&cfg->coreset, &cfg->search_space, cfg->rnti, cfg->aggregation_level, slot_idx, locations);
|
||||
int nof_locations =
|
||||
srslte_pdcch_nr_locations_coreset(coreset, search_space, rnti, aggregation_level, slot_cfg.idx, locations);
|
||||
|
||||
TESTASSERT(nof_locations == cfg->search_space.nof_candidates[cfg->aggregation_level]);
|
||||
TESTASSERT(nof_locations == search_space->nof_candidates[aggregation_level]);
|
||||
|
||||
for (uint32_t candidate = 0; candidate < nof_locations; candidate++) {
|
||||
cfg->n_cce = locations[candidate];
|
||||
dci_location.ncce = 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_put(&carrier, coreset, &slot_cfg, &dci_location, sf_symbols) == SRSLTE_SUCCESS);
|
||||
|
||||
TESTASSERT(srslte_dmrs_pdcch_estimate(estimator, slot_idx, sf_symbols) == SRSLTE_SUCCESS);
|
||||
TESTASSERT(srslte_dmrs_pdcch_estimate(estimator, &slot_cfg, 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);
|
||||
TESTASSERT(srslte_dmrs_pdcch_get_measure(estimator, &dci_location, &measure) == SRSLTE_SUCCESS);
|
||||
|
||||
if (fabsf(measure.rsrp - 1.0f) > 1e-2) {
|
||||
printf("EPRE=%f; RSRP=%f; CFO=%f; SYNC_ERR=%f;\n",
|
||||
|
@ -93,6 +100,12 @@ static int run_test(srslte_dmrs_pdcch_estimator_t* estimator, srslte_pdcch_cfg_n
|
|||
TESTASSERT(fabsf(measure.rsrp - 1.0f) < 1e-3f);
|
||||
TESTASSERT(fabsf(measure.cfo_hz) < 1e-3f);
|
||||
TESTASSERT(fabsf(measure.sync_error_us) < 1e-3f);
|
||||
|
||||
TESTASSERT(srslte_dmrs_pdcch_get_ce(estimator, &dci_location, ce) == SRSLTE_SUCCESS);
|
||||
float avg_pow = srslte_vec_avg_power_cf(ce->ce, ce->nof_re);
|
||||
float avg_pow_err = fabsf(avg_pow - 1.0f);
|
||||
TESTASSERT(ce->nof_re == ((SRSLTE_NRE - 3) * (1U << aggregation_level) * 6U));
|
||||
TESTASSERT(avg_pow_err < 0.1f);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -107,48 +120,45 @@ int main(int argc, char** argv)
|
|||
|
||||
parse_args(argc, argv);
|
||||
|
||||
srslte_pdcch_cfg_nr_t cfg = {};
|
||||
srslte_coreset_t coreset = {};
|
||||
srslte_search_space_t search_space = {};
|
||||
srslte_dmrs_pdcch_estimator_t estimator = {};
|
||||
|
||||
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);
|
||||
|
||||
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;
|
||||
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_resources[i] = (mask == 1);
|
||||
coreset.freq_resources[i] = (mask == 1);
|
||||
nof_freq_resources += mask;
|
||||
}
|
||||
|
||||
for (cfg.coreset.duration = 1; cfg.coreset.duration <= 3; cfg.coreset.duration++) {
|
||||
for (coreset.duration = 1; coreset.duration <= 3; 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 (search_space.type = srslte_search_space_type_common; search_space.type <= srslte_search_space_type_ue;
|
||||
search_space.type++) {
|
||||
|
||||
for (uint32_t i = 0; i < SRSLTE_SEARCH_SPACE_NOF_AGGREGATION_LEVELS_NR; i++) {
|
||||
uint32_t L = 1U << i;
|
||||
uint32_t nof_reg = cfg.coreset.duration * nof_freq_resources * 6;
|
||||
uint32_t nof_reg = coreset.duration * nof_freq_resources * 6;
|
||||
uint32_t nof_cce = nof_reg / 6;
|
||||
cfg.search_space.nof_candidates[i] = SRSLTE_MIN(nof_cce / L, SRSLTE_SEARCH_SPACE_MAX_NOF_CANDIDATES_NR);
|
||||
search_space.nof_candidates[i] = SRSLTE_MIN(nof_cce / L, SRSLTE_SEARCH_SPACE_MAX_NOF_CANDIDATES_NR);
|
||||
}
|
||||
|
||||
for (cfg.aggregation_level = 0; cfg.aggregation_level < SRSLTE_SEARCH_SPACE_NOF_AGGREGATION_LEVELS_NR;
|
||||
cfg.aggregation_level++) {
|
||||
for (uint32_t aggregation_level = 0; aggregation_level < SRSLTE_SEARCH_SPACE_NOF_AGGREGATION_LEVELS_NR;
|
||||
aggregation_level++) {
|
||||
|
||||
srslte_dmrs_pdcch_estimator_init(&estimator, &cfg.carrier, &cfg.coreset);
|
||||
srslte_dmrs_pdcch_estimator_init(&estimator, &carrier, &coreset);
|
||||
|
||||
if (run_test(&estimator, &cfg, sf_symbols, h)) {
|
||||
if (run_test(&estimator, &coreset, &search_space, aggregation_level, sf_symbols, &pdcch_ce)) {
|
||||
ERROR("Test %d failed\n", test_counter);
|
||||
} else {
|
||||
test_passed++;
|
||||
|
@ -165,10 +175,6 @@ int main(int argc, char** argv)
|
|||
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);
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@ static int dci_nr_format_1_0_freq_resource_size(const srslte_carrier_nr_t* carri
|
|||
|
||||
int srslte_dci_nr_format_1_0_pack(const srslte_carrier_nr_t* carrier,
|
||||
const srslte_coreset_t* coreset,
|
||||
const srslte_dci_dl_t* dci,
|
||||
const srslte_dci_dl_nr_t* dci,
|
||||
srslte_dci_msg_nr_t* msg)
|
||||
{
|
||||
uint8_t* y = msg->payload;
|
||||
|
@ -146,7 +146,7 @@ int srslte_dci_nr_format_1_0_pack(const srslte_carrier_nr_t* carrier,
|
|||
int srslte_dci_nr_format_1_0_unpack(const srslte_carrier_nr_t* carrier,
|
||||
const srslte_coreset_t* coreset,
|
||||
srslte_dci_msg_nr_t* msg,
|
||||
srslte_dci_dl_t* dci)
|
||||
srslte_dci_dl_nr_t* dci)
|
||||
{
|
||||
uint8_t* y = msg->payload;
|
||||
srslte_rnti_type_t rnti_type = msg->rnti_type;
|
||||
|
|
|
@ -100,3 +100,322 @@ int srslte_pdcch_nr_locations_coreset(const srslte_coreset_t* coreset,
|
|||
|
||||
return nof_candidates;
|
||||
}
|
||||
|
||||
static int pdcch_nr_init_common(srslte_pdcch_nr_t* q, const srslte_pdcch_nr_args_t* args)
|
||||
{
|
||||
if (q == NULL || args == NULL) {
|
||||
return SRSLTE_ERROR_INVALID_INPUTS;
|
||||
}
|
||||
|
||||
q->c = srslte_vec_u8_malloc(SRSLTE_PDCCH_MAX_RE * 2);
|
||||
if (q->c == NULL) {
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
q->d = srslte_vec_u8_malloc(SRSLTE_PDCCH_MAX_RE * 2);
|
||||
if (q->d == NULL) {
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
q->f = srslte_vec_u8_malloc(SRSLTE_PDCCH_MAX_RE * 2);
|
||||
if (q->f == NULL) {
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
q->symbols = srslte_vec_cf_malloc(SRSLTE_PDCCH_MAX_RE);
|
||||
if (q->symbols == NULL) {
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
if (srslte_crc_init(&q->crc24c, SRSLTE_LTE_CRC24C, 24) < SRSLTE_SUCCESS) {
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
if (srslte_polar_code_init(&q->code) < SRSLTE_SUCCESS) {
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
srslte_modem_table_lte(&q->modem_table, SRSLTE_MOD_QPSK);
|
||||
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
int srslte_pdcch_nr_init_tx(srslte_pdcch_nr_t* q, const srslte_pdcch_nr_args_t* args)
|
||||
{
|
||||
if (pdcch_nr_init_common(q, args) < SRSLTE_SUCCESS) {
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
q->is_tx = true;
|
||||
|
||||
srslte_polar_encoder_type_t encoder_type =
|
||||
(args->disable_simd) ? SRSLTE_POLAR_ENCODER_PIPELINED : SRSLTE_POLAR_ENCODER_AVX2;
|
||||
|
||||
if (srslte_polar_encoder_init(&q->encoder, encoder_type, NMAX_LOG) < SRSLTE_SUCCESS) {
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
if (srslte_polar_rm_tx_init(&q->rm) < SRSLTE_SUCCESS) {
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
int srslte_pdcch_nr_init_rx(srslte_pdcch_nr_t* q, const srslte_pdcch_nr_args_t* args)
|
||||
{
|
||||
if (pdcch_nr_init_common(q, args) < SRSLTE_SUCCESS) {
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
srslte_polar_decoder_type_t decoder_type =
|
||||
(args->disable_simd) ? SRSLTE_POLAR_DECODER_SSC_C : SRSLTE_POLAR_DECODER_SSC_C_AVX2;
|
||||
|
||||
if (srslte_polar_decoder_init(&q->decoder, decoder_type, NMAX_LOG) < SRSLTE_SUCCESS) {
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
if (srslte_polar_rm_rx_init_c(&q->rm) < SRSLTE_SUCCESS) {
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
if (args->measure_evm) {
|
||||
q->evm_buffer = srslte_evm_buffer_alloc(SRSLTE_PDCCH_MAX_RE * 2);
|
||||
}
|
||||
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
void srslte_pdcch_nr_init_free(srslte_pdcch_nr_t* q)
|
||||
{
|
||||
if (q == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
srslte_polar_code_free(&q->code);
|
||||
|
||||
if (q->is_tx) {
|
||||
srslte_polar_encoder_free(&q->encoder);
|
||||
srslte_polar_rm_tx_free(&q->rm);
|
||||
} else {
|
||||
srslte_polar_decoder_free(&q->decoder);
|
||||
srslte_polar_rm_rx_free_c(&q->rm);
|
||||
}
|
||||
|
||||
if (q->c) {
|
||||
free(q->c);
|
||||
}
|
||||
|
||||
if (q->d) {
|
||||
free(q->d);
|
||||
}
|
||||
|
||||
if (q->f) {
|
||||
free(q->f);
|
||||
}
|
||||
|
||||
srslte_modem_table_free(&q->modem_table);
|
||||
|
||||
SRSLTE_MEM_ZERO(q, srslte_pdcch_nr_t, 1);
|
||||
}
|
||||
|
||||
int srslte_pdcch_nr_set_carrier(srslte_pdcch_nr_t* q,
|
||||
const srslte_carrier_nr_t* carrier,
|
||||
const srslte_coreset_t* coreset)
|
||||
{
|
||||
if (q == NULL) {
|
||||
return SRSLTE_ERROR_INVALID_INPUTS;
|
||||
}
|
||||
|
||||
if (carrier != NULL) {
|
||||
q->carrier = *carrier;
|
||||
}
|
||||
|
||||
if (coreset != NULL) {
|
||||
q->coreset = *coreset;
|
||||
}
|
||||
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
static uint32_t pdcch_nr_cp(const srslte_pdcch_nr_t* q,
|
||||
const srslte_dci_location_t* dci_location,
|
||||
cf_t* slot_grid,
|
||||
cf_t* symbols,
|
||||
bool put)
|
||||
{
|
||||
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 * SRSLTE_NRE * 6) / q->coreset.duration;
|
||||
uint32_t k_end = k_begin + (L * 6 * SRSLTE_NRE) / q->coreset.duration;
|
||||
|
||||
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;
|
||||
for (uint32_t r = 0; r < SRSLTE_CORESET_FREQ_DOMAIN_RES_SIZE; r++) {
|
||||
if (q->coreset.freq_resources[r]) {
|
||||
for (uint32_t i = r * 6 * SRSLTE_NRE; i < (r + 1) * 6 * SRSLTE_NRE; i++, k++) {
|
||||
if (k >= k_begin && k < k_end && k % 4 != 1) {
|
||||
if (put) {
|
||||
slot_grid[q->carrier.nof_prb * SRSLTE_NRE * l + i] = symbols[count++];
|
||||
} else {
|
||||
symbols[count++] = slot_grid[q->carrier.nof_prb * SRSLTE_NRE * l + i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
uint32_t pdcch_nr_c_init(const srslte_pdcch_nr_t* q, const srslte_dci_msg_nr_t* dci_msg)
|
||||
{
|
||||
uint32_t n_id = (dci_msg->search_space == srslte_search_space_type_ue && q->coreset.dmrs_scrambling_id_present)
|
||||
? q->coreset.dmrs_scrambling_id
|
||||
: q->carrier.id;
|
||||
uint32_t n_rnti = (dci_msg->search_space == srslte_search_space_type_ue && q->coreset.dmrs_scrambling_id_present)
|
||||
? dci_msg->rnti
|
||||
: 0U;
|
||||
return ((n_rnti << 16U) + n_id) & 0x7fffffffU;
|
||||
}
|
||||
|
||||
int srslte_pdcch_nr_encode(srslte_pdcch_nr_t* q, const srslte_dci_msg_nr_t* dci_msg, cf_t* slot_symbols)
|
||||
{
|
||||
|
||||
if (q == NULL || dci_msg == NULL || slot_symbols == NULL) {
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
// Calculate...
|
||||
uint32_t K = dci_msg->nof_bits + 24U; // Payload size including CRC
|
||||
uint32_t M = (1U << dci_msg->location.L) * (SRSLTE_NRE - 3U) * 6U; // Number of RE
|
||||
uint32_t E = M * 2; // Number of Rate-Matched bits
|
||||
|
||||
// Get polar code
|
||||
if (srslte_polar_code_get(&q->code, K, E, 9U) < SRSLTE_SUCCESS) {
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
// Copy DCI message
|
||||
srslte_vec_u8_copy(q->c, dci_msg->payload, dci_msg->nof_bits);
|
||||
|
||||
// Append CRC
|
||||
srslte_crc_attach(&q->crc24c, q->c, dci_msg->nof_bits);
|
||||
|
||||
// Unpack RNTI
|
||||
uint8_t unpacked_rnti[16] = {};
|
||||
uint8_t* ptr = unpacked_rnti;
|
||||
srslte_bit_unpack(dci_msg->rnti, &ptr, 16);
|
||||
|
||||
// Scramble CRC with RNTI
|
||||
srslte_vec_xor_bbb(unpacked_rnti, &q->c[K - 16], &q->c[K - 16], 16);
|
||||
|
||||
// Encode bits
|
||||
if (srslte_polar_encoder_encode(&q->encoder, q->c, q->d, q->code.n) < SRSLTE_SUCCESS) {
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
// Rate matching
|
||||
srslte_polar_rm_tx(&q->rm, q->d, q->f, q->code.n, E, K, 0);
|
||||
|
||||
// Scrambling
|
||||
srslte_sequence_apply_bit(q->f, q->f, E, pdcch_nr_c_init(q, dci_msg));
|
||||
|
||||
// Modulation
|
||||
srslte_mod_modulate(&q->modem_table, q->f, q->symbols, E);
|
||||
|
||||
// Put symbols in grid
|
||||
uint32_t m = pdcch_nr_cp(q, &dci_msg->location, slot_symbols, q->symbols, true);
|
||||
if (M != m) {
|
||||
ERROR("Unmatch number of RE (%d != %d)\n", m, M);
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
int srslte_pdcch_nr_decode(srslte_pdcch_nr_t* q,
|
||||
cf_t* slot_symbols,
|
||||
srslte_dmrs_pdcch_ce_t* ce,
|
||||
srslte_dci_msg_nr_t* dci_msg,
|
||||
srslte_pdcch_nr_res_t* res)
|
||||
{
|
||||
if (q == NULL || dci_msg == NULL || ce == NULL || slot_symbols == NULL || res == NULL) {
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
// Calculate...
|
||||
uint32_t K = dci_msg->nof_bits + 24U; // Payload size including CRC
|
||||
uint32_t M = (1U << dci_msg->location.L) * (SRSLTE_NRE - 3U) * 6U; // Number of RE
|
||||
uint32_t E = M * 2; // Number of Rate-Matched bits
|
||||
|
||||
// Check number of estimates is correct
|
||||
if (ce->nof_re != M) {
|
||||
ERROR("Invalid number of channel estimates (%d != %d)\n", M, ce->nof_re);
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
// Get polar code
|
||||
if (srslte_polar_code_get(&q->code, K, E, 9U) < SRSLTE_SUCCESS) {
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
// Get symbols from grid
|
||||
uint32_t m = pdcch_nr_cp(q, &dci_msg->location, slot_symbols, q->symbols, false);
|
||||
if (M != m) {
|
||||
ERROR("Unmatch number of RE (%d != %d)\n", m, M);
|
||||
}
|
||||
|
||||
// Equalise
|
||||
srslte_predecoding_single(q->symbols, ce->ce, q->symbols, NULL, M, 1.0f, ce->noise_var);
|
||||
|
||||
// Demodulation
|
||||
int8_t* llr = (int8_t*)q->f;
|
||||
srslte_demod_soft_demodulate_b(SRSLTE_MOD_QPSK, q->symbols, llr, M);
|
||||
|
||||
// Measure EVM if configured
|
||||
if (q->evm_buffer != NULL) {
|
||||
res->evm = srslte_evm_run_b(q->evm_buffer, &q->modem_table, q->symbols, llr, E);
|
||||
} else {
|
||||
res->evm = NAN;
|
||||
}
|
||||
|
||||
// Descrambling
|
||||
srslte_sequence_apply_c(llr, llr, E, pdcch_nr_c_init(q, dci_msg));
|
||||
|
||||
// Un-rate matching
|
||||
int8_t* d = (int8_t*)q->d;
|
||||
if (srslte_polar_rm_rx_c(&q->rm, llr, d, E, q->code.n, K, 0) < SRSLTE_SUCCESS) {
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
// Decode
|
||||
if (srslte_polar_decoder_decode_c(&q->decoder, d, q->c, q->code.n, q->code.F_set, q->code.F_set_size) <
|
||||
SRSLTE_SUCCESS) {
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
// Unpack RNTI
|
||||
uint8_t unpacked_rnti[16] = {};
|
||||
uint8_t* ptr = unpacked_rnti;
|
||||
srslte_bit_unpack(dci_msg->rnti, &ptr, 16);
|
||||
|
||||
// De-Scramble CRC with RNTI
|
||||
ptr = &q->c[K - 24];
|
||||
srslte_vec_xor_bbb(unpacked_rnti, &q->c[K - 16], &q->c[K - 16], 16);
|
||||
|
||||
// Check CRC
|
||||
uint32_t checksum1 = srslte_crc_checksum(&q->crc24c, q->c, dci_msg->nof_bits);
|
||||
uint32_t checksum2 = srslte_bit_pack(&ptr, 24);
|
||||
res->crc = checksum1 == checksum2;
|
||||
|
||||
// Copy DCI message
|
||||
srslte_vec_u8_copy(dci_msg->payload, q->c, dci_msg->nof_bits);
|
||||
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
Loading…
Reference in New Issue