diff --git a/executables/nr-ue.c b/executables/nr-ue.c index f3769096f8..d3595087e8 100644 --- a/executables/nr-ue.c +++ b/executables/nr-ue.c @@ -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;