Compare commits

...

17 Commits

Author SHA1 Message Date
Robert Schmidt
33cc7906ee Revert "Restructure: first make sure UE can be allocated"
This reverts commit cf4d860278.
2026-04-17 13:39:07 +02:00
Robert Schmidt
7345553f74 Revert "To be finished: candidate/schedule UEs"
This reverts commit 514062c56d.
2026-04-17 13:39:01 +02:00
Robert Schmidt
514062c56d To be finished: candidate/schedule UEs 2026-04-17 13:38:45 +02:00
Robert Schmidt
cf4d860278 Restructure: first make sure UE can be allocated 2026-04-17 13:13:08 +02:00
Robert Schmidt
72dc2a3315 Update SINRx10_MCS_mapping with new measurements
I reran nr_dlsim for various SNR values as in the corresponding comment.
To accelerate this, it is convient to run in parallel:

    parallel -a data-0 --colsep ' ' --results dlsim_mu0_tbl0_mcs{1} -j $(nproc) ./nr_dlsim -n 10000 -q 0 -m 0 -R 25 -b 25 -e {1} -s {2} -S {3} -t 99.99

where data-0 is a file with lines conforming to

MCS SNR0 SNR1
MCS SNR0 SNR1

probably SNR1 is not required.
2026-04-17 13:12:53 +02:00
Robert Schmidt
6bf52fc134 Store MCS estimation per quantity
Store estimated MCS (from CQI, SINR, ...) individually to allow better
control on which MCS we check (or, possibly, to combine them in the
future).
2026-04-17 13:12:42 +02:00
Robert Schmidt
851302ef24 Remove optionality from Iperf in 7.2 FHI test
Since the right MCS should be chosen from the beginning, it's not
necessary to make this optional anymore.
2026-04-17 12:21:25 +02:00
Robert Schmidt
48dbae5cbb Switch to estimated MCS on big deviation
Switch to the estimated MCS if it varies a lot from the current MCS.
This can happen if e.g., we receive the first estimation, or in sudden
change of channel condition.
2026-04-17 12:20:19 +02:00
Robert Schmidt
7d38fa3028 Integrate no-retransmission case into estimate_next_mcs() 2026-04-17 12:20:16 +02:00
Robert Schmidt
3b97eef384 Estimate MCS on inactivity 2026-04-17 12:18:52 +02:00
Robert Schmidt
95a56c1a1c Do not scale down MCS on inactivity 2026-04-17 12:15:58 +02:00
Robert Schmidt
96afcdef68 Track UE activity for MCS selection
A UE is considered "active" if it has active data transmissions (a certain
minimum amount of traffic, or sudden burst). If not, after 100 frames,
it will be considered "inactive".

A future commit will handle the MCS selection in these cases.
2026-04-17 12:14:17 +02:00
Robert Schmidt
f8a1c3bea0 try maximum UEs per TTI
on this commit, on avra (20MHz), max 5?:

2025-09-26 13:22:54.528519 UTC [NR_MAC]    191.15 [DLSCH/PDSCH/PUCCH] RNTI 43b7 DCI L 1 start   0 RBs  13 startSymbol  1 nb_symbol 13 dmrspos 804 MCS 27 nrOfLayers 1 TBS 1729 HARQ PID  6 round 1 RV 2 NDI 1 dl_data_to_ULACK 0 (191.17) PUCCH allocation 3 TPC 1
2025-09-26 13:22:54.528528 UTC [NR_MAC]    191.15 [DLSCH/PDSCH/PUCCH] RNTI a4bf DCI L 1 start  13 RBs  10 startSymbol  1 nb_symbol 13 dmrspos 804 MCS 27 nrOfLayers 1 TBS 1345 HARQ PID  4 round 0 RV 0 NDI 1 dl_data_to_ULACK 0 (191.17) PUCCH allocation 3 TPC 0
2025-09-26 13:22:54.528535 UTC [NR_MAC]    191.15 [DLSCH/PDSCH/PUCCH] RNTI 1969 DCI L 1 start  23 RBs  10 startSymbol  1 nb_symbol 13 dmrspos 804 MCS 27 nrOfLayers 1 TBS 1345 HARQ PID 13 round 0 RV 0 NDI 0 dl_data_to_ULACK 0 (191.17) PUCCH allocation 3 TPC 0
2025-09-26 13:22:54.528542 UTC [NR_MAC]    191.15 [DLSCH/PDSCH/PUCCH] RNTI 5d1b DCI L 1 start  33 RBs  10 startSymbol  1 nb_symbol 13 dmrspos 804 MCS 27 nrOfLayers 1 TBS 1345 HARQ PID  2 round 0 RV 0 NDI 1 dl_data_to_ULACK 0 (191.17) PUCCH allocation 3 TPC 0
2025-09-26 13:22:54.528550 UTC [NR_MAC]    191.15 [DLSCH/PDSCH/PUCCH] RNTI f4f9 DCI L 1 start  43 RBs   8 startSymbol  1 nb_symbol 13 dmrspos 804 MCS 27 nrOfLayers 1 TBS 1057 HARQ PID  8 round 0 RV 0 NDI 0 dl_data_to_ULACK 0 (191.17) PUCCH allocation 3 TPC 1
2026-04-17 12:14:12 +02:00
OAI Jenkins
a1ab29d1b0 VIAVI Make UE coeff converge faster 2026-04-17 12:05:25 +02:00
Robert Schmidt
8b23d2449e TODO VIAVI increase max PUCCH.
Does not apply anymore after !3991. still relevrant?

