From aac4642910dfa3d81997cc040331829157151f92 Mon Sep 17 00:00:00 2001 From: Thomas Schlichter Date: Tue, 14 Jan 2025 13:05:59 +0100 Subject: [PATCH] NR UE: add support for continuous DL frequency offset compensation (--cont-fo-comp) --- executables/nr-ue.c | 13 +++++++++---- executables/nr-uesoftmodem.c | 1 + executables/nr-uesoftmodem.h | 3 +++ openair1/PHY/MODULATION/slot_fep_nr.c | 7 +++++++ openair1/PHY/defs_nr_UE.h | 2 ++ openair1/PHY/nr_phy_common/inc/nr_phy_common.h | 2 ++ openair1/PHY/nr_phy_common/inc/nr_ue_phy_meas.h | 1 + openair1/PHY/nr_phy_common/src/nr_phy_common.c | 13 +++++++++++++ openair1/SCHED_NR_UE/phy_procedures_nr_ue.c | 6 ++++-- 9 files changed, 42 insertions(+), 6 deletions(-) diff --git a/executables/nr-ue.c b/executables/nr-ue.c index d34e710cec..35977941e3 100644 --- a/executables/nr-ue.c +++ b/executables/nr-ue.c @@ -436,9 +436,13 @@ static void UE_synch(void *arg) { ((ret.rx_offset << 1) / fp->samples_per_subframe * fp->slots_per_subframe) + round((float)((ret.rx_offset << 1) % fp->samples_per_subframe) / fp->samples_per_slot0); - // rerun with new cell parameters and frequency-offset - // todo: the freq_offset computed on DL shall be scaled before being applied to UL - nr_rf_card_config_freq(cfg0, ul_carrier, dl_carrier, freq_offset); + if (get_nrUE_params()->cont_fo_comp) { + UE->freq_offset = freq_offset; + } else { + // rerun with new cell parameters and frequency-offset + nr_rf_card_config_freq(cfg0, ul_carrier, dl_carrier, freq_offset); + UE->rfdevice.trx_set_freq_func(&UE->rfdevice, cfg0); + } if (get_nrUE_params()->agc) { nr_ue_adjust_rx_gain(UE, cfg0, UE->adjust_rxgain); @@ -452,7 +456,6 @@ static void UE_synch(void *arg) { cfg0->rx_freq[0], cfg0->tx_freq[0]); - UE->rfdevice.trx_set_freq_func(&UE->rfdevice, cfg0); UE->is_synchronized = 1; } else { int gain_change = 0; @@ -913,6 +916,8 @@ void *UE_thread(void *arg) if (usrp_tx_thread == 1) UE->rfdevice.trx_write_init(&UE->rfdevice); + InitSinLUT(); + notifiedFIFO_t nf; initNotifiedFIFO(&nf); diff --git a/executables/nr-uesoftmodem.c b/executables/nr-uesoftmodem.c index 9f8b8d8563..485fcb8943 100644 --- a/executables/nr-uesoftmodem.c +++ b/executables/nr-uesoftmodem.c @@ -225,6 +225,7 @@ void set_options(int CC_id, PHY_VARS_NR_UE *UE){ UE->chest_time = nrUE_params.chest_time; UE->no_timing_correction = nrUE_params.no_timing_correction; UE->initial_fo = nrUE_params.initial_fo; + UE->cont_fo_comp = nrUE_params.cont_fo_comp; LOG_I(PHY,"Set UE_fo_compensation %d, UE_scan_carrier %d, UE_no_timing_correction %d \n, chest-freq %d, chest-time %d\n", UE->UE_fo_compensation, UE->UE_scan_carrier, UE->no_timing_correction, UE->chest_freq, UE->chest_time); diff --git a/executables/nr-uesoftmodem.h b/executables/nr-uesoftmodem.h index 93741a3424..5210db5362 100644 --- a/executables/nr-uesoftmodem.h +++ b/executables/nr-uesoftmodem.h @@ -15,6 +15,7 @@ #define CONFIG_HLP_NTN_INIT_TIME_DRIFT "Initial NTN DL time drift (feeder link and service link), given in µs/s\n" #define CONFIG_HLP_AUTONOMOUS_TA "Autonomously update TA based on DL drift (useful if main contribution to DL drift is movement, e.g. LEO satellite)\n" #define CONFIG_HLP_INITIAL_FO "Initially compensated DL frequency offset (e.g. known Doppler shift in NTN LEO scenario)\n" +#define CONFIG_HLP_CONT_FO_COMP "Enable continuous frequency offset estimation and compensation\n" #define CONFIG_HLP_AGC "Rx Gain control used for UE\n" /***************************************************************************************************************************************/ @@ -67,6 +68,7 @@ {"ntn-initial-time-drift", CONFIG_HLP_NTN_INIT_TIME_DRIFT, 0, .dblptr=&(nrUE_params.ntn_init_time_drift), .defdblval=0.0, TYPE_DOUBLE, 0}, \ {"autonomous-ta", CONFIG_HLP_AUTONOMOUS_TA, PARAMFLAG_BOOL, .iptr=&(nrUE_params.autonomous_ta), .defintval=0, TYPE_INT, 0}, \ {"initial-fo", CONFIG_HLP_INITIAL_FO, 0, .dblptr=&(nrUE_params.initial_fo), .defdblval=0.0, TYPE_DOUBLE, 0}, \ + {"cont-fo-comp", CONFIG_HLP_CONT_FO_COMP, PARAMFLAG_BOOL, .iptr=&(nrUE_params.cont_fo_comp), .defintval=0, TYPE_INT, 0}, \ {"agc", CONFIG_HLP_AGC, PARAMFLAG_BOOL, .iptr=&(nrUE_params.agc), .defintval=0, TYPE_INT, 0}, \ } // clang-format on @@ -92,6 +94,7 @@ typedef struct { double ntn_init_time_drift; int autonomous_ta; double initial_fo; + int cont_fo_comp; int agc; char *usrp_args; char *tx_subdev; diff --git a/openair1/PHY/MODULATION/slot_fep_nr.c b/openair1/PHY/MODULATION/slot_fep_nr.c index bd61d100f8..201101a39a 100644 --- a/openair1/PHY/MODULATION/slot_fep_nr.c +++ b/openair1/PHY/MODULATION/slot_fep_nr.c @@ -25,6 +25,7 @@ #include "nr_modulation.h" #include "PHY/LTE_ESTIMATION/lte_estimation.h" #include "PHY/NR_UE_ESTIMATION/nr_estimation.h" +#include "PHY/nr_phy_common/inc/nr_phy_common.h" #include //#define DEBUG_FEP @@ -108,6 +109,12 @@ int nr_slot_fep(PHY_VARS_NR_UE *ue, rxdata_ptr = (int16_t *)tmp_dft_in; } + if (ue && ue->cont_fo_comp) { + start_meas_nr_ue_phy(ue, RX_FO_COMPENSATION_STATS); + nr_fo_compensation(ue->freq_offset, frame_parms->samples_per_subframe, rx_offset, (c16_t *)rxdata_ptr, frame_parms->ofdm_symbol_size); + stop_meas_nr_ue_phy(ue, RX_FO_COMPENSATION_STATS); + } + if (ue) start_meas_nr_ue_phy(ue, RX_DFT_STATS); diff --git a/openair1/PHY/defs_nr_UE.h b/openair1/PHY/defs_nr_UE.h index 02fe0d6989..1b0bfe9f89 100644 --- a/openair1/PHY/defs_nr_UE.h +++ b/openair1/PHY/defs_nr_UE.h @@ -461,6 +461,8 @@ typedef struct PHY_VARS_NR_UE_s { int max_pos_acc; /// Timing offset accumuluated error for PI filter double initial_fo; /// initial frequency offset provided by the user + int cont_fo_comp; /// flag enabling the continuous frequency offset estimation and compensation + double freq_offset; /// currently compensated frequency offset /// Timing Advance updates variables /// Timing advance update computed from the TA command signalled from gNB diff --git a/openair1/PHY/nr_phy_common/inc/nr_phy_common.h b/openair1/PHY/nr_phy_common/inc/nr_phy_common.h index 9ae785d8ff..225388cb0d 100644 --- a/openair1/PHY/nr_phy_common/inc/nr_phy_common.h +++ b/openair1/PHY/nr_phy_common/inc/nr_phy_common.h @@ -80,4 +80,6 @@ void nr_256qam_llr(int32_t *rxdataF_comp, int32_t *ch_mag, int32_t *ch_mag2, int void freq2time(uint16_t ofdm_symbol_size, int16_t *freq_signal, int16_t *time_signal); void nr_est_delay(int ofdm_symbol_size, const c16_t *ls_est, c16_t *ch_estimates_time, delay_t *delay); unsigned int nr_get_tx_amp(int power_dBm, int power_max_dBm, int total_nb_rb, int nb_rb); +void nr_fo_compensation(double fo_Hz, int samples_per_ms, int sample_offset, c16_t *rxdata_ptr, int size); + #endif diff --git a/openair1/PHY/nr_phy_common/inc/nr_ue_phy_meas.h b/openair1/PHY/nr_phy_common/inc/nr_ue_phy_meas.h index 09e66e8adf..9f91274bae 100644 --- a/openair1/PHY/nr_phy_common/inc/nr_ue_phy_meas.h +++ b/openair1/PHY/nr_phy_common/inc/nr_ue_phy_meas.h @@ -28,6 +28,7 @@ #define FOREACH_NR_PHY_CPU_MEAS(FN) \ FN(RX_PDSCH_STATS),\ FN(DLSCH_RX_PDCCH_STATS),\ + FN(RX_FO_COMPENSATION_STATS),\ FN(RX_DFT_STATS),\ FN(DLSCH_CHANNEL_ESTIMATION_STATS),\ FN(DLSCH_DECODING_STATS),\ diff --git a/openair1/PHY/nr_phy_common/src/nr_phy_common.c b/openair1/PHY/nr_phy_common/src/nr_phy_common.c index e1580ca9f0..c363037850 100644 --- a/openair1/PHY/nr_phy_common/src/nr_phy_common.c +++ b/openair1/PHY/nr_phy_common/src/nr_phy_common.c @@ -453,3 +453,16 @@ unsigned int nr_get_tx_amp(int power_dBm, int power_max_dBm, int total_nb_rb, in } return (0); } + +void nr_fo_compensation(double fo_Hz, int samples_per_ms, int sample_offset, c16_t *rxdata_ptr, int size) +{ + const double phase_inc = -fo_Hz / (samples_per_ms * 1000); + double phase = sample_offset * phase_inc; + phase -= (int)phase; + for (int i = 0; i < size; i++) { + c16_t rot = get_sin_cos(phase); + *rxdata_ptr = c16mulShift(*rxdata_ptr, rot, 14); + rxdata_ptr++; + phase += phase_inc; + } +} diff --git a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c index 54788de4d1..c7bfbb0f3b 100644 --- a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c +++ b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c @@ -930,9 +930,11 @@ int pbch_pdcch_processing(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, nr_ nr_adjust_synch_ue(fp, ue, gNB_id, fp->ofdm_symbol_size, dl_ch_estimates_time, frame_rx, nr_slot_rx, 16384); } - if (/*ue->continuous_freq_correction &&*/ pbchSuccess == 0) { + if (get_nrUE_params()->cont_fo_comp && pbchSuccess == 0) { double freq_offset = nr_ue_pbch_freq_offset(fp, estimateSz, dl_ch_estimates); - LOG_I(PHY,"detected frequency offset = %.3f Hz\n", freq_offset); + LOG_D(PHY,"compensated frequency offset = %.3f Hz, detected residual frequency offset = %.3f Hz\n", ue->freq_offset, freq_offset); + + ue->freq_offset += freq_offset; } } LOG_D(PHY, "Doing N0 measurements in %s\n", __FUNCTION__);