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;
|
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)
|
static int handle_sync_req_from_mac(PHY_VARS_NR_UE *UE)
|
||||||
{
|
{
|
||||||
NR_DL_FRAME_PARMS *fp = &UE->frame_parms;
|
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);
|
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.
|
/* Clearing UE harq while DL actors are active causes race condition.
|
||||||
So we let the current execution to complete here.*/
|
So we let the current execution to complete here.*/
|
||||||
for (int i = 0; i < get_nrUE_params()->num_dl_actors; i++) {
|
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;
|
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
|
#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)
|
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;
|
const fapi_nr_dl_ntn_config_command_pdu *ntn_config_params = &UE->ntn_config_message->ntn_config_params;
|
||||||
|
|
||||||
// Handle terrestrial networks
|
// Handle terrestrial networks
|
||||||
if (ntn_config_params->cell_specific_k_offset == 0) {
|
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->dl_Doppler_shift = 0;
|
||||||
UE->ul_Doppler_shift = 0;
|
UE->ul_Doppler_shift = 0;
|
||||||
return;
|
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
|
const int abs_subframe_epoch = ntn_config_params->epoch_subframe
|
||||||
+ ntn_config_params->epoch_sfn * 10
|
+ ntn_config_params->epoch_sfn * 10
|
||||||
+ ntn_config_params->epoch_hfn * 10240;
|
+ 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 pos_sat_0 = ntn_config_params->pos_sat_0;
|
||||||
const position_t vel_sat_0 = ntn_config_params->vel_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 = ntn_config_params->N_common_ta_drift;
|
||||||
const double N_common_ta_drift_variant = ntn_config_params->N_common_ta_drift_variant;
|
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
|
if (abs_subframe_tx >= 0) {
|
||||||
+ N_common_ta_drift * ms_since_epoch / 1e6
|
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)
|
+ N_common_ta_drift_variant * ((int64_t)ms_since_epoch * ms_since_epoch) / 1e9)
|
||||||
* fp->samples_per_subframe;
|
* fp->samples_per_subframe;
|
||||||
|
}
|
||||||
|
|
||||||
UE->freq_offset -= dl_Doppler_shift - UE->dl_Doppler_shift;
|
UE->freq_offset -= dl_Doppler_shift - UE->dl_Doppler_shift;
|
||||||
UE->dl_Doppler_shift = dl_Doppler_shift;
|
UE->dl_Doppler_shift = dl_Doppler_shift;
|
||||||
UE->ul_Doppler_shift = ul_Doppler_shift;
|
UE->ul_Doppler_shift = ul_Doppler_shift;
|
||||||
|
|
||||||
LOG_D(PHY,
|
if (abs_subframe_tx < 0) {
|
||||||
"satellite velocity towards UE = %f m/s, DL Doppler shift = %f kHz, UL Doppler shift = %f kHz\n",
|
LOG_I(PHY,
|
||||||
vel_sat_ue,
|
"satellite velocity towards UE = %f m/s, DL Doppler shift = %f kHz, UL Doppler shift = %f kHz\n",
|
||||||
dl_Doppler_shift / 1000,
|
vel_sat_ue,
|
||||||
ul_Doppler_shift / 1000);
|
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,
|
static void apply_ntn_config(PHY_VARS_NR_UE *UE,
|
||||||
NR_DL_FRAME_PARMS *fp,
|
NR_DL_FRAME_PARMS *fp,
|
||||||
int hfn_rx,
|
int hfn_rx,
|
||||||
@@ -885,9 +923,14 @@ void *UE_thread(void *arg)
|
|||||||
notifiedFIFO_t freeBlocks;
|
notifiedFIFO_t freeBlocks;
|
||||||
initNotifiedFIFO_nothreadSafe(&freeBlocks);
|
initNotifiedFIFO_nothreadSafe(&freeBlocks);
|
||||||
|
|
||||||
double ntn_init_time_drift = get_nrUE_params()->ntn_init_time_drift;
|
const double ntn_init_time_drift = get_nrUE_params()->ntn_init_time_drift;
|
||||||
int ntn_koffset = 0;
|
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 duration_rx_to_tx = NR_UE_CAPABILITY_SLOT_RX_TO_TX;
|
||||||
int timing_advance = UE->timing_advance + UE->timing_advance_ntn;
|
int timing_advance = UE->timing_advance + UE->timing_advance_ntn;
|
||||||
UE->N_TA_offset = determine_N_TA_offset(UE);
|
UE->N_TA_offset = determine_N_TA_offset(UE);
|
||||||
@@ -983,10 +1026,6 @@ void *UE_thread(void *arg)
|
|||||||
syncMsg->UE = UE;
|
syncMsg->UE = UE;
|
||||||
memset(&syncMsg->proc, 0, sizeof(syncMsg->proc));
|
memset(&syncMsg->proc, 0, sizeof(syncMsg->proc));
|
||||||
pushNotifiedFIFO(&UE->sync_actor.fifo, Msg);
|
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;
|
trashed_frames = 0;
|
||||||
syncRunning = true;
|
syncRunning = true;
|
||||||
continue;
|
continue;
|
||||||
@@ -996,13 +1035,8 @@ void *UE_thread(void *arg)
|
|||||||
stream_status = STREAM_STATUS_SYNCING;
|
stream_status = STREAM_STATUS_SYNCING;
|
||||||
syncInFrame(UE, &sync_timestamp, duration_rx_to_tx, intialSyncOffset);
|
syncInFrame(UE, &sync_timestamp, duration_rx_to_tx, intialSyncOffset);
|
||||||
openair0_write_reorder_clear_context(&UE->rfdevice);
|
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
|
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
|
// read in first symbol
|
||||||
AssertFatal(fp->ofdm_symbol_size + fp->nb_prefix_samples0
|
AssertFatal(fp->ofdm_symbol_size + fp->nb_prefix_samples0
|
||||||
== UE->rfdevice.trx_read_func(&UE->rfdevice,
|
== 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
|
// Set to the slot where the SL-SSB was decoded
|
||||||
absolute_slot += UE->SL_UE_PHY_PARAMS.sync_params.slot_offset;
|
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
|
// 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));
|
memset(tx_wait_for_dlsch, 0, sizeof(tx_wait_for_dlsch));
|
||||||
for (int i = 0; i < NUM_PROCESS_SLOT_TX_BARRIERS; i++) {
|
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;
|
writeBlockSize -= new_N_TA_offset - UE->N_TA_offset;
|
||||||
UE->N_TA_offset = new_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)
|
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);
|
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;
|
curMsgTx->absolute_deadline_us = absolute_deadline_us;
|
||||||
|
|
||||||
int slot = curMsgTx->proc.nr_slot_tx;
|
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 next_tx_slot_and_frame = absolute_slot + duration_rx_to_tx + 1;
|
||||||
int wait_for_prev_slot = stream_status == STREAM_STATUS_SYNCED ? 1 : 0;
|
int wait_for_prev_slot = stream_status == STREAM_STATUS_SYNCED ? 1 : 0;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user