diff --git openair1/PHY/INIT/nr_init.c openair1/PHY/INIT/nr_init.c
index 7a360e30ff..44873ae607 100644
--- openair1/PHY/INIT/nr_init.c
+++ openair1/PHY/INIT/nr_init.c
@@ -464,7 +464,7 @@ void init_nr_transport(PHY_VARS_gNB *gNB)
   else
     buffer_ul_slots = (nb_ul_slots_period < slot_ahead) ? nb_ul_slots_period : slot_ahead;

-  gNB->max_nb_pucch = buffer_ul_slots ? MAX_MOBILES_PER_GNB * buffer_ul_slots : 1;
+  gNB->max_nb_pucch = buffer_ul_slots ? 2 * MAX_MOBILES_PER_GNB * buffer_ul_slots : 1;
   gNB->max_nb_pusch = buffer_ul_slots ? MAX_MOBILES_PER_GNB * buffer_ul_slots : 1;
   gNB->max_nb_srs = buffer_ul_slots ? buffer_ul_slots << 1 : 1; // assuming at most 2 SRS per slot
2026-04-17 12:01:12 +02:00
Teodora Vladić
4b6e87071c VIAVI Handle more UL PDUs per slot and place safe guards
7 Mbps UDP traffic to 64 UEs, the gNB asserts:
Assertion (crc->rnti == rx->rnti) failed!
In handle_nr_ulsch() /home/vladic/dev/openair2/NR_PHY_INTERFACE/NR_IF_Module.c:180
mis-match between CRC RNTI 9055 and RX RNTI f890

Co-authored-by: Robert Schmidt <robert.schmidt@openairinterface.org>
2026-04-17 11:59:11 +02:00
Teodora Vladić
e714eb3876 TODO Increase the max number of UEs 2026-04-17 10:37:32 +02:00
12 changed files with 106 additions and 69 deletions

View File

@@ -23,7 +23,7 @@ gNBs =
nr_cellid = 12345678L
////////// Physical parameters:
uess_agg_levels = [2, 2, 2, 0, 0];
uess_agg_levels = [4, 2, 2, 0, 0];
servingCellConfigCommon = (
{

View File

@@ -90,8 +90,7 @@
<testCase>
<class>Iperf</class>
<desc>Optional iperf (DL/700Mbps/UDP)(30 sec)</desc>
<may_fail>true</may_fail>
<desc>Iperf (DL/700Mbps/UDP)(30 sec)</desc>
<iperf_args>-u -b 700M -t 30 -R</iperf_args>
<id>up2-fhi72</id>
<iperf_packetloss_threshold>10</iperf_packetloss_threshold>

View File

@@ -5,7 +5,7 @@
#ifndef OPENAIRINTERFACE5G_LIMITS_H_
#define OPENAIRINTERFACE5G_LIMITS_H_
# define MAX_MOBILES_PER_GNB 16
# define MAX_MOBILES_PER_GNB 128
# define NUMBER_OF_eNB_MAX 1
# define NUMBER_OF_gNB_MAX 1
# define NUMBER_OF_RU_MAX 2

View File

@@ -22,16 +22,17 @@ UEs with retransmissions are allocated first; similarly, UEs that have not been
scheduled for some time in UL are scheduled automatically in UL and have
therefore priority over data with "normal" traffic.
The MCS selection is done in `get_mcs_from_bler()` in file
The MCS selection is done in `estimate_next_mcs()` in file
[`gNB_scheduler_primitives.c`](../../openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c).
It consider two thresholds for a "BLER" that is computed from the number of
first-round retransmissions over total transmissions in the last window (50ms).
If that ratio is higher than an "upper" threshold (see
`dl/ul_bler_target_upper` in the configuration section below), it is
interpreted as "bad channel" and MCS is decremented by 1. If the ratio is
lower than a "lower" threshold (see `dl/ul_bler_target_lower`), it is
On UE inactivity (low traffic), it returns an estimated MCS (from CQI, SINR,
...). On UE activity (UE with active traffic), it calculates the MCS from BLER
computed from the number of first-round retransmissions over total
transmissions in the last window (50ms). If that ratio is higher than an
"upper" threshold (see `dl/ul_bler_target_upper` in the configuration section
below), it is interpreted as "bad channel" and MCS is decremented by 1. If the
ratio is lower than a "lower" threshold (see `dl/ul_bler_target_lower`), it is
interpreted as "good channel" and MCS is incremented by 1. This happens each
window.
window of 10 frames.
The actual scheduler implementation can be found in functions `pf_dl()` and
`pf_ul()` in files

View File

@@ -411,7 +411,10 @@ static int nr_ulsch_procedures(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, int
}
#endif
DevAssert(UL_INFO->crc_ind.number_crcs == UL_INFO->rx_ind.number_of_pdus);
DevAssert(UL_INFO->crc_ind.number_crcs < sizeofArray(UL_INFO->crc_pdu_list));
nfapi_nr_crc_t *crc = &UL_INFO->crc_ind.crc_list[UL_INFO->crc_ind.number_crcs++];
DevAssert(UL_INFO->rx_ind.number_of_pdus < sizeofArray(UL_INFO->rx_pdu_list));
nfapi_nr_rx_data_pdu_t *pdu = &UL_INFO->rx_ind.pdu_list[UL_INFO->rx_ind.number_of_pdus++];
if (crc_valid && !check_abort(&ulsch_harq->abort_decode) && !pusch->DTX) {
LOG_D(NR_PHY,
@@ -1051,7 +1054,10 @@ static bool handle_pusch_decode_trigger(PHY_VARS_gNB *gNB, NR_gNB_PUSCH *pusch_v
if (!get_softmodem_params()->phy_test) {
/* in case of phy_test mode, we still want to decode to measure execution time.
Therefore, we don't yet call nr_fill_indication, it will be called later */
DevAssert(UL_INFO->crc_ind.number_crcs == UL_INFO->rx_ind.number_of_pdus);
DevAssert(UL_INFO->crc_ind.number_crcs < sizeofArray(UL_INFO->crc_pdu_list));
nfapi_nr_crc_t *crc = &UL_INFO->crc_ind.crc_list[UL_INFO->crc_ind.number_crcs++];
DevAssert(UL_INFO->rx_ind.number_of_pdus < sizeofArray(UL_INFO->rx_pdu_list));
nfapi_nr_rx_data_pdu_t *rx = &UL_INFO->rx_ind.pdu_list[UL_INFO->rx_ind.number_of_pdus++];
nr_fill_indication(gNB, ulsch->frame, ulsch->slot, pusch_vars, pdu, stats, NULL, 1, crc, rx);
(*pusch_DTX)++;

View File

@@ -607,6 +607,15 @@ static int comparator(const void *p, const void *q)
return 0;
}
static uint8_t get_est_mcs(const dl_est_mcs_t *est_mcs)
{
if (est_mcs->from_csirs_cqi)
return est_mcs->from_csirs_cqi;
if (est_mcs->from_ssb_sinr)
return est_mcs->from_ssb_sinr;
return 0;
}
static void pf_dl(gNB_MAC_INST *mac,
post_process_pdsch_t *pp_pdsch,
NR_UE_info_t **UE_list,
@@ -640,7 +649,7 @@ static void pf_dl(gNB_MAC_INST *mac,
int harq_pid = sched_ctrl->retrans_dl_harq.head;
/* Calculate Throughput */
const float a = 0.01f;
const float a = 0.05f;
const uint32_t b = stats->current_bytes;
UE->dl_thr_ue = (1 - a) * UE->dl_thr_ue + a * b;
@@ -692,14 +701,12 @@ static void pf_dl(gNB_MAC_INST *mac,
/* Calculate coeff */
const NR_bler_options_t *bo = &mac->dl_bler;
const int max_mcs_table = current_BWP->mcsTableIdx == 1 ? 27 : 28;
const int max_mcs = min(sched_ctrl->dl_max_mcs, max_mcs_table);
int selected_mcs;
if (bo->harq_round_max == 1) {
int new_mcs = min(bo->max_mcs, max_mcs);
selected_mcs = max(bo->min_mcs, new_mcs);
sched_ctrl->dl_bler_stats.mcs = selected_mcs;
} else
selected_mcs = get_mcs_from_bler(bo, stats, &sched_ctrl->dl_bler_stats, max_mcs, frame);
// UE is active if there is some traffic over time (more 1 Kb/s),
// or sudden burst
bool ue_is_active = UE->dl_thr_ue > 1000 || sched_ctrl->num_total_bytes >= 300;
const int est_mcs = get_est_mcs(&sched_ctrl->dl_est_mcs);
int selected_mcs = estimate_next_mcs(bo, stats, &sched_ctrl->dl_bler_stats, max_mcs_table, est_mcs, frame, ue_is_active);
LOG_D(NR_MAC, "%d.%d UE %04x mcs %d bler %f\n", frame, slot, UE->rnti, selected_mcs, sched_ctrl->dl_bler_stats.bler);
int l = get_dl_nrOfLayers(sched_ctrl, current_BWP->dci_format);
const uint8_t Qm = nr_get_Qm_dl(selected_mcs, current_BWP->mcsTableIdx);
const uint16_t R = nr_get_code_rate_dl(selected_mcs, current_BWP->mcsTableIdx);
@@ -732,6 +739,10 @@ static void pf_dl(gNB_MAC_INST *mac,
UEsched_t *iterator = UE_sched;
const int min_rbSize = 5;
const int UEperTTI = 4;
const int schedUE = max(1, min(UEperTTI, numUE));
DevAssert(num_beams == 1);
const int rbPerUE = n_rb_sched[0] / schedUE;
/* Loop UE_sched to find max coeff and allocate transmission */
while (iterator->UE != NULL) {
@@ -788,7 +799,7 @@ static void pf_dl(gNB_MAC_INST *mac,
int bwp_size = bwp_info.bwpSize;
// Freq-demain allocation
int max_rbSize = 0;
if (!get_rb_alloc(min_rbSize, bwp_size, bwp_start, bwp_size, rballoc_mask, slbitmap, &rbStart, &max_rbSize)) {
if (!get_rb_alloc(min_rbSize, rbPerUE, bwp_start, bwp_size, rballoc_mask, slbitmap, &rbStart, &max_rbSize)) {
LOG_D(NR_MAC,
"(%d.%d) Cannot schedule RNTI %04x, rbStart %d, rbSize %d\n",
frame,
@@ -905,8 +916,7 @@ static void nr_dlsch_preprocessor(gNB_MAC_INST *mac, post_process_pdsch_t *pp_pd
for (int i = 0; i < num_beams; i++)
n_rb_sched[i] = bw;
int average_agg_level = 4; // TODO find a better estimation
int max_sched_ues = bw / (average_agg_level * NR_NB_REG_PER_CCE);
int max_sched_ues = 10;
// FAPI cannot handle more than MAX_DCI_CORESET DCIs
max_sched_ues = min(max_sched_ues, MAX_DCI_CORESET);

View File

@@ -228,9 +228,9 @@ uint16_t get_pm_index(const gNB_MAC_INST *nrmac,
// command line: nr_dlsim -n 10000 -m 0 -R 25 -b 25 -e MCS -s START_SNR -t 99.99
// SNR Thresholds for MCS=[0,...,28]; START_SNR=chosen values with a resolution of 0.2dB to maintain a BLER of 10^-3
static const int SINRx10_MCS_mapping[29] = {
-10, -4, 6, 16, 24, 34, 42, 50, 56, 62, // 0..9
86, 92, 98, 104, 112, 118, 124, 140, 146, 154, // 10..19
162, 170, 178, 186, 194, 202, 212, 220, 245 // 20..28
-16, -8, 2, 12, 22, 32, 40, 48, 52, 60, // 0..9
82, 86, 94, 100, 110, 116, 122, 136, 142, 150, // 10..19
160, 164, 174, 182, 192, 200, 212, 216, 242 // 20..28
};
int get_mcs_from_SINRx10(int mcs_table, int SINRx10, int Nl)
@@ -811,40 +811,61 @@ NR_pusch_dmrs_t get_ul_dmrs_params(const NR_ServingCellConfigCommon_t *scc,
#define BLER_UPDATE_FRAME 10
#define BLER_FILTER 0.9f
int get_mcs_from_bler(const NR_bler_options_t *bler_options,
#define MAX_BLER_EST_MCS_DIFF 10
#define MAX_FRAMES_ACTIVE 100
int estimate_next_mcs(const NR_bler_options_t *bler_options,
const NR_mac_dir_stats_t *stats,
NR_bler_stats_t *bler_stats,
int max_mcs,
frame_t frame)
int est_mcs,
frame_t frame,
bool ue_is_active)
{
int diff = frame - bler_stats->last_frame;
if (diff < 0) // wrap around
diff += 1024;
bler_stats->frames_inactive = ue_is_active ? 0 : bler_stats->frames_inactive + diff;
max_mcs = min(max_mcs, bler_options->max_mcs);
const uint8_t old_mcs = min(bler_stats->mcs, max_mcs);
if (diff < BLER_UPDATE_FRAME)
return old_mcs; // no update
int new_mcs = bler_stats->mcs;
if (bler_stats->frames_inactive >= MAX_FRAMES_ACTIVE || bler_options->harq_round_max == 1) {
// if UE is inactive, return MCS estimation (or previous if no estimation)
// or if there is no HARQ => no retransmission => no BLER
if (est_mcs > 0) {
// bound the estimation between user configured min/max MCS and current
// MCS table max
est_mcs = min(est_mcs, max_mcs);
new_mcs = max(est_mcs, bler_options->min_mcs);
}
} else if (est_mcs > 0 && abs(bler_stats->mcs - est_mcs) >= MAX_BLER_EST_MCS_DIFF) {
// there is a big difference between MCS from BLER and what is estimated,
// correct this quickly
LOG_D(NR_MAC, "correct MCS %d => %d\n", bler_stats->mcs, est_mcs);
est_mcs = min(est_mcs, max_mcs);
new_mcs = max(est_mcs, bler_options->min_mcs);
} else {
if (diff < BLER_UPDATE_FRAME)
return bler_stats->mcs; // no update
// last update is longer than x frames ago
const int num_dl_sched = (int)(stats->rounds[0] - bler_stats->rounds[0]);
const int num_dl_retx = (int)(stats->rounds[1] - bler_stats->rounds[1]);
const float bler_window = num_dl_sched > 0 ? (float) num_dl_retx / num_dl_sched : bler_stats->bler;
bler_stats->bler = BLER_FILTER * bler_stats->bler + (1 - BLER_FILTER) * bler_window;
// last update is longer than x frames ago
const int num_dl_sched = (int)(stats->rounds[0] - bler_stats->rounds[0]);
const int num_dl_retx = (int)(stats->rounds[1] - bler_stats->rounds[1]);
const float bler_window = num_dl_sched > 0 ? (float) num_dl_retx / num_dl_sched : bler_stats->bler;
bler_stats->bler = BLER_FILTER * bler_stats->bler + (1 - BLER_FILTER) * bler_window;
int new_mcs = old_mcs;
if (bler_stats->bler < bler_options->lower && old_mcs < max_mcs && num_dl_sched > 3)
new_mcs += 1;
else if (bler_stats->bler > bler_options->upper || num_dl_sched <= 3) // above threshold or no activity
new_mcs -= 1;
// else we are within threshold boundaries
if (bler_stats->bler < bler_options->lower && new_mcs < max_mcs)
new_mcs += 1;
else if (bler_stats->bler > bler_options->upper && new_mcs > bler_options->min_mcs)
new_mcs -= 1;
// else we are within threshold boundaries or at limits
LOG_D(MAC, "frame %4d MCS %d -> %d (num_dl_sched %d, num_dl_retx %d, BLER wnd %.3f avg %.6f)\n",
frame, bler_stats->mcs, new_mcs, num_dl_sched, num_dl_retx, bler_window, bler_stats->bler);
}
new_mcs = max(new_mcs, bler_options->min_mcs);
bler_stats->last_frame = frame;
bler_stats->mcs = new_mcs;
memcpy(bler_stats->rounds, stats->rounds, sizeof(stats->rounds));
LOG_D(MAC, "frame %4d MCS %d -> %d (num_dl_sched %d, num_dl_retx %d, BLER wnd %.3f avg %.6f)\n",
frame, old_mcs, new_mcs, num_dl_sched, num_dl_retx, bler_window, bler_stats->bler);
return new_mcs;
}
@@ -3074,7 +3095,6 @@ bool add_connected_nr_ue(gNB_MAC_INST *nr_mac, NR_UE_info_t *UE)
}
NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
sched_ctrl->dl_max_mcs = 28; /* do not limit MCS for individual UEs */
sched_ctrl->pdcch_cl_adjust = 0;
reset_srs_stats(UE);

View File

@@ -498,9 +498,10 @@ static void evaluate_sinr_report(NR_UE_info_t *UE,
const int mcs_table = UE->current_DL_BWP.mcsTableIdx;
const int nrOfLayers = get_dl_nrOfLayers(sched_ctrl, UE->current_DL_BWP.dci_format);
sched_ctrl->dl_max_mcs = get_mcs_from_SINRx10(mcs_table, sinr_report->r[0].SINRx10, nrOfLayers);
int est_mcs = get_mcs_from_SINRx10(mcs_table, sinr_report->r[0].SINRx10, nrOfLayers);
sched_ctrl->dl_est_mcs.from_ssb_sinr = est_mcs;
LOG_D(MAC, "Reported SSB-SINR = %01f, dl_max_mcs %d\n", sinr_report->r[0].SINRx10 / 10.0, sched_ctrl->dl_max_mcs);
LOG_D(MAC, "Reported SSB-SINR = %.1f, est_mcs %d\n", (float) sinr_report->r[0].SINRx10 / 10.f, est_mcs);
}
static void evaluate_rsrp_report(NR_UE_info_t *UE,
@@ -639,9 +640,10 @@ static void evaluate_cqi_report(uint8_t *payload,
// TODO for wideband case and multiple TB
const int cqi_idx = sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.wb_cqi_1tb;
const int mcs_table = UE->current_DL_BWP.mcsTableIdx;
sched_ctrl->dl_max_mcs = get_mcs_from_cqi(mcs_table, cqi_Table, cqi_idx);
int est_mcs = get_mcs_from_cqi(mcs_table, cqi_Table, cqi_idx);
sched_ctrl->dl_est_mcs.from_csirs_cqi = est_mcs;
LOG_D(MAC, "Reported CQI = %d, dl_max_mcs %d\n", temp_cqi, sched_ctrl->dl_max_mcs);
LOG_D(MAC, "Reported CQI = %d, est_mcs %d\n", temp_cqi, est_mcs);
}
static uint8_t evaluate_pmi_report(uint8_t *payload,

View File

@@ -1915,7 +1915,7 @@ static int pf_ul(gNB_MAC_INST *nrmac,
NR_mac_dir_stats_t *stats = &UE->mac_stats.ul;
/* Calculate throughput */
const float a = 0.01f;
const float a = 0.05f;
const uint32_t b = stats->current_bytes;
UE->ul_thr_ue = (1 - a) * UE->ul_thr_ue + a * b;
@@ -2001,18 +2001,11 @@ static int pf_ul(gNB_MAC_INST *nrmac,
const NR_bler_options_t *bo = &nrmac->ul_bler;
const int max_mcs_table = (current_BWP->mcs_table == 0 || current_BWP->mcs_table == 2) ? 28 : 27;
const int max_mcs = min(bo->max_mcs, max_mcs_table); /* no per-user maximum MCS yet */
int selected_mcs;
int nrOfLayers = get_ul_nrOfLayers(sched_ctrl, current_BWP->dci_format);
if (bo->harq_round_max == 1) {
selected_mcs = get_mcs_from_SINRx10(current_BWP->mcs_table, sched_ctrl->pusch_pc.avg_snr * 10, nrOfLayers);
selected_mcs = min(max_mcs, selected_mcs);
selected_mcs = max(bo->min_mcs, selected_mcs);
sched_ctrl->ul_bler_stats.mcs = selected_mcs;
} else {
selected_mcs = get_mcs_from_bler(bo, stats, &sched_ctrl->ul_bler_stats, max_mcs, frame);
LOG_D(NR_MAC, "%d.%d starting mcs %d bler %f\n", frame, slot, selected_mcs, sched_ctrl->ul_bler_stats.bler);
}
bool sched_inactive = B == 0 && do_sched;
const int est_mcs = get_mcs_from_SINRx10(current_BWP->mcs_table, sched_ctrl->pusch_pc.avg_snr * 10, nrOfLayers);
int selected_mcs = estimate_next_mcs(bo, stats, &sched_ctrl->ul_bler_stats, max_mcs_table, est_mcs, frame, !sched_inactive);
LOG_D(NR_MAC, "%d.%d UE %04x mcs %d bler %f\n", frame, slot, UE->rnti, selected_mcs, sched_ctrl->ul_bler_stats.bler);
/* Create UE_sched for UEs eligibale for new data transmission*/
/* Calculate coefficient*/
@@ -2028,7 +2021,6 @@ static int pf_ul(gNB_MAC_INST *nrmac,
nrOfLayers)
>> 3;
float coeff_ue = (float) tbs / UE->ul_thr_ue;
bool sched_inactive = B == 0 && do_sched;
LOG_D(NR_MAC, "[UE %04x][%4d.%2d] b %d, ul_thr_ue %f, tbs %d, coeff_ue %f, sched_inactive %d\n",
UE->rnti,
frame,

View File

@@ -434,11 +434,13 @@ bool get_rb_alloc(int rbSize_min,
int *rbStart_ptr,
int *rbSize_ptr);
int get_mcs_from_bler(const NR_bler_options_t *bler_options,
int estimate_next_mcs(const NR_bler_options_t *bler_options,
const NR_mac_dir_stats_t *stats,
NR_bler_stats_t *bler_stats,
int max_mcs,
frame_t frame);
int est_mcs,
frame_t frame,
bool ue_is_active);
int ul_buffer_index(int frame, int slot, int slots_per_frame, int size);
void UL_tti_req_ahead_initialization(gNB_MAC_INST *gNB, int n, int CCid, frame_t frameP, int slotP);

View File

@@ -523,6 +523,7 @@ typedef struct NR_bler_stats {
float bler;
uint8_t mcs;
uint64_t rounds[8];
int frames_inactive;
} NR_bler_stats_t;
//
@@ -607,6 +608,11 @@ typedef struct nr_power_control {
float tpc_in_flight; /// TPCs applied by UE but not yet in average SNR
} nr_power_control_t;
typedef struct dl_est_mcs {
uint8_t from_csirs_cqi;
uint8_t from_ssb_sinr;
} dl_est_mcs_t;
/*! \brief scheduling control information set through an API */
typedef struct {
/// CCE index and aggregation, should be coherent with cce_list
@@ -637,8 +643,7 @@ typedef struct {
/// PHR info: nominal UE transmit power levels (dBm)
int pcmax;
/// UE-estimated maximum MCS (from CSI-RS)
uint8_t dl_max_mcs;
dl_est_mcs_t dl_est_mcs;
/// For UL synchronization: store last UL scheduling grant
frame_t last_ul_frame;

View File

@@ -23,7 +23,7 @@
#define MAX_NUM_TX_REQUEST_PDU 100
#define MAX_NUM_NR_RX_RACH_PDUS 4
#define MAX_UL_PDUS_PER_SLOT 8
#define MAX_UL_PDUS_PER_SLOT 16
#define MAX_NUM_NR_SRS_PDUS 8
#define MAX_NUM_NR_UCI_PDUS MAX_MOBILES_PER_GNB
typedef struct {