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
bc81662c
Commit
bc81662c
authored
Sep 23, 2025
by
Thomas Schlichter
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
NR UE: consider computed DL/UL Doppler shift in continuous FO compensation
parent
b59bcaf4
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
59 additions
and
26 deletions
+59
-26
executables/nr-ue.c
executables/nr-ue.c
+54
-23
openair1/PHY/MODULATION/slot_fep_nr.c
openair1/PHY/MODULATION/slot_fep_nr.c
+1
-1
openair1/PHY/defs_nr_UE.h
openair1/PHY/defs_nr_UE.h
+4
-2
No files found.
executables/nr-ue.c
View file @
bc81662c
...
@@ -258,7 +258,7 @@ static void UE_synch(void *arg) {
...
@@ -258,7 +258,7 @@ static void UE_synch(void *arg) {
+
round
((
float
)((
ret
.
rx_offset
<<
1
)
%
fp
->
samples_per_subframe
)
/
fp
->
samples_per_slot0
);
+
round
((
float
)((
ret
.
rx_offset
<<
1
)
%
fp
->
samples_per_subframe
)
/
fp
->
samples_per_slot0
);
if
(
get_nrUE_params
()
->
cont_fo_comp
)
{
if
(
get_nrUE_params
()
->
cont_fo_comp
)
{
UE
->
freq_offset
=
freq_offset
;
UE
->
freq_offset
=
freq_offset
-
UE
->
dl_Doppler_shift
;
}
else
{
}
else
{
// rerun with new cell parameters and frequency-offset
// rerun with new cell parameters and frequency-offset
nr_rf_card_config_freq
(
cfg0
,
ul_carrier
,
dl_carrier
,
freq_offset
);
nr_rf_card_config_freq
(
cfg0
,
ul_carrier
,
dl_carrier
,
freq_offset
);
...
@@ -400,7 +400,12 @@ static void RU_write(nr_rxtx_thread_data_t *rxtxD, bool sl_tx_action, c16_t **tx
...
@@ -400,7 +400,12 @@ static void RU_write(nr_rxtx_thread_data_t *rxtxD, bool sl_tx_action, c16_t **tx
if
(
get_nrUE_params
()
->
cont_fo_comp
==
2
)
// different from LO frequency error compensation, Doppler UL pre-compensation has to be negative
if
(
get_nrUE_params
()
->
cont_fo_comp
==
2
)
// different from LO frequency error compensation, Doppler UL pre-compensation has to be negative
ul_freq_offset
=
-
ul_freq_offset
;
ul_freq_offset
=
-
ul_freq_offset
;
for
(
int
i
=
0
;
i
<
fp
->
nb_antennas_tx
;
i
++
)
for
(
int
i
=
0
;
i
<
fp
->
nb_antennas_tx
;
i
++
)
nr_fo_compensation
(
ul_freq_offset
,
fp
->
samples_per_subframe
,
writeTimestamp
,
txp
[
i
],
txp
[
i
],
writeBlockSize
);
nr_fo_compensation
(
UE
->
ul_Doppler_shift
+
ul_freq_offset
,
fp
->
samples_per_subframe
,
writeTimestamp
,
txp
[
i
],
txp
[
i
],
writeBlockSize
);
}
}
int
tmp
=
openair0_write_reorder
(
&
UE
->
rfdevice
,
writeTimestamp
,
(
void
**
)
txp
,
writeBlockSize
,
fp
->
nb_antennas_tx
,
flags
);
int
tmp
=
openair0_write_reorder
(
&
UE
->
rfdevice
,
writeTimestamp
,
(
void
**
)
txp
,
writeBlockSize
,
fp
->
nb_antennas_tx
,
flags
);
...
@@ -723,10 +728,18 @@ static inline int get_readBlockSize(uint16_t slot, NR_DL_FRAME_PARMS *fp) {
...
@@ -723,10 +728,18 @@ static inline int get_readBlockSize(uint16_t slot, NR_DL_FRAME_PARMS *fp) {
}
}
#define SPEED_OF_LIGHT 299792458
#define SPEED_OF_LIGHT 299792458
static
inline
void
apply_ntn_timing_advance
(
PHY_VARS_NR_UE
*
UE
,
const
NR_DL_FRAME_PARMS
*
fp
,
int
abs_subframe_tx
)
static
void
apply_ntn_timing_advance_and_doppler
(
PHY_VARS_NR_UE
*
UE
,
const
NR_DL_FRAME_PARMS
*
fp
,
int
abs_subframe_tx
)
{
{
const
fapi_nr_dl_ntn_config_command_pdu
*
ntn_config_params
=
&
UE
->
ntn_config_message
->
ntn_config_params
;
const
fapi_nr_dl_ntn_config_command_pdu
*
ntn_config_params
=
&
UE
->
ntn_config_message
->
ntn_config_params
;
// Handle terrestrial networks
if
(
ntn_config_params
->
cell_specific_k_offset
==
0
)
{
UE
->
timing_advance_ntn
=
0
;
UE
->
dl_Doppler_shift
=
0
;
UE
->
ul_Doppler_shift
=
0
;
return
;
}
const
int
abs_subframe_epoch
=
ntn_config_params
->
epoch_subframe
const
int
abs_subframe_epoch
=
ntn_config_params
->
epoch_subframe
+
ntn_config_params
->
epoch_sfn
*
10
+
ntn_config_params
->
epoch_sfn
*
10
+
ntn_config_params
->
epoch_hfn
*
10240
;
+
ntn_config_params
->
epoch_hfn
*
10240
;
...
@@ -771,6 +784,12 @@ static inline void apply_ntn_timing_advance(PHY_VARS_NR_UE *UE, const NR_DL_FRAM
...
@@ -771,6 +784,12 @@ static inline void apply_ntn_timing_advance(PHY_VARS_NR_UE *UE, const NR_DL_FRAM
// calculate projected velocity from SAT towards UE
// calculate projected velocity from SAT towards UE
const
double
vel_sat_ue
=
(
vel_sat
.
X
*
dir_sat_ue
.
X
+
vel_sat
.
Y
*
dir_sat_ue
.
Y
+
vel_sat
.
Z
*
dir_sat_ue
.
Z
)
/
distance
;
const
double
vel_sat_ue
=
(
vel_sat
.
X
*
dir_sat_ue
.
X
+
vel_sat
.
Y
*
dir_sat_ue
.
Y
+
vel_sat
.
Z
*
dir_sat_ue
.
Z
)
/
distance
;
// calculate DL Doppler shift (moving source)
const
double
dl_Doppler_shift
=
(
vel_sat_ue
/
(
SPEED_OF_LIGHT
-
vel_sat_ue
))
*
fp
->
dl_CarrierFreq
;
// calculate UL Doppler shift (moving target)
const
double
ul_Doppler_shift
=
(
vel_sat_ue
/
SPEED_OF_LIGHT
)
*
fp
->
ul_CarrierFreq
;
// calculate round-trip-time (factor 2) between SAT and UE in ms (factor 1000)
// calculate round-trip-time (factor 2) between SAT and UE in ms (factor 1000)
const
double
N_UE_TA_adj
=
2000
*
distance
/
SPEED_OF_LIGHT
;
const
double
N_UE_TA_adj
=
2000
*
distance
/
SPEED_OF_LIGHT
;
...
@@ -783,32 +802,33 @@ static inline void apply_ntn_timing_advance(PHY_VARS_NR_UE *UE, const NR_DL_FRAM
...
@@ -783,32 +802,33 @@ static inline void apply_ntn_timing_advance(PHY_VARS_NR_UE *UE, const NR_DL_FRAM
+
N_common_ta_drift_variant
*
((
int64_t
)
ms_since_epoch
*
ms_since_epoch
)
/
1e9
)
+
N_common_ta_drift_variant
*
((
int64_t
)
ms_since_epoch
*
ms_since_epoch
)
/
1e9
)
*
fp
->
samples_per_subframe
;
*
fp
->
samples_per_subframe
;
UE
->
freq_offset
-=
dl_Doppler_shift
-
UE
->
dl_Doppler_shift
;
UE
->
dl_Doppler_shift
=
dl_Doppler_shift
;
UE
->
ul_Doppler_shift
=
ul_Doppler_shift
;
LOG_D
(
PHY
,
LOG_D
(
PHY
,
"N_UE_TA_adj = %f ms, N_common_ta_adj = %f ms, N_common_ta_drift = %f µs/s, N_common_ta_drift_variant = %f µs/s², "
"satellite velocity towards UE = %f m/s, DL Doppler shift = %f kHz, UL Doppler shift = %f kHz
\n
"
,
"ms_since_epoch = %d ms, computed timing_advance_ntn = %d samples, satellite velocity towards UE = %f m/s
\n
"
,
vel_sat_ue
,
N_UE_TA_adj
,
dl_Doppler_shift
/
1000
,
N_common_ta_adj
,
ul_Doppler_shift
/
1000
);
N_common_ta_drift
,
N_common_ta_drift_variant
,
ms_since_epoch
,
UE
->
timing_advance_ntn
,
vel_sat_ue
);
}
}
static
inline
void
apply_ntn_config
(
PHY_VARS_NR_UE
*
UE
,
static
void
apply_ntn_config
(
PHY_VARS_NR_UE
*
UE
,
NR_DL_FRAME_PARMS
*
fp
,
NR_DL_FRAME_PARMS
*
fp
,
int
hfn_rx
,
int
hfn_rx
,
int
frame_rx
,
int
frame_rx
,
int
slot_rx
,
int
slot_rx
,
int
*
duration_rx_to_tx
,
int
*
duration_rx_to_tx
,
int
*
timing_advance
,
int
*
timing_advance
,
int
*
ntn_koffset
)
int
*
ntn_koffset
)
{
{
if
(
UE
->
ntn_config_message
->
update
)
{
if
(
UE
->
ntn_config_message
->
update
)
{
UE
->
ntn_config_message
->
update
=
false
;
UE
->
ntn_config_message
->
update
=
false
;
const
fapi_nr_dl_ntn_config_command_pdu
*
ntn_config_params
=
&
UE
->
ntn_config_message
->
ntn_config_params
;
const
int
mu
=
fp
->
numerology_index
;
const
int
mu
=
fp
->
numerology_index
;
const
int
koffset
=
UE
->
ntn_config_message
->
ntn_config_params
.
cell_specific_k_offset
;
const
int
koffset
=
ntn_config_params
->
cell_specific_k_offset
;
*
duration_rx_to_tx
=
NR_UE_CAPABILITY_SLOT_RX_TO_TX
+
(
koffset
<<
mu
);
*
duration_rx_to_tx
=
NR_UE_CAPABILITY_SLOT_RX_TO_TX
+
(
koffset
<<
mu
);
if
(
koffset
>
*
ntn_koffset
)
if
(
koffset
>
*
ntn_koffset
)
...
@@ -818,7 +838,18 @@ static inline void apply_ntn_config(PHY_VARS_NR_UE *UE,
...
@@ -818,7 +838,18 @@ static inline void apply_ntn_config(PHY_VARS_NR_UE *UE,
*
ntn_koffset
=
koffset
;
*
ntn_koffset
=
koffset
;
const
int
abs_subframe_tx
=
10240
*
hfn_rx
+
10
*
frame_rx
+
((
slot_rx
+
*
duration_rx_to_tx
)
>>
mu
);
const
int
abs_subframe_tx
=
10240
*
hfn_rx
+
10
*
frame_rx
+
((
slot_rx
+
*
duration_rx_to_tx
)
>>
mu
);
apply_ntn_timing_advance
(
UE
,
fp
,
abs_subframe_tx
);
apply_ntn_timing_advance_and_doppler
(
UE
,
fp
,
abs_subframe_tx
);
LOG_I
(
PHY
,
"k_offset: %dms, N_Common_Ta: %fms, drift: %fµs/s, variant: %fµs/s², "
"timing_advance_ntn: %d samples, DL Doppler shift: %fkHz, UL Doppler shift: %fkHz
\n
"
,
koffset
<<
mu
,
ntn_config_params
->
N_common_ta_adj
,
ntn_config_params
->
N_common_ta_drift
,
ntn_config_params
->
N_common_ta_drift_variant
,
UE
->
timing_advance_ntn
,
UE
->
dl_Doppler_shift
/
1000
,
UE
->
ul_Doppler_shift
/
1000
);
}
}
}
}
...
@@ -1050,7 +1081,7 @@ void *UE_thread(void *arg)
...
@@ -1050,7 +1081,7 @@ void *UE_thread(void *arg)
// Calculate new TA based on SIB19 information for each subframe in NTN mode, if "autonomous_ta" is not enabled
// Calculate new TA based on SIB19 information for each subframe in NTN mode, if "autonomous_ta" is not enabled
if
(
ntn_koffset
&&
!
get_nrUE_params
()
->
autonomous_ta
&&
(
absolute_slot
+
duration_rx_to_tx
)
%
fp
->
slots_per_subframe
==
0
)
{
if
(
ntn_koffset
&&
!
get_nrUE_params
()
->
autonomous_ta
&&
(
absolute_slot
+
duration_rx_to_tx
)
%
fp
->
slots_per_subframe
==
0
)
{
const
int
abs_subframe_tx
=
(
absolute_slot
+
duration_rx_to_tx
)
/
fp
->
slots_per_subframe
;
const
int
abs_subframe_tx
=
(
absolute_slot
+
duration_rx_to_tx
)
/
fp
->
slots_per_subframe
;
apply_ntn_timing_advance
(
UE
,
fp
,
abs_subframe_tx
);
apply_ntn_timing_advance
_and_doppler
(
UE
,
fp
,
abs_subframe_tx
);
}
}
const
int
readBlockSize
=
get_readBlockSize
(
slot_nr
,
fp
)
-
iq_shift_to_apply
;
const
int
readBlockSize
=
get_readBlockSize
(
slot_nr
,
fp
)
-
iq_shift_to_apply
;
...
...
openair1/PHY/MODULATION/slot_fep_nr.c
View file @
bc81662c
...
@@ -119,7 +119,7 @@ int nr_slot_fep(PHY_VARS_NR_UE *ue,
...
@@ -119,7 +119,7 @@ int nr_slot_fep(PHY_VARS_NR_UE *ue,
if
(
ue
&&
ue
->
cont_fo_comp
)
{
if
(
ue
&&
ue
->
cont_fo_comp
)
{
start_meas_nr_ue_phy
(
ue
,
RX_FO_COMPENSATION_STATS
);
start_meas_nr_ue_phy
(
ue
,
RX_FO_COMPENSATION_STATS
);
nr_fo_compensation
(
ue
->
freq_offset
,
nr_fo_compensation
(
ue
->
dl_Doppler_shift
+
ue
->
freq_offset
,
frame_parms
->
samples_per_subframe
,
frame_parms
->
samples_per_subframe
,
rx_offset
,
rx_offset
,
rxdata_symb_ptr
[
aa
],
rxdata_symb_ptr
[
aa
],
...
...
openair1/PHY/defs_nr_UE.h
View file @
bc81662c
...
@@ -462,8 +462,10 @@ typedef struct PHY_VARS_NR_UE_s {
...
@@ -462,8 +462,10 @@ typedef struct PHY_VARS_NR_UE_s {
double
initial_fo
;
/// initial frequency offset provided by the user
double
initial_fo
;
/// initial frequency offset provided by the user
int
cont_fo_comp
;
/// flag enabling the continuous frequency offset estimation and compensation
int
cont_fo_comp
;
/// flag enabling the continuous frequency offset estimation and compensation
double
freq_offset
;
/// currently compensated frequency offset
double
freq_offset
;
/// currently compensated DL frequency offset (without dl_Doppler_shift)
double
freq_off_acc
;
/// accumulated frequency error (for PI controller)
double
freq_off_acc
;
/// accumulated DL frequency error (for PI controller)
double
dl_Doppler_shift
;
/// calculated DL Doppler shift
double
ul_Doppler_shift
;
/// calculated UL Doppler shift
/// Timing Advance updates variables
/// Timing Advance updates variables
/// Timing advance update computed from the TA command signalled from gNB
/// Timing advance update computed from the TA command signalled from gNB
...
...
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