Implement NR-PUCCH Format 2 encode/decode. Initial NR-PUCCH procedures.

This commit is contained in:
Xavier Arteaga 2021-01-25 18:15:28 +01:00 committed by Xavier Arteaga
parent 4b6849b775
commit 958afaee60
13 changed files with 838 additions and 158 deletions

View File

@ -17,6 +17,18 @@
#include "srslte/phy/ch_estimation/chest_ul.h"
#include "srslte/phy/phch/pucch_nr.h"
#define SRSLTE_DMRS_PUCCH_FORMAT_3_4_MAX_NSYMB 4
/**
* @brief Computes the symbol indexes carrying DMRS for NR-PUCCH formats 3 and 4
* @remark Implements TS 38.211 Table 6.4.1.3.3.2-1: DM-RS positions for PUCCH format 3 and 4.
* @param[in] resource Provides the format 3 or 4 resource
* @param[out] idx Destination data for storing the symbol indexes
* @return The number of DMRS symbols if the resource is valid, SRSLTE_ERROR code otherwise
*/
SRSLTE_API int srslte_dmrs_pucch_format_3_4_get_symbol_idx(const srslte_pucch_nr_resource_t* resource,
uint32_t idx[SRSLTE_DMRS_PUCCH_FORMAT_3_4_MAX_NSYMB]);
/**
* @brief Puts NR-PUCCH format 1 DMRS in the provided resource grid
* @param[in] q NR-PUCCH encoder/decoder object

View File

@ -64,7 +64,7 @@ extern "C" {
#define SRSLTE_LTE_CRC24B 0X1800063
#define SRSLTE_LTE_CRC24C 0X1B2B117
#define SRSLTE_LTE_CRC16 0x11021
#define SRSLTE_LTE_CRC11 0x621
#define SRSLTE_LTE_CRC11 0xE21
#define SRSLTE_LTE_CRC8 0x19B
#define SRSLTE_LTE_CRC6 0x61
@ -274,7 +274,7 @@ typedef enum SRSLTE_API { SRSLTE_MIMO_DECODER_ZF, SRSLTE_MIMO_DECODER_MMSE } srs
* \brief Types of modulations and associated modulation order.
*/
typedef enum SRSLTE_API {
SRSLTE_MOD_BPSK = 0, /*!< \brief pi/2-BPSK. */
SRSLTE_MOD_BPSK = 0, /*!< \brief BPSK. */
SRSLTE_MOD_QPSK, /*!< \brief QPSK. */
SRSLTE_MOD_16QAM, /*!< \brief QAM16. */
SRSLTE_MOD_64QAM, /*!< \brief QAM64. */

View File

@ -17,6 +17,54 @@
#include <stdbool.h>
#include <stdint.h>
/**
* NR-PUCCH Format 0 ranges
*/
#define SRSLTE_PUCCH_NR_FORMAT0_MAX_CS 11
#define SRSLTE_PUCCH_NR_FORMAT0_MIN_NSYMB 1
#define SRSLTE_PUCCH_NR_FORMAT0_MAX_NSYMB 2
#define SRSLTE_PUCCH_NR_FORMAT0_MAX_STARTSYMB 13
/**
* NR-PUCCH Format 1 ranges
*/
#define SRSLTE_PUCCH_NR_FORMAT1_MAX_CS 11
#define SRSLTE_PUCCH_NR_FORMAT1_MAX_TOCC 6
#define SRSLTE_PUCCH_NR_FORMAT1_MIN_NSYMB 4
#define SRSLTE_PUCCH_NR_FORMAT1_MAX_NSYMB 14
#define SRSLTE_PUCCH_NR_FORMAT1_MAX_STARTSYMB 10
/**
* NR-PUCCH Format 2 ranges
*/
#define SRSLTE_PUCCH_NR_FORMAT2_MIN_NPRB 1
#define SRSLTE_PUCCH_NR_FORMAT2_MAX_NPRB 16
#define SRSLTE_PUCCH_NR_FORMAT2_MIN_NSYMB 1
#define SRSLTE_PUCCH_NR_FORMAT2_MAX_NSYMB 2
#define SRSLTE_PUCCH_NR_FORMAT2_MAX_STARTSYMB 13
/**
* NR-PUCCH Format 3 ranges
*/
#define SRSLTE_PUCCH_NR_FORMAT3_MIN_NPRB 1
#define SRSLTE_PUCCH_NR_FORMAT3_MAX_NPRB 16
#define SRSLTE_PUCCH_NR_FORMAT3_MIN_NSYMB 4
#define SRSLTE_PUCCH_NR_FORMAT3_MAX_NSYMB 14
#define SRSLTE_PUCCH_NR_FORMAT3_MAX_STARTSYMB 10
/**
* NR-PUCCH Format 4 ranges
*/
#define SRSLTE_PUCCH_NR_FORMAT4_NPRB 1
#define SRSLTE_PUCCH_NR_FORMAT4_MIN_NSYMB 4
#define SRSLTE_PUCCH_NR_FORMAT4_MAX_NSYMB 14
#define SRSLTE_PUCCH_NR_FORMAT4_MAX_STARTSYMB 10
/**
* NR-PUCCH Formats 2, 3 and 4 code rate range
*/
#define SRSLTE_PUCCH_NR_MAX_CODE_RATE 7
typedef enum SRSLTE_API {
SRSLTE_PUCCH_NR_FORMAT_0 = 0,
SRSLTE_PUCCH_NR_FORMAT_1,
@ -42,6 +90,10 @@ typedef struct SRSLTE_API {
uint32_t hopping_id; ///< Cell-specific scrambling ID for group hopping and sequence hopping if enabled
bool hopping_id_present;
float p0_nominal; ///< Power control parameter P0 for PUCCH transmissions. Value in dBm. (-202..24)
// From PUSCH-config
bool scrambling_id_present;
uint32_t scambling_id; // Identifier used to initialize data scrambling (dataScramblingIdentityPUSCH, 0-1023)
} srslte_pucch_nr_common_cfg_t;
/**
@ -49,7 +101,7 @@ typedef struct SRSLTE_API {
* @remark Defined in TS 38.331 PUCCH-Config
*/
typedef struct SRSLTE_API {
//
// Common PUCCH-Resource parameter
uint32_t starting_prb;
bool intra_slot_hopping;
uint32_t second_hop_prb;
@ -58,36 +110,25 @@ typedef struct SRSLTE_API {
srslte_pucch_nr_format_t format; ///< PUCCH format this configuration belongs
uint32_t nof_symbols; ///< Number of symbols
uint32_t start_symbol_idx; ///< Starting symbol index
double max_code_rate; ///< Maximum code rate (0.08, 0.15, 0.25, 0.35, 0.45, 0.60, 0.80)
bool enable_pi_bpsk; ///< Enables PI-BPSK
// Specific PUCCH-Resource
uint32_t initial_cyclic_shift; ///< Used by formats 0, 1
uint32_t time_domain_occ; ///< Used by format 1
uint32_t nof_prb; ///< Used by formats 2, 3
uint32_t occ_lenth; ///< Spreading factor, used by format 4
uint32_t occ_lenth; ///< Spreading factor, used by format 4 (2, 4). Also called N_PUCCH4_SF
uint32_t occ_index; ///< Used by format 4
// PUCCH Format common parameters
bool enable_pi_bpsk; ///< Enables PI-BPSK
uint32_t max_code_rate; ///< Maximum code rate r (0..7)
bool additional_dmrs; ///< UE enables 2 DMRS symbols per hop of a PUCCH Format 3 or 4
} srslte_pucch_nr_resource_t;
/**
* @brief Validates a PUCCH format 0 resource configuration provided by upper layers
* @brief Validates an NR-PUCCH resource configuration provided by upper layers
* @param resource Resource configuration to validate
* @return SRSLTE_SUCCESS if valid, SRSLTE_ERROR code otherwise
*/
SRSLTE_API int srslte_pucch_nr_format0_resource_valid(const srslte_pucch_nr_resource_t* resource);
/**
* @brief Validates a PUCCH format 1 resource configuration provided by upper layers
* @param resource Resource configuration to validate
* @return SRSLTE_SUCCESS if valid, SRSLTE_ERROR code otherwise
*/
SRSLTE_API int srslte_pucch_nr_format1_resource_valid(const srslte_pucch_nr_resource_t* resource);
/**
* @brief Validates a PUCCH format 2 resource configuration provided by upper layers
* @param resource Resource configuration to validate
* @return SRSLTE_SUCCESS if valid, SRSLTE_ERROR code otherwise
*/
SRSLTE_API int srslte_pucch_nr_format2_resource_valid(const srslte_pucch_nr_resource_t* resource);
SRSLTE_API int srslte_pucch_nr_cfg_resource_valid(const srslte_pucch_nr_resource_t* resource);
#endif // SRSLTE_PUCCH_CFG_NR_H

View File

@ -53,6 +53,7 @@ typedef struct SRSLTE_API {
srslte_modem_table_t qpsk;
srslte_uci_nr_t uci;
uint8_t* b;
cf_t* d;
} srslte_pucch_nr_t;
/**

View File

@ -0,0 +1,27 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2020 Software Radio Systems Limited
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the distribution.
*
*/
#ifndef SRSLTE_RA_UL_NR_H
#define SRSLTE_RA_UL_NR_H
#include "srslte/config.h"
#include "srslte/phy/phch/pucch_cfg_nr.h"
#include "uci_cfg_nr.h"
/**
* @brief
* @return
*/
SRSLTE_API int srslte_ra_ul_nr_pucch_format_2_3_min_prb(const srslte_pucch_nr_resource_t* resource,
const srslte_uci_cfg_nr_t* uci_cfg);
#endif // SRSLTE_RA_UL_NR_H

View File

@ -13,6 +13,7 @@
#ifndef SRSLTE_UCI_CFG_NR_H
#define SRSLTE_UCI_CFG_NR_H
#include "srslte/phy/common/phy_common.h"
#include <stdbool.h>
#include <stdint.h>
@ -27,6 +28,7 @@ typedef struct SRSLTE_API {
uint32_t o_csi1; ///< Number of CSI1 report number of bits
uint32_t o_csi2; ///< Number of CSI2 report number of bits
srslte_mod_t modulation; ///< Modulation
uint16_t rnti; ///< RNTI
} srslte_uci_cfg_nr_t;
typedef struct SRSLTE_API {

View File

@ -29,7 +29,8 @@ typedef struct {
} srslte_uci_nr_args_t;
typedef struct {
srslte_polar_rm_t rm;
srslte_polar_rm_t rm_tx;
srslte_polar_rm_t rm_rx;
srslte_polar_encoder_t encoder;
srslte_polar_decoder_t decoder;
srslte_crc_t crc6;
@ -41,6 +42,12 @@ typedef struct {
uint8_t* d; ///< Polar code encoded intermediate
} srslte_uci_nr_t;
/**
* @brief Calculates in advance how many CRC bits will be appended for a given amount of UCI bits (A)
* @param A Number of UCI bits to transmit
*/
SRSLTE_API uint32_t srslte_uci_nr_crc_len(uint32_t A);
/**
* @brief Initialises NR-UCI encoder/decoder object
* @param[in,out] q NR-UCI object
@ -90,7 +97,7 @@ SRSLTE_API int srslte_uci_nr_encode_pucch(srslte_uci_nr_t* q,
SRSLTE_API int srslte_uci_nr_decode_pucch(srslte_uci_nr_t* q,
const srslte_pucch_nr_resource_t* pucch_resource_cfg,
const srslte_uci_cfg_nr_t* uci_cfg,
const int8_t* llr,
int8_t* llr,
srslte_uci_value_nr_t* value);
#endif // SRSLTE_UCI_NR_H

View File

@ -96,7 +96,7 @@ int srslte_dmrs_pucch_format1_put(const srslte_pucch_nr_t* q,
return SRSLTE_ERROR_INVALID_INPUTS;
}
if (srslte_pucch_nr_format1_resource_valid(resource) < SRSLTE_SUCCESS) {
if (srslte_pucch_nr_cfg_resource_valid(resource) < SRSLTE_SUCCESS) {
ERROR("Invalid PUCCH format 1 resource\n");
return SRSLTE_ERROR;
}
@ -164,7 +164,7 @@ int srslte_dmrs_pucch_format1_estimate(const srslte_pucch_nr_t* q,
return SRSLTE_ERROR_INVALID_INPUTS;
}
if (srslte_pucch_nr_format1_resource_valid(resource) < SRSLTE_SUCCESS) {
if (srslte_pucch_nr_cfg_resource_valid(resource) < SRSLTE_SUCCESS) {
ERROR("Invalid PUCCH format 1 resource\n");
return SRSLTE_ERROR;
}
@ -279,3 +279,101 @@ int srslte_dmrs_pucch_format1_estimate(const srslte_pucch_nr_t* q,
return SRSLTE_SUCCESS;
}
int srslte_dmrs_pucch_format_3_4_get_symbol_idx(const srslte_pucch_nr_resource_t* resource,
uint32_t idx[SRSLTE_DMRS_PUCCH_FORMAT_3_4_MAX_NSYMB])
{
if (resource == NULL || idx == NULL) {
return SRSLTE_ERROR_INVALID_INPUTS;
}
int count = 0;
switch (resource->nof_symbols) {
case 4:
if (resource->intra_slot_hopping) {
idx[count++] = 0;
idx[count++] = 2;
} else {
idx[count++] = 1;
}
break;
case 5:
idx[count++] = 0;
idx[count++] = 3;
break;
case 6:
case 7:
idx[count++] = 1;
idx[count++] = 4;
break;
case 8:
idx[count++] = 1;
idx[count++] = 5;
break;
case 9:
idx[count++] = 1;
idx[count++] = 6;
break;
case 10:
if (resource->additional_dmrs) {
idx[count++] = 1;
idx[count++] = 3;
idx[count++] = 6;
idx[count++] = 8;
} else {
idx[count++] = 2;
idx[count++] = 7;
}
break;
case 11:
if (resource->additional_dmrs) {
idx[count++] = 1;
idx[count++] = 3;
idx[count++] = 6;
idx[count++] = 9;
} else {
idx[count++] = 2;
idx[count++] = 7;
}
break;
case 12:
if (resource->additional_dmrs) {
idx[count++] = 1;
idx[count++] = 4;
idx[count++] = 7;
idx[count++] = 10;
} else {
idx[count++] = 2;
idx[count++] = 8;
}
break;
case 13:
if (resource->additional_dmrs) {
idx[count++] = 1;
idx[count++] = 4;
idx[count++] = 7;
idx[count++] = 11;
} else {
idx[count++] = 2;
idx[count++] = 9;
}
break;
case 14:
if (resource->additional_dmrs) {
idx[count++] = 1;
idx[count++] = 5;
idx[count++] = 8;
idx[count++] = 12;
} else {
idx[count++] = 3;
idx[count++] = 10;
}
break;
default:
ERROR("Invalid case (%d)\n", resource->nof_symbols);
return SRSLTE_ERROR;
}
return count;
}

View File

@ -11,30 +11,28 @@
*/
#include "srslte/phy/phch/pucch_cfg_nr.h"
#include "srslte/phy/common/phy_common_nr.h"
#include "srslte/phy/utils/debug.h"
int srslte_pucch_nr_format0_resource_valid(const srslte_pucch_nr_resource_t* resource)
static int pucch_nr_cfg_format0_resource_valid(const srslte_pucch_nr_resource_t* resource)
{
if (resource == NULL) {
return SRSLTE_ERROR_INVALID_INPUTS;
}
if (resource->format != SRSLTE_PUCCH_NR_FORMAT_0) {
ERROR("Invalid format (%d)\n", resource->format);
return SRSLTE_ERROR;
}
if (resource->nof_symbols != 1 && resource->nof_symbols != 2) {
if (resource->nof_symbols < SRSLTE_PUCCH_NR_FORMAT0_MIN_NSYMB ||
resource->nof_symbols > SRSLTE_PUCCH_NR_FORMAT0_MAX_NSYMB) {
ERROR("Invalid number of symbols (%d)\n", resource->nof_symbols);
return SRSLTE_ERROR;
}
if (resource->initial_cyclic_shift > 11) {
if (resource->initial_cyclic_shift > SRSLTE_PUCCH_NR_FORMAT0_MAX_CS) {
ERROR("Invalid initial cyclic shift (%d)\n", resource->initial_cyclic_shift);
return SRSLTE_ERROR;
}
if (resource->start_symbol_idx > 13) {
if (resource->start_symbol_idx > SRSLTE_PUCCH_NR_FORMAT0_MAX_STARTSYMB) {
ERROR("Invalid initial start symbol idx (%d)\n", resource->start_symbol_idx);
return SRSLTE_ERROR;
}
@ -42,70 +40,156 @@ int srslte_pucch_nr_format0_resource_valid(const srslte_pucch_nr_resource_t* res
return SRSLTE_SUCCESS;
}
int srslte_pucch_nr_format1_resource_valid(const srslte_pucch_nr_resource_t* resource)
static int pucch_nr_cfg_format1_resource_valid(const srslte_pucch_nr_resource_t* resource)
{
if (resource == NULL) {
return SRSLTE_ERROR_INVALID_INPUTS;
}
if (resource->format != SRSLTE_PUCCH_NR_FORMAT_1) {
ERROR("Invalid format (%d)\n", resource->format);
return SRSLTE_ERROR;
}
if (resource->nof_symbols < 4 || resource->nof_symbols > 14) {
if (resource->nof_symbols < SRSLTE_PUCCH_NR_FORMAT1_MIN_NSYMB ||
resource->nof_symbols > SRSLTE_PUCCH_NR_FORMAT1_MAX_NSYMB) {
ERROR("Invalid number of symbols (%d)\n", resource->nof_symbols);
return SRSLTE_ERROR;
}
if (resource->initial_cyclic_shift > 11) {
if (resource->initial_cyclic_shift > SRSLTE_PUCCH_NR_FORMAT1_MAX_CS) {
ERROR("Invalid initial cyclic shift (%d)\n", resource->initial_cyclic_shift);
return SRSLTE_ERROR;
}
if (resource->start_symbol_idx > 10) {
if (resource->start_symbol_idx > SRSLTE_PUCCH_NR_FORMAT1_MAX_STARTSYMB) {
ERROR("Invalid initial start symbol idx (%d)\n", resource->start_symbol_idx);
return SRSLTE_ERROR;
}
if (resource->time_domain_occ > 6) {
if (resource->time_domain_occ > SRSLTE_PUCCH_NR_FORMAT1_MAX_TOCC) {
ERROR("Invalid time domain occ (%d)\n", resource->time_domain_occ);
return SRSLTE_ERROR;
}
return SRSLTE_SUCCESS;
}
static int pucch_nr_cfg_format2_resource_valid(const srslte_pucch_nr_resource_t* resource)
{
if (resource->format != SRSLTE_PUCCH_NR_FORMAT_2) {
ERROR("Invalid format (%d)\n", resource->format);
return SRSLTE_ERROR;
}
if (resource->nof_symbols < SRSLTE_PUCCH_NR_FORMAT2_MIN_NSYMB ||
resource->nof_symbols > SRSLTE_PUCCH_NR_FORMAT2_MAX_NSYMB) {
ERROR("Invalid number of symbols (%d)\n", resource->nof_symbols);
return SRSLTE_ERROR;
}
if (resource->nof_prb < SRSLTE_PUCCH_NR_FORMAT2_MIN_NPRB || resource->nof_prb > SRSLTE_PUCCH_NR_FORMAT2_MAX_NPRB) {
ERROR("Invalid number of prb (%d)\n", resource->nof_prb);
return SRSLTE_ERROR;
}
if (resource->start_symbol_idx > SRSLTE_PUCCH_NR_FORMAT2_MAX_STARTSYMB) {
ERROR("Invalid initial start symbol idx (%d)\n", resource->start_symbol_idx);
return SRSLTE_ERROR;
}
return SRSLTE_SUCCESS;
}
static int pucch_nr_cfg_format3_resource_valid(const srslte_pucch_nr_resource_t* resource)
{
if (resource->format != SRSLTE_PUCCH_NR_FORMAT_3) {
ERROR("Invalid format (%d)\n", resource->format);
return SRSLTE_ERROR;
}
if (resource->nof_symbols < SRSLTE_PUCCH_NR_FORMAT3_MIN_NSYMB ||
resource->nof_symbols > SRSLTE_PUCCH_NR_FORMAT3_MAX_NSYMB) {
ERROR("Invalid number of symbols (%d)\n", resource->nof_symbols);
return SRSLTE_ERROR;
}
if (resource->nof_prb < SRSLTE_PUCCH_NR_FORMAT3_MIN_NPRB || resource->nof_prb > SRSLTE_PUCCH_NR_FORMAT3_MAX_NPRB) {
ERROR("Invalid number of prb (%d)\n", resource->nof_prb);
return SRSLTE_ERROR;
}
if (resource->start_symbol_idx > SRSLTE_PUCCH_NR_FORMAT3_MAX_STARTSYMB) {
ERROR("Invalid initial start symbol idx (%d)\n", resource->start_symbol_idx);
return SRSLTE_ERROR;
}
return SRSLTE_SUCCESS;
}
static int pucch_nr_cfg_format4_resource_valid(const srslte_pucch_nr_resource_t* resource)
{
if (resource->format != SRSLTE_PUCCH_NR_FORMAT_4) {
ERROR("Invalid format (%d)\n", resource->format);
return SRSLTE_ERROR;
}
if (resource->nof_symbols < SRSLTE_PUCCH_NR_FORMAT4_MIN_NSYMB ||
resource->nof_symbols > SRSLTE_PUCCH_NR_FORMAT4_MAX_NSYMB) {
ERROR("Invalid number of symbols (%d)\n", resource->nof_symbols);
return SRSLTE_ERROR;
}
if (resource->start_symbol_idx > SRSLTE_PUCCH_NR_FORMAT4_MAX_STARTSYMB) {
ERROR("Invalid initial start symbol idx (%d)\n", resource->start_symbol_idx);
return SRSLTE_ERROR;
}
if (resource->occ_lenth != 2 && resource->occ_lenth != 4) {
ERROR("Invalid OCC length (%d)\n", resource->occ_lenth);
return SRSLTE_ERROR;
}
return SRSLTE_SUCCESS;
}
int srslte_pucch_nr_cfg_resource_valid(const srslte_pucch_nr_resource_t* resource)
{
// Check pointer
if (resource == NULL) {
return SRSLTE_ERROR_INVALID_INPUTS;
}
if (resource->starting_prb > SRSLTE_MAX_NRE_NR - 1) {
return SRSLTE_ERROR;
}
if (resource->intra_slot_hopping) {
ERROR("Intra-slot hopping is not implemented\n");
return SRSLTE_ERROR;
}
return SRSLTE_SUCCESS;
if (resource->second_hop_prb > SRSLTE_MAX_NRE_NR - 1) {
return SRSLTE_ERROR;
}
if (resource->max_code_rate > SRSLTE_PUCCH_NR_MAX_CODE_RATE) {
ERROR("Invalid maximum code rate (%d)\n", resource->max_code_rate);
return SRSLTE_ERROR;
}
switch (resource->format) {
case SRSLTE_PUCCH_NR_FORMAT_0:
return pucch_nr_cfg_format0_resource_valid(resource);
case SRSLTE_PUCCH_NR_FORMAT_1:
return pucch_nr_cfg_format1_resource_valid(resource);
case SRSLTE_PUCCH_NR_FORMAT_2:
return pucch_nr_cfg_format2_resource_valid(resource);
case SRSLTE_PUCCH_NR_FORMAT_3:
return pucch_nr_cfg_format3_resource_valid(resource);
case SRSLTE_PUCCH_NR_FORMAT_4:
return pucch_nr_cfg_format4_resource_valid(resource);
case SRSLTE_PUCCH_NR_FORMAT_ERROR:
default:
ERROR("Invalid case\n");
break;
}
return SRSLTE_ERROR;
}
int srslte_pucch_nr_format2_resource_valid(const srslte_pucch_nr_resource_t* resource)
{
if (resource == NULL) {
return SRSLTE_ERROR_INVALID_INPUTS;
}
if (resource->format != SRSLTE_PUCCH_NR_FORMAT_2) {
ERROR("Invalid format (%d)\n", resource->format);
return SRSLTE_ERROR;
}
if (resource->nof_symbols < 1 || resource->nof_symbols > 2) {
ERROR("Invalid number of symbols (%d)\n", resource->nof_symbols);
return SRSLTE_ERROR;
}
if (resource->nof_prb < 1 || resource->nof_prb > 16) {
ERROR("Invalid number of prb (%d)\n", resource->nof_prb);
return SRSLTE_ERROR;
}
if (resource->start_symbol_idx > 13) {
ERROR("Invalid initial start symbol idx (%d)\n", resource->start_symbol_idx);
return SRSLTE_ERROR;
}
return SRSLTE_SUCCESS;
}

View File

@ -158,6 +158,13 @@ int srslte_pucch_nr_init(srslte_pucch_nr_t* q, const srslte_pucch_nr_args_t* arg
return SRSLTE_ERROR;
}
// Allocate encoded symbols d
q->d = srslte_vec_cf_malloc(max_encoded_bits / 2);
if (q->d == NULL) {
ERROR("Malloc\n");
return SRSLTE_ERROR;
}
return SRSLTE_SUCCESS;
}
@ -167,6 +174,7 @@ void srslte_pucch_nr_free(srslte_pucch_nr_t* q)
return;
}
srslte_uci_nr_free(&q->uci);
srslte_zc_sequence_lut_free(&q->r_uv_1prb);
srslte_modem_table_free(&q->bpsk);
@ -175,6 +183,9 @@ void srslte_pucch_nr_free(srslte_pucch_nr_t* q)
if (q->b != NULL) {
free(q->b);
}
if (q->d != NULL) {
free(q->d);
}
SRSLTE_MEM_ZERO(q, srslte_pucch_nr_t, 1);
}
@ -191,7 +202,7 @@ int srslte_pucch_nr_format0_encode(const srslte_pucch_nr_t* q,
return SRSLTE_ERROR_INVALID_INPUTS;
}
if (srslte_pucch_nr_format0_resource_valid(resource) < SRSLTE_SUCCESS) {
if (srslte_pucch_nr_cfg_resource_valid(resource) < SRSLTE_SUCCESS) {
ERROR("Invalid PUCCH format 0 resource\n");
return SRSLTE_SUCCESS;
}
@ -242,7 +253,7 @@ int srslte_pucch_nr_format0_measure(const srslte_pucch_nr_t* q,
return SRSLTE_ERROR_INVALID_INPUTS;
}
if (srslte_pucch_nr_format0_resource_valid(resource) < SRSLTE_SUCCESS) {
if (srslte_pucch_nr_cfg_resource_valid(resource) < SRSLTE_SUCCESS) {
ERROR("Invalid PUCCH format 0 resource\n");
return SRSLTE_SUCCESS;
}
@ -353,7 +364,7 @@ int srslte_pucch_nr_format1_encode(const srslte_pucch_nr_t* q,
return SRSLTE_ERROR_INVALID_INPUTS;
}
if (srslte_pucch_nr_format1_resource_valid(resource) < SRSLTE_SUCCESS) {
if (srslte_pucch_nr_cfg_resource_valid(resource) < SRSLTE_SUCCESS) {
ERROR("Invalid PUCCH format 1 resource\n");
return SRSLTE_SUCCESS;
}
@ -431,7 +442,7 @@ int srslte_pucch_nr_format1_decode(srslte_pucch_nr_t* q,
{
uint32_t m_cs = 0;
if (srslte_pucch_nr_format1_resource_valid(resource) < SRSLTE_SUCCESS) {
if (srslte_pucch_nr_cfg_resource_valid(resource) < SRSLTE_SUCCESS) {
ERROR("Invalid PUCCH format 1 resource\n");
return SRSLTE_SUCCESS;
}
@ -501,21 +512,97 @@ int srslte_pucch_nr_format1_decode(srslte_pucch_nr_t* q,
return SRSLTE_SUCCESS;
}
static uint32_t pucch_nr_format2_cinit(const srslte_pucch_nr_common_cfg_t* pucch_cfg,
const srslte_uci_cfg_nr_t* uci_cfg)
{
uint32_t n_id = (pucch_cfg->scrambling_id_present) ? pucch_cfg->scrambling_id_present : uci_cfg->rnti;
return ((uint32_t)uci_cfg->rnti << 15U) + n_id;
}
// Implements TS 38.211 section 6.3.2.5 PUCCH format 2
static int pucch_nr_format2_encode(srslte_pucch_nr_t* q,
const srslte_carrier_nr_t* carrier,
const srslte_pucch_nr_common_cfg_t* cfg,
const srslte_dl_slot_cfg_t* slot,
const srslte_pucch_nr_resource_t* resource,
const srslte_uci_cfg_nr_t* uci_cfg,
cf_t* slot_symbols)
{
// Validate configuration
if (srslte_pucch_nr_format2_resource_valid(resource) < SRSLTE_SUCCESS) {
if (srslte_pucch_nr_cfg_resource_valid(resource) < SRSLTE_SUCCESS) {
return SRSLTE_ERROR;
}
// Implement encode here
// ...
// Calculate number of encoded symbols
uint32_t E = 16 * resource->nof_symbols * resource->nof_prb;
// 6.3.2.5.1 Scrambling
uint32_t cinit = pucch_nr_format2_cinit(cfg, uci_cfg);
srslte_sequence_apply_bit(q->b, q->b, E, cinit);
// 6.3.2.5.2 Modulation
srslte_mod_modulate(&q->qpsk, q->b, q->d, E);
// 6.3.2.5.3 Mapping to physical resources
uint32_t l_start = resource->start_symbol_idx;
uint32_t l_end = resource->start_symbol_idx + resource->nof_symbols;
uint32_t k_start = SRSLTE_MIN(carrier->nof_prb - 1, resource->starting_prb) * SRSLTE_NRE;
uint32_t k_end = SRSLTE_MIN(carrier->nof_prb, resource->starting_prb + resource->nof_prb) * SRSLTE_NRE;
for (uint32_t l = l_start, i = 0; l < l_end; l++) {
cf_t* symbol_ptr = &slot_symbols[l * carrier->nof_prb * SRSLTE_NRE];
for (uint32_t k = k_start; k < k_end; k += 3) {
symbol_ptr[k] = q->d[i++];
symbol_ptr[k + 2] = q->d[i++];
}
}
return SRSLTE_SUCCESS;
}
static int pucch_nr_format2_decode(srslte_pucch_nr_t* q,
const srslte_carrier_nr_t* carrier,
const srslte_pucch_nr_common_cfg_t* cfg,
const srslte_pucch_nr_resource_t* resource,
const srslte_uci_cfg_nr_t* uci_cfg,
srslte_chest_ul_res_t* chest_res,
cf_t* slot_symbols,
int8_t* llr)
{
// Validate configuration
if (srslte_pucch_nr_cfg_resource_valid(resource) < SRSLTE_SUCCESS) {
return SRSLTE_ERROR;
}
// Calculate number of encoded symbols
uint32_t E = 16 * resource->nof_symbols * resource->nof_prb;
// Undo mapping to physical resources
uint32_t l_start = resource->start_symbol_idx;
uint32_t l_end = resource->start_symbol_idx + resource->nof_symbols;
uint32_t k_start = resource->starting_prb * SRSLTE_NRE;
uint32_t k_end = (resource->starting_prb + resource->nof_prb) * SRSLTE_NRE;
for (uint32_t l = l_start, i = 0; l < l_end; l++) {
cf_t* symbol_ptr = &slot_symbols[l * carrier->nof_prb * SRSLTE_NRE];
for (uint32_t k = k_start; k < k_end; k += 3) {
q->d[i++] = symbol_ptr[k];
q->d[i++] = symbol_ptr[k + 2];
}
}
// Equalise
if (srslte_predecoding_single(q->d, chest_res->ce, q->d, NULL, E, 1.0f, chest_res->noise_estimate) < SRSLTE_SUCCESS) {
ERROR("Error Pre-decoding\n");
return SRSLTE_ERROR;
}
// Soft-demodulate
if (srslte_demod_soft_demodulate_b(SRSLTE_MOD_QPSK, q->d, llr, E) < SRSLTE_SUCCESS) {
ERROR("Error soft-demodulate\n");
return SRSLTE_ERROR;
}
// Undo Scrambling
uint32_t cinit = pucch_nr_format2_cinit(cfg, uci_cfg);
srslte_sequence_apply_c(llr, llr, E, cinit);
return SRSLTE_SUCCESS;
}
@ -544,7 +631,7 @@ int srslte_pucch_nr_format_2_3_4_encode(srslte_pucch_nr_t* q,
// Modulate PUCCH
switch (resource->format) {
case SRSLTE_PUCCH_NR_FORMAT_2:
return pucch_nr_format2_encode(q, carrier, cfg, slot, resource, uci_cfg, slot_symbols);
return pucch_nr_format2_encode(q, carrier, cfg, resource, uci_cfg, slot_symbols);
case SRSLTE_PUCCH_NR_FORMAT_3:
case SRSLTE_PUCCH_NR_FORMAT_4:
ERROR("Not implemented\n");
@ -557,26 +644,6 @@ int srslte_pucch_nr_format_2_3_4_encode(srslte_pucch_nr_t* q,
return SRSLTE_ERROR;
}
static int pucch_nr_format2_decode(srslte_pucch_nr_t* q,
const srslte_carrier_nr_t* carrier,
const srslte_pucch_nr_common_cfg_t* cfg,
const srslte_dl_slot_cfg_t* slot,
const srslte_pucch_nr_resource_t* resource,
srslte_chest_ul_res_t* chest_res,
cf_t* slot_symbols,
int8_t* llr)
{
// Validate configuration
if (srslte_pucch_nr_format2_resource_valid(resource) < SRSLTE_SUCCESS) {
return SRSLTE_ERROR;
}
// Implement decode here
// ...
return SRSLTE_SUCCESS;
}
int srslte_pucch_nr_format_2_3_4_decode(srslte_pucch_nr_t* q,
const srslte_carrier_nr_t* carrier,
const srslte_pucch_nr_common_cfg_t* cfg,
@ -597,7 +664,11 @@ int srslte_pucch_nr_format_2_3_4_decode(srslte_pucch_nr_t* q,
int8_t* llr = (int8_t*)q->b;
switch (resource->format) {
case SRSLTE_PUCCH_NR_FORMAT_2:
return pucch_nr_format2_decode(q, carrier, cfg, slot, resource, chest_res, slot_symbols, llr);
if (pucch_nr_format2_decode(q, carrier, cfg, resource, uci_cfg, chest_res, slot_symbols, llr) < SRSLTE_SUCCESS) {
ERROR("Demodulating PUCCH format 2\n");
return SRSLTE_ERROR;
}
break;
case SRSLTE_PUCCH_NR_FORMAT_3:
case SRSLTE_PUCCH_NR_FORMAT_4:
ERROR("Not implemented\n");

158
lib/src/phy/phch/ra_ul_nr.c Normal file
View File

@ -0,0 +1,158 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2020 Software Radio Systems Limited
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the distribution.
*
*/
#include "srslte/phy/phch/ra_ul_nr.h"
#include "srslte/phy/ch_estimation/dmrs_pucch.h"
#include "srslte/phy/common/phy_common.h"
#include "srslte/phy/utils/debug.h"
#define RA_UL_PUCCH_CODE_RATE_N 8
#define RA_UL_PUCCH_CODE_RATE_RESERVED NAN
static const double ra_ul_pucch_code_rate_table[RA_UL_PUCCH_CODE_RATE_N] =
{0.08, 0.15, 0.25, 0.35, 0.45, 0.60, 0.80, RA_UL_PUCCH_CODE_RATE_RESERVED};
// Implements TS 38.213 Table 9.2.5.2-1: Code rate r corresponding to value of maxCodeRate
static double ra_ul_nr_pucch_code_rate_r(const srslte_pucch_nr_resource_t* resource)
{
if (resource->max_code_rate >= RA_UL_PUCCH_CODE_RATE_RESERVED) {
ERROR("Invalid code rate\n");
return RA_UL_PUCCH_CODE_RATE_RESERVED;
}
return ra_ul_pucch_code_rate_table[resource->max_code_rate];
}
// Calculate number of PRBs for PUCCH format 2, or PUCCH format 3, or PUCCH format 4, respectively
// static int ra_ul_nr_pucch_Mrb(const srslte_pucch_nr_resource_t* resource)
//{
// switch (resource->format) {
// case SRSLTE_PUCCH_NR_FORMAT_2:
// case SRSLTE_PUCCH_NR_FORMAT_3:
// return resource->nof_prb;
// case SRSLTE_PUCCH_NR_FORMAT_4:
// return SRSLTE_PUCCH_NR_FORMAT4_NPRB;
// default:
// ERROR("Invalid case\n");
// break;
// }
// return SRSLTE_ERROR;
//}
// Calculate number of subcarriers per resource block for payload (No DMRS)
static int ra_ul_nr_pucch_nre(const srslte_pucch_nr_resource_t* resource)
{
switch (resource->format) {
case SRSLTE_PUCCH_NR_FORMAT_2:
return SRSLTE_NRE - 4;
case SRSLTE_PUCCH_NR_FORMAT_3:
return SRSLTE_NRE;
case SRSLTE_PUCCH_NR_FORMAT_4:
return SRSLTE_NRE / resource->occ_lenth;
default:
ERROR("Invalid case\n");
break;
}
return SRSLTE_ERROR;
}
// Calculate number of PUCCH symbols excluding the ones used exclusively for DMRS for formats 3 and 4
static int ra_ul_nr_pucch_nsymb(const srslte_pucch_nr_resource_t* resource)
{
switch (resource->format) {
case SRSLTE_PUCCH_NR_FORMAT_2:
return resource->nof_symbols;
case SRSLTE_PUCCH_NR_FORMAT_3:
case SRSLTE_PUCCH_NR_FORMAT_4: {
uint32_t idx[SRSLTE_DMRS_PUCCH_FORMAT_3_4_MAX_NSYMB] = {};
// Get number of DMRS symbols for format 3 or 4
int nsymb_dmrs = srslte_dmrs_pucch_format_3_4_get_symbol_idx(resource, idx);
if (nsymb_dmrs < SRSLTE_SUCCESS) {
return SRSLTE_ERROR;
}
return (int)resource->nof_symbols - nsymb_dmrs;
}
default:
ERROR("Invalid case\n");
break;
}
return SRSLTE_ERROR;
}
// Calculate number of PUCCH symbols excluding the ones used exclusively for DMRS for formats 3 and 4
static int ra_ul_nr_pucch_qm(const srslte_pucch_nr_resource_t* resource)
{
switch (resource->format) {
case SRSLTE_PUCCH_NR_FORMAT_2:
return 2;
case SRSLTE_PUCCH_NR_FORMAT_3:
case SRSLTE_PUCCH_NR_FORMAT_4:
return resource->enable_pi_bpsk ? 1 : 2;
default:
ERROR("Invalid case\n");
break;
}
return SRSLTE_ERROR;
}
int srslte_ra_ul_nr_pucch_format_2_3_min_prb(const srslte_pucch_nr_resource_t* resource,
const srslte_uci_cfg_nr_t* uci_cfg)
{
if (resource == NULL || uci_cfg == NULL) {
return SRSLTE_ERROR_INVALID_INPUTS;
}
// Get maximum allowed code rate
double r = ra_ul_nr_pucch_code_rate_r(resource);
if (!isnormal(r)) {
ERROR("Invalid coderate %f\n", r);
return SRSLTE_ERROR;
}
// Get number of RE/PRB
int nre = ra_ul_nr_pucch_nre(resource);
if (nre < SRSLTE_SUCCESS) {
ERROR("Getting nre\n");
return SRSLTE_ERROR;
}
// Get number of symbols
int nsymb = ra_ul_nr_pucch_nsymb(resource);
if (nsymb < SRSLTE_SUCCESS) {
ERROR("Getting nsymb\n");
return SRSLTE_ERROR;
}
// Get modulation order
int qm = ra_ul_nr_pucch_qm(resource);
if (qm < SRSLTE_SUCCESS) {
ERROR("Getting qm\n");
return SRSLTE_ERROR;
}
// Calculate denominator
double nof_bits_rb = r * nre * nsymb * qm;
if (!isnormal(nof_bits_rb)) {
return SRSLTE_ERROR;
}
// Compute total number of UCI bits
uint32_t O_total = uci_cfg->o_ack + uci_cfg->o_sr + uci_cfg->o_csi1 + uci_cfg->o_csi2;
// Add CRC bits if any
O_total += srslte_uci_nr_crc_len(O_total);
// Return the minimum
return (int)ceil(O_total / nof_bits_rb);
}

View File

@ -13,7 +13,9 @@
#include "srslte/common/test_common.h"
#include "srslte/phy/ch_estimation/dmrs_pucch.h"
#include "srslte/phy/phch/pucch_nr.h"
#include "srslte/phy/phch/ra_ul_nr.h"
#include "srslte/phy/utils/debug.h"
#include "srslte/phy/utils/random.h"
#include "srslte/phy/utils/vector.h"
#include <stdio.h>
#include <stdlib.h>
@ -30,13 +32,16 @@ static srslte_carrier_nr_t carrier = {
1 // max_mimo_layers
};
static uint32_t starting_prb_stride = 4;
static uint32_t starting_symbol_stride = 4;
static uint32_t starting_prb_stride = 4;
static uint32_t starting_symbol_stride = 4;
static srslte_random_t random_gen = NULL;
static int format = -1;
static int test_pucch_format0(srslte_pucch_nr_t* pucch, const srslte_pucch_nr_common_cfg_t* cfg, cf_t* slot_symbols)
{
srslte_dl_slot_cfg_t slot = {};
srslte_pucch_nr_resource_t resource = {};
srslte_dl_slot_cfg_t slot = {};
srslte_pucch_nr_resource_t resource = {};
resource.format = SRSLTE_PUCCH_NR_FORMAT_0;
for (slot.idx = 0; slot.idx < SRSLTE_NSLOTS_PER_FRAME_NR(carrier.numerology); slot.idx++) {
for (resource.starting_prb = 0; resource.starting_prb < carrier.nof_prb;
@ -83,18 +88,23 @@ static int test_pucch_format1(srslte_pucch_nr_t* pucch,
srslte_chest_ul_res_t* chest_res,
cf_t* slot_symbols)
{
srslte_dl_slot_cfg_t slot = {};
srslte_pucch_nr_resource_t resource = {};
srslte_dl_slot_cfg_t slot = {};
srslte_pucch_nr_resource_t resource = {};
resource.format = SRSLTE_PUCCH_NR_FORMAT_1;
for (slot.idx = 0; slot.idx < SRSLTE_NSLOTS_PER_FRAME_NR(carrier.numerology); slot.idx++) {
for (resource.starting_prb = 0; resource.starting_prb < carrier.nof_prb;
resource.starting_prb += starting_prb_stride) {
for (resource.nof_symbols = 4; resource.nof_symbols <= 14; resource.nof_symbols++) {
for (resource.nof_symbols = SRSLTE_PUCCH_NR_FORMAT1_MIN_NSYMB;
resource.nof_symbols <= SRSLTE_PUCCH_NR_FORMAT1_MAX_NSYMB;
resource.nof_symbols++) {
for (resource.start_symbol_idx = 0;
resource.start_symbol_idx <= SRSLTE_NSYMB_PER_SLOT_NR - resource.nof_symbols;
resource.start_symbol_idx <=
SRSLTE_MIN(SRSLTE_PUCCH_NR_FORMAT1_MAX_STARTSYMB, SRSLTE_NSYMB_PER_SLOT_NR - resource.nof_symbols);
resource.start_symbol_idx += starting_symbol_stride) {
for (resource.time_domain_occ = 0; resource.time_domain_occ <= 6; resource.time_domain_occ++) {
for (resource.initial_cyclic_shift = 0; resource.initial_cyclic_shift <= 11;
for (resource.time_domain_occ = 0; resource.time_domain_occ <= SRSLTE_PUCCH_NR_FORMAT1_MAX_TOCC;
resource.time_domain_occ++) {
for (resource.initial_cyclic_shift = 0; resource.initial_cyclic_shift <= SRSLTE_PUCCH_NR_FORMAT1_MAX_CS;
resource.initial_cyclic_shift++) {
for (uint32_t nof_bits = 1; nof_bits <= SRSLTE_PUCCH_NR_FORMAT1_MAX_NOF_BITS; nof_bits++) {
for (uint32_t word = 0; word < (1U << nof_bits); word++) {
@ -138,18 +148,103 @@ static int test_pucch_format1(srslte_pucch_nr_t* pucch,
return SRSLTE_SUCCESS;
}
static int test_pucch_format2(srslte_pucch_nr_t* pucch,
const srslte_pucch_nr_common_cfg_t* cfg,
srslte_chest_ul_res_t* chest_res,
cf_t* slot_symbols)
{
srslte_dl_slot_cfg_t slot = {};
srslte_pucch_nr_resource_t resource = {};
resource.format = SRSLTE_PUCCH_NR_FORMAT_2;
for (slot.idx = 0; slot.idx < SRSLTE_NSLOTS_PER_FRAME_NR(carrier.numerology); slot.idx++) {
for (resource.nof_symbols = SRSLTE_PUCCH_NR_FORMAT2_MIN_NSYMB;
resource.nof_symbols <= SRSLTE_PUCCH_NR_FORMAT2_MAX_NSYMB;
resource.nof_symbols++) {
for (resource.start_symbol_idx = 0;
resource.start_symbol_idx <=
SRSLTE_MIN(SRSLTE_PUCCH_NR_FORMAT2_MAX_STARTSYMB, SRSLTE_NSYMB_PER_SLOT_NR - resource.nof_symbols);
resource.start_symbol_idx += starting_symbol_stride) {
// Maximum code rate is reserved
for (resource.max_code_rate = 0; resource.max_code_rate < SRSLTE_PUCCH_NR_MAX_CODE_RATE;
resource.max_code_rate++) {
srslte_uci_cfg_nr_t uci_cfg = {};
for (uci_cfg.o_ack = 12; uci_cfg.o_ack <= SRSLTE_UCI_NR_MAX_ACK_BITS; uci_cfg.o_ack++) {
srslte_uci_value_nr_t uci_value = {};
// Skip case if not enough PRB are used
int min_nof_prb = srslte_ra_ul_nr_pucch_format_2_3_min_prb(&resource, &uci_cfg);
TESTASSERT(min_nof_prb > SRSLTE_SUCCESS);
for (resource.nof_prb = min_nof_prb;
resource.nof_prb < SRSLTE_MIN(carrier.nof_prb, SRSLTE_PUCCH_NR_FORMAT2_MAX_NPRB);
resource.nof_prb++) {
for (resource.starting_prb = 0; resource.starting_prb < (carrier.nof_prb - resource.nof_prb);
resource.starting_prb += starting_prb_stride) {
// Generate ACKs
for (uint32_t i = 0; i < uci_cfg.o_ack; i++) {
uci_value.ack[i] = (uint8_t)srslte_random_uniform_int_dist(random_gen, 0, 1);
}
// Encode PUCCH
TESTASSERT(srslte_pucch_nr_format_2_3_4_encode(
pucch, &carrier, cfg, &slot, &resource, &uci_cfg, &uci_value, slot_symbols) ==
SRSLTE_SUCCESS);
// Put DMRS
// TESTASSERT(srslte_dmrs_pucch_format1_put(pucch, &carrier, cfg, &slot, &resource,
// slot_symbols) ==
// SRSLTE_SUCCESS);
// Estimate channel
// TESTASSERT(srslte_dmrs_pucch_format1_estimate(
// pucch, &carrier, cfg, &slot, &resource, slot_symbols, chest_res) ==
// SRSLTE_SUCCESS);
srslte_chest_ul_res_set_identity(chest_res);
// Decode PUCCH
srslte_uci_value_nr_t uci_value_rx = {};
TESTASSERT(
srslte_pucch_nr_format_2_3_4_decode(
pucch, &carrier, cfg, &slot, &resource, &uci_cfg, chest_res, slot_symbols, &uci_value_rx) ==
SRSLTE_SUCCESS);
TESTASSERT(uci_value_rx.valid == true);
// Check received ACKs
for (uint32_t i = 0; i < uci_cfg.o_ack; i++) {
TESTASSERT(uci_value.ack[i] == uci_value_rx.ack[i]);
}
}
}
}
}
}
}
}
return SRSLTE_SUCCESS;
}
static void usage(char* prog)
{
printf("Usage: %s [csNnv]\n", prog);
printf("\t-c cell id [Default %d]\n", carrier.id);
printf("\t-n nof_prb [Default %d]\n", carrier.nof_prb);
printf("\t-f format [Default %d]\n", format);
printf("\t-v [set verbose to debug, default none]\n");
}
static void parse_args(int argc, char** argv)
{
int opt;
while ((opt = getopt(argc, argv, "cnv")) != -1) {
while ((opt = getopt(argc, argv, "cnfv")) != -1) {
switch (opt) {
case 'c':
carrier.id = (uint32_t)strtol(argv[optind], NULL, 10);
@ -157,6 +252,9 @@ static void parse_args(int argc, char** argv)
case 'n':
carrier.nof_prb = (uint32_t)strtol(argv[optind], NULL, 10);
break;
case 'f':
format = (int)strtol(argv[optind], NULL, 10);
break;
case 'v':
srslte_verbose++;
break;
@ -177,6 +275,12 @@ int main(int argc, char** argv)
srslte_pucch_nr_t pucch = {};
srslte_chest_ul_res_t chest_res = {};
random_gen = srslte_random_init(0x1234);
if (random_gen == NULL) {
ERROR("Random init\n");
goto clean_exit;
}
if (slot_symb == NULL) {
ERROR("Alloc\n");
goto clean_exit;
@ -196,15 +300,27 @@ int main(int argc, char** argv)
srslte_pucch_nr_common_cfg_t common_cfg = {};
// Test Format 0
if (test_pucch_format0(&pucch, &common_cfg, slot_symb) < SRSLTE_SUCCESS) {
ERROR("Failed PUCCH format 0\n");
goto clean_exit;
if (format < 0 || format == 0) {
if (test_pucch_format0(&pucch, &common_cfg, slot_symb) < SRSLTE_SUCCESS) {
ERROR("Failed PUCCH format 0\n");
goto clean_exit;
}
}
// Test Format 1
if (test_pucch_format1(&pucch, &common_cfg, &chest_res, slot_symb) < SRSLTE_SUCCESS) {
ERROR("Failed PUCCH format 1\n");
goto clean_exit;
if (format < 0 || format == 1) {
if (test_pucch_format1(&pucch, &common_cfg, &chest_res, slot_symb) < SRSLTE_SUCCESS) {
ERROR("Failed PUCCH format 1\n");
goto clean_exit;
}
}
// Test Format 2
if (format < 0 || format == 2) {
if (test_pucch_format2(&pucch, &common_cfg, &chest_res, slot_symb) < SRSLTE_SUCCESS) {
ERROR("Failed PUCCH format 2\n");
goto clean_exit;
}
}
ret = SRSLTE_SUCCESS;
@ -216,6 +332,8 @@ clean_exit:
srslte_pucch_nr_free(&pucch);
srslte_chest_ul_res_free(&chest_res);
srslte_random_free(random_gen);
if (ret == SRSLTE_SUCCESS) {
printf("Test passed!\n");
} else {

View File

@ -17,13 +17,22 @@
#include "srslte/phy/utils/bit.h"
#include "srslte/phy/utils/vector.h"
#define UCI_NR_INFO_TX(...) INFO("UCI-NR Tx: " __VA_ARGS__)
#define UCI_NR_INFO_RX(...) INFO("UCI-NR Rx: " __VA_ARGS__)
// TS 38.212 section 5.2.1 Polar coding: The value of A is no larger than 1706.
#define UCI_NR_MAX_A 1706U
#define UCI_NR_MAX_L 11U
#define UCI_NR_POLAR_MAX 2048U
#define UCI_NR_POLAR_RM_IBIL 0
#define UCI_NR_PUCCH_POLAR_N_MAX 10
#define UCI_NR_BLOCK_CORR_THRESHOLD 0.5f
uint32_t srslte_uci_nr_crc_len(uint32_t A)
{
return (A <= 11) ? 0 : (A < 20) ? 6 : 11;
}
int srslte_uci_nr_init(srslte_uci_nr_t* q, const srslte_uci_nr_args_t* args)
{
if (q == NULL || args == NULL) {
@ -39,6 +48,11 @@ int srslte_uci_nr_init(srslte_uci_nr_t* q, const srslte_uci_nr_args_t* args)
}
#endif // LV_HAVE_AVX2
if (srslte_polar_code_init(&q->code)) {
ERROR("Initialising polar code\n");
return SRSLTE_ERROR;
}
if (srslte_polar_encoder_init(&q->encoder, polar_encoder_type, NMAX_LOG) < SRSLTE_SUCCESS) {
ERROR("Initialising polar encoder\n");
return SRSLTE_ERROR;
@ -49,7 +63,12 @@ int srslte_uci_nr_init(srslte_uci_nr_t* q, const srslte_uci_nr_args_t* args)
return SRSLTE_ERROR;
}
if (srslte_polar_rm_tx_init(&q->rm) < SRSLTE_SUCCESS) {
if (srslte_polar_rm_tx_init(&q->rm_tx) < SRSLTE_SUCCESS) {
ERROR("Initialising polar RM\n");
return SRSLTE_ERROR;
}
if (srslte_polar_rm_rx_init_c(&q->rm_rx) < SRSLTE_SUCCESS) {
ERROR("Initialising polar RM\n");
return SRSLTE_ERROR;
}
@ -99,8 +118,11 @@ void srslte_uci_nr_free(srslte_uci_nr_t* q)
return;
}
srslte_polar_code_free(&q->code);
srslte_polar_encoder_free(&q->encoder);
srslte_polar_decoder_free(&q->decoder);
srslte_polar_rm_tx_free(&q->rm_tx);
srslte_polar_rm_rx_free_c(&q->rm_rx);
if (q->bit_sequence != NULL) {
free(q->bit_sequence);
@ -130,6 +152,11 @@ static int uci_nr_pack_ack_sr(const srslte_uci_cfg_nr_t* cfg, const srslte_uci_v
srslte_vec_u8_copy(&sequence[A], value->sr, cfg->o_sr);
A += cfg->o_sr;
if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) {
UCI_NR_INFO_TX("Packed UCI bits: ");
srslte_vec_fprint_byte(stdout, sequence, A);
}
return A;
}
@ -145,6 +172,11 @@ static int uci_nr_unpack_ack_sr(const srslte_uci_cfg_nr_t* cfg, const uint8_t* s
srslte_vec_u8_copy(value->sr, &sequence[A], cfg->o_sr);
A += cfg->o_sr;
if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) {
UCI_NR_INFO_RX("Unpacked UCI bits: ");
srslte_vec_fprint_byte(stdout, sequence, A);
}
return A;
}
@ -356,11 +388,11 @@ static int uci_nr_encode_2bit(srslte_uci_nr_t* q, const srslte_uci_cfg_nr_t* cfg
static int
uci_nr_encode_3_11_bit(srslte_uci_nr_t* q, const srslte_uci_cfg_nr_t* cfg, uint32_t A, uint8_t* o, uint32_t E)
{
uint8_t encoded[SRSLTE_FEC_BLOCK_SIZE] = {};
srslte_block_encode(q->bit_sequence, A, encoded, SRSLTE_FEC_BLOCK_SIZE);
srslte_block_encode(q->bit_sequence, A, o, E);
for (uint32_t i = 0; i < E; i++) {
o[i] = (encoded[i % SRSLTE_FEC_BLOCK_SIZE] == 0) ? UCI_BIT_0 : UCI_BIT_1;
if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) {
UCI_NR_INFO_TX("Block encoded UCI bits; o=");
srslte_vec_fprint_b(stdout, o, E);
}
return E;
@ -384,6 +416,11 @@ static int uci_nr_decode_3_11_bit(srslte_uci_nr_t* q,
return SRSLTE_ERROR;
}
if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) {
UCI_NR_INFO_RX("Block decoding NR-UCI llr=");
srslte_vec_fprint_bs(stdout, llr, E);
}
// Decode
float corr = (float)srslte_block_decode_i8(llr, E, q->bit_sequence, A);
@ -408,10 +445,8 @@ uci_nr_encode_11_1706_bit(srslte_uci_nr_t* q, const srslte_uci_cfg_nr_t* cfg, ui
}
// Select CRC
srslte_crc_t* crc = &q->crc6;
if (A >= 20) {
crc = &q->crc11;
}
uint32_t L = srslte_uci_nr_crc_len(A);
srslte_crc_t* crc = (L == 6) ? &q->crc6 : &q->crc11;
// Segmentation
uint32_t C = 1;
@ -421,9 +456,9 @@ uci_nr_encode_11_1706_bit(srslte_uci_nr_t* q, const srslte_uci_cfg_nr_t* cfg, ui
uint32_t A_prime = CEIL(A, C) * C;
// Get polar code
uint32_t K_r = A_prime / C + crc->order;
uint32_t K_r = A_prime / C + L;
uint32_t E_r = E_uci / C;
if (srslte_polar_code_get(&q->code, K_r, E_r, 9U) < SRSLTE_SUCCESS) {
if (srslte_polar_code_get(&q->code, K_r, E_r, UCI_NR_PUCCH_POLAR_N_MAX) < SRSLTE_SUCCESS) {
return SRSLTE_ERROR;
}
@ -445,17 +480,33 @@ uci_nr_encode_11_1706_bit(srslte_uci_nr_t* q, const srslte_uci_cfg_nr_t* cfg, ui
// Attach CRC
srslte_crc_attach(crc, q->c, A_prime / C);
UCI_NR_INFO_TX("Attaching %d/%d CRC%d=%02lx\n", r, C, L, srslte_crc_checksum_get(crc));
if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) {
UCI_NR_INFO_TX("Polar cb %d/%d c=", r, C);
srslte_vec_fprint_byte(stdout, q->c, K_r);
}
// Allocate channel
srslte_polar_chanalloc_tx(q->c, q->allocated, q->code.N, q->code.K, q->code.nPC, q->code.K_set, q->code.PC_set);
if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) {
UCI_NR_INFO_TX("Polar alloc %d/%d ", r, C);
srslte_vec_fprint_byte(stdout, q->allocated, q->code.N);
}
// Encode bits
if (srslte_polar_encoder_encode(&q->encoder, q->allocated, q->d, q->code.n) < SRSLTE_SUCCESS) {
return SRSLTE_ERROR;
}
// Rate matching
srslte_polar_rm_tx(&q->rm, q->d, &o[E_r * r], q->code.n, E_r, K_r, UCI_NR_POLAR_RM_IBIL);
srslte_polar_rm_tx(&q->rm_tx, q->d, &o[E_r * r], q->code.n, E_r, K_r, UCI_NR_POLAR_RM_IBIL);
if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) {
UCI_NR_INFO_TX("Polar cw %d/%d ", r, C);
srslte_vec_fprint_byte(stdout, &o[E_r * r], q->code.N);
}
}
return E_uci;
@ -464,7 +515,7 @@ uci_nr_encode_11_1706_bit(srslte_uci_nr_t* q, const srslte_uci_cfg_nr_t* cfg, ui
static int uci_nr_decode_11_1706_bit(srslte_uci_nr_t* q,
const srslte_uci_cfg_nr_t* cfg,
uint32_t A,
const int8_t* llr,
int8_t* llr,
uint32_t E_uci,
bool* decoded_ok)
{
@ -477,10 +528,8 @@ static int uci_nr_decode_11_1706_bit(srslte_uci_nr_t* q,
}
// Select CRC
srslte_crc_t* crc = &q->crc6;
if (A >= 20) {
crc = &q->crc11;
}
uint32_t L = srslte_uci_nr_crc_len(A);
srslte_crc_t* crc = (L == 6) ? &q->crc6 : &q->crc11;
// Segmentation
uint32_t C = 1;
@ -490,19 +539,29 @@ static int uci_nr_decode_11_1706_bit(srslte_uci_nr_t* q,
uint32_t A_prime = CEIL(A, C) * C;
// Get polar code
uint32_t K_r = A_prime / C + crc->order;
uint32_t K_r = A_prime / C + L;
uint32_t E_r = E_uci / C;
if (srslte_polar_code_get(&q->code, K_r, E_r, 9U) < SRSLTE_SUCCESS) {
if (srslte_polar_code_get(&q->code, K_r, E_r, UCI_NR_PUCCH_POLAR_N_MAX) < SRSLTE_SUCCESS) {
return SRSLTE_ERROR;
}
// Negate all LLR
for (uint32_t i = 0; i < E_r; i++) {
llr[i] *= -1;
}
// Write codeword
for (uint32_t r = 0, s = 0; r < C; r++) {
uint32_t k = 0;
if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) {
UCI_NR_INFO_RX("Polar LLR %d/%d ", r, C);
srslte_vec_fprint_bs(stdout, &llr[E_r * r], q->code.N);
}
// Undo rate matching
int8_t* d = (int8_t*)q->d;
srslte_polar_rm_rx_c(&q->rm, &llr[E_r * r], d, q->code.n, E_r, K_r, UCI_NR_POLAR_RM_IBIL);
srslte_polar_rm_rx_c(&q->rm_rx, &llr[E_r * r], d, E_r, q->code.n, K_r, UCI_NR_POLAR_RM_IBIL);
// Decode bits
if (srslte_polar_decoder_decode_c(&q->decoder, d, q->allocated, q->code.n, q->code.F_set, q->code.F_set_size) <
@ -510,14 +569,25 @@ static int uci_nr_decode_11_1706_bit(srslte_uci_nr_t* q,
return SRSLTE_ERROR;
}
if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) {
UCI_NR_INFO_RX("Polar alloc %d/%d ", r, C);
srslte_vec_fprint_byte(stdout, q->allocated, q->code.N);
}
// Undo channel allocation
srslte_polar_chanalloc_rx(q->allocated, q->c, q->code.K, q->code.nPC, q->code.K_set, q->code.PC_set);
//
uint8_t* ptr = &q->c[q->code.K - crc->order];
uint32_t checksum1 = srslte_crc_checksum(crc, q->c, q->code.K);
uint32_t checksum2 = srslte_bit_pack(&ptr, crc->order);
if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) {
UCI_NR_INFO_RX("Polar cb %d/%d c=", r, C);
srslte_vec_fprint_byte(stdout, q->c, K_r);
}
// Calculate checksum
uint8_t* ptr = &q->c[A_prime / C];
uint32_t checksum1 = srslte_crc_checksum(crc, q->c, A_prime / C);
uint32_t checksum2 = srslte_bit_pack(&ptr, L);
(*decoded_ok) = ((*decoded_ok) && (checksum1 == checksum2));
UCI_NR_INFO_RX("Checking %d/%d CRC%d={%02x,%02x}\n", r, C, L, checksum1, checksum2);
// Prefix (A_prime - A) zeros for the first CB only
if (r == 0) {
@ -577,7 +647,7 @@ static int uci_nr_encode(srslte_uci_nr_t* q,
static int uci_nr_decode(srslte_uci_nr_t* q,
const srslte_uci_cfg_nr_t* uci_cfg,
const int8_t* llr,
int8_t* llr,
uint32_t E_uci,
srslte_uci_value_nr_t* uci_value)
{
@ -624,20 +694,9 @@ static int uci_nr_pucch_E_tot(const srslte_pucch_nr_resource_t* pucch_cfg, const
return SRSLTE_ERROR_INVALID_INPUTS;
}
// Compute total number of bits
uint32_t nof_bits = uci_cfg->o_sr + uci_cfg->o_ack + uci_cfg->o_csi1 + uci_cfg->o_csi2;
switch (pucch_cfg->format) {
case SRSLTE_PUCCH_NR_FORMAT_1:
if (nof_bits <= 2) {
return nof_bits;
}
break;
case SRSLTE_PUCCH_NR_FORMAT_2:
if (uci_cfg->modulation == SRSLTE_MOD_QPSK) {
return (int)(16 * pucch_cfg->nof_symbols * pucch_cfg->nof_prb);
}
break;
return (int)(16 * pucch_cfg->nof_symbols * pucch_cfg->nof_prb);
case SRSLTE_PUCCH_NR_FORMAT_3:
if (uci_cfg->modulation == SRSLTE_MOD_QPSK) {
return (int)(24 * pucch_cfg->nof_symbols * pucch_cfg->nof_prb);
@ -684,11 +743,13 @@ int srslte_uci_nr_encode_pucch(srslte_uci_nr_t* q,
{
int E_tot = uci_nr_pucch_E_tot(pucch_resource_cfg, uci_cfg);
if (E_tot < SRSLTE_SUCCESS) {
ERROR("Error calculating number of bits\n");
return SRSLTE_ERROR;
}
int E_uci = uci_nr_pucch_E_uci(pucch_resource_cfg, uci_cfg, E_tot);
if (E_uci < SRSLTE_SUCCESS) {
ERROR("Error calculating number of bits\n");
return SRSLTE_ERROR;
}
@ -698,7 +759,7 @@ int srslte_uci_nr_encode_pucch(srslte_uci_nr_t* q,
int srslte_uci_nr_decode_pucch(srslte_uci_nr_t* q,
const srslte_pucch_nr_resource_t* pucch_resource_cfg,
const srslte_uci_cfg_nr_t* uci_cfg,
const int8_t* llr,
int8_t* llr,
srslte_uci_value_nr_t* value)
{
int E_tot = uci_nr_pucch_E_tot(pucch_resource_cfg, uci_cfg);