diff --git a/openair2/GNB_APP/MACRLC_nr_paramdef.h b/openair2/GNB_APP/MACRLC_nr_paramdef.h index aca88b9ea7..31ee28e515 100644 --- a/openair2/GNB_APP/MACRLC_nr_paramdef.h +++ b/openair2/GNB_APP/MACRLC_nr_paramdef.h @@ -60,6 +60,11 @@ #define CONFIG_STRING_MACRLC_PUCCHTARGETSNRX10 "pucch_TargetSNRx10" #define CONFIG_STRING_MACRLC_PUCCHFAILURETHRES "pucch_FailureThres" #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" + /*-------------------------------------------------------------------------------------------------------------------------------------------------------*/ /* MacRLC configuration parameters */ @@ -88,6 +93,10 @@ {CONFIG_STRING_MACRLC_PUCCHTARGETSNRX10, NULL, 0, iptr:NULL, defintval:150, TYPE_INT, 0}, \ {CONFIG_STRING_MACRLC_PUCCHFAILURETHRES, NULL, 0, iptr:NULL, defintval:10, TYPE_INT, 0}, \ {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:20, TYPE_UINT8, 0}, \ } #define MACRLC_CC_IDX 0 #define MACRLC_TRANSPORT_N_PREFERENCE_IDX 1 @@ -111,5 +120,10 @@ #define MACRLC_PUCCHTARGETSNRX10_IDX 19 #define MACRLC_PUCCHFAILURETHRES_IDX 20 #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 + /*---------------------------------------------------------------------------------------------------------------------------------------------------------*/ #endif diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index 7e6fd61b0e..1910ece0b2 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -697,6 +697,10 @@ 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_slots_inactivity = *(MacRLC_ParamList.paramarray[j][MACRLC_ULSCH_MAX_SLOTS_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); }// for (j=0;j 0 LOG_E(PHY,"No %s configuration found\n", CONFIG_STRING_MACRLC_LIST); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c index 252144be3b..708e8d8378 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c @@ -77,25 +77,28 @@ void dump_mac_stats(gNB_MAC_INST *gNB) int stroff=0; for (int UE_id = UE_info->list.head; UE_id >= 0; UE_id = UE_info->list.next[UE_id]) { stroff = sprintf(output,"UE ID %d RNTI %04x (%d/%d)\n", UE_id, UE_info->rnti[UE_id], num++, UE_info->num_UEs); - LOG_I(NR_MAC, "UE ID %d RNTI %04x (%d/%d) PH %d dB PCMAX %d dBm\n", - UE_id, - UE_info->rnti[UE_id], - num++, - UE_info->num_UEs, - UE_info->UE_sched_ctrl[UE_id].ph, - UE_info->UE_sched_ctrl[UE_id].pcmax); NR_mac_stats_t *stats = &UE_info->mac_stats[UE_id]; + const NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id]; const int avg_rsrp = stats->num_rsrp_meas > 0 ? stats->cumul_rsrp / stats->num_rsrp_meas : 0; - stroff+=sprintf(output+stroff,"UE %d: dlsch_rounds %d/%d/%d/%d, dlsch_errors %d, average RSRP %d (%d meas)\n", + LOG_I(MAC, "UE ID %d RNTI %04x (%d/%d) PH %d dB PCMAX %d dBm, average RSRP %d (%d meas)\n", + UE_id, + UE_info->rnti[UE_id], + num++, + UE_info->num_UEs, + sched_ctrl->ph, + sched_ctrl->pcmax, + avg_rsrp, + stats->num_rsrp_meas); + stroff+=sprintf(output+stroff,"UE %d: dlsch_rounds %d/%d/%d/%d, dlsch_errors %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, - avg_rsrp, stats->num_rsrp_meas); - LOG_I(NR_MAC, "UE %d: dlsch_rounds %d/%d/%d/%d, dlsch_errors %d, average RSRP %d (%d meas)\n", - UE_id, - stats->dlsch_rounds[0], stats->dlsch_rounds[1], - stats->dlsch_rounds[2], stats->dlsch_rounds[3], stats->dlsch_errors, - avg_rsrp, stats->num_rsrp_meas); + sched_ctrl->dl_bler_stats.bler, sched_ctrl->dl_bler_stats.mcs); + LOG_I(MAC, "UE %d: dlsch_rounds %d/%d/%d/%d, dlsch_errors %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, + sched_ctrl->dl_bler_stats.bler, sched_ctrl->dl_bler_stats.mcs); stats->num_rsrp_meas = 0; stats->cumul_rsrp = 0 ; stroff+=sprintf(output+stroff,"UE %d: dlsch_total_bytes %d\n", UE_id, stats->dlsch_total_bytes); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index 2cbe232fe0..04d5a30c1a 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -381,6 +381,71 @@ 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) +{ + 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]; + + 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]; + 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 - 5); + 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 = stats->dlsch_rounds[0] - bler_stats->dlsch_rounds[0]; + const int dretx = stats->dlsch_rounds[1] - bler_stats->dlsch_rounds[1]; + const int dretx2 = 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; + /* 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 < nrmac->dl_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) { @@ -600,8 +665,8 @@ void pf_dl(module_id_t module_id, continue; /* Calculate coeff */ - sched_pdsch->mcs = 9; ps->nrOfLayers = 1; + sched_pdsch->mcs = get_mcs_from_bler(module_id, /* CC_id = */ 0, frame, slot, UE_id); uint32_t tbs = pf_tbs[ps->mcsTableIdx][sched_pdsch->mcs]; coeff_ue[UE_id] = (float) tbs / thr_ue[UE_id]; LOG_D(NR_MAC,"b %d, thr_ue[%d] %f, tbs %d, coeff_ue[%d] %f\n", diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index 22da5223c0..e97397e23b 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -420,6 +420,13 @@ 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; + float bler; + float rd2_bler; + uint8_t mcs; + int dlsch_rounds[8]; +} NR_DL_bler_stats_t; // /*! As per spec 38.214 section 5.2.1.4.2 @@ -563,6 +570,10 @@ typedef struct { mac_rlc_status_resp_t rlc_status[MAX_NUM_LCID]; int lcid_mask; + + /// Estimation of HARQ from BLER + NR_DL_bler_stats_t dl_bler_stats; + uint16_t ta_frame; int16_t ta_update; bool ta_apply; @@ -754,6 +765,10 @@ typedef struct gNB_MAC_INST_s { NR_Type0_PDCCH_CSS_config_t type0_PDCCH_CSS_config[64]; bool first_MIB; + double dl_bler_target_upper; + double dl_bler_target_lower; + double dl_rd2_bler_threshold; + uint8_t dl_max_mcs; } gNB_MAC_INST; #endif /*__LAYER2_NR_MAC_GNB_H__ */