From d5f06349756784247e163097e292ef3550e23635 Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Tue, 19 Jan 2021 21:55:24 +0100 Subject: [PATCH] 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 --- .../srslte/interfaces/enb_interfaces.h | 5 +- .../srslte/phy/ch_estimation/chest_ul.h | 4 + lib/include/srslte/phy/phch/pucch.h | 1 + lib/src/phy/ch_estimation/chest_ul.c | 90 +++++++++++-- lib/src/phy/enb/enb_ul.c | 1 + lib/src/phy/phch/pucch.c | 3 +- lib/src/phy/phch/test/pucch_test.c | 123 +++++++++++++++--- srsenb/hdr/phy/lte/cc_worker.h | 1 + srsenb/hdr/phy/phy_metrics.h | 4 +- srsenb/hdr/stack/enb_stack_lte.h | 4 +- srsenb/hdr/stack/mac/mac.h | 2 +- srsenb/src/main.cc | 4 +- srsenb/src/metrics_json.cc | 4 +- srsenb/src/metrics_stdout.cc | 19 ++- srsenb/src/phy/lte/cc_worker.cc | 14 +- srsenb/src/phy/lte/sf_worker.cc | 5 +- srsenb/src/phy/phy.cc | 7 +- srsenb/src/stack/mac/mac.cc | 4 +- srsenb/test/enb_metrics_test.cc | 9 +- srsenb/test/phy/enb_phy_test.cc | 2 +- 20 files changed, 248 insertions(+), 58 deletions(-) diff --git a/lib/include/srslte/interfaces/enb_interfaces.h b/lib/include/srslte/interfaces/enb_interfaces.h index b7945afb2..97e206572 100644 --- a/lib/include/srslte/interfaces/enb_interfaces.h +++ b/lib/include/srslte/interfaces/enb_interfaces.h @@ -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 diff --git a/lib/include/srslte/phy/ch_estimation/chest_ul.h b/lib/include/srslte/phy/ch_estimation/chest_ul.h index e49d4b750..b40c34014 100644 --- a/lib/include/srslte/phy/ch_estimation/chest_ul.h +++ b/lib/include/srslte/phy/ch_estimation/chest_ul.h @@ -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; diff --git a/lib/include/srslte/phy/phch/pucch.h b/lib/include/srslte/phy/phch/pucch.h index 66231e1d8..558427e9b 100644 --- a/lib/include/srslte/phy/phch/pucch.h +++ b/lib/include/srslte/phy/phch/pucch.h @@ -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; diff --git a/lib/src/phy/ch_estimation/chest_ul.c b/lib/src/phy/ch_estimation/chest_ul.c index 4cbab5cfc..539b6cca8 100644 --- a/lib/src/phy/ch_estimation/chest_ul.c +++ b/lib/src/phy/ch_estimation/chest_ul.c @@ -11,6 +11,7 @@ */ #include +#include #include #include #include @@ -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; @@ -539,4 +603,4 @@ int srslte_chest_ul_estimate_srs(srslte_chest_ul_t* q, chest_ul_estimate(q, 1, n_srs_re, 1, true, false, n_prb, res); return SRSLTE_SUCCESS; -} \ No newline at end of file +} diff --git a/lib/src/phy/enb/enb_ul.c b/lib/src/phy/enb/enb_ul.c index b486e15d0..eed9fa2f7 100644 --- a/lib/src/phy/enb/enb_ul.c +++ b/lib/src/phy/enb/enb_ul.c @@ -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) { diff --git a/lib/src/phy/phch/pucch.c b/lib/src/phy/phch/pucch.c index 3905f8fcf..bd26e2b11 100644 --- a/lib/src/phy/phch/pucch.c +++ b/lib/src/phy/phch/pucch.c @@ -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); diff --git a/lib/src/phy/phch/test/pucch_test.c b/lib/src/phy/phch/test/pucch_test.c index a1add4ace..fc158b898 100644 --- a/lib/src/phy/phch/test/pucch_test.c +++ b/lib/src/phy/phch/test/pucch_test.c @@ -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); } diff --git a/srsenb/hdr/phy/lte/cc_worker.h b/srsenb/hdr/phy/lte/cc_worker.h index 90afb0117..865b32c20 100644 --- a/srsenb/hdr/phy/lte/cc_worker.h +++ b/srsenb/hdr/phy/lte/cc_worker.h @@ -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: diff --git a/srsenb/hdr/phy/phy_metrics.h b/srsenb/hdr/phy/phy_metrics.h index 0d38607e8..592cf1729 100644 --- a/srsenb/hdr/phy/phy_metrics.h +++ b/srsenb/hdr/phy/phy_metrics.h @@ -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 { diff --git a/srsenb/hdr/stack/enb_stack_lte.h b/srsenb/hdr/stack/enb_stack_lte.h index 8929bbfc6..b4a2122a8 100644 --- a/srsenb/hdr/stack/enb_stack_lte.h +++ b/srsenb/hdr/stack/enb_stack_lte.h @@ -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 diff --git a/srsenb/hdr/stack/mac/mac.h b/srsenb/hdr/stack/mac/mac.h index 6f6a72a08..a90ee86bc 100644 --- a/srsenb/hdr/stack/mac/mac.h +++ b/srsenb/hdr/stack/mac/mac.h @@ -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; diff --git a/srsenb/src/main.cc b/srsenb/src/main.cc index ceacca5e2..40127306d 100644 --- a/srsenb/src/main.cc +++ b/srsenb/src/main.cc @@ -195,9 +195,9 @@ void parse_args(all_args_t* args, int argc, char* argv[]) ("expert.equalizer_mode", bpo::value(&args->phy.equalizer_mode)->default_value("mmse"), "Equalizer mode") ("expert.estimator_fil_w", bpo::value(&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(&use_standard_lte_rates)->default_value(false), "Whether to use default LTE sample rates instead of shorter variants.") - ("expert.report_json_enable", bpo::value(&args->general.report_json_enable)->default_value(true), "Write eNB report to JSON file") + ("expert.report_json_enable", bpo::value(&args->general.report_json_enable)->default_value(false), "Write eNB report to JSON file") ("expert.report_json_filename", bpo::value(&args->general.report_json_filename)->default_value("/tmp/enb_report.json"), "Report JSON filename") - ("expert.alarms_log_enable", bpo::value(&args->general.alarms_log_enable)->default_value(true), "Log alarms") + ("expert.alarms_log_enable", bpo::value(&args->general.alarms_log_enable)->default_value(false), "Log alarms") ("expert.alarms_filename", bpo::value(&args->general.alarms_filename)->default_value("/tmp/enb_alarms.log"), "Alarms filename") ("expert.rrc_inactivity_timer", bpo::value(&args->general.rrc_inactivity_timer)->default_value(30000), "Inactivity timer in ms.") ("expert.print_buffer_state", bpo::value(&args->general.print_buffer_state)->default_value(false), "Prints on the console the buffer state every 10 seconds") diff --git a/srsenb/src/metrics_json.cc b/srsenb/src/metrics_json.cc index 5e9065d4e..a27fb253f 100644 --- a/srsenb/src/metrics_json.cc +++ b/srsenb/src/metrics_json.cc @@ -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(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(std::max(0.1f, m.phy[i].ul.sinr)); + if (!std::isnan(m.phy[i].ul.pusch_sinr)) { + ue.write(std::max(0.1f, m.phy[i].ul.pusch_sinr)); } if (!std::isnan(m.phy[i].ul.mcs)) { ue.write(std::max(0.1f, m.phy[i].ul.mcs)); diff --git a/srsenb/src/metrics_stdout.cc b/srsenb/src/metrics_stdout.cc index 75d1be9d2..22928554e 100644 --- a/srsenb/src/metrics_stdout.cc +++ b/srsenb/src/metrics_stdout.cc @@ -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)) { diff --git a/srsenb/src/phy/lte/cc_worker.cc b/srsenb/src/phy/lte/cc_worker.cc index 0c568d39b..ab3b9ff3d 100644 --- a/srsenb/src/phy/lte/cc_worker.cc +++ b/srsenb/src/phy/lte/cc_worker.cc @@ -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)); diff --git a/srsenb/src/phy/lte/sf_worker.cc b/srsenb/src/phy/lte/sf_worker.cc index 6a2e443e0..ae0ca163f 100644 --- a/srsenb/src/phy/lte/sf_worker.cc +++ b/srsenb/src/phy/lte/sf_worker.cc @@ -285,11 +285,14 @@ uint32_t sf_worker::get_metrics(std::vector& 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; diff --git a/srsenb/src/phy/phy.cc b/srsenb/src/phy/phy.cc index c521f407e..d49b4dd6f 100644 --- a/srsenb/src/phy/phy.cc +++ b/srsenb/src/phy/phy.cc @@ -215,10 +215,12 @@ void phy::get_metrics(std::vector& 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& 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; } } diff --git a/srsenb/src/stack/mac/mac.cc b/srsenb/src/stack/mac/mac.cc index 2b7abc3b4..c9c187a89 100644 --- a/srsenb/src/stack/mac/mac.cc +++ b/srsenb/src/stack/mac/mac.cc @@ -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) diff --git a/srsenb/test/enb_metrics_test.cc b/srsenb/test/enb_metrics_test.cc index ebc3c60c0..f3e8d8f52 100644 --- a/srsenb/test/enb_metrics_test.cc +++ b/srsenb/test/enb_metrics_test.cc @@ -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; diff --git a/srsenb/test/phy/enb_phy_test.cc b/srsenb/test/phy/enb_phy_test.cc index eee341fe8..ab409dc01 100644 --- a/srsenb/test/phy/enb_phy_test.cc +++ b/srsenb/test/phy/enb_phy_test.cc @@ -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;