From 99f36285692b3906165107f39285b7c1f817ef7d Mon Sep 17 00:00:00 2001 From: Thomas Schlichter Date: Mon, 7 Apr 2025 12:57:28 +0000 Subject: [PATCH 01/15] gNB: add function nr_update_sib19() allowing to update SIB19 information --- openair2/COMMON/mac_messages_def.h | 2 + openair2/COMMON/mac_messages_types.h | 3 + openair2/GNB_APP/gnb_app.c | 5 ++ openair2/LAYER2/NR_MAC_gNB/config.c | 90 +++++++++++++++++++++++++ openair2/LAYER2/NR_MAC_gNB/mac_config.h | 46 +++++++++++++ openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h | 1 + 6 files changed, 147 insertions(+) create mode 100644 openair2/LAYER2/NR_MAC_gNB/mac_config.h diff --git a/openair2/COMMON/mac_messages_def.h b/openair2/COMMON/mac_messages_def.h index e3ef328017..f342444c65 100644 --- a/openair2/COMMON/mac_messages_def.h +++ b/openair2/COMMON/mac_messages_def.h @@ -60,3 +60,5 @@ MESSAGE_DEF(NR_RRC_MAC_CCCH_DATA_IND, MESSAGE_PRIORITY_MED_PLUS, NRRrcMacCcch MESSAGE_DEF(NR_RRC_MAC_BCCH_DATA_IND, MESSAGE_PRIORITY_MED_PLUS, NRRrcMacBcchDataInd, nr_rrc_mac_bcch_data_ind) MESSAGE_DEF(NR_RRC_MAC_SBCCH_DATA_IND, MESSAGE_PRIORITY_MED_PLUS, NRRrcMacSBcchDataInd, nr_rrc_mac_sbcch_data_ind) +// Message to GNB_APP to update SIB19 satellite position information +MESSAGE_DEF(GNB_SAT_POSITION_UPDATE, MESSAGE_PRIORITY_MED, gnb_sat_position_update_t, gnb_sat_position_update) diff --git a/openair2/COMMON/mac_messages_types.h b/openair2/COMMON/mac_messages_types.h index ebbda2fc26..f5712b115a 100644 --- a/openair2/COMMON/mac_messages_types.h +++ b/openair2/COMMON/mac_messages_types.h @@ -31,6 +31,7 @@ #include #include "OCTET_STRING.h" +#include "NR_MAC_gNB/mac_config.h" //-------------------------------------------------------------------------------------------// // Defines to access message fields. @@ -61,6 +62,8 @@ #define RRC_MAC_DRX_CONFIG_REQ(mSGpTR) (mSGpTR)->ittiMsg.rrc_mac_drx_config_req +#define GNB_SAT_POSITION_UPDATE(mSGpTR) (mSGpTR)->ittiMsg.gnb_sat_position_update + // Some constants from "LAYER2/MAC/defs.h" #define BCCH_SDU_SIZE (512) #define BCCH_SDU_MBMS_SIZE (512) diff --git a/openair2/GNB_APP/gnb_app.c b/openair2/GNB_APP/gnb_app.c index e90a83d3bc..3b97dfe515 100644 --- a/openair2/GNB_APP/gnb_app.c +++ b/openair2/GNB_APP/gnb_app.c @@ -212,6 +212,11 @@ void *gNB_app_task(void *args_p) LOG_I(GNB_APP, " Received %s: timer_id %ld\n", msg_name, TIMER_HAS_EXPIRED(msg_p).timer_id); break; + case GNB_SAT_POSITION_UPDATE: + LOG_I(GNB_APP, " Received GNB_SAT_POSITION_UPDATE message\n"); + nr_update_sib19(&GNB_SAT_POSITION_UPDATE(msg_p)); + break; + default: LOG_E(GNB_APP, "Received unexpected message %s\n", msg_name); break; diff --git a/openair2/LAYER2/NR_MAC_gNB/config.c b/openair2/LAYER2/NR_MAC_gNB/config.c index f87b4024b9..8224170271 100644 --- a/openair2/LAYER2/NR_MAC_gNB/config.c +++ b/openair2/LAYER2/NR_MAC_gNB/config.c @@ -927,6 +927,96 @@ bool nr_mac_configure_other_sib(gNB_MAC_INST *nrmac, int num_cu_sib, const f1ap_ return true; } +bool nr_update_sib19(const gnb_sat_position_update_t *sat_position) +{ + gNB_MAC_INST *nrmac = RC.nrmac[0]; + NR_COMMON_channels_t *cc = &nrmac->common_channels[0]; + NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon; + + if (!scc || !scc->ext2 || !scc->ext2->ntn_Config_r17) + return false; + + const vector_t *pos = &sat_position->position; + const vector_t *vel = &sat_position->velocity; + + LOG_D(NR_MAC, "SFN = %d, SubFrame = %d\n", sat_position->sfn, sat_position->subframe); + LOG_D(NR_MAC, "TA_Common: value %d, %f msec\n", sat_position->delay, sat_position->delay * 4.072e-6); + LOG_D(NR_MAC, "TA_CommonDrift: value %d, = %f µsec/sec\n", sat_position->drift, sat_position->drift * 0.2e-3); + LOG_D(NR_MAC, "TA_CommonDriftVariant: value %d, %f µsec/sec^2\n", sat_position->accel, sat_position->accel * 0.2e-4); + LOG_D(NR_MAC, "SAT Position: values %d/%d/%d, %.3f/%3f/%3f metres in X/Y/Z\n", pos->X, pos->Y, pos->Z, pos->X * 1.3, pos->Y * 1.3, pos->Z * 1.3); + LOG_D(NR_MAC, "SAT Velocity: values %d/%d/%d, %.3f/%3f/%3f m/s in X/Y/Z\n", vel->X, vel->Y, vel->Z, vel->X * 0.06, vel->Y * 0.06, vel->Z * 0.06); + + NR_SCHED_LOCK(&nrmac->sched_lock); + + if (!scc->ext2->ntn_Config_r17->epochTime_r17) + scc->ext2->ntn_Config_r17->epochTime_r17 = calloc (1, sizeof(*scc->ext2->ntn_Config_r17->epochTime_r17)); + + NR_EpochTime_r17_t *epoch_time_r17 = scc->ext2->ntn_Config_r17->epochTime_r17; + epoch_time_r17->sfn_r17 = sat_position->sfn; + epoch_time_r17->subFrameNR_r17 = sat_position->subframe; + + if (!scc->ext2->ntn_Config_r17->ta_Info_r17) + scc->ext2->ntn_Config_r17->ta_Info_r17 = calloc(1, sizeof(*scc->ext2->ntn_Config_r17->ta_Info_r17)); + + NR_TA_Info_r17_t *sib19_ta_info = scc->ext2->ntn_Config_r17->ta_Info_r17; + + // SIB19 provides Round trip delay on feeder link (between gNB and SAT). + sib19_ta_info->ta_Common_r17 = sat_position->delay; + + if (sat_position->drift) { + if (!sib19_ta_info->ta_CommonDrift_r17) + sib19_ta_info->ta_CommonDrift_r17 = calloc(1, sizeof(*sib19_ta_info->ta_CommonDrift_r17)); + *sib19_ta_info->ta_CommonDrift_r17 = sat_position->drift; + } else + free_and_zero(sib19_ta_info->ta_CommonDrift_r17); + + if (sat_position->accel) { + if (!sib19_ta_info->ta_CommonDriftVariant_r17) + sib19_ta_info->ta_CommonDriftVariant_r17 = calloc(1, sizeof(*sib19_ta_info->ta_CommonDriftVariant_r17)); + *sib19_ta_info->ta_CommonDriftVariant_r17 = sat_position->accel; + } else + free_and_zero(sib19_ta_info->ta_CommonDriftVariant_r17); + + // Currently PositionVelocity is supported and not yet the OrbitalParams + if (!scc->ext2->ntn_Config_r17->ephemerisInfo_r17) { + scc->ext2->ntn_Config_r17->ephemerisInfo_r17 = calloc(1, sizeof(*scc->ext2->ntn_Config_r17->ephemerisInfo_r17)); + scc->ext2->ntn_Config_r17->ephemerisInfo_r17->present = NR_EphemerisInfo_r17_PR_NOTHING; + } + if (scc->ext2->ntn_Config_r17->ephemerisInfo_r17->present == NR_EphemerisInfo_r17_PR_orbital_r17) { + ASN_STRUCT_FREE(asn_DEF_NR_Orbital_r17, scc->ext2->ntn_Config_r17->ephemerisInfo_r17->choice.orbital_r17); + scc->ext2->ntn_Config_r17->ephemerisInfo_r17->choice.orbital_r17 = NULL; + scc->ext2->ntn_Config_r17->ephemerisInfo_r17->present = NR_EphemerisInfo_r17_PR_NOTHING; + } + if (!scc->ext2->ntn_Config_r17->ephemerisInfo_r17->choice.positionVelocity_r17) + scc->ext2->ntn_Config_r17->ephemerisInfo_r17->choice.positionVelocity_r17 = + calloc(1, sizeof(*scc->ext2->ntn_Config_r17->ephemerisInfo_r17->choice.positionVelocity_r17)); + + scc->ext2->ntn_Config_r17->ephemerisInfo_r17->present = NR_EphemerisInfo_r17_PR_positionVelocity_r17; + NR_PositionVelocity_r17_t *sib19_PosVel = scc->ext2->ntn_Config_r17->ephemerisInfo_r17->choice.positionVelocity_r17; + + sib19_PosVel->positionX_r17 = pos->X; + sib19_PosVel->positionY_r17 = pos->Y; + sib19_PosVel->positionZ_r17 = pos->Z; + sib19_PosVel->velocityVX_r17 = vel->X; + sib19_PosVel->velocityVY_r17 = vel->Y; + sib19_PosVel->velocityVZ_r17 = vel->Z; + + NR_SystemInformation_IEs_t *sysInfov17 = calloc(1, sizeof(*sysInfov17)); // for othersibs + struct NR_SystemInformation_IEs__sib_TypeAndInfo__Member *type_du = calloc(1, sizeof(*type_du)); + type_du->present = NR_SystemInformation_IEs__sib_TypeAndInfo__Member_PR_sib19_v1700; + NR_SIB19_r17_t *sib19 = get_SIB19_NR(cc->ServingCellConfigCommon); + type_du->choice.sib19_v1700 = sib19; + add_sib_to_systeminformation(sysInfov17, type_du); + + cc->other_sib_bcch_length[1] = encode_sysinfo_ie(sysInfov17, cc->other_sib_bcch_pdu[1], sizeof(cc->other_sib_bcch_pdu[1])); + AssertFatal(cc->other_sib_bcch_length[1] > 0, "could not encode SIB19\n"); + ASN_STRUCT_FREE(asn_DEF_NR_SystemInformation_IEs, sysInfov17); + + NR_SCHED_UNLOCK(&nrmac->sched_lock); + + return true; +} + void prepare_du_configuration_update(gNB_MAC_INST *mac, f1ap_served_cell_info_t *info, NR_BCCH_BCH_Message_t *mib, diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_config.h b/openair2/LAYER2/NR_MAC_gNB/mac_config.h new file mode 100644 index 0000000000..1fdbe62115 --- /dev/null +++ b/openair2/LAYER2/NR_MAC_gNB/mac_config.h @@ -0,0 +1,46 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#ifndef __LAYER2_NR_MAC_CONFIG_H__ +#define __LAYER2_NR_MAC_CONFIG_H__ + +#include + +typedef struct vector_s { + int X; + int Y; + int Z; +} vector_t; + +// Format similar to values sent in SIB19 +typedef struct gnb_sat_position_update_s { + int sfn; + int subframe; + uint32_t delay; + int drift; + uint32_t accel; + vector_t position; + vector_t velocity; +} gnb_sat_position_update_t; + +bool nr_update_sib19(const gnb_sat_position_update_t *sat_position); + +#endif /*__LAYER2_NR_MAC_CONFIG_H__*/ diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index 3918e0215c..64bdb86980 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -88,6 +88,7 @@ /* MAC */ #include "LAYER2/NR_MAC_COMMON/nr_mac_common.h" +#include "LAYER2/NR_MAC_gNB/mac_config.h" #include "NR_TAG.h" /* Defs */ From 42bc0d4eb37ec0f95440f4f4187afc84c8942f85 Mon Sep 17 00:00:00 2001 From: Thomas Schlichter Date: Wed, 23 Apr 2025 12:38:13 +0000 Subject: [PATCH 02/15] rfsimulator: update SIB19 contents every second for LEO channel simulations --- radio/rfsimulator/apply_channelmod.c | 32 ++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/radio/rfsimulator/apply_channelmod.c b/radio/rfsimulator/apply_channelmod.c index efeb03b25c..2771706f55 100644 --- a/radio/rfsimulator/apply_channelmod.c +++ b/radio/rfsimulator/apply_channelmod.c @@ -25,6 +25,7 @@ #include #include #include +#include "openair2/LAYER2/NR_MAC_gNB/mac_config.h" #include "rfsimulator.h" /* @@ -95,6 +96,7 @@ void rxAddInput(const c16_t *input_sig, const double vel_ue_sat = (vel_sat_x * dir_ue_sat_x + vel_sat_y * dir_ue_sat_y + vel_sat_z * dir_ue_sat_z) / dist_ue_sat; double dist_sat_gnb = 0; + double vel_sat_gnb = 0; if (channelDesc->modelid == SAT_LEO_TRANS) { const double pos_gnb_x = 0; const double pos_gnb_y = 0; @@ -105,6 +107,7 @@ void rxAddInput(const c16_t *input_sig, const double dir_sat_gnb_z = pos_gnb_z - pos_sat_z; dist_sat_gnb = sqrt(dir_sat_gnb_x * dir_sat_gnb_x + dir_sat_gnb_y * dir_sat_gnb_y + dir_sat_gnb_z * dir_sat_gnb_z); + vel_sat_gnb = (vel_sat_x * dir_sat_gnb_x + vel_sat_y * dir_sat_gnb_y + vel_sat_z * dir_sat_gnb_z) / dist_sat_gnb; } const double prop_delay = (dist_ue_sat + dist_sat_gnb) / c; @@ -117,8 +120,29 @@ void rxAddInput(const c16_t *input_sig, if(TS - last_TS >= channelDesc->sampling_rate) { last_TS = TS; - LOG_D(HW, "Satellite orbit: time %f s, Position = (%f, %f, %f), Velocity = (%f, %f, %f)\n", t, pos_sat_x, pos_sat_y, pos_sat_z, vel_sat_x, vel_sat_y, vel_sat_z); - LOG_D(HW, "Uplink delay %f ms, Doppler shift UE->SAT %f kHz\n", prop_delay * 1000, f_Doppler_shift_ue_sat / 1000); + LOG_I(HW, "Satellite orbit: time %f s, Position = (%f, %f, %f), Velocity = (%f, %f, %f)\n", t, pos_sat_x, pos_sat_y, pos_sat_z, vel_sat_x, vel_sat_y, vel_sat_z); + LOG_I(HW, "Uplink delay %f ms, Doppler shift UE->SAT %f kHz\n", prop_delay * 1000, f_Doppler_shift_ue_sat / 1000); + + const int samples_per_subframe = channelDesc->sampling_rate / 1000; + const int abs_subframe = TS / samples_per_subframe; + gnb_sat_position_update_t sat_position = { + .sfn = (abs_subframe / 10) % 1024, + .subframe = abs_subframe % 10, + .delay = 2 * dist_sat_gnb / (c * 4.072e-9), + .drift = 2 * -vel_sat_gnb / (c * 0.2e-9), + .position.X = pos_sat_x / 1.3, + .position.Y = pos_sat_y / 1.3, + .position.Z = pos_sat_z / 1.3, + .velocity.X = vel_sat_x / 0.06, + .velocity.Y = vel_sat_y / 0.06, + .velocity.Z = vel_sat_z / 0.06, + }; + // Here we update the SIB19 information directly in the gNB MAC layer. + // Without rf-simulaor, in a real system or with an external channel emulator, the SIB19 updates would + // be provided via an external interface (e.g. O-RAN E2 interface) to the MAC layer (in the O-DU). + // We do it directly here, because we can, and an E2 Interface implementation (e.g using FlexRIC) + // would pull too many dependencies into rf-simulator, just for updating SIB19. + nr_update_sib19(&sat_position); } } else { const double dir_sat_ue_x = pos_ue_x - pos_sat_x; @@ -151,8 +175,8 @@ void rxAddInput(const c16_t *input_sig, if(TS - last_TS >= channelDesc->sampling_rate) { last_TS = TS; - LOG_D(HW, "Satellite orbit: time %f s, Position = (%f, %f, %f), Velocity = (%f, %f, %f)\n", t, pos_sat_x, pos_sat_y, pos_sat_z, vel_sat_x, vel_sat_y, vel_sat_z); - LOG_D(HW, "Downlink delay %f ms, Doppler shift SAT->UE %f kHz\n", prop_delay * 1000, f_Doppler_shift_sat_ue / 1000); + LOG_I(HW, "Satellite orbit: time %f s, Position = (%f, %f, %f), Velocity = (%f, %f, %f)\n", t, pos_sat_x, pos_sat_y, pos_sat_z, vel_sat_x, vel_sat_y, vel_sat_z); + LOG_I(HW, "Downlink delay %f ms, Doppler shift SAT->UE %f kHz\n", prop_delay * 1000, f_Doppler_shift_sat_ue / 1000); } } } From f1d612c01bbfd3fb1ce2c6de42cf726fedf944ed Mon Sep 17 00:00:00 2001 From: Thomas Schlichter Date: Wed, 23 Apr 2025 12:49:16 +0000 Subject: [PATCH 03/15] NR UE: improve initial timing advance calculation from SIB19 Before, we only considered ta_Common_r17 and the SAT position from SIB19 to compute the initial timing advance value. This is good enough if the satellite does not move too fast (e.g. GEO satellite). Now we also consider ta_CommonDrift_r17 and the SAT velocity together with the epoch time from SIB19. This improves the accuracy of the initial TA computation, esp. for LEO satellite scenarios. --- executables/nr-ue.c | 36 ++++--- .../nfapi/public_inc/fapi_nr_ue_interface.h | 10 +- openair1/SCHED_NR_UE/fapi_nr_ue_l1.c | 7 +- openair2/LAYER2/NR_MAC_UE/config_ue.c | 97 +++++++++++++------ openair2/LAYER2/NR_MAC_UE/mac_defs.h | 24 +++-- openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c | 4 +- openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c | 12 ++- 7 files changed, 135 insertions(+), 55 deletions(-) diff --git a/executables/nr-ue.c b/executables/nr-ue.c index d0a8f27a0f..ff3b5c2110 100644 --- a/executables/nr-ue.c +++ b/executables/nr-ue.c @@ -905,7 +905,8 @@ 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, + int frame_rx, + int slot_rx, int *duration_rx_to_tx, int *timing_advance, int *ntn_koffset) @@ -913,22 +914,33 @@ static inline void apply_ntn_config(PHY_VARS_NR_UE *UE, 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; + const int mu = fp->numerology_index; + const int koffset = UE->ntn_config_message->ntn_config_params.cell_specific_k_offset; - int mu = fp->numerology_index; - int koffset = UE->ntn_config_message->ntn_config_params.cell_specific_k_offset; - if (*ntn_koffset != koffset) { - *duration_rx_to_tx = NR_UE_CAPABILITY_SLOT_RX_TO_TX + (koffset << mu); - *timing_advance += fp->get_samples_slot_timestamp(slot_nr, fp, (koffset - *ntn_koffset) << mu); - *ntn_koffset = koffset; - } + *duration_rx_to_tx = NR_UE_CAPABILITY_SLOT_RX_TO_TX + (koffset << mu); + if (koffset > *ntn_koffset) + *timing_advance += fp->get_samples_slot_timestamp(slot_rx, fp, (koffset - *ntn_koffset) << mu); + else if (koffset < *ntn_koffset) + *timing_advance -= fp->get_samples_slot_timestamp(slot_rx, fp, (*ntn_koffset - koffset) << mu); + *ntn_koffset = koffset; + + const int abs_subframe_tx = 10 * frame_rx + ((slot_rx + *duration_rx_to_tx) >> mu); + const int abs_subframe_epoch = + 10 * UE->ntn_config_message->ntn_config_params.epoch_sfn + UE->ntn_config_message->ntn_config_params.epoch_subframe; + const int ms_since_epoch = (abs_subframe_tx - abs_subframe_epoch + 10240) % 10240; + + const double total_ta_ms = UE->ntn_config_message->ntn_config_params.ntn_total_time_advance_ms; + const double total_ta_drift = UE->ntn_config_message->ntn_config_params.ntn_total_time_advance_drift; // µs/s + UE->timing_advance = fp->samples_per_subframe * (total_ta_ms + (total_ta_drift / 1000.0) * (ms_since_epoch / 1000.0)); LOG_I(PHY, - "k_offset = %d ms (%d slots), ntn_total_time_advance_ms = %f ms (%d samples)\n", + "k_offset = %d ms (%d slots), total_ta_ms = %f ms, total_ta_drift = %f µs/s, ms_since_epoch = %d ms, computed " + "timing_advance = %d samples\n", *ntn_koffset, *ntn_koffset << mu, total_ta_ms, + total_ta_drift, + ms_since_epoch, UE->timing_advance); } } @@ -1227,7 +1239,7 @@ void *UE_thread(void *arg) } // apply new NTN timing information - apply_ntn_config(UE, fp, slot_nr, &duration_rx_to_tx, &timing_advance, &ntn_koffset); + apply_ntn_config(UE, fp, curMsg.proc.frame_rx, curMsg.proc.nr_slot_rx, &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 diff --git a/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h b/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h index 140ed130a4..b40c062f03 100644 --- a/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h +++ b/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h @@ -557,16 +557,22 @@ typedef struct { } fapi_nr_ta_command_pdu; typedef struct { + int epoch_sfn; + int epoch_subframe; + // N_common_ta_adj represents common round-trip-time between gNB and SAT received in SIB19 (ms) double N_common_ta_adj; - // N_UE_TA_adj calculated round-trip-time between UE and SAT (ms) - double N_UE_TA_adj; // drift rate of common ta in µs/s double ntn_ta_commondrift; + // N_UE_TA_adj calculated round-trip-time between UE and SAT (ms) + double N_UE_TA_adj; + // drift rate of N_UE_TA in µs/s + double N_UE_TA_drift; // cell scheduling offset expressed in terms of 15kHz SCS long cell_specific_k_offset; double ntn_total_time_advance_ms; + double ntn_total_time_advance_drift; } fapi_nr_dl_ntn_config_command_pdu; typedef struct { diff --git a/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c b/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c index 6bb7ed3e4c..c7235e807b 100644 --- a/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c +++ b/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c @@ -352,10 +352,15 @@ static void configure_ntn_params(PHY_VARS_NR_UE *ue, fapi_nr_dl_ntn_config_comma ue->ntn_config_message = CALLOC(1, sizeof(*ue->ntn_config_message)); } - ue->ntn_config_message->ntn_config_params.cell_specific_k_offset = ntn_params_message->cell_specific_k_offset; + ue->ntn_config_message->ntn_config_params.epoch_sfn = ntn_params_message->epoch_sfn; + ue->ntn_config_message->ntn_config_params.epoch_subframe = ntn_params_message->epoch_subframe; ue->ntn_config_message->ntn_config_params.N_common_ta_adj = ntn_params_message->N_common_ta_adj; ue->ntn_config_message->ntn_config_params.ntn_ta_commondrift = ntn_params_message->ntn_ta_commondrift; + ue->ntn_config_message->ntn_config_params.N_UE_TA_adj = ntn_params_message->N_UE_TA_adj; + ue->ntn_config_message->ntn_config_params.N_UE_TA_drift = ntn_params_message->N_UE_TA_drift; + ue->ntn_config_message->ntn_config_params.cell_specific_k_offset = ntn_params_message->cell_specific_k_offset; ue->ntn_config_message->ntn_config_params.ntn_total_time_advance_ms = ntn_params_message->ntn_total_time_advance_ms; + ue->ntn_config_message->ntn_config_params.ntn_total_time_advance_drift = ntn_params_message->ntn_total_time_advance_drift; ue->ntn_config_message->update = true; } diff --git a/openair2/LAYER2/NR_MAC_UE/config_ue.c b/openair2/LAYER2/NR_MAC_UE/config_ue.c index bfea78d540..8bf20428c2 100644 --- a/openair2/LAYER2/NR_MAC_UE/config_ue.c +++ b/openair2/LAYER2/NR_MAC_UE/config_ue.c @@ -267,59 +267,102 @@ static void config_common_ue_sa(NR_UE_MAC_INST_t *mac, NR_ServingCellConfigCommo } // computes round-trip-time between ue and sat based on SIB19 ephemeris data -static double calculate_ue_sat_ta(const position_t *position_params, NR_PositionVelocity_r17_t *sat_pos) +static void calculate_ue_sat_ta(const position_t *position_params, + const NR_PositionVelocity_r17_t *sat_pos, + ntn_timing_advance_componets_t *ntn_ta) { // get UE position coordinates - double posx = position_params->positionX; - double posy = position_params->positionY; - double posz = position_params->positionZ; + double pos_ue_x = position_params->positionX; + double pos_ue_y = position_params->positionY; + double pos_ue_z = position_params->positionZ; // get sat position coordinates - double posx_0 = (double)sat_pos->positionX_r17 * 1.3; - double posy_0 = (double)sat_pos->positionY_r17 * 1.3; - double posz_0 = (double)sat_pos->positionZ_r17 * 1.3; + double pos_sat_x = (double)sat_pos->positionX_r17 * 1.3; + double pos_sat_y = (double)sat_pos->positionY_r17 * 1.3; + double pos_sat_z = (double)sat_pos->positionZ_r17 * 1.3; - double distance = 2 * sqrt(pow(posx - posx_0, 2) + pow(posy - posy_0, 2) + pow(posz - posz_0, 2)); - double ta_ms = (distance / SPEED_OF_LIGHT) * 1000; + // calculate directional vector from SAT to UE + double dir_sat_ue_x = pos_ue_x - pos_sat_x; + double dir_sat_ue_y = pos_ue_y - pos_sat_y; + double dir_sat_ue_z = pos_ue_z - pos_sat_z; - return ta_ms; + // calculate distance between SAT and UE + double distance = sqrt(dir_sat_ue_x * dir_sat_ue_x + dir_sat_ue_y * dir_sat_ue_y + dir_sat_ue_z * dir_sat_ue_z); + + // get sat velocity vector + double vel_sat_x = (double)sat_pos->velocityVX_r17 * 0.06; + double vel_sat_y = (double)sat_pos->velocityVY_r17 * 0.06; + double vel_sat_z = (double)sat_pos->velocityVZ_r17 * 0.06; + + // calculate SAT velocity towards UE + double velocity = (vel_sat_x * dir_sat_ue_x + vel_sat_y * dir_sat_ue_y + vel_sat_z * dir_sat_ue_z) / distance; + + ntn_ta->N_UE_TA_adj = (2 * distance / SPEED_OF_LIGHT) * 1e3; // in ms + ntn_ta->N_UE_TA_drift = (2 * -velocity / SPEED_OF_LIGHT) * 1e6; // in µs/s } // populate ntn_ta structure from mac -void configure_ntn_ta(module_id_t module_id, ntn_timing_advance_componets_t *ntn_ta, NR_NTN_Config_r17_t *ntn_Config_r17) +static void configure_ntn_ta(module_id_t module_id, + ntn_timing_advance_componets_t *ntn_ta, + const NR_NTN_Config_r17_t *ntn_Config_r17) { position_t position_params = {0}; get_position_coordinates(module_id, &position_params); - // if ephemerisInfo_r17 present in SIB19 - NR_EphemerisInfo_r17_t *ephemeris_info = ntn_Config_r17->ephemerisInfo_r17; + // epochTime_r17 must be present (this is assured by function `eval_epoch_time()`) + const NR_EpochTime_r17_t *epoch_time_r17 = ntn_Config_r17->epochTime_r17; + AssertFatal(epoch_time_r17, "epoch_time_r17 should not be NULL here\n"); + ntn_ta->epoch_sfn = epoch_time_r17->sfn_r17; + ntn_ta->epoch_subframe = epoch_time_r17->subFrameNR_r17; + + // handle ephemerisInfo_r17 + const NR_EphemerisInfo_r17_t *ephemeris_info = ntn_Config_r17->ephemerisInfo_r17; if (ephemeris_info) { - NR_PositionVelocity_r17_t *position_velocity = ephemeris_info->choice.positionVelocity_r17; - if (position_velocity - && (position_velocity->positionX_r17 != 0 || position_velocity->positionY_r17 != 0 - || position_velocity->positionZ_r17 != 0)) { - ntn_ta->N_UE_TA_adj = calculate_ue_sat_ta(&position_params, position_velocity); + if (ephemeris_info->present == NR_EphemerisInfo_r17_PR_positionVelocity_r17) { + const NR_PositionVelocity_r17_t *position_velocity = ephemeris_info->choice.positionVelocity_r17; + AssertFatal(position_velocity, "position_velocity should not be NULL here\n"); + calculate_ue_sat_ta(&position_params, position_velocity, ntn_ta); + } else { + LOG_W(NR_MAC, "NR UE currently supports only ephemerisInfo_r17 of type positionVelocity_r17\n"); + ntn_ta->N_UE_TA_adj = 0; + ntn_ta->N_UE_TA_drift = 0; } + } else { // Need R - Release if not present + ntn_ta->N_UE_TA_adj = 0; + ntn_ta->N_UE_TA_drift = 0; } - // if cellSpecificKoffset_r17 is present - if (ntn_Config_r17->cellSpecificKoffset_r17) { + + // handle cellSpecificKoffset_r17 + if (ntn_Config_r17->cellSpecificKoffset_r17) ntn_ta->cell_specific_k_offset = *ntn_Config_r17->cellSpecificKoffset_r17; - } - // Check if ta_Info_r17 is present and convert directly ta_Common_r17 (is in units of 4.072e-3 µs) + else // Need R - Release if not present + ntn_ta->cell_specific_k_offset = 0; + + // Check if ta_Info_r17 is present and convert the time units if (ntn_Config_r17->ta_Info_r17) { + // ta_Common_r17 (is in units of 4.072e-3 µs) ntn_ta->N_common_ta_adj = ntn_Config_r17->ta_Info_r17->ta_Common_r17 * 4.072e-6; // ta_CommonDrift_r17 (is in units of 0.2e-3 µs/s) if (ntn_Config_r17->ta_Info_r17->ta_CommonDrift_r17) ntn_ta->ntn_ta_commondrift = *ntn_Config_r17->ta_Info_r17->ta_CommonDrift_r17 * 0.2e-3; + else // Need R - Release if not present + ntn_ta->ntn_ta_commondrift = 0; + } else { // Need R - Release if not present + ntn_ta->N_common_ta_adj = 0; + ntn_ta->ntn_ta_commondrift = 0; } + ntn_ta->ntn_params_changed = true; LOG_D(NR_MAC, - "SIB19 Rxd. k_offset:%ld, N_Common_Ta:%f,drift:%f,N_UE_TA:%f \n", + "SIB19 Rxd. Epoch SFN: %d, Epoch Subframe: %d, k_offset: %ldms, N_Common_Ta: %fms, drift: %fµs/s, N_UE_TA: %fms, drift: %fµs/s\n", + ntn_ta->epoch_sfn, + ntn_ta->epoch_subframe, ntn_ta->cell_specific_k_offset, ntn_ta->N_common_ta_adj, ntn_ta->ntn_ta_commondrift, - ntn_ta->N_UE_TA_adj); + ntn_ta->N_UE_TA_adj, + ntn_ta->N_UE_TA_drift); } static void config_common_ue(NR_UE_MAC_INST_t *mac, NR_ServingCellConfigCommon_t *scc, int cc_idP) @@ -1863,10 +1906,8 @@ void nr_rrc_mac_config_other_sib(module_id_t module_id, NR_SIB19_r17_t *sib19, b if (sib19) { // update ntn_Config_r17 with received values - NR_NTN_Config_r17_t *ntn_Config_r17 = mac->sc_info.ntn_Config_r17; - UPDATE_IE(ntn_Config_r17, sib19->ntn_Config_r17, NR_NTN_Config_r17_t); - - configure_ntn_ta(mac->ue_id, &mac->ntn_ta, ntn_Config_r17); + UPDATE_IE(mac->sc_info.ntn_Config_r17, sib19->ntn_Config_r17, NR_NTN_Config_r17_t); + configure_ntn_ta(mac->ue_id, &mac->ntn_ta, mac->sc_info.ntn_Config_r17); } if (mac->state == UE_RECEIVING_SIB && can_start_ra) mac->state = UE_PERFORMING_RA; diff --git a/openair2/LAYER2/NR_MAC_UE/mac_defs.h b/openair2/LAYER2/NR_MAC_UE/mac_defs.h index dee2a30c08..13f42ca9e3 100644 --- a/openair2/LAYER2/NR_MAC_UE/mac_defs.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_defs.h @@ -526,12 +526,17 @@ typedef struct { } si_schedInfo_t; typedef struct ntn_timing_advance_components { + int epoch_sfn; + int epoch_subframe; + // N_common_ta_adj represents common round-trip-time between gNB and SAT received in SIB19 (ms) double N_common_ta_adj; - // N_UE_TA_adj calculated round-trip-time between UE and SAT (ms) - double N_UE_TA_adj; // drift rate of common ta in µs/s double ntn_ta_commondrift; + // N_UE_TA_adj calculated round-trip-time between UE and SAT (ms) + double N_UE_TA_adj; + // drift rate of N_UE_TA in µs/s + double N_UE_TA_drift; // cell scheduling offset expressed in terms of 15kHz SCS long cell_specific_k_offset; @@ -650,15 +655,20 @@ static inline int GET_NTN_UE_K_OFFSET(const ntn_timing_advance_componets_t *ntn_ return (int)ntn_ta->cell_specific_k_offset << scs; } -static inline double GET_COMPLETE_TIME_ADVANCE_MS(const ntn_timing_advance_componets_t *ntn_ta) -{ - return ntn_ta->N_common_ta_adj + ntn_ta->N_UE_TA_adj; -} - static inline long GET_DURATION_RX_TO_TX(const ntn_timing_advance_componets_t *ntn_ta, int scs) { return NR_UE_CAPABILITY_SLOT_RX_TO_TX + (ntn_ta->cell_specific_k_offset << scs); } +static inline double get_total_TA_ms(const ntn_timing_advance_componets_t *ntn_ta) +{ + return ntn_ta->N_common_ta_adj + ntn_ta->N_UE_TA_adj; +} + +static inline double get_total_TA_drift(const ntn_timing_advance_componets_t *ntn_ta) +{ + return ntn_ta->ntn_ta_commondrift + ntn_ta->N_UE_TA_drift; +} + /*@}*/ #endif /*__LAYER2_MAC_DEFS_H__ */ diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c index 2f717a7466..58269f769a 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c @@ -818,7 +818,7 @@ static void setup_ra_response_window(RA_config_t *ra, int ta_Common_slots = 0; if (ntn_Config_r17) { - const double ta_Common_ms = GET_COMPLETE_TIME_ADVANCE_MS(ntn_ta); + const double ta_Common_ms = get_total_TA_ms(ntn_ta); ta_Common_slots = (int)ceil(ta_Common_ms * slots_per_frame / 10); } @@ -1066,7 +1066,7 @@ void nr_Msg3_transmitted(NR_UE_MAC_INST_t *mac, uint8_t CC_id, frame_t frameP, s { RA_config_t *ra = &mac->ra; NR_RACH_ConfigCommon_t *nr_rach_ConfigCommon = mac->current_UL_BWP->rach_ConfigCommon; - const double ta_Common_ms = GET_COMPLETE_TIME_ADVANCE_MS(&mac->ntn_ta); + const double ta_Common_ms = get_total_TA_ms(&mac->ntn_ta); const int slots_per_ms = mac->frame_structure.numb_slots_frame / 10; // start contention resolution timer diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c index 2c37b21f5b..a818096a6f 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c @@ -2843,11 +2843,17 @@ static uint8_t nr_ue_get_sdu(NR_UE_MAC_INST_t *mac, static void schedule_ntn_config_command(fapi_nr_dl_config_request_t *dl_config, NR_UE_MAC_INST_t *mac) { fapi_nr_dl_ntn_config_command_pdu *ntn_config_command_pdu = &dl_config->dl_config_list[dl_config->number_pdus].ntn_config_command_pdu; - ntn_config_command_pdu->cell_specific_k_offset = mac->ntn_ta.cell_specific_k_offset; - ntn_config_command_pdu->ntn_ta_commondrift = mac->ntn_ta.ntn_ta_commondrift; + + ntn_config_command_pdu->epoch_sfn = mac->ntn_ta.epoch_sfn; + ntn_config_command_pdu->epoch_subframe = mac->ntn_ta.epoch_subframe; ntn_config_command_pdu->N_common_ta_adj = mac->ntn_ta.N_common_ta_adj; + ntn_config_command_pdu->ntn_ta_commondrift = mac->ntn_ta.ntn_ta_commondrift; ntn_config_command_pdu->N_UE_TA_adj = mac->ntn_ta.N_UE_TA_adj; - ntn_config_command_pdu->ntn_total_time_advance_ms = mac->ntn_ta.N_common_ta_adj + mac->ntn_ta.N_UE_TA_adj; + ntn_config_command_pdu->N_UE_TA_drift = mac->ntn_ta.N_UE_TA_drift; + ntn_config_command_pdu->cell_specific_k_offset = mac->ntn_ta.cell_specific_k_offset; + ntn_config_command_pdu->ntn_total_time_advance_ms = get_total_TA_ms(&mac->ntn_ta); + ntn_config_command_pdu->ntn_total_time_advance_drift = get_total_TA_drift(&mac->ntn_ta); + dl_config->dl_config_list[dl_config->number_pdus].pdu_type = FAPI_NR_DL_NTN_CONFIG_PARAMS; dl_config->number_pdus += 1; } From ece430b6c3e8088da125f87e31f0cf3557f2ae25 Mon Sep 17 00:00:00 2001 From: Thomas Schlichter Date: Fri, 16 May 2025 13:48:34 +0000 Subject: [PATCH 04/15] NR UE: use shorter member names for position_t structure --- executables/position_interface.h | 12 ++++++------ openair2/LAYER2/NR_MAC_UE/config_ue.c | 20 ++++++-------------- 2 files changed, 12 insertions(+), 20 deletions(-) diff --git a/executables/position_interface.h b/executables/position_interface.h index 0324bceb15..8ef0b3144b 100644 --- a/executables/position_interface.h +++ b/executables/position_interface.h @@ -41,16 +41,16 @@ /*----------------------------------------------------------------------------------------------------------------------------------------------------*/ // clang-format off #define POSITION_CONFIG_PARAMS_DEF { \ - {CONFIG_STRING_POSITION_X, HELP_STRING_POSITION, 0, .dblptr=&(position->positionX), .defuintval=0, TYPE_DOUBLE, 0}, \ - {CONFIG_STRING_POSITION_Y, HELP_STRING_POSITION, 0, .dblptr=&(position->positionY), .defuintval=0, TYPE_DOUBLE, 0}, \ - {CONFIG_STRING_POSITION_Z, HELP_STRING_POSITION, 0, .dblptr=&(position->positionZ), .defuintval=0, TYPE_DOUBLE, 0} \ + {CONFIG_STRING_POSITION_X, HELP_STRING_POSITION, 0, .dblptr=&(position->X), .defuintval=0, TYPE_DOUBLE, 0}, \ + {CONFIG_STRING_POSITION_Y, HELP_STRING_POSITION, 0, .dblptr=&(position->Y), .defuintval=0, TYPE_DOUBLE, 0}, \ + {CONFIG_STRING_POSITION_Z, HELP_STRING_POSITION, 0, .dblptr=&(position->Z), .defuintval=0, TYPE_DOUBLE, 0} \ } // clang-format on typedef struct position { - double positionX; - double positionY; - double positionZ; + double X; + double Y; + double Z; } position_t; void get_position_coordinates(int Mod_id, position_t *position); diff --git a/openair2/LAYER2/NR_MAC_UE/config_ue.c b/openair2/LAYER2/NR_MAC_UE/config_ue.c index 8bf20428c2..2381bdb3e3 100644 --- a/openair2/LAYER2/NR_MAC_UE/config_ue.c +++ b/openair2/LAYER2/NR_MAC_UE/config_ue.c @@ -272,30 +272,22 @@ static void calculate_ue_sat_ta(const position_t *position_params, ntn_timing_advance_componets_t *ntn_ta) { // get UE position coordinates - double pos_ue_x = position_params->positionX; - double pos_ue_y = position_params->positionY; - double pos_ue_z = position_params->positionZ; + const position_t pos_ue = *position_params; // get sat position coordinates - double pos_sat_x = (double)sat_pos->positionX_r17 * 1.3; - double pos_sat_y = (double)sat_pos->positionY_r17 * 1.3; - double pos_sat_z = (double)sat_pos->positionZ_r17 * 1.3; + const position_t pos_sat = {sat_pos->positionX_r17 * 1.3, sat_pos->positionY_r17 * 1.3, sat_pos->positionZ_r17 * 1.3}; // calculate directional vector from SAT to UE - double dir_sat_ue_x = pos_ue_x - pos_sat_x; - double dir_sat_ue_y = pos_ue_y - pos_sat_y; - double dir_sat_ue_z = pos_ue_z - pos_sat_z; + const position_t dir_sat_ue = {pos_ue.X - pos_sat.X, pos_ue.Y - pos_sat.Y, pos_ue.Z - pos_sat.Z}; // calculate distance between SAT and UE - double distance = sqrt(dir_sat_ue_x * dir_sat_ue_x + dir_sat_ue_y * dir_sat_ue_y + dir_sat_ue_z * dir_sat_ue_z); + double distance = sqrt(dir_sat_ue.X * dir_sat_ue.X + dir_sat_ue.Y * dir_sat_ue.Y + dir_sat_ue.Z * dir_sat_ue.Z); // get sat velocity vector - double vel_sat_x = (double)sat_pos->velocityVX_r17 * 0.06; - double vel_sat_y = (double)sat_pos->velocityVY_r17 * 0.06; - double vel_sat_z = (double)sat_pos->velocityVZ_r17 * 0.06; + const position_t vel_sat = {sat_pos->velocityVX_r17 * 0.06, sat_pos->velocityVY_r17 * 0.06, sat_pos->velocityVZ_r17 * 0.06}; // calculate SAT velocity towards UE - double velocity = (vel_sat_x * dir_sat_ue_x + vel_sat_y * dir_sat_ue_y + vel_sat_z * dir_sat_ue_z) / distance; + double velocity = (vel_sat.X * dir_sat_ue.X + vel_sat.Y * dir_sat_ue.Y + vel_sat.Z * dir_sat_ue.Z) / distance; ntn_ta->N_UE_TA_adj = (2 * distance / SPEED_OF_LIGHT) * 1e3; // in ms ntn_ta->N_UE_TA_drift = (2 * -velocity / SPEED_OF_LIGHT) * 1e6; // in µs/s From 7ba63a20522e0fccb62e830c921bc8ad19edbd5a Mon Sep 17 00:00:00 2001 From: Thomas Schlichter Date: Thu, 24 Apr 2025 09:48:35 +0000 Subject: [PATCH 05/15] rfsimulator: for LEO NTN, calculate SAT acceleration towards gNB to determine ta-CommonDriftVariant-r17 --- radio/rfsimulator/apply_channelmod.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/radio/rfsimulator/apply_channelmod.c b/radio/rfsimulator/apply_channelmod.c index 2771706f55..1e873b8a2e 100644 --- a/radio/rfsimulator/apply_channelmod.c +++ b/radio/rfsimulator/apply_channelmod.c @@ -97,7 +97,12 @@ void rxAddInput(const c16_t *input_sig, double dist_sat_gnb = 0; double vel_sat_gnb = 0; + double acc_sat_gnb = 0; if (channelDesc->modelid == SAT_LEO_TRANS) { + const double acc_sat_x = 0; + const double acc_sat_y = -w_sat * w_sat * radius_sat * sin(w_sat * t); + const double acc_sat_z = -w_sat * w_sat * radius_sat * cos(w_sat * t); + const double pos_gnb_x = 0; const double pos_gnb_y = 0; const double pos_gnb_z = radius_earth; @@ -108,6 +113,7 @@ void rxAddInput(const c16_t *input_sig, dist_sat_gnb = sqrt(dir_sat_gnb_x * dir_sat_gnb_x + dir_sat_gnb_y * dir_sat_gnb_y + dir_sat_gnb_z * dir_sat_gnb_z); vel_sat_gnb = (vel_sat_x * dir_sat_gnb_x + vel_sat_y * dir_sat_gnb_y + vel_sat_z * dir_sat_gnb_z) / dist_sat_gnb; + acc_sat_gnb = (acc_sat_x * dir_sat_gnb_x + acc_sat_y * dir_sat_gnb_y + acc_sat_z * dir_sat_gnb_z) / dist_sat_gnb; } const double prop_delay = (dist_ue_sat + dist_sat_gnb) / c; @@ -122,6 +128,7 @@ void rxAddInput(const c16_t *input_sig, last_TS = TS; LOG_I(HW, "Satellite orbit: time %f s, Position = (%f, %f, %f), Velocity = (%f, %f, %f)\n", t, pos_sat_x, pos_sat_y, pos_sat_z, vel_sat_x, vel_sat_y, vel_sat_z); LOG_I(HW, "Uplink delay %f ms, Doppler shift UE->SAT %f kHz\n", prop_delay * 1000, f_Doppler_shift_ue_sat / 1000); + LOG_I(HW, "Satellite velocity towards gNB: %f m/s, acceleration towards gNB: %f m/s²\n", vel_sat_gnb, acc_sat_gnb); const int samples_per_subframe = channelDesc->sampling_rate / 1000; const int abs_subframe = TS / samples_per_subframe; @@ -130,6 +137,7 @@ void rxAddInput(const c16_t *input_sig, .subframe = abs_subframe % 10, .delay = 2 * dist_sat_gnb / (c * 4.072e-9), .drift = 2 * -vel_sat_gnb / (c * 0.2e-9), + .accel = 2 * acc_sat_gnb / (c * 0.2e-10), .position.X = pos_sat_x / 1.3, .position.Y = pos_sat_y / 1.3, .position.Z = pos_sat_z / 1.3, From f7ab814a3cf978aa3049a9ff11155627ddebb850 Mon Sep 17 00:00:00 2001 From: Thomas Schlichter Date: Thu, 24 Apr 2025 10:22:45 +0000 Subject: [PATCH 06/15] NR UE: remove unused elements from struc fapi_nr_dl_ntn_config_command_pdu --- nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h | 8 -------- openair1/SCHED_NR_UE/fapi_nr_ue_l1.c | 4 ---- openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c | 4 ---- 3 files changed, 16 deletions(-) diff --git a/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h b/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h index b40c062f03..024c0b4220 100644 --- a/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h +++ b/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h @@ -560,14 +560,6 @@ typedef struct { int epoch_sfn; int epoch_subframe; - // N_common_ta_adj represents common round-trip-time between gNB and SAT received in SIB19 (ms) - double N_common_ta_adj; - // drift rate of common ta in µs/s - double ntn_ta_commondrift; - // N_UE_TA_adj calculated round-trip-time between UE and SAT (ms) - double N_UE_TA_adj; - // drift rate of N_UE_TA in µs/s - double N_UE_TA_drift; // cell scheduling offset expressed in terms of 15kHz SCS long cell_specific_k_offset; diff --git a/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c b/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c index c7235e807b..fa8043966c 100644 --- a/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c +++ b/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c @@ -354,10 +354,6 @@ static void configure_ntn_params(PHY_VARS_NR_UE *ue, fapi_nr_dl_ntn_config_comma ue->ntn_config_message->ntn_config_params.epoch_sfn = ntn_params_message->epoch_sfn; ue->ntn_config_message->ntn_config_params.epoch_subframe = ntn_params_message->epoch_subframe; - ue->ntn_config_message->ntn_config_params.N_common_ta_adj = ntn_params_message->N_common_ta_adj; - ue->ntn_config_message->ntn_config_params.ntn_ta_commondrift = ntn_params_message->ntn_ta_commondrift; - ue->ntn_config_message->ntn_config_params.N_UE_TA_adj = ntn_params_message->N_UE_TA_adj; - ue->ntn_config_message->ntn_config_params.N_UE_TA_drift = ntn_params_message->N_UE_TA_drift; ue->ntn_config_message->ntn_config_params.cell_specific_k_offset = ntn_params_message->cell_specific_k_offset; ue->ntn_config_message->ntn_config_params.ntn_total_time_advance_ms = ntn_params_message->ntn_total_time_advance_ms; ue->ntn_config_message->ntn_config_params.ntn_total_time_advance_drift = ntn_params_message->ntn_total_time_advance_drift; diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c index a818096a6f..58ccbac7b4 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c @@ -2846,10 +2846,6 @@ static void schedule_ntn_config_command(fapi_nr_dl_config_request_t *dl_config, ntn_config_command_pdu->epoch_sfn = mac->ntn_ta.epoch_sfn; ntn_config_command_pdu->epoch_subframe = mac->ntn_ta.epoch_subframe; - ntn_config_command_pdu->N_common_ta_adj = mac->ntn_ta.N_common_ta_adj; - ntn_config_command_pdu->ntn_ta_commondrift = mac->ntn_ta.ntn_ta_commondrift; - ntn_config_command_pdu->N_UE_TA_adj = mac->ntn_ta.N_UE_TA_adj; - ntn_config_command_pdu->N_UE_TA_drift = mac->ntn_ta.N_UE_TA_drift; ntn_config_command_pdu->cell_specific_k_offset = mac->ntn_ta.cell_specific_k_offset; ntn_config_command_pdu->ntn_total_time_advance_ms = get_total_TA_ms(&mac->ntn_ta); ntn_config_command_pdu->ntn_total_time_advance_drift = get_total_TA_drift(&mac->ntn_ta); From 22866c3c1e32087e438310f8e85ae8e3ffefc500 Mon Sep 17 00:00:00 2001 From: Thomas Schlichter Date: Thu, 24 Apr 2025 09:51:05 +0000 Subject: [PATCH 07/15] NR UE: for consistency, rename ntn_ta_commondrift to N_common_ta_drift --- openair2/LAYER2/NR_MAC_UE/config_ue.c | 8 ++++---- openair2/LAYER2/NR_MAC_UE/mac_defs.h | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_UE/config_ue.c b/openair2/LAYER2/NR_MAC_UE/config_ue.c index 2381bdb3e3..921e3da6d1 100644 --- a/openair2/LAYER2/NR_MAC_UE/config_ue.c +++ b/openair2/LAYER2/NR_MAC_UE/config_ue.c @@ -336,12 +336,12 @@ static void configure_ntn_ta(module_id_t module_id, ntn_ta->N_common_ta_adj = ntn_Config_r17->ta_Info_r17->ta_Common_r17 * 4.072e-6; // ta_CommonDrift_r17 (is in units of 0.2e-3 µs/s) if (ntn_Config_r17->ta_Info_r17->ta_CommonDrift_r17) - ntn_ta->ntn_ta_commondrift = *ntn_Config_r17->ta_Info_r17->ta_CommonDrift_r17 * 0.2e-3; + ntn_ta->N_common_ta_drift = *ntn_Config_r17->ta_Info_r17->ta_CommonDrift_r17 * 0.2e-3; else // Need R - Release if not present - ntn_ta->ntn_ta_commondrift = 0; + ntn_ta->N_common_ta_drift = 0; } else { // Need R - Release if not present ntn_ta->N_common_ta_adj = 0; - ntn_ta->ntn_ta_commondrift = 0; + ntn_ta->N_common_ta_drift = 0; } ntn_ta->ntn_params_changed = true; @@ -352,7 +352,7 @@ static void configure_ntn_ta(module_id_t module_id, ntn_ta->epoch_subframe, ntn_ta->cell_specific_k_offset, ntn_ta->N_common_ta_adj, - ntn_ta->ntn_ta_commondrift, + ntn_ta->N_common_ta_drift, ntn_ta->N_UE_TA_adj, ntn_ta->N_UE_TA_drift); } diff --git a/openair2/LAYER2/NR_MAC_UE/mac_defs.h b/openair2/LAYER2/NR_MAC_UE/mac_defs.h index 13f42ca9e3..aeecf2ecaf 100644 --- a/openair2/LAYER2/NR_MAC_UE/mac_defs.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_defs.h @@ -532,7 +532,7 @@ typedef struct ntn_timing_advance_components { // N_common_ta_adj represents common round-trip-time between gNB and SAT received in SIB19 (ms) double N_common_ta_adj; // drift rate of common ta in µs/s - double ntn_ta_commondrift; + double N_common_ta_drift; // N_UE_TA_adj calculated round-trip-time between UE and SAT (ms) double N_UE_TA_adj; // drift rate of N_UE_TA in µs/s @@ -667,7 +667,7 @@ static inline double get_total_TA_ms(const ntn_timing_advance_componets_t *ntn_t static inline double get_total_TA_drift(const ntn_timing_advance_componets_t *ntn_ta) { - return ntn_ta->ntn_ta_commondrift + ntn_ta->N_UE_TA_drift; + return ntn_ta->N_common_ta_drift + ntn_ta->N_UE_TA_drift; } /*@}*/ From e91fb33da3fd01d4815799e1011052c79aa5cd8e Mon Sep 17 00:00:00 2001 From: Thomas Schlichter Date: Thu, 24 Apr 2025 10:25:47 +0000 Subject: [PATCH 08/15] NR UE: also use ta_CommonDriftVariant_r17 to calculate the initial timing advance --- executables/nr-ue.c | 6 ++++-- nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h | 4 ++++ openair1/SCHED_NR_UE/fapi_nr_ue_l1.c | 1 + openair2/LAYER2/NR_MAC_UE/config_ue.c | 9 ++++++++- openair2/LAYER2/NR_MAC_UE/mac_defs.h | 2 ++ openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c | 1 + 6 files changed, 20 insertions(+), 3 deletions(-) diff --git a/executables/nr-ue.c b/executables/nr-ue.c index ff3b5c2110..c4237cb914 100644 --- a/executables/nr-ue.c +++ b/executables/nr-ue.c @@ -931,15 +931,17 @@ static inline void apply_ntn_config(PHY_VARS_NR_UE *UE, const double total_ta_ms = UE->ntn_config_message->ntn_config_params.ntn_total_time_advance_ms; const double total_ta_drift = UE->ntn_config_message->ntn_config_params.ntn_total_time_advance_drift; // µs/s - UE->timing_advance = fp->samples_per_subframe * (total_ta_ms + (total_ta_drift / 1000.0) * (ms_since_epoch / 1000.0)); + const double total_ta_drift_variant = UE->ntn_config_message->ntn_config_params.ntn_total_time_advance_drift_variant; // µs/s² + UE->timing_advance = fp->samples_per_subframe * (total_ta_ms + (total_ta_drift / 1000.0) * (ms_since_epoch / 1000.0) + (total_ta_drift_variant / 1000.0) * (ms_since_epoch / 1000.0) * (ms_since_epoch / 1000.0)); LOG_I(PHY, - "k_offset = %d ms (%d slots), total_ta_ms = %f ms, total_ta_drift = %f µs/s, ms_since_epoch = %d ms, computed " + "k_offset = %d ms (%d slots), total_ta_ms = %f ms, total_ta_drift = %f µs/s, total_ta_drift_variant = %f µs/s², ms_since_epoch = %d ms, computed " "timing_advance = %d samples\n", *ntn_koffset, *ntn_koffset << mu, total_ta_ms, total_ta_drift, + total_ta_drift_variant, ms_since_epoch, UE->timing_advance); } diff --git a/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h b/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h index 024c0b4220..64c8dab07e 100644 --- a/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h +++ b/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h @@ -563,8 +563,12 @@ typedef struct { // cell scheduling offset expressed in terms of 15kHz SCS long cell_specific_k_offset; + // ntn_total_time_advance_ms represents the complete round-trip-time between gNB and UE via SAT double ntn_total_time_advance_ms; + // drift rate of ntn_total_time_advance_ms in µs/s double ntn_total_time_advance_drift; + // change rate of ntn_total_time_advance_ms drift in µs/s² + double ntn_total_time_advance_drift_variant; } fapi_nr_dl_ntn_config_command_pdu; typedef struct { diff --git a/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c b/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c index fa8043966c..52d5033457 100644 --- a/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c +++ b/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c @@ -357,6 +357,7 @@ static void configure_ntn_params(PHY_VARS_NR_UE *ue, fapi_nr_dl_ntn_config_comma ue->ntn_config_message->ntn_config_params.cell_specific_k_offset = ntn_params_message->cell_specific_k_offset; ue->ntn_config_message->ntn_config_params.ntn_total_time_advance_ms = ntn_params_message->ntn_total_time_advance_ms; ue->ntn_config_message->ntn_config_params.ntn_total_time_advance_drift = ntn_params_message->ntn_total_time_advance_drift; + ue->ntn_config_message->ntn_config_params.ntn_total_time_advance_drift_variant = ntn_params_message->ntn_total_time_advance_drift_variant; ue->ntn_config_message->update = true; } diff --git a/openair2/LAYER2/NR_MAC_UE/config_ue.c b/openair2/LAYER2/NR_MAC_UE/config_ue.c index 921e3da6d1..ad7ae1a338 100644 --- a/openair2/LAYER2/NR_MAC_UE/config_ue.c +++ b/openair2/LAYER2/NR_MAC_UE/config_ue.c @@ -339,20 +339,27 @@ static void configure_ntn_ta(module_id_t module_id, ntn_ta->N_common_ta_drift = *ntn_Config_r17->ta_Info_r17->ta_CommonDrift_r17 * 0.2e-3; else // Need R - Release if not present ntn_ta->N_common_ta_drift = 0; + // ta_CommonDriftVariant_r17 (is in units of 0.2e-4 µs/s²) + if (ntn_Config_r17->ta_Info_r17->ta_CommonDriftVariant_r17) + ntn_ta->N_common_ta_drift_variant = *ntn_Config_r17->ta_Info_r17->ta_CommonDriftVariant_r17 * 0.2e-4; + else // Need R - Release if not present + ntn_ta->N_common_ta_drift_variant = 0; } else { // Need R - Release if not present ntn_ta->N_common_ta_adj = 0; ntn_ta->N_common_ta_drift = 0; + ntn_ta->N_common_ta_drift_variant = 0; } ntn_ta->ntn_params_changed = true; LOG_D(NR_MAC, - "SIB19 Rxd. Epoch SFN: %d, Epoch Subframe: %d, k_offset: %ldms, N_Common_Ta: %fms, drift: %fµs/s, N_UE_TA: %fms, drift: %fµs/s\n", + "SIB19 Rxd. Epoch SFN: %d, Epoch Subframe: %d, k_offset: %ldms, N_Common_Ta: %fms, drift: %fµs/s, variant %fµs/s², N_UE_TA: %fms, drift: %fµs/s\n", ntn_ta->epoch_sfn, ntn_ta->epoch_subframe, ntn_ta->cell_specific_k_offset, ntn_ta->N_common_ta_adj, ntn_ta->N_common_ta_drift, + ntn_ta->N_common_ta_drift_variant, ntn_ta->N_UE_TA_adj, ntn_ta->N_UE_TA_drift); } diff --git a/openair2/LAYER2/NR_MAC_UE/mac_defs.h b/openair2/LAYER2/NR_MAC_UE/mac_defs.h index aeecf2ecaf..9e4fc64e63 100644 --- a/openair2/LAYER2/NR_MAC_UE/mac_defs.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_defs.h @@ -533,6 +533,8 @@ typedef struct ntn_timing_advance_components { double N_common_ta_adj; // drift rate of common ta in µs/s double N_common_ta_drift; + // change rate of common ta drift in µs/s² + double N_common_ta_drift_variant; // N_UE_TA_adj calculated round-trip-time between UE and SAT (ms) double N_UE_TA_adj; // drift rate of N_UE_TA in µs/s diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c index 58ccbac7b4..6f6e6746cf 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c @@ -2849,6 +2849,7 @@ static void schedule_ntn_config_command(fapi_nr_dl_config_request_t *dl_config, ntn_config_command_pdu->cell_specific_k_offset = mac->ntn_ta.cell_specific_k_offset; ntn_config_command_pdu->ntn_total_time_advance_ms = get_total_TA_ms(&mac->ntn_ta); ntn_config_command_pdu->ntn_total_time_advance_drift = get_total_TA_drift(&mac->ntn_ta); + ntn_config_command_pdu->ntn_total_time_advance_drift_variant = mac->ntn_ta.N_common_ta_drift_variant; dl_config->dl_config_list[dl_config->number_pdus].pdu_type = FAPI_NR_DL_NTN_CONFIG_PARAMS; dl_config->number_pdus += 1; From 786f4877bcd39d1235eaaee8dd39270afa885963 Mon Sep 17 00:00:00 2001 From: Thomas Schlichter Date: Thu, 24 Apr 2025 11:15:28 +0000 Subject: [PATCH 09/15] rfsimulator: for LEO NTN, update SIB19 information once for each frame --- radio/rfsimulator/apply_channelmod.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/radio/rfsimulator/apply_channelmod.c b/radio/rfsimulator/apply_channelmod.c index 1e873b8a2e..a976c63264 100644 --- a/radio/rfsimulator/apply_channelmod.c +++ b/radio/rfsimulator/apply_channelmod.c @@ -129,12 +129,14 @@ void rxAddInput(const c16_t *input_sig, LOG_I(HW, "Satellite orbit: time %f s, Position = (%f, %f, %f), Velocity = (%f, %f, %f)\n", t, pos_sat_x, pos_sat_y, pos_sat_z, vel_sat_x, vel_sat_y, vel_sat_z); LOG_I(HW, "Uplink delay %f ms, Doppler shift UE->SAT %f kHz\n", prop_delay * 1000, f_Doppler_shift_ue_sat / 1000); LOG_I(HW, "Satellite velocity towards gNB: %f m/s, acceleration towards gNB: %f m/s²\n", vel_sat_gnb, acc_sat_gnb); + } - const int samples_per_subframe = channelDesc->sampling_rate / 1000; - const int abs_subframe = TS / samples_per_subframe; + const int samples_per_subframe = channelDesc->sampling_rate / 1000; + const int abs_subframe = TS / samples_per_subframe; + if (abs_subframe % 10 == 0) { // update SIB19 information for the next frame gnb_sat_position_update_t sat_position = { - .sfn = (abs_subframe / 10) % 1024, - .subframe = abs_subframe % 10, + .sfn = (abs_subframe / 10 + 1) % 1024, + .subframe = 0, .delay = 2 * dist_sat_gnb / (c * 4.072e-9), .drift = 2 * -vel_sat_gnb / (c * 0.2e-9), .accel = 2 * acc_sat_gnb / (c * 0.2e-10), From a9a6ab367b6bc8adcba3901bb4760d6054b62eb7 Mon Sep 17 00:00:00 2001 From: Thomas Schlichter Date: Thu, 22 May 2025 09:58:22 +0000 Subject: [PATCH 10/15] NR UE: fix autonomous_ta to be applied only when we also adjust the DL sync --- executables/nr-ue.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/executables/nr-ue.c b/executables/nr-ue.c index c4237cb914..e7b305c7d2 100644 --- a/executables/nr-ue.c +++ b/executables/nr-ue.c @@ -1097,9 +1097,6 @@ void *UE_thread(void *arg) 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); - // TODO: remove this autonomous TA and use up-to-date values of ta-Common, ta-CommonDrift and ta-CommonDriftVariant from received SIB19 instead - if (get_nrUE_params()->autonomous_ta) - UE->timing_advance -= 2 * shiftForNextFrame; // read in first symbol AssertFatal(fp->ofdm_symbol_size + fp->nb_prefix_samples0 == UE->rfdevice.trx_read_func(&UE->rfdevice, From 960f2e710122e92b2271645b48ec4f49843aff88 Mon Sep 17 00:00:00 2001 From: Thomas Schlichter Date: Thu, 22 May 2025 09:59:57 +0000 Subject: [PATCH 11/15] NR UE: allow the epochTime-r17 in NTN-Config-r17 to be in the future The implementation is limited to epoch times that are not more than 5.12 seconds in the future (allowed are up to 10.24 seconds) and ntn-UlSyncValidityDuration < 5.12 seconds (allowed are up to 90 seconds). To fix this limitation, the hyper frame number HFN has to be introduced at the OAI UE! --- executables/nr-ue.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/executables/nr-ue.c b/executables/nr-ue.c index e7b305c7d2..1774000b8f 100644 --- a/executables/nr-ue.c +++ b/executables/nr-ue.c @@ -927,7 +927,15 @@ static inline void apply_ntn_config(PHY_VARS_NR_UE *UE, const int abs_subframe_tx = 10 * frame_rx + ((slot_rx + *duration_rx_to_tx) >> mu); const int abs_subframe_epoch = 10 * UE->ntn_config_message->ntn_config_params.epoch_sfn + UE->ntn_config_message->ntn_config_params.epoch_subframe; - const int ms_since_epoch = (abs_subframe_tx - abs_subframe_epoch + 10240) % 10240; + int ms_since_epoch = abs_subframe_tx - abs_subframe_epoch; + // cope with sfn wrap-around + // this currently limits us to epoch times that are not more than 5.12 seconds in the future (allowed are up to 10.24 seconds) + // and ntn-UlSyncValidityDuration < 5.12 seconds (allowed are up to 900 seconds) + // TODO: fix this limitation by introducing the hyper frame number HFN + if (ms_since_epoch < -5120) + ms_since_epoch += 10240; + else if (ms_since_epoch > 5120) + ms_since_epoch -= 10240; const double total_ta_ms = UE->ntn_config_message->ntn_config_params.ntn_total_time_advance_ms; const double total_ta_drift = UE->ntn_config_message->ntn_config_params.ntn_total_time_advance_drift; // µs/s From 1bb781b08cf72227e1d9d95197e847100115ad2e Mon Sep 17 00:00:00 2001 From: Thomas Schlichter Date: Fri, 20 Jun 2025 11:13:08 +0000 Subject: [PATCH 12/15] NR UE: trigger RRC timers based on RX frame and slot For NTN Epoch time calculations, we need to know the RX frame number. --- executables/nr-ue.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/executables/nr-ue.c b/executables/nr-ue.c index 1774000b8f..21048c8d52 100644 --- a/executables/nr-ue.c +++ b/executables/nr-ue.c @@ -1229,8 +1229,8 @@ void *UE_thread(void *arg) UE->N_TA_offset = new_N_TA_offset; } - if (curMsg.proc.nr_slot_tx == 0) - nr_ue_rrc_timer_trigger(UE->Mod_id, curMsg.proc.frame_tx, curMsg.proc.gNB_id); + if (curMsg.proc.nr_slot_rx == 0) + nr_ue_rrc_timer_trigger(UE->Mod_id, curMsg.proc.frame_rx, curMsg.proc.gNB_id); // RX slot processing. We launch and forget. notifiedFIFO_elt_t *newRx = newNotifiedFIFO_elt(sizeof(nr_rxtx_thread_data_t), curMsg.proc.nr_slot_tx, NULL, UE_dl_processing); From ef416234d9472eb672447e5ba59ed883478af909 Mon Sep 17 00:00:00 2001 From: Thomas Schlichter Date: Fri, 20 Jun 2025 11:43:59 +0000 Subject: [PATCH 13/15] NR UE: enable logging of NTN RRC timer information To verify the NTN epoch time and NTN timer calculations, enable the logging by default. This only affects NTN configurations. --- openair2/RRC/NR_UE/rrc_UE.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openair2/RRC/NR_UE/rrc_UE.c b/openair2/RRC/NR_UE/rrc_UE.c index 90713ff50c..3ff510c7f2 100644 --- a/openair2/RRC/NR_UE/rrc_UE.c +++ b/openair2/RRC/NR_UE/rrc_UE.c @@ -195,7 +195,7 @@ static void get_epochtime_from_sib19scheduling(NR_UE_RRC_SI_INFO *SI_info, int * int slot = slot_end_sib19_window % N; *subframe = ceil(slot / slots_per_subframe); - LOG_D(NR_RRC, + LOG_I(NR_RRC, "Get EPOCHTIME: x:%d, N:%d, slot_endw:%d, frame:%d, subframe:%d , slot:%d\n", x, N, @@ -228,7 +228,7 @@ static int eval_epoch_time(NR_UE_RRC_SI_INFO *SI_info, NR_NTN_Config_r17_t *ntnc // after the frame where the message indicating the epochTime is received // i.e. Epochframe can be present or future SFN diff_frames = (epoch_frame - frame + 1024) % 1024; // According to 38.331 Epochtime is defined for serving cell like this - LOG_D(NR_RRC, "Epoch frame %d, ahead by %d frames\n", epoch_frame, diff_frames); + LOG_I(NR_RRC, "Epoch frame %d, ahead by %d frames\n", epoch_frame, diff_frames); return diff_frames; } @@ -248,7 +248,7 @@ static int get_ntn_timervalues(NR_UE_RRC_SI_INFO *SI_info, NR_NTN_Config_r17_t * int expire_before_ms = ((val430 >= 120) ? 10000 : 2000); int diff = *val430_ms - expire_before_ms; int sib19_timer_ms = (diff > 0) ? diff : ((*val430_ms - sib19_periodicity_ms) > 0) ? (*val430_ms - sib19_periodicity_ms) : 0; - LOG_D(NR_RRC, "val430:%d s, T430:%d ms, sib19_timer:%d ms\n", val430, *val430_ms, sib19_timer_ms); + LOG_I(NR_RRC, "val430:%d s, T430:%d ms, sib19_timer:%d ms\n", val430, *val430_ms, sib19_timer_ms); return sib19_timer_ms; } From a3bb97b6b7f1fe69422c89e8403ba09ea1105978 Mon Sep 17 00:00:00 2001 From: Thomas Schlichter Date: Fri, 20 Jun 2025 13:55:45 +0000 Subject: [PATCH 14/15] gNB: set invalid NTN parameters in prepare_scc(), so fix_scc() will free them when not used --- openair2/GNB_APP/gnb_config.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index 36ac8b6b1f..044dc56351 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -221,11 +221,18 @@ void prepare_scc(NR_ServingCellConfigCommon_t *scc) scc->ext2->ntn_Config_r17->ephemerisInfo_r17 = calloc_or_fail(1, sizeof(*scc->ext2->ntn_Config_r17->ephemerisInfo_r17)); scc->ext2->ntn_Config_r17->ta_Info_r17 = calloc_or_fail(1, sizeof(*scc->ext2->ntn_Config_r17->ta_Info_r17)); + scc->ext2->ntn_Config_r17->ta_Info_r17->ta_Common_r17 = -1; scc->ext2->ntn_Config_r17->ta_Info_r17->ta_CommonDrift_r17 = calloc_or_fail(1, sizeof(*scc->ext2->ntn_Config_r17->ta_Info_r17->ta_CommonDrift_r17)); scc->ext2->ntn_Config_r17->ephemerisInfo_r17->present = NR_EphemerisInfo_r17_PR_positionVelocity_r17; scc->ext2->ntn_Config_r17->ephemerisInfo_r17->choice.positionVelocity_r17 = calloc_or_fail(1, sizeof(*scc->ext2->ntn_Config_r17->ephemerisInfo_r17->choice.positionVelocity_r17)); + scc->ext2->ntn_Config_r17->ephemerisInfo_r17->choice.positionVelocity_r17->positionX_r17 = LONG_MAX; + scc->ext2->ntn_Config_r17->ephemerisInfo_r17->choice.positionVelocity_r17->positionY_r17 = LONG_MAX; + scc->ext2->ntn_Config_r17->ephemerisInfo_r17->choice.positionVelocity_r17->positionZ_r17 = LONG_MAX; + scc->ext2->ntn_Config_r17->ephemerisInfo_r17->choice.positionVelocity_r17->velocityVX_r17 = LONG_MAX; + scc->ext2->ntn_Config_r17->ephemerisInfo_r17->choice.positionVelocity_r17->velocityVY_r17 = LONG_MAX; + scc->ext2->ntn_Config_r17->ephemerisInfo_r17->choice.positionVelocity_r17->velocityVZ_r17 = LONG_MAX; } void prepare_msgA_scc(NR_ServingCellConfigCommon_t *scc) { NR_BWP_UplinkCommon_t *initialUplinkBWP = scc->uplinkConfigCommon->initialUplinkBWP; From 7b991c4dbfae15bf3022a6198d4256e4fca250db Mon Sep 17 00:00:00 2001 From: Thomas Schlichter Date: Fri, 20 Jun 2025 13:58:55 +0000 Subject: [PATCH 15/15] NR UE: exit from configure_ntn_ta() if ntn_Config_r17 is not provided --- openair2/LAYER2/NR_MAC_UE/config_ue.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/openair2/LAYER2/NR_MAC_UE/config_ue.c b/openair2/LAYER2/NR_MAC_UE/config_ue.c index ad7ae1a338..e3535843fe 100644 --- a/openair2/LAYER2/NR_MAC_UE/config_ue.c +++ b/openair2/LAYER2/NR_MAC_UE/config_ue.c @@ -298,6 +298,9 @@ static void configure_ntn_ta(module_id_t module_id, ntn_timing_advance_componets_t *ntn_ta, const NR_NTN_Config_r17_t *ntn_Config_r17) { + if (!ntn_Config_r17) + return; + position_t position_params = {0}; get_position_coordinates(module_id, &position_params);