Add PUCCH SNR measurement (#2175)

* Add PUCCH SNR measurement

* Fix PUCCH SNR estimation

* Reverted PUCCH noise estimation

* use fpclassify instead of iszero

Co-authored-by: Xavier Arteaga <xavier@softwareradiosystems.com>
master
Ismael Gomez 4 years ago committed by GitHub
parent 0780f3caea
commit d5f0634975
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -123,6 +123,8 @@ public:
*/
virtual int cqi_info(uint32_t tti, uint16_t rnti, uint32_t cc_idx, uint32_t cqi_value) = 0;
typedef enum { PUSCH = 0, PUCCH, SRS } ul_channel_t;
/**
* PHY callback for giving MAC the SNR in dB of an UL transmission for a given RNTI at a given carrier
*
@ -130,9 +132,10 @@ public:
* @param rnti The UE identifier in the eNb
* @param cc_idx The eNb Cell/Carrier where the UL transmission was received
* @param snr_db The actual SNR of the received signal
* @param ch Indicates uplink channel (PUSCH, PUCCH or SRS)
* @return SRSLTE_SUCCESS if no error occurs, SRSLTE_ERROR* if an error occurs
*/
virtual int snr_info(uint32_t tti, uint16_t rnti, uint32_t cc_idx, float snr_db) = 0;
virtual int snr_info(uint32_t tti, uint16_t rnti, uint32_t cc_idx, float snr_db, ul_channel_t ch) = 0;
/**
* PHY callback for giving MAC the Time Aligment information in microseconds of a given RNTI during a TTI processing

@ -41,6 +41,10 @@ typedef struct SRSLTE_API {
uint32_t nof_re;
float noise_estimate;
float noise_estimate_dbm;
float rsrp;
float rsrp_dBfs;
float epre;
float epre_dBfs;
float snr;
float snr_db;
float cfo;

@ -83,6 +83,7 @@ typedef struct SRSLTE_API {
typedef struct SRSLTE_API {
srslte_uci_value_t uci_data;
float dmrs_correlation;
float snr_db;
float correlation;
bool detected;

@ -11,6 +11,7 @@
*/
#include <complex.h>
#include <float.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
@ -392,23 +393,46 @@ int srslte_chest_ul_estimate_pusch(srslte_chest_ul_t* q,
return 0;
}
static float
estimate_noise_pilots_pucch(srslte_chest_ul_t* q, cf_t* ce, uint32_t n_rs, uint32_t n_prb[SRSLTE_NOF_SLOTS_PER_SF])
{
float power = 0;
for (int ns = 0; ns < SRSLTE_NOF_SLOTS_PER_SF; ns++) {
for (int i = 0; i < n_rs; i++) {
// All CE are the same, so pick the first symbol of the first slot always and compare with the noisy estimates
power += srslte_chest_estimate_noise_pilots(
&q->pilot_estimates[(i + ns * n_rs) * SRSLTE_NRE],
&ce[SRSLTE_RE_IDX(q->cell.nof_prb, ns * SRSLTE_CP_NSYMB(q->cell.cp), n_prb[ns] * SRSLTE_NRE)],
q->tmp_noise,
SRSLTE_NRE);
}
}
power /= (SRSLTE_NOF_SLOTS_PER_SF * n_rs);
if (q->smooth_filter_len == 3) {
// Calibrated for filter length 3
float w = q->smooth_filter[0];
float a = 7.419 * w * w + 0.1117 * w - 0.005387;
return (power / (a * 0.8));
} else {
return power;
}
}
int srslte_chest_ul_estimate_pucch(srslte_chest_ul_t* q,
srslte_ul_sf_cfg_t* sf,
srslte_pucch_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;
}
int n_rs = srslte_refsignal_dmrs_N_rs(cfg->format, q->cell.cp);
if (!n_rs) {
ERROR("Error computing N_rs\n");
return SRSLTE_ERROR;
}
int nrefs_sf = SRSLTE_NRE * n_rs * 2;
int nrefs_sf = SRSLTE_NRE * n_rs * SRSLTE_NOF_SLOTS_PER_SF;
/* Get references from the input signal */
srslte_refsignal_dmrs_pucch_get(&q->dmrs_signal, cfg, input, q->pilot_recv_signal);
@ -446,8 +470,29 @@ int srslte_chest_ul_estimate_pucch(srslte_chest_ul_t* q,
srslte_vec_prod_conj_ccc(q->pilot_recv_signal, q->pilot_known_signal, q->pilot_estimates, nrefs_sf);
}
if (cfg->meas_ta_en && n_rs > 0) {
float ta_err = 0.0;
// Measure power
float rsrp_avg = 0.0f;
for (int ns = 0; ns < SRSLTE_NOF_SLOTS_PER_SF; ns++) {
for (int i = 0; i < n_rs; i++) {
cf_t corr = srslte_vec_acc_cc(q->pilot_estimates, SRSLTE_NOF_SLOTS_PER_SF * SRSLTE_NRE * n_rs) / (SRSLTE_NRE);
rsrp_avg += __real__ corr * __real__ corr + __imag__ corr * __imag__ corr;
}
}
rsrp_avg /= SRSLTE_NOF_SLOTS_PER_SF * n_rs;
float epre = srslte_vec_avg_power_cf(q->pilot_estimates, SRSLTE_NOF_SLOTS_PER_SF * SRSLTE_NRE * n_rs);
// RSRP shall not be greater than EPRE
rsrp_avg = SRSLTE_MIN(rsrp_avg, epre);
// Set EPRE and RSRP
res->epre = epre;
res->epre_dBfs = srslte_convert_power_to_dB(res->epre);
res->rsrp = rsrp_avg;
res->rsrp_dBfs = srslte_convert_power_to_dB(res->rsrp);
// Estimate time alignment
if (cfg->meas_ta_en) {
float ta_err = 0.0f;
for (int ns = 0; ns < SRSLTE_NOF_SLOTS_PER_SF; ns++) {
for (int i = 0; i < n_rs; i++) {
ta_err += srslte_vec_estimate_frequency(&q->pilot_estimates[(i + ns * n_rs) * SRSLTE_NRE], SRSLTE_NRE) /
@ -467,6 +512,8 @@ int srslte_chest_ul_estimate_pucch(srslte_chest_ul_t* q,
}
if (res->ce != NULL) {
uint32_t n_prb[2] = {};
/* TODO: Currently averaging entire slot, performance good enough? */
for (int ns = 0; ns < 2; ns++) {
// Average all slot
@ -490,15 +537,32 @@ int srslte_chest_ul_estimate_pucch(srslte_chest_ul_t* q,
q->smooth_filter_len);
// Determine n_prb
uint32_t n_prb = srslte_pucch_n_prb(&q->cell, cfg, ns);
n_prb[ns] = srslte_pucch_n_prb(&q->cell, cfg, ns);
// copy estimates to slot
for (int i = 0; i < SRSLTE_CP_NSYMB(q->cell.cp); i++) {
memcpy(&res->ce[SRSLTE_RE_IDX(q->cell.nof_prb, i + ns * SRSLTE_CP_NSYMB(q->cell.cp), n_prb * SRSLTE_NRE)],
&q->pilot_recv_signal[ns * n_rs * SRSLTE_NRE],
sizeof(cf_t) * SRSLTE_NRE);
srslte_vec_cf_copy(
&res->ce[SRSLTE_RE_IDX(q->cell.nof_prb, i + ns * SRSLTE_CP_NSYMB(q->cell.cp), n_prb[ns] * SRSLTE_NRE)],
&q->pilot_recv_signal[ns * n_rs * SRSLTE_NRE],
SRSLTE_NRE);
}
}
// Estimate noise/interference
res->noise_estimate = estimate_noise_pilots_pucch(q, res->ce, n_rs, n_prb);
if (fpclassify(res->noise_estimate) == FP_ZERO) {
res->noise_estimate = FLT_MIN;
}
res->noise_estimate_dbm = srslte_convert_power_to_dBm(res->noise_estimate);
// Estimate SINR
if (isnormal(res->noise_estimate)) {
res->snr = res->rsrp / res->noise_estimate;
res->snr_db = srslte_convert_power_to_dB(res->snr);
} else {
res->snr = NAN;
res->snr_db = NAN;
}
}
return 0;

@ -204,6 +204,7 @@ static int get_pucch(srslte_enb_ul_t* q, srslte_ul_sf_cfg_t* ul_sf, srslte_pucch
ERROR("Error estimating PUCCH DMRS\n");
return SRSLTE_ERROR;
}
pucch_res.snr_db = q->chest_res.snr_db;
ret = srslte_pucch_decode(&q->pucch, ul_sf, cfg, &q->chest_res, q->sf_symbols, &pucch_res);
if (ret < SRSLTE_SUCCESS) {

@ -1380,7 +1380,8 @@ void srslte_pucch_rx_info(srslte_pucch_cfg_t* cfg, srslte_pucch_res_t* pucch_res
if (pucch_res) {
if (isnormal(cfg->threshold_dmrs_detection)) {
n = srslte_print_check(str, str_len, n, ", dmrs_corr=%.3f", pucch_res->dmrs_correlation);
n = srslte_print_check(
str, str_len, n, ", dmrs_corr=%.3f, snr=%.1f dB", pucch_res->dmrs_correlation, pucch_res->snr_db);
}
n = srslte_print_check(str, str_len, n, ", corr=%.3f", pucch_res->correlation);

@ -19,7 +19,7 @@
#include "srslte/srslte.h"
srslte_cell_t cell = {
static srslte_cell_t cell = {
25, // nof_prb
1, // nof_ports
1, // cell_id
@ -30,23 +30,25 @@ srslte_cell_t cell = {
};
uint32_t subframe = 0;
bool test_cqi_only = false;
static uint32_t subframe = 0;
static bool test_cqi_only = false;
static float snr_db = 20.0f;
void usage(char* prog)
static void usage(char* prog)
{
printf("Usage: %s [csNnv]\n", prog);
printf("\t-c cell id [Default %d]\n", cell.id);
printf("\t-s subframe [Default %d]\n", subframe);
printf("\t-n nof_prb [Default %d]\n", cell.nof_prb);
printf("\t-q Test CQI encoding/decoding only [Default %s].\n", test_cqi_only ? "yes" : "no");
printf("\t-S Signal to Noise Ratio in dB [Default %.2f].\n", snr_db);
printf("\t-v [set verbose to debug, default none]\n");
}
void parse_args(int argc, char** argv)
{
int opt;
while ((opt = getopt(argc, argv, "csNnqv")) != -1) {
while ((opt = getopt(argc, argv, "csNnqSv")) != -1) {
switch (opt) {
case 's':
subframe = (uint32_t)strtol(argv[optind], NULL, 10);
@ -60,6 +62,9 @@ void parse_args(int argc, char** argv)
case 'q':
test_cqi_only = true;
break;
case 'S':
snr_db = strtof(argv[optind], NULL);
break;
case 'v':
srslte_verbose++;
break;
@ -126,12 +131,16 @@ int test_uci_cqi_pucch(void)
int main(int argc, char** argv)
{
srslte_pucch_t pucch;
srslte_pucch_cfg_t pucch_cfg;
srslte_pucch_t pucch_ue = {};
srslte_pucch_t pucch_enb = {};
srslte_pucch_cfg_t pucch_cfg = {};
srslte_refsignal_ul_t dmrs;
cf_t* sf_symbols = NULL;
cf_t pucch_dmrs[2 * SRSLTE_NRE * 3];
int ret = -1;
int ret = -1;
srslte_chest_ul_t chest = {};
srslte_chest_ul_res_t chest_res = {};
srslte_channel_awgn_t awgn = {};
parse_args(argc, argv);
@ -139,14 +148,30 @@ int main(int argc, char** argv)
return test_uci_cqi_pucch();
}
if (srslte_pucch_init_ue(&pucch)) {
if (srslte_pucch_init_ue(&pucch_ue)) {
ERROR("Error creating PDSCH object\n");
exit(-1);
}
if (srslte_pucch_set_cell(&pucch_ue, cell)) {
ERROR("Error creating PDSCH object\n");
exit(-1);
}
if (srslte_pucch_set_rnti(&pucch_ue, 11)) {
ERROR("Error setting C-RNTI\n");
goto quit;
}
if (srslte_pucch_init_enb(&pucch_enb)) {
ERROR("Error creating PDSCH object\n");
exit(-1);
}
if (srslte_pucch_set_cell(&pucch, cell)) {
if (srslte_pucch_set_cell(&pucch_enb, cell)) {
ERROR("Error creating PDSCH object\n");
exit(-1);
}
if (srslte_pucch_set_rnti(&pucch_enb, 11)) {
ERROR("Error setting C-RNTI\n");
goto quit;
}
if (srslte_refsignal_ul_init(&dmrs, cell.nof_prb)) {
ERROR("Error creating PDSCH object\n");
exit(-1);
@ -156,10 +181,27 @@ int main(int argc, char** argv)
exit(-1);
}
bzero(&pucch_cfg, sizeof(srslte_pucch_cfg_t));
if (srslte_chest_ul_init(&chest, cell.nof_prb) < SRSLTE_SUCCESS) {
ERROR("Error initiating channel estimator\n");
goto quit;
}
if (srslte_pucch_set_rnti(&pucch, 11)) {
ERROR("Error setting C-RNTI\n");
if (srslte_chest_ul_res_init(&chest_res, cell.nof_prb) < SRSLTE_SUCCESS) {
ERROR("Error initiating channel estimator result\n");
goto quit;
}
if (srslte_chest_ul_set_cell(&chest, cell) < SRSLTE_SUCCESS) {
ERROR("Error setting channel estimator cell\n");
goto quit;
}
if (srslte_channel_awgn_init(&awgn, 0x1234) < SRSLTE_SUCCESS) {
ERROR("Error initiating AWGN\n");
goto quit;
}
if (srslte_channel_awgn_set_n0(&awgn, -snr_db) < SRSLTE_SUCCESS) {
ERROR("Error setting AWGN\n");
goto quit;
}
@ -172,7 +214,7 @@ int main(int argc, char** argv)
ZERO_OBJECT(ul_sf);
srslte_pucch_format_t format;
for (format = 0; format <= SRSLTE_PUCCH_FORMAT_3; format++) {
for (format = 0; format < SRSLTE_PUCCH_FORMAT_ERROR; format++) {
for (uint32_t d = 1; d <= 3; d++) {
for (uint32_t ncs = 0; ncs < 8; ncs += d) {
for (uint32_t n_pucch = 1; n_pucch < 130; n_pucch += 50) {
@ -215,8 +257,9 @@ int main(int argc, char** argv)
uci_data.cfg.cqi.data_enable = true;
}
// Encode PUCCH signals
gettimeofday(&t[1], NULL);
if (srslte_pucch_encode(&pucch, &ul_sf, &pucch_cfg, &uci_data.value, sf_symbols)) {
if (srslte_pucch_encode(&pucch_ue, &ul_sf, &pucch_cfg, &uci_data.value, sf_symbols)) {
ERROR("Error encoding PUCCH\n");
goto quit;
}
@ -231,7 +274,48 @@ int main(int argc, char** argv)
}
gettimeofday(&t[2], NULL);
get_time_interval(t);
INFO("format %d, n_pucch: %d, ncs: %d, d: %d, t_exec=%ld us\n", format, n_pucch, ncs, d, t[0].tv_usec);
uint64_t t_enc = t[0].tv_usec + t[0].tv_sec * 1000000UL;
// Run AWGN channel
srslte_channel_awgn_run_c(&awgn, sf_symbols, sf_symbols, SRSLTE_NOF_RE(cell));
// Decode PUCCH signals
gettimeofday(&t[1], NULL);
if (srslte_chest_ul_estimate_pucch(&chest, &ul_sf, &pucch_cfg, sf_symbols, &chest_res) < SRSLTE_SUCCESS) {
ERROR("Error estimating PUCCH channel\n");
goto quit;
}
srslte_pucch_res_t res = {};
if (srslte_pucch_decode(&pucch_enb, &ul_sf, &pucch_cfg, &chest_res, sf_symbols, &res) < SRSLTE_SUCCESS) {
ERROR("Error decoding PUCCH\n");
goto quit;
}
gettimeofday(&t[2], NULL);
get_time_interval(t);
uint64_t t_dec = t[0].tv_usec + t[0].tv_sec * 1000000UL;
// Check EPRE and RSRP are +/- 1 dB and SNR measurements are +/- 3dB
if (fabsf(chest_res.epre_dBfs) > 1.0 || fabsf(chest_res.rsrp_dBfs) > 1.0 ||
fabsf(chest_res.snr_db - snr_db) > 3.0) {
ERROR("Invalid EPRE (%+.2f), RSRP (%+.2f) or SNR (%+.2f)\n",
chest_res.epre_dBfs,
chest_res.rsrp_dBfs,
chest_res.snr_db);
goto quit;
}
INFO("format %d, n_pucch: %d, ncs: %d, d: %d, t_encode=%ld us, t_decode=%ld us, EPRE=%+.1f dBfs, RSRP=%+.1f "
"dBfs, SNR=%+.1f dBfs\n",
format,
n_pucch,
ncs,
d,
t_enc,
t_dec,
chest_res.epre_dBfs,
chest_res.rsrp_dBfs,
chest_res.snr_db);
}
}
}
@ -239,9 +323,12 @@ int main(int argc, char** argv)
ret = 0;
quit:
srslte_pucch_free(&pucch);
srslte_pucch_free(&pucch_ue);
srslte_pucch_free(&pucch_enb);
srslte_refsignal_ul_free(&dmrs);
srslte_chest_ul_free(&chest);
srslte_chest_ul_res_free(&chest_res);
srslte_channel_awgn_free(&awgn);
if (sf_symbols) {
free(sf_symbols);
}

@ -100,6 +100,7 @@ private:
void metrics_read(phy_metrics_t* metrics);
void metrics_dl(uint32_t mcs);
void metrics_ul(uint32_t mcs, float rssi, float sinr, float turbo_iters);
void metrics_ul_pucch(float sinr);
uint32_t get_rnti() const { return rnti; }
private:

@ -19,11 +19,13 @@ namespace srsenb {
struct ul_metrics_t {
float n;
float sinr;
float pusch_sinr;
float pucch_sinr;
float rssi;
float turbo_iters;
float mcs;
int n_samples;
int n_samples_pucch;
};
struct dl_metrics_t {

@ -67,9 +67,9 @@ public:
{
return mac.cqi_info(tti, rnti, cc_idx, cqi_value);
}
int snr_info(uint32_t tti_rx, uint16_t rnti, uint32_t cc_idx, float snr_db) final
int snr_info(uint32_t tti_rx, uint16_t rnti, uint32_t cc_idx, float snr_db, ul_channel_t ch) final
{
return mac.snr_info(tti_rx, rnti, cc_idx, snr_db);
return mac.snr_info(tti_rx, rnti, cc_idx, snr_db, ch);
}
int ta_info(uint32_t tti, uint16_t rnti, float ta_us) override { return mac.ta_info(tti, rnti, ta_us); }
int ack_info(uint32_t tti, uint16_t rnti, uint32_t enb_cc_idx, uint32_t tb_idx, bool ack) final

@ -52,7 +52,7 @@ public:
int ri_info(uint32_t tti, uint16_t rnti, uint32_t enb_cc_idx, uint32_t ri_value) override;
int pmi_info(uint32_t tti, uint16_t rnti, uint32_t enb_cc_idx, uint32_t pmi_value) override;
int cqi_info(uint32_t tti, uint16_t rnti, uint32_t enb_cc_idx, uint32_t cqi_value) override;
int snr_info(uint32_t tti, uint16_t rnti, uint32_t enb_cc_idx, float snr) override;
int snr_info(uint32_t tti, uint16_t rnti, uint32_t enb_cc_idx, float snr, ul_channel_t ch) override;
int ta_info(uint32_t tti, uint16_t rnti, float ta_us) override;
int ack_info(uint32_t tti, uint16_t rnti, uint32_t enb_cc_idx, uint32_t tb_idx, bool ack) override;
int crc_info(uint32_t tti, uint16_t rnti, uint32_t enb_cc_idx, uint32_t nof_bytes, bool crc_res) override;

@ -195,9 +195,9 @@ void parse_args(all_args_t* args, int argc, char* argv[])
("expert.equalizer_mode", bpo::value<string>(&args->phy.equalizer_mode)->default_value("mmse"), "Equalizer mode")
("expert.estimator_fil_w", bpo::value<float>(&args->phy.estimator_fil_w)->default_value(0.1), "Chooses the coefficients for the 3-tap channel estimator centered filter.")
("expert.lte_sample_rates", bpo::value<bool>(&use_standard_lte_rates)->default_value(false), "Whether to use default LTE sample rates instead of shorter variants.")
("expert.report_json_enable", bpo::value<bool>(&args->general.report_json_enable)->default_value(true), "Write eNB report to JSON file")
("expert.report_json_enable", bpo::value<bool>(&args->general.report_json_enable)->default_value(false), "Write eNB report to JSON file")
("expert.report_json_filename", bpo::value<string>(&args->general.report_json_filename)->default_value("/tmp/enb_report.json"), "Report JSON filename")
("expert.alarms_log_enable", bpo::value<bool>(&args->general.alarms_log_enable)->default_value(true), "Log alarms")
("expert.alarms_log_enable", bpo::value<bool>(&args->general.alarms_log_enable)->default_value(false), "Log alarms")
("expert.alarms_filename", bpo::value<string>(&args->general.alarms_filename)->default_value("/tmp/enb_alarms.log"), "Alarms filename")
("expert.rrc_inactivity_timer", bpo::value<uint32_t>(&args->general.rrc_inactivity_timer)->default_value(30000), "Inactivity timer in ms.")
("expert.print_buffer_state", bpo::value<bool>(&args->general.print_buffer_state)->default_value(false), "Prints on the console the buffer state every 10 seconds")

@ -100,8 +100,8 @@ static void fill_ue_metrics(mset_ue_container& ue, const enb_metrics_t& m, unsig
if (m.stack.mac.ues[i].tx_pkts > 0 && m.stack.mac.ues[i].tx_errors > 0) {
ue.write<metric_dl_bler>(std::max(0.1f, (float)100 * m.stack.mac.ues[i].tx_errors / m.stack.mac.ues[i].tx_pkts));
}
if (!std::isnan(m.phy[i].ul.sinr)) {
ue.write<metric_ul_snr>(std::max(0.1f, m.phy[i].ul.sinr));
if (!std::isnan(m.phy[i].ul.pusch_sinr)) {
ue.write<metric_ul_snr>(std::max(0.1f, m.phy[i].ul.pusch_sinr));
}
if (!std::isnan(m.phy[i].ul.mcs)) {
ue.write<metric_ul_mcs>(std::max(0.1f, m.phy[i].ul.mcs));

@ -83,8 +83,8 @@ void metrics_stdout::set_metrics(const enb_metrics_t& metrics, const uint32_t pe
if (++n_reports > 10) {
n_reports = 0;
cout << endl;
cout << "------DL--------------------------------UL------------------------------------" << endl;
cout << "rnti cqi ri mcs brate ok nok (%) snr phr mcs brate ok nok (%) bsr" << endl;
cout << "------DL-------------------------------UL--------------------------------------------" << endl;
cout << "rnti cqi ri mcs brate ok nok (%) pusch pucch phr mcs brate ok nok (%) bsr" << endl;
}
for (size_t i = 0; i < metrics.stack.rrc.ues.size(); i++) {
@ -122,13 +122,20 @@ void metrics_stdout::set_metrics(const enb_metrics_t& metrics, const uint32_t pe
} else {
cout << float_to_string(0, 1, 4) << "%";
}
cout << " ";
cout << " ";
if (not isnan(metrics.phy[i].ul.sinr)) {
cout << float_to_string(SRSLTE_MAX(0.1, metrics.phy[i].ul.sinr), 2, 4);
if (not isnan(metrics.phy[i].ul.pusch_sinr)) {
cout << float_to_string(SRSLTE_MAX(0.1, metrics.phy[i].ul.pusch_sinr), 2, 5);
} else {
cout << float_to_string(0, 1, 4);
cout << float_to_string(0, 2, 5);
}
if (not isnan(metrics.phy[i].ul.pucch_sinr)) {
cout << float_to_string(SRSLTE_MAX(0.1, metrics.phy[i].ul.pucch_sinr), 2, 5);
} else {
cout << float_to_string(0, 2, 5);
}
cout << " ";
cout << float_to_string(metrics.stack.mac.ues[i].phr, 2, 5);
if (not isnan(metrics.phy[i].ul.mcs)) {

@ -335,7 +335,7 @@ void cc_worker::decode_pusch_rnti(stack_interface_phy_lte::ul_sched_grant_t& ul_
// Notify MAC of RL status
if (snr_db >= PUSCH_RL_SNR_DB_TH) {
// Notify MAC UL channel quality
phy->stack->snr_info(ul_sf.tti, rnti, cc_idx, snr_db);
phy->stack->snr_info(ul_sf.tti, rnti, cc_idx, snr_db, mac_interface_phy_lte::PUSCH);
// Notify MAC of Time Alignment only if it enabled and valid measurement, ignore value otherwise
if (ul_cfg.pusch.meas_ta_en and not std::isnan(enb_ul.chest_res.ta_us) and not std::isinf(enb_ul.chest_res.ta_us)) {
@ -409,6 +409,7 @@ int cc_worker::decode_pucch()
if (pucch_res.detected and pucch_res.ta_valid) {
phy->stack->ta_info(tti_rx, rnti, pucch_res.ta_us);
phy->stack->snr_info(tti_rx, rnti, cc_idx, pucch_res.snr_db, mac_interface_phy_lte::PUCCH);
}
// Logging
@ -417,6 +418,9 @@ int cc_worker::decode_pucch()
srslte_pucch_rx_info(&ul_cfg.pucch, &pucch_res, str, sizeof(str));
log_h->info("PUCCH: cc=%d; %s\n", cc_idx, str);
}
// Save metrics
ue_db[rnti]->metrics_ul_pucch(pucch_res.snr_db);
}
}
}
@ -615,12 +619,18 @@ void cc_worker::ue::metrics_dl(uint32_t mcs)
void cc_worker::ue::metrics_ul(uint32_t mcs, float rssi, float sinr, float turbo_iters)
{
metrics.ul.mcs = SRSLTE_VEC_CMA((float)mcs, metrics.ul.mcs, metrics.ul.n_samples);
metrics.ul.sinr = SRSLTE_VEC_CMA((float)sinr, metrics.ul.sinr, metrics.ul.n_samples);
metrics.ul.pusch_sinr = SRSLTE_VEC_CMA((float)sinr, metrics.ul.pusch_sinr, metrics.ul.n_samples);
metrics.ul.rssi = SRSLTE_VEC_CMA((float)rssi, metrics.ul.rssi, metrics.ul.n_samples);
metrics.ul.turbo_iters = SRSLTE_VEC_CMA((float)turbo_iters, metrics.ul.turbo_iters, metrics.ul.n_samples);
metrics.ul.n_samples++;
}
void cc_worker::ue::metrics_ul_pucch(float sinr)
{
metrics.ul.pucch_sinr = SRSLTE_VEC_CMA((float)sinr, metrics.ul.pucch_sinr, metrics.ul.n_samples_pucch);
metrics.ul.n_samples_pucch++;
}
int cc_worker::read_ce_abs(float* ce_abs)
{
int sz = srslte_symbol_sz(phy->get_nof_prb(cc_idx));

@ -285,11 +285,14 @@ uint32_t sf_worker::get_metrics(std::vector<phy_metrics_t>& metrics)
m->dl.mcs = SRSLTE_VEC_PMA(m->dl.mcs, m->dl.n_samples, m_->dl.mcs, m_->dl.n_samples);
m->dl.n_samples += m_->dl.n_samples;
m->ul.n = SRSLTE_VEC_PMA(m->ul.n, m->ul.n_samples, m_->ul.n, m_->ul.n_samples);
m->ul.sinr = SRSLTE_VEC_PMA(m->ul.sinr, m->ul.n_samples, m_->ul.sinr, m_->ul.n_samples);
m->ul.pusch_sinr = SRSLTE_VEC_PMA(m->ul.pusch_sinr, m->ul.n_samples, m_->ul.pusch_sinr, m_->ul.n_samples);
m->ul.pucch_sinr =
SRSLTE_VEC_PMA(m->ul.pucch_sinr, m->ul.n_samples_pucch, m_->ul.pucch_sinr, m_->ul.n_samples_pucch);
m->ul.mcs = SRSLTE_VEC_PMA(m->ul.mcs, m->ul.n_samples, m_->ul.mcs, m_->ul.n_samples);
m->ul.rssi = SRSLTE_VEC_PMA(m->ul.rssi, m->ul.n_samples, m_->ul.rssi, m_->ul.n_samples);
m->ul.turbo_iters = SRSLTE_VEC_PMA(m->ul.turbo_iters, m->ul.n_samples, m_->ul.turbo_iters, m_->ul.n_samples);
m->ul.n_samples += m_->ul.n_samples;
m->ul.n_samples_pucch += m_->ul.n_samples_pucch;
}
}
return cnt;

@ -215,10 +215,12 @@ void phy::get_metrics(std::vector<phy_metrics_t>& metrics)
metrics[j].dl.mcs += metrics_tmp[j].dl.n_samples * metrics_tmp[j].dl.mcs;
metrics[j].ul.n_samples += metrics_tmp[j].ul.n_samples;
metrics[j].ul.n_samples_pucch += metrics_tmp[j].ul.n_samples_pucch;
metrics[j].ul.mcs += metrics_tmp[j].ul.n_samples * metrics_tmp[j].ul.mcs;
metrics[j].ul.n += metrics_tmp[j].ul.n_samples * metrics_tmp[j].ul.n;
metrics[j].ul.rssi += metrics_tmp[j].ul.n_samples * metrics_tmp[j].ul.rssi;
metrics[j].ul.sinr += metrics_tmp[j].ul.n_samples * metrics_tmp[j].ul.sinr;
metrics[j].ul.pusch_sinr += metrics_tmp[j].ul.n_samples * metrics_tmp[j].ul.pusch_sinr;
metrics[j].ul.pucch_sinr += metrics_tmp[j].ul.n_samples_pucch * metrics_tmp[j].ul.pucch_sinr;
metrics[j].ul.turbo_iters += metrics_tmp[j].ul.n_samples * metrics_tmp[j].ul.turbo_iters;
}
}
@ -227,7 +229,8 @@ void phy::get_metrics(std::vector<phy_metrics_t>& metrics)
metrics[j].ul.mcs /= metrics[j].ul.n_samples;
metrics[j].ul.n /= metrics[j].ul.n_samples;
metrics[j].ul.rssi /= metrics[j].ul.n_samples;
metrics[j].ul.sinr /= metrics[j].ul.n_samples;
metrics[j].ul.pusch_sinr /= metrics[j].ul.n_samples;
metrics[j].ul.pucch_sinr /= metrics[j].ul.n_samples_pucch;
metrics[j].ul.turbo_iters /= metrics[j].ul.n_samples;
}
}

@ -388,7 +388,7 @@ int mac::cqi_info(uint32_t tti, uint16_t rnti, uint32_t enb_cc_idx, uint32_t cqi
return SRSLTE_SUCCESS;
}
int mac::snr_info(uint32_t tti_rx, uint16_t rnti, uint32_t enb_cc_idx, float snr)
int mac::snr_info(uint32_t tti_rx, uint16_t rnti, uint32_t enb_cc_idx, float snr, ul_channel_t ch)
{
log_h->step(tti_rx);
srslte::rwlock_read_guard lock(rwlock);
@ -397,7 +397,7 @@ int mac::snr_info(uint32_t tti_rx, uint16_t rnti, uint32_t enb_cc_idx, float snr
return SRSLTE_ERROR;
}
return scheduler.ul_snr_info(tti_rx, rnti, enb_cc_idx, snr, 0);
return scheduler.ul_snr_info(tti_rx, rnti, enb_cc_idx, snr, (uint32_t)ch);
}
int mac::ta_info(uint32_t tti, uint16_t rnti, float ta_us)

@ -55,7 +55,8 @@ public:
metrics[0].phy.resize(1);
metrics[0].phy[0].dl.mcs = 28.0;
metrics[0].phy[0].ul.mcs = 20.2;
metrics[0].phy[0].ul.sinr = 14.2;
metrics[0].phy[0].ul.pucch_sinr = 14.2;
metrics[0].phy[0].ul.pusch_sinr = 14.2;
// second
metrics[1].rf.rf_o = 10;
@ -77,7 +78,8 @@ public:
metrics[1].phy.resize(1);
metrics[1].phy[0].dl.mcs = 6.2;
metrics[1].phy[0].ul.mcs = 28.0;
metrics[1].phy[0].ul.sinr = 22.2;
metrics[1].phy[0].ul.pucch_sinr = 22.2;
metrics[1].phy[0].ul.pusch_sinr = 22.2;
// third entry
metrics[2].rf.rf_o = 10;
@ -99,7 +101,8 @@ public:
metrics[2].phy.resize(1);
metrics[2].phy[0].dl.mcs = 28.0;
metrics[2].phy[0].ul.mcs = 20.2;
metrics[2].phy[0].ul.sinr = 14.2;
metrics[2].phy[0].ul.pusch_sinr = 14.2;
metrics[2].phy[0].ul.pucch_sinr = 14.2;
// fourth entry with incomple PHY and MAC stats
metrics[3].rf.rf_o = 10;

@ -454,7 +454,7 @@ public:
return SRSLTE_SUCCESS;
}
int snr_info(uint32_t tti, uint16_t rnti, uint32_t cc_idx, float snr_db) override
int snr_info(uint32_t tti, uint16_t rnti, uint32_t cc_idx, float snr_db, ul_channel_t ch) override
{
notify_snr_info();
return 0;

Loading…
Cancel
Save