From 5968157ea58ffd6e8e5bad7f32aeba37ec621a60 Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Tue, 22 Sep 2020 14:32:08 +0200 Subject: [PATCH] Protect better the access to shared variables in phy_common and metrics (#1750) --- srsue/hdr/phy/cc_worker.h | 8 +- srsue/hdr/phy/phy_common.h | 101 ++++++++++---- srsue/hdr/phy/phy_metrics.h | 10 +- srsue/hdr/phy/sf_worker.h | 10 +- srsue/hdr/phy/sync.h | 2 +- srsue/src/metrics_csv.cc | 6 +- srsue/src/metrics_stdout.cc | 6 +- srsue/src/phy/cc_worker.cc | 111 +++------------- srsue/src/phy/phy.cc | 9 +- srsue/src/phy/phy_common.cc | 259 +++++++++++++++++++++++++++++------- srsue/src/phy/sf_worker.cc | 87 ++---------- srsue/src/phy/sync.cc | 4 +- srsue/test/metrics_test.cc | 4 +- 13 files changed, 346 insertions(+), 271 deletions(-) diff --git a/srsue/hdr/phy/cc_worker.h b/srsue/hdr/phy/cc_worker.h index e7a29a56e..e3ced18d0 100644 --- a/srsue/hdr/phy/cc_worker.h +++ b/srsue/hdr/phy/cc_worker.h @@ -44,7 +44,6 @@ public: void set_tti(uint32_t tti); void set_cfo(float cfo); - float get_ref_cfo() const; void set_tdd_config(srslte_tdd_config_t config); void set_config(srslte::phy_cfg_t& phy_cfg); @@ -61,7 +60,8 @@ public: int read_ce_abs(float* ce_abs, uint32_t tx_antenna, uint32_t rx_antenna); int read_pdsch_d(cf_t* pdsch_d); - void update_measurements(); + void update_measurements(std::vector& serving_cells, + cf_t* rssi_power_buffer = nullptr); private: void dl_phy_to_mac_grant(srslte_pdsch_grant_t* phy_grant, @@ -117,10 +117,6 @@ private: srslte_ue_ul_t ue_ul = {}; srslte_ue_ul_cfg_t ue_ul_cfg = {}; - // Metrics - dl_metrics_t dl_metrics = {}; - ul_metrics_t ul_metrics = {}; - // Mutex, for protecting what matters most: ue_ul, ue_ul_cfg, ue_dl, ue_dl_cfg, cell, pmch_cfg std::mutex mutex; }; diff --git a/srsue/hdr/phy/phy_common.h b/srsue/hdr/phy/phy_common.h index 7c1811268..2cbc12cc5 100644 --- a/srsue/hdr/phy/phy_common.h +++ b/srsue/hdr/phy/phy_common.h @@ -39,7 +39,7 @@ namespace srsue { -class chest_feedback_itf +class rsrp_insync_itf { public: virtual void in_sync() = 0; @@ -59,20 +59,6 @@ public: srslte::phy_cfg_mbsfn_t mbsfn_config = {}; - /* Power control variables */ - float pathloss[SRSLTE_MAX_CARRIERS] = {}; - float cur_pathloss = 0.0f; - float cur_pusch_power = 0.0f; - float avg_rsrp[SRSLTE_MAX_CARRIERS] = {}; - float avg_rsrp_dbm[SRSLTE_MAX_CARRIERS] = {}; - float avg_rsrq_db[SRSLTE_MAX_CARRIERS] = {}; - float avg_rssi_dbm[SRSLTE_MAX_CARRIERS] = {}; - float avg_cfo_hz[SRSLTE_MAX_CARRIERS] = {}; - float rx_gain_offset = 0.0f; - float avg_snr_db_cqi[SRSLTE_MAX_CARRIERS] = {}; - float avg_noise[SRSLTE_MAX_CARRIERS] = {}; - uint32_t pcell_report_period = 0; - // SCell EARFCN, PCI, configured and enabled list typedef struct { uint32_t earfcn = 0; @@ -97,7 +83,11 @@ public: ~phy_common(); - void init(phy_args_t* args, srslte::log* _log, srslte::radio_interface_phy* _radio, stack_interface_phy_lte* _stack); + void init(phy_args_t* args, + srslte::log* _log, + srslte::radio_interface_phy* _radio, + stack_interface_phy_lte* _stack, + rsrp_insync_itf* rsrp_insync); uint32_t ul_pidof(uint32_t tti, srslte_tdd_config_t* tdd_config); @@ -157,10 +147,15 @@ public: srslte::radio_interface_phy* get_radio(); - void set_dl_metrics(dl_metrics_t m, uint32_t cc_idx); + void set_dl_metrics(uint32_t cc_idx, const dl_metrics_t& m); void get_dl_metrics(dl_metrics_t m[SRSLTE_MAX_CARRIERS]); - void set_ul_metrics(ul_metrics_t m, uint32_t cc_idx); + + void set_ch_metrics(uint32_t cc_idx, const ch_metrics_t& m); + void get_ch_metrics(ch_metrics_t m[SRSLTE_MAX_CARRIERS]); + + void set_ul_metrics(uint32_t cc_idx, const ul_metrics_t& m); void get_ul_metrics(ul_metrics_t m[SRSLTE_MAX_CARRIERS]); + void set_sync_metrics(const uint32_t& cc_idx, const sync_metrics_t& m); void get_sync_metrics(sync_metrics_t m[SRSLTE_MAX_CARRIERS]); @@ -185,7 +180,58 @@ public: */ uint32_t get_ul_earfcn(uint32_t dl_earfcn); + void update_measurements(uint32_t cc_idx, + srslte_chest_dl_res_t chest_res, + srslte_dl_sf_cfg_t sf_cfg_dl, + float tx_crs_power, + std::vector& serving_cells, + cf_t* rssi_power_buffer = nullptr); + + void update_cfo_measurement(uint32_t cc_idx, float cfo_hz); + + float get_sinr_db(uint32_t cc_idx) + { + std::unique_lock lock(meas_mutex); + return avg_snr_db_cqi[cc_idx]; + } + + float get_pusch_power() + { + std::unique_lock lock(meas_mutex); + return cur_pusch_power; + } + + float get_pathloss() + { + std::unique_lock lock(meas_mutex); + return cur_pathloss; + } + + float get_rx_gain_offset() + { + std::unique_lock lock(meas_mutex); + return rx_gain_offset; + } + private: + std::mutex meas_mutex; + + float pathloss[SRSLTE_MAX_CARRIERS] = {}; + float cur_pathloss = 0.0f; + float cur_pusch_power = 0.0f; + float avg_rsrp[SRSLTE_MAX_CARRIERS] = {}; + float avg_rsrp_dbm[SRSLTE_MAX_CARRIERS] = {}; + float avg_rsrq_db[SRSLTE_MAX_CARRIERS] = {}; + float avg_rssi_dbm[SRSLTE_MAX_CARRIERS] = {}; + float avg_cfo_hz[SRSLTE_MAX_CARRIERS] = {}; + float rx_gain_offset = 0.0f; + float avg_snr_db_cqi[SRSLTE_MAX_CARRIERS] = {}; + float avg_noise[SRSLTE_MAX_CARRIERS] = {}; + uint32_t pcell_report_period = 0; + uint32_t rssi_read_cnt = 0; + + rsrp_insync_itf* insync_itf = nullptr; + bool have_mtch_stop = false; std::mutex mtch_mutex; std::condition_variable mtch_cvar; @@ -244,15 +290,16 @@ private: srslte_cell_t cell = {}; - dl_metrics_t dl_metrics[SRSLTE_MAX_CARRIERS] = {}; - uint32_t dl_metrics_count = 0; - bool dl_metrics_read = true; - ul_metrics_t ul_metrics[SRSLTE_MAX_CARRIERS] = {}; - uint32_t ul_metrics_count = 0; - bool ul_metrics_read = true; - sync_metrics_t sync_metrics[SRSLTE_MAX_CARRIERS] = {}; - uint32_t sync_metrics_count = 0; - bool sync_metrics_read = true; + std::mutex metrics_mutex; + + ch_metrics_t ch_metrics[SRSLTE_MAX_CARRIERS] = {}; + uint32_t ch_metrics_count[SRSLTE_MAX_CARRIERS] = {}; + dl_metrics_t dl_metrics[SRSLTE_MAX_CARRIERS] = {}; + uint32_t dl_metrics_count[SRSLTE_MAX_CARRIERS] = {}; + ul_metrics_t ul_metrics[SRSLTE_MAX_CARRIERS] = {}; + uint32_t ul_metrics_count[SRSLTE_MAX_CARRIERS] = {}; + sync_metrics_t sync_metrics[SRSLTE_MAX_CARRIERS] = {}; + uint32_t sync_metrics_count[SRSLTE_MAX_CARRIERS] = {}; // MBSFN bool sib13_configured = false; diff --git a/srsue/hdr/phy/phy_metrics.h b/srsue/hdr/phy/phy_metrics.h index 850986fb8..fbb17371d 100644 --- a/srsue/hdr/phy/phy_metrics.h +++ b/srsue/hdr/phy/phy_metrics.h @@ -37,19 +37,22 @@ struct sync_metrics_t { float sfo; }; -struct dl_metrics_t { +struct ch_metrics_t { float n; float sinr; float rsrp; float rsrq; float rssi; float ri; - float turbo_iters; - float mcs; float pathloss; float sync_err; }; +struct dl_metrics_t { + float turbo_iters; + float mcs; +}; + struct ul_metrics_t { float mcs; float power; @@ -58,6 +61,7 @@ struct ul_metrics_t { struct phy_metrics_t { info_metrics_t info[SRSLTE_MAX_CARRIERS]; sync_metrics_t sync[SRSLTE_MAX_CARRIERS]; + ch_metrics_t ch[SRSLTE_MAX_CARRIERS]; dl_metrics_t dl[SRSLTE_MAX_CARRIERS]; ul_metrics_t ul[SRSLTE_MAX_CARRIERS]; uint32_t nof_active_cc; diff --git a/srsue/hdr/phy/sf_worker.h b/srsue/hdr/phy/sf_worker.h index 8b2296f2c..8dcbb7a04 100644 --- a/srsue/hdr/phy/sf_worker.h +++ b/srsue/hdr/phy/sf_worker.h @@ -41,11 +41,7 @@ namespace srsue { class sf_worker : public srslte::thread_pool::worker { public: - sf_worker(uint32_t max_prb, - phy_common* phy, - srslte::log* log, - srslte::log* log_phy_lib_h, - chest_feedback_itf* chest_loop); + sf_worker(uint32_t max_prb, phy_common* phy, srslte::log* log, srslte::log* log_phy_lib_h); virtual ~sf_worker(); void reset(); @@ -77,7 +73,6 @@ public: } uint32_t get_rx_nof_antennas() { return phy->args->nof_rx_ant; } int read_pdsch_d(cf_t* pdsch_d); - float get_sync_error(); float get_cfo(); void start_plot(); @@ -96,8 +91,6 @@ private: srslte::log* log_phy_lib_h = nullptr; - chest_feedback_itf* chest_loop = nullptr; - srslte_cell_t cell = {}; std::mutex cell_mutex; srslte_tdd_config_t tdd_config = {}; @@ -111,7 +104,6 @@ private: uint32_t tti = 0; srslte::rf_timestamp_t tx_time = {}; - uint32_t rssi_read_cnt = 0; }; } // namespace srsue diff --git a/srsue/hdr/phy/sync.h b/srsue/hdr/phy/sync.h index 7dce0ba6a..bcdf9f6fc 100644 --- a/srsue/hdr/phy/sync.h +++ b/srsue/hdr/phy/sync.h @@ -48,7 +48,7 @@ namespace srsue { typedef _Complex float cf_t; -class sync : public srslte::thread, public chest_feedback_itf, public search_callback, public scell::sync_callback +class sync : public srslte::thread, public rsrp_insync_itf, public search_callback, public scell::sync_callback { public: sync() : thread("SYNC"), sf_buffer(sync_nof_rx_subframes), dummy_buffer(sync_nof_rx_subframes){}; diff --git a/srsue/src/metrics_csv.cc b/srsue/src/metrics_csv.cc index 8cdfdb739..eec69a27d 100644 --- a/srsue/src/metrics_csv.cc +++ b/srsue/src/metrics_csv.cc @@ -98,8 +98,8 @@ void metrics_csv::set_metrics(const ue_metrics_t& metrics, const uint32_t period file << metrics.phy.info[r].pci << ";"; // Print PHY metrics for first CC - file << float_to_string(metrics.phy.dl[r].rsrp, 2); - file << float_to_string(metrics.phy.dl[r].pathloss, 2); + file << float_to_string(metrics.phy.ch[r].rsrp, 2); + file << float_to_string(metrics.phy.ch[r].pathloss, 2); file << float_to_string(metrics.phy.sync[r].cfo, 2); // Find strongest neighbour for this EARFCN (cells are ordered) @@ -120,7 +120,7 @@ void metrics_csv::set_metrics(const ue_metrics_t& metrics, const uint32_t period } file << float_to_string(metrics.phy.dl[r].mcs, 2); - file << float_to_string(metrics.phy.dl[r].sinr, 2); + file << float_to_string(metrics.phy.ch[r].sinr, 2); file << float_to_string(metrics.phy.dl[r].turbo_iters, 2); if (metrics.stack.mac[r].rx_brate > 0) { diff --git a/srsue/src/metrics_stdout.cc b/srsue/src/metrics_stdout.cc index 4aeedf8bc..bd28ed789 100644 --- a/srsue/src/metrics_stdout.cc +++ b/srsue/src/metrics_stdout.cc @@ -118,8 +118,8 @@ void metrics_stdout::set_metrics(const ue_metrics_t& metrics, const uint32_t per for (uint32_t r = 0; r < metrics.phy.nof_active_cc; r++) { cout << std::setw(2) << r; cout << std::setw(4) << metrics.phy.info[r].pci << std::setw(0); - cout << float_to_string(metrics.phy.dl[r].rsrp, 2); - cout << float_to_string(metrics.phy.dl[r].pathloss, 2); + cout << float_to_string(metrics.phy.ch[r].rsrp, 2); + cout << float_to_string(metrics.phy.ch[r].pathloss, 2); cout << float_to_eng_string(metrics.phy.sync[r].cfo, 2); // Find strongest neighbour for this EARFCN (cells are ordered) @@ -140,7 +140,7 @@ void metrics_stdout::set_metrics(const ue_metrics_t& metrics, const uint32_t per } cout << float_to_string(metrics.phy.dl[r].mcs, 2); - cout << float_to_string(metrics.phy.dl[r].sinr, 2); + cout << float_to_string(metrics.phy.ch[r].sinr, 2); cout << float_to_string(metrics.phy.dl[r].turbo_iters, 2); cout << float_to_eng_string((float)metrics.stack.mac[r].rx_brate / (metrics.stack.mac[r].nof_tti * 1e-3), 2); diff --git a/srsue/src/phy/cc_worker.cc b/srsue/src/phy/cc_worker.cc index 8d0c831f8..fe0dc5715 100644 --- a/srsue/src/phy/cc_worker.cc +++ b/srsue/src/phy/cc_worker.cc @@ -117,9 +117,6 @@ cc_worker::~cc_worker() void cc_worker::reset() { - bzero(&dl_metrics, sizeof(dl_metrics_t)); - bzero(&ul_metrics, sizeof(ul_metrics_t)); - // constructor sets defaults srslte::phy_cfg_t empty_cfg; set_config(empty_cfg); @@ -184,11 +181,6 @@ void cc_worker::set_cfo(float cfo) ue_ul_cfg.cfo_value = cfo; } -float cc_worker::get_ref_cfo() const -{ - return ue_dl.chest_res.cfo; -} - void cc_worker::set_crnti(uint16_t rnti) { std::unique_lock lock(mutex); @@ -476,8 +468,14 @@ int cc_worker::decode_pdsch(srslte_pdsch_ack_resource_t ack_resource, if (decode_enable) { // Metrics - dl_metrics.mcs = ue_dl_cfg.cfg.pdsch.grant.tb[0].mcs_idx; + dl_metrics_t dl_metrics = {}; + if (ue_dl_cfg.cfg.pdsch.grant.nof_tb == 1) { + dl_metrics.mcs = ue_dl_cfg.cfg.pdsch.grant.tb[0].mcs_idx; + } else { + dl_metrics.mcs = (ue_dl_cfg.cfg.pdsch.grant.tb[0].mcs_idx + ue_dl_cfg.cfg.pdsch.grant.tb[1].mcs_idx) / 2; + } dl_metrics.turbo_iters = pdsch_dec->avg_iterations_block / 2; + phy->set_dl_metrics(cc_idx, dl_metrics); // Logging if (log_h->get_level() >= srslte::LOG_LEVEL_INFO) { @@ -508,7 +506,11 @@ int cc_worker::decode_pmch(mac_interface_phy_lte::tb_action_dl_t* action, srslte } // Store metrics - dl_metrics.mcs = pmch_cfg.pdsch_cfg.grant.tb[0].mcs_idx; + // Metrics + dl_metrics_t dl_metrics = {}; + dl_metrics.mcs = ue_dl_cfg.cfg.pdsch.grant.tb[0].mcs_idx; + dl_metrics.turbo_iters = pmch_dec.avg_iterations_block / 2; + phy->set_dl_metrics(cc_idx, dl_metrics); Info("PMCH: l_crb=%2d, tbs=%d, mcs=%d, crc=%s, snr=%.1f dB, n_iter=%.1f\n", pmch_cfg.pdsch_cfg.grant.nof_prb, @@ -552,85 +554,11 @@ void cc_worker::decode_phich() } } -void cc_worker::update_measurements() +void cc_worker::update_measurements(std::vector& serving_cells, + cf_t* rssi_power_buffer) { - std::unique_lock lock(mutex); - float snr_ema_coeff = phy->args->snr_ema_coeff; - - // In TDD, ignore special subframes without PDSCH - if (srslte_sfidx_tdd_type(sf_cfg_dl.tdd_config, CURRENT_SFIDX) == SRSLTE_TDD_SF_S && - srslte_sfidx_tdd_nof_dw(sf_cfg_dl.tdd_config) < 4) { - return; - } - - // Average RSRQ over DEFAULT_MEAS_PERIOD_MS then sent to RRC - float rsrq_db = ue_dl.chest_res.rsrq_db; - if (std::isnormal(rsrq_db)) { - if (!(CURRENT_TTI % phy->pcell_report_period) || !std::isnormal(phy->avg_rsrq_db[cc_idx])) { - phy->avg_rsrq_db[cc_idx] = rsrq_db; - } else { - phy->avg_rsrq_db[cc_idx] = - SRSLTE_VEC_CMA(rsrq_db, phy->avg_rsrq_db[cc_idx], CURRENT_TTI % phy->pcell_report_period); - } - } - - // Average RSRP taken from CRS - float rsrp_lin = ue_dl.chest_res.rsrp; - if (std::isnormal(rsrp_lin)) { - if (!std::isnormal(phy->avg_rsrp[cc_idx])) { - phy->avg_rsrp[cc_idx] = rsrp_lin; - } else { - phy->avg_rsrp[cc_idx] = SRSLTE_VEC_EMA(rsrp_lin, phy->avg_rsrp[cc_idx], snr_ema_coeff); - } - } - - /* Correct absolute power measurements by RX gain offset */ - float rsrp_dbm = ue_dl.chest_res.rsrp_dbm - phy->rx_gain_offset; - - // Serving cell RSRP measurements are averaged over DEFAULT_MEAS_PERIOD_MS then sent to RRC - if (std::isnormal(rsrp_dbm)) { - if (!(CURRENT_TTI % phy->pcell_report_period) || !std::isnormal(phy->avg_rsrp_dbm[cc_idx])) { - phy->avg_rsrp_dbm[cc_idx] = rsrp_dbm; - } else { - phy->avg_rsrp_dbm[cc_idx] = - SRSLTE_VEC_CMA(rsrp_dbm, phy->avg_rsrp_dbm[cc_idx], CURRENT_TTI % phy->pcell_report_period); - } - } - - // Compute PL - float tx_crs_power = ue_dl_cfg.cfg.pdsch.rs_power; - phy->pathloss[cc_idx] = tx_crs_power - phy->avg_rsrp_dbm[cc_idx]; - - // Average noise - float cur_noise = ue_dl.chest_res.noise_estimate; - if (std::isnormal(cur_noise)) { - if (!std::isnormal(phy->avg_noise[cc_idx])) { - phy->avg_noise[cc_idx] = cur_noise; - } else { - phy->avg_noise[cc_idx] = SRSLTE_VEC_EMA(cur_noise, phy->avg_noise[cc_idx], snr_ema_coeff); - } - } - - // Average snr in the log domain - if (std::isnormal(ue_dl.chest_res.snr_db)) { - if (!std::isnormal(phy->avg_snr_db_cqi[cc_idx])) { - phy->avg_snr_db_cqi[cc_idx] = ue_dl.chest_res.snr_db; - } else { - phy->avg_snr_db_cqi[cc_idx] = SRSLTE_VEC_EMA(ue_dl.chest_res.snr_db, phy->avg_snr_db_cqi[cc_idx], snr_ema_coeff); - } - } - - // Store metrics - dl_metrics.n = phy->avg_noise[cc_idx]; - dl_metrics.rsrp = phy->avg_rsrp_dbm[cc_idx]; - dl_metrics.rsrq = phy->avg_rsrq_db[cc_idx]; - dl_metrics.rssi = phy->avg_rssi_dbm[cc_idx]; - dl_metrics.pathloss = phy->pathloss[cc_idx]; - dl_metrics.sinr = phy->avg_snr_db_cqi[cc_idx]; - dl_metrics.sync_err = ue_dl.chest_res.sync_error; - - phy->set_dl_metrics(dl_metrics, cc_idx); - phy->set_ul_metrics(ul_metrics, cc_idx); + phy->update_measurements( + cc_idx, ue_dl.chest_res, sf_cfg_dl, ue_dl_cfg.cfg.pdsch.rs_power, serving_cells, rssi_power_buffer); } /************ @@ -835,7 +763,10 @@ bool cc_worker::encode_uplink(mac_interface_phy_lte::tb_action_ul_t* action, srs // Store metrics if (action->tb.enabled) { - ul_metrics.mcs = ue_ul_cfg.ul_cfg.pusch.grant.tb.mcs_idx; + ul_metrics_t ul_metrics = {}; + ul_metrics.mcs = ue_ul_cfg.ul_cfg.pusch.grant.tb.mcs_idx; + ul_metrics.power = 0; + phy->set_ul_metrics(cc_idx, ul_metrics); } // Logging @@ -866,7 +797,7 @@ uint32_t cc_worker::get_wideband_cqi() int cqi_fixed = phy->args->cqi_fixed; int cqi_max = phy->args->cqi_max; - uint32_t wb_cqi_value = srslte_cqi_from_snr(phy->avg_snr_db_cqi[cc_idx] + ue_dl_cfg.snr_to_cqi_offset); + uint32_t wb_cqi_value = srslte_cqi_from_snr(phy->get_sinr_db(cc_idx) + ue_dl_cfg.snr_to_cqi_offset); if (cqi_fixed >= 0) { wb_cqi_value = cqi_fixed; diff --git a/srsue/src/phy/phy.cc b/srsue/src/phy/phy.cc index 18e8650d5..e7eea09bf 100644 --- a/srsue/src/phy/phy.cc +++ b/srsue/src/phy/phy.cc @@ -180,12 +180,12 @@ void phy::run_thread() { std::unique_lock lock(config_mutex); prach_buffer.init(SRSLTE_MAX_PRB, log_h); - common.init(&args, (srslte::log*)log_vec[0].get(), radio, stack); + common.init(&args, (srslte::log*)log_vec[0].get(), radio, stack, &sfsync); // Add workers to workers pool and start threads for (uint32_t i = 0; i < nof_workers; i++) { auto w = std::unique_ptr(new sf_worker( - SRSLTE_MAX_PRB, &common, (srslte::log*)log_vec[i].get(), (srslte::log*)log_vec[nof_workers].get(), &sfsync)); + SRSLTE_MAX_PRB, &common, (srslte::log*)log_vec[i].get(), (srslte::log*)log_vec[nof_workers].get())); workers_pool.init_worker(i, w.get(), WORKERS_THREAD_PRIO, args.worker_cpu_mask); workers.push_back(std::move(w)); } @@ -248,6 +248,7 @@ void phy::get_metrics(phy_metrics_t* m) m->info[i].pci = common.scell_cfg[i].pci; } + common.get_ch_metrics(m->ch); common.get_dl_metrics(m->dl); common.get_ul_metrics(m->ul); common.get_sync_metrics(m->sync); @@ -322,13 +323,13 @@ bool phy::cell_is_camping() float phy::get_phr() { - float phr = radio->get_info()->max_tx_gain - common.cur_pusch_power; + float phr = radio->get_info()->max_tx_gain - common.get_pusch_power(); return phr; } float phy::get_pathloss_db() { - return common.cur_pathloss; + return common.get_pathloss(); } void phy::prach_send(uint32_t preamble_idx, int allowed_subframe, float target_power_dbm, float ta_base_sec) diff --git a/srsue/src/phy/phy_common.cc b/srsue/src/phy/phy_common.cc index e7d2ac54e..d458b5996 100644 --- a/srsue/src/phy/phy_common.cc +++ b/srsue/src/phy/phy_common.cc @@ -57,12 +57,14 @@ void phy_common::set_nof_workers(uint32_t nof_workers_) void phy_common::init(phy_args_t* _args, srslte::log* _log, srslte::radio_interface_phy* _radio, - stack_interface_phy_lte* _stack) + stack_interface_phy_lte* _stack, + rsrp_insync_itf* _chest_loop) { log_h = _log; radio_h = _radio; stack = _stack; args = _args; + insync_itf = _chest_loop; sr_last_tx_tti = -1; ta.set_logger(_log); @@ -603,75 +605,241 @@ void phy_common::set_cell(const srslte_cell_t& c) } } -void phy_common::set_dl_metrics(const dl_metrics_t m, uint32_t cc_idx) +void phy_common::update_cfo_measurement(uint32_t cc_idx, float cfo_hz) { - if (dl_metrics_read) { - bzero(dl_metrics, sizeof(dl_metrics_t) * SRSLTE_MAX_CARRIERS); - dl_metrics_count = 0; - dl_metrics_read = false; + std::unique_lock lock(meas_mutex); + + // use SNR EMA coefficient for averaging + avg_cfo_hz[cc_idx] = SRSLTE_VEC_EMA(cfo_hz, avg_cfo_hz[cc_idx], args->snr_ema_coeff); +} + +void phy_common::update_measurements(uint32_t cc_idx, + srslte_chest_dl_res_t chest_res, + srslte_dl_sf_cfg_t sf_cfg_dl, + float tx_crs_power, + std::vector& serving_cells, + cf_t* rssi_power_buffer) +{ + std::unique_lock lock(meas_mutex); + + float snr_ema_coeff = args->snr_ema_coeff; + + // In TDD, ignore special subframes without PDSCH + if (srslte_sfidx_tdd_type(sf_cfg_dl.tdd_config, sf_cfg_dl.tti % 10) == SRSLTE_TDD_SF_S && + srslte_sfidx_tdd_nof_dw(sf_cfg_dl.tdd_config) < 4) { + return; + } + + // Only worker 0 reads the RSSI sensor + if (rssi_power_buffer) { + + if (!rssi_read_cnt) { + // Average RSSI over all symbols in antenna port 0 (make sure SF length is non-zero) + float rssi_dbm = SRSLTE_SF_LEN_PRB(cell.nof_prb) > 0 ? (srslte_convert_power_to_dB(srslte_vec_avg_power_cf( + rssi_power_buffer, SRSLTE_SF_LEN_PRB(cell.nof_prb))) + + 30) + : 0; + if (std::isnormal(rssi_dbm)) { + avg_rssi_dbm[0] = SRSLTE_VEC_EMA(rssi_dbm, avg_rssi_dbm[0], args->snr_ema_coeff); + } + + rx_gain_offset = get_radio()->get_rx_gain() + args->rx_gain_offset; + } + rssi_read_cnt++; + if (rssi_read_cnt == 1000) { + rssi_read_cnt = 0; + } + } + + // Average RSRQ over DEFAULT_MEAS_PERIOD_MS then sent to RRC + float rsrq_db = chest_res.rsrq_db; + if (std::isnormal(rsrq_db)) { + if (!(sf_cfg_dl.tti % pcell_report_period) || !std::isnormal(avg_rsrq_db[cc_idx])) { + avg_rsrq_db[cc_idx] = rsrq_db; + } else { + avg_rsrq_db[cc_idx] = SRSLTE_VEC_CMA(rsrq_db, avg_rsrq_db[cc_idx], sf_cfg_dl.tti % pcell_report_period); + } + } + + // Average RSRP taken from CRS + float rsrp_lin = chest_res.rsrp; + if (std::isnormal(rsrp_lin)) { + if (!std::isnormal(avg_rsrp[cc_idx])) { + avg_rsrp[cc_idx] = rsrp_lin; + } else { + avg_rsrp[cc_idx] = SRSLTE_VEC_EMA(rsrp_lin, avg_rsrp[cc_idx], snr_ema_coeff); + } + } + + /* Correct absolute power measurements by RX gain offset */ + float rsrp_dbm = chest_res.rsrp_dbm - rx_gain_offset; + + // Serving cell RSRP measurements are averaged over DEFAULT_MEAS_PERIOD_MS then sent to RRC + if (std::isnormal(rsrp_dbm)) { + if (!(sf_cfg_dl.tti % pcell_report_period) || !std::isnormal(avg_rsrp_dbm[cc_idx])) { + avg_rsrp_dbm[cc_idx] = rsrp_dbm; + } else { + avg_rsrp_dbm[cc_idx] = SRSLTE_VEC_CMA(rsrp_dbm, avg_rsrp_dbm[cc_idx], sf_cfg_dl.tti % pcell_report_period); + } + } + + // Compute PL + pathloss[cc_idx] = tx_crs_power - avg_rsrp_dbm[cc_idx]; + + // Average noise + float cur_noise = chest_res.noise_estimate; + if (std::isnormal(cur_noise)) { + if (!std::isnormal(avg_noise[cc_idx])) { + avg_noise[cc_idx] = cur_noise; + } else { + avg_noise[cc_idx] = SRSLTE_VEC_EMA(cur_noise, avg_noise[cc_idx], snr_ema_coeff); + } + } + + // Average snr in the log domain + if (std::isnormal(chest_res.snr_db)) { + if (!std::isnormal(avg_snr_db_cqi[cc_idx])) { + avg_snr_db_cqi[cc_idx] = chest_res.snr_db; + } else { + avg_snr_db_cqi[cc_idx] = SRSLTE_VEC_EMA(chest_res.snr_db, avg_snr_db_cqi[cc_idx], snr_ema_coeff); + } } - dl_metrics_count++; - dl_metrics[cc_idx].mcs = dl_metrics[cc_idx].mcs + (m.mcs - dl_metrics[cc_idx].mcs) / dl_metrics_count; - dl_metrics[cc_idx].n = dl_metrics[cc_idx].n + (m.n - dl_metrics[cc_idx].n) / dl_metrics_count; - dl_metrics[cc_idx].rsrq = dl_metrics[cc_idx].rsrq + (m.rsrq - dl_metrics[cc_idx].rsrq) / dl_metrics_count; - dl_metrics[cc_idx].rssi = dl_metrics[cc_idx].rssi + (m.rssi - dl_metrics[cc_idx].rssi) / dl_metrics_count; - dl_metrics[cc_idx].rsrp = dl_metrics[cc_idx].rsrp + (m.rsrp - dl_metrics[cc_idx].rsrp) / dl_metrics_count; - dl_metrics[cc_idx].sinr = dl_metrics[cc_idx].sinr + (m.sinr - dl_metrics[cc_idx].sinr) / dl_metrics_count; - dl_metrics[cc_idx].sync_err = - dl_metrics[cc_idx].sync_err + (m.sync_err - dl_metrics[cc_idx].sync_err) / dl_metrics_count; - dl_metrics[cc_idx].pathloss = - dl_metrics[cc_idx].pathloss + (m.pathloss - dl_metrics[cc_idx].pathloss) / dl_metrics_count; + + // Store metrics + ch_metrics_t ch = {}; + ch.n = avg_noise[cc_idx]; + ch.rsrp = avg_rsrp_dbm[cc_idx]; + ch.rsrq = avg_rsrq_db[cc_idx]; + ch.rssi = avg_rssi_dbm[cc_idx]; + ch.pathloss = pathloss[cc_idx]; + ch.sinr = avg_snr_db_cqi[cc_idx]; + ch.sync_err = chest_res.sync_error; + + set_ch_metrics(cc_idx, ch); + + // Prepare measurements for serving cells + bool active = (cc_idx == 0 || scell_cfg[cc_idx].configured); + if (active && ((sf_cfg_dl.tti % pcell_report_period) == pcell_report_period - 1)) { + rrc_interface_phy_lte::phy_meas_t meas = {}; + meas.rsrp = avg_rsrp_dbm[cc_idx]; + meas.rsrq = avg_rsrq_db[cc_idx]; + meas.cfo_hz = avg_cfo_hz[cc_idx]; + // Save EARFCN and PCI for secondary cells, primary cell has earfcn=0 + if (cc_idx > 0) { + meas.earfcn = scell_cfg[cc_idx].earfcn; + meas.pci = scell_cfg[cc_idx].pci; + } + serving_cells.push_back(meas); + } + + // Check in-sync / out-sync conditions + if (avg_rsrp_dbm[0] > args->in_sync_rsrp_dbm_th && avg_snr_db_cqi[0] > args->in_sync_snr_db_th) { + log_h->debug( + "SNR=%.1f dB, RSRP=%.1f dBm sync=in-sync from channel estimator\n", avg_snr_db_cqi[0], avg_rsrp_dbm[0]); + if (insync_itf) { + insync_itf->in_sync(); + } + } else { + log_h->warning( + "SNR=%.1f dB RSRP=%.1f dBm, sync=out-of-sync from channel estimator\n", avg_snr_db_cqi[0], avg_rsrp_dbm[0]); + if (insync_itf) { + insync_itf->out_of_sync(); + } + } + // Call feedback loop for chest + if (cc_idx == 0) { + if (insync_itf && ((1U << (sf_cfg_dl.tti % 10U)) & args->cfo_ref_mask)) { + insync_itf->set_cfo(chest_res.cfo); + } + } +} + +void phy_common::set_dl_metrics(uint32_t cc_idx, const dl_metrics_t& m) +{ + std::unique_lock lock(metrics_mutex); + + dl_metrics_count[cc_idx]++; + dl_metrics[cc_idx].mcs = dl_metrics[cc_idx].mcs + (m.mcs - dl_metrics[cc_idx].mcs) / dl_metrics_count[cc_idx]; dl_metrics[cc_idx].turbo_iters = - dl_metrics[cc_idx].turbo_iters + (m.turbo_iters - dl_metrics[cc_idx].turbo_iters) / dl_metrics_count; + dl_metrics[cc_idx].turbo_iters + (m.turbo_iters - dl_metrics[cc_idx].turbo_iters) / dl_metrics_count[cc_idx]; } void phy_common::get_dl_metrics(dl_metrics_t m[SRSLTE_MAX_CARRIERS]) { - memcpy(m, dl_metrics, sizeof(dl_metrics_t) * SRSLTE_MAX_CARRIERS); - dl_metrics_read = true; + std::unique_lock lock(metrics_mutex); + + for (uint32_t i = 0; i < args->nof_carriers; i++) { + m[i] = dl_metrics[i]; + dl_metrics[i] = {}; + dl_metrics_count[i] = 0; + } } -void phy_common::set_ul_metrics(const ul_metrics_t m, uint32_t cc_idx) +void phy_common::set_ch_metrics(uint32_t cc_idx, const ch_metrics_t& m) { - if (ul_metrics_read) { - bzero(ul_metrics, sizeof(ul_metrics_t) * SRSLTE_MAX_CARRIERS); - ul_metrics_count = 0; - ul_metrics_read = false; - } - ul_metrics_count++; - for (uint32_t r = 0; r < args->nof_carriers; r++) { - ul_metrics[cc_idx].mcs = ul_metrics[cc_idx].mcs + (m.mcs - ul_metrics[cc_idx].mcs) / ul_metrics_count; - ul_metrics[cc_idx].power = ul_metrics[cc_idx].power + (m.power - ul_metrics[cc_idx].power) / ul_metrics_count; + std::unique_lock lock(metrics_mutex); + + ch_metrics_count[cc_idx]++; + ch_metrics[cc_idx].n = ch_metrics[cc_idx].n + (m.n - ch_metrics[cc_idx].n) / ch_metrics_count[cc_idx]; + ch_metrics[cc_idx].rsrq = ch_metrics[cc_idx].rsrq + (m.rsrq - ch_metrics[cc_idx].rsrq) / ch_metrics_count[cc_idx]; + ch_metrics[cc_idx].rssi = ch_metrics[cc_idx].rssi + (m.rssi - ch_metrics[cc_idx].rssi) / ch_metrics_count[cc_idx]; + ch_metrics[cc_idx].rsrp = ch_metrics[cc_idx].rsrp + (m.rsrp - ch_metrics[cc_idx].rsrp) / ch_metrics_count[cc_idx]; + ch_metrics[cc_idx].sinr = ch_metrics[cc_idx].sinr + (m.sinr - ch_metrics[cc_idx].sinr) / ch_metrics_count[cc_idx]; + ch_metrics[cc_idx].sync_err = + ch_metrics[cc_idx].sync_err + (m.sync_err - ch_metrics[cc_idx].sync_err) / ch_metrics_count[cc_idx]; + ch_metrics[cc_idx].pathloss = + ch_metrics[cc_idx].pathloss + (m.pathloss - ch_metrics[cc_idx].pathloss) / ch_metrics_count[cc_idx]; +} + +void phy_common::get_ch_metrics(ch_metrics_t m[SRSLTE_MAX_CARRIERS]) +{ + std::unique_lock lock(metrics_mutex); + + for (uint32_t i = 0; i < args->nof_carriers; i++) { + m[i] = ch_metrics[i]; + ch_metrics[i] = {}; + ch_metrics_count[i] = 0; } } +void phy_common::set_ul_metrics(uint32_t cc_idx, const ul_metrics_t& m) +{ + std::unique_lock lock(metrics_mutex); + + ul_metrics_count[cc_idx]++; + ul_metrics[cc_idx].mcs = ul_metrics[cc_idx].mcs + (m.mcs - ul_metrics[cc_idx].mcs) / ul_metrics_count[cc_idx]; + ul_metrics[cc_idx].power = ul_metrics[cc_idx].power + (m.power - ul_metrics[cc_idx].power) / ul_metrics_count[cc_idx]; +} + void phy_common::get_ul_metrics(ul_metrics_t m[SRSLTE_MAX_CARRIERS]) { - memcpy(m, ul_metrics, sizeof(ul_metrics_t) * SRSLTE_MAX_CARRIERS); - ul_metrics_read = true; + std::unique_lock lock(metrics_mutex); + + for (uint32_t i = 0; i < args->nof_carriers; i++) { + m[i] = ul_metrics[i]; + ul_metrics[i] = {}; + ul_metrics_count[i] = 0; + } } void phy_common::set_sync_metrics(const uint32_t& cc_idx, const sync_metrics_t& m) { - if (sync_metrics_read) { - sync_metrics[cc_idx] = m; - sync_metrics_count = 1; - if (cc_idx == 0) - sync_metrics_read = false; - } else { - if (cc_idx == 0) - sync_metrics_count++; - sync_metrics[cc_idx].cfo = sync_metrics[cc_idx].cfo + (m.cfo - sync_metrics[cc_idx].cfo) / sync_metrics_count; - sync_metrics[cc_idx].sfo = sync_metrics[cc_idx].sfo + (m.sfo - sync_metrics[cc_idx].sfo) / sync_metrics_count; - } + std::unique_lock lock(metrics_mutex); + + sync_metrics_count[cc_idx]++; + sync_metrics[cc_idx].cfo = sync_metrics[cc_idx].cfo + (m.cfo - sync_metrics[cc_idx].cfo) / sync_metrics_count[cc_idx]; + sync_metrics[cc_idx].sfo = sync_metrics[cc_idx].sfo + (m.sfo - sync_metrics[cc_idx].sfo) / sync_metrics_count[cc_idx]; } void phy_common::get_sync_metrics(sync_metrics_t m[SRSLTE_MAX_CARRIERS]) { + std::unique_lock lock(metrics_mutex); + for (uint32_t i = 0; i < args->nof_carriers; i++) { - m[i] = sync_metrics[i]; + m[i] = sync_metrics[i]; + sync_metrics[i] = {}; + sync_metrics_count[i] = 0; } - sync_metrics_read = true; } void phy_common::reset_radio() @@ -691,7 +859,6 @@ void phy_common::reset() cur_pathloss = 0; cur_pusch_power = 0; sr_last_tx_tti = -1; - cur_pusch_power = 0; pcell_report_period = 20; ZERO_OBJECT(pathloss); diff --git a/srsue/src/phy/sf_worker.cc b/srsue/src/phy/sf_worker.cc index 4a7573cce..7c473838a 100644 --- a/srsue/src/phy/sf_worker.cc +++ b/srsue/src/phy/sf_worker.cc @@ -55,16 +55,11 @@ static int plot_worker_id = -1; namespace srsue { -sf_worker::sf_worker(uint32_t max_prb, - phy_common* phy_, - srslte::log* log_h_, - srslte::log* log_phy_lib_h_, - chest_feedback_itf* chest_loop_) +sf_worker::sf_worker(uint32_t max_prb, phy_common* phy_, srslte::log* log_h_, srslte::log* log_phy_lib_h_) { phy = phy_; log_h = log_h_; log_phy_lib_h = log_phy_lib_h_; - chest_loop = chest_loop_; // ue_sync in phy.cc requires a buffer for 3 subframes for (uint32_t r = 0; r < phy->args->nof_carriers; r++) { @@ -81,7 +76,6 @@ sf_worker::~sf_worker() void sf_worker::reset() { - rssi_read_cnt = 0; for (auto& cc_worker : cc_workers) { cc_worker->reset(); } @@ -270,11 +264,6 @@ void sf_worker::work_imp() update_measurements(); } - // Call feedback loop for chest - if (chest_loop && ((1U << (tti % 10U)) & phy->args->cfo_ref_mask)) { - chest_loop->set_cfo(cc_workers[0]->get_ref_cfo()); - } - /* Tell the plotting thread to draw the plots */ #ifdef ENABLE_GUI if ((int)get_id() == plot_worker_id) { @@ -294,66 +283,20 @@ void sf_worker::reset_uci(srslte_uci_data_t* uci_data) void sf_worker::update_measurements() { - /* Only worker 0 reads the RSSI sensor every ~1-nof_cores s */ + // Run measurements in all carriers, but only in one worker if (get_id() == 0) { - - // Average RSSI over all symbols in antenna port 0 (make sure SF length is non-zero) - float rssi_dbm = SRSLTE_SF_LEN_PRB(cell.nof_prb) > 0 - ? (srslte_convert_power_to_dB(srslte_vec_avg_power_cf(cc_workers[0]->get_rx_buffer(0), - SRSLTE_SF_LEN_PRB(cell.nof_prb))) + - 30) - : 0; - if (std::isnormal(rssi_dbm)) { - phy->avg_rssi_dbm[0] = SRSLTE_VEC_EMA(rssi_dbm, phy->avg_rssi_dbm[0], phy->args->snr_ema_coeff); - } - - if (!rssi_read_cnt) { - phy->rx_gain_offset = phy->get_radio()->get_rx_gain() + phy->args->rx_gain_offset; - } - rssi_read_cnt++; - if (rssi_read_cnt == 1000) { - rssi_read_cnt = 0; - } - } - - // Run measurements in all carriers - std::vector serving_cells = {}; - for (uint32_t cc_idx = 0; cc_idx < cc_workers.size(); cc_idx++) { - bool active = (cc_idx == 0 || phy->scell_cfg[cc_idx].configured); - - // Update measurement of the Component Carrier - cc_workers[cc_idx]->update_measurements(); - - // Send measurements for serving cells - if (active && ((tti % phy->pcell_report_period) == phy->pcell_report_period - 1)) { - rrc_interface_phy_lte::phy_meas_t meas = {}; - meas.rsrp = phy->avg_rsrp_dbm[cc_idx]; - meas.rsrq = phy->avg_rsrq_db[cc_idx]; - meas.cfo_hz = phy->avg_cfo_hz[cc_idx]; - // Save EARFCN and PCI for secondary cells, primary cell has earfcn=0 - if (cc_idx > 0) { - meas.earfcn = phy->scell_cfg[cc_idx].earfcn; - meas.pci = phy->scell_cfg[cc_idx].pci; + std::vector serving_cells = {}; + for (uint32_t cc_idx = 0; cc_idx < cc_workers.size(); cc_idx++) { + cf_t* rssi_power_buffer = nullptr; + if (cc_idx == 0) { + rssi_power_buffer = cc_workers[0]->get_rx_buffer(0); } - serving_cells.push_back(meas); + cc_workers[cc_idx]->update_measurements(serving_cells, rssi_power_buffer); + } + // Send report to stack + if (not serving_cells.empty()) { + phy->stack->new_cell_meas(serving_cells); } - } - // Send report to stack - if (not serving_cells.empty()) { - phy->stack->new_cell_meas(serving_cells); - } - - // Check in-sync / out-sync conditions - if (phy->avg_rsrp_dbm[0] > phy->args->in_sync_rsrp_dbm_th && phy->avg_snr_db_cqi[0] > phy->args->in_sync_snr_db_th) { - log_h->debug("SNR=%.1f dB, RSRP=%.1f dBm sync=in-sync from channel estimator\n", - phy->avg_snr_db_cqi[0], - phy->avg_rsrp_dbm[0]); - chest_loop->in_sync(); - } else { - log_h->warning("SNR=%.1f dB RSRP=%.1f dBm, sync=out-of-sync from channel estimator\n", - phy->avg_snr_db_cqi[0], - phy->avg_rsrp_dbm[0]); - chest_loop->out_of_sync(); } } @@ -387,12 +330,6 @@ int sf_worker::read_pdsch_d(cf_t* pdsch_d) { return cc_workers[0]->read_pdsch_d(pdsch_d); } -float sf_worker::get_sync_error() -{ - dl_metrics_t dl_metrics[SRSLTE_MAX_CARRIERS] = {}; - phy->get_dl_metrics(dl_metrics); - return dl_metrics->sync_err; -} float sf_worker::get_cfo() { diff --git a/srsue/src/phy/sync.cc b/srsue/src/phy/sync.cc index 2beddbb7f..40aeca48b 100644 --- a/srsue/src/phy/sync.cc +++ b/srsue/src/phy/sync.cc @@ -445,7 +445,7 @@ void sync::run_camping_in_sync_state(sf_worker* worker, srslte::rf_buffer_t& syn // Set CFO for all Carriers for (uint32_t cc = 0; cc < worker_com->args->nof_carriers; cc++) { worker->set_cfo(cc, get_tx_cfo()); - worker_com->avg_cfo_hz[cc] = srslte_ue_sync_get_cfo(&ue_sync); + worker_com->update_cfo_measurement(cc, srslte_ue_sync_get_cfo(&ue_sync)); } worker->set_tti(tti); @@ -870,7 +870,7 @@ int sync::radio_recv_fnc(srslte::rf_buffer_t& data, srslte_timestamp_t* rx_time) intra_freq_meas[i]->write(tti, data.get(i, 0, worker_com->args->nof_rx_ant), SRSLTE_SF_LEN_PRB(cell.nof_prb)); // Update RX gain - intra_freq_meas[i]->set_rx_gain_offset(worker_com->rx_gain_offset); + intra_freq_meas[i]->set_rx_gain_offset(worker_com->get_rx_gain_offset()); } } diff --git a/srsue/test/metrics_test.cc b/srsue/test/metrics_test.cc index 3415c9098..68dfff327 100644 --- a/srsue/test/metrics_test.cc +++ b/srsue/test/metrics_test.cc @@ -46,8 +46,8 @@ public: bzero(m, sizeof(ue_metrics_t)); m->rf.rf_o = 10; m->phy.nof_active_cc = 2; - m->phy.dl[0].rsrp = -10.0f; - m->phy.dl[0].pathloss = 74; + m->phy.ch[0].rsrp = -10.0f; + m->phy.ch[0].pathloss = 74; m->stack.mac[0].rx_pkts = 100; m->stack.mac[0].rx_errors = 0;