Merge remote-tracking branch 'origin/ntn_leo_freq_comp' into integration_2025_w15 (!3355)
NR UE: add support for continuous frequency offset compensation (in particular NTN LEO Doppler)
- move function add_noise() to file
openair1/SIMULATION/TOOLS/phase_noise.c
- refactor (co)sinus calculation out of phase_noise() into get_sin_cos()
in nr_common.c
- NR UE: continuously estimate the frequency offset using PBCH DMRS
- NR UE: add command line parameter --initial-fo to specify known
initial frequency offset
- NR UE: add support for continuous DL frequency offset compensation
--cont-fo-comp
- NR UE: add support for continuous UL frequency offset
pre-compensation. Depending on the main source of frequency offset,
pre-compensate the UL frequency offset (FO) accordingly. Therefore
modify the flag --cont-fo-comp to accept an integer value, where
* 1 specifies, that the main FO contribution comes from the accuracy of the local oscillator (LO)
* 2 specifies, that the main FO contribution comes from Doppler shift
- NR UE: add PI controller to continuous frequency offset compensation
- rfsimulator: enable and correct NTN LEO doppler simulation
- use SIMD to speed up nr_fo_compensation()
- Extend NTN LEO example in RUNMODEM.md to include continuous Doppler
compensation
- NR UE: in nr_adjust_synch_ue() extend the peak search to +/- cyclic
prefix size, esp. for LEO NTN scenarios the timing drifts during
initial sync, which is mostly compensated with
--ntn-initial-time-drift. But there might be a residual time offset,
and by extending the peak search window we make this more tolerant.
- NR UE: remove unused nr_slot_tx_offset, it is unused since commit
f3e60a14
- NR UE: remove now unnecessary local variable
update_ntn_system_information, directly use
UE->ntn_config_message->update instead
This commit is contained in:
+24
-20
@@ -41,6 +41,7 @@
|
||||
#include "instrumentation.h"
|
||||
#include "common/utils/threadPool/notified_fifo.h"
|
||||
#include "position_interface.h"
|
||||
#include "nr_phy_common.h"
|
||||
|
||||
/*
|
||||
* NR SLOT PROCESSING SEQUENCE
|
||||
@@ -438,9 +439,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);
|
||||
@@ -454,7 +459,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;
|
||||
@@ -553,6 +557,15 @@ static void RU_write(nr_rxtx_thread_data_t *rxtxD, bool sl_tx_action)
|
||||
writeBlockSize -= dummyBlockSize;
|
||||
}
|
||||
|
||||
// pre-compensate UL frequency offset
|
||||
if (flags != TX_BURST_INVALID && get_nrUE_params()->cont_fo_comp) {
|
||||
double ul_freq_offset = -UE->freq_offset * ((double)fp->ul_CarrierFreq / (double)fp->dl_CarrierFreq);
|
||||
if (get_nrUE_params()->cont_fo_comp == 2) // different from LO frequency error compensation, Doppler UL pre-compensation has to be negative
|
||||
ul_freq_offset = -ul_freq_offset;
|
||||
for (int i = 0; i < fp->nb_antennas_tx; i++)
|
||||
nr_fo_compensation(ul_freq_offset, fp->samples_per_subframe, writeTimestamp, txp[i], writeBlockSize);
|
||||
}
|
||||
|
||||
int tmp = openair0_write_reorder(&UE->rfdevice, writeTimestamp, txp, writeBlockSize, fp->nb_antennas_tx, flags);
|
||||
AssertFatal(tmp == writeBlockSize, "");
|
||||
}
|
||||
@@ -868,13 +881,12 @@ static inline int get_readBlockSize(uint16_t slot, NR_DL_FRAME_PARMS *fp) {
|
||||
static inline void apply_ntn_config(PHY_VARS_NR_UE *UE,
|
||||
NR_DL_FRAME_PARMS *fp,
|
||||
int slot_nr,
|
||||
bool *update_ntn_system_information,
|
||||
int *duration_rx_to_tx,
|
||||
int *timing_advance,
|
||||
int *ntn_koffset)
|
||||
{
|
||||
if (*update_ntn_system_information) {
|
||||
*update_ntn_system_information = false;
|
||||
if (UE->ntn_config_message->update) {
|
||||
UE->ntn_config_message->update = false;
|
||||
|
||||
double total_ta_ms = UE->ntn_config_message->ntn_config_params.ntn_total_time_advance_ms;
|
||||
UE->timing_advance = fp->samples_per_subframe * total_ta_ms;
|
||||
@@ -920,6 +932,8 @@ void *UE_thread(void *arg)
|
||||
if (usrp_tx_thread == 1)
|
||||
UE->rfdevice.trx_write_init(&UE->rfdevice);
|
||||
|
||||
InitSinLUT();
|
||||
|
||||
notifiedFIFO_t nf;
|
||||
initNotifiedFIFO(&nf);
|
||||
|
||||
@@ -954,13 +968,9 @@ void *UE_thread(void *arg)
|
||||
|
||||
double ntn_init_time_drift = get_nrUE_params()->ntn_init_time_drift;
|
||||
int ntn_koffset = 0;
|
||||
|
||||
int duration_rx_to_tx = NR_UE_CAPABILITY_SLOT_RX_TO_TX;
|
||||
int nr_slot_tx_offset = 0;
|
||||
bool update_ntn_system_information = false;
|
||||
|
||||
while (!oai_exit) {
|
||||
nr_slot_tx_offset = 0;
|
||||
if (syncRunning) {
|
||||
notifiedFIFO_elt_t *res = pollNotifiedFIFO(&nf);
|
||||
|
||||
@@ -1085,12 +1095,6 @@ void *UE_thread(void *arg)
|
||||
absolute_slot++;
|
||||
TracyCFrameMark;
|
||||
|
||||
if (UE->ntn_config_message->update) {
|
||||
UE->ntn_config_message->update = false;
|
||||
update_ntn_system_information = true;
|
||||
nr_slot_tx_offset = UE->ntn_config_message->ntn_config_params.cell_specific_k_offset << fp->numerology_index;
|
||||
}
|
||||
|
||||
int slot_nr = absolute_slot % nb_slot_frame;
|
||||
nr_rxtx_thread_data_t curMsg = {0};
|
||||
curMsg.UE=UE;
|
||||
@@ -1180,8 +1184,8 @@ void *UE_thread(void *arg)
|
||||
shiftForNextFrame = ret;
|
||||
pushNotifiedFIFO(&UE->dl_actors[curMsg.proc.nr_slot_rx % NUM_DL_ACTORS].fifo, newRx);
|
||||
|
||||
// apply new duration next run to avoid thread dead lock
|
||||
apply_ntn_config(UE, fp, slot_nr, &update_ntn_system_information, &duration_rx_to_tx, &timing_advance, &ntn_koffset);
|
||||
// apply new NTN timing information
|
||||
apply_ntn_config(UE, fp, slot_nr, &duration_rx_to_tx, &timing_advance, &ntn_koffset);
|
||||
|
||||
// Start TX slot processing here. It runs in parallel with RX slot processing
|
||||
// in current code, DURATION_RX_TO_TX constant is the limit to get UL data to encode from a RX slot
|
||||
@@ -1192,7 +1196,7 @@ void *UE_thread(void *arg)
|
||||
curMsgTx->writeBlockSize = writeBlockSize;
|
||||
curMsgTx->proc.timestamp_tx = writeTimestamp;
|
||||
curMsgTx->UE = UE;
|
||||
curMsgTx->proc.nr_slot_tx_offset = nr_slot_tx_offset;
|
||||
|
||||
int slot = curMsgTx->proc.nr_slot_tx;
|
||||
int slot_and_frame = slot + curMsgTx->proc.frame_tx * UE->frame_parms.slots_per_frame;
|
||||
int next_tx_slot_and_frame = absolute_slot + duration_rx_to_tx + 1;
|
||||
|
||||
@@ -224,6 +224,8 @@ 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;
|
||||
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);
|
||||
|
||||
@@ -14,6 +14,10 @@
|
||||
#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_FREQ_SYNC_P "coefficient for Proportional part of continuous frequency offset compensation PI controller\n"
|
||||
#define CONFIG_HLP_FREQ_SYNC_I "coefficient for Integrating part of continuous frequency offset compensation PI controller\n"
|
||||
#define CONFIG_HLP_CONT_FO_COMP "Enable continuous frequency offset (FO) estimation and compensation and specify main FO source (1 = local oscillator, 2 = Doppler shift)\n"
|
||||
#define CONFIG_HLP_AGC "Rx Gain control used for UE\n"
|
||||
#define CONFIG_HLP_NUM_UL_ACTORS "Number of UL actors to use. Set to 0 to use the default value\n"
|
||||
|
||||
@@ -66,6 +70,10 @@
|
||||
{"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}, \
|
||||
{"freq-sync-P", CONFIG_HLP_FREQ_SYNC_P, 0, .dblptr=&(nrUE_params.freq_sync_P), .defdblval=0.01, TYPE_DOUBLE, 0}, \
|
||||
{"freq-sync-I", CONFIG_HLP_FREQ_SYNC_I, 0, .dblptr=&(nrUE_params.freq_sync_I), .defdblval=0.001, TYPE_DOUBLE, 0}, \
|
||||
{"cont-fo-comp", CONFIG_HLP_CONT_FO_COMP, 0, .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}, \
|
||||
{"num-ul-actors", CONFIG_HLP_NUM_UL_ACTORS, 0, .iptr=&nrUE_params.num_ul_actors, .defintval=0, TYPE_INT, 0}, \
|
||||
}
|
||||
@@ -91,6 +99,10 @@ typedef struct {
|
||||
double time_sync_I;
|
||||
double ntn_init_time_drift;
|
||||
int autonomous_ta;
|
||||
double initial_fo;
|
||||
double freq_sync_P;
|
||||
double freq_sync_I;
|
||||
int cont_fo_comp;
|
||||
int agc;
|
||||
char *usrp_args;
|
||||
char *tx_subdev;
|
||||
|
||||
Reference in New Issue
Block a user