From 4039473a70b1466fd71e41df4bb63444e8c2b99f Mon Sep 17 00:00:00 2001 From: Thomas Schlichter Date: Thu, 1 Aug 2024 13:16:20 +0200 Subject: [PATCH] NR_UE: add PI controller to time sync this allows to compensate larger continuous time drift in DL (e.g. large Doppler from LEO satellite) --- executables/nr-ue.c | 2 +- executables/nr-uesoftmodem.h | 6 +++ .../PHY/NR_UE_ESTIMATION/nr_adjust_synch_ue.c | 42 ++++++++++--------- openair1/PHY/NR_UE_ESTIMATION/nr_estimation.h | 3 -- openair1/PHY/defs_nr_UE.h | 3 +- 5 files changed, 31 insertions(+), 25 deletions(-) diff --git a/executables/nr-ue.c b/executables/nr-ue.c index 4317f72041..50e7b68bf5 100644 --- a/executables/nr-ue.c +++ b/executables/nr-ue.c @@ -947,7 +947,7 @@ void *UE_thread(void *arg) if (slot_nr == nb_slot_frame - 1) { // we shift of half of measured drift, at each beginning of frame for both rx and tx iq_shift_to_apply = shiftForNextFrame; - shiftForNextFrame = 0; // We will get a new measured offset if we decode PBCH + shiftForNextFrame = -round(UE->max_pos_acc * get_nrUE_params()->time_sync_I); } const int readBlockSize = get_readBlockSize(slot_nr, fp) - iq_shift_to_apply; diff --git a/executables/nr-uesoftmodem.h b/executables/nr-uesoftmodem.h index 08cafc8379..984058a939 100644 --- a/executables/nr-uesoftmodem.h +++ b/executables/nr-uesoftmodem.h @@ -9,6 +9,8 @@ #define CONFIG_HLP_DLSCH_PARA "number of threads for dlsch processing 0 for no parallelization\n" #define CONFIG_HLP_OFFSET_DIV "Divisor for computing OFDM symbol offset in Rx chain (num samples in CP/). Default value is 8. To set the sample offset to 0, set this value ~ 10e6\n" #define CONFIG_HLP_MAX_LDPC_ITERATIONS "Maximum LDPC decoder iterations\n" +#define CONFIG_HLP_TIME_SYNC_P "coefficient for Proportional part of time sync PI controller\n" +#define CONFIG_HLP_TIME_SYNC_I "coefficient for Integrating part of time sync PI controller\n" #define CONFIG_HLP_NTN_KOFFSET "NTN cellSpecificKoffset-r17 (number of slots for a given subcarrier spacing of 15 kHz)\n" #define CONFIG_HLP_NTN_TA_COMMON "NTN ta-Common, but given in ms\n" @@ -59,6 +61,8 @@ {"ue-timing-correction-disable", CONFIG_HLP_DISABLETIMECORR, PARAMFLAG_BOOL, .iptr=&(nrUE_params.no_timing_correction), .defintval=0, TYPE_INT, 0}, \ {"SLC", CONFIG_HLP_SLF, 0, .u64ptr=&(sidelink_frequency[0][0]), .defuintval=2600000000,TYPE_UINT64,0}, \ {"num-ues", NULL, 0, .iptr=&(NB_UE_INST), .defuintval=1, TYPE_INT, 0}, \ + {"time-sync-P", CONFIG_HLP_TIME_SYNC_P, 0, .dblptr=&(nrUE_params.time_sync_P), .defdblval=0.5, TYPE_DOUBLE, 0}, \ + {"time-sync-I", CONFIG_HLP_TIME_SYNC_I, 0, .dblptr=&(nrUE_params.time_sync_I), .defdblval=0.2, TYPE_DOUBLE, 0}, \ {"ntn-koffset", CONFIG_HLP_NTN_KOFFSET, 0, .uptr=&(nrUE_params.ntn_koffset), .defuintval=0, TYPE_UINT, 0}, \ {"ntn-ta-common", CONFIG_HLP_NTN_TA_COMMON, 0, .dblptr=&(nrUE_params.ntn_ta_common), .defdblval=0.0, TYPE_DOUBLE, 0}, \ {"agc", CONFIG_HLP_AGC, PARAMFLAG_BOOL, .iptr=&(nrUE_params.agc), .defintval=0, TYPE_INT, 0}, \ @@ -82,6 +86,8 @@ typedef struct { int N_RB_DL; int ssb_start_subcarrier; int ldpc_offload_flag; + double time_sync_P; + double time_sync_I; unsigned int ntn_koffset; double ntn_ta_common; int agc; diff --git a/openair1/PHY/NR_UE_ESTIMATION/nr_adjust_synch_ue.c b/openair1/PHY/NR_UE_ESTIMATION/nr_adjust_synch_ue.c index 61c12d145a..5b91a068ed 100644 --- a/openair1/PHY/NR_UE_ESTIMATION/nr_adjust_synch_ue.c +++ b/openair1/PHY/NR_UE_ESTIMATION/nr_adjust_synch_ue.c @@ -24,7 +24,7 @@ #include "PHY/NR_UE_ESTIMATION/nr_estimation.h" #include "PHY/impl_defs_top.h" -#include "executables/softmodem-common.h" +#include "executables/nr-uesoftmodem.h" #include "common/utils/LOG/vcd_signal_dumper.h" //#define DEBUG_PHY @@ -43,12 +43,9 @@ int nr_adjust_synch_ue(NR_DL_FRAME_PARMS *frame_parms, short coef) { int max_val = 0, max_pos = 0; - uint8_t sync_offset = 0; VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_ADJUST_SYNCH, VCD_FUNCTION_IN); - short ncoef = 32767 - coef; - // search for maximum position within the cyclic prefix for (int i = -frame_parms->nb_prefix_samples/2; i < frame_parms->nb_prefix_samples/2; i++) { int temp = 0; @@ -67,32 +64,37 @@ int nr_adjust_synch_ue(NR_DL_FRAME_PARMS *frame_parms, } // filter position to reduce jitter - ue->max_pos_avg = ((ue->max_pos_avg * coef) >> 15) + (max_pos * ncoef); - - int diff = ue->max_pos_avg >> 15; + const int ncoef = 32767 - coef; + ue->max_pos_iir = ((ue->max_pos_iir * coef) >> 15) + (max_pos * ncoef); + const int diff = (ue->max_pos_iir + 16384) >> 15; + // FIXME: Do we really need this hysteresis for FR2? + int sampleShift = diff; if (frame_parms->freq_range == FR2) - sync_offset = 2; - else - sync_offset = 0; + if (abs(diff) <= 2) + sampleShift = 0; - int sampleShift = 0; - if (abs(diff) > (NR_SYNCH_HYST + sync_offset)) - sampleShift = diff; - - const int sample_shift = -(sampleShift / 2); - // reset IIR filter for next offset calculation - ue->max_pos_avg += sample_shift * 32768; + // PI controller + const double PID_P = get_nrUE_params()->time_sync_P; + const double PID_I = get_nrUE_params()->time_sync_I; + int sample_shift = -round(sampleShift * PID_P + ue->max_pos_acc * PID_I); LOG_D(PHY, - "Slot %d: diff = %i, rx_offset (final) = %i : max_pos = %d, max_pos filtered = %ld, max_power = %d\n", + "Frame %d, Slot %d: max_pos = %d, max_pos filtered = %f, diff = %i, sampleShift = %i, max_pos_acc = %d, sample_shift (final) = %d, max_power = %d\n", + frame, slot, + max_pos, + ue->max_pos_iir / 32768.0, diff, sampleShift, - max_pos, - ue->max_pos_avg, + ue->max_pos_acc, + sample_shift, max_val); + // reset IIR filter for next offset calculation + ue->max_pos_iir += -round(sampleShift * PID_P) * 32768; + ue->max_pos_acc += max_pos; + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_ADJUST_SYNCH, VCD_FUNCTION_OUT); return sample_shift; } diff --git a/openair1/PHY/NR_UE_ESTIMATION/nr_estimation.h b/openair1/PHY/NR_UE_ESTIMATION/nr_estimation.h index 0ce6c0d83b..d08cc87f1d 100644 --- a/openair1/PHY/NR_UE_ESTIMATION/nr_estimation.h +++ b/openair1/PHY/NR_UE_ESTIMATION/nr_estimation.h @@ -29,9 +29,6 @@ * @{ */ -/*!\brief Timing drift hysterisis in samples*/ -#define NR_SYNCH_HYST 1 - /* A function to perform the channel estimation of DL PRS signal */ int nr_prs_channel_estimation(uint8_t gNB_id, uint8_t rsc_id, diff --git a/openair1/PHY/defs_nr_UE.h b/openair1/PHY/defs_nr_UE.h index 2ab028b6a9..96eb22049f 100644 --- a/openair1/PHY/defs_nr_UE.h +++ b/openair1/PHY/defs_nr_UE.h @@ -456,7 +456,8 @@ typedef struct PHY_VARS_NR_UE_s { /// temporary offset during cell search prior to MIB decoding int ssb_offset; uint16_t symbol_offset; /// offset in terms of symbols for detected ssb in sync - int64_t max_pos_avg; /// Timing offset IIR filter + int64_t max_pos_iir; /// Timing offset IIR filter + int max_pos_acc; /// Timing offset accumuluated error for PI filter /// Timing Advance updates variables /// Timing advance update computed from the TA command signalled from gNB