Introduce SRS multi-symbol channel estimation

This commit is contained in:
Rakesh Mundlamuri
2026-01-09 16:58:34 +05:30
parent 0b0dce9995
commit 0b197891cc
4 changed files with 245 additions and 208 deletions
@@ -800,26 +800,37 @@ 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))) { if (N_ap == 4 && ((K_TC == 2 && srs_pdu->cyclic_shift >= 4) || (K_TC == 4 && srs_pdu->cyclic_shift >= 6))) {
fd_cdm = 2; fd_cdm = 2;
} }
uint16_t subcarrier;
c16_t srs_ls_estimated_channel[ofdm_symbol_size * N_symb_SRS]; 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) 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_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) >> 2; // >> 2 <=> /sizeof(int32_t)
// filt16_end is {4096,8192,8192,8192,12288,16384,16384,16384,0,0,0,0,0,0,0,0} // 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 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, // The c16multaddVectRealComplex applies the remaining 8 zeros of filter, therefore, to avoid a buffer overflow,
// we added 8 in the array size // 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 srs_est[ofdm_symbol_size + mem_offset + 8] __attribute__((aligned(32)));
c16_t ls_estimated = {0}; c16_t ls_estimated = {0};
memset(srs_ls_estimated_channel, 0, ofdm_symbol_size * N_symb_SRS * sizeof(c16_t)); memset(srs_est, 0, (ofdm_symbol_size + mem_offset + 8) * sizeof(c16_t));
memset(srs_est, 0, (ofdm_symbol_size * N_symb_SRS + mem_offset) * sizeof(c16_t));
#ifdef SRS_DEBUG #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 #endif
uint16_t subcarrier = subcarrier_offset + nr_srs_info->k_0_p[p_index][0]; subcarrier = subcarrier_offset + nr_srs_info->k_0_p[p_index][srs_symb];
if (subcarrier >= ofdm_symbol_size) { if (subcarrier >= ofdm_symbol_size) {
subcarrier -= ofdm_symbol_size; subcarrier -= ofdm_symbol_size;
} }
@@ -832,8 +843,8 @@ int nr_srs_channel_estimation(int ant,
uint16_t subcarrier_cdm = subcarrier; uint16_t subcarrier_cdm = subcarrier;
for (int cdm_idx = 0; cdm_idx < fd_cdm; cdm_idx++) { for (int cdm_idx = 0; cdm_idx < fd_cdm; cdm_idx++) {
c16_t generated_srs = srs_generated_signal[subcarrier_cdm]; c16_t generated_srs = srs_generated_signal[srs_symbol_offset + subcarrier_cdm];
c16_t received_srs = srs_received_signal[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 // 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 // generated_srs. So we only need a nr_srs_info->srs_generated_signal_bits shift to ensure that the result fits into 16
// bits. // bits.
@@ -847,7 +858,7 @@ int nr_srs_channel_estimation(int ant,
} }
} }
srs_ls_estimated_channel[subcarrier] = ls_estimated; srs_ls_estimated_channel[srs_symbol_offset + subcarrier] = ls_estimated;
#ifdef SRS_DEBUG #ifdef SRS_DEBUG
int subcarrier_log = subcarrier - subcarrier_offset; int subcarrier_log = subcarrier - subcarrier_offset;
@@ -861,10 +872,10 @@ int nr_srs_channel_estimation(int ant,
LOG_I(NR_PHY, LOG_I(NR_PHY,
"(%4i) %6i\t%6i | %6i\t%6i | %6i\t%6i\n", "(%4i) %6i\t%6i | %6i\t%6i | %6i\t%6i\n",
subcarrier_log, subcarrier_log,
srs_generated_signal[subcarrier].r, srs_generated_signal[srs_symbol_offset + subcarrier].r,
srs_generated_signal[subcarrier].i, srs_generated_signal[srs_symbol_offset + subcarrier].i,
srs_received_signal[subcarrier].r, srs_received_signal[srs_symbol_offset + subcarrier].r,
srs_received_signal[subcarrier].i, srs_received_signal[srs_symbol_offset + subcarrier].i,
ls_estimated.r, ls_estimated.r,
ls_estimated.i); ls_estimated.i);
#endif #endif
@@ -921,10 +932,17 @@ int nr_srs_channel_estimation(int ant,
} // for (int k = 0; k < M_sc_b_SRS; k++) } // 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)); 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 #ifdef SRS_DEBUG
subcarrier = subcarrier_offset + nr_srs_info->k_0_p[p_index][0]; subcarrier = subcarrier_offset + nr_srs_info->k_0_p[p_index][srs_symb];
if (subcarrier >= ofdm_symbol_size) { if (subcarrier >= ofdm_symbol_size) {
subcarrier -= ofdm_symbol_size; subcarrier -= ofdm_symbol_size;
} }
@@ -936,19 +954,22 @@ int nr_srs_channel_estimation(int ant,
} }
if (subcarrier_log % 12 == 0) { if (subcarrier_log % 12 == 0) {
LOG_I(NR_PHY, "------------------------------------- %d -------------------------------------\n", subcarrier_log / 12); 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, "\t __lsRe__________lsIm__|____intRe_______intIm__|____noiRe_______noiIm__\n");
} }
LOG_I(NR_PHY, LOG_I(NR_PHY,
"(%4i) %6i\t%6i | %6i\t%6i | %6i\t%6i\n", "(%4i) %6i\t%6i | %6i\t%6i | %6i\t%6i\n",
subcarrier_log, subcarrier_log,
srs_ls_estimated_channel[subcarrier].r, srs_ls_estimated_channel[srs_symbol_offset + subcarrier].r,
srs_ls_estimated_channel[subcarrier].i, srs_ls_estimated_channel[srs_symbol_offset + subcarrier].i,
srs_estimated_channel_freq[subcarrier].r, srs_estimated_channel_freq[srs_symbol_offset + subcarrier].r,
srs_estimated_channel_freq[subcarrier].i, srs_estimated_channel_freq[srs_symbol_offset + subcarrier].i,
srs_received_noise[subcarrier].r, srs_received_noise[srs_symbol_offset + subcarrier].r,
srs_received_noise[subcarrier].i); srs_received_noise[srs_symbol_offset + subcarrier].i);
// Subcarrier increment // Subcarrier increment
subcarrier++; subcarrier++;
@@ -957,6 +978,7 @@ int nr_srs_channel_estimation(int ant,
} }
} }
#endif #endif
}
// Convert to time domain // Convert to time domain
int16_t ofdm_symbol_size_half = ofdm_symbol_size >> 1; int16_t ofdm_symbol_size_half = ofdm_symbol_size >> 1;
@@ -968,9 +990,9 @@ int nr_srs_channel_estimation(int ant,
memset(chF_interpol, 0, sizeof(chF_interpol)); memset(chF_interpol, 0, sizeof(chF_interpol));
// Place SRS channel estimates in FFT shifted format for oversampling // 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[0], &srs_estimated_channel_freq_avg[0], ofdm_symbol_size_half * sizeof(c16_t));
memcpy(&chF_interpol[start_offset], memcpy(&chF_interpol[start_offset],
&srs_estimated_channel_freq[ofdm_symbol_size_half], &srs_estimated_channel_freq_avg[ofdm_symbol_size_half],
ofdm_symbol_size_half * sizeof(c16_t)); ofdm_symbol_size_half * sizeof(c16_t));
// Convert to time domain oversampled // Convert to time domain oversampled
@@ -981,7 +1003,7 @@ int nr_srs_channel_estimation(int ant,
memcpy(&srs_estimated_channel_time_shifted[ofdm_os_size_half], srs_estimated_channel_time, 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 // Compute wideband SNR on the symbol 0
int tot_subcarriers = m_SRS_b * NR_NB_SC_PER_RB; int tot_subcarriers = m_SRS_b * NR_NB_SC_PER_RB;
subcarrier = subcarrier_offset + nr_srs_info->k_0_p[p_index][0]; subcarrier = subcarrier_offset + nr_srs_info->k_0_p[p_index][0];
if (subcarrier >= ofdm_symbol_size) { if (subcarrier >= ofdm_symbol_size) {
@@ -1011,7 +1033,7 @@ int nr_srs_channel_estimation(int ant,
return -1; return -1;
} }
// Compute SNR per RB for port 0 // Compute SNR per RB for port 0 and symbol 0
if (p_index == 0) { if (p_index == 0) {
subcarrier = subcarrier_offset + nr_srs_info->k_0_p[p_index][0]; subcarrier = subcarrier_offset + nr_srs_info->k_0_p[p_index][0];
for (int rb = 0; rb < m_SRS_b; rb++) { for (int rb = 0; rb < m_SRS_b; rb++) {
@@ -1031,13 +1053,23 @@ int nr_srs_channel_estimation(int ant,
subcarrier += NR_NB_SC_PER_RB; subcarrier += NR_NB_SC_PER_RB;
#ifdef SRS_DEBUG #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[rb],
dB_fixed(*signal_power) - dB_fixed(noise_power_per_rb[rb]));
#endif #endif
} }
} }
#ifdef SRS_DEBUG #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); 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 #endif
return 0; return 0;
+1 -1
View File
@@ -928,7 +928,7 @@ void nr_srs_rx_procedures(PHY_VARS_gNB *gNB,
T_INT(slot_rx), T_INT(slot_rx),
T_INT(ant_rx_ind), T_INT(ant_rx_ind),
T_INT(p_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(T_GNB_PHY_UL_TIME_CHANNEL_ESTIMATE,
T_INT(gNB->Mod_id), T_INT(gNB->Mod_id),
+1 -1
View File
@@ -143,7 +143,7 @@ int main(int argc, char *argv[])
AssertFatal(nb_symb_srs == 1 || nb_symb_srs == 2 || nb_symb_srs == 4, AssertFatal(nb_symb_srs == 1 || nb_symb_srs == 2 || nb_symb_srs == 4,
"number of srs symbols %d is not 1,2,4\n", "number of srs symbols %d is not 1,2,4\n",
nb_symb_srs); 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; break;
case 'c': case 'c':
+5
View File
@@ -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.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.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.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 ###### ###### offload-specific tests ######