mirror of https://github.com/PentHertz/srsLTE.git
Initial resource allocation for NR
This commit is contained in:
parent
0439161de6
commit
736e6db616
|
@ -60,11 +60,13 @@ typedef struct {
|
|||
|
||||
/**
|
||||
* @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 pdsch_cfg PDSCH configuration provided by upper layers
|
||||
* @param grant PDSCH information provided by a DCI
|
||||
* @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.
|
||||
*/
|
||||
SRSLTE_API int srslte_dmrs_pdsch_get_symbols_idx(const srslte_pdsch_cfg_nr_t* pdsch_cfg,
|
||||
SRSLTE_API int srslte_dmrs_pdsch_get_symbols_idx(const srslte_pdsch_cfg_nr_t* pdsch_cfg,
|
||||
const srslte_pdsch_grant_nr_t* grant,
|
||||
uint32_t symbols_idx[SRSLTE_DMRS_PDSCH_MAX_SYMBOLS]);
|
||||
|
||||
/**
|
||||
|
@ -78,6 +80,14 @@ SRSLTE_API int srslte_dmrs_pdsch_get_symbols_idx(const srslte_pdsch_cfg_nr_t* pd
|
|||
*/
|
||||
SRSLTE_API int srslte_dmrs_pdsch_get_sc_idx(const srslte_pdsch_dmrs_cfg_t* cfg, uint32_t max_count, uint32_t* sc_idx);
|
||||
|
||||
/**
|
||||
* @brief Calculates the number of resource elements taken by a PDSCH-DMRS for a given PDSCH transmission
|
||||
* @param pdsch_cfg PDSCH configuration provided by upper layers
|
||||
* @param grant PDSCH information provided by a DCI
|
||||
* @return it returns the number of resource elements if the configuration is valid, otherwise it returns SRSLTE_ERROR
|
||||
*/
|
||||
SRSLTE_API int srslte_dmrs_pdsch_get_N_prb(const srslte_pdsch_cfg_nr_t* cfg, const srslte_pdsch_grant_nr_t* grant);
|
||||
|
||||
/**
|
||||
* @brief Stringifies the PDSCH DMRS configuration
|
||||
*
|
||||
|
@ -122,15 +132,17 @@ SRSLTE_API int srslte_dmrs_pdsch_set_carrier(srslte_dmrs_pdsch_t* q, const srslt
|
|||
*
|
||||
* @param q DMRS PDSCH object
|
||||
* @param slot_cfg Slot configuration
|
||||
* @param pdsch_cfg PDSCH transmission configuration
|
||||
* @param pdsch_cfg PDSCH configuration provided by upper layers
|
||||
* @param grant PDSCH information provided by a DCI
|
||||
* @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_put_sf(srslte_dmrs_pdsch_t* q,
|
||||
const srslte_dl_slot_cfg_t* slot_cfg,
|
||||
const srslte_pdsch_cfg_nr_t* pdsch_cfg,
|
||||
const srslte_pdsch_grant_nr_t* grant,
|
||||
cf_t* sf_symbols);
|
||||
|
||||
/**
|
||||
* @brief Estimates the channel for PDSCH from the DMRS
|
||||
|
@ -139,16 +151,19 @@ SRSLTE_API int srslte_dmrs_pdsch_put_sf(srslte_dmrs_pdsch_t* q,
|
|||
*
|
||||
* @param q DMRS-PDSCH object
|
||||
* @param slot_cfg Slot configuration
|
||||
* @param pdsch_cfg PDSCH configuration provided by upper layers
|
||||
* @param grant PDSCH information provided by a DCI
|
||||
* @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);
|
||||
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 srslte_pdsch_grant_nr_t* grant,
|
||||
const cf_t* sf_symbols,
|
||||
srslte_chest_dl_res_t* chest_res);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -85,6 +85,18 @@ extern "C" {
|
|||
*/
|
||||
#define SRSLTE_SEARCH_SPACE_MAX_NOF_CANDIDATES_NR 8
|
||||
|
||||
/**
|
||||
* @brief defines the maximum number of resource elements per PRB
|
||||
* @remark Defined in TS 36.214 V15.10.0 5.1.3.2 Transport block size determination, point 1, second bullet
|
||||
*/
|
||||
#define SRSLTE_MAX_NRE_NR 156
|
||||
|
||||
/**
|
||||
* @brief defines the maximum number of resource elements in a PDSCH transmission
|
||||
* @remark deduced from in TS 36.214 V15.10.0 5.1.3.2 Transport block size determination
|
||||
*/
|
||||
#define SRSLTE_PDSCH_MAX_RE_NR (SRSLTE_MAX_NRE_NR * SRSLTE_MAX_PRB_NR)
|
||||
|
||||
/**
|
||||
* @brief Maximum number of PDSCH time domain resource allocations. This is defined by TS 38.331 v15.10.0
|
||||
* as maxNrofDL-Allocations
|
||||
|
@ -111,21 +123,35 @@ typedef enum SRSLTE_API {
|
|||
* @brief PDSCH mapping type
|
||||
* @remark Described in TS 38.331 V15.10.0 Section PDSCH-TimeDomainResourceAllocationList
|
||||
*/
|
||||
typedef enum SRSLTE_API {
|
||||
/// Type A allocation is relative to the
|
||||
srslte_pdsch_mapping_type_A = 0,
|
||||
srslte_pdsch_mapping_type_B
|
||||
} srslte_pdsch_mapping_type_t;
|
||||
typedef enum SRSLTE_API { srslte_pdsch_mapping_type_A = 0, srslte_pdsch_mapping_type_B } srslte_pdsch_mapping_type_t;
|
||||
|
||||
typedef enum SRSLTE_API {
|
||||
srslte_search_space_type_common = 0,
|
||||
srslte_search_space_type_ue,
|
||||
} srslte_search_space_type_t;
|
||||
|
||||
/**
|
||||
* @brief Indicates the MCS table the UE shall use for PDSCH and/or PUSCH without transform precoding
|
||||
*/
|
||||
typedef enum SRSLTE_API {
|
||||
srslte_mcs_table_64qam = 0,
|
||||
srslte_mcs_table_256qam,
|
||||
srslte_mcs_table_qam64LowSE
|
||||
} srslte_mcs_table_t;
|
||||
|
||||
/**
|
||||
* @brief DCI formats
|
||||
* @remark Described in TS 38.331 V15.10.0 Section PDSCH-TimeDomainResourceAllocationList
|
||||
*/
|
||||
typedef enum SRSLTE_API {
|
||||
srslte_dci_format_nr_1_0 = 0,
|
||||
srslte_dci_format_nr_1_1,
|
||||
} srslte_dci_format_nr_t;
|
||||
|
||||
/**
|
||||
* @brief NR carrier parameters. It is a combination of fixed cell and bandwidth-part (BWP)
|
||||
*/
|
||||
typedef struct {
|
||||
typedef struct SRSLTE_API {
|
||||
uint32_t id;
|
||||
uint32_t numerology;
|
||||
uint32_t nof_prb;
|
||||
|
@ -135,7 +161,7 @@ typedef struct {
|
|||
/**
|
||||
* @brief NR Slot parameters. It contains parameters that change in a slot basis.
|
||||
*/
|
||||
typedef struct {
|
||||
typedef struct SRSLTE_API {
|
||||
/// Slot index in the radio frame
|
||||
uint32_t idx;
|
||||
|
||||
|
|
|
@ -22,10 +22,10 @@
|
|||
#ifndef SRSLTE_EVM_H_
|
||||
#define SRSLTE_EVM_H_
|
||||
|
||||
#include <srslte/config.h>
|
||||
#include <srslte/phy/phch/ra.h>
|
||||
#include <srslte/phy/utils/debug.h>
|
||||
#include <srslte/phy/utils/vector.h>
|
||||
#include "srslte/config.h"
|
||||
#include "srslte/phy/phch/ra.h"
|
||||
#include "srslte/phy/utils/debug.h"
|
||||
#include "srslte/phy/utils/vector.h"
|
||||
|
||||
/** @struct srslte_evm_buffer_t
|
||||
* This structure carries the necessary temporary data required for calculating the EVM.
|
||||
|
|
|
@ -74,17 +74,17 @@ typedef enum {
|
|||
*/
|
||||
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;
|
||||
bool scrambling_id0_present;
|
||||
uint32_t scrambling_id0;
|
||||
bool scrambling_id1_present;
|
||||
uint32_t scrambling_id1;
|
||||
srslte_dmrs_pdsch_type_t type;
|
||||
srslte_dmrs_pdsch_add_pos_t additional_pos;
|
||||
srslte_dmrs_pdsch_len_t length;
|
||||
bool scrambling_id0_present;
|
||||
uint32_t scrambling_id0;
|
||||
bool scrambling_id1_present;
|
||||
uint32_t scrambling_id1;
|
||||
|
||||
/// Parameters provided by ServingCellConfigCommon
|
||||
srslte_dmrs_pdsch_typeA_pos_t typeA_pos;
|
||||
bool lte_CRS_to_match_around;
|
||||
bool lte_CRS_to_match_around;
|
||||
|
||||
/// Parameters provided by FeatureSetDownlink-v1540
|
||||
bool additional_DMRS_DL_Alt;
|
||||
|
@ -108,6 +108,9 @@ typedef struct SRSLTE_API {
|
|||
|
||||
} srslte_pdsch_allocation_t;
|
||||
|
||||
/**
|
||||
* @brief PDSCH grant information provided by the Downlink Control Information (DCI)
|
||||
*/
|
||||
typedef struct SRSLTE_API {
|
||||
/// UE identifier
|
||||
uint16_t rnti;
|
||||
|
@ -121,16 +124,33 @@ typedef struct SRSLTE_API {
|
|||
/// Frequency domain resources
|
||||
bool prb_idx[SRSLTE_MAX_PRB_NR];
|
||||
|
||||
/// Spatial resources
|
||||
uint32_t nof_layers;
|
||||
|
||||
/// DMRS Scrambling sequence initialization (false: 0 or true: 1)
|
||||
bool n_scid;
|
||||
|
||||
/// DCI information
|
||||
srslte_dci_format_nr_t dci_format;
|
||||
srslte_search_space_type_t dci_search_space;
|
||||
|
||||
/// Transport block
|
||||
uint32_t tb_scaling_field;
|
||||
/// ....
|
||||
} srslte_pdsch_grant_nr_t;
|
||||
|
||||
/**
|
||||
* @brief flatten PDSCH configuration parameters provided by higher layers
|
||||
* @remark Described in TS 38.331 V15.10.0 Section PDSCH-Config
|
||||
*/
|
||||
typedef struct SRSLTE_API {
|
||||
srslte_pdsch_grant_nr_t grant;
|
||||
srslte_pdsch_dmrs_cfg_t dmrs_cfg;
|
||||
|
||||
bool scrambling_id_present;
|
||||
uint32_t scambling_id; // Identifier used to initialize data scrambling (0-1023)
|
||||
|
||||
srslte_pdsch_dmrs_cfg_t dmrs_cfg_typeA;
|
||||
srslte_pdsch_dmrs_cfg_t dmrs_cfg_typeB;
|
||||
srslte_mcs_table_t mcs_table;
|
||||
} srslte_pdsch_cfg_nr_t;
|
||||
|
||||
#endif // SRSLTE_PDSCH_CFG_NR_H
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Copyright 2013-2020 Software Radio Systems Limited
|
||||
*
|
||||
* This file is part of srsLTE.
|
||||
*
|
||||
* srsLTE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* srsLTE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Affero General Public License can be found in
|
||||
* the LICENSE file in the top-level directory of this distribution
|
||||
* and at http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
|
||||
/******************************************************************************
|
||||
* File: ra_nr.h
|
||||
*
|
||||
* Description: Implements Resource allocation Procedures common in for DL and UL
|
||||
*
|
||||
* Reference: 3GPP TS 38.214 version 15.10.0
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef SRSLTE_RA_NR_H
|
||||
#define SRSLTE_RA_NR_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "srslte/config.h"
|
||||
#include "srslte/phy/common/phy_common_nr.h"
|
||||
#include "srslte/phy/phch/pdsch_cfg_nr.h"
|
||||
|
||||
/**************************************************
|
||||
* Common structures used for Resource Allocation
|
||||
**************************************************/
|
||||
|
||||
typedef struct SRSLTE_API {
|
||||
srslte_mod_t mod;
|
||||
int tbs;
|
||||
int rv;
|
||||
uint32_t nof_bits;
|
||||
uint32_t cw_idx;
|
||||
bool enabled;
|
||||
|
||||
// this is for debugging and metrics purposes
|
||||
uint32_t mcs_idx;
|
||||
} srslte_ra_tb_nr_t;
|
||||
|
||||
SRSLTE_API int
|
||||
srslte_ra_nr_tbs(const srslte_pdsch_cfg_nr_t* pdsch_cfg, const srslte_pdsch_grant_nr_t* grant, uint32_t mcs_idx);
|
||||
|
||||
#endif // SRSLTE_RA_NR_H
|
|
@ -164,16 +164,19 @@ static uint32_t srslte_dmrs_put_pilots(srslte_dmrs_pdsch_t* q,
|
|||
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)
|
||||
static int srslte_dmrs_pdsch_put_symbol(srslte_dmrs_pdsch_t* q,
|
||||
const srslte_pdsch_cfg_nr_t* pdsch_cfg,
|
||||
const srslte_pdsch_grant_nr_t* grant,
|
||||
uint32_t cinit,
|
||||
uint32_t delta,
|
||||
cf_t* symbols)
|
||||
{
|
||||
const srslte_pdsch_dmrs_cfg_t* dmrs_cfg =
|
||||
grant->mapping == srslte_pdsch_mapping_type_A ? &pdsch_cfg->dmrs_cfg_typeA : &pdsch_cfg->dmrs_cfg_typeB;
|
||||
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 nof_pilots_x_prb = dmrs_cfg->type == srslte_dmrs_pdsch_type_1 ? 6 : 4;
|
||||
uint32_t pilot_count = 0;
|
||||
|
||||
// Initialise sequence
|
||||
|
@ -183,7 +186,7 @@ static int srslte_dmrs_pdsch_put_symbol(srslte_dmrs_pdsch_t* q,
|
|||
// 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 (grant->prb_idx[prb_idx]) {
|
||||
// If it is the first PRB...
|
||||
if (prb_count == 0) {
|
||||
// ... save first consecutive PRB in the group
|
||||
|
@ -208,7 +211,7 @@ static int srslte_dmrs_pdsch_put_symbol(srslte_dmrs_pdsch_t* q,
|
|||
|
||||
// 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]);
|
||||
q, &sequence_state, dmrs_cfg->type, prb_start, prb_count, delta, &symbols[prb_start * SRSLTE_NRE]);
|
||||
|
||||
// Reset counter
|
||||
prb_count = 0;
|
||||
|
@ -216,15 +219,15 @@ static int srslte_dmrs_pdsch_put_symbol(srslte_dmrs_pdsch_t* q,
|
|||
|
||||
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]);
|
||||
q, &sequence_state, 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
|
||||
static int srslte_dmrs_pdsch_get_symbols_idx_mapping_type_A_single(const srslte_pdsch_cfg_nr_t* cfg,
|
||||
uint32_t ld,
|
||||
static int srslte_dmrs_pdsch_get_symbols_idx_mapping_type_A_single(const srslte_pdsch_dmrs_cfg_t* dmrs_cfg,
|
||||
uint32_t ld,
|
||||
uint32_t symbols[SRSLTE_DMRS_PDSCH_MAX_SYMBOLS])
|
||||
{
|
||||
int count = 0;
|
||||
|
@ -235,7 +238,7 @@ static int srslte_dmrs_pdsch_get_symbols_idx_mapping_type_A_single(const srslte_
|
|||
}
|
||||
|
||||
// l0 = 3 if the higher-layer parameter dmrs-TypeA-Position is equal to 'pos3' and l0 = 2 otherwise
|
||||
int l0 = (cfg->dmrs_cfg.typeA_pos == srslte_dmrs_pdsch_typeA_pos_3) ? 3 : 2;
|
||||
int l0 = (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
|
||||
// which case l1 = 12:
|
||||
|
@ -243,15 +246,15 @@ 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 UE has indicated it is capable of additionalDMRS-DL-Alt
|
||||
int l1 = 11;
|
||||
if (cfg->dmrs_cfg.lte_CRS_to_match_around && cfg->dmrs_cfg.additional_pos == srslte_dmrs_pdsch_add_pos_1 &&
|
||||
cfg->dmrs_cfg.typeA_pos == srslte_dmrs_pdsch_typeA_pos_3 && cfg->dmrs_cfg.additional_DMRS_DL_Alt) {
|
||||
if (dmrs_cfg->lte_CRS_to_match_around && dmrs_cfg->additional_pos == srslte_dmrs_pdsch_add_pos_1 &&
|
||||
dmrs_cfg->typeA_pos == srslte_dmrs_pdsch_typeA_pos_3 && dmrs_cfg->additional_DMRS_DL_Alt) {
|
||||
l1 = 12;
|
||||
}
|
||||
|
||||
symbols[count] = l0;
|
||||
count++;
|
||||
|
||||
if (ld < 8 || cfg->dmrs_cfg.additional_pos == srslte_dmrs_pdsch_add_pos_0) {
|
||||
if (ld < 8 || dmrs_cfg->additional_pos == srslte_dmrs_pdsch_add_pos_0) {
|
||||
return count;
|
||||
}
|
||||
|
||||
|
@ -259,7 +262,7 @@ static int srslte_dmrs_pdsch_get_symbols_idx_mapping_type_A_single(const srslte_
|
|||
symbols[count] = 7;
|
||||
count++;
|
||||
} else if (ld < 12) {
|
||||
if (cfg->dmrs_cfg.additional_pos > srslte_dmrs_pdsch_add_pos_2) {
|
||||
if (dmrs_cfg->additional_pos > srslte_dmrs_pdsch_add_pos_2) {
|
||||
symbols[count] = 6;
|
||||
count++;
|
||||
}
|
||||
|
@ -268,7 +271,7 @@ static int srslte_dmrs_pdsch_get_symbols_idx_mapping_type_A_single(const srslte_
|
|||
count++;
|
||||
|
||||
} else if (ld == 12) {
|
||||
switch (cfg->dmrs_cfg.additional_pos) {
|
||||
switch (dmrs_cfg->additional_pos) {
|
||||
case srslte_dmrs_pdsch_add_pos_1:
|
||||
symbols[count] = 9;
|
||||
count++;
|
||||
|
@ -288,7 +291,7 @@ static int srslte_dmrs_pdsch_get_symbols_idx_mapping_type_A_single(const srslte_
|
|||
count++;
|
||||
}
|
||||
} else {
|
||||
switch (cfg->dmrs_cfg.additional_pos) {
|
||||
switch (dmrs_cfg->additional_pos) {
|
||||
case srslte_dmrs_pdsch_add_pos_1:
|
||||
symbols[count] = l1;
|
||||
count++;
|
||||
|
@ -313,8 +316,8 @@ 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
|
||||
static int srslte_dmrs_pdsch_get_symbols_idx_mapping_type_A_double(const srslte_pdsch_cfg_nr_t* cfg,
|
||||
uint32_t ld,
|
||||
static int srslte_dmrs_pdsch_get_symbols_idx_mapping_type_A_double(const srslte_pdsch_dmrs_cfg_t* dmrs_cfg,
|
||||
uint32_t ld,
|
||||
uint32_t symbols[SRSLTE_DMRS_PDSCH_MAX_SYMBOLS])
|
||||
{
|
||||
int count = 0;
|
||||
|
@ -324,14 +327,14 @@ static int srslte_dmrs_pdsch_get_symbols_idx_mapping_type_A_double(const srslte_
|
|||
}
|
||||
|
||||
// l0 = 3 if the higher-layer parameter dmrs-TypeA-Position is equal to 'pos3' and l0 = 2 otherwise
|
||||
int l0 = (cfg->dmrs_cfg.typeA_pos == srslte_dmrs_pdsch_typeA_pos_3) ? 3 : 2;
|
||||
int l0 = (dmrs_cfg->typeA_pos == srslte_dmrs_pdsch_typeA_pos_3) ? 3 : 2;
|
||||
|
||||
symbols[count] = l0;
|
||||
count++;
|
||||
symbols[count] = symbols[count - 1] + 1;
|
||||
count++;
|
||||
|
||||
if (ld < 10 || cfg->dmrs_cfg.additional_pos == srslte_dmrs_pdsch_add_pos_0) {
|
||||
if (ld < 10 || dmrs_cfg->additional_pos == srslte_dmrs_pdsch_add_pos_0) {
|
||||
return count;
|
||||
}
|
||||
|
||||
|
@ -350,22 +353,27 @@ static int srslte_dmrs_pdsch_get_symbols_idx_mapping_type_A_double(const srslte_
|
|||
return count;
|
||||
}
|
||||
|
||||
int srslte_dmrs_pdsch_get_symbols_idx(const srslte_pdsch_cfg_nr_t* cfg, uint32_t symbols[SRSLTE_DMRS_PDSCH_MAX_SYMBOLS])
|
||||
int srslte_dmrs_pdsch_get_symbols_idx(const srslte_pdsch_cfg_nr_t* cfg,
|
||||
const srslte_pdsch_grant_nr_t* grant,
|
||||
uint32_t symbols[SRSLTE_DMRS_PDSCH_MAX_SYMBOLS])
|
||||
{
|
||||
// The position(s) of the DM-RS symbols is given by l and duration ld where
|
||||
// - for PDSCH mapping type A, ld is the duration between the first OFDM symbol of the slot and the last OFDM symbol
|
||||
// of the scheduled PDSCH resources in the slot
|
||||
// - for PDSCH mapping type B, ld is the duration of the scheduled PDSCH resources
|
||||
uint32_t ld = cfg->grant.L;
|
||||
if (cfg->grant.mapping == srslte_pdsch_mapping_type_A) {
|
||||
ld = cfg->grant.S + cfg->grant.L;
|
||||
uint32_t ld = grant->L;
|
||||
if (grant->mapping == srslte_pdsch_mapping_type_A) {
|
||||
ld = grant->S + grant->L;
|
||||
}
|
||||
|
||||
switch (cfg->grant.mapping) {
|
||||
const srslte_pdsch_dmrs_cfg_t* dmrs_cfg =
|
||||
grant->mapping == srslte_pdsch_mapping_type_A ? &cfg->dmrs_cfg_typeA : &cfg->dmrs_cfg_typeB;
|
||||
|
||||
switch (grant->mapping) {
|
||||
case srslte_pdsch_mapping_type_A:
|
||||
// The case dmrs-AdditionalPosition equals to 'pos3' is only supported when dmrs-TypeA-Position is equal to 'pos2'
|
||||
if (cfg->dmrs_cfg.typeA_pos != srslte_dmrs_pdsch_typeA_pos_2 &&
|
||||
cfg->dmrs_cfg.additional_pos == srslte_dmrs_pdsch_add_pos_3) {
|
||||
if (dmrs_cfg->typeA_pos != srslte_dmrs_pdsch_typeA_pos_2 &&
|
||||
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 "
|
||||
"to 'pos2'\n");
|
||||
return SRSLTE_ERROR;
|
||||
|
@ -373,16 +381,16 @@ int srslte_dmrs_pdsch_get_symbols_idx(const srslte_pdsch_cfg_nr_t* cfg, uint32_t
|
|||
|
||||
// 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
|
||||
if ((ld == 3 || ld == 4) && cfg->dmrs_cfg.typeA_pos != srslte_dmrs_pdsch_typeA_pos_2) {
|
||||
if ((ld == 3 || ld == 4) && 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 "
|
||||
"is only applicable when dmrs-TypeA-Position is equal to 'pos2\n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
if (cfg->dmrs_cfg.length == srslte_dmrs_pdsch_len_1) {
|
||||
return srslte_dmrs_pdsch_get_symbols_idx_mapping_type_A_single(cfg, ld, symbols);
|
||||
if (dmrs_cfg->length == srslte_dmrs_pdsch_len_1) {
|
||||
return srslte_dmrs_pdsch_get_symbols_idx_mapping_type_A_single(dmrs_cfg, ld, symbols);
|
||||
}
|
||||
return srslte_dmrs_pdsch_get_symbols_idx_mapping_type_A_double(cfg, ld, symbols);
|
||||
return srslte_dmrs_pdsch_get_symbols_idx_mapping_type_A_double(dmrs_cfg, ld, symbols);
|
||||
case srslte_pdsch_mapping_type_B:
|
||||
ERROR("Error PDSCH mapping type B not supported\n");
|
||||
return SRSLTE_ERROR;
|
||||
|
@ -413,20 +421,42 @@ int srslte_dmrs_pdsch_get_sc_idx(const srslte_pdsch_dmrs_cfg_t* cfg, uint32_t ma
|
|||
return count;
|
||||
}
|
||||
|
||||
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)
|
||||
int srslte_dmrs_pdsch_get_N_prb(const srslte_pdsch_cfg_nr_t* cfg, const srslte_pdsch_grant_nr_t* grant)
|
||||
{
|
||||
const srslte_pdsch_dmrs_cfg_t* dmrs_cfg =
|
||||
grant->mapping == srslte_pdsch_mapping_type_A ? &cfg->dmrs_cfg_typeA : &cfg->dmrs_cfg_typeB;
|
||||
|
||||
// Get number of frequency domain resource elements used for DMRS
|
||||
int nof_sc = dmrs_cfg->type == srslte_dmrs_pdsch_type_1 ? 6 : 4;
|
||||
|
||||
// Get number of symbols used for DMRS
|
||||
uint32_t symbols[SRSLTE_DMRS_PDSCH_MAX_SYMBOLS] = {};
|
||||
int ret = srslte_dmrs_pdsch_get_symbols_idx(cfg, grant, symbols);
|
||||
if (ret < SRSLTE_SUCCESS) {
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
return nof_sc * ret;
|
||||
}
|
||||
|
||||
static uint32_t srslte_dmrs_pdsch_seed(const srslte_carrier_nr_t* carrier,
|
||||
const srslte_pdsch_cfg_nr_t* cfg,
|
||||
const srslte_pdsch_grant_nr_t* grant,
|
||||
uint32_t slot_idx,
|
||||
uint32_t symbol_idx)
|
||||
{
|
||||
const srslte_pdsch_dmrs_cfg_t* dmrs_cfg =
|
||||
grant->mapping == srslte_pdsch_mapping_type_A ? &cfg->dmrs_cfg_typeA : &cfg->dmrs_cfg_typeB;
|
||||
|
||||
// Calculate scrambling IDs
|
||||
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) {
|
||||
uint32_t n_scid = (grant->n_scid) ? 1 : 0;
|
||||
if (!grant->n_scid && 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_id = dmrs_cfg->scrambling_id0;
|
||||
} else if (grant->n_scid && dmrs_cfg->scrambling_id1_present) {
|
||||
// n_scid = 1 and ID1 present
|
||||
n_id = cfg->dmrs_cfg.scrambling_id1;
|
||||
n_id = dmrs_cfg->scrambling_id1;
|
||||
}
|
||||
|
||||
return (uint32_t)(((((SRSLTE_MAX_NSYMB * slot_idx + symbol_idx + 1UL) * (2UL * n_id + 1UL)) << 17UL) +
|
||||
|
@ -468,7 +498,7 @@ int srslte_dmrs_pdsch_set_carrier(srslte_dmrs_pdsch_t* q, const srslte_carrier_n
|
|||
bool max_nof_prb_changed = q->max_nof_prb < carrier->nof_prb;
|
||||
|
||||
// Set carrier and update maximum number of PRB
|
||||
q->carrier = *carrier;
|
||||
q->carrier = *carrier;
|
||||
q->max_nof_prb = SRSLTE_MAX(q->max_nof_prb, carrier->nof_prb);
|
||||
|
||||
// Resize/allocate temp for gNb and UE
|
||||
|
@ -516,10 +546,11 @@ int srslte_dmrs_pdsch_set_carrier(srslte_dmrs_pdsch_t* q, const srslte_carrier_n
|
|||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
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)
|
||||
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,
|
||||
const srslte_pdsch_grant_nr_t* grant,
|
||||
cf_t* sf_symbols)
|
||||
{
|
||||
uint32_t delta = 0;
|
||||
|
||||
|
@ -531,7 +562,7 @@ int srslte_dmrs_pdsch_put_sf(srslte_dmrs_pdsch_t* q,
|
|||
|
||||
// Get symbols indexes
|
||||
uint32_t symbols[SRSLTE_DMRS_PDSCH_MAX_SYMBOLS] = {};
|
||||
int nof_symbols = srslte_dmrs_pdsch_get_symbols_idx(pdsch_cfg, symbols);
|
||||
int nof_symbols = srslte_dmrs_pdsch_get_symbols_idx(pdsch_cfg, grant, symbols);
|
||||
if (nof_symbols < SRSLTE_SUCCESS) {
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
@ -540,25 +571,29 @@ int srslte_dmrs_pdsch_put_sf(srslte_dmrs_pdsch_t* q,
|
|||
for (uint32_t i = 0; i < nof_symbols; i++) {
|
||||
uint32_t l = symbols[i]; // Symbol index inside the slot
|
||||
uint32_t slot_idx = slot_cfg->idx; // Slot index in the frame
|
||||
uint32_t cinit = srslte_dmrs_pdsch_seed(&q->carrier, pdsch_cfg, slot_idx, l);
|
||||
uint32_t cinit = srslte_dmrs_pdsch_seed(&q->carrier, pdsch_cfg, grant, slot_idx, l);
|
||||
|
||||
srslte_dmrs_pdsch_put_symbol(q, pdsch_cfg, cinit, delta, &sf_symbols[symbol_sz * l]);
|
||||
srslte_dmrs_pdsch_put_symbol(q, pdsch_cfg, grant, cinit, delta, &sf_symbols[symbol_sz * l]);
|
||||
}
|
||||
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
static int srslte_dmrs_pdsch_get_symbol(srslte_dmrs_pdsch_t* q,
|
||||
const srslte_pdsch_cfg_nr_t* pdsch_cfg,
|
||||
uint32_t cinit,
|
||||
uint32_t delta,
|
||||
const cf_t* symbols,
|
||||
cf_t* least_square_estimates)
|
||||
static int srslte_dmrs_pdsch_get_symbol(srslte_dmrs_pdsch_t* q,
|
||||
const srslte_pdsch_cfg_nr_t* pdsch_cfg,
|
||||
const srslte_pdsch_grant_nr_t* grant,
|
||||
uint32_t cinit,
|
||||
uint32_t delta,
|
||||
const cf_t* symbols,
|
||||
cf_t* least_square_estimates)
|
||||
{
|
||||
const srslte_pdsch_dmrs_cfg_t* dmrs_cfg =
|
||||
grant->mapping == srslte_pdsch_mapping_type_A ? &pdsch_cfg->dmrs_cfg_typeA : &pdsch_cfg->dmrs_cfg_typeB;
|
||||
|
||||
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 nof_pilots_x_prb = dmrs_cfg->type == srslte_dmrs_pdsch_type_1 ? 6 : 4;
|
||||
uint32_t pilot_count = 0;
|
||||
|
||||
// Initialise sequence
|
||||
|
@ -568,7 +603,7 @@ static int srslte_dmrs_pdsch_get_symbol(srslte_dmrs_pdsch_t* q,
|
|||
// 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 (grant->prb_idx[prb_idx]) {
|
||||
// If it is the first PRB...
|
||||
if (prb_count == 0) {
|
||||
// ... save first consecutive PRB in the group
|
||||
|
@ -594,7 +629,7 @@ static int srslte_dmrs_pdsch_get_symbol(srslte_dmrs_pdsch_t* q,
|
|||
// Get contiguous pilots
|
||||
pilot_count += srslte_dmrs_get_lse(q,
|
||||
&sequence_state,
|
||||
pdsch_cfg->dmrs_cfg.type,
|
||||
dmrs_cfg->type,
|
||||
prb_start,
|
||||
prb_count,
|
||||
delta,
|
||||
|
@ -608,7 +643,7 @@ static int srslte_dmrs_pdsch_get_symbol(srslte_dmrs_pdsch_t* q,
|
|||
if (prb_count > 0) {
|
||||
pilot_count += srslte_dmrs_get_lse(q,
|
||||
&sequence_state,
|
||||
pdsch_cfg->dmrs_cfg.type,
|
||||
dmrs_cfg->type,
|
||||
prb_start,
|
||||
prb_count,
|
||||
delta,
|
||||
|
@ -619,23 +654,28 @@ static int srslte_dmrs_pdsch_get_symbol(srslte_dmrs_pdsch_t* q,
|
|||
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)
|
||||
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 srslte_pdsch_grant_nr_t* grant,
|
||||
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;
|
||||
}
|
||||
|
||||
const srslte_pdsch_dmrs_cfg_t* dmrs_cfg =
|
||||
grant->mapping == srslte_pdsch_mapping_type_A ? &pdsch_cfg->dmrs_cfg_typeA : &pdsch_cfg->dmrs_cfg_typeB;
|
||||
|
||||
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);
|
||||
int nof_symbols = srslte_dmrs_pdsch_get_symbols_idx(pdsch_cfg, grant, symbols);
|
||||
if (nof_symbols < SRSLTE_SUCCESS) {
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
@ -646,10 +686,10 @@ int srslte_dmrs_pdsch_estimate(srslte_dmrs_pdsch_t* q,
|
|||
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);
|
||||
uint32_t cinit = srslte_dmrs_pdsch_seed(&q->carrier, pdsch_cfg, grant, 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]);
|
||||
q, pdsch_cfg, grant, cinit, delta, &sf_symbols[symbol_sz * l], &q->pilot_estimates[nof_pilots_x_symbol * i]);
|
||||
}
|
||||
|
||||
// Perform measurements here
|
||||
|
@ -666,8 +706,8 @@ int srslte_dmrs_pdsch_estimate(srslte_dmrs_pdsch_t* q,
|
|||
|
||||
// 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) {
|
||||
(dmrs_cfg->type == srslte_dmrs_pdsch_type_1) ? nof_pilots_x_symbol * 2 : nof_pilots_x_symbol * 3;
|
||||
if (dmrs_cfg->type == srslte_dmrs_pdsch_type_1) {
|
||||
// Prepare interpolator
|
||||
srslte_interp_linear_resize(&q->interpolator_type1, nof_pilots_x_symbol, 2);
|
||||
|
||||
|
@ -683,12 +723,12 @@ int srslte_dmrs_pdsch_estimate(srslte_dmrs_pdsch_t* q,
|
|||
}
|
||||
|
||||
// Time domain hold
|
||||
for (uint32_t i = 1; i < pdsch_cfg->grant.L; i++) {
|
||||
for (uint32_t i = 1; i < 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;
|
||||
chest_res->nof_re = nof_re_x_symbol * grant->L;
|
||||
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
|
@ -164,36 +164,36 @@ void parse_args(int argc, char** argv)
|
|||
}
|
||||
}
|
||||
|
||||
static int assert_cfg(const srslte_pdsch_cfg_nr_t* pdsch_cfg)
|
||||
static int assert_cfg(const srslte_pdsch_cfg_nr_t* pdsch_cfg, const srslte_pdsch_grant_nr_t* grant)
|
||||
{
|
||||
for (uint32_t i = 0; gold[i].nof_sc != 0; i++) {
|
||||
// Gold examples are done for more than 12 symbols
|
||||
if (pdsch_cfg->grant.L <= 12) {
|
||||
if (grant->L <= 12) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pdsch_cfg->grant.mapping != gold[i].mapping_type) {
|
||||
if (grant->mapping != gold[i].mapping_type) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pdsch_cfg->dmrs_cfg.typeA_pos != gold[i].typeA_pos) {
|
||||
if (pdsch_cfg->dmrs_cfg_typeA.typeA_pos != gold[i].typeA_pos) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pdsch_cfg->dmrs_cfg.additional_pos != gold[i].additional_pos) {
|
||||
if (pdsch_cfg->dmrs_cfg_typeA.additional_pos != gold[i].additional_pos) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pdsch_cfg->dmrs_cfg.length != gold[i].max_length) {
|
||||
if (pdsch_cfg->dmrs_cfg_typeA.length != gold[i].max_length) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pdsch_cfg->dmrs_cfg.type != gold[i].type) {
|
||||
if (pdsch_cfg->dmrs_cfg_typeA.type != gold[i].type) {
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32_t symbols[SRSLTE_DMRS_PDSCH_MAX_SYMBOLS] = {};
|
||||
int nof_symbols = srslte_dmrs_pdsch_get_symbols_idx(pdsch_cfg, symbols);
|
||||
int nof_symbols = srslte_dmrs_pdsch_get_symbols_idx(pdsch_cfg, grant, symbols);
|
||||
|
||||
TESTASSERT(nof_symbols == gold[i].nof_symbols);
|
||||
|
||||
|
@ -202,7 +202,7 @@ static int assert_cfg(const srslte_pdsch_cfg_nr_t* pdsch_cfg)
|
|||
}
|
||||
|
||||
uint32_t sc[SRSLTE_NRE] = {};
|
||||
srslte_dmrs_pdsch_get_sc_idx(&pdsch_cfg->dmrs_cfg, SRSLTE_NRE, sc);
|
||||
srslte_dmrs_pdsch_get_sc_idx(&pdsch_cfg->dmrs_cfg_typeA, SRSLTE_NRE, sc);
|
||||
|
||||
for (uint32_t j = 0; j < gold[i].nof_sc; j++) {
|
||||
TESTASSERT(sc[j] == gold[i].sc_idx[j]);
|
||||
|
@ -214,18 +214,19 @@ static int assert_cfg(const srslte_pdsch_cfg_nr_t* pdsch_cfg)
|
|||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
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)
|
||||
static int run_test(srslte_dmrs_pdsch_t* dmrs_pdsch,
|
||||
const srslte_pdsch_cfg_nr_t* pdsch_cfg,
|
||||
const srslte_pdsch_grant_nr_t* grant,
|
||||
cf_t* sf_symbols,
|
||||
srslte_chest_dl_res_t* chest_res)
|
||||
{
|
||||
TESTASSERT(assert_cfg(pdsch_cfg) == SRSLTE_SUCCESS);
|
||||
TESTASSERT(assert_cfg(pdsch_cfg, grant) == SRSLTE_SUCCESS);
|
||||
|
||||
srslte_dl_slot_cfg_t slot_cfg = {};
|
||||
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, &slot_cfg, pdsch_cfg, sf_symbols);
|
||||
srslte_dmrs_pdsch_put_sf(dmrs_pdsch, &slot_cfg, pdsch_cfg, grant, sf_symbols);
|
||||
|
||||
srslte_dmrs_pdsch_estimate(dmrs_pdsch, &slot_cfg, pdsch_cfg, sf_symbols, chest_res);
|
||||
srslte_dmrs_pdsch_estimate(dmrs_pdsch, &slot_cfg, pdsch_cfg, grant, sf_symbols, chest_res);
|
||||
|
||||
float mse = 0.0f;
|
||||
for (uint32_t i = 0; i < chest_res->nof_re; i++) {
|
||||
|
@ -247,9 +248,10 @@ int main(int argc, char** argv)
|
|||
|
||||
parse_args(argc, argv);
|
||||
|
||||
srslte_dmrs_pdsch_t dmrs_pdsch = {};
|
||||
srslte_pdsch_cfg_nr_t pdsch_cfg = {};
|
||||
srslte_chest_dl_res_t chest_dl_res = {};
|
||||
srslte_dmrs_pdsch_t dmrs_pdsch = {};
|
||||
srslte_pdsch_cfg_nr_t pdsch_cfg = {};
|
||||
srslte_pdsch_grant_nr_t grant = {};
|
||||
srslte_chest_dl_res_t chest_dl_res = {};
|
||||
|
||||
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);
|
||||
|
@ -279,44 +281,53 @@ int main(int argc, char** argv)
|
|||
srslte_dmrs_pdsch_type_t type_begin = srslte_dmrs_pdsch_type_1;
|
||||
srslte_dmrs_pdsch_type_t type_end = srslte_dmrs_pdsch_type_2;
|
||||
|
||||
for (pdsch_cfg.dmrs_cfg.type = type_begin; pdsch_cfg.dmrs_cfg.type <= type_end; pdsch_cfg.dmrs_cfg.type++) {
|
||||
for (pdsch_cfg.dmrs_cfg_typeA.type = type_begin; pdsch_cfg.dmrs_cfg_typeA.type <= type_end;
|
||||
pdsch_cfg.dmrs_cfg_typeA.type++) {
|
||||
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 (pdsch_cfg.dmrs_cfg.typeA_pos = typeA_pos_begin; pdsch_cfg.dmrs_cfg.typeA_pos <= typeA_pos_end;
|
||||
pdsch_cfg.dmrs_cfg.typeA_pos++) {
|
||||
for (pdsch_cfg.dmrs_cfg_typeA.typeA_pos = typeA_pos_begin; pdsch_cfg.dmrs_cfg_typeA.typeA_pos <= typeA_pos_end;
|
||||
pdsch_cfg.dmrs_cfg_typeA.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;
|
||||
|
||||
if (pdsch_cfg.dmrs_cfg.typeA_pos == srslte_dmrs_pdsch_typeA_pos_3) {
|
||||
if (pdsch_cfg.dmrs_cfg_typeA.typeA_pos == srslte_dmrs_pdsch_typeA_pos_3) {
|
||||
add_pos_end = srslte_dmrs_pdsch_add_pos_1;
|
||||
}
|
||||
|
||||
for (pdsch_cfg.dmrs_cfg.additional_pos = add_pos_begin; pdsch_cfg.dmrs_cfg.additional_pos <= add_pos_end;
|
||||
pdsch_cfg.dmrs_cfg.additional_pos++) {
|
||||
for (pdsch_cfg.dmrs_cfg_typeA.additional_pos = add_pos_begin;
|
||||
pdsch_cfg.dmrs_cfg_typeA.additional_pos <= add_pos_end;
|
||||
pdsch_cfg.dmrs_cfg_typeA.additional_pos++) {
|
||||
|
||||
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 (pdsch_cfg.dmrs_cfg_typeA.length = max_len_begin; pdsch_cfg.dmrs_cfg_typeA.length <= max_len_end;
|
||||
pdsch_cfg.dmrs_cfg_typeA.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);
|
||||
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);
|
||||
srslte_ue_dl_nr_pdsch_time_resource_default_A(0, pdsch_cfg.dmrs_cfg_typeA.typeA_pos, &grant);
|
||||
|
||||
int n = run_test(&dmrs_pdsch, &pdsch_cfg, sf_symbols, &chest_dl_res);
|
||||
// Copy configuration
|
||||
pdsch_cfg.dmrs_cfg_typeB = pdsch_cfg.dmrs_cfg_typeA;
|
||||
|
||||
int n = run_test(&dmrs_pdsch, &pdsch_cfg, &grant, sf_symbols, &chest_dl_res);
|
||||
|
||||
if (n == SRSLTE_SUCCESS) {
|
||||
test_passed++;
|
||||
} else {
|
||||
const srslte_pdsch_dmrs_cfg_t* dmrs_cfg = grant.mapping == srslte_pdsch_mapping_type_A
|
||||
? &pdsch_cfg.dmrs_cfg_typeA
|
||||
: &pdsch_cfg.dmrs_cfg_typeB;
|
||||
|
||||
char str[64] = {};
|
||||
srslte_dmrs_pdsch_cfg_to_str(&pdsch_cfg.dmrs_cfg, str, 64);
|
||||
srslte_dmrs_pdsch_cfg_to_str(dmrs_cfg, str, 64);
|
||||
|
||||
ERROR("Test %d failed. %s.\n", test_counter, str);
|
||||
}
|
||||
|
|
|
@ -36,17 +36,17 @@ static void srslte_pdsch_re_cp(cf_t* sf_symbols, cf_t* symbols, uint32_t count,
|
|||
}
|
||||
}
|
||||
|
||||
static uint32_t srslte_pdsch_nr_cp_dmrs_type1(const srslte_pdsch_nr_t* q,
|
||||
const srslte_pdsch_cfg_nr_t* cfg,
|
||||
cf_t* symbols,
|
||||
cf_t* sf_symbols,
|
||||
bool put)
|
||||
static uint32_t srslte_pdsch_nr_cp_dmrs_type1(const srslte_pdsch_nr_t* q,
|
||||
const srslte_pdsch_grant_nr_t* grant,
|
||||
cf_t* symbols,
|
||||
cf_t* sf_symbols,
|
||||
bool put)
|
||||
{
|
||||
uint32_t count = 0;
|
||||
uint32_t delta = 0;
|
||||
|
||||
for (uint32_t i = 0; i < q->carrier.nof_prb; i++) {
|
||||
if (cfg->grant.prb_idx[i]) {
|
||||
if (grant->prb_idx[i]) {
|
||||
for (uint32_t j = 0; j < SRSLTE_NRE; j += 2) {
|
||||
if (put) {
|
||||
sf_symbols[i * SRSLTE_NRE + delta + j] = symbols[count++];
|
||||
|
@ -60,17 +60,17 @@ static uint32_t srslte_pdsch_nr_cp_dmrs_type1(const srslte_pdsch_nr_t* q,
|
|||
return count;
|
||||
}
|
||||
|
||||
static uint32_t srslte_pdsch_nr_cp_dmrs_type2(const srslte_pdsch_nr_t* q,
|
||||
const srslte_pdsch_cfg_nr_t* cfg,
|
||||
cf_t* symbols,
|
||||
cf_t* sf_symbols,
|
||||
bool put)
|
||||
static uint32_t srslte_pdsch_nr_cp_dmrs_type2(const srslte_pdsch_nr_t* q,
|
||||
const srslte_pdsch_grant_nr_t* grant,
|
||||
cf_t* symbols,
|
||||
cf_t* sf_symbols,
|
||||
bool put)
|
||||
{
|
||||
uint32_t count = 0;
|
||||
uint32_t delta = 0;
|
||||
|
||||
for (uint32_t i = 0; i < q->carrier.nof_prb; i++) {
|
||||
if (cfg->grant.prb_idx[i]) {
|
||||
if (grant->prb_idx[i]) {
|
||||
// Copy RE before first pilot pair
|
||||
if (delta > 0) {
|
||||
srslte_pdsch_re_cp(&sf_symbols[i * SRSLTE_NRE], &symbols[count], delta, put);
|
||||
|
@ -90,38 +90,42 @@ static uint32_t srslte_pdsch_nr_cp_dmrs_type2(const srslte_pdsch_nr_t* q,
|
|||
return count;
|
||||
}
|
||||
|
||||
static uint32_t srslte_pdsch_nr_cp_dmrs(const srslte_pdsch_nr_t* q,
|
||||
const srslte_pdsch_cfg_nr_t* cfg,
|
||||
cf_t* symbols,
|
||||
cf_t* sf_symbols,
|
||||
bool put)
|
||||
static uint32_t srslte_pdsch_nr_cp_dmrs(const srslte_pdsch_nr_t* q,
|
||||
const srslte_pdsch_cfg_nr_t* cfg,
|
||||
const srslte_pdsch_grant_nr_t* grant,
|
||||
cf_t* symbols,
|
||||
cf_t* sf_symbols,
|
||||
bool put)
|
||||
{
|
||||
uint32_t count = 0;
|
||||
|
||||
switch (cfg->dmrs_cfg.type) {
|
||||
const srslte_pdsch_dmrs_cfg_t* dmrs_cfg =
|
||||
grant->mapping == srslte_pdsch_mapping_type_A ? &cfg->dmrs_cfg_typeA : &cfg->dmrs_cfg_typeB;
|
||||
|
||||
switch (dmrs_cfg->type) {
|
||||
case srslte_dmrs_pdsch_type_1:
|
||||
count = srslte_pdsch_nr_cp_dmrs_type1(q, cfg, symbols, sf_symbols, put);
|
||||
count = srslte_pdsch_nr_cp_dmrs_type1(q, grant, symbols, sf_symbols, put);
|
||||
break;
|
||||
case srslte_dmrs_pdsch_type_2:
|
||||
count = srslte_pdsch_nr_cp_dmrs_type2(q, cfg, symbols, sf_symbols, put);
|
||||
count = srslte_pdsch_nr_cp_dmrs_type2(q, grant, symbols, sf_symbols, put);
|
||||
break;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static uint32_t srslte_pdsch_nr_cp_clean(const srslte_pdsch_nr_t* q,
|
||||
const srslte_pdsch_cfg_nr_t* cfg,
|
||||
cf_t* symbols,
|
||||
cf_t* sf_symbols,
|
||||
bool put)
|
||||
static uint32_t srslte_pdsch_nr_cp_clean(const srslte_pdsch_nr_t* q,
|
||||
const srslte_pdsch_grant_nr_t* grant,
|
||||
cf_t* symbols,
|
||||
cf_t* sf_symbols,
|
||||
bool put)
|
||||
{
|
||||
uint32_t count = 0;
|
||||
uint32_t start = 0; // Index of the start of continuous data
|
||||
uint32_t length = 0; // End of continuous RE
|
||||
|
||||
for (uint32_t i = 0; i < q->carrier.nof_prb; i++) {
|
||||
if (cfg->grant.prb_idx[i]) {
|
||||
if (grant->prb_idx[i]) {
|
||||
// If fist continuous block, save start
|
||||
if (length == 0) {
|
||||
start = i * SRSLTE_NRE;
|
||||
|
@ -156,23 +160,24 @@ static uint32_t srslte_pdsch_nr_cp_clean(const srslte_pdsch_nr_t* q,
|
|||
return count;
|
||||
}
|
||||
|
||||
static int srslte_pdsch_nr_cp(const srslte_pdsch_nr_t* q,
|
||||
const srslte_pdsch_cfg_nr_t* cfg,
|
||||
cf_t* symbols,
|
||||
cf_t* sf_symbols,
|
||||
bool put)
|
||||
static int srslte_pdsch_nr_cp(const srslte_pdsch_nr_t* q,
|
||||
const srslte_pdsch_cfg_nr_t* cfg,
|
||||
const srslte_pdsch_grant_nr_t* grant,
|
||||
cf_t* symbols,
|
||||
cf_t* sf_symbols,
|
||||
bool put)
|
||||
{
|
||||
uint32_t count = 0;
|
||||
uint32_t dmrs_l_idx[SRSLTE_DMRS_PDSCH_MAX_SYMBOLS] = {};
|
||||
uint32_t dmrs_l_count = 0;
|
||||
|
||||
// Get symbol indexes carrying DMRS
|
||||
int32_t nof_dmrs_symbols = srslte_dmrs_pdsch_get_symbols_idx(cfg, dmrs_l_idx);
|
||||
int32_t nof_dmrs_symbols = srslte_dmrs_pdsch_get_symbols_idx(cfg, grant, dmrs_l_idx);
|
||||
if (nof_dmrs_symbols < SRSLTE_SUCCESS) {
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
for (uint32_t l = cfg->grant.S; l < cfg->grant.L; l++) {
|
||||
for (uint32_t l = grant->S; l < grant->L; l++) {
|
||||
// Advance DMRS symbol counter until:
|
||||
// - the current DMRS symbol index is greater or equal than current symbol l
|
||||
// - no more DMRS symbols
|
||||
|
@ -181,18 +186,24 @@ static int srslte_pdsch_nr_cp(const srslte_pdsch_nr_t* q,
|
|||
}
|
||||
|
||||
if (l == dmrs_l_idx[dmrs_l_count]) {
|
||||
count += srslte_pdsch_nr_cp_dmrs(q, cfg, &symbols[count], &sf_symbols[l * q->carrier.nof_prb * SRSLTE_NRE], put);
|
||||
count += srslte_pdsch_nr_cp_dmrs(
|
||||
q, cfg, grant, &symbols[count], &sf_symbols[l * q->carrier.nof_prb * SRSLTE_NRE], put);
|
||||
} else {
|
||||
count += srslte_pdsch_nr_cp_clean(q, cfg, &symbols[count], &sf_symbols[l * q->carrier.nof_prb * SRSLTE_NRE], put);
|
||||
count +=
|
||||
srslte_pdsch_nr_cp_clean(q, grant, &symbols[count], &sf_symbols[l * q->carrier.nof_prb * SRSLTE_NRE], put);
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
int srslte_pdsch_nr_put(const srslte_pdsch_nr_t* q, const srslte_pdsch_cfg_nr_t* cfg, cf_t* symbols, cf_t* sf_symbols)
|
||||
int srslte_pdsch_nr_put(const srslte_pdsch_nr_t* q,
|
||||
const srslte_pdsch_cfg_nr_t* cfg,
|
||||
const srslte_pdsch_grant_nr_t* grant,
|
||||
cf_t* symbols,
|
||||
cf_t* sf_symbols)
|
||||
{
|
||||
return srslte_pdsch_nr_cp(q, cfg, symbols, sf_symbols, true);
|
||||
return srslte_pdsch_nr_cp(q, cfg, grant, symbols, sf_symbols, true);
|
||||
}
|
||||
|
||||
int srslte_pdsch_nr_encode(srslte_pdsch_nr_t* q,
|
||||
|
|
|
@ -0,0 +1,348 @@
|
|||
/*
|
||||
* Copyright 2013-2020 Software Radio Systems Limited
|
||||
*
|
||||
* This file is part of srsLTE.
|
||||
*
|
||||
* srsLTE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* srsLTE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Affero General Public License can be found in
|
||||
* the LICENSE file in the top-level directory of this distribution
|
||||
* and at http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "srslte/phy/phch/ra_nr.h"
|
||||
#include "srslte/phy/phch/pdsch_nr.h"
|
||||
#include "srslte/phy/utils/debug.h"
|
||||
|
||||
typedef struct {
|
||||
srslte_mod_t modulation;
|
||||
double R; // Target code Rate R x [1024]
|
||||
double S; // Spectral efficiency
|
||||
} mcs_entry_t;
|
||||
|
||||
#define RA_NR_MCS_SIZE_TABLE1 29
|
||||
#define RA_NR_MCS_SIZE_TABLE2 28
|
||||
#define RA_NR_MCS_SIZE_TABLE3 29
|
||||
#define RA_NR_TBS_SIZE_TABLE 93
|
||||
|
||||
#define RA_NR_READ_TABLE(N) \
|
||||
static double srslte_ra_nr_R_from_mcs_table##N(uint32_t mcs_idx) \
|
||||
{ \
|
||||
if (mcs_idx >= RA_NR_MCS_SIZE_TABLE##N) { \
|
||||
return NAN; \
|
||||
} \
|
||||
\
|
||||
return ra_nr_table##N[mcs_idx].R; \
|
||||
} \
|
||||
\
|
||||
static srslte_mod_t srslte_ra_nr_modulation_from_mcs_table##N(uint32_t mcs_idx) \
|
||||
{ \
|
||||
if (mcs_idx >= RA_NR_MCS_SIZE_TABLE##N) { \
|
||||
return SRSLTE_MOD_NITEMS; \
|
||||
} \
|
||||
\
|
||||
return ra_nr_table##N[mcs_idx].modulation; \
|
||||
}
|
||||
|
||||
/**
|
||||
* TS 38.214 V15.10.0 Table 5.1.3.1-1: MCS index table 1 for PDSCH
|
||||
*/
|
||||
static const mcs_entry_t ra_nr_table1[RA_NR_MCS_SIZE_TABLE1] = {
|
||||
{SRSLTE_MOD_QPSK, 120, 0.2344}, {SRSLTE_MOD_QPSK, 157, 0.3066}, {SRSLTE_MOD_QPSK, 193, 0.3770},
|
||||
{SRSLTE_MOD_QPSK, 251, 0.4902}, {SRSLTE_MOD_QPSK, 308, 0.6016}, {SRSLTE_MOD_QPSK, 379, 0.7402},
|
||||
{SRSLTE_MOD_QPSK, 449, 0.8770}, {SRSLTE_MOD_QPSK, 526, 1.0273}, {SRSLTE_MOD_QPSK, 602, 1.1758},
|
||||
{SRSLTE_MOD_QPSK, 679, 1.3262}, {SRSLTE_MOD_16QAM, 340, 1.3281}, {SRSLTE_MOD_16QAM, 378, 1.4766},
|
||||
{SRSLTE_MOD_16QAM, 434, 1.6953}, {SRSLTE_MOD_16QAM, 490, 1.9141}, {SRSLTE_MOD_16QAM, 553, 2.1602},
|
||||
{SRSLTE_MOD_16QAM, 616, 2.4063}, {SRSLTE_MOD_16QAM, 658, 2.5703}, {SRSLTE_MOD_64QAM, 438, 2.5664},
|
||||
{SRSLTE_MOD_64QAM, 466, 2.7305}, {SRSLTE_MOD_64QAM, 517, 3.0293}, {SRSLTE_MOD_64QAM, 567, 3.3223},
|
||||
{SRSLTE_MOD_64QAM, 616, 3.6094}, {SRSLTE_MOD_64QAM, 666, 3.9023}, {SRSLTE_MOD_64QAM, 719, 4.2129},
|
||||
{SRSLTE_MOD_64QAM, 772, 4.5234}, {SRSLTE_MOD_64QAM, 822, 4.8164}, {SRSLTE_MOD_64QAM, 873, 5.1152},
|
||||
{SRSLTE_MOD_64QAM, 910, 5.3320}, {SRSLTE_MOD_64QAM, 948, 5.5547}};
|
||||
|
||||
/**
|
||||
* TS 38.214 V15.10.0 Table 5.1.3.1-2: MCS index table 2 for PDSCH
|
||||
*/
|
||||
static const mcs_entry_t ra_nr_table2[RA_NR_MCS_SIZE_TABLE2] = {
|
||||
{SRSLTE_MOD_QPSK, 120, 0.2344}, {SRSLTE_MOD_QPSK, 193, 0.3770}, {SRSLTE_MOD_QPSK, 308, 0.6016},
|
||||
{SRSLTE_MOD_QPSK, 449, 0.8770}, {SRSLTE_MOD_QPSK, 602, 1.1758}, {SRSLTE_MOD_16QAM, 378, 1.4766},
|
||||
{SRSLTE_MOD_16QAM, 434, 1.6953}, {SRSLTE_MOD_16QAM, 490, 1.9141}, {SRSLTE_MOD_16QAM, 553, 2.1602},
|
||||
{SRSLTE_MOD_16QAM, 616, 2.4063}, {SRSLTE_MOD_16QAM, 658, 2.5703}, {SRSLTE_MOD_64QAM, 466, 2.7305},
|
||||
{SRSLTE_MOD_64QAM, 517, 3.0293}, {SRSLTE_MOD_64QAM, 567, 3.3223}, {SRSLTE_MOD_64QAM, 616, 3.6094},
|
||||
{SRSLTE_MOD_64QAM, 666, 3.9023}, {SRSLTE_MOD_64QAM, 719, 4.2129}, {SRSLTE_MOD_64QAM, 772, 4.5234},
|
||||
{SRSLTE_MOD_64QAM, 822, 4.8164}, {SRSLTE_MOD_64QAM, 873, 5.1152}, {SRSLTE_MOD_256QAM, 682.5, 5.3320},
|
||||
{SRSLTE_MOD_256QAM, 711, 5.5547}, {SRSLTE_MOD_256QAM, 754, 5.8906}, {SRSLTE_MOD_256QAM, 797, 6.2266},
|
||||
{SRSLTE_MOD_256QAM, 841, 6.5703}, {SRSLTE_MOD_256QAM, 885, 6.9141}, {SRSLTE_MOD_256QAM, 916.5, 7.1602},
|
||||
{SRSLTE_MOD_256QAM, 948, 7.4063}};
|
||||
|
||||
/**
|
||||
* TS 38.214 V15.10.0 Table 5.1.3.1-2: MCS index table 2 for PDSCH
|
||||
*/
|
||||
static const mcs_entry_t ra_nr_table3[RA_NR_MCS_SIZE_TABLE3] = {
|
||||
{SRSLTE_MOD_QPSK, 30, 0.0586}, {SRSLTE_MOD_QPSK, 40, 0.0781}, {SRSLTE_MOD_QPSK, 50, 0.0977},
|
||||
{SRSLTE_MOD_QPSK, 64, 0.1250}, {SRSLTE_MOD_QPSK, 78, 0.1523}, {SRSLTE_MOD_QPSK, 99, 0.1934},
|
||||
{SRSLTE_MOD_QPSK, 120, 0.2344}, {SRSLTE_MOD_QPSK, 157, 0.3066}, {SRSLTE_MOD_QPSK, 193, 0.3770},
|
||||
{SRSLTE_MOD_QPSK, 251, 0.4902}, {SRSLTE_MOD_QPSK, 308, 0.6016}, {SRSLTE_MOD_QPSK, 379, 0.7402},
|
||||
{SRSLTE_MOD_QPSK, 449, 0.8770}, {SRSLTE_MOD_QPSK, 526, 1.0273}, {SRSLTE_MOD_QPSK, 602, 1.1758},
|
||||
{SRSLTE_MOD_16QAM, 340, 1.3281}, {SRSLTE_MOD_16QAM, 378, 1.4766}, {SRSLTE_MOD_16QAM, 434, 1.6953},
|
||||
{SRSLTE_MOD_16QAM, 490, 1.9141}, {SRSLTE_MOD_16QAM, 553, 2.1602}, {SRSLTE_MOD_16QAM, 616, 2.4063},
|
||||
{SRSLTE_MOD_64QAM, 438, 2.5664}, {SRSLTE_MOD_64QAM, 466, 2.7305}, {SRSLTE_MOD_64QAM, 517, 3.0293},
|
||||
{SRSLTE_MOD_64QAM, 567, 3.3223}, {SRSLTE_MOD_64QAM, 616, 3.6094}, {SRSLTE_MOD_64QAM, 666, 3.9023},
|
||||
{SRSLTE_MOD_64QAM, 719, 4.2129}, {SRSLTE_MOD_64QAM, 772, 4.5234}};
|
||||
|
||||
/**
|
||||
* Generate MCS table access functions
|
||||
*/
|
||||
RA_NR_READ_TABLE(1)
|
||||
RA_NR_READ_TABLE(2)
|
||||
RA_NR_READ_TABLE(3)
|
||||
|
||||
/**
|
||||
* TS 38.214 V15.10.0 Table 5.1.3.2-1: TBS for N inf o ≤ 3824
|
||||
*/
|
||||
static const uint32_t ra_nr_tbs_table[RA_NR_TBS_SIZE_TABLE] = {
|
||||
24, 32, 40, 48, 56, 64, 72, 80, 88, 96, 104, 112, 120, 128, 136, 144, 152, 160, 168,
|
||||
176, 184, 192, 208, 224, 240, 256, 272, 288, 304, 320, 336, 352, 368, 384, 408, 432, 456, 480,
|
||||
504, 528, 552, 576, 608, 640, 672, 704, 736, 768, 808, 848, 888, 928, 984, 1032, 1064, 1128, 1160,
|
||||
1192, 1224, 1256, 1288, 1320, 1352, 1416, 1480, 1544, 1608, 1672, 1736, 1800, 1864, 1928, 2024, 2088, 2152, 2216,
|
||||
2280, 2408, 2472, 2536, 2600, 2664, 2728, 2792, 2856, 2976, 3104, 3240, 3368, 3496, 3624, 3752, 3824};
|
||||
|
||||
typedef enum { ra_nr_table_1 = 0, ra_nr_table_2, ra_nr_table_3 } ra_nr_table_t;
|
||||
|
||||
static ra_nr_table_t ra_nr_select_table(srslte_mcs_table_t mcs_table,
|
||||
srslte_dci_format_nr_t dci_format,
|
||||
srslte_search_space_type_t search_space_type,
|
||||
uint16_t rnti)
|
||||
{
|
||||
// Non-implemented parameters
|
||||
bool sps_config_mcs_table_present = false;
|
||||
srslte_mcs_table_t sps_config_mcs_table = srslte_mcs_table_64qam;
|
||||
bool is_cs_rnti = false;
|
||||
bool is_pdcch_sps = false;
|
||||
|
||||
// - the higher layer parameter mcs-Table given by PDSCH-Config is set to 'qam256', and
|
||||
// - the PDSCH is scheduled by a PDCCH with DCI format 1_1 with
|
||||
// - CRC scrambled by C-RNTI
|
||||
if (mcs_table == srslte_mcs_table_256qam && dci_format == srslte_dci_format_nr_1_1 && SRSLTE_RNTI_ISUSER(rnti)) {
|
||||
return ra_nr_table_1;
|
||||
}
|
||||
|
||||
// the UE is not configured with MCS-C-RNTI,
|
||||
// the higher layer parameter mcs-Table given by PDSCH-Config is set to 'qam64LowSE', and
|
||||
// the PDSCH is scheduled by a PDCCH in a UE-specific search space with
|
||||
// CRC scrambled by C - RNTI
|
||||
if (mcs_table == srslte_mcs_table_qam64LowSE && search_space_type == srslte_search_space_type_ue &&
|
||||
SRSLTE_RNTI_ISUSER(rnti)) {
|
||||
return ra_nr_table_3;
|
||||
}
|
||||
|
||||
// - the UE is not configured with the higher layer parameter mcs-Table given by SPS-Config,
|
||||
// - the higher layer parameter mcs-Table given by PDSCH-Config is set to 'qam256',
|
||||
// - if the PDSCH is scheduled by a PDCCH with DCI format 1_1 with CRC scrambled by CS-RNTI or
|
||||
// - if the PDSCH is scheduled without corresponding PDCCH transmission using SPS-Config,
|
||||
if (!sps_config_mcs_table_present && mcs_table == srslte_mcs_table_256qam &&
|
||||
((dci_format == srslte_dci_format_nr_1_1 && is_cs_rnti) || (!is_pdcch_sps))) {
|
||||
return ra_nr_table_2;
|
||||
}
|
||||
|
||||
// - the UE is configured with the higher layer parameter mcs-Table given by SPS-Config set to 'qam64LowSE'
|
||||
// - if the PDSCH is scheduled by a PDCCH with CRC scrambled by CS-RNTI or
|
||||
// - if the PDSCH is scheduled without corresponding PDCCH transmission using SPS-Config,
|
||||
if (sps_config_mcs_table_present && sps_config_mcs_table == srslte_mcs_table_qam64LowSE &&
|
||||
(is_cs_rnti || is_pdcch_sps)) {
|
||||
return ra_nr_table_3;
|
||||
}
|
||||
|
||||
// else
|
||||
return ra_nr_table_1;
|
||||
}
|
||||
|
||||
double srslte_ra_nr_R_from_mcs(srslte_mcs_table_t mcs_table,
|
||||
srslte_dci_format_nr_t dci_format,
|
||||
srslte_search_space_type_t search_space_type,
|
||||
uint16_t rnti,
|
||||
uint32_t mcs_idx)
|
||||
{
|
||||
ra_nr_table_t table = ra_nr_select_table(mcs_table, dci_format, search_space_type, rnti);
|
||||
|
||||
switch (table) {
|
||||
case ra_nr_table_1:
|
||||
return srslte_ra_nr_R_from_mcs_table1(mcs_idx) / 1024.0;
|
||||
case ra_nr_table_2:
|
||||
return srslte_ra_nr_R_from_mcs_table2(mcs_idx) / 1024.0;
|
||||
case ra_nr_table_3:
|
||||
return srslte_ra_nr_R_from_mcs_table3(mcs_idx) / 1024.0;
|
||||
default:
|
||||
ERROR("Invalid table %d\n", table);
|
||||
}
|
||||
|
||||
return NAN;
|
||||
}
|
||||
|
||||
srslte_mod_t srslte_ra_nr_mod_from_mcs(srslte_mcs_table_t mcs_table,
|
||||
srslte_dci_format_nr_t dci_format,
|
||||
srslte_search_space_type_t search_space_type,
|
||||
uint16_t rnti,
|
||||
uint32_t mcs_idx)
|
||||
{
|
||||
ra_nr_table_t table = ra_nr_select_table(mcs_table, dci_format, search_space_type, rnti);
|
||||
|
||||
switch (table) {
|
||||
case ra_nr_table_1:
|
||||
return srslte_ra_nr_modulation_from_mcs_table1(mcs_idx);
|
||||
case ra_nr_table_2:
|
||||
return srslte_ra_nr_modulation_from_mcs_table2(mcs_idx);
|
||||
case ra_nr_table_3:
|
||||
return srslte_ra_nr_modulation_from_mcs_table3(mcs_idx);
|
||||
default:
|
||||
ERROR("Invalid table %d\n", table);
|
||||
}
|
||||
|
||||
return SRSLTE_MOD_NITEMS;
|
||||
}
|
||||
|
||||
static int ra_nr_determine_N_re(const srslte_pdsch_cfg_nr_t* pdsch_cfg, const srslte_pdsch_grant_nr_t* grant)
|
||||
{
|
||||
// the number of symbols of the PDSCH allocation within the slot
|
||||
int n_sh_symb = grant->L;
|
||||
|
||||
// the number of REs for DM-RS per PRB in the scheduled duration
|
||||
int n_prb_dmrs = srslte_dmrs_pdsch_get_N_prb(pdsch_cfg, grant);
|
||||
if (n_prb_dmrs < SRSLTE_SUCCESS) {
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
// the overhead configured by higher layer parameter xOverhead in PDSCH-ServingCellConfig
|
||||
uint32_t n_prb_oh = 0;
|
||||
|
||||
// Compute total number of n_re used for PDSCH
|
||||
uint32_t n_re_prime = SRSLTE_NRE * n_sh_symb - n_prb_dmrs - n_prb_oh;
|
||||
|
||||
uint32_t n_prb = 0;
|
||||
for (uint32_t i = 0; i < SRSLTE_MAX_PRB_NR; i++) {
|
||||
n_prb += (uint32_t)grant->prb_idx[i];
|
||||
}
|
||||
|
||||
// Return the number of resource elements for PDSCH
|
||||
return SRSLTE_MIN(SRSLTE_MAX_NRE_NR, n_re_prime) * n_prb;
|
||||
}
|
||||
|
||||
#define CEIL(NUM, DEN) (((NUM) + ((DEN)-1)) / (DEN))
|
||||
#define FLOOR(NUM, DEN) ((NUM) / (DEN))
|
||||
#define ROUND(NUM, DEN) ((uint32_t)round((NUM) / (DEN)))
|
||||
#define POW2(N) (1U << (N))
|
||||
|
||||
static uint32_t ra_nr_tbs_from_n_info3(uint32_t n_info)
|
||||
{
|
||||
// quantized intermediate number of information bits
|
||||
uint32_t n = (uint32_t)SRSLTE_MAX(3.0, floor(log2(n_info)) - 6.0);
|
||||
uint32_t n_info_prime = SRSLTE_MAX(ra_nr_tbs_table[0], POW2(n) * FLOOR(n_info, POW2(n)));
|
||||
|
||||
// use Table 5.1.3.2-1 find the closest TBS that is not less than n_info_prime
|
||||
for (uint32_t i = 0; i < RA_NR_TBS_SIZE_TABLE; i++) {
|
||||
if (n_info_prime <= ra_nr_tbs_table[i]) {
|
||||
return ra_nr_tbs_table[i];
|
||||
}
|
||||
}
|
||||
|
||||
return ra_nr_tbs_table[RA_NR_TBS_SIZE_TABLE - 1];
|
||||
}
|
||||
|
||||
static uint32_t ra_nr_tbs_from_n_info4(uint32_t n_info, double R)
|
||||
{
|
||||
// quantized intermediate number of information bits
|
||||
uint32_t n = (uint32_t)(floor(log2(n_info - 24.0)) - 5.0);
|
||||
uint32_t n_info_prime = SRSLTE_MAX(3840, POW2(n) * ROUND(n_info - 24.0, POW2(n)));
|
||||
|
||||
if (R <= 0.25) {
|
||||
uint32_t C = CEIL(n_info_prime + 24U, 3816U);
|
||||
return 8U * C * CEIL(n_info_prime + 24U, 8U * C) - 24U;
|
||||
}
|
||||
|
||||
if (n_info_prime > 8424) {
|
||||
uint32_t C = CEIL(n_info_prime + 24U, 8424U);
|
||||
return 8U * C * CEIL(n_info_prime + 24U, 8U * C) - 24U;
|
||||
}
|
||||
|
||||
return 8U * CEIL(n_info_prime + 24U, 8U) - 24U;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Implements TS 38.214 V15.10.0 Table 5.1.3.2-2 Scaling factor of N_info for P-RNTI and RA-RNTI
|
||||
* @param tb_scaling_field provided by the grant
|
||||
* @return It returns the value if the field is in range, otherwise it returns NAN
|
||||
*/
|
||||
static double ra_nr_get_scaling(uint32_t tb_scaling_field)
|
||||
{
|
||||
static const double tb_scaling[4] = {1.0, 0.5, 0.25, NAN};
|
||||
|
||||
if (tb_scaling_field < 4) {
|
||||
return tb_scaling[tb_scaling_field];
|
||||
}
|
||||
|
||||
return NAN;
|
||||
}
|
||||
|
||||
int srslte_ra_nr_tbs(const srslte_pdsch_cfg_nr_t* pdsch_cfg, const srslte_pdsch_grant_nr_t* grant, uint32_t mcs_idx)
|
||||
{
|
||||
// Get target Rate
|
||||
double R =
|
||||
srslte_ra_nr_R_from_mcs(pdsch_cfg->mcs_table, grant->dci_format, grant->dci_search_space, grant->rnti, mcs_idx);
|
||||
if (!isnormal(R)) {
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
// Get modulation
|
||||
srslte_mod_t m =
|
||||
srslte_ra_nr_mod_from_mcs(pdsch_cfg->mcs_table, grant->dci_format, grant->dci_search_space, grant->rnti, mcs_idx);
|
||||
if (m >= SRSLTE_MOD_NITEMS) {
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
// Get modulation order
|
||||
uint32_t Qm = srslte_mod_bits_x_symbol(m);
|
||||
if (Qm == 0) {
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
// For the PDSCH assigned by a
|
||||
// - PDCCH with DCI format 1_0 with
|
||||
// - CRC scrambled by P-RNTI, or RA-RNTI,
|
||||
double S = 1.0;
|
||||
if ((SRSLTE_RNTI_ISRAR(grant->rnti) || SRSLTE_RNTI_ISPA(grant->rnti)) &&
|
||||
grant->dci_format == srslte_dci_format_nr_1_0) {
|
||||
// where the scaling factor S is determined based on the TB scaling
|
||||
// field in the DCI as in Table 5.1.3.2-2.
|
||||
S = ra_nr_get_scaling(grant->tb_scaling_field);
|
||||
|
||||
// If the scaling is invalid return error
|
||||
if (!isnormal(S)) {
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
// 1) The UE shall first determine the number of REs (N RE ) within the slot.
|
||||
int n_re = ra_nr_determine_N_re(pdsch_cfg, grant);
|
||||
if (n_re < SRSLTE_SUCCESS) {
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
// 2) Intermediate number of information bits (N info ) is obtained by N inf o = N RE · R · Q m · υ .
|
||||
uint32_t n_info = (uint32_t)(n_re * S * R * Qm * grant->nof_layers);
|
||||
|
||||
// 3) When n_info ≤ 3824
|
||||
if (n_info <= 3824) {
|
||||
return (int)ra_nr_tbs_from_n_info3(n_info);
|
||||
}
|
||||
|
||||
// 4) When n_info > 3824
|
||||
return (int)ra_nr_tbs_from_n_info4(n_info, R);
|
||||
}
|
Loading…
Reference in New Issue