diff --git a/common/utils/nr/nr_common.c b/common/utils/nr/nr_common.c index c1bd80f074..ffa7079071 100644 --- a/common/utils/nr/nr_common.c +++ b/common/utils/nr/nr_common.c @@ -33,6 +33,7 @@ #include #include "assertions.h" #include "nr_common.h" +#include const char *duplex_mode[]={"FDD","TDD"}; @@ -738,3 +739,27 @@ uint32_t get_ssb_offset_to_pointA(uint32_t absoluteFrequencySSB, AssertFatal(sco % scs_scaling == 0, "ssb offset %d can create frequency offset\n", sco); return ssb_offset_point_a; } + +int get_delay_idx(int delay, int max_delay_comp) +{ + int delay_idx = max_delay_comp + delay; + // If the measured delay is less than -MAX_DELAY_COMP, a -MAX_DELAY_COMP delay is compensated. + delay_idx = max(delay_idx, 0); + // If the measured delay is greater than +MAX_DELAY_COMP, a +MAX_DELAY_COMP delay is compensated. + delay_idx = min(delay_idx, max_delay_comp << 1); + return delay_idx; +} + +void init_delay_table(uint16_t ofdm_symbol_size, + int max_delay_comp, + int max_ofdm_symbol_size, + c16_t delay_table[][max_ofdm_symbol_size]) +{ + for (int delay = -max_delay_comp; delay <= max_delay_comp; delay++) { + for (int k = 0; k < ofdm_symbol_size; k++) { + double complex delay_cexp = cexp(I * (2.0 * M_PI * k * delay / ofdm_symbol_size)); + delay_table[max_delay_comp + delay][k].r = (int16_t)round(256 * creal(delay_cexp)); + delay_table[max_delay_comp + delay][k].i = (int16_t)round(256 * cimag(delay_cexp)); + } + } +} diff --git a/common/utils/nr/nr_common.h b/common/utils/nr/nr_common.h index e7cc5875b2..95859caa06 100644 --- a/common/utils/nr/nr_common.h +++ b/common/utils/nr/nr_common.h @@ -123,6 +123,7 @@ uint32_t get_ssb_offset_to_pointA(uint32_t absoluteFrequencySSB, int ssbSubcarrierSpacing, int frequency_range); int get_ssb_subcarrier_offset(uint32_t absoluteFrequencySSB, uint32_t absoluteFrequencyPointA); +int get_delay_idx(int delay, int max_delay_comp); #define CEILIDIV(a,b) ((a+b-1)/b) #define ROUNDIDIV(a,b) (((a<<1)+b)/(b<<1)) diff --git a/openair1/PHY/INIT/nr_init.c b/openair1/PHY/INIT/nr_init.c index 1c406eae98..ed3fd55079 100644 --- a/openair1/PHY/INIT/nr_init.c +++ b/openair1/PHY/INIT/nr_init.c @@ -66,17 +66,6 @@ int l1_north_init_gNB() { return(0); } -void init_ul_delay_table(NR_DL_FRAME_PARMS *fp) -{ - for (int delay = -MAX_UL_DELAY_COMP; delay <= MAX_UL_DELAY_COMP; delay++) { - for (int k = 0; k < fp->ofdm_symbol_size; k++) { - double complex delay_cexp = cexp(I * (2.0 * M_PI * k * delay / fp->ofdm_symbol_size)); - fp->ul_delay_table[MAX_UL_DELAY_COMP + delay][k].r = (int16_t)round(256 * creal(delay_cexp)); - fp->ul_delay_table[MAX_UL_DELAY_COMP + delay][k].i = (int16_t)round(256 * cimag(delay_cexp)); - } - } -} - NR_gNB_PHY_STATS_t *get_phy_stats(PHY_VARS_gNB *gNB, uint16_t rnti) { NR_gNB_PHY_STATS_t *stats; @@ -544,7 +533,7 @@ int phy_init_nr_gNB(PHY_VARS_gNB *gNB) gNB->max_nb_pdsch = MAX_MOBILES_PER_GNB; init_codebook_gNB(gNB); - init_ul_delay_table(fp); + init_delay_table(fp->ofdm_symbol_size, MAX_DELAY_COMP, NR_MAX_OFDM_SYMBOL_SIZE, fp->delay_table); // PBCH DMRS gold sequences generation nr_init_pbch_dmrs(gNB); diff --git a/openair1/PHY/INIT/nr_init_ue.c b/openair1/PHY/INIT/nr_init_ue.c index c1477aa7c1..32220ca38b 100644 --- a/openair1/PHY/INIT/nr_init_ue.c +++ b/openair1/PHY/INIT/nr_init_ue.c @@ -674,6 +674,7 @@ void init_N_TA_offset(PHY_VARS_NR_UE *ue){ void phy_init_nr_top(PHY_VARS_NR_UE *ue) { NR_DL_FRAME_PARMS *frame_parms = &ue->frame_parms; + init_delay_table(frame_parms->ofdm_symbol_size, MAX_DELAY_COMP, NR_MAX_OFDM_SYMBOL_SIZE, frame_parms->delay_table); crcTableInit(); init_scrambling_luts(); load_dftslib(); diff --git a/openair1/PHY/INIT/nr_phy_init.h b/openair1/PHY/INIT/nr_phy_init.h index d025a3555f..0d5170b05e 100644 --- a/openair1/PHY/INIT/nr_phy_init.h +++ b/openair1/PHY/INIT/nr_phy_init.h @@ -56,5 +56,9 @@ void free_nr_ue_ul_harq(NR_UL_UE_HARQ_t harq_list[NR_MAX_ULSCH_HARQ_PROCESSES], void phy_init_nr_top(PHY_VARS_NR_UE *ue); void phy_term_nr_top(void); +void init_delay_table(uint16_t ofdm_symbol_size, + int max_delay_comp, + int max_ofdm_symbol_size, + c16_t delay_table[][max_ofdm_symbol_size]); #endif diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c index 32a0962232..48e2a97b20 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c +++ b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c @@ -104,19 +104,6 @@ __attribute__((always_inline)) inline c16_t c32x16cumulVectVectWithSteps(c16_t * return c16x32div(cumul, N); } -int get_delay_idx(int delay) { - int delay_idx = MAX_UL_DELAY_COMP + delay; - // If the measured delay is less than -MAX_UL_DELAY_COMP, a -MAX_UL_DELAY_COMP delay is compensated. - if (delay_idx < 0) { - delay_idx = 0; - } - // If the measured delay is greater than +MAX_UL_DELAY_COMP, a +MAX_UL_DELAY_COMP delay is compensated. - if (delay_idx > MAX_UL_DELAY_COMP<<1) { - delay_idx = MAX_UL_DELAY_COMP<<1; - } - return delay_idx; -} - int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, unsigned char Ns, unsigned short p, @@ -240,12 +227,11 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, freq2time(symbolSize, (int16_t *)ul_ls_est, (int16_t *)pusch_vars->ul_ch_estimates_time[aarx]); nr_est_timing_advance_pusch(&gNB->frame_parms, pusch_vars->ul_ch_estimates_time[aarx], delay); - int pusch_delay = delay->est_delay; - int delay_idx = get_delay_idx(pusch_delay); - c16_t *ul_delay_table = gNB->frame_parms.ul_delay_table[delay_idx]; + int delay_idx = get_delay_idx(delay->est_delay, MAX_DELAY_COMP); + c16_t *ul_delay_table = gNB->frame_parms.delay_table[delay_idx]; #ifdef DEBUG_PUSCH - printf("Estimated delay = %i\n", pusch_delay >> 1); + printf("Estimated delay = %i\n", delay->est_delay >> 1); #endif pilot_cnt = 0; @@ -285,8 +271,8 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, // Revert delay pilot_cnt = 0; ul_ch = &ul_ch_estimates[p * gNB->frame_parms.nb_antennas_rx + aarx][ch_offset]; - int inv_delay_idx = get_delay_idx(-pusch_delay); - c16_t *ul_inv_delay_table = gNB->frame_parms.ul_delay_table[inv_delay_idx]; + int inv_delay_idx = get_delay_idx(-delay->est_delay, MAX_DELAY_COMP); + c16_t *ul_inv_delay_table = gNB->frame_parms.delay_table[inv_delay_idx]; for (int n = 0; n < 3 * nb_rb_pusch; n++) { for (int k_line = 0; k_line <= 1; k_line++) { int k = pilot_cnt << 1; @@ -326,9 +312,8 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, // Delay compensation freq2time(symbolSize, (int16_t *)ul_ls_est, (int16_t *)pusch_vars->ul_ch_estimates_time[aarx]); nr_est_timing_advance_pusch(&gNB->frame_parms, pusch_vars->ul_ch_estimates_time[aarx], delay); - int pusch_delay = delay->est_delay; - int delay_idx = get_delay_idx(-pusch_delay); - c16_t *ul_delay_table = gNB->frame_parms.ul_delay_table[delay_idx]; + int delay_idx = get_delay_idx(-delay->est_delay, MAX_DELAY_COMP); + c16_t *ul_delay_table = gNB->frame_parms.delay_table[delay_idx]; for (int n = 0; n < nb_rb_pusch * NR_NB_SC_PER_RB; n++) { ul_ch[n] = c16mulShift(ul_ls_est[n], ul_delay_table[n % 6], 8); } diff --git a/openair1/PHY/NR_UE_ESTIMATION/nr_dl_channel_estimation.c b/openair1/PHY/NR_UE_ESTIMATION/nr_dl_channel_estimation.c index 2de6e17115..41c494b593 100644 --- a/openair1/PHY/NR_UE_ESTIMATION/nr_dl_channel_estimation.c +++ b/openair1/PHY/NR_UE_ESTIMATION/nr_dl_channel_estimation.c @@ -1377,6 +1377,7 @@ void NFAPI_NR_DMRS_TYPE1_linear_interp(NR_DL_FRAME_PARMS *frame_parms, int8_t delta, delay_t *delay) { + c16_t *dl_ch0 = dl_ch; int re_offset = bwp_start_subcarrier % frame_parms->ofdm_symbol_size; c16_t dl_ls_est[frame_parms->ofdm_symbol_size] __attribute__((aligned(32))); @@ -1409,21 +1410,33 @@ void NFAPI_NR_DMRS_TYPE1_linear_interp(NR_DL_FRAME_PARMS *frame_parms, } nr_est_delay_pdsch(frame_parms, dl_ls_est, delay); + int delay_idx = get_delay_idx(delay->est_delay, MAX_DELAY_COMP); + c16_t *dl_delay_table = frame_parms->delay_table[delay_idx]; for (int pilot_cnt = 0; pilot_cnt < 6 * nb_rb_pdsch; pilot_cnt++) { + int k = pilot_cnt << 1; + c16_t ch = c16mulShift(dl_ls_est[k], dl_delay_table[k], 8); if (pilot_cnt == 0) { // Treat first pilot - c16multaddVectRealComplex(filt16_ul_p0, &dl_ls_est[pilot_cnt << 1], dl_ch, 16); + c16multaddVectRealComplex(filt16_ul_p0, &ch, dl_ch, 16); } else if (pilot_cnt == 1 || pilot_cnt == 2) { - c16multaddVectRealComplex(filt16_ul_p1p2, &dl_ls_est[pilot_cnt << 1], dl_ch, 16); + c16multaddVectRealComplex(filt16_ul_p1p2, &ch, dl_ch, 16); } else if (pilot_cnt == 6 * nb_rb_pdsch - 1) { // Treat last pilot - c16multaddVectRealComplex(filt16_ul_last, &dl_ls_est[pilot_cnt << 1], dl_ch, 16); + c16multaddVectRealComplex(filt16_ul_last, &ch, dl_ch, 16); } else { // Treat middle pilots - c16multaddVectRealComplex(filt16_ul_middle, &dl_ls_est[pilot_cnt << 1], dl_ch, 16); + c16multaddVectRealComplex(filt16_ul_middle, &ch, dl_ch, 16); if (pilot_cnt % 2 == 0) { dl_ch += 4; } } } + + // Revert delay + dl_ch = dl_ch0; + int inv_delay_idx = get_delay_idx(-delay->est_delay, MAX_DELAY_COMP); + c16_t *dl_inv_delay_table = frame_parms->delay_table[inv_delay_idx]; + for (int k = 0; k < 12 * nb_rb_pdsch; k++) { + dl_ch[k] = c16mulShift(dl_ch[k], dl_inv_delay_table[k], 8); + } } void NFAPI_NR_DMRS_TYPE1_average_prb(NR_DL_FRAME_PARMS *frame_parms, diff --git a/openair1/PHY/defs_nr_common.h b/openair1/PHY/defs_nr_common.h index 0741291fb4..2acca1ca0c 100644 --- a/openair1/PHY/defs_nr_common.h +++ b/openair1/PHY/defs_nr_common.h @@ -95,7 +95,7 @@ #define NR_NB_NSCID 2 -#define MAX_UL_DELAY_COMP 20 +#define MAX_DELAY_COMP 20 typedef enum { NR_MU_0=0, @@ -227,8 +227,8 @@ struct NR_DL_FRAME_PARMS { /// sequence used to compensate the phase rotation due to timeshifted OFDM symbols /// First dimenstion is for different CP lengths c16_t timeshift_symbol_rotation[4096*2] __attribute__ ((aligned (16))); - /// Table used to apply the delay compensation in UL - c16_t ul_delay_table[2 * MAX_UL_DELAY_COMP + 1][NR_MAX_OFDM_SYMBOL_SIZE * 2]; + /// Table used to apply the delay compensation in DL/UL + c16_t delay_table[2 * MAX_DELAY_COMP + 1][NR_MAX_OFDM_SYMBOL_SIZE]; /// shift of pilot position in one RB uint8_t nushift; /// SRS configuration from TS 38.331 RRC