diff --git a/CMakeLists.txt b/CMakeLists.txt index 4d76434190..5ce23ce926 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1513,6 +1513,7 @@ set (MAC_NR_SRC_UE ${NR_UE_MAC_DIR}/nr_ue_scheduler.c ${NR_UE_MAC_DIR}/nr_ue_dci_configuration.c ${NR_UE_MAC_DIR}/nr_ra_procedures.c + ${NR_UE_MAC_DIR}/nr_ue_power_procedures.c ) set (ENB_APP_SRC diff --git a/common/utils/nr/nr_common.c b/common/utils/nr/nr_common.c index ca9d735fca..25586abe82 100644 --- a/common/utils/nr/nr_common.c +++ b/common/utils/nr/nr_common.c @@ -36,20 +36,20 @@ const char *duplex_mode[]={"FDD","TDD"}; -int tables_5_3_2[5][11] = { - {25, 52, 79, 106, 133, 160, 216, 270, -1, -1, -1}, // 15 FR1 - {11, 24, 38, 51, 65, 78, 106, 133, 162, 217, 273}, // 30 FR1 - {-1, 11, 18, 24, 31, 38, 51, 65, 79, 107, 135}, // 60 FR1 - {66, 132, 264, -1 , -1, -1, -1, -1, -1, -1, -1}, // 60 FR2 - {32, 66, 132, 264, -1, -1, -1, -1, -1, -1, -1} // 120FR2 +int tables_5_3_2[5][12] = { + {25, 52, 79, 106, 133, 160, 216, 270, -1, -1, -1, -1}, // 15 FR1 + {11, 24, 38, 51, 65, 78, 106, 133, 162, 217, 245, 273},// 30 FR1 + {-1, 11, 18, 24, 31, 38, 51, 65, 79, 107, 121, 135}, // 60 FR1 + {66, 132, 264, -1 , -1, -1, -1, -1, -1, -1, -1, -1}, // 60 FR2 + {32, 66, 132, 264, -1, -1, -1, -1, -1, -1, -1, -1} // 120FR2 }; -int get_supported_band_index(int scs, int band, int n_rbs){ - +int get_supported_band_index(int scs, int band, int n_rbs) +{ int scs_index = scs; - if (band>256) + if (band > 256) scs_index++; - for (int i=0; i<11; i++) { + for (int i = 0; i < 11; i++) { if(n_rbs == tables_5_3_2[scs][i]) return i; } @@ -130,6 +130,66 @@ const nr_bandentry_t nr_bandtable[] = { {261,27500040,28350000,27500040,28350000, 2,2070833, 120} }; +int get_supported_bw_khz(frequency_range_t frequency_range, int bw_index) +{ + if (frequency_range == FR1) { + switch (bw_index) { + case 0 : + return 5000; // 5MHz + case 1 : + return 10000; + case 2 : + return 15000; + case 3 : + return 20000; + case 4 : + return 25000; + case 5 : + return 30000; + case 6 : + return 40000; + case 7 : + return 50000; + case 8 : + return 60000; + case 9 : + return 80000; + case 10 : + return 90000; + case 11 : + return 100000; + default : + AssertFatal(false, "Invalid band index for FR1 %d\n", bw_index); + } + } + else { + switch (bw_index) { + case 0 : + return 50000; // 50MHz + case 1 : + return 100000; + case 2 : + return 200000; + case 3 : + return 400000; + default : + AssertFatal(false, "Invalid band index for FR2 %d\n", bw_index); + } + } +} + +bool compare_relative_ul_channel_bw(int nr_band, int scs, int nb_ul, frame_type_t frame_type) +{ + // 38.101-1 section 6.2.2 + // Relative channel bandwidth <= 4% for TDD bands and <= 3% for FDD bands + int index = get_nr_table_idx(nr_band, scs); + int bw_index = get_supported_band_index(scs, nr_band, nb_ul); + int band_size_khz = get_supported_bw_khz(nr_band > 256 ? FR2 : FR1, bw_index); + float limit = frame_type == TDD ? 0.04 : 0.03; + float rel_bw = (float) (2 * band_size_khz) / (float) (nr_bandtable[index].ul_max + nr_bandtable[index].ul_min); + return rel_bw <= limit; +} + uint16_t get_band(uint64_t downlink_frequency, int32_t delta_duplex) { const int64_t dl_freq_khz = downlink_frequency / 1000; diff --git a/common/utils/nr/nr_common.h b/common/utils/nr/nr_common.h index fc3e5c3fa4..9c3ba88be2 100644 --- a/common/utils/nr/nr_common.h +++ b/common/utils/nr/nr_common.h @@ -93,6 +93,7 @@ int get_nb_periods_per_frame(uint8_t tdd_period); int get_supported_band_index(int scs, int band, int n_rbs); long rrc_get_max_nr_csrs(const int max_rbs, long b_SRS); void get_K1_K2(int N1, int N2, int *K1, int *K2); +bool compare_relative_ul_channel_bw(int nr_band, int scs, int nb_ul, frame_type_t frame_type); void get_samplerate_and_bw(int mu, int n_rb, int8_t threequarter_fs, diff --git a/openair2/LAYER2/NR_MAC_UE/config_ue.c b/openair2/LAYER2/NR_MAC_UE/config_ue.c index 8dfc05952d..43194b324f 100644 --- a/openair2/LAYER2/NR_MAC_UE/config_ue.c +++ b/openair2/LAYER2/NR_MAC_UE/config_ue.c @@ -174,7 +174,6 @@ void config_common_ue_sa(NR_UE_MAC_INST_t *mac, } } - mac->nr_band = *scc->downlinkConfigCommon.frequencyInfoDL.frequencyBandList.list.array[0]->freqBandIndicatorNR; mac->frame_type = get_frame_type(mac->nr_band, get_softmodem_params()->numerology); // cell config @@ -261,8 +260,8 @@ void config_common_ue_sa(NR_UE_MAC_INST_t *mac, void config_common_ue(NR_UE_MAC_INST_t *mac, module_id_t module_id, - int cc_idP) { - + int cc_idP) +{ fapi_nr_config_request_t *cfg = &mac->phy_config.config_req; NR_ServingCellConfigCommon_t *scc = mac->scc; int i; @@ -717,7 +716,7 @@ int nr_rrc_mac_config_req_ue(module_id_t module_id, if (sccP != NULL) { mac->scc_SIB = sccP; - LOG_D(NR_MAC, "In %s: Keeping ServingCellConfigCommonSIB\n", __FUNCTION__); + mac->nr_band = *sccP->downlinkConfigCommon.frequencyInfoDL.frequencyBandList.list.array[0]->freqBandIndicatorNR; config_common_ue_sa(mac, module_id, cc_idP); configure_current_BWP(mac, sccP, NULL); @@ -758,6 +757,7 @@ int nr_rrc_mac_config_req_ue(module_id_t module_id, ra->rach_ConfigDedicated = scell_group_config->spCellConfig->reconfigurationWithSync->rach_ConfigDedicated->choice.uplink; } mac->scc = scell_group_config->spCellConfig->reconfigurationWithSync->spCellConfigCommon; + mac->nr_band = *mac->scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.array[0]; mac->physCellId = *mac->scc->physCellId; config_common_ue(mac,module_id,cc_idP); mac->crnti = scell_group_config->spCellConfig->reconfigurationWithSync->newUE_Identity; @@ -793,6 +793,7 @@ int nr_rrc_mac_config_req_ue(module_id_t module_id, ra->rach_ConfigDedicated = cell_group_config->spCellConfig->reconfigurationWithSync->rach_ConfigDedicated->choice.uplink; } mac->scc = cell_group_config->spCellConfig->reconfigurationWithSync->spCellConfigCommon; + mac->nr_band = *mac->scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.array[0]; if (mac->scc_SIB) { free(mac->scc_SIB); mac->scc_SIB = NULL; diff --git a/openair2/LAYER2/NR_MAC_UE/mac_proto.h b/openair2/LAYER2/NR_MAC_UE/mac_proto.h index eb6f9c185a..867f44e640 100644 --- a/openair2/LAYER2/NR_MAC_UE/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_proto.h @@ -307,6 +307,8 @@ void nr_ue_configure_pucch(NR_UE_MAC_INST_t *mac, PUCCH_sched_t *pucch, fapi_nr_ul_config_pucch_pdu *pucch_pdu); +int nr_get_Pcmax(NR_UE_MAC_INST_t *mac, int Qm, bool powerBoostPi2BPSK, int scs, int N_RB_UL, bool is_transform_precoding, int n_prbs, int start_prb); + /* Random Access */ /* \brief This function schedules the PRACH according to prach_ConfigurationIndex and TS 38.211 tables 6.3.3.2.x diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c index cfc8be87c9..60c3fbd485 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c @@ -40,93 +40,13 @@ #include -// Implementation of 6.2.4 Configured ransmitted power -// 3GPP TS 38.101-1 version 16.5.0 Release 16 -// - -// The UE is allowed to set its configured maximum output power PCMAX,f,c for carrier f of serving cell c in each slot. -// The configured maximum output power PCMAX,f,c is set within the following bounds: PCMAX_L,f,c <= PCMAX,f,c <= PCMAX_H,f,c -// - -// Measurement units: -// - p_max: dBm -// - delta_TC_c: dB -// - P_powerclass: dBm -// - delta_P_powerclass: dB -// - MPR_c: dB -// - delta_MPR_c: dB -// - delta_T_IB_c dB -// - delta_rx_SRS dB -// note: -// - Assuming: -// -- Powerclass 3 capable UE (which is default power class unless otherwise stated) -// -- Maximum power reduction (MPR_c) for power class 3, QPSK, inner RB allocations -// -- no additional MPR (A_MPR_c) -// todo: -// - in current implementation delta_P_powerclass is not handling power classes different from 3 -long nr_get_Pcmax(module_id_t mod_id){ - - NR_UE_MAC_INST_t *mac = get_mac_inst(mod_id); - uint32_t band = (mac->scc!=NULL) ? *mac->scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.array[0] : - *mac->scc_SIB->downlinkConfigCommon.frequencyInfoDL.frequencyBandList.list.array[0]->freqBandIndicatorNR; - NR_P_Max_t p_max = 0; - uint8_t P_powerclass = 23; - uint8_t delta_P_powerclass = 0; - uint8_t MPR_c = 1; - uint8_t delta_MPR_c = 0; - uint8_t A_MPR_c = 0; - uint8_t delta_T_IB_c = 0; - uint8_t delta_TC_c = 0; - uint8_t delta_rx_SRS = 0; - uint8_t P_MPR_c = 0; - long P_cmax_l = 0; - long P_cmax_h = 0; - long P_cmax = 0; - - if (band == 28 && mac->phy_config.config_req.carrier_config.uplink_bandwidth == 30){ - delta_MPR_c = 1; - } - - if (mac->cg && mac->cg->spCellConfig->spCellConfigDedicated->uplinkConfig->ext1){ - if (*mac->cg->spCellConfig->spCellConfigDedicated->uplinkConfig->ext1->powerBoostPi2BPSK == 1){ - // TbD: assuming power class 3 capable UE operating in TDD bands n40, n41, n77, n78, and n79 with Pi/2 BPSK modulation - delta_P_powerclass = -3; - p_max += 3; - } - } - - NR_P_Max_t *p_Max = (mac->scc!=NULL) ? mac->scc->uplinkConfigCommon->frequencyInfoUL->p_Max : mac->scc_SIB->uplinkConfigCommon->frequencyInfoUL.p_Max; - if (p_Max){ - - p_max += *p_Max; - - LOG_D(MAC, "In %s maximum UL transmission power p_max is %ld dBm \n", __FUNCTION__, p_max); - - P_cmax_l = min(p_max - delta_TC_c, (P_powerclass - delta_P_powerclass) - max(max(MPR_c + delta_MPR_c, A_MPR_c) + delta_T_IB_c + delta_TC_c + delta_rx_SRS, P_MPR_c)); - - P_cmax_h = min(p_max, P_powerclass - delta_P_powerclass); - - } else { - - P_cmax_l = (P_powerclass - delta_P_powerclass) - max(max(MPR_c + delta_MPR_c, A_MPR_c) + delta_T_IB_c + delta_TC_c + delta_rx_SRS, P_MPR_c); - - P_cmax_h = P_powerclass - delta_P_powerclass; - - } - - P_cmax = (P_cmax_h + P_cmax_l) / 2; - - LOG_D(MAC, "In %s configured maximum output power: %ld dBm <= PCMAX %ld dBm <= %ld dBm \n", __FUNCTION__, P_cmax_l, P_cmax, P_cmax_h); - - return P_cmax; - -} - int16_t get_prach_tx_power(module_id_t mod_id) { NR_UE_MAC_INST_t *mac = get_mac_inst(mod_id); RA_config_t *ra = &mac->ra; int16_t pathloss = compute_nr_SSB_PL(mac, mac->ssb_measurements.ssb_rsrp_dBm); int16_t ra_preamble_rx_power = (int16_t)(ra->prach_resources.ra_PREAMBLE_RECEIVED_TARGET_POWER - pathloss + 30); - return min(nr_get_Pcmax(mod_id), ra_preamble_rx_power); + return min(ra->prach_resources.RA_PCMAX, ra_preamble_rx_power); } @@ -153,7 +73,13 @@ void init_RA(module_id_t mod_id, ra->RA_backoff_cnt = 0; prach_resources->RA_PREAMBLE_BACKOFF = 0; - prach_resources->RA_PCMAX = nr_get_Pcmax(mod_id); + NR_SubcarrierSpacing_t prach_scs = *nr_rach_ConfigCommon->msg1_SubcarrierSpacing; + int n_prbs = get_N_RA_RB (prach_scs, mac->current_UL_BWP.scs); + int start_prb = rach_ConfigGeneric->msg1_FrequencyStart + mac->current_UL_BWP.BWPStart; + int carrier_bandwidth = mac->scc_SIB ? mac->scc_SIB->uplinkConfigCommon->frequencyInfoUL.scs_SpecificCarrierList.list.array[0]->carrierBandwidth : + mac->scc->uplinkConfigCommon->frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth; + // PRACH shall be as specified for QPSK modulated DFT-s-OFDM of equivalent RB allocation (38.101-1) + prach_resources->RA_PCMAX = nr_get_Pcmax(mac, 2, false, prach_scs, carrier_bandwidth, true, n_prbs, start_prb); prach_resources->RA_PREAMBLE_TRANSMISSION_COUNTER = 1; prach_resources->RA_PREAMBLE_POWER_RAMPING_COUNTER = 1; prach_resources->POWER_OFFSET_2STEP_RA = 0; diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_power_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_power_procedures.c new file mode 100644 index 0000000000..21c726336e --- /dev/null +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_power_procedures.c @@ -0,0 +1,159 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/*! \file ra_procedures.c + * \brief Routines for UE MAC-layer power control procedures + * \author Francesco Mani + * \date 2023 + * \version 0.1 + * \email: email@francescomani.it + * \note + * \warning + */ + +#include "LAYER2/NR_MAC_UE/mac_proto.h" + +// Implementation of 6.2.4 Configured ransmitted power +// 3GPP TS 38.101-1 version 16.5.0 Release 16 +// - +// The UE is allowed to set its configured maximum output power PCMAX,f,c for carrier f of serving cell c in each slot. +// The configured maximum output power PCMAX,f,c is set within the following bounds: PCMAX_L,f,c <= PCMAX,f,c <= PCMAX_H,f,c +// - +// Measurement units: +// - p_max: dBm +// - delta_TC_c: dB +// - P_powerclass: dBm +// - delta_P_powerclass: dB +// - MPR_c: dB +// - delta_MPR_c: dB +// - delta_T_IB_c dB +// - delta_rx_SRS dB +// note: +// - Assuming: +// -- Powerclass 3 capable UE (which is default power class unless otherwise stated) +// -- Maximum power reduction (MPR_c) for power class 3 +// -- no additional MPR (A_MPR_c) +int nr_get_Pcmax(NR_UE_MAC_INST_t *mac, int Qm, bool powerBoostPi2BPSK, int scs, int N_RB_UL, bool is_transform_precoding, int n_prbs, int start_prb) +{ + int nr_band = mac->nr_band; + if(mac->frequency_range == FR1) { + + //TODO configure P-MAX from the upper layers according to 38.331 + long *p_emax = (mac->scc!=NULL) ? mac->scc->uplinkConfigCommon->frequencyInfoUL->p_Max : mac->scc_SIB->uplinkConfigCommon->frequencyInfoUL.p_Max; + int p_powerclass = 23; // dBm assuming poweclass 3 UE + + int delta_P_powerclass = 0; // for powerclass 2 needs to be changed + if(p_emax && Qm == 1 && powerBoostPi2BPSK && (nr_band == 40 || nr_band == 41 || nr_band == 77 || nr_band == 78 || nr_band == 79)) { + *p_emax += 3; + delta_P_powerclass -= 3; + } + + // TODO to be set for CA and DC + int delta_T_IB = 0; + + // TODO in case of band 41 and PRB allocation within 4MHz of the upper or lower limit of the band -> delta_TC = 1.5 + if(nr_band == 41) + LOG_E(NR_MAC, "Need to implement delta_TC for band 41\n"); + int delta_TC = 0; + + float MPR = 0; + frame_type_t frame_type = get_frame_type(nr_band, scs); + if(compare_relative_ul_channel_bw(nr_band, scs, N_RB_UL, frame_type)) { + int rb_low = (n_prbs / 2) > 1 ? (n_prbs / 2) : 1; + int rb_high = N_RB_UL - rb_low - n_prbs; + bool is_inner_rb = start_prb >= rb_low && start_prb <= rb_high && n_prbs <= ((N_RB_UL / 2) + (N_RB_UL & 1)); + // Table 6.2.2-1 in 38.101 + switch (Qm) { + case 1 : + AssertFatal(false, "MPR for Pi/2 BPSK not implemented yet\n"); + break; + case 2 : + if (is_transform_precoding) { + if(!is_inner_rb) + MPR = 1; + } + else { + if(is_inner_rb) + MPR = 1.5; + else + MPR = 3; + } + break; + case 4 : + if (is_transform_precoding) { + if(is_inner_rb) + MPR = 1; + else + MPR = 2; + } + else { + if(is_inner_rb) + MPR = 2; + else + MPR = 3; + } + break; + case 6 : + if (is_transform_precoding) + MPR = 2.5; + else + MPR = 3.5; + break; + case 8 : + if (is_transform_precoding) + MPR = 4.5; + else + MPR = 6.5; + break; + break; + default: + AssertFatal(false, "Invalid Qm %d\n", Qm); + } + } + + int A_MPR = 0; // TODO too complicated to implement for now (see 6.2.3 in 38.101-1) + int delta_rx_SRS = 0; // TODO for SRS + int P_MPR = 0; // to ensure compliance with applicable electromagnetic energy absorption requirements + + float total_reduction = (MPR > A_MPR ? MPR : A_MPR) + delta_T_IB + delta_TC + delta_rx_SRS; + if (P_MPR > total_reduction) + total_reduction = P_MPR; + int pcmax_high, pcmax_low; + if(p_emax) { + pcmax_high = *p_emax < (p_powerclass - delta_P_powerclass) ? *p_emax : (p_powerclass - delta_P_powerclass); + pcmax_low = (*p_emax - delta_TC) < (p_powerclass - delta_P_powerclass - total_reduction) ? + (*p_emax - delta_TC) : (p_powerclass - delta_P_powerclass - total_reduction); + } + else { + pcmax_high = p_powerclass - delta_P_powerclass; + pcmax_low = p_powerclass - delta_P_powerclass - total_reduction; + } + // TODO we need a strategy to select a value between minimum and maximum allowed PC_max + int pcmax = (pcmax_low + pcmax_high) / 2; + LOG_D(MAC, "Configured maximum output power: %d dBm <= PCMAX %d dBm <= %d dBm \n", pcmax_low, pcmax, pcmax_high); + return pcmax; + } + else { + // FR2 TODO it is even more complex because it is radiated power + return 23; + } +} + diff --git a/openair2/RRC/NR/nr_rrc_config.c b/openair2/RRC/NR/nr_rrc_config.c index 3e506b964c..49115023dc 100644 --- a/openair2/RRC/NR/nr_rrc_config.c +++ b/openair2/RRC/NR/nr_rrc_config.c @@ -998,8 +998,6 @@ void set_dl_mcs_table(int scs, } } AssertFatal(bw_rb>0,"Could not find scs-SpecificCarrierList element for scs %d",scs); - int bw = get_supported_band_index(scs, band, bw_rb); - AssertFatal(bw>=0,"Supported band corresponding to %d RBs not found\n", bw_rb); bool supported = false; if (band>256) {