Merge remote-tracking branch 'origin/sinr_based_amc' into integration_2025_w37 (!3601)
gNB: adaptive DL/UL MCS based on reported SSB-SINR and measured PUSCH SNR Currently this is used esp. if the number of rounds is limited to 1 (e.g. disable_harq).
This commit is contained in:
@@ -16,6 +16,7 @@ gNBs =
|
||||
|
||||
////////// Physical parameters:
|
||||
|
||||
do_SINR = 1;
|
||||
min_rxtxtime = 6;
|
||||
disable_harq = 1;
|
||||
cu_sibs = [2];
|
||||
|
||||
@@ -78,7 +78,7 @@ available in the the file `nrMAC-stats.log` in the same directory in which
|
||||
Example:
|
||||
|
||||
```
|
||||
UE RNTI 2460 CU-UE-ID 2 in-sync PH 28 dB PCMAX 24 dBm, average RSRP -74 (8 meas)
|
||||
UE RNTI 2460 CU-UE-ID 2 in-sync PH 28 dB PCMAX 24 dBm, average RSRP -74 (8 meas), average SINR 40.0 (32 meas)
|
||||
UE 2460: CQI 15, RI 2, PMI (14,1)
|
||||
UE 2460: UL-RI 2 TPMI 0
|
||||
UE 2460: dlsch_rounds 32917/5113/1504/560, dlsch_errors 211, pucch0_DTX 1385, BLER 0.19557 MCS (1) 23 CCE fail 3
|
||||
@@ -103,6 +103,8 @@ In the first line,
|
||||
* `RSRP` (`-74`): measured power of the DL reference signals at the UE. >-80dBm
|
||||
you should have full DL throughput. <-95 dBm, you are very limited in terms
|
||||
of connectivity.
|
||||
* `SINR` (`40.0`): measured signal to interference and noise ratio of the SSB
|
||||
received at the UE. Maximum value that can be reported by the UE is 40.0 dB.
|
||||
|
||||
The second and third line reflect channel state information (CSI) as
|
||||
reported by the UE, and only appear if CSI-RS/SRS are enabled and _received_
|
||||
|
||||
@@ -38,9 +38,8 @@
|
||||
#include "common/utils/LOG/log.h"
|
||||
#include "PHY/sse_intrin.h"
|
||||
|
||||
//#define k1 1000
|
||||
#define k1 ((long long int) 1000)
|
||||
#define k2 ((long long int) (1024-k1))
|
||||
#define K1 ((long long int) 512)
|
||||
#define K2 ((long long int) (1024-K1))
|
||||
|
||||
//#define DEBUG_MEAS_RRC
|
||||
//#define DEBUG_MEAS_UE
|
||||
@@ -136,11 +135,11 @@ void nr_ue_measurements(PHY_VARS_NR_UE *ue,
|
||||
if (ue->init_averaging == 0) {
|
||||
|
||||
for (gNB_id = 0; gNB_id < ue->n_connected_gNB; gNB_id++)
|
||||
ue->measurements.rx_power_avg[gNB_id] = (int)(((k1*((long long int)(ue->measurements.rx_power_avg[gNB_id]))) + (k2*((long long int)(ue->measurements.rx_power_tot[gNB_id])))) >> 10);
|
||||
ue->measurements.rx_power_avg[gNB_id] = (int)((K1 * ue->measurements.rx_power_avg[gNB_id] + K2 * ue->measurements.rx_power_tot[gNB_id]) >> 10);
|
||||
|
||||
ue->measurements.n0_power_avg = (int)(((k1*((long long int) (ue->measurements.n0_power_avg))) + (k2*((long long int) (ue->measurements.n0_power_tot))))>>10);
|
||||
ue->measurements.n0_power_avg = (int)((K1 * ue->measurements.n0_power_avg + K2 * ue->measurements.n0_power_tot) >> 10);
|
||||
|
||||
LOG_D(PHY, "Noise Power Computation: k1 %lld k2 %lld n0 avg %u n0 tot %u\n", k1, k2, ue->measurements.n0_power_avg, ue->measurements.n0_power_tot);
|
||||
LOG_D(PHY, "Noise Power Computation: K1 %lld K2 %lld n0 avg %u n0 tot %u\n", K1, K2, ue->measurements.n0_power_avg, ue->measurements.n0_power_tot);
|
||||
|
||||
} else {
|
||||
|
||||
|
||||
@@ -311,9 +311,9 @@ int main(int argc, char **argv)
|
||||
int i,aa;//,l;
|
||||
double sigma2, sigma2_dB=10, SNR, snr0=-2.0, snr1=2.0;
|
||||
uint8_t snr1set=0;
|
||||
float effRate;
|
||||
double effRate;
|
||||
//float psnr;
|
||||
float eff_tp_check = 0.7;
|
||||
double eff_tp_check = 0.7;
|
||||
uint32_t TBS = 0;
|
||||
c16_t **txdata;
|
||||
double **s_re,**s_im,**r_re,**r_im;
|
||||
@@ -547,7 +547,7 @@ int main(int argc, char **argv)
|
||||
break;
|
||||
|
||||
case 't':
|
||||
eff_tp_check = (float)atoi(optarg)/100;
|
||||
eff_tp_check = atof(optarg) / 100.0;
|
||||
break;
|
||||
|
||||
case 'w':
|
||||
@@ -1081,8 +1081,6 @@ printf("%d\n", slot);
|
||||
Sched_INFO->sched_response_id = -1;
|
||||
|
||||
while (round < num_rounds && !UE_harq_process->decodeResult && !stop) {
|
||||
round_trials[round]++;
|
||||
|
||||
clear_nr_nfapi_information(RC.nrmac[0], 0, frame, slot, &Sched_INFO->DL_req, &Sched_INFO->TX_req, &Sched_INFO->UL_dci_req);
|
||||
UE_info->UE_sched_ctrl.harq_processes[harq_pid].ndi = !(trial&1);
|
||||
UE_info->UE_sched_ctrl.harq_processes[harq_pid].round = round;
|
||||
@@ -1235,6 +1233,9 @@ printf("%d\n", slot);
|
||||
if (dlsch0->last_iteration_cnt >= dlsch0->max_ldpc_iterations)
|
||||
n_errors[round]++;
|
||||
|
||||
if (dlsch0->active)
|
||||
round_trials[round]++;
|
||||
|
||||
int16_t *UE_llr = (int16_t*)UE->phy_sim_pdsch_llr;
|
||||
|
||||
TBS = dlsch0->dlsch_config.TBS;//rel15->TBSize[0];
|
||||
@@ -1266,8 +1267,8 @@ printf("%d\n", slot);
|
||||
} // round
|
||||
|
||||
if (test_input_bit == NULL) {
|
||||
test_input_bit = (unsigned char *)malloc16(sizeof(unsigned char) * TBS);
|
||||
estimated_output_bit = (unsigned char *)malloc16(sizeof(unsigned char) * TBS);
|
||||
test_input_bit = (unsigned char *)malloc16(8 * rel15->TBSize[0]);
|
||||
estimated_output_bit = (unsigned char *)malloc16(8 * rel15->TBSize[0]);
|
||||
}
|
||||
for (i = 0; i < TBS; i++) {
|
||||
|
||||
@@ -1288,12 +1289,12 @@ printf("%d\n", slot);
|
||||
if (n_trials == 1)
|
||||
printf("errors_bit = %u (trial %d)\n", errors_bit, trial);
|
||||
}
|
||||
roundStats += ((float)round);
|
||||
roundStats += round;
|
||||
if (UE_harq_process->decodeResult)
|
||||
effRate += ((float)TBS) / round;
|
||||
effRate += ((double)TBS) / round;
|
||||
} // noise trials
|
||||
|
||||
roundStats /= ((float)n_trials);
|
||||
roundStats /= n_trials;
|
||||
|
||||
for (int r = 0; r < num_rounds; r++) {
|
||||
blerStats[r] = (double)n_errors[r] / round_trials[r];
|
||||
@@ -1316,7 +1317,7 @@ printf("%d\n", slot);
|
||||
printf("), Channel BER (%e", berStats[0]);
|
||||
for (int r = 1; r < num_rounds; r++)
|
||||
printf(",%e", berStats[r]);
|
||||
printf(") Avg round %.2f, Eff Rate %.4f bits/slot, Eff Throughput %.2f, TBS %u bits/slot\n", roundStats, effRate, effRate / TBS * 100, TBS);
|
||||
printf(") Avg round %.2f, Eff Rate %.4f bits/slot, Eff Throughput %.2f, TBS %u bits/slot\n", roundStats, effRate, effRate / (8 * rel15->TBSize[0]) * 100, 8 * rel15->TBSize[0]);
|
||||
printf("*****************************************\n");
|
||||
printf("\n");
|
||||
// writing to csv file
|
||||
@@ -1324,7 +1325,7 @@ printf("%d\n", slot);
|
||||
fprintf(csv_file,"%f,%d/%d,",SNR,n_false_positive,n_trials);
|
||||
for (int r = 0; r < num_rounds; r++)
|
||||
fprintf(csv_file,"%d/%d,%u/%u,%f,%e,",n_errors[r], round_trials[r], errors_scrambling[r], available_bits * round_trials[r],blerStats[r],berStats[r]);
|
||||
fprintf(csv_file,"%.2f,%.4f,%.2f,%u\n", roundStats, effRate, effRate / TBS * 100, TBS);
|
||||
fprintf(csv_file,"%.2f,%.4f,%.2f,%u\n", roundStats, effRate, effRate / (8 * rel15->TBSize[0]) * 100, 8 * rel15->TBSize[0]);
|
||||
}
|
||||
if (print_perf==1) {
|
||||
printf("\ngNB TX function statistics (per %d us slot, NPRB %d, mcs %d, C %d, block %d)\n",
|
||||
@@ -1332,7 +1333,7 @@ printf("%d\n", slot);
|
||||
g_rbSize,
|
||||
g_mcsIndex,
|
||||
UE->dl_harq_processes[0][slot].C,
|
||||
msgDataTx->dlsch[0][0].harq_process.pdsch_pdu.pdsch_pdu_rel15.TBSize[0] << 3);
|
||||
8 * rel15->TBSize[0]);
|
||||
printDistribution(&gNB->phy_proc_tx,table_tx,"PHY proc tx");
|
||||
printStatIndent2(&gNB->dci_generation_stats, "DCI encoding time");
|
||||
printStatIndent2(&gNB->dlsch_encoding_stats,"DLSCH encoding time");
|
||||
@@ -1406,7 +1407,7 @@ printf("%d\n", slot);
|
||||
break;
|
||||
}
|
||||
|
||||
if (effRate > (eff_tp_check*TBS)) {
|
||||
if (effRate >= (eff_tp_check * 8 * rel15->TBSize[0])) {
|
||||
printf("PDSCH test OK\n");
|
||||
ret = 0;
|
||||
break;
|
||||
|
||||
@@ -1478,8 +1478,8 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
for (i = 0; i < available_bits; i++) {
|
||||
if (((UE->ul_harq_processes[harq_pid].f[i] == 0) && (pusch_vars->llr[i] <= 0))
|
||||
|| ((UE->ul_harq_processes[harq_pid].f[i] == 1) && (pusch_vars->llr[i] >= 0))) {
|
||||
const uint8_t current_bit = (UE->ul_harq_processes[harq_pid].f[i / 8] >> (i & 7)) & 1;
|
||||
if (((current_bit == 0) && (pusch_vars->llr[i] <= 0)) || ((current_bit == 1) && (pusch_vars->llr[i] >= 0))) {
|
||||
/*if(errors_scrambling == 0)
|
||||
printf("\x1B[34m" "[frame %d][trial %d]\t1st bit in error in unscrambling = %d\n" "\x1B[0m", frame, trial, i);*/
|
||||
errors_scrambling[round]++;
|
||||
|
||||
@@ -683,7 +683,8 @@ static void pf_dl(module_id_t module_id,
|
||||
const int max_mcs_table = current_BWP->mcsTableIdx == 1 ? 27 : 28;
|
||||
const int max_mcs = min(sched_ctrl->dl_max_mcs, max_mcs_table);
|
||||
if (bo->harq_round_max == 1) {
|
||||
sched_pdsch->mcs = min(bo->max_mcs, max_mcs);
|
||||
int new_mcs = min(bo->max_mcs, max_mcs);
|
||||
sched_pdsch->mcs = max(bo->min_mcs, new_mcs);
|
||||
sched_ctrl->dl_bler_stats.mcs = sched_pdsch->mcs;
|
||||
} else
|
||||
sched_pdsch->mcs = get_mcs_from_bler(bo, stats, &sched_ctrl->dl_bler_stats, max_mcs, frame);
|
||||
|
||||
@@ -248,6 +248,38 @@ uint16_t get_pm_index(const gNB_MAC_INST *nrmac,
|
||||
}
|
||||
}
|
||||
|
||||
// look-up table for AMC. Based on BLER vs SNR curves from the nr_dlsim simulation
|
||||
// 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
|
||||
};
|
||||
|
||||
int get_mcs_from_SINRx10(int mcs_table, int SINRx10, int Nl)
|
||||
{
|
||||
if (mcs_table != 0) {
|
||||
LOG_E(MAC, "mcs_table = %d, but get_mcs_from_SINRx10() only supports MCS table 0 (TS 38.214 - Table 5.1.3.1-1)\n", mcs_table);
|
||||
return 28;
|
||||
}
|
||||
|
||||
int MIMO_SNRx10 = 0;
|
||||
if (Nl == 2)
|
||||
MIMO_SNRx10 = 40;
|
||||
else if (Nl == 4)
|
||||
MIMO_SNRx10 = 70;
|
||||
|
||||
for (int i = 28; i >= 0; i--) {
|
||||
if (SINRx10 >= SINRx10_MCS_mapping[i] + MIMO_SNRx10)
|
||||
return i;
|
||||
}
|
||||
|
||||
LOG_W(MAC, "SINR (%d.%d dB) too low, no MCS possible to achieve BLER of 10^-3\n", SINRx10 / 10, SINRx10 % 10);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t get_mcs_from_cqi(int mcs_table, int cqi_table, int cqi_idx)
|
||||
{
|
||||
if (cqi_idx <= 0) {
|
||||
|
||||
@@ -414,6 +414,25 @@ static void handle_dl_harq(NR_UE_info_t * UE,
|
||||
}
|
||||
}
|
||||
|
||||
// Referred Table 10.1.16.1-1 in 38.133 V16.7.0.
|
||||
static int get_measured_sinr(int index)
|
||||
{
|
||||
if (index < 0 || index > 127)
|
||||
return INT_MAX;
|
||||
|
||||
return -235 + index * 5;
|
||||
}
|
||||
|
||||
// Referred Table 10.1.16.1-2 in 38.133 V16.7.0.
|
||||
static int get_diff_sinr(int index, int best_SINRx10)
|
||||
{
|
||||
if (index <= 0)
|
||||
return best_SINRx10;
|
||||
if (index >= 15)
|
||||
return best_SINRx10 - 150;
|
||||
return best_SINRx10 - index * 10;
|
||||
}
|
||||
|
||||
//returns the measured RSRP value (upper limit)
|
||||
static bool get_measured_rsrp(uint8_t index, int *rsrp)
|
||||
{
|
||||
@@ -498,22 +517,33 @@ static void evaluate_sinr_report(gNB_MAC_INST *nrmac,
|
||||
}
|
||||
|
||||
curr_payload = pickandreverse_bits(payload, 7, *cumul_bits);
|
||||
sinr_report->SINR_index[0] = curr_payload & 0x7f;
|
||||
int sinr_index = curr_payload & 0x7f;
|
||||
*cumul_bits += 7;
|
||||
|
||||
csi_report->nb_of_csi_ssb_report++;
|
||||
if (sinr_report->SINR_index[0] < 0 || sinr_report->SINR_index[0] > 127) {
|
||||
LOG_E(NR_MAC, "UE %04x: reported SINR index %d invalid\n", UE->rnti, sinr_report->SINR_index[0]);
|
||||
int SINRx10 = get_measured_sinr(sinr_index);
|
||||
if (SINRx10 == INT_MAX) {
|
||||
LOG_E(NR_MAC, "UE %04x: reported SINR index %d invalid\n", UE->rnti, sinr_index);
|
||||
return;
|
||||
}
|
||||
sinr_report->SINRx10[0] = SINRx10;
|
||||
|
||||
for (int i = 1; i < sinr_report->nr_reports; i++) {
|
||||
curr_payload = pickandreverse_bits(payload, 4, *cumul_bits);
|
||||
sinr_report->SINR_index[i] = curr_payload & 0x0f;
|
||||
sinr_report->SINRx10[i] = get_diff_sinr(curr_payload & 0x0f, sinr_report->SINRx10[0]);
|
||||
*cumul_bits += 4;
|
||||
}
|
||||
|
||||
LOG_D(MAC, "Reported SSB-SINR index = %d\n", sinr_report->SINR_index[0]);
|
||||
NR_mac_stats_t *stats = &UE->mac_stats;
|
||||
// including ssb SINR in mac stats
|
||||
stats->cumul_sinrx10 += sinr_report->SINRx10[0];
|
||||
stats->num_sinr_meas++;
|
||||
|
||||
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->SINRx10[0], nrOfLayers);
|
||||
|
||||
LOG_D(MAC, "Reported SSB-SINR = %d.%d, dl_max_mcs %d\n", sinr_report->SINRx10[0] / 10, sinr_report->SINRx10[0] % 10, sched_ctrl->dl_max_mcs);
|
||||
}
|
||||
|
||||
static void evaluate_rsrp_report(gNB_MAC_INST *nrmac,
|
||||
|
||||
@@ -2061,7 +2061,11 @@ static int pf_ul(gNB_MAC_INST *nrmac,
|
||||
const int max_mcs = min(bo->max_mcs, max_mcs_table); /* no per-user maximum MCS yet */
|
||||
int selected_mcs;
|
||||
if (bo->harq_round_max == 1) {
|
||||
selected_mcs = sched_ctrl->ul_bler_stats.mcs = max_mcs;
|
||||
int nrOfLayers = get_ul_nrOfLayers(sched_ctrl, current_BWP->dci_format);
|
||||
selected_mcs = get_mcs_from_SINRx10(current_BWP->mcs_table, sched_ctrl->pusch_snrx10, 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);
|
||||
|
||||
@@ -403,6 +403,7 @@ uint16_t get_pm_index(const gNB_MAC_INST *nrmac,
|
||||
int layers,
|
||||
int xp_pdsch_antenna_ports);
|
||||
|
||||
int get_mcs_from_SINRx10(int mcs_table, int SINRx10, int Nl);
|
||||
uint8_t get_mcs_from_cqi(int mcs_table, int cqi_table, int cqi_idx);
|
||||
|
||||
uint8_t get_dl_nrOfLayers(const NR_UE_sched_ctrl_t *sched_ctrl, const nr_dci_format_t dci_format);
|
||||
|
||||
@@ -126,24 +126,37 @@ size_t dump_mac_stats(gNB_MAC_INST *gNB, char *output, size_t strlen, bool reset
|
||||
NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
|
||||
NR_mac_stats_t *stats = &UE->mac_stats;
|
||||
const int avg_rsrp = stats->num_rsrp_meas > 0 ? stats->cumul_rsrp / stats->num_rsrp_meas : 0;
|
||||
const int avg_sinrx10 = stats->num_sinr_meas > 0 ? stats->cumul_sinrx10 / stats->num_sinr_meas : 0;
|
||||
|
||||
output += snprintf(output, end - output, "UE RNTI %04x CU-UE-ID ", UE->rnti);
|
||||
if (du_exists_f1_ue_data(UE->rnti)) {
|
||||
f1_ue_data_t ued = du_get_f1_ue_data(UE->rnti);
|
||||
output += snprintf(output, end - output, "%d", ued.secondary_ue);
|
||||
} else {
|
||||
output += snprintf(output, end-output, "(none)");
|
||||
output += snprintf(output, end - output, "(none)");
|
||||
}
|
||||
|
||||
bool in_sync = !sched_ctrl->ul_failure;
|
||||
output += snprintf(output,
|
||||
end - output,
|
||||
" %s PH %d dB PCMAX %d dBm, average RSRP %d (%d meas)\n",
|
||||
" %s PH %d dB PCMAX %d dBm",
|
||||
in_sync ? "in-sync" : "out-of-sync",
|
||||
sched_ctrl->ph,
|
||||
sched_ctrl->pcmax,
|
||||
avg_rsrp,
|
||||
stats->num_rsrp_meas);
|
||||
sched_ctrl->pcmax);
|
||||
|
||||
if (stats->num_rsrp_meas)
|
||||
output += snprintf(output, end - output, ", average RSRP %d (%d meas)", avg_rsrp, stats->num_rsrp_meas);
|
||||
|
||||
if (stats->num_sinr_meas) {
|
||||
output += snprintf(output,
|
||||
end - output,
|
||||
", average SINR %d.%d (%d meas)",
|
||||
avg_sinrx10 / 10,
|
||||
avg_sinrx10 % 10,
|
||||
stats->num_sinr_meas);
|
||||
}
|
||||
|
||||
output += snprintf(output, end - output, "\n");
|
||||
|
||||
if(sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.print_report)
|
||||
output += snprintf(output,
|
||||
@@ -178,6 +191,8 @@ size_t dump_mac_stats(gNB_MAC_INST *gNB, char *output, size_t strlen, bool reset
|
||||
if (reset_rsrp) {
|
||||
stats->num_rsrp_meas = 0;
|
||||
stats->cumul_rsrp = 0;
|
||||
stats->num_sinr_meas = 0;
|
||||
stats->cumul_sinrx10 = 0;
|
||||
}
|
||||
output += snprintf(output,
|
||||
end - output,
|
||||
|
||||
@@ -521,8 +521,7 @@ typedef struct RSRP_report {
|
||||
uint8_t nr_reports;
|
||||
uint8_t resource_id[MAX_NR_OF_REPORTED_RS];
|
||||
int RSRP[MAX_NR_OF_REPORTED_RS];
|
||||
// SINR index according to tables 10.1.16.1-1, 10.1.16.1-2
|
||||
int SINR_index[MAX_NR_OF_REPORTED_RS];
|
||||
int SINRx10[MAX_NR_OF_REPORTED_RS];
|
||||
} RSRP_report_t;
|
||||
|
||||
struct CSI_Report {
|
||||
@@ -694,6 +693,8 @@ typedef struct NR_mac_stats {
|
||||
uint32_t pucch0_DTX;
|
||||
int cumul_rsrp;
|
||||
uint8_t num_rsrp_meas;
|
||||
int cumul_sinrx10;
|
||||
uint8_t num_sinr_meas;
|
||||
char srs_stats[50]; // Statistics may differ depending on SRS usage
|
||||
int pusch_snrx10;
|
||||
int deltaMCS;
|
||||
|
||||
Reference in New Issue
Block a user