From a1a797589aa8c780d20df97420f4bab39fb7e6e3 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Fri, 12 Apr 2019 17:35:49 +0200 Subject: [PATCH] Added UE synchronization error metric (hard-coded disabled by default) --- .../srslte/phy/ch_estimation/chest_dl.h | 3 ++ lib/src/phy/ch_estimation/chest_dl.c | 14 ++++++++ srsue/hdr/phy/phy_metrics.h | 1 + srsue/hdr/phy/sf_worker.h | 3 ++ srsue/src/phy/cc_worker.cc | 1 + srsue/src/phy/phy_common.cc | 3 ++ srsue/src/phy/sf_worker.cc | 34 +++++++++++++++++-- 7 files changed, 57 insertions(+), 2 deletions(-) diff --git a/lib/include/srslte/phy/ch_estimation/chest_dl.h b/lib/include/srslte/phy/ch_estimation/chest_dl.h index a5a6ae111..5fb012a6c 100644 --- a/lib/include/srslte/phy/ch_estimation/chest_dl.h +++ b/lib/include/srslte/phy/ch_estimation/chest_dl.h @@ -63,6 +63,7 @@ typedef struct SRSLTE_API { float rsrq_ant_port_db[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; float rssi_dbm; float cfo; + float sync_error; } srslte_chest_dl_res_t; typedef enum SRSLTE_API { @@ -98,6 +99,7 @@ typedef struct SRSLTE_API { float rsrp[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; float rsrp_corr[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; float noise_estimate[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; + float sync_err[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; float cfo; /* Use PSS for noise estimation in LS linear interpolation mode */ @@ -118,6 +120,7 @@ typedef struct SRSLTE_API { bool rsrp_neighbour; bool cfo_estimate_enable; uint32_t cfo_estimate_sf_mask; + bool sync_error_enable; } srslte_chest_dl_cfg_t; diff --git a/lib/src/phy/ch_estimation/chest_dl.c b/lib/src/phy/ch_estimation/chest_dl.c index 7aa0804b5..28fed20f7 100644 --- a/lib/src/phy/ch_estimation/chest_dl.c +++ b/lib/src/phy/ch_estimation/chest_dl.c @@ -691,6 +691,19 @@ static int estimate_port(srslte_chest_dl_t* q, srslte_vec_prod_conj_ccc( q->pilot_recv_signal, q->csr_refs.pilots[port_id / 2][sf->tti % 10], q->pilot_estimates, npilots); + // Estimate synchronization error + if (cfg->sync_error_enable) { + uint32_t nsymb = srslte_refsignal_cs_nof_symbols(&q->csr_refs, sf, port_id); + float k = (float)srslte_symbol_sz(q->cell.nof_prb) / 6.0f; + float sum = 0.0f; + for (uint32_t i = 0; i < nsymb; i++) { + sum += srslte_vec_estimate_frequency(q->pilot_estimates + i * npilots / nsymb, npilots / nsymb) * k; + } + q->sync_err[rxant_id][port_id] = sum / nsymb; + } else { + q->sync_err[rxant_id][port_id] = NAN; + } + /* Compute RSRP for the channel estimates in this port */ if (cfg->rsrp_neighbour) { double energy = cabs(srslte_vec_acc_cc(q->pilot_estimates, npilots)/npilots); @@ -843,6 +856,7 @@ static void fill_res(srslte_chest_dl_t* q, srslte_chest_dl_res_t* res) res->rsrq_db = db(res->rsrq); res->snr_db = db(get_snr(q)); res->rssi_dbm = dbm(get_rssi(q)); + res->sync_error = q->sync_err[0][0]; // Take only the channel used for synch for (uint32_t port_id = 0; port_id < q->cell.nof_ports; port_id++) { res->rsrp_port_dbm[port_id] = dbm(get_rsrp_port(q, port_id)); diff --git a/srsue/hdr/phy/phy_metrics.h b/srsue/hdr/phy/phy_metrics.h index a936339fc..fdde3fe09 100644 --- a/srsue/hdr/phy/phy_metrics.h +++ b/srsue/hdr/phy/phy_metrics.h @@ -44,6 +44,7 @@ struct dl_metrics_t float turbo_iters; float mcs; float pathloss; + float sync_err; }; struct ul_metrics_t diff --git a/srsue/hdr/phy/sf_worker.h b/srsue/hdr/phy/sf_worker.h index 7d4b6d61a..bd7ad7700 100644 --- a/srsue/hdr/phy/sf_worker.h +++ b/srsue/hdr/phy/sf_worker.h @@ -61,6 +61,7 @@ public: void set_crnti(uint16_t rnti); void enable_pregen_signals(bool enabled); + /* Methods for plotting */ int read_ce_abs(float* ce_abs, uint32_t tx_antenna, uint32_t rx_antenna); uint32_t get_cell_nof_ports() { @@ -72,6 +73,8 @@ 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(); private: diff --git a/srsue/src/phy/cc_worker.cc b/srsue/src/phy/cc_worker.cc index ab243bca2..d33c9b824 100644 --- a/srsue/src/phy/cc_worker.cc +++ b/srsue/src/phy/cc_worker.cc @@ -652,6 +652,7 @@ void cc_worker::update_measurements() dl_metrics.rssi = phy->avg_rssi_dbm; 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); diff --git a/srsue/src/phy/phy_common.cc b/srsue/src/phy/phy_common.cc index 3fa34ef4e..54d5ce46a 100644 --- a/srsue/src/phy/phy_common.cc +++ b/srsue/src/phy/phy_common.cc @@ -154,6 +154,7 @@ void phy_common::set_ue_dl_cfg(srslte_ue_dl_cfg_t* ue_dl_cfg) } chest_cfg->rsrp_neighbour = false; + chest_cfg->sync_error_enable = false; chest_cfg->interpolate_subframe = args->interpolate_subframe_enabled; chest_cfg->cfo_estimate_enable = args->cfo_ref_mask != 0; chest_cfg->cfo_estimate_sf_mask = args->cfo_ref_mask; @@ -610,6 +611,8 @@ void phy_common::set_dl_metrics(const dl_metrics_t m, uint32_t cc_idx) 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; dl_metrics[cc_idx].turbo_iters = diff --git a/srsue/src/phy/sf_worker.cc b/srsue/src/phy/sf_worker.cc index c5fb92a1d..1b8628f20 100644 --- a/srsue/src/phy/sf_worker.cc +++ b/srsue/src/phy/sf_worker.cc @@ -395,7 +395,19 @@ 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() +{ + sync_metrics_t sync_metrics = {}; + phy->get_sync_metrics(sync_metrics); + return sync_metrics.cfo; +} } // namespace srsue /*********************************************************** @@ -419,9 +431,17 @@ static uint32_t icfo = 0; static float cfo_buffer[CFO_PLOT_LEN]; #endif /* CFO_PLOT_LEN > 0 */ +#define SYNC_PLOT_LEN 0 /* Set to non zero for enabling Sync error plot */ +#if SYNC_PLOT_LEN > 0 +static plot_real_t psync; +static uint32_t isync = 0; +static float sync_buffer[SYNC_PLOT_LEN]; +#endif /* SYNC_PLOT_LEN > 0 */ + void* plot_thread_run(void* arg) { srsue::sf_worker* worker = (srsue::sf_worker*)arg; + uint32_t row_count = 0; sdrgui_init(); for (uint32_t tx = 0; tx < worker->get_cell_nof_ports(); tx++) { @@ -436,13 +456,14 @@ void* plot_thread_run(void* arg) plot_real_addToWindowGrid(&pce[tx][rx], (char*)"srsue", tx, rx); } } + row_count = worker->get_rx_nof_antennas(); plot_scatter_init(&pconst); plot_scatter_setTitle(&pconst, (char*)"PDSCH - Equalized Symbols"); plot_scatter_setXAxisScale(&pconst, -4, 4); plot_scatter_setYAxisScale(&pconst, -4, 4); - plot_scatter_addToWindowGrid(&pconst, (char*)"srsue", 0, worker->get_rx_nof_antennas()); + plot_scatter_addToWindowGrid(&pconst, (char*)"srsue", 0, row_count); #if CFO_PLOT_LEN > 0 plot_real_init(&pcfo); @@ -450,9 +471,18 @@ void* plot_thread_run(void* arg) plot_real_setLabels(&pcfo, (char*)"Time", (char*)"Hz"); plot_real_setYAxisScale(&pcfo, -4000, 4000); - plot_scatter_addToWindowGrid(&pcfo, (char*)"srsue", 1, worker->get_rx_nof_antennas()); + plot_scatter_addToWindowGrid(&pcfo, (char*)"srsue", 1, row_count++); #endif /* CFO_PLOT_LEN > 0 */ +#if SYNC_PLOT_LEN > 0 + plot_real_init(&psync); + plot_real_setTitle(&psync, (char*)"Sync error (in samples)"); + plot_real_setLabels(&psync, (char*)"Time", (char*)"Error"); + plot_real_setYAxisScale(&psync, -2, +2); + + plot_scatter_addToWindowGrid(&psync, (char*)"srsue", 1, row_count++); +#endif /* SYNC_PLOT_LEN > 0 */ + int n; int readed_pdsch_re = 0; while (1) {