diff --git a/openair2/LAYER2/MAC/defs.h b/openair2/LAYER2/MAC/defs.h
index 020be61fb1a7b72428a60332f7138668aed889b0..a16b1450396e56bb007c6049b75960846cf62fb7 100644
--- a/openair2/LAYER2/MAC/defs.h
+++ b/openair2/LAYER2/MAC/defs.h
@@ -757,7 +757,11 @@ typedef struct {
   uint32_t pusch_tpc_tx_subframe;
   uint32_t pucch_tpc_tx_frame;
   uint32_t pucch_tpc_tx_subframe;
-
+  
+  /// stores the frame where the last bler was calculated
+  uint32_t pusch_bler_calc_frame;
+  uint32_t pusch_bler_calc_subframe;
+  
 #ifdef LOCALIZATION
   eNB_UE_estimated_distances distance;
 #endif
@@ -833,6 +837,12 @@ typedef struct {
   uint8_t       pusch_snr[NFAPI_CC_MAX];
   uint8_t       pusch_snr_avg[NFAPI_CC_MAX];
   uint8_t       pusch_snr_amc[NFAPI_CC_MAX];
+  uint64_t      pusch_rx_num[NFAPI_CC_MAX];
+  uint64_t      pusch_rx_num_old[NFAPI_CC_MAX];
+  uint64_t      pusch_rx_error_num[NFAPI_CC_MAX];
+  uint64_t      pusch_rx_error_num_old[NFAPI_CC_MAX];
+  double        pusch_bler[NFAPI_CC_MAX];
+  uint8_t       mcs_offset[NFAPI_CC_MAX];
   uint16_t      feedback_cnt[NFAPI_CC_MAX];
   uint16_t      timing_advance;
   uint16_t      timing_advance_r9;
diff --git a/openair2/LAYER2/MAC/eNB_scheduler_fairRR.c b/openair2/LAYER2/MAC/eNB_scheduler_fairRR.c
index 13d02f94070ffb5e57f919df3b73ff60d7fda9b4..774fac80eb4e4acf4ea3a9650161369252f5c780 100644
--- a/openair2/LAYER2/MAC/eNB_scheduler_fairRR.c
+++ b/openair2/LAYER2/MAC/eNB_scheduler_fairRR.c
@@ -2570,9 +2570,11 @@ void ulsch_scheduler_pre_processor_fairRR(module_id_t module_idP,
   uint8_t            total_rbs=0;
   uint8_t            average_rbs;
   uint16_t           first_rb[MAX_NUM_CCs];
-  uint8_t            mcs;
+  int8_t             mcs;
   uint8_t            snr;
-  uint8_t            snr2mcs_offset = 0;
+  uint8_t            snr2mcs_offset = 3;
+  double             bler_filter=0.9;
+  double             bler;
   uint8_t            rb_table_index;
   uint8_t            num_pucch_rb;
   uint32_t           tbs;
@@ -2666,16 +2668,61 @@ void ulsch_scheduler_pre_processor_fairRR(module_id_t module_idP,
       } else {
         UE_template = &UE_info->UE_template[CC_id][UE_id];
 
+        int32_t framex10psubframe = UE_template->pusch_bler_calc_frame*10+UE_template->pusch_bler_calc_subframe;
+        int pusch_bler_interval=100;
+        double total_bler;
+        
+        if(UE_info->UE_sched_ctrl[UE_id].pusch_rx_num[CC_id] == 0 && UE_info->UE_sched_ctrl[UE_id].pusch_rx_error_num[CC_id] == 0) {
+          total_bler = 0;
+        }
+        else {
+          total_bler = (double)UE_info->UE_sched_ctrl[UE_id].pusch_rx_error_num[CC_id] / (double)(UE_info->UE_sched_ctrl[UE_id].pusch_rx_error_num[CC_id] + UE_info->UE_sched_ctrl[UE_id].pusch_rx_num[CC_id]) * 100;
+        }
+
+        if (((framex10psubframe+pusch_bler_interval)<=(frameP*10+subframeP)) || //normal case
+          ((framex10psubframe>(frameP*10+subframeP)) && (((10240-framex10psubframe+frameP*10+subframeP)>=pusch_bler_interval)))) { //frame wrap-around
+
+          UE_template->pusch_bler_calc_frame=frameP;
+          UE_template->pusch_bler_calc_subframe=subframeP;
+
+          int pusch_rx_num_diff       = UE_info->UE_sched_ctrl[UE_id].pusch_rx_num[CC_id] - UE_info->UE_sched_ctrl[UE_id].pusch_rx_num_old[CC_id];
+          int pusch_rx_error_num_diff = UE_info->UE_sched_ctrl[UE_id].pusch_rx_error_num[CC_id] - UE_info->UE_sched_ctrl[UE_id].pusch_rx_error_num_old[CC_id];
+
+          if((pusch_rx_num_diff == 0) && (pusch_rx_error_num_diff == 0)) { /* first rx case or no rx among interval time */
+            bler = UE_info->UE_sched_ctrl[UE_id].pusch_bler[CC_id];
+          }
+          else {
+            bler = (double)pusch_rx_error_num_diff / (double)(pusch_rx_num_diff + pusch_rx_error_num_diff) * 100;
+          }
+          UE_info->UE_sched_ctrl[UE_id].pusch_bler[CC_id] = UE_info->UE_sched_ctrl[UE_id].pusch_bler[CC_id] * bler_filter + bler * (1.0-bler_filter);
+          UE_info->UE_sched_ctrl[UE_id].pusch_rx_num_old[CC_id] = UE_info->UE_sched_ctrl[UE_id].pusch_rx_num[CC_id];
+          UE_info->UE_sched_ctrl[UE_id].pusch_rx_error_num_old[CC_id] = UE_info->UE_sched_ctrl[UE_id].pusch_rx_error_num[CC_id];
+
+          if(bler < 0.5) {
+            if(UE_info->UE_sched_ctrl[UE_id].mcs_offset[CC_id] !=0) {
+              UE_info->UE_sched_ctrl[UE_id].mcs_offset[CC_id]--;
+            }
+          }
+          if(bler >= 2) {
+            UE_info->UE_sched_ctrl[UE_id].mcs_offset[CC_id]++;
+            if(UE_info->UE_sched_ctrl[UE_id].mcs_offset[CC_id] >= 20) {
+              UE_info->UE_sched_ctrl[UE_id].mcs_offset[CC_id]=20;
+            }
+          }
+        }
+
         if ( UE_info->UE_sched_ctrl[UE_id].phr_received == 1 ) {
           snr = (5 * UE_info->UE_sched_ctrl[UE_id].pusch_snr_amc[CC_id] - 640) / 10;
-          if((snr + snr2mcs_offset) >= 20) {
+          mcs = snr - snr2mcs_offset;
+          if(mcs > 20) {
             mcs = 20;
           }
-          else if((snr + snr2mcs_offset) < 3) {
-            mcs = 3;
+
+          if(mcs - UE_info->UE_sched_ctrl[UE_id].mcs_offset[CC_id] < 6) {
+            mcs = 6;
           }
-          else {
-            mcs = snr + snr2mcs_offset;
+          else { 
+            mcs = mcs - UE_list->UE_sched_ctrl[UE_id].mcs_offset[CC_id];
           }
         } else {
           mcs = 10;
@@ -2689,19 +2736,13 @@ void ulsch_scheduler_pre_processor_fairRR(module_id_t module_idP,
           if ( ulsch_ue_select[CC_id].list[ulsch_ue_num].ul_total_buffer > 0 ) {
             rb_table_index = 2;
             tbs = get_TBS_UL(mcs,rb_table[rb_table_index]);
-            tx_power= estimate_ue_tx_power(tbs*8,rb_table[rb_table_index],0,frame_parms->Ncp,0);
-
-            while ( (((UE_template->phr_info - tx_power) < 0 ) || (tbs > bytes_to_schedule)) && (mcs > 3) ) {
-              mcs--;
-              tbs = get_TBS_UL(mcs,rb_table[rb_table_index]);
-              tx_power= estimate_ue_tx_power(tbs*8,rb_table[rb_table_index],0,frame_parms->Ncp,0);
-            }
+            tx_power = (int8_t)(hundred_times_log10_NPRB[rb_table[rb_table_index] - 1] / 100);
 
             while ( (tbs < bytes_to_schedule) && (rb_table[rb_table_index]<(frame_parms->N_RB_UL-num_pucch_rb-first_rb[CC_id])) &&
                     ((UE_template->phr_info - tx_power) > 0) && (rb_table_index < 32 )) {
               rb_table_index++;
               tbs = get_TBS_UL(mcs,rb_table[rb_table_index]);
-              tx_power= estimate_ue_tx_power(tbs*8,rb_table[rb_table_index],0,frame_parms->Ncp,0);
+              tx_power = (int8_t)(hundred_times_log10_NPRB[rb_table[rb_table_index] - 1] / 100);
             }
 
             if ( rb_table[rb_table_index]<3 ) {
@@ -2731,6 +2772,11 @@ void ulsch_scheduler_pre_processor_fairRR(module_id_t module_idP,
               UE_info->UE_template[CC_id][UE_id].pre_allocated_rb_table_index_ul = rb_table_index;
               UE_info->UE_template[CC_id][UE_id].pre_assigned_mcs_ul = mcs;
             }
+            
+            LOG_D(MAC,"[eNB %d] frame %d subframe %d, UE %d/%x CC %d snr %d mcs %d mcs_offset %d bler %lf total_bler %lf ( %d %d ) rb_num %d phr_info %d tx_power %d bsr %d\n",
+                  module_idP,frameP,subframeP,UE_id,UE_RNTI(CC_id,UE_id),CC_id, snr, mcs, UE_list->UE_sched_ctrl[UE_id].mcs_offset[CC_id], UE_list->UE_sched_ctrl[UE_id].pusch_bler[CC_id], 
+                  total_bler, UE_list->UE_sched_ctrl[UE_id].pusch_rx_num[CC_id], UE_list->UE_sched_ctrl[UE_id].pusch_rx_error_num[CC_id], rb_table[rb_table_index-1], UE_template->phr_info, tx_power, bytes_to_schedule);
+            
           } else {
             if (mac_eNB_get_rrc_status(module_idP,UE_RNTI(module_idP, UE_id)) < RRC_CONNECTED) {
               // assigne RBS( 6 RBs)
@@ -3207,8 +3253,8 @@ void schedule_ulsch_rnti_fairRR(module_id_t   module_idP,
         nfapi_hi_dci0_request_t        *nfapi_hi_dci0_req = &eNB->HI_DCI0_req[CC_id][subframeP];
         nfapi_hi_dci0_req->sfn_sf = frameP<<4|subframeP; // sfnsf_add_subframe(sched_frame, sched_subframeP, 0); // sunday!
         nfapi_hi_dci0_req->header.message_id = NFAPI_HI_DCI0_REQUEST;
-        LOG_D(MAC,"[PUSCH %d] Frame %d, Subframe %d: Adding UL CONFIG.Request for UE %d/%x, ulsch_frame %d, ulsch_subframe %d mcs %d first_rb %d num_rb %d round %d\n",
-              harq_pid,frameP,subframeP,UE_id,rnti,sched_frame,sched_subframeP,UE_template->mcs_UL[harq_pid],first_rb[CC_id],rb_table[rb_table_index],0);
+        LOG_D(MAC,"[PUSCH %d] Frame %d, Subframe %d: Adding UL CONFIG.Request for UE %d/%x, ulsch_frame %d, ulsch_subframe %d mcs %d first_rb %d num_rb %d round %d mcs %d sinr %d bler %lf\n",
+              harq_pid,frameP,subframeP,UE_id,rnti,sched_frame,sched_subframeP,UE_template->mcs_UL[harq_pid],first_rb[CC_id],rb_table[rb_table_index],0,UE_template->mcs_UL[harq_pid],(5 * UE_sched_ctrl->pusch_snr_amc[CC_id] - 640) / 10,UE_sched_ctrl->pusch_bler[CC_id]);
         ul_req_index = 0;
         dlsch_flag = 0;
 
@@ -3358,8 +3404,9 @@ void schedule_ulsch_rnti_fairRR(module_id_t   module_idP,
         hi_dci0_pdu->dci_pdu.dci_pdu_rel8.harq_pid                          = harq_pid;
         hi_dci0_req->number_of_dci++;
         // Add UL_config PDUs
-        LOG_D(MAC,"[PUSCH %d] Frame %d, Subframe %d: Adding UL CONFIG.Request for UE %d/%x, ulsch_frame %d, ulsch_subframe %d mcs %d first_rb %d num_rb %d round %d\n",
-              harq_pid,frameP,subframeP,UE_id,rnti,sched_frame,sched_subframeP,mcs_rv,ulsch_ue_select[CC_id].list[ulsch_ue_num].start_rb,ulsch_ue_select[CC_id].list[ulsch_ue_num].nb_rb,UE_sched_ctrl->round_UL[CC_id][harq_pid]);
+        LOG_D(MAC,"[PUSCH %d] Frame %d, Subframe %d: Adding UL CONFIG.Request for UE %d/%x, ulsch_frame %d, ulsch_subframe %d mcs %d first_rb %d num_rb %d round %d mcs %d sinr %d bler %lf\n",
+              harq_pid,frameP,subframeP,UE_id,rnti,sched_frame,sched_subframeP,mcs_rv,ulsch_ue_select[CC_id].list[ulsch_ue_num].start_rb,ulsch_ue_select[CC_id].list[ulsch_ue_num].nb_rb,UE_sched_ctrl->round_UL[CC_id][harq_pid],UE_template->mcs_UL[harq_pid],(5 * UE_sched_ctrl->pusch_snr_amc[CC_id] - 640) / 10,UE_sched_ctrl->pusch_bler[CC_id]);
+
         ul_req_index = 0;
         dlsch_flag = 0;
 
diff --git a/openair2/LAYER2/MAC/eNB_scheduler_primitives.c b/openair2/LAYER2/MAC/eNB_scheduler_primitives.c
index 95a5b48598ae1d77d472de84b7351d3dc642e9b1..82b640e7d06543d5d0667d9c938841889e93af79 100644
--- a/openair2/LAYER2/MAC/eNB_scheduler_primitives.c
+++ b/openair2/LAYER2/MAC/eNB_scheduler_primitives.c
@@ -2219,6 +2219,13 @@ add_new_ue(module_id_t mod_idP,
     UE_info->UE_sched_ctrl[UE_id].pusch_snr[cc_idP] = 0;
     UE_info->UE_sched_ctrl[UE_id].pusch_snr_avg[cc_idP] = 0;
     UE_info->UE_sched_ctrl[UE_id].pusch_snr_amc[cc_idP] = 0;
+    UE_info->UE_sched_ctrl[UE_id].pusch_rx_num[cc_idP] = 0;
+    UE_info->UE_sched_ctrl[UE_id].pusch_rx_num_old[cc_idP] = 0;
+    UE_info->UE_sched_ctrl[UE_id].pusch_rx_error_num[cc_idP] = 0;
+    UE_info->UE_sched_ctrl[UE_id].pusch_rx_error_num_old[cc_idP] = 0;
+    UE_info->UE_sched_ctrl[UE_id].pusch_bler[cc_idP] = 0;
+    UE_info->UE_sched_ctrl[UE_id].mcs_offset[cc_idP] = 0;
+
     for (j = 0; j < 8; j++) {
       UE_info->UE_template[cc_idP][UE_id].oldNDI[j] = 0;
       UE_info->UE_template[cc_idP][UE_id].oldNDI_UL[j] = 0;
diff --git a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c
index d8a8983ac1f1f8b35b122bafb6bbc3e05bb6a5c6..73e3465817f47572d6d5622a68aadede6d5bbbef 100644
--- a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c
+++ b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c
@@ -160,6 +160,8 @@ rx_sdu(const module_id_t enb_mod_idP,
       UE_scheduling_control->ul_inactivity_timer = 0;
       UE_scheduling_control->ul_failure_timer = 0;
       UE_scheduling_control->ul_scheduled &= (~(1 << harq_pid));
+      UE_scheduling_control->pusch_rx_num[CC_idP]++;
+      
       /* Update with smoothing: 3/4 of old value and 1/4 of new.
        * This is the logic that was done in the function
        * lte_est_timing_advance_pusch, maybe it's not necessary?
@@ -199,6 +201,7 @@ rx_sdu(const module_id_t enb_mod_idP,
         UE_template_ptr->scheduled_ul_bytes = 0;
       }
     } else {  // sduP == NULL => error
+      UE_scheduling_control->pusch_rx_error_num[CC_idP]++;
       LOG_W(MAC, "[eNB %d][PUSCH %d] CC_id %d %d.%d ULSCH in error in round %d, ul_cqi %d, UE_id %d, RNTI %x (len %d)\n",
             enb_mod_idP,
             harq_pid,
diff --git a/openair2/LAYER2/MAC/mac.h b/openair2/LAYER2/MAC/mac.h
index 3c15bd5ac9c71213cb33b5a242e612a57db0aed0..09edd00a80928f018417b9579c34896565b8e691 100644
--- a/openair2/LAYER2/MAC/mac.h
+++ b/openair2/LAYER2/MAC/mac.h
@@ -906,6 +906,11 @@ typedef struct {
   uint32_t pucch_tpc_tx_frame;
   uint32_t pucch_tpc_tx_subframe;
 
+  /// stores the frame where the last bler was calculated
+  uint32_t pusch_bler_calc_frame;
+  uint32_t pusch_bler_calc_subframe;
+
+
   uint8_t rach_resource_type;
   uint16_t mpdcch_repetition_cnt;
   frame_t Msg2_frame;
@@ -963,6 +968,12 @@ typedef struct {
   uint8_t pusch_snr[NFAPI_CC_MAX];
   uint8_t pusch_snr_avg[NFAPI_CC_MAX];
   uint8_t pusch_snr_amc[NFAPI_CC_MAX];
+  uint64_t pusch_rx_num[NFAPI_CC_MAX];
+  uint64_t pusch_rx_num_old[NFAPI_CC_MAX];
+  uint64_t pusch_rx_error_num[NFAPI_CC_MAX];
+  uint64_t pusch_rx_error_num_old[NFAPI_CC_MAX];
+  double  pusch_bler[NFAPI_CC_MAX];
+  uint8_t  mcs_offset[NFAPI_CC_MAX];
   uint16_t feedback_cnt[NFAPI_CC_MAX];
   uint16_t timing_advance;
   uint16_t timing_advance_r9;