TPMI computation for single-layer transmission using two antenna ports

This commit is contained in:
Roberto Louro Magueta
2022-06-21 21:12:01 +01:00
parent 4a8cc3490c
commit a51e8332cf
3 changed files with 322 additions and 2 deletions
@@ -312,6 +312,16 @@ const uint8_t table_5_1_2_1_1_5_time_dom_res_alloc_C_dmrs_typeA_pos3[16][4]={
{1,0,2,6} // row index 16
};
// TS 38.211 - Table 6.3.1.5-1: Precoding matrix W for single-layer transmission using two antenna ports, 'n' = -1 and 'o' = -j
const char table_38211_6_3_1_5_1[6][2][1] = {
{{'1'}, {'0'}},//pmi 0
{{'0'}, {'1'}},
{{'1'}, {'1'}},
{{'1'}, {'n'}},
{{'1'}, {'j'}},
{{'1'}, {'o'}} //pmi 5
};
void get_info_from_tda_tables(int default_abc,
int tda,
int dmrs_TypeA_Position,
@@ -143,4 +143,5 @@ extern const float table_38213_13_12_c3[16];
extern const int32_t table_38213_10_1_1_c2[5];
extern const char table_38211_6_3_1_5_1[6][2][1];
#endif //DEF_H
@@ -764,6 +764,308 @@ void nr_rx_sdu(const module_id_t gnb_mod_idP,
}
}
uint32_t calc_power_complex(const int16_t *x, const int16_t *y, const uint32_t size) {
// Real part value
int64_t sum_x = 0;
int64_t sum_x2 = 0;
for(int k = 0; k<size; k++) {
sum_x = sum_x + x[k];
sum_x2 = sum_x2 + x[k]*x[k];
}
uint32_t power_re = sum_x2/size - (sum_x/size)*(sum_x/size);
// Imaginary part power
int64_t sum_y = 0;
int64_t sum_y2 = 0;
for(int k = 0; k<size; k++) {
sum_y = sum_y + y[k];
sum_y2 = sum_y2 + y[k]*y[k];
}
uint32_t power_im = sum_y2/size - (sum_y/size)*(sum_y/size);
return power_re+power_im;
}
c16_t nr_h_times_w(c16_t h, char w) {
c16_t output;
switch (w) {
case '0': // 0
output.r = 0;
output.i = 0;
break;
case '1': // 1
output.r = h.r;
output.i = h.i;
break;
case 'n': // -1
output.r = -h.r;
output.i = -h.i;
break;
case 'j': // j
output.r = -h.i;
output.i = h.r;
break;
case 'o': // -j
output.r = h.i;
output.i = -h.r;
break;
default:
AssertFatal(1==0,"Invalid precoder value %c\n", w);
}
return output;
}
uint8_t get_max_tpmi(const NR_PUSCH_Config_t *pusch_Config,
const uint16_t num_ue_srs_ports,
const uint8_t *nrOfLayers,
int *additional_max_tpmi) {
uint8_t max_tpmi = 0;
if ((pusch_Config && pusch_Config->txConfig != NULL && *pusch_Config->txConfig == NR_PUSCH_Config__txConfig_nonCodebook) ||
num_ue_srs_ports == 1) {
return max_tpmi;
}
long max_rank = *pusch_Config->maxRank;
long *ul_FullPowerTransmission = pusch_Config->ext1 ? pusch_Config->ext1->ul_FullPowerTransmission_r16 : NULL;
long *codebookSubset = pusch_Config->codebookSubset;
if (num_ue_srs_ports == 2) {
if (max_rank == 1) {
if (ul_FullPowerTransmission && *ul_FullPowerTransmission == NR_PUSCH_Config__ext1__ul_FullPowerTransmission_r16_fullpowerMode1) {
max_tpmi = 2;
} else {
if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) {
max_tpmi = 1;
} else {
max_tpmi = 5;
}
}
} else {
if (ul_FullPowerTransmission && *ul_FullPowerTransmission == NR_PUSCH_Config__ext1__ul_FullPowerTransmission_r16_fullpowerMode1) {
max_tpmi = *nrOfLayers == 1 ? 2 : 0;
} else {
if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) {
max_tpmi = *nrOfLayers == 1 ? 1 : 0;
} else {
max_tpmi = *nrOfLayers == 1 ? 5 : 2;
}
}
}
} else if (num_ue_srs_ports == 4) {
if (max_rank == 1) {
if (ul_FullPowerTransmission && *ul_FullPowerTransmission == NR_PUSCH_Config__ext1__ul_FullPowerTransmission_r16_fullpowerMode1) {
if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) {
max_tpmi = 3;
*additional_max_tpmi = 13;
} else {
max_tpmi = 15;
}
} else {
if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) {
max_tpmi = 3;
} else if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_partialAndNonCoherent) {
max_tpmi = 11;
} else {
max_tpmi = 27;
}
}
} else {
if (ul_FullPowerTransmission && *ul_FullPowerTransmission == NR_PUSCH_Config__ext1__ul_FullPowerTransmission_r16_fullpowerMode1) {
if (max_rank == 2) {
if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) {
max_tpmi = *nrOfLayers == 1 ? 3 : 6;
if (*nrOfLayers == 1) {
*additional_max_tpmi = 13;
}
} else {
max_tpmi = *nrOfLayers == 1 ? 15 : 13;
}
} else {
if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) {
switch (*nrOfLayers) {
case 1:
max_tpmi = 3;
*additional_max_tpmi = 13;
break;
case 2:
max_tpmi = 6;
break;
case 3:
max_tpmi = 1;
break;
case 4:
max_tpmi = 0;
break;
default:
LOG_E(NR_MAC,"Number of layers %d is invalid!\n", *nrOfLayers);
}
} else {
switch (*nrOfLayers) {
case 1:
max_tpmi = 15;
break;
case 2:
max_tpmi = 13;
break;
case 3:
case 4:
max_tpmi = 2;
break;
default:
LOG_E(NR_MAC,"Number of layers %d is invalid!\n", *nrOfLayers);
}
}
}
} else {
if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) {
switch (*nrOfLayers) {
case 1:
max_tpmi = 3;
break;
case 2:
max_tpmi = 5;
break;
case 3:
case 4:
max_tpmi = 0;
break;
default:
LOG_E(NR_MAC,"Number of layers %d is invalid!\n", *nrOfLayers);
}
} else if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_partialAndNonCoherent) {
switch (*nrOfLayers) {
case 1:
max_tpmi = 11;
break;
case 2:
max_tpmi = 13;
break;
case 3:
case 4:
max_tpmi = 2;
break;
default:
LOG_E(NR_MAC,"Number of layers %d is invalid!\n", *nrOfLayers);
}
} else {
switch (*nrOfLayers) {
case 1:
max_tpmi = 28;
break;
case 2:
max_tpmi = 22;
break;
case 3:
max_tpmi = 7;
break;
case 4:
max_tpmi = 5;
break;
default:
LOG_E(NR_MAC,"Number of layers %d is invalid!\n", *nrOfLayers);
}
}
}
}
}
return max_tpmi;
}
void get_precoder_matrix_coef(char *w, uint8_t tpmi, uint8_t uI) {
// TODO: Add the remaining tables
*w = *table_38211_6_3_1_5_1[tpmi][uI];
}
int nr_srs_tpmi_estimation(const NR_PUSCH_Config_t *pusch_Config,
const uint8_t *channel_matrix,
const uint8_t normalized_iq_representation,
const uint16_t num_gnb_antenna_elements,
const uint16_t num_ue_srs_ports,
const uint16_t prg_size,
const uint16_t num_prgs,
const uint8_t ul_ri) {
uint8_t tpmi_sel = 0;
int16_t precoded_channel_matrix_re[num_prgs*num_gnb_antenna_elements];
int16_t precoded_channel_matrix_im[num_prgs*num_gnb_antenna_elements];
c16_t *channel_matrix16 = (c16_t*)channel_matrix;
uint32_t max_precoded_signal_power = 0;
int additional_max_tpmi = -1;
char w;
uint8_t max_tpmi = get_max_tpmi(pusch_Config,
num_ue_srs_ports,
&ul_ri,
&additional_max_tpmi);
uint8_t end_tpmi_loop = additional_max_tpmi > max_tpmi ? additional_max_tpmi : max_tpmi;
// channel_matrix x precoder_matrix
// [ (gI=0,uI=0) (gI=0,uI=1) ... (gI=0,uI=num_ue_srs_ports-1) ] x [uI=0]
// [ (gI=1,uI=0) (gI=1,uI=1) ... (gI=1,uI=num_ue_srs_ports-1) ] [uI=1]
// [ (gI=2,uI=0) (gI=2,uI=1) ... (gI=2,uI=num_ue_srs_ports-1) ] [uI=2]
// ... ...
for(uint8_t tpmi = 0; tpmi<=end_tpmi_loop; tpmi++) {
if (tpmi > max_tpmi) {
tpmi = end_tpmi_loop;
}
for(int pI = 0; pI <num_prgs; pI++) {
for(int gI = 0; gI < num_gnb_antenna_elements; gI++) {
uint16_t index_gI_pI = gI*num_prgs + pI;
precoded_channel_matrix_re[index_gI_pI] = 0;
precoded_channel_matrix_im[index_gI_pI] = 0;
for(int uI = 0; uI < num_ue_srs_ports; uI++) {
uint16_t index = uI*num_gnb_antenna_elements*num_prgs + index_gI_pI;
get_precoder_matrix_coef(&w, tpmi, uI);
c16_t h_times_w = nr_h_times_w(channel_matrix16[index], w);
precoded_channel_matrix_re[index_gI_pI] += h_times_w.r;
precoded_channel_matrix_im[index_gI_pI] += h_times_w.i;
#ifdef SRS_IND_DEBUG
LOG_I(NR_MAC, "(uI %i, gI %i, pI %i) channel_matrix --> real %i, imag %i\n",
uI, gI, pI, channel_matrix16[index].r, channel_matrix16[index].i);
#endif
}
#ifdef SRS_IND_DEBUG
LOG_I(NR_MAC, "(gI %i, pI %i) precoded_channel_coef --> real %i, imag %i\n",
gI, pI, precoded_channel_matrix_re[index_gI_pI], precoded_channel_matrix_im[index_gI_pI]);
#endif
}
}
uint32_t precoded_signal_power = calc_power_complex(precoded_channel_matrix_re,
precoded_channel_matrix_im,
num_prgs*num_gnb_antenna_elements);
#ifdef SRS_IND_DEBUG
LOG_I(NR_MAC, "(tpmi %i) precoded_signal_power = %i\n", tpmi, precoded_signal_power);
#endif
if (precoded_signal_power > max_precoded_signal_power) {
max_precoded_signal_power = precoded_signal_power;
tpmi_sel = tpmi;
}
}
return tpmi_sel;
}
void handle_nr_srs_measurements(const module_id_t module_id,
const frame_t frame,
const sub_frame_t slot,
@@ -869,8 +1171,15 @@ void handle_nr_srs_measurements(const module_id_t module_id,
NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
NR_pusch_semi_static_t *ps = &sched_ctrl->pusch_semi_static;
ps->srs_feedback.sri = NR_SRS_SRI_0;
ps->srs_feedback.ul_ri = 0;
ps->srs_feedback.tpmi = 0;
ps->srs_feedback.ul_ri = 0; // TODO: Compute this
ps->srs_feedback.tpmi = nr_srs_tpmi_estimation(ps->pusch_Config,
nr_srs_normalized_channel_iq_matrix->channel_matrix,
nr_srs_normalized_channel_iq_matrix->normalized_iq_representation,
nr_srs_normalized_channel_iq_matrix->num_gnb_antenna_elements,
nr_srs_normalized_channel_iq_matrix->num_ue_srs_ports,
nr_srs_normalized_channel_iq_matrix->prg_size,
nr_srs_normalized_channel_iq_matrix->num_prgs,
ps->srs_feedback.ul_ri);
sprintf(stats->srs_stats,"UL-RI %d, TPMI %d", ps->srs_feedback.ul_ri+1, ps->srs_feedback.tpmi);
break;
}