diff --git a/doc/MAC/mac-usage.md b/doc/MAC/mac-usage.md index 94c813d7ac..84150506c5 100644 --- a/doc/MAC/mac-usage.md +++ b/doc/MAC/mac-usage.md @@ -82,7 +82,7 @@ UE RNTI 2460 CU-UE-ID 2 in-sync PH 28 dB PCMAX 24 dBm, average RSRP -74 (8 meas) UE 2460: CQI 15, RI 2, PMI (14,1) UE 2460: UL-RI 2 TPMI 0 UE 2460: dlsch_rounds 32917/5113/1504/560, dlsch_errors 211, pucch0_DTX 1385, BLER 0.19557 MCS (1) 23 CCE fail 3 -UE 2460: ulsch_rounds 3756/353/182/179, ulsch_errors 170, ulsch_DTX 285, BLER 0.33021 MCS (1) 27 (Qm 8 dB) NPRB 5 SNR 31.0 dB CCE fail 0 +UE 2460: ulsch_rounds 3756/353/182/179, ulsch_errors 170, ulsch_DTX 285, BLER 0.33021 MCS (1) 27 (Qm 8 dB) NPRB 5 SNR 31.0 (-1.0) dB CCE fail 0 UE 2460: MAC: TX 1530943191 RX 194148 bytes UE 2460: LCID 1: TX 651 RX 3031 bytes UE 2460: LCID 2: TX 0 RX 0 bytes @@ -162,10 +162,9 @@ The fourth and fifth line show HARQ-related information: fluctuate a lot but when doing high throughput with iperf, it indicates the number of PRBs that the UE is actually able to use with its power budget and should be high. -* ULSCH `SNR`: the current SNR that the gNB receives the UE signal with. It - should be close to the target in the gNB configuration file, - `pusch_TargetSNRx10`, which should be around 10 times the value shown in the - log +* ULSCH `SNR`: the current SNR that the gNB receives the UE PUSCH signal with. + This value should be close to the target SNR; in paranthesis, the difference + to the target SNR. * Both ULSCH/DLSCH `CCE fail`: lists the number of failed CCE attempts. If this number gets high, it signifies that the scheduler tried to scheduled this UE, but could not allocate the DCI. diff --git a/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_mac.c b/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_mac.c index 13b6306a1c..2778913524 100644 --- a/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_mac.c +++ b/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_mac.c @@ -81,7 +81,7 @@ bool read_mac_sm(void* data) rd->dl_aggr_sdus = UE->mac_stats.dl.num_mac_sdu; rd->ul_aggr_sdus = UE->mac_stats.ul.num_mac_sdu; - rd->pusch_snr = (float) sched_ctrl->pusch_snrx10 / 10; //: float = -64; + rd->pusch_snr = sched_ctrl->pusch_pc.avg_snr; //: float = -64; rd->pucch_snr = (float) sched_ctrl->pucch_snrx10 / 10; //: float = -64; rd->wb_cqi = sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.wb_cqi_1tb; diff --git a/openair2/LAYER2/NR_MAC_gNB/config.c b/openair2/LAYER2/NR_MAC_gNB/config.c index bc402e7125..a6b09bb53b 100644 --- a/openair2/LAYER2/NR_MAC_gNB/config.c +++ b/openair2/LAYER2/NR_MAC_gNB/config.c @@ -1143,7 +1143,7 @@ bool nr_mac_add_test_ue(gNB_MAC_INST *nrmac, uint32_t rnti, NR_CellGroupConfig_t DevAssert(get_softmodem_params()->phy_test); NR_SCHED_LOCK(&nrmac->sched_lock); - NR_UE_info_t *UE = get_new_nr_ue_inst(&nrmac->UE_info.uid_allocator, rnti, CellGroup); + NR_UE_info_t *UE = get_new_nr_ue_inst(&nrmac->UE_info.uid_allocator, rnti, CellGroup, &nrmac->radio_config); DevAssert(UE->uid < MAX_MOBILES_PER_GNB); // physical simulators: we assume we can always create a UE free_and_zero(UE->ra); // physical simulators: UE will not do RA UE->local_bwp_id = 1; // for physical simulators diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c index fc563b56b9..e554fbe21c 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c @@ -604,7 +604,7 @@ int nr_fill_successrar(const NR_UE_sched_ctrl_t *ue_sched_ctl, successRAR->CONT_RES_6 = ue_cont_res_id[5]; successRAR->R = 0; successRAR->CH_ACESS_CPEXT = 1; - successRAR->TPC = ue_sched_ctl->tpc0; + successRAR->TPC = 1; // 0dB change, don't know how to determine this. successRAR->HARQ_FTI = timing_indicator; successRAR->PUCCH_RI = resource_indicator; successRAR->TA1 = (uint8_t)(timing_advance_cmd >> 8); // 4 MSBs of timing advance; @@ -718,7 +718,7 @@ void nr_initiate_ra_proc(module_id_t module_idP, return; } - UE = get_new_nr_ue_inst(&nr_mac->UE_info.uid_allocator, rnti, NULL); + UE = get_new_nr_ue_inst(&nr_mac->UE_info.uid_allocator, rnti, NULL, &nr_mac->radio_config); if (!add_new_UE_RA(nr_mac, UE)) { LOG_E(NR_MAC, "FAILURE: %4d.%2d initiating RA procedure for preamble index %d: no free RA process\n", frame, slot, preamble_index); delete_nr_ue_data(UE, NULL, &nr_mac->UE_info.uid_allocator); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index 7b9a32f547..0cffa53b09 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -2973,7 +2973,7 @@ static void init_bler_stats(const NR_bler_options_t *bler_options, NR_bler_stats * It will be typically added to the access_ue_list, but not always (e.g., * phytest mode), so this is not done in this function (and also, to allow * error handling). Remove with delete_nr_ue_data(). */ -NR_UE_info_t *get_new_nr_ue_inst(uid_allocator_t *uia, rnti_t rnti, NR_CellGroupConfig_t *CellGroup) +NR_UE_info_t *get_new_nr_ue_inst(uid_allocator_t *uia, rnti_t rnti, NR_CellGroupConfig_t *CellGroup, const nr_mac_config_t *config) { NR_UE_info_t *UE = calloc_or_fail(1, sizeof(NR_UE_info_t)); UE->uid = uid_linear_allocator_new(uia); @@ -2983,6 +2983,10 @@ NR_UE_info_t *get_new_nr_ue_inst(uid_allocator_t *uia, rnti_t rnti, NR_CellGroup NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; sched_ctrl->ta_update = 31; + nr_mac_set_target_snrx10(&sched_ctrl->pusch_pc, config->pusch.target_snrx10); + sched_ctrl->pusch_pc.avg_snr = config->pusch.target_snrx10 / 10.0f; // set initial SNR to what we would expect on average + nr_mac_set_rssi_threshold(&sched_ctrl->pusch_pc, config->pusch.rssi_threshold); + /* Set default BWPs */ AssertFatal(UE->sc_info.n_ul_bwp <= NR_MAX_NUM_BWP, "uplinkBWP_ToAddModList has %d BWP!\n", UE->sc_info.n_ul_bwp); @@ -3134,6 +3138,19 @@ uint8_t nr_get_tpc(int target, uint8_t cqi, int incr, int tx_power) return 1; // no change } +/** + * @brief Returns the number of dBs for given transmit power control (TPC) + * command. Asserts on illegal TPC. + * @param tpc TPC command in range 0..3 + * @return The dB value expressed by the TPC command + */ +static int tpc_to_db(int tpc) +{ + DevAssert(tpc >= 0 && tpc <= 3); + const int db[] = {-1, 0, 1, 3}; + return db[tpc]; +} + /** * @brief Limits the power control commands (TPC) in NR by checking the RSSI threshold. * @@ -3156,11 +3173,10 @@ uint8_t nr_limit_tpc(int tpc, int rssi, int rssi_threshold) const int fapi_rssi_0dBm_or_0dBFS = 1280; int rssi_fapi_threshold = fapi_rssi_0dBm_or_0dBFS + rssi_threshold; // Further limit TPC if above or near RSSI threshold - int tpc_to_db[] = {-1, 0, 1, 3}; if (rssi > rssi_fapi_threshold) { // RSSI above theshold, reduce power return 0; - } else if (rssi + tpc_to_db[tpc] * 10 > rssi_fapi_threshold) { + } else if (rssi + tpc_to_db(tpc) * 10 > rssi_fapi_threshold) { // Cannot apply required TPC, check 1 dB increment if (rssi + 10 > rssi_fapi_threshold) { // Still cannot apply required TPC, keep power @@ -4134,3 +4150,127 @@ void nr_mac_update_pdcch_closed_loop_adjust(NR_UE_sched_ctrl_t *sched_ctrl, bool sched_ctrl->pdcch_cl_adjust = max(0, sched_ctrl->pdcch_cl_adjust - 0.01); } } + +/** + * @brief Calculate the current average SNR for the given power control loop. + * @param pc the power control loop + * @return the current average SNR + */ +float nr_mac_get_snr(const nr_power_control_t *pc) +{ + return pc->avg_snr + pc->tpc_in_flight; +} + +/** + * @brief Calculates the difference of current average SNR to the target SNR + * set in the power control loop. + * @param pc the power control loop + * @return the SNR difference + */ +static float get_snr_diff(const nr_power_control_t *pc) +{ + float snr = nr_mac_get_snr(pc); + float delta = (snr * 10.0f - pc->target_snrx10) / 10.0f; + LOG_D(NR_MAC, "target %.2f snr %.2f delta %.2f\n", pc->target_snrx10 / 10.0f, snr, delta); + return delta; +} + +/// averaging constant for power control (used for SNR, RSSI). +#define PC_AVG_CNST 0.975f +/** + * @brief Enter new SNR and RSSI value for the latest UL transmission, and + * update the average SNR and average RSSI of the corresponding UE. + * + * Since the SNR is averaged, any changes through transmit power control (TPC) + * commands will take time to reflect in the averaged SNR. To allow a + * continuous tracking of necessary TPC, as well as a continuous adjustment of + * the target SNR, the algorithm keeps track of "TPC in flight" which is a + * moving average of the last TPC commands sent to the UE. The sum of the + * averaged SNR and "TPC in flight" is the actual, current SNR. The RSSI in + * turn is used to limit TPC commands (see also nr_limit_tpc()). + * + * @param pc the power control loop + * @param snrx10 the current SNR measurement multiplied by 10 + * @param rssi the current RSSI measurement + */ +void nr_mac_pc_snr(nr_power_control_t *pc, int snrx10, int rssi) +{ + pc->avg_snr = PC_AVG_CNST * pc->avg_snr + (1.0f - PC_AVG_CNST) * 0.1 * snrx10; + pc->avg_rssi = PC_AVG_CNST * pc->avg_rssi + (1.0f - PC_AVG_CNST) * rssi; + // use an EMA to average out tpc_in_flight as fast as EMA for avg_snr. + // this will ensure that on TPC change, avg_snr approximates real SNR as + // fast as tpc_in_flight returns to 0. + pc->tpc_in_flight = PC_AVG_CNST * pc->tpc_in_flight; // + (1 - PC_AVG_CNST) * 0.0f +} + +/** + * @brief Set a new target SNR for this power control loop, which can be + * updated on a continuous basis, and will be reflected immediately upon + * calls to nr_mac_get_tpc() (no "settle time" necessary). + * + * @param pc the power control loop + * @param target_snrx10 the target SNR to be set times 10. + */ +void nr_mac_set_target_snrx10(nr_power_control_t *pc, int target_snrx10) +{ + pc->target_snrx10 = target_snrx10; +} + +/** + * @brif Set a new RSSI threshold for this power control loop. Will be used to + * limit TPCs, see also nr_limit_tpc(). + * + * @param pc the power control loop + * @param rssi_threshold the RSSI threshold + */ +void nr_mac_set_rssi_threshold(nr_power_control_t *pc, int rssi_threshold) +{ + pc->rssi_threshold = rssi_threshold; +} + +/** + * @brief Signal that this power control loop experienced a discontinuous + * transmission (DTC), aka "no reception".. This will decrease the "TPC in + * flight" to artificially reduce the current SNR, which will trigger a TPC + * command to increase the power. Repeated DTX will lead to more TPC. + * + * @param pc the power control loop + */ +void nr_mac_signal_dtx(nr_power_control_t *pc) +{ + // repeated DTX will make nr_mac_get_tpc() return positive TPCs, see + // nr_mac_pc_snr(). The more DTX, the more TPC increase, which will + // eventually zero out and return back to target SNR (change is temporary). + // Also, this will only send positive TPC changes. + pc->tpc_in_flight = max(pc->tpc_in_flight - 1.0f, -5.0f); // TODO threshold good? +} + +/** + * @brief Get a transmit power control (TPC) command for the given power + * control loop according to current and target SNR. This function can be + * called continuously on every UL transmission occasion, and keeps track of + * past TPC commands. It also limits TPC commands according to RSSI, see + * nr_limit_tpc() for more information. + * + * @param pc the power control loop + * @return the next TPC command. + */ +int nr_mac_get_tpc(nr_power_control_t *pc) +{ + float diff = get_snr_diff(pc); + int tpc = 1; + if (diff <= -3.0f) { + tpc = 3; // increase 3dB + } else if (diff <= -1.0f) { + tpc = 2; // increase 1dB + } else if (diff >= 2.0f) { + tpc = 0; // decrease 1dB + } else { + tpc = 1; // within -1<=target<=2dB => is ok. + } + tpc = nr_limit_tpc(tpc, pc->avg_rssi, pc->rssi_threshold); + int change = tpc_to_db(tpc); + pc->tpc_in_flight += change; + LOG_D(NR_MAC, "tpc %d => %d\n", tpc, change); + return tpc; +} diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index 3b2c3cc2f7..016423d7a2 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -850,13 +850,11 @@ static void nr_rx_ra_sdu(const module_id_t mod_id, DevAssert(harq_pid >= 0 && harq_pid < 8); if (ul_cqi != 0xff) { NR_UE_ul_harq_t *harq = &UE_scheduling_control->ul_harq_processes[harq_pid]; - DevAssert(harq->sched_pusch.phr_txpower_calc == 0); - UE_scheduling_control->tpc0 = nr_get_tpc(target_snrx10, ul_cqi, 30, harq->sched_pusch.phr_txpower_calc); - UE_scheduling_control->pusch_snrx10 = ul_cqi * 5 - 640 - harq->sched_pusch.phr_txpower_calc * 10; + DevAssert(harq->sched_pusch.phr_txpower_calc == 0); // TODO remove from here + UE_scheduling_control->pusch_pc.avg_snr = 0.1 * (ul_cqi * 5 - 640); } if (timing_advance != 0xffff) UE_scheduling_control->ta_update = timing_advance; - LOG_D(NR_MAC, "[UE %04x] PUSCH TPC %d and TA %d\n", UE->rnti, UE_scheduling_control->tpc0, UE_scheduling_control->ta_update); LOG_D(NR_MAC, "[RAPROC] Received %s:\n", ra->ra_type == RA_2_STEP ? "MsgA-PUSCH" : "Msg3"); for (uint32_t k = 0; k < sdu_len; k++) { @@ -944,8 +942,6 @@ static void _nr_rx_sdu(const module_id_t gnb_mod_idP, gNB_MAC_INST *gNB_mac = RC.nrmac[gnb_mod_idP]; const int current_rnti = rntiP; LOG_D(NR_MAC, "rx_sdu for rnti %04x\n", current_rnti); - const int target_snrx10 = gNB_mac->radio_config.pusch.target_snrx10; - const int rssi_threshold = gNB_mac->radio_config.pusch.rssi_threshold; const int pusch_failure_thres = gNB_mac->radio_config.pusch.failure_thres; NR_UE_info_t *UE = find_nr_UE(&gNB_mac->UE_info, current_rnti); if (UE) { @@ -977,21 +973,18 @@ static void _nr_rx_sdu(const module_id_t gnb_mod_idP, int txpower_calc = UE_scheduling_control->ul_harq_processes[harq_pid].sched_pusch.phr_txpower_calc; UE->mac_stats.deltaMCS = txpower_calc; UE->mac_stats.NPRB = UE_scheduling_control->ul_harq_processes[harq_pid].sched_pusch.rbSize; - if (ul_cqi != 0xff) - UE_scheduling_control->tpc0 = nr_get_tpc(target_snrx10, ul_cqi, 30, txpower_calc); - if (UE_scheduling_control->ph < 0 && UE_scheduling_control->tpc0 > 1) - UE_scheduling_control->tpc0 = 1; - UE_scheduling_control->tpc0 = nr_limit_tpc(UE_scheduling_control->tpc0, rssi, rssi_threshold); + int pusch_snrx10 = ul_cqi * 5 - 640 - txpower_calc * 10; // TODO don't log T? + if (ul_cqi != 0xff) + nr_mac_pc_snr(&UE_scheduling_control->pusch_pc, pusch_snrx10, rssi); if (timing_advance != 0xffff) UE_scheduling_control->ta_update = timing_advance; - int pusch_snrx10 = ul_cqi * 5 - 640; - UE_scheduling_control->pusch_snrx10 = pusch_snrx10 - (txpower_calc * 10); + const NR_sched_pusch_t *sched_pusch = &UE_scheduling_control->ul_harq_processes[harq_pid].sched_pusch; (void) sched_pusch; // avoids warnings of unused sched_pusch when compiling without T T(T_GNB_MAC_PUSCH_POWER_CONTROL, T_INT(rntiP), T_INT(frameP), T_INT(slotP), - T_INT(UE_scheduling_control->pusch_snrx10), + T_INT(pusch_snrx10), T_INT(UE_scheduling_control->ph), T_INT(sched_pusch->tpc_pusch), T_INT(sched_pusch->tb_size), @@ -999,27 +992,6 @@ static void _nr_rx_sdu(const module_id_t gnb_mod_idP, T_INT(sched_pusch->rbSize), T_INT(sched_pusch->mcs), T_INT(rssi)); - if (false) - LOG_I(NR_MAC, - "[UE %04x] %4d.%2d. rssi %4d snr %3d txp_calc %3d PHR %2d RB %2d MCS %2d\n", - UE->rnti, - frameP, - slotP, - rssi, - pusch_snrx10 / 10, - txpower_calc, - UE_scheduling_control->ph, - UE_scheduling_control->ul_harq_processes[harq_pid].sched_pusch.rbSize, - UE_scheduling_control->ul_harq_processes[harq_pid].sched_pusch.mcs); - - NR_UE_ul_harq_t *cur_harq = &UE_scheduling_control->ul_harq_processes[harq_pid]; - if (cur_harq->round == 0) - UE->mac_stats.pusch_snrx10 = UE_scheduling_control->pusch_snrx10; - LOG_D(NR_MAC, "[UE %04x] PUSCH TPC %d and TA %d\n",UE->rnti,UE_scheduling_control->tpc0,UE_scheduling_control->ta_update); - } - else{ - LOG_D(NR_MAC,"[UE %04x] Detected DTX : increasing UE TX power\n",UE->rnti); - UE_scheduling_control->tpc0 = 1; } #if defined(ENABLE_MAC_PAYLOAD_DEBUG) @@ -1046,6 +1018,7 @@ static void _nr_rx_sdu(const module_id_t gnb_mod_idP, if (ul_cqi == 0xff || ul_cqi <= 128) { UE->UE_sched_ctrl.pusch_consecutive_dtx_cnt++; UE->mac_stats.ulsch_DTX++; + nr_mac_signal_dtx(&UE_scheduling_control->pusch_pc); } if (!get_softmodem_params()->phy_test && UE->UE_sched_ctrl.pusch_consecutive_dtx_cnt >= pusch_failure_thres) { @@ -2092,7 +2065,7 @@ static int pf_ul(gNB_MAC_INST *nrmac, int selected_mcs; int nrOfLayers = get_ul_nrOfLayers(sched_ctrl, current_BWP->dci_format); if (bo->harq_round_max == 1) { - selected_mcs = get_mcs_from_SINRx10(current_BWP->mcs_table, sched_ctrl->pusch_snrx10, nrOfLayers); + selected_mcs = get_mcs_from_SINRx10(current_BWP->mcs_table, sched_ctrl->pusch_pc.avg_snr * 10, nrOfLayers); selected_mcs = min(max_mcs, selected_mcs); selected_mcs = max(bo->min_mcs, selected_mcs); sched_ctrl->ul_bler_stats.mcs = selected_mcs; @@ -2513,6 +2486,7 @@ void post_process_ulsch(gNB_MAC_INST *nr_mac, post_process_pusch_t *pusch, NR_UE deltaMCS, false); + int tpc = nr_mac_get_tpc(&sched_ctrl->pusch_pc); LOG_D(NR_MAC, "ULSCH/PUSCH: %4d.%2d RNTI %04x UL sched %4d.%2d DCI L %d start %2d RBS %3d TDA %2d dmrs_pos %x MCS " "Table %2d MCS %2d nrOfLayers %2d num_dmrs_cdm_grps_no_data %2d TBS %4d HARQ PID %2d round %d RV %d NDI %d est %6d sched " @@ -2539,7 +2513,7 @@ void post_process_ulsch(gNB_MAC_INST *nr_mac, post_process_pusch_t *pusch, NR_UE sched_ctrl->estimated_ul_buffer, sched_ctrl->sched_ul_bytes, sched_ctrl->estimated_ul_buffer - sched_ctrl->sched_ul_bytes, - sched_ctrl->tpc0); + tpc); /* Save information on MCS, TBS etc for the current initial transmission * so we have access to it when retransmitting */ @@ -2599,14 +2573,12 @@ void post_process_ulsch(gNB_MAC_INST *nr_mac, post_process_pusch_t *pusch, NR_UE &sched_ctrl->srs_feedback, tpmi, sched_pusch->time_domain_allocation, - UE->UE_sched_ctrl.tpc0, + tpc, cur_harq->ndi, current_BWP, ss->searchSpaceType->present); - // Reset TPC to 0 dB to not request new gain multiple times before computing new value for SNR - cur_harq->sched_pusch.tpc_pusch = sched_ctrl->tpc0; - sched_ctrl->tpc0 = 1; + cur_harq->sched_pusch.tpc_pusch = tpc; fill_dci_pdu_rel15(&UE->sc_info, &UE->current_DL_BWP, diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index 5a59ed67af..2936c20bb4 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -321,7 +321,7 @@ bool transition_ra_connected_nr_ue(gNB_MAC_INST *nr_mac, NR_UE_info_t *UE); bool add_connected_nr_ue(gNB_MAC_INST *nr_mac, NR_UE_info_t *UE); bool nr_check_Msg4_MsgB_Ack(module_id_t module_id, frame_t frame, slot_t slot, NR_UE_info_t *UE, bool success); void mac_remove_nr_ue(gNB_MAC_INST *nr_mac, rnti_t rnti); -NR_UE_info_t *get_new_nr_ue_inst(uid_allocator_t *uia, rnti_t rnti, NR_CellGroupConfig_t *CellGroup); +NR_UE_info_t *get_new_nr_ue_inst(uid_allocator_t *uia, rnti_t rnti, NR_CellGroupConfig_t *CellGroup, const nr_mac_config_t *config); int nr_get_default_pucch_res(int pucch_ResourceCommon); nfapi_nr_pusch_pdu_t *prepare_pusch_pdu(nfapi_nr_ul_tti_request_t *future_ul_tti_req, const NR_UE_info_t *UE, @@ -502,4 +502,12 @@ void nr_mac_clean_cellgroup(NR_CellGroupConfig_t *cell_group); void post_process_dlsch(gNB_MAC_INST *nr_mac, post_process_pdsch_t *pdsch, NR_UE_info_t *UE, NR_sched_pdsch_t *sched_pdsch); void post_process_ulsch(gNB_MAC_INST *nr_mac, post_process_pusch_t *pusch, NR_UE_info_t *UE, NR_sched_pusch_t *sched_pusch); + +float nr_mac_get_snr(const nr_power_control_t *pc); +void nr_mac_pc_snr(nr_power_control_t *pc, int snrx10, int rssi); +void nr_mac_set_target_snrx10(nr_power_control_t *pc, int target_snrx10); +void nr_mac_set_rssi_threshold(nr_power_control_t *pc, int rssi_threshold); +void nr_mac_signal_dtx(nr_power_control_t *pc); +int nr_mac_get_tpc(nr_power_control_t *pc); + #endif /*__LAYER2_NR_MAC_PROTO_H__*/ diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c index d14696db74..19fe908906 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c +++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c @@ -560,7 +560,7 @@ static NR_UE_info_t *create_new_UE(gNB_MAC_INST *mac, uint32_t cu_id, const NR_C bool success = du_add_f1_ue_data(rnti, &new_ue_data); DevAssert(success); - NR_UE_info_t *UE = get_new_nr_ue_inst(&mac->UE_info.uid_allocator, rnti, NULL); + NR_UE_info_t *UE = get_new_nr_ue_inst(&mac->UE_info.uid_allocator, rnti, NULL, &mac->radio_config); AssertFatal(UE->uid < MAX_MOBILES_PER_GNB, "cannot create UE context, UE context setup failure not implemented\n"); NR_CellGroupConfig_t *cellGroupConfig = NULL; diff --git a/openair2/LAYER2/NR_MAC_gNB/main.c b/openair2/LAYER2/NR_MAC_gNB/main.c index 7b32665717..babbeb5e47 100644 --- a/openair2/LAYER2/NR_MAC_gNB/main.c +++ b/openair2/LAYER2/NR_MAC_gNB/main.c @@ -219,9 +219,11 @@ size_t dump_mac_stats(gNB_MAC_INST *gNB, char *output, size_t strlen, bool reset for (int i = 1; i < gNB->ul_bler.harq_round_max; i++) output = st_append(output, end, "/%"PRIu64, stats->ul.rounds[i]); + float snr = nr_mac_get_snr(&sched_ctrl->pusch_pc); + float diff_target = (snr * 10.0f - sched_ctrl->pusch_pc.target_snrx10) / 10.0f; output = st_append(output, end, - ", ulsch_errors %"PRIu64", ulsch_DTX %d, BLER %.5f MCS (%d) %d (Qm %d deltaMCS %d dB) NPRB %d SNR %d.%d dB CCE fail %d\n", + ", ulsch_errors %"PRIu64", ulsch_DTX %d, BLER %.5f MCS (%d) %d (Qm %d deltaMCS %d dB) NPRB %d SNR %.1f (%+.1f) dB CCE fail %d\n", stats->ul.errors, stats->ulsch_DTX, sched_ctrl->ul_bler_stats.bler, @@ -230,8 +232,8 @@ size_t dump_mac_stats(gNB_MAC_INST *gNB, char *output, size_t strlen, bool reset nr_get_Qm_ul(sched_ctrl->ul_bler_stats.mcs,UE->current_UL_BWP.mcs_table), UE->mac_stats.deltaMCS, UE->mac_stats.NPRB, - sched_ctrl->pusch_snrx10 / 10, - sched_ctrl->pusch_snrx10 % 10, + snr, + diff_target, sched_ctrl->ul_cce_fail); output = st_append(output, end, diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index 9677c6c2f4..0d7b8db12f 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -616,6 +616,14 @@ typedef struct nr_lc_config { NR_QoS_config_t qos_config[NR_MAX_NUM_QFI]; } nr_lc_config_t; +typedef struct nr_power_control { + float avg_snr; /// average SNR (in dB) + int target_snrx10; /// UE-specific target SNR x10 + float avg_rssi; /// average RSSI + int rssi_threshold; /// UE-specific RSSI threshld in 0.1dBm/dBFS, range -1280 to 0 + float tpc_in_flight; /// TPCs applied by UE but not yet in average SNR +} nr_power_control_t; + /*! \brief scheduling control information set through an API */ typedef struct { /// CCE index and aggregation, should be coherent with cce_list @@ -665,9 +673,7 @@ typedef struct { uint16_t ta_frame; int16_t ta_update; bool ta_apply; - uint8_t tpc0; uint8_t tpc1; - int pusch_snrx10; int pucch_snrx10; int pusch_consecutive_dtx_cnt; int pucch_consecutive_dtx_cnt; @@ -711,6 +717,8 @@ typedef struct { // pdcch closed loop adjust for PDCCH aggregation level, range <0, 1> // 0 - good channel, 1 - bad channel float pdcch_cl_adjust; + + nr_power_control_t pusch_pc; } NR_UE_sched_ctrl_t; typedef struct NR_mac_dir_stats { @@ -737,7 +745,6 @@ typedef struct NR_mac_stats { int cumul_sinrx10; uint8_t num_sinr_meas; char srs_stats[50]; // Statistics may differ depending on SRS usage - int pusch_snrx10; int deltaMCS; int NPRB; } NR_mac_stats_t;