SRS tx power with power control state

This commit is contained in:
Bartosz Podrygajlo
2024-10-01 10:15:23 +02:00
parent fc0cbc3147
commit bfc47445ee
12 changed files with 317 additions and 91 deletions
+3
View File
@@ -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;
/*@}*/
+6
View File
@@ -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,
@@ -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);
}
+13 -5
View File
@@ -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
@@ -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 = &current_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 = &current_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 = &current_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 = &current_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();