Review NR NSA CFO estimation and compensation

This commit is contained in:
Xavier Arteaga 2021-09-20 12:54:15 +02:00 committed by Andre Puschmann
parent 63bb86bce1
commit de00b80228
9 changed files with 14 additions and 13 deletions

View File

@ -180,6 +180,7 @@ struct phy_args_nr_t {
bool store_pdsch_ko = false; bool store_pdsch_ko = false;
float trs_epre_ema_alpha = 0.1f; ///< EPRE measurement exponential average alpha 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_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 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 bool enable_worker_cfo = true; ///< Enable/Disable open loop CFO correction at the workers

View File

@ -719,7 +719,7 @@ int srsran_csi_rs_nzp_measure_trs(const srsran_carrier_nr_t* carrier,
float cfo_max = 0.0f; float cfo_max = 0.0f;
for (uint32_t i = 1; i < count; i++) { 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 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; float cfo_max_temp = 0.0f;
// Avoid zero division // Avoid zero division

View File

@ -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 // 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 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_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 // Compute average RSRP
float rsrp_pss = SRSRAN_CSQABS(corr_pss); float rsrp_pss = SRSRAN_CSQABS(corr_pss);

View File

@ -71,7 +71,7 @@ static void run_channel()
} }
// CFO // 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 // AWGN
srsran_channel_awgn_run_c(&awgn, buffer, buffer, sf_len); srsran_channel_awgn_run_c(&awgn, buffer, buffer, sf_len);

View File

@ -101,7 +101,7 @@ void srsran_ue_ul_nr_set_freq_offset(srsran_ue_ul_nr_t* q, float freq_offset_hz)
return; 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, int srsran_ue_ul_nr_encode_pusch(srsran_ue_ul_nr_t* q,

View File

@ -482,8 +482,8 @@ public:
// Compute synch metrics and report it to the PHY state // Compute synch metrics and report it to the PHY state
sync_metrics_t new_sync_metrics = {}; sync_metrics_t new_sync_metrics = {};
new_sync_metrics.cfo = new_meas.cfo_hz; new_sync_metrics.cfo = new_meas.cfo_hz + ul_ext_cfo_hz;
set_sync_metrics(sync_metrics); set_sync_metrics(new_sync_metrics);
// Convert to CSI channel measurement and report new NZP-CSI-RS measurement to the PHY state // Convert to CSI channel measurement and report new NZP-CSI-RS measurement to the PHY state
srsran_csi_channel_measurements_t measurements = {}; srsran_csi_channel_measurements_t measurements = {};
@ -499,11 +499,10 @@ public:
trs_measurements_mutex.lock(); 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.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.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. // 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); 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.nof_re++;
trs_measurements_mutex.unlock(); trs_measurements_mutex.unlock();

View File

@ -487,10 +487,11 @@ bool cc_worker::work_dl()
// Compensate CFO from TRS measurements // Compensate CFO from TRS measurements
if (std::isnormal(phy.args.enable_worker_cfo)) { 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) { for (cf_t* b : rx_buffer) {
if (b != nullptr and ue_ul.ifft.sf_sz != 0) { 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);
} }
} }
} }

View File

@ -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)) { if (prach_buffer->is_ready_to_send(tti, phy_state.cfg.carrier.pci)) {
uint32_t nof_prach_sf = 0; uint32_t nof_prach_sf = 0;
float prach_target_power = 0.0f; 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); worker->set_prach(prach_ptr, prach_target_power);
} }

View File

@ -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 // 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. // 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. // 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); worker_com->semaphore.push(nr_worker);