Review NR NSA CFO estimation and compensation

master
Xavier Arteaga 3 years ago committed by Andre Puschmann
parent 63bb86bce1
commit de00b80228

@ -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

@ -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

@ -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);

@ -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);

@ -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,

@ -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();

@ -488,9 +488,10 @@ 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_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);
}
}
}

@ -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);
}

@ -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);

Loading…
Cancel
Save