Commit 834a6fc1 authored by Thomas Schlichter's avatar Thomas Schlichter

NR UE: improve physical layer for NTN (esp. LEO) reestablishment and HO

parent ae12190a
...@@ -497,6 +497,8 @@ static uint64_t get_carrier_frequency(const int N_RB, const int mu, const uint32 ...@@ -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) ...@@ -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) { ...@@ -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 ...@@ -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 ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment