Implementation of time-domain PF scheduler

- PF scheduling becomes the new default
This commit is contained in:
Francisco 2020-11-27 16:50:46 +00:00 committed by Andre Puschmann
parent 07d2bc4fe8
commit d7fae0b7a3
8 changed files with 509 additions and 27 deletions

View File

@ -0,0 +1,99 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2020 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 SRSLTE_SCHED_PF_H
#define SRSLTE_SCHED_PF_H
#include "sched.h"
#include <queue>
namespace srsenb {
class sched_dl_pf : public sched::metric_dl
{
using ue_cit_t = std::map<uint16_t, sched_ue>::const_iterator;
public:
void set_params(const sched_cell_params_t& cell_params_) final;
void sched_users(std::map<uint16_t, sched_ue>& ue_db, dl_sf_sched_itf* tti_sched) final;
private:
const sched_cell_params_t* cc_cfg = nullptr;
srslte::log_ref log_h;
struct ue_ctxt {
ue_ctxt(uint16_t rnti_) : rnti(rnti_) {}
float avg_rate() const { return nof_samples == 0 ? 0 : rate; }
uint32_t count() const { return nof_samples; }
void new_tti(const sched_cell_params_t& cell, sched_ue& ue, dl_sf_sched_itf* tti_sched);
void save_history(bool alloc, float alpha);
const uint16_t rnti;
uint32_t ue_cc_idx = 0;
bool is_retx = false;
float prio = 0;
dl_harq_proc* h = nullptr;
private:
float rate = 0;
uint32_t nof_samples = 0;
};
std::map<uint16_t, ue_ctxt> ue_history_db;
struct ue_prio_compare {
bool operator()(const ue_ctxt* lhs, const ue_ctxt* rhs) const;
};
std::priority_queue<ue_ctxt*, std::vector<ue_ctxt*>, ue_prio_compare> ue_queue;
bool try_dl_alloc(ue_ctxt& ue_ctxt, sched_ue& ue, dl_sf_sched_itf* tti_sched);
};
class sched_ul_pf : public sched::metric_ul
{
using ue_cit_t = std::map<uint16_t, sched_ue>::const_iterator;
public:
void set_params(const sched_cell_params_t& cell_params_) final;
void sched_users(std::map<uint16_t, sched_ue>& ue_db, ul_sf_sched_itf* tti_sched) final;
private:
const sched_cell_params_t* cc_cfg = nullptr;
srslte::log_ref log_h;
struct ue_ctxt {
ue_ctxt(uint16_t rnti_) : rnti(rnti_) {}
float avg_rate() const { return nof_samples == 0 ? 0 : rate; }
uint32_t count() const { return nof_samples; }
void new_tti(const sched_cell_params_t& cell, sched_ue& ue, ul_sf_sched_itf* tti_sched);
void save_history(bool alloc, float alpha);
const uint16_t rnti;
uint32_t ue_cc_idx = 0;
float prio = 0;
ul_harq_proc* h = nullptr;
private:
float rate = 0;
uint32_t nof_samples = 0;
};
std::map<uint16_t, ue_ctxt> ue_history_db;
struct ue_prio_compare {
bool operator()(const ue_ctxt* lhs, const ue_ctxt* rhs) const;
};
std::priority_queue<ue_ctxt*, std::vector<ue_ctxt*>, ue_prio_compare> ue_queue;
bool try_ul_alloc(ue_ctxt& ue_ctxt, sched_ue& ue, ul_sf_sched_itf* tti_sched);
};
} // namespace srsenb
#endif // SRSLTE_SCHED_PF_H

View File

@ -49,8 +49,8 @@ struct cc_sched_ue {
const sched_cell_params_t* get_cell_cfg() const { return cell_params; }
uint32_t get_ue_cc_idx() const { return ue_cc_idx; }
void set_dl_cqi(uint32_t tti_tx_dl, uint32_t dl_cqi);
int cqi_to_tbs(uint32_t nof_prb, uint32_t nof_re, bool use_tbs_index_alt, bool is_ul, uint32_t* mcs);
cc_st cc_state() const { return cc_state_; }
int cqi_to_tbs(uint32_t nof_prb, uint32_t nof_re, bool is_ul, uint32_t* mcs);
cc_st cc_state() const { return cc_state_; }
harq_entity harq_ent;
@ -144,11 +144,13 @@ public:
rbg_interval get_required_dl_rbgs(uint32_t ue_cc_idx);
srslte::interval<uint32_t> get_requested_dl_bytes(uint32_t ue_cc_idx);
uint32_t get_pending_dl_rlc_data() const;
uint32_t get_expected_dl_bitrate(uint32_t ue_cc_idx) const;
uint32_t get_pending_ul_data_total(uint32_t tti, int this_ue_cc_idx);
uint32_t get_pending_ul_new_data(uint32_t tti, int this_ue_cc_idx);
uint32_t get_pending_ul_old_data();
uint32_t get_pending_ul_old_data(uint32_t cc_idx);
uint32_t get_expected_ul_bitrate(uint32_t ue_cc_idx) const;
dl_harq_proc* get_pending_dl_harq(uint32_t tti_tx_dl, uint32_t cc_idx);
dl_harq_proc* get_empty_dl_harq(uint32_t tti_tx_dl, uint32_t cc_idx);

View File

@ -7,7 +7,7 @@
#
set(SOURCES mac.cc ue.cc sched.cc sched_carrier.cc sched_grid.cc sched_harq.cc sched_metric.cc sched_ue.cc
sched_lch.cc sched_interface_helpers.cc)
sched_lch.cc sched_interface_helpers.cc sched_pf.cc)
add_library(srsenb_mac STATIC ${SOURCES})
if(ENABLE_5GNR)

View File

@ -13,6 +13,7 @@
#include "srsenb/hdr/stack/mac/sched_carrier.h"
#include "srsenb/hdr/stack/mac/sched_interface_helpers.h"
#include "srsenb/hdr/stack/mac/sched_metric.h"
#include "srsenb/hdr/stack/mac/sched_pf.h"
#include "srslte/common/log_helper.h"
#include "srslte/common/logmap.h"
@ -288,9 +289,13 @@ void sched::carrier_sched::carrier_cfg(const sched_cell_params_t& cell_params_)
ra_sched_ptr.reset(new ra_sched{*cc_cfg, *ue_db});
// Setup data scheduling algorithms
dl_metric.reset(new srsenb::dl_metric_rr{});
// dl_metric.reset(new srsenb::dl_metric_rr{});
// dl_metric->set_params(*cc_cfg);
// ul_metric.reset(new srsenb::ul_metric_rr{});
// ul_metric->set_params(*cc_cfg);
dl_metric.reset(new srsenb::sched_dl_pf{});
dl_metric->set_params(*cc_cfg);
ul_metric.reset(new srsenb::ul_metric_rr{});
ul_metric.reset(new srsenb::sched_ul_pf{});
ul_metric->set_params(*cc_cfg);
// Initiate the tti_scheduler for each TTI

View File

@ -371,21 +371,6 @@ void harq_entity::reset_pending_data(srslte::tti_point tti_rx)
for (auto& h : dl_harqs) {
h.reset_pending_data();
}
// delete old DL harq procs
for (auto& h : dl_harqs) {
if (not h.is_empty()) {
if (tti_tx_dl > h.get_tti() + 100) {
srslte::logmap::get("MAC")->info("SCHED: pid=%d is old. tti_pid=%d, now is %d, resetting\n",
h.get_id(),
h.get_tti().to_uint(),
tti_tx_dl.to_uint());
for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) {
h.reset(tb);
}
}
}
}
}
/**

View File

@ -245,6 +245,10 @@ ul_harq_proc* ul_metric_rr::allocate_user_retx_prbs(sched_ue* user)
// if there are procedures and we have space
if (h->has_pending_retx()) {
// Avoid measGaps
if (not user->pusch_enabled(tti_rx, cc_cfg->enb_cc_idx, false)) {
return nullptr;
}
prb_interval alloc = h->get_alloc();
// If can schedule the same mask, do it
@ -257,6 +261,10 @@ ul_harq_proc* ul_metric_rr::allocate_user_retx_prbs(sched_ue* user)
return nullptr;
}
// Avoid measGaps accounting for PDCCH
if (not user->pusch_enabled(tti_rx, cc_cfg->enb_cc_idx, true)) {
return nullptr;
}
if (find_allocation(alloc.length(), &alloc)) {
ret = tti_alloc->alloc_ul_user(user, alloc);
if (ret == alloc_outcome_t::SUCCESS) {

View File

@ -0,0 +1,355 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2020 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.
*
*/
#include "srsenb/hdr/stack/mac/sched_pf.h"
#include "srsenb/hdr/stack/mac/sched_harq.h"
namespace srsenb {
void sched_dl_pf::set_params(const sched_cell_params_t& cell_params_)
{
cc_cfg = &cell_params_;
log_h = srslte::logmap::get("MAC");
}
void sched_dl_pf::sched_users(std::map<uint16_t, sched_ue>& ue_db, dl_sf_sched_itf* tti_sched)
{
if (ue_db.empty()) {
return;
}
// remove deleted users from history
for (auto it = ue_history_db.begin(); it != ue_history_db.end();) {
if (not ue_db.count(it->first)) {
it = ue_history_db.erase(it);
} else {
++it;
}
}
// add new users to history db, and update priority queue
for (auto& u : ue_db) {
auto it = ue_history_db.find(u.first);
if (it == ue_history_db.end()) {
it = ue_history_db.insert(std::make_pair(u.first, ue_ctxt{u.first})).first;
}
it->second.new_tti(*cc_cfg, u.second, tti_sched);
ue_queue.push(&it->second);
}
while (not ue_queue.empty()) {
ue_ctxt& ue = *ue_queue.top();
bool alloc_success = try_dl_alloc(ue, ue_db[ue.rnti], tti_sched);
ue.save_history(alloc_success, 0.01);
ue_queue.pop();
}
}
void sched_dl_pf::ue_ctxt::new_tti(const sched_cell_params_t& cell, sched_ue& ue, dl_sf_sched_itf* tti_sched)
{
h = nullptr;
prio = 0;
is_retx = false;
auto p = ue.get_active_cell_index(cell.enb_cc_idx);
if (not p.first) {
return;
}
if (not ue.pdsch_enabled(srslte::tti_point(tti_sched->get_tti_tx_dl() - TX_ENB_DELAY), cell.enb_cc_idx)) {
return;
}
ue_cc_idx = p.second;
// search for DL HARQ
h = ue.get_pending_dl_harq(tti_sched->get_tti_tx_dl(), ue_cc_idx);
is_retx = h != nullptr;
if (h == nullptr) {
h = ue.get_empty_dl_harq(tti_sched->get_tti_tx_dl(), ue_cc_idx);
if (h == nullptr) {
return;
}
}
// calculate PF priority
float r = ue.get_expected_dl_bitrate(ue_cc_idx) / 8;
float R = avg_rate();
prio = (R != 0) ? r / R : (r == 0 ? 0 : std::numeric_limits<float>::max());
}
void sched_dl_pf::ue_ctxt::save_history(bool alloc, float alpha)
{
float sample = alloc ? (h->get_tbs(0) + h->get_tbs(1)) : 0;
if (nof_samples < 1 / alpha) {
// fast start
rate = rate + (sample - rate) / (nof_samples + 1);
} else {
rate = (1 - alpha) * rate + (alpha)*sample;
}
nof_samples++;
}
bool find_allocation(uint32_t min_nof_rbg, uint32_t max_nof_rbg, rbgmask_t* rbgmask, dl_sf_sched_itf* tti_alloc)
{
if (tti_alloc->get_dl_mask().all()) {
return false;
}
// 1's for free rbgs
rbgmask_t localmask = ~(tti_alloc->get_dl_mask());
uint32_t i = 0, nof_alloc = 0;
for (; i < localmask.size() and nof_alloc < max_nof_rbg; ++i) {
if (localmask.test(i)) {
nof_alloc++;
}
}
if (nof_alloc < min_nof_rbg) {
return false;
}
localmask.fill(i, localmask.size(), false);
*rbgmask = localmask;
return true;
}
bool sched_dl_pf::try_dl_alloc(ue_ctxt& ue_ctxt, sched_ue& ue, dl_sf_sched_itf* tti_sched)
{
if (tti_sched->is_dl_alloc(ue_ctxt.rnti) or ue_ctxt.prio == 0) {
return false;
}
alloc_outcome_t code;
if (ue_ctxt.is_retx) {
// Try to reuse the same mask
rbgmask_t retx_mask = ue_ctxt.h->get_rbgmask();
code = tti_sched->alloc_dl_user(&ue, retx_mask, ue_ctxt.h->get_id());
if (code == alloc_outcome_t::SUCCESS) {
return true;
}
if (code == alloc_outcome_t::DCI_COLLISION) {
// No DCIs available for this user. Move to next
log_h->info("SCHED: Couldn't find space in PDCCH for DL retx for rnti=0x%x\n", ue_ctxt.rnti);
return false;
}
// If previous mask does not fit, find another with exact same number of rbgs
size_t nof_rbg = retx_mask.count();
if (find_allocation(nof_rbg, nof_rbg, &retx_mask, tti_sched)) {
code = tti_sched->alloc_dl_user(&ue, retx_mask, ue_ctxt.h->get_id());
if (code == alloc_outcome_t::SUCCESS) {
return true;
}
if (code == alloc_outcome_t::DCI_COLLISION) {
log_h->info("SCHED: Couldn't find space in PDCCH for DL retx for rnti=0x%x\n", ue.get_rnti());
return false;
}
}
} else {
// Allocate resources based on pending data
rbg_interval req_rbgs = ue.get_required_dl_rbgs(ue_ctxt.ue_cc_idx);
if (req_rbgs.stop() > 0) {
rbgmask_t newtx_mask(tti_sched->get_dl_mask().size());
if (find_allocation(req_rbgs.start(), req_rbgs.stop(), &newtx_mask, tti_sched)) {
// some empty spaces were found
code = tti_sched->alloc_dl_user(&ue, newtx_mask, ue_ctxt.h->get_id());
if (code == alloc_outcome_t::SUCCESS) {
return true;
} else if (code == alloc_outcome_t::DCI_COLLISION) {
log_h->info("SCHED: Couldn't find space in PDCCH for DL tx for rnti=0x%x\n", ue_ctxt.rnti);
}
}
}
}
return false;
}
bool sched_dl_pf::ue_prio_compare::operator()(const sched_dl_pf::ue_ctxt* lhs, const sched_dl_pf::ue_ctxt* rhs) const
{
return (not lhs->is_retx and rhs->is_retx) or (lhs->is_retx == rhs->is_retx and lhs->prio < rhs->prio);
}
/*****************************************************************
*
* Uplink Metric
*
*****************************************************************/
void sched_ul_pf::set_params(const sched_cell_params_t& cell_params_)
{
cc_cfg = &cell_params_;
log_h = srslte::logmap::get("MAC");
}
void sched_ul_pf::sched_users(std::map<uint16_t, sched_ue>& ue_db, ul_sf_sched_itf* tti_sched)
{
if (ue_db.empty()) {
return;
}
// remove deleted users from history
for (auto it = ue_history_db.begin(); it != ue_history_db.end();) {
if (not ue_db.count(it->first)) {
it = ue_history_db.erase(it);
} else {
++it;
}
}
// add new users to history db, and update priority queue
for (auto& u : ue_db) {
auto it = ue_history_db.find(u.first);
if (it == ue_history_db.end()) {
it = ue_history_db.insert(std::make_pair(u.first, ue_ctxt{u.first})).first;
}
it->second.new_tti(*cc_cfg, u.second, tti_sched);
ue_queue.push(&it->second);
}
while (not ue_queue.empty()) {
ue_ctxt& ue = *ue_queue.top();
bool alloc_success = try_ul_alloc(ue, ue_db[ue.rnti], tti_sched);
ue.save_history(alloc_success, 0.01);
ue_queue.pop();
}
}
/**
* Finds a range of L contiguous PRBs that are empty
* @param L Size of the requested UL allocation in PRBs
* @param alloc Found allocation. It is guaranteed that 0 <= alloc->L <= L
* @return true if the requested allocation of size L was strictly met
*/
bool find_allocation(uint32_t L, prb_interval* alloc, ul_sf_sched_itf* tti_sched)
{
const prbmask_t* used_rb = &tti_sched->get_ul_mask();
*alloc = {};
for (uint32_t n = 0; n < used_rb->size() && alloc->length() < L; n++) {
if (not used_rb->test(n) && alloc->length() == 0) {
alloc->displace_to(n);
}
if (not used_rb->test(n)) {
alloc->resize_by(1);
} else if (alloc->length() > 0) {
// avoid edges
if (n < 3) {
*alloc = {};
} else {
break;
}
}
}
if (alloc->length() == 0) {
return false;
}
// Make sure L is allowed by SC-FDMA modulation
while (!srslte_dft_precoding_valid_prb(alloc->length())) {
alloc->resize_by(-1);
}
return alloc->length() == L;
}
bool sched_ul_pf::try_ul_alloc(ue_ctxt& ue_ctxt, sched_ue& ue, ul_sf_sched_itf* tti_sched)
{
if (ue_ctxt.h == nullptr or tti_sched->is_ul_alloc(ue_ctxt.rnti) or ue_ctxt.prio == 0) {
return false;
}
srslte::tti_point tti_rx{tti_sched->get_tti_tx_ul() - (TX_ENB_DELAY + FDD_HARQ_DELAY_DL_MS)};
alloc_outcome_t ret;
if (ue_ctxt.h->has_pending_retx()) {
prb_interval alloc = ue_ctxt.h->get_alloc();
// If can schedule the same mask, do it
ret = tti_sched->alloc_ul_user(&ue, alloc);
if (ret == alloc_outcome_t::SUCCESS) {
return true;
}
if (ret == alloc_outcome_t::DCI_COLLISION) {
log_h->info("SCHED: Couldn't find space in PDCCH for UL retx of rnti=0x%x\n", ue.get_rnti());
return false;
}
// Avoid measGaps accounting for PDCCH
if (not ue.pusch_enabled(tti_rx, cc_cfg->enb_cc_idx, true)) {
return false;
}
if (find_allocation(alloc.length(), &alloc, tti_sched)) {
ret = tti_sched->alloc_ul_user(&ue, alloc);
if (ret == alloc_outcome_t::SUCCESS) {
return true;
}
if (ret == alloc_outcome_t::DCI_COLLISION) {
log_h->info("SCHED: Couldn't find space in PDCCH for UL retx of rnti=0x%x\n", ue.get_rnti());
}
}
} else {
// Avoid measGaps accounting for PDCCH
if (not ue.pusch_enabled(tti_rx, cc_cfg->enb_cc_idx, true)) {
return false;
}
uint32_t pending_data = ue.get_pending_ul_new_data(tti_sched->get_tti_tx_ul(), ue_ctxt.ue_cc_idx);
// find an empty PID
if (ue_ctxt.h->is_empty(0) and pending_data > 0) {
uint32_t pending_rb = ue.get_required_prb_ul(ue_ctxt.ue_cc_idx, pending_data);
prb_interval alloc{};
find_allocation(pending_rb, &alloc, tti_sched);
if (alloc.length() > 0) { // at least one PRB was scheduled
ret = tti_sched->alloc_ul_user(&ue, alloc);
if (ret == alloc_outcome_t::SUCCESS) {
return true;
}
if (ret == alloc_outcome_t::DCI_COLLISION) {
log_h->info("SCHED: Couldn't find space in PDCCH for UL tx of rnti=0x%x\n", ue.get_rnti());
}
}
}
}
return false;
}
void sched_ul_pf::ue_ctxt::new_tti(const sched_cell_params_t& cell, sched_ue& ue, ul_sf_sched_itf* tti_sched)
{
srslte::tti_point tti_rx = srslte::tti_point(tti_sched->get_tti_tx_ul() - TX_ENB_DELAY - FDD_HARQ_DELAY_DL_MS);
h = nullptr;
prio = 0;
auto p = ue.get_active_cell_index(cell.enb_cc_idx);
if (not p.first) {
return;
}
if (not ue.pusch_enabled(tti_rx, cell.enb_cc_idx, false)) {
return;
}
ue_cc_idx = p.second;
h = ue.get_ul_harq(tti_sched->get_tti_tx_ul(), ue_cc_idx);
// calculate PF priority
float r = ue.get_expected_ul_bitrate(ue_cc_idx) / 8;
float R = avg_rate();
prio = (R != 0) ? r / R : (r == 0 ? 0 : std::numeric_limits<float>::max());
}
void sched_ul_pf::ue_ctxt::save_history(bool alloc, float alpha)
{
float sample = alloc ? h->get_pending_data() : 0;
if (nof_samples < 1 / alpha) {
// fast start
rate = rate + (sample - rate) / (nof_samples + 1);
} else {
rate = (1 - alpha) * rate + (alpha)*sample;
}
nof_samples++;
}
bool sched_ul_pf::ue_prio_compare::operator()(const sched_ul_pf::ue_ctxt* lhs, const sched_ul_pf::ue_ctxt* rhs) const
{
bool is_retx1 = lhs->h != nullptr and lhs->h->has_pending_retx(),
is_retx2 = rhs->h != nullptr and rhs->h->has_pending_retx();
return (not is_retx1 and is_retx2) or (is_retx1 == is_retx2 and lhs->prio < rhs->prio);
}
} // namespace srsenb

