Created PDSCH-NR configuration structures and refactored DMRS

master
Xavier Arteaga 4 years ago committed by Xavier Arteaga
parent 009f300c5e
commit 8d34d344a8

@ -27,6 +27,7 @@ extern "C" {
#endif #endif
#include "srslte/phy/common/phy_common_nr.h" #include "srslte/phy/common/phy_common_nr.h"
#include "srslte/phy/phch/pdsch_cfg_nr.h"
#include "srslte/srslte.h" #include "srslte/srslte.h"
#include <stdint.h> #include <stdint.h>
@ -34,76 +35,122 @@ extern "C" {
#define SRSLTE_DMRS_PDSCH_TYPEA_SINGLE_DURATION_MIN 3 #define SRSLTE_DMRS_PDSCH_TYPEA_SINGLE_DURATION_MIN 3
#define SRSLTE_DMRS_PDSCH_TYPEA_DOUBLE_DURATION_MIN 4 #define SRSLTE_DMRS_PDSCH_TYPEA_DOUBLE_DURATION_MIN 4
typedef enum { /**
srslte_dmrs_pdsch_type_1 = 0, // 1 pilot every 2 sub-carriers (default) * @brief PDSCH DMRS estimator object
srslte_dmrs_pdsch_type_2 // 2 consecutive pilots every 6 sub-carriers *
} srslte_dmrs_pdsch_type_t; * @note The DMRS PDSCH object has to be initialised and the carrier parameters needs to be set.
*
* @see srslte_dmrs_pdsch_init
* @see srslte_dmrs_pdsch_set_carrier
* @see srslte_dmrs_pdsch_free
* @see srslte_dmrs_pdsch_put_sf
* @see srslte_dmrs_pdsch_estimate
*/
typedef struct {
bool is_ue;
typedef enum { srslte_carrier_nr_t carrier;
srslte_dmrs_pdsch_len_1 = 0, // single, 1 symbol long (default)
srslte_dmrs_pdsch_len_2 // double, 2 symbol long srslte_interp_lin_t interpolator_type1; /// Type 1 DMRS: 1 pilot every 2 RE
} srslte_dmrs_pdsch_len_t; srslte_interp_lin_t interpolator_type2; /// Type 2 DMRS: 2 consecutive pilots every 6 RE
uint32_t max_nof_prb;
cf_t* pilot_estimates; /// Pilots least squares estimates
cf_t* temp; /// Temporal data vector of size SRSLTE_NRE * carrier.nof_prb
} srslte_dmrs_pdsch_t;
/** /**
* Determines whether the first pilot goes into symbol index 2 or 3 * @brief Computes the symbol indexes carrying DMRS and stores them in symbols_idx
* @param cfg PDSCH configuration that includes DMRS, PDSCH and grant parameters
* @param symbols_idx is the destination pointer where the symbols indexes are stored
* @return It returns the number of symbols if inputs are valid, otherwise, it returns SRSLTE_ERROR code.
*/ */
typedef enum { SRSLTE_API int srslte_dmrs_pdsch_get_symbols_idx(const srslte_pdsch_cfg_nr_t* pdsch_cfg,
srslte_dmrs_pdsch_typeA_pos_2 = 0, // Start in slot symbol index 2 (default) uint32_t symbols_idx[SRSLTE_DMRS_PDSCH_MAX_SYMBOLS]);
srslte_dmrs_pdsch_typeA_pos_3 // Start in slot symbol index 3
} srslte_dmrs_pdsch_typeA_pos_t;
/** /**
* Determines additional symbols if possible to be added * @brief Computes the sub-carrier indexes carrying DMRS
*
* @param cfg PDSCH DMRS configuration provided by upper layers
* @param max_count is the number of sub-carriers to generate
* @param sc_idx is the destination pointer where the sub-carrier indexes are stored
*
* @return It returns the number of sub-carriers if inputs are valid, otherwise, it returns SRSLTE_ERROR code.
*/ */
typedef enum { SRSLTE_API int srslte_dmrs_pdsch_get_sc_idx(const srslte_pdsch_dmrs_cfg_t* cfg, uint32_t max_count, uint32_t* sc_idx);
srslte_dmrs_pdsch_add_pos_2 = 0,
srslte_dmrs_pdsch_add_pos_0,
srslte_dmrs_pdsch_add_pos_1,
srslte_dmrs_pdsch_add_pos_3
} srslte_dmrs_pdsch_add_pos_t;
typedef struct {
/// Parameters provided by DMRS-DownlinkConfig
srslte_dmrs_pdsch_type_t type;
srslte_dmrs_pdsch_typeA_pos_t typeA_pos;
srslte_dmrs_pdsch_add_pos_t additional_pos;
srslte_dmrs_pdsch_len_t length;
uint32_t duration;
/// Parameters provided by PDSCH-TimeDomainResourceAllocation
srslte_pdsch_mapping_type_t mapping_type;
bool lte_CRS_to_match_around;
bool additional_DMRS_DL_Alt;
uint32_t n_id;
uint32_t n_scid;
uint32_t nof_prb;
float beta;
uint32_t reference_point;
} srslte_dmrs_pdsch_cfg_t;
typedef struct {
srslte_dmrs_pdsch_cfg_t cfg;
uint32_t symbols_idx[SRSLTE_DMRS_PDSCH_MAX_SYMBOLS]; /**
uint32_t nof_symbols; * @brief Stringifies the PDSCH DMRS configuration
*
uint32_t sc_idx[SRSLTE_NRE]; * @param cfg PDSCH DMRS configuration
uint32_t nof_sc; * @param msg Pointer to the destination array
* @param max_len Maximum number of characters to write
*
* @return It returns the number of characters written in the vector if no error occurs, otherwise it returns
* SRSLTE_ERROR code
*/
SRSLTE_API int srslte_dmrs_pdsch_cfg_to_str(const srslte_pdsch_dmrs_cfg_t* cfg, char* msg, uint32_t max_len);
} srslte_dmrs_pdsch_t; /**
* @brief Initialises DMRS PDSCH object
*
* @param q DMRS PDSCH object
* @param is_ue indicates whethe the object is for a UE (in this case, it shall initialise as an estimator)
* @return it returns SRSLTE_ERROR code if an error occurs, otherwise it returns SRSLTE_SUCCESS
*/
SRSLTE_API int srslte_dmrs_pdsch_init(srslte_dmrs_pdsch_t* q, bool is_ue);
SRSLTE_API int srslte_dmrs_pdsch_cfg_to_str(const srslte_dmrs_pdsch_cfg_t* cfg, char* msg, uint32_t max_len); /**
* @brief Frees DMRS PDSCH object
*
* @param q DMRS PDSCH object
*/
SRSLTE_API void srslte_dmrs_pdsch_free(srslte_dmrs_pdsch_t* q);
SRSLTE_API int srslte_dmrs_pdsch_init(srslte_dmrs_pdsch_t* q, const srslte_dmrs_pdsch_cfg_t* cfg); /**
* @brief Sets the carrier configuration. if the PDSCH DMRS object is configured as UE, it will resize internal buffers
* and objects.
*
* @param q DMRS PDSCH object
* @param carrier Carrier configuration
*
* @return it returns SRSLTE_ERROR code if an error occurs, otherwise it returns SRSLTE_SUCCESS
*/
SRSLTE_API int srslte_dmrs_pdsch_set_carrier(srslte_dmrs_pdsch_t* q, const srslte_carrier_nr_t* carrier);
SRSLTE_API int srslte_dmrs_pdsch_put_sf(srslte_dmrs_pdsch_t* q, const srslte_dl_sf_cfg_t* sf, cf_t* sf_symbols); /**
* @brief Puts PDSCH DMRS into a given resource grid
*
* @param q DMRS PDSCH object
* @param slot_cfg Slot configuration
* @param pdsch_cfg PDSCH transmission configuration
* @param sf_symbols Resource grid
*
* @return it returns SRSLTE_ERROR code if an error occurs, otherwise it returns SRSLTE_SUCCESS
*/
SRSLTE_API int srslte_dmrs_pdsch_put_sf(srslte_dmrs_pdsch_t* q,
const srslte_dl_slot_cfg_t* slot_cfg,
const srslte_pdsch_cfg_nr_t* pdsch_cfg,
cf_t* sf_symbols);
SRSLTE_API int srslte_dmrs_pdsch_get_sf(srslte_dmrs_pdsch_t* q, /**
const srslte_dl_sf_cfg_t* sf, * @brief Estimates the channel for PDSCH from the DMRS
const cf_t* sf_symbols, *
cf_t* lest_square_estimates); * @attention Current implementation is thought for type1 PDSCH DMRS (1 pilot every 2 RE)
*
* @param q DMRS-PDSCH object
* @param slot_cfg Slot configuration
* @param sf_symbols Received resource grid
* @param[out] ce Channel estimates
*
* @return it returns SRSLTE_ERROR code if an error occurs, otherwise it returns SRSLTE_SUCCESS
*/
SRSLTE_API int srslte_dmrs_pdsch_estimate(srslte_dmrs_pdsch_t* q,
const srslte_dl_slot_cfg_t* slot_cfg,
const srslte_pdsch_cfg_nr_t* pdsch_cfg,
const cf_t* sf_symbols,
srslte_chest_dl_res_t* chest_res);
#ifdef __cplusplus #ifdef __cplusplus
} }

@ -123,7 +123,7 @@ typedef enum SRSLTE_API {
} srslte_search_space_type_t; } srslte_search_space_type_t;
/** /**
* @brief NR carrier parameters * @brief NR carrier parameters. It is a combination of fixed cell and bandwidth-part (BWP)
*/ */
typedef struct { typedef struct {
uint32_t id; uint32_t id;
@ -133,18 +133,38 @@ typedef struct {
} srslte_carrier_nr_t; } srslte_carrier_nr_t;
/** /**
* CORESET related constants * @brief NR Slot parameters. It contains parameters that change in a slot basis.
*/
typedef struct {
/// Slot index in the radio frame
uint32_t idx;
/// Left for future parameters
/// ...
} srslte_dl_slot_cfg_t;
/**
* @brief Min number of OFDM symbols in a control resource set.
*/ */
#define SRSLTE_CORESET_DURATION_MIN 1 #define SRSLTE_CORESET_DURATION_MIN 1
/**
* @brief Max number of OFDM symbols in a control resource set. Specified in TS 38.331 V15.10.0 as maxCoReSetDuration
*/
#define SRSLTE_CORESET_DURATION_MAX 3 #define SRSLTE_CORESET_DURATION_MAX 3
/**
* @brief Number of possible CORESET frequency resources.
*/
#define SRSLTE_CORESET_FREQ_DOMAIN_RES_SIZE 45 #define SRSLTE_CORESET_FREQ_DOMAIN_RES_SIZE 45
/**
* @brief Max value for shift index
*/
#define SRSLTE_CORESET_SHIFT_INDEX_MAX (SRSLTE_CORESET_NOF_PRB_MAX - 1) #define SRSLTE_CORESET_SHIFT_INDEX_MAX (SRSLTE_CORESET_NOF_PRB_MAX - 1)
/** /**
* CORESET structure * @brief CORESET parameters as defined in TS 38.331 V15.10.0 - ControlResourceSet
*
* Fields follow the same order than described in 3GPP 38.331 R15 - ControlResourceSet
*
*/ */
typedef struct SRSLTE_API { typedef struct SRSLTE_API {
srslte_coreset_mapping_type_t mapping_type; srslte_coreset_mapping_type_t mapping_type;
@ -171,6 +191,9 @@ typedef struct SRSLTE_API {
uint32_t nof_candidates[SRSLTE_SEARCH_SPACE_NOF_AGGREGATION_LEVELS]; uint32_t nof_candidates[SRSLTE_SEARCH_SPACE_NOF_AGGREGATION_LEVELS];
} srslte_search_space_t; } srslte_search_space_t;
/**
* @brief PDCCH configuration
*/
typedef struct SRSLTE_API { typedef struct SRSLTE_API {
srslte_carrier_nr_t carrier; srslte_carrier_nr_t carrier;
uint16_t rnti; uint16_t rnti;

@ -30,12 +30,68 @@
#ifndef SRSLTE_PDSCH_CFG_NR_H #ifndef SRSLTE_PDSCH_CFG_NR_H
#define SRSLTE_PDSCH_CFG_NR_H #define SRSLTE_PDSCH_CFG_NR_H
#include "srslte/phy/ch_estimation/dmrs_pdsch.h"
#include "srslte/phy/common/phy_common_nr.h" #include "srslte/phy/common/phy_common_nr.h"
#include "srslte/phy/fec/cbsegm.h" #include "srslte/phy/fec/cbsegm.h"
#include "srslte/phy/fec/softbuffer.h" #include "srslte/phy/fec/softbuffer.h"
#include "srslte/phy/phch/ra.h" #include "srslte/phy/phch/ra.h"
/**
* @brief PDSCH DMRS type
*/
typedef enum {
srslte_dmrs_pdsch_type_1 = 0, // 1 pilot every 2 sub-carriers (default)
srslte_dmrs_pdsch_type_2 // 2 consecutive pilots every 6 sub-carriers
} srslte_dmrs_pdsch_type_t;
/**
* @brief PDSCH DMRS length in symbols
*/
typedef enum {
srslte_dmrs_pdsch_len_1 = 0, // single, 1 symbol long (default)
srslte_dmrs_pdsch_len_2 // double, 2 symbol long
} srslte_dmrs_pdsch_len_t;
/**
* @brief Determines whether the first pilot goes into symbol index 2 or 3
*/
typedef enum {
srslte_dmrs_pdsch_typeA_pos_2 = 0, // Start in slot symbol index 2 (default)
srslte_dmrs_pdsch_typeA_pos_3 // Start in slot symbol index 3
} srslte_dmrs_pdsch_typeA_pos_t;
/**
* @brief Determines additional symbols if possible to be added
*/
typedef enum {
srslte_dmrs_pdsch_add_pos_2 = 0,
srslte_dmrs_pdsch_add_pos_0,
srslte_dmrs_pdsch_add_pos_1,
srslte_dmrs_pdsch_add_pos_3
} srslte_dmrs_pdsch_add_pos_t;
/**
* @brief Provides PDSCH DMRS configuration from higher layers
* @remark Parameters described in TS 38.331 V15.10.0
*/
typedef struct {
/// Parameters provided by IE DMRS-DownlinkConfig
srslte_dmrs_pdsch_type_t type;
srslte_dmrs_pdsch_add_pos_t additional_pos;
srslte_dmrs_pdsch_len_t length;
srslte_dmrs_pdsch_typeA_pos_t typeA_pos;
bool scrambling_id0_present;
uint32_t scrambling_id0;
bool scrambling_id1_present;
uint32_t scrambling_id1;
/// Parameters provided by ServingCellConfig
bool lte_CRS_to_match_around;
/// Parameters provided by FeatureSetDownlink-v1540
bool additional_DMRS_DL_Alt;
} srslte_pdsch_dmrs_cfg_t;
/** /**
* @brief flatten PDSCH time domain allocation parameters * @brief flatten PDSCH time domain allocation parameters
* @remark Described in TS 38.331 V15.10.0 Section PDSCH-TimeDomainResourceAllocationList * @remark Described in TS 38.331 V15.10.0 Section PDSCH-TimeDomainResourceAllocationList
@ -54,17 +110,28 @@ typedef struct SRSLTE_API {
} srslte_pdsch_allocation_t; } srslte_pdsch_allocation_t;
typedef struct SRSLTE_API { typedef struct SRSLTE_API {
/// TBD /// UE identifier
} srslte_pdsch_grant_nr_t; uint16_t rnti;
typedef struct SRSLTE_API { /// Time domain resources
srslte_pdsch_allocation_t allocation; uint32_t k0;
uint32_t S;
uint32_t L;
srslte_pdsch_mapping_type_t mapping;
/// Frequency domain resources
bool prb_idx[SRSLTE_MAX_PRB_NR];
/// PDSCH Start symbol index /// DMRS Scrambling sequence initialization (false: 0 or true: 1)
uint32_t S; bool n_scid;
/// PDSCH length in number of symbols /// Transport block
uint32_t L; /// ....
} srslte_pdsch_grant_nr_t;
typedef struct SRSLTE_API {
srslte_pdsch_grant_nr_t grant;
srslte_pdsch_dmrs_cfg_t dmrs_cfg;
} srslte_pdsch_cfg_nr_t; } srslte_pdsch_cfg_nr_t;
#endif // SRSLTE_PDSCH_CFG_NR_H #endif // SRSLTE_PDSCH_CFG_NR_H

@ -22,7 +22,7 @@
/****************************************************************************** /******************************************************************************
* @file ue_dl_nr.h * @file ue_dl_nr.h
* *
* Description: UE downlink object for NR dataplane. * Description: UE downlink object for NR data.
* *
* This module is a frontend to all the downlink data channel processing modules. * This module is a frontend to all the downlink data channel processing modules.
* *
@ -36,37 +36,32 @@
#include "srslte/phy/phch/pdsch_cfg_nr.h" #include "srslte/phy/phch/pdsch_cfg_nr.h"
/** /**
* @brief Calculates the PDSCH time resource provided by higher layers * @brief Calculates the PDSCH time resource provided by higher layers and stores it in the provided PDSCH NR grant.
* *
* @remark Defined by TS 36.214 V15.10.0 section 5.1.2.1.1 Determination of the resource allocation table to be used for * @remark Defined by TS 36.214 V15.10.0 section 5.1.2.1.1 Determination of the resource allocation table to be used for
* PDSCH * PDSCH
* *
* @param pdsch_alloc Flattened PHY PDSCH allocation configuration provided from higher layers * @param pdsch_alloc Flattened PHY PDSCH allocation configuration provided from higher layers
* @param[out] S Start symbol * @param[out] grant PDSCH mapping type
* @param[out] L PDSCH transmission length in symbols
* @return Returns SRSLTE_SUCCESS if the provided allocation is valid, otherwise it returns SRSLTE_ERROR code * @return Returns SRSLTE_SUCCESS if the provided allocation is valid, otherwise it returns SRSLTE_ERROR code
*/ */
SRSLTE_API int SRSLTE_API int srslte_ue_dl_nr_pdsch_time_resource_hl(const srslte_pdsch_allocation_t* pdsch_alloc,
srslte_ue_dl_nr_pdsch_time_resource_hl(const srslte_pdsch_allocation_t* pdsch_alloc, uint32_t* S, uint32_t* L); srslte_pdsch_grant_nr_t* grant);
/** /**
* @brief Calculates the PDSCH time resource default A. This can be used by SI-RNTI, RA-RNTI, P-RNTI and C-RNTI. See * @brief Calculates the PDSCH time resource default A and stores it in the provided PDSCH NR grant. This can be used by
* Table 5.1.2.1.1-1 for more details about the usage. * SI-RNTI, RA-RNTI, P-RNTI and C-RNTI. See Table 5.1.2.1.1-1 for more details about the usage.
* *
* @remark Defined by TS 36.214 V15.10.0 Table 5.1.2.1.1-2: Default PDSCH time domain resource allocation A for normal * @remark Defined by TS 38.214 V15.10.0 Table 5.1.2.1.1-2: Default PDSCH time domain resource allocation A for normal
* CP * CP
* *
* @attention k0 shall be zero.
*
* @param m Time domain resource assignment field value m of the DCI * @param m Time domain resource assignment field value m of the DCI
* @param dmrs_typeA_pos DMRS TypeA position provided by higher layers * @param dmrs_typeA_pos DMRS TypeA position provided by higher layers
* @param[out] S Start symbol * @param[out] grant PDSCH mapping type
* @param[out] L PDSCH transmission length in symbols
* @return Returns SRSLTE_SUCCESS if the provided allocation is valid, otherwise it returns SRSLTE_ERROR code * @return Returns SRSLTE_SUCCESS if the provided allocation is valid, otherwise it returns SRSLTE_ERROR code
*/ */
SRSLTE_API int srslte_ue_dl_nr_pdsch_time_resource_default_A(uint32_t m, SRSLTE_API int srslte_ue_dl_nr_pdsch_time_resource_default_A(uint32_t m,
srslte_dmrs_pdsch_typeA_pos_t dmrs_typeA_pos, srslte_dmrs_pdsch_typeA_pos_t dmrs_typeA_pos,
uint32_t* S, srslte_pdsch_grant_nr_t* grant);
uint32_t* L);
#endif // SRSLTE_UE_DL_NR_DATA_H #endif // SRSLTE_UE_DL_NR_DATA_H

@ -22,7 +22,7 @@
#include "srslte/phy/ch_estimation/dmrs_pdsch.h" #include "srslte/phy/ch_estimation/dmrs_pdsch.h"
#include <srslte/phy/utils/debug.h> #include <srslte/phy/utils/debug.h>
int srslte_dmrs_pdsch_cfg_to_str(const srslte_dmrs_pdsch_cfg_t* cfg, char* msg, uint32_t max_len) int srslte_dmrs_pdsch_cfg_to_str(const srslte_pdsch_dmrs_cfg_t* cfg, char* msg, uint32_t max_len)
{ {
int type = (int)cfg->type + 1; int type = (int)cfg->type + 1;
int typeA_pos = (int)cfg->typeA_pos + 2; int typeA_pos = (int)cfg->typeA_pos + 2;
@ -31,33 +31,207 @@ int srslte_dmrs_pdsch_cfg_to_str(const srslte_dmrs_pdsch_cfg_t* cfg, char* msg,
: cfg->additional_pos == srslte_dmrs_pdsch_add_pos_1 : cfg->additional_pos == srslte_dmrs_pdsch_add_pos_1
? 1 ? 1
: cfg->additional_pos == srslte_dmrs_pdsch_add_pos_2 ? 2 : 3; : cfg->additional_pos == srslte_dmrs_pdsch_add_pos_2 ? 2 : 3;
const char* len = cfg->length == srslte_dmrs_pdsch_len_1 ? "single" : "double"; const char* len = cfg->length == srslte_dmrs_pdsch_len_1 ? "single" : "double";
const char* mapping = cfg->mapping_type == srslte_pdsch_mapping_type_A ? "A" : "B";
return srslte_print_check(
return srslte_print_check(msg, msg, max_len, 0, "type=%d, typeA_pos=%d, add_pos=%d, len=%s", type, typeA_pos, additional_pos, len);
max_len, }
0,
"mapping=%s, type=%d, typeA_pos=%d, add_pos=%d, len=%s", static uint32_t
mapping, srslte_dmrs_get_pilots_type1(uint32_t start_prb, uint32_t nof_prb, uint32_t delta, const cf_t* symbols, cf_t* pilots)
type, {
typeA_pos, uint32_t count = 0;
additional_pos, uint32_t n_begin = start_prb * 3;
len); uint32_t n_enb = n_begin + nof_prb * 3;
for (uint32_t n = n_begin; n < n_enb; n++) {
for (uint32_t k_prime = 0; k_prime < 2; k_prime++, count++) {
pilots[count] = symbols[4 * n + 2 * k_prime + delta];
}
}
return count;
}
static uint32_t
srslte_dmrs_get_pilots_type2(uint32_t start_prb, uint32_t nof_prb, uint32_t delta, const cf_t* symbols, cf_t* pilots)
{
uint32_t count = 0;
uint32_t n_begin = start_prb * 2;
uint32_t n_enb = n_begin + nof_prb * 2;
for (uint32_t n = n_begin; n < n_enb; n++) {
for (uint32_t k_prime = 0; k_prime < 2; k_prime++, count++) {
pilots[count] = symbols[6 * n + k_prime + delta];
}
}
return count;
}
static uint32_t srslte_dmrs_get_lse(srslte_dmrs_pdsch_t* q,
srslte_sequence_state_t* sequence_state,
srslte_dmrs_pdsch_type_t dmrs_type,
uint32_t start_prb,
uint32_t nof_prb,
uint32_t delta,
const cf_t* symbols,
cf_t* least_square_estimates)
{
uint32_t count = 0;
switch (dmrs_type) {
case srslte_dmrs_pdsch_type_1:
count = srslte_dmrs_get_pilots_type1(start_prb, nof_prb, delta, symbols, least_square_estimates);
break;
case srslte_dmrs_pdsch_type_2:
count = srslte_dmrs_get_pilots_type2(start_prb, nof_prb, delta, symbols, least_square_estimates);
break;
default:
ERROR("Unknown DMRS type.\n");
}
// Generate sequence for the given pilots
srslte_sequence_state_gen_f(sequence_state, M_SQRT1_2, (float*)q->temp, count * 2);
// Calculate least square estimates
srslte_vec_prod_conj_ccc(least_square_estimates, q->temp, least_square_estimates, count);
return count;
}
static uint32_t
srslte_dmrs_put_pilots_type1(uint32_t start_prb, uint32_t nof_prb, uint32_t delta, cf_t* symbols, const cf_t* pilots)
{
uint32_t count = 0;
uint32_t n_begin = start_prb * 3;
uint32_t n_enb = n_begin + nof_prb * 3;
for (uint32_t n = n_begin; n < n_enb; n++) {
for (uint32_t k_prime = 0; k_prime < 2; k_prime++, count++) {
symbols[4 * n + 2 * k_prime + delta] = pilots[count];
}
}
return count;
}
static uint32_t
srslte_dmrs_put_pilots_type2(uint32_t start_prb, uint32_t nof_prb, uint32_t delta, cf_t* symbols, const cf_t* pilots)
{
uint32_t count = 0;
uint32_t n_begin = start_prb * 2;
uint32_t n_enb = n_begin + nof_prb * 2;
for (uint32_t n = n_begin; n < n_enb; n++) {
for (uint32_t k_prime = 0; k_prime < 2; k_prime++, count++) {
symbols[6 * n + k_prime + delta] = pilots[count];
}
}
return count;
}
static uint32_t srslte_dmrs_put_pilots(srslte_dmrs_pdsch_t* q,
srslte_sequence_state_t* sequence_state,
srslte_dmrs_pdsch_type_t dmrs_type,
uint32_t start_prb,
uint32_t nof_prb,
uint32_t delta,
cf_t* symbols)
{
uint32_t count = (dmrs_type == srslte_dmrs_pdsch_type_1) ? nof_prb * 6 : nof_prb * 4;
// Generate sequence for the given pilots
srslte_sequence_state_gen_f(sequence_state, M_SQRT1_2, (float*)q->temp, count * 2);
switch (dmrs_type) {
case srslte_dmrs_pdsch_type_1:
count = srslte_dmrs_put_pilots_type1(start_prb, nof_prb, delta, symbols, q->temp);
break;
case srslte_dmrs_pdsch_type_2:
count = srslte_dmrs_put_pilots_type2(start_prb, nof_prb, delta, symbols, q->temp);
break;
default:
ERROR("Unknown DMRS type.\n");
}
return count;
}
static int srslte_dmrs_pdsch_put_symbol(srslte_dmrs_pdsch_t* q,
const srslte_pdsch_cfg_nr_t* pdsch_cfg,
uint32_t cinit,
uint32_t delta,
cf_t* symbols)
{
uint32_t prb_count = 0; // Counts consecutive used PRB
uint32_t prb_start = 0; // Start consecutive used PRB
uint32_t prb_skip = 0; // Number of PRB to skip
uint32_t nof_pilots_x_prb = pdsch_cfg->dmrs_cfg.type == srslte_dmrs_pdsch_type_1 ? 6 : 4;
uint32_t pilot_count = 0;
// Initialise sequence
srslte_sequence_state_t sequence_state = {};
srslte_sequence_state_init(&sequence_state, cinit);
// Iterate over PRBs
for (uint32_t prb_idx = 0; prb_idx < q->carrier.nof_prb; prb_idx++) {
// If the PRB is used for PDSCH transmission count
if (pdsch_cfg->grant.prb_idx[prb_idx]) {
// If it is the first PRB...
if (prb_count == 0) {
// ... save first consecutive PRB in the group
prb_start = prb_idx;
// ... discard unused pilots and reset counter
srslte_sequence_state_advance(&sequence_state, prb_skip * nof_pilots_x_prb * 2);
prb_skip = 0;
}
prb_count++;
continue;
}
// Increase number of PRB to skip
prb_skip++;
// End of consecutive PRB, skip copying if no PRB was counted
if (prb_count == 0) {
continue;
}
// Get contiguous pilots
pilot_count += srslte_dmrs_put_pilots(
q, &sequence_state, pdsch_cfg->dmrs_cfg.type, prb_start, prb_count, delta, &symbols[prb_start * SRSLTE_NRE]);
// Reset counter
prb_count = 0;
}
if (prb_count > 0) {
pilot_count += srslte_dmrs_put_pilots(
q, &sequence_state, pdsch_cfg->dmrs_cfg.type, prb_start, prb_count, delta, &symbols[prb_start * SRSLTE_NRE]);
}
return pilot_count;
} }
// Implements 3GPP 38.211 R.15 Table 7.4.1.1.2-3 PDSCH mapping type A Single // Implements 3GPP 38.211 R.15 Table 7.4.1.1.2-3 PDSCH mapping type A Single
static int srslte_dmrs_pdsch_get_symbols_idx_mapping_type_A_single(const srslte_dmrs_pdsch_cfg_t* cfg, static int srslte_dmrs_pdsch_get_symbols_idx_mapping_type_A_single(const srslte_pdsch_cfg_nr_t* cfg,
uint32_t symbols[SRSLTE_DMRS_PDSCH_MAX_SYMBOLS]) uint32_t symbols[SRSLTE_DMRS_PDSCH_MAX_SYMBOLS])
{ {
int count = 0; int count = 0;
if (cfg->duration < SRSLTE_DMRS_PDSCH_TYPEA_SINGLE_DURATION_MIN) { if (cfg->grant.L < SRSLTE_DMRS_PDSCH_TYPEA_SINGLE_DURATION_MIN) {
ERROR("Duration is below the minimum\n"); ERROR("Duration is below the minimum\n");
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
// l0 = 3 if the higher-layer parameter dmrs-TypeA-Position is equal to 'pos3' and l0 = 2 otherwise // l0 = 3 if the higher-layer parameter dmrs-TypeA-Position is equal to 'pos3' and l0 = 2 otherwise
int l0 = (cfg->typeA_pos == srslte_dmrs_pdsch_typeA_pos_3) ? 3 : 2; int l0 = (cfg->dmrs_cfg.typeA_pos == srslte_dmrs_pdsch_typeA_pos_3) ? 3 : 2;
// For PDSCH mapping Type A single-symbol DM-RS, l1 = 11 except if all of the following conditions are fulfilled in // For PDSCH mapping Type A single-symbol DM-RS, l1 = 11 except if all of the following conditions are fulfilled in
// which case l1 = 12: // which case l1 = 12:
@ -65,23 +239,23 @@ static int srslte_dmrs_pdsch_get_symbols_idx_mapping_type_A_single(const srslte_
// - the higher-layer parameters dmrs-AdditionalPosition is equal to 'pos1' and l0 = 3; and // - the higher-layer parameters dmrs-AdditionalPosition is equal to 'pos1' and l0 = 3; and
// - the UE has indicated it is capable of additionalDMRS-DL-Alt // - the UE has indicated it is capable of additionalDMRS-DL-Alt
int l1 = 11; int l1 = 11;
if (cfg->lte_CRS_to_match_around && cfg->additional_pos == srslte_dmrs_pdsch_add_pos_1 && if (cfg->dmrs_cfg.lte_CRS_to_match_around && cfg->dmrs_cfg.additional_pos == srslte_dmrs_pdsch_add_pos_1 &&
cfg->typeA_pos == srslte_dmrs_pdsch_typeA_pos_3 && cfg->additional_DMRS_DL_Alt) { cfg->dmrs_cfg.typeA_pos == srslte_dmrs_pdsch_typeA_pos_3 && cfg->dmrs_cfg.additional_DMRS_DL_Alt) {
l1 = 12; l1 = 12;
} }
symbols[count] = l0; symbols[count] = l0;
count++; count++;
if (cfg->duration < 8 || cfg->additional_pos == srslte_dmrs_pdsch_add_pos_0) { if (cfg->grant.L < 8 || cfg->dmrs_cfg.additional_pos == srslte_dmrs_pdsch_add_pos_0) {
return count; return count;
} }
if (cfg->duration < 10) { if (cfg->grant.L < 10) {
symbols[count] = 7; symbols[count] = 7;
count++; count++;
} else if (cfg->duration < 12) { } else if (cfg->grant.L < 12) {
if (cfg->additional_pos > srslte_dmrs_pdsch_add_pos_2) { if (cfg->dmrs_cfg.additional_pos > srslte_dmrs_pdsch_add_pos_2) {
symbols[count] = 6; symbols[count] = 6;
count++; count++;
} }
@ -89,8 +263,8 @@ static int srslte_dmrs_pdsch_get_symbols_idx_mapping_type_A_single(const srslte_
symbols[count] = 9; symbols[count] = 9;
count++; count++;
} else if (cfg->duration == 12) { } else if (cfg->grant.L == 12) {
switch (cfg->additional_pos) { switch (cfg->dmrs_cfg.additional_pos) {
case srslte_dmrs_pdsch_add_pos_1: case srslte_dmrs_pdsch_add_pos_1:
symbols[count] = 9; symbols[count] = 9;
count++; count++;
@ -110,7 +284,7 @@ static int srslte_dmrs_pdsch_get_symbols_idx_mapping_type_A_single(const srslte_
count++; count++;
} }
} else { } else {
switch (cfg->additional_pos) { switch (cfg->dmrs_cfg.additional_pos) {
case srslte_dmrs_pdsch_add_pos_1: case srslte_dmrs_pdsch_add_pos_1:
symbols[count] = l1; symbols[count] = l1;
count++; count++;
@ -135,28 +309,28 @@ static int srslte_dmrs_pdsch_get_symbols_idx_mapping_type_A_single(const srslte_
} }
// Implements 3GPP 38.211 R.15 Table 7.4.1.1.2-4 PDSCH mapping type A Double // Implements 3GPP 38.211 R.15 Table 7.4.1.1.2-4 PDSCH mapping type A Double
static int srslte_dmrs_pdsch_get_symbols_idx_mapping_type_A_double(const srslte_dmrs_pdsch_cfg_t* cfg, static int srslte_dmrs_pdsch_get_symbols_idx_mapping_type_A_double(const srslte_pdsch_cfg_nr_t* cfg,
uint32_t symbols[SRSLTE_DMRS_PDSCH_MAX_SYMBOLS]) uint32_t symbols[SRSLTE_DMRS_PDSCH_MAX_SYMBOLS])
{ {
int count = 0; int count = 0;
if (cfg->duration < SRSLTE_DMRS_PDSCH_TYPEA_DOUBLE_DURATION_MIN) { if (cfg->grant.L < SRSLTE_DMRS_PDSCH_TYPEA_DOUBLE_DURATION_MIN) {
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
// l0 = 3 if the higher-layer parameter dmrs-TypeA-Position is equal to 'pos3' and l0 = 2 otherwise // l0 = 3 if the higher-layer parameter dmrs-TypeA-Position is equal to 'pos3' and l0 = 2 otherwise
int l0 = (cfg->typeA_pos == srslte_dmrs_pdsch_typeA_pos_3) ? 3 : 2; int l0 = (cfg->dmrs_cfg.typeA_pos == srslte_dmrs_pdsch_typeA_pos_3) ? 3 : 2;
symbols[count] = l0; symbols[count] = l0;
count++; count++;
symbols[count] = symbols[count - 1] + 1; symbols[count] = symbols[count - 1] + 1;
count++; count++;
if (cfg->duration < 10 || cfg->additional_pos == srslte_dmrs_pdsch_add_pos_0) { if (cfg->grant.L < 10 || cfg->dmrs_cfg.additional_pos == srslte_dmrs_pdsch_add_pos_0) {
return count; return count;
} }
if (cfg->duration < 13) { if (cfg->grant.L < 13) {
symbols[count] = 8; symbols[count] = 8;
count++; count++;
symbols[count] = symbols[count - 1] + 1; symbols[count] = symbols[count - 1] + 1;
@ -171,12 +345,13 @@ static int srslte_dmrs_pdsch_get_symbols_idx_mapping_type_A_double(const srslte_
return count; return count;
} }
static int srslte_dmrs_pdsch_get_symbols_idx(const srslte_dmrs_pdsch_cfg_t* cfg, uint32_t* symbols) int srslte_dmrs_pdsch_get_symbols_idx(const srslte_pdsch_cfg_nr_t* cfg, uint32_t symbols[SRSLTE_DMRS_PDSCH_MAX_SYMBOLS])
{ {
switch (cfg->mapping_type) { switch (cfg->grant.mapping) {
case srslte_pdsch_mapping_type_A: case srslte_pdsch_mapping_type_A:
// The case dmrs-AdditionalPosition equals to 'pos3' is only supported when dmrs-TypeA-Position is equal to 'pos2' // The case dmrs-AdditionalPosition equals to 'pos3' is only supported when dmrs-TypeA-Position is equal to 'pos2'
if (cfg->typeA_pos != srslte_dmrs_pdsch_typeA_pos_2 && cfg->additional_pos == srslte_dmrs_pdsch_add_pos_3) { if (cfg->dmrs_cfg.typeA_pos != srslte_dmrs_pdsch_typeA_pos_2 &&
cfg->dmrs_cfg.additional_pos == srslte_dmrs_pdsch_add_pos_3) {
ERROR("The case dmrs-AdditionalPosition equals to 'pos3' is only supported when dmrs-TypeA-Position is equal " ERROR("The case dmrs-AdditionalPosition equals to 'pos3' is only supported when dmrs-TypeA-Position is equal "
"to 'pos2'\n"); "to 'pos2'\n");
return SRSLTE_ERROR; return SRSLTE_ERROR;
@ -184,13 +359,13 @@ static int srslte_dmrs_pdsch_get_symbols_idx(const srslte_dmrs_pdsch_cfg_t* cfg,
// For PDSCH mapping type A, ld = 3 and ld = 4 symbols in Tables 7.4.1.1.2-3 and 7.4.1.1.2-4 respectively is only // For PDSCH mapping type A, ld = 3 and ld = 4 symbols in Tables 7.4.1.1.2-3 and 7.4.1.1.2-4 respectively is only
// applicable when dmrs-TypeA-Position is equal to 'pos2 // applicable when dmrs-TypeA-Position is equal to 'pos2
if ((cfg->duration == 3 || cfg->duration == 4) && cfg->typeA_pos != srslte_dmrs_pdsch_typeA_pos_2) { if ((cfg->grant.L == 3 || cfg->grant.L == 4) && cfg->dmrs_cfg.typeA_pos != srslte_dmrs_pdsch_typeA_pos_2) {
ERROR("For PDSCH mapping type A, ld = 3 and ld = 4 symbols in Tables 7.4.1.1.2-3 and 7.4.1.1.2-4 respectively " ERROR("For PDSCH mapping type A, ld = 3 and ld = 4 symbols in Tables 7.4.1.1.2-3 and 7.4.1.1.2-4 respectively "
"is only applicable when dmrs-TypeA-Position is equal to 'pos2\n"); "is only applicable when dmrs-TypeA-Position is equal to 'pos2\n");
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
if (cfg->length == srslte_dmrs_pdsch_len_1) { if (cfg->dmrs_cfg.length == srslte_dmrs_pdsch_len_1) {
return srslte_dmrs_pdsch_get_symbols_idx_mapping_type_A_single(cfg, symbols); return srslte_dmrs_pdsch_get_symbols_idx_mapping_type_A_single(cfg, symbols);
} }
return srslte_dmrs_pdsch_get_symbols_idx_mapping_type_A_double(cfg, symbols); return srslte_dmrs_pdsch_get_symbols_idx_mapping_type_A_double(cfg, symbols);
@ -202,20 +377,20 @@ static int srslte_dmrs_pdsch_get_symbols_idx(const srslte_dmrs_pdsch_cfg_t* cfg,
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
static int srslte_dmrs_pdsch_get_sc_idx(const srslte_dmrs_pdsch_cfg_t* cfg, uint32_t sc_idx[SRSLTE_NRE]) int srslte_dmrs_pdsch_get_sc_idx(const srslte_pdsch_dmrs_cfg_t* cfg, uint32_t max_count, uint32_t* sc_idx)
{ {
int count = 0; int count = 0;
uint32_t delta = 0; uint32_t delta = 0;
if (cfg->type == srslte_dmrs_pdsch_type_1) { if (cfg->type == srslte_dmrs_pdsch_type_1) {
for (uint32_t n = 0; n < SRSLTE_NRE; n += 4) { for (uint32_t n = 0; count < max_count; n += 4) {
for (uint32_t k_prime = 0; k_prime < 2; k_prime++) { for (uint32_t k_prime = 0; k_prime < 2 && count < max_count; k_prime++) {
sc_idx[count++] = n + 2 * k_prime + delta; sc_idx[count++] = n + 2 * k_prime + delta;
} }
} }
} else { } else {
for (uint32_t n = 0; n < SRSLTE_NRE; n += 6) { for (uint32_t n = 0; count < max_count; n += 6) {
for (uint32_t k_prime = 0; k_prime < 2; k_prime++) { for (uint32_t k_prime = 0; k_prime < 2 && count < max_count; k_prime++) {
sc_idx[count++] = n + k_prime + delta; sc_idx[count++] = n + k_prime + delta;
} }
} }
@ -224,122 +399,280 @@ static int srslte_dmrs_pdsch_get_sc_idx(const srslte_dmrs_pdsch_cfg_t* cfg, uint
return count; return count;
} }
static uint32_t srslte_dmrs_pdsch_seed(const srslte_dmrs_pdsch_cfg_t* cfg, uint32_t slot_idx, uint32_t symbol_idx) static uint32_t srslte_dmrs_pdsch_seed(const srslte_carrier_nr_t* carrier,
const srslte_pdsch_cfg_nr_t* cfg,
uint32_t slot_idx,
uint32_t symbol_idx)
{ {
return (uint32_t)(((((SRSLTE_MAX_NSYMB * slot_idx + symbol_idx + 1UL) * (2UL * cfg->n_id + 1UL)) << 17UL) + // Calculate scrambling IDs
(2UL * cfg->n_id + cfg->n_scid)) & uint32_t n_id = carrier->id;
uint32_t n_scid = (cfg->grant.n_scid) ? 1 : 0;
if (!cfg->grant.n_scid && cfg->dmrs_cfg.scrambling_id0_present) {
// n_scid = 0 and ID0 present
n_id = cfg->dmrs_cfg.scrambling_id0;
} else if (cfg->grant.n_scid && cfg->dmrs_cfg.scrambling_id1_present) {
// n_scid = 1 and ID1 present
n_id = cfg->dmrs_cfg.scrambling_id1;
}
return (uint32_t)(((((SRSLTE_MAX_NSYMB * slot_idx + symbol_idx + 1UL) * (2UL * n_id + 1UL)) << 17UL) +
(2UL * carrier->id + n_scid)) &
(uint64_t)INT32_MAX); (uint64_t)INT32_MAX);
} }
int srslte_dmrs_pdsch_init(srslte_dmrs_pdsch_t* q, const srslte_dmrs_pdsch_cfg_t* cfg) int srslte_dmrs_pdsch_init(srslte_dmrs_pdsch_t* q, bool is_ue)
{ {
// Copy new configuration if (q == NULL) {
q->cfg = *cfg; return SRSLTE_ERROR_INVALID_INPUTS;
// Calculate the symbols that carry PDSCH DMRS
int n = srslte_dmrs_pdsch_get_symbols_idx(&q->cfg, q->symbols_idx);
if (n < SRSLTE_SUCCESS) {
ERROR("Getting symbols indexes\n");
return n;
} }
q->nof_symbols = (uint32_t)n;
// Calculate the sub-carrier index that carry PDSCH DMRS if (is_ue) {
n = srslte_dmrs_pdsch_get_sc_idx(&q->cfg, q->sc_idx); q->is_ue = true;
if (n < SRSLTE_SUCCESS) {
ERROR("Getting sub-carriers indexes\n");
return n;
} }
q->nof_sc = (uint32_t)n;
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
} }
#define SRSLTE_DMRS_PDSCH_TEMP_PILOT_SIZE 64
int srslte_dmrs_pdsch_put_sf(srslte_dmrs_pdsch_t* q, const srslte_dl_sf_cfg_t* sf, cf_t* sf_symbols) void srslte_dmrs_pdsch_free(srslte_dmrs_pdsch_t* q)
{ {
uint32_t delta = 0; if (q == NULL) {
return;
}
// Iterate symbols srslte_interp_linear_free(&q->interpolator_type1);
for (uint32_t i = 0; i < q->nof_symbols; i++) { srslte_interp_linear_free(&q->interpolator_type2);
uint32_t l = q->symbols_idx[i]; // Symbol index inside the sub-frame if (q->pilot_estimates) {
uint32_t slot_idx = (sf->tti % SRSLTE_NOF_SF_X_FRAME) * SRSLTE_NOF_SLOTS_PER_SF; // Slot index in the frame free(q->pilot_estimates);
uint32_t symbol_sz = q->cfg.nof_prb * SRSLTE_NRE; // Symbol size in resource elements }
if (q->temp) {
srslte_sequence_state_t sequence_state = {}; free(q->temp);
srslte_sequence_state_init(&sequence_state, srslte_dmrs_pdsch_seed(&q->cfg, slot_idx, l)); }
}
// Generate
uint32_t k_end = q->cfg.nof_prb * SRSLTE_NRE; int srslte_dmrs_pdsch_set_carrier(srslte_dmrs_pdsch_t* q, const srslte_carrier_nr_t* carrier)
for (uint32_t k = delta; k < k_end;) { {
bool nof_prb_changed = q->carrier.nof_prb != carrier->nof_prb;
cf_t temp_pilots[SRSLTE_DMRS_PDSCH_TEMP_PILOT_SIZE] = {};
srslte_sequence_state_gen_f( // Set carrier
&sequence_state, M_SQRT1_2, (float*)temp_pilots, 2 * SRSLTE_DMRS_PDSCH_TEMP_PILOT_SIZE); q->carrier = *carrier;
switch (q->cfg.type) {
if (!q->is_ue) {
case srslte_dmrs_pdsch_type_1: return SRSLTE_SUCCESS;
for (uint32_t idx = 0; idx < SRSLTE_DMRS_PDSCH_TEMP_PILOT_SIZE && k < k_end; k += 2) { }
sf_symbols[l * symbol_sz + k] = temp_pilots[idx++];
} // Free interpolator
break; if (nof_prb_changed) {
case srslte_dmrs_pdsch_type_2: srslte_interp_linear_free(&q->interpolator_type1);
for (uint32_t idx = 0; idx < SRSLTE_DMRS_PDSCH_TEMP_PILOT_SIZE && k < k_end; k += 6) { srslte_interp_linear_free(&q->interpolator_type2);
sf_symbols[l * symbol_sz + k] = temp_pilots[idx++];
sf_symbols[l * symbol_sz + k + 1] = temp_pilots[idx++]; if (srslte_interp_linear_init(&q->interpolator_type1, carrier->nof_prb * SRSLTE_NRE / 2, 2) != SRSLTE_SUCCESS) {
} return SRSLTE_ERROR;
break; }
} if (srslte_interp_linear_init(&q->interpolator_type2, carrier->nof_prb * SRSLTE_NRE / 3, 6) != SRSLTE_SUCCESS) {
return SRSLTE_ERROR;
}
}
if (q->max_nof_prb < carrier->nof_prb) {
q->max_nof_prb = carrier->nof_prb;
if (q->pilot_estimates) {
free(q->pilot_estimates);
}
// The maximum number of pilots is for Type 1
q->pilot_estimates = srslte_vec_cf_malloc(SRSLTE_DMRS_PDSCH_MAX_SYMBOLS * q->max_nof_prb * SRSLTE_NRE / 2);
if (!q->pilot_estimates) {
ERROR("malloc\n");
return SRSLTE_ERROR;
}
if (q->temp) {
free(q->temp);
}
q->temp = srslte_vec_cf_malloc(q->max_nof_prb * SRSLTE_NRE);
if (!q->temp) {
ERROR("malloc\n");
return SRSLTE_ERROR;
} }
} }
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
} }
int srslte_dmrs_pdsch_get_sf(srslte_dmrs_pdsch_t* q, int srslte_dmrs_pdsch_put_sf(srslte_dmrs_pdsch_t* q,
const srslte_dl_sf_cfg_t* sf, const srslte_dl_slot_cfg_t* slot_cfg,
const cf_t* sf_symbols, const srslte_pdsch_cfg_nr_t* pdsch_cfg,
cf_t* least_square_estimates) cf_t* sf_symbols)
{ {
uint32_t delta = 0; uint32_t delta = 0;
if (q == NULL || slot_cfg == NULL || pdsch_cfg == NULL || sf_symbols == NULL) {
return SRSLTE_ERROR_INVALID_INPUTS;
}
uint32_t symbol_sz = q->carrier.nof_prb * SRSLTE_NRE; // Symbol size in resource elements
// Get symbols indexes
uint32_t symbols[SRSLTE_DMRS_PDSCH_MAX_SYMBOLS] = {};
int nof_symbols = srslte_dmrs_pdsch_get_symbols_idx(pdsch_cfg, symbols);
if (nof_symbols < SRSLTE_SUCCESS) {
return SRSLTE_ERROR;
}
// Iterate symbols // Iterate symbols
for (uint32_t i = 0; i < q->nof_symbols; i++) { for (uint32_t i = 0; i < nof_symbols; i++) {
uint32_t l = q->symbols_idx[i]; // Symbol index inside the sub-frame uint32_t l = symbols[i]; // Symbol index inside the slot
uint32_t slot_idx = (sf->tti % SRSLTE_NOF_SF_X_FRAME) * SRSLTE_NOF_SLOTS_PER_SF; // Slot index in the frame uint32_t slot_idx = slot_cfg->idx; // Slot index in the frame
uint32_t symbol_sz = q->cfg.nof_prb * SRSLTE_NRE; // Symbol size in resource elements uint32_t cinit = srslte_dmrs_pdsch_seed(&q->carrier, pdsch_cfg, slot_idx, l);
srslte_sequence_state_t sequence_state = {}; srslte_dmrs_pdsch_put_symbol(q, pdsch_cfg, cinit, delta, &sf_symbols[symbol_sz * l]);
srslte_sequence_state_init(&sequence_state, srslte_dmrs_pdsch_seed(&q->cfg, slot_idx, l)); }
uint32_t n_end = q->cfg.nof_prb * SRSLTE_NRE; return SRSLTE_SUCCESS;
for (uint32_t n = 0; n < n_end;) { }
cf_t temp_pilots[SRSLTE_DMRS_PDSCH_TEMP_PILOT_SIZE]; static int srslte_dmrs_pdsch_get_symbol(srslte_dmrs_pdsch_t* q,
srslte_sequence_state_gen_f( const srslte_pdsch_cfg_nr_t* pdsch_cfg,
&sequence_state, M_SQRT1_2, (float*)temp_pilots, 2 * SRSLTE_DMRS_PDSCH_TEMP_PILOT_SIZE); uint32_t cinit,
uint32_t delta,
switch (q->cfg.type) { const cf_t* symbols,
cf_t* least_square_estimates)
case srslte_dmrs_pdsch_type_1: {
for (uint32_t idx = 0; idx < SRSLTE_DMRS_PDSCH_TEMP_PILOT_SIZE && n < n_end; n += 4) { uint32_t prb_count = 0; // Counts consecutive used PRB
for (uint32_t k_prime = 0; k_prime < 2; k_prime++) { uint32_t prb_start = 0; // Start consecutive used PRB
uint32_t k = n + 2 * k_prime + delta; uint32_t prb_skip = 0; // Number of PRB to skip
*(least_square_estimates++) = sf_symbols[l * symbol_sz + k] * conjf(temp_pilots[idx++]); uint32_t nof_pilots_x_prb = pdsch_cfg->dmrs_cfg.type == srslte_dmrs_pdsch_type_1 ? 6 : 4;
} uint32_t pilot_count = 0;
}
break; // Initialise sequence
case srslte_dmrs_pdsch_type_2: srslte_sequence_state_t sequence_state = {};
for (uint32_t idx = 0; idx < SRSLTE_DMRS_PDSCH_TEMP_PILOT_SIZE && n < n_end; n += 6) { srslte_sequence_state_init(&sequence_state, cinit);
for (uint32_t k_prime = 0; k_prime < 2; k_prime++) {
uint32_t k = n + k_prime + delta; // Iterate over PRBs
*(least_square_estimates++) = sf_symbols[l * symbol_sz + k] * conjf(temp_pilots[idx++]); for (uint32_t prb_idx = 0; prb_idx < q->carrier.nof_prb; prb_idx++) {
} // If the PRB is used for PDSCH transmission count
} if (pdsch_cfg->grant.prb_idx[prb_idx]) {
break; // If it is the first PRB...
if (prb_count == 0) {
// ... save first consecutive PRB in the group
prb_start = prb_idx;
// ... discard unused pilots and reset counter
srslte_sequence_state_advance(&sequence_state, prb_skip * nof_pilots_x_prb * 2);
prb_skip = 0;
} }
prb_count++;
continue;
}
// Increase number of PRB to skip
prb_skip++;
// End of consecutive PRB, skip copying if no PRB was counted
if (prb_count == 0) {
continue;
} }
// Get contiguous pilots
pilot_count += srslte_dmrs_get_lse(q,
&sequence_state,
pdsch_cfg->dmrs_cfg.type,
prb_start,
prb_count,
delta,
&symbols[prb_start * SRSLTE_NRE],
&least_square_estimates[pilot_count]);
// Reset counter
prb_count = 0;
}
if (prb_count > 0) {
pilot_count += srslte_dmrs_get_lse(q,
&sequence_state,
pdsch_cfg->dmrs_cfg.type,
prb_start,
prb_count,
delta,
&symbols[prb_start * SRSLTE_NRE],
&least_square_estimates[pilot_count]);
}
return pilot_count;
}
int srslte_dmrs_pdsch_estimate(srslte_dmrs_pdsch_t* q,
const srslte_dl_slot_cfg_t* slot_cfg,
const srslte_pdsch_cfg_nr_t* pdsch_cfg,
const cf_t* sf_symbols,
srslte_chest_dl_res_t* chest_res)
{
const uint32_t delta = 0;
if (q == NULL || slot_cfg == NULL || sf_symbols == NULL || chest_res == NULL) {
return SRSLTE_ERROR_INVALID_INPUTS;
}
cf_t* ce = chest_res->ce[0][0];
uint32_t symbol_sz = q->carrier.nof_prb * SRSLTE_NRE; // Symbol size in resource elements
// Get symbols indexes
uint32_t symbols[SRSLTE_DMRS_PDSCH_MAX_SYMBOLS] = {};
int nof_symbols = srslte_dmrs_pdsch_get_symbols_idx(pdsch_cfg, symbols);
if (nof_symbols < SRSLTE_SUCCESS) {
return SRSLTE_ERROR;
}
uint32_t nof_pilots_x_symbol = 0;
// Iterate symbols
for (uint32_t i = 0; i < nof_symbols; i++) {
uint32_t l = symbols[i]; // Symbol index inside the slot
uint32_t cinit = srslte_dmrs_pdsch_seed(&q->carrier, pdsch_cfg, slot_cfg->idx, l);
nof_pilots_x_symbol = srslte_dmrs_pdsch_get_symbol(
q, pdsch_cfg, cinit, delta, &sf_symbols[symbol_sz * l], &q->pilot_estimates[nof_pilots_x_symbol * i]);
}
// Perform measurements here
// ...
// Average over time, only if more than one DMRS symbol
for (uint32_t i = 1; i < nof_symbols; i++) {
srslte_vec_sum_ccc(
q->pilot_estimates, &q->pilot_estimates[nof_pilots_x_symbol * i], q->pilot_estimates, nof_pilots_x_symbol);
}
if (nof_symbols > 0) {
srslte_vec_sc_prod_cfc(q->pilot_estimates, 1.0f / (float)nof_symbols, q->pilot_estimates, nof_pilots_x_symbol);
} }
// Frequency domain interpolate
uint32_t nof_re_x_symbol =
(pdsch_cfg->dmrs_cfg.type == srslte_dmrs_pdsch_type_1) ? nof_pilots_x_symbol * 2 : nof_pilots_x_symbol * 3;
if (pdsch_cfg->dmrs_cfg.type == srslte_dmrs_pdsch_type_1) {
// Prepare interpolator
srslte_interp_linear_resize(&q->interpolator_type1, nof_pilots_x_symbol, 2);
// Interpolate
srslte_interp_linear_offset(&q->interpolator_type1, q->pilot_estimates, ce, delta, 2 - delta);
} else {
// Prepare interpolator
srslte_interp_linear_resize(&q->interpolator_type2, nof_pilots_x_symbol, 3);
// Interpolate
srslte_interp_linear_offset(&q->interpolator_type2, q->pilot_estimates, ce, delta, 3 - delta);
}
// Time domain hold
for (uint32_t i = 1; i < pdsch_cfg->grant.L; i++) {
srslte_vec_cf_copy(&ce[i * nof_re_x_symbol], ce, nof_re_x_symbol);
}
// Set other values in the estimation result
chest_res->nof_re = nof_re_x_symbol * pdsch_cfg->grant.L;
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
} }

@ -20,32 +20,32 @@
*/ */
#include "srslte/common/test_common.h" #include "srslte/common/test_common.h"
#include "srslte/phy/ch_estimation/dmrs_pdsch.h"
#include "srslte/phy/ue/ue_dl_nr_data.h"
#include "srslte/srslte.h" #include "srslte/srslte.h"
#include <complex.h> #include <complex.h>
#include <srslte/phy/ch_estimation/dmrs_pdsch.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <strings.h> #include <strings.h>
#include <unistd.h> #include <unistd.h>
static srslte_cell_t cell = {50, // nof_prb static srslte_carrier_nr_t carrier = {
1, // nof_ports 0, // cell_id
1, // cell_id 0, // numerology
SRSLTE_CP_NORM, // cyclic prefix 50, // nof_prb
SRSLTE_PHICH_NORM, 0 // start
SRSLTE_PHICH_R_1, // PHICH length };
SRSLTE_FDD};
typedef struct { typedef struct {
srslte_pdsch_mapping_type_t mapping_type; srslte_pdsch_mapping_type_t mapping_type;
srslte_dmrs_pdsch_typeA_pos_t typeA_pos; srslte_dmrs_pdsch_typeA_pos_t typeA_pos;
srslte_dmrs_pdsch_len_t max_length; srslte_dmrs_pdsch_len_t max_length;
srslte_dmrs_pdsch_add_pos_t additional_pos; srslte_dmrs_pdsch_add_pos_t additional_pos;
srslte_dmrs_pdsch_type_t type; srslte_dmrs_pdsch_type_t type;
uint32_t symbol_idx[SRSLTE_DMRS_PDSCH_MAX_SYMBOLS]; uint32_t symbol_idx[SRSLTE_DMRS_PDSCH_MAX_SYMBOLS];
uint32_t nof_symbols; uint32_t nof_symbols;
uint32_t sc_idx[SRSLTE_NRE]; uint32_t sc_idx[SRSLTE_NRE];
uint32_t nof_sc; uint32_t nof_sc;
} golden_t; } golden_t;
// Golden values extracted from https://www.sharetechnote.com/html/5G/5G_PDSCH_DMRS.html // Golden values extracted from https://www.sharetechnote.com/html/5G/5G_PDSCH_DMRS.html
@ -136,10 +136,9 @@ void usage(char* prog)
{ {
printf("Usage: %s [recov]\n", prog); printf("Usage: %s [recov]\n", prog);
printf("\t-r nof_prb [Default %d]\n", cell.nof_prb); 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", cell.id); printf("\t-c cell_id [Default %d]\n", carrier.id);
printf("\t-v increase verbosity\n"); printf("\t-v increase verbosity\n");
} }
@ -147,16 +146,13 @@ void usage(char* prog)
void parse_args(int argc, char** argv) void parse_args(int argc, char** argv)
{ {
int opt; int opt;
while ((opt = getopt(argc, argv, "recov")) != -1) { while ((opt = getopt(argc, argv, "rcov")) != -1) {
switch (opt) { switch (opt) {
case 'r': case 'r':
cell.nof_prb = (uint32_t)strtol(argv[optind], NULL, 10); carrier.nof_prb = (uint32_t)strtol(argv[optind], NULL, 10);
break;
case 'e':
cell.cp = SRSLTE_CP_EXT;
break; break;
case 'c': case 'c':
cell.id = (uint32_t)strtol(argv[optind], NULL, 10); carrier.id = (uint32_t)strtol(argv[optind], NULL, 10);
break; break;
case 'v': case 'v':
srslte_verbose++; srslte_verbose++;
@ -168,37 +164,48 @@ void parse_args(int argc, char** argv)
} }
} }
static int assert_cfg(srslte_dmrs_pdsch_t* dmrs_pdsch) static int assert_cfg(const srslte_pdsch_cfg_nr_t* pdsch_cfg)
{ {
for (uint32_t i = 0; gold[i].nof_sc != 0; i++) { for (uint32_t i = 0; gold[i].nof_sc != 0; i++) {
if (dmrs_pdsch->cfg.mapping_type != gold[i].mapping_type) { // Gold examples are done for more than 12 symbols
if (pdsch_cfg->grant.L <= 12) {
continue;
}
if (pdsch_cfg->grant.mapping != gold[i].mapping_type) {
continue; continue;
} }
if (dmrs_pdsch->cfg.typeA_pos != gold[i].typeA_pos) { if (pdsch_cfg->dmrs_cfg.typeA_pos != gold[i].typeA_pos) {
continue; continue;
} }
if (dmrs_pdsch->cfg.additional_pos != gold[i].additional_pos) { if (pdsch_cfg->dmrs_cfg.additional_pos != gold[i].additional_pos) {
continue; continue;
} }
if (dmrs_pdsch->cfg.length != gold[i].max_length) { if (pdsch_cfg->dmrs_cfg.length != gold[i].max_length) {
continue; continue;
} }
if (dmrs_pdsch->cfg.type != gold[i].type) { if (pdsch_cfg->dmrs_cfg.type != gold[i].type) {
continue; continue;
} }
TESTASSERT(dmrs_pdsch->nof_symbols == gold[i].nof_symbols); uint32_t symbols[SRSLTE_DMRS_PDSCH_MAX_SYMBOLS] = {};
int nof_symbols = srslte_dmrs_pdsch_get_symbols_idx(pdsch_cfg, symbols);
TESTASSERT(nof_symbols == gold[i].nof_symbols);
for (uint32_t j = 0; j < gold[i].nof_symbols; j++) { for (uint32_t j = 0; j < gold[i].nof_symbols; j++) {
TESTASSERT(dmrs_pdsch->symbols_idx[j] == gold[i].symbol_idx[j]); TESTASSERT(symbols[j] == gold[i].symbol_idx[j]);
} }
uint32_t sc[SRSLTE_NRE] = {};
srslte_dmrs_pdsch_get_sc_idx(&pdsch_cfg->dmrs_cfg, SRSLTE_NRE, sc);
for (uint32_t j = 0; j < gold[i].nof_sc; j++) { for (uint32_t j = 0; j < gold[i].nof_sc; j++) {
TESTASSERT(dmrs_pdsch->sc_idx[j] == gold[i].sc_idx[j]); TESTASSERT(sc[j] == gold[i].sc_idx[j]);
} }
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
@ -207,25 +214,25 @@ static int assert_cfg(srslte_dmrs_pdsch_t* dmrs_pdsch)
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
} }
static int run_test(srslte_dmrs_pdsch_t* dmrs_pdsch, cf_t* sf_symbols, cf_t* h) static int run_test(srslte_dmrs_pdsch_t* dmrs_pdsch,
const srslte_pdsch_cfg_nr_t* pdsch_cfg,
cf_t* sf_symbols,
srslte_chest_dl_res_t* chest_res)
{ {
TESTASSERT(dmrs_pdsch->nof_symbols > 0); TESTASSERT(assert_cfg(pdsch_cfg) == SRSLTE_SUCCESS);
TESTASSERT(dmrs_pdsch->nof_sc > 0);
TESTASSERT(assert_cfg(dmrs_pdsch) == SRSLTE_SUCCESS);
srslte_dl_sf_cfg_t dl_sf = {}; srslte_dl_slot_cfg_t slot_cfg = {};
for (dl_sf.tti = 0; dl_sf.tti < SRSLTE_NOF_SF_X_FRAME; dl_sf.tti++) { for (slot_cfg.idx = 0; slot_cfg.idx < SRSLTE_NSLOTS_PER_FRAME_NR(dmrs_pdsch->carrier.numerology); slot_cfg.idx++) {
srslte_dmrs_pdsch_put_sf(dmrs_pdsch, &dl_sf, sf_symbols); srslte_dmrs_pdsch_put_sf(dmrs_pdsch, &slot_cfg, pdsch_cfg, sf_symbols);
srslte_dmrs_pdsch_get_sf(dmrs_pdsch, &dl_sf, sf_symbols, h); srslte_dmrs_pdsch_estimate(dmrs_pdsch, &slot_cfg, pdsch_cfg, sf_symbols, chest_res);
float mse = 0.0f; float mse = 0.0f;
for (uint32_t i = 0; i < dmrs_pdsch->nof_symbols * dmrs_pdsch->nof_sc * SRSLTE_NRE; i++) { for (uint32_t i = 0; i < chest_res->nof_re; i++) {
cf_t err = h[i] - 1.0f; cf_t err = chest_res->ce[0][0][i] - 1.0f;
mse += cabsf(err); mse += cabsf(err);
} }
mse /= (float)dmrs_pdsch->nof_symbols * dmrs_pdsch->nof_sc; mse /= (float)chest_res->nof_re;
TESTASSERT(!isnan(mse)); TESTASSERT(!isnan(mse));
TESTASSERT(mse < 1e-6f); TESTASSERT(mse < 1e-6f);
@ -240,66 +247,95 @@ int main(int argc, char** argv)
parse_args(argc, argv); parse_args(argc, argv);
srslte_dmrs_pdsch_cfg_t cfg = {}; srslte_dmrs_pdsch_t dmrs_pdsch = {};
cfg.duration = SRSLTE_NOF_SLOTS_PER_SF * SRSLTE_MAX_NSYMB; srslte_pdsch_cfg_nr_t pdsch_cfg = {};
cfg.nof_prb = cell.nof_prb; srslte_chest_dl_res_t chest_dl_res = {};
uint32_t nof_re = cell.nof_prb * SRSLTE_NRE * SRSLTE_NOF_SLOTS_PER_SF * SRSLTE_MAX_NSYMB; 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* 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_counter = 0;
uint32_t test_passed = 0; uint32_t test_passed = 0;
for (cfg.type = srslte_dmrs_pdsch_type_1; cfg.type <= srslte_dmrs_pdsch_type_2; cfg.type++) { // Initialise object DMRS for PDSCH
srslte_dmrs_pdsch_typeA_pos_t typeA_pos_begin = srslte_dmrs_pdsch_typeA_pos_2; if (srslte_dmrs_pdsch_init(&dmrs_pdsch, true) != SRSLTE_SUCCESS) {
srslte_dmrs_pdsch_typeA_pos_t typeA_pos_end = srslte_dmrs_pdsch_typeA_pos_3; ERROR("Init\n");
goto clean_exit;
}
for (cfg.typeA_pos = typeA_pos_begin; cfg.typeA_pos <= typeA_pos_end; cfg.typeA_pos++) { // Set carrier configuration
srslte_dmrs_pdsch_add_pos_t add_pos_begin = srslte_dmrs_pdsch_add_pos_2; if (srslte_dmrs_pdsch_set_carrier(&dmrs_pdsch, &carrier) != SRSLTE_SUCCESS) {
srslte_dmrs_pdsch_add_pos_t add_pos_end = srslte_dmrs_pdsch_add_pos_3; ERROR("Setting carrier\n");
goto clean_exit;
}
if (cfg.typeA_pos == srslte_dmrs_pdsch_typeA_pos_3) { if (srslte_chest_dl_res_init(&chest_dl_res, carrier.nof_prb) != SRSLTE_SUCCESS) {
add_pos_end = srslte_dmrs_pdsch_add_pos_1; ERROR("Initiating channel estimation result\n");
} goto clean_exit;
}
for (cfg.additional_pos = add_pos_begin; cfg.additional_pos <= add_pos_end; cfg.additional_pos++) { // For each DCI m param
for (uint32_t m = 0; m < 16; m++) {
srslte_dmrs_pdsch_type_t type_begin = srslte_dmrs_pdsch_type_1;
srslte_dmrs_pdsch_type_t type_end = srslte_dmrs_pdsch_type_2;
srslte_dmrs_pdsch_len_t max_len_begin = srslte_dmrs_pdsch_len_1; for (pdsch_cfg.dmrs_cfg.type = type_begin; pdsch_cfg.dmrs_cfg.type <= type_end; pdsch_cfg.dmrs_cfg.type++) {
srslte_dmrs_pdsch_len_t max_len_end = srslte_dmrs_pdsch_len_2; srslte_dmrs_pdsch_typeA_pos_t typeA_pos_begin = srslte_dmrs_pdsch_typeA_pos_2;
srslte_dmrs_pdsch_typeA_pos_t typeA_pos_end = srslte_dmrs_pdsch_typeA_pos_3;
for (cfg.length = max_len_begin; cfg.length <= max_len_end; cfg.length++) { for (pdsch_cfg.dmrs_cfg.typeA_pos = typeA_pos_begin; pdsch_cfg.dmrs_cfg.typeA_pos <= typeA_pos_end;
srslte_dmrs_pdsch_t dmrs_pdsch = {}; pdsch_cfg.dmrs_cfg.typeA_pos++) {
srslte_dmrs_pdsch_add_pos_t add_pos_begin = srslte_dmrs_pdsch_add_pos_2;
srslte_dmrs_pdsch_add_pos_t add_pos_end = srslte_dmrs_pdsch_add_pos_3;
// Initialise object with current configuration if (pdsch_cfg.dmrs_cfg.typeA_pos == srslte_dmrs_pdsch_typeA_pos_3) {
if (srslte_dmrs_pdsch_init(&dmrs_pdsch, &cfg)) { add_pos_end = srslte_dmrs_pdsch_add_pos_1;
ERROR("Error initialising PDSCH DMRS\n"); }
continue;
}
int n = run_test(&dmrs_pdsch, sf_symbols, h);
if (n == SRSLTE_SUCCESS) { for (pdsch_cfg.dmrs_cfg.additional_pos = add_pos_begin; pdsch_cfg.dmrs_cfg.additional_pos <= add_pos_end;
test_passed++; pdsch_cfg.dmrs_cfg.additional_pos++) {
} else {
char str[64] = {};
srslte_dmrs_pdsch_cfg_to_str(&cfg, str, 64);
ERROR("Test %d failed. %s.\n", test_counter, str); srslte_dmrs_pdsch_len_t max_len_begin = srslte_dmrs_pdsch_len_1;
} srslte_dmrs_pdsch_len_t max_len_end = srslte_dmrs_pdsch_len_2;
for (pdsch_cfg.dmrs_cfg.length = max_len_begin; pdsch_cfg.dmrs_cfg.length <= max_len_end;
pdsch_cfg.dmrs_cfg.length++) {
for (uint32_t bw = 1; bw <= carrier.nof_prb; bw++) {
for (uint32_t i = 0; i < carrier.nof_prb; i++) {
pdsch_cfg.grant.prb_idx[i] = (i < bw);
}
// Load default type A grant
srslte_ue_dl_nr_pdsch_time_resource_default_A(0, pdsch_cfg.dmrs_cfg.typeA_pos, &pdsch_cfg.grant);
int n = run_test(&dmrs_pdsch, &pdsch_cfg, sf_symbols, &chest_dl_res);
test_counter++; if (n == SRSLTE_SUCCESS) {
test_passed++;
} else {
char str[64] = {};
srslte_dmrs_pdsch_cfg_to_str(&pdsch_cfg.dmrs_cfg, str, 64);
ERROR("Test %d failed. %s.\n", test_counter, str);
}
test_counter++;
}
}
} }
} }
} }
} }
clean_exit:
if (sf_symbols) { if (sf_symbols) {
free(sf_symbols); free(sf_symbols);
} }
srslte_chest_dl_res_free(&chest_dl_res);
if (h) { srslte_dmrs_pdsch_free(&dmrs_pdsch);
free(h);
}
ret = test_passed == test_counter ? SRSLTE_SUCCESS : SRSLTE_ERROR; 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); printf("%s, %d of %d test passed successfully.\n", ret ? "Failed" : "Passed", test_passed, test_counter);

@ -19,6 +19,7 @@
* *
*/ */
#include "srslte/phy/ue/ue_dl_nr_data.h" #include "srslte/phy/ue/ue_dl_nr_data.h"
#include "srslte/phy/utils/debug.h"
static int srslte_ue_dl_nr_pdsch_time_resource_hl_A(uint32_t sliv, uint32_t* S, uint32_t* L) static int srslte_ue_dl_nr_pdsch_time_resource_hl_A(uint32_t sliv, uint32_t* S, uint32_t* L)
{ {
@ -63,26 +64,28 @@ static int srslte_ue_dl_nr_pdsch_time_resource_hl_B(uint32_t sliv, uint32_t* S,
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
int srslte_ue_dl_nr_pdsch_time_resource_hl(const srslte_pdsch_allocation_t* pdsch_alloc, uint32_t* S, uint32_t* L) int srslte_ue_dl_nr_pdsch_time_resource_hl(const srslte_pdsch_allocation_t* pdsch_alloc, srslte_pdsch_grant_nr_t* grant)
{ {
if (pdsch_alloc == NULL || S == NULL || L == NULL) { if (pdsch_alloc == NULL || grant == NULL) {
return SRSLTE_ERROR_INVALID_INPUTS; return SRSLTE_ERROR_INVALID_INPUTS;
} }
grant->k0 = pdsch_alloc->k0;
grant->mapping = pdsch_alloc->mapping_type;
if (pdsch_alloc->mapping_type == srslte_pdsch_mapping_type_A) { if (pdsch_alloc->mapping_type == srslte_pdsch_mapping_type_A) {
return srslte_ue_dl_nr_pdsch_time_resource_hl_A(pdsch_alloc->sliv, S, L); return srslte_ue_dl_nr_pdsch_time_resource_hl_A(pdsch_alloc->sliv, &grant->S, &grant->L);
} }
return srslte_ue_dl_nr_pdsch_time_resource_hl_B(pdsch_alloc->sliv, S, L); return srslte_ue_dl_nr_pdsch_time_resource_hl_B(pdsch_alloc->sliv, &grant->S, &grant->L);
} }
int srslte_ue_dl_nr_pdsch_time_resource_default_A(uint32_t m, int srslte_ue_dl_nr_pdsch_time_resource_default_A(uint32_t m,
srslte_dmrs_pdsch_typeA_pos_t dmrs_typeA_pos, srslte_dmrs_pdsch_typeA_pos_t dmrs_typeA_pos,
uint32_t* S, srslte_pdsch_grant_nr_t* grant)
uint32_t* L)
{ {
if (S == NULL || L == NULL) { if (grant == NULL) {
return SRSLTE_ERROR_INVALID_INPUTS; return SRSLTE_ERROR_INVALID_INPUTS;
} }
@ -91,20 +94,43 @@ int srslte_ue_dl_nr_pdsch_time_resource_default_A(uint32_t
return SRSLTE_ERROR_INVALID_INPUTS; return SRSLTE_ERROR_INVALID_INPUTS;
} }
// Select k0
grant->k0 = 0;
// Select PDSCH mapping
static srslte_pdsch_mapping_type_t pdsch_mapping_lut[16] = {srslte_pdsch_mapping_type_A,
srslte_pdsch_mapping_type_A,
srslte_pdsch_mapping_type_A,
srslte_pdsch_mapping_type_A,
srslte_pdsch_mapping_type_A,
srslte_pdsch_mapping_type_B,
srslte_pdsch_mapping_type_B,
srslte_pdsch_mapping_type_B,
srslte_pdsch_mapping_type_B,
srslte_pdsch_mapping_type_B,
srslte_pdsch_mapping_type_B,
srslte_pdsch_mapping_type_A,
srslte_pdsch_mapping_type_A,
srslte_pdsch_mapping_type_A,
srslte_pdsch_mapping_type_B,
srslte_pdsch_mapping_type_B};
grant->mapping = pdsch_mapping_lut[m];
static uint32_t S_pos2[16] = {2, 2, 2, 2, 2, 9, 4, 5, 5, 9, 12, 1, 1, 2, 4, 8}; static uint32_t S_pos2[16] = {2, 2, 2, 2, 2, 9, 4, 5, 5, 9, 12, 1, 1, 2, 4, 8};
static uint32_t L_pos2[16] = {12, 10, 9, 7, 5, 4, 4, 7, 2, 2, 2, 13, 6, 4, 7, 4}; static uint32_t L_pos2[16] = {12, 10, 9, 7, 5, 4, 4, 7, 2, 2, 2, 13, 6, 4, 7, 4};
static uint32_t S_pos3[16] = {3, 3, 3, 3, 3, 10, 6, 5, 5, 9, 12, 1, 1, 2, 4, 8}; static uint32_t S_pos3[16] = {3, 3, 3, 3, 3, 10, 6, 5, 5, 9, 12, 1, 1, 2, 4, 8};
static uint32_t L_pos3[16] = {11, 9, 8, 6, 4, 4, 4, 7, 2, 2, 2, 13, 6, 4, 7, 4}; static uint32_t L_pos3[16] = {11, 9, 8, 6, 4, 4, 4, 7, 2, 2, 2, 13, 6, 4, 7, 4};
// Select start symbol (S) and length (L)
switch (dmrs_typeA_pos) { switch (dmrs_typeA_pos) {
case srslte_dmrs_pdsch_typeA_pos_2: case srslte_dmrs_pdsch_typeA_pos_2:
*S = S_pos2[m]; grant->S = S_pos2[m];
*L = L_pos2[m]; grant->L = L_pos2[m];
break; break;
case srslte_dmrs_pdsch_typeA_pos_3: case srslte_dmrs_pdsch_typeA_pos_3:
*S = S_pos3[m]; grant->S = S_pos3[m];
*L = L_pos3[m]; grant->L = L_pos3[m];
break; break;
default: default:
ERROR("Undefined case (%d)\n", dmrs_typeA_pos); ERROR("Undefined case (%d)\n", dmrs_typeA_pos);

Loading…
Cancel
Save