From 17cbc4dbf4c347b5dd3f0383f0c4130533dbd14b Mon Sep 17 00:00:00 2001
From: Robert Schmidt <robert.schmidt@openairinterface.org>
Date: Fri, 21 Jan 2022 16:55:14 +0100
Subject: [PATCH] Generalize get_mcs_from_bler()

---
 openair2/GNB_APP/MACRLC_nr_paramdef.h         | 12 ++-
 openair2/GNB_APP/gnb_config.c                 |  8 +-
 .../LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c   | 81 ++-----------------
 .../NR_MAC_gNB/gNB_scheduler_primitives.c     | 45 +++++++++++
 openair2/LAYER2/NR_MAC_gNB/mac_proto.h        |  6 ++
 openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h       | 21 ++---
 6 files changed, 77 insertions(+), 96 deletions(-)

diff --git a/openair2/GNB_APP/MACRLC_nr_paramdef.h b/openair2/GNB_APP/MACRLC_nr_paramdef.h
index e634f077e26..b7c8401971f 100644
--- a/openair2/GNB_APP/MACRLC_nr_paramdef.h
+++ b/openair2/GNB_APP/MACRLC_nr_paramdef.h
@@ -62,7 +62,6 @@
 #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_HARQ_ROUND_MAX                "harq_round_max"
 #define CONFIG_STRING_MACRLC_MIN_GRANT_PRB                 "min_grant_prb"
@@ -97,7 +96,6 @@
 {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_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}, \
@@ -127,10 +125,10 @@
 #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_HARQ_ROUND_MAX_IDX                              25
+#define MACRLC_MIN_GRANT_PRB_IDX                               26
+#define MACRLC_MIN_GRANT_MCS_IDX                               27
+
 /*---------------------------------------------------------------------------------------------------------------------------------------------------------*/
 #endif
diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c
index c11d6b80923..f57402c1843 100644
--- a/openair2/GNB_APP/gnb_config.c
+++ b/openair2/GNB_APP/gnb_config.c
@@ -873,10 +873,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_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);
       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_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c
index 3a179fbaea1..30127847dc8 100644
--- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c
+++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c
@@ -397,79 +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;
-
-  NR_UE_sched_ctrl_t *sched_ctrl = &nrmac->UE_info.UE_sched_ctrl[UE_id];
-  NR_DL_bler_stats_t *bler_stats = &sched_ctrl->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->dl.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->dl.rounds, sizeof(stats->dl.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->dl.rounds[0] - bler_stats->dlsch_rounds[0]);
-  const int dretx = (int)(stats->dl.rounds[1] - bler_stats->dlsch_rounds[1]);
-  const int dretx2 = (int)(stats->dl.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) {*/
-  const int max_mcs = min(max_allowed_mcs, min(sched_ctrl->dl_max_mcs, nrmac->dl_max_mcs));
-  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) // above threshold
-           || (dtx <= 3 && old_mcs > 9))  // no activity
-    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->dl.rounds, sizeof(stats->dl.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) {
@@ -740,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 */
@@ -747,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].dl.current_bytes;
+    const uint32_t b = stats->current_bytes;
     thr_ue[UE_id] = (1 - a) * thr_ue[UE_id] + a * b;
 
     /* retransmission */
@@ -770,7 +698,10 @@ void pf_dl(module_id_t module_id,
         continue;
 
       /* Calculate coeff */
-      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);
diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c
index 09b890a8606..933dee8be47 100644
--- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c
+++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c
@@ -761,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,
diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h
index cdb1658f55b..f645bc91482 100644
--- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h
+++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h
@@ -535,6 +535,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/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h
index 6f5f7b3d957..33fe7c8bda9 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
@@ -627,7 +626,7 @@ 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;
 
   uint16_t ta_frame;
   int16_t ta_update;
@@ -694,6 +693,11 @@ typedef struct NR_mac_stats {
   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
@@ -835,10 +839,7 @@ 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;
   uint8_t harq_round_max;
   uint8_t min_grant_prb;
   uint8_t min_grant_mcs;
-- 
GitLab