From de00b802287dc5562cf02d26c827e4a57ee7b6a3 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Mon, 20 Sep 2021 12:54:15 +0200 Subject: [PATCH] Review NR NSA CFO estimation and compensation --- lib/include/srsran/interfaces/ue_nr_interfaces.h | 1 + lib/src/phy/ch_estimation/csi_rs.c | 2 +- lib/src/phy/sync/ssb.c | 2 +- lib/src/phy/sync/test/ssb_measure_test.c | 2 +- lib/src/phy/ue/ue_ul_nr.c | 2 +- srsue/hdr/phy/nr/state.h | 9 ++++----- srsue/src/phy/nr/cc_worker.cc | 5 +++-- srsue/src/phy/nr/worker_pool.cc | 2 +- srsue/src/phy/sync.cc | 2 +- 9 files changed, 14 insertions(+), 13 deletions(-) diff --git a/lib/include/srsran/interfaces/ue_nr_interfaces.h b/lib/include/srsran/interfaces/ue_nr_interfaces.h index 030082010..b67fe3372 100644 --- a/lib/include/srsran/interfaces/ue_nr_interfaces.h +++ b/lib/include/srsran/interfaces/ue_nr_interfaces.h @@ -180,6 +180,7 @@ struct phy_args_nr_t { bool store_pdsch_ko = false; float trs_epre_ema_alpha = 0.1f; ///< EPRE measurement exponential average alpha float trs_rsrp_ema_alpha = 0.1f; ///< RSRP measurement exponential average alpha + float trs_sinr_ema_alpha = 0.1f; ///< SINR measurement exponential average alpha float trs_cfo_ema_alpha = 0.1f; ///< RSRP measurement exponential average alpha bool enable_worker_cfo = true; ///< Enable/Disable open loop CFO correction at the workers diff --git a/lib/src/phy/ch_estimation/csi_rs.c b/lib/src/phy/ch_estimation/csi_rs.c index 6c7c3920b..75a77a9e8 100644 --- a/lib/src/phy/ch_estimation/csi_rs.c +++ b/lib/src/phy/ch_estimation/csi_rs.c @@ -719,7 +719,7 @@ int srsran_csi_rs_nzp_measure_trs(const srsran_carrier_nr_t* carrier, float cfo_max = 0.0f; for (uint32_t i = 1; i < count; i++) { float time_diff = srsran_symbol_distance_s(measurements[i - 1].l0, measurements[i].l0, carrier->scs); - float phase_diff = cargf(measurements[i - 1].corr * conjf(measurements[i].corr)); + float phase_diff = cargf(measurements[i].corr * conjf(measurements[i - 1].corr)); float cfo_max_temp = 0.0f; // Avoid zero division diff --git a/lib/src/phy/sync/ssb.c b/lib/src/phy/sync/ssb.c index 357ab7710..7c2a859a0 100644 --- a/lib/src/phy/sync/ssb.c +++ b/lib/src/phy/sync/ssb.c @@ -697,7 +697,7 @@ ssb_measure(srsran_ssb_t* q, const cf_t ssb_grid[SRSRAN_SSB_NOF_RE], uint32_t N_ // Compute CFO in Hz float distance_s = srsran_symbol_distance_s(SRSRAN_PSS_NR_SYMBOL_IDX, SRSRAN_SSS_NR_SYMBOL_IDX, q->cfg.scs); float cfo_hz_max = 1.0f / distance_s; - float cfo_hz = cargf(corr_pss * conjf(corr_sss)) / (2.0f * M_PI) * cfo_hz_max; + float cfo_hz = cargf(corr_sss * conjf(corr_pss)) / (2.0f * M_PI) * cfo_hz_max; // Compute average RSRP float rsrp_pss = SRSRAN_CSQABS(corr_pss); diff --git a/lib/src/phy/sync/test/ssb_measure_test.c b/lib/src/phy/sync/test/ssb_measure_test.c index e6c328d59..d4e5b39c0 100644 --- a/lib/src/phy/sync/test/ssb_measure_test.c +++ b/lib/src/phy/sync/test/ssb_measure_test.c @@ -71,7 +71,7 @@ static void run_channel() } // CFO - srsran_vec_apply_cfo(buffer, -cfo_hz / srate_hz, buffer, sf_len); + srsran_vec_apply_cfo(buffer, cfo_hz / srate_hz, buffer, sf_len); // AWGN srsran_channel_awgn_run_c(&awgn, buffer, buffer, sf_len); diff --git a/lib/src/phy/ue/ue_ul_nr.c b/lib/src/phy/ue/ue_ul_nr.c index 38e8b0fb8..e92ea7974 100644 --- a/lib/src/phy/ue/ue_ul_nr.c +++ b/lib/src/phy/ue/ue_ul_nr.c @@ -101,7 +101,7 @@ void srsran_ue_ul_nr_set_freq_offset(srsran_ue_ul_nr_t* q, float freq_offset_hz) return; } - q->freq_offset_hz = freq_offset_hz; + q->freq_offset_hz = -freq_offset_hz; } int srsran_ue_ul_nr_encode_pusch(srsran_ue_ul_nr_t* q, diff --git a/srsue/hdr/phy/nr/state.h b/srsue/hdr/phy/nr/state.h index c6f8c3186..78891e68e 100644 --- a/srsue/hdr/phy/nr/state.h +++ b/srsue/hdr/phy/nr/state.h @@ -482,8 +482,8 @@ public: // Compute synch metrics and report it to the PHY state sync_metrics_t new_sync_metrics = {}; - new_sync_metrics.cfo = new_meas.cfo_hz; - set_sync_metrics(sync_metrics); + new_sync_metrics.cfo = new_meas.cfo_hz + ul_ext_cfo_hz; + set_sync_metrics(new_sync_metrics); // Convert to CSI channel measurement and report new NZP-CSI-RS measurement to the PHY state srsran_csi_channel_measurements_t measurements = {}; @@ -499,11 +499,10 @@ public: trs_measurements_mutex.lock(); trs_measurements.rsrp_dB = SRSRAN_VEC_SAFE_EMA(new_meas.rsrp_dB, trs_measurements.rsrp_dB, args.trs_epre_ema_alpha); trs_measurements.epre_dB = SRSRAN_VEC_SAFE_EMA(new_meas.epre_dB, trs_measurements.epre_dB, args.trs_rsrp_ema_alpha); + trs_measurements.snr_dB = SRSRAN_VEC_SAFE_EMA(new_meas.snr_dB, trs_measurements.snr_dB, args.trs_sinr_ema_alpha); // Consider CFO measurement invalid if the SNR is negative. In this case, set CFO to 0. - if (trs_measurements.snr_dB > 0.0f) { + if (new_meas.snr_dB > 0.0f) { trs_measurements.cfo_hz = SRSRAN_VEC_SAFE_EMA(new_meas.cfo_hz, trs_measurements.cfo_hz, args.trs_cfo_ema_alpha); - } else { - trs_measurements.cfo_hz = 0.0f; } trs_measurements.nof_re++; trs_measurements_mutex.unlock(); diff --git a/srsue/src/phy/nr/cc_worker.cc b/srsue/src/phy/nr/cc_worker.cc index 6416399ef..1d7d12f75 100644 --- a/srsue/src/phy/nr/cc_worker.cc +++ b/srsue/src/phy/nr/cc_worker.cc @@ -487,10 +487,11 @@ bool cc_worker::work_dl() // Compensate CFO from TRS measurements if (std::isnormal(phy.args.enable_worker_cfo)) { - float dl_cfo_hz = phy.get_dl_cfo(); + float dl_cfo_hz = phy.get_dl_cfo(); + float dl_cfo_norm = -dl_cfo_hz / (1000.0f * ue_ul.ifft.sf_sz); for (cf_t* b : rx_buffer) { if (b != nullptr and ue_ul.ifft.sf_sz != 0) { - srsran_vec_apply_cfo(b, dl_cfo_hz / (1000.0f * ue_ul.ifft.sf_sz), b, ue_ul.ifft.sf_sz); + srsran_vec_apply_cfo(b, dl_cfo_norm, b, ue_ul.ifft.sf_sz); } } } diff --git a/srsue/src/phy/nr/worker_pool.cc b/srsue/src/phy/nr/worker_pool.cc index d41183d4b..2c8b62493 100644 --- a/srsue/src/phy/nr/worker_pool.cc +++ b/srsue/src/phy/nr/worker_pool.cc @@ -79,7 +79,7 @@ sf_worker* worker_pool::wait_worker(uint32_t tti) if (prach_buffer->is_ready_to_send(tti, phy_state.cfg.carrier.pci)) { uint32_t nof_prach_sf = 0; float prach_target_power = 0.0f; - cf_t* prach_ptr = prach_buffer->generate(-phy_state.get_ul_cfo() / 15000, &nof_prach_sf, &prach_target_power); + cf_t* prach_ptr = prach_buffer->generate(phy_state.get_ul_cfo() / 15000, &nof_prach_sf, &prach_target_power); worker->set_prach(prach_ptr, prach_target_power); } diff --git a/srsue/src/phy/sync.cc b/srsue/src/phy/sync.cc index 5d7c56608..c8fd3a81c 100644 --- a/srsue/src/phy/sync.cc +++ b/srsue/src/phy/sync.cc @@ -543,7 +543,7 @@ void sync::run_camping_in_sync_state(lte::sf_worker* lte_worker, // As UE sync compensates CFO externally based on LTE signal and the NR carrier may estimate the CFO from the LTE // signal. It is necessary setting an NR external CFO offset to compensate it. - nr_worker_pool->set_ul_ext_cfo(-srsran_ue_sync_get_cfo(&ue_sync)); + nr_worker_pool->set_ul_ext_cfo(srsran_ue_sync_get_cfo(&ue_sync)); // NR worker needs to be launched first, phy_common::worker_end expects first the NR worker and the LTE worker. worker_com->semaphore.push(nr_worker);