From cf647b1fd5e65209e95be2aa861b1de36c1d8fcb Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Fri, 18 Feb 2022 14:57:03 +0100 Subject: [PATCH] srsenb,metrics: add PUSCH/PUCCH RSSI metrics. Add bearer DL total data metric for RLC UM --- lib/include/srsran/phy/phch/pucch.h | 1 + lib/include/srsran/phy/utils/vector.h | 9 +++++++++ lib/src/pdcp/pdcp_entity_lte.cc | 4 ++++ lib/src/phy/ch_estimation/chest_ul.c | 5 ++++- lib/src/phy/enb/enb_ul.c | 3 ++- srsenb/enb.conf.example | 3 ++- srsenb/hdr/phy/lte/cc_worker.h | 2 +- srsenb/hdr/phy/phy_interfaces.h | 1 + srsenb/hdr/phy/phy_metrics.h | 28 +++++++++++---------------- srsenb/src/main.cc | 1 + srsenb/src/phy/lte/cc_worker.cc | 20 +++++++++++++++---- srsenb/src/phy/lte/sf_worker.cc | 16 ++++++++------- srsenb/src/phy/phy.cc | 22 +++++++++++++-------- 13 files changed, 75 insertions(+), 40 deletions(-) diff --git a/lib/include/srsran/phy/phch/pucch.h b/lib/include/srsran/phy/phch/pucch.h index 73c7ec6a1..5a70a676f 100644 --- a/lib/include/srsran/phy/phch/pucch.h +++ b/lib/include/srsran/phy/phch/pucch.h @@ -75,6 +75,7 @@ typedef struct SRSRAN_API { srsran_uci_value_t uci_data; float dmrs_correlation; float snr_db; + float rsrp_db; float correlation; bool detected; diff --git a/lib/include/srsran/phy/utils/vector.h b/lib/include/srsran/phy/utils/vector.h index 83385638a..d94d640ec 100644 --- a/lib/include/srsran/phy/utils/vector.h +++ b/lib/include/srsran/phy/utils/vector.h @@ -61,6 +61,15 @@ extern "C" { // Proportional moving average #define SRSRAN_VEC_PMA(average1, n1, average2, n2) (((average1) * (n1) + (average2) * (n2)) / ((n1) + (n2))) +// Safe Proportional moving average +#ifdef __cplusplus +#define SRSRAN_VEC_SAFE_PMA(average1, n1, average2, n2) \ + (std::isnormal((n1) + (n2)) ? SRSRAN_VEC_PMA(average1, n1, average2, n2) : (0)) +#else +#define SRSRAN_VEC_SAFE_PMA(average1, n1, average2, n2) \ + (isnormal((n1) + (n2)) ? SRSRAN_VEC_PMA(average1, n1, average2, n2) : (0)) +#endif + // Exponential moving average #define SRSRAN_VEC_EMA(data, average, alpha) ((alpha) * (data) + (1 - alpha) * (average)) diff --git a/lib/src/pdcp/pdcp_entity_lte.cc b/lib/src/pdcp/pdcp_entity_lte.cc index 8047ad6da..0491e246a 100644 --- a/lib/src/pdcp/pdcp_entity_lte.cc +++ b/lib/src/pdcp/pdcp_entity_lte.cc @@ -221,6 +221,10 @@ void pdcp_entity_lte::write_sdu(unique_byte_buffer_t sdu, int upper_sn) // Pass PDU to lower layers metrics.num_tx_pdus++; metrics.num_tx_pdu_bytes += sdu->N_bytes; + // Count TX'd bytes as if they were ACK'd if RLC is UM + if (rlc->rb_is_um(lcid)) { + metrics.num_tx_acked_bytes = metrics.num_tx_pdu_bytes; + } rlc->write_sdu(lcid, std::move(sdu)); } diff --git a/lib/src/phy/ch_estimation/chest_ul.c b/lib/src/phy/ch_estimation/chest_ul.c index 00873f077..056845966 100644 --- a/lib/src/phy/ch_estimation/chest_ul.c +++ b/lib/src/phy/ch_estimation/chest_ul.c @@ -347,13 +347,16 @@ static void chest_ul_estimate(srsran_chest_ul_t* q, } // Estimate received pilot power + float signal_power = srsran_vec_avg_power_cf(q->pilot_recv_signal, nslots * nrefs_sym); if (isnormal(res->noise_estimate)) { - res->snr = srsran_vec_avg_power_cf(q->pilot_recv_signal, nslots * nrefs_sym) / res->noise_estimate; + res->snr = signal_power / res->noise_estimate; } else { res->snr = NAN; } // Convert measurements in logarithm scale + res->rsrp = signal_power; + res->rsrp_dBfs = srsran_convert_power_to_dB(signal_power); res->snr_db = srsran_convert_power_to_dB(res->snr); res->noise_estimate_dbm = srsran_convert_power_to_dBm(res->noise_estimate); } diff --git a/lib/src/phy/enb/enb_ul.c b/lib/src/phy/enb/enb_ul.c index 605fe7295..d8bffa553 100644 --- a/lib/src/phy/enb/enb_ul.c +++ b/lib/src/phy/enb/enb_ul.c @@ -184,7 +184,8 @@ static int get_pucch(srsran_enb_ul_t* q, srsran_ul_sf_cfg_t* ul_sf, srsran_pucch ERROR("Error estimating PUCCH DMRS"); return SRSRAN_ERROR; } - pucch_res.snr_db = q->chest_res.snr_db; + pucch_res.snr_db = q->chest_res.snr_db; + pucch_res.rsrp_db = q->chest_res.rsrp_dBfs; ret = srsran_pucch_decode(&q->pucch, ul_sf, cfg, &q->chest_res, q->sf_symbols, &pucch_res); if (ret < SRSRAN_SUCCESS) { diff --git a/srsenb/enb.conf.example b/srsenb/enb.conf.example index c18387112..505771a05 100644 --- a/srsenb/enb.conf.example +++ b/srsenb/enb.conf.example @@ -387,7 +387,7 @@ nr_pdsch_mcs=28 # rlf_release_timer_ms: Time taken by eNB to release UE context after it detects a RLF # rlf_min_ul_snr_estim: SNR threshold in dB below which the enb is notified with RLF ko # s1_setup_max_retries: Maximum amount of retries to setup the S1AP connection. If this value is exceeded, an alarm is written to the log. -1 means infinity. -# +# rx_gain_offset: RX Gain offset to add to rx_gain to calibrate RSRP readings ##################################################################### [expert] #pusch_max_its = 8 # These are half iterations @@ -423,3 +423,4 @@ nr_pdsch_mcs=28 #rlf_release_timer_ms = 4000 #rlf_min_ul_snr_estim = -2 #s1_setup_max_retries = -1 +#rx_gain_offset = 62 diff --git a/srsenb/hdr/phy/lte/cc_worker.h b/srsenb/hdr/phy/lte/cc_worker.h index 2edbe6547..aa64e6490 100644 --- a/srsenb/hdr/phy/lte/cc_worker.h +++ b/srsenb/hdr/phy/lte/cc_worker.h @@ -100,7 +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); + void metrics_ul_pucch(float rssi, float sinr); uint32_t get_rnti() const { return rnti; } private: diff --git a/srsenb/hdr/phy/phy_interfaces.h b/srsenb/hdr/phy/phy_interfaces.h index 0caf92528..661860ab8 100644 --- a/srsenb/hdr/phy/phy_interfaces.h +++ b/srsenb/hdr/phy/phy_interfaces.h @@ -50,6 +50,7 @@ struct phy_args_t { std::string type; srsran::phy_log_args_t log; + float rx_gain_offset = 62; float max_prach_offset_us = 10; uint32_t pusch_max_its = 10; uint32_t nr_pusch_max_its = 10; diff --git a/srsenb/hdr/phy/phy_metrics.h b/srsenb/hdr/phy/phy_metrics.h index 0b27a5417..a89d0196a 100644 --- a/srsenb/hdr/phy/phy_metrics.h +++ b/srsenb/hdr/phy/phy_metrics.h @@ -20,28 +20,22 @@ namespace srsenb { // PHY metrics per user struct ul_metrics_t { - float n; - float pusch_sinr; - // Initialize this member with an invalid value as this field is optional. - float pusch_rssi = std::numeric_limits::quiet_NaN(); - // Initialize this member with an invalid value as this field is optional. - int64_t pusch_tpc = 0; + float n; + float pusch_sinr; + float pusch_rssi; + int64_t pusch_tpc; float pucch_sinr; - // Initialize this member with an invalid value as this field is optional. - float pucch_rssi = std::numeric_limits::quiet_NaN(); - // Initialize this member with an invalid value as this field is optional. - float pucch_ni = std::numeric_limits::quiet_NaN(); - float rssi; - float turbo_iters; - float mcs; - int n_samples; - int n_samples_pucch; + float pucch_rssi; + float pucch_ni; + float turbo_iters; + float mcs; + int n_samples; + int n_samples_pucch; }; struct dl_metrics_t { float mcs; - // Initialize this member with an invalid value as this field is optional. - int64_t pucch_tpc = 0; + int64_t pucch_tpc; int n_samples; }; diff --git a/srsenb/src/main.cc b/srsenb/src/main.cc index 2118e1048..975abee54 100644 --- a/srsenb/src/main.cc +++ b/srsenb/src/main.cc @@ -259,6 +259,7 @@ void parse_args(all_args_t* args, int argc, char* argv[]) ("expert.ts1_reloc_overall_timeout", bpo::value(&args->stack.s1ap.ts1_reloc_overall_timeout)->default_value(10000), "S1AP TS 36.413 TS1RelocOverall Expiry Timeout value in milliseconds.") ("expert.rlf_min_ul_snr_estim", bpo::value(&args->stack.mac.rlf_min_ul_snr_estim)->default_value(-2), "SNR threshold in dB below which the eNB is notified with rlf ko.") ("expert.max_s1_setup_retries", bpo::value(&args->stack.s1ap.max_s1_setup_retries)->default_value(-1), "Max S1 setup retries") + ("expert.rx_gain_offset", bpo::value(&args->phy.rx_gain_offset)->default_value(62), "RX Gain offset to add to rx_gain to calibrate RSRP readings") // eMBMS section ("embms.enable", bpo::value(&args->stack.embms.enable)->default_value(false), "Enables MBMS in the eNB") diff --git a/srsenb/src/phy/lte/cc_worker.cc b/srsenb/src/phy/lte/cc_worker.cc index aa17fb709..1193587da 100644 --- a/srsenb/src/phy/lte/cc_worker.cc +++ b/srsenb/src/phy/lte/cc_worker.cc @@ -363,7 +363,10 @@ bool cc_worker::decode_pusch_rnti(stack_interface_phy_lte::ul_sched_grant_t& ul_ // Save statistics only if data was provided if (ul_grant.data != nullptr) { // Save metrics stats - ue_db[rnti]->metrics_ul(ul_grant.dci.tb.mcs_idx, 0, enb_ul.chest_res.snr_db, pusch_res.avg_iterations_block); + ue_db[rnti]->metrics_ul(ul_grant.dci.tb.mcs_idx, + enb_ul.chest_res.rsrp_dBfs - phy->params.rx_gain_offset, + enb_ul.chest_res.snr_db, + pusch_res.avg_iterations_block); } return true; } @@ -451,7 +454,9 @@ int cc_worker::decode_pucch() } // Save metrics - ue_db[rnti]->metrics_ul_pucch(pucch_res.snr_db); + if (pucch_res.detected) { + ue_db[rnti]->metrics_ul_pucch(pucch_res.rsrp_db - phy->params.rx_gain_offset, pucch_res.snr_db); + } } } } @@ -666,15 +671,22 @@ 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) { + if (isnan(rssi)) { + rssi = 0; + } metrics.ul.mcs = SRSRAN_VEC_CMA((float)mcs, metrics.ul.mcs, metrics.ul.n_samples); metrics.ul.pusch_sinr = SRSRAN_VEC_CMA((float)sinr, metrics.ul.pusch_sinr, metrics.ul.n_samples); - metrics.ul.rssi = SRSRAN_VEC_CMA((float)rssi, metrics.ul.rssi, metrics.ul.n_samples); + metrics.ul.pusch_rssi = SRSRAN_VEC_CMA((float)rssi, metrics.ul.pusch_rssi, metrics.ul.n_samples); metrics.ul.turbo_iters = SRSRAN_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) +void cc_worker::ue::metrics_ul_pucch(float rssi, float sinr) { + if (isnan(rssi)) { + rssi = 0; + } + metrics.ul.pucch_rssi = SRSRAN_VEC_CMA((float)rssi, metrics.ul.pucch_rssi, metrics.ul.n_samples_pucch); metrics.ul.pucch_sinr = SRSRAN_VEC_CMA((float)sinr, metrics.ul.pucch_sinr, metrics.ul.n_samples_pucch); metrics.ul.n_samples_pucch++; } diff --git a/srsenb/src/phy/lte/sf_worker.cc b/srsenb/src/phy/lte/sf_worker.cc index 8353d345e..05c09b32f 100644 --- a/srsenb/src/phy/lte/sf_worker.cc +++ b/srsenb/src/phy/lte/sf_worker.cc @@ -268,15 +268,17 @@ uint32_t sf_worker::get_metrics(std::vector& metrics) for (uint32_t r = 0; r < cnt; r++) { phy_metrics_t* m = &metrics[r]; phy_metrics_t* m_ = &metrics_[r]; - m->dl.mcs = SRSRAN_VEC_PMA(m->dl.mcs, m->dl.n_samples, m_->dl.mcs, m_->dl.n_samples); + m->dl.mcs = SRSRAN_VEC_SAFE_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 = SRSRAN_VEC_PMA(m->ul.n, m->ul.n_samples, m_->ul.n, m_->ul.n_samples); - m->ul.pusch_sinr = SRSRAN_VEC_PMA(m->ul.pusch_sinr, m->ul.n_samples, m_->ul.pusch_sinr, m_->ul.n_samples); + m->ul.n = SRSRAN_VEC_SAFE_PMA(m->ul.n, m->ul.n_samples, m_->ul.n, m_->ul.n_samples); + m->ul.pusch_sinr = SRSRAN_VEC_SAFE_PMA(m->ul.pusch_sinr, m->ul.n_samples, m_->ul.pusch_sinr, m_->ul.n_samples); m->ul.pucch_sinr = - SRSRAN_VEC_PMA(m->ul.pucch_sinr, m->ul.n_samples_pucch, m_->ul.pucch_sinr, m_->ul.n_samples_pucch); - m->ul.mcs = SRSRAN_VEC_PMA(m->ul.mcs, m->ul.n_samples, m_->ul.mcs, m_->ul.n_samples); - m->ul.rssi = SRSRAN_VEC_PMA(m->ul.rssi, m->ul.n_samples, m_->ul.rssi, m_->ul.n_samples); - m->ul.turbo_iters = SRSRAN_VEC_PMA(m->ul.turbo_iters, m->ul.n_samples, m_->ul.turbo_iters, m_->ul.n_samples); + SRSRAN_VEC_SAFE_PMA(m->ul.pucch_sinr, m->ul.n_samples_pucch, m_->ul.pucch_sinr, m_->ul.n_samples_pucch); + m->ul.mcs = SRSRAN_VEC_SAFE_PMA(m->ul.mcs, m->ul.n_samples, m_->ul.mcs, m_->ul.n_samples); + m->ul.pusch_rssi = SRSRAN_VEC_SAFE_PMA(m->ul.pusch_rssi, m->ul.n_samples, m_->ul.pusch_rssi, m_->ul.n_samples); + m->ul.pucch_rssi = + SRSRAN_VEC_SAFE_PMA(m->ul.pucch_rssi, m->ul.n_samples_pucch, m_->ul.pucch_rssi, m_->ul.n_samples_pucch); + m->ul.turbo_iters = SRSRAN_VEC_SAFE_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; } diff --git a/srsenb/src/phy/phy.cc b/srsenb/src/phy/phy.cc index 8a185187a..4434d53d4 100644 --- a/srsenb/src/phy/phy.cc +++ b/srsenb/src/phy/phy.cc @@ -252,20 +252,26 @@ void phy::get_metrics(std::vector& metrics) 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.pusch_rssi += metrics_tmp[j].ul.n_samples * metrics_tmp[j].ul.pusch_rssi; metrics[j].ul.pusch_sinr += metrics_tmp[j].ul.n_samples * metrics_tmp[j].ul.pusch_sinr; + metrics[j].ul.pucch_rssi += metrics_tmp[j].ul.n_samples_pucch * metrics_tmp[j].ul.pucch_rssi; 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; } } for (uint32_t j = 0; j < metrics.size(); j++) { - metrics[j].dl.mcs /= metrics[j].dl.n_samples; - 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.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; + if (metrics[j].dl.n_samples > 0) { + metrics[j].dl.mcs /= metrics[j].dl.n_samples; + } + if (metrics[j].ul.n_samples > 0) { + metrics[j].ul.mcs /= metrics[j].ul.n_samples; + metrics[j].ul.n /= metrics[j].ul.n_samples; + metrics[j].ul.pusch_rssi /= metrics[j].ul.n_samples; + metrics[j].ul.pusch_sinr /= metrics[j].ul.n_samples; + metrics[j].ul.pucch_rssi /= metrics[j].ul.n_samples_pucch; + metrics[j].ul.pucch_sinr /= metrics[j].ul.n_samples_pucch; + metrics[j].ul.turbo_iters /= metrics[j].ul.n_samples; + } } }