From 2abe486e18e7a8484fa5d03ffa8877c21de2bc34 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Wed, 6 Jan 2021 19:53:54 +0000 Subject: [PATCH] separate control loops for PUCCH and PUSCH TPC --- srsenb/hdr/stack/mac/sched_ue_ctrl/tpc.h | 181 +++++++++++------------ srsenb/hdr/stack/rrc/rrc_config.h | 2 +- srsenb/src/enb_cfg_parser.cc | 4 - srsenb/src/stack/mac/sched_ue.cc | 4 +- srsenb/test/mac/sched_tpc_test.cc | 9 +- 5 files changed, 93 insertions(+), 107 deletions(-) diff --git a/srsenb/hdr/stack/mac/sched_ue_ctrl/tpc.h b/srsenb/hdr/stack/mac/sched_ue_ctrl/tpc.h index 1774f1236..96c6c63a9 100644 --- a/srsenb/hdr/stack/mac/sched_ue_ctrl/tpc.h +++ b/srsenb/hdr/stack/mac/sched_ue_ctrl/tpc.h @@ -27,30 +27,36 @@ namespace srsenb { */ class tpc { - static constexpr int undefined_phr = std::numeric_limits::max(); - static constexpr float null_snr = std::numeric_limits::max(); + static constexpr int undefined_phr = std::numeric_limits::max(); + static constexpr float null_snr = std::numeric_limits::max(); + static constexpr uint32_t nof_ul_ch_code = 2; public: - static constexpr int PHR_NEG_NOF_PRB = 1; + static constexpr uint32_t PUSCH_CODE = 0, PUCCH_CODE = 1; + static constexpr int PHR_NEG_NOF_PRB = 1; - tpc(uint32_t cell_nof_prb, float target_snr_dB_ = -1.0, bool phr_handling_flag_ = false) : + explicit tpc(uint32_t cell_nof_prb, float target_snr_dB_ = -1.0, bool phr_handling_flag_ = false) : nof_prb(cell_nof_prb), target_snr_dB(target_snr_dB_), - snr_avg(0.1, target_snr_dB_), - win_pusch_tpc_values(FDD_HARQ_DELAY_UL_MS + FDD_HARQ_DELAY_DL_MS), - win_pucch_tpc_values(FDD_HARQ_DELAY_DL_MS + FDD_HARQ_DELAY_UL_MS), + snr_estim_list({ul_ch_snr_estim{target_snr_dB_}, ul_ch_snr_estim{target_snr_dB_}}), phr_handling_flag(phr_handling_flag_) { max_prbs_cached = nof_prb; } void set_cfg(float target_snr_dB_) { target_snr_dB = target_snr_dB_; } - void set_snr(float snr) { pending_snr = snr; } + void set_snr(float snr, uint32_t ul_ch_code) + { + if (ul_ch_code < nof_ul_ch_code) { + snr_estim_list[ul_ch_code].pending_snr = snr; + } + } void set_phr(int phr_) { - last_phr = phr_; - pucch_phr_flag = false; - pusch_phr_flag = false; + last_phr = phr_; + for (auto& ch_snr : snr_estim_list) { + ch_snr.phr_flag = false; + } // compute and cache the max nof UL PRBs that avoids overflowing PHR if (phr_handling_flag) { @@ -66,30 +72,27 @@ public: void new_tti() { - if (target_snr_dB < 0) { - pending_pusch_delta = 0; - pending_pucch_delta = 0; - return; - } + for (auto& ch_snr : snr_estim_list) { + if (target_snr_dB < 0) { + ch_snr.pending_delta = 0; + continue; + } - // Enqueue pending SNR measurement - if (pending_snr == null_snr) { - last_snr_sample_count++; - acc_pusch_tpc_values += win_pusch_tpc_values.oldest(); - acc_pucch_tpc_values += win_pusch_tpc_values.oldest(); - } else { - acc_pucch_tpc_values = 0; - acc_pusch_tpc_values = 0; - snr_avg.push(pending_snr, last_snr_sample_count); - last_snr_sample_count = 1; - } - pending_snr = null_snr; + // Enqueue pending UL Channel SNR measurement + if (ch_snr.pending_snr == null_snr) { + ch_snr.last_snr_sample_count++; + ch_snr.acc_tpc_values += ch_snr.win_tpc_values.oldest(); + } else { + ch_snr.acc_tpc_values = 0; + ch_snr.snr_avg.push(ch_snr.pending_snr, ch_snr.last_snr_sample_count); + ch_snr.last_snr_sample_count = 1; + } + ch_snr.pending_snr = null_snr; - // Enqueue PUSCH/PUCCH TPC sent in last TTI (zero for both Delta_PUSCH/Delta_PUCCH=0 and TPC not sent) - win_pusch_tpc_values.push(pending_pusch_delta); - pending_pusch_delta = 0; - win_pucch_tpc_values.push(pending_pucch_delta); - pending_pucch_delta = 0; + // Enqueue PUSCH/PUCCH TPC sent in last TTI (zero for both Delta_PUSCH/Delta_PUCCH=0 and TPC not sent) + ch_snr.win_tpc_values.push(ch_snr.pending_delta); + ch_snr.pending_delta = 0; + } } /** @@ -97,67 +100,14 @@ public: * @remark See TS 36.213 Section 5.1.1 * @return accumulated TPC value {-1, 0, 1, 3} */ - uint8_t encode_pusch_tpc() - { - assert(pending_pusch_delta == 0); // ensure called once per {cc,tti} - if (target_snr_dB < 0) { - // undefined target SINR case. Increase Tx power once per PHR, considering the number of allocable PRBs remains - // unchanged - if (not pusch_phr_flag) { - pending_pusch_delta = (max_prbs_cached == nof_prb) ? 1 : (last_phr < 0 ? -1 : 0); - pusch_phr_flag = true; - } - } else { - // target SINR is finite and there is power headroom - float diff = target_snr_dB - snr_avg.value(); - diff -= win_pusch_tpc_values.value() + acc_pusch_tpc_values; - int8_t diff_round = roundf(diff); - if (diff_round >= 1) { - pending_pusch_delta = diff_round > 3 ? 3 : 1; - } else if (diff_round <= -1) { - pending_pusch_delta = -1; - } - if (last_phr <= 0) { - // In case there is no headroom, forbid power increases - pending_pusch_delta = std::min(pending_pusch_delta, 0); - } - } - return encode_tpc_delta(pending_pusch_delta); - } + uint8_t encode_pusch_tpc() { return enconde_tpc(PUSCH_CODE); } /** * Called during DCI format1/2A/A encoding to set PUCCH TPC command - * Note: For now we use the same algorithm for PUCCH and PUSCH * @remark See TS 36.213 Section 5.1.2 * @return accumulated TPC value {-1, 0, 1, 3} */ - uint8_t encode_pucch_tpc() - { - assert(pending_pucch_delta == 0); // ensure called once per {cc,tti} - if (target_snr_dB < 0) { - // undefined target SINR case. Increase Tx power once per PHR, considering the number of allocable PRBs remains - // unchanged - if (not pucch_phr_flag) { - pending_pucch_delta = (max_prbs_cached == nof_prb) ? 1 : (last_phr < 0 ? -1 : 0); - pucch_phr_flag = true; - } - } else { - // target SINR is finite and there is power headroom - float diff = target_snr_dB - snr_avg.value(); - diff -= win_pucch_tpc_values.value() + acc_pucch_tpc_values; - int8_t diff_round = roundf(diff); - if (diff_round >= 1) { - pending_pucch_delta = diff_round > 3 ? 3 : 1; - } else if (diff_round <= -1) { - pending_pucch_delta = -1; - } - if (last_phr <= 0) { - // In case there is no headroom, forbid power increases - pending_pucch_delta = std::min(pending_pucch_delta, 0); - } - } - return encode_tpc_delta(pending_pucch_delta); - } + uint8_t encode_pucch_tpc() { return enconde_tpc(PUCCH_CODE); } uint32_t max_ul_prbs() const { return max_prbs_cached; } @@ -178,6 +128,34 @@ private: return 1; } } + uint8_t enconde_tpc(uint32_t 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. Increase Tx power once per PHR, considering the number of allocable PRBs remains + // unchanged + if (not ch_snr.phr_flag) { + ch_snr.pending_delta = (max_prbs_cached == nof_prb) ? 1 : (last_phr < 0 ? -1 : 0); + ch_snr.phr_flag = true; + } + } 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); + } + } + return encode_tpc_delta(ch_snr.pending_delta); + } uint32_t nof_prb; float target_snr_dB; @@ -186,17 +164,26 @@ private: // PHR-related variables int last_phr = undefined_phr; uint32_t max_prbs_cached = 100; - bool pusch_phr_flag = false, pucch_phr_flag = false; // SNR estimation - srslte::exp_average_irreg_sampling snr_avg; - float pending_snr = srslte::null_sliding_average::null_value(); - uint32_t last_snr_sample_count = 1; - - // Accumulation of past TPC commands - srslte::sliding_sum win_pusch_tpc_values, win_pucch_tpc_values; - int pending_pusch_delta = 0, pending_pucch_delta = 0; - int acc_pusch_tpc_values = 0, acc_pucch_tpc_values = 0; + struct ul_ch_snr_estim { + // flag used in undefined target SINR case + bool phr_flag = false; + // pending new snr sample + float pending_snr = srslte::null_sliding_average::null_value(); + // SNR average estimation with irregular sample spacing + uint32_t last_snr_sample_count = 1; // jump in spacing + srslte::exp_average_irreg_sampling snr_avg; + // Accumulation of past TPC commands + srslte::sliding_sum win_tpc_values; + int pending_delta = 0; + int acc_tpc_values = 0; + + explicit ul_ch_snr_estim(float target_ul_snr = -1) : + snr_avg(0.1, target_ul_snr), win_tpc_values(FDD_HARQ_DELAY_UL_MS + FDD_HARQ_DELAY_DL_MS) + {} + }; + std::array snr_estim_list; }; } // namespace srsenb diff --git a/srsenb/hdr/stack/rrc/rrc_config.h b/srsenb/hdr/stack/rrc/rrc_config.h index e2834c830..ee6e6b3b8 100644 --- a/srsenb/hdr/stack/rrc/rrc_config.h +++ b/srsenb/hdr/stack/rrc/rrc_config.h @@ -30,7 +30,7 @@ struct rrc_cfg_sr_t { }; typedef struct { - bool configured; + bool configured = false; asn1::rrc::lc_ch_cfg_s::ul_specific_params_s_ lc_cfg; asn1::rrc::pdcp_cfg_s pdcp_cfg; asn1::rrc::rlc_cfg_c rlc_cfg; diff --git a/srsenb/src/enb_cfg_parser.cc b/srsenb/src/enb_cfg_parser.cc index 146f2e447..985e22952 100644 --- a/srsenb/src/enb_cfg_parser.cc +++ b/srsenb/src/enb_cfg_parser.cc @@ -385,10 +385,6 @@ int field_qci::parse(libconfig::Setting& root) { auto nof_qci = (uint32_t)root.getLength(); - for (uint32_t i = 0; i < MAX_NOF_QCI; i++) { - cfg->configured = false; - } - for (uint32_t i = 0; i < nof_qci; i++) { libconfig::Setting& q = root[i]; diff --git a/srsenb/src/stack/mac/sched_ue.cc b/srsenb/src/stack/mac/sched_ue.cc index 70a1f82fd..0434d3cea 100644 --- a/srsenb/src/stack/mac/sched_ue.cc +++ b/srsenb/src/stack/mac/sched_ue.cc @@ -475,7 +475,7 @@ void sched_ue::set_ul_snr(tti_point tti_rx, uint32_t enb_cc_idx, float snr, uint { cc_sched_ue* c = find_ue_carrier(enb_cc_idx); if (c != nullptr and c->cc_state() != cc_st::idle) { - c->tpc_fsm.set_snr(snr); + c->tpc_fsm.set_snr(snr, ul_ch_code); c->ul_cqi = srslte_cqi_from_snr(snr); c->ul_cqi_tti_rx = tti_rx; } else { @@ -1404,7 +1404,7 @@ void cc_sched_ue::set_cfg(const sched_interface::ue_cfg_t& cfg_) void cc_sched_ue::finish_tti(tti_point tti_rx) { - last_tti = tti_point{tti_rx}; + last_tti = tti_rx; // reset PIDs with pending data or blocked harq_ent.reset_pending_data(last_tti); diff --git a/srsenb/test/mac/sched_tpc_test.cc b/srsenb/test/mac/sched_tpc_test.cc index 3d09f7626..b9114918c 100644 --- a/srsenb/test/mac/sched_tpc_test.cc +++ b/srsenb/test/mac/sched_tpc_test.cc @@ -39,7 +39,8 @@ int test_finite_target_snr() // - TPC commands should be sent to decrease power // - The sum power of TPC commands should not exceed the difference between current and target SNRs int snr_diff = 10; - tpcfsm.set_snr(target_snr + snr_diff); + tpcfsm.set_snr(target_snr + snr_diff, tpc::PUSCH_CODE); + tpcfsm.set_snr(target_snr + snr_diff, tpc::PUCCH_CODE); int sum_pusch = 0, sum_pucch = 0; for (uint32_t i = 0; i < 100; ++i) { tpcfsm.new_tti(); @@ -53,7 +54,8 @@ int test_finite_target_snr() // - TPC commands should be sent to increase power // - The sum of TPC commands should not exceed the difference between current and target SNRs snr_diff = -10; - tpcfsm.set_snr(target_snr + snr_diff); + tpcfsm.set_snr(target_snr + snr_diff, tpc::PUSCH_CODE); + tpcfsm.set_snr(target_snr + snr_diff, tpc::PUCCH_CODE); sum_pusch = 0; sum_pucch = 0; for (uint32_t i = 0; i < 100; ++i) { @@ -86,7 +88,8 @@ int test_undefined_target_snr() // TEST: SNR info should not affect TPC in undefined target SNR mode int snr_info = 10; - tpcfsm.set_snr(snr_info); + tpcfsm.set_snr(snr_info, tpc::PUSCH_CODE); + tpcfsm.set_snr(snr_info, tpc::PUCCH_CODE); sum_pusch = 0; sum_pucch = 0; for (uint32_t i = 0; i < 100; ++i) {