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; +}