View File

@ -1035,6 +1035,34 @@ uint32_t sched_ue::get_pending_dl_rlc_data() const
return pending_data;
}
uint32_t sched_ue::get_expected_dl_bitrate(uint32_t ue_cc_idx) const
{
const cc_sched_ue* cc = &carriers[ue_cc_idx];
auto* cell_cfg = carriers[ue_cc_idx].get_cell_cfg();
uint32_t nof_re =
srslte_ra_dl_approx_nof_re(&cell_cfg->cfg.cell, cell_cfg->nof_prb(), cell_cfg->sched_cfg->max_nof_ctrl_symbols);
float max_coderate = srslte_cqi_to_coderate(std::min(cc->dl_cqi + 1u, 15u), cfg.use_tbs_index_alt);
// Inverse of srslte_coderate(tbs, nof_re)
uint32_t tbs = max_coderate * nof_re - 24;
return tbs / tti_duration_ms;
}
uint32_t sched_ue::get_expected_ul_bitrate(uint32_t ue_cc_idx) const
{
const cc_sched_ue* cc = &carriers[ue_cc_idx];
uint32_t N_srs = 0;
uint32_t nof_symb = 2 * (SRSLTE_CP_NSYMB(cell.cp) - 1) - N_srs;
uint32_t nof_re = nof_symb * cell.nof_prb * SRSLTE_NRE;
float max_coderate = srslte_cqi_to_coderate(std::min(cc->ul_cqi + 1u, 15u), false);
// Inverse of srslte_coderate(tbs, nof_re)
uint32_t tbs = max_coderate * nof_re - 24;
return tbs / tti_duration_ms;
}
/// Returns nof bytes allocated to active UL HARQs in the carrier cc_idx.
/// NOTE: The returned value accounts for the MAC header and payload (RLC headers and actual data)
uint32_t sched_ue::get_pending_ul_old_data(uint32_t ue_cc_idx)
@ -1249,7 +1277,7 @@ int sched_ue::enb_to_ue_cc_idx(uint32_t enb_cc_idx) const
return it != carriers.end() ? std::distance(carriers.begin(), it) : -1;
}
int cc_sched_ue::cqi_to_tbs(uint32_t nof_prb, uint32_t nof_re, bool use_tbs_index_alt, bool is_ul, uint32_t* mcs)
int cc_sched_ue::cqi_to_tbs(uint32_t nof_prb, uint32_t nof_re, bool is_ul, uint32_t* mcs)
{
using ul64qam_cap = sched_interface::ue_cfg_t::ul64qam_cap;
uint32_t max_Qm;
@ -1261,17 +1289,17 @@ int cc_sched_ue::cqi_to_tbs(uint32_t nof_prb, uint32_t nof_re, bool use_tbs_inde
max_coderate = srslte_cqi_to_coderate(std::min(ul_cqi + 1u, 15u), false);
} else {
max_mcs = max_mcs_dl;
max_Qm = use_tbs_index_alt ? 8 : 6;
max_coderate = srslte_cqi_to_coderate(std::min(dl_cqi + 1u, 15u), use_tbs_index_alt);
max_Qm = cfg->use_tbs_index_alt ? 8 : 6;
max_coderate = srslte_cqi_to_coderate(std::min(dl_cqi + 1u, 15u), cfg->use_tbs_index_alt);
}
// function with sign-flip at solution
auto compute_tbs = [&](int sel_mcs) -> float {
uint32_t tbs_idx = srslte_ra_tbs_idx_from_mcs(sel_mcs, use_tbs_index_alt, is_ul);
uint32_t tbs_idx = srslte_ra_tbs_idx_from_mcs(sel_mcs, cfg->use_tbs_index_alt, is_ul);
int tbs = srslte_ra_tbs_from_idx(tbs_idx, nof_prb);
float coderate = srslte_coderate(tbs, nof_re);
srslte_mod_t mod =
(is_ul) ? srslte_ra_ul_mod_from_mcs(sel_mcs) : srslte_ra_dl_mod_from_mcs(sel_mcs, use_tbs_index_alt);
(is_ul) ? srslte_ra_ul_mod_from_mcs(sel_mcs) : srslte_ra_dl_mod_from_mcs(sel_mcs, cfg->use_tbs_index_alt);
uint32_t Qm = std::min(max_Qm, srslte_mod_bits_x_symbol(mod));
return coderate - std::min(max_coderate, 0.930f * Qm);
};
@ -1288,7 +1316,7 @@ int cc_sched_ue::cqi_to_tbs(uint32_t nof_prb, uint32_t nof_re, bool use_tbs_inde
}
}
int chosen_mcs = std::get<0>(ret);
uint32_t tbs_idx = srslte_ra_tbs_idx_from_mcs(chosen_mcs, use_tbs_index_alt, is_ul);
uint32_t tbs_idx = srslte_ra_tbs_idx_from_mcs(chosen_mcs, cfg->use_tbs_index_alt, is_ul);
int chosen_tbs = srslte_ra_tbs_from_idx(tbs_idx, nof_prb);
if (mcs != nullptr) {
@ -1441,7 +1469,7 @@ int cc_sched_ue::alloc_tbs(uint32_t nof_prb, uint32_t nof_re, uint32_t req_bytes
uint32_t sel_mcs = 0;
// TODO: Compute real spectral efficiency based on PUSCH-UCI configuration
int tbs_bytes = cqi_to_tbs(nof_prb, nof_re, cfg->use_tbs_index_alt, is_ul, &sel_mcs) / 8;
int tbs_bytes = cqi_to_tbs(nof_prb, nof_re, is_ul, &sel_mcs) / 8;
/* If less bytes are requested, lower the MCS */
if (tbs_bytes > (int)req_bytes && req_bytes > 0) {