Merge remote-tracking branch 'origin/dmrs_channel_estimation_parallelization' into integration_2024_w47 (!2972)
Parallelize PUSCH channel estimation This MR adds PUSCH channel estimation parallelization which reduces the processing time. It also adds time measurements for each antenna and makes num_antennas_per_thread configurable in nr_ulsim and the gNB config file. Some results: - **273 PRBs 4 antennas** `./nr_ulsim -n200 -m25 -s40 -S40 -q1 -R273 -r273 -z4 -P` | Number of threads | ULSCH channel estimation time (us) develop| ULSCH channel estimation time (us)| Antenna Processing time (us) | | ------ | ------ | ------ | ------ | | 0 | 194.06 |193.17 | 134.82| | 2 | 194.88 |154.02 | 93.43 | | 4 | 195.23 |134.27 | 72.71| - **273 PRBs 8 antennas** `./nr_ulsim -n200 -m25 -s40 -S40 -q1 -R273 -r273 -z8 -P` | Number of threads | ULSCH channel estimation time (us) develop| ULSCH channel estimation time (us)| Antenna Processing time (us) | | ------ | ------ | ------ | ------ | | 0 | 387.93 |384.99 | 269.39| | 2 | 388.10 |279.47 | 161.32| | 4 | 387.47 |225.37 | 106.52| | 8 | 390.53 |204.48 | 83.74| - **106 PRBs MIMO 4 layers** `./nr_ulsim -n100 -m9 -r106 -s10 -W4 -y4 -z4 -P` | Number of threads | ULSCH channel estimation time (us) develop| ULSCH channel estimation time (us)| Antenna Processing time (us) | | ------ | ------ | ------ | ------ | | 0 | 263.20 |268.97 | 57.49 | | 2 | 263.90 |252.61 | 51.22 | | 4 | 264.17 |192.49 | 36.29 |
This commit is contained in:
@@ -19,7 +19,6 @@
|
|||||||
* contact@openairinterface.org
|
* contact@openairinterface.org
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "nr_ul_estimation.h"
|
#include "nr_ul_estimation.h"
|
||||||
@@ -35,7 +34,6 @@
|
|||||||
#include "executables/softmodem-common.h"
|
#include "executables/softmodem-common.h"
|
||||||
#include "nr_phy_common.h"
|
#include "nr_phy_common.h"
|
||||||
|
|
||||||
|
|
||||||
//#define DEBUG_CH
|
//#define DEBUG_CH
|
||||||
//#define DEBUG_PUSCH
|
//#define DEBUG_PUSCH
|
||||||
//#define SRS_DEBUG
|
//#define SRS_DEBUG
|
||||||
@@ -50,8 +48,8 @@ __attribute__((always_inline)) inline c16_t c32x16cumulVectVectWithSteps(c16_t *
|
|||||||
int *offset2,
|
int *offset2,
|
||||||
const int step2,
|
const int step2,
|
||||||
const int modulo2,
|
const int modulo2,
|
||||||
const int N) {
|
const int N)
|
||||||
|
{
|
||||||
int localOffset1 = *offset1;
|
int localOffset1 = *offset1;
|
||||||
int localOffset2 = *offset2;
|
int localOffset2 = *offset2;
|
||||||
c32_t cumul = {0};
|
c32_t cumul = {0};
|
||||||
@@ -65,35 +63,43 @@ __attribute__((always_inline)) inline c16_t c32x16cumulVectVectWithSteps(c16_t *
|
|||||||
return c16x32div(cumul, N);
|
return c16x32div(cumul, N);
|
||||||
}
|
}
|
||||||
|
|
||||||
int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB,
|
static void nr_pusch_antenna_processing(void *arg)
|
||||||
unsigned char Ns,
|
|
||||||
int nl,
|
|
||||||
unsigned short p,
|
|
||||||
unsigned char symbol,
|
|
||||||
int ul_id,
|
|
||||||
int beam_nb,
|
|
||||||
unsigned short bwp_start_subcarrier,
|
|
||||||
nfapi_nr_pusch_pdu_t *pusch_pdu,
|
|
||||||
int *max_ch,
|
|
||||||
uint32_t *nvar)
|
|
||||||
{
|
{
|
||||||
c16_t pilot[3280] __attribute__((aligned(32)));
|
puschAntennaProc_t *rdata = (puschAntennaProc_t *)arg;
|
||||||
const int chest_freq = gNB->chest_freq;
|
unsigned char Ns = rdata->Ns;
|
||||||
|
int nl = rdata->nl;
|
||||||
|
unsigned short p = rdata->p;
|
||||||
|
unsigned char symbol = rdata->symbol;
|
||||||
|
int aarx = rdata->aarx;
|
||||||
|
int numAntennas = rdata->numAntennas;
|
||||||
|
unsigned short bwp_start_subcarrier = rdata->bwp_start_subcarrier;
|
||||||
|
nfapi_nr_pusch_pdu_t *pusch_pdu = rdata->pusch_pdu;
|
||||||
|
int *max_ch = rdata->max_ch;
|
||||||
|
c16_t *pilot = rdata->pilot;
|
||||||
|
uint64_t noise_amp2 = *(rdata->noise_amp2);
|
||||||
|
int nest_count = *(rdata->nest_count);
|
||||||
|
delay_t *delay = rdata->delay;
|
||||||
|
|
||||||
#ifdef DEBUG_CH
|
const int chest_freq = rdata->chest_freq;
|
||||||
FILE *debug_ch_est;
|
NR_gNB_PUSCH *pusch_vars = rdata->pusch_vars;
|
||||||
debug_ch_est = fopen("debug_ch_est.txt","w");
|
|
||||||
#endif
|
|
||||||
NR_gNB_PUSCH *pusch_vars = &gNB->pusch_vars[ul_id];
|
|
||||||
c16_t **ul_ch_estimates = (c16_t **)pusch_vars->ul_ch_estimates;
|
c16_t **ul_ch_estimates = (c16_t **)pusch_vars->ul_ch_estimates;
|
||||||
const int symbolSize = gNB->frame_parms.ofdm_symbol_size;
|
NR_DL_FRAME_PARMS *frame_parms = rdata->frame_parms;
|
||||||
const int slot_offset = (Ns & 3) * gNB->frame_parms.symbols_per_slot * symbolSize;
|
const int symbolSize = frame_parms->ofdm_symbol_size;
|
||||||
|
const int slot_offset = (Ns & 3) * frame_parms->symbols_per_slot * symbolSize;
|
||||||
const int delta = get_delta(p, pusch_pdu->dmrs_config_type);
|
const int delta = get_delta(p, pusch_pdu->dmrs_config_type);
|
||||||
const int symbol_offset = symbolSize * symbol;
|
const int symbol_offset = symbolSize * symbol;
|
||||||
const int k0 = bwp_start_subcarrier;
|
const int k0 = bwp_start_subcarrier;
|
||||||
const int nb_rb_pusch = pusch_pdu->rb_size;
|
const int nb_rb_pusch = pusch_pdu->rb_size;
|
||||||
|
const int beam_nb = rdata->beam_nb;
|
||||||
|
for (int antenna = aarx; antenna < aarx + numAntennas; antenna++) {
|
||||||
|
c16_t ul_ls_est[symbolSize] __attribute__((aligned(32)));
|
||||||
|
memset(ul_ls_est, 0, sizeof(c16_t) * symbolSize);
|
||||||
|
c16_t *rxdataF = (c16_t *)&rdata->rxdataF[beam_nb][antenna][symbol_offset + slot_offset];
|
||||||
|
c16_t *ul_ch = &ul_ch_estimates[nl * frame_parms->nb_antennas_rx + antenna][symbol_offset];
|
||||||
|
memset(ul_ch, 0, sizeof(*ul_ch) * symbolSize);
|
||||||
|
|
||||||
LOG_D(PHY, "symbol_offset %d, slot_offset %d, OFDM size %d, Ns = %d, k0 = %d, symbol %d\n",
|
LOG_D(PHY,
|
||||||
|
"symbol_offset %d, slot_offset %d, OFDM size %d, Ns = %d, k0 = %d, symbol %d\n",
|
||||||
symbol_offset,
|
symbol_offset,
|
||||||
slot_offset,
|
slot_offset,
|
||||||
symbolSize,
|
symbolSize,
|
||||||
@@ -101,71 +107,14 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB,
|
|||||||
k0,
|
k0,
|
||||||
symbol);
|
symbol);
|
||||||
|
|
||||||
//------------------generate DMRS------------------//
|
|
||||||
|
|
||||||
if (pusch_pdu->transform_precoding == transformPrecoder_disabled) {
|
|
||||||
// Note: pilot returned by the following function is already the complex conjugate of the transmitted DMRS
|
|
||||||
NR_DL_FRAME_PARMS *fp = &gNB->frame_parms;
|
|
||||||
const uint32_t *gold = nr_gold_pusch(fp->N_RB_UL,
|
|
||||||
fp->symbols_per_slot,
|
|
||||||
gNB->gNB_config.cell_config.phy_cell_id.value,
|
|
||||||
pusch_pdu->scid,
|
|
||||||
Ns,
|
|
||||||
symbol);
|
|
||||||
nr_pusch_dmrs_rx(gNB,
|
|
||||||
Ns,
|
|
||||||
gold,
|
|
||||||
pilot,
|
|
||||||
(1000 + p),
|
|
||||||
0,
|
|
||||||
nb_rb_pusch,
|
|
||||||
(pusch_pdu->bwp_start + pusch_pdu->rb_start) * NR_NB_SC_PER_RB,
|
|
||||||
pusch_pdu->dmrs_config_type);
|
|
||||||
} else { // if transform precoding or SC-FDMA is enabled in Uplink
|
|
||||||
// NR_SC_FDMA supports type1 DMRS so only 6 DMRS REs per RB possible
|
|
||||||
const int index = get_index_for_dmrs_lowpapr_seq(nb_rb_pusch * (NR_NB_SC_PER_RB / 2));
|
|
||||||
const uint8_t u = pusch_pdu->dfts_ofdm.low_papr_group_number;
|
|
||||||
const uint8_t v = pusch_pdu->dfts_ofdm.low_papr_sequence_number;
|
|
||||||
c16_t *dmrs_seq = gNB_dmrs_lowpaprtype1_sequence[u][v][index];
|
|
||||||
LOG_D(PHY,"Transform Precoding params. u: %d, v: %d, index for dmrsseq: %d\n", u, v, index);
|
|
||||||
AssertFatal(index >= 0, "Num RBs not configured according to 3GPP 38.211 section 6.3.1.4. For PUSCH with transform precoding, num RBs cannot be multiple of any other primenumber other than 2,3,5\n");
|
|
||||||
AssertFatal(dmrs_seq != NULL, "DMRS low PAPR seq not found, check if DMRS sequences are generated");
|
|
||||||
nr_pusch_lowpaprtype1_dmrs_rx(gNB, Ns, dmrs_seq, pilot, 1000, 0, nb_rb_pusch, 0, pusch_pdu->dmrs_config_type);
|
|
||||||
#ifdef DEBUG_PUSCH
|
|
||||||
printf ("NR_UL_CHANNEL_EST: index %d, u %d,v %d\n", index, u, v);
|
|
||||||
LOG_M("gNb_DMRS_SEQ.m","gNb_DMRS_SEQ", dmrs_seq,6*nb_rb_pusch,1,1);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
//------------------------------------------------//
|
|
||||||
|
|
||||||
#ifdef DEBUG_PUSCH
|
|
||||||
|
|
||||||
for (int i = 0; i < (6 * nb_rb_pusch); i++) {
|
|
||||||
LOG_I(PHY, "In %s: %d + j*(%d)\n", __FUNCTION__, pilot[i].r,pilot[i].i);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int nest_count = 0;
|
|
||||||
uint64_t noise_amp2 = 0;
|
|
||||||
c16_t ul_ls_est[symbolSize] __attribute__((aligned(32)));
|
|
||||||
memset(ul_ls_est, 0, sizeof(c16_t) * symbolSize);
|
|
||||||
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++) {
|
|
||||||
c16_t *rxdataF = (c16_t *)&gNB->common_vars.rxdataF[beam_nb][aarx][symbol_offset + slot_offset];
|
|
||||||
c16_t *ul_ch = &ul_ch_estimates[nl * gNB->frame_parms.nb_antennas_rx + aarx][symbol_offset];
|
|
||||||
|
|
||||||
memset(ul_ch, 0, sizeof(*ul_ch) * symbolSize);
|
|
||||||
#ifdef DEBUG_PUSCH
|
#ifdef DEBUG_PUSCH
|
||||||
LOG_I(PHY, "symbol_offset %d, delta %d\n", symbol_offset, delta);
|
LOG_I(PHY, "symbol_offset %d, delta %d\n", symbol_offset, delta);
|
||||||
LOG_I(PHY, "ch est pilot, N_RB_UL %d\n", gNB->frame_parms.N_RB_UL);
|
LOG_I(PHY, "ch est pilot, N_RB_UL %d\n", frame_parms->N_RB_UL);
|
||||||
LOG_I(PHY,
|
LOG_I(PHY,
|
||||||
"bwp_start_subcarrier %d, k0 %d, first_carrier %d, nb_rb_pusch %d\n",
|
"bwp_start_subcarrier %d, k0 %d, first_carrier %d, nb_rb_pusch %d\n",
|
||||||
bwp_start_subcarrier,
|
bwp_start_subcarrier,
|
||||||
k0,
|
k0,
|
||||||
gNB->frame_parms.first_carrier_offset,
|
frame_parms->first_carrier_offset,
|
||||||
nb_rb_pusch);
|
nb_rb_pusch);
|
||||||
LOG_I(PHY, "ul_ch addr %p \n", ul_ch);
|
LOG_I(PHY, "ul_ch addr %p \n", ul_ch);
|
||||||
#endif
|
#endif
|
||||||
@@ -187,16 +136,16 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB,
|
|||||||
}
|
}
|
||||||
|
|
||||||
c16_t ch16 = {.r = (int16_t)ch.r, .i = (int16_t)ch.i};
|
c16_t ch16 = {.r = (int16_t)ch.r, .i = (int16_t)ch.i};
|
||||||
*max_ch = max(*max_ch, max(abs(ch.r), abs(ch.i)));
|
*max_ch = max(abs(ch.r), abs(ch.i));
|
||||||
for (int k = pilot_cnt << 1; k < (pilot_cnt << 1) + 4; k++) {
|
for (int k = pilot_cnt << 1; k < (pilot_cnt << 1) + 4; k++) {
|
||||||
ul_ls_est[k] = ch16;
|
ul_ls_est[k] = ch16;
|
||||||
}
|
}
|
||||||
pilot_cnt += 2;
|
pilot_cnt += 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
nr_est_delay(gNB->frame_parms.ofdm_symbol_size, ul_ls_est, (c16_t *)pusch_vars->ul_ch_estimates_time[aarx], delay);
|
nr_est_delay(frame_parms->ofdm_symbol_size, ul_ls_est, (c16_t *)pusch_vars->ul_ch_estimates_time[antenna], delay);
|
||||||
int delay_idx = get_delay_idx(delay->est_delay, MAX_DELAY_COMP);
|
int delay_idx = get_delay_idx(delay->est_delay, MAX_DELAY_COMP);
|
||||||
c16_t *ul_delay_table = gNB->frame_parms.delay_table[delay_idx];
|
c16_t *ul_delay_table = frame_parms->delay_table[delay_idx];
|
||||||
|
|
||||||
#ifdef DEBUG_PUSCH
|
#ifdef DEBUG_PUSCH
|
||||||
printf("Estimated delay = %i\n", delay->est_delay >> 1);
|
printf("Estimated delay = %i\n", delay->est_delay >> 1);
|
||||||
@@ -204,10 +153,8 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB,
|
|||||||
|
|
||||||
pilot_cnt = 0;
|
pilot_cnt = 0;
|
||||||
for (int n = 0; n < 3 * nb_rb_pusch; n++) {
|
for (int n = 0; n < 3 * nb_rb_pusch; n++) {
|
||||||
|
|
||||||
// Channel interpolation
|
// Channel interpolation
|
||||||
for (int k_line = 0; k_line <= 1; k_line++) {
|
for (int k_line = 0; k_line <= 1; k_line++) {
|
||||||
|
|
||||||
// Apply delay
|
// Apply delay
|
||||||
int k = pilot_cnt << 1;
|
int k = pilot_cnt << 1;
|
||||||
c16_t ch16 = c16mulShift(ul_ls_est[k], ul_delay_table[k], 8);
|
c16_t ch16 = c16mulShift(ul_ls_est[k], ul_delay_table[k], 8);
|
||||||
@@ -216,7 +163,13 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB,
|
|||||||
re_offset = (k0 + (n << 2) + (k_line << 1)) % symbolSize;
|
re_offset = (k0 + (n << 2) + (k_line << 1)) % symbolSize;
|
||||||
c16_t *rxF = &rxdataF[re_offset];
|
c16_t *rxF = &rxdataF[re_offset];
|
||||||
printf("pilot %4d: pil -> (%6d,%6d), rxF -> (%4d,%4d), ch -> (%4d,%4d)\n",
|
printf("pilot %4d: pil -> (%6d,%6d), rxF -> (%4d,%4d), ch -> (%4d,%4d)\n",
|
||||||
pilot_cnt, pil->r, pil->i, rxF->r, rxF->i, ch16.r, ch16.i);
|
pilot_cnt,
|
||||||
|
pil->r,
|
||||||
|
pil->i,
|
||||||
|
rxF->r,
|
||||||
|
rxF->i,
|
||||||
|
ch.r,
|
||||||
|
ch.i);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (pilot_cnt == 0) {
|
if (pilot_cnt == 0) {
|
||||||
@@ -238,9 +191,9 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB,
|
|||||||
|
|
||||||
// Revert delay
|
// Revert delay
|
||||||
pilot_cnt = 0;
|
pilot_cnt = 0;
|
||||||
ul_ch = &ul_ch_estimates[nl * gNB->frame_parms.nb_antennas_rx + aarx][symbol_offset];
|
ul_ch = &ul_ch_estimates[nl * frame_parms->nb_antennas_rx + antenna][symbol_offset];
|
||||||
int inv_delay_idx = get_delay_idx(-delay->est_delay, MAX_DELAY_COMP);
|
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];
|
c16_t *ul_inv_delay_table = frame_parms->delay_table[inv_delay_idx];
|
||||||
for (int n = 0; n < 3 * nb_rb_pusch; n++) {
|
for (int n = 0; n < 3 * nb_rb_pusch; n++) {
|
||||||
for (int k_line = 0; k_line <= 1; k_line++) {
|
for (int k_line = 0; k_line <= 1; k_line++) {
|
||||||
int k = pilot_cnt << 1;
|
int k = pilot_cnt << 1;
|
||||||
@@ -258,7 +211,8 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (pusch_pdu->dmrs_config_type == pusch_dmrs_type2 && chest_freq == 0) { // pusch_dmrs_type2 |p_r,p_l,d,d,d,d,p_r,p_l,d,d,d,d|
|
} else if (pusch_pdu->dmrs_config_type == pusch_dmrs_type2
|
||||||
|
&& chest_freq == 0) { // pusch_dmrs_type2 |p_r,p_l,d,d,d,d,p_r,p_l,d,d,d,d|
|
||||||
LOG_D(PHY, "PUSCH estimation DMRS type 2, Freq-domain interpolation\n");
|
LOG_D(PHY, "PUSCH estimation DMRS type 2, Freq-domain interpolation\n");
|
||||||
c16_t *pil = pilot;
|
c16_t *pil = pilot;
|
||||||
c16_t *rx = &rxdataF[delta];
|
c16_t *rx = &rxdataF[delta];
|
||||||
@@ -268,24 +222,25 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB,
|
|||||||
c16_t ch1 = c16mulShift(*pil, rx[(k0 + n + 1) % symbolSize], 15);
|
c16_t ch1 = c16mulShift(*pil, rx[(k0 + n + 1) % symbolSize], 15);
|
||||||
pil++;
|
pil++;
|
||||||
c16_t ch = c16addShift(ch0, ch1, 1);
|
c16_t ch = c16addShift(ch0, ch1, 1);
|
||||||
*max_ch = max(*max_ch, max(abs(ch.r), abs(ch.i)));
|
*max_ch = max(abs(ch.r), abs(ch.i));
|
||||||
multadd_real_four_symbols_vector_complex_scalar(filt8_rep4, &ch, &ul_ls_est[n]);
|
multadd_real_four_symbols_vector_complex_scalar(filt8_rep4, &ch, &ul_ls_est[n]);
|
||||||
ul_ls_est[n + 4] = ch;
|
ul_ls_est[n + 4] = ch;
|
||||||
ul_ls_est[n + 5] = ch;
|
ul_ls_est[n + 5] = ch;
|
||||||
noise_amp2 += c16amp2(c16sub(ch0, ch));
|
noise_amp2 += c16amp2(c16sub(ch0, ch));
|
||||||
nest_count++;
|
nest_count += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delay compensation
|
// Delay compensation
|
||||||
nr_est_delay(gNB->frame_parms.ofdm_symbol_size, ul_ls_est, (c16_t *)pusch_vars->ul_ch_estimates_time[aarx], delay);
|
nr_est_delay(frame_parms->ofdm_symbol_size, ul_ls_est, (c16_t *)pusch_vars->ul_ch_estimates_time[antenna], delay);
|
||||||
int delay_idx = get_delay_idx(-delay->est_delay, MAX_DELAY_COMP);
|
int delay_idx = get_delay_idx(-delay->est_delay, MAX_DELAY_COMP);
|
||||||
c16_t *ul_delay_table = gNB->frame_parms.delay_table[delay_idx];
|
c16_t *ul_delay_table = frame_parms->delay_table[delay_idx];
|
||||||
for (int n = 0; n < nb_rb_pusch * NR_NB_SC_PER_RB; n++) {
|
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);
|
ul_ch[n] = c16mulShift(ul_ls_est[n], ul_delay_table[n % 6], 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
// this is case without frequency-domain linear interpolation, just take average of LS channel estimates of 6 DMRS REs and use a common value for the whole PRB
|
// this is case without frequency-domain linear interpolation, just take average of LS channel estimates of 6 DMRS REs and use a
|
||||||
|
// common value for the whole PRB
|
||||||
else if (pusch_pdu->dmrs_config_type == pusch_dmrs_type1) {
|
else if (pusch_pdu->dmrs_config_type == pusch_dmrs_type1) {
|
||||||
LOG_D(PHY, "PUSCH estimation DMRS type 1, no Freq-domain interpolation\n");
|
LOG_D(PHY, "PUSCH estimation DMRS type 1, no Freq-domain interpolation\n");
|
||||||
c16_t *rxF = &rxdataF[delta];
|
c16_t *rxF = &rxdataF[delta];
|
||||||
@@ -310,7 +265,7 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB,
|
|||||||
|
|
||||||
for (int pilot_cnt = 6; pilot_cnt < 6 * (nb_rb_pusch - 1); pilot_cnt += 6) {
|
for (int pilot_cnt = 6; pilot_cnt < 6 * (nb_rb_pusch - 1); pilot_cnt += 6) {
|
||||||
ch = c32x16cumulVectVectWithSteps(pilot, &pil_offset, 1, rxF, &re_offset, 2, symbolSize, 6);
|
ch = c32x16cumulVectVectWithSteps(pilot, &pil_offset, 1, rxF, &re_offset, 2, symbolSize, 6);
|
||||||
*max_ch = max(*max_ch, max(abs(ch.r), abs(ch.i)));
|
*max_ch = max(abs(ch.r), abs(ch.i));
|
||||||
|
|
||||||
#if NO_INTERP
|
#if NO_INTERP
|
||||||
for (c16_t *end = ul_ch + 12; ul_ch < end; ul_ch++)
|
for (c16_t *end = ul_ch + 12; ul_ch < end; ul_ch++)
|
||||||
@@ -343,7 +298,8 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB,
|
|||||||
ul_ch += 8;
|
ul_ch += 8;
|
||||||
c16multaddVectRealComplex(filt8_avlip6, &ch, ul_ch, 8);
|
c16multaddVectRealComplex(filt8_avlip6, &ch, ul_ch, 8);
|
||||||
#endif
|
#endif
|
||||||
} else { // this is case without frequency-domain linear interpolation, just take average of LS channel estimates of 4 DMRS REs and use a common value for the whole PRB
|
} else { // this is case without frequency-domain linear interpolation, just take average of LS channel estimates of 4 DMRS REs
|
||||||
|
// and use a common value for the whole PRB
|
||||||
LOG_D(PHY, "PUSCH estimation DMRS type 2, no Freq-domain interpolation");
|
LOG_D(PHY, "PUSCH estimation DMRS type 2, no Freq-domain interpolation");
|
||||||
c16_t *pil = pilot;
|
c16_t *pil = pilot;
|
||||||
int re_offset = (k0 + delta) % symbolSize;
|
int re_offset = (k0 + delta) % symbolSize;
|
||||||
@@ -393,7 +349,7 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB,
|
|||||||
re_offset = (re_offset + 5) % symbolSize;
|
re_offset = (re_offset + 5) % symbolSize;
|
||||||
|
|
||||||
ch = c16x32div(ch0, 4);
|
ch = c16x32div(ch0, 4);
|
||||||
*max_ch = max(*max_ch, max(abs(ch.r), abs(ch.i)));
|
*max_ch = max(abs(ch.r), abs(ch.i));
|
||||||
|
|
||||||
#if NO_INTERP
|
#if NO_INTERP
|
||||||
for (c16_t *end = ul_ch + 12; ul_ch < end; ul_ch++)
|
for (c16_t *end = ul_ch + 12; ul_ch < end; ul_ch++)
|
||||||
@@ -449,7 +405,157 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB,
|
|||||||
printf("%d\n", idxP);
|
printf("%d\n", idxP);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
// update the values inside the arrays
|
||||||
|
*(rdata->noise_amp2) = noise_amp2;
|
||||||
|
*(rdata->nest_count) = nest_count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB,
|
||||||
|
unsigned char Ns,
|
||||||
|
int nl,
|
||||||
|
unsigned short p,
|
||||||
|
unsigned char symbol,
|
||||||
|
int ul_id,
|
||||||
|
int beam_nb,
|
||||||
|
unsigned short bwp_start_subcarrier,
|
||||||
|
nfapi_nr_pusch_pdu_t *pusch_pdu,
|
||||||
|
int *max_ch,
|
||||||
|
uint32_t *nvar)
|
||||||
|
{
|
||||||
|
c16_t pilot[3280] __attribute__((aligned(32)));
|
||||||
|
|
||||||
|
#ifdef DEBUG_CH
|
||||||
|
FILE *debug_ch_est;
|
||||||
|
debug_ch_est = fopen("debug_ch_est.txt", "w");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const int nb_rb_pusch = pusch_pdu->rb_size;
|
||||||
|
|
||||||
|
//------------------generate DMRS------------------//
|
||||||
|
|
||||||
|
if (pusch_pdu->transform_precoding == transformPrecoder_disabled) {
|
||||||
|
// Note: pilot returned by the following function is already the complex conjugate of the transmitted DMRS
|
||||||
|
NR_DL_FRAME_PARMS *fp = &gNB->frame_parms;
|
||||||
|
const uint32_t *gold = nr_gold_pusch(fp->N_RB_UL,
|
||||||
|
fp->symbols_per_slot,
|
||||||
|
gNB->gNB_config.cell_config.phy_cell_id.value,
|
||||||
|
pusch_pdu->scid,
|
||||||
|
Ns,
|
||||||
|
symbol);
|
||||||
|
nr_pusch_dmrs_rx(gNB,
|
||||||
|
Ns,
|
||||||
|
gold,
|
||||||
|
pilot,
|
||||||
|
(1000 + p),
|
||||||
|
0,
|
||||||
|
nb_rb_pusch,
|
||||||
|
(pusch_pdu->bwp_start + pusch_pdu->rb_start) * NR_NB_SC_PER_RB,
|
||||||
|
pusch_pdu->dmrs_config_type);
|
||||||
|
} else { // if transform precoding or SC-FDMA is enabled in Uplink
|
||||||
|
// NR_SC_FDMA supports type1 DMRS so only 6 DMRS REs per RB possible
|
||||||
|
const int index = get_index_for_dmrs_lowpapr_seq(nb_rb_pusch * (NR_NB_SC_PER_RB / 2));
|
||||||
|
const uint8_t u = pusch_pdu->dfts_ofdm.low_papr_group_number;
|
||||||
|
const uint8_t v = pusch_pdu->dfts_ofdm.low_papr_sequence_number;
|
||||||
|
c16_t *dmrs_seq = gNB_dmrs_lowpaprtype1_sequence[u][v][index];
|
||||||
|
LOG_D(PHY, "Transform Precoding params. u: %d, v: %d, index for dmrsseq: %d\n", u, v, index);
|
||||||
|
AssertFatal(index >= 0,
|
||||||
|
"Num RBs not configured according to 3GPP 38.211 section 6.3.1.4. For PUSCH with transform precoding, num RBs "
|
||||||
|
"cannot be multiple of any other primenumber other than 2,3,5\n");
|
||||||
|
AssertFatal(dmrs_seq != NULL, "DMRS low PAPR seq not found, check if DMRS sequences are generated");
|
||||||
|
nr_pusch_lowpaprtype1_dmrs_rx(gNB, Ns, dmrs_seq, pilot, 1000, 0, nb_rb_pusch, 0, pusch_pdu->dmrs_config_type);
|
||||||
|
#ifdef DEBUG_PUSCH
|
||||||
|
printf("NR_UL_CHANNEL_EST: index %d, u %d,v %d\n", index, u, v);
|
||||||
|
LOG_M("gNb_DMRS_SEQ.m", "gNb_DMRS_SEQ", dmrs_seq, 6 * nb_rb_pusch, 1, 1);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
//------------------------------------------------//
|
||||||
|
|
||||||
|
#ifdef DEBUG_PUSCH
|
||||||
|
|
||||||
|
for (int i = 0; i < (6 * nb_rb_pusch); i++) {
|
||||||
|
LOG_I(PHY, "In %s: %d + j*(%d)\n", __FUNCTION__, pilot[i].r, pilot[i].i);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int nbAarx = 0;
|
||||||
|
int nest_count = 0;
|
||||||
|
uint64_t noise_amp2 = 0;
|
||||||
|
delay_t *delay = &gNB->ulsch[ul_id].delay;
|
||||||
|
memset(delay, 0, sizeof(*delay));
|
||||||
|
|
||||||
|
int nb_antennas_rx = gNB->frame_parms.nb_antennas_rx;
|
||||||
|
delay_t delay_arr[nb_antennas_rx];
|
||||||
|
uint64_t noise_amp2_arr[nb_antennas_rx];
|
||||||
|
int max_ch_arr[nb_antennas_rx];
|
||||||
|
int nest_count_arr[nb_antennas_rx];
|
||||||
|
|
||||||
|
for (int i = 0; i < nb_antennas_rx; ++i) {
|
||||||
|
max_ch_arr[i] = *max_ch;
|
||||||
|
nest_count_arr[i] = nest_count;
|
||||||
|
noise_amp2_arr[i] = noise_amp2;
|
||||||
|
delay_arr[i] = *delay;
|
||||||
|
}
|
||||||
|
|
||||||
|
notifiedFIFO_t respPuschAarx;
|
||||||
|
initNotifiedFIFO(&respPuschAarx);
|
||||||
|
start_meas(&gNB->pusch_channel_estimation_antenna_processing_stats);
|
||||||
|
int numAntennas = gNB->dmrs_num_antennas_per_thread;
|
||||||
|
for (int aarx = 0; aarx < gNB->frame_parms.nb_antennas_rx; aarx += numAntennas) {
|
||||||
|
union puschAntennaReqUnion id = {.s = {ul_id, 0}};
|
||||||
|
id.p = 1 + aarx;
|
||||||
|
notifiedFIFO_elt_t *req = newNotifiedFIFO_elt(sizeof(puschAntennaProc_t),
|
||||||
|
id.p,
|
||||||
|
&respPuschAarx,
|
||||||
|
&nr_pusch_antenna_processing); // create a job for Tpool
|
||||||
|
puschAntennaProc_t *rdata = (puschAntennaProc_t *)NotifiedFifoData(req); // data for the job
|
||||||
|
|
||||||
|
// Local init in the current loop
|
||||||
|
rdata->Ns = Ns;
|
||||||
|
rdata->nl = nl;
|
||||||
|
rdata->p = p;
|
||||||
|
rdata->symbol = symbol;
|
||||||
|
rdata->aarx = aarx;
|
||||||
|
rdata->numAntennas = numAntennas;
|
||||||
|
rdata->bwp_start_subcarrier = bwp_start_subcarrier;
|
||||||
|
rdata->pusch_pdu = pusch_pdu;
|
||||||
|
rdata->max_ch = &max_ch_arr[rdata->aarx];
|
||||||
|
rdata->pilot = pilot;
|
||||||
|
rdata->nest_count = &nest_count_arr[rdata->aarx];
|
||||||
|
rdata->noise_amp2 = &noise_amp2_arr[rdata->aarx];
|
||||||
|
rdata->delay = &delay_arr[rdata->aarx];
|
||||||
|
rdata->beam_nb = beam_nb;
|
||||||
|
rdata->frame_parms = &gNB->frame_parms;
|
||||||
|
rdata->pusch_vars = &gNB->pusch_vars[ul_id];
|
||||||
|
rdata->chest_freq = gNB->chest_freq;
|
||||||
|
rdata->rxdataF = gNB->common_vars.rxdataF;
|
||||||
|
// Call the nr_pusch_antenna_processing function
|
||||||
|
pushTpool(&gNB->threadPool, req);
|
||||||
|
nbAarx++;
|
||||||
|
|
||||||
|
LOG_D(PHY, "Added Antenna (count %d) to process, in pipe\n", nbAarx);
|
||||||
|
} // Antenna Loop
|
||||||
|
|
||||||
|
while (nbAarx > 0) {
|
||||||
|
notifiedFIFO_elt_t *req = pullTpool(&respPuschAarx, &gNB->threadPool);
|
||||||
|
nbAarx--;
|
||||||
|
delNotifiedFIFO_elt(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
stop_meas(&gNB->pusch_channel_estimation_antenna_processing_stats);
|
||||||
|
for (int aarx = 0; aarx < gNB->frame_parms.nb_antennas_rx; aarx++) {
|
||||||
|
*max_ch = max(*max_ch, max_ch_arr[aarx]);
|
||||||
|
noise_amp2 += noise_amp2_arr[aarx];
|
||||||
|
nest_count += nest_count_arr[aarx];
|
||||||
|
}
|
||||||
|
// get the maximum delay
|
||||||
|
*delay = delay_arr[0];
|
||||||
|
for (int aarx = 1; aarx < gNB->frame_parms.nb_antennas_rx; aarx++) {
|
||||||
|
if (delay_arr[aarx].est_delay >= delay->est_delay) {
|
||||||
|
*delay = delay_arr[aarx];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG_CH
|
#ifdef DEBUG_CH
|
||||||
@@ -463,7 +569,6 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************
|
/*******************************************************************
|
||||||
*
|
*
|
||||||
* NAME : nr_pusch_ptrs_processing
|
* NAME : nr_pusch_ptrs_processing
|
||||||
@@ -521,18 +626,13 @@ void nr_pusch_ptrs_processing(PHY_VARS_gNB *gNB,
|
|||||||
#ifdef DEBUG_UL_PTRS
|
#ifdef DEBUG_UL_PTRS
|
||||||
printf("[PHY][PTRS]: DMRS Symbol %d -> %4d + j*%4d\n", symbol, phase_per_symbol[symbol].r, phase_per_symbol[symbol].i);
|
printf("[PHY][PTRS]: DMRS Symbol %d -> %4d + j*%4d\n", symbol, phase_per_symbol[symbol].r, phase_per_symbol[symbol].i);
|
||||||
#endif
|
#endif
|
||||||
}
|
} else { // real ptrs value is set to 0
|
||||||
else {// real ptrs value is set to 0
|
|
||||||
phase_per_symbol[symbol].r = 0;
|
phase_per_symbol[symbol].r = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (symbol == *startSymbIndex) {
|
if (symbol == *startSymbIndex) {
|
||||||
*ptrsSymbPos = 0;
|
*ptrsSymbPos = 0;
|
||||||
set_ptrs_symb_idx(ptrsSymbPos,
|
set_ptrs_symb_idx(ptrsSymbPos, *nbSymb, *startSymbIndex, 1 << *L_ptrs, *dmrsSymbPos);
|
||||||
*nbSymb,
|
|
||||||
*startSymbIndex,
|
|
||||||
1<< *L_ptrs,
|
|
||||||
*dmrsSymbPos);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if not PTRS symbol set current ptrs symbol index to zero*/
|
/* if not PTRS symbol set current ptrs symbol index to zero*/
|
||||||
@@ -639,7 +739,8 @@ int nr_srs_channel_estimation(
|
|||||||
c16_t noise[arr_len];
|
c16_t noise[arr_len];
|
||||||
memset(noise, 0, arr_len * sizeof(c16_t));
|
memset(noise, 0, arr_len * sizeof(c16_t));
|
||||||
|
|
||||||
uint8_t mem_offset = ((16 - ((long)&srs_estimated_channel_freq[0][0][subcarrier_offset + nr_srs_info->k_0_p[0][0]])) & 0xF) >> 2; // >> 2 <=> /sizeof(int32_t)
|
uint8_t mem_offset = ((16 - ((long)&srs_estimated_channel_freq[0][0][subcarrier_offset + nr_srs_info->k_0_p[0][0]])) & 0xF)
|
||||||
|
>> 2; // >> 2 <=> /sizeof(int32_t)
|
||||||
|
|
||||||
// filt16_end is {4096,8192,8192,8192,12288,16384,16384,16384,0,0,0,0,0,0,0,0}
|
// filt16_end is {4096,8192,8192,8192,12288,16384,16384,16384,0,0,0,0,0,0,0,0}
|
||||||
// The End of OFDM symbol corresponds to the position of last 16384 in the filter
|
// The End of OFDM symbol corresponds to the position of last 16384 in the filter
|
||||||
@@ -649,9 +750,7 @@ int nr_srs_channel_estimation(
|
|||||||
c16_t ls_estimated = {0};
|
c16_t ls_estimated = {0};
|
||||||
|
|
||||||
for (int ant = 0; ant < frame_parms->nb_antennas_rx; ant++) {
|
for (int ant = 0; ant < frame_parms->nb_antennas_rx; ant++) {
|
||||||
|
|
||||||
for (int p_index = 0; p_index < N_ap; p_index++) {
|
for (int p_index = 0; p_index < N_ap; p_index++) {
|
||||||
|
|
||||||
memset(srs_ls_estimated_channel, 0, frame_parms->ofdm_symbol_size * (1 << srs_pdu->num_symbols) * sizeof(c16_t));
|
memset(srs_ls_estimated_channel, 0, frame_parms->ofdm_symbol_size * (1 << srs_pdu->num_symbols) * sizeof(c16_t));
|
||||||
memset(srs_est, 0, (frame_parms->ofdm_symbol_size * (1 << srs_pdu->num_symbols) + mem_offset) * sizeof(int32_t));
|
memset(srs_est, 0, (frame_parms->ofdm_symbol_size * (1 << srs_pdu->num_symbols) + mem_offset) * sizeof(int32_t));
|
||||||
|
|
||||||
@@ -667,7 +766,6 @@ int nr_srs_channel_estimation(
|
|||||||
c16_t *srs_estimated_channel16 = (c16_t *)&srs_est[subcarrier + mem_offset];
|
c16_t *srs_estimated_channel16 = (c16_t *)&srs_est[subcarrier + mem_offset];
|
||||||
|
|
||||||
for (int k = 0; k < M_sc_b_SRS; k++) {
|
for (int k = 0; k < M_sc_b_SRS; k++) {
|
||||||
|
|
||||||
if (k % fd_cdm == 0) {
|
if (k % fd_cdm == 0) {
|
||||||
ls_estimated = (c16_t){0, 0};
|
ls_estimated = (c16_t){0, 0};
|
||||||
uint16_t subcarrier_cdm = subcarrier;
|
uint16_t subcarrier_cdm = subcarrier;
|
||||||
@@ -679,10 +777,13 @@ int nr_srs_channel_estimation(
|
|||||||
int16_t received_real = ((c16_t *)srs_received_signal[ant])[subcarrier_cdm].r;
|
int16_t received_real = ((c16_t *)srs_received_signal[ant])[subcarrier_cdm].r;
|
||||||
int16_t received_imag = ((c16_t *)srs_received_signal[ant])[subcarrier_cdm].i;
|
int16_t received_imag = ((c16_t *)srs_received_signal[ant])[subcarrier_cdm].i;
|
||||||
|
|
||||||
// We know that nr_srs_info->srs_generated_signal_bits bits are enough to represent the generated_real and generated_imag.
|
// We know that nr_srs_info->srs_generated_signal_bits bits are enough to represent the generated_real and
|
||||||
// So we only need a nr_srs_info->srs_generated_signal_bits shift to ensure that the result fits into 16 bits.
|
// generated_imag. So we only need a nr_srs_info->srs_generated_signal_bits shift to ensure that the result fits into 16
|
||||||
ls_estimated.r += (int16_t)(((int32_t)generated_real*received_real + (int32_t)generated_imag*received_imag)>>nr_srs_info->srs_generated_signal_bits);
|
// bits.
|
||||||
ls_estimated.i += (int16_t)(((int32_t)generated_real*received_imag - (int32_t)generated_imag*received_real)>>nr_srs_info->srs_generated_signal_bits);
|
ls_estimated.r += (int16_t)(((int32_t)generated_real * received_real + (int32_t)generated_imag * received_imag)
|
||||||
|
>> nr_srs_info->srs_generated_signal_bits);
|
||||||
|
ls_estimated.i += (int16_t)(((int32_t)generated_real * received_imag - (int32_t)generated_imag * received_real)
|
||||||
|
>> nr_srs_info->srs_generated_signal_bits);
|
||||||
|
|
||||||
// Subcarrier increment
|
// Subcarrier increment
|
||||||
subcarrier_cdm += K_TC;
|
subcarrier_cdm += K_TC;
|
||||||
@@ -703,11 +804,15 @@ int nr_srs_channel_estimation(
|
|||||||
LOG_I(NR_PHY, "------------------------------------ %d ------------------------------------\n", subcarrier_log / 12);
|
LOG_I(NR_PHY, "------------------------------------ %d ------------------------------------\n", subcarrier_log / 12);
|
||||||
LOG_I(NR_PHY, "\t __genRe________genIm__|____rxRe_________rxIm__|____lsRe________lsIm_\n");
|
LOG_I(NR_PHY, "\t __genRe________genIm__|____rxRe_________rxIm__|____lsRe________lsIm_\n");
|
||||||
}
|
}
|
||||||
LOG_I(NR_PHY,"(%4i) %6i\t%6i | %6i\t%6i | %6i\t%6i\n",
|
LOG_I(NR_PHY,
|
||||||
|
"(%4i) %6i\t%6i | %6i\t%6i | %6i\t%6i\n",
|
||||||
subcarrier_log,
|
subcarrier_log,
|
||||||
((c16_t*)srs_generated_signal[p_index])[subcarrier].r, ((c16_t*)srs_generated_signal[p_index])[subcarrier].i,
|
((c16_t *)srs_generated_signal[p_index])[subcarrier].r,
|
||||||
((c16_t*)srs_received_signal[ant])[subcarrier].r, ((c16_t*)srs_received_signal[ant])[subcarrier].i,
|
((c16_t *)srs_generated_signal[p_index])[subcarrier].i,
|
||||||
ls_estimated.r, ls_estimated.i);
|
((c16_t *)srs_received_signal[ant])[subcarrier].r,
|
||||||
|
((c16_t *)srs_received_signal[ant])[subcarrier].i,
|
||||||
|
ls_estimated.r,
|
||||||
|
ls_estimated.i);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const uint16_t sc_offset = subcarrier + mem_offset;
|
const uint16_t sc_offset = subcarrier + mem_offset;
|
||||||
@@ -722,7 +827,8 @@ int nr_srs_channel_estimation(
|
|||||||
srs_estimated_channel16 = (c16_t *)&srs_est[subcarrier];
|
srs_estimated_channel16 = (c16_t *)&srs_est[subcarrier];
|
||||||
const short *filter = mem_offset == 0 ? filt8_start : filt8_start_shift2;
|
const short *filter = mem_offset == 0 ? filt8_start : filt8_start_shift2;
|
||||||
c16multaddVectRealComplex(filter, &ls_estimated, srs_estimated_channel16, 8);
|
c16multaddVectRealComplex(filter, &ls_estimated, srs_estimated_channel16, 8);
|
||||||
} else if ((subcarrier + K_TC) >= frame_parms->ofdm_symbol_size || k == (M_sc_b_SRS - 1)) { // End of OFDM symbol or last subcarrier cases
|
} else if ((subcarrier + K_TC) >= frame_parms->ofdm_symbol_size
|
||||||
|
|| k == (M_sc_b_SRS - 1)) { // End of OFDM symbol or last subcarrier cases
|
||||||
// filt8_end is {4096,8192,12288,16384,0,0,0,0}
|
// filt8_end is {4096,8192,12288,16384,0,0,0,0}
|
||||||
const short *filter = mem_offset == 0 || k == (M_sc_b_SRS - 1) ? filt8_end : filt8_end_shift2;
|
const short *filter = mem_offset == 0 || k == (M_sc_b_SRS - 1) ? filt8_end : filt8_end_shift2;
|
||||||
c16multaddVectRealComplex(filter, &ls_estimated, srs_estimated_channel16, 8);
|
c16multaddVectRealComplex(filter, &ls_estimated, srs_estimated_channel16, 8);
|
||||||
@@ -742,7 +848,8 @@ int nr_srs_channel_estimation(
|
|||||||
srs_estimated_channel16 = (c16_t *)&srs_est[sc_offset];
|
srs_estimated_channel16 = (c16_t *)&srs_est[sc_offset];
|
||||||
// filt16_start is {12288,8192,8192,8192,4096,0,0,0,0,0,0,0,0,0,0,0}
|
// filt16_start is {12288,8192,8192,8192,4096,0,0,0,0,0,0,0,0,0,0,0}
|
||||||
c16multaddVectRealComplex(filt16_start, &ls_estimated, srs_estimated_channel16, 16);
|
c16multaddVectRealComplex(filt16_start, &ls_estimated, srs_estimated_channel16, 16);
|
||||||
} else if ((subcarrier + K_TC) >= frame_parms->ofdm_symbol_size || k == (M_sc_b_SRS - 1)) { // End of OFDM symbol or last subcarrier cases
|
} else if ((subcarrier + K_TC) >= frame_parms->ofdm_symbol_size
|
||||||
|
|| k == (M_sc_b_SRS - 1)) { // End of OFDM symbol or last subcarrier cases
|
||||||
// filt16_end is {4096,8192,8192,8192,12288,16384,16384,16384,0,0,0,0,0,0,0,0}
|
// filt16_end is {4096,8192,8192,8192,12288,16384,16384,16384,0,0,0,0,0,0,0,0}
|
||||||
c16multaddVectRealComplex(filt16_end, &ls_estimated, srs_estimated_channel16, 16);
|
c16multaddVectRealComplex(filt16_end, &ls_estimated, srs_estimated_channel16, 16);
|
||||||
} else { // Middle case
|
} else { // Middle case
|
||||||
@@ -787,7 +894,6 @@ int nr_srs_channel_estimation(
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (int k = 0; k < K_TC * M_sc_b_SRS; k++) {
|
for (int k = 0; k < K_TC * M_sc_b_SRS; k++) {
|
||||||
|
|
||||||
int subcarrier_log = subcarrier - subcarrier_offset;
|
int subcarrier_log = subcarrier - subcarrier_offset;
|
||||||
if (subcarrier_log < 0) {
|
if (subcarrier_log < 0) {
|
||||||
subcarrier_log = subcarrier_log + frame_parms->ofdm_symbol_size;
|
subcarrier_log = subcarrier_log + frame_parms->ofdm_symbol_size;
|
||||||
@@ -798,7 +904,8 @@ int nr_srs_channel_estimation(
|
|||||||
LOG_I(NR_PHY, "\t __lsRe__________lsIm__|____intRe_______intIm__|____noiRe_______noiIm__\n");
|
LOG_I(NR_PHY, "\t __lsRe__________lsIm__|____intRe_______intIm__|____noiRe_______noiIm__\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_I(NR_PHY,"(%4i) %6i\t%6i | %6i\t%6i | %6i\t%6i\n",
|
LOG_I(NR_PHY,
|
||||||
|
"(%4i) %6i\t%6i | %6i\t%6i | %6i\t%6i\n",
|
||||||
subcarrier_log,
|
subcarrier_log,
|
||||||
srs_ls_estimated_channel[subcarrier].r,
|
srs_ls_estimated_channel[subcarrier].r,
|
||||||
srs_ls_estimated_channel[subcarrier].i,
|
srs_ls_estimated_channel[subcarrier].i,
|
||||||
@@ -852,7 +959,6 @@ int nr_srs_channel_estimation(
|
|||||||
uint64_t sum_im2 = 0;
|
uint64_t sum_im2 = 0;
|
||||||
|
|
||||||
for (int rb = 0; rb < m_SRS_b; rb++) {
|
for (int rb = 0; rb < m_SRS_b; rb++) {
|
||||||
|
|
||||||
sum_re = 0;
|
sum_re = 0;
|
||||||
sum_re2 = 0;
|
sum_re2 = 0;
|
||||||
sum_im = 0;
|
sum_im = 0;
|
||||||
@@ -870,8 +976,9 @@ int nr_srs_channel_estimation(
|
|||||||
} // for (int p_index = 0; p_index < N_ap; p_index++)
|
} // for (int p_index = 0; p_index < N_ap; p_index++)
|
||||||
} // for (int ant = 0; ant < frame_parms->nb_antennas_rx; ant++)
|
} // for (int ant = 0; ant < frame_parms->nb_antennas_rx; ant++)
|
||||||
|
|
||||||
noise_power_per_rb[rb] = max(sum_re2 / n_noise_est - (sum_re / n_noise_est) * (sum_re / n_noise_est) +
|
noise_power_per_rb[rb] = max(sum_re2 / n_noise_est - (sum_re / n_noise_est) * (sum_re / n_noise_est) + sum_im2 / n_noise_est
|
||||||
sum_im2 / n_noise_est - (sum_im / n_noise_est) * (sum_im / n_noise_est), 1);
|
- (sum_im / n_noise_est) * (sum_im / n_noise_est),
|
||||||
|
1);
|
||||||
snr_per_rb[rb] = dB_fixed(signal_power) - dB_fixed(noise_power_per_rb[rb]);
|
snr_per_rb[rb] = dB_fixed(signal_power) - dB_fixed(noise_power_per_rb[rb]);
|
||||||
|
|
||||||
#ifdef SRS_DEBUG
|
#ifdef SRS_DEBUG
|
||||||
|
|||||||
@@ -543,6 +543,7 @@ typedef struct PHY_VARS_gNB_s {
|
|||||||
time_stats_t ulsch_decoding_stats;
|
time_stats_t ulsch_decoding_stats;
|
||||||
time_stats_t ulsch_deinterleaving_stats;
|
time_stats_t ulsch_deinterleaving_stats;
|
||||||
time_stats_t ulsch_channel_estimation_stats;
|
time_stats_t ulsch_channel_estimation_stats;
|
||||||
|
time_stats_t pusch_channel_estimation_antenna_processing_stats;
|
||||||
time_stats_t ulsch_llr_stats;
|
time_stats_t ulsch_llr_stats;
|
||||||
time_stats_t rx_srs_stats;
|
time_stats_t rx_srs_stats;
|
||||||
time_stats_t generate_srs_stats;
|
time_stats_t generate_srs_stats;
|
||||||
@@ -562,7 +563,10 @@ typedef struct PHY_VARS_gNB_s {
|
|||||||
notifiedFIFO_t L1_rx_out;
|
notifiedFIFO_t L1_rx_out;
|
||||||
notifiedFIFO_t resp_RU_tx;
|
notifiedFIFO_t resp_RU_tx;
|
||||||
tpool_t threadPool;
|
tpool_t threadPool;
|
||||||
|
int nbSymb;
|
||||||
|
int nbAarx;
|
||||||
int num_pusch_symbols_per_thread;
|
int num_pusch_symbols_per_thread;
|
||||||
|
int dmrs_num_antennas_per_thread;
|
||||||
pthread_t L1_rx_thread;
|
pthread_t L1_rx_thread;
|
||||||
int L1_rx_thread_core;
|
int L1_rx_thread_core;
|
||||||
pthread_t L1_tx_thread;
|
pthread_t L1_tx_thread;
|
||||||
@@ -585,6 +589,37 @@ union puschSymbolReqUnion {
|
|||||||
uint64_t p;
|
uint64_t p;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef struct puschAntennaProc_s {
|
||||||
|
unsigned char Ns;
|
||||||
|
int nl;
|
||||||
|
unsigned short p;
|
||||||
|
unsigned char symbol;
|
||||||
|
unsigned short bwp_start_subcarrier;
|
||||||
|
int aarx;
|
||||||
|
int beam_nb;
|
||||||
|
int numAntennas;
|
||||||
|
nfapi_nr_pusch_pdu_t *pusch_pdu;
|
||||||
|
int *max_ch;
|
||||||
|
c16_t *pilot;
|
||||||
|
int *nest_count;
|
||||||
|
uint64_t *noise_amp2;
|
||||||
|
delay_t *delay;
|
||||||
|
int chest_freq;
|
||||||
|
NR_gNB_PUSCH *pusch_vars;
|
||||||
|
NR_DL_FRAME_PARMS *frame_parms;
|
||||||
|
c16_t ***rxdataF;
|
||||||
|
} puschAntennaProc_t;
|
||||||
|
|
||||||
|
struct puschAntennaReqId {
|
||||||
|
uint16_t ul_id;
|
||||||
|
uint16_t spare;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
union puschAntennaReqUnion {
|
||||||
|
struct puschAntennaReqId s;
|
||||||
|
uint64_t p;
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct LDPCDecode_s {
|
typedef struct LDPCDecode_s {
|
||||||
PHY_VARS_gNB *gNB;
|
PHY_VARS_gNB *gNB;
|
||||||
NR_UL_gNB_HARQ_t *ulsch_harq;
|
NR_UL_gNB_HARQ_t *ulsch_harq;
|
||||||
|
|||||||
@@ -213,6 +213,7 @@ int main(int argc, char *argv[])
|
|||||||
int params_from_file = 0;
|
int params_from_file = 0;
|
||||||
int threadCnt=0;
|
int threadCnt=0;
|
||||||
int max_ldpc_iterations = 5;
|
int max_ldpc_iterations = 5;
|
||||||
|
int num_antennas_per_thread = 1;
|
||||||
if ((uniqCfg = load_configmodule(argc, argv, CONFIG_ENABLECMDLINEONLY)) == 0) {
|
if ((uniqCfg = load_configmodule(argc, argv, CONFIG_ENABLECMDLINEONLY)) == 0) {
|
||||||
exit_fun("[NR_ULSIM] Error, configuration module init failed\n");
|
exit_fun("[NR_ULSIM] Error, configuration module init failed\n");
|
||||||
}
|
}
|
||||||
@@ -224,7 +225,7 @@ int main(int argc, char *argv[])
|
|||||||
InitSinLUT();
|
InitSinLUT();
|
||||||
|
|
||||||
int c;
|
int c;
|
||||||
while ((c = getopt(argc, argv, "--:O:a:b:c:d:ef:g:h:i:k:m:n:op:q:r:s:t:u:v:w:y:z:C:F:G:H:I:M:N:PR:S:T:U:L:ZW:E:X:")) != -1) {
|
while ((c = getopt(argc, argv, "--:O:a:b:c:d:ef:g:h:i:k:m:n:op:q:r:s:t:u:v:w:y:z:A:C:F:G:H:I:M:N:PR:S:T:U:L:ZW:E:X:")) != -1) {
|
||||||
|
|
||||||
/* ignore long options starting with '--', option '-O' and their arguments that are handled by configmodule */
|
/* ignore long options starting with '--', option '-O' and their arguments that are handled by configmodule */
|
||||||
/* with this opstring getopt returns 1 for non-option arguments, refer to 'man 3 getopt' */
|
/* with this opstring getopt returns 1 for non-option arguments, refer to 'man 3 getopt' */
|
||||||
@@ -395,6 +396,10 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'A':
|
||||||
|
num_antennas_per_thread = atoi(optarg);
|
||||||
|
break;
|
||||||
|
|
||||||
case 'F':
|
case 'F':
|
||||||
input_fd = fopen(optarg, "r");
|
input_fd = fopen(optarg, "r");
|
||||||
if (input_fd == NULL) {
|
if (input_fd == NULL) {
|
||||||
@@ -512,6 +517,7 @@ int main(int argc, char *argv[])
|
|||||||
printf("-w Start PRB for PUSCH\n");
|
printf("-w Start PRB for PUSCH\n");
|
||||||
printf("-y Number of TX antennas used at UE\n");
|
printf("-y Number of TX antennas used at UE\n");
|
||||||
printf("-z Number of RX antennas used at gNB\n");
|
printf("-z Number of RX antennas used at gNB\n");
|
||||||
|
printf("-A Number of antennas per thread for PUSCH channel estimation\n");
|
||||||
printf("-C Specify the number of threads for the simulation\n");
|
printf("-C Specify the number of threads for the simulation\n");
|
||||||
printf("-E {SRS: [0] Disabled, [1] Enabled} e.g. -E 1\n");
|
printf("-E {SRS: [0] Disabled, [1] Enabled} e.g. -E 1\n");
|
||||||
printf("-F Input filename (.txt format) for RX conformance testing\n");
|
printf("-F Input filename (.txt format) for RX conformance testing\n");
|
||||||
@@ -559,6 +565,7 @@ int main(int argc, char *argv[])
|
|||||||
gNB = RC.gNB[0];
|
gNB = RC.gNB[0];
|
||||||
gNB->ofdm_offset_divisor = UINT_MAX;
|
gNB->ofdm_offset_divisor = UINT_MAX;
|
||||||
gNB->num_pusch_symbols_per_thread = 1;
|
gNB->num_pusch_symbols_per_thread = 1;
|
||||||
|
gNB->dmrs_num_antennas_per_thread = num_antennas_per_thread;
|
||||||
gNB->RU_list[0] = calloc(1, sizeof(**gNB->RU_list));
|
gNB->RU_list[0] = calloc(1, sizeof(**gNB->RU_list));
|
||||||
gNB->RU_list[0]->rfdevice.openair0_cfg = openair0_cfg;
|
gNB->RU_list[0]->rfdevice.openair0_cfg = openair0_cfg;
|
||||||
|
|
||||||
@@ -952,6 +959,7 @@ int main(int argc, char *argv[])
|
|||||||
reset_meas(&gNB->rx_pusch_symbol_processing_stats);
|
reset_meas(&gNB->rx_pusch_symbol_processing_stats);
|
||||||
reset_meas(&gNB->ulsch_decoding_stats);
|
reset_meas(&gNB->ulsch_decoding_stats);
|
||||||
reset_meas(&gNB->ulsch_channel_estimation_stats);
|
reset_meas(&gNB->ulsch_channel_estimation_stats);
|
||||||
|
reset_meas(&gNB->pusch_channel_estimation_antenna_processing_stats);
|
||||||
reset_meas(&gNB->rx_srs_stats);
|
reset_meas(&gNB->rx_srs_stats);
|
||||||
reset_meas(&gNB->generate_srs_stats);
|
reset_meas(&gNB->generate_srs_stats);
|
||||||
reset_meas(&gNB->get_srs_signal_stats);
|
reset_meas(&gNB->get_srs_signal_stats);
|
||||||
@@ -1512,6 +1520,7 @@ int main(int argc, char *argv[])
|
|||||||
printDistribution(&gNB->phy_proc_rx,table_rx, "Total PHY proc rx");
|
printDistribution(&gNB->phy_proc_rx,table_rx, "Total PHY proc rx");
|
||||||
printStatIndent(&gNB->rx_pusch_stats, "RX PUSCH time");
|
printStatIndent(&gNB->rx_pusch_stats, "RX PUSCH time");
|
||||||
printStatIndent2(&gNB->ulsch_channel_estimation_stats, "ULSCH channel estimation time");
|
printStatIndent2(&gNB->ulsch_channel_estimation_stats, "ULSCH channel estimation time");
|
||||||
|
printStatIndent3(&gNB->pusch_channel_estimation_antenna_processing_stats, "Antenna Processing time");
|
||||||
printStatIndent2(&gNB->rx_pusch_init_stats, "RX PUSCH Initialization time");
|
printStatIndent2(&gNB->rx_pusch_init_stats, "RX PUSCH Initialization time");
|
||||||
printStatIndent2(&gNB->rx_pusch_symbol_processing_stats, "RX PUSCH Symbol Processing time");
|
printStatIndent2(&gNB->rx_pusch_symbol_processing_stats, "RX PUSCH Symbol Processing time");
|
||||||
printStatIndent(&gNB->ulsch_decoding_stats,"ULSCH total decoding time");
|
printStatIndent(&gNB->ulsch_decoding_stats,"ULSCH total decoding time");
|
||||||
|
|||||||
@@ -59,6 +59,8 @@
|
|||||||
#define HLP_L1TX_BO "Backoff from full-scale output at the L1 entity(frequency domain), ex. 12 would corresponding to 14-bit input level (6 dB/bit). Default 36 dBFS for OAI RU entity"
|
#define HLP_L1TX_BO "Backoff from full-scale output at the L1 entity(frequency domain), ex. 12 would corresponding to 14-bit input level (6 dB/bit). Default 36 dBFS for OAI RU entity"
|
||||||
#define CONFIG_STRING_L1_PHASE_COMP "phase_compensation"
|
#define CONFIG_STRING_L1_PHASE_COMP "phase_compensation"
|
||||||
#define HLP_L1_PHASE_COMP "Apply NR symbolwise phase rotation"
|
#define HLP_L1_PHASE_COMP "Apply NR symbolwise phase rotation"
|
||||||
|
#define CONFIG_STRING_NUM_ANTENNAS_PER_THREAD "dmrs_num_antennas_per_thread"
|
||||||
|
#define HLP_NUM_ARX "Number of antennas per thread for PUSCH channel estimation"
|
||||||
/*----------------------------------------------------------------------------------------------------------------------------------------------------*/
|
/*----------------------------------------------------------------------------------------------------------------------------------------------------*/
|
||||||
/* L1 configuration parameters */
|
/* L1 configuration parameters */
|
||||||
/* optname helpstr paramflags XXXptr defXXXval type numelt */
|
/* optname helpstr paramflags XXXptr defXXXval type numelt */
|
||||||
@@ -84,6 +86,7 @@
|
|||||||
{CONFIG_STRING_L1_TX_THREAD_CORE, NULL, 0, .uptr=NULL, .defintval=-1, TYPE_UINT, 0}, \
|
{CONFIG_STRING_L1_TX_THREAD_CORE, NULL, 0, .uptr=NULL, .defintval=-1, TYPE_UINT, 0}, \
|
||||||
{CONFIG_STRING_L1_TX_AMP_BACKOFF_dB, HLP_L1TX_BO,0, .uptr=NULL, .defintval=36, TYPE_UINT, 0}, \
|
{CONFIG_STRING_L1_TX_AMP_BACKOFF_dB, HLP_L1TX_BO,0, .uptr=NULL, .defintval=36, TYPE_UINT, 0}, \
|
||||||
{CONFIG_STRING_L1_PHASE_COMP, HLP_L1_PHASE_COMP,PARAMFLAG_BOOL, .uptr=NULL,.defintval=1, TYPE_UINT, 0}, \
|
{CONFIG_STRING_L1_PHASE_COMP, HLP_L1_PHASE_COMP,PARAMFLAG_BOOL, .uptr=NULL,.defintval=1, TYPE_UINT, 0}, \
|
||||||
|
{CONFIG_STRING_NUM_ANTENNAS_PER_THREAD, HLP_NUM_ARX,0, .uptr=NULL, .defintval=1, TYPE_UINT, 0}, \
|
||||||
}
|
}
|
||||||
// clang-format on
|
// clang-format on
|
||||||
#define L1_CC_IDX 0
|
#define L1_CC_IDX 0
|
||||||
@@ -105,6 +108,7 @@
|
|||||||
#define L1_TX_THREAD_CORE 16
|
#define L1_TX_THREAD_CORE 16
|
||||||
#define L1_TX_AMP_BACKOFF_dB 17
|
#define L1_TX_AMP_BACKOFF_dB 17
|
||||||
#define L1_PHASE_COMP 18
|
#define L1_PHASE_COMP 18
|
||||||
|
#define NUM_ANTENNAS_PER_THREAD 19
|
||||||
|
|
||||||
/*----------------------------------------------------------------------------------------------------------------------------------------------------*/
|
/*----------------------------------------------------------------------------------------------------------------------------------------------------*/
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -914,6 +914,7 @@ void RCconfig_NR_L1(void)
|
|||||||
LOG_I(NR_PHY, "L1_RX_THREAD_CORE %d (%d)\n", *(L1_ParamList.paramarray[j][L1_RX_THREAD_CORE].iptr), L1_RX_THREAD_CORE);
|
LOG_I(NR_PHY, "L1_RX_THREAD_CORE %d (%d)\n", *(L1_ParamList.paramarray[j][L1_RX_THREAD_CORE].iptr), L1_RX_THREAD_CORE);
|
||||||
gNB->TX_AMP = (int16_t)(32767.0 / pow(10.0, .05 * (double)(*L1_ParamList.paramarray[j][L1_TX_AMP_BACKOFF_dB].uptr)));
|
gNB->TX_AMP = (int16_t)(32767.0 / pow(10.0, .05 * (double)(*L1_ParamList.paramarray[j][L1_TX_AMP_BACKOFF_dB].uptr)));
|
||||||
gNB->phase_comp = *L1_ParamList.paramarray[j][L1_PHASE_COMP].uptr;
|
gNB->phase_comp = *L1_ParamList.paramarray[j][L1_PHASE_COMP].uptr;
|
||||||
|
gNB->dmrs_num_antennas_per_thread = *(L1_ParamList.paramarray[j][NUM_ANTENNAS_PER_THREAD].uptr);
|
||||||
LOG_I(NR_PHY, "TX_AMP = %d (-%d dBFS)\n", gNB->TX_AMP, *L1_ParamList.paramarray[j][L1_TX_AMP_BACKOFF_dB].uptr);
|
LOG_I(NR_PHY, "TX_AMP = %d (-%d dBFS)\n", gNB->TX_AMP, *L1_ParamList.paramarray[j][L1_TX_AMP_BACKOFF_dB].uptr);
|
||||||
AssertFatal(gNB->TX_AMP > 300, "TX_AMP is too small, must be larger than 300 (is %d)\n", gNB->TX_AMP);
|
AssertFatal(gNB->TX_AMP > 300, "TX_AMP is too small, must be larger than 300 (is %d)\n", gNB->TX_AMP);
|
||||||
// Midhaul configuration
|
// Midhaul configuration
|
||||||
|
|||||||
Reference in New Issue
Block a user