From b94d24ed9862c89a33ee6969666a00a61a80b721 Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Wed, 23 Sep 2020 21:46:03 +0200 Subject: [PATCH] Take into account CRS from neigbhour cells when measuring interference (#1757) * Take into account CRS from neigbhour cells when measuring interference * fix std::isnormal compilation * Fixed compilation of test * Address comments * Remove unused overrides --- .../srslte/phy/ch_estimation/refsignal_dl.h | 2 ++ lib/src/phy/ch_estimation/refsignal_dl.c | 12 +++++++++ srsue/hdr/phy/phy_common.h | 26 +++++++++++++++++++ srsue/hdr/phy/scell/intra_measure.h | 13 ++++++++-- srsue/hdr/phy/sync.h | 10 ++++++- srsue/src/phy/phy_common.cc | 20 +++++++++++--- srsue/src/phy/scell/intra_measure.cc | 11 +++++--- srsue/src/phy/sync.cc | 16 +++++++++++- srsue/test/phy/scell_search_test.cc | 16 ++++-------- 9 files changed, 104 insertions(+), 22 deletions(-) diff --git a/lib/include/srslte/phy/ch_estimation/refsignal_dl.h b/lib/include/srslte/phy/ch_estimation/refsignal_dl.h index 941db4f1b..65346c497 100644 --- a/lib/include/srslte/phy/ch_estimation/refsignal_dl.h +++ b/lib/include/srslte/phy/ch_estimation/refsignal_dl.h @@ -74,6 +74,8 @@ SRSLTE_API uint32_t srslte_refsignal_cs_v(uint32_t port_id, uint32_t ref_symbol_ SRSLTE_API uint32_t srslte_refsignal_cs_nof_symbols(srslte_refsignal_t* q, srslte_dl_sf_cfg_t* sf, uint32_t port_id); +SRSLTE_API uint32_t srslte_refsignal_cs_nof_pilots_x_slot(uint32_t nof_ports); + SRSLTE_API uint32_t srslte_refsignal_cs_nof_re(srslte_refsignal_t* q, srslte_dl_sf_cfg_t* sf, uint32_t port_id); SRSLTE_API int srslte_refsignal_mbsfn_init(srslte_refsignal_t* q, uint32_t max_prb); diff --git a/lib/src/phy/ch_estimation/refsignal_dl.c b/lib/src/phy/ch_estimation/refsignal_dl.c index 597430454..4057b0a58 100644 --- a/lib/src/phy/ch_estimation/refsignal_dl.c +++ b/lib/src/phy/ch_estimation/refsignal_dl.c @@ -227,6 +227,18 @@ inline uint32_t srslte_refsignal_cs_nof_symbols(srslte_refsignal_t* q, srslte_dl } } +inline uint32_t srslte_refsignal_cs_nof_pilots_x_slot(uint32_t nof_ports) +{ + switch (nof_ports) { + case 2: + return 8; + case 4: + return 12; + default: + return 4; + } +} + inline uint32_t srslte_refsignal_cs_nof_re(srslte_refsignal_t* q, srslte_dl_sf_cfg_t* sf, uint32_t port_id) { uint32_t nof_re = srslte_refsignal_cs_nof_symbols(q, sf, port_id); diff --git a/srsue/hdr/phy/phy_common.h b/srsue/hdr/phy/phy_common.h index 2cbc12cc5..28cbcd8fa 100644 --- a/srsue/hdr/phy/phy_common.h +++ b/srsue/hdr/phy/phy_common.h @@ -213,6 +213,30 @@ public: return rx_gain_offset; } + void neighbour_cells_reset(uint32_t cc_idx) { avg_rsrp_neigh[cc_idx] = NAN; } + + void set_neighbour_cells(uint32_t cc_idx, const std::vector& meas) + { + // Add RSRP in the linear domain and average + float total_rsrp = 0; + for (auto& m : meas) { + total_rsrp += srslte_convert_dB_to_power(m.rsrp); + } + if (std::isnormal(total_rsrp)) { + if (std::isnormal(avg_rsrp_neigh[cc_idx])) { + avg_rsrp_neigh[cc_idx] = SRSLTE_VEC_EMA(total_rsrp, avg_rsrp_neigh[cc_idx], 0.9); + } else { + avg_rsrp_neigh[cc_idx] = total_rsrp; + } + } + } + void reset_neighbour_cells() + { + for (uint32_t i = 0; i < SRSLTE_MAX_CARRIERS; i++) { + avg_rsrp_neigh[i] = NAN; + } + } + private: std::mutex meas_mutex; @@ -227,6 +251,8 @@ private: float rx_gain_offset = 0.0f; float avg_snr_db_cqi[SRSLTE_MAX_CARRIERS] = {}; float avg_noise[SRSLTE_MAX_CARRIERS] = {}; + float avg_rsrp_neigh[SRSLTE_MAX_CARRIERS] = {}; + uint32_t pcell_report_period = 0; uint32_t rssi_read_cnt = 0; diff --git a/srsue/hdr/phy/scell/intra_measure.h b/srsue/hdr/phy/scell/intra_measure.h index 9be2179c4..dfc48eccf 100644 --- a/srsue/hdr/phy/scell/intra_measure.h +++ b/srsue/hdr/phy/scell/intra_measure.h @@ -55,6 +55,14 @@ class intra_measure : public srslte::thread * +---------+ */ public: + // Interface for reporting new cell measurements + class meas_itf + { + public: + virtual void cell_meas_reset(uint32_t cc_idx) = 0; + virtual void new_cell_meas(uint32_t cc_idx, const std::vector& meas) = 0; + }; + /** * Constructor */ @@ -71,7 +79,7 @@ public: * @param rrc SRSUE PHY->RRC interface for supplying the RRC with the measurements * @param log_h Physical layer Logging filter pointer */ - void init(phy_common* common, rrc_interface_phy_lte* rrc, srslte::log* log_h); + void init(uint32_t cc_idx, phy_common* common, meas_itf* new_cell_itf, srslte::log* log_h); /** * Stops the operation of this component @@ -191,8 +199,9 @@ private: const static int INTRA_FREQ_MEAS_PRIO = DEFAULT_PRIORITY + 5; scell_recv scell = {}; - rrc_interface_phy_lte* rrc = nullptr; + meas_itf* new_cell_itf = nullptr; srslte::log* log_h = nullptr; + uint32_t cc_idx = 0; uint32_t current_earfcn = 0; uint32_t current_sflen = 0; srslte_cell_t serving_cell = {}; diff --git a/srsue/hdr/phy/sync.h b/srsue/hdr/phy/sync.h index 4a33f53d9..fb35b9a30 100644 --- a/srsue/hdr/phy/sync.h +++ b/srsue/hdr/phy/sync.h @@ -48,7 +48,11 @@ namespace srsue { typedef _Complex float cf_t; -class sync : public srslte::thread, public rsrp_insync_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 scell::intra_measure::meas_itf { public: sync() : thread("SYNC"), sf_buffer(sync_nof_rx_subframes), dummy_buffer(sync_nof_rx_subframes){}; @@ -115,6 +119,10 @@ public: */ void set_rx_channel_offset(uint32_t ch, int32_t offset) override { radio_h->set_channel_rx_offset(ch, offset); } + // Interface from scell::intra_measure for providing neighbour cell measurements + void cell_meas_reset(uint32_t cc_idx) override; + void new_cell_meas(uint32_t cc_idx, const std::vector& meas) override; + private: void reset(); void radio_error(); diff --git a/srsue/src/phy/phy_common.cc b/srsue/src/phy/phy_common.cc index 649a8c105..74d3152fd 100644 --- a/srsue/src/phy/phy_common.cc +++ b/srsue/src/phy/phy_common.cc @@ -699,12 +699,24 @@ void phy_common::update_measurements(uint32_t } } + // Calculate SINR using CRS from neighbours if are detected + float sinr_db = chest_res.snr_db; + if (std::isnormal(avg_rsrp_neigh[cc_idx])) { + cur_noise /= pow(10, rx_gain_offset / 10); + + // Normalize the measured power ot the fraction of CRS pilots per PRB. Assume all neighbours have the same + // number of ports and CP length + uint32_t nof_re_x_prb = SRSLTE_NRE * (SRSLTE_CP_NSYMB(cell.cp)); + float factor = nof_re_x_prb / (srslte_refsignal_cs_nof_pilots_x_slot(cell.nof_ports)); + sinr_db = avg_rsrp_dbm[cc_idx] - srslte_convert_power_to_dB(avg_rsrp_neigh[cc_idx] / factor + cur_noise); + } + // Average snr in the log domain - if (std::isnormal(chest_res.snr_db)) { + if (std::isnormal(sinr_db)) { if (!std::isnormal(avg_snr_db_cqi[cc_idx])) { - avg_snr_db_cqi[cc_idx] = chest_res.snr_db; + avg_snr_db_cqi[cc_idx] = sinr_db; } else { - avg_snr_db_cqi[cc_idx] = SRSLTE_VEC_EMA(chest_res.snr_db, avg_snr_db_cqi[cc_idx], snr_ema_coeff); + avg_snr_db_cqi[cc_idx] = SRSLTE_VEC_EMA(sinr_db, avg_snr_db_cqi[cc_idx], snr_ema_coeff); } } @@ -877,6 +889,8 @@ void phy_common::reset() ZERO_OBJECT(avg_rsrq_db); ZERO_OBJECT(scell_cfg); + reset_neighbour_cells(); + // Note: Using memset to reset these members is forbidden because they are real objects, not plain arrays. { std::lock_guard lock(pending_dl_ack_mutex); diff --git a/srsue/src/phy/scell/intra_measure.cc b/srsue/src/phy/scell/intra_measure.cc index 03732c519..af17a6122 100644 --- a/srsue/src/phy/scell/intra_measure.cc +++ b/srsue/src/phy/scell/intra_measure.cc @@ -45,10 +45,11 @@ intra_measure::~intra_measure() free(search_buffer); } -void intra_measure::init(phy_common* common, rrc_interface_phy_lte* rrc_, srslte::log* log_h_) +void intra_measure::init(uint32_t cc_idx_, phy_common* common, meas_itf* new_cell_itf_, srslte::log* log_h_) { - rrc = rrc_; - log_h = log_h_; + cc_idx = cc_idx_; + new_cell_itf = new_cell_itf_; + log_h = log_h_; if (common) { intra_freq_meas_len_ms = common->args->intra_freq_meas_len_ms; @@ -174,6 +175,8 @@ void intra_measure::measure_proc() // Initialise empty neighbour cell list std::vector neighbour_cells = {}; + new_cell_itf->cell_meas_reset(cc_idx); + // Use Cell Reference signal to measure cells in the time domain for all known active PCI for (auto id : cells_to_measure) { // Do not measure serving cell here since it's measured by workers @@ -208,7 +211,7 @@ void intra_measure::measure_proc() // Send measurements to RRC if any cell found if (not neighbour_cells.empty()) { - rrc->new_cell_meas(neighbour_cells); + new_cell_itf->new_cell_meas(cc_idx, neighbour_cells); } // Inform that measurement has finished diff --git a/srsue/src/phy/sync.cc b/srsue/src/phy/sync.cc index 8486e4298..0aeefcf38 100644 --- a/srsue/src/phy/sync.cc +++ b/srsue/src/phy/sync.cc @@ -100,7 +100,7 @@ void sync::init(srslte::radio_interface_phy* _radio, // Start intra-frequency measurement for (uint32_t i = 0; i < worker_com->args->nof_carriers; i++) { scell::intra_measure* q = new scell::intra_measure; - q->init(worker_com, stack, log_h); + q->init(i, worker_com, this, log_h); intra_freq_meas.push_back(std::unique_ptr(q)); } @@ -1027,4 +1027,18 @@ void sync::scell_sync_stop() } } +void sync::cell_meas_reset(uint32_t cc_idx) +{ + worker_com->neighbour_cells_reset(cc_idx); +} + +void sync::new_cell_meas(uint32_t cc_idx, const std::vector& meas) +{ + // Pass measurements to phy_common for SINR estimation + worker_com->set_neighbour_cells(cc_idx, meas); + + // Pass-through to the stack + stack->new_cell_meas(meas); +} + } // namespace srsue diff --git a/srsue/test/phy/scell_search_test.cc b/srsue/test/phy/scell_search_test.cc index fdd0badee..a186b51ea 100644 --- a/srsue/test/phy/scell_search_test.cc +++ b/srsue/test/phy/scell_search_test.cc @@ -227,7 +227,7 @@ public: } }; -class dummy_rrc : public srsue::rrc_interface_phy_lte +class meas_itf_listener : public srsue::scell::intra_measure::meas_itf { public: typedef struct { @@ -242,9 +242,8 @@ public: std::map cells; - void in_sync() override {} - void out_of_sync() override {} - void new_cell_meas(const std::vector& meas) override + void cell_meas_reset(uint32_t cc_idx) override {} + void new_cell_meas(uint32_t cc_idx, const std::vector& meas) override { for (auto& m : meas) { uint32_t pci = m.pci; @@ -269,11 +268,6 @@ public: } } - void cell_search_complete(cell_search_ret_t ret, srsue::phy_cell_t found_cell) override {} - void cell_select_complete(bool status) override {} - void set_config_complete(bool status) override {} - void set_scell_complete(bool status) override {} - bool print_stats() { printf("\n-- Statistics:\n"); @@ -418,7 +412,7 @@ int main(int argc, char** argv) srslte::rf_timestamp_t ts = {}; srsue::scell::intra_measure intra_measure; srslte::log_filter logger("intra_measure"); - dummy_rrc rrc; + meas_itf_listener rrc; srsue::phy_common common; // Simulation only @@ -489,7 +483,7 @@ int main(int argc, char** argv) logger.set_level(intra_meas_log_level); - intra_measure.init(&common, &rrc, &logger); + intra_measure.init(0, &common, &rrc, &logger); intra_measure.set_primary_cell(SRSLTE_MAX(earfcn_dl, 0), cell_base); if (earfcn_dl >= 0) {