Initial NR-PUCCH formats 0 and 1 encoder

master
Xavier Arteaga 4 years ago committed by Xavier Arteaga
parent e7562e5b3f
commit 33bb387f52

@ -37,7 +37,7 @@ extern "C" {
/**
* @brief Defines the maximum numerology supported. Defined by TS 38.211 v15.8.0 Table 4.3.2-1.
*/
#define SRSLTE_NR_MAX_NUMEROLOGY 4
#define SRSLTE_NR_MAX_NUMEROLOGY 4U
/**
* @brief Defines the symbol duration, including cyclic prefix

@ -14,9 +14,17 @@
#define SRSLTE_PUCCH_NR_H
#include "srslte/config.h"
#include "srslte/phy/common/phy_common_nr.h"
#include "srslte/phy/common/zc_sequence.h"
#include "srslte/phy/modem/modem_table.h"
#include <stdbool.h>
#include <stdint.h>
/**
* @brief Maximum number of NR-PUCCH format 1 symbols (without DMRS)
*/
#define SRSLTE_PUCCH_NR_FORMAT1_N_MAX 7
typedef enum SRSLTE_API {
SRSLTE_PUCCH_NR_FORMAT_0 = 0,
SRSLTE_PUCCH_NR_FORMAT_1,
@ -26,24 +34,143 @@ typedef enum SRSLTE_API {
SRSLTE_PUCCH_NR_FORMAT_ERROR,
} srslte_pucch_nr_format_t;
typedef enum SRSLTE_API {
SRSLTE_PUCCH_NR_GROUP_HOPPING_NEITHER = 0,
SRSLTE_PUCCH_NR_GROUP_HOPPING_ENABLE,
SRSLTE_PUCCH_NR_GROUP_HOPPING_DISABLE
} srslte_pucch_nr_group_hopping_t;
/**
* @brief PUCCH Common configuration
* @remark Defined in TS 38.331 PUCCH-ConfigCommon
*/
typedef struct SRSLTE_API {
uint32_t resource_common; ///< Configures a set of cell-specific PUCCH resources/parameters
srslte_pucch_nr_group_hopping_t group_hopping; ///< Configuration of group and sequence hopping
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)
} srslte_pucch_nr_common_cfg_t;
/**
* @brief Generic PUCCH Resource configuration
* @remark Defined in TS 38.331 PUCCH-Config
*/
typedef struct SRSLTE_API {
// Common
//
uint32_t starting_prb;
bool intra_slot_frequency_hopping;
uint32_t second_hop_prb;
// Common PUCCH-Resource parameters among all formats
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
// Other parameters
// 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_index; ///< Used by format 4
} srslte_pucch_nr_resource_t;
typedef struct SRSLTE_API {
float rsrp;
float rsrp_dBfs;
float epre;
float epre_dBfs;
float norm_corr;
} srslte_pucch_nr_measure_t;
} srslte_pucch_nr_cfg_t;
/**
* @brief PUCCH Resource configuration for Format 0
* @remark Defined in TS 38.331 PUCCH-Config
*/
typedef struct SRSLTE_API {
uint32_t starting_prb;
uint32_t initial_cyclic_shift; ///< initialCyclicShift (0..11)
uint32_t start_symbol_idx; ///< startingSymbolIndex (0..13)
uint32_t nof_symbols; ///< nrofSymbols (1..2)
} srslte_pucch_nr_resource_format0_t;
/**
* @brief PUCCH Resource configuration for Format 1
* @remark Defined in TS 38.331 PUCCH-Config
*/
typedef struct SRSLTE_API {
uint32_t starting_prb;
uint32_t initial_cyclic_shift; ///< initialCyclicShift (0..11)
uint32_t start_symbol_idx; ///< startingSymbolIndex (0..10)
uint32_t nof_symbols; ///< nrofSymbols (4..14)
uint32_t time_domain_occ; ///< TimeDomainOCC(0..6)
bool intra_slot_hopping;
} srslte_pucch_nr_resource_format1_t;
/**
* @brief NR-PUCCH encoder/decoder object
*/
typedef struct SRSLTE_API {
srslte_zc_sequence_lut_t r_uv_1prb;
cf_t format1_w_i_m[SRSLTE_PUCCH_NR_FORMAT1_N_MAX][SRSLTE_PUCCH_NR_FORMAT1_N_MAX][SRSLTE_PUCCH_NR_FORMAT1_N_MAX];
srslte_modem_table_t bpsk;
srslte_modem_table_t qpsk;
} srslte_pucch_nr_t;
/**
* @brief Initialises an NR-PUCCH encoder/decoder object
* @param q Object
* @return SRSLTE_SUCCESS if successful, SRSLTE_ERROR code otherwise
*/
int srslte_pucch_nr_init(srslte_pucch_nr_t* q);
/**
* @brief Deallocates an NR-PUCCH encoder/decoder object
* @param q Object
*/
void srslte_pucch_nr_free(srslte_pucch_nr_t* q);
/**
* @brief Puts NR-PUCCH format 0 in the resource grid
* @remark Described in TS 38.211 clause 6.3.2.3 PUCCH format 0
* @param[in] q NR-PUCCH encoder/decoder object
* @param[in] carrier Carrier configuration
* @param[in] cfg PUCCH common configuration
* @param[in] slot slot configuration
* @param[in] resource PUCCH format 0 resource
* @param[in] m_cs Cyclic shift according to TS 38.213 clause 5
* @param[out] slot_symbols Resource grid of the given slot
* @return SRSLTE_SUCCESS if successful, SRSLTE_ERROR code otherwise
*/
int srslte_pucch_nr_format0_put(const 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,
srslte_pucch_nr_resource_format0_t* resource,
uint32_t m_cs,
cf_t* slot_symbols);
/**
* @brief Measures PUCCH format 0 in the resource grid
* @param[in] q NR-PUCCH encoder/decoder object
* @param[in] carrier Carrier configuration
* @param[in] cfg PUCCH common configuration
* @param[in] slot slot configuration
* @param[in] resource PUCCH format 0 resource
* @param[in] m_cs Cyclic shift according to TS 38.213 clause 5
* @param[in] slot_symbols Resource grid of the given slot
* @param[out] measure Measurement structure
* @return SRSLTE_SUCCESS if successful, SRSLTE_ERROR code otherwise
*/
int srslte_pucch_nr_format0_measure(const 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,
srslte_pucch_nr_resource_format0_t* resource,
uint32_t m_cs,
const cf_t* slot_symbols,
srslte_pucch_nr_measure_t* measure);
#endif // SRSLTE_PUCCH_NR_H

