Initial Sounding Reference Signals implementation

master
Xavier Arteaga 4 years ago committed by Xavier Arteaga
parent 857c4de420
commit 039f2164a6

@ -63,6 +63,9 @@ typedef struct {
srslte_refsignal_ul_dmrs_pregen_t dmrs_pregen;
bool dmrs_signal_configured;
srslte_refsignal_srs_pregen_t srs_pregen;
bool srs_signal_configured;
cf_t* pilot_estimates;
cf_t* pilot_estimates_tmp[4];
cf_t* pilot_recv_signal;
@ -92,7 +95,9 @@ SRSLTE_API void srslte_chest_ul_res_free(srslte_chest_ul_res_t* q);
SRSLTE_API int srslte_chest_ul_set_cell(srslte_chest_ul_t* q, srslte_cell_t cell);
SRSLTE_API void srslte_chest_ul_pregen(srslte_chest_ul_t* q, srslte_refsignal_dmrs_pusch_cfg_t* cfg);
SRSLTE_API void srslte_chest_ul_pregen(srslte_chest_ul_t* q,
srslte_refsignal_dmrs_pusch_cfg_t* cfg,
srslte_refsignal_srs_cfg_t* srs_cfg);
SRSLTE_API int srslte_chest_ul_estimate_pusch(srslte_chest_ul_t* q,
srslte_ul_sf_cfg_t* sf,
@ -106,4 +111,11 @@ SRSLTE_API int srslte_chest_ul_estimate_pucch(srslte_chest_ul_t* q,
cf_t* input,
srslte_chest_ul_res_t* res);
SRSLTE_API int srslte_chest_ul_estimate_srs(srslte_chest_ul_t* q,
srslte_ul_sf_cfg_t* sf,
srslte_refsignal_srs_cfg_t* cfg,
srslte_refsignal_dmrs_pusch_cfg_t* pusch_cfg,
cf_t* input,
srslte_chest_ul_res_t* res);
#endif // SRSLTE_CHEST_UL_H

@ -86,6 +86,7 @@ typedef struct SRSLTE_API {
} srslte_refsignal_ul_t;
typedef struct {
uint32_t max_prb;
cf_t** r[SRSLTE_NOF_CSHIFT][SRSLTE_NOF_SF_X_FRAME];
} srslte_refsignal_ul_dmrs_pregen_t;
@ -173,6 +174,12 @@ SRSLTE_API int srslte_refsignal_srs_put(srslte_refsignal_ul_t* q,
cf_t* r_srs,
cf_t* sf_symbols);
SRSLTE_API int srslte_refsignal_srs_get(srslte_refsignal_ul_t* q,
srslte_refsignal_srs_cfg_t* cfg,
uint32_t tti,
cf_t* r_srs,
cf_t* sf_symbols);
SRSLTE_API void srslte_refsignal_srs_pusch_shortened(srslte_refsignal_ul_t* q,
srslte_ul_sf_cfg_t* sf,
srslte_refsignal_srs_cfg_t* srs_cfg,

@ -67,8 +67,10 @@ SRSLTE_API int srslte_enb_ul_init(srslte_enb_ul_t* q, cf_t* in_buffer, uint32_t
SRSLTE_API void srslte_enb_ul_free(srslte_enb_ul_t* q);
SRSLTE_API int
srslte_enb_ul_set_cell(srslte_enb_ul_t* q, srslte_cell_t cell, srslte_refsignal_dmrs_pusch_cfg_t* pusch_cfg);
SRSLTE_API int srslte_enb_ul_set_cell(srslte_enb_ul_t* q,
srslte_cell_t cell,
srslte_refsignal_dmrs_pusch_cfg_t* pusch_cfg,
srslte_refsignal_srs_cfg_t* srs_cfg);
SRSLTE_API int srslte_enb_ul_add_rnti(srslte_enb_ul_t* q, uint16_t rnti);

@ -189,18 +189,25 @@ int srslte_chest_ul_set_cell(srslte_chest_ul_t* q, srslte_cell_t cell)
return ret;
}
void srslte_chest_ul_pregen(srslte_chest_ul_t* q, srslte_refsignal_dmrs_pusch_cfg_t* cfg)
void srslte_chest_ul_pregen(srslte_chest_ul_t* q,
srslte_refsignal_dmrs_pusch_cfg_t* cfg,
srslte_refsignal_srs_cfg_t* srs_cfg)
{
srslte_refsignal_dmrs_pusch_pregen(&q->dmrs_signal, &q->dmrs_pregen, cfg);
q->dmrs_signal_configured = true;
if (srs_cfg) {
srslte_refsignal_srs_pregen(&q->dmrs_signal, &q->srs_pregen, srs_cfg, cfg);
q->srs_signal_configured = true;
}
}
/* Uses the difference between the averaged and non-averaged pilot estimates */
static float estimate_noise_pilots(srslte_chest_ul_t* q, cf_t* ce, uint32_t nrefs, uint32_t n_prb[2])
static float estimate_noise_pilots(srslte_chest_ul_t* q, cf_t* ce, uint32_t nslots, uint32_t nrefs, uint32_t n_prb[2])
{
float power = 0;
for (int i = 0; i < 2; i++) {
for (int i = 0; i < nslots; i++) {
power += srslte_chest_estimate_noise_pilots(
&q->pilot_estimates[i * nrefs],
&ce[SRSLTE_REFSIGNAL_UL_L(i, q->cell.cp) * q->cell.nof_prb * SRSLTE_NRE + n_prb[i] * SRSLTE_NRE],
@ -208,7 +215,7 @@ static float estimate_noise_pilots(srslte_chest_ul_t* q, cf_t* ce, uint32_t nref
nrefs);
}
power /= 2;
power /= nslots;
if (q->smooth_filter_len == 3) {
// Calibrated for filter length 3
@ -222,7 +229,7 @@ static float estimate_noise_pilots(srslte_chest_ul_t* q, cf_t* ce, uint32_t nref
// The interpolator currently only supports same frequency allocation for each subframe
#define cesymb(i) ce[SRSLTE_RE_IDX(q->cell.nof_prb, i, n_prb[0] * SRSLTE_NRE)]
static void interpolate_pilots(srslte_chest_ul_t* q, cf_t* ce, uint32_t nrefs, uint32_t n_prb[2])
static void interpolate_pilots(srslte_chest_ul_t* q, cf_t* ce, uint32_t nslots, uint32_t nrefs, uint32_t n_prb[2])
{
#ifdef DO_LINEAR_INTERPOLATION
uint32_t L1 = SRSLTE_REFSIGNAL_UL_L(0, q->cell.cp);
@ -245,25 +252,26 @@ static void interpolate_pilots(srslte_chest_ul_t* q, cf_t* ce, uint32_t nrefs, u
nrefs);
#else
// Instead of a linear interpolation, we just copy the estimates to all symbols in that subframe
for (int s = 0; s < 2; s++) {
for (int s = 0; s < nslots; s++) {
for (int i = 0; i < SRSLTE_CP_NSYMB(q->cell.cp); i++) {
int src_symb = SRSLTE_REFSIGNAL_UL_L(s, q->cell.cp);
int dst_symb = i + s * SRSLTE_CP_NSYMB(q->cell.cp);
// skip the symbol with the estimates
if (dst_symb != src_symb) {
memcpy(&ce[(dst_symb * q->cell.nof_prb + n_prb[s]) * SRSLTE_NRE],
&ce[(src_symb * q->cell.nof_prb + n_prb[s]) * SRSLTE_NRE],
nrefs * sizeof(cf_t));
srslte_vec_cf_copy(&ce[(dst_symb * q->cell.nof_prb + n_prb[s]) * SRSLTE_NRE],
&ce[(src_symb * q->cell.nof_prb + n_prb[s]) * SRSLTE_NRE],
nrefs);
}
}
}
#endif
}
static void average_pilots(srslte_chest_ul_t* q, cf_t* input, cf_t* ce, uint32_t nrefs, uint32_t n_prb[2])
static void
average_pilots(srslte_chest_ul_t* q, cf_t* input, cf_t* ce, uint32_t nslots, uint32_t nrefs, uint32_t n_prb[2])
{
for (int i = 0; i < 2; i++) {
for (uint32_t i = 0; i < nslots; i++) {
srslte_chest_average_pilots(
&input[i * nrefs],
&ce[SRSLTE_REFSIGNAL_UL_L(i, q->cell.cp) * q->cell.nof_prb * SRSLTE_NRE + n_prb[i] * SRSLTE_NRE],
@ -274,81 +282,117 @@ static void average_pilots(srslte_chest_ul_t* q, cf_t* input, cf_t* ce, uint32_t
}
}
int srslte_chest_ul_estimate_pusch(srslte_chest_ul_t* q,
srslte_ul_sf_cfg_t* sf,
srslte_pusch_cfg_t* cfg,
cf_t* input,
srslte_chest_ul_res_t* res)
/**
* Generic PUSCH and DMRS channel estimation. It assumes q->pilot_estimates has been populated with the Least Square
* Estimates
*
* @param q Uplink Channel estimation instance
* @param nslots number of slots (2 for DMRS, 1 for SRS)
* @param nrefs_sym number of reference resource elements per symbols (depends on configuration)
* @param stride sub-carrier distance between reference signal resource elements (1 for DMRS, 2 for SRS)
* @param meas_ta_en enables or disables the Time Alignment error measurement
* @param write_estimates Write channel estimation in res, (true for DMRS and false for SRS)
* @param n_prb Resource block start for the grant, set to zero for Sounding Reference Signals
* @param res UL channel estimation result
*/
static void chest_ul_estimate(srslte_chest_ul_t* q,
uint32_t nslots,
uint32_t nrefs_sym,
uint32_t stride,
bool meas_ta_en,
bool write_estimates,
uint32_t n_prb[SRSLTE_NOF_SLOTS_PER_SF],
srslte_chest_ul_res_t* res)
{
if (!q->dmrs_signal_configured) {
ERROR("Error must call srslte_chest_ul_set_cfg() before using the UL estimator\n");
return SRSLTE_ERROR;
}
uint32_t nof_prb = cfg->grant.L_prb;
if (!srslte_dft_precoding_valid_prb(nof_prb)) {
ERROR("Error invalid nof_prb=%d\n", nof_prb);
return SRSLTE_ERROR_INVALID_INPUTS;
}
int nrefs_sym = nof_prb * SRSLTE_NRE;
int nrefs_sf = nrefs_sym * SRSLTE_NOF_SLOTS_PER_SF;
/* Get references from the input signal */
srslte_refsignal_dmrs_pusch_get(&q->dmrs_signal, cfg, input, q->pilot_recv_signal);
/* Use the known DMRS signal to compute Least-squares estimates */
srslte_vec_prod_conj_ccc(
q->pilot_recv_signal, q->dmrs_pregen.r[cfg->grant.n_dmrs][sf->tti % 10][nof_prb], q->pilot_estimates, nrefs_sf);
// Calculate time alignment error
float ta_err = 0.0f;
if (cfg->meas_ta_en) {
for (int i = 0; i < SRSLTE_NOF_SLOTS_PER_SF; i++) {
ta_err += srslte_vec_estimate_frequency(&q->pilot_estimates[i * nrefs_sym], nrefs_sym) / SRSLTE_NOF_SLOTS_PER_SF;
if (meas_ta_en) {
for (int i = 0; i < nslots; i++) {
ta_err += srslte_vec_estimate_frequency(&q->pilot_estimates[i * nrefs_sym], nrefs_sym) / nslots;
}
}
// Average and store time aligment error
if (isnormal(ta_err)) {
res->ta_us = roundf(ta_err / 15e-3 * 10) / 10;
res->ta_us = roundf(ta_err / 15e-2f) / (10.0f * (float)stride);
} else {
res->ta_us = 0.0f;
}
if (cfg->grant.n_prb[0] != cfg->grant.n_prb[1]) {
printf("ERROR: intra-subframe frequency hopping not supported in the estimator!!\n");
// Check if intra-subframe frequency hopping is enabled
if (n_prb[0] != n_prb[1]) {
ERROR("ERROR: intra-subframe frequency hopping not supported in the estimator!!\n");
}
if (res->ce != NULL) {
if (q->smooth_filter_len > 0) {
average_pilots(q, q->pilot_estimates, res->ce, nrefs_sym, cfg->grant.n_prb);
interpolate_pilots(q, res->ce, nrefs_sym, cfg->grant.n_prb);
average_pilots(q, q->pilot_estimates, res->ce, nslots, nrefs_sym, n_prb);
/* If averaging, compute noise from difference between received and averaged estimates */
res->noise_estimate = estimate_noise_pilots(q, res->ce, nrefs_sym, cfg->grant.n_prb);
if (write_estimates) {
interpolate_pilots(q, res->ce, nslots, nrefs_sym, n_prb);
}
// If averaging, compute noise from difference between received and averaged estimates
res->noise_estimate = estimate_noise_pilots(q, res->ce, nslots, nrefs_sym, n_prb);
} else {
// Copy estimates to CE vector without averaging
for (int i = 0; i < 2; i++) {
memcpy(&res->ce[SRSLTE_REFSIGNAL_UL_L(i, q->cell.cp) * q->cell.nof_prb * SRSLTE_NRE +
cfg->grant.n_prb[i] * SRSLTE_NRE],
&q->pilot_estimates[i * nrefs_sym],
nrefs_sym * sizeof(cf_t));
for (int i = 0; i < nslots; i++) {
srslte_vec_cf_copy(
&res->ce[SRSLTE_REFSIGNAL_UL_L(i, q->cell.cp) * q->cell.nof_prb * SRSLTE_NRE + n_prb[i] * SRSLTE_NRE],
&q->pilot_estimates[i * nrefs_sym],
nrefs_sym);
}
if (write_estimates) {
interpolate_pilots(q, res->ce, nslots, nrefs_sym, n_prb);
}
interpolate_pilots(q, res->ce, nrefs_sym, cfg->grant.n_prb);
res->noise_estimate = 0;
}
}
// Estimate received pilot power
if (res->noise_estimate) {
res->snr = srslte_vec_avg_power_cf(q->pilot_recv_signal, nrefs_sf) / res->noise_estimate;
if (isnormal(res->noise_estimate)) {
res->snr = srslte_vec_avg_power_cf(q->pilot_recv_signal, nslots * nrefs_sym) / res->noise_estimate;
} else {
res->snr = NAN;
}
// Convert measurements in logarithm scale
res->snr_db = srslte_convert_power_to_dB(res->snr);
res->noise_estimate_dbm = srslte_convert_power_to_dBm(res->noise_estimate);
}
int srslte_chest_ul_estimate_pusch(srslte_chest_ul_t* q,
srslte_ul_sf_cfg_t* sf,
srslte_pusch_cfg_t* cfg,
cf_t* input,
srslte_chest_ul_res_t* res)
{
if (!q->dmrs_signal_configured) {
ERROR("Error must call srslte_chest_ul_set_cfg() before using the UL estimator\n");
return SRSLTE_ERROR;
}
uint32_t nof_prb = cfg->grant.L_prb;
if (!srslte_dft_precoding_valid_prb(nof_prb)) {
ERROR("Error invalid nof_prb=%d\n", nof_prb);
return SRSLTE_ERROR_INVALID_INPUTS;
}
int nrefs_sym = nof_prb * SRSLTE_NRE;
int nrefs_sf = nrefs_sym * SRSLTE_NOF_SLOTS_PER_SF;
/* Get references from the input signal */
srslte_refsignal_dmrs_pusch_get(&q->dmrs_signal, cfg, input, q->pilot_recv_signal);
// Use the known DMRS signal to compute Least-squares estimates
srslte_vec_prod_conj_ccc(q->pilot_recv_signal,
q->dmrs_pregen.r[cfg->grant.n_dmrs][sf->tti % SRSLTE_NOF_SF_X_FRAME][nof_prb],
q->pilot_estimates,
nrefs_sf);
// Estimate
chest_ul_estimate(q, SRSLTE_NOF_SLOTS_PER_SF, nrefs_sym, 1, cfg->meas_ta_en, true, cfg->grant.n_prb, res);
return 0;
}
@ -444,3 +488,40 @@ int srslte_chest_ul_estimate_pucch(srslte_chest_ul_t* q,
return 0;
}
int srslte_chest_ul_estimate_srs(srslte_chest_ul_t* q,
srslte_ul_sf_cfg_t* sf,
srslte_refsignal_srs_cfg_t* cfg,
srslte_refsignal_dmrs_pusch_cfg_t* pusch_cfg,
cf_t* input,
srslte_chest_ul_res_t* res)
{
if (q == NULL || sf == NULL || cfg == NULL || pusch_cfg == NULL || input == NULL || res == NULL) {
return SRSLTE_ERROR_INVALID_INPUTS;
}
// Extract parameters
uint32_t n_srs_re = srslte_refsignal_srs_M_sc(&q->dmrs_signal, cfg);
// Extract Sounding Reference Signal
if (srslte_refsignal_srs_get(&q->dmrs_signal, cfg, sf->tti, q->pilot_recv_signal, input) != SRSLTE_SUCCESS) {
return SRSLTE_ERROR;
}
// Get Known pilots
cf_t* known_pilots = q->pilot_known_signal;
if (q->srs_signal_configured) {
known_pilots = q->srs_pregen.r[sf->tti % SRSLTE_NOF_SF_X_FRAME];
} else {
srslte_refsignal_srs_gen(&q->dmrs_signal, cfg, pusch_cfg, sf->tti % SRSLTE_NOF_SF_X_FRAME, known_pilots);
}
// Compute least squares estimates
srslte_vec_prod_conj_ccc(q->pilot_recv_signal, known_pilots, q->pilot_estimates, n_srs_re);
// Estimate
uint32_t n_prb[2] = {};
chest_ul_estimate(q, 1, n_srs_re, 1, true, false, n_prb, res);
return SRSLTE_SUCCESS;
}

@ -33,7 +33,6 @@
#include "srslte/phy/utils/debug.h"
#include "srslte/phy/utils/vector.h"
// n_dmrs_2 table 5.5.2.1.1-1 from 36.211
uint32_t n_dmrs_2[8] = {0, 6, 3, 4, 2, 8, 10, 9};
@ -354,6 +353,8 @@ static void compute_r(srslte_refsignal_ul_t* q,
int srslte_refsignal_dmrs_pusch_pregen_init(srslte_refsignal_ul_dmrs_pregen_t* pregen, uint32_t max_prb)
{
pregen->max_prb = max_prb;
for (uint32_t sf_idx = 0; sf_idx < SRSLTE_NOF_SF_X_FRAME; sf_idx++) {
for (uint32_t cs = 0; cs < SRSLTE_NOF_CSHIFT; cs++) {
pregen->r[cs][sf_idx] = (cf_t**)calloc(sizeof(cf_t*), max_prb + 1);
@ -405,11 +406,9 @@ void srslte_refsignal_dmrs_pusch_pregen_free(srslte_refsignal_ul_t* q, srslte_re
for (uint32_t sf_idx = 0; sf_idx < SRSLTE_NOF_SF_X_FRAME; sf_idx++) {
for (uint32_t cs = 0; cs < SRSLTE_NOF_CSHIFT; cs++) {
if (pregen->r[cs][sf_idx]) {
for (uint32_t n = 0; n <= q->cell.nof_prb; n++) {
if (srslte_dft_precoding_valid_prb(n)) {
if (pregen->r[cs][sf_idx][n]) {
free(pregen->r[cs][sf_idx][n]);
}
for (uint32_t n = 0; n <= pregen->max_prb; n++) {
if (pregen->r[cs][sf_idx][n]) {
free(pregen->r[cs][sf_idx][n]);
}
}
free(pregen->r[cs][sf_idx]);
@ -1005,7 +1004,7 @@ int srslte_refsignal_srs_put(srslte_refsignal_ul_t* q,
cf_t* sf_symbols)
{
int ret = SRSLTE_ERROR_INVALID_INPUTS;
if (r_srs && q) {
if (r_srs && q && sf_symbols && cfg) {
uint32_t M_sc = srslte_refsignal_srs_M_sc(q, cfg);
uint32_t k0 = srs_k0_ue(cfg, q->cell.nof_prb, tti);
for (int i = 0; i < M_sc; i++) {
@ -1015,3 +1014,21 @@ int srslte_refsignal_srs_put(srslte_refsignal_ul_t* q,
}
return ret;
}
int srslte_refsignal_srs_get(srslte_refsignal_ul_t* q,
srslte_refsignal_srs_cfg_t* cfg,
uint32_t tti,
cf_t* r_srs,
cf_t* sf_symbols)
{
int ret = SRSLTE_ERROR_INVALID_INPUTS;
if (r_srs && q && sf_symbols && cfg) {
uint32_t M_sc = srslte_refsignal_srs_M_sc(q, cfg);
uint32_t k0 = srs_k0_ue(cfg, q->cell.nof_prb, tti);
for (int i = 0; i < M_sc; i++) {
r_srs[i] = sf_symbols[SRSLTE_RE_IDX(q->cell.nof_prb, 2 * SRSLTE_CP_NSYMB(q->cell.cp) - 1, k0 + 2 * i)];
}
ret = SRSLTE_SUCCESS;
}
return ret;
}

@ -46,7 +46,18 @@ target_link_libraries(refsignal_ul_test_all srslte_phy srslte_common)
add_test(chest_test_ul_cellid0 chest_test_ul -c 0 -r 50)
add_test(chest_test_ul_cellid1 chest_test_ul -c 1 -r 50)
add_test(chest_test_ul_cellid1 chest_test_ul -c 2 -r 50)
add_test(chest_test_ul_cellid1 chest_test_ul -c 2 -r 50)
########################################################################
# Uplink Sounding Reference Signals Channel Estimation TEST
########################################################################
add_executable(chest_test_srs chest_test_srs.c)
target_link_libraries(chest_test_srs srslte_phy srslte_common)
foreach (cell_n_prb 6 15 25 50 75 100)
add_test(chest_test_srs_${cell_n_prb} chest_test_srs -c 2 -r ${cell_n_prb})
endforeach(cell_n_prb 6 15 25 50 75 100)
########################################################################

@ -0,0 +1,246 @@
/*
* Copyright 2013-2020 Software Radio Systems Limited
*
* This file is part of srsLTE.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include "srslte/common/test_common.h"
#include "srslte/srslte.h"
#include <complex.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <unistd.h>
static srslte_cell_t cell = {6, // nof_prb
1, // nof_ports
1, // cell_id
SRSLTE_CP_NORM, // cyclic prefix
SRSLTE_PHICH_NORM,
SRSLTE_PHICH_R_1, // PHICH length
SRSLTE_FDD};
static srslte_refsignal_dmrs_pusch_cfg_t dmrs_pusch_cfg = {};
static srslte_refsignal_srs_cfg_t srs_cfg = {};
static uint32_t test_counter = 0;
static float snr_db = 10.0f;
static float n0_dbm = 30.0f - 20.0f;
static srslte_channel_awgn_t channel = {};
#define CHEST_TEST_SRS_SNR_DB_TOLERANCE 10.0f
void usage(char* prog)
{
printf("Usage: %s [recov]\n", prog);
printf("\t-r nof_prb [Default %d]\n", cell.nof_prb);
printf("\t-e extended cyclic prefix [Default normal]\n");
printf("\t-c cell_id [Default %d]\n", cell.id);
printf("\t-v increase verbosity\n");
}
typedef struct {
uint32_t sf_size;
srslte_refsignal_ul_t refsignal_ul;
srslte_refsignal_srs_pregen_t srs_pregen;
srslte_chest_ul_t chest_ul;
cf_t* sf_symbols;
srslte_chest_ul_res_t chest_ul_res;
} srs_test_context_t;
int srs_test_context_init(srs_test_context_t* q)
{
q->sf_size = SRSLTE_SF_LEN_RE(SRSLTE_MAX_PRB, cell.cp);
// Initiate UL ref signals
if (srslte_refsignal_ul_init(&q->refsignal_ul, SRSLTE_MAX_PRB) != SRSLTE_SUCCESS) {
return SRSLTE_ERROR;
}
// Set cell
if (srslte_refsignal_ul_set_cell(&q->refsignal_ul, cell) != SRSLTE_SUCCESS) {
return SRSLTE_ERROR;
}
// Pregenerate signals
if (srslte_refsignal_srs_pregen(&q->refsignal_ul, &q->srs_pregen, &srs_cfg, &dmrs_pusch_cfg) != SRSLTE_SUCCESS) {
return SRSLTE_ERROR;
}
// Allocate buffer
q->sf_symbols = srslte_vec_cf_malloc(q->sf_size);
if (q->sf_symbols == NULL) {
return SRSLTE_ERROR;
}
// Create UL channel estimator
if (srslte_chest_ul_init(&q->chest_ul, SRSLTE_MAX_PRB) != SRSLTE_SUCCESS) {
return SRSLTE_ERROR;
}
// Set cell in UL channel estimator
if (srslte_chest_ul_set_cell(&q->chest_ul, cell) != SRSLTE_SUCCESS) {
return SRSLTE_ERROR;
}
// Initialise UL channel estimator result
if (srslte_chest_ul_res_init(&q->chest_ul_res, SRSLTE_MAX_PRB) != SRSLTE_SUCCESS) {
return SRSLTE_ERROR;
}
return SRSLTE_SUCCESS;
}
void srs_test_context_free(srs_test_context_t* q)
{
srslte_refsignal_ul_free(&q->refsignal_ul);
srslte_refsignal_srs_pregen_free(&q->refsignal_ul, &q->srs_pregen);
srslte_chest_ul_free(&q->chest_ul);
srslte_chest_ul_res_free(&q->chest_ul_res);
if (q->sf_symbols) {
free(q->sf_symbols);
}
}
int srs_test_context_run(srs_test_context_t* q)
{
srslte_ul_sf_cfg_t ul_sf_cfg = {};
INFO(" TEST: bw_cfg=%d; sf_cfg=%d; B=%d; b_hops=%d; n_srs=%d; I_srs=%d;\n",
srs_cfg.bw_cfg,
srs_cfg.subframe_config,
srs_cfg.B,
srs_cfg.b_hop,
srs_cfg.n_srs,
srs_cfg.I_srs);
for (ul_sf_cfg.tti = 0; ul_sf_cfg.tti < SRSLTE_NOF_SF_X_FRAME; ul_sf_cfg.tti++) {
// Set resource grid to zero
srslte_vec_cf_zero(q->sf_symbols, q->sf_size);
// Put sounding reference signals
TESTASSERT(srslte_refsignal_srs_put(
&q->refsignal_ul, &srs_cfg, ul_sf_cfg.tti, q->srs_pregen.r[ul_sf_cfg.tti], q->sf_symbols) ==
SRSLTE_SUCCESS);
// Apply AWGN channel
if (!isnan(snr_db) && !isinf(snr_db)) {
srslte_channel_awgn_run_c(&channel, q->sf_symbols, q->sf_symbols, q->sf_size);
}
// Estimate
TESTASSERT(srslte_chest_ul_estimate_srs(
&q->chest_ul, &ul_sf_cfg, &srs_cfg, &dmrs_pusch_cfg, q->sf_symbols, &q->chest_ul_res) ==
SRSLTE_SUCCESS);
INFO("RESULTS: tti=%d; snr_db=%+.1f; noise_estimate_dbm=%+.1f; ta_us=%+.1f;\n",
ul_sf_cfg.tti,
q->chest_ul_res.snr_db,
q->chest_ul_res.noise_estimate_dbm,
q->chest_ul_res.ta_us);
// Assert SRS measurements
TESTASSERT(fabsf(q->chest_ul_res.snr_db - snr_db) < CHEST_TEST_SRS_SNR_DB_TOLERANCE);
TESTASSERT(fabsf(q->chest_ul_res.noise_estimate_dbm - n0_dbm) < CHEST_TEST_SRS_SNR_DB_TOLERANCE);
TESTASSERT(fabsf(q->chest_ul_res.ta_us) < 0.1f);
}
return SRSLTE_SUCCESS;
}
void parse_args(int argc, char** argv)
{
int opt;
while ((opt = getopt(argc, argv, "recov")) != -1) {
switch (opt) {
case 'r':
cell.nof_prb = (uint32_t)strtol(argv[optind], NULL, 10);
break;
case 'e':
cell.cp = SRSLTE_CP_EXT;
break;
case 'c':
cell.id = (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)
{
srs_test_context_t context = {};
int ret = SRSLTE_SUCCESS;
parse_args(argc, argv);
if (srslte_channel_awgn_init(&channel, 123456789) != SRSLTE_SUCCESS) {
ret = SRSLTE_ERROR;
}
if (!isnan(snr_db) && !isinf(snr_db)) {
n0_dbm = 30.0f - snr_db;
srslte_channel_awgn_set_n0(&channel, n0_dbm - 33.0f);
}
for (srs_cfg.bw_cfg = 0; srs_cfg.bw_cfg < 8 && !ret; srs_cfg.bw_cfg++) {
for (srs_cfg.B = 0; srs_cfg.B < 4 && !ret; srs_cfg.B++) {
for (srs_cfg.n_srs = 0; srs_cfg.n_srs < 8 && !ret; srs_cfg.n_srs++) {
// Initialise context
ret = srs_test_context_init(&context);
if (ret) {
printf("Failed setting context: bw_cfg=%d; B=%d; n_srs=%d;\n", srs_cfg.bw_cfg, srs_cfg.B, srs_cfg.n_srs);
}
for (srs_cfg.subframe_config = 0; srs_cfg.subframe_config < 16 && !ret; srs_cfg.subframe_config++) {
for (srs_cfg.b_hop = 0; srs_cfg.b_hop < 4 && !ret; srs_cfg.b_hop++) {
for (srs_cfg.I_srs = 0; srs_cfg.I_srs < 1024 && !ret; srs_cfg.I_srs += 123) {
// Run actual test
ret = srs_test_context_run(&context);
if (!ret) {
test_counter++;
}
}
}
}
// Free context
srs_test_context_free(&context);
}
}
}
srslte_channel_awgn_free(&channel);
if (!ret) {
printf("OK, %d test passed successfully.\n", test_counter);
} else {
printf("Failed at test %d.\n", test_counter);
}
return ret;
}

@ -164,7 +164,7 @@ int main(int argc, char** argv)
}
pusch_cfg.group_hopping_en = group_hopping_en;
pusch_cfg.sequence_hopping_en = sequence_hopping_en;
srslte_chest_ul_pregen(&est, &pusch_cfg);
srslte_chest_ul_pregen(&est, &pusch_cfg, NULL);
// Loop through subframe idx and cyclic shifts

@ -107,7 +107,10 @@ void srslte_enb_ul_free(srslte_enb_ul_t* q)
}
}
int srslte_enb_ul_set_cell(srslte_enb_ul_t* q, srslte_cell_t cell, srslte_refsignal_dmrs_pusch_cfg_t* pusch_cfg)
int srslte_enb_ul_set_cell(srslte_enb_ul_t* q,
srslte_cell_t cell,
srslte_refsignal_dmrs_pusch_cfg_t* pusch_cfg,
srslte_refsignal_srs_cfg_t* srs_cfg)
{
int ret = SRSLTE_ERROR_INVALID_INPUTS;
@ -136,7 +139,7 @@ int srslte_enb_ul_set_cell(srslte_enb_ul_t* q, srslte_cell_t cell, srslte_refsig
}
// SRS is a dedicated configuration
srslte_chest_ul_pregen(&q->chest, pusch_cfg);
srslte_chest_ul_pregen(&q->chest, pusch_cfg, srs_cfg);
ret = SRSLTE_SUCCESS;
}

@ -91,7 +91,7 @@ static int test_pucch_ca(srslte_ack_nack_feedback_mode_t ack_nack_feedback_mode,
// Init eNb
TESTASSERT(!srslte_enb_ul_init(&enb_ul, buffer, cell.nof_prb));
TESTASSERT(!srslte_enb_ul_set_cell(&enb_ul, cell, &dmrs_pusch_cfg));
TESTASSERT(!srslte_enb_ul_set_cell(&enb_ul, cell, &dmrs_pusch_cfg, NULL));
TESTASSERT(!srslte_enb_ul_add_rnti(&enb_ul, rnti));
// The test itself starts here

@ -121,7 +121,7 @@ void cc_worker::init(phy_common* phy_, srslte::log* log_h_, uint32_t cc_idx_)
return;
}
if (srslte_enb_ul_set_cell(&enb_ul, cell, &phy->dmrs_pusch_cfg)) {
if (srslte_enb_ul_set_cell(&enb_ul, cell, &phy->dmrs_pusch_cfg, nullptr)) {
ERROR("Error initiating ENB UL\n");
return;
}

Loading…
Cancel
Save