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.
This commit is contained in:
@@ -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];
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user