Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
O
OpenXG-RAN
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
OpenXG
OpenXG-RAN
Commits
834a6fc1
Commit
834a6fc1
authored
Sep 24, 2025
by
Thomas Schlichter
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
NR UE: improve physical layer for NTN (esp. LEO) reestablishment and HO
parent
ae12190a
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
75 additions
and
24 deletions
+75
-24
executables/nr-ue.c
executables/nr-ue.c
+75
-24
No files found.
executables/nr-ue.c
View file @
834a6fc1
...
...
@@ -497,6 +497,8 @@ static uint64_t get_carrier_frequency(const int N_RB, const int mu, const uint32
return
carrier_freq
;
}
static
void
apply_ntn_timing_advance_and_doppler
(
PHY_VARS_NR_UE
*
UE
,
const
NR_DL_FRAME_PARMS
*
fp
,
int
abs_subframe_tx
);
static
int
handle_sync_req_from_mac
(
PHY_VARS_NR_UE
*
UE
)
{
NR_DL_FRAME_PARMS
*
fp
=
&
UE
->
frame_parms
;
...
...
@@ -521,6 +523,12 @@ static int handle_sync_req_from_mac(PHY_VARS_NR_UE *UE)
init_symbol_rotation
(
fp
);
}
// Apply Doppler based on NTN-Config for target cell
if
(
UE
->
target_Nid_cell
!=
fp
->
Nid_cell
)
apply_ntn_timing_advance_and_doppler
(
UE
,
fp
,
-
1
);
// Apply NTN DL Doppler as initial FO
UE
->
initial_fo
=
UE
->
dl_Doppler_shift
;
/* Clearing UE harq while DL actors are active causes race condition.
So we let the current execution to complete here.*/
for
(
int
i
=
0
;
i
<
get_nrUE_params
()
->
num_dl_actors
;
i
++
)
{
...
...
@@ -727,13 +735,39 @@ static inline int get_readBlockSize(uint16_t slot, NR_DL_FRAME_PARMS *fp) {
return
rem_samples
+
next_slot_first_symbol
;
}
static
void
fix_ntn_epoch_hfn
(
PHY_VARS_NR_UE
*
UE
,
int
hfn
,
int
frame
)
{
const
int
epoch_frame
=
UE
->
ntn_config_message
->
ntn_config_params
.
epoch_sfn
;
const
int
diff1
=
(
frame
-
epoch_frame
+
1024
)
%
1024
;
const
int
diff2
=
(
epoch_frame
-
frame
+
1024
)
%
1024
;
int
*
epoch_hfn
=
&
UE
->
ntn_config_message
->
ntn_config_params
.
epoch_hfn
;
if
(
diff1
<
diff2
)
{
// epoch_frame in the past
LOG_I
(
PHY
,
"epoch is %d frames in the past
\n
"
,
diff1
);
if
(
epoch_frame
<=
frame
)
*
epoch_hfn
=
hfn
;
else
*
epoch_hfn
=
hfn
-
1
;
}
else
{
// epoch_frame in the future
LOG_I
(
PHY
,
"epoch is %d frames in the future
\n
"
,
diff2
);
if
(
epoch_frame
>=
frame
)
*
epoch_hfn
=
hfn
;
else
*
epoch_hfn
=
hfn
+
1
;
}
LOG_I
(
PHY
,
"setting epoch_hfn = %d
\n
"
,
*
epoch_hfn
);
}
#define SPEED_OF_LIGHT 299792458
// calculate TA and Doppler based on the NTN-Config, if abs_subframe_tx < 0 then apply only Doppler
static
void
apply_ntn_timing_advance_and_doppler
(
PHY_VARS_NR_UE
*
UE
,
const
NR_DL_FRAME_PARMS
*
fp
,
int
abs_subframe_tx
)
{
const
fapi_nr_dl_ntn_config_command_pdu
*
ntn_config_params
=
&
UE
->
ntn_config_message
->
ntn_config_params
;
// Handle terrestrial networks
if
(
ntn_config_params
->
cell_specific_k_offset
==
0
)
{
if
(
abs_subframe_tx
>=
0
)
UE
->
timing_advance_ntn
=
0
;
UE
->
dl_Doppler_shift
=
0
;
UE
->
ul_Doppler_shift
=
0
;
...
...
@@ -743,7 +777,7 @@ static void apply_ntn_timing_advance_and_doppler(PHY_VARS_NR_UE *UE, const NR_DL
const
int
abs_subframe_epoch
=
ntn_config_params
->
epoch_subframe
+
ntn_config_params
->
epoch_sfn
*
10
+
ntn_config_params
->
epoch_hfn
*
10240
;
const
int
ms_since_epoch
=
abs_subframe_tx
-
abs_subframe_epoch
;
const
int
ms_since_epoch
=
abs_subframe_tx
<
0
?
0
:
abs_subframe_tx
-
abs_subframe_epoch
;
const
position_t
pos_sat_0
=
ntn_config_params
->
pos_sat_0
;
const
position_t
vel_sat_0
=
ntn_config_params
->
vel_sat_0
;
...
...
@@ -797,22 +831,26 @@ static void apply_ntn_timing_advance_and_doppler(PHY_VARS_NR_UE *UE, const NR_DL
const
double
N_common_ta_drift
=
ntn_config_params
->
N_common_ta_drift
;
const
double
N_common_ta_drift_variant
=
ntn_config_params
->
N_common_ta_drift_variant
;
UE
->
timing_advance_ntn
=
(
N_UE_TA_adj
+
N_common_ta_adj
+
N_common_ta_drift
*
ms_since_epoch
/
1e6
if
(
abs_subframe_tx
>=
0
)
{
UE
->
timing_advance_ntn
=
(
N_UE_TA_adj
+
N_common_ta_adj
+
N_common_ta_drift
*
ms_since_epoch
/
1e6
+
N_common_ta_drift_variant
*
((
int64_t
)
ms_since_epoch
*
ms_since_epoch
)
/
1e9
)
*
fp
->
samples_per_subframe
;
}
UE
->
freq_offset
-=
dl_Doppler_shift
-
UE
->
dl_Doppler_shift
;
UE
->
dl_Doppler_shift
=
dl_Doppler_shift
;
UE
->
ul_Doppler_shift
=
ul_Doppler_shift
;
LOG_D
(
PHY
,
if
(
abs_subframe_tx
<
0
)
{
LOG_I
(
PHY
,
"satellite velocity towards UE = %f m/s, DL Doppler shift = %f kHz, UL Doppler shift = %f kHz
\n
"
,
vel_sat_ue
,
dl_Doppler_shift
/
1000
,
ul_Doppler_shift
/
1000
);
}
}
// apply values based on the NTN-Config
static
void
apply_ntn_config
(
PHY_VARS_NR_UE
*
UE
,
NR_DL_FRAME_PARMS
*
fp
,
int
hfn_rx
,
...
...
@@ -885,9 +923,14 @@ void *UE_thread(void *arg)
notifiedFIFO_t
freeBlocks
;
initNotifiedFIFO_nothreadSafe
(
&
freeBlocks
);
double
ntn_init_time_drift
=
get_nrUE_params
()
->
ntn_init_time_drift
;
int
ntn_koffset
=
0
;
const
double
ntn_init_time_drift
=
get_nrUE_params
()
->
ntn_init_time_drift
;
if
(
get_nrUE_params
()
->
time_sync_I
)
// ntn_init_time_drift is in µs/s, max_pos_acc * time_sync_I is in samples/frame
UE
->
max_pos_acc
=
ntn_init_time_drift
*
1e-6
*
fp
->
samples_per_frame
/
get_nrUE_params
()
->
time_sync_I
;
else
UE
->
max_pos_acc
=
0
;
int
ntn_koffset
=
0
;
int
duration_rx_to_tx
=
NR_UE_CAPABILITY_SLOT_RX_TO_TX
;
int
timing_advance
=
UE
->
timing_advance
+
UE
->
timing_advance_ntn
;
UE
->
N_TA_offset
=
determine_N_TA_offset
(
UE
);
...
...
@@ -983,10 +1026,6 @@ void *UE_thread(void *arg)
syncMsg
->
UE
=
UE
;
memset
(
&
syncMsg
->
proc
,
0
,
sizeof
(
syncMsg
->
proc
));
pushNotifiedFIFO
(
&
UE
->
sync_actor
.
fifo
,
Msg
);
if
(
ntn_koffset
==
0
)
{
// reset timing_advance for TN
timing_advance
=
0
;
UE
->
timing_advance
=
0
;
}
trashed_frames
=
0
;
syncRunning
=
true
;
continue
;
...
...
@@ -996,13 +1035,8 @@ void *UE_thread(void *arg)
stream_status
=
STREAM_STATUS_SYNCING
;
syncInFrame
(
UE
,
&
sync_timestamp
,
duration_rx_to_tx
,
intialSyncOffset
);
openair0_write_reorder_clear_context
(
&
UE
->
rfdevice
);
if
(
get_nrUE_params
()
->
time_sync_I
)
// ntn_init_time_drift is in µs/s, max_pos_acc * time_sync_I is in samples/frame
UE
->
max_pos_acc
=
ntn_init_time_drift
*
1e-6
*
fp
->
samples_per_frame
/
get_nrUE_params
()
->
time_sync_I
;
else
UE
->
max_pos_acc
=
0
;
shiftForNextFrame
=
-
(
UE
->
init_sync_frame
+
trashed_frames
+
2
)
*
UE
->
max_pos_acc
*
get_nrUE_params
()
->
time_sync_I
;
// compensate for the time drift that happened during initial sync
LOG_
D
(
PHY
,
"max_pos_acc = %d, shiftForNextFrame = %d
\n
"
,
UE
->
max_pos_acc
,
shiftForNextFrame
);
LOG_
I
(
PHY
,
"max_pos_acc = %d, shiftForNextFrame = %d
\n
"
,
UE
->
max_pos_acc
,
shiftForNextFrame
);
// read in first symbol
AssertFatal
(
fp
->
ofdm_symbol_size
+
fp
->
nb_prefix_samples0
==
UE
->
rfdevice
.
trx_read_func
(
&
UE
->
rfdevice
,
...
...
@@ -1020,6 +1054,18 @@ void *UE_thread(void *arg)
// Set to the slot where the SL-SSB was decoded
absolute_slot
+=
UE
->
SL_UE_PHY_PARAMS
.
sync_params
.
slot_offset
;
}
// With the correct frame and slot numbers, we can now fix the UL timing
const
int
frame_rx
=
(
absolute_slot
/
nb_slot_frame
)
%
1024
;
const
int
hfn_rx
=
(
absolute_slot
/
nb_slot_frame
)
/
1024
;
fix_ntn_epoch_hfn
(
UE
,
hfn_rx
,
frame_rx
);
if
(
UE
->
ntn_config_message
->
update
)
{
apply_ntn_config
(
UE
,
fp
,
hfn_rx
,
frame_rx
,
0
,
&
duration_rx_to_tx
,
&
timing_advance
,
&
ntn_koffset
);
}
else
{
const
int
mu
=
fp
->
numerology_index
;
const
int
abs_subframe_tx
=
10240
*
hfn_rx
+
10
*
frame_rx
+
(
duration_rx_to_tx
>>
mu
);
apply_ntn_timing_advance_and_doppler
(
UE
,
fp
,
abs_subframe_tx
);
}
UE
->
timing_advance
=
0
;
// We have resynchronized, maybe after RF loss so we need to purge any existing context
memset
(
tx_wait_for_dlsch
,
0
,
sizeof
(
tx_wait_for_dlsch
));
for
(
int
i
=
0
;
i
<
NUM_PROCESS_SLOT_TX_BARRIERS
;
i
++
)
{
...
...
@@ -1134,6 +1180,11 @@ void *UE_thread(void *arg)
writeBlockSize
-=
new_N_TA_offset
-
UE
->
N_TA_offset
;
UE
->
N_TA_offset
=
new_N_TA_offset
;
}
if
(
writeBlockSize
<
0
)
{
timing_advance
+=
writeBlockSize
-
1
;
LOG_I
(
PHY
,
"writeBlockSize is %d, setting it to 1 and changing timing_advance to %d
\n
"
,
writeBlockSize
,
timing_advance
);
writeBlockSize
=
1
;
}
if
(
curMsg
.
proc
.
nr_slot_rx
==
0
)
nr_ue_rrc_timer_trigger
(
UE
->
Mod_id
,
curMsg
.
proc
.
hfn_rx
,
curMsg
.
proc
.
frame_rx
,
curMsg
.
proc
.
gNB_id
);
...
...
@@ -1166,7 +1217,7 @@ void *UE_thread(void *arg)
curMsgTx
->
absolute_deadline_us
=
absolute_deadline_us
;
int
slot
=
curMsgTx
->
proc
.
nr_slot_tx
;
int
slot_and_frame
=
slot
+
curMsgTx
->
proc
.
frame_tx
*
UE
->
frame_parms
.
slots_per
_frame
;
int
slot_and_frame
=
slot
+
curMsgTx
->
proc
.
frame_tx
*
nb_slot
_frame
;
int
next_tx_slot_and_frame
=
absolute_slot
+
duration_rx_to_tx
+
1
;
int
wait_for_prev_slot
=
stream_status
==
STREAM_STATUS_SYNCED
?
1
:
0
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment