mirror of https://github.com/pvnis/srsRAN_4G.git
Merge branch 'next' into agpl_next
# Conflicts: # srsue/hdr/phy/scell/intra_measure.h # srsue/src/phy/scell/intra_measure.ccmaster
commit
e77c197633
@ -0,0 +1,174 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2021 Software Radio Systems Limited
|
||||
*
|
||||
* By using this file, you agree to the terms and conditions set
|
||||
* forth in the LICENSE file which can be found at the top level of
|
||||
* the distribution.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SRSRAN_SCHED_PHY_RESOURCE_H
|
||||
#define SRSRAN_SCHED_PHY_RESOURCE_H
|
||||
|
||||
#include "srsran/adt/bounded_bitset.h"
|
||||
#include "srsran/adt/interval.h"
|
||||
#include "srsran/common/srsran_assert.h"
|
||||
extern "C" {
|
||||
#include "srsran/phy/phch/ra.h"
|
||||
}
|
||||
|
||||
// Description: This file defines the types associated with representing the allocation masks/intervals for RBGs, PRBs
|
||||
// and PDCCH CCEs, and provides some function helpers and algorithms to handle these types.
|
||||
|
||||
constexpr uint32_t MAX_NOF_RBGS = 25;
|
||||
constexpr uint32_t MAX_NOF_PRBS = 100;
|
||||
constexpr uint32_t MAX_NOF_CCES = 128;
|
||||
|
||||
namespace srsenb {
|
||||
|
||||
/// convert cell nof PRBs to nof RBGs
|
||||
inline uint32_t cell_nof_prb_to_rbg(uint32_t nof_prbs)
|
||||
{
|
||||
switch (nof_prbs) {
|
||||
case 6:
|
||||
return 6;
|
||||
case 15:
|
||||
return 8;
|
||||
case 25:
|
||||
return 13;
|
||||
case 50:
|
||||
return 17;
|
||||
case 75:
|
||||
return 19;
|
||||
case 100:
|
||||
return 25;
|
||||
default:
|
||||
srsran_terminate("Provided nof PRBs not valid");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// convert cell nof RBGs to nof PRBs
|
||||
inline uint32_t cell_nof_rbg_to_prb(uint32_t nof_rbgs)
|
||||
{
|
||||
switch (nof_rbgs) {
|
||||
case 6:
|
||||
return 6;
|
||||
case 8:
|
||||
return 15;
|
||||
case 13:
|
||||
return 25;
|
||||
case 17:
|
||||
return 50;
|
||||
case 19:
|
||||
return 75;
|
||||
case 25:
|
||||
return 100;
|
||||
default:
|
||||
srsran_terminate("Provided nof PRBs not valid");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// Bitmask used for CCE allocations
|
||||
using pdcch_mask_t = srsran::bounded_bitset<MAX_NOF_CCES, true>;
|
||||
|
||||
/// Bitmask that stores the allocared DL RBGs
|
||||
using rbgmask_t = srsran::bounded_bitset<MAX_NOF_RBGS, true>;
|
||||
|
||||
/// Bitmask that stores the allocated UL PRBs
|
||||
using prbmask_t = srsran::bounded_bitset<MAX_NOF_PRBS, true>;
|
||||
|
||||
/// Struct to express a {min,...,max} range of RBGs
|
||||
struct prb_interval;
|
||||
struct rbg_interval : public srsran::interval<uint32_t> {
|
||||
using interval::interval;
|
||||
static rbg_interval find_first_interval(const rbgmask_t& mask);
|
||||
static rbg_interval prbs_to_rbgs(const prb_interval& prbs, uint32_t cell_nof_prb);
|
||||
};
|
||||
|
||||
/// Struct to express a {min,...,max} range of PRBs
|
||||
struct prb_interval : public srsran::interval<uint32_t> {
|
||||
using interval::interval;
|
||||
static prb_interval rbgs_to_prbs(const rbg_interval& rbgs, uint32_t cell_nof_prb)
|
||||
{
|
||||
uint32_t P = srsran_ra_type0_P(cell_nof_prb);
|
||||
return prb_interval{rbgs.start() * P, std::min(rbgs.stop() * P, cell_nof_prb)};
|
||||
}
|
||||
static prb_interval riv_to_prbs(uint32_t riv, uint32_t nof_prbs, int nof_vrbs = -1);
|
||||
};
|
||||
|
||||
inline rbg_interval rbg_interval::prbs_to_rbgs(const prb_interval& prbs, uint32_t cell_nof_prb)
|
||||
{
|
||||
uint32_t P = srsran_ra_type0_P(cell_nof_prb);
|
||||
return rbg_interval{prbs.start() / P, srsran::ceil_div(prbs.stop(), P)};
|
||||
}
|
||||
|
||||
/*******************************************************
|
||||
* helper functions
|
||||
*******************************************************/
|
||||
|
||||
/// If the RBG mask one bits are all contiguous
|
||||
inline bool is_contiguous(const rbgmask_t& mask)
|
||||
{
|
||||
return rbg_interval::find_first_interval(mask).length() == mask.count();
|
||||
}
|
||||
|
||||
/// Count number of PRBs present in a DL RBG mask
|
||||
inline uint32_t count_prb_per_tb(const rbgmask_t& bitmask)
|
||||
{
|
||||
uint32_t Nprb = cell_nof_rbg_to_prb(bitmask.size());
|
||||
uint32_t P = srsran_ra_type0_P(Nprb);
|
||||
uint32_t nof_prb = P * bitmask.count();
|
||||
if (bitmask.test(bitmask.size() - 1)) {
|
||||
nof_prb -= bitmask.size() * P - Nprb;
|
||||
}
|
||||
return nof_prb;
|
||||
}
|
||||
|
||||
/// Estimate of number of PRBs in DL grant given Nof RBGs
|
||||
inline uint32_t count_prb_per_tb_approx(uint32_t nof_rbgs, uint32_t cell_nof_prb)
|
||||
{
|
||||
uint32_t P = srsran_ra_type0_P(cell_nof_prb);
|
||||
return std::min(nof_rbgs * P, cell_nof_prb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a contiguous interval of "zeroed"/available RBG resources
|
||||
* @param max_nof_rbgs maximum number of RBGs
|
||||
* @param current_mask bitmask of occupied RBGs, used to search for available RBGs
|
||||
* @return interval with found RBGs. If a valid interval wasn't found, interval.length() == 0
|
||||
*/
|
||||
rbg_interval find_empty_rbg_interval(uint32_t max_nof_rbgs, const rbgmask_t& current_mask);
|
||||
|
||||
/**
|
||||
* Finds a bitmask of "zeroed"/available RBG resources
|
||||
* @param max_nof_rbgs maximum number of RBGs
|
||||
* @param current_mask bitmask of occupied RBGs, used to search for available RBGs
|
||||
* @return bitmask of found RBGs. If a valid mask wasn't found, bitmask::size() == 0
|
||||
*/
|
||||
rbgmask_t find_available_rbgmask(uint32_t max_nof_rbgs, bool is_contiguous, const rbgmask_t& current_mask);
|
||||
|
||||
/**
|
||||
* Finds a range of L contiguous PRBs that are empty
|
||||
* @param L Max length of the requested UL PRBs
|
||||
* @param current_mask input PRB mask where to search for available PRBs
|
||||
* @return found interval of PRBs
|
||||
*/
|
||||
prb_interval find_contiguous_ul_prbs(uint32_t L, const prbmask_t& current_mask);
|
||||
|
||||
} // namespace srsenb
|
||||
|
||||
namespace fmt {
|
||||
|
||||
template <>
|
||||
struct formatter<srsenb::rbg_interval> : public formatter<srsran::interval<uint32_t> > {};
|
||||
template <>
|
||||
struct formatter<srsenb::prb_interval> : public formatter<srsran::interval<uint32_t> > {};
|
||||
|
||||
} // namespace fmt
|
||||
|
||||
#endif // SRSRAN_SCHED_PHY_RESOURCE_H
|
@ -0,0 +1,240 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2021 Software Radio Systems Limited
|
||||
*
|
||||
* By using this file, you agree to the terms and conditions set
|
||||
* forth in the LICENSE file which can be found at the top level of
|
||||
* the distribution.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SRSRAN_SCHED_DL_CQI_H
|
||||
#define SRSRAN_SCHED_DL_CQI_H
|
||||
|
||||
#include "srsenb/hdr/stack/mac/sched_common.h"
|
||||
#include "srsenb/hdr/stack/mac/sched_helpers.h"
|
||||
#include "srsenb/hdr/stack/mac/sched_phy_ch/sched_phy_resource.h"
|
||||
#include "srsran/adt/accumulators.h"
|
||||
#include "srsran/common/common_lte.h"
|
||||
#include "srsran/phy/phch/cqi.h"
|
||||
|
||||
namespace srsenb {
|
||||
|
||||
/**
|
||||
* Class that handles DL CQI state of a given {rnti,sector}
|
||||
* - The cell bandwidth is divided into J parts. J = f(nof_cell_prbs)
|
||||
* - UE reports wideband CQI every H.Np msec, where Np is the CQI period and H=JK + 1, where K is configured in RRC
|
||||
* - Thus, for K==0, only wideband CQI is active
|
||||
*/
|
||||
class sched_dl_cqi
|
||||
{
|
||||
public:
|
||||
sched_dl_cqi(uint32_t cell_nof_prb_, uint32_t K_, uint32_t init_dl_cqi) :
|
||||
cell_nof_prb(cell_nof_prb_),
|
||||
cell_nof_rbg(cell_nof_prb_to_rbg(cell_nof_prb_)),
|
||||
K(K_),
|
||||
wb_cqi_avg(init_dl_cqi),
|
||||
bp_list(nof_bandwidth_parts(cell_nof_prb_), bandwidth_part_context(init_dl_cqi)),
|
||||
subband_cqi(std::max(1, srsran_cqi_hl_get_no_subbands(cell_nof_prb)), 0)
|
||||
{
|
||||
srsran_assert(K <= 4, "K=%d outside of {0, 4}", K);
|
||||
srsran_assert(K == 0 or cell_nof_prb_ > 6, "K > 0 not allowed for nof_prbs=6");
|
||||
}
|
||||
|
||||
/// Set K value from upper layers. See TS 36.331, CQI-ReportPeriodic
|
||||
void set_K(uint32_t K_)
|
||||
{
|
||||
srsran_assert(K <= 4, "K=%d outside of {0, 4}", K);
|
||||
srsran_assert(K == 0 or cell_nof_prb > 6, "K > 0 not allowed for nof_prbs=6");
|
||||
K = K_;
|
||||
}
|
||||
|
||||
/// Update wideband CQI
|
||||
void cqi_wb_info(tti_point tti, uint32_t cqi_value)
|
||||
{
|
||||
if (cqi_value > 0) {
|
||||
last_pos_cqi_tti = tti;
|
||||
}
|
||||
|
||||
last_wb_tti = tti;
|
||||
wb_cqi_avg = static_cast<float>(cqi_value);
|
||||
}
|
||||
|
||||
/// Update subband CQI for subband "sb_index"
|
||||
void cqi_sb_info(tti_point tti, uint32_t sb_index, uint32_t cqi_value)
|
||||
{
|
||||
if (cqi_value > 0) {
|
||||
last_pos_cqi_tti = tti;
|
||||
}
|
||||
|
||||
uint32_t bp_idx = get_bp_index(sb_index);
|
||||
bp_list[bp_idx].last_feedback_tti = tti;
|
||||
bp_list[bp_idx].last_cqi_subband_idx = sb_index;
|
||||
bp_list[bp_idx].cqi_val = static_cast<float>(cqi_value);
|
||||
|
||||
// just cap all sub-bands in the same bandwidth part
|
||||
srsran::interval<uint32_t> interv = get_bp_sb_indexes(bp_idx);
|
||||
for (uint32_t sb_index2 = interv.start(); sb_index2 < interv.stop(); ++sb_index2) {
|
||||
subband_cqi[sb_index2] = bp_list[bp_idx].cqi_val;
|
||||
}
|
||||
}
|
||||
|
||||
/// Resets CQI to provided value
|
||||
void reset_cqi(uint32_t dl_cqi)
|
||||
{
|
||||
last_pos_cqi_tti = {};
|
||||
last_wb_tti = {};
|
||||
wb_cqi_avg = dl_cqi;
|
||||
for (bandwidth_part_context& bp : bp_list) {
|
||||
bp = bandwidth_part_context(dl_cqi);
|
||||
}
|
||||
}
|
||||
|
||||
int get_avg_cqi() const { return get_grant_avg_cqi(rbg_interval(0, cell_nof_rbg)); }
|
||||
|
||||
/// Get CQI of RBG
|
||||
int get_rbg_cqi(uint32_t rbg) const
|
||||
{
|
||||
if (not subband_cqi_enabled()) {
|
||||
return static_cast<int>(wb_cqi_avg);
|
||||
}
|
||||
uint32_t sb_idx = rbg_to_sb_index(rbg);
|
||||
return get_subband_cqi_(sb_idx);
|
||||
}
|
||||
|
||||
/// Get average CQI in given RBG interval
|
||||
int get_grant_avg_cqi(rbg_interval interv) const
|
||||
{
|
||||
if (not subband_cqi_enabled()) {
|
||||
return static_cast<int>(wb_cqi_avg);
|
||||
}
|
||||
float cqi = 0;
|
||||
uint32_t sbstart = rbg_to_sb_index(interv.start()), sbend = rbg_to_sb_index(interv.stop() - 1) + 1;
|
||||
for (uint32_t sb = sbstart; sb < sbend; ++sb) {
|
||||
cqi += get_subband_cqi_(sb);
|
||||
}
|
||||
return static_cast<int>(cqi / (sbend - sbstart));
|
||||
}
|
||||
|
||||
/// Get average CQI in given PRB interval
|
||||
int get_grant_avg_cqi(prb_interval prb_interv) const
|
||||
{
|
||||
return get_grant_avg_cqi(rbg_interval::prbs_to_rbgs(prb_interv, cell_nof_prb));
|
||||
}
|
||||
|
||||
/// Get average CQI in given RBG mask
|
||||
int get_grant_avg_cqi(const rbgmask_t& mask) const
|
||||
{
|
||||
if (not subband_cqi_enabled()) {
|
||||
return static_cast<int>(wb_cqi_avg);
|
||||
}
|
||||
float cqi = 0;
|
||||
uint32_t count = 0;
|
||||
for (int rbg = mask.find_lowest(0, mask.size()); rbg != -1; rbg = mask.find_lowest(rbg, mask.size())) {
|
||||
uint32_t sb = rbg_to_sb_index(rbg);
|
||||
cqi += get_subband_cqi_(sb);
|
||||
count++;
|
||||
rbg = static_cast<int>(((sb + 1U) * cell_nof_rbg + N() - 1U) / N()); // skip to next subband index
|
||||
}
|
||||
return static_cast<int>(cqi / count);
|
||||
}
|
||||
|
||||
/// Get CQI-optimal RBG mask with at most "req_rbgs" RBGs
|
||||
rbgmask_t get_optim_rbgmask(uint32_t req_rbgs, bool max_min_flag = true) const
|
||||
{
|
||||
rbgmask_t rbgmask(cell_nof_rbg);
|
||||
return get_optim_rbgmask(rbgmask, req_rbgs, max_min_flag);
|
||||
}
|
||||
rbgmask_t get_optim_rbgmask(const rbgmask_t& dl_mask, uint32_t req_rbgs, bool max_min_flag = true) const;
|
||||
|
||||
/// TS 36.321, 7.2.2 - Parameter N
|
||||
uint32_t nof_subbands() const { return subband_cqi.size(); }
|
||||
|
||||
/// TS 36.321, 7.2.2 - Parameter J
|
||||
uint32_t nof_bandwidth_parts() const { return bp_list.size(); }
|
||||
|
||||
bool subband_cqi_enabled() const { return K > 0; }
|
||||
|
||||
bool is_cqi_info_received() const { return last_pos_cqi_tti.is_valid(); }
|
||||
|
||||
tti_point last_cqi_info_tti() const { return last_pos_cqi_tti; }
|
||||
|
||||
int get_wb_cqi_info() const { return wb_cqi_avg; }
|
||||
|
||||
uint32_t rbg_to_sb_index(uint32_t rbg_index) const { return rbg_index * N() / cell_nof_rbg; }
|
||||
|
||||
/// Get CQI of given subband index
|
||||
int get_subband_cqi(uint32_t subband_index) const
|
||||
{
|
||||
if (subband_cqi_enabled()) {
|
||||
return get_wb_cqi_info();
|
||||
}
|
||||
return bp_list[get_bp_index(subband_index)].last_feedback_tti.is_valid() ? subband_cqi[subband_index] : wb_cqi_avg;
|
||||
}
|
||||
|
||||
private:
|
||||
static const uint32_t max_subband_size = 8;
|
||||
static const uint32_t max_nof_subbands = 13;
|
||||
static const uint32_t max_bandwidth_parts = 4;
|
||||
|
||||
/// TS 36.321, Table 7.2.2-2
|
||||
static uint32_t nof_bandwidth_parts(uint32_t nof_prb)
|
||||
{
|
||||
static const uint32_t nrb[] = {0, 2, 2, 3, 4, 4};
|
||||
return nrb[srsran::lte_cell_nof_prb_to_index(nof_prb)];
|
||||
}
|
||||
|
||||
uint32_t J() const { return nof_bandwidth_parts(); }
|
||||
uint32_t N() const { return nof_subbands(); }
|
||||
|
||||
uint32_t get_bp_index(uint32_t sb_index) const { return sb_index * J() / N(); }
|
||||
|
||||
uint32_t prb_to_sb_index(uint32_t prb_index) const { return prb_index * N() / cell_nof_prb; }
|
||||
|
||||
srsran::interval<uint32_t> get_bp_sb_indexes(uint32_t bp_idx) const
|
||||
{
|
||||
return srsran::interval<uint32_t>{bp_idx * N() / J(), (bp_idx + 1) * N() / J()};
|
||||
}
|
||||
|
||||
float get_subband_cqi_(uint32_t sb_idx) const
|
||||
{
|
||||
return bp_list[get_bp_index(sb_idx)].last_feedback_tti.is_valid() ? subband_cqi[sb_idx] : wb_cqi_avg;
|
||||
}
|
||||
|
||||
uint32_t cell_nof_prb;
|
||||
uint32_t cell_nof_rbg;
|
||||
uint32_t K; ///< set in RRC
|
||||
|
||||
/// context of bandwidth part
|
||||
struct bandwidth_part_context {
|
||||
tti_point last_feedback_tti{};
|
||||
uint32_t last_cqi_subband_idx;
|
||||
float cqi_val;
|
||||
|
||||
explicit bandwidth_part_context(uint32_t init_dl_cqi) : cqi_val(init_dl_cqi), last_cqi_subband_idx(max_nof_subbands)
|
||||
{}
|
||||
};
|
||||
|
||||
tti_point last_pos_cqi_tti;
|
||||
|
||||
tti_point last_wb_tti;
|
||||
float wb_cqi_avg;
|
||||
|
||||
srsran::bounded_vector<bandwidth_part_context, max_bandwidth_parts> bp_list;
|
||||
srsran::bounded_vector<float, max_nof_subbands> subband_cqi;
|
||||
};
|
||||
|
||||
/// Get {RBG index, CQI} tuple which correspond to the set RBG with the lowest CQI
|
||||
std::tuple<uint32_t, int> find_min_cqi_rbg(const rbgmask_t& mask, const sched_dl_cqi& dl_cqi);
|
||||
|
||||
/// Returns the same RBG mask, but with the RBGs of the subband with the lowest CQI reset
|
||||
rbgmask_t remove_min_cqi_subband(const rbgmask_t& rbgmask, const sched_dl_cqi& dl_cqi);
|
||||
|
||||
/// Returns the same RBG mask, but with the RBG with the lowest CQI reset
|
||||
rbgmask_t remove_min_cqi_rbg(const rbgmask_t& rbgmask, const sched_dl_cqi& dl_cqi);
|
||||
|
||||
} // namespace srsenb
|
||||
|
||||
#endif // SRSRAN_SCHED_DL_CQI_H
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue