diff --git a/common/utils/nr/nr_common.h b/common/utils/nr/nr_common.h index 396c908e22..e7cc5875b2 100644 --- a/common/utils/nr/nr_common.h +++ b/common/utils/nr/nr_common.h @@ -72,6 +72,15 @@ typedef enum frequency_range_e { FR2 } frequency_range_t; +typedef struct { + /// Time shift in number of samples estimated based on DMRS-PDSCH/PUSCH + int est_delay; + /// Max position in OFDM symbol related to time shift estimation based on DMRS-PDSCH/PUSCH + int delay_max_pos; + /// Max value related to time shift estimation based on DMRS-PDSCH/PUSCH + int delay_max_val; +} delay_t; + extern const nr_bandentry_t nr_bandtable[]; static inline int get_num_dmrs(uint16_t dmrs_mask ) { @@ -114,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); + #define CEILIDIV(a,b) ((a+b-1)/b) #define ROUNDIDIV(a,b) (((a<<1)+b)/(b<<1)) diff --git a/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c b/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c index a26a1d0574..31eca819ee 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c +++ b/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c @@ -38,10 +38,10 @@ extern openair0_config_t openair0_cfg[MAX_CARDS]; -void nr_est_timing_advance_pusch(const NR_DL_FRAME_PARMS *frame_parms, const int32_t *ul_ch_estimates_time, NR_ULSCH_delay_t *delay) +void nr_est_timing_advance_pusch(const NR_DL_FRAME_PARMS *frame_parms, const int32_t *ul_ch_estimates_time, delay_t *delay) { - int max_pos = delay->pusch_delay_max_pos; - int max_val = delay->pusch_delay_max_val; + int max_pos = delay->delay_max_pos; + int max_val = delay->delay_max_val; const int sync_pos = 0; for (int i = 0; i < frame_parms->ofdm_symbol_size; i++) { @@ -56,9 +56,9 @@ void nr_est_timing_advance_pusch(const NR_DL_FRAME_PARMS *frame_parms, const int if (max_pos > frame_parms->ofdm_symbol_size / 2) max_pos = max_pos - frame_parms->ofdm_symbol_size; - delay->pusch_delay_max_pos = max_pos; - delay->pusch_delay_max_val = max_val; - delay->pusch_est_delay = max_pos - sync_pos; + delay->delay_max_pos = max_pos; + delay->delay_max_val = max_val; + delay->est_delay = max_pos - sync_pos; } int nr_est_timing_advance_srs(const NR_DL_FRAME_PARMS *frame_parms, diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c index 1eb864f010..32a0962232 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c +++ b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c @@ -42,9 +42,10 @@ #define NO_INTERP 1 #define dBc(x,y) (dB_fixed(((int32_t)(x))*(x) + ((int32_t)(y))*(y))) -void freq2time(uint16_t ofdm_symbol_size, - int16_t *freq_signal, - int16_t *time_signal) { +static void freq2time(uint16_t ofdm_symbol_size, + int16_t *freq_signal, + int16_t *time_signal) +{ switch (ofdm_symbol_size) { case 128: @@ -194,7 +195,7 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, uint64_t noise_amp2 = 0; c16_t ul_ls_est[symbolSize] __attribute__((aligned(32))); memset(ul_ls_est, 0, sizeof(c16_t) * symbolSize); - NR_ULSCH_delay_t *delay = &gNB->ulsch[ul_id].delay; + delay_t *delay = &gNB->ulsch[ul_id].delay; memset(delay, 0, sizeof(*delay)); for (int aarx=0; aarxframe_parms.nb_antennas_rx; aarx++) { @@ -239,7 +240,7 @@ 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->pusch_est_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]; @@ -325,7 +326,7 @@ 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->pusch_est_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]; for (int n = 0; n < nb_rb_pusch * NR_NB_SC_PER_RB; n++) { diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h b/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h index 9dc6edf8d2..f50e0f1bd7 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h +++ b/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h @@ -61,8 +61,7 @@ void nr_gnb_measurements(PHY_VARS_gNB *gNB, uint8_t nrOfLayers); void nr_est_timing_advance_pusch(const NR_DL_FRAME_PARMS *frame_parms, - const int32_t *ul_ch_estimates_time, - NR_ULSCH_delay_t *delay); + const int32_t *ul_ch_estimates_time, delay_t *delay); int nr_est_timing_advance_srs(const NR_DL_FRAME_PARMS *frame_parms, const int32_t srs_estimated_channel_time[][frame_parms->ofdm_symbol_size]); 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 0de7dbaa9c..2de6e17115 100644 --- a/openair1/PHY/NR_UE_ESTIMATION/nr_dl_channel_estimation.c +++ b/openair1/PHY/NR_UE_ESTIMATION/nr_dl_channel_estimation.c @@ -1303,112 +1303,127 @@ void nr_pdcch_channel_estimation(PHY_VARS_NR_UE *ue, } } +static void freq2time(uint16_t ofdm_symbol_size, + int16_t *freq_signal, + int16_t *time_signal) +{ + + switch (ofdm_symbol_size) { + case 128: + idft(IDFT_128, freq_signal, time_signal, 1); + break; + case 256: + idft(IDFT_256, freq_signal, time_signal, 1); + break; + case 512: + idft(IDFT_512, freq_signal, time_signal, 1); + break; + case 1024: + idft(IDFT_1024, freq_signal, time_signal, 1); + break; + case 1536: + idft(IDFT_1536, freq_signal, time_signal, 1); + break; + case 2048: + idft(IDFT_2048, freq_signal, time_signal, 1); + break; + case 4096: + idft(IDFT_4096, freq_signal, time_signal, 1); + break; + case 6144: + idft(IDFT_6144, freq_signal, time_signal, 1); + break; + case 8192: + idft(IDFT_8192, freq_signal, time_signal, 1); + break; + default: + AssertFatal (1 == 0, "Invalid ofdm_symbol_size %i\n", ofdm_symbol_size); + break; + } +} + +void nr_est_delay_pdsch(const NR_DL_FRAME_PARMS *frame_parms, const c16_t *dl_ls_est, delay_t *delay) +{ + c16_t dl_ch_estimates_time[frame_parms->ofdm_symbol_size] __attribute__((aligned(32))); + memset(dl_ch_estimates_time, 0, sizeof(dl_ch_estimates_time)); + freq2time(frame_parms->ofdm_symbol_size, (int16_t *)dl_ls_est, (int16_t *)dl_ch_estimates_time); + + int max_pos = delay->delay_max_pos; + int max_val = delay->delay_max_val; + const int sync_pos = 0; + + for (int i = 0; i < frame_parms->ofdm_symbol_size; i++) { + int temp = c16amp2(dl_ch_estimates_time[i]) >> 1; + if (temp > max_val) { + max_pos = i; + max_val = temp; + } + } + + if (max_pos > frame_parms->ofdm_symbol_size / 2) + max_pos = max_pos - frame_parms->ofdm_symbol_size; + + delay->delay_max_pos = max_pos; + delay->delay_max_val = max_val; + delay->est_delay = max_pos - sync_pos; +} + void NFAPI_NR_DMRS_TYPE1_linear_interp(NR_DL_FRAME_PARMS *frame_parms, c16_t *rxF, c16_t *pil, c16_t *dl_ch, unsigned short bwp_start_subcarrier, unsigned short nb_rb_pdsch, - int8_t delta) + int8_t delta, + delay_t *delay) { int re_offset = bwp_start_subcarrier % frame_parms->ofdm_symbol_size; - c16_t *pil0 = pil; - c16_t *dl_ch0 = dl_ch; - c16_t ch = {0}; - const int16_t *fdcl = NULL; - const int16_t *fdcr = NULL; - const int16_t *fdclh = NULL; - const int16_t *fdcrh = NULL; - switch (delta) { - case 0: // port 0,1 - fdcl = filt8_dcl0; // left DC interpolation Filter (even RB) - fdcr = filt8_dcr0; // right DC interpolation Filter (even RB) - fdclh = filt8_dcl0_h; // left DC interpolation Filter (odd RB) - fdcrh = filt8_dcr0_h; // right DC interpolation Filter (odd RB) - break; - - case 1: // port2,3 - fdcl = filt8_dcl1; - fdcr = filt8_dcr1; - fdclh = filt8_dcl1_h; - fdcrh = filt8_dcr1_h; - break; - - default: - AssertFatal(1 == 0, "pdsch_channel_estimation: Invalid delta %i\n", delta); - break; - } + c16_t dl_ls_est[frame_parms->ofdm_symbol_size] __attribute__((aligned(32))); + memset(dl_ls_est, 0, sizeof(dl_ls_est)); for (int pilot_cnt = 0; pilot_cnt < 6 * nb_rb_pdsch; pilot_cnt++) { if (pilot_cnt % 2 == 0) { - ch = c16mulShift(*pil, rxF[re_offset], 15); + c16_t ch = c16mulShift(*pil, rxF[re_offset], 15); pil++; re_offset = (re_offset + 2) % frame_parms->ofdm_symbol_size; ch = c16maddShift(*pil, rxF[re_offset], ch, 15); ch = c16Shift(ch, 1); pil++; re_offset = (re_offset + 2) % frame_parms->ofdm_symbol_size; + for (int k = pilot_cnt << 1; k < (pilot_cnt << 1) + 4; k++) { + dl_ls_est[k] = ch; + } } #ifdef DEBUG_PDSCH - printf("pilot %3d: pil -> (%6d,%6d), rxF -> (%4d,%4d), ch -> (%4d,%4d) \n", pilot_cnt, pil->r, pil->i, rxF[re_offset].r, rxF[re_offset].i, ch.r, ch.i); + printf("pilot %3d: pil -> (%6d,%6d), rxF -> (%4d,%4d), ch -> (%4d,%4d) \n", + pilot_cnt, + pil->r, + pil->i, + rxF[re_offset].r, + rxF[re_offset].i, + dl_ls_est[pilot_cnt << 1].r, + dl_ls_est[pilot_cnt << 1].i); #endif + } + nr_est_delay_pdsch(frame_parms, dl_ls_est, delay); + + for (int pilot_cnt = 0; pilot_cnt < 6 * nb_rb_pdsch; pilot_cnt++) { if (pilot_cnt == 0) { // Treat first pilot - c16multaddVectRealComplex(filt16_ul_p0, &ch, dl_ch, 16); + c16multaddVectRealComplex(filt16_ul_p0, &dl_ls_est[pilot_cnt << 1], dl_ch, 16); } else if (pilot_cnt == 1 || pilot_cnt == 2) { - c16multaddVectRealComplex(filt16_ul_p1p2, &ch, dl_ch, 16); + c16multaddVectRealComplex(filt16_ul_p1p2, &dl_ls_est[pilot_cnt << 1], dl_ch, 16); } else if (pilot_cnt == 6 * nb_rb_pdsch - 1) { // Treat last pilot - c16multaddVectRealComplex(filt16_ul_last, &ch, dl_ch, 16); + c16multaddVectRealComplex(filt16_ul_last, &dl_ls_est[pilot_cnt << 1], dl_ch, 16); } else { // Treat middle pilots - c16multaddVectRealComplex(filt16_ul_middle, &ch, dl_ch, 16); + c16multaddVectRealComplex(filt16_ul_middle, &dl_ls_est[pilot_cnt << 1], dl_ch, 16); if (pilot_cnt % 2 == 0) { dl_ch += 4; } } } - - // check if PRB crosses DC and improve estimates around DC - if ((bwp_start_subcarrier < frame_parms->ofdm_symbol_size) && (bwp_start_subcarrier + nb_rb_pdsch * 12 >= frame_parms->ofdm_symbol_size)) { - dl_ch = dl_ch0; - uint16_t idxDC = 2 * (frame_parms->ofdm_symbol_size - bwp_start_subcarrier); - uint16_t idxPil = idxDC / 4; - re_offset = bwp_start_subcarrier % frame_parms->ofdm_symbol_size; - pil = pil0; - pil += (idxPil - 1); - dl_ch += (idxDC / 2 - 2); - dl_ch = memset(dl_ch, 0, sizeof(c16_t) * 5); - re_offset = (re_offset + idxDC / 2 - 2) % frame_parms->ofdm_symbol_size; - ch = c16mulShift(*pil, rxF[re_offset], 15); - pil++; - re_offset = (re_offset + 2) % frame_parms->ofdm_symbol_size; - ch = c16maddShift(*pil, rxF[re_offset], ch, 15); - ch = c16Shift(ch, 1); - - // for proper allignment of SIMD vectors - if ((frame_parms->N_RB_DL & 1) == 0) { - c16multaddVectRealComplex(fdcl, &ch, dl_ch - 2, 8); - pil++; - re_offset = (re_offset + 2) % frame_parms->ofdm_symbol_size; - ch = c16mulShift(*pil, rxF[re_offset], 15); - pil++; - re_offset = (re_offset + 2) % frame_parms->ofdm_symbol_size; - ch = c16maddShift(*pil, rxF[re_offset], ch, 15); - ch = c16Shift(ch, 1); - c16multaddVectRealComplex(fdcr, &ch, dl_ch - 2, 8); - } else { - c16multaddVectRealComplex(fdclh, &ch, dl_ch, 8); - pil++; - re_offset = (re_offset + 2) % frame_parms->ofdm_symbol_size; - ch = c16mulShift(*pil, rxF[re_offset], 15); - pil++; - re_offset = (re_offset + 2) % frame_parms->ofdm_symbol_size; - ch = c16maddShift(*pil, rxF[re_offset], ch, 15); - ch = c16Shift(ch, 1); - c16multaddVectRealComplex(fdcrh, &ch, dl_ch, 8); - } - } } void NFAPI_NR_DMRS_TYPE1_average_prb(NR_DL_FRAME_PARMS *frame_parms, @@ -1503,7 +1518,8 @@ void NFAPI_NR_DMRS_TYPE2_linear_interp(NR_DL_FRAME_PARMS *frame_parms, unsigned short bwp_start_subcarrier, unsigned short nb_rb_pdsch, int8_t delta, - unsigned short p) + unsigned short p, + delay_t *delay) { int re_offset = bwp_start_subcarrier % frame_parms->ofdm_symbol_size; c16_t *dl_ch0 = dl_ch; @@ -1715,6 +1731,8 @@ int nr_pdsch_channel_estimation(PHY_VARS_NR_UE *ue, ue->frame_parms.nushift = nushift; } + delay_t delay = {0}; + for (int aarx = 0; aarx < ue->frame_parms.nb_antennas_rx; aarx++) { #ifdef DEBUG_PDSCH @@ -1734,7 +1752,8 @@ int nr_pdsch_channel_estimation(PHY_VARS_NR_UE *ue, dl_ch, bwp_start_subcarrier, nb_rb_pdsch, - delta); + delta, + &delay); } else if (config_type == NFAPI_NR_DMRS_TYPE2 && ue->chest_freq == 0) { NFAPI_NR_DMRS_TYPE2_linear_interp(&ue->frame_parms, diff --git a/openair1/PHY/defs_gNB.h b/openair1/PHY/defs_gNB.h index 20322a2d73..c2e6dfba75 100644 --- a/openair1/PHY/defs_gNB.h +++ b/openair1/PHY/defs_gNB.h @@ -255,15 +255,6 @@ typedef struct { int subband_cqi_tot_dB[275]; } ulsch_measurements_gNB; -typedef struct { - /// Time shift in number of samples estimated based on DMRS-PUSCH - int pusch_est_delay; - /// Max position in OFDM symbol related to time shift estimation based on DMRS-PUSCH - int pusch_delay_max_pos; - /// Max value related to time shift estimation based on DMRS-PUSCH - int pusch_delay_max_val; -} NR_ULSCH_delay_t; - typedef struct { uint32_t frame; uint32_t slot; @@ -281,7 +272,7 @@ typedef struct { bool active; /// Flag to indicate that the UL configuration has been handled. Used to remove a stale ULSCH when frame wraps around uint8_t handled; - NR_ULSCH_delay_t delay; + delay_t delay; ulsch_measurements_gNB ulsch_measurements; } NR_gNB_ULSCH_t; diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index 5ce9b7e39b..8aa86624b3 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -422,7 +422,7 @@ void nr_fill_indication(PHY_VARS_gNB *gNB, int frame, int slot_rx, int ULSCH_id, nfapi_nr_pusch_pdu_t *pusch_pdu = &harq_process->ulsch_pdu; // Get estimated timing advance for MAC - int sync_pos = ulsch->delay.pusch_est_delay; + int sync_pos = ulsch->delay.est_delay; // scale the 16 factor in N_TA calculation in 38.213 section 4.2 according to the used FFT size uint16_t bw_scaling = 16 * gNB->frame_parms.ofdm_symbol_size / 2048; diff --git a/openair1/SIMULATION/NR_PHY/ulsim.c b/openair1/SIMULATION/NR_PHY/ulsim.c index 4915b1cffa..2d1d32efbf 100644 --- a/openair1/SIMULATION/NR_PHY/ulsim.c +++ b/openair1/SIMULATION/NR_PHY/ulsim.c @@ -1540,9 +1540,9 @@ int main(int argc, char **argv) if (!crc_status) effRate += ((double)TBS) / (double)round; - sum_pusch_delay += ulsch_gNB->delay.pusch_est_delay; - min_pusch_delay = ulsch_gNB->delay.pusch_est_delay < min_pusch_delay ? ulsch_gNB->delay.pusch_est_delay : min_pusch_delay; - max_pusch_delay = ulsch_gNB->delay.pusch_est_delay > max_pusch_delay ? ulsch_gNB->delay.pusch_est_delay : max_pusch_delay; + sum_pusch_delay += ulsch_gNB->delay.est_delay; + min_pusch_delay = min(ulsch_gNB->delay.est_delay, min_pusch_delay); + max_pusch_delay = max(ulsch_gNB->delay.est_delay, max_pusch_delay); delay_pusch_est_count++; } // trial loop