TPMI computation for single-layer transmission using two antenna ports
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user