Implementation of delay estimation in NFAPI_NR_DMRS_TYPE1_linear_interp() at UE
This commit is contained in:
@@ -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))
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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; aarx<gNB->frame_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++) {
|
||||
|
||||
@@ -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]);
|
||||
|
||||
@@ -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,
|
||||
|
||||
+1
-10
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user