@ -71,10 +71,10 @@ SRSLTE_API void srslte_uci_nr_free(srslte_uci_nr_t* q);
* @param[out] o Output encoded bits
* @return Number of encoded bits if encoding is successful, SRSLTE_ERROR code otherwise
*/
SRSLTE_API int srslte_uci_nr_encode_pucch(srslte_uci_nr_t* q,
const srslte_pucch_nr_cfg_t* pucch_cfg,
const srslte_uci_cfg_nr_t* uci_cfg,
const srslte_uci_value_nr_t* value,
uint8_t* o);
SRSLTE_API int srslte_uci_nr_encode_pucch(srslte_uci_nr_t* q,
const srslte_pucch_nr_resource_t* pucch_resource,
const srslte_uci_cfg_nr_t* uci_cfg,
const srslte_uci_value_nr_t* value,
uint8_t* o);
#endif // SRSLTE_UCI_NR_H

@ -0,0 +1,434 @@
/**
*
* \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/pucch_nr.h"
#include "srslte/phy/common/phy_common_nr.h"
#include "srslte/phy/common/sequence.h"
#include "srslte/phy/common/zc_sequence.h"
#include "srslte/phy/modem/mod.h"
#include "srslte/phy/utils/debug.h"
#include "srslte/phy/utils/vector.h"
#include <complex.h>
// Implements TS 38.211 clause 6.3.2.2.1 Group and sequence hopping
static int pucch_nr_group_sequence(const srslte_carrier_nr_t* carrier,
const srslte_pucch_nr_common_cfg_t* cfg,
uint32_t* u_,
uint32_t* v_)
{
uint32_t f_gh = 0;
uint32_t f_ss = 0;
uint32_t n_id = cfg->hopping_id_present ? cfg->hopping_id : carrier->id;
switch (cfg->group_hopping) {
case SRSLTE_PUCCH_NR_GROUP_HOPPING_NEITHER:
f_ss = n_id % SRSLTE_ZC_SEQUENCE_NOF_GROUPS;
break;
case SRSLTE_PUCCH_NR_GROUP_HOPPING_ENABLE:
ERROR("Group hopping is not implemented\n");
return SRSLTE_ERROR;
case SRSLTE_PUCCH_NR_GROUP_HOPPING_DISABLE:
ERROR("Hopping is not implemented\n");
return SRSLTE_ERROR;
}
uint32_t u = (f_gh + f_ss) % SRSLTE_ZC_SEQUENCE_NOF_GROUPS;
uint32_t v = 0;
if (u_) {
*u_ = u;
}
if (v_) {
*v_ = v;
}
return SRSLTE_SUCCESS;
}
// Implements TS 38.211 clause 6.3.2.2.2 Cyclic shift hopping
static uint32_t pucch_nr_alpha_idx(const srslte_carrier_nr_t* carrier,
const srslte_pucch_nr_common_cfg_t* cfg,
const srslte_dl_slot_cfg_t* slot,
uint32_t l,
uint32_t l_prime,
uint32_t m0,
uint32_t m_cs)
{
// Compute number of slot
uint32_t n_slot = slot->idx % SRSLTE_NSLOTS_PER_FRAME_NR(carrier->numerology);
// Generate pseudo-random sequence
uint32_t cinit = cfg->hopping_id_present ? cfg->hopping_id : carrier->id;
uint8_t cs[SRSLTE_NSYMB_PER_SLOT_NR * SRSLTE_NSLOTS_PER_FRAME_NR(SRSLTE_NR_MAX_NUMEROLOGY) * 8U] = {};
srslte_sequence_apply_bit(
cs, cs, SRSLTE_NSYMB_PER_SLOT_NR * SRSLTE_NSLOTS_PER_FRAME_NR(carrier->numerology) * 8, cinit);
// Create n_cs parameter
uint32_t n_cs = 0;
for (uint32_t m = 0; m < 8; m++) {
n_cs += cs[SRSLTE_NSYMB_PER_SLOT_NR * n_slot + (l + l_prime) * 8 + m] << m;
}
return (m0 + m_cs + n_cs) % SRSLTE_NRE;
}
static int srslte_pucch_nr_format0_resource_valid(const srslte_pucch_nr_resource_format0_t* resource)
{
if (resource == NULL) {
return SRSLTE_ERROR_INVALID_INPUTS;
}
if (resource->nof_symbols != 1 && resource->nof_symbols != 2) {
ERROR("Invalid number of symbols (%d)\n", resource->nof_symbols);
return SRSLTE_ERROR;
}
if (resource->initial_cyclic_shift > 11) {
ERROR("Invalid initial cyclic shift (%d)\n", resource->initial_cyclic_shift);
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;
}
static int srslte_pucch_nr_format1_resource_valid(const srslte_pucch_nr_resource_format1_t* resource)
{
if (resource == NULL) {
return SRSLTE_ERROR_INVALID_INPUTS;
}
if (resource->nof_symbols < 4 || resource->nof_symbols > 14) {
ERROR("Invalid number of symbols (%d)\n", resource->nof_symbols);
return SRSLTE_ERROR;
}
if (resource->initial_cyclic_shift > 11) {
ERROR("Invalid initial cyclic shift (%d)\n", resource->initial_cyclic_shift);
return SRSLTE_ERROR;
}
if (resource->start_symbol_idx > 10) {
ERROR("Invalid initial start symbol idx (%d)\n", resource->start_symbol_idx);
return SRSLTE_ERROR;
}
if (resource->time_domain_occ > 6) {
ERROR("Invalid time domain occ (%d)\n", resource->time_domain_occ);
return SRSLTE_ERROR;
}
if (resource->intra_slot_hopping) {
ERROR("Intra-slot hopping is not implemented\n");
return SRSLTE_ERROR;
}
return SRSLTE_SUCCESS;
}
// TS 38.211 Table 6.3.2.4.1-2: Orthogonal sequences for PUCCH format 1
static uint32_t
pucch_nr_format1_rho[SRSLTE_PUCCH_NR_FORMAT1_N_MAX][SRSLTE_PUCCH_NR_FORMAT1_N_MAX][SRSLTE_PUCCH_NR_FORMAT1_N_MAX] =
{{{0}, {0, 0}, {0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0}},
{{}, {0, 1}, {0, 1, 2}, {0, 2, 0, 2}, {0, 1, 2, 3, 4}, {0, 1, 2, 3, 4, 5}, {0, 1, 2, 3, 4, 5, 6}},
{{}, {}, {0, 2, 1}, {0, 0, 2, 2}, {0, 2, 4, 1, 3}, {0, 2, 4, 0, 2, 4}, {0, 2, 4, 6, 1, 3, 5}},
{{}, {}, {}, {0, 2, 2, 0}, {0, 3, 1, 4, 2}, {0, 3, 0, 3, 0, 3}, {0, 3, 6, 2, 5, 1, 4}},
{{}, {}, {}, {}, {0, 4, 3, 2, 1}, {0, 4, 2, 0, 4, 2}, {0, 4, 1, 5, 2, 6, 3}},
{{}, {}, {}, {}, {}, {0, 5, 4, 3, 2, 1}, {0, 5, 3, 1, 6, 4, 2}},
{{}, {}, {}, {}, {}, {}, {0, 6, 5, 4, 3, 2, 1}}};
#define SRSLTE_PUCCH_NR_FORMAT1_MAX_NOF_BITS 2
int srslte_pucch_nr_init(srslte_pucch_nr_t* q)
{
if (q == NULL) {
return SRSLTE_ERROR_INVALID_INPUTS;
}
// Initialise ZC sequences for 1PRB
float alphas_1prb[SRSLTE_NRE] = {};
for (uint32_t i = 0; i < SRSLTE_NRE; i++) {
alphas_1prb[i] = 2.0f * (float)M_PI * (float)i / (float)SRSLTE_NRE;
}
srslte_zc_sequence_lut_init_nr(&q->r_uv_1prb, 1, 0, alphas_1prb, SRSLTE_NRE);
// Initialise BPSK modulation table
if (srslte_modem_table_lte(&q->bpsk, SRSLTE_MOD_BPSK) < SRSLTE_SUCCESS) {
ERROR("Initiating modem table\n");
return SRSLTE_ERROR;
}
// Initialise QPSK modulation table
if (srslte_modem_table_lte(&q->qpsk, SRSLTE_MOD_QPSK) < SRSLTE_SUCCESS) {
ERROR("Initiating modem table\n");
return SRSLTE_ERROR;
}
for (uint32_t n_pucch = 1; n_pucch <= SRSLTE_PUCCH_NR_FORMAT1_N_MAX; n_pucch++) {
for (uint32_t i = 0; i < SRSLTE_PUCCH_NR_FORMAT1_N_MAX; i++) {
for (uint32_t m = 0; m < SRSLTE_PUCCH_NR_FORMAT1_N_MAX; m++) {
uint32_t rho = pucch_nr_format1_rho[i][n_pucch - 1][m];
q->format1_w_i_m[i][n_pucch - 1][m] = cexpf(I * 2.0f * (float)M_PI * (float)rho / n_pucch);
}
}
}
return SRSLTE_SUCCESS;
}
void srslte_pucch_nr_free(srslte_pucch_nr_t* q)
{
if (q == NULL) {
return;
}
srslte_zc_sequence_lut_free(&q->r_uv_1prb);
srslte_modem_table_free(&q->bpsk);
srslte_modem_table_free(&q->qpsk);
SRSLTE_MEM_ZERO(q, srslte_pucch_nr_t, 1);
}
int srslte_pucch_nr_format0_put(const 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,
srslte_pucch_nr_resource_format0_t* resource,
uint32_t m_cs,
cf_t* slot_symbols)
{
if (carrier == NULL || cfg == NULL || slot == NULL || resource == NULL || slot_symbols == NULL) {
return SRSLTE_ERROR_INVALID_INPUTS;
}
if (srslte_pucch_nr_format0_resource_valid(resource) < SRSLTE_SUCCESS) {
ERROR("Invalid PUCCH format 0 resource\n");
return SRSLTE_SUCCESS;
}
uint32_t u = 0;
uint32_t v = 0;
if (pucch_nr_group_sequence(carrier, cfg, &u, &v) < SRSLTE_SUCCESS) {
ERROR("Error getting group sequence\n");
return SRSLTE_ERROR;
}
uint32_t l_prime = resource->start_symbol_idx;
for (uint32_t l = 0; l < resource->nof_symbols; l++) {
// Get Alpha index
uint32_t alpha_idx = pucch_nr_alpha_idx(carrier, cfg, slot, l, l_prime, resource->initial_cyclic_shift, m_cs);
// get r_uv sequence from LUT object
const cf_t* r_uv = srslte_zc_sequence_lut_get(&q->r_uv_1prb, u, v, alpha_idx);
if (r_uv == NULL) {
ERROR("Getting r_uv sequence\n");
return SRSLTE_ERROR;
}
// Get start of the sequence in resource grid
cf_t* slot_symbols_ptr = &slot_symbols[(carrier->nof_prb * (l + l_prime) + resource->starting_prb) * SRSLTE_NRE];
// Copy sequence in grid
srslte_vec_cf_copy(slot_symbols_ptr, r_uv, SRSLTE_NRE);
}
return SRSLTE_SUCCESS;
}
int srslte_pucch_nr_format0_measure(const 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,
srslte_pucch_nr_resource_format0_t* resource,
uint32_t m_cs,
const cf_t* slot_symbols,
srslte_pucch_nr_measure_t* measure)
{
if (carrier == NULL || cfg == NULL || slot == NULL || resource == NULL || slot_symbols == NULL || measure == NULL) {
return SRSLTE_ERROR_INVALID_INPUTS;
}
if (srslte_pucch_nr_format0_resource_valid(resource) < SRSLTE_SUCCESS) {
ERROR("Invalid PUCCH format 0 resource\n");
return SRSLTE_SUCCESS;
}
uint32_t u = 0;
uint32_t v = 0;
if (pucch_nr_group_sequence(carrier, cfg, &u, &v) < SRSLTE_SUCCESS) {
ERROR("Error getting group sequence\n");
return SRSLTE_ERROR;
}
uint32_t l_prime = resource->start_symbol_idx;
float epre = 0.0f;
float rsrp = 0.0f;
for (uint32_t l = 0; l < resource->nof_symbols; l++) {
// Get Alpha index
uint32_t alpha_idx = pucch_nr_alpha_idx(carrier, cfg, slot, l, l_prime, resource->initial_cyclic_shift, m_cs);
// get r_uv sequence from LUT object
const cf_t* r_uv = srslte_zc_sequence_lut_get(&q->r_uv_1prb, u, v, alpha_idx);
if (r_uv == NULL) {
ERROR("Getting r_uv sequence\n");
return SRSLTE_ERROR;
}
// Get start of the sequence in resource grid
const cf_t* slot_symbols_ptr =
&slot_symbols[(carrier->nof_prb * (l + l_prime) + resource->starting_prb) * SRSLTE_NRE];
// Measure EPRE and average
epre += srslte_vec_avg_power_cf(slot_symbols_ptr, SRSLTE_NRE) / resource->nof_symbols;
// Do correlation
cf_t corr = srslte_vec_dot_prod_conj_ccc(r_uv, slot_symbols_ptr, SRSLTE_NRE);
corr /= SRSLTE_NRE;
// Measure RSRP and average
rsrp += (__real__ corr * __real__ corr + __imag__ corr * __imag__ corr) / resource->nof_symbols;
}
// Save measurement
measure->rsrp = rsrp;
measure->rsrp_dBfs = srslte_convert_power_to_dB(rsrp);
measure->epre = epre;
measure->epre_dBfs = srslte_convert_power_to_dB(epre);
if (isnormal(epre)) {
measure->norm_corr = rsrp / epre;
} else {
measure->norm_corr = 0.0f;
}
return SRSLTE_SUCCESS;
}
// Implements TS 38.211 table 6.3.2.4.1-1 Number of PUCCH symbols and the corresponding N_PUC...
uint32_t pucch_nr_format1_n_pucch(const srslte_pucch_nr_resource_format1_t* resource, uint32_t m_prime)
{
if (resource->intra_slot_hopping) {
if (m_prime == 0) {
return resource->nof_symbols / 4;
}
return resource->nof_symbols / 2 - resource->nof_symbols / 4;
}
if (m_prime == 1) {
return 0;
}
return resource->nof_symbols / 2;
}
static cf_t pucch_nr_format1_w(const srslte_pucch_nr_t* q, uint32_t n_pucch, uint32_t i, uint32_t m)
{
if (n_pucch < 1 || n_pucch > SRSLTE_PUCCH_NR_FORMAT1_N_MAX) {
ERROR("Invalid n_pucch\n");
return NAN;
}
if (i >= SRSLTE_PUCCH_NR_FORMAT1_N_MAX) {
ERROR("Invalid i\n");
return NAN;
}
if (m >= SRSLTE_PUCCH_NR_FORMAT1_N_MAX) {
ERROR("Invalid m\n");
return NAN;
}
// Get value
return q->format1_w_i_m[i][n_pucch - 1][m];
}
int srslte_pucch_nr_put_format1(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_format1_t* resource,
uint8_t b[SRSLTE_PUCCH_NR_FORMAT1_MAX_NOF_BITS],
uint32_t nof_bits,
cf_t* slot_symbols)
{
uint32_t m_cs = 0;
if (carrier == NULL || cfg == NULL || slot == NULL || resource == NULL || b == NULL || slot_symbols == NULL) {
return SRSLTE_ERROR_INVALID_INPUTS;
}
if (srslte_pucch_nr_format1_resource_valid(resource) < SRSLTE_SUCCESS) {
ERROR("Invalid PUCCH format 1 resource\n");
return SRSLTE_SUCCESS;
}
if (nof_bits > 2) {
ERROR("Invalid number of bits (%d)\n", nof_bits);
return SRSLTE_ERROR;
}
// Modulate d
cf_t d = 0;
if (nof_bits == 1) {
srslte_mod_modulate(&q->bpsk, b, &d, nof_bits);
} else {
srslte_mod_modulate(&q->qpsk, b, &d, nof_bits);
}
// Get group sequence
uint32_t u = 0;
uint32_t v = 0;
if (pucch_nr_group_sequence(carrier, cfg, &u, &v) < SRSLTE_SUCCESS) {
ERROR("Error getting group sequence\n");
return SRSLTE_ERROR;
}
// Calculate number of symbols carrying PUCCH (No DMRS)
uint32_t n_pucch = pucch_nr_format1_n_pucch(resource, 0);
uint32_t l_prime = resource->start_symbol_idx;
for (uint32_t l = 1, m = 0; l < resource->nof_symbols; l += 2, m++) {
// Get start of the sequence in resource grid
cf_t* slot_symbols_ptr = &slot_symbols[(carrier->nof_prb * (l + l_prime) + resource->starting_prb) * SRSLTE_NRE];
// Get Alpha index
uint32_t alpha_idx = pucch_nr_alpha_idx(carrier, cfg, slot, l, l_prime, resource->initial_cyclic_shift, m_cs);
// get r_uv sequence from LUT object
const cf_t* r_uv = srslte_zc_sequence_lut_get(&q->r_uv_1prb, u, v, alpha_idx);
if (r_uv == NULL) {
ERROR("Getting r_uv sequence\n");
return SRSLTE_ERROR;
}
// Compute y = d(0) * r_uv
cf_t y[SRSLTE_NRE];
srslte_vec_sc_prod_ccc(r_uv, d, y, SRSLTE_NRE);
// Get w_i_m
cf_t w_i_m = pucch_nr_format1_w(q, n_pucch, resource->time_domain_occ, m);
// Compute z(n) = w(i) * y(n)
cf_t z[SRSLTE_NRE];
srslte_vec_sc_prod_ccc(y, w_i_m, z, SRSLTE_NRE);
// Put z in the grid
srslte_vec_cf_copy(slot_symbols_ptr, z, SRSLTE_NRE);
}
return SRSLTE_SUCCESS;
}

@ -614,6 +614,10 @@ endif(RF_FOUND)
# NR
########################################################################
add_executable(pucch_nr_test pucch_nr_test.c)
target_link_libraries(pucch_nr_test srslte_phy)
add_test(pucch_nr_test pucch_nr_test)
add_executable(sch_nr_test sch_nr_test.c)
target_link_libraries(sch_nr_test srslte_phy)
add_test(sch_nr_test sch_nr_test -m 0 -p 1)

@ -0,0 +1,149 @@
/**
*
* \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/common/test_common.h"
#include "srslte/phy/phch/pucch_nr.h"
#include "srslte/phy/utils/debug.h"
#include "srslte/phy/utils/vector.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <sys/time.h>
#include <unistd.h>
static srslte_carrier_nr_t carrier = {
0, // cell_id
0, // numerology
6, // nof_prb
0, // start
1 // max_mimo_layers
};
static uint32_t starting_prb_stride = 4;
static uint32_t starting_symbol_stride = 4;
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_format0_t resource = {};
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 = 1; resource.nof_symbols <= 2; 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 += starting_symbol_stride) {
for (resource.initial_cyclic_shift = 0; resource.initial_cyclic_shift <= 11;
resource.initial_cyclic_shift++) {
for (uint32_t m_cs = 0; m_cs <= 6; m_cs += 2) {
TESTASSERT(srslte_pucch_nr_format0_put(pucch, &carrier, cfg, &slot, &resource, m_cs, slot_symbols) ==
SRSLTE_SUCCESS);
// Measure PUCCH format 0 for all possible values of m_cs
for (uint32_t m_cs_test = 0; m_cs_test <= 6; m_cs_test += 2) {
srslte_pucch_nr_measure_t measure = {};
TESTASSERT(srslte_pucch_nr_format0_measure(
pucch, &carrier, cfg, &slot, &resource, m_cs_test, slot_symbols, &measure) ==
SRSLTE_SUCCESS);
if (m_cs == m_cs_test) {
TESTASSERT(fabsf(measure.epre - 1) < 0.001);
TESTASSERT(fabsf(measure.rsrp - 1) < 0.001);
TESTASSERT(fabsf(measure.norm_corr - 1) < 0.001);
} else {
TESTASSERT(fabsf(measure.epre - 1) < 0.001);
TESTASSERT(fabsf(measure.rsrp - 0) < 0.1);
TESTASSERT(fabsf(measure.norm_corr - 0) < 0.1);
}
}
}
}
}
}
}
}
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-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) {
switch (opt) {
case 'c':
carrier.id = (uint32_t)strtol(argv[optind], NULL, 10);
break;
case 'n':
carrier.nof_prb = (uint32_t)strtol(argv[optind], NULL, 10);
break;
case 'v':
srslte_verbose++;
break;
default:
usage(argv[0]);
exit(-1);
}
}
}
int main(int argc, char** argv)
{
int ret = SRSLTE_ERROR;
parse_args(argc, argv);
uint32_t nof_re = carrier.nof_prb * SRSLTE_NRE * SRSLTE_NSYMB_PER_SLOT_NR;
cf_t* slot_symb = srslte_vec_cf_malloc(nof_re);
srslte_pucch_nr_t pucch = {};
if (slot_symb == NULL) {
ERROR("Alloc\n");
goto clean_exit;
}
if (srslte_pucch_nr_init(&pucch) < SRSLTE_SUCCESS) {
ERROR("PUCCH init\n");
goto clean_exit;
}
srslte_pucch_nr_common_cfg_t common_cfg = {};
if (test_pucch_format0(&pucch, &common_cfg, slot_symb) < SRSLTE_SUCCESS) {
ERROR("Failed PUCCH format 0\n");
goto clean_exit;
}
ret = SRSLTE_SUCCESS;
clean_exit:
if (slot_symb) {
free(slot_symb);
}
srslte_pucch_nr_free(&pucch);
if (ret == SRSLTE_SUCCESS) {
printf("Test passed!\n");
} else {
printf("Test failed!\n");
}
return ret;
}

@ -412,7 +412,7 @@ int uci_nr_encode(srslte_uci_nr_t* q,
}
// Implements TS 38.212 Table 6.3.1.4-1: Total rate matching output sequence length Etot
static int uci_nr_pucch_E_tot(const srslte_pucch_nr_cfg_t* pucch_cfg, const srslte_uci_cfg_nr_t* uci_cfg)
static int uci_nr_pucch_E_tot(const srslte_pucch_nr_resource_t* pucch_cfg, const srslte_uci_cfg_nr_t* uci_cfg)
{
if (pucch_cfg == NULL || uci_cfg == NULL) {
return SRSLTE_ERROR_INVALID_INPUTS;
@ -453,7 +453,7 @@ static int uci_nr_pucch_E_tot(const srslte_pucch_nr_cfg_t* pucch_cfg, const srsl
// Implements TS 38.212 Table 6.3.1.4.1-1: Rate matching output sequence length E UCI
static int
uci_nr_pucch_E_uci(const srslte_pucch_nr_cfg_t* pucch_cfg, const srslte_uci_cfg_nr_t* uci_cfg, uint32_t E_tot)
uci_nr_pucch_E_uci(const srslte_pucch_nr_resource_t* pucch_cfg, const srslte_uci_cfg_nr_t* uci_cfg, uint32_t E_tot)
{
if (uci_cfg->o_csi1 != 0 && uci_cfg->o_csi2) {
ERROR("Simultaneous CSI part 1 and CSI part 2 is not implemented\n");
@ -463,19 +463,19 @@ uci_nr_pucch_E_uci(const srslte_pucch_nr_cfg_t* pucch_cfg, const srslte_uci_cfg_
return E_tot;
}
int srslte_uci_nr_encode_pucch(srslte_uci_nr_t* q,
const srslte_pucch_nr_cfg_t* pucch_cfg,
const srslte_uci_cfg_nr_t* uci_cfg,
const srslte_uci_value_nr_t* value,
uint8_t* o)
int srslte_uci_nr_encode_pucch(srslte_uci_nr_t* q,
const srslte_pucch_nr_resource_t* pucch_resource_cfg,
const srslte_uci_cfg_nr_t* uci_cfg,
const srslte_uci_value_nr_t* value,
uint8_t* o)
{
int E_tot = uci_nr_pucch_E_tot(pucch_cfg, uci_cfg);
int E_tot = uci_nr_pucch_E_tot(pucch_resource_cfg, uci_cfg);
if (E_tot < SRSLTE_SUCCESS) {
return SRSLTE_ERROR;
}
int E_uci = uci_nr_pucch_E_uci(pucch_cfg, uci_cfg, E_tot);
int E_uci = uci_nr_pucch_E_uci(pucch_resource_cfg, uci_cfg, E_tot);
if (E_uci < SRSLTE_SUCCESS) {
return SRSLTE_ERROR;
}

Loading…
Cancel
Save