From 3684c3e0e8dd0a99bbee14811011de179de7df3a Mon Sep 17 00:00:00 2001 From: Rakesh Mundlamuri Date: Fri, 17 Oct 2025 18:01:31 +0530 Subject: [PATCH 01/22] Declare ue_srs_procedures_nr in a header file to use in nr_srssim --- openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h | 6 ++++++ openair1/SCHED_NR_UE/phy_procedures_nr_ue.c | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h index 2a24902295..ab51d118ff 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h @@ -178,6 +178,12 @@ uint8_t nr_ue_pusch_common_procedures(PHY_VARS_NR_UE *UE, bool was_symbol_used[NR_NUMBER_OF_SYMBOLS_PER_SLOT], bool no_phase_pre_comp); +bool ue_srs_procedures_nr(PHY_VARS_NR_UE *ue, + const UE_nr_rxtx_proc_t *proc, + c16_t **txdataF, + nr_phy_data_tx_t *phy_data, + bool was_symbol_used[NR_NUMBER_OF_SYMBOLS_PER_SLOT]); + void clean_UE_harq(PHY_VARS_NR_UE *UE); void nr_dlsch_unscrambling(int16_t* llr, diff --git a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c index 68c0541e3a..745f4961bf 100644 --- a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c +++ b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c @@ -304,7 +304,7 @@ static void configure_srs_info(fapi_nr_ul_config_srs_pdu *srs_config_pdu, nr_srs * send srs according to current configuration * *********************************************************************/ -static bool ue_srs_procedures_nr(PHY_VARS_NR_UE *ue, +bool ue_srs_procedures_nr(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, c16_t **txdataF, nr_phy_data_tx_t *phy_data, From 4b102ea237949bc658fcb0a6ccfc8b12db2ed536 Mon Sep 17 00:00:00 2001 From: Rakesh Mundlamuri Date: Fri, 17 Oct 2025 18:13:33 +0530 Subject: [PATCH 02/22] Make SRS receive procedures as a function --- .../PHY/NR_TRANSPORT/nr_transport_proto.h | 14 ++ openair1/SCHED_NR/phy_procedures_nr_gNB.c | 175 ++++++++++-------- 2 files changed, 116 insertions(+), 73 deletions(-) diff --git a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h index 29fca5975e..1a0fabf14e 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h +++ b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h @@ -231,6 +231,20 @@ int nr_get_srs_signal(PHY_VARS_gNB *gNB, c16_t srs_received_signal[][gNB->frame_parms.ofdm_symbol_size * (1 << srs_pdu->num_symbols)], c16_t srs_received_noise[][gNB->frame_parms.ofdm_symbol_size * (1 << srs_pdu->num_symbols)]); +void nr_srs_rx_procedures(PHY_VARS_gNB *gNB, + int frame_rx, + int slot_rx, + uint8_t nb_antennas_rx, + uint8_t N_ap, + uint8_t N_symb_SRS, + uint16_t ofdm_symbol_size, + NR_gNB_SRS_t *srs, + nr_srs_info_t *nr_srs_info, + int *srs_est, + c16_t srs_estimated_channel_freq[][N_ap][ofdm_symbol_size * N_symb_SRS], + c16_t srs_estimated_channel_time[][N_ap][ofdm_symbol_size], + int16_t *snr_per_rb); + int get_nr_prach_duration(uint8_t prach_format); void free_nr_prach_entry(prach_list_t *, prach_item_t *); diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index 1271734866..69dc6ad3e7 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -857,6 +857,81 @@ static bool check_and_configure_srs_info(nfapi_nr_srs_pdu_t *srs_config_pdu, nr_ return false; } +void nr_srs_rx_procedures(PHY_VARS_gNB *gNB, + int frame_rx, + int slot_rx, + uint8_t nb_antennas_rx, + uint8_t N_ap, + uint8_t N_symb_SRS, + uint16_t ofdm_symbol_size, + NR_gNB_SRS_t *srs, + nr_srs_info_t *nr_srs_info, + int *srs_est, + c16_t srs_estimated_channel_freq[][N_ap][ofdm_symbol_size * N_symb_SRS], + c16_t srs_estimated_channel_time[][N_ap][ofdm_symbol_size], + int16_t *snr_per_rb) +{ + NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms; + nfapi_nr_srs_pdu_t *srs_pdu = &srs->srs_pdu; + c16_t srs_received_signal[nb_antennas_rx][ofdm_symbol_size * N_symb_SRS]; + c16_t srs_received_noise[nb_antennas_rx][ofdm_symbol_size * N_symb_SRS]; + c16_t srs_estimated_channel_time_shifted[nb_antennas_rx][N_ap][ofdm_symbol_size]; + + start_meas(&gNB->generate_srs_stats); + + if (check_and_configure_srs_info(srs_pdu, nr_srs_info)) { + generate_srs_nr(frame_parms, nr_srs_info->srs_generated_signal, 0, srs_pdu->bwp_start, nr_srs_info, AMP, frame_rx, slot_rx); + } + + stop_meas(&gNB->generate_srs_stats); + c16_t **rxdataF = gNB->common_vars.rxdataF[srs->beam_nb]; + start_meas(&gNB->get_srs_signal_stats); + *srs_est = nr_get_srs_signal(gNB, rxdataF, frame_rx, slot_rx, srs_pdu, nr_srs_info, srs_received_signal, srs_received_noise); + stop_meas(&gNB->get_srs_signal_stats); + + if (*srs_est >= 0) { + start_meas(&gNB->srs_channel_estimation_stats); + nr_srs_channel_estimation(gNB, + frame_rx, + slot_rx, + srs_pdu, + nr_srs_info, + (const c16_t **)nr_srs_info->srs_generated_signal, + srs_received_signal, + srs_received_noise, + srs_estimated_channel_freq, + srs_estimated_channel_time, + srs_estimated_channel_time_shifted, + snr_per_rb, + &gNB->srs->snr); + stop_meas(&gNB->srs_channel_estimation_stats); + } + + T(T_GNB_PHY_UL_FREQ_CHANNEL_ESTIMATE, + T_INT(0), + T_INT(srs_pdu->rnti), + T_INT(frame_rx), + T_INT(0), + T_INT(0), + T_BUFFER(srs_estimated_channel_freq[0][0], ofdm_symbol_size * sizeof(int32_t))); + + T(T_GNB_PHY_UL_TIME_CHANNEL_ESTIMATE, + T_INT(0), + T_INT(srs_pdu->rnti), + T_INT(frame_rx), + T_INT(0), + T_INT(0), + T_BUFFER(srs_estimated_channel_time_shifted[0][0], ofdm_symbol_size * sizeof(int32_t))); + + T(T_GNB_PHY_UL_SNR_ESTIMATE, + T_INT(0), + T_INT(srs_pdu->rnti), + T_INT(frame_rx), + T_INT(0), + T_INT(0), + T_BUFFER(snr_per_rb, srs_pdu->bwp_size * sizeof(int16_t))); +} + int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, NR_UL_IND_t *UL_INFO) { /* those variables to log T_GNB_PHY_PUCCH_PUSCH_IQ only when we try to decode */ @@ -865,9 +940,9 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, N int pusch_DTX = 0; const NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms; - const int symb_sz = frame_parms->ofdm_symbol_size; + const uint16_t ofdm_symbol_size = frame_parms->ofdm_symbol_size; const int nb_symb = frame_parms->symbols_per_slot; - const int ant = gNB->frame_parms.nb_antennas_rx; + const uint8_t nb_antennas_rx = frame_parms->nb_antennas_rx; VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_gNB_UESPEC_RX,1); LOG_D(PHY,"phy_procedures_gNB_uespec_RX frame %d, slot %d\n",frame_rx,slot_rx); { @@ -892,7 +967,7 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, N gNB_I0_measurements(gNB, slot_rx, first_symb, num_symb, rb_mask_ul); } - const int soffset = (slot_rx & 3) * nb_symb * symb_sz; + const int soffset = (slot_rx & 3) * nb_symb * ofdm_symbol_size; start_meas(&gNB->phy_proc_rx); for (int i = 0; i < gNB->max_nb_pucch; i++) { @@ -911,7 +986,8 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, N uci->pdu_type = NFAPI_NR_UCI_FORMAT_0_1_PDU_TYPE; uci->pdu_size = sizeof(nfapi_nr_uci_pucch_pdu_format_0_1_t); nfapi_nr_uci_pucch_pdu_format_0_1_t *uci_pdu_format0 = &uci->pucch_pdu_format_0_1; - int offset = pucch_pdu->start_symbol_index * symb_sz + (frame_parms->first_carrier_offset + pucch_pdu->prb_start * 12); + int offset = + pucch_pdu->start_symbol_index * ofdm_symbol_size + (frame_parms->first_carrier_offset + pucch_pdu->prb_start * 12); LOG_D(NR_PHY, "frame %d, slot %d: PUCCH signal energy %d\n", frame_rx, @@ -988,7 +1064,7 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, N NR_gNB_PUSCH *pusch_vars = &gNB->pusch_vars[ULSCH_id]; pusch_vars->ulsch_power_tot = 0; pusch_vars->ulsch_noise_power_tot = 0; - for (int aarx = 0; aarx < ant; aarx++) { + for (int aarx = 0; aarx < nb_antennas_rx; aarx++) { pusch_vars->ulsch_power[aarx] /= num_dmrs; pusch_vars->ulsch_power_tot += pusch_vars->ulsch_power[aarx]; pusch_vars->ulsch_noise_power[aarx] /= num_dmrs; @@ -1063,80 +1139,33 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, N start_meas(&gNB->rx_srs_stats); + uint8_t N_symb_SRS = 1 << srs->srs_pdu.num_symbols; + uint8_t N_ap = 1 << srs->srs_pdu.num_ant_ports; + int16_t snr_per_rb[srs->srs_pdu.bwp_size]; nfapi_nr_srs_pdu_t *srs_pdu = &srs->srs_pdu; - uint8_t N_symb_SRS = 1 << srs_pdu->num_symbols; - c16_t srs_received_signal[ant][symb_sz * N_symb_SRS]; - c16_t srs_received_noise[ant][symb_sz * N_symb_SRS]; - c16_t srs_estimated_channel_freq[ant][1 << srs_pdu->num_ant_ports][symb_sz * N_symb_SRS] __attribute__((aligned(32))); - c16_t srs_estimated_channel_time[ant][1 << srs_pdu->num_ant_ports][symb_sz] __attribute__((aligned(32))); - c16_t srs_estimated_channel_time_shifted[ant][1 << srs_pdu->num_ant_ports][symb_sz]; - int16_t snr_per_rb[srs_pdu->bwp_size]; + int srs_est; - start_meas(&gNB->generate_srs_stats); + c16_t srs_estimated_channel_freq[nb_antennas_rx][N_ap][ofdm_symbol_size * N_symb_SRS] __attribute__((aligned(32))); + c16_t srs_estimated_channel_time[nb_antennas_rx][N_ap][ofdm_symbol_size] __attribute__((aligned(32))); - if (check_and_configure_srs_info(srs_pdu, gNB->nr_srs_info[i])) { - generate_srs_nr(frame_parms, - gNB->nr_srs_info[i]->srs_generated_signal, - 0, - srs_pdu->bwp_start, - gNB->nr_srs_info[i], - AMP, - frame_rx, - slot_rx); - } - stop_meas(&gNB->generate_srs_stats); - c16_t **rxdataF = gNB->common_vars.rxdataF[srs->beam_nb]; - start_meas(&gNB->get_srs_signal_stats); - int srs_est = - nr_get_srs_signal(gNB, rxdataF, frame_rx, slot_rx, srs_pdu, gNB->nr_srs_info[i], srs_received_signal, srs_received_noise); - stop_meas(&gNB->get_srs_signal_stats); - - if (srs_est >= 0) { - start_meas(&gNB->srs_channel_estimation_stats); - nr_srs_channel_estimation(gNB, - frame_rx, - slot_rx, - srs_pdu, - gNB->nr_srs_info[i], - (const c16_t **)gNB->nr_srs_info[i]->srs_generated_signal, - srs_received_signal, - srs_received_noise, - srs_estimated_channel_freq, - srs_estimated_channel_time, - srs_estimated_channel_time_shifted, - snr_per_rb, - &gNB->srs->snr); - stop_meas(&gNB->srs_channel_estimation_stats); - } + nr_srs_rx_procedures(gNB, + frame_rx, + slot_rx, + nb_antennas_rx, + N_ap, + N_symb_SRS, + ofdm_symbol_size, + srs, + gNB->nr_srs_info[i], + &srs_est, + srs_estimated_channel_freq, + srs_estimated_channel_time, + snr_per_rb); if ((gNB->srs->snr * 10) < gNB->srs_thres) { srs_est = -1; } - T(T_GNB_PHY_UL_FREQ_CHANNEL_ESTIMATE, - T_INT(0), - T_INT(srs_pdu->rnti), - T_INT(frame_rx), - T_INT(0), - T_INT(0), - T_BUFFER(srs_estimated_channel_freq[0][0], symb_sz * sizeof(int32_t))); - - T(T_GNB_PHY_UL_TIME_CHANNEL_ESTIMATE, - T_INT(0), - T_INT(srs_pdu->rnti), - T_INT(frame_rx), - T_INT(0), - T_INT(0), - T_BUFFER(srs_estimated_channel_time_shifted[0][0], symb_sz * sizeof(int32_t))); - - T(T_GNB_PHY_UL_SNR_ESTIMATE, - T_INT(0), - T_INT(srs_pdu->rnti), - T_INT(frame_rx), - T_INT(0), - T_INT(0), - T_BUFFER(snr_per_rb, srs_pdu->bwp_size * sizeof(int16_t))); - UL_INFO->srs_ind.sfn = frame_rx; UL_INFO->srs_ind.slot = slot_rx; @@ -1234,7 +1263,7 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, N srs_pdu, gNB->nr_srs_info[i], srs_pdu->srs_parameters_v4.iq_representation, - ant, + nb_antennas_rx, srs_pdu->srs_parameters_v4.num_total_ue_antennas, srs_pdu->srs_parameters_v4.prg_size, srs_pdu->srs_parameters_v4.srs_bandwidth_size / srs_pdu->srs_parameters_v4.prg_size, @@ -1306,7 +1335,7 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, N T(T_GNB_PHY_PUCCH_PUSCH_IQ, T_INT(frame_rx), T_INT(slot_rx), - T_BUFFER(&gNB->common_vars.rxdataF[0][0][0], nb_symb * symb_sz * 4)); + T_BUFFER(&gNB->common_vars.rxdataF[0][0][0], nb_symb * ofdm_symbol_size * 4)); } VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_gNB_UESPEC_RX,0); From 5803e2037e725c00178d14eb61fb0ef90c67b5b0 Mon Sep 17 00:00:00 2001 From: Rakesh Mundlamuri Date: Fri, 17 Oct 2025 18:16:44 +0530 Subject: [PATCH 03/22] bugfix to avoid error after enabling DEBUG_CH --- openair1/SIMULATION/TOOLS/multipath_channel.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openair1/SIMULATION/TOOLS/multipath_channel.c b/openair1/SIMULATION/TOOLS/multipath_channel.c index f17c2166a3..aeaa4f811f 100644 --- a/openair1/SIMULATION/TOOLS/multipath_channel.c +++ b/openair1/SIMULATION/TOOLS/multipath_channel.c @@ -68,7 +68,7 @@ void __attribute__ ((no_sanitize_address)) multipath_channel(channel_desc_t *des #ifdef DEBUG_CH - for (l = 0; l<(int)desc->channel_length; l++) { + for (int l = 0; l<(int)desc->channel_length; l++) { printf("%p (%f,%f) ",desc->ch[0],desc->ch[0][l].x,desc->ch[0][l].y); } @@ -168,7 +168,7 @@ void __attribute__ ((no_sanitize_address)) multipath_channel(channel_desc_t *des } #ifdef DEBUG_CH - for (l = 0; l<(int)desc->channel_length; l++) { + for (int l = 0; l<(int)desc->channel_length; l++) { printf("ch[%i] = (%f, %f)\n", l, desc->ch[0][l].r, desc->ch[0][l].i); } #endif From 3d68a44da068cc0a2490bcbd6e74d1a74a6d27d7 Mon Sep 17 00:00:00 2001 From: Rakesh Mundlamuri Date: Fri, 17 Oct 2025 18:25:18 +0530 Subject: [PATCH 04/22] Introduce SRS physical simulator --- CMakeLists.txt | 15 +- cmake_targets/build_oai | 2 +- .../PHY/NR_ESTIMATION/nr_measurements_gNB.c | 2 + openair1/SIMULATION/NR_PHY/srssim.c | 706 ++++++++++++++++++ 4 files changed, 723 insertions(+), 2 deletions(-) create mode 100644 openair1/SIMULATION/NR_PHY/srssim.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 2730c510e0..14d90a4c3b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2037,6 +2037,19 @@ target_link_libraries(nr_ulsim PRIVATE ) target_link_libraries(nr_ulsim PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs) +add_executable(nr_srssim + ${OPENAIR1_DIR}/SIMULATION/NR_PHY/srssim.c + ${OPENAIR_DIR}/executables/softmodem-common.c + ${NFAPI_USER_DIR}/nfapi.c + ${NFAPI_USER_DIR}/gnb_ind_vars.c + ${PHY_INTERFACE_DIR}/queue_t.c + ) + +target_link_libraries(nr_srssim PRIVATE + -Wl,--start-group UTIL SIMU PHY_COMMON PHY_NR_COMMON PHY_NR PHY_NR_UE SCHED_NR_LIB SCHED_NR_UE_LIB MAC_UE_NR MAC_NR_COMMON nr_rrc L2_NR -lz -Wl,--end-group + m pthread ITTI dl nr_ue_phy_meas physim_common + ) + # these simulators do not compile: # dlsim_tm7 pbchsim scansim mbmssim pdcchsim pucchsim prachsim syncsim foreach(myExe dlsim ulsim) @@ -2085,7 +2098,7 @@ if (${T_TRACER}) nr-uesoftmodem dlsim dlsim_tm4 dlsim_tm7 ulsim pbchsim scansim mbmssim pdcchsim pucchsim prachsim syncsim nr_ulsim nr_dlsim nr_dlschsim nr_pbchsim nr_pucchsim - nr_ulschsim ldpctest polartest smallblocktest + nr_ulschsim ldpctest polartest smallblocktest nr_srssim #all "add_library" definitions ITTI lte_rrc nr_rrc s1ap x2ap m2ap m3ap f1ap params_libconfig diff --git a/cmake_targets/build_oai b/cmake_targets/build_oai index 6f61196e7e..0e4d092916 100755 --- a/cmake_targets/build_oai +++ b/cmake_targets/build_oai @@ -300,7 +300,7 @@ function main() { SIMUS_PHY=1 CMAKE_CMD="$CMAKE_CMD -DENABLE_PHYSIM_TESTS=ON" # TODO: fix: dlsim_tm4 pucchsim prachsim pdcchsim pbchsim mbmssim - TARGET_LIST="$TARGET_LIST dlsim ulsim ldpctest polartest smallblocktest nr_pbchsim nr_dlschsim nr_ulschsim nr_dlsim nr_ulsim nr_pucchsim nr_prachsim nr_psbchsim" + TARGET_LIST="$TARGET_LIST dlsim ulsim ldpctest polartest smallblocktest nr_pbchsim nr_dlschsim nr_ulschsim nr_dlsim nr_ulsim nr_pucchsim nr_prachsim nr_psbchsim nr_srssim" echo_info "Will compile dlsim, ulsim, ..." shift;; -V | --vcd) diff --git a/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c b/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c index a1fde35b00..f48e1101eb 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c +++ b/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c @@ -59,6 +59,8 @@ int nr_est_timing_advance_srs(const NR_DL_FRAME_PARMS *frame_parms, timing_advance = timing_advance - frame_parms->ofdm_symbol_size; } + LOG_I(NR_PHY, "Estimated SRS ToA %d\n", timing_advance); + // Scale the 16 factor in N_TA calculation in 38.213 section 4.2 according to the used FFT size const uint16_t bw_scaling = frame_parms->ofdm_symbol_size >> 7; diff --git a/openair1/SIMULATION/NR_PHY/srssim.c b/openair1/SIMULATION/NR_PHY/srssim.c new file mode 100644 index 0000000000..9f89d29b1d --- /dev/null +++ b/openair1/SIMULATION/NR_PHY/srssim.c @@ -0,0 +1,706 @@ +/* + * 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 +#include +#include "common/utils/nr/nr_common.h" +#include "common/utils/var_array.h" +#define inMicroS(a) (((double)(a)) / (get_cpu_freq_GHz() * 1000.0)) +#include "SIMULATION/LTE_PHY/common_sim.h" +#include "common/utils/assertions.h" +#include "PHY/INIT/nr_phy_init.h" +#include "PHY/MODULATION/nr_modulation.h" +#include "PHY/MODULATION/modulation_common.h" +#include "PHY/NR_REFSIG/ul_ref_seq_nr.h" +#include "PHY/NR_TRANSPORT/nr_transport_common_proto.h" +#include "PHY/NR_TRANSPORT/nr_transport_proto.h" +#include "PHY/NR_UE_TRANSPORT/nr_transport_ue.h" +#include "PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h" +#include "PHY/NR_ESTIMATION/nr_ul_estimation.h" +#include "PHY/phy_vars_nr_ue.h" +#include "e1ap_messages_types.h" +#include "executables/nr-uesoftmodem.h" +#include "SIMULATION/NR_PHY/nr_unitary_defs.h" +#include "SIMULATION/TOOLS/sim.h" +#include "common/ran_context.h" +#include "time_meas.h" +#include "SCHED_NR/phy_frame_config_nr.h" + +PHY_VARS_gNB *gNB; +PHY_VARS_NR_UE *UE; +RAN_CONTEXT_t RC; +char *uecap_file = NULL; +int32_t uplink_frequency_offset[MAX_NUM_CCs][4]; + +double cpuf; +uint64_t downlink_frequency[MAX_NUM_CCs][4]; +uint64_t uplink_frequency[MAX_NUM_CCs][4]; +THREAD_STRUCT thread_struct; + +// needed for some functions +uint16_t n_rnti = 0x1234; +openair0_config_t openair0_cfg[MAX_CARDS]; +nrUE_params_t nrUE_params; + +nrUE_params_t *get_nrUE_params(void) +{ + return &nrUE_params; +} + +channel_desc_t *UE2gNB[MAX_MOBILES_PER_GNB][NUMBER_OF_gNB_MAX]; +configmodule_interface_t *uniqCfg = NULL; + +void e1_bearer_context_setup(const e1ap_bearer_setup_req_t *req) +{ + abort(); +} +void e1_bearer_context_modif(const e1ap_bearer_mod_req_t *req) +{ + abort(); +} +void e1_bearer_release_cmd(const e1ap_bearer_release_cmd_t *cmd) +{ + abort(); +} + +int main(int argc, char *argv[]) +{ + stop = false; + __attribute__((unused)) struct sigaction oldaction; + sigaction(SIGINT, &sigint_action, &oldaction); + + double SNR, snr0 = 0, snr1 = 20.0; + double sum_srs_snr = 0; + double sigma, sigma_dB; + double snr_step = 5; + uint8_t snr1set = 0; + double **s_re, **s_im, **r_re, **r_im; + int trial, n_trials = 1, delay = 0; + double maxDoppler = 0.0; + uint8_t n_tx = 1, n_rx = 1; + channel_desc_t *UE2gNB; + uint8_t extended_prefix_flag = 0; + SCM_t channel_model = AWGN; + corr_level_t corr_level = CORR_LEVEL_LOW; + uint16_t N_RB_DL = 106, N_RB_UL = 106, mu = 1; + int srs_start_symbol = 13; + int srs_comb_size = 0; + int srs_comb_offset = 0; + int srs_cyclic_shift = 0; + int nb_symb_srs = 0; + int32_t txlev_sum = 0, atxlev[4]; + int i; + int loglvl = OAILOG_WARNING; + int print_perf = 0; + int slot = 8; + int frame = 1; + cpuf = get_cpu_freq_GHz(); + double DS_TDL = .03; + int threequarter_fs = 0; + uint64_t SSB_positions = 0x01; + uint16_t Nid_cell = 0; + + if ((uniqCfg = load_configmodule(argc, argv, CONFIG_ENABLECMDLINEONLY)) == 0) { + exit_fun("[NR_SRSSIM] Error, configuration module init failed\n"); + } + + randominit(); + + /* initialize the sin-cos table */ + InitSinLUT(); + + int c; + while ((c = getopt(argc, argv, "--:O:a:b:c:d:e:f:g:h:i:k:l:m:n:p:s:u:y:z:A:B:C:H:PR:S:L:")) != -1) { + /* ignore long options starting with '--', option '-O' and their arguments that are handled by configmodule */ + /* with this opstring getopt returns 1 for non-option arguments, refer to 'man 3 getopt' */ + if (c == 1 || c == '-' || c == 'O') + continue; + + printf("handling optarg %c\n", c); + switch (c) { + case 'a': + srs_start_symbol = atoi(optarg); + AssertFatal(srs_start_symbol >= 8 && srs_start_symbol <= 13, "start_symbol %d is not in 8..13\n", srs_start_symbol); + break; + + case 'b': + nb_symb_srs = atoi(optarg); + AssertFatal(nb_symb_srs == 1 || nb_symb_srs == 2 || nb_symb_srs == 4, + "number of srs symbols %d is not 1,2,4\n", + nb_symb_srs); + nb_symb_srs >>= 2; // Value: 0 = 1 symbol, 1 = 2 symbols, 2 = 4 symbols + break; + + case 'c': + n_rnti = atoi(optarg); + AssertFatal(n_rnti > 0 && n_rnti <= 65535, "Illegal n_rnti %x\n", n_rnti); + break; + + case 'd': + delay = atoi(optarg); + break; + + case 'e': + srs_comb_size = atoi(optarg); + AssertFatal(srs_comb_size >= 0 && srs_comb_size < 2, "comb_size %d is not in 0 or 1\n", srs_comb_size); + break; + + case 'f': + srs_comb_offset = atoi(optarg); + if (srs_comb_size == 0) { + AssertFatal(srs_comb_offset >= 0 && srs_comb_offset <= 1, "comb_offset %d is not in 0...1\n", srs_comb_offset); + } else if (srs_comb_size == 1) { + AssertFatal(srs_comb_offset >= 0 && srs_comb_offset <= 3, "comb_offset %d is not in 0...3\n", srs_comb_offset); + } + break; + + case 'g': + + switch ((char)*optarg) { + case 'A': + channel_model = TDL_A; + DS_TDL = 0.030; // 30 ns + printf("Channel model: TDLA30\n"); + break; + case 'B': + channel_model = TDL_B; + DS_TDL = 0.100; // 100ns + printf("Channel model: TDLB100\n"); + break; + case 'C': + channel_model = TDL_C; + DS_TDL = 0.300; // 300 ns + printf("Channel model: TDLC300\n"); + break; + default: + printf("Unsupported channel model!\n"); + exit(-1); + } + + if (optarg[1] == ',') { + switch (optarg[2]) { + case 'l': + corr_level = CORR_LEVEL_LOW; + break; + case 'm': + corr_level = CORR_LEVEL_MEDIUM; + break; + case 'h': + corr_level = CORR_LEVEL_HIGH; + break; + default: + printf("Invalid correlation level!\n"); + } + } + + if (optarg[3] == ',') { + maxDoppler = atoi(&optarg[4]); + printf("Maximum Doppler Frequency: %.0f Hz\n", maxDoppler); + } + break; + + case 'i': + srs_cyclic_shift = atoi(optarg); + if (srs_comb_size == 0) { + AssertFatal(srs_cyclic_shift >= 0 && srs_cyclic_shift <= 7, "comb_shift %d is not in 0...7\n", srs_cyclic_shift); + } else if (srs_comb_size == 1) { + AssertFatal(srs_cyclic_shift >= 0 && srs_cyclic_shift <= 11, "comb_shift %d is not in 0...11\n", srs_cyclic_shift); + } + break; + + case 'k': + printf("Setting threequarter_fs_flag\n"); + threequarter_fs = 1; + break; + + case 'n': + n_trials = atoi(optarg); + break; + + case 'p': + extended_prefix_flag = 1; + break; + + case 's': + snr0 = atof(optarg); + printf("Setting SNR0 to %f\n", snr0); + break; + + case 'u': + mu = atoi(optarg); + break; + + case 'y': + n_tx = atoi(optarg); + if ((n_tx == 0) || (n_tx > 4)) { + printf("Unsupported number of tx antennas %d\n", n_tx); + exit(-1); + } + break; + + case 'z': + n_rx = atoi(optarg); + if ((n_rx == 0) || (n_rx > 8)) { + printf("Unsupported number of rx antennas %d\n", n_rx); + exit(-1); + } + break; + + case 'H': + slot = atoi(optarg); + break; + + case 'R': + N_RB_DL = atoi(optarg); + N_RB_UL = N_RB_DL; + break; + + case 'S': + snr1 = atof(optarg); + snr1set = 1; + printf("Setting SNR1 to %f\n", snr1); + break; + + case 'P': + print_perf = 1; + cpu_meas_enabled = 1; + break; + + case 'L': + loglvl = atoi(optarg); + break; + + default: + case 'h': + printf("%s -h(elp)\n", argv[0]); + printf("-a SRS starting symbol (8 .. 13)\n"); + printf("-b SRS number of symbols (1, 2, 4)\n"); + printf("-c RNTI\n"); + printf("-d Introduce delay in terms of number of samples\n"); + printf("-e SRS comb size, 0 (comb size 2), 1 (comb size 4) \n"); + printf("-f SRS comb offset, 0 .. 1 (comb size 2), 0 .. 3 (comb size 4) \n"); + printf( + "-g Channel model configuration. Arguments list: Number of arguments = 3, {Channel model: [A] TDLA30, [B] TDLB100, [C] " + "TDLC300}, {Correlation: [l] Low, [m] Medium, [h] High}, {Maximum Doppler shift} e.g. -g A,l,10\n"); + printf("-h This message\n"); + printf("-i SRS cyclic shift, 0 .. 7 (comb size 2), 0 .. 11 (comb size 4) \n"); + printf("-k 3/4 sampling\n"); + printf("-n Number of trials to simulate\n"); + printf("-p Use extended prefix mode\n"); + printf("-s Starting SNR, runs from SNR0 to SNR0 + 10 dB if ending SNR isn't given\n"); + printf("-S Ending SNR, runs from SNR0 to SNR1\n"); + printf("-u Set the numerology\n"); + printf("-y Number of TX antennas used at UE\n"); + printf("-z Number of RX antennas used at gNB\n"); + printf("-H Slot number\n"); + printf("-L \n"); + printf("-P Print SRS performances\n"); + printf("-R Maximum number of available resorce blocks (N_RB_DL)\n"); + exit(-1); + break; + } + } + + logInit(); + set_glog(loglvl); + + int ret = 1; + + if (snr1set == 0) + snr1 = snr0 + 10; + + double sampling_rate, tx_bandwidth, rx_bandwidth; + uint32_t samples; + get_samplerate_and_bw(mu, N_RB_DL, threequarter_fs, &sampling_rate, &samples, &tx_bandwidth, &rx_bandwidth); + + // Initialize gNB + gNB = calloc_or_fail(1, sizeof(PHY_VARS_gNB)); + gNB->ofdm_offset_divisor = UINT_MAX; + gNB->RU_list[0] = calloc_or_fail(1, sizeof(**gNB->RU_list)); + gNB->RU_list[0]->rfdevice.openair0_cfg = openair0_cfg; + + NR_DL_FRAME_PARMS *fp = &gNB->frame_parms; + fp->N_RB_DL = N_RB_DL; + fp->N_RB_UL = N_RB_UL; + fp->Ncp = extended_prefix_flag ? EXTENDED : NORMAL; + fp->nb_antennas_tx = n_tx; + fp->nb_antennas_rx = n_rx; + fp->threequarter_fs = threequarter_fs; + nr_phy_config_request_sim(gNB, N_RB_UL, N_RB_UL, mu, Nid_cell, SSB_positions); + printf("dl freq %" PRIu64 " , ul freq %" PRIu64 " \n", fp->dl_CarrierFreq, fp->ul_CarrierFreq); + do_tdd_config_sim(gNB, mu); + phy_init_nr_gNB(gNB); + + // Initialize UE + UE = calloc_or_fail(1, sizeof(PHY_VARS_NR_UE)); + memcpy(&UE->frame_parms, fp, sizeof(NR_DL_FRAME_PARMS)); // setting same frame parameters as gNB + + /* RU handles rxdataF, and gNB just has a pointer. Here, we don't have an RU, + * so we need to allocate that memory as well. First index in rxdataF[0] index refers to beams*/ + for (i = 0; i < n_rx; i++) + gNB->common_vars.rxdataF[0][i] = malloc16_clear(fp->samples_per_frame_wCP * sizeof(int32_t)); + + /* no RU: need to have rxdata */ + c16_t **rxdata; + rxdata = malloc_or_fail(n_rx * sizeof(*rxdata)); + for (i = 0; i < n_rx; i++) + rxdata[i] = malloc16_clear(fp->samples_per_frame * sizeof(c16_t)); + + /* no memory allocated for UE common_vars: need to have txdata and txdataF */ + c16_t **txdata; + txdata = malloc_or_fail(n_tx * sizeof(*txdata)); + for (i = 0; i < n_tx; i++) + txdata[i] = malloc16_clear(fp->samples_per_frame * sizeof(c16_t)); + + c16_t **txdataF; + txdataF = malloc_or_fail(n_tx * sizeof(*txdataF)); + for (i = 0; i < n_tx; i++) + txdataF[i] = malloc16_clear(fp->samples_per_frame_wCP * sizeof(c16_t)); + + // Configure channel model + UE2gNB = new_channel_desc_scm(n_tx, + n_rx, + channel_model, + sampling_rate / 1e6, + fp->ul_CarrierFreq, + tx_bandwidth, + DS_TDL, + maxDoppler, + corr_level, + 0, + delay, + 0, + 0); + + if (UE2gNB == NULL) { + printf("Problem generating channel model. Exiting.\n"); + exit(-1); + } + + // Allocate memory to intermediate variables to apply channel + int slot_length = get_samples_per_slot(slot, fp); + + s_re = malloc_or_fail(n_tx * sizeof(double *)); + s_im = malloc_or_fail(n_tx * sizeof(double *)); + r_re = malloc_or_fail(n_rx * sizeof(double *)); + r_im = malloc_or_fail(n_rx * sizeof(double *)); + + for (int aatx = 0; aatx < n_tx; aatx++) { + s_re[aatx] = calloc_or_fail(1, slot_length * sizeof(double)); + s_im[aatx] = calloc_or_fail(1, slot_length * sizeof(double)); + } + + for (int aarx = 0; aarx < n_rx; aarx++) { + r_re[aarx] = calloc_or_fail(1, slot_length * sizeof(double)); + r_im[aarx] = calloc_or_fail(1, slot_length * sizeof(double)); + } + + //----------- configure SRS ---------------------------- + long locationAndBandwidth = PRBalloc_to_locationandbandwidth(N_RB_DL, 0); + + // Configure SRS parameters at gNB + const uint16_t m_SRS[64] = {4, 8, 12, 16, 16, 20, 24, 24, 28, 32, 36, 40, 48, 48, 52, 56, + 60, 64, 72, 72, 76, 80, 88, 96, 96, 104, 112, 120, 120, 120, 128, 128, + 128, 132, 136, 144, 144, 144, 144, 152, 160, 160, 160, 168, 176, 184, 192, 192, + 192, 192, 208, 216, 224, 240, 240, 240, 240, 256, 256, 256, 264, 272, 272, 272}; + nfapi_nr_srs_pdu_t srs_pdu = {.rnti = n_rnti, + .bwp_size = NRRIV2BW(locationAndBandwidth, 275), + .bwp_start = NRRIV2PRBOFFSET(locationAndBandwidth, 275), + .subcarrier_spacing = fp->numerology_index, + .cyclic_prefix = extended_prefix_flag, + .num_ant_ports = n_tx == 4 ? 2 + : n_tx == 2 ? 1 + : 0, + .num_symbols = nb_symb_srs, + .num_repetitions = 0, // Value: 0 = 1, 1 = 2, 2 = 4 + .time_start_position = fp->symbols_per_slot - 1 - srs_start_symbol, + .bandwidth_index = 0, + .config_index = rrc_get_max_nr_csrs(srs_pdu.bwp_size, srs_pdu.bandwidth_index), + .sequence_id = 40, + .comb_size = srs_comb_size, + .comb_offset = srs_comb_offset, + .cyclic_shift = srs_cyclic_shift, + .frequency_position = 0, + .frequency_shift = 0, + .frequency_hopping = 0, + .group_or_sequence_hopping = 0, + .resource_type = NR_SRS_Resource__resourceType_PR_periodic, + .t_srs = 1, + .t_offset = 0, + .srs_parameters_v4.srs_bandwidth_size = m_SRS[srs_pdu.config_index], + .srs_parameters_v4.usage = 1 << NR_SRS_ResourceSet__usage_codebook, + .srs_parameters_v4.report_type[0] = 1, + .srs_parameters_v4.iq_representation = 1, + .srs_parameters_v4.prg_size = 1, + .srs_parameters_v4.num_total_ue_antennas = 1 << srs_pdu.num_ant_ports, + .beamforming.num_prgs = m_SRS[srs_pdu.config_index], + .beamforming.prg_size = 1}; + + gNB->srs->srs_pdu = srs_pdu; + gNB->srs->active = true; + gNB->srs->beam_nb = 0; + gNB->srs->frame = frame; + gNB->srs->slot = slot; + + // Configure SRS parameters at UE + fapi_nr_ul_config_srs_pdu srs_config_pdu = {.rnti = srs_pdu.rnti, + .bwp_size = srs_pdu.bwp_size, + .bwp_start = srs_pdu.bwp_start, + .subcarrier_spacing = srs_pdu.subcarrier_spacing, + .cyclic_prefix = srs_pdu.cyclic_prefix, + .num_ant_ports = srs_pdu.num_ant_ports, + .num_symbols = srs_pdu.num_symbols, + .num_repetitions = srs_pdu.num_repetitions, + .time_start_position = srs_pdu.time_start_position, + .bandwidth_index = srs_pdu.bandwidth_index, + .config_index = srs_pdu.config_index, + .sequence_id = srs_pdu.sequence_id, + .comb_size = srs_pdu.comb_size, + .comb_offset = srs_pdu.comb_offset, + .cyclic_shift = srs_pdu.cyclic_shift, + .frequency_position = srs_pdu.frequency_position, + .frequency_shift = srs_pdu.frequency_shift, + .frequency_hopping = srs_pdu.frequency_hopping, + .group_or_sequence_hopping = srs_pdu.group_or_sequence_hopping, + .resource_type = srs_pdu.resource_type, + .t_srs = srs_pdu.t_srs, + .t_offset = srs_pdu.t_offset, + .beamforming.num_prgs = srs_pdu.beamforming.num_prgs, + .beamforming.prg_size = srs_pdu.beamforming.prg_size}; + + nr_phy_data_tx_t phy_data = {0}; + phy_data.srs_vars.active = true; + phy_data.srs_vars.srs_config_pdu = srs_config_pdu; + UE->nr_srs_info = malloc16_clear(sizeof(nr_srs_info_t)); + + //----------- UE TX SRS procedures --------------------- + + UE_nr_rxtx_proc_t proc; + proc.frame_rx = frame; + proc.frame_tx = frame; + proc.nr_slot_tx = slot; + proc.nr_slot_rx = slot; + bool was_symbol_used[NR_NUMBER_OF_SYMBOLS_PER_SLOT] = {0}; + int slot_offset = get_samples_slot_timestamp(fp, slot); + uint16_t ofdm_symbol_size = fp->ofdm_symbol_size; + int slot_offsetF = (slot % RU_RX_SLOT_DEPTH) * NR_SYMBOLS_PER_SLOT * ofdm_symbol_size; + + c16_t *txF[fp->nb_antennas_tx]; + for (i = 0; i < fp->nb_antennas_tx; i++) + txF[i] = txdataF[i] + slot_offsetF; + + ue_srs_procedures_nr(UE, &proc, (c16_t **)txF, &phy_data, was_symbol_used); + + //------------ TX rotation and OFDM Modulation -------------------------- + + for (int aa = 0; aa < fp->nb_antennas_tx; aa++) { + apply_nr_rotation_TX(fp, &txF[aa][0], fp->symbol_rotation[1], slot, fp->N_RB_UL, 0, fp->Ncp == EXTENDED ? 12 : 14); + if (srs_pdu.cyclic_prefix == 1) { + for (i = 0; i < NR_NUMBER_OF_SYMBOLS_PER_SLOT_EXTENDED_CP; i++) { + if (was_symbol_used[i] == true) { + PHY_ofdm_mod((int *)&txF[aa][0], + (int *)&txdata[aa][slot_offset + (ofdm_symbol_size + fp->nb_prefix_samples) * i], + ofdm_symbol_size, + 1, + fp->nb_prefix_samples, + CYCLIC_PREFIX); + } + } + } else { + nr_normal_prefix_mod(&txF[aa][0], &txdata[aa][slot_offset], fp->symbols_per_slot, fp, slot, was_symbol_used); + } + } + + //----------- Apply propagation channel and add noise ---------------------------- + + double ts = 1.0 / (fp->subcarrier_spacing * ofdm_symbol_size); + + for (i = 0; i < slot_length; i++) { + for (int aa = 0; aa < UE->frame_parms.nb_antennas_tx; aa++) { + s_re[aa][i] = (double)txdata[aa][slot_offset + i].r; + s_im[aa][i] = (double)txdata[aa][slot_offset + i].i; + } + } + + // Compute SRS symbol offset + int symbol_offset = slot_offset; + int abs_first_symbol = slot * fp->symbols_per_slot; + int idx_sym; + for (idx_sym = abs_first_symbol; idx_sym < abs_first_symbol + srs_pdu.time_start_position; idx_sym++) + symbol_offset += (idx_sym % (0x7 << fp->numerology_index)) ? fp->nb_prefix_samples : fp->nb_prefix_samples0; + + symbol_offset += ofdm_symbol_size * srs_pdu.time_start_position; + + // Compute transmitter level + txlev_sum = 0; + for (int aa = 0; aa < UE->frame_parms.nb_antennas_tx; aa++) { + atxlev[aa] = signal_energy( + (int32_t *)&txdata[aa][symbol_offset], + ofdm_symbol_size + (idx_sym % (0x7 << fp->numerology_index)) ? fp->nb_prefix_samples : fp->nb_prefix_samples0); + + txlev_sum += atxlev[aa]; + + if (n_trials == 1) + printf("txlev[%d] = %d (%f dB) txlev_sum %d\n", aa, atxlev[aa], 10 * log10((double)atxlev[aa]), txlev_sum); + } + + for (SNR = snr0; SNR <= snr1 && !stop; SNR += snr_step) { + varArray_t *table_rx = initVarArray(1000, sizeof(double)); + reset_meas(&gNB->rx_srs_stats); + reset_meas(&gNB->generate_srs_stats); + reset_meas(&gNB->get_srs_signal_stats); + reset_meas(&gNB->srs_channel_estimation_stats); + reset_meas(&gNB->srs_timing_advance_stats); + + sum_srs_snr = 0; + for (trial = 0; trial < n_trials && !stop; trial++) { + // Estimate noise power from the transmitter level and SNR + sigma_dB = 10 * log10(((double)txlev_sum) * ((double)ofdm_symbol_size / (12 * srs_pdu.bwp_size))) - SNR; + sigma = pow(10, sigma_dB / 10); + + if (n_trials == 1) + printf("sigma %f (%f dB), txlev_sum %f (factor %f)\n", + sigma, + sigma_dB, + 10 * log10((double)txlev_sum), + (double)(double)ofdm_symbol_size / (12 * srs_pdu.bwp_size)); + + //----------- Apply propagation channel ---------------------------- + multipath_channel(UE2gNB, s_re, s_im, r_re, r_im, slot_length, 0, (n_trials == 1) ? 1 : 0); + + //----------- Add noise ---------------------------- + add_noise(rxdata, + (const double **)r_re, + (const double **)r_im, + sigma, + slot_length, + slot_offset, + ts, + 0, // delay + 0, // pdu_bit_map + 0, // PTRS_BITMAP, + fp->nb_antennas_rx); + + //----------- OFDM Demodulation and RX rotation-------------------------- + + for (uint8_t symbol = 0; symbol < (fp->Ncp == EXTENDED ? 12 : 14); symbol++) { + for (int aa = 0; aa < fp->nb_antennas_rx; aa++) + nr_slot_fep_ul(fp, (int32_t *)&rxdata[aa][0], (int32_t *)&gNB->common_vars.rxdataF[0][aa][slot_offsetF], symbol, slot, 0); + } + + for (int aa = 0; aa < fp->nb_antennas_rx; aa++) { + for (uint8_t symbol = 0; symbol < fp->symbols_per_slot; symbol++) { + if (was_symbol_used[symbol] == true) { + apply_nr_rotation_symbol_RX(fp, + &gNB->common_vars.rxdataF[0][aa][slot_offsetF + symbol * fp->ofdm_symbol_size], + fp->symbol_rotation[1], + fp->N_RB_UL, + slot, + symbol); + } + } + } + + //----------- UE RX SRS procedures --------------------- + + start_meas(&gNB->rx_srs_stats); + NR_gNB_SRS_t *srs = &gNB->srs[0]; + uint8_t N_symb_SRS = 1 << srs->srs_pdu.num_symbols; + uint8_t N_ap = 1 << srs->srs_pdu.num_ant_ports; + uint8_t nb_antennas_rx = fp->nb_antennas_rx; + int16_t snr_per_rb[srs->srs_pdu.bwp_size]; + int srs_est; + c16_t srs_estimated_channel_freq[nb_antennas_rx][N_ap][ofdm_symbol_size * N_symb_SRS] __attribute__((aligned(32))); + c16_t srs_estimated_channel_time[nb_antennas_rx][N_ap][ofdm_symbol_size] __attribute__((aligned(32))); + + nr_srs_rx_procedures(gNB, + frame, + slot, + nb_antennas_rx, + N_ap, + N_symb_SRS, + ofdm_symbol_size, + srs, + gNB->nr_srs_info[0], + &srs_est, + srs_estimated_channel_freq, + srs_estimated_channel_time, + snr_per_rb); + + start_meas(&gNB->srs_timing_advance_stats); + nr_est_timing_advance_srs(fp, srs_estimated_channel_time[0]); + stop_meas(&gNB->srs_timing_advance_stats); + sum_srs_snr += pow(10, (double)gNB->srs->snr / 10.0); + stop_meas(&gNB->rx_srs_stats); + } // trail loop + sum_srs_snr /= n_trials; + printf("Actual SNR : %f, Estimated SNR from SRS %f (dB)\n", SNR, 10 * log10(sum_srs_snr)); + + if (print_perf == 1) { + printf("\ngNB RX\n"); + printDistribution(&gNB->rx_srs_stats, table_rx, "RX SRS time"); + printStatIndent(&gNB->generate_srs_stats, "Generate SRS sequence time"); + printStatIndent(&gNB->get_srs_signal_stats, "Get SRS signal time"); + printStatIndent(&gNB->srs_channel_estimation_stats, "SRS channel estimation time"); + printStatIndent(&gNB->srs_timing_advance_stats, "SRS timing advance estimation time"); + printf("\n"); + } + + } // SNR loop + + // free memory + + for (i = 0; i < n_tx; i++) { + free(s_re[i]); + free(s_im[i]); + } + for (i = 0; i < n_rx; i++) { + free(r_re[i]); + free(r_im[i]); + } + + free(s_re); + free(s_im); + free(r_re); + free(r_im); + + for (i = 0; i < n_rx; i++) { + free(rxdata[i]); + } + free(rxdata); + + for (i = 0; i < n_tx; i++) { + free(txdata[i]); + } + free(txdata); + + for (i = 0; i < n_tx; i++) { + free(txdataF[i]); + } + free(txdataF); + + phy_free_nr_gNB(gNB); + free_and_zero(UE->nr_srs_info); + free(gNB->RU_list[0]); + free(UE); + + return ret; +} From 1ffb1cfe169abd4ee4fa1b04c16ab2bf9df639ee Mon Sep 17 00:00:00 2001 From: Rakesh Mundlamuri Date: Wed, 22 Oct 2025 16:48:20 +0530 Subject: [PATCH 05/22] Adding testcases to test nr_srssim --- openair1/SIMULATION/tests/CMakeLists.txt | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/openair1/SIMULATION/tests/CMakeLists.txt b/openair1/SIMULATION/tests/CMakeLists.txt index 566028234d..a9fbfec228 100644 --- a/openair1/SIMULATION/tests/CMakeLists.txt +++ b/openair1/SIMULATION/tests/CMakeLists.txt @@ -341,6 +341,21 @@ add_physim_test(physim.5g.nr_prachsim.test8 "15kHz SCS, 25 PRBs" nr_prachsim -a add_physim_test(physim.5g.nr_psbchsim.test1 "SLSS Search" nr_psbchsim -I) add_physim_test(physim.5g.nr_psbchsim.test2 "PSBCH TxRx" nr_psbchsim -n 30) +#################################################################################### +###### nr_srssim unit test ###### +#################################################################################### + +add_physim_test(physim.5g.nr_srssim.test1 "SRS: 30KHz SCS, 106 PRBs, SNR 20 dB, ToA 24, Combsize 2" nr_srssim -n300 -R106 -y2 -z2 -d 24) +add_physim_test(physim.5g.nr_srssim.test2 "SRS: 30KHz SCS, 106 PRBs, SNR 20 dB, ToA 15, Combsize 2, Threequarter sampling" nr_srssim -n300 -R106 -y2 -z2 -d 15 -k) +add_physim_test(physim.5g.nr_srssim.test3 "SRS: 30KHz SCS, 217 PRBs, SNR 20 dB, ToA 8, Combsize 2" nr_srssim -n300 -R217 -y2 -z2 -d 8) +add_physim_test(physim.5g.nr_srssim.test4 "SRS: 30KHz SCS, 273 PRBs, SNR 20 dB, TOA 30, Combsize 2" nr_srssim -n300 -R273 -y2 -z2 -d 30) +add_physim_test(physim.5g.nr_srssim.test5 "SRS: 30KHz SCS, 106 PRBs, SNR 20 dB, ToA 16, Combsize 2, Cyclic shift 3" nr_srssim -n300 -R106 -y2 -z2 -d 16 -i 1) +add_physim_test(physim.5g.nr_srssim.test6 "SRS: 30KHz SCS, 106 PRBs, SNR 20 dB, ToA 23, Combsize 2, Comb offset 1" nr_srssim -n300 -R106 -y2 -z2 -d 23 -f 1) +add_physim_test(physim.5g.nr_srssim.test7 "SRS: 30KHz SCS, 106 PRBs, SNR 20 dB, ToA 8, Combsize 2, Symbol start 9" nr_srssim -n300 -R106 -y2 -z2 -d 8 -a 9) +add_physim_test(physim.5g.nr_srssim.test8 "SRS: 120KHz SCS, 32 PRBs, SNR 20 dB, ToA 19, Combsize 2" nr_srssim -n300 -R32 -y2 -z2 -d 19 -u 3) +add_physim_test(physim.5g.nr_srssim.test9 "SRS: 30KHz SCS, 106 PRBs, SNR 20 dB, ToA 11, Combsize 4" nr_srssim -n300 -R106 -y2 -z2 -d 11 -e 1) +add_physim_test(physim.5g.nr_srssim.test10 "SRS: 30KHz SCS, 106 PRBs, SNR 20 dB, ToA 7, Combsize 4, Comb offset 1" nr_srssim -n300 -R106 -y2 -z2 -d 7 -e 1 -f 1) + #################################################################################### ###### offload-specific tests ###### #################################################################################### From a5a09676adf3317f70b37e9e852c80aac79e14a7 Mon Sep 17 00:00:00 2001 From: Rakesh Mundlamuri Date: Wed, 22 Oct 2025 18:52:36 +0530 Subject: [PATCH 06/22] rewrite nr_srs_channel_estimation() to loop over rx antennas and antenna ports to be able to parallelize --- .../NR_ESTIMATION/nr_ul_channel_estimation.c | 170 ++++++++---------- openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h | 31 ++-- openair1/SCHED_NR/phy_procedures_nr_gNB.c | 51 ++++-- 3 files changed, 132 insertions(+), 120 deletions(-) diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c index d73a315354..ae91f637fb 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c +++ b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c @@ -769,21 +769,22 @@ void nr_pusch_ptrs_processing(PHY_VARS_gNB *gNB, } // Antenna loop } -int nr_srs_channel_estimation( - const PHY_VARS_gNB *gNB, - const int frame, - const int slot, - const nfapi_nr_srs_pdu_t *srs_pdu, - const nr_srs_info_t *nr_srs_info, - const c16_t **srs_generated_signal, - c16_t srs_received_signal[][gNB->frame_parms.ofdm_symbol_size * (1 << srs_pdu->num_symbols)], - c16_t srs_received_noise[][gNB->frame_parms.ofdm_symbol_size * (1 << srs_pdu->num_symbols)], - c16_t srs_estimated_channel_freq[][1 << srs_pdu->num_ant_ports] - [gNB->frame_parms.ofdm_symbol_size * (1 << srs_pdu->num_symbols)], - c16_t srs_estimated_channel_time[][1 << srs_pdu->num_ant_ports][gNB->frame_parms.ofdm_symbol_size], - c16_t srs_estimated_channel_time_shifted[][1 << srs_pdu->num_ant_ports][gNB->frame_parms.ofdm_symbol_size], - int16_t *snr_per_rb, - int8_t *snr) +int nr_srs_channel_estimation(const PHY_VARS_gNB *gNB, + const int frame, + const int slot, + const int ant, + const int p_index, + const nfapi_nr_srs_pdu_t *srs_pdu, + const nr_srs_info_t *nr_srs_info, + const c16_t *srs_generated_signal, + c16_t srs_received_signal[gNB->frame_parms.ofdm_symbol_size * (1 << srs_pdu->num_symbols)], + c16_t srs_received_noise[gNB->frame_parms.ofdm_symbol_size * (1 << srs_pdu->num_symbols)], + c16_t srs_estimated_channel_freq[gNB->frame_parms.ofdm_symbol_size * (1 << srs_pdu->num_symbols)], + c16_t srs_estimated_channel_time[gNB->frame_parms.ofdm_symbol_size], + c16_t srs_estimated_channel_time_shifted[gNB->frame_parms.ofdm_symbol_size], + uint32_t *signal_power, + uint32_t *noise_power, + int16_t *noise_power_per_rb) { #ifdef SRS_DEBUG LOG_I(NR_PHY, "Calling %s function\n", __FUNCTION__); @@ -802,7 +803,7 @@ int nr_srs_channel_estimation( } c16_t srs_ls_estimated_channel[frame_parms->ofdm_symbol_size * (1 << srs_pdu->num_symbols)]; - uint8_t mem_offset = ((16 - ((intptr_t)&srs_estimated_channel_freq[0][0][subcarrier_offset + nr_srs_info->k_0_p[0][0]])) & 0xF) + uint8_t mem_offset = ((16 - ((intptr_t)&srs_estimated_channel_freq[subcarrier_offset + nr_srs_info->k_0_p[p_index][0]])) & 0xF) >> 2; // >> 2 <=> /sizeof(int32_t) // filt16_end is {4096,8192,8192,8192,12288,16384,16384,16384,0,0,0,0,0,0,0,0} @@ -812,8 +813,6 @@ int nr_srs_channel_estimation( c16_t srs_est[frame_parms->ofdm_symbol_size * (1 << srs_pdu->num_symbols) + mem_offset + 8] __attribute__((aligned(32))); c16_t ls_estimated = {0}; - for (int ant = 0; ant < frame_parms->nb_antennas_rx; ant++) { - for (int p_index = 0; p_index < N_ap; p_index++) { memset(srs_ls_estimated_channel, 0, frame_parms->ofdm_symbol_size * (1 << srs_pdu->num_symbols) * sizeof(c16_t)); memset(srs_est, 0, (frame_parms->ofdm_symbol_size * (1 << srs_pdu->num_symbols) + mem_offset) * sizeof(c16_t)); @@ -834,8 +833,8 @@ int nr_srs_channel_estimation( uint16_t subcarrier_cdm = subcarrier; for (int cdm_idx = 0; cdm_idx < fd_cdm; cdm_idx++) { - c16_t generated_srs = srs_generated_signal[p_index][subcarrier_cdm]; - c16_t received_srs = srs_received_signal[ant][subcarrier_cdm]; + c16_t generated_srs = srs_generated_signal[subcarrier_cdm]; + c16_t received_srs = srs_received_signal[subcarrier_cdm]; // We know that nr_srs_info->srs_generated_signal_bits bits are enough to represent the real and imaginary parts of // generated_srs. So we only need a nr_srs_info->srs_generated_signal_bits shift to ensure that the result fits into 16 // bits. @@ -863,10 +862,10 @@ int nr_srs_channel_estimation( LOG_I(NR_PHY, "(%4i) %6i\t%6i | %6i\t%6i | %6i\t%6i\n", subcarrier_log, - srs_generated_signal[p_index][subcarrier].r, - srs_generated_signal[p_index][subcarrier].i, - srs_received_signal[ant][subcarrier].r, - srs_received_signal[ant][subcarrier].i, + srs_generated_signal[subcarrier].r, + srs_generated_signal[subcarrier].i, + srs_received_signal[subcarrier].r, + srs_received_signal[subcarrier].i, ls_estimated.r, ls_estimated.i); #endif @@ -923,7 +922,7 @@ int nr_srs_channel_estimation( } // for (int k = 0; k < M_sc_b_SRS; k++) - memcpy(srs_estimated_channel_freq[ant][p_index], + memcpy(srs_estimated_channel_freq, &srs_est[mem_offset], (frame_parms->ofdm_symbol_size * (1 << srs_pdu->num_symbols)) * sizeof(c16_t)); @@ -949,10 +948,10 @@ int nr_srs_channel_estimation( subcarrier_log, srs_ls_estimated_channel[subcarrier].r, srs_ls_estimated_channel[subcarrier].i, - srs_estimated_channel_freq[ant][p_index][subcarrier].r, - srs_estimated_channel_freq[ant][p_index][subcarrier].i, - srs_received_noise[ant][subcarrier].r, - srs_received_noise[ant][subcarrier].i); + srs_estimated_channel_freq[subcarrier].r, + srs_estimated_channel_freq[subcarrier].i, + srs_received_noise[subcarrier].r, + srs_received_noise[subcarrier].i); // Subcarrier increment subcarrier++; @@ -963,83 +962,70 @@ int nr_srs_channel_estimation( #endif // Convert to time domain - freq2time(gNB->frame_parms.ofdm_symbol_size, - (int16_t *)srs_estimated_channel_freq[ant][p_index], - (int16_t *)srs_estimated_channel_time[ant][p_index]); + freq2time(gNB->frame_parms.ofdm_symbol_size, (int16_t *)srs_estimated_channel_freq, (int16_t *)srs_estimated_channel_time); - memcpy(srs_estimated_channel_time_shifted[ant][p_index], - &srs_estimated_channel_time[ant][p_index][gNB->frame_parms.ofdm_symbol_size >> 1], + memcpy(srs_estimated_channel_time_shifted, + &srs_estimated_channel_time[gNB->frame_parms.ofdm_symbol_size >> 1], (gNB->frame_parms.ofdm_symbol_size >> 1) * sizeof(c16_t)); - memcpy(&srs_estimated_channel_time_shifted[ant][p_index][gNB->frame_parms.ofdm_symbol_size >> 1], - srs_estimated_channel_time[ant][p_index], + memcpy(&srs_estimated_channel_time_shifted[gNB->frame_parms.ofdm_symbol_size >> 1], + srs_estimated_channel_time, (gNB->frame_parms.ofdm_symbol_size >> 1) * sizeof(c16_t)); - } // for (int p_index = 0; p_index < N_ap; p_index++) - } // for (int ant = 0; ant < frame_parms->nb_antennas_rx; ant++) - - // Compute wideband SNR - int tot_subcarriers = m_SRS_b * NR_NB_SC_PER_RB; - uint32_t signal_power = 0; - uint32_t noise_power = 0; - for (int ant = 0; ant < frame_parms->nb_antennas_rx; ant++) { - for (int p_index = 0; p_index < N_ap; p_index++) { - uint16_t subcarrier0 = subcarrier_offset + nr_srs_info->k_0_p[p_index][0]; - if (subcarrier0 >= frame_parms->ofdm_symbol_size) { - subcarrier0 -= frame_parms->ofdm_symbol_size; + // Compute wideband SNR + int tot_subcarriers = m_SRS_b * NR_NB_SC_PER_RB; + subcarrier = subcarrier_offset + nr_srs_info->k_0_p[p_index][0]; + if (subcarrier >= frame_parms->ofdm_symbol_size) { + subcarrier -= frame_parms->ofdm_symbol_size; } - if (subcarrier0 + tot_subcarriers < frame_parms->ofdm_symbol_size) { - signal_power += signal_energy_nodc(&srs_estimated_channel_freq[ant][p_index][subcarrier0], tot_subcarriers); - if (p_index == 0) - noise_power += signal_energy_nodc(&srs_received_noise[ant][subcarrier0], tot_subcarriers); - } else { - int size1 = frame_parms->ofdm_symbol_size - subcarrier0; - int size2 = tot_subcarriers - size1; - uint64_t signal_power_p1 = signal_energy_nodc(&srs_estimated_channel_freq[ant][p_index][subcarrier0], size1) * size1; - uint64_t signal_power_p2 = signal_energy_nodc(&srs_estimated_channel_freq[ant][p_index][0], size2) * size2; - signal_power += (signal_power_p1 + signal_power_p2) / tot_subcarriers; + if (subcarrier + tot_subcarriers < frame_parms->ofdm_symbol_size) { + *signal_power = signal_energy_nodc(&srs_estimated_channel_freq[subcarrier], tot_subcarriers) / tot_subcarriers; if (p_index == 0) { - uint64_t noise_power_p1 = signal_energy_nodc(&srs_received_noise[ant][subcarrier0], size1) * size1; - uint64_t noise_power_p2 = signal_energy_nodc(&srs_received_noise[ant][0], size2) * size2; - noise_power += (noise_power_p1 + noise_power_p2) / tot_subcarriers; + *noise_power = signal_energy_nodc(&srs_received_noise[subcarrier], tot_subcarriers) / tot_subcarriers; } - } - } - } - signal_power = max(signal_power / (frame_parms->nb_antennas_rx * N_ap), 1); - noise_power = max(noise_power / (frame_parms->nb_antennas_rx), 1); - if (signal_power == 0) { - LOG_W(NR_PHY, "Received SRS signal power is 0\n"); - return -1; - } - *snr = dB_fixed(signal_power) - dB_fixed(noise_power); - - // Compute SNR per RB - uint16_t subcarrier = subcarrier_offset + nr_srs_info->k_0_p[0][0]; - for (int rb = 0; rb < m_SRS_b; rb++) { - if (subcarrier >= frame_parms->ofdm_symbol_size) { - subcarrier -= frame_parms->ofdm_symbol_size; - } - uint32_t noise_power_per_rb = 0; - for (int ant = 0; ant < frame_parms->nb_antennas_rx; ant++) { - if (subcarrier + NR_NB_SC_PER_RB < frame_parms->ofdm_symbol_size) { - noise_power_per_rb += signal_energy_nodc(&srs_received_noise[ant][subcarrier], NR_NB_SC_PER_RB); } else { int size1 = frame_parms->ofdm_symbol_size - subcarrier; - int size2 = NR_NB_SC_PER_RB - size1; - uint32_t noise_power_per_rb1 = signal_energy_nodc(&srs_received_noise[ant][subcarrier], size1) * size1; - uint32_t noise_power_per_rb2 = signal_energy_nodc(&srs_received_noise[ant][0], size2) * size2; - noise_power_per_rb += (noise_power_per_rb1 + noise_power_per_rb2) / NR_NB_SC_PER_RB; + int size2 = tot_subcarriers - size1; + uint64_t signal_power_p1 = signal_energy_nodc(&srs_estimated_channel_freq[subcarrier], size1) * size1; + uint64_t signal_power_p2 = signal_energy_nodc(&srs_estimated_channel_freq[0], size2) * size2; + *signal_power = (signal_power_p1 + signal_power_p2) / tot_subcarriers; + if (p_index == 0) { + uint64_t noise_power_p1 = signal_energy_nodc(&srs_received_noise[subcarrier], size1) * size1; + uint64_t noise_power_p2 = signal_energy_nodc(&srs_received_noise[0], size2) * size2; + *noise_power = (noise_power_p1 + noise_power_p2) / tot_subcarriers; + } } - } - noise_power_per_rb = max(noise_power_per_rb / (frame_parms->nb_antennas_rx), 1); - snr_per_rb[rb] = dB_fixed(signal_power) - dB_fixed(noise_power_per_rb); - subcarrier += NR_NB_SC_PER_RB; + + *signal_power = max(*signal_power, 1); + if (*signal_power == 0) { + LOG_W(NR_PHY, "Received SRS signal power is 0\n"); + return -1; + } + + // Compute SNR per RB for port 0 + if (p_index == 0) { + subcarrier = subcarrier_offset + nr_srs_info->k_0_p[p_index][0]; + for (int rb = 0; rb < m_SRS_b; rb++) { + if (subcarrier >= frame_parms->ofdm_symbol_size) { + subcarrier -= frame_parms->ofdm_symbol_size; + } + if (subcarrier + NR_NB_SC_PER_RB < frame_parms->ofdm_symbol_size) { + noise_power_per_rb[rb] += signal_energy_nodc(&srs_received_noise[subcarrier], NR_NB_SC_PER_RB); + } else { + int size1 = frame_parms->ofdm_symbol_size - subcarrier; + int size2 = NR_NB_SC_PER_RB - size1; + uint32_t noise_power_per_rb1 = signal_energy_nodc(&srs_received_noise[subcarrier], size1) * size1; + uint32_t noise_power_per_rb2 = signal_energy_nodc(&srs_received_noise[0], size2) * size2; + noise_power_per_rb[rb] += (noise_power_per_rb1 + noise_power_per_rb2) / NR_NB_SC_PER_RB; + } + noise_power_per_rb[rb] = max(noise_power_per_rb[rb], 1); + subcarrier += NR_NB_SC_PER_RB; #ifdef SRS_DEBUG - LOG_I(NR_PHY, "[RB %3i] noise_power_per_rb = %i, snr_per_rb = %i dB\n", rb, noise_power_per_rb, snr_per_rb[rb]); + LOG_I(NR_PHY, "[RB %3i] noise_power_per_rb = %i, snr_per_rb = %i dB\n", rb, noise_power_per_rb, snr_per_rb[rb]); #endif - } + } + } #ifdef SRS_DEBUG LOG_I(NR_PHY, "signal_power = %i dB, noise_power = %i dB, SNR = %i dB\n", dB_fixed(signal_power), dB_fixed(noise_power), *snr); diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h b/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h index 7e0a2a97bd..e503bcf116 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h +++ b/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h @@ -70,21 +70,22 @@ void nr_pusch_ptrs_processing(PHY_VARS_gNB *gNB, unsigned char symbol, uint32_t nb_re_pusch); -int nr_srs_channel_estimation( - const PHY_VARS_gNB *gNB, - const int frame, - const int slot, - const nfapi_nr_srs_pdu_t *srs_pdu, - const nr_srs_info_t *nr_srs_info, - const c16_t **srs_generated_signal, - c16_t srs_received_signal[][gNB->frame_parms.ofdm_symbol_size * (1 << srs_pdu->num_symbols)], - c16_t srs_received_noise[][gNB->frame_parms.ofdm_symbol_size * (1 << srs_pdu->num_symbols)], - c16_t srs_estimated_channel_freq[][1 << srs_pdu->num_ant_ports] - [gNB->frame_parms.ofdm_symbol_size * (1 << srs_pdu->num_symbols)], - c16_t srs_estimated_channel_time[][1 << srs_pdu->num_ant_ports][gNB->frame_parms.ofdm_symbol_size], - c16_t srs_estimated_channel_time_shifted[][1 << srs_pdu->num_ant_ports][gNB->frame_parms.ofdm_symbol_size], - int16_t *snr_per_rb, - int8_t *snr); +int nr_srs_channel_estimation(const PHY_VARS_gNB *gNB, + const int frame, + const int slot, + const int ant, + const int p_index, + const nfapi_nr_srs_pdu_t *srs_pdu, + const nr_srs_info_t *nr_srs_info, + const c16_t *srs_generated_signal, + c16_t srs_received_signal[gNB->frame_parms.ofdm_symbol_size * (1 << srs_pdu->num_symbols)], + c16_t srs_received_noise[gNB->frame_parms.ofdm_symbol_size * (1 << srs_pdu->num_symbols)], + c16_t srs_estimated_channel_freq[gNB->frame_parms.ofdm_symbol_size * (1 << srs_pdu->num_symbols)], + c16_t srs_estimated_channel_time[gNB->frame_parms.ofdm_symbol_size], + c16_t srs_estimated_channel_time_shifted[gNB->frame_parms.ofdm_symbol_size], + uint32_t *signal_power, + uint32_t *noise_power, + int16_t *noise_power_per_rb); void nr_freq_equalization(NR_DL_FRAME_PARMS *frame_parms, c16_t *rxdataF_comp, diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index 69dc6ad3e7..0a4d73df96 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -889,21 +889,46 @@ void nr_srs_rx_procedures(PHY_VARS_gNB *gNB, *srs_est = nr_get_srs_signal(gNB, rxdataF, frame_rx, slot_rx, srs_pdu, nr_srs_info, srs_received_signal, srs_received_noise); stop_meas(&gNB->get_srs_signal_stats); + uint32_t signal_power_avg = 0; + uint32_t noise_power_avg = 0; + int16_t noise_power_per_rb[srs_pdu->bwp_size]; + memset(noise_power_per_rb, 0, srs_pdu->bwp_size * sizeof(int16_t)); + if (*srs_est >= 0) { start_meas(&gNB->srs_channel_estimation_stats); - nr_srs_channel_estimation(gNB, - frame_rx, - slot_rx, - srs_pdu, - nr_srs_info, - (const c16_t **)nr_srs_info->srs_generated_signal, - srs_received_signal, - srs_received_noise, - srs_estimated_channel_freq, - srs_estimated_channel_time, - srs_estimated_channel_time_shifted, - snr_per_rb, - &gNB->srs->snr); + for (int ant_rx_ind = 0; ant_rx_ind < nb_antennas_rx; ant_rx_ind++) { + uint32_t noise_power = 0; + for (int p_ind = 0; p_ind < N_ap; p_ind++) { + uint32_t signal_power = 0; + nr_srs_channel_estimation(gNB, + frame_rx, + slot_rx, + ant_rx_ind, + p_ind, + srs_pdu, + nr_srs_info, + nr_srs_info->srs_generated_signal[p_ind], + srs_received_signal[ant_rx_ind], + srs_received_noise[ant_rx_ind], + srs_estimated_channel_freq[ant_rx_ind][p_ind], + srs_estimated_channel_time[ant_rx_ind][p_ind], + srs_estimated_channel_time_shifted[ant_rx_ind][p_ind], + &signal_power, + &noise_power, + noise_power_per_rb); + signal_power_avg += signal_power; + } + noise_power_avg += noise_power; + } + signal_power_avg /= (nb_antennas_rx * N_ap); + noise_power_avg /= nb_antennas_rx; + signal_power_avg = max(signal_power_avg, 1); + gNB->srs->snr = dB_fixed(signal_power_avg) - dB_fixed(max(noise_power_avg, 1)); + + const uint16_t m_SRS_b = get_m_srs(srs_pdu->config_index, srs_pdu->bandwidth_index); + for (int rb = 0; rb < m_SRS_b; rb++) { + snr_per_rb[rb] = dB_fixed(signal_power_avg) - dB_fixed(max(noise_power_per_rb[rb] / nb_antennas_rx, 1)); + } stop_meas(&gNB->srs_channel_estimation_stats); } From 7846d83b076e9fd3168834df5e285f45fcbb47df Mon Sep 17 00:00:00 2001 From: Rakesh Mundlamuri Date: Wed, 22 Oct 2025 19:11:58 +0530 Subject: [PATCH 07/22] use intermediate variables to improve readability and avoid additional computations --- .../NR_ESTIMATION/nr_ul_channel_estimation.c | 89 +++++++++---------- openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h | 20 ++--- openair1/SCHED_NR/phy_procedures_nr_gNB.c | 12 +-- 3 files changed, 59 insertions(+), 62 deletions(-) diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c index ae91f637fb..5cb60f28b3 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c +++ b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c @@ -769,19 +769,19 @@ void nr_pusch_ptrs_processing(PHY_VARS_gNB *gNB, } // Antenna loop } -int nr_srs_channel_estimation(const PHY_VARS_gNB *gNB, - const int frame, - const int slot, - const int ant, - const int p_index, +int nr_srs_channel_estimation(int ant, + int p_index, + uint16_t ofdm_symbol_size, + uint16_t first_carrier_offset, + uint8_t N_symb_SRS, const nfapi_nr_srs_pdu_t *srs_pdu, const nr_srs_info_t *nr_srs_info, const c16_t *srs_generated_signal, - c16_t srs_received_signal[gNB->frame_parms.ofdm_symbol_size * (1 << srs_pdu->num_symbols)], - c16_t srs_received_noise[gNB->frame_parms.ofdm_symbol_size * (1 << srs_pdu->num_symbols)], - c16_t srs_estimated_channel_freq[gNB->frame_parms.ofdm_symbol_size * (1 << srs_pdu->num_symbols)], - c16_t srs_estimated_channel_time[gNB->frame_parms.ofdm_symbol_size], - c16_t srs_estimated_channel_time_shifted[gNB->frame_parms.ofdm_symbol_size], + c16_t srs_received_signal[ofdm_symbol_size * N_symb_SRS], + c16_t srs_received_noise[ofdm_symbol_size * N_symb_SRS], + c16_t srs_estimated_channel_freq[ofdm_symbol_size * N_symb_SRS], + c16_t srs_estimated_channel_time[ofdm_symbol_size], + c16_t srs_estimated_channel_time_shifted[ofdm_symbol_size], uint32_t *signal_power, uint32_t *noise_power, int16_t *noise_power_per_rb) @@ -790,8 +790,7 @@ int nr_srs_channel_estimation(const PHY_VARS_gNB *gNB, LOG_I(NR_PHY, "Calling %s function\n", __FUNCTION__); #endif - const NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms; - const uint64_t subcarrier_offset = frame_parms->first_carrier_offset + srs_pdu->bwp_start * NR_NB_SC_PER_RB; + const uint64_t subcarrier_offset = first_carrier_offset + srs_pdu->bwp_start * NR_NB_SC_PER_RB; const uint8_t N_ap = 1 << srs_pdu->num_ant_ports; const uint8_t K_TC = 2 << srs_pdu->comb_size; @@ -802,7 +801,7 @@ int nr_srs_channel_estimation(const PHY_VARS_gNB *gNB, fd_cdm = 2; } - c16_t srs_ls_estimated_channel[frame_parms->ofdm_symbol_size * (1 << srs_pdu->num_symbols)]; + c16_t srs_ls_estimated_channel[ofdm_symbol_size * N_symb_SRS]; uint8_t mem_offset = ((16 - ((intptr_t)&srs_estimated_channel_freq[subcarrier_offset + nr_srs_info->k_0_p[p_index][0]])) & 0xF) >> 2; // >> 2 <=> /sizeof(int32_t) @@ -810,19 +809,19 @@ int nr_srs_channel_estimation(const PHY_VARS_gNB *gNB, // The End of OFDM symbol corresponds to the position of last 16384 in the filter // The c16multaddVectRealComplex applies the remaining 8 zeros of filter, therefore, to avoid a buffer overflow, // we added 8 in the array size - c16_t srs_est[frame_parms->ofdm_symbol_size * (1 << srs_pdu->num_symbols) + mem_offset + 8] __attribute__((aligned(32))); + c16_t srs_est[ofdm_symbol_size * N_symb_SRS + mem_offset + 8] __attribute__((aligned(32))); c16_t ls_estimated = {0}; - memset(srs_ls_estimated_channel, 0, frame_parms->ofdm_symbol_size * (1 << srs_pdu->num_symbols) * sizeof(c16_t)); - memset(srs_est, 0, (frame_parms->ofdm_symbol_size * (1 << srs_pdu->num_symbols) + mem_offset) * sizeof(c16_t)); + memset(srs_ls_estimated_channel, 0, ofdm_symbol_size * N_symb_SRS * sizeof(c16_t)); + memset(srs_est, 0, (ofdm_symbol_size * N_symb_SRS + mem_offset) * sizeof(c16_t)); #ifdef SRS_DEBUG LOG_I(NR_PHY, "====================== UE port %d --> gNB Rx antenna %i ======================\n", p_index, ant); #endif uint16_t subcarrier = subcarrier_offset + nr_srs_info->k_0_p[p_index][0]; - if (subcarrier >= frame_parms->ofdm_symbol_size) { - subcarrier -= frame_parms->ofdm_symbol_size; + if (subcarrier >= ofdm_symbol_size) { + subcarrier -= ofdm_symbol_size; } c16_t *srs_estimated_channel16 = &srs_est[subcarrier + mem_offset]; @@ -842,8 +841,8 @@ int nr_srs_channel_estimation(const PHY_VARS_gNB *gNB, // Subcarrier increment subcarrier_cdm += K_TC; - if (subcarrier_cdm >= frame_parms->ofdm_symbol_size) { - subcarrier_cdm = subcarrier_cdm - frame_parms->ofdm_symbol_size; + if (subcarrier_cdm >= ofdm_symbol_size) { + subcarrier_cdm = subcarrier_cdm - ofdm_symbol_size; } } } @@ -853,7 +852,7 @@ int nr_srs_channel_estimation(const PHY_VARS_gNB *gNB, #ifdef SRS_DEBUG int subcarrier_log = subcarrier - subcarrier_offset; if (subcarrier_log < 0) { - subcarrier_log = subcarrier_log + frame_parms->ofdm_symbol_size; + subcarrier_log = subcarrier_log + ofdm_symbol_size; } if (subcarrier_log % 12 == 0) { LOG_I(NR_PHY, "------------------------------------ %d ------------------------------------\n", subcarrier_log / 12); @@ -882,7 +881,7 @@ int nr_srs_channel_estimation(const PHY_VARS_gNB *gNB, srs_estimated_channel16 = &srs_est[subcarrier]; const short *filter = mem_offset == 0 ? filt8_start : filt8_start_shift2; c16multaddVectRealComplex(filter, &ls_estimated, srs_estimated_channel16, 8); - } else if ((subcarrier + K_TC) >= frame_parms->ofdm_symbol_size + } else if ((subcarrier + K_TC) >= ofdm_symbol_size || k == (M_sc_b_SRS - 1)) { // End of OFDM symbol or last subcarrier cases // filt8_end is {4096,8192,12288,16384,0,0,0,0} const short *filter = mem_offset == 0 || k == (M_sc_b_SRS - 1) ? filt8_end : filt8_end_shift2; @@ -903,7 +902,7 @@ int nr_srs_channel_estimation(const PHY_VARS_gNB *gNB, srs_estimated_channel16 = &srs_est[sc_offset]; // filt16_start is {12288,8192,8192,8192,4096,0,0,0,0,0,0,0,0,0,0,0} c16multaddVectRealComplex(filt16_start, &ls_estimated, srs_estimated_channel16, 16); - } else if ((subcarrier + K_TC) >= frame_parms->ofdm_symbol_size + } else if ((subcarrier + K_TC) >= ofdm_symbol_size || k == (M_sc_b_SRS - 1)) { // End of OFDM symbol or last subcarrier cases // filt16_end is {4096,8192,8192,8192,12288,16384,16384,16384,0,0,0,0,0,0,0,0} c16multaddVectRealComplex(filt16_end, &ls_estimated, srs_estimated_channel16, 16); @@ -916,26 +915,24 @@ int nr_srs_channel_estimation(const PHY_VARS_gNB *gNB, // Subcarrier increment subcarrier += K_TC; - if (subcarrier >= frame_parms->ofdm_symbol_size) { - subcarrier -= frame_parms->ofdm_symbol_size; + if (subcarrier >= ofdm_symbol_size) { + subcarrier -= ofdm_symbol_size; } } // for (int k = 0; k < M_sc_b_SRS; k++) - memcpy(srs_estimated_channel_freq, - &srs_est[mem_offset], - (frame_parms->ofdm_symbol_size * (1 << srs_pdu->num_symbols)) * sizeof(c16_t)); + memcpy(srs_estimated_channel_freq, &srs_est[mem_offset], (ofdm_symbol_size * N_symb_SRS) * sizeof(c16_t)); #ifdef SRS_DEBUG subcarrier = subcarrier_offset + nr_srs_info->k_0_p[p_index][0]; - if (subcarrier >= frame_parms->ofdm_symbol_size) { - subcarrier -= frame_parms->ofdm_symbol_size; + if (subcarrier >= ofdm_symbol_size) { + subcarrier -= ofdm_symbol_size; } for (int k = 0; k < K_TC * M_sc_b_SRS; k++) { int subcarrier_log = subcarrier - subcarrier_offset; if (subcarrier_log < 0) { - subcarrier_log = subcarrier_log + frame_parms->ofdm_symbol_size; + subcarrier_log = subcarrier_log + ofdm_symbol_size; } if (subcarrier_log % 12 == 0) { @@ -955,36 +952,36 @@ int nr_srs_channel_estimation(const PHY_VARS_gNB *gNB, // Subcarrier increment subcarrier++; - if (subcarrier >= frame_parms->ofdm_symbol_size) { - subcarrier -= frame_parms->ofdm_symbol_size; + if (subcarrier >= ofdm_symbol_size) { + subcarrier -= ofdm_symbol_size; } } #endif // Convert to time domain - freq2time(gNB->frame_parms.ofdm_symbol_size, (int16_t *)srs_estimated_channel_freq, (int16_t *)srs_estimated_channel_time); + freq2time(ofdm_symbol_size, (int16_t *)srs_estimated_channel_freq, (int16_t *)srs_estimated_channel_time); memcpy(srs_estimated_channel_time_shifted, - &srs_estimated_channel_time[gNB->frame_parms.ofdm_symbol_size >> 1], - (gNB->frame_parms.ofdm_symbol_size >> 1) * sizeof(c16_t)); + &srs_estimated_channel_time[ofdm_symbol_size >> 1], + (ofdm_symbol_size >> 1) * sizeof(c16_t)); - memcpy(&srs_estimated_channel_time_shifted[gNB->frame_parms.ofdm_symbol_size >> 1], + memcpy(&srs_estimated_channel_time_shifted[ofdm_symbol_size >> 1], srs_estimated_channel_time, - (gNB->frame_parms.ofdm_symbol_size >> 1) * sizeof(c16_t)); + (ofdm_symbol_size >> 1) * sizeof(c16_t)); // Compute wideband SNR int tot_subcarriers = m_SRS_b * NR_NB_SC_PER_RB; subcarrier = subcarrier_offset + nr_srs_info->k_0_p[p_index][0]; - if (subcarrier >= frame_parms->ofdm_symbol_size) { - subcarrier -= frame_parms->ofdm_symbol_size; + if (subcarrier >= ofdm_symbol_size) { + subcarrier -= ofdm_symbol_size; } - if (subcarrier + tot_subcarriers < frame_parms->ofdm_symbol_size) { + if (subcarrier + tot_subcarriers < ofdm_symbol_size) { *signal_power = signal_energy_nodc(&srs_estimated_channel_freq[subcarrier], tot_subcarriers) / tot_subcarriers; if (p_index == 0) { *noise_power = signal_energy_nodc(&srs_received_noise[subcarrier], tot_subcarriers) / tot_subcarriers; } } else { - int size1 = frame_parms->ofdm_symbol_size - subcarrier; + int size1 = ofdm_symbol_size - subcarrier; int size2 = tot_subcarriers - size1; uint64_t signal_power_p1 = signal_energy_nodc(&srs_estimated_channel_freq[subcarrier], size1) * size1; uint64_t signal_power_p2 = signal_energy_nodc(&srs_estimated_channel_freq[0], size2) * size2; @@ -1006,13 +1003,13 @@ int nr_srs_channel_estimation(const PHY_VARS_gNB *gNB, if (p_index == 0) { subcarrier = subcarrier_offset + nr_srs_info->k_0_p[p_index][0]; for (int rb = 0; rb < m_SRS_b; rb++) { - if (subcarrier >= frame_parms->ofdm_symbol_size) { - subcarrier -= frame_parms->ofdm_symbol_size; + if (subcarrier >= ofdm_symbol_size) { + subcarrier -= ofdm_symbol_size; } - if (subcarrier + NR_NB_SC_PER_RB < frame_parms->ofdm_symbol_size) { + if (subcarrier + NR_NB_SC_PER_RB < ofdm_symbol_size) { noise_power_per_rb[rb] += signal_energy_nodc(&srs_received_noise[subcarrier], NR_NB_SC_PER_RB); } else { - int size1 = frame_parms->ofdm_symbol_size - subcarrier; + int size1 = ofdm_symbol_size - subcarrier; int size2 = NR_NB_SC_PER_RB - size1; uint32_t noise_power_per_rb1 = signal_energy_nodc(&srs_received_noise[subcarrier], size1) * size1; uint32_t noise_power_per_rb2 = signal_energy_nodc(&srs_received_noise[0], size2) * size2; diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h b/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h index e503bcf116..4df2b47a17 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h +++ b/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h @@ -70,19 +70,19 @@ void nr_pusch_ptrs_processing(PHY_VARS_gNB *gNB, unsigned char symbol, uint32_t nb_re_pusch); -int nr_srs_channel_estimation(const PHY_VARS_gNB *gNB, - const int frame, - const int slot, - const int ant, - const int p_index, +int nr_srs_channel_estimation(int ant, + int p_index, + uint16_t ofdm_symbol_size, + uint16_t first_carrier_offset, + uint8_t N_symb_SRS, const nfapi_nr_srs_pdu_t *srs_pdu, const nr_srs_info_t *nr_srs_info, const c16_t *srs_generated_signal, - c16_t srs_received_signal[gNB->frame_parms.ofdm_symbol_size * (1 << srs_pdu->num_symbols)], - c16_t srs_received_noise[gNB->frame_parms.ofdm_symbol_size * (1 << srs_pdu->num_symbols)], - c16_t srs_estimated_channel_freq[gNB->frame_parms.ofdm_symbol_size * (1 << srs_pdu->num_symbols)], - c16_t srs_estimated_channel_time[gNB->frame_parms.ofdm_symbol_size], - c16_t srs_estimated_channel_time_shifted[gNB->frame_parms.ofdm_symbol_size], + c16_t srs_received_signal[ofdm_symbol_size * N_symb_SRS], + c16_t srs_received_noise[ofdm_symbol_size * N_symb_SRS], + c16_t srs_estimated_channel_freq[ofdm_symbol_size * N_symb_SRS], + c16_t srs_estimated_channel_time[ofdm_symbol_size], + c16_t srs_estimated_channel_time_shifted[ofdm_symbol_size], uint32_t *signal_power, uint32_t *noise_power, int16_t *noise_power_per_rb); diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index 0a4d73df96..d25d8aace6 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -900,11 +900,11 @@ void nr_srs_rx_procedures(PHY_VARS_gNB *gNB, uint32_t noise_power = 0; for (int p_ind = 0; p_ind < N_ap; p_ind++) { uint32_t signal_power = 0; - nr_srs_channel_estimation(gNB, - frame_rx, - slot_rx, - ant_rx_ind, + nr_srs_channel_estimation(ant_rx_ind, p_ind, + ofdm_symbol_size, + frame_parms->first_carrier_offset, + N_symb_SRS, srs_pdu, nr_srs_info, nr_srs_info->srs_generated_signal[p_ind], @@ -1247,10 +1247,10 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, N start_meas(&gNB->srs_beam_report_stats); nfapi_nr_srs_beamforming_report_t nr_srs_bf_report; nr_srs_bf_report.prg_size = srs_pdu->beamforming.prg_size; - nr_srs_bf_report.num_symbols = 1 << srs_pdu->num_symbols; + nr_srs_bf_report.num_symbols = N_symb_SRS; nr_srs_bf_report.wide_band_snr = srs_est >= 0 ? (gNB->srs->snr + 64) << 1 : 0xFF; // 0xFF will be set if this field is invalid - nr_srs_bf_report.num_reported_symbols = 1 << srs_pdu->num_symbols; + nr_srs_bf_report.num_reported_symbols = N_symb_SRS; AssertFatal(nr_srs_bf_report.num_reported_symbols == 1, "nr_srs_bf_report.num_reported_symbols %i not handled yet!\n", nr_srs_bf_report.num_reported_symbols); From b378acf2e0f6cf2352fb8619610daae7de5b5dde Mon Sep 17 00:00:00 2001 From: Rakesh Mundlamuri Date: Wed, 22 Oct 2025 19:35:21 +0530 Subject: [PATCH 08/22] Introduce SRS oversampling for better accuracy in estimating nanoseconds --- .../PHY/NR_ESTIMATION/nr_measurements_gNB.c | 9 +++--- .../NR_ESTIMATION/nr_ul_channel_estimation.c | 30 +++++++++++++------ openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h | 9 +++--- .../PHY/NR_TRANSPORT/nr_transport_proto.h | 2 +- openair1/PHY/defs_gNB.h | 1 + openair1/SCHED_NR/phy_procedures_nr_gNB.c | 9 +++--- 6 files changed, 38 insertions(+), 22 deletions(-) diff --git a/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c b/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c index f48e1101eb..7541d14436 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c +++ b/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c @@ -37,12 +37,12 @@ #define I0_SKIP_DC 1 int nr_est_timing_advance_srs(const NR_DL_FRAME_PARMS *frame_parms, - const c16_t srs_estimated_channel_time[][frame_parms->ofdm_symbol_size]) + const c16_t srs_estimated_channel_time[][NR_SRS_IDFT_OVERSAMP_FACTOR * frame_parms->ofdm_symbol_size]) { int timing_advance = 0; int max_val = 0; - for (int i = 0; i < frame_parms->ofdm_symbol_size; i++) { + for (int i = 0; i < NR_SRS_IDFT_OVERSAMP_FACTOR * frame_parms->ofdm_symbol_size; i++) { int temp = 0; for (int aa = 0; aa < frame_parms->nb_antennas_rx; aa++) { int Re = ((c16_t*)srs_estimated_channel_time[aa])[i].r; @@ -55,9 +55,10 @@ int nr_est_timing_advance_srs(const NR_DL_FRAME_PARMS *frame_parms, } } - if (timing_advance > frame_parms->ofdm_symbol_size/2) { - timing_advance = timing_advance - frame_parms->ofdm_symbol_size; + if (timing_advance > (NR_SRS_IDFT_OVERSAMP_FACTOR * frame_parms->ofdm_symbol_size) / 2) { + timing_advance = timing_advance - (NR_SRS_IDFT_OVERSAMP_FACTOR * frame_parms->ofdm_symbol_size); } + timing_advance = timing_advance / NR_SRS_IDFT_OVERSAMP_FACTOR; LOG_I(NR_PHY, "Estimated SRS ToA %d\n", timing_advance); diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c index 5cb60f28b3..0906321e87 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c +++ b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c @@ -780,8 +780,8 @@ int nr_srs_channel_estimation(int ant, c16_t srs_received_signal[ofdm_symbol_size * N_symb_SRS], c16_t srs_received_noise[ofdm_symbol_size * N_symb_SRS], c16_t srs_estimated_channel_freq[ofdm_symbol_size * N_symb_SRS], - c16_t srs_estimated_channel_time[ofdm_symbol_size], - c16_t srs_estimated_channel_time_shifted[ofdm_symbol_size], + c16_t srs_estimated_channel_time[NR_SRS_IDFT_OVERSAMP_FACTOR * ofdm_symbol_size], + c16_t srs_estimated_channel_time_shifted[NR_SRS_IDFT_OVERSAMP_FACTOR * ofdm_symbol_size], uint32_t *signal_power, uint32_t *noise_power, int16_t *noise_power_per_rb) @@ -959,15 +959,27 @@ int nr_srs_channel_estimation(int ant, #endif // Convert to time domain - freq2time(ofdm_symbol_size, (int16_t *)srs_estimated_channel_freq, (int16_t *)srs_estimated_channel_time); + int16_t ofdm_symbol_size_half = ofdm_symbol_size >> 1; + int16_t ofdm_os_size = NR_SRS_IDFT_OVERSAMP_FACTOR * ofdm_symbol_size; + int16_t ofdm_os_size_half = ofdm_os_size >> 1; + int16_t start_offset = ofdm_os_size - ofdm_symbol_size_half; - memcpy(srs_estimated_channel_time_shifted, - &srs_estimated_channel_time[ofdm_symbol_size >> 1], - (ofdm_symbol_size >> 1) * sizeof(c16_t)); + c16_t chF_interpol[ofdm_os_size] __attribute__((aligned(32))); + memset(chF_interpol, 0, sizeof(chF_interpol)); - memcpy(&srs_estimated_channel_time_shifted[ofdm_symbol_size >> 1], - srs_estimated_channel_time, - (ofdm_symbol_size >> 1) * sizeof(c16_t)); + // Place SRS channel estimates in FFT shifted format for oversampling + memcpy(&chF_interpol[0], &srs_estimated_channel_freq[0], ofdm_symbol_size_half * sizeof(c16_t)); + memcpy(&chF_interpol[start_offset], + &srs_estimated_channel_freq[ofdm_symbol_size_half], + ofdm_symbol_size_half * sizeof(c16_t)); + + // Convert to time domain oversampled + freq2time(ofdm_os_size, (int16_t *)chF_interpol, (int16_t *)srs_estimated_channel_time); + + // Do FFT shift + memcpy(srs_estimated_channel_time_shifted, &srs_estimated_channel_time[ofdm_os_size_half], ofdm_os_size_half * sizeof(c16_t)); + + memcpy(&srs_estimated_channel_time_shifted[ofdm_os_size_half], srs_estimated_channel_time, ofdm_os_size_half * sizeof(c16_t)); // Compute wideband SNR int tot_subcarriers = m_SRS_b * NR_NB_SC_PER_RB; diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h b/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h index 4df2b47a17..f04fde7b1b 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h +++ b/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h @@ -59,8 +59,9 @@ void dump_nr_I0_stats(FILE *fd,PHY_VARS_gNB *gNB); void gNB_I0_measurements(PHY_VARS_gNB *gNB, int slot, int first_symb, int num_symb, uint32_t rb_mask_ul[14][9]); -int nr_est_timing_advance_srs(const NR_DL_FRAME_PARMS *frame_parms, - const c16_t srs_estimated_channel_time[][frame_parms->ofdm_symbol_size]); +int nr_est_timing_advance_srs( + const NR_DL_FRAME_PARMS *frame_parms, + const c16_t srs_estimated_channel_time[][NR_SRS_IDFT_OVERSAMP_FACTOR * frame_parms->ofdm_symbol_size]); void nr_pusch_ptrs_processing(PHY_VARS_gNB *gNB, NR_DL_FRAME_PARMS *frame_parms, @@ -81,8 +82,8 @@ int nr_srs_channel_estimation(int ant, c16_t srs_received_signal[ofdm_symbol_size * N_symb_SRS], c16_t srs_received_noise[ofdm_symbol_size * N_symb_SRS], c16_t srs_estimated_channel_freq[ofdm_symbol_size * N_symb_SRS], - c16_t srs_estimated_channel_time[ofdm_symbol_size], - c16_t srs_estimated_channel_time_shifted[ofdm_symbol_size], + c16_t srs_estimated_channel_time[NR_SRS_IDFT_OVERSAMP_FACTOR * ofdm_symbol_size], + c16_t srs_estimated_channel_time_shifted[NR_SRS_IDFT_OVERSAMP_FACTOR * ofdm_symbol_size], uint32_t *signal_power, uint32_t *noise_power, int16_t *noise_power_per_rb); diff --git a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h index 1a0fabf14e..b01361ec8d 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h +++ b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h @@ -242,7 +242,7 @@ void nr_srs_rx_procedures(PHY_VARS_gNB *gNB, nr_srs_info_t *nr_srs_info, int *srs_est, c16_t srs_estimated_channel_freq[][N_ap][ofdm_symbol_size * N_symb_SRS], - c16_t srs_estimated_channel_time[][N_ap][ofdm_symbol_size], + c16_t srs_estimated_channel_time[][N_ap][NR_SRS_IDFT_OVERSAMP_FACTOR * ofdm_symbol_size], int16_t *snr_per_rb); int get_nr_prach_duration(uint8_t prach_format); diff --git a/openair1/PHY/defs_gNB.h b/openair1/PHY/defs_gNB.h index abc700f9d2..5710b24105 100644 --- a/openair1/PHY/defs_gNB.h +++ b/openair1/PHY/defs_gNB.h @@ -46,6 +46,7 @@ #define MAX_NUM_RU_PER_gNB 8 #define MAX_PUCCH0_NID 8 +#define NR_SRS_IDFT_OVERSAMP_FACTOR 2 typedef struct { int nb_id; diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index d25d8aace6..1b04f63950 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -868,14 +868,14 @@ void nr_srs_rx_procedures(PHY_VARS_gNB *gNB, nr_srs_info_t *nr_srs_info, int *srs_est, c16_t srs_estimated_channel_freq[][N_ap][ofdm_symbol_size * N_symb_SRS], - c16_t srs_estimated_channel_time[][N_ap][ofdm_symbol_size], + c16_t srs_estimated_channel_time[][N_ap][NR_SRS_IDFT_OVERSAMP_FACTOR * ofdm_symbol_size], int16_t *snr_per_rb) { NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms; nfapi_nr_srs_pdu_t *srs_pdu = &srs->srs_pdu; c16_t srs_received_signal[nb_antennas_rx][ofdm_symbol_size * N_symb_SRS]; c16_t srs_received_noise[nb_antennas_rx][ofdm_symbol_size * N_symb_SRS]; - c16_t srs_estimated_channel_time_shifted[nb_antennas_rx][N_ap][ofdm_symbol_size]; + c16_t srs_estimated_channel_time_shifted[nb_antennas_rx][N_ap][NR_SRS_IDFT_OVERSAMP_FACTOR * ofdm_symbol_size]; start_meas(&gNB->generate_srs_stats); @@ -946,7 +946,7 @@ void nr_srs_rx_procedures(PHY_VARS_gNB *gNB, T_INT(frame_rx), T_INT(0), T_INT(0), - T_BUFFER(srs_estimated_channel_time_shifted[0][0], ofdm_symbol_size * sizeof(int32_t))); + T_BUFFER(srs_estimated_channel_time_shifted[0][0], NR_SRS_IDFT_OVERSAMP_FACTOR * ofdm_symbol_size * sizeof(int32_t))); T(T_GNB_PHY_UL_SNR_ESTIMATE, T_INT(0), @@ -1171,7 +1171,8 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, N int srs_est; c16_t srs_estimated_channel_freq[nb_antennas_rx][N_ap][ofdm_symbol_size * N_symb_SRS] __attribute__((aligned(32))); - c16_t srs_estimated_channel_time[nb_antennas_rx][N_ap][ofdm_symbol_size] __attribute__((aligned(32))); + c16_t srs_estimated_channel_time[nb_antennas_rx][N_ap][NR_SRS_IDFT_OVERSAMP_FACTOR * ofdm_symbol_size] + __attribute__((aligned(32))); nr_srs_rx_procedures(gNB, frame_rx, From 1b974c6ab233b5ce50a16f42338bb0a1c2b859fb Mon Sep 17 00:00:00 2001 From: Rakesh Mundlamuri Date: Wed, 22 Oct 2025 20:45:06 +0530 Subject: [PATCH 09/22] merge timing_advance_offset and timing_advance_offset_ns computation --- common/utils/nr/nr_common.h | 1 + .../PHY/NR_ESTIMATION/nr_measurements_gNB.c | 91 ++++++++++++------- openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h | 10 +- .../PHY/NR_TRANSPORT/nr_transport_proto.h | 4 +- openair1/PHY/defs_gNB.h | 1 + openair1/SCHED_NR/phy_procedures_nr_gNB.c | 32 +++++-- openair1/SIMULATION/NR_PHY/srssim.c | 51 +++++++++-- 7 files changed, 132 insertions(+), 58 deletions(-) diff --git a/common/utils/nr/nr_common.h b/common/utils/nr/nr_common.h index 52eb305824..1e2f8164bd 100644 --- a/common/utils/nr/nr_common.h +++ b/common/utils/nr/nr_common.h @@ -346,6 +346,7 @@ float get_beta_dmrs(int num_cdm_groups_no_data, bool is_type2); #define CEILIDIV(a,b) ((a+b-1)/b) #define ROUNDIDIV(a,b) (((a<<1)+b)/(b<<1)) +#define BOUNDED_EVAL(a, b, c) (min(c, max(a, b))) static const char *const duplex_mode_txt[] = {"FDD", "TDD"}; diff --git a/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c b/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c index 7541d14436..89aba954e9 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c +++ b/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c @@ -36,52 +36,73 @@ #define I0_SKIP_DC 1 -int nr_est_timing_advance_srs(const NR_DL_FRAME_PARMS *frame_parms, - const c16_t srs_estimated_channel_time[][NR_SRS_IDFT_OVERSAMP_FACTOR * frame_parms->ofdm_symbol_size]) +void nr_est_srs_timing_advance_offset(uint16_t ofdm_symbol_size, + const c16_t srs_estimated_channel_time[][NR_SRS_IDFT_OVERSAMP_FACTOR * ofdm_symbol_size], + uint8_t ant, + uint8_t N_ap, + uint32_t samples_per_frame, + uint16_t *ta_offset, + int16_t *ta_offset_nsec) { - int timing_advance = 0; - int max_val = 0; - - for (int i = 0; i < NR_SRS_IDFT_OVERSAMP_FACTOR * frame_parms->ofdm_symbol_size; i++) { - int temp = 0; - for (int aa = 0; aa < frame_parms->nb_antennas_rx; aa++) { - int Re = ((c16_t*)srs_estimated_channel_time[aa])[i].r; - int Im = ((c16_t*)srs_estimated_channel_time[aa])[i].i; - temp += (Re*Re/2) + (Im*Im/2); + int64_t mean_val = 0; + int64_t max_val = 0; + int32_t max_idx = 0; + int16_t srs_toa = 0; + int16_t ofdm_os_size = NR_SRS_IDFT_OVERSAMP_FACTOR * ofdm_symbol_size; + for (int k = 0; k < ofdm_os_size; k++) { + int64_t abs_val = 0; + for (int p_index = 0; p_index < N_ap; p_index++) { + abs_val += squaredMod(srs_estimated_channel_time[p_index][k]); } - if (temp > max_val) { - timing_advance = i; - max_val = temp; + mean_val += abs_val; + if (abs_val > max_val) { + max_val = abs_val; + max_idx = k; } } + max_val = max_val / N_ap; + mean_val = mean_val / (N_ap * ofdm_os_size); - if (timing_advance > (NR_SRS_IDFT_OVERSAMP_FACTOR * frame_parms->ofdm_symbol_size) / 2) { - timing_advance = timing_advance - (NR_SRS_IDFT_OVERSAMP_FACTOR * frame_parms->ofdm_symbol_size); - } - timing_advance = timing_advance / NR_SRS_IDFT_OVERSAMP_FACTOR; + if (max_idx > ofdm_os_size >> 1) + max_idx = max_idx - ofdm_os_size; - LOG_I(NR_PHY, "Estimated SRS ToA %d\n", timing_advance); + // Check for detection threshold + if ((mean_val != 0) && (max_val / mean_val > NR_SRS_DETECTION_THRESHOLD)) { + srs_toa = max_idx / NR_SRS_IDFT_OVERSAMP_FACTOR; - // Scale the 16 factor in N_TA calculation in 38.213 section 4.2 according to the used FFT size - const uint16_t bw_scaling = frame_parms->ofdm_symbol_size >> 7; + // restrict the computation of ta_offset to antenna 0 + if (ant == 0) { + // Scale the 16 factor in N_TA calculation in 38.213 section 4.2 according to the used FFT size + const uint16_t bw_scaling = ofdm_symbol_size >> 7; - // do some integer rounding to improve TA accuracy - int sync_pos_rounded; - if (timing_advance > 0) { - sync_pos_rounded = timing_advance + (bw_scaling >> 1) - 1; + // do some integer rounding to improve TA accuracy + int sync_pos_rounded; + if (srs_toa > 0) { + sync_pos_rounded = srs_toa + (bw_scaling >> 1) - 1; + } else { + sync_pos_rounded = srs_toa - (bw_scaling >> 1) + 1; + } + + *ta_offset = sync_pos_rounded / bw_scaling; + + // put timing advance command in 0..63 range + *ta_offset = BOUNDED_EVAL(0, *ta_offset + 31, 63); + } + *ta_offset_nsec = (max_idx * 1e9) / (NR_SRS_IDFT_OVERSAMP_FACTOR * samples_per_frame * 100); } else { - sync_pos_rounded = timing_advance - (bw_scaling >> 1) + 1; + *ta_offset = 0xFFFF; + *ta_offset_nsec = 0x8000; } - int timing_advance_update = sync_pos_rounded / bw_scaling; - - // put timing advance command in 0..63 range - timing_advance_update += 31; - - if (timing_advance_update < 0) timing_advance_update = 0; - if (timing_advance_update > 63) timing_advance_update = 63; - - return timing_advance_update; + LOG_D(NR_PHY, + "SRS estimatd ToA %d [RX ant %d]: TA offset %d, TA offset ns %d (max_val %ld, mean_val %ld, max_idx %d)\n", + srs_toa, + ant, + *ta_offset, + *ta_offset_nsec, + max_val, + mean_val, + max_idx); } void dump_nr_I0_stats(FILE *fd,PHY_VARS_gNB *gNB) { diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h b/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h index f04fde7b1b..21ecb39427 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h +++ b/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h @@ -59,9 +59,13 @@ void dump_nr_I0_stats(FILE *fd,PHY_VARS_gNB *gNB); void gNB_I0_measurements(PHY_VARS_gNB *gNB, int slot, int first_symb, int num_symb, uint32_t rb_mask_ul[14][9]); -int nr_est_timing_advance_srs( - const NR_DL_FRAME_PARMS *frame_parms, - const c16_t srs_estimated_channel_time[][NR_SRS_IDFT_OVERSAMP_FACTOR * frame_parms->ofdm_symbol_size]); +void nr_est_srs_timing_advance_offset(uint16_t ofdm_symbol_size, + const c16_t srs_estimated_channel_time[][NR_SRS_IDFT_OVERSAMP_FACTOR * ofdm_symbol_size], + uint8_t ant, + uint8_t N_ap, + uint32_t samples_per_frame, + uint16_t *timing_advance_offset, + int16_t *timing_advance_offset_nsec); void nr_pusch_ptrs_processing(PHY_VARS_gNB *gNB, NR_DL_FRAME_PARMS *frame_parms, diff --git a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h index b01361ec8d..29ae5bb612 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h +++ b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h @@ -243,7 +243,9 @@ void nr_srs_rx_procedures(PHY_VARS_gNB *gNB, int *srs_est, c16_t srs_estimated_channel_freq[][N_ap][ofdm_symbol_size * N_symb_SRS], c16_t srs_estimated_channel_time[][N_ap][NR_SRS_IDFT_OVERSAMP_FACTOR * ofdm_symbol_size], - int16_t *snr_per_rb); + int16_t *snr_per_rb, + uint16_t *timing_advance_offset, + int16_t *timing_advance_offset_nsec); int get_nr_prach_duration(uint8_t prach_format); diff --git a/openair1/PHY/defs_gNB.h b/openair1/PHY/defs_gNB.h index 5710b24105..f3350d707e 100644 --- a/openair1/PHY/defs_gNB.h +++ b/openair1/PHY/defs_gNB.h @@ -47,6 +47,7 @@ #define MAX_NUM_RU_PER_gNB 8 #define MAX_PUCCH0_NID 8 #define NR_SRS_IDFT_OVERSAMP_FACTOR 2 +#define NR_SRS_DETECTION_THRESHOLD 10 typedef struct { int nb_id; diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index 1b04f63950..36dc8a3b5a 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -869,7 +869,9 @@ void nr_srs_rx_procedures(PHY_VARS_gNB *gNB, int *srs_est, c16_t srs_estimated_channel_freq[][N_ap][ofdm_symbol_size * N_symb_SRS], c16_t srs_estimated_channel_time[][N_ap][NR_SRS_IDFT_OVERSAMP_FACTOR * ofdm_symbol_size], - int16_t *snr_per_rb) + int16_t *snr_per_rb, + uint16_t *timing_advance_offset, + int16_t *timing_advance_offset_nsec) { NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms; nfapi_nr_srs_pdu_t *srs_pdu = &srs->srs_pdu; @@ -930,6 +932,18 @@ void nr_srs_rx_procedures(PHY_VARS_gNB *gNB, snr_per_rb[rb] = dB_fixed(signal_power_avg) - dB_fixed(max(noise_power_per_rb[rb] / nb_antennas_rx, 1)); } stop_meas(&gNB->srs_channel_estimation_stats); + + start_meas(&gNB->srs_timing_advance_stats); + for (int ant_rx_ind = 0; ant_rx_ind < nb_antennas_rx; ant_rx_ind++) { + nr_est_srs_timing_advance_offset(ofdm_symbol_size, + srs_estimated_channel_time[ant_rx_ind], + ant_rx_ind, + N_ap, + frame_parms->samples_per_frame, + timing_advance_offset, + &timing_advance_offset_nsec[ant_rx_ind]); + } + stop_meas(&gNB->srs_timing_advance_stats); } T(T_GNB_PHY_UL_FREQ_CHANNEL_ESTIMATE, @@ -1168,6 +1182,8 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, N uint8_t N_ap = 1 << srs->srs_pdu.num_ant_ports; int16_t snr_per_rb[srs->srs_pdu.bwp_size]; nfapi_nr_srs_pdu_t *srs_pdu = &srs->srs_pdu; + uint16_t timing_advance_offset; + int16_t timing_advance_offset_nsec[nb_antennas_rx]; int srs_est; c16_t srs_estimated_channel_freq[nb_antennas_rx][N_ap][ofdm_symbol_size * N_symb_SRS] __attribute__((aligned(32))); @@ -1186,7 +1202,9 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, N &srs_est, srs_estimated_channel_freq, srs_estimated_channel_time, - snr_per_rb); + snr_per_rb, + &timing_advance_offset, + timing_advance_offset_nsec); if ((gNB->srs->snr * 10) < gNB->srs_thres) { srs_est = -1; @@ -1200,13 +1218,9 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, N nfapi_nr_srs_indication_pdu_t *srs_indication = UL_INFO->srs_pdu_list + UL_INFO->srs_ind.number_of_pdus++; srs_indication->handle = srs_pdu->handle; srs_indication->rnti = srs_pdu->rnti; - start_meas(&gNB->srs_timing_advance_stats); - srs_indication->timing_advance_offset = - srs_est >= 0 ? nr_est_timing_advance_srs(frame_parms, srs_estimated_channel_time[0]) : 0xFFFF; - stop_meas(&gNB->srs_timing_advance_stats); - srs_indication->timing_advance_offset_nsec = - srs_est >= 0 ? (int16_t)((((int32_t)srs_indication->timing_advance_offset - 31) * ((int32_t)TC_NSEC_x32768)) >> 15) - : 0xFFFF; + srs_indication->timing_advance_offset = srs_est >= 0 ? timing_advance_offset : 0xFFFF; + // TODO: currently we fill timing_advance_offset_nsec for antenna 0. Need to extend it for other antennas + srs_indication->timing_advance_offset_nsec = srs_est >= 0 ? timing_advance_offset_nsec[0] : 0x8000; switch (srs_pdu->srs_parameters_v4.usage) { case 0: LOG_W(NR_PHY, "SRS report was not requested by MAC\n"); diff --git a/openair1/SIMULATION/NR_PHY/srssim.c b/openair1/SIMULATION/NR_PHY/srssim.c index 9f89d29b1d..f83da5941e 100644 --- a/openair1/SIMULATION/NR_PHY/srssim.c +++ b/openair1/SIMULATION/NR_PHY/srssim.c @@ -88,9 +88,8 @@ int main(int argc, char *argv[]) sigaction(SIGINT, &sigint_action, &oldaction); double SNR, snr0 = 0, snr1 = 20.0; - double sum_srs_snr = 0; double sigma, sigma_dB; - double snr_step = 5; + double snr_step = 1; uint8_t snr1set = 0; double **s_re, **s_im, **r_re, **r_im; int trial, n_trials = 1, delay = 0; @@ -128,7 +127,7 @@ int main(int argc, char *argv[]) InitSinLUT(); int c; - while ((c = getopt(argc, argv, "--:O:a:b:c:d:e:f:g:h:i:k:l:m:n:p:s:u:y:z:A:B:C:H:PR:S:L:")) != -1) { + while ((c = getopt(argc, argv, "--:O:a:b:c:d:e:f:g:h:i:kl:m:n:p:s:u:y:z:A:B:C:H:PR:S:L:")) != -1) { /* ignore long options starting with '--', option '-O' and their arguments that are handled by configmodule */ /* with this opstring getopt returns 1 for non-option arguments, refer to 'man 3 getopt' */ if (c == 1 || c == '-' || c == 'O') @@ -570,7 +569,8 @@ int main(int argc, char *argv[]) reset_meas(&gNB->srs_channel_estimation_stats); reset_meas(&gNB->srs_timing_advance_stats); - sum_srs_snr = 0; + double sum_srs_snr = 0; + int tao_ns_count = 0; for (trial = 0; trial < n_trials && !stop; trial++) { // Estimate noise power from the transmitter level and SNR sigma_dB = 10 * log10(((double)txlev_sum) * ((double)ofdm_symbol_size / (12 * srs_pdu.bwp_size))) - SNR; @@ -627,6 +627,8 @@ int main(int argc, char *argv[]) uint8_t N_ap = 1 << srs->srs_pdu.num_ant_ports; uint8_t nb_antennas_rx = fp->nb_antennas_rx; int16_t snr_per_rb[srs->srs_pdu.bwp_size]; + uint16_t timing_advance_offset; + int16_t timing_advance_offset_nsec[nb_antennas_rx]; int srs_est; c16_t srs_estimated_channel_freq[nb_antennas_rx][N_ap][ofdm_symbol_size * N_symb_SRS] __attribute__((aligned(32))); c16_t srs_estimated_channel_time[nb_antennas_rx][N_ap][ofdm_symbol_size] __attribute__((aligned(32))); @@ -643,16 +645,41 @@ int main(int argc, char *argv[]) &srs_est, srs_estimated_channel_freq, srs_estimated_channel_time, - snr_per_rb); + snr_per_rb, + &timing_advance_offset, + timing_advance_offset_nsec); - start_meas(&gNB->srs_timing_advance_stats); - nr_est_timing_advance_srs(fp, srs_estimated_channel_time[0]); - stop_meas(&gNB->srs_timing_advance_stats); sum_srs_snr += pow(10, (double)gNB->srs->snr / 10.0); + + int16_t delay_ns = delay * 1e9 / (fp->samples_per_frame * 100); + for (int ant_idx = 0; ant_idx < nb_antennas_rx; ant_idx++) { + if (n_trials == 1) + printf("[RX ant %d] SRS estimated: TA offset %d, TA offset ns %d \n", + ant_idx, + timing_advance_offset, + timing_advance_offset_nsec[ant_idx]); + if (timing_advance_offset_nsec[ant_idx] == delay_ns) + tao_ns_count++; + } stop_meas(&gNB->rx_srs_stats); } // trail loop - sum_srs_snr /= n_trials; - printf("Actual SNR : %f, Estimated SNR from SRS %f (dB)\n", SNR, 10 * log10(sum_srs_snr)); + float tao_ns_rate = (float)tao_ns_count / (n_trials * n_rx); + float SRS_SNR_dB = 10 * log10(sum_srs_snr / n_trials); + printf("Actual SNR : %f, Estimated SNR from SRS %f (dB), TA offset success rate %f %%\n", SNR, SRS_SNR_dB, tao_ns_rate * 100); + + int srs_ret = 1; + if (SNR > 30 && SRS_SNR_dB > 30) { + srs_ret = 0; + } else if (SNR >= SRS_SNR_dB) { + srs_ret = SRS_SNR_dB >= 0.7 * SNR ? 0 : 1; + } else if (SRS_SNR_dB > SNR) { + srs_ret = SNR >= 0.7 * SRS_SNR_dB ? 0 : 1; + } + + if (tao_ns_rate > 0.9 && srs_ret == 0) { + ret = 0; + break; + } if (print_perf == 1) { printf("\ngNB RX\n"); @@ -666,6 +693,10 @@ int main(int argc, char *argv[]) } // SNR loop + printf("*************\n"); + printf("SRS test %s\n", ret == 0 ? "OK" : "FAILED"); + printf("*************\n"); + // free memory for (i = 0; i < n_tx; i++) { From 9a0a89fa8897c506bb87f045e038cd9a1d21a9fd Mon Sep 17 00:00:00 2001 From: Rakesh Mundlamuri Date: Thu, 23 Oct 2025 19:34:47 +0530 Subject: [PATCH 10/22] fix nr_phy_config_request_sim that overwrites threequarter sampling rate parameter --- openair1/PHY/INIT/nr_init.c | 43 ++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/openair1/PHY/INIT/nr_init.c b/openair1/PHY/INIT/nr_init.c index 58ad0f2449..ad92ae6c34 100644 --- a/openair1/PHY/INIT/nr_init.c +++ b/openair1/PHY/INIT/nr_init.c @@ -295,8 +295,8 @@ void nr_phy_config_request_sim(PHY_VARS_gNB *gNB, { NR_DL_FRAME_PARMS *fp = &gNB->frame_parms; nfapi_nr_config_request_scf_t *gNB_config = &gNB->gNB_config; - //overwrite for new NR parameters + // overwrite with new NR parameters uint64_t rev_burst=0; for (int i=0; i<64; i++) rev_burst |= (((position_in_burst>>(63-i))&0x01)<carrier_config.num_tx_ant.value = fp->nb_antennas_tx; gNB_config->carrier_config.num_rx_ant.value = fp->nb_antennas_rx; - gNB_config->tdd_table.tdd_period.value = 0; - //gNB_config->subframe_config.dl_cyclic_prefix_type.value = (fp->Ncp == NORMAL) ? NFAPI_CP_NORMAL : NFAPI_CP_EXTENDED; - - if (mu==0) { - fp->dl_CarrierFreq = 2600000000;//from_nrarfcn(gNB_config->nfapi_config.rf_bands.rf_band[0],gNB_config->nfapi_config.nrarfcn.value); - fp->ul_CarrierFreq = 2600000000;//fp->dl_CarrierFreq - (get_uldl_offset(gNB_config->nfapi_config.rf_bands.rf_band[0])*100000); - fp->nr_band = 38; - // fp->threequarter_fs= 0; - } else if (mu==1) { - fp->dl_CarrierFreq = 3600000000;//from_nrarfcn(gNB_config->nfapi_config.rf_bands.rf_band[0],gNB_config->nfapi_config.nrarfcn.value); - fp->ul_CarrierFreq = 3600000000;//fp->dl_CarrierFreq - (get_uldl_offset(gNB_config->nfapi_config.rf_bands.rf_band[0])*100000); - fp->nr_band = 78; - // fp->threequarter_fs= 0; - } else if (mu==3) { - fp->dl_CarrierFreq = 27524520000;//from_nrarfcn(gNB_config->nfapi_config.rf_bands.rf_band[0],gNB_config->nfapi_config.nrarfcn.value); - fp->ul_CarrierFreq = 27524520000;//fp->dl_CarrierFreq - (get_uldl_offset(gNB_config->nfapi_config.rf_bands.rf_band[0])*100000); - fp->nr_band = 261; - // fp->threequarter_fs= 0; + switch (mu) { + case 0: + gNB->gNB_config.tdd_table.tdd_period.value = 7; + fp->dl_CarrierFreq = 2600000000; + fp->ul_CarrierFreq = 2600000000; + fp->nr_band = 38; + break; + case 1: + gNB->gNB_config.tdd_table.tdd_period.value = 6; + fp->dl_CarrierFreq = 3600000000; + fp->ul_CarrierFreq = 3600000000; + fp->nr_band = 78; + break; + case 3: + gNB->gNB_config.tdd_table.tdd_period.value = 3; + fp->dl_CarrierFreq = 27524520000; + fp->ul_CarrierFreq = 27524520000; + fp->nr_band = 261; + break; + default: + printf("unsupported numerology %d\n", mu); + exit(-1); } - fp->threequarter_fs = 0; frequency_range_t frequency_range = get_freq_range_from_band(fp->nr_band); int bw_index = get_supported_band_index(mu, frequency_range, N_RB_DL); gNB_config->carrier_config.dl_bandwidth.value = get_supported_bw_mhz(frequency_range, bw_index); From 14cfbbf425c54acfe2faf2f14315153b26b5642a Mon Sep 17 00:00:00 2001 From: Rakesh Mundlamuri Date: Thu, 23 Oct 2025 19:36:53 +0530 Subject: [PATCH 11/22] fix do_tdd_config_sim() while filling uplink slots --- openair1/SCHED_NR/phy_frame_config_nr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair1/SCHED_NR/phy_frame_config_nr.c b/openair1/SCHED_NR/phy_frame_config_nr.c index 9479e960a8..0806bd6286 100644 --- a/openair1/SCHED_NR/phy_frame_config_nr.c +++ b/openair1/SCHED_NR/phy_frame_config_nr.c @@ -226,7 +226,7 @@ void do_tdd_config_sim(PHY_VARS_gNB *gNB, int mu) pc->tdd_slot_bitmap[i].num_dl_symbols = 6; pc->tdd_slot_bitmap[i].num_ul_symbols = 4; } - for (int i = pc->num_ul_slots; i < fs.numb_slots_period; i++) { + for (int i = fs.numb_slots_period - pc->num_ul_slots; i < fs.numb_slots_period; i++) { pc->tdd_slot_bitmap[i].slot_type = TDD_NR_UPLINK_SLOT; pc->tdd_slot_bitmap[i].num_dl_symbols = 0; pc->tdd_slot_bitmap[i].num_ul_symbols = 0; From 729dc02b880d84c7023ac8149963857002c9fa59 Mon Sep 17 00:00:00 2001 From: Rakesh Mundlamuri Date: Tue, 28 Oct 2025 19:50:40 +0530 Subject: [PATCH 12/22] Split the code in the SNR loop as functions for readability - Introduce signal energy and noise variance functions - Combine rotation and OFDM modulation RX as a function - Harmonize the use of number of antennas across the code - Rename nr_ue_pusch_common_procedures() to nr_tx_rotation_and_ofdm_mod() to decribe the functionality better --- openair1/PHY/MODULATION/nr_modulation.h | 11 ++- openair1/PHY/MODULATION/ofdm_mod.c | 1 - openair1/PHY/MODULATION/slot_fep_nr.c | 26 ++++- .../NR_UE_TRANSPORT/nr_transport_proto_ue.h | 17 ++-- openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c | 17 ++-- openair1/PHY/TOOLS/signal_energy.c | 29 ++++++ openair1/PHY/TOOLS/tools_defs.h | 3 + openair1/SCHED_NR_UE/phy_procedures_nr_ue.c | 17 ++-- .../SCHED_NR_UE/phy_procedures_nr_ue_sl.c | 17 ++-- openair1/SIMULATION/NR_PHY/srssim.c | 99 ++++++------------- openair1/SIMULATION/NR_PHY/ulsim.c | 30 +++--- 11 files changed, 139 insertions(+), 128 deletions(-) diff --git a/openair1/PHY/MODULATION/nr_modulation.h b/openair1/PHY/MODULATION/nr_modulation.h index 996a66b343..3fc1da8301 100644 --- a/openair1/PHY/MODULATION/nr_modulation.h +++ b/openair1/PHY/MODULATION/nr_modulation.h @@ -78,7 +78,7 @@ void nr_ue_layer_mapping(const c16_t *mod_symbs, const int n_layers, const int n \param sample_offset offset within rxdata (points to beginning of subframe) */ -int nr_slot_fep_ul(NR_DL_FRAME_PARMS *frame_parms, +int nr_slot_fep_ul(const NR_DL_FRAME_PARMS *frame_parms, int32_t *rxdata, int32_t *rxdataF, unsigned char symbol, @@ -111,6 +111,15 @@ void apply_nr_rotation_TX(const NR_DL_FRAME_PARMS *fp, int first_symbol, int nsymb); +void nr_ofdm_demod_and_rx_rotation(c16_t **rxdata, + c16_t **rxdataF, + const NR_DL_FRAME_PARMS *fp, + int nb_antennas, + int slot, + int slot_offsetF, + enum nr_Link linktype, + bool was_symbol_used[NR_NUMBER_OF_SYMBOLS_PER_SLOT]); + void perform_symbol_rotation(NR_DL_FRAME_PARMS *fp, double f0, c16_t *symbol_rotation); void init_symbol_rotation(NR_DL_FRAME_PARMS *fp); diff --git a/openair1/PHY/MODULATION/ofdm_mod.c b/openair1/PHY/MODULATION/ofdm_mod.c index 6cc8cbe7c5..c3311fb78a 100644 --- a/openair1/PHY/MODULATION/ofdm_mod.c +++ b/openair1/PHY/MODULATION/ofdm_mod.c @@ -326,4 +326,3 @@ void apply_nr_rotation_TX(const NR_DL_FRAME_PARMS *fp, } } } - diff --git a/openair1/PHY/MODULATION/slot_fep_nr.c b/openair1/PHY/MODULATION/slot_fep_nr.c index 58e47fc13a..c012d39d82 100644 --- a/openair1/PHY/MODULATION/slot_fep_nr.c +++ b/openair1/PHY/MODULATION/slot_fep_nr.c @@ -135,7 +135,7 @@ int nr_slot_fep(PHY_VARS_NR_UE *ue, return 0; } -int nr_slot_fep_ul(NR_DL_FRAME_PARMS *frame_parms, +int nr_slot_fep_ul(const NR_DL_FRAME_PARMS *frame_parms, int32_t *rxdata, int32_t *rxdataF, unsigned char symbol, @@ -237,3 +237,27 @@ void apply_nr_rotation_symbol_RX(const NR_DL_FRAME_PARMS *frame_parms, 15); } } + +void nr_ofdm_demod_and_rx_rotation(c16_t **rxdata, + c16_t **rxdataF, + const NR_DL_FRAME_PARMS *fp, + int nb_antennas, + int slot, + int slot_offsetF, + enum nr_Link linktype, + bool was_symbol_used[NR_NUMBER_OF_SYMBOLS_PER_SLOT]) +{ + for (int aa = 0; aa < nb_antennas; aa++) { + for (uint8_t symbol = 0; symbol < fp->symbols_per_slot; symbol++) { + if (was_symbol_used[symbol] == true) { + nr_slot_fep_ul(fp, (int32_t *)&rxdata[aa][0], (int32_t *)&rxdataF[aa][slot_offsetF], symbol, slot, 0); + apply_nr_rotation_symbol_RX(fp, + &rxdataF[aa][slot_offsetF + symbol * fp->ofdm_symbol_size], + fp->symbol_rotation[linktype], + fp->N_RB_UL, + slot, + symbol); + } + } + } +} diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h index ab51d118ff..68904f1fa2 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h @@ -168,15 +168,14 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, /** \brief This function does IFFT for PUSCH */ -uint8_t nr_ue_pusch_common_procedures(PHY_VARS_NR_UE *UE, - const uint8_t slot, - const NR_DL_FRAME_PARMS *frame_parms, - const uint8_t n_antenna_ports, - c16_t **txdataF, - c16_t **txdata, - uint32_t linktype, - bool was_symbol_used[NR_NUMBER_OF_SYMBOLS_PER_SLOT], - bool no_phase_pre_comp); +uint8_t nr_tx_rotation_and_ofdm_mod(const uint8_t slot, + const NR_DL_FRAME_PARMS *frame_parms, + const uint8_t n_antenna_ports, + c16_t **txdataF, + c16_t **txdata, + uint32_t linktype, + bool was_symbol_used[NR_NUMBER_OF_SYMBOLS_PER_SLOT], + bool no_phase_pre_comp); bool ue_srs_procedures_nr(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c index 310fa7dc5f..8251f278ad 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c @@ -1502,15 +1502,14 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, stop_meas_nr_ue_phy(UE, PUSCH_PROC_STATS); } -uint8_t nr_ue_pusch_common_procedures(PHY_VARS_NR_UE *UE, - const uint8_t slot, - const NR_DL_FRAME_PARMS *frame_parms, - const uint8_t n_antenna_ports, - c16_t **txdataF, - c16_t **txdata, - uint32_t linktype, - bool was_symbol_used[NR_NUMBER_OF_SYMBOLS_PER_SLOT], - bool no_phase_pre_comp) +uint8_t nr_tx_rotation_and_ofdm_mod(const uint8_t slot, + const NR_DL_FRAME_PARMS *frame_parms, + const uint8_t n_antenna_ports, + c16_t **txdataF, + c16_t **txdata, + uint32_t linktype, + bool was_symbol_used[NR_NUMBER_OF_SYMBOLS_PER_SLOT], + bool no_phase_pre_comp) { int N_RB = (linktype == link_type_sl) ? frame_parms->N_RB_SL : frame_parms->N_RB_UL; diff --git a/openair1/PHY/TOOLS/signal_energy.c b/openair1/PHY/TOOLS/signal_energy.c index a7c314dd44..9b50b947c3 100644 --- a/openair1/PHY/TOOLS/signal_energy.c +++ b/openair1/PHY/TOOLS/signal_energy.c @@ -180,3 +180,32 @@ int32_t interference_power(int32_t *input, uint32_t length) return temp; } +// Computes transmitter energy level +double compute_tx_energy_level(c16_t **txdata, int nb_antennas, int offset, int length, int n_trials) +{ + double txlev_sum = 0, atxlev[nb_antennas]; + for (int aa = 0; aa < nb_antennas; aa++) { + atxlev[aa] = signal_energy((int32_t *)&txdata[aa][offset], length); + + txlev_sum += atxlev[aa]; + + if (n_trials == 1) + printf("txlev[%d] = %f (%f dB) txlev_sum %f\n", aa, atxlev[aa], 10 * log10(atxlev[aa]), txlev_sum); + } + return txlev_sum; +} + +// Computes noise variance from the input transmit energy and SNR +double compute_noise_variance(double txlev_sum, uint16_t ofdm_symbol_size, int N_RB, double SNR, int n_trials) +{ + double sigma_dB = 10 * log10(txlev_sum * ((double)ofdm_symbol_size / (12 * N_RB))) - SNR; + double sigma = pow(10, sigma_dB / 10); + + if (n_trials == 1) + printf("sigma %f (%f dB), txlev_sum %f (factor %f)\n", + sigma, + sigma_dB, + 10 * log10(txlev_sum), + (double)(double)ofdm_symbol_size / (12 * N_RB)); + return sigma; +} diff --git a/openair1/PHY/TOOLS/tools_defs.h b/openair1/PHY/TOOLS/tools_defs.h index c5a8ab13b7..2f7bd438d6 100644 --- a/openair1/PHY/TOOLS/tools_defs.h +++ b/openair1/PHY/TOOLS/tools_defs.h @@ -927,6 +927,9 @@ double signal_energy_fp(double *s_re[2], double *s_im[2], uint32_t nb_antennas, */ double signal_energy_fp2(struct complexd *s, uint32_t length); +double compute_tx_energy_level(c16_t **txdata, int nb_antennas, int offset, int length, int n_trials); + +double compute_noise_variance(double txlev_sum, uint16_t ofdm_symbol_size, int N_RB, double SNR, int n_trials); int32_t iSqrt(int32_t value); uint8_t log2_approx(uint32_t); diff --git a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c index 745f4961bf..bc2a803de8 100644 --- a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c +++ b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c @@ -400,15 +400,14 @@ void phy_procedures_nrUE_TX(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, n const NR_UE_PRACH *prach_var = ue->prach_vars[proc->gNB_id]; if (!prach_var->active) { start_meas_nr_ue_phy(ue, OFDM_MOD_STATS); - nr_ue_pusch_common_procedures(ue, - proc->nr_slot_tx, - &ue->frame_parms, - ue->frame_parms.nb_antennas_tx, - (c16_t **)txdataF, - txp, - link_type_ul, - was_symbol_used, - ue->no_phase_pre_comp); + nr_tx_rotation_and_ofdm_mod(proc->nr_slot_tx, + &ue->frame_parms, + ue->frame_parms.nb_antennas_tx, + (c16_t **)txdataF, + txp, + link_type_ul, + was_symbol_used, + ue->no_phase_pre_comp); stop_meas_nr_ue_phy(ue, OFDM_MOD_STATS); } diff --git a/openair1/SCHED_NR_UE/phy_procedures_nr_ue_sl.c b/openair1/SCHED_NR_UE/phy_procedures_nr_ue_sl.c index d1bbb7ae99..40f3a8256b 100644 --- a/openair1/SCHED_NR_UE/phy_procedures_nr_ue_sl.c +++ b/openair1/SCHED_NR_UE/phy_procedures_nr_ue_sl.c @@ -315,15 +315,14 @@ void phy_procedures_nrUE_SL_TX(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc was_symbol_used[i] = true; if (tx_action) { LOG_D(NR_PHY, "Sending Uplink data \n"); - nr_ue_pusch_common_procedures(ue, - proc->nr_slot_tx, - fp, - fp->nb_antennas_tx, - txdataF, - txp, - link_type_sl, - was_symbol_used, - ue->no_phase_pre_comp); + nr_tx_rotation_and_ofdm_mod(proc->nr_slot_tx, + fp, + fp->nb_antennas_tx, + txdataF, + txp, + link_type_sl, + was_symbol_used, + ue->no_phase_pre_comp); } LOG_D(NR_PHY, "****** end Sidelink TX-Chain for AbsSubframe %d.%d ******\n", frame_tx, slot_tx); diff --git a/openair1/SIMULATION/NR_PHY/srssim.c b/openair1/SIMULATION/NR_PHY/srssim.c index f83da5941e..6ce6d3b897 100644 --- a/openair1/SIMULATION/NR_PHY/srssim.c +++ b/openair1/SIMULATION/NR_PHY/srssim.c @@ -88,7 +88,6 @@ int main(int argc, char *argv[]) sigaction(SIGINT, &sigint_action, &oldaction); double SNR, snr0 = 0, snr1 = 20.0; - double sigma, sigma_dB; double snr_step = 1; uint8_t snr1set = 0; double **s_re, **s_im, **r_re, **r_im; @@ -105,7 +104,6 @@ int main(int argc, char *argv[]) int srs_comb_offset = 0; int srs_cyclic_shift = 0; int nb_symb_srs = 0; - int32_t txlev_sum = 0, atxlev[4]; int i; int loglvl = OAILOG_WARNING; int print_perf = 0; @@ -502,44 +500,31 @@ int main(int argc, char *argv[]) uint16_t ofdm_symbol_size = fp->ofdm_symbol_size; int slot_offsetF = (slot % RU_RX_SLOT_DEPTH) * NR_SYMBOLS_PER_SLOT * ofdm_symbol_size; - c16_t *txF[fp->nb_antennas_tx]; - for (i = 0; i < fp->nb_antennas_tx; i++) + c16_t *txF[n_tx]; + for (i = 0; i < n_tx; i++) txF[i] = txdataF[i] + slot_offsetF; + c16_t *txd[n_tx]; + for (i = 0; i < n_tx; i++) + txd[i] = txdata[i] + slot_offset; + ue_srs_procedures_nr(UE, &proc, (c16_t **)txF, &phy_data, was_symbol_used); //------------ TX rotation and OFDM Modulation -------------------------- - - for (int aa = 0; aa < fp->nb_antennas_tx; aa++) { - apply_nr_rotation_TX(fp, &txF[aa][0], fp->symbol_rotation[1], slot, fp->N_RB_UL, 0, fp->Ncp == EXTENDED ? 12 : 14); - if (srs_pdu.cyclic_prefix == 1) { - for (i = 0; i < NR_NUMBER_OF_SYMBOLS_PER_SLOT_EXTENDED_CP; i++) { - if (was_symbol_used[i] == true) { - PHY_ofdm_mod((int *)&txF[aa][0], - (int *)&txdata[aa][slot_offset + (ofdm_symbol_size + fp->nb_prefix_samples) * i], - ofdm_symbol_size, - 1, - fp->nb_prefix_samples, - CYCLIC_PREFIX); - } - } - } else { - nr_normal_prefix_mod(&txF[aa][0], &txdata[aa][slot_offset], fp->symbols_per_slot, fp, slot, was_symbol_used); - } - } + nr_tx_rotation_and_ofdm_mod(slot, fp, n_tx, txF, txd, link_type_ul, was_symbol_used, false); //----------- Apply propagation channel and add noise ---------------------------- double ts = 1.0 / (fp->subcarrier_spacing * ofdm_symbol_size); for (i = 0; i < slot_length; i++) { - for (int aa = 0; aa < UE->frame_parms.nb_antennas_tx; aa++) { + for (int aa = 0; aa < n_tx; aa++) { s_re[aa][i] = (double)txdata[aa][slot_offset + i].r; s_im[aa][i] = (double)txdata[aa][slot_offset + i].i; } } - // Compute SRS symbol offset + // Compute SRS symbol offset and length int symbol_offset = slot_offset; int abs_first_symbol = slot * fp->symbols_per_slot; int idx_sym; @@ -547,19 +532,10 @@ int main(int argc, char *argv[]) symbol_offset += (idx_sym % (0x7 << fp->numerology_index)) ? fp->nb_prefix_samples : fp->nb_prefix_samples0; symbol_offset += ofdm_symbol_size * srs_pdu.time_start_position; + int symbol_length = ofdm_symbol_size + (idx_sym % (0x7 << fp->numerology_index)) ? fp->nb_prefix_samples : fp->nb_prefix_samples0; - // Compute transmitter level - txlev_sum = 0; - for (int aa = 0; aa < UE->frame_parms.nb_antennas_tx; aa++) { - atxlev[aa] = signal_energy( - (int32_t *)&txdata[aa][symbol_offset], - ofdm_symbol_size + (idx_sym % (0x7 << fp->numerology_index)) ? fp->nb_prefix_samples : fp->nb_prefix_samples0); - - txlev_sum += atxlev[aa]; - - if (n_trials == 1) - printf("txlev[%d] = %d (%f dB) txlev_sum %d\n", aa, atxlev[aa], 10 * log10((double)atxlev[aa]), txlev_sum); - } + // Compute transmitter energy level + double txlev_sum = compute_tx_energy_level(txdata, n_tx, symbol_offset, symbol_length, n_trials); for (SNR = snr0; SNR <= snr1 && !stop; SNR += snr_step) { varArray_t *table_rx = initVarArray(1000, sizeof(double)); @@ -573,15 +549,7 @@ int main(int argc, char *argv[]) int tao_ns_count = 0; for (trial = 0; trial < n_trials && !stop; trial++) { // Estimate noise power from the transmitter level and SNR - sigma_dB = 10 * log10(((double)txlev_sum) * ((double)ofdm_symbol_size / (12 * srs_pdu.bwp_size))) - SNR; - sigma = pow(10, sigma_dB / 10); - - if (n_trials == 1) - printf("sigma %f (%f dB), txlev_sum %f (factor %f)\n", - sigma, - sigma_dB, - 10 * log10((double)txlev_sum), - (double)(double)ofdm_symbol_size / (12 * srs_pdu.bwp_size)); + double sigma = compute_noise_variance(txlev_sum, ofdm_symbol_size, srs_pdu.bwp_size, SNR, n_trials); //----------- Apply propagation channel ---------------------------- multipath_channel(UE2gNB, s_re, s_im, r_re, r_im, slot_length, 0, (n_trials == 1) ? 1 : 0); @@ -590,34 +558,24 @@ int main(int argc, char *argv[]) add_noise(rxdata, (const double **)r_re, (const double **)r_im, - sigma, + sigma, // noise power slot_length, slot_offset, ts, 0, // delay 0, // pdu_bit_map 0, // PTRS_BITMAP, - fp->nb_antennas_rx); + n_rx); //----------- OFDM Demodulation and RX rotation-------------------------- - - for (uint8_t symbol = 0; symbol < (fp->Ncp == EXTENDED ? 12 : 14); symbol++) { - for (int aa = 0; aa < fp->nb_antennas_rx; aa++) - nr_slot_fep_ul(fp, (int32_t *)&rxdata[aa][0], (int32_t *)&gNB->common_vars.rxdataF[0][aa][slot_offsetF], symbol, slot, 0); - } - - for (int aa = 0; aa < fp->nb_antennas_rx; aa++) { - for (uint8_t symbol = 0; symbol < fp->symbols_per_slot; symbol++) { - if (was_symbol_used[symbol] == true) { - apply_nr_rotation_symbol_RX(fp, - &gNB->common_vars.rxdataF[0][aa][slot_offsetF + symbol * fp->ofdm_symbol_size], - fp->symbol_rotation[1], - fp->N_RB_UL, - slot, - symbol); - } - } - } + nr_ofdm_demod_and_rx_rotation(rxdata, + gNB->common_vars.rxdataF[0], + fp, + n_rx, + slot, + slot_offsetF, + link_type_ul, + was_symbol_used); //----------- UE RX SRS procedures --------------------- @@ -625,18 +583,17 @@ int main(int argc, char *argv[]) NR_gNB_SRS_t *srs = &gNB->srs[0]; uint8_t N_symb_SRS = 1 << srs->srs_pdu.num_symbols; uint8_t N_ap = 1 << srs->srs_pdu.num_ant_ports; - uint8_t nb_antennas_rx = fp->nb_antennas_rx; int16_t snr_per_rb[srs->srs_pdu.bwp_size]; uint16_t timing_advance_offset; - int16_t timing_advance_offset_nsec[nb_antennas_rx]; + int16_t timing_advance_offset_nsec[n_rx]; int srs_est; - c16_t srs_estimated_channel_freq[nb_antennas_rx][N_ap][ofdm_symbol_size * N_symb_SRS] __attribute__((aligned(32))); - c16_t srs_estimated_channel_time[nb_antennas_rx][N_ap][ofdm_symbol_size] __attribute__((aligned(32))); + c16_t srs_estimated_channel_freq[n_rx][N_ap][ofdm_symbol_size * N_symb_SRS] __attribute__((aligned(32))); + c16_t srs_estimated_channel_time[n_rx][N_ap][ofdm_symbol_size] __attribute__((aligned(32))); nr_srs_rx_procedures(gNB, frame, slot, - nb_antennas_rx, + n_rx, N_ap, N_symb_SRS, ofdm_symbol_size, @@ -652,7 +609,7 @@ int main(int argc, char *argv[]) sum_srs_snr += pow(10, (double)gNB->srs->snr / 10.0); int16_t delay_ns = delay * 1e9 / (fp->samples_per_frame * 100); - for (int ant_idx = 0; ant_idx < nb_antennas_rx; ant_idx++) { + for (int ant_idx = 0; ant_idx < n_rx; ant_idx++) { if (n_trials == 1) printf("[RX ant %d] SRS estimated: TA offset %d, TA offset ns %d \n", ant_idx, diff --git a/openair1/SIMULATION/NR_PHY/ulsim.c b/openair1/SIMULATION/NR_PHY/ulsim.c index 18f6f3f605..c6e91d78aa 100644 --- a/openair1/SIMULATION/NR_PHY/ulsim.c +++ b/openair1/SIMULATION/NR_PHY/ulsim.c @@ -1460,26 +1460,20 @@ int main(int argc, char *argv[]) UL_INFO.crc_ind.number_crcs = 0; UL_INFO.srs_ind.number_of_pdus = 0; - for(uint8_t symbol = 0; symbol < (gNB->frame_parms.Ncp == EXTENDED ? 12 : 14); symbol++) { - for (int aa = 0; aa < gNB->frame_parms.nb_antennas_rx; aa++) - nr_slot_fep_ul(&gNB->frame_parms, - (int32_t *)rxdata[aa], - (int32_t *)gNB->common_vars.rxdataF[0][aa], - symbol, - slot, - 0); - } + //----------- OFDM Demodulation and RX rotation-------------------------- + bool was_symbol_used[14] = {0}; int offset = (slot & 3) * gNB->frame_parms.symbols_per_slot * gNB->frame_parms.ofdm_symbol_size; - for (int aa = 0; aa < gNB->frame_parms.nb_antennas_rx; aa++) { - const unsigned int max_symb = (gNB->frame_parms.Ncp == EXTENDED) ? 12 : 14; - for (int sym = 0; sym < max_symb; sym++) - apply_nr_rotation_symbol_RX(&gNB->frame_parms, - gNB->common_vars.rxdataF[0][aa] + offset + sym * gNB->frame_parms.ofdm_symbol_size, - gNB->frame_parms.symbol_rotation[1], - gNB->frame_parms.N_RB_UL, - slot, - sym); + for (int i = 0; i < 14; i++) { + was_symbol_used[i] = true; } + nr_ofdm_demod_and_rx_rotation(rxdata, + gNB->common_vars.rxdataF[0], + &gNB->frame_parms, + gNB->frame_parms.nb_antennas_rx, + slot, + offset, + link_type_ul, + was_symbol_used); ul_proc_error = phy_procedures_gNB_uespec_RX(gNB, frame, slot, &UL_INFO); From 0b0dce9995fc5237e7871686c50f029a62f62a78 Mon Sep 17 00:00:00 2001 From: Rakesh Mundlamuri Date: Wed, 29 Oct 2025 13:59:16 +0530 Subject: [PATCH 13/22] Update T traces to record toa in ns and SRS time/frequency channel over multiple rx antennas and ports --- common/utils/T/T_messages.txt | 8 +++- openair1/SCHED_NR/phy_procedures_nr_gNB.c | 58 +++++++++++++---------- 2 files changed, 40 insertions(+), 26 deletions(-) diff --git a/common/utils/T/T_messages.txt b/common/utils/T/T_messages.txt index cd81deda2b..d2405f9033 100644 --- a/common/utils/T/T_messages.txt +++ b/common/utils/T/T_messages.txt @@ -138,11 +138,11 @@ ID = GNB_PHY_UL_PAYLOAD_RX_BITS ID = GNB_PHY_UL_FREQ_CHANNEL_ESTIMATE DESC = gNodeB channel estimation in the frequency domain GROUP = ALL:PHY:GRAPHIC:HEAVY:GNB - FORMAT = int,gNB_ID : int,rnti : int,frame : int,subframe : int,antenna : buffer,chest_t + FORMAT = int,gNB_ID : int,rnti : int,frame : int,subframe : int,antenna : int,port : buffer,chest_f ID = GNB_PHY_UL_TIME_CHANNEL_ESTIMATE DESC = gNodeB channel estimation in the time domain GROUP = ALL:PHY:GRAPHIC:HEAVY:GNB - FORMAT = int,gNB_ID : int,rnti : int,frame : int,subframe : int,antenna : buffer,chest_t + FORMAT = int,gNB_ID : int,rnti : int,frame : int,subframe : int,antenna : int,port : buffer,chest_t ID = GNB_PHY_UL_SNR_ESTIMATE DESC = gNodeB SNR estimation based on SRS GROUP = ALL:PHY:GRAPHIC:HEAVY:GNB @@ -155,6 +155,10 @@ ID = GNB_PHY_DL_OUTPUT_SIGNAL DESC = gNodeB output data in the freq domain for slots GROUP = ALL:PHY:GRAPHIC:HEAVY:GNB FORMAT = int,gNB_ID : int,frame : int,slot : int,antenna : buffer,txdata +ID = GNB_PHY_UL_SRS_TOA_NS + DESC = gNB ToA estimate from SRS (in ns) + GROUP = ALL:PHY:GNB + FORMAT = int,gNB_ID : int,rnti : int,frame : int,subframe : buffer,toa_ns #MAC logs ID = ENB_MAC_UE_DL_SDU diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index 36dc8a3b5a..67fad3cc2f 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -918,7 +918,26 @@ void nr_srs_rx_procedures(PHY_VARS_gNB *gNB, &signal_power, &noise_power, noise_power_per_rb); + signal_power_avg += signal_power; + + T(T_GNB_PHY_UL_FREQ_CHANNEL_ESTIMATE, + T_INT(gNB->Mod_id), + T_INT(srs_pdu->rnti), + T_INT(frame_rx), + T_INT(slot_rx), + T_INT(ant_rx_ind), + T_INT(p_ind), + T_BUFFER(srs_estimated_channel_freq[ant_rx_ind][p_ind], ofdm_symbol_size * sizeof(c16_t))); + + T(T_GNB_PHY_UL_TIME_CHANNEL_ESTIMATE, + T_INT(gNB->Mod_id), + T_INT(srs_pdu->rnti), + T_INT(frame_rx), + T_INT(slot_rx), + T_INT(ant_rx_ind), + T_INT(p_ind), + T_BUFFER(srs_estimated_channel_time_shifted[ant_rx_ind][p_ind], ofdm_symbol_size * sizeof(c16_t))); } noise_power_avg += noise_power; } @@ -944,31 +963,22 @@ void nr_srs_rx_procedures(PHY_VARS_gNB *gNB, &timing_advance_offset_nsec[ant_rx_ind]); } stop_meas(&gNB->srs_timing_advance_stats); + + T(T_GNB_PHY_UL_SNR_ESTIMATE, + T_INT(0), + T_INT(srs_pdu->rnti), + T_INT(frame_rx), + T_INT(0), + T_INT(0), + T_BUFFER(snr_per_rb, srs_pdu->bwp_size * sizeof(int16_t))); + + T(T_GNB_PHY_UL_SRS_TOA_NS, + T_INT(gNB->Mod_id), + T_INT(srs_pdu->rnti), + T_INT(frame_rx), + T_INT(slot_rx), + T_BUFFER(timing_advance_offset_nsec, nb_antennas_rx * sizeof(int16_t))); } - - T(T_GNB_PHY_UL_FREQ_CHANNEL_ESTIMATE, - T_INT(0), - T_INT(srs_pdu->rnti), - T_INT(frame_rx), - T_INT(0), - T_INT(0), - T_BUFFER(srs_estimated_channel_freq[0][0], ofdm_symbol_size * sizeof(int32_t))); - - T(T_GNB_PHY_UL_TIME_CHANNEL_ESTIMATE, - T_INT(0), - T_INT(srs_pdu->rnti), - T_INT(frame_rx), - T_INT(0), - T_INT(0), - T_BUFFER(srs_estimated_channel_time_shifted[0][0], NR_SRS_IDFT_OVERSAMP_FACTOR * ofdm_symbol_size * sizeof(int32_t))); - - T(T_GNB_PHY_UL_SNR_ESTIMATE, - T_INT(0), - T_INT(srs_pdu->rnti), - T_INT(frame_rx), - T_INT(0), - T_INT(0), - T_BUFFER(snr_per_rb, srs_pdu->bwp_size * sizeof(int16_t))); } int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, NR_UL_IND_t *UL_INFO) From 0b197891ccd5c9304873261764ea5a26ec215656 Mon Sep 17 00:00:00 2001 From: Rakesh Mundlamuri Date: Fri, 31 Oct 2025 12:14:18 +0530 Subject: [PATCH 14/22] Introduce SRS multi-symbol channel estimation --- .../NR_ESTIMATION/nr_ul_channel_estimation.c | 444 ++++++++++-------- openair1/SCHED_NR/phy_procedures_nr_gNB.c | 2 +- openair1/SIMULATION/NR_PHY/srssim.c | 2 +- openair1/SIMULATION/tests/CMakeLists.txt | 5 + 4 files changed, 245 insertions(+), 208 deletions(-) diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c index 0906321e87..c3a13e94a2 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c +++ b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c @@ -800,244 +800,276 @@ int nr_srs_channel_estimation(int ant, if (N_ap == 4 && ((K_TC == 2 && srs_pdu->cyclic_shift >= 4) || (K_TC == 4 && srs_pdu->cyclic_shift >= 6))) { fd_cdm = 2; } + uint16_t subcarrier; c16_t srs_ls_estimated_channel[ofdm_symbol_size * N_symb_SRS]; - uint8_t mem_offset = ((16 - ((intptr_t)&srs_estimated_channel_freq[subcarrier_offset + nr_srs_info->k_0_p[p_index][0]])) & 0xF) - >> 2; // >> 2 <=> /sizeof(int32_t) - - // filt16_end is {4096,8192,8192,8192,12288,16384,16384,16384,0,0,0,0,0,0,0,0} - // The End of OFDM symbol corresponds to the position of last 16384 in the filter - // The c16multaddVectRealComplex applies the remaining 8 zeros of filter, therefore, to avoid a buffer overflow, - // we added 8 in the array size - c16_t srs_est[ofdm_symbol_size * N_symb_SRS + mem_offset + 8] __attribute__((aligned(32))); - c16_t ls_estimated = {0}; - + c16_t srs_estimated_channel_freq_avg[ofdm_symbol_size]; memset(srs_ls_estimated_channel, 0, ofdm_symbol_size * N_symb_SRS * sizeof(c16_t)); - memset(srs_est, 0, (ofdm_symbol_size * N_symb_SRS + mem_offset) * sizeof(c16_t)); + memset(srs_estimated_channel_freq_avg, 0, ofdm_symbol_size * sizeof(c16_t)); + + for (int srs_symb = 0; srs_symb < N_symb_SRS; srs_symb++) { + uint16_t srs_symbol_offset = srs_symb * ofdm_symbol_size; + + uint8_t mem_offset = + ((16 + - ((intptr_t)&srs_estimated_channel_freq[srs_symbol_offset + subcarrier_offset + nr_srs_info->k_0_p[p_index][srs_symb]])) + & 0xF) + >> 2; // >> 2 <=> /sizeof(int32_t) + + // filt16_end is {4096,8192,8192,8192,12288,16384,16384,16384,0,0,0,0,0,0,0,0} + // The End of OFDM symbol corresponds to the position of last 16384 in the filter + // The c16multaddVectRealComplex applies the remaining 8 zeros of filter, therefore, to avoid a buffer overflow, + // we added 8 in the array size + c16_t srs_est[ofdm_symbol_size + mem_offset + 8] __attribute__((aligned(32))); + c16_t ls_estimated = {0}; + + memset(srs_est, 0, (ofdm_symbol_size + mem_offset + 8) * sizeof(c16_t)); #ifdef SRS_DEBUG - LOG_I(NR_PHY, "====================== UE port %d --> gNB Rx antenna %i ======================\n", p_index, ant); + LOG_I(NR_PHY, "====================== UE port %d --> gNB Rx antenna %i ======================\n", p_index, ant); + LOG_I(NR_PHY, "============================== SRS symbol index %d ===========================\n", srs_symb); #endif - uint16_t subcarrier = subcarrier_offset + nr_srs_info->k_0_p[p_index][0]; - if (subcarrier >= ofdm_symbol_size) { - subcarrier -= ofdm_symbol_size; - } + subcarrier = subcarrier_offset + nr_srs_info->k_0_p[p_index][srs_symb]; + if (subcarrier >= ofdm_symbol_size) { + subcarrier -= ofdm_symbol_size; + } - c16_t *srs_estimated_channel16 = &srs_est[subcarrier + mem_offset]; + c16_t *srs_estimated_channel16 = &srs_est[subcarrier + mem_offset]; - for (int k = 0; k < M_sc_b_SRS; k++) { - if (k % fd_cdm == 0) { - ls_estimated = (c16_t){0, 0}; - uint16_t subcarrier_cdm = subcarrier; + for (int k = 0; k < M_sc_b_SRS; k++) { + if (k % fd_cdm == 0) { + ls_estimated = (c16_t){0, 0}; + uint16_t subcarrier_cdm = subcarrier; - for (int cdm_idx = 0; cdm_idx < fd_cdm; cdm_idx++) { - c16_t generated_srs = srs_generated_signal[subcarrier_cdm]; - c16_t received_srs = srs_received_signal[subcarrier_cdm]; - // We know that nr_srs_info->srs_generated_signal_bits bits are enough to represent the real and imaginary parts of - // generated_srs. So we only need a nr_srs_info->srs_generated_signal_bits shift to ensure that the result fits into 16 - // bits. - ls_estimated = c16maddConjShift(generated_srs, received_srs, ls_estimated, nr_srs_info->srs_generated_signal_bits); + for (int cdm_idx = 0; cdm_idx < fd_cdm; cdm_idx++) { + c16_t generated_srs = srs_generated_signal[srs_symbol_offset + subcarrier_cdm]; + c16_t received_srs = srs_received_signal[srs_symbol_offset + subcarrier_cdm]; + // We know that nr_srs_info->srs_generated_signal_bits bits are enough to represent the real and imaginary parts of + // generated_srs. So we only need a nr_srs_info->srs_generated_signal_bits shift to ensure that the result fits into 16 + // bits. + ls_estimated = c16maddConjShift(generated_srs, received_srs, ls_estimated, nr_srs_info->srs_generated_signal_bits); - // Subcarrier increment - subcarrier_cdm += K_TC; - if (subcarrier_cdm >= ofdm_symbol_size) { - subcarrier_cdm = subcarrier_cdm - ofdm_symbol_size; - } + // Subcarrier increment + subcarrier_cdm += K_TC; + if (subcarrier_cdm >= ofdm_symbol_size) { + subcarrier_cdm = subcarrier_cdm - ofdm_symbol_size; } } + } - srs_ls_estimated_channel[subcarrier] = ls_estimated; + srs_ls_estimated_channel[srs_symbol_offset + subcarrier] = ls_estimated; #ifdef SRS_DEBUG - int subcarrier_log = subcarrier - subcarrier_offset; - if (subcarrier_log < 0) { - subcarrier_log = subcarrier_log + ofdm_symbol_size; - } - if (subcarrier_log % 12 == 0) { - LOG_I(NR_PHY, "------------------------------------ %d ------------------------------------\n", subcarrier_log / 12); - LOG_I(NR_PHY, "\t __genRe________genIm__|____rxRe_________rxIm__|____lsRe________lsIm_\n"); - } - LOG_I(NR_PHY, - "(%4i) %6i\t%6i | %6i\t%6i | %6i\t%6i\n", - subcarrier_log, - srs_generated_signal[subcarrier].r, - srs_generated_signal[subcarrier].i, - srs_received_signal[subcarrier].r, - srs_received_signal[subcarrier].i, - ls_estimated.r, - ls_estimated.i); + int subcarrier_log = subcarrier - subcarrier_offset; + if (subcarrier_log < 0) { + subcarrier_log = subcarrier_log + ofdm_symbol_size; + } + if (subcarrier_log % 12 == 0) { + LOG_I(NR_PHY, "------------------------------------ %d ------------------------------------\n", subcarrier_log / 12); + LOG_I(NR_PHY, "\t __genRe________genIm__|____rxRe_________rxIm__|____lsRe________lsIm_\n"); + } + LOG_I(NR_PHY, + "(%4i) %6i\t%6i | %6i\t%6i | %6i\t%6i\n", + subcarrier_log, + srs_generated_signal[srs_symbol_offset + subcarrier].r, + srs_generated_signal[srs_symbol_offset + subcarrier].i, + srs_received_signal[srs_symbol_offset + subcarrier].r, + srs_received_signal[srs_symbol_offset + subcarrier].i, + ls_estimated.r, + ls_estimated.i); #endif - const uint16_t sc_offset = subcarrier + mem_offset; + const uint16_t sc_offset = subcarrier + mem_offset; - // Channel interpolation - if (srs_pdu->comb_size == 0) { - if (k == 0) { // First subcarrier case - // filt8_start is {12288,8192,4096,0,0,0,0,0} - c16multaddVectRealComplex(filt8_start, &ls_estimated, srs_estimated_channel16, 8); - } else if (subcarrier < K_TC) { // Start of OFDM symbol case - // filt8_start is {12288,8192,4096,0,0,0,0,0} - srs_estimated_channel16 = &srs_est[subcarrier]; - const short *filter = mem_offset == 0 ? filt8_start : filt8_start_shift2; - c16multaddVectRealComplex(filter, &ls_estimated, srs_estimated_channel16, 8); - } else if ((subcarrier + K_TC) >= ofdm_symbol_size - || k == (M_sc_b_SRS - 1)) { // End of OFDM symbol or last subcarrier cases - // filt8_end is {4096,8192,12288,16384,0,0,0,0} - const short *filter = mem_offset == 0 || k == (M_sc_b_SRS - 1) ? filt8_end : filt8_end_shift2; - c16multaddVectRealComplex(filter, &ls_estimated, srs_estimated_channel16, 8); - } else if (k % 2 == 1) { // 1st middle case - // filt8_middle2 is {4096,8192,8192,8192,4096,0,0,0} - c16multaddVectRealComplex(filt8_middle2, &ls_estimated, srs_estimated_channel16, 8); - } else if (k % 2 == 0) { // 2nd middle case - // filt8_middle4 is {0,0,4096,8192,8192,8192,4096,0} - c16multaddVectRealComplex(filt8_middle4, &ls_estimated, srs_estimated_channel16, 8); - srs_estimated_channel16 = &srs_est[sc_offset]; - } - } else { - if (k == 0) { // First subcarrier case - // filt16_start is {12288,8192,8192,8192,4096,0,0,0,0,0,0,0,0,0,0,0} - c16multaddVectRealComplex(filt16_start, &ls_estimated, srs_estimated_channel16, 16); - } else if (subcarrier < K_TC) { // Start of OFDM symbol case - srs_estimated_channel16 = &srs_est[sc_offset]; - // filt16_start is {12288,8192,8192,8192,4096,0,0,0,0,0,0,0,0,0,0,0} - c16multaddVectRealComplex(filt16_start, &ls_estimated, srs_estimated_channel16, 16); - } else if ((subcarrier + K_TC) >= ofdm_symbol_size - || k == (M_sc_b_SRS - 1)) { // End of OFDM symbol or last subcarrier cases - // filt16_end is {4096,8192,8192,8192,12288,16384,16384,16384,0,0,0,0,0,0,0,0} - c16multaddVectRealComplex(filt16_end, &ls_estimated, srs_estimated_channel16, 16); - } else { // Middle case - // filt16_middle4 is {4096,8192,8192,8192,8192,8192,8192,8192,4096,0,0,0,0,0,0,0} - c16multaddVectRealComplex(filt16_middle4, &ls_estimated, srs_estimated_channel16, 16); - srs_estimated_channel16 = &srs_est[sc_offset]; - } - } - - // Subcarrier increment - subcarrier += K_TC; - if (subcarrier >= ofdm_symbol_size) { - subcarrier -= ofdm_symbol_size; - } - - } // for (int k = 0; k < M_sc_b_SRS; k++) - - memcpy(srs_estimated_channel_freq, &srs_est[mem_offset], (ofdm_symbol_size * N_symb_SRS) * sizeof(c16_t)); - -#ifdef SRS_DEBUG - subcarrier = subcarrier_offset + nr_srs_info->k_0_p[p_index][0]; - if (subcarrier >= ofdm_symbol_size) { - subcarrier -= ofdm_symbol_size; - } - - for (int k = 0; k < K_TC * M_sc_b_SRS; k++) { - int subcarrier_log = subcarrier - subcarrier_offset; - if (subcarrier_log < 0) { - subcarrier_log = subcarrier_log + ofdm_symbol_size; - } - - if (subcarrier_log % 12 == 0) { - LOG_I(NR_PHY, "------------------------------------- %d -------------------------------------\n", subcarrier_log / 12); - LOG_I(NR_PHY, "\t __lsRe__________lsIm__|____intRe_______intIm__|____noiRe_______noiIm__\n"); - } - - LOG_I(NR_PHY, - "(%4i) %6i\t%6i | %6i\t%6i | %6i\t%6i\n", - subcarrier_log, - srs_ls_estimated_channel[subcarrier].r, - srs_ls_estimated_channel[subcarrier].i, - srs_estimated_channel_freq[subcarrier].r, - srs_estimated_channel_freq[subcarrier].i, - srs_received_noise[subcarrier].r, - srs_received_noise[subcarrier].i); - - // Subcarrier increment - subcarrier++; - if (subcarrier >= ofdm_symbol_size) { - subcarrier -= ofdm_symbol_size; - } - } -#endif - - // Convert to time domain - int16_t ofdm_symbol_size_half = ofdm_symbol_size >> 1; - int16_t ofdm_os_size = NR_SRS_IDFT_OVERSAMP_FACTOR * ofdm_symbol_size; - int16_t ofdm_os_size_half = ofdm_os_size >> 1; - int16_t start_offset = ofdm_os_size - ofdm_symbol_size_half; - - c16_t chF_interpol[ofdm_os_size] __attribute__((aligned(32))); - memset(chF_interpol, 0, sizeof(chF_interpol)); - - // Place SRS channel estimates in FFT shifted format for oversampling - memcpy(&chF_interpol[0], &srs_estimated_channel_freq[0], ofdm_symbol_size_half * sizeof(c16_t)); - memcpy(&chF_interpol[start_offset], - &srs_estimated_channel_freq[ofdm_symbol_size_half], - ofdm_symbol_size_half * sizeof(c16_t)); - - // Convert to time domain oversampled - freq2time(ofdm_os_size, (int16_t *)chF_interpol, (int16_t *)srs_estimated_channel_time); - - // Do FFT shift - memcpy(srs_estimated_channel_time_shifted, &srs_estimated_channel_time[ofdm_os_size_half], ofdm_os_size_half * sizeof(c16_t)); - - memcpy(&srs_estimated_channel_time_shifted[ofdm_os_size_half], srs_estimated_channel_time, ofdm_os_size_half * sizeof(c16_t)); - - // Compute wideband SNR - int tot_subcarriers = m_SRS_b * NR_NB_SC_PER_RB; - subcarrier = subcarrier_offset + nr_srs_info->k_0_p[p_index][0]; - if (subcarrier >= ofdm_symbol_size) { - subcarrier -= ofdm_symbol_size; - } - if (subcarrier + tot_subcarriers < ofdm_symbol_size) { - *signal_power = signal_energy_nodc(&srs_estimated_channel_freq[subcarrier], tot_subcarriers) / tot_subcarriers; - if (p_index == 0) { - *noise_power = signal_energy_nodc(&srs_received_noise[subcarrier], tot_subcarriers) / tot_subcarriers; + // Channel interpolation + if (srs_pdu->comb_size == 0) { + if (k == 0) { // First subcarrier case + // filt8_start is {12288,8192,4096,0,0,0,0,0} + c16multaddVectRealComplex(filt8_start, &ls_estimated, srs_estimated_channel16, 8); + } else if (subcarrier < K_TC) { // Start of OFDM symbol case + // filt8_start is {12288,8192,4096,0,0,0,0,0} + srs_estimated_channel16 = &srs_est[subcarrier]; + const short *filter = mem_offset == 0 ? filt8_start : filt8_start_shift2; + c16multaddVectRealComplex(filter, &ls_estimated, srs_estimated_channel16, 8); + } else if ((subcarrier + K_TC) >= ofdm_symbol_size + || k == (M_sc_b_SRS - 1)) { // End of OFDM symbol or last subcarrier cases + // filt8_end is {4096,8192,12288,16384,0,0,0,0} + const short *filter = mem_offset == 0 || k == (M_sc_b_SRS - 1) ? filt8_end : filt8_end_shift2; + c16multaddVectRealComplex(filter, &ls_estimated, srs_estimated_channel16, 8); + } else if (k % 2 == 1) { // 1st middle case + // filt8_middle2 is {4096,8192,8192,8192,4096,0,0,0} + c16multaddVectRealComplex(filt8_middle2, &ls_estimated, srs_estimated_channel16, 8); + } else if (k % 2 == 0) { // 2nd middle case + // filt8_middle4 is {0,0,4096,8192,8192,8192,4096,0} + c16multaddVectRealComplex(filt8_middle4, &ls_estimated, srs_estimated_channel16, 8); + srs_estimated_channel16 = &srs_est[sc_offset]; } } else { - int size1 = ofdm_symbol_size - subcarrier; - int size2 = tot_subcarriers - size1; - uint64_t signal_power_p1 = signal_energy_nodc(&srs_estimated_channel_freq[subcarrier], size1) * size1; - uint64_t signal_power_p2 = signal_energy_nodc(&srs_estimated_channel_freq[0], size2) * size2; - *signal_power = (signal_power_p1 + signal_power_p2) / tot_subcarriers; - if (p_index == 0) { - uint64_t noise_power_p1 = signal_energy_nodc(&srs_received_noise[subcarrier], size1) * size1; - uint64_t noise_power_p2 = signal_energy_nodc(&srs_received_noise[0], size2) * size2; - *noise_power = (noise_power_p1 + noise_power_p2) / tot_subcarriers; + if (k == 0) { // First subcarrier case + // filt16_start is {12288,8192,8192,8192,4096,0,0,0,0,0,0,0,0,0,0,0} + c16multaddVectRealComplex(filt16_start, &ls_estimated, srs_estimated_channel16, 16); + } else if (subcarrier < K_TC) { // Start of OFDM symbol case + srs_estimated_channel16 = &srs_est[sc_offset]; + // filt16_start is {12288,8192,8192,8192,4096,0,0,0,0,0,0,0,0,0,0,0} + c16multaddVectRealComplex(filt16_start, &ls_estimated, srs_estimated_channel16, 16); + } else if ((subcarrier + K_TC) >= ofdm_symbol_size + || k == (M_sc_b_SRS - 1)) { // End of OFDM symbol or last subcarrier cases + // filt16_end is {4096,8192,8192,8192,12288,16384,16384,16384,0,0,0,0,0,0,0,0} + c16multaddVectRealComplex(filt16_end, &ls_estimated, srs_estimated_channel16, 16); + } else { // Middle case + // filt16_middle4 is {4096,8192,8192,8192,8192,8192,8192,8192,4096,0,0,0,0,0,0,0} + c16multaddVectRealComplex(filt16_middle4, &ls_estimated, srs_estimated_channel16, 16); + srs_estimated_channel16 = &srs_est[sc_offset]; } } - *signal_power = max(*signal_power, 1); - if (*signal_power == 0) { - LOG_W(NR_PHY, "Received SRS signal power is 0\n"); - return -1; + // Subcarrier increment + subcarrier += K_TC; + if (subcarrier >= ofdm_symbol_size) { + subcarrier -= ofdm_symbol_size; } - // Compute SNR per RB for port 0 - if (p_index == 0) { - subcarrier = subcarrier_offset + nr_srs_info->k_0_p[p_index][0]; - for (int rb = 0; rb < m_SRS_b; rb++) { - if (subcarrier >= ofdm_symbol_size) { - subcarrier -= ofdm_symbol_size; - } - if (subcarrier + NR_NB_SC_PER_RB < ofdm_symbol_size) { - noise_power_per_rb[rb] += signal_energy_nodc(&srs_received_noise[subcarrier], NR_NB_SC_PER_RB); - } else { - int size1 = ofdm_symbol_size - subcarrier; - int size2 = NR_NB_SC_PER_RB - size1; - uint32_t noise_power_per_rb1 = signal_energy_nodc(&srs_received_noise[subcarrier], size1) * size1; - uint32_t noise_power_per_rb2 = signal_energy_nodc(&srs_received_noise[0], size2) * size2; - noise_power_per_rb[rb] += (noise_power_per_rb1 + noise_power_per_rb2) / NR_NB_SC_PER_RB; - } - noise_power_per_rb[rb] = max(noise_power_per_rb[rb], 1); - subcarrier += NR_NB_SC_PER_RB; + } // for (int k = 0; k < M_sc_b_SRS; k++) + + memcpy(&srs_estimated_channel_freq[srs_symbol_offset], &srs_est[mem_offset], ofdm_symbol_size * sizeof(c16_t)); + + // Average srs channel estimates over multiple symbols + int16_t scale_factor = (1 << 15) / N_symb_SRS; + multadd_complex_vector_real_scalar(&srs_estimated_channel_freq[srs_symbol_offset], + scale_factor, + srs_estimated_channel_freq_avg, + ofdm_symbol_size); #ifdef SRS_DEBUG - LOG_I(NR_PHY, "[RB %3i] noise_power_per_rb = %i, snr_per_rb = %i dB\n", rb, noise_power_per_rb, snr_per_rb[rb]); + subcarrier = subcarrier_offset + nr_srs_info->k_0_p[p_index][srs_symb]; + if (subcarrier >= ofdm_symbol_size) { + subcarrier -= ofdm_symbol_size; + } + + for (int k = 0; k < K_TC * M_sc_b_SRS; k++) { + int subcarrier_log = subcarrier - subcarrier_offset; + if (subcarrier_log < 0) { + subcarrier_log = subcarrier_log + ofdm_symbol_size; + } + + if (subcarrier_log % 12 == 0) { + LOG_I(NR_PHY, + "---------------------------- PRB %d, symbol %d -------------------------------\n", + subcarrier_log / 12, + srs_symb); + LOG_I(NR_PHY, "\t __lsRe__________lsIm__|____intRe_______intIm__|____noiRe_______noiIm__\n"); + } + + LOG_I(NR_PHY, + "(%4i) %6i\t%6i | %6i\t%6i | %6i\t%6i\n", + subcarrier_log, + srs_ls_estimated_channel[srs_symbol_offset + subcarrier].r, + srs_ls_estimated_channel[srs_symbol_offset + subcarrier].i, + srs_estimated_channel_freq[srs_symbol_offset + subcarrier].r, + srs_estimated_channel_freq[srs_symbol_offset + subcarrier].i, + srs_received_noise[srs_symbol_offset + subcarrier].r, + srs_received_noise[srs_symbol_offset + subcarrier].i); + + // Subcarrier increment + subcarrier++; + if (subcarrier >= ofdm_symbol_size) { + subcarrier -= ofdm_symbol_size; + } + } #endif - } + } + + // Convert to time domain + int16_t ofdm_symbol_size_half = ofdm_symbol_size >> 1; + int16_t ofdm_os_size = NR_SRS_IDFT_OVERSAMP_FACTOR * ofdm_symbol_size; + int16_t ofdm_os_size_half = ofdm_os_size >> 1; + int16_t start_offset = ofdm_os_size - ofdm_symbol_size_half; + + c16_t chF_interpol[ofdm_os_size] __attribute__((aligned(32))); + memset(chF_interpol, 0, sizeof(chF_interpol)); + + // Place SRS channel estimates in FFT shifted format for oversampling + memcpy(&chF_interpol[0], &srs_estimated_channel_freq_avg[0], ofdm_symbol_size_half * sizeof(c16_t)); + memcpy(&chF_interpol[start_offset], + &srs_estimated_channel_freq_avg[ofdm_symbol_size_half], + ofdm_symbol_size_half * sizeof(c16_t)); + + // Convert to time domain oversampled + freq2time(ofdm_os_size, (int16_t *)chF_interpol, (int16_t *)srs_estimated_channel_time); + + // Do FFT shift + memcpy(srs_estimated_channel_time_shifted, &srs_estimated_channel_time[ofdm_os_size_half], ofdm_os_size_half * sizeof(c16_t)); + + memcpy(&srs_estimated_channel_time_shifted[ofdm_os_size_half], srs_estimated_channel_time, ofdm_os_size_half * sizeof(c16_t)); + + // Compute wideband SNR on the symbol 0 + int tot_subcarriers = m_SRS_b * NR_NB_SC_PER_RB; + subcarrier = subcarrier_offset + nr_srs_info->k_0_p[p_index][0]; + if (subcarrier >= ofdm_symbol_size) { + subcarrier -= ofdm_symbol_size; + } + if (subcarrier + tot_subcarriers < ofdm_symbol_size) { + *signal_power = signal_energy_nodc(&srs_estimated_channel_freq[subcarrier], tot_subcarriers) / tot_subcarriers; + if (p_index == 0) { + *noise_power = signal_energy_nodc(&srs_received_noise[subcarrier], tot_subcarriers) / tot_subcarriers; + } + } else { + int size1 = ofdm_symbol_size - subcarrier; + int size2 = tot_subcarriers - size1; + uint64_t signal_power_p1 = signal_energy_nodc(&srs_estimated_channel_freq[subcarrier], size1) * size1; + uint64_t signal_power_p2 = signal_energy_nodc(&srs_estimated_channel_freq[0], size2) * size2; + *signal_power = (signal_power_p1 + signal_power_p2) / tot_subcarriers; + if (p_index == 0) { + uint64_t noise_power_p1 = signal_energy_nodc(&srs_received_noise[subcarrier], size1) * size1; + uint64_t noise_power_p2 = signal_energy_nodc(&srs_received_noise[0], size2) * size2; + *noise_power = (noise_power_p1 + noise_power_p2) / tot_subcarriers; + } + } + + *signal_power = max(*signal_power, 1); + if (*signal_power == 0) { + LOG_W(NR_PHY, "Received SRS signal power is 0\n"); + return -1; + } + + // Compute SNR per RB for port 0 and symbol 0 + if (p_index == 0) { + subcarrier = subcarrier_offset + nr_srs_info->k_0_p[p_index][0]; + for (int rb = 0; rb < m_SRS_b; rb++) { + if (subcarrier >= ofdm_symbol_size) { + subcarrier -= ofdm_symbol_size; } + if (subcarrier + NR_NB_SC_PER_RB < ofdm_symbol_size) { + noise_power_per_rb[rb] += signal_energy_nodc(&srs_received_noise[subcarrier], NR_NB_SC_PER_RB); + } else { + int size1 = ofdm_symbol_size - subcarrier; + int size2 = NR_NB_SC_PER_RB - size1; + uint32_t noise_power_per_rb1 = signal_energy_nodc(&srs_received_noise[subcarrier], size1) * size1; + uint32_t noise_power_per_rb2 = signal_energy_nodc(&srs_received_noise[0], size2) * size2; + noise_power_per_rb[rb] += (noise_power_per_rb1 + noise_power_per_rb2) / NR_NB_SC_PER_RB; + } + noise_power_per_rb[rb] = max(noise_power_per_rb[rb], 1); + subcarrier += NR_NB_SC_PER_RB; #ifdef SRS_DEBUG - LOG_I(NR_PHY, "signal_power = %i dB, noise_power = %i dB, SNR = %i dB\n", dB_fixed(signal_power), dB_fixed(noise_power), *snr); + LOG_I(NR_PHY, + "[RB %3i] noise_power_per_rb = %i, SNR_per_rb = %i dB\n", + rb, + noise_power_per_rb[rb], + dB_fixed(*signal_power) - dB_fixed(noise_power_per_rb[rb])); +#endif + } + } + +#ifdef SRS_DEBUG + int32_t signal_power_dB = dB_fixed(*signal_power); + int32_t noise_power_dB = dB_fixed(*noise_power); + LOG_I(NR_PHY, + "signal_power = %i dB, noise_power = %i dB, SNR = %i dB\n", + signal_power_dB, + noise_power_dB, + signal_power_dB - noise_power_dB); #endif return 0; diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index 67fad3cc2f..020d33039e 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -928,7 +928,7 @@ void nr_srs_rx_procedures(PHY_VARS_gNB *gNB, T_INT(slot_rx), T_INT(ant_rx_ind), T_INT(p_ind), - T_BUFFER(srs_estimated_channel_freq[ant_rx_ind][p_ind], ofdm_symbol_size * sizeof(c16_t))); + T_BUFFER(srs_estimated_channel_freq[ant_rx_ind][p_ind], N_symb_SRS * ofdm_symbol_size * sizeof(c16_t))); T(T_GNB_PHY_UL_TIME_CHANNEL_ESTIMATE, T_INT(gNB->Mod_id), diff --git a/openair1/SIMULATION/NR_PHY/srssim.c b/openair1/SIMULATION/NR_PHY/srssim.c index 6ce6d3b897..2b891361c6 100644 --- a/openair1/SIMULATION/NR_PHY/srssim.c +++ b/openair1/SIMULATION/NR_PHY/srssim.c @@ -143,7 +143,7 @@ int main(int argc, char *argv[]) AssertFatal(nb_symb_srs == 1 || nb_symb_srs == 2 || nb_symb_srs == 4, "number of srs symbols %d is not 1,2,4\n", nb_symb_srs); - nb_symb_srs >>= 2; // Value: 0 = 1 symbol, 1 = 2 symbols, 2 = 4 symbols + nb_symb_srs >>= 1; // Value: 0 = 1 symbol, 1 = 2 symbols, 2 = 4 symbols break; case 'c': diff --git a/openair1/SIMULATION/tests/CMakeLists.txt b/openair1/SIMULATION/tests/CMakeLists.txt index a9fbfec228..98c8a53604 100644 --- a/openair1/SIMULATION/tests/CMakeLists.txt +++ b/openair1/SIMULATION/tests/CMakeLists.txt @@ -355,6 +355,11 @@ add_physim_test(physim.5g.nr_srssim.test7 "SRS: 30KHz SCS, 106 PRBs, SNR 20 dB, add_physim_test(physim.5g.nr_srssim.test8 "SRS: 120KHz SCS, 32 PRBs, SNR 20 dB, ToA 19, Combsize 2" nr_srssim -n300 -R32 -y2 -z2 -d 19 -u 3) add_physim_test(physim.5g.nr_srssim.test9 "SRS: 30KHz SCS, 106 PRBs, SNR 20 dB, ToA 11, Combsize 4" nr_srssim -n300 -R106 -y2 -z2 -d 11 -e 1) add_physim_test(physim.5g.nr_srssim.test10 "SRS: 30KHz SCS, 106 PRBs, SNR 20 dB, ToA 7, Combsize 4, Comb offset 1" nr_srssim -n300 -R106 -y2 -z2 -d 7 -e 1 -f 1) +add_physim_test(physim.5g.nr_srssim.test11 "SRS: 30KHz SCS, 106 PRBs, SNR 20 dB, ToA 24, Combsize 2, SRS symbols 2" nr_srssim -n300 -R106 -y2 -z2 -d 24 -b 2) +add_physim_test(physim.5g.nr_srssim.test12 "SRS: 30KHz SCS, 106 PRBs, SNR 20 dB, ToA 24, Combsize 2, SRS symbols 4" nr_srssim -n300 -R106 -y2 -z2 -d 24 -b 4) +add_physim_test(physim.5g.nr_srssim.test13 "SRS: 30KHz SCS, 106 PRBs, SNR 20 dB, ToA 24, Combsize 4, SRS symbols 2" nr_srssim -n300 -R106 -y2 -z2 -d 24 -b 2 -e1) +add_physim_test(physim.5g.nr_srssim.test14 "SRS: 30KHz SCS, 106 PRBs, SNR 20 dB, ToA 24, Combsize 4, SRS symbols 4" nr_srssim -n300 -R106 -y2 -z2 -d 24 -b 4 -e1) +add_physim_test(physim.5g.nr_srssim.test15 "SRS: 30KHz SCS, 217 PRBs, SNR 20 dB, ToA 8, Combsize 2, SRS symbols 4" nr_srssim -n300 -R217 -y2 -z2 -d 8 -b 4) #################################################################################### ###### offload-specific tests ###### From 4c48d915383de41bf0f8ec8579a2d08aaaf3d5ed Mon Sep 17 00:00:00 2001 From: Rakesh Mundlamuri Date: Wed, 5 Nov 2025 18:08:19 +0530 Subject: [PATCH 15/22] Fix issues detected using address sanitizer --- openair1/SIMULATION/NR_PHY/srssim.c | 50 +++++++++++++---------------- 1 file changed, 23 insertions(+), 27 deletions(-) diff --git a/openair1/SIMULATION/NR_PHY/srssim.c b/openair1/SIMULATION/NR_PHY/srssim.c index 2b891361c6..0592bc42d1 100644 --- a/openair1/SIMULATION/NR_PHY/srssim.c +++ b/openair1/SIMULATION/NR_PHY/srssim.c @@ -588,7 +588,7 @@ int main(int argc, char *argv[]) int16_t timing_advance_offset_nsec[n_rx]; int srs_est; c16_t srs_estimated_channel_freq[n_rx][N_ap][ofdm_symbol_size * N_symb_SRS] __attribute__((aligned(32))); - c16_t srs_estimated_channel_time[n_rx][N_ap][ofdm_symbol_size] __attribute__((aligned(32))); + c16_t srs_estimated_channel_time[n_rx][N_ap][NR_SRS_IDFT_OVERSAMP_FACTOR * ofdm_symbol_size] __attribute__((aligned(32))); nr_srs_rx_procedures(gNB, frame, @@ -624,6 +624,18 @@ int main(int argc, char *argv[]) float SRS_SNR_dB = 10 * log10(sum_srs_snr / n_trials); printf("Actual SNR : %f, Estimated SNR from SRS %f (dB), TA offset success rate %f %%\n", SNR, SRS_SNR_dB, tao_ns_rate * 100); + if (print_perf == 1) { + printf("\ngNB RX\n"); + printDistribution(&gNB->rx_srs_stats, table_rx, "RX SRS time"); + printStatIndent(&gNB->generate_srs_stats, "Generate SRS sequence time"); + printStatIndent(&gNB->get_srs_signal_stats, "Get SRS signal time"); + printStatIndent(&gNB->srs_channel_estimation_stats, "SRS channel estimation time"); + printStatIndent(&gNB->srs_timing_advance_stats, "SRS timing advance estimation time"); + printf("\n"); + } + + free(table_rx); + int srs_ret = 1; if (SNR > 30 && SRS_SNR_dB > 30) { srs_ret = 0; @@ -638,16 +650,6 @@ int main(int argc, char *argv[]) break; } - if (print_perf == 1) { - printf("\ngNB RX\n"); - printDistribution(&gNB->rx_srs_stats, table_rx, "RX SRS time"); - printStatIndent(&gNB->generate_srs_stats, "Generate SRS sequence time"); - printStatIndent(&gNB->get_srs_signal_stats, "Get SRS signal time"); - printStatIndent(&gNB->srs_channel_estimation_stats, "SRS channel estimation time"); - printStatIndent(&gNB->srs_timing_advance_stats, "SRS timing advance estimation time"); - printf("\n"); - } - } // SNR loop printf("*************\n"); @@ -659,33 +661,27 @@ int main(int argc, char *argv[]) for (i = 0; i < n_tx; i++) { free(s_re[i]); free(s_im[i]); + free(txdata[i]); + free(txdataF[i]); } + free(s_re); + free(s_im); + free(txdata); + free(txdataF); + for (i = 0; i < n_rx; i++) { free(r_re[i]); free(r_im[i]); + free(rxdata[i]); + free(gNB->common_vars.rxdataF[0][i]); } - free(s_re); - free(s_im); free(r_re); free(r_im); - - for (i = 0; i < n_rx; i++) { - free(rxdata[i]); - } free(rxdata); - for (i = 0; i < n_tx; i++) { - free(txdata[i]); - } - free(txdata); - - for (i = 0; i < n_tx; i++) { - free(txdataF[i]); - } - free(txdataF); - phy_free_nr_gNB(gNB); + free_channel_desc_scm(UE2gNB); free_and_zero(UE->nr_srs_info); free(gNB->RU_list[0]); free(UE); From bfb0c707febdbe1870c143de8654d72a161ab1e9 Mon Sep 17 00:00:00 2001 From: Rakesh Mundlamuri Date: Mon, 10 Nov 2025 20:30:30 +0530 Subject: [PATCH 16/22] Fix tdd pattern of phy_simulators for mu = 0, 3 --- openair1/SCHED_NR/phy_frame_config_nr.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/openair1/SCHED_NR/phy_frame_config_nr.c b/openair1/SCHED_NR/phy_frame_config_nr.c index 0806bd6286..4c2c19847c 100644 --- a/openair1/SCHED_NR/phy_frame_config_nr.c +++ b/openair1/SCHED_NR/phy_frame_config_nr.c @@ -199,8 +199,8 @@ void do_tdd_config_sim(PHY_VARS_gNB *gNB, int mu) switch (mu) { case 0: - pc->num_dl_slots = 3; - pc->num_ul_slots = 1; + pc->num_dl_slots = 7; + pc->num_ul_slots = 2; break; case 1: @@ -209,8 +209,8 @@ void do_tdd_config_sim(PHY_VARS_gNB *gNB, int mu) break; case 3: - pc->num_dl_slots = 27; - pc->num_ul_slots = 12; + pc->num_dl_slots = 7; + pc->num_ul_slots = 2; break; default: From 7b698531a93462c7780650d8154dcb217bfd3394 Mon Sep 17 00:00:00 2001 From: Rakesh Mundlamuri Date: Mon, 10 Nov 2025 20:31:38 +0530 Subject: [PATCH 17/22] update phy_simulators testcases --- openair1/PHY/NR_TRANSPORT/srs_rx.c | 5 +-- .../PHY/nr_phy_common/src/nr_phy_common_srs.c | 5 +++ openair1/SCHED_NR/phy_procedures_nr_gNB.c | 3 +- openair1/SCHED_NR_UE/phy_procedures_nr_ue.c | 10 +++--- openair1/SIMULATION/NR_PHY/srssim.c | 6 ++-- openair1/SIMULATION/NR_PHY/ulsim.c | 3 +- openair1/SIMULATION/tests/CMakeLists.txt | 31 ++++++++++--------- .../LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c | 5 +-- 8 files changed, 39 insertions(+), 29 deletions(-) diff --git a/openair1/PHY/NR_TRANSPORT/srs_rx.c b/openair1/PHY/NR_TRANSPORT/srs_rx.c index d5731557a0..5d84c11c99 100644 --- a/openair1/PHY/NR_TRANSPORT/srs_rx.c +++ b/openair1/PHY/NR_TRANSPORT/srs_rx.c @@ -56,7 +56,8 @@ void nr_fill_srs(PHY_VARS_gNB *gNB, frame_t frame, slot_t slot, nfapi_nr_srs_pdu srs->active = true; srs->beam_nb = 0; if (gNB->common_vars.beam_id) { - int bitmap = SL_to_bitmap(srs_pdu->time_start_position, 1 << srs_pdu->num_symbols); + const uint8_t l0 = gNB->frame_parms.symbols_per_slot - 1 - srs_pdu->time_start_position; + int bitmap = SL_to_bitmap(l0, 1 << srs_pdu->num_symbols); int fapi_beam_idx = srs_pdu->beamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx; srs->beam_nb = beam_index_allocation(gNB->enable_analog_das, fapi_beam_idx, @@ -84,7 +85,7 @@ int nr_get_srs_signal(PHY_VARS_gNB *gNB, const NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms; const uint16_t n_symbols = (slot % RU_RX_SLOT_DEPTH) * frame_parms->symbols_per_slot; // number of symbols until this slot - const uint8_t l0 = srs_pdu->time_start_position; // starting symbol in this slot + const uint8_t l0 = frame_parms->symbols_per_slot - 1 - srs_pdu->time_start_position; // starting symbol in this slot const uint64_t symbol_offset = (n_symbols + l0) * frame_parms->ofdm_symbol_size; const uint64_t subcarrier_offset = frame_parms->first_carrier_offset + srs_pdu->bwp_start * NR_NB_SC_PER_RB; diff --git a/openair1/PHY/nr_phy_common/src/nr_phy_common_srs.c b/openair1/PHY/nr_phy_common/src/nr_phy_common_srs.c index 9d91986b50..95b3a86d91 100644 --- a/openair1/PHY/nr_phy_common/src/nr_phy_common_srs.c +++ b/openair1/PHY/nr_phy_common/src/nr_phy_common_srs.c @@ -180,6 +180,11 @@ bool generate_srs_nr(const NR_DL_FRAME_PARMS *frame_parms, LOG_I(NR_PHY,"M_sc_b_SRS = %i\n", M_sc_b_SRS); #endif + AssertFatal(l0 + nr_srs_info->N_symb_SRS - 1 < frame_parms->symbols_per_slot, + "last symbol index %d should be < %d\n", + l0 + nr_srs_info->N_symb_SRS, + frame_parms->symbols_per_slot - 1); + // Validation of SRS config parameters if (nr_srs_info->R == 0) { diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index 020d33039e..7e47f422e8 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -717,9 +717,10 @@ static void fill_ul_rb_mask(PHY_VARS_gNB *gNB, if (!(srs && srs->active && srs->frame == frame_rx && srs->slot == slot_rx)) continue; nfapi_nr_srs_pdu_t *srs_pdu = &srs->srs_pdu; + const uint8_t l0 = gNB->frame_parms.symbols_per_slot - 1 - srs_pdu->time_start_position; for (int symbol = 0; symbol < (1 << srs_pdu->num_symbols); symbol++) { for (int rb = srs_pdu->bwp_start; rb < (srs_pdu->bwp_start + srs_pdu->bwp_size); rb++) { - rb_mask_ul[srs_pdu->time_start_position + symbol][rb >> 5] |= 1U << (rb & 31); + rb_mask_ul[l0 + symbol][rb >> 5] |= 1U << (rb & 31); } } } diff --git a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c index bc2a803de8..b40a2ab063 100644 --- a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c +++ b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c @@ -314,12 +314,13 @@ bool ue_srs_procedures_nr(PHY_VARS_NR_UE *ue, return false; } + NR_DL_FRAME_PARMS *frame_parms = &(ue->frame_parms); fapi_nr_ul_config_srs_pdu *srs_config_pdu = &phy_data->srs_vars.srs_config_pdu; - int first_srs_symbol = ue->frame_parms.symbols_per_slot - 1 - srs_config_pdu->time_start_position; + const uint8_t l0 = frame_parms->symbols_per_slot - 1 - srs_config_pdu->time_start_position; // Num consecutive SRS symbols according to 38.211 6.4.1.4.1 int num_srs_symbols[] = {1, 2, 4, 8, 12}; - int last_srs_symbol = first_srs_symbol + num_srs_symbols[srs_config_pdu->num_symbols] - 1; - for (int i = first_srs_symbol; i <= last_srs_symbol; i++) { + int last_srs_symbol = l0 + num_srs_symbols[srs_config_pdu->num_symbols] - 1; + for (int i = l0; i <= last_srs_symbol; i++) { was_symbol_used[i] = true; } @@ -351,8 +352,7 @@ bool ue_srs_procedures_nr(PHY_VARS_NR_UE *ue, #endif configure_srs_info(srs_config_pdu, ue->nr_srs_info); - NR_DL_FRAME_PARMS *frame_parms = &(ue->frame_parms); - uint16_t symbol_offset = (frame_parms->symbols_per_slot - 1 - srs_config_pdu->time_start_position)*frame_parms->ofdm_symbol_size; + uint16_t symbol_offset = l0 * frame_parms->ofdm_symbol_size; bool generated = generate_srs_nr(frame_parms, txdataF, symbol_offset, diff --git a/openair1/SIMULATION/NR_PHY/srssim.c b/openair1/SIMULATION/NR_PHY/srssim.c index 0592bc42d1..fa7388498b 100644 --- a/openair1/SIMULATION/NR_PHY/srssim.c +++ b/openair1/SIMULATION/NR_PHY/srssim.c @@ -498,7 +498,7 @@ int main(int argc, char *argv[]) bool was_symbol_used[NR_NUMBER_OF_SYMBOLS_PER_SLOT] = {0}; int slot_offset = get_samples_slot_timestamp(fp, slot); uint16_t ofdm_symbol_size = fp->ofdm_symbol_size; - int slot_offsetF = (slot % RU_RX_SLOT_DEPTH) * NR_SYMBOLS_PER_SLOT * ofdm_symbol_size; + int slot_offsetF = (slot % RU_RX_SLOT_DEPTH) * fp->symbols_per_slot * ofdm_symbol_size; c16_t *txF[n_tx]; for (i = 0; i < n_tx; i++) @@ -528,10 +528,10 @@ int main(int argc, char *argv[]) int symbol_offset = slot_offset; int abs_first_symbol = slot * fp->symbols_per_slot; int idx_sym; - for (idx_sym = abs_first_symbol; idx_sym < abs_first_symbol + srs_pdu.time_start_position; idx_sym++) + for (idx_sym = abs_first_symbol; idx_sym < abs_first_symbol + srs_start_symbol; idx_sym++) symbol_offset += (idx_sym % (0x7 << fp->numerology_index)) ? fp->nb_prefix_samples : fp->nb_prefix_samples0; - symbol_offset += ofdm_symbol_size * srs_pdu.time_start_position; + symbol_offset += ofdm_symbol_size * srs_start_symbol; int symbol_length = ofdm_symbol_size + (idx_sym % (0x7 << fp->numerology_index)) ? fp->nb_prefix_samples : fp->nb_prefix_samples0; // Compute transmitter energy level diff --git a/openair1/SIMULATION/NR_PHY/ulsim.c b/openair1/SIMULATION/NR_PHY/ulsim.c index c6e91d78aa..444492b545 100644 --- a/openair1/SIMULATION/NR_PHY/ulsim.c +++ b/openair1/SIMULATION/NR_PHY/ulsim.c @@ -1273,7 +1273,7 @@ int main(int argc, char *argv[]) srs_pdu->subcarrier_spacing = gNB->frame_parms.subcarrier_spacing; srs_pdu->num_ant_ports = n_tx == 4 ? 2 : n_tx == 2 ? 1 : 0; srs_pdu->sequence_id = 40; - srs_pdu->time_start_position = gNB->frame_parms.symbols_per_slot - 1; + srs_pdu->time_start_position = 0; srs_pdu->config_index = rrc_get_max_nr_csrs(srs_pdu->bwp_size, srs_pdu->bandwidth_index); srs_pdu->resource_type = NR_SRS_Resource__resourceType_PR_periodic; srs_pdu->t_srs = 1; @@ -1371,6 +1371,7 @@ int main(int argc, char *argv[]) srs_config_pdu->sequence_id = 40; srs_config_pdu->resource_type = NR_SRS_Resource__resourceType_PR_periodic; srs_config_pdu->t_srs = 1; + srs_config_pdu->time_start_position = 0; } for (int i = 0; i < (TBS / 8); i++) diff --git a/openair1/SIMULATION/tests/CMakeLists.txt b/openair1/SIMULATION/tests/CMakeLists.txt index 98c8a53604..0c2ab8dd39 100644 --- a/openair1/SIMULATION/tests/CMakeLists.txt +++ b/openair1/SIMULATION/tests/CMakeLists.txt @@ -345,21 +345,22 @@ add_physim_test(physim.5g.nr_psbchsim.test2 "PSBCH TxRx" nr_psbchsim -n 30) ###### nr_srssim unit test ###### #################################################################################### -add_physim_test(physim.5g.nr_srssim.test1 "SRS: 30KHz SCS, 106 PRBs, SNR 20 dB, ToA 24, Combsize 2" nr_srssim -n300 -R106 -y2 -z2 -d 24) -add_physim_test(physim.5g.nr_srssim.test2 "SRS: 30KHz SCS, 106 PRBs, SNR 20 dB, ToA 15, Combsize 2, Threequarter sampling" nr_srssim -n300 -R106 -y2 -z2 -d 15 -k) -add_physim_test(physim.5g.nr_srssim.test3 "SRS: 30KHz SCS, 217 PRBs, SNR 20 dB, ToA 8, Combsize 2" nr_srssim -n300 -R217 -y2 -z2 -d 8) -add_physim_test(physim.5g.nr_srssim.test4 "SRS: 30KHz SCS, 273 PRBs, SNR 20 dB, TOA 30, Combsize 2" nr_srssim -n300 -R273 -y2 -z2 -d 30) -add_physim_test(physim.5g.nr_srssim.test5 "SRS: 30KHz SCS, 106 PRBs, SNR 20 dB, ToA 16, Combsize 2, Cyclic shift 3" nr_srssim -n300 -R106 -y2 -z2 -d 16 -i 1) -add_physim_test(physim.5g.nr_srssim.test6 "SRS: 30KHz SCS, 106 PRBs, SNR 20 dB, ToA 23, Combsize 2, Comb offset 1" nr_srssim -n300 -R106 -y2 -z2 -d 23 -f 1) -add_physim_test(physim.5g.nr_srssim.test7 "SRS: 30KHz SCS, 106 PRBs, SNR 20 dB, ToA 8, Combsize 2, Symbol start 9" nr_srssim -n300 -R106 -y2 -z2 -d 8 -a 9) -add_physim_test(physim.5g.nr_srssim.test8 "SRS: 120KHz SCS, 32 PRBs, SNR 20 dB, ToA 19, Combsize 2" nr_srssim -n300 -R32 -y2 -z2 -d 19 -u 3) -add_physim_test(physim.5g.nr_srssim.test9 "SRS: 30KHz SCS, 106 PRBs, SNR 20 dB, ToA 11, Combsize 4" nr_srssim -n300 -R106 -y2 -z2 -d 11 -e 1) -add_physim_test(physim.5g.nr_srssim.test10 "SRS: 30KHz SCS, 106 PRBs, SNR 20 dB, ToA 7, Combsize 4, Comb offset 1" nr_srssim -n300 -R106 -y2 -z2 -d 7 -e 1 -f 1) -add_physim_test(physim.5g.nr_srssim.test11 "SRS: 30KHz SCS, 106 PRBs, SNR 20 dB, ToA 24, Combsize 2, SRS symbols 2" nr_srssim -n300 -R106 -y2 -z2 -d 24 -b 2) -add_physim_test(physim.5g.nr_srssim.test12 "SRS: 30KHz SCS, 106 PRBs, SNR 20 dB, ToA 24, Combsize 2, SRS symbols 4" nr_srssim -n300 -R106 -y2 -z2 -d 24 -b 4) -add_physim_test(physim.5g.nr_srssim.test13 "SRS: 30KHz SCS, 106 PRBs, SNR 20 dB, ToA 24, Combsize 4, SRS symbols 2" nr_srssim -n300 -R106 -y2 -z2 -d 24 -b 2 -e1) -add_physim_test(physim.5g.nr_srssim.test14 "SRS: 30KHz SCS, 106 PRBs, SNR 20 dB, ToA 24, Combsize 4, SRS symbols 4" nr_srssim -n300 -R106 -y2 -z2 -d 24 -b 4 -e1) -add_physim_test(physim.5g.nr_srssim.test15 "SRS: 30KHz SCS, 217 PRBs, SNR 20 dB, ToA 8, Combsize 2, SRS symbols 4" nr_srssim -n300 -R217 -y2 -z2 -d 8 -b 4) +add_physim_test(physim.5g.nr_srssim.test1 "SRS: 30KHz SCS, 106 PRBs, ToA 24, Combsize 2" nr_srssim -n300 -R106 -s0 -S5 -y2 -z2 -d 24) +add_physim_test(physim.5g.nr_srssim.test2 "SRS: 30KHz SCS, 106 PRBs, ToA 15, Combsize 2, Threequarter sampling" nr_srssim -n300 -R106 -s0 -S5 -y2 -z2 -d 15 -k) +add_physim_test(physim.5g.nr_srssim.test3 "SRS: 30KHz SCS, 217 PRBs, ToA 8, Combsize 2" nr_srssim -n300 -R217 -s0 -S5 -y2 -z2 -d 8) +add_physim_test(physim.5g.nr_srssim.test4 "SRS: 30KHz SCS, 273 PRBs, TOA 30, Combsize 2" nr_srssim -n300 -R273 -s0 -S5 -y2 -z2 -d 30) +add_physim_test(physim.5g.nr_srssim.test5 "SRS: 30KHz SCS, 106 PRBs, ToA 16, Combsize 2, Cyclic shift 3" nr_srssim -n300 -R106 -s0 -S5 -y2 -z2 -d 16 -i 1) +add_physim_test(physim.5g.nr_srssim.test6 "SRS: 30KHz SCS, 106 PRBs, ToA 23, Combsize 2, Comb offset 1" nr_srssim -n300 -R106 -s0 -S5 -y2 -z2 -d 23 -f 1) +add_physim_test(physim.5g.nr_srssim.test7 "SRS: 30KHz SCS, 106 PRBs, ToA 8, Combsize 2, Symbol start 9" nr_srssim -n300 -R106 -s0 -S5 -y2 -z2 -d 8 -a 9) +add_physim_test(physim.5g.nr_srssim.test8 "SRS: 120KHz SCS, 32 PRBs, ToA 19, Combsize 2" nr_srssim -n300 -R32 -s0 -S5 -y2 -z2 -d 19 -u 3) +add_physim_test(physim.5g.nr_srssim.test9 "SRS: 30KHz SCS, 106 PRBs, ToA 11, Combsize 4" nr_srssim -n300 -R106 -s5 -S10 -y2 -z2 -d 11 -e 1) +add_physim_test(physim.5g.nr_srssim.test10 "SRS: 30KHz SCS, 106 PRBs, ToA 7, Combsize 4, Comb offset 1" nr_srssim -n300 -R106 -s5 -S10 -y2 -z2 -d 7 -e 1 -f 1) +add_physim_test(physim.5g.nr_srssim.test11 "SRS: 30KHz SCS, 106 PRBs, ToA 24, Combsize 2, SRS symbols 2, SRS start symbol 8" nr_srssim -n300 -R106 -s0 -S5 -y2 -z2 -d 24 -b 2 -a 8) +add_physim_test(physim.5g.nr_srssim.test12 "SRS: 30KHz SCS, 106 PRBs, ToA 24, Combsize 2, SRS symbols 4, SRS start symbol 8" nr_srssim -n300 -R106 -s0 -S5 -y2 -z2 -d 24 -b 4 -a 8) +add_physim_test(physim.5g.nr_srssim.test13 "SRS: 30KHz SCS, 106 PRBs, ToA 24, Combsize 4, SRS symbols 2, SRS start symbol 8" nr_srssim -n300 -R106 -s5 -S10 -y2 -z2 -d 24 -b 2 -e1 -a 8) +add_physim_test(physim.5g.nr_srssim.test14 "SRS: 30KHz SCS, 106 PRBs, ToA 24, Combsize 4, SRS symbols 4, SRS start symbol 8" nr_srssim -n300 -R106 -s5 -S10 -y2 -z2 -d 24 -b 4 -e1 -a 8) +add_physim_test(physim.5g.nr_srssim.test15 "SRS: 30KHz SCS, 217 PRBs, ToA 8, Combsize 2, SRS symbols 4, SRS start symbol 8" nr_srssim -n300 -R217 -s0 -S5 -y2 -z2 -d 8 -b 4 -a 8) +add_physim_test(physim.5g.nr_srssim.test16 "SRS: 30KHz SCS, 106 PRBs, SNR 2 dB to 30 dB in steps of 5 dB, ToA 24, Combsize 2" nr_srssim -n300 -R106 -s2 -S30 -y2 -z2 -d 24) #################################################################################### ###### offload-specific tests ###### diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c index 8c8a25e446..1afa2d1502 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c @@ -428,7 +428,7 @@ static void nr_configure_srs(gNB_MAC_INST *nrmac, srs_pdu->num_ant_ports = srs_resource->nrofSRS_Ports; srs_pdu->num_symbols = srs_resource->resourceMapping.nrofSymbols; srs_pdu->num_repetitions = srs_resource->resourceMapping.repetitionFactor; - srs_pdu->time_start_position = NR_NUMBER_OF_SYMBOLS_PER_SLOT - 1 - srs_resource->resourceMapping.startPosition; + srs_pdu->time_start_position = srs_resource->resourceMapping.startPosition; srs_pdu->config_index = srs_resource->freqHopping.c_SRS; srs_pdu->sequence_id = srs_resource->sequenceId; srs_pdu->bandwidth_index = srs_resource->freqHopping.b_SRS; @@ -479,7 +479,8 @@ static void nr_configure_srs(gNB_MAC_INST *nrmac, AssertFatal(beam.idx >= 0, "Cannot allocate SRS in any available beam\n"); uint16_t *vrb_map_UL = &nrmac->common_channels[CC_id].vrb_map_UL[beam.idx][buffer_index * MAX_BWP_SIZE]; uint16_t num = 1 << srs_pdu->num_symbols; // 0,1,2 means 1,2,4 symbols, see 222.10.04 table 3-105 - uint16_t mask = SL_to_bitmap(srs_pdu->time_start_position, num); + const uint8_t l0 = NR_NUMBER_OF_SYMBOLS_PER_SLOT - 1 - srs_pdu->time_start_position; + uint16_t mask = SL_to_bitmap(l0, num); DevAssert(mask != 0); for (int i = 0; i < srs_pdu->bwp_size; ++i) { int rb = i + srs_pdu->bwp_start; From be3ad2beba4152e6e22548253d5a5d4ed10943cc Mon Sep 17 00:00:00 2001 From: Rakesh Mundlamuri Date: Thu, 20 Nov 2025 17:20:29 +0530 Subject: [PATCH 18/22] rewrite srs channel estimation to fix memory alignment in SRS channel estimation The memory alignment is required to use c16multaddVectRealComplex in SRS channel interpolation. With a change in SRS comb_offset, the existing algorithm was giving segmentation fault. The existing srs channel estimation required memory alignment at two stages. 1. When k = 0 (the first srs subcarrier), 2. When subcarrier < K_TC (wrapped around after ofdm_symbol_size). Thus two memory alignments are required leading to complications. The srs channel estimation is now simplified to do it linearly instead of wrapping around. This simplified the memory alignment required only when k = 0. --- .../NR_ESTIMATION/nr_ul_channel_estimation.c | 103 ++++++++---------- openair1/SCHED_NR/phy_procedures_nr_gNB.c | 3 +- 2 files changed, 50 insertions(+), 56 deletions(-) diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c index c3a13e94a2..f9203f488f 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c +++ b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c @@ -791,6 +791,7 @@ int nr_srs_channel_estimation(int ant, #endif const uint64_t subcarrier_offset = first_carrier_offset + srs_pdu->bwp_start * NR_NB_SC_PER_RB; + const uint64_t first_subcarrier = (first_carrier_offset - (ofdm_symbol_size >> 1)) + srs_pdu->bwp_start * NR_NB_SC_PER_RB; const uint8_t N_ap = 1 << srs_pdu->num_ant_ports; const uint8_t K_TC = 2 << srs_pdu->comb_size; @@ -810,21 +811,17 @@ int nr_srs_channel_estimation(int ant, for (int srs_symb = 0; srs_symb < N_symb_SRS; srs_symb++) { uint16_t srs_symbol_offset = srs_symb * ofdm_symbol_size; - uint8_t mem_offset = - ((16 - - ((intptr_t)&srs_estimated_channel_freq[srs_symbol_offset + subcarrier_offset + nr_srs_info->k_0_p[p_index][srs_symb]])) - & 0xF) - >> 2; // >> 2 <=> /sizeof(int32_t) + // Additional 4 in the array size is needed to maintain 16 byte memory alignment required for AVX2 instructions in channel + // interpolation + c16_t srs_est[ofdm_symbol_size + 4] __attribute__((aligned(32))); + memset(srs_est, 0, (ofdm_symbol_size + 4) * sizeof(c16_t)); + + // Estimate 16 byte memory alignment offset for the first SRS subcarrier to use AVX2 instructions in channel interpolation + uint8_t mem_offset = (16 - (((intptr_t)&srs_est[first_subcarrier + nr_srs_info->k_0_p[p_index][srs_symb]]) & 0xF)) + >> 2; // >> 2 <=> /sizeof(int32_t) - // filt16_end is {4096,8192,8192,8192,12288,16384,16384,16384,0,0,0,0,0,0,0,0} - // The End of OFDM symbol corresponds to the position of last 16384 in the filter - // The c16multaddVectRealComplex applies the remaining 8 zeros of filter, therefore, to avoid a buffer overflow, - // we added 8 in the array size - c16_t srs_est[ofdm_symbol_size + mem_offset + 8] __attribute__((aligned(32))); c16_t ls_estimated = {0}; - memset(srs_est, 0, (ofdm_symbol_size + mem_offset + 8) * sizeof(c16_t)); - #ifdef SRS_DEBUG LOG_I(NR_PHY, "====================== UE port %d --> gNB Rx antenna %i ======================\n", p_index, ant); LOG_I(NR_PHY, "============================== SRS symbol index %d ===========================\n", srs_symb); @@ -835,7 +832,8 @@ int nr_srs_channel_estimation(int ant, subcarrier -= ofdm_symbol_size; } - c16_t *srs_estimated_channel16 = &srs_est[subcarrier + mem_offset]; + uint16_t subcarrier_abs = mem_offset + first_subcarrier + nr_srs_info->k_0_p[p_index][srs_symb]; + c16_t *srs_estimated_channel16 = &srs_est[subcarrier_abs]; for (int k = 0; k < M_sc_b_SRS; k++) { if (k % fd_cdm == 0) { @@ -880,47 +878,33 @@ int nr_srs_channel_estimation(int ant, ls_estimated.i); #endif - const uint16_t sc_offset = subcarrier + mem_offset; - // Channel interpolation if (srs_pdu->comb_size == 0) { if (k == 0) { // First subcarrier case // filt8_start is {12288,8192,4096,0,0,0,0,0} c16multaddVectRealComplex(filt8_start, &ls_estimated, srs_estimated_channel16, 8); - } else if (subcarrier < K_TC) { // Start of OFDM symbol case - // filt8_start is {12288,8192,4096,0,0,0,0,0} - srs_estimated_channel16 = &srs_est[subcarrier]; - const short *filter = mem_offset == 0 ? filt8_start : filt8_start_shift2; - c16multaddVectRealComplex(filter, &ls_estimated, srs_estimated_channel16, 8); - } else if ((subcarrier + K_TC) >= ofdm_symbol_size - || k == (M_sc_b_SRS - 1)) { // End of OFDM symbol or last subcarrier cases + } else if (k == (M_sc_b_SRS - 1)) { // End of OFDM symbol or last subcarrier cases // filt8_end is {4096,8192,12288,16384,0,0,0,0} - const short *filter = mem_offset == 0 || k == (M_sc_b_SRS - 1) ? filt8_end : filt8_end_shift2; - c16multaddVectRealComplex(filter, &ls_estimated, srs_estimated_channel16, 8); + c16multaddVectRealComplex(filt8_end, &ls_estimated, srs_estimated_channel16, 8); } else if (k % 2 == 1) { // 1st middle case // filt8_middle2 is {4096,8192,8192,8192,4096,0,0,0} c16multaddVectRealComplex(filt8_middle2, &ls_estimated, srs_estimated_channel16, 8); } else if (k % 2 == 0) { // 2nd middle case // filt8_middle4 is {0,0,4096,8192,8192,8192,4096,0} c16multaddVectRealComplex(filt8_middle4, &ls_estimated, srs_estimated_channel16, 8); - srs_estimated_channel16 = &srs_est[sc_offset]; + srs_estimated_channel16 = &srs_est[subcarrier_abs]; } } else { if (k == 0) { // First subcarrier case // filt16_start is {12288,8192,8192,8192,4096,0,0,0,0,0,0,0,0,0,0,0} c16multaddVectRealComplex(filt16_start, &ls_estimated, srs_estimated_channel16, 16); - } else if (subcarrier < K_TC) { // Start of OFDM symbol case - srs_estimated_channel16 = &srs_est[sc_offset]; - // filt16_start is {12288,8192,8192,8192,4096,0,0,0,0,0,0,0,0,0,0,0} - c16multaddVectRealComplex(filt16_start, &ls_estimated, srs_estimated_channel16, 16); - } else if ((subcarrier + K_TC) >= ofdm_symbol_size - || k == (M_sc_b_SRS - 1)) { // End of OFDM symbol or last subcarrier cases + } else if (k == (M_sc_b_SRS - 1)) { // End of OFDM symbol or last subcarrier cases // filt16_end is {4096,8192,8192,8192,12288,16384,16384,16384,0,0,0,0,0,0,0,0} c16multaddVectRealComplex(filt16_end, &ls_estimated, srs_estimated_channel16, 16); } else { // Middle case // filt16_middle4 is {4096,8192,8192,8192,8192,8192,8192,8192,4096,0,0,0,0,0,0,0} c16multaddVectRealComplex(filt16_middle4, &ls_estimated, srs_estimated_channel16, 16); - srs_estimated_channel16 = &srs_est[sc_offset]; + srs_estimated_channel16 = &srs_est[subcarrier_abs]; } } @@ -930,6 +914,8 @@ int nr_srs_channel_estimation(int ant, subcarrier -= ofdm_symbol_size; } + subcarrier_abs += K_TC; + } // for (int k = 0; k < M_sc_b_SRS; k++) memcpy(&srs_estimated_channel_freq[srs_symbol_offset], &srs_est[mem_offset], ofdm_symbol_size * sizeof(c16_t)); @@ -947,6 +933,8 @@ int nr_srs_channel_estimation(int ant, subcarrier -= ofdm_symbol_size; } + subcarrier_abs = first_subcarrier + nr_srs_info->k_0_p[p_index][srs_symb]; + for (int k = 0; k < K_TC * M_sc_b_SRS; k++) { int subcarrier_log = subcarrier - subcarrier_offset; if (subcarrier_log < 0) { @@ -966,8 +954,8 @@ int nr_srs_channel_estimation(int ant, subcarrier_log, srs_ls_estimated_channel[srs_symbol_offset + subcarrier].r, srs_ls_estimated_channel[srs_symbol_offset + subcarrier].i, - srs_estimated_channel_freq[srs_symbol_offset + subcarrier].r, - srs_estimated_channel_freq[srs_symbol_offset + subcarrier].i, + srs_estimated_channel_freq[srs_symbol_offset + subcarrier_abs].r, + srs_estimated_channel_freq[srs_symbol_offset + subcarrier_abs].i, srs_received_noise[srs_symbol_offset + subcarrier].r, srs_received_noise[srs_symbol_offset + subcarrier].i); @@ -976,6 +964,7 @@ int nr_srs_channel_estimation(int ant, if (subcarrier >= ofdm_symbol_size) { subcarrier -= ofdm_symbol_size; } + subcarrier_abs++; } #endif } @@ -990,10 +979,8 @@ int nr_srs_channel_estimation(int ant, memset(chF_interpol, 0, sizeof(chF_interpol)); // Place SRS channel estimates in FFT shifted format for oversampling - memcpy(&chF_interpol[0], &srs_estimated_channel_freq_avg[0], ofdm_symbol_size_half * sizeof(c16_t)); - memcpy(&chF_interpol[start_offset], - &srs_estimated_channel_freq_avg[ofdm_symbol_size_half], - ofdm_symbol_size_half * sizeof(c16_t)); + memcpy(&chF_interpol[0], &srs_estimated_channel_freq_avg[ofdm_symbol_size_half], ofdm_symbol_size_half * sizeof(c16_t)); + memcpy(&chF_interpol[start_offset], &srs_estimated_channel_freq_avg[0], ofdm_symbol_size_half * sizeof(c16_t)); // Convert to time domain oversampled freq2time(ofdm_os_size, (int16_t *)chF_interpol, (int16_t *)srs_estimated_channel_time); @@ -1005,34 +992,40 @@ int nr_srs_channel_estimation(int ant, // Compute wideband SNR on the symbol 0 int tot_subcarriers = m_SRS_b * NR_NB_SC_PER_RB; + + uint16_t subcarrier_abs = first_subcarrier + nr_srs_info->k_0_p[p_index][0]; + if (subcarrier_abs + tot_subcarriers < ofdm_symbol_size_half) { + *signal_power = signal_energy_nodc(&srs_estimated_channel_freq[subcarrier_abs], tot_subcarriers) / tot_subcarriers; + } else { + int size1 = ofdm_symbol_size_half - subcarrier_abs; + int size2 = tot_subcarriers - size1; + uint64_t signal_power_p1 = signal_energy_nodc(&srs_estimated_channel_freq[subcarrier_abs], size1) * size1; + uint64_t signal_power_p2 = signal_energy_nodc(&srs_estimated_channel_freq[ofdm_symbol_size_half], size2) * size2; + *signal_power = (signal_power_p1 + signal_power_p2) / tot_subcarriers; + } + + if (*signal_power == 0) { + LOG_W(NR_PHY, "Received SRS signal power is 0\n"); + return -1; + } + subcarrier = subcarrier_offset + nr_srs_info->k_0_p[p_index][0]; if (subcarrier >= ofdm_symbol_size) { subcarrier -= ofdm_symbol_size; } - if (subcarrier + tot_subcarriers < ofdm_symbol_size) { - *signal_power = signal_energy_nodc(&srs_estimated_channel_freq[subcarrier], tot_subcarriers) / tot_subcarriers; - if (p_index == 0) { + + if (p_index == 0) { + if (subcarrier + tot_subcarriers < ofdm_symbol_size) { *noise_power = signal_energy_nodc(&srs_received_noise[subcarrier], tot_subcarriers) / tot_subcarriers; - } - } else { - int size1 = ofdm_symbol_size - subcarrier; - int size2 = tot_subcarriers - size1; - uint64_t signal_power_p1 = signal_energy_nodc(&srs_estimated_channel_freq[subcarrier], size1) * size1; - uint64_t signal_power_p2 = signal_energy_nodc(&srs_estimated_channel_freq[0], size2) * size2; - *signal_power = (signal_power_p1 + signal_power_p2) / tot_subcarriers; - if (p_index == 0) { + } else { + int size1 = ofdm_symbol_size - subcarrier; + int size2 = tot_subcarriers - size1; uint64_t noise_power_p1 = signal_energy_nodc(&srs_received_noise[subcarrier], size1) * size1; uint64_t noise_power_p2 = signal_energy_nodc(&srs_received_noise[0], size2) * size2; *noise_power = (noise_power_p1 + noise_power_p2) / tot_subcarriers; } } - *signal_power = max(*signal_power, 1); - if (*signal_power == 0) { - LOG_W(NR_PHY, "Received SRS signal power is 0\n"); - return -1; - } - // Compute SNR per RB for port 0 and symbol 0 if (p_index == 0) { subcarrier = subcarrier_offset + nr_srs_info->k_0_p[p_index][0]; diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index 7e47f422e8..292692540a 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -938,7 +938,8 @@ void nr_srs_rx_procedures(PHY_VARS_gNB *gNB, T_INT(slot_rx), T_INT(ant_rx_ind), T_INT(p_ind), - T_BUFFER(srs_estimated_channel_time_shifted[ant_rx_ind][p_ind], ofdm_symbol_size * sizeof(c16_t))); + T_BUFFER(srs_estimated_channel_time_shifted[ant_rx_ind][p_ind], + NR_SRS_IDFT_OVERSAMP_FACTOR * ofdm_symbol_size * sizeof(c16_t))); } noise_power_avg += noise_power; } From dea4508f89bc5dcd2fb33fb14cfa757ca9a1b69e Mon Sep 17 00:00:00 2001 From: Rakesh Mundlamuri Date: Mon, 24 Nov 2025 14:59:43 +0530 Subject: [PATCH 19/22] Update docker file to compile nr_srssim to fix tests in gracehopper --- ci-scripts/docker/Dockerfile.physim.ubuntu | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-scripts/docker/Dockerfile.physim.ubuntu b/ci-scripts/docker/Dockerfile.physim.ubuntu index 8fe6d91c4a..c820c7fd7a 100644 --- a/ci-scripts/docker/Dockerfile.physim.ubuntu +++ b/ci-scripts/docker/Dockerfile.physim.ubuntu @@ -44,4 +44,4 @@ RUN cmake -GNinja -DENABLE_PHYSIM_TESTS=ON \ -DCMAKE_C_FLAGS=-Werror -DCMAKE_CXX_FLAGS=-Werror \ -DPHYSIM_CHECK_FILES="ThresholdsGracehopper.cmake" \ .. && \ - ninja ldpctest polartest smallblocktest nr_pbchsim nr_dlschsim nr_ulschsim nr_dlsim nr_ulsim nr_pucchsim nr_prachsim nr_psbchsim + ninja ldpctest polartest smallblocktest nr_pbchsim nr_dlschsim nr_ulschsim nr_dlsim nr_ulsim nr_pucchsim nr_prachsim nr_psbchsim nr_srssim From f84ed0bbcf3f6f926d1f7a84f2bdec8ba99b44cd Mon Sep 17 00:00:00 2001 From: Rakesh Mundlamuri Date: Fri, 19 Dec 2025 18:35:11 +0530 Subject: [PATCH 20/22] Make nb_antenna as a input parameter to generate_srs_nr() - We use the same function at gNB and UE. - We always use nb_antennas_tx to check the max possible number of ports (which is wrong). - At gNB, we should use nb_antennas_rx and at the UE, we should use nb_antennas_tx. --- openair1/PHY/nr_phy_common/inc/nr_phy_common.h | 3 ++- openair1/PHY/nr_phy_common/src/nr_phy_common_srs.c | 5 +++-- openair1/SCHED_NR/phy_procedures_nr_gNB.c | 10 +++++++++- openair1/SCHED_NR_UE/phy_procedures_nr_ue.c | 3 ++- 4 files changed, 16 insertions(+), 5 deletions(-) diff --git a/openair1/PHY/nr_phy_common/inc/nr_phy_common.h b/openair1/PHY/nr_phy_common/inc/nr_phy_common.h index a2011e1fa6..5b60f3bdf6 100644 --- a/openair1/PHY/nr_phy_common/inc/nr_phy_common.h +++ b/openair1/PHY/nr_phy_common/inc/nr_phy_common.h @@ -372,7 +372,8 @@ bool generate_srs_nr(const NR_DL_FRAME_PARMS *frame_parms, nr_srs_info_t *nr_srs_info, int16_t amp, frame_t frame_number, - slot_t slot_number); + slot_t slot_number, + uint8_t nb_antennas); void nr_generate_csi_rs(const NR_DL_FRAME_PARMS *frame_parms, const csi_mapping_parms_t *phy_csi_parms, const int16_t amp, diff --git a/openair1/PHY/nr_phy_common/src/nr_phy_common_srs.c b/openair1/PHY/nr_phy_common/src/nr_phy_common_srs.c index 95b3a86d91..f258b92205 100644 --- a/openair1/PHY/nr_phy_common/src/nr_phy_common_srs.c +++ b/openair1/PHY/nr_phy_common/src/nr_phy_common_srs.c @@ -146,11 +146,12 @@ bool generate_srs_nr(const NR_DL_FRAME_PARMS *frame_parms, nr_srs_info_t *nr_srs_info, int16_t amp, frame_t frame_number, - slot_t slot_number) + slot_t slot_number, + uint8_t nb_antennas) { uint8_t K_TC = 2 << nr_srs_info->comb_size; /* Number of antenna ports (M) can't be higher than number of physical antennas (N): M <= N */ - int N_ap = nr_srs_info->n_srs_ports > frame_parms->nb_antennas_tx ? frame_parms->nb_antennas_tx : nr_srs_info->n_srs_ports; + int N_ap = nr_srs_info->n_srs_ports > nb_antennas ? nb_antennas : nr_srs_info->n_srs_ports; uint8_t l0 = frame_parms->symbols_per_slot - 1 - nr_srs_info->l_offset; // Starting symbol position in the time domain uint8_t n_SRS_cs_max = srs_max_number_cs[nr_srs_info->comb_size]; int m_SRS_b = get_m_srs(nr_srs_info->C_SRS, nr_srs_info->B_SRS); // Number of resource blocks diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index 292692540a..ff82310d29 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -883,7 +883,15 @@ void nr_srs_rx_procedures(PHY_VARS_gNB *gNB, start_meas(&gNB->generate_srs_stats); if (check_and_configure_srs_info(srs_pdu, nr_srs_info)) { - generate_srs_nr(frame_parms, nr_srs_info->srs_generated_signal, 0, srs_pdu->bwp_start, nr_srs_info, AMP, frame_rx, slot_rx); + generate_srs_nr(frame_parms, + nr_srs_info->srs_generated_signal, + 0, + srs_pdu->bwp_start, + nr_srs_info, + AMP, + frame_rx, + slot_rx, + nb_antennas_rx); } stop_meas(&gNB->generate_srs_stats); diff --git a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c index b40a2ab063..c2aa0b4bd7 100644 --- a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c +++ b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c @@ -360,7 +360,8 @@ bool ue_srs_procedures_nr(PHY_VARS_NR_UE *ue, ue->nr_srs_info, AMP, proc->frame_tx, - proc->nr_slot_tx); + proc->nr_slot_tx, + frame_parms->nb_antennas_tx); return generated; } From a752f43ad60371b0d27dfa52fe5db39813ef7ea3 Mon Sep 17 00:00:00 2001 From: Rakesh Mundlamuri Date: Wed, 31 Dec 2025 16:38:02 +0530 Subject: [PATCH 21/22] Harmonize phy_simulators to use compute_tx_energy_level() and compute_noise_variance() --- openair1/PHY/TOOLS/signal_energy.c | 11 ++++++-- openair1/PHY/TOOLS/tools_defs.h | 7 ++++- openair1/SIMULATION/NR_PHY/dlsim.c | 25 ++++++++--------- openair1/SIMULATION/NR_PHY/prachsim.c | 11 ++------ openair1/SIMULATION/NR_PHY/pucchsim.c | 24 ++++++++++++----- openair1/SIMULATION/NR_PHY/srssim.c | 2 +- openair1/SIMULATION/NR_PHY/ulsim.c | 39 +++++++++------------------ 7 files changed, 58 insertions(+), 61 deletions(-) diff --git a/openair1/PHY/TOOLS/signal_energy.c b/openair1/PHY/TOOLS/signal_energy.c index 9b50b947c3..4e29f0ab2b 100644 --- a/openair1/PHY/TOOLS/signal_energy.c +++ b/openair1/PHY/TOOLS/signal_energy.c @@ -196,9 +196,16 @@ double compute_tx_energy_level(c16_t **txdata, int nb_antennas, int offset, int } // Computes noise variance from the input transmit energy and SNR -double compute_noise_variance(double txlev_sum, uint16_t ofdm_symbol_size, int N_RB, double SNR, int n_trials) +double compute_noise_variance(double txlev_sum, + uint16_t ofdm_symbol_size, + int N_RB, + uint8_t precod_nbr_layers, + double SNR, + int n_trials) { - double sigma_dB = 10 * log10(txlev_sum * ((double)ofdm_symbol_size / (12 * N_RB))) - SNR; + // Justification of division by precod_nbr_layers: + // When the channel is the identity matrix, the results in terms of SNR should be almost equal for 2x2 and 4x4. + double sigma_dB = 10 * log10(txlev_sum / precod_nbr_layers * ((double)ofdm_symbol_size / (12 * N_RB))) - SNR; double sigma = pow(10, sigma_dB / 10); if (n_trials == 1) diff --git a/openair1/PHY/TOOLS/tools_defs.h b/openair1/PHY/TOOLS/tools_defs.h index 2f7bd438d6..36fc496545 100644 --- a/openair1/PHY/TOOLS/tools_defs.h +++ b/openair1/PHY/TOOLS/tools_defs.h @@ -929,7 +929,12 @@ double signal_energy_fp2(struct complexd *s, uint32_t length); double compute_tx_energy_level(c16_t **txdata, int nb_antennas, int offset, int length, int n_trials); -double compute_noise_variance(double txlev_sum, uint16_t ofdm_symbol_size, int N_RB, double SNR, int n_trials); +double compute_noise_variance(double txlev_sum, + uint16_t ofdm_symbol_size, + int N_RB, + uint8_t precod_nbr_layers, + double SNR, + int n_trials); int32_t iSqrt(int32_t value); uint8_t log2_approx(uint32_t); diff --git a/openair1/SIMULATION/NR_PHY/dlsim.c b/openair1/SIMULATION/NR_PHY/dlsim.c index f7c8752c76..40ad816d2c 100644 --- a/openair1/SIMULATION/NR_PHY/dlsim.c +++ b/openair1/SIMULATION/NR_PHY/dlsim.c @@ -324,7 +324,7 @@ int main(int argc, char **argv) setbuf(stdout, NULL); int c; int i,aa;//,l; - double sigma2, sigma2_dB=10, SNR, snr0=-2.0, snr1=2.0; + double SNR, snr0 = -2.0, snr1 = 2.0; uint8_t snr1set=0; double effRate; //float psnr; @@ -1172,15 +1172,12 @@ int main(int argc, char **argv) } } - int txlev[n_tx]; - int txlev_sum = 0; + // Compute transmitter energy level int l_ofdm = 6; - for (aa=0; aaofdm_symbol_size + (l_ofdm-1)*frame_parms->nb_prefix_samples + frame_parms->nb_prefix_samples0], - frame_parms->ofdm_symbol_size + frame_parms->nb_prefix_samples); - txlev_sum += txlev[aa]; - if (n_trials==1) printf("txlev[%d] = %d (%f dB) txlev_sum %d\n",aa,txlev[aa],10*log10((double)txlev[aa]),txlev_sum); - } + int symbol_offset = slot_offset + l_ofdm * frame_parms->ofdm_symbol_size + (l_ofdm - 1) * frame_parms->nb_prefix_samples + + frame_parms->nb_prefix_samples0; + int symbol_length = frame_parms->ofdm_symbol_size + frame_parms->nb_prefix_samples; + double txlev_sum = compute_tx_energy_level(txdata, n_tx, symbol_offset, symbol_length, n_trials); for (i = 0; i < slot_length; i++) { for (aa=0; aanb_antennas_tx; aa++) { @@ -1189,11 +1186,11 @@ int main(int argc, char **argv) } } - double ts = 1.0/(frame_parms->subcarrier_spacing * frame_parms->ofdm_symbol_size); - //Compute AWGN variance - sigma2_dB = 10 * log10((double)txlev_sum * ((double)UE->frame_parms.ofdm_symbol_size/(12*pdsch_pdu_rel15->rbSize))) - SNR; - sigma2 = pow(10, sigma2_dB/10); - if (n_trials==1) printf("sigma2 %f (%f dB), txlev_sum %f (factor %f)\n",sigma2,sigma2_dB,10*log10((double)txlev_sum),(double)(double)UE->frame_parms.ofdm_symbol_size/(12*pdsch_pdu_rel15->rbSize)); + double ts = 1.0/(frame_parms->subcarrier_spacing * frame_parms->ofdm_symbol_size); + + // Estimate noise power from the transmitter level and SNR + double sigma2 = + compute_noise_variance(txlev_sum, UE->frame_parms.ofdm_symbol_size, pdsch_pdu_rel15->rbSize, 1, SNR, n_trials); for (aa = 0; aa < n_rx; aa++) { bzero(r_re[aa], slot_length * sizeof(double)); diff --git a/openair1/SIMULATION/NR_PHY/prachsim.c b/openair1/SIMULATION/NR_PHY/prachsim.c index f1a419d2a1..4dbac5dd7f 100644 --- a/openair1/SIMULATION/NR_PHY/prachsim.c +++ b/openair1/SIMULATION/NR_PHY/prachsim.c @@ -131,7 +131,7 @@ int main(int argc, char **argv){ sigaction(SIGINT, &sigint_action, &oldaction); get_softmodem_params()->sl_mode = 0; - double sigma2, sigma2_dB = 0, SNR, snr0 = -2.0, snr1 = 0.0, ue_speed0 = 0.0, ue_speed1 = 0.0; + double SNR, snr0 = -2.0, snr1 = 0.0, ue_speed0 = 0.0, ue_speed1 = 0.0; double **s_re, **s_im, **r_re, **r_im, iqim = 0.0, delay_avg = 0, ue_speed = 0, fs=-1, bw; int i, l, aa, aarx, trial, n_frames = 1, rx_prach_start; //, ntrials=1; c16_t **txdata; @@ -728,14 +728,7 @@ int main(int argc, char **argv){ for (trial = 0; trial < n_frames && !stop; trial++) { if (input_fd == NULL) { - sigma2_dB = 10*log10((double)tx_lev) - SNR - 10*log10(N_RB_UL*12/N_ZC); - - if (n_frames==1) - printf("sigma2_dB %f (SNR %f dB) tx_lev_dB %f\n",sigma2_dB,SNR,10*log10((double)tx_lev)); - - //AWGN - sigma2 = pow(10,sigma2_dB/10); - // printf("Sigma2 %f (sigma2_dB %f)\n",sigma2,sigma2_dB); + double sigma2 = compute_noise_variance(tx_lev, N_ZC, N_RB_UL, 1, SNR, n_frames); if (awgn_flag == 0) { multipath_tv_channel(UE2gNB, s_re, s_im, r_re, r_im, frame_parms->samples_per_frame, 0); diff --git a/openair1/SIMULATION/NR_PHY/pucchsim.c b/openair1/SIMULATION/NR_PHY/pucchsim.c index 21d43f48ad..db20b21b8f 100644 --- a/openair1/SIMULATION/NR_PHY/pucchsim.c +++ b/openair1/SIMULATION/NR_PHY/pucchsim.c @@ -96,7 +96,7 @@ int main(int argc, char **argv) sigaction(SIGINT, &sigint_action, &oldaction); int i;//,l; - double sigma2, sigma2_dB=10,SNR,snr0=-2.0,snr1=2.0; + double SNR, snr0 = -2.0, snr1 = 2.0; double cfo=0; uint8_t snr1set=0; double **s_re,**s_im,**r_re,**r_im; @@ -566,15 +566,16 @@ int main(int argc, char **argv) // SNR Computation // standard says: SNR = S / N, where S is the total signal energy, N is the noise energy in the transmission bandwidth (i.e. N_RB_DL resource blocks) // txlev = S. - int txlev = signal_energy((int32_t *)&txdataF[0][startingSymbolIndex*frame_parms->ofdm_symbol_size], frame_parms->ofdm_symbol_size); + + // Compute transmitter energy level + int symbol_offset = startingSymbolIndex * frame_parms->ofdm_symbol_size; + int symbol_length = frame_parms->ofdm_symbol_size; + double txlev = compute_tx_energy_level(txdataF, 1, symbol_offset, symbol_length, n_trials); // sigma2 is variance per dimension, so N/(N_RB*12) // so, sigma2 = N/(N_RB_DL*12) => (S/SNR)/(N_RB*12) int N_RB = (format == 0 || format == 1) ? 1 : nrofPRB; - sigma2_dB = 10*log10(txlev*(N_RB_DL/N_RB))-SNR; - sigma2 = pow(10.0,sigma2_dB/10.0); - - if (n_trials==1) printf("txlev %d (%f dB), offset %d, sigma2 %f ( %f dB)\n",txlev,10*log10(txlev),startingSymbolIndex*frame_parms->ofdm_symbol_size,sigma2,sigma2_dB); + double sigma2 = compute_noise_variance(txlev, N_RB_DL * 12, N_RB, 1, SNR, n_trials); for (int symb=0; symbframe_parms.symbols_per_slot;symb++) { if (symb= startingSymbolIndex+nrofSymbols) { @@ -648,7 +649,16 @@ int main(int argc, char **argv) gNB_I0_measurements(gNB, nr_slot_tx, 0, gNB->frame_parms.symbols_per_slot, rb_mask_ul); start_meas(&gNB->phy_proc_rx); - if (n_trials==1) printf("noise rxlev %d (%d dB), rxlev pucch %d dB sigma2 %f dB, SNR %f, TX %f, I0 (pucch) %d, I0 (avg) %d\n",rxlev,dB_fixed(rxlev),dB_fixed(rxlev_pucch),sigma2_dB,SNR,10*log10((double)txlev*UE->frame_parms.ofdm_symbol_size/12),gNB->measurements.n0_subband_power_tot_dB[startingPRB],gNB->measurements.n0_subband_power_avg_dB); + if (n_trials == 1) + printf("noise rxlev %d (%d dB), rxlev pucch %d dB sigma2 %f dB, SNR %f, TX %f, I0 (pucch) %d, I0 (avg) %d\n", + rxlev, + dB_fixed(rxlev), + dB_fixed(rxlev_pucch), + 10 * log10(sigma2), + SNR, + 10 * log10((double)txlev * UE->frame_parms.ofdm_symbol_size / 12), + gNB->measurements.n0_subband_power_tot_dB[startingPRB], + gNB->measurements.n0_subband_power_avg_dB); if(format==0){ nfapi_nr_uci_pucch_pdu_format_0_1_t uci_pdu; nfapi_nr_pucch_pdu_t pucch_pdu; diff --git a/openair1/SIMULATION/NR_PHY/srssim.c b/openair1/SIMULATION/NR_PHY/srssim.c index fa7388498b..c86ab2b6a9 100644 --- a/openair1/SIMULATION/NR_PHY/srssim.c +++ b/openair1/SIMULATION/NR_PHY/srssim.c @@ -549,7 +549,7 @@ int main(int argc, char *argv[]) int tao_ns_count = 0; for (trial = 0; trial < n_trials && !stop; trial++) { // Estimate noise power from the transmitter level and SNR - double sigma = compute_noise_variance(txlev_sum, ofdm_symbol_size, srs_pdu.bwp_size, SNR, n_trials); + double sigma = compute_noise_variance(txlev_sum, ofdm_symbol_size, srs_pdu.bwp_size, 1, SNR, n_trials); //----------- Apply propagation channel ---------------------------- multipath_channel(UE2gNB, s_re, s_im, r_re, r_im, slot_length, 0, (n_trials == 1) ? 1 : 0); diff --git a/openair1/SIMULATION/NR_PHY/ulsim.c b/openair1/SIMULATION/NR_PHY/ulsim.c index 444492b545..d7bd25555f 100644 --- a/openair1/SIMULATION/NR_PHY/ulsim.c +++ b/openair1/SIMULATION/NR_PHY/ulsim.c @@ -281,7 +281,6 @@ int main(int argc, char *argv[]) char *filename_csv = NULL; int i; double SNR, snr0 = -2.0, snr1 = 2.0; - double sigma, sigma_dB; double snr_step = .2; uint8_t snr1set = 0; int slot = 8, frame = 1; @@ -308,7 +307,7 @@ int main(int argc, char *argv[]) int Imcs = 9; uint8_t precod_nbr_layers = 1; int tx_offset; - int32_t txlev_sum = 0, atxlev[4]; + double txlev_sum = 0; int start_rb = 0; int UE_id = 0; int print_perf = 0; @@ -1401,36 +1400,22 @@ int main(int argc, char *argv[]) } /////////// //////////////////////////////////////////////////// + // Compute transmitter energy level tx_offset = get_samples_slot_timestamp(&gNB->frame_parms, slot); - txlev_sum = 0; - for (int aa = 0; aa < UE->frame_parms.nb_antennas_tx; aa++) { - atxlev[aa] = - signal_energy((int32_t *)&UE->common_vars - .txData[aa][tx_offset + 5 * gNB->frame_parms.ofdm_symbol_size - + 4 * gNB->frame_parms.nb_prefix_samples + gNB->frame_parms.nb_prefix_samples0], - gNB->frame_parms.ofdm_symbol_size + gNB->frame_parms.nb_prefix_samples); - - txlev_sum += atxlev[aa]; - - if (n_trials == 1) - printf("txlev[%d] = %d (%f dB) txlev_sum %d\n", aa, atxlev[aa], 10 * log10((double)atxlev[aa]), txlev_sum); - } + int symbol_offset = tx_offset + 5 * gNB->frame_parms.ofdm_symbol_size + 4 * gNB->frame_parms.nb_prefix_samples + + gNB->frame_parms.nb_prefix_samples0; + int symbol_length = gNB->frame_parms.ofdm_symbol_size + gNB->frame_parms.nb_prefix_samples; + txlev_sum = compute_tx_energy_level(UE->common_vars.txData, + UE->frame_parms.nb_antennas_tx, + symbol_offset, + symbol_length, + n_trials); } else n_trials = 1; if (input_fd == NULL) { - // Justification of division by precod_nbr_layers: - // When the channel is the identity matrix, the results in terms of SNR should be almost equal for 2x2 and 4x4. - sigma_dB = - 10 * log10((double)txlev_sum / precod_nbr_layers * ((double)gNB->frame_parms.ofdm_symbol_size / (12 * nb_rb))) - SNR; - sigma = pow(10, sigma_dB / 10); - - if (n_trials == 1) - printf("sigma %f (%f dB), txlev_sum %f (factor %f)\n", - sigma, - sigma_dB, - 10 * log10((double)txlev_sum), - (double)(double)gNB->frame_parms.ofdm_symbol_size / (12 * nb_rb)); + double sigma = + compute_noise_variance(txlev_sum, gNB->frame_parms.ofdm_symbol_size, nb_rb, precod_nbr_layers, SNR, n_trials); for (i = 0; i < slot_length; i++) { for (int aa = 0; aa < UE->frame_parms.nb_antennas_tx; aa++) { From 5d545a6cc5302876b9613c4a6a74315b33b2602c Mon Sep 17 00:00:00 2001 From: Rakesh Mundlamuri Date: Wed, 31 Dec 2025 18:16:42 +0530 Subject: [PATCH 22/22] Add srssim to the feature set --- doc/BUILD.md | 2 +- doc/cross-compile.md | 2 +- doc/physical-simulators.md | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/doc/BUILD.md b/doc/BUILD.md index 8298204859..bf05a5cc00 100644 --- a/doc/BUILD.md +++ b/doc/BUILD.md @@ -32,7 +32,7 @@ The main oai binaries, which are tested by the Continuous Integration process ar - The 5G gNodeB: `nr-softmodem` - The 5G CU-UP: `nr-cuup` - The LTE PHY simulators: `dlsim` and `ulsim` -- The 5G PHY simulators: `nr_dlschsim`, `nr_dlsim`, `nr_pbchsim`, `nr_pucchsim`, `nr_ulschsim`, `nr_ulsim`, `polartest`, `smallblocktest`, `nr _ulsim`, `ldpctest` +- The 5G PHY simulators: `nr_dlschsim`, `nr_dlsim`, `nr_pbchsim`, `nr_pucchsim`, `nr_ulschsim`, `nr_ulsim`, `polartest`, `smallblocktest`, `nr _ulsim`, `ldpctest`, `nr_srssim` Running the [build_oai](../cmake_targets/build_oai) script also generates some utilities required to build and/or run the oai softmodem binaries: diff --git a/doc/cross-compile.md b/doc/cross-compile.md index 79c4bae761..20edec65b8 100644 --- a/doc/cross-compile.md +++ b/doc/cross-compile.md @@ -89,7 +89,7 @@ be defined in order to tell cmake where the host tools have been built. cd ../build-cross cmake ../../.. -GNinja -DCMAKE_TOOLCHAIN_FILE=../../../cmake_targets/cross-arm.cmake -DNATIVE_DIR=../build -ninja dlsim ulsim ldpctest polartest smallblocktest nr_pbchsim nr_dlschsim nr_ulschsim nr_dlsim nr_ulsim nr_pucchsim nr_prachsim +ninja dlsim ulsim ldpctest polartest smallblocktest nr_pbchsim nr_dlschsim nr_ulschsim nr_dlsim nr_ulsim nr_pucchsim nr_prachsim nr_srssim ninja lte-softmodem nr-softmodem nr-cuup oairu lte-uesoftmodem nr-uesoftmodem ninja params_libconfig coding rfsimulator ``` diff --git a/doc/physical-simulators.md b/doc/physical-simulators.md index b74531fd20..0f000bb16f 100644 --- a/doc/physical-simulators.md +++ b/doc/physical-simulators.md @@ -36,6 +36,7 @@ pipelines: | | `nr_pbchsim` | Broadcast channel simulation | | | `nr_prachsim` | PRACH simulation | | | `nr_psbchsim` | Sidelink simulation | +| | `nr_srssim` | SRS simulation | | Coding | `ldpctest`, `polartest`, `smallblocktest` | LDPC, Polar, and other FEC tests | ## Source Locations