diff --git a/doc/RUNMODEM.md b/doc/RUNMODEM.md index b24b4940e5..56359071a8 100644 --- a/doc/RUNMODEM.md +++ b/doc/RUNMODEM.md @@ -137,6 +137,7 @@ Here are some useful command line options for the NR UE: |--------------------------|---------------------------------------------------------------------------------------------------------------| | `--ue-scan-carrier` | Scan for cells in current bandwidth. This option can be used if the SSB position of the gNB is unknown. If multiple cells are detected, the UE will try to connect to the first cell. By default, this option is disabled and the UE attempts to only decode SSB given by `--ssb`. | | `--ue-fo-compensation` | Enables the frequency offset compensation at the UE. Useful when running over the air and/or without an external clock/time source. | +| `--initial-fo` | Sets the known initial frequency offset. Useful especially with large Doppler frequency, e.g. LEO satellite. | | `--usrp-args` | Equivalent to the `sdr_addrs` field in the gNB config file. Used to identify the USRP and set some basic parameters (like the clock source). | | `--clock-source` | Sets the clock source (internal or external). | | `--time-source` | Sets the time source (internal or external). | diff --git a/executables/nr-uesoftmodem.c b/executables/nr-uesoftmodem.c index c0142ce896..9f8b8d8563 100644 --- a/executables/nr-uesoftmodem.c +++ b/executables/nr-uesoftmodem.c @@ -224,6 +224,7 @@ void set_options(int CC_id, PHY_VARS_NR_UE *UE){ UE->chest_freq = nrUE_params.chest_freq; UE->chest_time = nrUE_params.chest_time; UE->no_timing_correction = nrUE_params.no_timing_correction; + UE->initial_fo = nrUE_params.initial_fo; 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 f7e3b42a72..93741a3424 100644 --- a/executables/nr-uesoftmodem.h +++ b/executables/nr-uesoftmodem.h @@ -14,6 +14,7 @@ #define CONFIG_HLP_TIME_SYNC_I "coefficient for Integrating part of time sync PI controller\n" #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_AGC "Rx Gain control used for UE\n" /***************************************************************************************************************************************/ @@ -65,6 +66,7 @@ {"time-sync-I", CONFIG_HLP_TIME_SYNC_I, 0, .dblptr=&(nrUE_params.time_sync_I), .defdblval=0.0, TYPE_DOUBLE, 0}, \ {"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}, \ {"agc", CONFIG_HLP_AGC, PARAMFLAG_BOOL, .iptr=&(nrUE_params.agc), .defintval=0, TYPE_INT, 0}, \ } // clang-format on @@ -89,6 +91,7 @@ typedef struct { double time_sync_I; double ntn_init_time_drift; int autonomous_ta; + double initial_fo; int agc; char *usrp_args; char *tx_subdev; diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_initial_sync.c b/openair1/PHY/NR_UE_TRANSPORT/nr_initial_sync.c index 3143333a3c..dc634584f6 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_initial_sync.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_initial_sync.c @@ -199,6 +199,9 @@ void nr_scan_ssb(void *arg) // initial sync performed on two successive frames, if pbch passes on first frame, no need to process second frame // only one frame is used for simulation tools for (int frame_id = 0; frame_id < ssbInfo->nFrames && !ssbInfo->syncRes.cell_detected; frame_id++) { + if (ssbInfo->freqOffset) + compensate_freq_offset(rxdata, fp, ssbInfo->freqOffset, frame_id); + /* process pss search on received buffer */ ssbInfo->syncRes.frame_id = frame_id; int nid2; @@ -268,7 +271,7 @@ void nr_scan_ssb(void *arg) phase_tdd_ncp, ssbInfo->syncRes.rx_offset); #endif - ssbInfo->freqOffset = freq_offset_pss + freq_offset_sss; + ssbInfo->freqOffset += freq_offset_pss + freq_offset_sss; if (ssbInfo->syncRes.cell_detected) { // we got sss channel ssbInfo->syncRes.cell_detected = nr_pbch_detection(ssbInfo->proc, @@ -319,6 +322,7 @@ nr_initial_sync_t nr_initial_sync(UE_nr_rxtx_proc_t *proc, .syncRes.cell_detected = false, .nFrames = n_frames, .foFlag = ue->UE_fo_compensation, + .freqOffset = ue->initial_fo, .targetNidCell = ue->target_Nid_cell}; ssbInfo->rxdata = malloc16_clear(fp->nb_antennas_rx * sizeof(c16_t *)); for (int ant = 0; ant < fp->nb_antennas_rx; ant++) { diff --git a/openair1/PHY/defs_nr_UE.h b/openair1/PHY/defs_nr_UE.h index 2cb2b3d8e6..02fe0d6989 100644 --- a/openair1/PHY/defs_nr_UE.h +++ b/openair1/PHY/defs_nr_UE.h @@ -460,6 +460,8 @@ typedef struct PHY_VARS_NR_UE_s { int64_t max_pos_iir; /// Timing offset IIR filter int max_pos_acc; /// Timing offset accumuluated error for PI filter + double initial_fo; /// initial frequency offset provided by the user + /// Timing Advance updates variables /// Timing advance update computed from the TA command signalled from gNB int timing_advance;