diff --git a/lib/include/srsran/interfaces/sched_interface.h b/lib/include/srsran/interfaces/sched_interface.h index cb946349d..f2b53188d 100644 --- a/lib/include/srsran/interfaces/sched_interface.h +++ b/lib/include/srsran/interfaces/sched_interface.h @@ -61,6 +61,7 @@ public: float max_delta_dl_cqi = 5; float max_delta_ul_snr = 5; float adaptive_link_step_size = 0.001; + uint32_t min_tpc_tti_interval = 1; }; struct cell_cfg_t { diff --git a/srsenb/enb.conf.example b/srsenb/enb.conf.example index fb2f73e7e..a0e73714e 100644 --- a/srsenb/enb.conf.example +++ b/srsenb/enb.conf.example @@ -173,6 +173,7 @@ enable = false # max_delta_dl_cqi: Maximum shift in CQI for adaptive DL link # max_delta_ul_snr: Maximum shift in UL SNR for adaptive UL link # adaptive_link_step_size: Step size or learning rate used in adaptive link +# min_tpc_tti_interval: Minimum TTI interval between TPCs different than 1 # ##################################################################### [scheduler] @@ -192,6 +193,7 @@ enable = false #max_delta_dl_cqi = 5 #max_delta_ul_snr = 5 #adaptive_link_step_size = 0.001 +#min_tpc_tti_interval = 1 ##################################################################### # eMBMS configuration options diff --git a/srsenb/hdr/stack/mac/sched_ue_ctrl/tpc.h b/srsenb/hdr/stack/mac/sched_ue_ctrl/tpc.h index ad6ad4b26..4844f1bc3 100644 --- a/srsenb/hdr/stack/mac/sched_ue_ctrl/tpc.h +++ b/srsenb/hdr/stack/mac/sched_ue_ctrl/tpc.h @@ -36,17 +36,19 @@ public: static constexpr int PHR_NEG_NOF_PRB = 1; explicit tpc(uint32_t cell_nof_prb, - float target_pucch_snr_dB_ = -1.0, - float target_pusch_sn_dB_ = -1.0, - bool phr_handling_flag_ = false) : + float target_pucch_snr_dB_ = -1.0, + float target_pusch_sn_dB_ = -1.0, + bool phr_handling_flag_ = false, + uint32_t min_tpc_tti_interval_ = 1) : nof_prb(cell_nof_prb), target_pucch_snr_dB(target_pucch_snr_dB_), target_pusch_snr_dB(target_pusch_sn_dB_), snr_estim_list({ul_ch_snr_estim{target_pusch_snr_dB}, ul_ch_snr_estim{target_pucch_snr_dB}}), - phr_handling_flag(phr_handling_flag_) - { - max_prbs_cached = nof_prb; - } + phr_handling_flag(phr_handling_flag_), + max_prbs_cached(nof_prb), + min_tpc_tti_interval(min_tpc_tti_interval_), + logger(srslog::fetch_basic_logger("MAC")) + {} void set_cfg(float target_pusch_snr_dB_, float target_pucch_snr_dB_) { target_pucch_snr_dB = target_pucch_snr_dB_; @@ -85,7 +87,8 @@ public: void new_tti() { - for (size_t chidx = 0; chidx < 2; ++chidx) { + tti_count++; + for (size_t chidx = 0; chidx < nof_ul_ch_code; ++chidx) { float target_snr_dB = chidx == PUSCH_CODE ? target_pusch_snr_dB : target_pucch_snr_dB; auto& ch_snr = snr_estim_list[chidx]; @@ -139,39 +142,50 @@ private: case 3: return 3; default: - srslog::fetch_basic_logger("MAC").warning("Invalid TPC delta value=%d", delta); + logger.warning("Invalid TPC delta value=%d", delta); return 1; } } uint8_t encode_tpc(uint32_t cc) { - float target_snr_dB = cc == PUSCH_CODE ? target_pusch_snr_dB : target_pucch_snr_dB; - auto& ch_snr = snr_estim_list[cc]; + auto& ch_snr = snr_estim_list[cc]; assert(ch_snr.pending_delta == 0); // ensure called once per {cc,tti} - if (target_snr_dB < 0) { - // undefined target sinr case. - ch_snr.pending_delta = 0; - } else { - // target SINR is finite and there is power headroom - float diff = target_snr_dB - ch_snr.snr_avg.value(); - diff -= ch_snr.win_tpc_values.value() + ch_snr.acc_tpc_values; - int8_t diff_round = roundf(diff); - if (diff_round >= 1) { - ch_snr.pending_delta = diff_round > 3 ? 3 : 1; - } else if (diff_round <= -1) { - ch_snr.pending_delta = -1; - } - if (last_phr <= 0) { - // In case there is no headroom, forbid power increases - ch_snr.pending_delta = std::min(ch_snr.pending_delta, 0); - } + + float target_snr_dB = cc == PUSCH_CODE ? target_pusch_snr_dB : target_pucch_snr_dB; + if (target_snr_dB < 0 or last_phr == 0) { + // undefined target sinr case, or no more PHR + return encode_tpc_delta(0); + } + if (last_phr < 0) { + // negative PHR + encode_tpc_delta(-1); + } + if ((tti_count - ch_snr.last_tpc_tti_count) < min_tpc_tti_interval) { + // more time required before sending next TPC + return encode_tpc_delta(0); + } + + // target SINR is finite and there is power headroom + float diff = target_snr_dB - ch_snr.snr_avg.value(); + diff -= ch_snr.win_tpc_values.value() + ch_snr.acc_tpc_values; + if (diff >= 1) { + ch_snr.pending_delta = diff > 3 ? 3 : 1; + ch_snr.last_tpc_tti_count = tti_count; + } else if (diff <= -1) { + ch_snr.pending_delta = -1; + ch_snr.last_tpc_tti_count = tti_count; } return encode_tpc_delta(ch_snr.pending_delta); } - uint32_t nof_prb; - float target_pucch_snr_dB, target_pusch_snr_dB; - bool phr_handling_flag; + uint32_t nof_prb; + uint32_t min_tpc_tti_interval = 1; + float target_pucch_snr_dB, target_pusch_snr_dB; + bool phr_handling_flag; + srslog::basic_logger& logger; + + // state + uint32_t tti_count = 0; // PHR-related variables int last_phr = undefined_phr; @@ -188,8 +202,9 @@ private: srsran::exp_average_irreg_sampling snr_avg; // Accumulation of past TPC commands srsran::sliding_sum win_tpc_values; - int pending_delta = 0; - int acc_tpc_values = 0; + int8_t pending_delta = 0; + int acc_tpc_values = 0; + uint32_t last_tpc_tti_count = 0; explicit ul_ch_snr_estim(float initial_snr) : snr_avg(0.1, initial_snr < 0 ? 5 : initial_snr), win_tpc_values(FDD_HARQ_DELAY_UL_MS + FDD_HARQ_DELAY_DL_MS) diff --git a/srsenb/src/main.cc b/srsenb/src/main.cc index 7b6be3828..8ec826e56 100644 --- a/srsenb/src/main.cc +++ b/srsenb/src/main.cc @@ -155,6 +155,7 @@ void parse_args(all_args_t* args, int argc, char* argv[]) ("scheduler.max_delta_dl_cqi", bpo::value(&args->stack.mac.sched.max_delta_dl_cqi)->default_value(5.0), "Maximum shift in CQI for adaptive DL link") ("scheduler.max_delta_ul_snr", bpo::value(&args->stack.mac.sched.max_delta_ul_snr)->default_value(5.0), "Maximum shift in UL SNR for adaptive UL link") ("scheduler.adaptive_link_step_size", bpo::value(&args->stack.mac.sched.max_delta_ul_snr)->default_value(0.001), "Step size or learning rate used in adaptive link") + ("scheduler.min_tpc_tti_interval", bpo::value(&args->stack.mac.sched.min_tpc_tti_interval)->default_value(1), "Minimum TTI interval between positive or negative TPCs") /* Downlink Channel emulator section */ diff --git a/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc b/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc index 9304ea8e0..c34a6511c 100644 --- a/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc +++ b/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc @@ -38,7 +38,8 @@ sched_ue_cell::sched_ue_cell(uint16_t rnti_, const sched_cell_params_t& cell_cfg tpc_fsm(cell_cfg->nof_prb(), cell_cfg->cfg.target_pucch_ul_sinr, cell_cfg->cfg.target_pusch_ul_sinr, - cell_cfg->cfg.enable_phr_handling), + cell_cfg->cfg.enable_phr_handling, + cell_cfg->sched_cfg->min_tpc_tti_interval), fixed_mcs_dl(cell_cfg_.sched_cfg->pdsch_mcs), fixed_mcs_ul(cell_cfg_.sched_cfg->pusch_mcs), current_tti(current_tti_),