From a51e8332cf859b6ea3f843ba22cb53d947603f96 Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Tue, 21 Jun 2022 21:12:01 +0100 Subject: [PATCH] TPMI computation for single-layer transmission using two antenna ports --- openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c | 10 + openair2/LAYER2/NR_MAC_COMMON/nr_mac_extern.h | 1 + .../LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 313 +++++++++++++++++- 3 files changed, 322 insertions(+), 2 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c index f5606b32e6..7343b900fa 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c @@ -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, diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_extern.h b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_extern.h index 4b37c19dff..4829ee15d8 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_extern.h +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_extern.h @@ -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 diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index 3a6c278adb..8c72aa4c97 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -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; ktxConfig != 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 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; }