Delay compensation for PUCCH2
This commit is contained in:
@@ -138,6 +138,7 @@ void phy_init_nr_gNB(PHY_VARS_gNB *gNB)
|
||||
|
||||
gNB->max_nb_pdsch = MAX_MOBILES_PER_GNB;
|
||||
init_delay_table(fp->ofdm_symbol_size, MAX_DELAY_COMP, NR_MAX_OFDM_SYMBOL_SIZE, fp->delay_table);
|
||||
init_delay_table(128, MAX_DELAY_COMP, 128, fp->delay_table128);
|
||||
|
||||
gNB->bad_pucch = 0;
|
||||
if (gNB->TX_AMP == 0)
|
||||
|
||||
@@ -53,6 +53,7 @@
|
||||
#include "SCHED_NR/sched_nr.h"
|
||||
|
||||
#include "T.h"
|
||||
#include "nr_phy_common.h"
|
||||
|
||||
//#define DEBUG_NR_PUCCH_RX 1
|
||||
|
||||
@@ -1086,15 +1087,7 @@ void nr_decode_pucch2(PHY_VARS_gNB *gNB,
|
||||
|
||||
pucch2_lev /= Prx * pucch_pdu->nr_of_symbols;
|
||||
int pucch2_levdB = dB_fixed(pucch2_lev);
|
||||
int scaling = 0;
|
||||
if (pucch2_levdB > 72)
|
||||
scaling = 4;
|
||||
else if (pucch2_levdB > 66)
|
||||
scaling = 3;
|
||||
else if (pucch2_levdB > 60)
|
||||
scaling = 2;
|
||||
else if (pucch2_levdB > 54)
|
||||
scaling = 1;
|
||||
int scaling = max((log2_approx64(pucch2_lev) >> 1) - 8, 0);
|
||||
|
||||
LOG_D(NR_PHY,
|
||||
"%d.%d Decoding pucch2 for %d symbols, %d PRB, nb_harq %d, nb_sr %d, nb_csi %d/%d, pucch2_lev %d dB (scaling %d)\n",
|
||||
@@ -1180,6 +1173,140 @@ void nr_decode_pucch2(PHY_VARS_gNB *gNB,
|
||||
slot,pucch_pdu->start_symbol_index,symb,pucch_pdu->dmrs_scrambling_id);
|
||||
#endif
|
||||
uint32_t *sGold = gold_cache(x2, pucch_pdu->prb_start / 4 + ngroup / 2);
|
||||
|
||||
// Compute pilot conjugate
|
||||
int16_t pil_re16[4 * pucch_pdu->prb_size] __attribute__((aligned(32)));
|
||||
int16_t pil_im16[4 * pucch_pdu->prb_size] __attribute__((aligned(32)));
|
||||
simde__m128i m1 = simde_mm_set_epi16(-1, -1, -1, -1, -1, -1, -1, -1);
|
||||
for (int group = 0, goldIdx = pucch_pdu->prb_start / 4; group < ngroup; group++) {
|
||||
uint8_t *sGold8 = (uint8_t *)&sGold[goldIdx];
|
||||
((simde__m64 *)&pil_re16[8 * group])[0] = byte2m64_re[sGold8[(group & 1) << 1]];
|
||||
((simde__m64 *)&pil_re16[8 * group])[1] = byte2m64_re[sGold8[1 + ((group & 1) << 1)]];
|
||||
simde__m128i dmrs_im;
|
||||
((simde__m64 *)&dmrs_im)[0] = byte2m64_im[sGold8[(group & 1) << 1]];
|
||||
((simde__m64 *)&dmrs_im)[1] = byte2m64_im[sGold8[1 + ((group & 1) << 1)]];
|
||||
*((simde__m128i *)&pil_im16[8 * group]) = simde_mm_mullo_epi16(dmrs_im, m1);
|
||||
if ((group & 1) == 1)
|
||||
goldIdx++;
|
||||
}
|
||||
|
||||
// Compute delay
|
||||
c16_t ch_ls[128] __attribute__((aligned(32))) = {0};
|
||||
int prb_size_loop = (pucch_pdu->prb_size >> 1) << 1;
|
||||
for (int aa = 0; aa < Prx; aa++) {
|
||||
int prb = 0;
|
||||
for (; prb < prb_size_loop; prb += 2) {
|
||||
simde__m128i res_re, res_im;
|
||||
complex_mult_simd(*(simde__m128i *)&pil_re16[4 * prb],
|
||||
*(simde__m128i *)&pil_im16[4 * prb],
|
||||
*(simde__m128i *)&rd_re_ext[aa][symb][4 * prb],
|
||||
*(simde__m128i *)&rd_im_ext[aa][symb][4 * prb],
|
||||
&res_re,
|
||||
&res_im,
|
||||
0,
|
||||
0,
|
||||
0);
|
||||
int16_t *re = (int16_t *)&res_re;
|
||||
int16_t *im = (int16_t *)&res_im;
|
||||
for (int idx = 0; idx < 8; idx++) {
|
||||
for (int k = 0; k < 3 && 12 * prb + 3 * idx + k < 128; k++) {
|
||||
ch_ls[12 * prb + 3 * idx + k] = (c16_t){re[idx], im[idx]};
|
||||
}
|
||||
}
|
||||
}
|
||||
for (; prb < pucch_pdu->prb_size; prb++) {
|
||||
int16_t *rd_re_ext_p = &rd_re_ext[aa][symb][4 * prb];
|
||||
int16_t *rd_im_ext_p = &rd_im_ext[aa][symb][4 * prb];
|
||||
for (int idx = 0; idx < 4; idx++) {
|
||||
c16_t ch = c16mulShift((c16_t){pil_re16[idx + 4 * prb], pil_im16[idx + 4 * prb]},
|
||||
(c16_t){rd_re_ext_p[idx], rd_im_ext_p[idx]},
|
||||
0);
|
||||
for (int k = 0; k < 3 && 12 * prb + 3 * idx + k < 128; k++) {
|
||||
ch_ls[12 * prb + 3 * idx + k] = ch;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
c16_t ch_temp[128] __attribute__((aligned(32))) = {0};
|
||||
delay_t delay = {0};
|
||||
nr_est_delay(128, ch_ls, ch_temp, &delay);
|
||||
int delay_idx = get_delay_idx(delay.est_delay, MAX_DELAY_COMP);
|
||||
c16_t *delay_table = frame_parms->delay_table128[delay_idx];
|
||||
|
||||
// Apply delay compensation
|
||||
for (int aa = 0; aa < Prx; aa++) {
|
||||
for (int prb = 0; prb < pucch_pdu->prb_size; prb++) {
|
||||
int prb12 = 12 * prb;
|
||||
simde__m128i delay_table_128_re = simde_mm_set_epi16(delay_table[prb12 + 11].r,
|
||||
delay_table[prb12 + 9].r,
|
||||
delay_table[prb12 + 8].r,
|
||||
delay_table[prb12 + 6].r,
|
||||
delay_table[prb12 + 5].r,
|
||||
delay_table[prb12 + 3].r,
|
||||
delay_table[prb12 + 2].r,
|
||||
delay_table[prb12].r);
|
||||
simde__m128i delay_table_128_im = simde_mm_set_epi16(delay_table[prb12 + 11].i,
|
||||
delay_table[prb12 + 9].i,
|
||||
delay_table[prb12 + 8].i,
|
||||
delay_table[prb12 + 6].i,
|
||||
delay_table[prb12 + 5].i,
|
||||
delay_table[prb12 + 3].i,
|
||||
delay_table[prb12 + 2].i,
|
||||
delay_table[prb12].i);
|
||||
int prb8 = 8 * prb;
|
||||
complex_mult_simd(*(simde__m128i *)&r_re_ext[aa][symb][prb8],
|
||||
*(simde__m128i *)&r_im_ext[aa][symb][prb8],
|
||||
delay_table_128_re,
|
||||
delay_table_128_im,
|
||||
(simde__m128i *)&r_re_ext[aa][symb][prb8],
|
||||
(simde__m128i *)&r_im_ext[aa][symb][prb8],
|
||||
0,
|
||||
3,
|
||||
5);
|
||||
}
|
||||
|
||||
int prb = 0;
|
||||
for (; prb < prb_size_loop; prb += 2) {
|
||||
int prb12 = 12 * prb;
|
||||
simde__m128i delay_table_128_re = simde_mm_set_epi16(delay_table[prb12 + 22].r,
|
||||
delay_table[prb12 + 19].r,
|
||||
delay_table[prb12 + 16].r,
|
||||
delay_table[prb12 + 13].r,
|
||||
delay_table[prb12 + 10].r,
|
||||
delay_table[prb12 + 7].r,
|
||||
delay_table[prb12 + 4].r,
|
||||
delay_table[prb12 + 1].r);
|
||||
simde__m128i delay_table_128_im = simde_mm_set_epi16(delay_table[prb12 + 22].i,
|
||||
delay_table[prb12 + 19].i,
|
||||
delay_table[prb12 + 16].i,
|
||||
delay_table[prb12 + 13].i,
|
||||
delay_table[prb12 + 10].i,
|
||||
delay_table[prb12 + 7].i,
|
||||
delay_table[prb12 + 4].i,
|
||||
delay_table[prb12 + 1].i);
|
||||
int prb4 = 4 * prb;
|
||||
complex_mult_simd(*(simde__m128i *)&rd_re_ext[aa][symb][prb4],
|
||||
*(simde__m128i *)&rd_im_ext[aa][symb][prb4],
|
||||
delay_table_128_re,
|
||||
delay_table_128_im,
|
||||
(simde__m128i *)&rd_re_ext[aa][symb][prb4],
|
||||
(simde__m128i *)&rd_im_ext[aa][symb][prb4],
|
||||
0,
|
||||
3,
|
||||
5);
|
||||
}
|
||||
for (; prb < pucch_pdu->prb_size; prb++) {
|
||||
int16_t *rd_re_ext_p = &rd_re_ext[aa][symb][4 * prb];
|
||||
int16_t *rd_im_ext_p = &rd_im_ext[aa][symb][4 * prb];
|
||||
for (int idx = 0; idx < 4; idx++) {
|
||||
int k = 3 * idx + 12 * prb;
|
||||
c16_t tmp = c16mulShift((c16_t){rd_re_ext_p[idx], rd_im_ext_p[idx]}, delay_table[k + 1], 8);
|
||||
rd_re_ext_p[idx] = tmp.r;
|
||||
rd_im_ext_p[idx] = tmp.i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int group = 0, goldIdx = pucch_pdu->prb_start / 4; group < ngroup; group++) {
|
||||
// each group has 8*nc_group_size elements, compute 1 complex correlation with DMRS per group
|
||||
// non-coherent combining across groups
|
||||
|
||||
@@ -217,6 +217,8 @@ struct NR_DL_FRAME_PARMS {
|
||||
c16_t timeshift_symbol_rotation[4096*2] __attribute__ ((aligned (16)));
|
||||
/// Table used to apply the delay compensation in DL/UL
|
||||
c16_t delay_table[2 * MAX_DELAY_COMP + 1][NR_MAX_OFDM_SYMBOL_SIZE];
|
||||
/// Table used to apply the delay compensation in PUCCH2
|
||||
c16_t delay_table128[2 * MAX_DELAY_COMP + 1][128];
|
||||
/// SRS configuration from TS 38.331 RRC
|
||||
SRS_NR srs_nr;
|
||||
/// Power used by SSB in order to estimate signal strength and path loss
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
#define USE_128BIT
|
||||
#endif
|
||||
|
||||
#define PEAK_DETECT_THRESHOLD 15
|
||||
|
||||
int16_t saturating_sub(int16_t a, int16_t b)
|
||||
{
|
||||
int32_t result = (int32_t)a - (int32_t)b;
|
||||
@@ -367,20 +369,28 @@ void nr_est_delay(int ofdm_symbol_size, const c16_t *ls_est, c16_t *ch_estimates
|
||||
int max_val = delay->delay_max_val;
|
||||
const int sync_pos = 0;
|
||||
|
||||
uint64_t mean_val = 0;
|
||||
for (int i = 0; i < ofdm_symbol_size; i++) {
|
||||
int temp = c16amp2(ch_estimates_time[i]) >> 1;
|
||||
mean_val += temp;
|
||||
if (temp > max_val) {
|
||||
max_pos = i;
|
||||
max_val = temp;
|
||||
}
|
||||
}
|
||||
mean_val /= ofdm_symbol_size;
|
||||
|
||||
if (max_pos > ofdm_symbol_size / 2)
|
||||
max_pos = max_pos - ofdm_symbol_size;
|
||||
|
||||
delay->delay_max_pos = max_pos;
|
||||
delay->delay_max_val = max_val;
|
||||
delay->est_delay = max_pos - sync_pos;
|
||||
|
||||
// The peak in general is quite clear. It only gives a small peak when the noise is high, generally obtaining an incorrect
|
||||
// estimated delay, and causing the delay compensation to worsen the result instead of improving it. After analyzing several
|
||||
// peaks, and doing many tests, a PEAK_DETECT_THRESHOLD = 15 is an adequate value, to apply delay compensation only when there is
|
||||
// clearly a peak
|
||||
delay->est_delay = mean_val > 0 && max_val / mean_val > PEAK_DETECT_THRESHOLD ? max_pos - sync_pos : 0;
|
||||
}
|
||||
|
||||
unsigned int nr_get_tx_amp(int power_dBm, int power_max_dBm, int total_nb_rb, int nb_rb)
|
||||
|
||||
Reference in New Issue
Block a user