Merge remote-tracking branch 'origin/move_ntn_l1_files' into integration_2026_w02 (!3836)

move NTN UE L1 functions to a new file

Moved from nr-ue not to overload that file with functions of a specific mode
This commit is contained in:
Jaroslava Fiedlerova
2026-01-06 10:00:10 +01:00
4 changed files with 203 additions and 172 deletions
+1
View File
@@ -979,6 +979,7 @@ set(PHY_SRC_UE
${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/cic_filter_nr.c
${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/nr_initial_sync.c
${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/nr_initial_sync_sl.c
${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/nr_ntn_l1.c
${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/nr_ue_rf_helpers.c
${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/nr_pbch.c
${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/nr_psbch_rx.c
-171
View File
@@ -497,8 +497,6 @@ 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;
@@ -735,175 +733,6 @@ 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)
{
if (!UE->nrUE_config.ntn_config.is_targetcell)
return;
UE->nrUE_config.ntn_config.is_targetcell = false;
const int epoch_frame = UE->nrUE_config.ntn_config.epoch_sfn;
const int diff1 = (frame - epoch_frame + 1024) % 1024;
const int diff2 = (epoch_frame - frame + 1024) % 1024;
int *epoch_hfn = &UE->nrUE_config.ntn_config.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_ntn_config_t *ntn_config_params = &UE->nrUE_config.ntn_config;
// 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;
return;
}
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 < 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;
position_t pos_sat;
position_t vel_sat;
const double omega = ntn_config_params->omega;
if (omega) {
const double cos_wt = cos(omega * ms_since_epoch);
const double sin_wt = sin(omega * ms_since_epoch);
const position_t pos_sat_90 = ntn_config_params->pos_sat_90;
pos_sat = (position_t){pos_sat_0.X * cos_wt + pos_sat_90.X * sin_wt,
pos_sat_0.Y * cos_wt + pos_sat_90.Y * sin_wt,
pos_sat_0.Z * cos_wt + pos_sat_90.Z * sin_wt};
const position_t vel_sat_90 = ntn_config_params->vel_sat_90;
vel_sat = (position_t){vel_sat_0.X * cos_wt + vel_sat_90.X * sin_wt,
vel_sat_0.Y * cos_wt + vel_sat_90.Y * sin_wt,
vel_sat_0.Z * cos_wt + vel_sat_90.Z * sin_wt};
} else {
pos_sat = (position_t){pos_sat_0.X + vel_sat_0.X * ms_since_epoch / 1000,
pos_sat_0.Y + vel_sat_0.Y * ms_since_epoch / 1000,
pos_sat_0.Z + vel_sat_0.Z * ms_since_epoch / 1000};
vel_sat = vel_sat_0;
}
position_t pos_ue = {0};
get_position_coordinates(UE->Mod_id, &pos_ue);
// 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};
// calculate distance between SAT and UE
const 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);
// 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;
// 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)
const double N_UE_TA_adj = 2000 * distance / SPEED_OF_LIGHT;
const double N_common_ta_adj = ntn_config_params->N_common_ta_adj;
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;
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;
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,
int frame_rx,
int slot_rx,
int *duration_rx_to_tx,
int *timing_advance,
int *ntn_koffset,
bool *ntn_targetcell)
{
// return if there is no pending update
if (!UE->nrUE_config.ntn_config.params_changed)
return;
*ntn_targetcell = UE->nrUE_config.ntn_config.is_targetcell;
// skip update if it is for the target cell
if (UE->nrUE_config.ntn_config.is_targetcell)
return;
UE->nrUE_config.ntn_config.params_changed = false;
const fapi_nr_ntn_config_t *ntn_config_params = &UE->nrUE_config.ntn_config;
const int mu = fp->numerology_index;
const int koffset = ntn_config_params->cell_specific_k_offset;
*duration_rx_to_tx = NR_UE_CAPABILITY_SLOT_RX_TO_TX + (koffset << mu);
if (koffset > *ntn_koffset)
*timing_advance += get_samples_slot_duration(fp, slot_rx, (koffset - *ntn_koffset) << mu);
else if (koffset < *ntn_koffset)
*timing_advance -= get_samples_slot_duration(fp, slot_rx, (*ntn_koffset - koffset) << mu);
*ntn_koffset = koffset;
const int abs_subframe_tx = 10240 * hfn_rx + 10 * frame_rx + ((slot_rx + *duration_rx_to_tx) >> mu);
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);
}
void *UE_thread(void *arg)
{
//this thread should be over the processing thread to keep in real time
+191
View File
@@ -0,0 +1,191 @@
/*
* 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
*/
#include "PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h"
void fix_ntn_epoch_hfn(PHY_VARS_NR_UE *UE, int hfn, int frame)
{
if (!UE->nrUE_config.ntn_config.is_targetcell)
return;
UE->nrUE_config.ntn_config.is_targetcell = false;
const int epoch_frame = UE->nrUE_config.ntn_config.epoch_sfn;
const int diff1 = (frame - epoch_frame + 1024) % 1024;
const int diff2 = (epoch_frame - frame + 1024) % 1024;
int *epoch_hfn = &UE->nrUE_config.ntn_config.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
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_ntn_config_t *ntn_config_params = &UE->nrUE_config.ntn_config;
// 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;
return;
}
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 < 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;
position_t pos_sat;
position_t vel_sat;
const double omega = ntn_config_params->omega;
if (omega) {
const double cos_wt = cos(omega * ms_since_epoch);
const double sin_wt = sin(omega * ms_since_epoch);
const position_t pos_sat_90 = ntn_config_params->pos_sat_90;
pos_sat = (position_t){pos_sat_0.X * cos_wt + pos_sat_90.X * sin_wt,
pos_sat_0.Y * cos_wt + pos_sat_90.Y * sin_wt,
pos_sat_0.Z * cos_wt + pos_sat_90.Z * sin_wt};
const position_t vel_sat_90 = ntn_config_params->vel_sat_90;
vel_sat = (position_t){vel_sat_0.X * cos_wt + vel_sat_90.X * sin_wt,
vel_sat_0.Y * cos_wt + vel_sat_90.Y * sin_wt,
vel_sat_0.Z * cos_wt + vel_sat_90.Z * sin_wt};
} else {
pos_sat = (position_t){pos_sat_0.X + vel_sat_0.X * ms_since_epoch / 1000,
pos_sat_0.Y + vel_sat_0.Y * ms_since_epoch / 1000,
pos_sat_0.Z + vel_sat_0.Z * ms_since_epoch / 1000};
vel_sat = vel_sat_0;
}
position_t pos_ue = {0};
get_position_coordinates(UE->Mod_id, &pos_ue);
// 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};
// calculate distance between SAT and UE
const 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);
// 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;
// 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)
const double N_UE_TA_adj = 2000 * distance / SPEED_OF_LIGHT;
const double N_common_ta_adj = ntn_config_params->N_common_ta_adj;
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;
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;
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
void apply_ntn_config(PHY_VARS_NR_UE *UE,
NR_DL_FRAME_PARMS *fp,
int hfn_rx,
int frame_rx,
int slot_rx,
int *duration_rx_to_tx,
int *timing_advance,
int *ntn_koffset,
bool *ntn_targetcell)
{
// return if there is no pending update
if (!UE->nrUE_config.ntn_config.params_changed)
return;
*ntn_targetcell = UE->nrUE_config.ntn_config.is_targetcell;
// skip update if it is for the target cell
if (UE->nrUE_config.ntn_config.is_targetcell)
return;
UE->nrUE_config.ntn_config.params_changed = false;
const fapi_nr_ntn_config_t *ntn_config_params = &UE->nrUE_config.ntn_config;
const int mu = fp->numerology_index;
const int koffset = ntn_config_params->cell_specific_k_offset;
*duration_rx_to_tx = NR_UE_CAPABILITY_SLOT_RX_TO_TX + (koffset << mu);
if (koffset > *ntn_koffset)
*timing_advance += get_samples_slot_duration(fp, slot_rx, (koffset - *ntn_koffset) << mu);
else if (koffset < *ntn_koffset)
*timing_advance -= get_samples_slot_duration(fp, slot_rx, (*ntn_koffset - koffset) << mu);
*ntn_koffset = koffset;
const int abs_subframe_tx = 10240 * hfn_rx + 10 * frame_rx + ((slot_rx + *duration_rx_to_tx) >> mu);
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);
}
@@ -330,7 +330,17 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue,
pdsch_scope_req_t *scope_req);
int32_t generate_nr_prach(PHY_VARS_NR_UE *ue, uint8_t gNB_id, int frame, uint8_t slot, c16_t **txData);
void apply_ntn_config(PHY_VARS_NR_UE *UE,
NR_DL_FRAME_PARMS *fp,
int hfn_rx,
int frame_rx,
int slot_rx,
int *duration_rx_to_tx,
int *timing_advance,
int *ntn_koffset,
bool *ntn_targetcell);
void fix_ntn_epoch_hfn(PHY_VARS_NR_UE *UE, int hfn, int frame);
void apply_ntn_timing_advance_and_doppler(PHY_VARS_NR_UE *UE, const NR_DL_FRAME_PARMS *fp, int abs_subframe_tx);
void dump_nrdlsch(PHY_VARS_NR_UE *ue,uint8_t gNB_id,uint8_t nr_slot_rx,unsigned int *coded_bits_per_codeword,int round, unsigned char harq_pid);
void nr_a_sum_b(c16_t *input_x, c16_t *input_y, unsigned short nb_rb);