diff --git a/openair2/GNB_APP/MACRLC_nr_paramdef.h b/openair2/GNB_APP/MACRLC_nr_paramdef.h index e634f077e269c030b2ab53da28f8f2ff7e216e1e..a7bc3e85454f200f7220c39c8e345475008c1dd0 100644 --- a/openair2/GNB_APP/MACRLC_nr_paramdef.h +++ b/openair2/GNB_APP/MACRLC_nr_paramdef.h @@ -62,12 +62,15 @@ #define CONFIG_STRING_MACRLC_PUSCHFAILURETHRES "pusch_FailureThres" #define CONFIG_STRING_MACRLC_DL_BLER_TARGET_UPPER "dl_bler_target_upper" #define CONFIG_STRING_MACRLC_DL_BLER_TARGET_LOWER "dl_bler_target_lower" -#define CONFIG_STRING_MACRLC_DL_RD2_BLER_THRESHOLD "dl_rd2_bler_threshold" #define CONFIG_STRING_MACRLC_DL_MAX_MCS "dl_max_mcs" +#define CONFIG_STRING_MACRLC_UL_BLER_TARGET_UPPER "ul_bler_target_upper" +#define CONFIG_STRING_MACRLC_UL_BLER_TARGET_LOWER "ul_bler_target_lower" +#define CONFIG_STRING_MACRLC_UL_MAX_MCS "ul_max_mcs" #define CONFIG_STRING_MACRLC_HARQ_ROUND_MAX "harq_round_max" #define CONFIG_STRING_MACRLC_MIN_GRANT_PRB "min_grant_prb" #define CONFIG_STRING_MACRLC_MIN_GRANT_MCS "min_grant_mcs" + /*-------------------------------------------------------------------------------------------------------------------------------------------------------*/ /* MacRLC configuration parameters */ /* optname helpstr paramflags XXXptr defXXXval type numelt */ @@ -97,8 +100,10 @@ {CONFIG_STRING_MACRLC_PUSCHFAILURETHRES, NULL, 0, iptr:NULL, defintval:10, TYPE_INT, 0}, \ {CONFIG_STRING_MACRLC_DL_BLER_TARGET_UPPER, "Upper threshold of BLER to decrease DL MCS", 0, dblptr:NULL, defdblval:0.15, TYPE_DOUBLE, 0}, \ {CONFIG_STRING_MACRLC_DL_BLER_TARGET_LOWER, "Lower threshold of BLER to increase DL MCS", 0, dblptr:NULL, defdblval:0.05, TYPE_DOUBLE, 0}, \ -{CONFIG_STRING_MACRLC_DL_RD2_BLER_THRESHOLD, "Threshold of RD2/RETX2 BLER to decrease DL MCS", 0, dblptr:NULL, defdblval:0.01, TYPE_DOUBLE, 0}, \ {CONFIG_STRING_MACRLC_DL_MAX_MCS, "Maximum DL MCS that should be used", 0, u8ptr:NULL, defintval:28, TYPE_UINT8, 0}, \ +{CONFIG_STRING_MACRLC_UL_BLER_TARGET_UPPER, "Upper threshold of BLER to decrease UL MCS", 0, dblptr:NULL, defdblval:0.15, TYPE_DOUBLE, 0}, \ +{CONFIG_STRING_MACRLC_UL_BLER_TARGET_LOWER, "Lower threshold of BLER to increase UL MCS", 0, dblptr:NULL, defdblval:0.05, TYPE_DOUBLE, 0}, \ +{CONFIG_STRING_MACRLC_UL_MAX_MCS, "Maximum UL MCS that should be used", 0, u8ptr:NULL, defintval:9, TYPE_UINT8, 0}, \ {CONFIG_STRING_MACRLC_HARQ_ROUND_MAX, "Maximum number of HARQ rounds", 0, u8ptr:NULL, defintval:4, TYPE_UINT8, 0}, \ {CONFIG_STRING_MACRLC_MIN_GRANT_PRB, "Minimal Periodic ULSCH Grant PRBs", 0, u8ptr:NULL, defintval:5, TYPE_UINT8, 0}, \ {CONFIG_STRING_MACRLC_MIN_GRANT_MCS, "Minimal Periodic ULSCH Grant MCS", 0, u8ptr:NULL, defintval:9, TYPE_UINT8, 0} \ @@ -127,10 +132,13 @@ #define MACRLC_PUSCHFAILURETHRES_IDX 21 #define MACRLC_DL_BLER_TARGET_UPPER_IDX 22 #define MACRLC_DL_BLER_TARGET_LOWER_IDX 23 -#define MACRLC_DL_RD2_BLER_THRESHOLD_IDX 24 -#define MACRLC_DL_MAX_MCS_IDX 25 -#define MACRLC_HARQ_ROUND_MAX_IDX 26 -#define MACRLC_MIN_GRANT_PRB_IDX 27 -#define MACRLC_MIN_GRANT_MCS_IDX 28 +#define MACRLC_DL_MAX_MCS_IDX 24 +#define MACRLC_UL_BLER_TARGET_UPPER_IDX 25 +#define MACRLC_UL_BLER_TARGET_LOWER_IDX 26 +#define MACRLC_UL_MAX_MCS_IDX 27 +#define MACRLC_HARQ_ROUND_MAX_IDX 28 +#define MACRLC_MIN_GRANT_PRB_IDX 29 +#define MACRLC_MIN_GRANT_MCS_IDX 30 + /*---------------------------------------------------------------------------------------------------------------------------------------------------------*/ #endif diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index c11d6b8092353c065864c083283dc3dcac49df6e..9292d1f96210f883899aed8725af726a5f01dd3f 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -873,10 +873,14 @@ void RCconfig_nr_macrlc() { AssertFatal(1==0,"MACRLC %d: %s unknown southbound midhaul\n",j,*(MacRLC_ParamList.paramarray[j][MACRLC_TRANSPORT_S_PREFERENCE_IDX].strptr)); } RC.nrmac[j]->ulsch_max_frame_inactivity = *(MacRLC_ParamList.paramarray[j][MACRLC_ULSCH_MAX_FRAME_INACTIVITY].uptr); - RC.nrmac[j]->dl_bler_target_upper = *(MacRLC_ParamList.paramarray[j][MACRLC_DL_BLER_TARGET_UPPER_IDX].dblptr); - RC.nrmac[j]->dl_bler_target_lower = *(MacRLC_ParamList.paramarray[j][MACRLC_DL_BLER_TARGET_LOWER_IDX].dblptr); - RC.nrmac[j]->dl_rd2_bler_threshold = *(MacRLC_ParamList.paramarray[j][MACRLC_DL_RD2_BLER_THRESHOLD_IDX].dblptr); - RC.nrmac[j]->dl_max_mcs = *(MacRLC_ParamList.paramarray[j][MACRLC_DL_MAX_MCS_IDX].u8ptr); + NR_bler_options_t *dl_bler_options = &RC.nrmac[j]->dl_bler; + dl_bler_options->upper = *(MacRLC_ParamList.paramarray[j][MACRLC_DL_BLER_TARGET_UPPER_IDX].dblptr); + dl_bler_options->lower = *(MacRLC_ParamList.paramarray[j][MACRLC_DL_BLER_TARGET_LOWER_IDX].dblptr); + dl_bler_options->max_mcs = *(MacRLC_ParamList.paramarray[j][MACRLC_DL_MAX_MCS_IDX].u8ptr); + NR_bler_options_t *ul_bler_options = &RC.nrmac[j]->ul_bler; + ul_bler_options->upper = *(MacRLC_ParamList.paramarray[j][MACRLC_UL_BLER_TARGET_UPPER_IDX].dblptr); + ul_bler_options->lower = *(MacRLC_ParamList.paramarray[j][MACRLC_UL_BLER_TARGET_LOWER_IDX].dblptr); + ul_bler_options->max_mcs = *(MacRLC_ParamList.paramarray[j][MACRLC_UL_MAX_MCS_IDX].u8ptr); RC.nrmac[j]->harq_round_max = *(MacRLC_ParamList.paramarray[j][MACRLC_HARQ_ROUND_MAX_IDX].u8ptr); RC.nrmac[j]->min_grant_prb = *(MacRLC_ParamList.paramarray[j][MACRLC_MIN_GRANT_PRB_IDX].u8ptr); RC.nrmac[j]->min_grant_mcs = *(MacRLC_ParamList.paramarray[j][MACRLC_MIN_GRANT_MCS_IDX].u8ptr); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c index 20951be0e845c57008cb44efb5c971827aed6728..e95899ecea173addf305c07aa44b153ce0e51c66 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c @@ -1983,8 +1983,8 @@ void nr_check_Msg4_Ack(module_id_t module_id, int CC_id, frame_t frame, sub_fram if (harq->is_waiting == 0) { if (harq->round == 0) { - if (stats->dlsch_errors == 0) { - LOG_I(NR_MAC, "(ue %i, rnti 0x%04x) Received Ack of RA-Msg4. CBRA procedure succeeded!\n", UE_id, ra->rnti); + if (stats->dl.errors == 0) { + LOG_A(NR_MAC, "(ue %i, rnti 0x%04x) Received Ack of RA-Msg4. CBRA procedure succeeded!\n", UE_id, ra->rnti); UE_info->active[UE_id] = true; UE_info->Msg4_ACKed[UE_id] = true; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index 221dd0b5cecc058440742dfd8e98ad33935cd3cc..aab77c515a2c291d77593048838ad345b202d1ac 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -397,81 +397,6 @@ int nr_write_ce_dlsch_pdu(module_id_t module_idP, return offset; } -#define BLER_UPDATE_FRAME 10 -#define BLER_FILTER 0.9f -int get_mcs_from_bler(module_id_t mod_id, int CC_id, frame_t frame, sub_frame_t slot, int UE_id, int mcs_table) { - gNB_MAC_INST *nrmac = RC.nrmac[mod_id]; - const NR_ServingCellConfigCommon_t *scc = nrmac->common_channels[CC_id].ServingCellConfigCommon; - const int n = nr_slots_per_frame[*scc->ssbSubcarrierSpacing]; - int max_allowed_mcs = (mcs_table == 1) ? 27 : 28; - int max_mcs = nrmac->dl_max_mcs; - - if (nrmac->dl_max_mcs>max_allowed_mcs) - max_mcs = max_allowed_mcs; - - NR_DL_bler_stats_t *bler_stats = &nrmac->UE_info.UE_sched_ctrl[UE_id].dl_bler_stats; - - /* first call: everything is zero. Initialize to sensible default */ - if (bler_stats->last_frame_slot == 0 && bler_stats->mcs == 0) { - bler_stats->last_frame_slot = frame * n + slot; - bler_stats->mcs = 9; - bler_stats->bler = (nrmac->dl_bler_target_lower + nrmac->dl_bler_target_upper) / 2; - bler_stats->rd2_bler = nrmac->dl_rd2_bler_threshold; - } - - const int now = frame * n + slot; - int diff = now - bler_stats->last_frame_slot; - - if (diff < 0) // wrap around - diff += 1024 * n; - - const uint8_t old_mcs = bler_stats->mcs; - const NR_mac_stats_t *stats = &nrmac->UE_info.mac_stats[UE_id]; - - // TODO put back this condition when relevant - /*const int dret3x = stats->dlsch_rounds[3] - bler_stats->dlsch_rounds[3]; - if (dret3x > 0) { - if there is a third retransmission, decrease MCS for stabilization and - restart averaging window to stabilize transmission - bler_stats->last_frame_slot = now; - bler_stats->mcs = max(9, bler_stats->mcs - 1); - memcpy(bler_stats->dlsch_rounds, stats->dlsch_rounds, sizeof(stats->dlsch_rounds)); - LOG_D(MAC, "%4d.%2d: %d retx in 3rd round, setting MCS to %d and restarting window\n", frame, slot, dret3x, bler_stats->mcs); - return bler_stats->mcs; - }*/ - if (diff < BLER_UPDATE_FRAME * n) - return old_mcs; // no update - - // last update is longer than x frames ago - const int dtx = (int)(stats->dlsch_rounds[0] - bler_stats->dlsch_rounds[0]); - const int dretx = (int)(stats->dlsch_rounds[1] - bler_stats->dlsch_rounds[1]); - const int dretx2 = (int)(stats->dlsch_rounds[2] - bler_stats->dlsch_rounds[2]); - const float bler_window = dtx > 0 ? (float) dretx / dtx : bler_stats->bler; - const float rd2_bler_wnd = dtx > 0 ? (float) dretx2 / dtx : bler_stats->rd2_bler; - bler_stats->bler = BLER_FILTER * bler_stats->bler + (1 - BLER_FILTER) * bler_window; - bler_stats->rd2_bler = BLER_FILTER / 4 * bler_stats->rd2_bler + (1 - BLER_FILTER / 4) * rd2_bler_wnd; - int new_mcs = old_mcs; - - // TODO put back this condition when relevant - /* first ensure that number of 2nd retx is below threshold. If this is the - * case, use 1st retx to adjust faster - if (bler_stats->rd2_bler > nrmac->dl_rd2_bler_threshold && old_mcs > 6) { - new_mcs -= 2; - } else if (bler_stats->rd2_bler < nrmac->dl_rd2_bler_threshold) {*/ - if (bler_stats->bler < nrmac->dl_bler_target_lower && old_mcs < max_mcs && dtx > 9) - new_mcs += 1; - else if (bler_stats->bler > nrmac->dl_bler_target_upper && old_mcs > 6) - new_mcs -= 1; - - // else we are within threshold boundaries - bler_stats->last_frame_slot = now; - bler_stats->mcs = new_mcs; - memcpy(bler_stats->dlsch_rounds, stats->dlsch_rounds, sizeof(stats->dlsch_rounds)); - LOG_D(MAC, "%4d.%2d MCS %d -> %d (dtx %d, dretx %d, BLER wnd %.3f avg %.6f, dretx2 %d, RD2 BLER wnd %.3f avg %.6f)\n", - frame, slot, old_mcs, new_mcs, dtx, dretx, bler_window, bler_stats->bler, dretx2, rd2_bler_wnd, bler_stats->rd2_bler); - return new_mcs; -} - void nr_store_dlsch_buffer(module_id_t module_id, frame_t frame, sub_frame_t slot) { @@ -742,6 +667,7 @@ void pf_dl(module_id_t module_id, if (sched_ctrl->ul_failure==1 && get_softmodem_params()->phy_test==0) continue; + const NR_mac_dir_stats_t *stats = &UE_info->mac_stats[UE_id].dl; NR_sched_pdsch_t *sched_pdsch = &sched_ctrl->sched_pdsch; NR_pdsch_semi_static_t *ps = &sched_ctrl->pdsch_semi_static; /* get the PID of a HARQ process awaiting retrnasmission, or -1 otherwise */ @@ -749,7 +675,7 @@ void pf_dl(module_id_t module_id, layers[UE_id] = ps->nrOfLayers; // initialization of layers to the previous value in the strcuture /* Calculate Throughput */ const float a = 0.0005f; // corresponds to 200ms window - const uint32_t b = UE_info->mac_stats[UE_id].dlsch_current_bytes; + const uint32_t b = stats->current_bytes; thr_ue[UE_id] = (1 - a) * thr_ue[UE_id] + a * b; /* retransmission */ @@ -772,8 +698,10 @@ void pf_dl(module_id_t module_id, continue; /* Calculate coeff */ - set_dl_mcs(sched_pdsch,sched_ctrl,&mac->dl_max_mcs,ps->mcsTableIdx); - sched_pdsch->mcs = get_mcs_from_bler(module_id, /* CC_id = */ 0, frame, slot, UE_id, ps->mcsTableIdx); + const NR_bler_options_t *bo = &mac->dl_bler; + const int max_mcs_table = ps->mcsTableIdx == 1 ? 27 : 28; + const int max_mcs = min(sched_ctrl->dl_max_mcs, max_mcs_table); + sched_pdsch->mcs = get_mcs_from_bler(bo, stats, &sched_ctrl->dl_bler_stats, max_mcs, frame); layers[UE_id] = set_dl_nrOfLayers(sched_ctrl); const uint8_t Qm = nr_get_Qm_dl(sched_pdsch->mcs, ps->mcsTableIdx); const uint16_t R = nr_get_code_rate_dl(sched_pdsch->mcs, ps->mcsTableIdx); @@ -1091,7 +1019,7 @@ void nr_schedule_ue_spec(module_id_t module_id, if (sched_ctrl->ul_failure==1 && get_softmodem_params()->phy_test==0) continue; NR_sched_pdsch_t *sched_pdsch = &sched_ctrl->sched_pdsch; - UE_info->mac_stats[UE_id].dlsch_current_bytes = 0; + UE_info->mac_stats[UE_id].dl.current_bytes = 0; NR_CellGroupConfig_t *cg = UE_info->CellGroup[UE_id]; NR_BWP_DownlinkDedicated_t *bwpd = @@ -1149,7 +1077,7 @@ void nr_schedule_ue_spec(module_id_t module_id, harq->feedback_frame = pucch->frame; harq->feedback_slot = pucch->ul_slot; harq->is_waiting = true; - UE_info->mac_stats[UE_id].dlsch_rounds[harq->round]++; + UE_info->mac_stats[UE_id].dl.rounds[harq->round]++; LOG_D(NR_MAC, "%4d.%2d [DLSCH/PDSCH/PUCCH] UE %d RNTI %04x DCI L %d start %3d RBs %3d startSymbol %2d nb_symbol %2d dmrspos %x MCS %2d nrOfLayers %d TBS %4d HARQ PID %2d round %d RV %d NDI %d dl_data_to_ULACK %d (%d.%d) PUCCH allocation %d TPC %d\n", frame, @@ -1483,7 +1411,7 @@ void nr_schedule_ue_spec(module_id_t module_id, lcid_bytes += len; } - UE_info->mac_stats[UE_id].lc_bytes_tx[lcid] += lcid_bytes; + UE_info->mac_stats[UE_id].dl.lc_bytes[lcid] += lcid_bytes; } } else if (get_softmodem_params()->phy_test || get_softmodem_params()->do_ra) { /* we will need the large header, phy-test typically allocates all @@ -1521,8 +1449,10 @@ void nr_schedule_ue_spec(module_id_t module_id, buf=bufEnd; } - UE_info->mac_stats[UE_id].dlsch_total_bytes += TBS; - UE_info->mac_stats[UE_id].dlsch_current_bytes = TBS; + NR_mac_stats_t *mac_stats = &UE_info->mac_stats[UE_id]; + mac_stats->dl.total_bytes += TBS; + mac_stats->dl.current_bytes = TBS; + /* save retransmission information */ harq->sched_pdsch = *sched_pdsch; /* save which time allocation has been used, to be used on diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index 86349146a0dfe74db80a3b5764434be16409eeb3..9141bc78b43979337a8a2a72e4b7417071b486e9 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -145,7 +145,6 @@ uint8_t set_dl_nrOfLayers(NR_UE_sched_ctrl_t *sched_ctrl) { } - uint16_t set_pm_index(NR_UE_sched_ctrl_t *sched_ctrl, int layers, int N1, int N2, @@ -169,51 +168,45 @@ uint16_t set_pm_index(NR_UE_sched_ctrl_t *sched_ctrl, AssertFatal(1==0,"More than 2 antenna ports not yet supported\n"); } +uint8_t get_mcs_from_cqi(int mcs_table, int cqi_table, int cqi_idx) +{ + if (cqi_idx <= 0) { + LOG_E(NR_MAC, "invalid cqi_idx %d, default to MCS 9\n", cqi_idx); + return 9; + } -void set_dl_mcs(NR_sched_pdsch_t *sched_pdsch, - NR_UE_sched_ctrl_t *sched_ctrl, - uint8_t *target_mcs, - uint8_t mcs_table_idx) { - - if (sched_ctrl->set_mcs) { - // TODO for wideband case and multiple TB - int cqi_idx = sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.wb_cqi_1tb; - uint16_t target_coderate,target_qm; - if (cqi_idx>0) { - int cqi_table = sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.cqi_table; - if (cqi_table != mcs_table_idx) - LOG_W(NR_MAC,"Indices of MCS tables don't correspond yet, cri_ri_li_pmi_cqi_report.cqi_table %d, mcs_table_index %d\n",cqi_table,mcs_table_idx); - switch (cqi_table) { - case 0: - target_qm = cqi_table1[cqi_idx][0]; - target_coderate = cqi_table1[cqi_idx][1]; - break; - case 1: - target_qm = cqi_table2[cqi_idx][0]; - target_coderate = cqi_table2[cqi_idx][1]; - break; - case 2: - target_qm = cqi_table3[cqi_idx][0]; - target_coderate = cqi_table3[cqi_idx][1]; - break; - default: - AssertFatal(1==0,"Invalid cqi table index %d\n",cqi_table); - } - int max_mcs = 28; - int R,Qm; - if (mcs_table_idx == 1) - max_mcs = 27; - for (int i=0; i<=max_mcs; i++) { - R = nr_get_code_rate_dl(i, mcs_table_idx); - Qm = nr_get_Qm_dl(i, mcs_table_idx); - if ((Qm == target_qm) && (target_coderate <= R)) { - *target_mcs = i; - break; - } - } - } - sched_ctrl->set_mcs = false; + if (mcs_table != cqi_table) { + LOG_E(NR_MAC, "indices of CQI (%d) and MCS (%d) tables don't correspond yet\n", cqi_table, mcs_table); + return 9; } + + uint16_t target_coderate, target_qm; + switch (cqi_table) { + case 0: + target_qm = cqi_table1[cqi_idx][0]; + target_coderate = cqi_table1[cqi_idx][1]; + break; + case 1: + target_qm = cqi_table2[cqi_idx][0]; + target_coderate = cqi_table2[cqi_idx][1]; + break; + case 2: + target_qm = cqi_table3[cqi_idx][0]; + target_coderate = cqi_table3[cqi_idx][1]; + break; + default: + AssertFatal(1==0,"Invalid cqi table index %d\n",cqi_table); + } + const int max_mcs = mcs_table == 1 ? 27 : 28; + for (int i = 0; i <= max_mcs; i++) { + const int R = nr_get_code_rate_dl(i, mcs_table); + const int Qm = nr_get_Qm_dl(i, mcs_table); + if (Qm == target_qm && target_coderate <= R) + return i; + } + + LOG_E(NR_MAC, "could not find maximum MCS from cqi_idx %d, default to 9\n", cqi_idx); + return 9; } void set_dl_dmrs_ports(NR_pdsch_semi_static_t *ps) { @@ -768,6 +761,51 @@ void nr_set_pusch_semi_static(const NR_SIB1_t *sib1, : num_dmrs_cdm_grps_no_data * 4; } +#define BLER_UPDATE_FRAME 10 +#define BLER_FILTER 0.9f +int get_mcs_from_bler(const NR_bler_options_t *bler_options, + const NR_mac_dir_stats_t *stats, + NR_bler_stats_t *bler_stats, + int max_mcs, + frame_t frame) +{ + /* first call: everything is zero. Initialize to sensible default */ + if (bler_stats->last_frame == 0 && bler_stats->mcs == 0) { + bler_stats->last_frame = frame; + bler_stats->mcs = 9; + bler_stats->bler = (bler_options->lower + bler_options->upper) / 2.0f; + } + int diff = frame - bler_stats->last_frame; + if (diff < 0) // wrap around + diff += 1024; + + max_mcs = min(max_mcs, bler_options->max_mcs); + const uint8_t old_mcs = min(bler_stats->mcs, max_mcs); + if (diff < BLER_UPDATE_FRAME) + return old_mcs; // no update + + // last update is longer than x frames ago + const int dtx = (int)(stats->rounds[0] - bler_stats->rounds[0]); + const int dretx = (int)(stats->rounds[1] - bler_stats->rounds[1]); + const float bler_window = dtx > 0 ? (float) dretx / dtx : bler_stats->bler; + bler_stats->bler = BLER_FILTER * bler_stats->bler + (1 - BLER_FILTER) * bler_window; + + int new_mcs = old_mcs; + if (bler_stats->bler < bler_options->lower && old_mcs < max_mcs && dtx > 9) + new_mcs += 1; + else if ((bler_stats->bler > bler_options->upper && old_mcs > 6) // above threshold + || (dtx <= 3 && old_mcs > 9)) // no activity + new_mcs -= 1; + // else we are within threshold boundaries + + bler_stats->last_frame = frame; + bler_stats->mcs = new_mcs; + memcpy(bler_stats->rounds, stats->rounds, sizeof(stats->rounds)); + LOG_D(MAC, "frame %4d MCS %d -> %d (dtx %d, dretx %d, BLER wnd %.3f avg %.6f)\n", + frame, old_mcs, new_mcs, dtx, dretx, bler_window, bler_stats->bler); + return new_mcs; +} + void nr_configure_css_dci_initial(nfapi_nr_dl_tti_pdcch_pdu_rel15_t* pdcch_pdu, nr_scs_e scs_common, nr_scs_e pdcch_scs, @@ -2359,7 +2397,7 @@ int add_new_nr_ue(module_id_t mod_idP, rnti_t rntiP, NR_CellGroupConfig_t *CellG compute_csi_bitlen (CellGroup->spCellConfig->spCellConfigDedicated->csi_MeasConfig->choice.setup, UE_info, UE_id, mod_idP); NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id]; memset(sched_ctrl, 0, sizeof(*sched_ctrl)); - sched_ctrl->set_mcs = true; + sched_ctrl->dl_max_mcs = 28; /* do not limit MCS for individual UEs */ sched_ctrl->set_pmi = false; sched_ctrl->ta_frame = 0; sched_ctrl->ta_update = 31; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c index a29aa8018cd5b679da1a3f7d3f82fe5cfd8f9cc2..b9292876e350101907409e9843e5c1f3166cd64b 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c @@ -838,8 +838,8 @@ static void handle_dl_harq(module_id_t mod_id, harq->round = 0; harq->ndi ^= 1; NR_mac_stats_t *stats = &UE_info->mac_stats[UE_id]; - stats->dlsch_errors++; - LOG_D(NR_MAC, "retransmission error for UE %d (total %"PRIu64")\n", UE_id, stats->dlsch_errors); + stats->dl.errors++; + LOG_D(NR_MAC, "retransmission error for UE %d (total %"PRIu64")\n", UE_id, stats->dl.errors); } else { LOG_D(PHY,"NACK for: pid %d, ue %x\n",harq_pid, UE_id); add_tail_nr_list(&UE_info->UE_sched_ctrl[UE_id].retrans_dl_harq, harq_pid); @@ -1250,7 +1250,12 @@ void evaluate_cqi_report(uint8_t *payload, sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.wb_cqi_2tb = temp_cqi; LOG_D(MAC,"Wide-band CQI for the second TB %d\n", temp_cqi); } - sched_ctrl->set_mcs = true; + + // TODO for wideband case and multiple TB + const int cqi_idx = sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.wb_cqi_1tb; + const int mcs_table = sched_ctrl->pdsch_semi_static.mcsTableIdx; + const int cqi_table = sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.cqi_table; + sched_ctrl->dl_max_mcs = get_mcs_from_cqi(mcs_table, cqi_table, cqi_idx); } diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index 2fce141e7e2c5a37739f18943ec48bd1483eb97a..747808bfa893e100f43158e4e3371d6a8fda2a8a 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -464,7 +464,7 @@ int nr_process_mac_pdu(module_id_t module_idP, rx_lcid, module_idP, mac_len); - UE_info->mac_stats[UE_id].lc_bytes_rx[rx_lcid] += mac_len; + UE_info->mac_stats[UE_id].ul.lc_bytes[rx_lcid] += mac_len; mac_rlc_data_ind(module_idP, UE_info->rnti[UE_id], @@ -526,7 +526,7 @@ void abort_nr_ul_harq(module_id_t mod_id, int UE_id, int8_t harq_pid) harq->ndi ^= 1; harq->round = 0; - UE_info->mac_stats[UE_id].ulsch_errors++; + UE_info->mac_stats[UE_id].ul.errors++; add_tail_nr_list(&sched_ctrl->available_ul_harq, harq_pid); /* the transmission failed: the UE won't send the data we expected initially, @@ -637,7 +637,7 @@ void nr_rx_sdu(const module_id_t gnb_mod_idP, T_INT(rntiP), T_INT(frameP), T_INT(slotP), T_INT(harq_pid), T_BUFFER(sduP, sdu_lenP)); - UE_info->mac_stats[UE_id].ulsch_total_bytes_rx += sdu_lenP; + UE_info->mac_stats[UE_id].ul.total_bytes += sdu_lenP; LOG_D(NR_MAC, "[gNB %d][PUSCH %d] CC_id %d %d.%d Received ULSCH sdu from PHY (rnti %x, UE_id %d) ul_cqi %d TA %d sduP %p, rssi %d\n", gnb_mod_idP, harq_pid, @@ -1174,10 +1174,11 @@ void pf_ul(module_id_t module_id, const uint16_t bwpSize = NRRIV2BW(genericParameters->locationAndBandwidth, MAX_BWP_SIZE); NR_sched_pusch_t *sched_pusch = &sched_ctrl->sched_pusch; NR_pusch_semi_static_t *ps = &sched_ctrl->pusch_semi_static; + const NR_mac_dir_stats_t *stats = &UE_info->mac_stats[UE_id].ul; /* Calculate throughput */ const float a = 0.0005f; // corresponds to 200ms window - const uint32_t b = UE_info->mac_stats[UE_id].ulsch_current_bytes; + const uint32_t b = stats->current_bytes; ul_thr_ue[UE_id] = (1 - a) * ul_thr_ue[UE_id] + a * b; /* Check if retransmission is necessary */ @@ -1209,6 +1210,10 @@ void pf_ul(module_id_t module_id, continue; } + const NR_bler_options_t *bo = &nrmac->ul_bler; + const int max_mcs = bo->max_mcs; /* no per-user maximum MCS yet */ + sched_pusch->mcs = get_mcs_from_bler(bo, stats, &sched_ctrl->ul_bler_stats, max_mcs, frame); + /* Schedule UE on SR or UL inactivity and no data (otherwise, will be scheduled * based on data to transmit) */ if (B == 0 && do_sched) { @@ -1284,7 +1289,7 @@ void pf_ul(module_id_t module_id, sched_ctrl->aggregation_level); NR_sched_pusch_t *sched_pusch = &sched_ctrl->sched_pusch; - sched_pusch->mcs = nrmac->min_grant_mcs; + sched_pusch->mcs = min(nrmac->min_grant_mcs, sched_pusch->mcs); update_ul_ue_R_Qm(sched_pusch, ps); sched_pusch->rbStart = rbStart; sched_pusch->rbSize = min_rb; @@ -1310,7 +1315,6 @@ void pf_ul(module_id_t module_id, add_tail_nr_list(&UE_sched, UE_id); /* Calculate coefficient*/ - sched_pusch->mcs = nrmac->min_grant_mcs; const uint32_t tbs = ul_pf_tbs[ps->mcs_table][sched_pusch->mcs]; coeff_ue[UE_id] = (float) tbs / ul_thr_ue[UE_id]; LOG_D(NR_MAC,"b %d, ul_thr_ue[%d] %f, tbs %d, coeff_ue[%d] %f\n", @@ -1652,7 +1656,8 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot) cg->spCellConfig->spCellConfigDedicated->uplinkConfig ? cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP : NULL; - UE_info->mac_stats[UE_id].ulsch_current_bytes = 0; + NR_mac_stats_t *mac_stats = &UE_info->mac_stats[UE_id]; + mac_stats->ul.current_bytes = 0; /* dynamic PUSCH values (RB alloc, MCS, hence R, Qm, TBS) that change in * every TTI are pre-populated by the preprocessor and used below */ @@ -1696,10 +1701,10 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot) NR_pusch_semi_static_t *ps = &sched_ctrl->pusch_semi_static; /* Statistics */ - AssertFatal(cur_harq->round < 8, "Indexing ulsch_rounds[%d] is out of bounds\n", cur_harq->round); - UE_info->mac_stats[UE_id].ulsch_rounds[cur_harq->round]++; + AssertFatal(cur_harq->round < 8, "Indexing UL rounds[%d] is out of bounds\n", cur_harq->round); + mac_stats->ul.rounds[cur_harq->round]++; if (cur_harq->round == 0) { - UE_info->mac_stats[UE_id].ulsch_total_bytes_scheduled += sched_pusch->tb_size; + mac_stats->ulsch_total_bytes_scheduled += sched_pusch->tb_size; /* Save information on MCS, TBS etc for the current initial transmission * so we have access to it when retransmitting */ cur_harq->sched_pusch = *sched_pusch; @@ -1719,7 +1724,7 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot) cur_harq->round, cur_harq->ndi); } - UE_info->mac_stats[UE_id].ulsch_current_bytes = sched_pusch->tb_size; + mac_stats->ul.current_bytes = sched_pusch->tb_size; sched_ctrl->last_ul_frame = sched_pusch->frame; sched_ctrl->last_ul_slot = sched_pusch->slot; diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index cfb6573f4923adb71027b567175d4521846ca6ff..da234fe30a2ef76b397c79eb2ccf8dfe93ec6698 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -507,10 +507,7 @@ uint16_t set_pm_index(NR_UE_sched_ctrl_t *sched_ctrl, int xp_pdsch_antenna_ports, int codebook_mode); -void set_dl_mcs(NR_sched_pdsch_t *sched_pdsch, - NR_UE_sched_ctrl_t *sched_ctrl, - uint8_t *target_mcs, - uint8_t mcs_table_idx); +uint8_t get_mcs_from_cqi(int mcs_table, int cqi_table, int cqi_idx); uint8_t set_dl_nrOfLayers(NR_UE_sched_ctrl_t *sched_ctrl); @@ -531,6 +528,12 @@ bool nr_find_nb_rb(uint16_t Qm, uint32_t *tbs, uint16_t *nb_rb); +int get_mcs_from_bler(const NR_bler_options_t *bler_options, + const NR_mac_dir_stats_t *stats, + NR_bler_stats_t *bler_stats, + int max_mcs, + frame_t frame); + void nr_sr_reporting(int Mod_idP, frame_t frameP, sub_frame_t slotP); void dump_mac_stats(gNB_MAC_INST *gNB, char *output, int strlen, bool reset_rsrp); diff --git a/openair2/LAYER2/NR_MAC_gNB/main.c b/openair2/LAYER2/NR_MAC_gNB/main.c index e047494b5296666e55510465702e5f7a72429f68..4c14233a32ad9a658b1850db8713f4e063af8f51 100644 --- a/openair2/LAYER2/NR_MAC_gNB/main.c +++ b/openair2/LAYER2/NR_MAC_gNB/main.c @@ -102,9 +102,9 @@ void dump_mac_stats(gNB_MAC_INST *gNB, char *output, int strlen, bool reset_rsrp stroff+=sprintf(output+stroff,"UE %d: dlsch_rounds %"PRIu64"/%"PRIu64"/%"PRIu64"/%"PRIu64", dlsch_errors %"PRIu64", pucch0_DTX %d, BLER %.5f MCS %d\n", UE_id, - stats->dlsch_rounds[0], stats->dlsch_rounds[1], - stats->dlsch_rounds[2], stats->dlsch_rounds[3], - stats->dlsch_errors, + stats->dl.rounds[0], stats->dl.rounds[1], + stats->dl.rounds[2], stats->dl.rounds[3], + stats->dl.errors, stats->pucch0_DTX, sched_ctrl->dl_bler_stats.bler, sched_ctrl->dl_bler_stats.mcs); @@ -112,25 +112,27 @@ void dump_mac_stats(gNB_MAC_INST *gNB, char *output, int strlen, bool reset_rsrp stats->num_rsrp_meas = 0; stats->cumul_rsrp = 0; } - stroff+=sprintf(output+stroff,"UE %d: dlsch_total_bytes %"PRIu64"\n", UE_id, stats->dlsch_total_bytes); - stroff+=sprintf(output+stroff,"UE %d: ulsch_rounds %"PRIu64"/%"PRIu64"/%"PRIu64"/%"PRIu64", ulsch_DTX %d, ulsch_errors %"PRIu64"\n", + stroff+=sprintf(output+stroff,"UE %d: dlsch_total_bytes %"PRIu64"\n", UE_id, stats->dl.total_bytes); + stroff+=sprintf(output+stroff,"UE %d: ulsch_rounds %"PRIu64"/%"PRIu64"/%"PRIu64"/%"PRIu64", ulsch_DTX %d, ulsch_errors %"PRIu64", BLER %.5f MCS %d\n", UE_id, - stats->ulsch_rounds[0], stats->ulsch_rounds[1], - stats->ulsch_rounds[2], stats->ulsch_rounds[3], + stats->ul.rounds[0], stats->ul.rounds[1], + stats->ul.rounds[2], stats->ul.rounds[3], stats->ulsch_DTX, - stats->ulsch_errors); + stats->ul.errors, + sched_ctrl->ul_bler_stats.bler, + sched_ctrl->ul_bler_stats.mcs); stroff+=sprintf(output+stroff, "UE %d: ulsch_total_bytes_scheduled %"PRIu64", ulsch_total_bytes_received %"PRIu64"\n", UE_id, - stats->ulsch_total_bytes_scheduled, stats->ulsch_total_bytes_rx); + stats->ulsch_total_bytes_scheduled, stats->ul.total_bytes); for (int lc_id = 0; lc_id < 63; lc_id++) { - if (stats->lc_bytes_tx[lc_id] > 0) { - stroff+=sprintf(output+stroff, "UE %d: LCID %d: %"PRIu64" bytes TX\n", UE_id, lc_id, stats->lc_bytes_tx[lc_id]); - LOG_D(NR_MAC, "UE %d: LCID %d: %"PRIu64" bytes TX\n", UE_id, lc_id, stats->lc_bytes_tx[lc_id]); + if (stats->dl.lc_bytes[lc_id] > 0) { + stroff+=sprintf(output+stroff, "UE %d: LCID %d: %"PRIu64" bytes TX\n", UE_id, lc_id, stats->dl.lc_bytes[lc_id]); + LOG_D(NR_MAC, "UE %d: LCID %d: %"PRIu64" bytes TX\n", UE_id, lc_id, stats->dl.lc_bytes[lc_id]); } - if (stats->lc_bytes_rx[lc_id] > 0) { - stroff+=sprintf(output+stroff, "UE %d: LCID %d: %"PRIu64" bytes RX\n", UE_id, lc_id, stats->lc_bytes_rx[lc_id]); - LOG_D(NR_MAC, "UE %d: LCID %d: %"PRIu64" bytes RX\n", UE_id, lc_id, stats->lc_bytes_rx[lc_id]); + if (stats->ul.lc_bytes[lc_id] > 0) { + stroff+=sprintf(output+stroff, "UE %d: LCID %d: %"PRIu64" bytes RX\n", UE_id, lc_id, stats->ul.lc_bytes[lc_id]); + LOG_D(NR_MAC, "UE %d: LCID %d: %"PRIu64" bytes RX\n", UE_id, lc_id, stats->ul.lc_bytes[lc_id]); } } } diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index 9d8e28da9719165f4af5bd7a16dd71a2f86991b0..99095e1dede3e0a64f6132b56e4c59f15862dd5a 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -459,13 +459,12 @@ typedef struct NR_UE_harq { //! fixme : need to enhace for the multiple TB CQI report -typedef struct NR_DL_bler_stats { - frame_t last_frame_slot; +typedef struct NR_bler_stats { + frame_t last_frame; float bler; - float rd2_bler; uint8_t mcs; - uint64_t dlsch_rounds[8]; -} NR_DL_bler_stats_t; + uint64_t rounds[8]; +} NR_bler_stats_t; // /*! As per spec 38.214 section 5.2.1.4.2 @@ -613,6 +612,9 @@ typedef struct { NR_pdsch_semi_static_t pdsch_semi_static; /// Sched PDSCH: scheduling decisions, copied into HARQ and cleared every TTI NR_sched_pdsch_t sched_pdsch; + /// UE-estimated maximum MCS (from CSI-RS) + uint8_t dl_max_mcs; + /// For UL synchronization: store last UL scheduling grant frame_t last_ul_frame; sub_frame_t last_ul_slot; @@ -624,7 +626,8 @@ typedef struct { mac_rlc_status_resp_t rlc_status[NR_MAX_NUM_LCID]; /// Estimation of HARQ from BLER - NR_DL_bler_stats_t dl_bler_stats; + NR_bler_stats_t dl_bler_stats; + NR_bler_stats_t ul_bler_stats; uint16_t ta_frame; int16_t ta_update; @@ -641,7 +644,6 @@ typedef struct { int ul_failure; struct CSI_Report CSI_report; bool SR; - bool set_mcs; bool set_pmi; /// information about every HARQ process NR_UE_harq_t harq_processes[NR_MAX_NB_HARQ_PROCESSES]; @@ -674,24 +676,29 @@ typedef struct { uicc_t *uicc; } NRUEcontext_t; -typedef struct { - uint64_t lc_bytes_tx[64]; - uint64_t lc_bytes_rx[64]; - uint64_t dlsch_rounds[8]; - uint64_t dlsch_errors; - uint64_t dlsch_total_bytes; - int dlsch_current_bytes; - uint64_t ulsch_rounds[8]; - uint64_t ulsch_errors; +typedef struct NR_mac_dir_stats { + uint64_t lc_bytes[64]; + uint64_t rounds[8]; + uint64_t errors; + uint64_t total_bytes; + uint32_t current_bytes; +} NR_mac_dir_stats_t; + +typedef struct NR_mac_stats { + NR_mac_dir_stats_t dl; + NR_mac_dir_stats_t ul; uint32_t ulsch_DTX; uint64_t ulsch_total_bytes_scheduled; - uint64_t ulsch_total_bytes_rx; - int ulsch_current_bytes; uint32_t pucch0_DTX; int cumul_rsrp; uint8_t num_rsrp_meas; } NR_mac_stats_t; +typedef struct NR_bler_options { + double upper; + double lower; + uint8_t max_mcs; +} NR_bler_options_t; /*! \brief UE list used by gNB to order UEs/CC for scheduling*/ #define MAX_CSI_REPORTCONFIG 48 @@ -833,10 +840,8 @@ typedef struct gNB_MAC_INST_s { int xp_pdsch_antenna_ports; bool first_MIB; - double dl_bler_target_upper; - double dl_bler_target_lower; - double dl_rd2_bler_threshold; - uint8_t dl_max_mcs; + NR_bler_options_t dl_bler; + NR_bler_options_t ul_bler; uint8_t harq_round_max; uint8_t min_grant_prb; uint8_t min_grant_mcs;