Merge remote-tracking branch 'origin/ntn_continuous_sib19_updates' into integration_2025_w27 (!3398)

continuously update SIB19 information for rfsim NTN LEO scenarios

Contains mainly these changes:

- gNB: add function nr_update_sib19() allowing to update SIB19
  information
- rfsimulator: update SIB19 contents every frame for LEO channel
  simulations
- 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, ta_CommonDriftVariant_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.
This commit is contained in:
Robert Schmidt
2025-07-04 09:42:19 +02:00
17 changed files with 350 additions and 81 deletions
+36 -17
View File
@@ -908,7 +908,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)
@@ -916,22 +917,43 @@ 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;
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
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), 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, 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);
}
}
@@ -1088,9 +1110,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,
@@ -1215,8 +1234,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);
@@ -1232,7 +1251,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
+6 -6
View File
@@ -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);
@@ -557,16 +557,18 @@ typedef struct {
} fapi_nr_ta_command_pdu;
typedef struct {
// 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;
int epoch_sfn;
int epoch_subframe;
// 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 {
+4 -2
View File
@@ -352,10 +352,12 @@ 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.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.cell_specific_k_offset = ntn_params_message->cell_specific_k_offset;
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.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;
}
+2
View File
@@ -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)
+3
View File
@@ -31,6 +31,7 @@
#include <LTE_DRX-Config.h>
#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)
+5
View File
@@ -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;
+7
View File
@@ -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;
+73 -30
View File
@@ -267,59 +267,104 @@ 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;
const position_t pos_ue = *position_params;
// 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;
const position_t pos_sat = {sat_pos->positionX_r17 * 1.3, sat_pos->positionY_r17 * 1.3, 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
const position_t dir_sat_ue = {pos_ue.X - pos_sat.X, pos_ue.Y - pos_sat.Y, 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
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;
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)
{
if (!ntn_Config_r17)
return;
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;
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. 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, 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->ntn_ta_commondrift,
ntn_ta->N_UE_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);
}
static void config_common_ue(NR_UE_MAC_INST_t *mac, NR_ServingCellConfigCommon_t *scc, int cc_idP)
@@ -1875,10 +1920,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;
+19 -7
View File
@@ -528,12 +528,19 @@ 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;
// 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 common ta in µs/s
double ntn_ta_commondrift;
// 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;
@@ -652,15 +659,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->N_common_ta_drift + ntn_ta->N_UE_TA_drift;
}
/*@}*/
#endif /*__LAYER2_MAC_DEFS_H__ */
+2 -2
View File
@@ -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
+7 -4
View File
@@ -2848,11 +2848,14 @@ 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->epoch_sfn = mac->ntn_ta.epoch_sfn;
ntn_config_command_pdu->epoch_subframe = mac->ntn_ta.epoch_subframe;
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->N_common_ta_adj = mac->ntn_ta.N_common_ta_adj;
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->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;
}
+90
View File
@@ -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,
+46
View File
@@ -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 <stdint.h>
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__*/
+1
View File
@@ -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 */
+3 -3
View File
@@ -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;
}
+38 -4
View File
@@ -25,6 +25,7 @@
#include <complex.h>
#include <common/utils/LOG/log.h>
#include <openair1/SIMULATION/TOOLS/sim.h>
#include "openair2/LAYER2/NR_MAC_gNB/mac_config.h"
#include "rfsimulator.h"
/*
@@ -95,7 +96,13 @@ 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;
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;
@@ -105,6 +112,8 @@ 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;
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;
@@ -117,8 +126,33 @@ 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);
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;
if (abs_subframe % 10 == 0) { // update SIB19 information for the next frame
gnb_sat_position_update_t sat_position = {
.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),
.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 +185,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);
}
}
}