NR UE: improve physical layer for NTN (esp. LEO) reestablishment and HO
This commit is contained in:
+75
-24
@@ -497,6 +497,8 @@ static uint64_t get_carrier_frequency(const int N_RB, const int mu, const uint32
|
||||
return carrier_freq;
|
||||
}
|
||||
|
||||
static void apply_ntn_timing_advance_and_doppler(PHY_VARS_NR_UE *UE, const NR_DL_FRAME_PARMS *fp, int abs_subframe_tx);
|
||||
|
||||
static int handle_sync_req_from_mac(PHY_VARS_NR_UE *UE)
|
||||
{
|
||||
NR_DL_FRAME_PARMS *fp = &UE->frame_parms;
|
||||
@@ -521,6 +523,12 @@ static int handle_sync_req_from_mac(PHY_VARS_NR_UE *UE)
|
||||
init_symbol_rotation(fp);
|
||||
}
|
||||
|
||||
// Apply Doppler based on NTN-Config for target cell
|
||||
if (UE->target_Nid_cell != fp->Nid_cell)
|
||||
apply_ntn_timing_advance_and_doppler(UE, fp, -1);
|
||||
// Apply NTN DL Doppler as initial FO
|
||||
UE->initial_fo = UE->dl_Doppler_shift;
|
||||
|
||||
/* Clearing UE harq while DL actors are active causes race condition.
|
||||
So we let the current execution to complete here.*/
|
||||
for (int i = 0; i < get_nrUE_params()->num_dl_actors; i++) {
|
||||
@@ -727,14 +735,40 @@ static inline int get_readBlockSize(uint16_t slot, NR_DL_FRAME_PARMS *fp) {
|
||||
return rem_samples + next_slot_first_symbol;
|
||||
}
|
||||
|
||||
static void fix_ntn_epoch_hfn(PHY_VARS_NR_UE *UE, int hfn, int frame)
|
||||
{
|
||||
const int epoch_frame = UE->ntn_config_message->ntn_config_params.epoch_sfn;
|
||||
const int diff1 = (frame - epoch_frame + 1024) % 1024;
|
||||
const int diff2 = (epoch_frame - frame + 1024) % 1024;
|
||||
|
||||
int *epoch_hfn = &UE->ntn_config_message->ntn_config_params.epoch_hfn;
|
||||
if (diff1 < diff2) { // epoch_frame in the past
|
||||
LOG_I(PHY, "epoch is %d frames in the past\n", diff1);
|
||||
if (epoch_frame <= frame)
|
||||
*epoch_hfn = hfn;
|
||||
else
|
||||
*epoch_hfn = hfn - 1;
|
||||
} else { // epoch_frame in the future
|
||||
LOG_I(PHY, "epoch is %d frames in the future\n", diff2);
|
||||
if (epoch_frame >= frame)
|
||||
*epoch_hfn = hfn;
|
||||
else
|
||||
*epoch_hfn = hfn + 1;
|
||||
}
|
||||
LOG_I(PHY, "setting epoch_hfn = %d\n", *epoch_hfn);
|
||||
}
|
||||
|
||||
#define SPEED_OF_LIGHT 299792458
|
||||
|
||||
// calculate TA and Doppler based on the NTN-Config, if abs_subframe_tx < 0 then apply only Doppler
|
||||
static void apply_ntn_timing_advance_and_doppler(PHY_VARS_NR_UE *UE, const NR_DL_FRAME_PARMS *fp, int abs_subframe_tx)
|
||||
{
|
||||
const fapi_nr_dl_ntn_config_command_pdu *ntn_config_params = &UE->ntn_config_message->ntn_config_params;
|
||||
|
||||
// Handle terrestrial networks
|
||||
if (ntn_config_params->cell_specific_k_offset == 0) {
|
||||
UE->timing_advance_ntn = 0;
|
||||
if (abs_subframe_tx >= 0)
|
||||
UE->timing_advance_ntn = 0;
|
||||
UE->dl_Doppler_shift = 0;
|
||||
UE->ul_Doppler_shift = 0;
|
||||
return;
|
||||
@@ -743,7 +777,7 @@ static void apply_ntn_timing_advance_and_doppler(PHY_VARS_NR_UE *UE, const NR_DL
|
||||
const int abs_subframe_epoch = ntn_config_params->epoch_subframe
|
||||
+ ntn_config_params->epoch_sfn * 10
|
||||
+ ntn_config_params->epoch_hfn * 10240;
|
||||
const int ms_since_epoch = abs_subframe_tx - abs_subframe_epoch;
|
||||
const int ms_since_epoch = abs_subframe_tx < 0 ? 0 : abs_subframe_tx - abs_subframe_epoch;
|
||||
|
||||
const position_t pos_sat_0 = ntn_config_params->pos_sat_0;
|
||||
const position_t vel_sat_0 = ntn_config_params->vel_sat_0;
|
||||
@@ -797,22 +831,26 @@ static void apply_ntn_timing_advance_and_doppler(PHY_VARS_NR_UE *UE, const NR_DL
|
||||
const double N_common_ta_drift = ntn_config_params->N_common_ta_drift;
|
||||
const double N_common_ta_drift_variant = ntn_config_params->N_common_ta_drift_variant;
|
||||
|
||||
UE->timing_advance_ntn = (N_UE_TA_adj + N_common_ta_adj
|
||||
+ N_common_ta_drift * ms_since_epoch / 1e6
|
||||
+ N_common_ta_drift_variant * ((int64_t)ms_since_epoch * ms_since_epoch) / 1e9)
|
||||
* fp->samples_per_subframe;
|
||||
if (abs_subframe_tx >= 0) {
|
||||
UE->timing_advance_ntn = (N_UE_TA_adj + N_common_ta_adj + N_common_ta_drift * ms_since_epoch / 1e6
|
||||
+ N_common_ta_drift_variant * ((int64_t)ms_since_epoch * ms_since_epoch) / 1e9)
|
||||
* fp->samples_per_subframe;
|
||||
}
|
||||
|
||||
UE->freq_offset -= dl_Doppler_shift - UE->dl_Doppler_shift;
|
||||
UE->dl_Doppler_shift = dl_Doppler_shift;
|
||||
UE->ul_Doppler_shift = ul_Doppler_shift;
|
||||
|
||||
LOG_D(PHY,
|
||||
"satellite velocity towards UE = %f m/s, DL Doppler shift = %f kHz, UL Doppler shift = %f kHz\n",
|
||||
vel_sat_ue,
|
||||
dl_Doppler_shift / 1000,
|
||||
ul_Doppler_shift / 1000);
|
||||
if (abs_subframe_tx < 0) {
|
||||
LOG_I(PHY,
|
||||
"satellite velocity towards UE = %f m/s, DL Doppler shift = %f kHz, UL Doppler shift = %f kHz\n",
|
||||
vel_sat_ue,
|
||||
dl_Doppler_shift / 1000,
|
||||
ul_Doppler_shift / 1000);
|
||||
}
|
||||
}
|
||||
|
||||
// apply values based on the NTN-Config
|
||||
static void apply_ntn_config(PHY_VARS_NR_UE *UE,
|
||||
NR_DL_FRAME_PARMS *fp,
|
||||
int hfn_rx,
|
||||
@@ -885,9 +923,14 @@ void *UE_thread(void *arg)
|
||||
notifiedFIFO_t freeBlocks;
|
||||
initNotifiedFIFO_nothreadSafe(&freeBlocks);
|
||||
|
||||
double ntn_init_time_drift = get_nrUE_params()->ntn_init_time_drift;
|
||||
int ntn_koffset = 0;
|
||||
const double ntn_init_time_drift = get_nrUE_params()->ntn_init_time_drift;
|
||||
if (get_nrUE_params()->time_sync_I)
|
||||
// ntn_init_time_drift is in µs/s, max_pos_acc * time_sync_I is in samples/frame
|
||||
UE->max_pos_acc = ntn_init_time_drift * 1e-6 * fp->samples_per_frame / get_nrUE_params()->time_sync_I;
|
||||
else
|
||||
UE->max_pos_acc = 0;
|
||||
|
||||
int ntn_koffset = 0;
|
||||
int duration_rx_to_tx = NR_UE_CAPABILITY_SLOT_RX_TO_TX;
|
||||
int timing_advance = UE->timing_advance + UE->timing_advance_ntn;
|
||||
UE->N_TA_offset = determine_N_TA_offset(UE);
|
||||
@@ -983,10 +1026,6 @@ void *UE_thread(void *arg)
|
||||
syncMsg->UE = UE;
|
||||
memset(&syncMsg->proc, 0, sizeof(syncMsg->proc));
|
||||
pushNotifiedFIFO(&UE->sync_actor.fifo, Msg);
|
||||
if (ntn_koffset == 0) { // reset timing_advance for TN
|
||||
timing_advance = 0;
|
||||
UE->timing_advance = 0;
|
||||
}
|
||||
trashed_frames = 0;
|
||||
syncRunning = true;
|
||||
continue;
|
||||
@@ -996,13 +1035,8 @@ void *UE_thread(void *arg)
|
||||
stream_status = STREAM_STATUS_SYNCING;
|
||||
syncInFrame(UE, &sync_timestamp, duration_rx_to_tx, intialSyncOffset);
|
||||
openair0_write_reorder_clear_context(&UE->rfdevice);
|
||||
if (get_nrUE_params()->time_sync_I)
|
||||
// ntn_init_time_drift is in µs/s, max_pos_acc * time_sync_I is in samples/frame
|
||||
UE->max_pos_acc = ntn_init_time_drift * 1e-6 * fp->samples_per_frame / get_nrUE_params()->time_sync_I;
|
||||
else
|
||||
UE->max_pos_acc = 0;
|
||||
shiftForNextFrame = -(UE->init_sync_frame + trashed_frames + 2) * UE->max_pos_acc * get_nrUE_params()->time_sync_I; // compensate for the time drift that happened during initial sync
|
||||
LOG_D(PHY, "max_pos_acc = %d, shiftForNextFrame = %d\n", UE->max_pos_acc, shiftForNextFrame);
|
||||
LOG_I(PHY, "max_pos_acc = %d, shiftForNextFrame = %d\n", UE->max_pos_acc, shiftForNextFrame);
|
||||
// read in first symbol
|
||||
AssertFatal(fp->ofdm_symbol_size + fp->nb_prefix_samples0
|
||||
== UE->rfdevice.trx_read_func(&UE->rfdevice,
|
||||
@@ -1020,6 +1054,18 @@ void *UE_thread(void *arg)
|
||||
// Set to the slot where the SL-SSB was decoded
|
||||
absolute_slot += UE->SL_UE_PHY_PARAMS.sync_params.slot_offset;
|
||||
}
|
||||
// With the correct frame and slot numbers, we can now fix the UL timing
|
||||
const int frame_rx = (absolute_slot / nb_slot_frame) % 1024;
|
||||
const int hfn_rx = (absolute_slot / nb_slot_frame) / 1024;
|
||||
fix_ntn_epoch_hfn(UE, hfn_rx, frame_rx);
|
||||
if (UE->ntn_config_message->update) {
|
||||
apply_ntn_config(UE, fp, hfn_rx, frame_rx, 0, &duration_rx_to_tx, &timing_advance, &ntn_koffset);
|
||||
} else {
|
||||
const int mu = fp->numerology_index;
|
||||
const int abs_subframe_tx = 10240 * hfn_rx + 10 * frame_rx + (duration_rx_to_tx >> mu);
|
||||
apply_ntn_timing_advance_and_doppler(UE, fp, abs_subframe_tx);
|
||||
}
|
||||
UE->timing_advance = 0;
|
||||
// We have resynchronized, maybe after RF loss so we need to purge any existing context
|
||||
memset(tx_wait_for_dlsch, 0, sizeof(tx_wait_for_dlsch));
|
||||
for (int i = 0; i < NUM_PROCESS_SLOT_TX_BARRIERS; i++) {
|
||||
@@ -1134,6 +1180,11 @@ void *UE_thread(void *arg)
|
||||
writeBlockSize -= new_N_TA_offset - UE->N_TA_offset;
|
||||
UE->N_TA_offset = new_N_TA_offset;
|
||||
}
|
||||
if (writeBlockSize < 0) {
|
||||
timing_advance += writeBlockSize - 1;
|
||||
LOG_I(PHY, "writeBlockSize is %d, setting it to 1 and changing timing_advance to %d\n", writeBlockSize, timing_advance);
|
||||
writeBlockSize = 1;
|
||||
}
|
||||
|
||||
if (curMsg.proc.nr_slot_rx == 0)
|
||||
nr_ue_rrc_timer_trigger(UE->Mod_id, curMsg.proc.hfn_rx, curMsg.proc.frame_rx, curMsg.proc.gNB_id);
|
||||
@@ -1166,7 +1217,7 @@ void *UE_thread(void *arg)
|
||||
curMsgTx->absolute_deadline_us = absolute_deadline_us;
|
||||
|
||||
int slot = curMsgTx->proc.nr_slot_tx;
|
||||
int slot_and_frame = slot + curMsgTx->proc.frame_tx * UE->frame_parms.slots_per_frame;
|
||||
int slot_and_frame = slot + curMsgTx->proc.frame_tx * nb_slot_frame;
|
||||
int next_tx_slot_and_frame = absolute_slot + duration_rx_to_tx + 1;
|
||||
int wait_for_prev_slot = stream_status == STREAM_STATUS_SYNCED ? 1 : 0;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user