From be3ad2beba4152e6e22548253d5a5d4ed10943cc Mon Sep 17 00:00:00 2001 From: Rakesh Mundlamuri Date: Thu, 20 Nov 2025 17:20:29 +0530 Subject: [PATCH] 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; }