Merge remote-tracking branch 'origin/srs-delay-comp' into integration_2026_w12 (!3859)

Delay compensation in SRS

Implementation of delay compensation in channel estimation based on SRS.

Testing, for example, with

    sudo ./nr_ulsim -n1 -s50 -S50 -R51 -E 1 -W2 -y2 -z2 -d 10

we obtain the following logs.

LOGs with develop branch:

    [NR_PHY] 	  __lsRe__________lsIm__|____intRe_______intIm__|____noiRe_______noiIm__
    [NR_PHY] (   0)    687	  -198  |     688	  -198  |      -1	    -3
    [NR_PHY] (   1)      0	     0  |     688	  -196  |      -1	    -3
    [NR_PHY] (   2)    687	  -198  |     644	  -272  |      -1	    -1
    [NR_PHY] (   3)      0	     0  |     600	  -346  |      -1	    -1
    [NR_PHY] (   4)    513	  -498  |     556	  -422  |      -1	    -1
    [NR_PHY] (   5)      0	     0  |     512	  -496  |      -1	    -1
    [NR_PHY] (   6)    513	  -498  |     440	  -542  |      -1	     0
    [NR_PHY] (   7)      0	     0  |     370	  -588  |      -1	     0
    [NR_PHY] (   8)    226	  -682  |     298	  -634  |      -1	    -3
    [NR_PHY] (   9)      0	     0  |     228	  -680  |      -1	    -3
    [NR_PHY] (  10)    226	  -682  |     140	  -686  |      -1	    -1
    [NR_PHY] (  11)      0	     0  |      52	  -690  |      -1	    -1

intRe and intIm are the real and imaginary part of the interpolated
channel, respectively. These are the columns that matter. As we can see,
for example, in subcarrier 0 we have (688, -198), then in subcarrier 1
we have (688, -196), which is almost the same, and then in subcarrier 3
we have a jump (644, -272). This MR improves channel estimation by
taking delay into account. If we look at the following logs, we see that
the values vary more consistently from subcarrier to subcarrier.

LOGs with this MR:

    [NR_PHY] 	  __lsRe__________lsIm__|____intRe_______intIm__|____noiRe_______noiIm__
    [NR_PHY] (   0)    487	  -139  |     490	  -111  |      -1	     0
    [NR_PHY] (   1)    487	  -139  |     483	  -138  |      -1	     0
    [NR_PHY] (   2)    487	  -139  |     465	  -197  |       0	     0
    [NR_PHY] (   3)    487	  -139  |     436	  -254  |       0	     0
    [NR_PHY] (   4)    364	  -353  |     402	  -305  |      -1	    -1
    [NR_PHY] (   5)    364	  -353  |     361	  -352  |      -1	    -1
    [NR_PHY] (   6)    364	  -353  |     317	  -392  |      -1	    -1
    [NR_PHY] (   7)    364	  -353  |     269	  -426  |      -1	    -1
    [NR_PHY] (   8)    160	  -481  |     214	  -455  |       0	    -1
    [NR_PHY] (   9)    160	  -481  |     159	  -478  |       0	    -1
    [NR_PHY] (  10)    160	  -481  |      98	  -495  |      -1	     0
    [NR_PHY] (  11)    160	  -481  |      39	  -502  |      -1	     0
This commit is contained in:
Robert Schmidt
2026-03-19 17:41:59 +01:00
5 changed files with 268 additions and 156 deletions

View File

@@ -195,7 +195,7 @@ static void gnb_main_gui(gnb_gui *e, gui *g, event_handler *h, void *database, g
e->ul_freq_estimate_ue_xy_plot = w;
widget_add_child(g, line, w, -1);
xy_plot_set_range(g, w, 0, 2048, -10, 80);
l = new_framelog(h, database, "GNB_PHY_UL_FREQ_CHANNEL_ESTIMATE", "subframe", "chest_t");
l = new_framelog(h, database, "GNB_PHY_UL_FREQ_CHANNEL_ESTIMATE", "subframe", "chest_f");
framelog_set_update_only_at_sf9(l, 0);
v = new_view_xy(2048, 10, g, w, new_color(g, "#0c0c72"), XY_LOOP_MODE);
logger_add_view(l, v);

View File

@@ -366,6 +366,10 @@ void nr_deconstruct_5g_s_tmsi(const uint64_t fiveg_s_tmsi, uint16_t *amf_set_id,
#define ROUNDIDIV(a,b) (((a<<1)+b)/(b<<1))
#define BOUNDED_EVAL(a, b, c) (min(c, max(a, b)))
/* Macro used to perform a circular increment. This implementation is computationally more efficient than using the remainder of the
* integer division, and improves code readability when compared to repetitive if... else statements. */
#define CIRCULAR_INC(val, inc, size) (((val) + (inc) >= (size)) ? ((val) + (inc) - (size)) : ((val) + (inc)))
static const char *const duplex_mode_txt[] = {"FDD", "TDD"};
#ifdef __cplusplus

View File

@@ -765,29 +765,23 @@ void nr_pusch_ptrs_processing(PHY_VARS_gNB *gNB,
} // Antenna loop
}
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[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[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)
int nr_srs_ls_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[ofdm_symbol_size * N_symb_SRS],
c16_t srs_ls_estimated_channel[ofdm_symbol_size * N_symb_SRS],
delay_t *delay)
{
#ifdef SRS_DEBUG
LOG_I(NR_PHY, "Calling %s function\n", __FUNCTION__);
#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;
@@ -797,40 +791,20 @@ 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];
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;
// 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)
c16_t ls_estimated = {0};
#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);
#endif
subcarrier = subcarrier_offset + nr_srs_info->k_0_p[p_index][srs_symb];
if (subcarrier >= ofdm_symbol_size) {
subcarrier -= ofdm_symbol_size;
}
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];
uint16_t subcarrier = CIRCULAR_INC(subcarrier_offset + nr_srs_info->k_0_p[p_index][srs_symb], 0, ofdm_symbol_size);
c16_t ls_estimated = {0};
for (int k = 0; k < M_sc_b_SRS; k++) {
if (k % fd_cdm == 0) {
ls_estimated = (c16_t){0, 0};
@@ -845,14 +819,13 @@ int nr_srs_channel_estimation(int ant,
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_cdm = CIRCULAR_INC(subcarrier_cdm, K_TC, ofdm_symbol_size);
}
}
srs_ls_estimated_channel[srs_symbol_offset + subcarrier] = ls_estimated;
for (int ktc = 0; ktc < K_TC && srs_symbol_offset + subcarrier + ktc < ofdm_symbol_size * N_symb_SRS; ktc++) {
srs_ls_estimated_channel[srs_symbol_offset + subcarrier + ktc] = ls_estimated;
}
#ifdef SRS_DEBUG
int subcarrier_log = subcarrier - subcarrier_offset;
@@ -874,6 +847,140 @@ int nr_srs_channel_estimation(int ant,
ls_estimated.i);
#endif
// Subcarrier increment
subcarrier = CIRCULAR_INC(subcarrier, K_TC, ofdm_symbol_size);
} // for (int k = 0; k < M_sc_b_SRS; k++)
// Delay estimation
if (srs_symb == 0) {
c16_t ch_estimates_time[ofdm_symbol_size] __attribute__((aligned(32)));
nr_est_delay(ofdm_symbol_size, srs_ls_estimated_channel, ch_estimates_time, delay);
}
} // for (int srs_symb = 0; srs_symb < N_symb_SRS; srs_symb++)
return 0;
}
void nr_srs_noise_power_estimation(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,
uint32_t signal_power,
const c16_t srs_received_noise[ofdm_symbol_size * N_symb_SRS],
uint32_t *noise_power,
int16_t *noise_power_per_rb)
{
const uint64_t subcarrier_offset = first_carrier_offset + srs_pdu->bwp_start * NR_NB_SC_PER_RB;
const uint16_t m_SRS_b = get_m_srs(srs_pdu->config_index, srs_pdu->bandwidth_index);
int tot_subcarriers = m_SRS_b * NR_NB_SC_PER_RB;
uint16_t subcarrier = CIRCULAR_INC(subcarrier_offset + nr_srs_info->k_0_p[0][0], 0, ofdm_symbol_size);
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 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;
}
// Compute SNR per RB on symbol 0
subcarrier = CIRCULAR_INC(subcarrier_offset + nr_srs_info->k_0_p[0][0], 0, ofdm_symbol_size);
for (int rb = 0; rb < m_SRS_b; rb++) {
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 = CIRCULAR_INC(subcarrier, NR_NB_SC_PER_RB, 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[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
}
int nr_srs_channel_interpolation(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_ls_estimated_channel[ofdm_symbol_size * N_symb_SRS],
int est_delay,
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[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,
c16_t delay_table[2 * MAX_DELAY_COMP + 1][NR_MAX_OFDM_SYMBOL_SIZE])
{
#ifdef SRS_DEBUG
LOG_I(NR_PHY, "Calling %s function\n", __FUNCTION__);
#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 K_TC = 2 << srs_pdu->comb_size;
const uint16_t m_SRS_b = get_m_srs(srs_pdu->config_index, srs_pdu->bandwidth_index);
const uint16_t M_sc_b_SRS = m_SRS_b * NR_NB_SC_PER_RB / K_TC;
c16_t srs_estimated_channel_freq_avg[ofdm_symbol_size];
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;
#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);
#endif
// 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)) / sizeof(c16_t);
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];
uint16_t subcarrier = CIRCULAR_INC(subcarrier_offset + nr_srs_info->k_0_p[p_index][srs_symb], 0, ofdm_symbol_size);
int delay_idx = get_delay_idx(est_delay, MAX_DELAY_COMP);
const c16_t *srs_delay_table = delay_table[delay_idx];
for (int k = 0; k < M_sc_b_SRS; k++) {
// Apply delay
c16_t ls_estimated = c16mulShift(srs_ls_estimated_channel[srs_symbol_offset + subcarrier], srs_delay_table[subcarrier], 8);
// Channel interpolation
if (srs_pdu->comb_size == 0) {
if (k == 0) { // First subcarrier case
@@ -905,15 +1012,23 @@ int nr_srs_channel_estimation(int ant,
}
// Subcarrier increment
subcarrier += K_TC;
if (subcarrier >= ofdm_symbol_size) {
subcarrier -= ofdm_symbol_size;
}
subcarrier = CIRCULAR_INC(subcarrier, K_TC, ofdm_symbol_size);
subcarrier_abs += K_TC;
} // for (int k = 0; k < M_sc_b_SRS; k++)
// Revert delay
int inv_delay_idx = get_delay_idx(-est_delay, MAX_DELAY_COMP);
const c16_t *srs_inv_delay_table = delay_table[inv_delay_idx];
subcarrier_abs = mem_offset + first_subcarrier + nr_srs_info->k_0_p[p_index][srs_symb];
subcarrier = CIRCULAR_INC(subcarrier_offset + nr_srs_info->k_0_p[p_index][0], 0, ofdm_symbol_size);
for (int k = 0; k < K_TC * M_sc_b_SRS; k++) {
srs_est[subcarrier_abs] = c16mulShift(srs_est[subcarrier_abs], srs_inv_delay_table[subcarrier], 8);
// Subcarrier increment
subcarrier = CIRCULAR_INC(subcarrier, 1, ofdm_symbol_size);
subcarrier_abs++;
}
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
@@ -924,11 +1039,7 @@ int nr_srs_channel_estimation(int ant,
ofdm_symbol_size);
#ifdef SRS_DEBUG
subcarrier = subcarrier_offset + nr_srs_info->k_0_p[p_index][srs_symb];
if (subcarrier >= ofdm_symbol_size) {
subcarrier -= ofdm_symbol_size;
}
subcarrier = CIRCULAR_INC(subcarrier_offset + nr_srs_info->k_0_p[p_index][srs_symb], 0, 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++) {
@@ -956,10 +1067,7 @@ int nr_srs_channel_estimation(int ant,
srs_received_noise[srs_symbol_offset + subcarrier].i);
// Subcarrier increment
subcarrier++;
if (subcarrier >= ofdm_symbol_size) {
subcarrier -= ofdm_symbol_size;
}
subcarrier = CIRCULAR_INC(subcarrier, 1, ofdm_symbol_size);
subcarrier_abs++;
}
#endif
@@ -996,61 +1104,5 @@ int nr_srs_channel_estimation(int ant,
return -1;
}
subcarrier = subcarrier_offset + nr_srs_info->k_0_p[p_index][0];
if (subcarrier >= ofdm_symbol_size) {
subcarrier -= ofdm_symbol_size;
}
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 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;
}
}
// 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,
"[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;
}

View File

@@ -75,22 +75,43 @@ void nr_pusch_ptrs_processing(PHY_VARS_gNB *gNB,
unsigned char symbol,
uint32_t nb_re_pusch);
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[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[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);
int nr_srs_ls_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[ofdm_symbol_size * N_symb_SRS],
c16_t srs_ls_estimated_channel[ofdm_symbol_size * N_symb_SRS],
delay_t *delay);
int nr_srs_channel_interpolation(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_ls_estimated_channel[ofdm_symbol_size * N_symb_SRS],
int est_delay,
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[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,
c16_t delay_table[2 * MAX_DELAY_COMP + 1][NR_MAX_OFDM_SYMBOL_SIZE]);
void nr_srs_noise_power_estimation(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,
uint32_t signal_power,
const c16_t srs_received_noise[ofdm_symbol_size * N_symb_SRS],
uint32_t *noise_power,
int16_t *noise_power_per_rb);
void nr_freq_equalization(NR_DL_FRAME_PARMS *frame_parms,
c16_t *rxdataF_comp,

View File

@@ -880,32 +880,49 @@ void nr_srs_rx_procedures(PHY_VARS_gNB *gNB,
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));
c16_t srs_ls_estimated_channel[nb_antennas_rx][N_ap][ofdm_symbol_size * N_symb_SRS];
if (*srs_est >= 0) {
start_meas(&gNB->srs_channel_estimation_stats);
delay_t delay = {0};
for (int ant_rx_ind = 0; ant_rx_ind < nb_antennas_rx; ant_rx_ind++) {
for (int p_ind = 0; p_ind < N_ap; p_ind++) {
delay_t delay_aux = {0};
nr_srs_ls_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],
srs_received_signal[ant_rx_ind],
srs_ls_estimated_channel[ant_rx_ind][p_ind],
&delay_aux);
if (delay_aux.delay_max_val > delay.delay_max_val)
delay = delay_aux;
}
}
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(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],
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);
nr_srs_channel_interpolation(ant_rx_ind,
p_ind,
ofdm_symbol_size,
frame_parms->first_carrier_offset,
N_symb_SRS,
srs_pdu,
nr_srs_info,
srs_ls_estimated_channel[ant_rx_ind][p_ind],
delay.est_delay,
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,
frame_parms->delay_table);
signal_power_avg += signal_power;
@@ -913,7 +930,7 @@ void nr_srs_rx_procedures(PHY_VARS_gNB *gNB,
T_INT(gNB->Mod_id),
T_INT(srs_pdu->rnti),
T_INT(frame_rx),
T_INT(slot_rx),
T_INT(0),
T_INT(ant_rx_ind),
T_INT(p_ind),
T_BUFFER(srs_estimated_channel_freq[ant_rx_ind][p_ind], N_symb_SRS * ofdm_symbol_size * sizeof(c16_t)));
@@ -922,17 +939,35 @@ void nr_srs_rx_procedures(PHY_VARS_gNB *gNB,
T_INT(gNB->Mod_id),
T_INT(srs_pdu->rnti),
T_INT(frame_rx),
T_INT(slot_rx),
T_INT(0),
T_INT(ant_rx_ind),
T_INT(p_ind),
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;
}
signal_power_avg /= (nb_antennas_rx * N_ap);
noise_power_avg /= nb_antennas_rx;
signal_power_avg = max(signal_power_avg, 1);
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));
for (int ant_rx_ind = 0; ant_rx_ind < nb_antennas_rx; ant_rx_ind++) {
uint32_t noise_power_per_ant = 0;
nr_srs_noise_power_estimation(ofdm_symbol_size,
frame_parms->first_carrier_offset,
N_symb_SRS,
srs_pdu,
nr_srs_info,
signal_power_avg,
srs_received_noise[ant_rx_ind],
&noise_power_per_ant,
noise_power_per_rb);
noise_power_avg += noise_power_per_ant;
}
noise_power_avg /= nb_antennas_rx;
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);