Commit ec3642ea authored by Robert Schmidt's avatar Robert Schmidt

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
parents 040b62e8 4f31a4eb
...@@ -195,7 +195,7 @@ static void gnb_main_gui(gnb_gui *e, gui *g, event_handler *h, void *database, g ...@@ -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; e->ul_freq_estimate_ue_xy_plot = w;
widget_add_child(g, line, w, -1); widget_add_child(g, line, w, -1);
xy_plot_set_range(g, w, 0, 2048, -10, 80); 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); framelog_set_update_only_at_sf9(l, 0);
v = new_view_xy(2048, 10, g, w, new_color(g, "#0c0c72"), XY_LOOP_MODE); v = new_view_xy(2048, 10, g, w, new_color(g, "#0c0c72"), XY_LOOP_MODE);
logger_add_view(l, v); logger_add_view(l, v);
......
...@@ -366,6 +366,10 @@ void nr_deconstruct_5g_s_tmsi(const uint64_t fiveg_s_tmsi, uint16_t *amf_set_id, ...@@ -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 ROUNDIDIV(a,b) (((a<<1)+b)/(b<<1))
#define BOUNDED_EVAL(a, b, c) (min(c, max(a, b))) #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"}; static const char *const duplex_mode_txt[] = {"FDD", "TDD"};
#ifdef __cplusplus #ifdef __cplusplus
......
...@@ -75,22 +75,43 @@ void nr_pusch_ptrs_processing(PHY_VARS_gNB *gNB, ...@@ -75,22 +75,43 @@ void nr_pusch_ptrs_processing(PHY_VARS_gNB *gNB,
unsigned char symbol, unsigned char symbol,
uint32_t nb_re_pusch); uint32_t nb_re_pusch);
int nr_srs_channel_estimation(int ant, int nr_srs_ls_channel_estimation(int ant,
int p_index, int p_index,
uint16_t ofdm_symbol_size, uint16_t ofdm_symbol_size,
uint16_t first_carrier_offset, uint16_t first_carrier_offset,
uint8_t N_symb_SRS, uint8_t N_symb_SRS,
const nfapi_nr_srs_pdu_t *srs_pdu, const nfapi_nr_srs_pdu_t *srs_pdu,
const nr_srs_info_t *nr_srs_info, const nr_srs_info_t *nr_srs_info,
const c16_t *srs_generated_signal, const c16_t *srs_generated_signal,
c16_t srs_received_signal[ofdm_symbol_size * N_symb_SRS], 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_ls_estimated_channel[ofdm_symbol_size * N_symb_SRS],
c16_t srs_estimated_channel_freq[ofdm_symbol_size * N_symb_SRS], delay_t *delay);
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], int nr_srs_channel_interpolation(int ant,
uint32_t *signal_power, int p_index,
uint32_t *noise_power, uint16_t ofdm_symbol_size,
int16_t *noise_power_per_rb); 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, void nr_freq_equalization(NR_DL_FRAME_PARMS *frame_parms,
c16_t *rxdataF_comp, c16_t *rxdataF_comp,
......
...@@ -880,32 +880,49 @@ void nr_srs_rx_procedures(PHY_VARS_gNB *gNB, ...@@ -880,32 +880,49 @@ void nr_srs_rx_procedures(PHY_VARS_gNB *gNB,
stop_meas(&gNB->get_srs_signal_stats); stop_meas(&gNB->get_srs_signal_stats);
uint32_t signal_power_avg = 0; uint32_t signal_power_avg = 0;
uint32_t noise_power_avg = 0; c16_t srs_ls_estimated_channel[nb_antennas_rx][N_ap][ofdm_symbol_size * N_symb_SRS];
int16_t noise_power_per_rb[srs_pdu->bwp_size];
memset(noise_power_per_rb, 0, srs_pdu->bwp_size * sizeof(int16_t));
if (*srs_est >= 0) { if (*srs_est >= 0) {
start_meas(&gNB->srs_channel_estimation_stats); 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++) { 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++) { for (int p_ind = 0; p_ind < N_ap; p_ind++) {
uint32_t signal_power = 0; uint32_t signal_power = 0;
nr_srs_channel_estimation(ant_rx_ind, nr_srs_channel_interpolation(ant_rx_ind,
p_ind, p_ind,
ofdm_symbol_size, ofdm_symbol_size,
frame_parms->first_carrier_offset, frame_parms->first_carrier_offset,
N_symb_SRS, N_symb_SRS,
srs_pdu, srs_pdu,
nr_srs_info, nr_srs_info,
nr_srs_info->srs_generated_signal[p_ind], srs_ls_estimated_channel[ant_rx_ind][p_ind],
srs_received_signal[ant_rx_ind], delay.est_delay,
srs_received_noise[ant_rx_ind], srs_received_noise[ant_rx_ind],
srs_estimated_channel_freq[ant_rx_ind][p_ind], srs_estimated_channel_freq[ant_rx_ind][p_ind],
srs_estimated_channel_time[ant_rx_ind][p_ind], srs_estimated_channel_time[ant_rx_ind][p_ind],
srs_estimated_channel_time_shifted[ant_rx_ind][p_ind], srs_estimated_channel_time_shifted[ant_rx_ind][p_ind],
&signal_power, &signal_power,
&noise_power, frame_parms->delay_table);
noise_power_per_rb);
signal_power_avg += signal_power; signal_power_avg += signal_power;
...@@ -913,7 +930,7 @@ void nr_srs_rx_procedures(PHY_VARS_gNB *gNB, ...@@ -913,7 +930,7 @@ void nr_srs_rx_procedures(PHY_VARS_gNB *gNB,
T_INT(gNB->Mod_id), T_INT(gNB->Mod_id),
T_INT(srs_pdu->rnti), T_INT(srs_pdu->rnti),
T_INT(frame_rx), T_INT(frame_rx),
T_INT(slot_rx), T_INT(0),
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], N_symb_SRS * 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)));
...@@ -922,17 +939,35 @@ void nr_srs_rx_procedures(PHY_VARS_gNB *gNB, ...@@ -922,17 +939,35 @@ void nr_srs_rx_procedures(PHY_VARS_gNB *gNB,
T_INT(gNB->Mod_id), T_INT(gNB->Mod_id),
T_INT(srs_pdu->rnti), T_INT(srs_pdu->rnti),
T_INT(frame_rx), T_INT(frame_rx),
T_INT(slot_rx), T_INT(0),
T_INT(ant_rx_ind), T_INT(ant_rx_ind),
T_INT(p_ind), T_INT(p_ind),
T_BUFFER(srs_estimated_channel_time_shifted[ant_rx_ind][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))); NR_SRS_IDFT_OVERSAMP_FACTOR * ofdm_symbol_size * sizeof(c16_t)));
} }
noise_power_avg += noise_power;
} }
signal_power_avg /= (nb_antennas_rx * N_ap); signal_power_avg /= (nb_antennas_rx * N_ap);
noise_power_avg /= nb_antennas_rx;
signal_power_avg = max(signal_power_avg, 1); 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)); 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); const uint16_t m_SRS_b = get_m_srs(srs_pdu->config_index, srs_pdu->bandwidth_index);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment