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
master
Ismael Gomez 4 years ago committed by GitHub
parent 098172c911
commit b94d24ed98
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -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_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 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); SRSLTE_API int srslte_refsignal_mbsfn_init(srslte_refsignal_t* q, uint32_t max_prb);

@ -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) 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); uint32_t nof_re = srslte_refsignal_cs_nof_symbols(q, sf, port_id);

@ -213,6 +213,30 @@ public:
return rx_gain_offset; 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<rrc_interface_phy_lte::phy_meas_t>& 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: private:
std::mutex meas_mutex; std::mutex meas_mutex;
@ -227,6 +251,8 @@ private:
float rx_gain_offset = 0.0f; float rx_gain_offset = 0.0f;
float avg_snr_db_cqi[SRSLTE_MAX_CARRIERS] = {}; float avg_snr_db_cqi[SRSLTE_MAX_CARRIERS] = {};
float avg_noise[SRSLTE_MAX_CARRIERS] = {}; float avg_noise[SRSLTE_MAX_CARRIERS] = {};
float avg_rsrp_neigh[SRSLTE_MAX_CARRIERS] = {};
uint32_t pcell_report_period = 0; uint32_t pcell_report_period = 0;
uint32_t rssi_read_cnt = 0; uint32_t rssi_read_cnt = 0;

@ -55,6 +55,14 @@ class intra_measure : public srslte::thread
* +---------+ * +---------+
*/ */
public: 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<rrc_interface_phy_lte::phy_meas_t>& meas) = 0;
};
/** /**
* Constructor * Constructor
*/ */
@ -71,7 +79,7 @@ public:
* @param rrc SRSUE PHY->RRC interface for supplying the RRC with the measurements * @param rrc SRSUE PHY->RRC interface for supplying the RRC with the measurements
* @param log_h Physical layer Logging filter pointer * @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 * Stops the operation of this component
@ -191,8 +199,9 @@ private:
const static int INTRA_FREQ_MEAS_PRIO = DEFAULT_PRIORITY + 5; const static int INTRA_FREQ_MEAS_PRIO = DEFAULT_PRIORITY + 5;
scell_recv scell = {}; scell_recv scell = {};
rrc_interface_phy_lte* rrc = nullptr; meas_itf* new_cell_itf = nullptr;
srslte::log* log_h = nullptr; srslte::log* log_h = nullptr;
uint32_t cc_idx = 0;
uint32_t current_earfcn = 0; uint32_t current_earfcn = 0;
uint32_t current_sflen = 0; uint32_t current_sflen = 0;
srslte_cell_t serving_cell = {}; srslte_cell_t serving_cell = {};

@ -48,7 +48,11 @@ namespace srsue {
typedef _Complex float cf_t; 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: public:
sync() : thread("SYNC"), sf_buffer(sync_nof_rx_subframes), dummy_buffer(sync_nof_rx_subframes){}; 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); } 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<rrc_interface_phy_lte::phy_meas_t>& meas) override;
private: private:
void reset(); void reset();
void radio_error(); void radio_error();

@ -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 // 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])) { 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 { } 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(avg_rsrq_db);
ZERO_OBJECT(scell_cfg); ZERO_OBJECT(scell_cfg);
reset_neighbour_cells();
// Note: Using memset to reset these members is forbidden because they are real objects, not plain arrays. // Note: Using memset to reset these members is forbidden because they are real objects, not plain arrays.
{ {
std::lock_guard<std::mutex> lock(pending_dl_ack_mutex); std::lock_guard<std::mutex> lock(pending_dl_ack_mutex);

@ -45,10 +45,11 @@ intra_measure::~intra_measure()
free(search_buffer); 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_; cc_idx = cc_idx_;
log_h = log_h_; new_cell_itf = new_cell_itf_;
log_h = log_h_;
if (common) { if (common) {
intra_freq_meas_len_ms = common->args->intra_freq_meas_len_ms; 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 // Initialise empty neighbour cell list
std::vector<rrc_interface_phy_lte::phy_meas_t> neighbour_cells = {}; std::vector<rrc_interface_phy_lte::phy_meas_t> 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 // Use Cell Reference signal to measure cells in the time domain for all known active PCI
for (auto id : cells_to_measure) { for (auto id : cells_to_measure) {
// Do not measure serving cell here since it's measured by workers // 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 // Send measurements to RRC if any cell found
if (not neighbour_cells.empty()) { 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 // Inform that measurement has finished

@ -100,7 +100,7 @@ void sync::init(srslte::radio_interface_phy* _radio,
// Start intra-frequency measurement // Start intra-frequency measurement
for (uint32_t i = 0; i < worker_com->args->nof_carriers; i++) { for (uint32_t i = 0; i < worker_com->args->nof_carriers; i++) {
scell::intra_measure* q = new scell::intra_measure; 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<scell::intra_measure>(q)); intra_freq_meas.push_back(std::unique_ptr<scell::intra_measure>(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<rrc_interface_phy_lte::phy_meas_t>& 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 } // namespace srsue

@ -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: public:
typedef struct { typedef struct {
@ -242,9 +242,8 @@ public:
std::map<uint32_t, cell_meas_t> cells; std::map<uint32_t, cell_meas_t> cells;
void in_sync() override {} void cell_meas_reset(uint32_t cc_idx) override {}
void out_of_sync() override {} void new_cell_meas(uint32_t cc_idx, const std::vector<srsue::rrc_interface_phy_lte::phy_meas_t>& meas) override
void new_cell_meas(const std::vector<phy_meas_t>& meas) override
{ {
for (auto& m : meas) { for (auto& m : meas) {
uint32_t pci = m.pci; 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() bool print_stats()
{ {
printf("\n-- Statistics:\n"); printf("\n-- Statistics:\n");
@ -418,7 +412,7 @@ int main(int argc, char** argv)
srslte::rf_timestamp_t ts = {}; srslte::rf_timestamp_t ts = {};
srsue::scell::intra_measure intra_measure; srsue::scell::intra_measure intra_measure;
srslte::log_filter logger("intra_measure"); srslte::log_filter logger("intra_measure");
dummy_rrc rrc; meas_itf_listener rrc;
srsue::phy_common common; srsue::phy_common common;
// Simulation only // Simulation only
@ -489,7 +483,7 @@ int main(int argc, char** argv)
logger.set_level(intra_meas_log_level); 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); intra_measure.set_primary_cell(SRSLTE_MAX(earfcn_dl, 0), cell_base);
if (earfcn_dl >= 0) { if (earfcn_dl >= 0) {

Loading…
Cancel
Save