From cd8f076979d6f5942ab5d8a8bcfa9d32b90c5327 Mon Sep 17 00:00:00 2001 From: Bartosz Podrygajlo Date: Tue, 2 Jul 2024 11:53:05 +0200 Subject: [PATCH] PUSCH power control state --- .../nfapi/public_inc/fapi_nr_ue_interface.h | 1 - openair1/SIMULATION/NR_PHY/ulsim.c | 1 - openair2/LAYER2/NR_MAC_UE/mac_defs.h | 2 + openair2/LAYER2/NR_MAC_UE/main_ue_nr.c | 1 + .../LAYER2/NR_MAC_UE/nr_ue_power_procedures.c | 18 ++- openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c | 32 ++-- .../tests/test_nr_ue_power_procedures.cpp | 138 ++++++++++++++++++ 7 files changed, 175 insertions(+), 18 deletions(-) diff --git a/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h b/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h index f76647d6af..0206bfa36c 100644 --- a/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h +++ b/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h @@ -359,7 +359,6 @@ typedef struct //beamforming nfapi_nr_ue_ul_beamforming_t beamforming; //OAI specific - int8_t absolute_delta_PUSCH; int16_t tx_power; fapi_nr_tx_request_body_t tx_request_body; } nfapi_nr_ue_pusch_pdu_t; diff --git a/openair1/SIMULATION/NR_PHY/ulsim.c b/openair1/SIMULATION/NR_PHY/ulsim.c index 822153fd14..d40d1dc71e 100644 --- a/openair1/SIMULATION/NR_PHY/ulsim.c +++ b/openair1/SIMULATION/NR_PHY/ulsim.c @@ -1119,7 +1119,6 @@ int main(int argc, char *argv[]) pusch_config_pdu->num_dmrs_cdm_grps_no_data = num_dmrs_cdm_grps_no_data; pusch_config_pdu->nrOfLayers = precod_nbr_layers; pusch_config_pdu->dmrs_ports = ((1 << precod_nbr_layers) - 1); - pusch_config_pdu->absolute_delta_PUSCH = 0; pusch_config_pdu->target_code_rate = code_rate; pusch_config_pdu->tbslbrm = tbslbrm; pusch_config_pdu->ldpcBaseGraph = get_BG(TBS, code_rate); diff --git a/openair2/LAYER2/NR_MAC_UE/mac_defs.h b/openair2/LAYER2/NR_MAC_UE/mac_defs.h index 5c6b0bd93a..781192fbc2 100644 --- a/openair2/LAYER2/NR_MAC_UE/mac_defs.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_defs.h @@ -593,6 +593,8 @@ typedef struct NR_UE_MAC_INST_s { // PUCCH closed loop power control state int G_b_f_c; bool pucch_power_control_initialized; + int f_b_f_c; + bool pusch_power_control_initialized; } NR_UE_MAC_INST_t; /*@}*/ diff --git a/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c b/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c index 4d8b79a2ab..139d84fe8d 100644 --- a/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c +++ b/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c @@ -84,6 +84,7 @@ void nr_ue_init_mac(NR_UE_MAC_INST_t *mac) memset(&mac->scheduling_info.sr_info[i], 0, sizeof(mac->scheduling_info.sr_info[i])); mac->pucch_power_control_initialized = false; + mac->pusch_power_control_initialized = false; } void nr_ue_mac_default_configs(NR_UE_MAC_INST_t *mac) diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_power_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_power_procedures.c index 02aea8dd4d..cb60f0236c 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_power_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_power_procedures.c @@ -553,12 +553,28 @@ int get_pusch_tx_power_ue(NR_UE_MAC_INST_t *mac, // TODO: compute pathoss using correct reference int16_t pathloss = compute_nr_SSB_PL(mac, mac->ssb_measurements.ssb_rsrp_dBm); + int P_CMIN = nr_get_Pcmin(mac->current_UL_BWP->scs, mac->nr_band, mac->current_UL_BWP->BWPSize); + + float pusch_power_without_f_b_f_c = P_O_PUSCH + M_pusch_component + alpha * pathloss + DELTA_TF; int f_b_f_c = 0; if (has_pusch_power_control_config && pusch_Config->pusch_PowerControl->tpc_Accumulation) { f_b_f_c = delta_pusch; } else { - // TODO: PUSCH power control state + if (!mac->pusch_power_control_initialized && is_rar_tx_retx) { + NR_PRACH_RESOURCES_t* prach_resources = &mac->ra.prach_resources; + float DELTA_P_rampup_requested = (prach_resources->RA_PREAMBLE_POWER_RAMPING_COUNTER - 1) * prach_resources->RA_PREAMBLE_POWER_RAMPING_STEP; + float DELTA_P_rampup = P_CMAX - (P_O_PUSCH + M_pusch_component + alpha * pathloss + DELTA_TF + delta_pusch); + DELTA_P_rampup = min(DELTA_P_rampup_requested, max(0, DELTA_P_rampup)); + mac->f_b_f_c = DELTA_P_rampup + delta_pusch; + mac->pusch_power_control_initialized = true; + } else { + if (!((pusch_power_without_f_b_f_c + mac->f_b_f_c >= P_CMAX && delta_pusch > 0) || + (pusch_power_without_f_b_f_c + mac->f_b_f_c <= P_CMIN && delta_pusch < 0))) { + mac->f_b_f_c += delta_pusch; + } + } + f_b_f_c = mac->f_b_f_c; } LOG_D(NR_MAC, "PUSCH tx power components P_O_PUSCH=%d, M_pusch_component=%d, alpha*pathloss=%f, delta_TF=%f, f_b_f_c=%d\n", diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c index b88ca7e5f3..3824d80cbd 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c @@ -793,20 +793,6 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac, pusch_config_pdu->pusch_data.rv_index = dci->rv; /* HARQ_PROCESS_NUMBER */ pusch_config_pdu->pusch_data.harq_process_id = dci->harq_pid; - /* TPC_PUSCH */ - // according to TS 38.213 Table Table 7.1.1-1 - if (dci->tpc == 0) { - pusch_config_pdu->absolute_delta_PUSCH = -4; - } - if (dci->tpc == 1) { - pusch_config_pdu->absolute_delta_PUSCH = -1; - } - if (dci->tpc == 2) { - pusch_config_pdu->absolute_delta_PUSCH = 1; - } - if (dci->tpc == 3) { - pusch_config_pdu->absolute_delta_PUSCH = 4; - } if (NR_DMRS_ulconfig != NULL) add_pos = (NR_DMRS_ulconfig->dmrs_AdditionalPosition == NULL) ? 2 : *NR_DMRS_ulconfig->dmrs_AdditionalPosition; @@ -913,6 +899,22 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac, pusch_config_pdu->pusch_data.tb_size = mac->ul_harq_info[pid].TBS; } + /* TPC_PUSCH */ + int delta_pusch = 0; + if (dci) { + bool stateless_pusch_power_control = mac->current_UL_BWP->pusch_Config != NULL + && mac->current_UL_BWP->pusch_Config->pusch_PowerControl != NULL + && mac->current_UL_BWP->pusch_Config->pusch_PowerControl->tpc_Accumulation != NULL; + int table_38_213_7_1_1_1[2][4] = {{-1, 0, 1, 3}, {-4, -1, 1, 4}}; + if (stateless_pusch_power_control) { + delta_pusch = table_38_213_7_1_1_1[1][dci->tpc]; + } else { + // TODO: This is not entirely correct. In case there is a prevously scheduled PUSCH for a future slot + // we should apply its TPC now. + delta_pusch = table_38_213_7_1_1_1[0][dci->tpc]; + } + } + bool is_rar_tx_retx = rnti_type == TYPE_TC_RNTI_; pusch_config_pdu->tx_power = get_pusch_tx_power_ue(mac, @@ -925,7 +927,7 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac, pusch_config_pdu->target_code_rate, pusch_config_pdu->pusch_uci.beta_offset_csi1, pusch_config_pdu->pusch_data.tb_size << 3, - pusch_config_pdu->absolute_delta_PUSCH, + delta_pusch, is_rar_tx_retx, pusch_config_pdu->transform_precoding); diff --git a/openair2/LAYER2/NR_MAC_UE/tests/test_nr_ue_power_procedures.cpp b/openair2/LAYER2/NR_MAC_UE/tests/test_nr_ue_power_procedures.cpp index 3f865ec597..c594d43082 100644 --- a/openair2/LAYER2/NR_MAC_UE/tests/test_nr_ue_power_procedures.cpp +++ b/openair2/LAYER2/NR_MAC_UE/tests/test_nr_ue_power_procedures.cpp @@ -198,6 +198,7 @@ TEST(pusch_power_control, pusch_power_control_msg3) NR_PUSCH_PowerControl pusch_PowerControl = {0}; pusch_Config.pusch_PowerControl = &pusch_PowerControl; pusch_PowerControl.tpc_Accumulation = (long*)1; + mac.pusch_power_control_initialized = true; mac.frame_type = TDD; // msg3 cofiguration as in 5g_rfsimulator testcase @@ -358,6 +359,143 @@ TEST(pusch_power_control, pusch_power_data) EXPECT_EQ(power, P_CMAX) << "Expecting max tx power because of deltaMCS with CSI-only"; } +TEST(pusch_power_control, pusch_power_control_state_initialization) +{ + NR_UE_MAC_INST_t mac = {0}; + NR_UE_UL_BWP_t current_UL_BWP = {0}; + current_UL_BWP.scs = 1; + current_UL_BWP.BWPSize = 106; + mac.current_UL_BWP = ¤t_UL_BWP; + NR_RACH_ConfigCommon_t nr_rach_ConfigCommon = {0}; + current_UL_BWP.rach_ConfigCommon = &nr_rach_ConfigCommon; + mac.nr_band = 78; + NR_PUSCH_Config_t pusch_Config = {0}; + current_UL_BWP.pusch_Config = &pusch_Config; + NR_PUSCH_PowerControl pusch_PowerControl = {0}; + pusch_Config.pusch_PowerControl = &pusch_PowerControl; + mac.pusch_power_control_initialized = false; + + // msg3 cofiguration as in 5g_rfsimulator testcase + int num_rb = 8; + int start_prb = 0; + uint16_t nb_symb_sch = 3; + uint16_t nb_dmrs_prb = 12; + uint16_t nb_ptrs_prb = 0; + uint16_t Qm = 2; + uint16_t R = 1570; + uint16_t beta_offset_csi1 = 0; + uint32_t sum_bits_in_codeblocks = 56; + int delta_pusch = 0; + bool is_rar_tx_retx = true; + long preambleReceivedTargetPower = -96; + nr_rach_ConfigCommon.rach_ConfigGeneric.preambleReceivedTargetPower = preambleReceivedTargetPower; + + get_pusch_tx_power_ue(&mac, + num_rb, + start_prb, + nb_symb_sch, + nb_dmrs_prb, + nb_ptrs_prb, + Qm, + R, + beta_offset_csi1, + sum_bits_in_codeblocks, + delta_pusch, + is_rar_tx_retx, + false); + EXPECT_EQ(mac.pusch_power_control_initialized, true); +} + +TEST(pusch_power_control, pusch_power_control_state) +{ + NR_UE_MAC_INST_t mac = {0}; + NR_UE_UL_BWP_t current_UL_BWP = {0}; + current_UL_BWP.scs = 1; + current_UL_BWP.BWPSize = 106; + mac.current_UL_BWP = ¤t_UL_BWP; + NR_RACH_ConfigCommon_t nr_rach_ConfigCommon = {0}; + current_UL_BWP.rach_ConfigCommon = &nr_rach_ConfigCommon; + mac.nr_band = 78; + mac.f_b_f_c = 0; + mac.pusch_power_control_initialized = true; + + bool is_rar_tx_retx = false; + int num_rb = 5; + int start_prb = 0; + uint16_t nb_symb_sch = 3; + uint16_t nb_dmrs_prb = 6; + uint16_t nb_ptrs_prb = 0; + uint16_t Qm = 2; + uint16_t R = 6790; + uint16_t beta_offset_csi1 = 0; + uint32_t sum_bits_in_codeblocks = 192; + int delta_pusch = 1; + bool transform_precoding = false; + NR_PUSCH_Config_t pusch_Config = {0}; + current_UL_BWP.pusch_Config = &pusch_Config; + NR_PUSCH_PowerControl pusch_PowerControl = {0}; + pusch_Config.pusch_PowerControl = &pusch_PowerControl; + long p0_NominalWithGrant = 0; + current_UL_BWP.p0_NominalWithGrant = &p0_NominalWithGrant; + mac.frame_type = TDD; + + int P_CMAX = nr_get_Pcmax(23, mac.nr_band, mac.frame_type, FR1, Qm, false, current_UL_BWP.scs, current_UL_BWP.BWPSize, transform_precoding, num_rb, start_prb); + + int power = get_pusch_tx_power_ue(&mac, + num_rb, + start_prb, + nb_symb_sch, + nb_dmrs_prb, + nb_ptrs_prb, + Qm, + R, + beta_offset_csi1, + sum_bits_in_codeblocks, + delta_pusch, + is_rar_tx_retx, + transform_precoding); + EXPECT_LE(power, P_CMAX); + EXPECT_EQ(power, 11); + for (int i = 0; i < 20; i++) { + int increased_power = get_pusch_tx_power_ue(&mac, + num_rb, + start_prb, + nb_symb_sch, + nb_dmrs_prb, + nb_ptrs_prb, + Qm, + R, + beta_offset_csi1, + sum_bits_in_codeblocks, + delta_pusch, + is_rar_tx_retx, + transform_precoding); + EXPECT_GE(increased_power, power); + EXPECT_LE(increased_power, P_CMAX); + power = increased_power; + } + + delta_pusch = -1; + for (int i = 0; i < 20; i++) { + int reduced_power = get_pusch_tx_power_ue(&mac, + num_rb, + start_prb, + nb_symb_sch, + nb_dmrs_prb, + nb_ptrs_prb, + Qm, + R, + beta_offset_csi1, + sum_bits_in_codeblocks, + delta_pusch, + is_rar_tx_retx, + transform_precoding); + EXPECT_LE(reduced_power, power); + EXPECT_LE(reduced_power, P_CMAX); + power = reduced_power; + } +} + int main(int argc, char** argv) { logInit();