mirror of https://github.com/PentHertz/srsLTE.git
Added NR-PUCCH Format 1 encoder, decoder and DMRS
This commit is contained in:
parent
33bb387f52
commit
697bdb4d6d
|
@ -0,0 +1,56 @@
|
|||
/**
|
||||
*
|
||||
* \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_DMRS_PUCCH_H
|
||||
#define SRSLTE_DMRS_PUCCH_H
|
||||
|
||||
#include "srslte/config.h"
|
||||
#include "srslte/phy/ch_estimation/chest_ul.h"
|
||||
#include "srslte/phy/phch/pucch_nr.h"
|
||||
|
||||
/**
|
||||
* @brief Puts NR-PUCCH format 1 DMRS in the provided 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 1 resource
|
||||
* @param[out] slot_symbols Resource grid of the given slot
|
||||
* @return SRSLTE_SUCCESS if successful, SRSLTE_ERROR code otherwise
|
||||
*/
|
||||
SRSLTE_API int srslte_dmrs_pucch_format1_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,
|
||||
const srslte_pucch_nr_resource_format1_t* resource,
|
||||
cf_t* slot_symbols);
|
||||
|
||||
/**
|
||||
* @brief Estimates NR-PUCCH format 1 resource elements from their DMRS in the provided 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 1 resource
|
||||
* @param[in] slot_symbols Resource grid of the given slot
|
||||
* @param[out] res UL Channel estimator result
|
||||
* @return SRSLTE_SUCCESS if successful, SRSLTE_ERROR code otherwise
|
||||
*/
|
||||
SRSLTE_API int srslte_dmrs_pucch_format1_estimate(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,
|
||||
const srslte_pucch_nr_resource_format1_t* resource,
|
||||
const cf_t* slot_symbols,
|
||||
srslte_chest_ul_res_t* res);
|
||||
|
||||
#endif // SRSLTE_DMRS_PUCCH_H
|
|
@ -17,14 +17,20 @@
|
|||
#include "srslte/phy/common/phy_common_nr.h"
|
||||
#include "srslte/phy/common/zc_sequence.h"
|
||||
#include "srslte/phy/modem/modem_table.h"
|
||||
#include <srslte/srslte.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* @brief Maximum number of NR-PUCCH format 1 symbols (without DMRS)
|
||||
* @brief Maximum number of symbols (without DMRS) that NR-PUCCH format 1 can transmit
|
||||
*/
|
||||
#define SRSLTE_PUCCH_NR_FORMAT1_N_MAX 7
|
||||
|
||||
/**
|
||||
* @brief Maximum number of bit that NR-PUCCH format 1 can carry
|
||||
*/
|
||||
#define SRSLTE_PUCCH_NR_FORMAT1_MAX_NOF_BITS 2
|
||||
|
||||
typedef enum SRSLTE_API {
|
||||
SRSLTE_PUCCH_NR_FORMAT_0 = 0,
|
||||
SRSLTE_PUCCH_NR_FORMAT_1,
|
||||
|
@ -124,16 +130,58 @@ typedef struct SRSLTE_API {
|
|||
* @param q Object
|
||||
* @return SRSLTE_SUCCESS if successful, SRSLTE_ERROR code otherwise
|
||||
*/
|
||||
int srslte_pucch_nr_init(srslte_pucch_nr_t* q);
|
||||
SRSLTE_API 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);
|
||||
SRSLTE_API void srslte_pucch_nr_free(srslte_pucch_nr_t* q);
|
||||
|
||||
/**
|
||||
* @brief Puts NR-PUCCH format 0 in the resource grid
|
||||
* @brief Computes the NR-PUCCH group sequence
|
||||
* @remark Implemented according to TS 38.211 clause 6.3.2.2.1 Group and sequence hopping
|
||||
* @param[in] carrier Serving cell and UL BWP configuration
|
||||
* @param[in] cfg PUCCH common configuration
|
||||
* @param[out] u_ Group sequence (u)
|
||||
* @param[out] v_ Base sequence (v)
|
||||
* @return SRSLTE_SUCCESS if provide arguments are right, SRSLTE_ERROR code otherwise
|
||||
*/
|
||||
SRSLTE_API int srslte_pucch_nr_group_sequence(const srslte_carrier_nr_t* carrier,
|
||||
const srslte_pucch_nr_common_cfg_t* cfg,
|
||||
uint32_t* u_,
|
||||
uint32_t* v_);
|
||||
|
||||
/**
|
||||
* @brief Computes the NR alpha index (1-NRE)
|
||||
* @param[in] carrier Serving cell and UL BWP configuration
|
||||
* @param[in] cfg PUCCH common configuration
|
||||
* @param[in] slot slot configuration
|
||||
* @param[in] l OFDM Symbol, relative to the NR-PUCCH transmission start
|
||||
* @param[in] l_prime Initial OFDM symbol, relative to the transmission slot start
|
||||
* @param[in] m0 Initial cyclic shift
|
||||
* @param[in] m_cs Set to zero expect for format 0
|
||||
* @param[out] alpha_idx Computed alpha index
|
||||
* @return SRSLTE_SUCCESS if provide arguments are right, SRSLTE_ERROR code otherwise
|
||||
*/
|
||||
SRSLTE_API int srslte_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,
|
||||
uint32_t* alpha_idx);
|
||||
|
||||
/**
|
||||
* @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_format0_resource_valid(const srslte_pucch_nr_resource_format0_t* resource);
|
||||
|
||||
/**
|
||||
* @brief Encode and writes 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
|
||||
|
@ -144,13 +192,13 @@ void srslte_pucch_nr_free(srslte_pucch_nr_t* q);
|
|||
* @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);
|
||||
SRSLTE_API int srslte_pucch_nr_format0_encode(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
|
||||
|
@ -164,13 +212,76 @@ int srslte_pucch_nr_format0_put(const srslte_pucch_nr_t* q,
|
|||
* @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);
|
||||
SRSLTE_API 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);
|
||||
|
||||
/**
|
||||
* @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_format1_t* resource);
|
||||
|
||||
/**
|
||||
* @brief Get NR-PUCCH orthogonal sequence w
|
||||
* @remark Defined by TS 38.211 Table 6.3.2.4.1-2: Orthogonal sequences ... for PUCCH format 1
|
||||
* @param[in] q NR-PUCCH encoder/decoder object
|
||||
* @param[in] n_pucch Number of PUCCH symbols
|
||||
* @param[in] i sequence index
|
||||
* @param m OFDM symbol index
|
||||
* @return Orthogonal sequence complex number if valid, NAN otherwise
|
||||
*/
|
||||
SRSLTE_API cf_t srslte_pucch_nr_format1_w(const srslte_pucch_nr_t* q, uint32_t n_pucch, uint32_t i, uint32_t m);
|
||||
|
||||
/**
|
||||
* @brief Encodes and puts NR-PUCCH format 1 in the resource grid
|
||||
* @remark Described in TS 38.211 clause 6.3.2.4 PUCCH format 1
|
||||
* @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 1 resource
|
||||
* @param[in] b Bits to encode in the message
|
||||
* @param[in] nof_bits Number of bits to encode in the message
|
||||
* @param[out] slot_symbols Resource grid of the given slot
|
||||
* @return SRSLTE_SUCCESS if successful, SRSLTE_ERROR code otherwise
|
||||
*/
|
||||
SRSLTE_API int srslte_pucch_nr_format1_encode(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,
|
||||
const srslte_pucch_nr_resource_format1_t* resource,
|
||||
uint8_t* b,
|
||||
uint32_t nof_bits,
|
||||
cf_t* slot_symbols);
|
||||
|
||||
/**
|
||||
* @brief Decodes NR-PUCCH format 1
|
||||
* @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 1 resource
|
||||
* @param[in] chest_res Channel estimator result
|
||||
* @param[in] slot_symbols Resource grid of the given slot
|
||||
* @param[out] b Bits to decode
|
||||
* @param[in] nof_bits Number of bits to decode in the message
|
||||
* @return SRSLTE_SUCCESS if successful, SRSLTE_ERROR code otherwise
|
||||
*/
|
||||
SRSLTE_API int srslte_pucch_nr_format1_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_format1_t* resource,
|
||||
srslte_chest_ul_res_t* chest_res,
|
||||
cf_t* slot_symbols,
|
||||
uint8_t b[SRSLTE_PUCCH_NR_FORMAT1_MAX_NOF_BITS],
|
||||
uint32_t nof_bits);
|
||||
|
||||
#endif // SRSLTE_PUCCH_NR_H
|
||||
|
|
|
@ -0,0 +1,281 @@
|
|||
/**
|
||||
*
|
||||
* \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/ch_estimation/dmrs_pucch.h"
|
||||
#include "srslte/phy/utils/debug.h"
|
||||
#include "srslte/phy/utils/vector.h"
|
||||
|
||||
// Implements TS 38.211 table 6.4.1.3.1.1-1: Number of DM-RS symbols and the corresponding N_PUCCH...
|
||||
static uint32_t dmrs_pucch_format1_n_pucch(const srslte_pucch_nr_resource_format1_t* resource, uint32_t m_prime)
|
||||
{
|
||||
if (resource->intra_slot_hopping) {
|
||||
if (m_prime == 0) {
|
||||
switch (resource->nof_symbols) {
|
||||
case 4:
|
||||
case 5:
|
||||
return 1;
|
||||
case 6:
|
||||
case 7:
|
||||
case 8:
|
||||
case 9:
|
||||
return 2;
|
||||
case 10:
|
||||
case 11:
|
||||
case 12:
|
||||
case 13:
|
||||
return 3;
|
||||
case 14:
|
||||
return 4;
|
||||
default:; // Do nothing
|
||||
}
|
||||
} else {
|
||||
switch (resource->nof_symbols) {
|
||||
case 4:
|
||||
case 6:
|
||||
return 1;
|
||||
case 5:
|
||||
case 7:
|
||||
case 8:
|
||||
case 10:
|
||||
return 2;
|
||||
case 9:
|
||||
case 11:
|
||||
case 12:
|
||||
case 14:
|
||||
return 3;
|
||||
case 13:
|
||||
return 4;
|
||||
default:; // Do nothing
|
||||
}
|
||||
}
|
||||
} else if (m_prime == 0) {
|
||||
switch (resource->nof_symbols) {
|
||||
case 4:
|
||||
return 2;
|
||||
case 5:
|
||||
case 6:
|
||||
return 3;
|
||||
case 7:
|
||||
case 8:
|
||||
return 4;
|
||||
case 9:
|
||||
case 10:
|
||||
return 5;
|
||||
case 11:
|
||||
case 12:
|
||||
return 6;
|
||||
case 13:
|
||||
case 14:
|
||||
return 7;
|
||||
default:; // Do nothing
|
||||
}
|
||||
}
|
||||
|
||||
ERROR("Invalid case nof_symbols=%d and m_prime=%d\n", resource->nof_symbols, m_prime);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int srslte_dmrs_pucch_format1_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,
|
||||
const srslte_pucch_nr_resource_format1_t* resource,
|
||||
cf_t* slot_symbols)
|
||||
{
|
||||
|
||||
if (q == NULL || carrier == NULL || cfg == NULL || slot == NULL || resource == 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_ERROR;
|
||||
}
|
||||
|
||||
// Get group sequence
|
||||
uint32_t u = 0;
|
||||
uint32_t v = 0;
|
||||
if (srslte_pucch_nr_group_sequence(carrier, cfg, &u, &v) < SRSLTE_SUCCESS) {
|
||||
ERROR("Error getting group sequence\n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
uint32_t n_pucch = dmrs_pucch_format1_n_pucch(resource, 0);
|
||||
if (n_pucch == 0) {
|
||||
ERROR("Error getting number of symbols\n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
uint32_t l_prime = resource->start_symbol_idx;
|
||||
for (uint32_t m = 0; m < n_pucch; m++) {
|
||||
// Clause 6.4.1.3.1.2 specifies l=0,2,4...
|
||||
uint32_t l = m * 2;
|
||||
|
||||
// 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 = 0;
|
||||
if (srslte_pucch_nr_alpha_idx(carrier, cfg, slot, l, l_prime, resource->initial_cyclic_shift, 0, &alpha_idx) <
|
||||
SRSLTE_SUCCESS) {
|
||||
ERROR("Calculating alpha\n");
|
||||
}
|
||||
|
||||
// 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 w_i_m
|
||||
cf_t w_i_m = srslte_pucch_nr_format1_w(q, n_pucch, resource->time_domain_occ, m);
|
||||
|
||||
// Compute z(n) = w(i) * r_uv(n)
|
||||
cf_t z[SRSLTE_NRE];
|
||||
srslte_vec_sc_prod_ccc(r_uv, w_i_m, z, SRSLTE_NRE);
|
||||
|
||||
// Put z in the grid
|
||||
srslte_vec_cf_copy(slot_symbols_ptr, z, SRSLTE_NRE);
|
||||
}
|
||||
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
int srslte_dmrs_pucch_format1_estimate(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,
|
||||
const srslte_pucch_nr_resource_format1_t* resource,
|
||||
const cf_t* slot_symbols,
|
||||
srslte_chest_ul_res_t* res)
|
||||
{
|
||||
|
||||
if (q == NULL || carrier == NULL || cfg == NULL || slot == NULL || resource == 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_ERROR;
|
||||
}
|
||||
|
||||
// Get group sequence
|
||||
uint32_t u = 0;
|
||||
uint32_t v = 0;
|
||||
if (srslte_pucch_nr_group_sequence(carrier, cfg, &u, &v) < SRSLTE_SUCCESS) {
|
||||
ERROR("Error getting group sequence\n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
uint32_t n_pucch = dmrs_pucch_format1_n_pucch(resource, 0);
|
||||
if (n_pucch == 0) {
|
||||
ERROR("Error getting number of symbols\n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
cf_t ce[SRSLTE_PUCCH_NR_FORMAT1_N_MAX][SRSLTE_NRE];
|
||||
uint32_t l_prime = resource->start_symbol_idx;
|
||||
for (uint32_t m = 0; m < n_pucch; m++) {
|
||||
// Clause 6.4.1.3.1.2 specifies l=0,2,4...
|
||||
uint32_t l = m * 2;
|
||||
|
||||
// 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];
|
||||
|
||||
// Get Alpha index
|
||||
uint32_t alpha_idx = 0;
|
||||
if (srslte_pucch_nr_alpha_idx(carrier, cfg, slot, l, l_prime, resource->initial_cyclic_shift, 0, &alpha_idx) <
|
||||
SRSLTE_SUCCESS) {
|
||||
ERROR("Calculating alpha\n");
|
||||
}
|
||||
|
||||
// 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 w_i_m
|
||||
cf_t w_i_m = srslte_pucch_nr_format1_w(q, n_pucch, resource->time_domain_occ, m);
|
||||
|
||||
// Compute z(n) = w(i) * r_uv(n)
|
||||
cf_t z[SRSLTE_NRE];
|
||||
srslte_vec_sc_prod_ccc(r_uv, w_i_m, z, SRSLTE_NRE);
|
||||
|
||||
// Calculate least square estimates for this symbol
|
||||
srslte_vec_prod_conj_ccc(slot_symbols_ptr, z, ce[m], SRSLTE_NRE);
|
||||
}
|
||||
|
||||
// Perform measurements
|
||||
float rsrp = 0.0f;
|
||||
float epre = 0.0f;
|
||||
float ta_err = 0.0f;
|
||||
for (uint32_t m = 0; m < n_pucch; m++) {
|
||||
cf_t corr = srslte_vec_acc_cc(ce[m], SRSLTE_NRE);
|
||||
rsrp += __real__ corr * __real__ corr + __imag__ corr * __imag__ corr;
|
||||
epre += srslte_vec_avg_power_cf(ce[m], SRSLTE_NRE);
|
||||
ta_err += srslte_vec_estimate_frequency(ce[m], SRSLTE_NRE);
|
||||
}
|
||||
|
||||
// Average measurements
|
||||
rsrp /= n_pucch;
|
||||
epre /= n_pucch;
|
||||
ta_err /= n_pucch;
|
||||
|
||||
// Set power measures
|
||||
rsrp = SRSLTE_MIN(rsrp, epre);
|
||||
res->noise_estimate = epre - rsrp;
|
||||
res->noise_estimate_dbm = srslte_convert_power_to_dB(res->noise_estimate);
|
||||
res->snr = rsrp / res->noise_estimate;
|
||||
res->snr_db = srslte_convert_power_to_dB(res->snr_db);
|
||||
|
||||
// Compute Time Aligment error in microseconds
|
||||
if (isnormal(ta_err)) {
|
||||
ta_err /= 15e3f * (float)(1U << carrier->numerology); // Convert from normalized frequency to seconds
|
||||
ta_err *= 1e6f; // Convert to micro-seconds
|
||||
ta_err = roundf(ta_err * 10.0f) / 10.0f; // Round to one tenth of micro-second
|
||||
res->ta_us = ta_err;
|
||||
} else {
|
||||
res->ta_us = 0.0f;
|
||||
}
|
||||
|
||||
// Measure CFO
|
||||
res->cfo = NAN; // Not implemented
|
||||
|
||||
// Do averaging here
|
||||
// ... Not implemented
|
||||
|
||||
// Interpolates between DMRS symbols
|
||||
for (uint32_t m = 0; m < n_pucch; m++) {
|
||||
uint32_t l = m * 2 + 1;
|
||||
cf_t* ce_ptr = &res->ce[(carrier->nof_prb * (l + l_prime) + resource->starting_prb) * SRSLTE_NRE];
|
||||
|
||||
if (m != n_pucch - 1) {
|
||||
// If it is not the last symbol with DMRS, average between
|
||||
srslte_vec_sum_ccc(ce[m], ce[m + 1], ce_ptr, SRSLTE_NRE);
|
||||
srslte_vec_sc_prod_cfc(ce_ptr, 0.5f, ce_ptr, SRSLTE_NRE);
|
||||
} else if (m != 0) {
|
||||
// Extrapolate for the last if more than 1 are provided
|
||||
srslte_vec_sc_prod_cfc(ce[m], 3.0f, ce_ptr, SRSLTE_NRE);
|
||||
srslte_vec_sub_ccc(ce_ptr, ce[m - 1], ce_ptr, SRSLTE_NRE);
|
||||
srslte_vec_sc_prod_cfc(ce_ptr, 0.5f, ce_ptr, SRSLTE_NRE);
|
||||
} else {
|
||||
// Simply copy the
|
||||
srslte_vec_cf_copy(ce_ptr, ce[m], SRSLTE_NRE);
|
||||
}
|
||||
}
|
||||
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
|
@ -18,9 +18,9 @@
|
|||
#include "srslte/phy/utils/debug.h"
|
||||
#include "srslte/phy/utils/vector.h"
|
||||
#include <complex.h>
|
||||
#include <srslte/srslte.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,
|
||||
int srslte_pucch_nr_group_sequence(const srslte_carrier_nr_t* carrier,
|
||||
const srslte_pucch_nr_common_cfg_t* cfg,
|
||||
uint32_t* u_,
|
||||
uint32_t* v_)
|
||||
|
@ -57,14 +57,19 @@ static int pucch_nr_group_sequence(const srslte_carrier_nr_t* carrier,
|
|||
}
|
||||
|
||||
// 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)
|
||||
int srslte_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,
|
||||
uint32_t* alpha_idx)
|
||||
{
|
||||
if (carrier == NULL || cfg == NULL || slot == NULL || alpha_idx == NULL) {
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
// Compute number of slot
|
||||
uint32_t n_slot = slot->idx % SRSLTE_NSLOTS_PER_FRAME_NR(carrier->numerology);
|
||||
|
||||
|
@ -80,10 +85,12 @@ static uint32_t pucch_nr_alpha_idx(const srslte_carrier_nr_t* carrier,
|
|||
n_cs += cs[SRSLTE_NSYMB_PER_SLOT_NR * n_slot + (l + l_prime) * 8 + m] << m;
|
||||
}
|
||||
|
||||
return (m0 + m_cs + n_cs) % SRSLTE_NRE;
|
||||
*alpha_idx = (m0 + m_cs + n_cs) % SRSLTE_NRE;
|
||||
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
static int srslte_pucch_nr_format0_resource_valid(const srslte_pucch_nr_resource_format0_t* resource)
|
||||
int srslte_pucch_nr_format0_resource_valid(const srslte_pucch_nr_resource_format0_t* resource)
|
||||
{
|
||||
if (resource == NULL) {
|
||||
return SRSLTE_ERROR_INVALID_INPUTS;
|
||||
|
@ -107,7 +114,7 @@ static int srslte_pucch_nr_format0_resource_valid(const srslte_pucch_nr_resource
|
|||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
static int srslte_pucch_nr_format1_resource_valid(const srslte_pucch_nr_resource_format1_t* resource)
|
||||
int srslte_pucch_nr_format1_resource_valid(const srslte_pucch_nr_resource_format1_t* resource)
|
||||
{
|
||||
if (resource == NULL) {
|
||||
return SRSLTE_ERROR_INVALID_INPUTS;
|
||||
|
@ -152,8 +159,6 @@ static uint32_t
|
|||
{{}, {}, {}, {}, {}, {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) {
|
||||
|
@ -205,13 +210,13 @@ void srslte_pucch_nr_free(srslte_pucch_nr_t* q)
|
|||
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)
|
||||
int srslte_pucch_nr_format0_encode(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;
|
||||
|
@ -224,7 +229,7 @@ int srslte_pucch_nr_format0_put(const srslte_pucch_nr_t* q,
|
|||
|
||||
uint32_t u = 0;
|
||||
uint32_t v = 0;
|
||||
if (pucch_nr_group_sequence(carrier, cfg, &u, &v) < SRSLTE_SUCCESS) {
|
||||
if (srslte_pucch_nr_group_sequence(carrier, cfg, &u, &v) < SRSLTE_SUCCESS) {
|
||||
ERROR("Error getting group sequence\n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
@ -232,7 +237,11 @@ int srslte_pucch_nr_format0_put(const srslte_pucch_nr_t* q,
|
|||
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);
|
||||
uint32_t alpha_idx = 0;
|
||||
if (srslte_pucch_nr_alpha_idx(carrier, cfg, slot, l, l_prime, resource->initial_cyclic_shift, m_cs, &alpha_idx) <
|
||||
SRSLTE_SUCCESS) {
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
@ -271,7 +280,7 @@ int srslte_pucch_nr_format0_measure(const srslte_pucch_nr_t* q,
|
|||
|
||||
uint32_t u = 0;
|
||||
uint32_t v = 0;
|
||||
if (pucch_nr_group_sequence(carrier, cfg, &u, &v) < SRSLTE_SUCCESS) {
|
||||
if (srslte_pucch_nr_group_sequence(carrier, cfg, &u, &v) < SRSLTE_SUCCESS) {
|
||||
ERROR("Error getting group sequence\n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
@ -281,7 +290,11 @@ int srslte_pucch_nr_format0_measure(const srslte_pucch_nr_t* q,
|
|||
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);
|
||||
uint32_t alpha_idx = 0;
|
||||
if (srslte_pucch_nr_alpha_idx(carrier, cfg, slot, l, l_prime, resource->initial_cyclic_shift, m_cs, &alpha_idx) <
|
||||
SRSLTE_SUCCESS) {
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
@ -320,7 +333,7 @@ int srslte_pucch_nr_format0_measure(const srslte_pucch_nr_t* q,
|
|||
}
|
||||
|
||||
// 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)
|
||||
static 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) {
|
||||
|
@ -337,7 +350,7 @@ uint32_t pucch_nr_format1_n_pucch(const srslte_pucch_nr_resource_format1_t* reso
|
|||
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)
|
||||
cf_t srslte_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");
|
||||
|
@ -356,14 +369,14 @@ static cf_t pucch_nr_format1_w(const srslte_pucch_nr_t* q, uint32_t n_pucch, uin
|
|||
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)
|
||||
int srslte_pucch_nr_format1_encode(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,
|
||||
const srslte_pucch_nr_resource_format1_t* resource,
|
||||
uint8_t* b,
|
||||
uint32_t nof_bits,
|
||||
cf_t* slot_symbols)
|
||||
{
|
||||
uint32_t m_cs = 0;
|
||||
|
||||
|
@ -392,7 +405,7 @@ int srslte_pucch_nr_put_format1(srslte_pucch_nr_t* q,
|
|||
// Get group sequence
|
||||
uint32_t u = 0;
|
||||
uint32_t v = 0;
|
||||
if (pucch_nr_group_sequence(carrier, cfg, &u, &v) < SRSLTE_SUCCESS) {
|
||||
if (srslte_pucch_nr_group_sequence(carrier, cfg, &u, &v) < SRSLTE_SUCCESS) {
|
||||
ERROR("Error getting group sequence\n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
@ -406,7 +419,11 @@ int srslte_pucch_nr_put_format1(srslte_pucch_nr_t* q,
|
|||
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);
|
||||
uint32_t alpha_idx = 0;
|
||||
if (srslte_pucch_nr_alpha_idx(carrier, cfg, slot, l, l_prime, resource->initial_cyclic_shift, m_cs, &alpha_idx) <
|
||||
SRSLTE_SUCCESS) {
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
@ -420,7 +437,7 @@ int srslte_pucch_nr_put_format1(srslte_pucch_nr_t* q,
|
|||
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);
|
||||
cf_t w_i_m = srslte_pucch_nr_format1_w(q, n_pucch, resource->time_domain_occ, m);
|
||||
|
||||
// Compute z(n) = w(i) * y(n)
|
||||
cf_t z[SRSLTE_NRE];
|
||||
|
@ -430,5 +447,91 @@ int srslte_pucch_nr_put_format1(srslte_pucch_nr_t* q,
|
|||
srslte_vec_cf_copy(slot_symbols_ptr, z, SRSLTE_NRE);
|
||||
}
|
||||
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
int srslte_pucch_nr_format1_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_format1_t* resource,
|
||||
srslte_chest_ul_res_t* chest_res,
|
||||
cf_t* slot_symbols,
|
||||
uint8_t b[SRSLTE_PUCCH_NR_FORMAT1_MAX_NOF_BITS],
|
||||
uint32_t nof_bits)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
// Received symbol d
|
||||
cf_t d = 0;
|
||||
|
||||
// Get group sequence
|
||||
uint32_t u = 0;
|
||||
uint32_t v = 0;
|
||||
if (srslte_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];
|
||||
cf_t* ce_ptr = &chest_res->ce[(carrier->nof_prb * (l + l_prime) + resource->starting_prb) * SRSLTE_NRE];
|
||||
|
||||
// Equalise x = w(i) * d' * r_uv(n)
|
||||
cf_t x[SRSLTE_NRE];
|
||||
srslte_predecoding_single(slot_symbols_ptr, ce_ptr, x, NULL, SRSLTE_NRE, 1.0f, chest_res->noise_estimate);
|
||||
|
||||
// Get Alpha index
|
||||
uint32_t alpha_idx = 0;
|
||||
if (srslte_pucch_nr_alpha_idx(carrier, cfg, slot, l, l_prime, resource->initial_cyclic_shift, m_cs, &alpha_idx) <
|
||||
SRSLTE_SUCCESS) {
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
// 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 w_i_m
|
||||
cf_t w_i_m = srslte_pucch_nr_format1_w(q, n_pucch, resource->time_domain_occ, m);
|
||||
|
||||
// Compute z(n) = w(i) * r_uv(n)
|
||||
cf_t z[SRSLTE_NRE];
|
||||
srslte_vec_sc_prod_ccc(r_uv, w_i_m, z, SRSLTE_NRE);
|
||||
|
||||
// Compute d = sum(x * conj(w(i) * r_uv(n))) = sum(w(i) * d' * r_uv(n) * conj(w(i) * r_uv(n))) = d'
|
||||
d += srslte_vec_dot_prod_conj_ccc(x, z, SRSLTE_NRE);
|
||||
}
|
||||
|
||||
// Demodulate d
|
||||
float llr[SRSLTE_PUCCH_NR_FORMAT1_MAX_NOF_BITS];
|
||||
srslte_demod_soft_demodulate((nof_bits == 1) ? SRSLTE_MOD_BPSK : SRSLTE_MOD_QPSK, &d, llr, 1);
|
||||
|
||||
// Hard decision
|
||||
for (uint32_t i = 0; i < nof_bits; i++) {
|
||||
b[i] = llr[i] > 0.0f ? 1 : 0;
|
||||
}
|
||||
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
|
@ -11,6 +11,7 @@
|
|||
*/
|
||||
|
||||
#include "srslte/common/test_common.h"
|
||||
#include "srslte/phy/ch_estimation/dmrs_pucch.h"
|
||||
#include "srslte/phy/phch/pucch_nr.h"
|
||||
#include "srslte/phy/utils/debug.h"
|
||||
#include "srslte/phy/utils/vector.h"
|
||||
|
@ -47,7 +48,7 @@ static int test_pucch_format0(srslte_pucch_nr_t* pucch, const srslte_pucch_nr_co
|
|||
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) ==
|
||||
TESTASSERT(srslte_pucch_nr_format0_encode(pucch, &carrier, cfg, &slot, &resource, m_cs, slot_symbols) ==
|
||||
SRSLTE_SUCCESS);
|
||||
|
||||
// Measure PUCCH format 0 for all possible values of m_cs
|
||||
|
@ -77,6 +78,66 @@ static int test_pucch_format0(srslte_pucch_nr_t* pucch, const srslte_pucch_nr_co
|
|||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
static int test_pucch_format1(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_format1_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 = 4; resource.nof_symbols <= 14; 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.time_domain_occ = 0; resource.time_domain_occ <= 6; resource.time_domain_occ++) {
|
||||
for (resource.initial_cyclic_shift = 0; resource.initial_cyclic_shift <= 11;
|
||||
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++) {
|
||||
// Generate bits
|
||||
uint8_t b[SRSLTE_PUCCH_NR_FORMAT1_MAX_NOF_BITS] = {};
|
||||
for (uint32_t i = 0; i < nof_bits; i++) {
|
||||
b[i] = (word >> i) & 1U;
|
||||
}
|
||||
|
||||
// Encode PUCCH
|
||||
TESTASSERT(srslte_pucch_nr_format1_encode(
|
||||
pucch, &carrier, cfg, &slot, &resource, b, nof_bits, 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);
|
||||
|
||||
// Decode PUCCH
|
||||
uint8_t b_rx[SRSLTE_PUCCH_NR_FORMAT1_MAX_NOF_BITS];
|
||||
TESTASSERT(srslte_pucch_nr_format1_decode(
|
||||
pucch, &carrier, cfg, &slot, &resource, chest_res, slot_symbols, b_rx, nof_bits) ==
|
||||
SRSLTE_SUCCESS);
|
||||
|
||||
// Check received bits
|
||||
for (uint32_t i = 0; i < nof_bits; i++) {
|
||||
TESTASSERT(b[i] == b_rx[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
static void usage(char* prog)
|
||||
{
|
||||
printf("Usage: %s [csNnv]\n", prog);
|
||||
|
@ -111,9 +172,10 @@ 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 = {};
|
||||
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 = {};
|
||||
srslte_chest_ul_res_t chest_res = {};
|
||||
|
||||
if (slot_symb == NULL) {
|
||||
ERROR("Alloc\n");
|
||||
|
@ -125,12 +187,25 @@ int main(int argc, char** argv)
|
|||
goto clean_exit;
|
||||
}
|
||||
|
||||
if (srslte_chest_ul_res_init(&chest_res, carrier.nof_prb)) {
|
||||
ERROR("Chest UL\n");
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
ret = SRSLTE_SUCCESS;
|
||||
clean_exit:
|
||||
if (slot_symb) {
|
||||
|
@ -138,6 +213,7 @@ clean_exit:
|
|||
}
|
||||
|
||||
srslte_pucch_nr_free(&pucch);
|
||||
srslte_chest_ul_res_free(&chest_res);
|
||||
|
||||
if (ret == SRSLTE_SUCCESS) {
|
||||
printf("Test passed!\n");
|
||||
|
|
Loading…
Reference in New Issue