diff --git a/common/utils/nr/nr_common.c b/common/utils/nr/nr_common.c index fafc1bcd47..09dd5e7d94 100644 --- a/common/utils/nr/nr_common.c +++ b/common/utils/nr/nr_common.c @@ -36,6 +36,79 @@ #include "nr_common.h" #include +#define C_SRS_NUMBER (64) +#define B_SRS_NUMBER (4) + +/* TS 38.211 Table 6.4.1.4.3-1: SRS bandwidth configuration */ +static const unsigned short srs_bandwidth_config[C_SRS_NUMBER][B_SRS_NUMBER][2] = { + /* B_SRS = 0 B_SRS = 1 B_SRS = 2 B_SRS = 3 */ + /* C SRS m_srs0 N_0 m_srs1 N_1 m_srs2 N_2 m_srs3 N_3 */ + /* 0 */ {{4, 1}, {4, 1}, {4, 1}, {4, 1}}, + /* 1 */ {{8, 1}, {4, 2}, {4, 1}, {4, 1}}, + /* 2 */ {{12, 1}, {4, 3}, {4, 1}, {4, 1}}, + /* 3 */ {{16, 1}, {4, 4}, {4, 1}, {4, 1}}, + /* 4 */ {{16, 1}, {8, 2}, {4, 2}, {4, 1}}, + /* 5 */ {{20, 1}, {4, 5}, {4, 1}, {4, 1}}, + /* 6 */ {{24, 1}, {4, 6}, {4, 1}, {4, 1}}, + /* 7 */ {{24, 1}, {12, 2}, {4, 3}, {4, 1}}, + /* 8 */ {{28, 1}, {4, 7}, {4, 1}, {4, 1}}, + /* 9 */ {{32, 1}, {16, 2}, {8, 2}, {4, 2}}, + /* 10 */ {{36, 1}, {12, 3}, {4, 3}, {4, 1}}, + /* 11 */ {{40, 1}, {20, 2}, {4, 5}, {4, 1}}, + /* 12 */ {{48, 1}, {16, 3}, {8, 2}, {4, 2}}, + /* 13 */ {{48, 1}, {24, 2}, {12, 2}, {4, 3}}, + /* 14 */ {{52, 1}, {4, 13}, {4, 1}, {4, 1}}, + /* 15 */ {{56, 1}, {28, 2}, {4, 7}, {4, 1}}, + /* 16 */ {{60, 1}, {20, 3}, {4, 5}, {4, 1}}, + /* 17 */ {{64, 1}, {32, 2}, {16, 2}, {4, 4}}, + /* 18 */ {{72, 1}, {24, 3}, {12, 2}, {4, 3}}, + /* 19 */ {{72, 1}, {36, 2}, {12, 3}, {4, 3}}, + /* 20 */ {{76, 1}, {4, 19}, {4, 1}, {4, 1}}, + /* 21 */ {{80, 1}, {40, 2}, {20, 2}, {4, 5}}, + /* 22 */ {{88, 1}, {44, 2}, {4, 11}, {4, 1}}, + /* 23 */ {{96, 1}, {32, 3}, {16, 2}, {4, 4}}, + /* 24 */ {{96, 1}, {48, 2}, {24, 2}, {4, 6}}, + /* 25 */ {{104, 1}, {52, 2}, {4, 13}, {4, 1}}, + /* 26 */ {{112, 1}, {56, 2}, {28, 2}, {4, 7}}, + /* 27 */ {{120, 1}, {60, 2}, {20, 3}, {4, 5}}, + /* 28 */ {{120, 1}, {40, 3}, {8, 5}, {4, 2}}, + /* 29 */ {{120, 1}, {24, 5}, {12, 2}, {4, 3}}, + /* 30 */ {{128, 1}, {64, 2}, {32, 2}, {4, 8}}, + /* 31 */ {{128, 1}, {64, 2}, {16, 4}, {4, 4}}, + /* 32 */ {{128, 1}, {16, 8}, {8, 2}, {4, 2}}, + /* 33 */ {{132, 1}, {44, 3}, {4, 11}, {4, 1}}, + /* 34 */ {{136, 1}, {68, 2}, {4, 17}, {4, 1}}, + /* 35 */ {{144, 1}, {72, 2}, {36, 2}, {4, 9}}, + /* 36 */ {{144, 1}, {48, 3}, {24, 2}, {12, 2}}, + /* 37 */ {{144, 1}, {48, 3}, {16, 3}, {4, 4}}, + /* 38 */ {{144, 1}, {16, 9}, {8, 2}, {4, 2}}, + /* 39 */ {{152, 1}, {76, 2}, {4, 19}, {4, 1}}, + /* 40 */ {{160, 1}, {80, 2}, {40, 2}, {4, 10}}, + /* 41 */ {{160, 1}, {80, 2}, {20, 4}, {4, 5}}, + /* 42 */ {{160, 1}, {32, 5}, {16, 2}, {4, 4}}, + /* 43 */ {{168, 1}, {84, 2}, {28, 3}, {4, 7}}, + /* 44 */ {{176, 1}, {88, 2}, {44, 2}, {4, 11}}, + /* 45 */ {{184, 1}, {92, 2}, {4, 23}, {4, 1}}, + /* 46 */ {{192, 1}, {96, 2}, {48, 2}, {4, 12}}, + /* 47 */ {{192, 1}, {96, 2}, {24, 4}, {4, 6}}, + /* 48 */ {{192, 1}, {64, 3}, {16, 4}, {4, 4}}, + /* 49 */ {{192, 1}, {24, 8}, {8, 3}, {4, 2}}, + /* 50 */ {{208, 1}, {104, 2}, {52, 2}, {4, 13}}, + /* 51 */ {{216, 1}, {108, 2}, {36, 3}, {4, 9}}, + /* 52 */ {{224, 1}, {112, 2}, {56, 2}, {4, 14}}, + /* 53 */ {{240, 1}, {120, 2}, {60, 2}, {4, 15}}, + /* 54 */ {{240, 1}, {80, 3}, {20, 4}, {4, 5}}, + /* 55 */ {{240, 1}, {48, 5}, {16, 3}, {8, 2}}, + /* 56 */ {{240, 1}, {24, 10}, {12, 2}, {4, 3}}, + /* 57 */ {{256, 1}, {128, 2}, {64, 2}, {4, 16}}, + /* 58 */ {{256, 1}, {128, 2}, {32, 4}, {4, 8}}, + /* 59 */ {{256, 1}, {16, 16}, {8, 2}, {4, 2}}, + /* 60 */ {{264, 1}, {132, 2}, {44, 3}, {4, 11}}, + /* 61 */ {{272, 1}, {136, 2}, {68, 2}, {4, 17}}, + /* 62 */ {{272, 1}, {68, 4}, {4, 17}, {4, 1}}, + /* 63 */ {{272, 1}, {16, 17}, {8, 2}, {4, 2}}, +}; + const char *duplex_mode[]={"FDD","TDD"}; static const uint8_t bit_reverse_table_256[] = { @@ -1212,3 +1285,11 @@ void nr_timer_setup(NR_timer_t *timer, const uint32_t target, const uint32_t ste timer->step = step; nr_timer_stop(timer); } + +unsigned short get_m_srs(int c_srs, int b_srs) { + return srs_bandwidth_config[c_srs][b_srs][0]; +} + +unsigned short get_N_b_srs(int c_srs, int b_srs) { + return srs_bandwidth_config[c_srs][b_srs][1]; +} diff --git a/common/utils/nr/nr_common.h b/common/utils/nr/nr_common.h index 1e4fecc4f5..9087f335c5 100644 --- a/common/utils/nr/nr_common.h +++ b/common/utils/nr/nr_common.h @@ -250,6 +250,8 @@ int get_scan_ssb_first_sc(const double fc, void check_ssb_raster(uint64_t freq, int band, int scs); int get_smallest_supported_bandwidth_index(int scs, frequency_range_t frequency_range, int n_rbs); +unsigned short get_m_srs(int c_srs, int b_srs); +unsigned short get_N_b_srs(int c_srs, int b_srs); #define CEILIDIV(a,b) ((a+b-1)/b) #define ROUNDIDIV(a,b) (((a<<1)+b)/(b<<1)) 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 f0d9b73e63..d0d9fc9093 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 @@ -391,6 +391,7 @@ typedef struct { uint16_t t_srs; // SRS-Periodicity in slots [3GPP TS 38.211, Sec 6.4.1.4.4], Value: 1,2,3,4,5,8,10,16,20,32,40,64,80,160,320,640,1280,2560 uint16_t t_offset; // Slot offset value [3GPP TS 38.211, Sec 6.4.1.4.3], Value:0->2559 nfapi_nr_ue_ul_beamforming_t beamforming; + int16_t tx_power; } fapi_nr_ul_config_srs_pdu; typedef struct { diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c index fea6b930ac..7a46cd1b20 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c +++ b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c @@ -631,7 +631,7 @@ int nr_srs_channel_estimation( const uint8_t N_ap = 1<num_ant_ports; const uint8_t K_TC = 2<comb_size; - const uint16_t m_SRS_b = srs_bandwidth_config[srs_pdu->config_index][srs_pdu->bandwidth_index][0]; + const uint16_t m_SRS_b = get_m_srs(srs_pdu->config_index, srs_pdu->bandwidth_index); const uint16_t M_sc_b_SRS = m_SRS_b * NR_NB_SC_PER_RB/K_TC; uint8_t fd_cdm = N_ap; if (N_ap == 4 && ((K_TC == 2 && srs_pdu->cyclic_shift >= 4) || (K_TC == 4 && srs_pdu->cyclic_shift >= 6))) { diff --git a/openair1/PHY/NR_TRANSPORT/srs_rx.c b/openair1/PHY/NR_TRANSPORT/srs_rx.c index a7d975dbb7..037528b407 100644 --- a/openair1/PHY/NR_TRANSPORT/srs_rx.c +++ b/openair1/PHY/NR_TRANSPORT/srs_rx.c @@ -80,7 +80,7 @@ int nr_get_srs_signal(PHY_VARS_gNB *gNB, const uint8_t N_ap = 1<num_ant_ports; const uint8_t N_symb_SRS = 1 << srs_pdu->num_symbols; const uint8_t K_TC = 2 << srs_pdu->comb_size; - const uint16_t M_sc_b_SRS = srs_bandwidth_config[srs_pdu->config_index][srs_pdu->bandwidth_index][0] * NR_NB_SC_PER_RB/K_TC; + const uint16_t M_sc_b_SRS = get_m_srs(srs_pdu->config_index, srs_pdu->bandwidth_index) * NR_NB_SC_PER_RB / K_TC; int32_t *rx_signal; bool no_srs_signal = true; diff --git a/openair1/PHY/NR_UE_TRANSPORT/srs_modulation_nr.c b/openair1/PHY/NR_UE_TRANSPORT/srs_modulation_nr.c index 02ad38cc0e..f362e3f218 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/srs_modulation_nr.c +++ b/openair1/PHY/NR_UE_TRANSPORT/srs_modulation_nr.c @@ -110,17 +110,17 @@ uint16_t compute_F_b(frame_t frame_number, uint16_t product_N_b = 1; for (unsigned int b_prime = b_hop; b_prime < B_SRS; b_prime++) { if (b_prime != b_hop) { - product_N_b *= srs_bandwidth_config[C_SRS][b_prime][1]; + product_N_b *= get_N_b_srs(C_SRS, b_prime); } } uint16_t F_b = 0; - uint8_t N_b = srs_bandwidth_config[C_SRS][b][1]; + uint8_t N_b = get_N_b_srs(C_SRS, b); if (N_b & 1) { // Nb odd F_b = (N_b/2)*(n_SRS/product_N_b); } else { // Nb even uint16_t product_N_b_B_SRS = product_N_b; - product_N_b_B_SRS *= srs_bandwidth_config[C_SRS][B_SRS][1]; /* product for b_hop to b */ + product_N_b_B_SRS *= get_N_b_srs(C_SRS, B_SRS); /* product for b_hop to b */ F_b = (N_b/2)*((n_SRS%product_N_b_B_SRS)/product_N_b) + ((n_SRS%product_N_b_B_SRS)/2*product_N_b); } @@ -142,8 +142,8 @@ uint16_t compute_n_b(frame_t frame_number, uint8_t l_line, uint8_t b) { - uint8_t N_b = srs_bandwidth_config[C_SRS][b][1]; - uint16_t m_SRS_b = srs_bandwidth_config[C_SRS][B_SRS][0]; + uint8_t N_b = get_N_b_srs(C_SRS, b); + uint16_t m_SRS_b = get_m_srs(C_SRS, B_SRS); uint16_t n_b = 0; if (b_hop >= B_SRS) { @@ -211,7 +211,7 @@ int generate_srs_nr(nfapi_nr_srs_pdu_t *srs_config_pdu, uint8_t N_symb_SRS = 1<num_symbols; // Number of consecutive OFDM symbols uint8_t l0 = frame_parms->symbols_per_slot - 1 - l_offset; // Starting symbol position in the time domain uint8_t n_SRS_cs_max = srs_max_number_cs[srs_config_pdu->comb_size]; - uint16_t m_SRS_b = srs_bandwidth_config[C_SRS][B_SRS][0]; // Number of resource blocks + uint16_t m_SRS_b = get_m_srs(C_SRS, B_SRS); // Number of resource blocks uint16_t M_sc_b_SRS = m_SRS_b * NR_NB_SC_PER_RB/K_TC; // Length of the SRS sequence #ifdef SRS_DEBUG @@ -273,7 +273,7 @@ int generate_srs_nr(nfapi_nr_srs_pdu_t *srs_config_pdu, } uint64_t subcarrier_offset = frame_parms->first_carrier_offset + srs_config_pdu->bwp_start*NR_NB_SC_PER_RB; double sqrt_N_ap = sqrt(N_ap); - uint16_t n_b[B_SRS_NUMBER]; + uint16_t n_b[B_SRS + 1]; // Find index of table which is for this SRS length uint16_t M_sc_b_SRS_index = 0; diff --git a/openair1/PHY/NR_UE_TRANSPORT/srs_modulation_nr.h b/openair1/PHY/NR_UE_TRANSPORT/srs_modulation_nr.h index a017d79730..dba339d14b 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/srs_modulation_nr.h +++ b/openair1/PHY/NR_UE_TRANSPORT/srs_modulation_nr.h @@ -35,83 +35,6 @@ #include "PHY/defs_nr_UE.h" -/************** DEFINE ********************************************/ - -#define C_SRS_NUMBER (64) -#define B_SRS_NUMBER (4) - -/************** VARIABLES *****************************************/ - -/* TS 38.211 Table 6.4.1.4.3-1: SRS bandwidth configuration */ -static const unsigned short srs_bandwidth_config[C_SRS_NUMBER][B_SRS_NUMBER][2] = { - /* B_SRS = 0 B_SRS = 1 B_SRS = 2 B_SRS = 3 */ - /* C SRS m_srs0 N_0 m_srs1 N_1 m_srs2 N_2 m_srs3 N_3 */ - /* 0 */ {{4, 1}, {4, 1}, {4, 1}, {4, 1}}, - /* 1 */ {{8, 1}, {4, 2}, {4, 1}, {4, 1}}, - /* 2 */ {{12, 1}, {4, 3}, {4, 1}, {4, 1}}, - /* 3 */ {{16, 1}, {4, 4}, {4, 1}, {4, 1}}, - /* 4 */ {{16, 1}, {8, 2}, {4, 2}, {4, 1}}, - /* 5 */ {{20, 1}, {4, 5}, {4, 1}, {4, 1}}, - /* 6 */ {{24, 1}, {4, 6}, {4, 1}, {4, 1}}, - /* 7 */ {{24, 1}, {12, 2}, {4, 3}, {4, 1}}, - /* 8 */ {{28, 1}, {4, 7}, {4, 1}, {4, 1}}, - /* 9 */ {{32, 1}, {16, 2}, {8, 2}, {4, 2}}, - /* 10 */ {{36, 1}, {12, 3}, {4, 3}, {4, 1}}, - /* 11 */ {{40, 1}, {20, 2}, {4, 5}, {4, 1}}, - /* 12 */ {{48, 1}, {16, 3}, {8, 2}, {4, 2}}, - /* 13 */ {{48, 1}, {24, 2}, {12, 2}, {4, 3}}, - /* 14 */ {{52, 1}, {4, 13}, {4, 1}, {4, 1}}, - /* 15 */ {{56, 1}, {28, 2}, {4, 7}, {4, 1}}, - /* 16 */ {{60, 1}, {20, 3}, {4, 5}, {4, 1}}, - /* 17 */ {{64, 1}, {32, 2}, {16, 2}, {4, 4}}, - /* 18 */ {{72, 1}, {24, 3}, {12, 2}, {4, 3}}, - /* 19 */ {{72, 1}, {36, 2}, {12, 3}, {4, 3}}, - /* 20 */ {{76, 1}, {4, 19}, {4, 1}, {4, 1}}, - /* 21 */ {{80, 1}, {40, 2}, {20, 2}, {4, 5}}, - /* 22 */ {{88, 1}, {44, 2}, {4, 11}, {4, 1}}, - /* 23 */ {{96, 1}, {32, 3}, {16, 2}, {4, 4}}, - /* 24 */ {{96, 1}, {48, 2}, {24, 2}, {4, 6}}, - /* 25 */ {{104, 1}, {52, 2}, {4, 13}, {4, 1}}, - /* 26 */ {{112, 1}, {56, 2}, {28, 2}, {4, 7}}, - /* 27 */ {{120, 1}, {60, 2}, {20, 3}, {4, 5}}, - /* 28 */ {{120, 1}, {40, 3}, {8, 5}, {4, 2}}, - /* 29 */ {{120, 1}, {24, 5}, {12, 2}, {4, 3}}, - /* 30 */ {{128, 1}, {64, 2}, {32, 2}, {4, 8}}, - /* 31 */ {{128, 1}, {64, 2}, {16, 4}, {4, 4}}, - /* 32 */ {{128, 1}, {16, 8}, {8, 2}, {4, 2}}, - /* 33 */ {{132, 1}, {44, 3}, {4, 11}, {4, 1}}, - /* 34 */ {{136, 1}, {68, 2}, {4, 17}, {4, 1}}, - /* 35 */ {{144, 1}, {72, 2}, {36, 2}, {4, 9}}, - /* 36 */ {{144, 1}, {48, 3}, {24, 2}, {12, 2}}, - /* 37 */ {{144, 1}, {48, 3}, {16, 3}, {4, 4}}, - /* 38 */ {{144, 1}, {16, 9}, {8, 2}, {4, 2}}, - /* 39 */ {{152, 1}, {76, 2}, {4, 19}, {4, 1}}, - /* 40 */ {{160, 1}, {80, 2}, {40, 2}, {4, 10}}, - /* 41 */ {{160, 1}, {80, 2}, {20, 4}, {4, 5}}, - /* 42 */ {{160, 1}, {32, 5}, {16, 2}, {4, 4}}, - /* 43 */ {{168, 1}, {84, 2}, {28, 3}, {4, 7}}, - /* 44 */ {{176, 1}, {88, 2}, {44, 2}, {4, 11}}, - /* 45 */ {{184, 1}, {92, 2}, {4, 23}, {4, 1}}, - /* 46 */ {{192, 1}, {96, 2}, {48, 2}, {4, 12}}, - /* 47 */ {{192, 1}, {96, 2}, {24, 4}, {4, 6}}, - /* 48 */ {{192, 1}, {64, 3}, {16, 4}, {4, 4}}, - /* 49 */ {{192, 1}, {24, 8}, {8, 3}, {4, 2}}, - /* 50 */ {{208, 1}, {104, 2}, {52, 2}, {4, 13}}, - /* 51 */ {{216, 1}, {108, 2}, {36, 3}, {4, 9}}, - /* 52 */ {{224, 1}, {112, 2}, {56, 2}, {4, 14}}, - /* 53 */ {{240, 1}, {120, 2}, {60, 2}, {4, 15}}, - /* 54 */ {{240, 1}, {80, 3}, {20, 4}, {4, 5}}, - /* 55 */ {{240, 1}, {48, 5}, {16, 3}, {8, 2}}, - /* 56 */ {{240, 1}, {24, 10}, {12, 2}, {4, 3}}, - /* 57 */ {{256, 1}, {128, 2}, {64, 2}, {4, 16}}, - /* 58 */ {{256, 1}, {128, 2}, {32, 4}, {4, 8}}, - /* 59 */ {{256, 1}, {16, 16}, {8, 2}, {4, 2}}, - /* 60 */ {{264, 1}, {132, 2}, {44, 3}, {4, 11}}, - /* 61 */ {{272, 1}, {136, 2}, {68, 2}, {4, 17}}, - /* 62 */ {{272, 1}, {68, 4}, {4, 17}, {4, 1}}, - /* 63 */ {{272, 1}, {16, 17}, {8, 2}, {4, 2}}, -}; - #define SRS_PERIODICITY (17) static const uint16_t srs_periodicity[SRS_PERIODICITY] = {1, 2, 4, 5, 8, 10, 16, 20, 32, 40, 64, 80, 160, 320, 640, 1280, 2560}; diff --git a/openair2/LAYER2/NR_MAC_UE/mac_defs.h b/openair2/LAYER2/NR_MAC_UE/mac_defs.h index d9c5fa2345..aed42e6c53 100644 --- a/openair2/LAYER2/NR_MAC_UE/mac_defs.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_defs.h @@ -609,6 +609,9 @@ typedef struct NR_UE_MAC_INST_s { bool pucch_power_control_initialized; int f_b_f_c; bool pusch_power_control_initialized; + int h_b_f_c; + bool srs_power_control_initialized; + int delta_msg2; } NR_UE_MAC_INST_t; /*@}*/ diff --git a/openair2/LAYER2/NR_MAC_UE/mac_proto.h b/openair2/LAYER2/NR_MAC_UE/mac_proto.h index e2d6125145..1f53812dec 100644 --- a/openair2/LAYER2/NR_MAC_UE/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_proto.h @@ -240,6 +240,12 @@ int get_pusch_tx_power_ue( bool is_rar_tx_retx, bool transform_precoding); +int get_srs_tx_power_ue(NR_UE_MAC_INST_t *mac, + NR_SRS_Resource_t *srs_resource, + NR_SRS_ResourceSet_t *srs_resource_set, + int delta_srs, + bool is_configured_for_pusch_on_current_bwp); + int nr_ue_configure_pucch(NR_UE_MAC_INST_t *mac, int slot, frame_t frame, 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 36fbf3a527..fba8f63bd4 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_power_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_power_procedures.c @@ -578,6 +578,7 @@ int get_pusch_tx_power_ue(NR_UE_MAC_INST_t *mac, 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; + mac->delta_msg2 = delta_pusch; } 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))) { @@ -595,3 +596,84 @@ int get_pusch_tx_power_ue(NR_UE_MAC_INST_t *mac, f_b_f_c); return min(P_CMAX, P_O_PUSCH + M_pusch_component + alpha * pathloss + DELTA_TF + f_b_f_c); } + +int get_srs_tx_power_ue(NR_UE_MAC_INST_t *mac, + NR_SRS_Resource_t *srs_resource, + NR_SRS_ResourceSet_t *srs_resource_set, + int delta_srs, + bool is_configured_for_pusch_on_current_bwp) +{ + NR_UE_UL_BWP_t *current_UL_BWP = mac->current_UL_BWP; + AssertFatal(current_UL_BWP, "Missing configuration: need UL_BWP to calculate SRS tx power\n"); + AssertFatal(srs_resource_set->p0, "P0 mantatory present at configuration\n"); + int P_0_SRS = *srs_resource_set->p0; + + // alpha is optional, use same default as PUSCH + const float alpha_factor_table[8] = {0.0f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f}; + float alpha = srs_resource_set->alpha ? alpha_factor_table[*srs_resource_set->alpha] : 1.0f; + int m_srs_component = + 10 * log10(pow(2, current_UL_BWP->scs) * get_m_srs(srs_resource->freqHopping.c_SRS, srs_resource->freqHopping.b_SRS)); + + // The allowed MPR for SRS, PUCCH formats 0, 1, 3 and 4, and PRACH shall be as specified for QPSK modulated DFTs-OFDM of + // equivalent RB allocation. The allowed MPR for PUCCH format 2 shall be as specified for QPSK modulated CP-OFDM of equivalent RB + // allocation. + int P_CMAX = nr_get_Pcmax(mac->p_Max, + mac->nr_band, + mac->frame_type, + mac->frequency_range, + mac->current_UL_BWP->channel_bandwidth, + 2, + false, + mac->current_UL_BWP->scs, + mac->current_UL_BWP->BWPSize, + true, + get_m_srs(srs_resource->freqHopping.c_SRS, srs_resource->freqHopping.b_SRS), + 0); // TODO: Determine SRS start RB + + int16_t pathloss = compute_nr_SSB_PL(mac, mac->ssb_measurements.ssb_rsrp_dBm); + + int srs_power_without_h_b_f_c = P_0_SRS + alpha * pathloss + m_srs_component; + + // Power adjustment state + int h_b_f_c = 0; + bool use_pusch_power_adjustment_state = srs_resource_set->srs_PowerControlAdjustmentStates == NULL; + if (is_configured_for_pusch_on_current_bwp && use_pusch_power_adjustment_state) { + // Case 1: Use PUSCH power control adjustment state + h_b_f_c = mac->f_b_f_c; + } else { + // Case 2: Separate power control adjustment state + AssertFatal(srs_resource_set->srs_PowerControlAdjustmentStates == NULL + || *srs_resource_set->srs_PowerControlAdjustmentStates + != NR_SRS_ResourceSet__srs_PowerControlAdjustmentStates_sameAsFci2, + "Two PUSCH power adjustment states not supported"); + + bool is_tpc_accumulation_provided = current_UL_BWP->srs_Config != NULL && current_UL_BWP->srs_Config->tpc_Accumulation != NULL; + bool separate_pc_adjustment_state = srs_resource_set->srs_PowerControlAdjustmentStates + && *srs_resource_set->srs_PowerControlAdjustmentStates + == NR_SRS_ResourceSet__srs_PowerControlAdjustmentStates_separateClosedLoop; + + if (!is_tpc_accumulation_provided && (!is_configured_for_pusch_on_current_bwp || separate_pc_adjustment_state)) { + if (!mac->srs_power_control_initialized) { + 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_0_SRS + m_srs_component + alpha * pathloss); + DELTA_P_rampup = min(DELTA_P_rampup_requested, max(0, DELTA_P_rampup)); + mac->srs_power_control_initialized = true; + mac->h_b_f_c = DELTA_P_rampup + mac->delta_msg2; + } else { + int P_CMIN = mac->current_UL_BWP->P_CMIN; + if (!((srs_power_without_h_b_f_c + mac->h_b_f_c >= P_CMAX && delta_srs > 0) + || (srs_power_without_h_b_f_c + mac->h_b_f_c <= P_CMIN && delta_srs < 0))) { + mac->h_b_f_c += delta_srs; + } + } + h_b_f_c = mac->h_b_f_c; + } else { + // Case 3: No accumulation + h_b_f_c = delta_srs; + } + } + + return min(P_CMAX, srs_power_without_h_b_f_c + h_b_f_c); +} diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c index 84a35dcf52..a076829a8a 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c @@ -1058,7 +1058,8 @@ int configure_srs_pdu(NR_UE_MAC_INST_t *mac, NR_SRS_Resource_t *srs_resource, fapi_nr_ul_config_srs_pdu *srs_config_pdu, int period, - int offset) + int offset, + NR_SRS_ResourceSet_t *srs_resource_set) { NR_UE_UL_BWP_t *current_UL_BWP = mac->current_UL_BWP; @@ -1100,6 +1101,11 @@ int configure_srs_pdu(NR_UE_MAC_INST_t *mac, srs_config_pdu->t_offset = offset; } + bool is_configured_for_pusch_on_current_bwp = true; + int delta_srs = 0; // DCI format 2_3 not implemented + srs_config_pdu->tx_power = + get_srs_tx_power_ue(mac, srs_resource, srs_resource_set, delta_srs, is_configured_for_pusch_on_current_bwp); + #ifdef SRS_DEBUG LOG_I(NR_MAC,"Frame = %i, slot = %i\n", frame, slot); LOG_I(NR_MAC,"srs_config_pdu->rnti = 0x%04x\n", srs_config_pdu->rnti); @@ -1142,10 +1148,11 @@ void nr_ue_aperiodic_srs_scheduling(NR_UE_MAC_INST_t *mac, long resource_trigger int slot_offset = 0; NR_SRS_Resource_t *srs_resource = NULL; + NR_SRS_ResourceSet_t *srs_resource_set = NULL; for(int rs = 0; rs < srs_config->srs_ResourceSetToAddModList->list.count; rs++) { // Find aperiodic resource set - NR_SRS_ResourceSet_t *srs_resource_set = srs_config->srs_ResourceSetToAddModList->list.array[rs]; + srs_resource_set = srs_config->srs_ResourceSetToAddModList->list.array[rs]; if(srs_resource_set->resourceType.present != NR_SRS_ResourceSet__resourceType_PR_aperiodic) continue; // the resource trigger need to match the DCI one @@ -1186,7 +1193,7 @@ void nr_ue_aperiodic_srs_scheduling(NR_UE_MAC_INST_t *mac, long resource_trigger fapi_nr_ul_config_request_pdu_t *pdu = lockGet_ul_config(mac, sched_frame, sched_slot, FAPI_NR_UL_CONFIG_TYPE_SRS); if (!pdu) return; - int ret = configure_srs_pdu(mac, srs_resource, &pdu->srs_config_pdu, 0, 0); + int ret = configure_srs_pdu(mac, srs_resource, &pdu->srs_config_pdu, 0, 0, srs_resource_set); if (ret != 0) remove_ul_config_last_item(pdu); release_ul_config(pdu, false); @@ -1204,9 +1211,10 @@ static bool nr_ue_periodic_srs_scheduling(NR_UE_MAC_INST_t *mac, frame_t frame, } bool srs_scheduled = false; + NR_SRS_ResourceSet_t *srs_resource_set = NULL; for(int rs = 0; rs < srs_config->srs_ResourceSetToAddModList->list.count; rs++) { // Find periodic resource set - NR_SRS_ResourceSet_t *srs_resource_set = srs_config->srs_ResourceSetToAddModList->list.array[rs]; + srs_resource_set = srs_config->srs_ResourceSetToAddModList->list.array[rs]; if(srs_resource_set->resourceType.present != NR_SRS_ResourceSet__resourceType_PR_periodic) { continue; } @@ -1237,7 +1245,7 @@ static bool nr_ue_periodic_srs_scheduling(NR_UE_MAC_INST_t *mac, frame_t frame, fapi_nr_ul_config_request_pdu_t *pdu = lockGet_ul_config(mac, frame, slot, FAPI_NR_UL_CONFIG_TYPE_SRS); if (!pdu) return false; - int ret = configure_srs_pdu(mac, srs_resource, &pdu->srs_config_pdu, period, offset); + int ret = configure_srs_pdu(mac, srs_resource, &pdu->srs_config_pdu, period, offset, srs_resource_set); if (ret != 0) remove_ul_config_last_item(pdu); else 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 c8467241b8..26f9681079 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 @@ -594,6 +594,126 @@ TEST(test_pcmax, test_non_obvious_bwp_size) nr_get_Pcmax(23, nr_band, frame_type, FR1, channel_bandwidth, 2, false, 1, N_RB_UL, false, 6, prb_start)); } +TEST(test_srs_power, use_pusch_power_adjustment_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_SRS_Resource_t srs_resource = {0}; + NR_SRS_ResourceSet_t srs_resource_set = {0}; + bool is_configured_for_pusch_on_current_bwp = true; + int delta_srs = 0; + srs_resource_set.srs_PowerControlAdjustmentStates = NULL; + mac.nr_band = 78; + mac.f_b_f_c = 0; + mac.pusch_power_control_initialized = true; + long p0 = 0; + srs_resource_set.p0 = &p0; + + int tx_power = get_srs_tx_power_ue(&mac, &srs_resource, &srs_resource_set, delta_srs, is_configured_for_pusch_on_current_bwp); + + mac.f_b_f_c = 4; + + int increased_tx_power = + get_srs_tx_power_ue(&mac, &srs_resource, &srs_resource_set, delta_srs, is_configured_for_pusch_on_current_bwp); + EXPECT_EQ(tx_power + mac.f_b_f_c, increased_tx_power); +} + +TEST(test_srs_power, no_support_for_two_pusch_power_adjustment_states) +{ + 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_SRS_Resource_t srs_resource = {0}; + NR_SRS_ResourceSet_t srs_resource_set = {0}; + long p0 = 0; + srs_resource_set.p0 = &p0; + bool is_configured_for_pusch_on_current_bwp = true; + int delta_srs = 0; + long srs_PowerControlAdjustmentStates = NR_SRS_ResourceSet__srs_PowerControlAdjustmentStates_sameAsFci2; + srs_resource_set.srs_PowerControlAdjustmentStates = &srs_PowerControlAdjustmentStates; + mac.nr_band = 78; + mac.f_b_f_c = 0; + mac.pusch_power_control_initialized = true; + + EXPECT_DEATH(get_srs_tx_power_ue(&mac, &srs_resource, &srs_resource_set, delta_srs, is_configured_for_pusch_on_current_bwp), + "Two PUSCH power adjustment states not supported"); +} + +TEST(test_srs_power, no_tpc_accumulation) +{ + 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_SRS_Resource_t srs_resource = {0}; + NR_SRS_ResourceSet_t srs_resource_set = {0}; + long p0 = 0; + srs_resource_set.p0 = &p0; + bool is_configured_for_pusch_on_current_bwp = true; + int delta_srs = 0; + long srs_PowerControlAdjustmentStates = NR_SRS_ResourceSet__srs_PowerControlAdjustmentStates_separateClosedLoop; + srs_resource_set.srs_PowerControlAdjustmentStates = &srs_PowerControlAdjustmentStates; + mac.nr_band = 78; + mac.f_b_f_c = 0; + mac.pusch_power_control_initialized = true; + + NR_SRS_Config_t srs_Config = {0}; + long tpc_Accumulation = 0; + srs_Config.tpc_Accumulation = &tpc_Accumulation; + current_UL_BWP.srs_Config = &srs_Config; + + int tx_power = get_srs_tx_power_ue(&mac, &srs_resource, &srs_resource_set, delta_srs, is_configured_for_pusch_on_current_bwp); + + delta_srs = 4; + + int increased_tx_power = + get_srs_tx_power_ue(&mac, &srs_resource, &srs_resource_set, delta_srs, is_configured_for_pusch_on_current_bwp); + EXPECT_EQ(tx_power + delta_srs, increased_tx_power); +} + +TEST(test_srs_power, tpc_accumulation) +{ + 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_SRS_Resource_t srs_resource = {0}; + NR_SRS_ResourceSet_t srs_resource_set = {0}; + long p0 = 0; + srs_resource_set.p0 = &p0; + bool is_configured_for_pusch_on_current_bwp = true; + int delta_srs = 0; + long srs_PowerControlAdjustmentStates = NR_SRS_ResourceSet__srs_PowerControlAdjustmentStates_separateClosedLoop; + srs_resource_set.srs_PowerControlAdjustmentStates = &srs_PowerControlAdjustmentStates; + mac.nr_band = 78; + mac.f_b_f_c = 0; + mac.pusch_power_control_initialized = true; + mac.srs_power_control_initialized = true; + mac.h_b_f_c = 0; + + NR_SRS_Config_t srs_Config = {0}; + current_UL_BWP.srs_Config = &srs_Config; + + int tx_power = get_srs_tx_power_ue(&mac, &srs_resource, &srs_resource_set, delta_srs, is_configured_for_pusch_on_current_bwp); + + delta_srs = 4; + + int increased_tx_power = + get_srs_tx_power_ue(&mac, &srs_resource, &srs_resource_set, delta_srs, is_configured_for_pusch_on_current_bwp); + EXPECT_EQ(tx_power + delta_srs, increased_tx_power); + + int more_tx_power = + get_srs_tx_power_ue(&mac, &srs_resource, &srs_resource_set, delta_srs, is_configured_for_pusch_on_current_bwp); + EXPECT_EQ(tx_power + delta_srs * 2, more_tx_power); +} + int main(int argc, char** argv) { logInit();