|
|
@ -11,6 +11,7 @@
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#include "srslte/phy/ch_estimation/dmrs_pucch.h"
|
|
|
|
#include "srslte/phy/ch_estimation/dmrs_pucch.h"
|
|
|
|
|
|
|
|
#include "srslte/phy/common/sequence.h"
|
|
|
|
#include "srslte/phy/utils/debug.h"
|
|
|
|
#include "srslte/phy/utils/debug.h"
|
|
|
|
#include "srslte/phy/utils/vector.h"
|
|
|
|
#include "srslte/phy/utils/vector.h"
|
|
|
|
|
|
|
|
|
|
|
@ -160,7 +161,8 @@ int srslte_dmrs_pucch_format1_estimate(const srslte_pucch_nr_t* q,
|
|
|
|
srslte_chest_ul_res_t* res)
|
|
|
|
srslte_chest_ul_res_t* res)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
if (q == NULL || carrier == NULL || cfg == NULL || slot == NULL || resource == NULL || slot_symbols == NULL) {
|
|
|
|
if (q == NULL || carrier == NULL || cfg == NULL || slot == NULL || resource == NULL || slot_symbols == NULL ||
|
|
|
|
|
|
|
|
res == NULL) {
|
|
|
|
return SRSLTE_ERROR_INVALID_INPUTS;
|
|
|
|
return SRSLTE_ERROR_INVALID_INPUTS;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -223,7 +225,7 @@ int srslte_dmrs_pucch_format1_estimate(const srslte_pucch_nr_t* q,
|
|
|
|
float epre = 0.0f;
|
|
|
|
float epre = 0.0f;
|
|
|
|
float ta_err = 0.0f;
|
|
|
|
float ta_err = 0.0f;
|
|
|
|
for (uint32_t m = 0; m < n_pucch; m++) {
|
|
|
|
for (uint32_t m = 0; m < n_pucch; m++) {
|
|
|
|
cf_t corr = srslte_vec_acc_cc(ce[m], SRSLTE_NRE);
|
|
|
|
cf_t corr = srslte_vec_acc_cc(ce[m], SRSLTE_NRE) / SRSLTE_NRE;
|
|
|
|
rsrp += __real__ corr * __real__ corr + __imag__ corr * __imag__ corr;
|
|
|
|
rsrp += __real__ corr * __real__ corr + __imag__ corr * __imag__ corr;
|
|
|
|
epre += srslte_vec_avg_power_cf(ce[m], SRSLTE_NRE);
|
|
|
|
epre += srslte_vec_avg_power_cf(ce[m], SRSLTE_NRE);
|
|
|
|
ta_err += srslte_vec_estimate_frequency(ce[m], SRSLTE_NRE);
|
|
|
|
ta_err += srslte_vec_estimate_frequency(ce[m], SRSLTE_NRE);
|
|
|
@ -236,10 +238,14 @@ int srslte_dmrs_pucch_format1_estimate(const srslte_pucch_nr_t* q,
|
|
|
|
|
|
|
|
|
|
|
|
// Set power measures
|
|
|
|
// Set power measures
|
|
|
|
rsrp = SRSLTE_MIN(rsrp, epre);
|
|
|
|
rsrp = SRSLTE_MIN(rsrp, epre);
|
|
|
|
|
|
|
|
res->rsrp = rsrp;
|
|
|
|
|
|
|
|
res->rsrp_dBfs = srslte_convert_power_to_dB(rsrp);
|
|
|
|
|
|
|
|
res->epre = epre;
|
|
|
|
|
|
|
|
res->epre_dBfs = srslte_convert_power_to_dB(epre);
|
|
|
|
res->noise_estimate = epre - rsrp;
|
|
|
|
res->noise_estimate = epre - rsrp;
|
|
|
|
res->noise_estimate_dbm = srslte_convert_power_to_dB(res->noise_estimate);
|
|
|
|
res->noise_estimate_dbm = srslte_convert_power_to_dB(res->noise_estimate);
|
|
|
|
res->snr = rsrp / res->noise_estimate;
|
|
|
|
res->snr = rsrp / res->noise_estimate;
|
|
|
|
res->snr_db = srslte_convert_power_to_dB(res->snr_db);
|
|
|
|
res->snr_db = srslte_convert_power_to_dB(res->snr);
|
|
|
|
|
|
|
|
|
|
|
|
// Compute Time Aligment error in microseconds
|
|
|
|
// Compute Time Aligment error in microseconds
|
|
|
|
if (isnormal(ta_err)) {
|
|
|
|
if (isnormal(ta_err)) {
|
|
|
@ -280,6 +286,152 @@ int srslte_dmrs_pucch_format1_estimate(const srslte_pucch_nr_t* q,
|
|
|
|
return SRSLTE_SUCCESS;
|
|
|
|
return SRSLTE_SUCCESS;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static uint32_t dmrs_pucch_format2_cinit(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 n = SRSLTE_SLOT_NR_MOD(slot->idx, carrier->numerology);
|
|
|
|
|
|
|
|
uint32_t n_id = (cfg->scrambling_id_present) ? cfg->scambling_id : carrier->id;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return SRSLTE_SEQUENCE_MOD((((SRSLTE_NSYMB_PER_SLOT_NR * n + l + 1U) * (2U * n_id + 1U)) << 17U) + 2U * n_id);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int srslte_dmrs_pucch_format2_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_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_cfg_resource_valid(resource) < SRSLTE_SUCCESS) {
|
|
|
|
|
|
|
|
ERROR("Invalid PUCCH format 1 resource\n");
|
|
|
|
|
|
|
|
return SRSLTE_ERROR;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 + 1;
|
|
|
|
|
|
|
|
uint32_t k_end = SRSLTE_MIN(carrier->nof_prb, resource->starting_prb + resource->nof_prb) * SRSLTE_NRE;
|
|
|
|
|
|
|
|
for (uint32_t l = l_start; l < l_end; l++) {
|
|
|
|
|
|
|
|
// Compute sequence initial state
|
|
|
|
|
|
|
|
uint32_t cinit = dmrs_pucch_format2_cinit(carrier, cfg, slot, l);
|
|
|
|
|
|
|
|
srslte_sequence_state_t sequence = {};
|
|
|
|
|
|
|
|
srslte_sequence_state_init(&sequence, cinit);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Skip PRBs to start
|
|
|
|
|
|
|
|
srslte_sequence_state_advance(&sequence, 2 * 4 * resource->starting_prb);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Generate sequence
|
|
|
|
|
|
|
|
cf_t r_l[SRSLTE_PUCCH_NR_FORMAT2_MAX_NPRB * 4];
|
|
|
|
|
|
|
|
srslte_sequence_state_gen_f(&sequence, M_SQRT1_2, (float*)r_l, 2 * 4 * resource->nof_prb);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Put sequence in k = 3 * m + 1
|
|
|
|
|
|
|
|
for (uint32_t k = k_start, i = 0; k < k_end; k += 3, i++) {
|
|
|
|
|
|
|
|
slot_symbols[l * carrier->nof_prb * SRSLTE_NRE + k] = r_l[i];
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return SRSLTE_SUCCESS;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int srslte_dmrs_pucch_format2_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_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 ||
|
|
|
|
|
|
|
|
res == NULL) {
|
|
|
|
|
|
|
|
return SRSLTE_ERROR_INVALID_INPUTS;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (srslte_pucch_nr_cfg_resource_valid(resource) < SRSLTE_SUCCESS) {
|
|
|
|
|
|
|
|
ERROR("Invalid PUCCH format 1 resource\n");
|
|
|
|
|
|
|
|
return SRSLTE_ERROR;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
cf_t ce[SRSLTE_PUCCH_NR_FORMAT2_MAX_NSYMB][SRSLTE_PUCCH_NR_FORMAT2_MAX_NPRB * 4];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 + 1;
|
|
|
|
|
|
|
|
uint32_t k_end = SRSLTE_MIN(carrier->nof_prb, resource->starting_prb + resource->nof_prb) * SRSLTE_NRE;
|
|
|
|
|
|
|
|
uint32_t nof_ref = 4 * resource->nof_prb;
|
|
|
|
|
|
|
|
for (uint32_t l = l_start, j = 0; l < l_end; l++, j++) {
|
|
|
|
|
|
|
|
// Compute sequence initial state
|
|
|
|
|
|
|
|
uint32_t cinit = dmrs_pucch_format2_cinit(carrier, cfg, slot, l);
|
|
|
|
|
|
|
|
srslte_sequence_state_t sequence = {};
|
|
|
|
|
|
|
|
srslte_sequence_state_init(&sequence, cinit);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Skip PRBs to start
|
|
|
|
|
|
|
|
srslte_sequence_state_advance(&sequence, 2 * 4 * resource->starting_prb);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Generate sequence
|
|
|
|
|
|
|
|
cf_t r_l[SRSLTE_PUCCH_NR_FORMAT2_MAX_NPRB * 4];
|
|
|
|
|
|
|
|
srslte_sequence_state_gen_f(&sequence, M_SQRT1_2, (float*)r_l, 2 * nof_ref);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Put sequence in k = 3 * m + 1
|
|
|
|
|
|
|
|
for (uint32_t k = k_start, i = 0; k < k_end; k += 3, i++) {
|
|
|
|
|
|
|
|
ce[j][i] = slot_symbols[l * carrier->nof_prb * SRSLTE_NRE + k];
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
srslte_vec_prod_conj_ccc(ce[j], r_l, ce[j], nof_ref);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Perform measurements
|
|
|
|
|
|
|
|
float epre = 0.0f;
|
|
|
|
|
|
|
|
float rsrp = 0.0f;
|
|
|
|
|
|
|
|
float ta_err = 0.0f;
|
|
|
|
|
|
|
|
for (uint32_t i = 0; i < resource->nof_symbols; i++) {
|
|
|
|
|
|
|
|
cf_t corr = srslte_vec_acc_cc(ce[i], nof_ref) / nof_ref;
|
|
|
|
|
|
|
|
rsrp += __real__ corr * __real__ corr + __imag__ corr * __imag__ corr;
|
|
|
|
|
|
|
|
epre += srslte_vec_avg_power_cf(ce[i], nof_ref);
|
|
|
|
|
|
|
|
ta_err += srslte_vec_estimate_frequency(ce[i], nof_ref);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
epre /= resource->nof_symbols;
|
|
|
|
|
|
|
|
rsrp /= resource->nof_symbols;
|
|
|
|
|
|
|
|
ta_err /= resource->nof_symbols;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Set power measures
|
|
|
|
|
|
|
|
rsrp = SRSLTE_MIN(rsrp, epre);
|
|
|
|
|
|
|
|
res->rsrp = rsrp;
|
|
|
|
|
|
|
|
res->rsrp_dBfs = srslte_convert_power_to_dB(rsrp);
|
|
|
|
|
|
|
|
res->epre = epre;
|
|
|
|
|
|
|
|
res->epre_dBfs = srslte_convert_power_to_dB(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);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Compute Time Aligment error in microseconds
|
|
|
|
|
|
|
|
if (isnormal(ta_err)) {
|
|
|
|
|
|
|
|
ta_err /= 15e3f * (float)(1U << carrier->numerology) * 3; // 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;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Perform averaging
|
|
|
|
|
|
|
|
// ...
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Zero order hold
|
|
|
|
|
|
|
|
for (uint32_t l = l_start, j = 0; l < l_end; l++, j++) {
|
|
|
|
|
|
|
|
for (uint32_t k = k_start - 1, i = 0; k < k_end; k++, i++) {
|
|
|
|
|
|
|
|
res->ce[l * carrier->nof_prb * SRSLTE_NRE + k] = ce[j][i / 3];
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return SRSLTE_SUCCESS;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int srslte_dmrs_pucch_format_3_4_get_symbol_idx(const srslte_pucch_nr_resource_t* resource,
|
|
|
|
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])
|
|
|
|
uint32_t idx[SRSLTE_DMRS_PUCCH_FORMAT_3_4_MAX_NSYMB])
|
|
|
|
{
|
|
|
|
{
|
|
|
|