From 2c164336bcb8d336d054cadb0c12ddc0bc0f80de Mon Sep 17 00:00:00 2001 From: Raghavendra Dinavahi Date: Thu, 13 Feb 2025 15:14:16 +0100 Subject: [PATCH 1/6] gNB changes in RRC- Enable SSB-SINR based CSI reporting 3GPP 38.331 release 16 specifies that If the field reportQuantity-r16 is present, UE shall ignore reportQuantity (without suffix). reportQuantity-r16 configures SSB based SINR as the reporting quantity. set do_SINR = 1; in gNB params part of the config file to enable SSB based SINR reporting instead of the default RSRP based. --- openair2/GNB_APP/gnb_config.c | 5 ++++- openair2/GNB_APP/gnb_paramdef.h | 5 +++++ openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h | 1 + openair2/RRC/NR/nr_rrc_config.c | 24 +++++++++++++++++++++--- 4 files changed, 31 insertions(+), 4 deletions(-) diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index cbb46f0132..f5fb224365 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -822,6 +822,7 @@ void RCconfig_verify(configmodule_interface_t *cfg, ngran_node_t node_type) verify_gnb_param_notset(gnbp, GNB_DISABLE_HARQ_IDX, GNB_CONFIG_STRING_DISABLE_HARQ); verify_gnb_param_notset(gnbp, GNB_NUM_DL_HARQ_IDX, GNB_CONFIG_STRING_NUM_DL_HARQPROCESSES); verify_gnb_param_notset(gnbp, GNB_NUM_UL_HARQ_IDX, GNB_CONFIG_STRING_NUM_UL_HARQPROCESSES); + verify_gnb_param_notset(gnbp, GNB_DO_SINR_IDX, GNB_CONFIG_STRING_DOSINR); // check for some general sections verify_section_notset(cfg, NULL, CONFIG_STRING_L1_LIST); @@ -1519,6 +1520,7 @@ void RCconfig_nr_macrlc(configmodule_interface_t *cfg) LOG_I(GNB_APP, "SIB1 TDA %d\n", config.sib1_tda); config.do_CSIRS = *GNBParamList.paramarray[0][GNB_DO_CSIRS_IDX].iptr; config.do_SRS = *GNBParamList.paramarray[0][GNB_DO_SRS_IDX].iptr; + config.do_SINR = *GNBParamList.paramarray[0][GNB_DO_SINR_IDX].iptr; config.force_256qam_off = *GNBParamList.paramarray[0][GNB_FORCE256QAMOFF_IDX].iptr; config.force_UL256qam_off = *GNBParamList.paramarray[0][GNB_FORCEUL256QAMOFF_IDX].iptr; config.use_deltaMCS = *GNBParamList.paramarray[0][GNB_USE_DELTA_MCS_IDX].iptr != 0; @@ -1529,9 +1531,10 @@ void RCconfig_nr_macrlc(configmodule_interface_t *cfg) if (config.disable_harq) LOG_W(GNB_APP, "\"disable_harq\" is a REL17 feature and is incompatible with REL15 and REL16 UEs!\n"); LOG_I(GNB_APP, - "CSI-RS %d, SRS %d, 256 QAM %s, delta_MCS %s, maxMIMO_Layers %d, HARQ feedback %s, num DLHARQ:%d, num ULHARQ:%d\n", + "CSI-RS %d, SRS %d, SINR:%d, 256 QAM %s, delta_MCS %s, maxMIMO_Layers %d, HARQ feedback %s, num DLHARQ:%d, num ULHARQ:%d\n", config.do_CSIRS, config.do_SRS, + config.do_SINR, config.force_256qam_off ? "force off" : "may be on", config.use_deltaMCS ? "on" : "off", config.maxMIMO_layers, diff --git a/openair2/GNB_APP/gnb_paramdef.h b/openair2/GNB_APP/gnb_paramdef.h index c76b6bc143..99eb8847af 100644 --- a/openair2/GNB_APP/gnb_paramdef.h +++ b/openair2/GNB_APP/gnb_paramdef.h @@ -141,6 +141,7 @@ typedef enum { #define GNB_CONFIG_STRING_UESS_AGG_LEVEL_LIST "uess_agg_levels" #define GNB_CONFIG_STRING_CU_SIB_LIST "cu_sibs" #define GNB_CONFIG_STRING_DU_SIB_LIST "du_sibs" +#define GNB_CONFIG_STRING_DOSINR "do_SINR" #define GNB_CONFIG_HLP_STRING_ENABLE_SDAP "enable the SDAP layer\n" #define GNB_CONFIG_HLP_FORCE256QAMOFF "suppress activation of 256 QAM despite UE support" @@ -154,6 +155,7 @@ typedef enum { #define GNB_CONFIG_HLP_UESS_AGG_LEVEL_LIST "List of aggregation levels with number of candidates per level. Element 0 - aggregation level 1" #define GNB_CONFIG_HLP_CU_SIBS "List of CU generated SIBs to be transmitted" #define GNB_CONFIG_HLP_DU_SIBS "List of DU generated SIBs to be transmitted" +#define GNB_CONFIG_HLP_DOSINR "Enable CSI feedback using SINR measurements on SSB" /*-----------------------------------------------------------------------------------------------------------------------------------------*/ /* cell configuration parameters */ @@ -201,6 +203,7 @@ typedef enum { GNB_CONFIG_HLP_UESS_AGG_LEVEL_LIST, 0, .iptr=NULL, .defintarrayval=NULL, TYPE_INTARRAY, 0}, \ {GNB_CONFIG_STRING_CU_SIB_LIST, GNB_CONFIG_HLP_CU_SIBS, 0, .iptr=NULL, .defintarrayval=0, TYPE_INTARRAY, 0}, \ {GNB_CONFIG_STRING_DU_SIB_LIST, GNB_CONFIG_HLP_DU_SIBS, 0, .iptr=NULL, .defintarrayval=0, TYPE_INTARRAY, 0}, \ +{GNB_CONFIG_STRING_DOSINR, GNB_CONFIG_HLP_DOSINR, 0, .iptr=NULL, .defintval=0, TYPE_INT, 0}, \ } // clang-format on @@ -244,6 +247,7 @@ typedef enum { #define GNB_UESS_AGG_LEVEL_LIST_IDX 36 #define GNB_CU_SIBS_IDX 37 #define GNB_DU_SIBS_IDX 38 +#define GNB_DO_SINR_IDX 39 #define TRACKING_AREA_CODE_OKRANGE {0x0001,0xFFFD} #define NUM_DL_HARQ_OKVALUES {2,4,6,8,10,12,16,32} @@ -289,6 +293,7 @@ typedef enum { { .s5 = { NULL } }, \ { .s5 = { NULL } }, \ { .s5 = { NULL } }, \ + { .s5 = { NULL } }, \ } /*-------------------------------------------------------------------------------------------------------------------------------------------------*/ diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index 3a01ecfbfb..513e62b5ac 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -179,6 +179,7 @@ typedef struct nr_mac_config_t { int32_t *bw_list; int num_agg_level_candidates[NUM_PDCCH_AGG_LEVELS]; nr_redcap_config_t *redcap; + bool do_SINR; } nr_mac_config_t; typedef struct NR_preamble_ue { diff --git a/openair2/RRC/NR/nr_rrc_config.c b/openair2/RRC/NR/nr_rrc_config.c index d377b2aff3..0391ed282f 100644 --- a/openair2/RRC/NR/nr_rrc_config.c +++ b/openair2/RRC/NR/nr_rrc_config.c @@ -1934,7 +1934,8 @@ static void config_rsrp_meas_report(NR_CSI_MeasConfig_t *csi_MeasConfig, int rep_id, int uid, int curr_bwp, - int num_antenna_ports) + int num_antenna_ports, + bool do_sinr) { int resource_id = -1; for (int csi_list = 0; csi_list < csi_MeasConfig->csi_ResourceConfigToAddModList->list.count; csi_list++) { @@ -1968,6 +1969,14 @@ static void config_rsrp_meas_report(NR_CSI_MeasConfig_t *csi_MeasConfig, } else { csirep->reportQuantity.present = NR_CSI_ReportConfig__reportQuantity_PR_ssb_Index_RSRP; csirep->reportQuantity.choice.ssb_Index_RSRP = (NULL_t)0; + if (do_sinr) { + csirep->reportQuantity.present = NR_CSI_ReportConfig__reportQuantity_PR_none; + csirep->reportQuantity.choice.none = (NULL_t)0; + csirep->ext2 = calloc(1, sizeof(*csirep->ext2)); + csirep->ext2->reportQuantity_r16 = calloc(1, sizeof(*csirep->ext2->reportQuantity_r16)); + csirep->ext2->reportQuantity_r16->present = NR_CSI_ReportConfig__ext2__reportQuantity_r16_PR_ssb_Index_SINR_r16; + csirep->ext2->reportQuantity_r16->choice.ssb_Index_SINR_r16 = (NULL_t)0; + } } csirep->groupBasedBeamReporting.present = NR_CSI_ReportConfig__groupBasedBeamReporting_PR_disabled; csirep->groupBasedBeamReporting.choice.disabled = calloc(1, sizeof(*csirep->groupBasedBeamReporting.choice.disabled)); @@ -3298,7 +3307,15 @@ static NR_SpCellConfig_t *get_initial_SpCellConfig(int uid, NR_PUCCH_CSI_Resource_t *pucchrsrp = calloc(1, sizeof(*pucchrsrp)); pucchrsrp->uplinkBandwidthPartId = bwp_id; pucchrsrp->pucch_Resource = pucch_Resource; - config_rsrp_meas_report(csi_MeasConfig, scc, pucchrsrp, configuration->do_CSIRS, bwp_id + 10, uid, curr_bwp, pdsch_AntennaPorts); + config_rsrp_meas_report(csi_MeasConfig, + scc, + pucchrsrp, + configuration->do_CSIRS, + bwp_id + 10, + uid, + curr_bwp, + pdsch_AntennaPorts, + configuration->do_SINR); } fill_harq_IEs(SpCellConfig->spCellConfigDedicated, configuration->num_dlharq, configuration->num_ulharq); @@ -3811,7 +3828,8 @@ NR_CellGroupConfig_t *get_default_secondaryCellGroup(const NR_ServingCellConfigC bwp->bwp_Id + 10, uid, curr_bwp, - dl_antenna_ports); + dl_antenna_ports, + configuration->do_SINR); } secondaryCellGroup->spCellConfig->spCellConfigDedicated->sCellDeactivationTimer = NULL; secondaryCellGroup->spCellConfig->spCellConfigDedicated->crossCarrierSchedulingConfig = NULL; From 61778f3d5599e6e1ec9091e2b37eb885eac4230a Mon Sep 17 00:00:00 2001 From: Raghavendra Dinavahi Date: Thu, 13 Feb 2025 15:57:02 +0100 Subject: [PATCH 2/6] gNB changes- Compute bitlen in case of SSB-SINR compute SINR bitlen according to 38.212 table 6.3.1.1.2-6A --- openair2/LAYER2/NR_MAC_COMMON/nr_mac.h | 7 +- openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c | 105 ++++++++++++------ 2 files changed, 73 insertions(+), 39 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac.h b/openair2/LAYER2/NR_MAC_COMMON/nr_mac.h index 007976a1a5..68182ab9ec 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac.h +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac.h @@ -517,7 +517,9 @@ typedef struct { uint8_t cri_ssbri_bitlen; uint8_t rsrp_bitlen; uint8_t diff_rsrp_bitlen; -} L1_RSRP_bitlen_t; + uint8_t sinr_bitlen; + uint8_t diff_sinr_bitlen; +} L1_Meas_bitlen_t; typedef struct{ uint8_t ri_restriction; @@ -535,13 +537,14 @@ typedef struct{ typedef struct nr_csi_report { NR_CSI_ReportConfigId_t reportConfigId; NR_CSI_ReportConfig__reportQuantity_PR reportQuantity_type; + NR_CSI_ReportConfig__ext2__reportQuantity_r16_PR reportQuantity_type_r16; long periodicity; uint16_t offset; long **SSB_Index_list; long **CSI_Index_list; // uint8_t nb_of_nzp_csi_report; uint8_t nb_of_csi_ssb_report; - L1_RSRP_bitlen_t CSI_report_bitlen; + L1_Meas_bitlen_t CSI_report_bitlen; CSI_Meas_bitlen_t csi_meas_bitlen; int codebook_mode; int N1; diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c index 44c6673f2f..57ab38c0ef 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c @@ -4427,7 +4427,10 @@ static uint8_t number_of_bits_set(uint8_t buf) return nb_of_bits_set; } -static void compute_rsrp_bitlen(const NR_CSI_ReportConfig_t *csi_reportconfig, uint8_t nb_resources, nr_csi_report_t *csi_report) +static void compute_rsrp_or_sinr_bitlen(const NR_CSI_ReportConfig_t *csi_reportconfig, + uint8_t nb_resources, + nr_csi_report_t *csi_report, + bool is_RSRP_configured) { if (NR_CSI_ReportConfig__groupBasedBeamReporting_PR_disabled == csi_reportconfig->groupBasedBeamReporting.present) { if (csi_reportconfig->groupBasedBeamReporting.choice.disabled->nrofReportedRS) @@ -4445,13 +4448,20 @@ static void compute_rsrp_bitlen(const NR_CSI_ReportConfig_t *csi_reportconfig, u csi_report->CSI_report_bitlen.nb_ssbri_cri = 2; if (nb_resources) { - csi_report->CSI_report_bitlen.cri_ssbri_bitlen =ceil(log2 (nb_resources)); - csi_report->CSI_report_bitlen.rsrp_bitlen = 7; // From spec 38.212 Table 6.3.1.1.2-6: CRI, SSBRI, and RSRP - csi_report->CSI_report_bitlen.diff_rsrp_bitlen = 4; // From spec 38.212 Table 6.3.1.1.2-6: CRI, SSBRI, and RSRP + csi_report->CSI_report_bitlen.cri_ssbri_bitlen = ceil(log2 (nb_resources)); + if (is_RSRP_configured) { + csi_report->CSI_report_bitlen.rsrp_bitlen = 7; // From spec 38.212 Table 6.3.1.1.2-6: CRI, SSBRI, and RSRP + csi_report->CSI_report_bitlen.diff_rsrp_bitlen = 4; // From spec 38.212 Table 6.3.1.1.2-6: CRI, SSBRI, and RSRP + } else { + csi_report->CSI_report_bitlen.sinr_bitlen = 7; // From spec 38.212 Table 6.3.1.1.2-6A: CRI, SSBRI, and SINR + csi_report->CSI_report_bitlen.diff_sinr_bitlen = 4; // From spec 38.212 Table 6.3.1.1.2-6A: CRI, SSBRI, and SINR + } } else { csi_report->CSI_report_bitlen.cri_ssbri_bitlen = 0; csi_report->CSI_report_bitlen.rsrp_bitlen = 0; csi_report->CSI_report_bitlen.diff_rsrp_bitlen = 0; + csi_report->CSI_report_bitlen.sinr_bitlen = 0; + csi_report->CSI_report_bitlen.diff_sinr_bitlen = 0; } } @@ -4878,9 +4888,13 @@ void compute_csi_bitlen(const NR_CSI_MeasConfig_t *csi_MeasConfig, nr_csi_report reportQuantity_type = csi_reportconfig->reportQuantity.present; csi_report->reportQuantity_type = reportQuantity_type; csi_report->reportConfigId = csi_reportconfig->reportConfigId; + csi_report->reportQuantity_type_r16 = NR_CSI_ReportConfig__ext2__reportQuantity_r16_PR_NOTHING; + if (csi_reportconfig->ext2 != NULL && csi_reportconfig->ext2->reportQuantity_r16) + csi_report->reportQuantity_type_r16 = csi_reportconfig->ext2->reportQuantity_r16->present; // setting the CSI or SSB index list - if (NR_CSI_ReportConfig__reportQuantity_PR_ssb_Index_RSRP == csi_report->reportQuantity_type) { + if (NR_CSI_ReportConfig__reportQuantity_PR_ssb_Index_RSRP == csi_report->reportQuantity_type + || NR_CSI_ReportConfig__ext2__reportQuantity_r16_PR_ssb_Index_SINR_r16 == csi_report->reportQuantity_type_r16) { for (int csi_idx = 0; csi_idx < csi_MeasConfig->csi_SSB_ResourceSetToAddModList->list.count; csi_idx++) { if (csi_MeasConfig->csi_SSB_ResourceSetToAddModList->list.array[csi_idx]->csi_SSB_ResourceSetId == *(csi_resourceconfig->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB->csi_SSB_ResourceSetList->list.array[0])){ @@ -4891,8 +4905,7 @@ void compute_csi_bitlen(const NR_CSI_MeasConfig_t *csi_MeasConfig, nr_csi_report break; } } - } - else { + } else { if (resourceType == NR_CSI_ResourceConfig__resourceType_periodic) { AssertFatal(csi_MeasConfig->nzp_CSI_RS_ResourceSetToAddModList != NULL, "Wrong settings! Report quantity requires CSI-RS but csi_MeasConfig->nzp_CSI_RS_ResourceSetToAddModList is NULL\n"); @@ -4911,33 +4924,46 @@ void compute_csi_bitlen(const NR_CSI_MeasConfig_t *csi_MeasConfig, nr_csi_report } LOG_D(NR_MAC,"nb_resources %d\n",nb_resources); // computation of bit length depending on the report type - switch(reportQuantity_type){ - case (NR_CSI_ReportConfig__reportQuantity_PR_ssb_Index_RSRP): - compute_rsrp_bitlen(csi_reportconfig, nb_resources, csi_report); - break; - case (NR_CSI_ReportConfig__reportQuantity_PR_cri_RSRP): - compute_rsrp_bitlen(csi_reportconfig, nb_resources, csi_report); - break; - case (NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_CQI): - csi_report->csi_meas_bitlen.cri_bitlen = ceil(log2(nb_resources)); - csi_report->csi_meas_bitlen.ri_restriction = compute_ri_bitlen(csi_reportconfig, csi_report); - compute_cqi_bitlen(csi_reportconfig, csi_report->csi_meas_bitlen.ri_restriction, csi_report); - break; - case (NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_PMI_CQI): - csi_report->csi_meas_bitlen.cri_bitlen = ceil(log2(nb_resources)); - csi_report->csi_meas_bitlen.ri_restriction = compute_ri_bitlen(csi_reportconfig, csi_report); - compute_cqi_bitlen(csi_reportconfig, csi_report->csi_meas_bitlen.ri_restriction, csi_report); - compute_pmi_bitlen(csi_reportconfig, csi_report->csi_meas_bitlen.ri_restriction, csi_report); - break; - case (NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_LI_PMI_CQI): - csi_report->csi_meas_bitlen.cri_bitlen = ceil(log2(nb_resources)); - csi_report->csi_meas_bitlen.ri_restriction = compute_ri_bitlen(csi_reportconfig, csi_report); - compute_li_bitlen(csi_reportconfig, csi_report->csi_meas_bitlen.ri_restriction, csi_report); - compute_cqi_bitlen(csi_reportconfig, csi_report->csi_meas_bitlen.ri_restriction, csi_report); - compute_pmi_bitlen(csi_reportconfig, csi_report->csi_meas_bitlen.ri_restriction, csi_report); - break; - default: - AssertFatal(1==0,"Not yet supported CSI report quantity type"); + if (csi_report->reportQuantity_type_r16 != NR_CSI_ReportConfig__ext2__reportQuantity_r16_PR_NOTHING) { + switch (csi_report->reportQuantity_type_r16) { + case NR_CSI_ReportConfig__ext2__reportQuantity_r16_PR_ssb_Index_SINR_r16: + compute_rsrp_or_sinr_bitlen(csi_reportconfig, nb_resources, csi_report, false); + break; + case NR_CSI_ReportConfig__ext2__reportQuantity_r16_PR_cri_SINR_r16: + compute_rsrp_or_sinr_bitlen(csi_reportconfig, nb_resources, csi_report, false); + break; + default: + AssertFatal(1 == 0, "Not yet supported CSI report quantity type"); + } + } else { + switch (reportQuantity_type) { + case (NR_CSI_ReportConfig__reportQuantity_PR_ssb_Index_RSRP): + compute_rsrp_or_sinr_bitlen(csi_reportconfig, nb_resources, csi_report, true); + break; + case (NR_CSI_ReportConfig__reportQuantity_PR_cri_RSRP): + compute_rsrp_or_sinr_bitlen(csi_reportconfig, nb_resources, csi_report, true); + break; + case (NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_CQI): + csi_report->csi_meas_bitlen.cri_bitlen = ceil(log2(nb_resources)); + csi_report->csi_meas_bitlen.ri_restriction = compute_ri_bitlen(csi_reportconfig, csi_report); + compute_cqi_bitlen(csi_reportconfig, csi_report->csi_meas_bitlen.ri_restriction, csi_report); + break; + case (NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_PMI_CQI): + csi_report->csi_meas_bitlen.cri_bitlen = ceil(log2(nb_resources)); + csi_report->csi_meas_bitlen.ri_restriction = compute_ri_bitlen(csi_reportconfig, csi_report); + compute_cqi_bitlen(csi_reportconfig, csi_report->csi_meas_bitlen.ri_restriction, csi_report); + compute_pmi_bitlen(csi_reportconfig, csi_report->csi_meas_bitlen.ri_restriction, csi_report); + break; + case (NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_LI_PMI_CQI): + csi_report->csi_meas_bitlen.cri_bitlen = ceil(log2(nb_resources)); + csi_report->csi_meas_bitlen.ri_restriction = compute_ri_bitlen(csi_reportconfig, csi_report); + compute_li_bitlen(csi_reportconfig, csi_report->csi_meas_bitlen.ri_restriction, csi_report); + compute_cqi_bitlen(csi_reportconfig, csi_report->csi_meas_bitlen.ri_restriction, csi_report); + compute_pmi_bitlen(csi_reportconfig, csi_report->csi_meas_bitlen.ri_restriction, csi_report); + break; + default: + AssertFatal(1 == 0, "Not yet supported CSI report quantity type"); + } } } } @@ -4946,11 +4972,16 @@ uint16_t nr_get_csi_bitlen(nr_csi_report_t *csi_report) { uint16_t csi_bitlen = 0; uint16_t max_bitlen = 0; - L1_RSRP_bitlen_t *CSI_report_bitlen = NULL; + L1_Meas_bitlen_t *CSI_report_bitlen = NULL; CSI_Meas_bitlen_t *csi_meas_bitlen = NULL; - if (csi_report->reportQuantity_type == NR_CSI_ReportConfig__reportQuantity_PR_ssb_Index_RSRP || - csi_report->reportQuantity_type == NR_CSI_ReportConfig__reportQuantity_PR_cri_RSRP) { + if (csi_report->reportQuantity_type_r16 == NR_CSI_ReportConfig__ext2__reportQuantity_r16_PR_ssb_Index_SINR_r16 + || csi_report->reportQuantity_type_r16 == NR_CSI_ReportConfig__ext2__reportQuantity_r16_PR_cri_SINR_r16) { + CSI_report_bitlen = &(csi_report->CSI_report_bitlen); // This might need to be moodif for Aperiodic CSI-RS measurements + csi_bitlen += ((CSI_report_bitlen->cri_ssbri_bitlen * CSI_report_bitlen->nb_ssbri_cri) + CSI_report_bitlen->sinr_bitlen + + (CSI_report_bitlen->diff_sinr_bitlen * (CSI_report_bitlen->nb_ssbri_cri - 1))); + } else if (csi_report->reportQuantity_type == NR_CSI_ReportConfig__reportQuantity_PR_ssb_Index_RSRP + || csi_report->reportQuantity_type == NR_CSI_ReportConfig__reportQuantity_PR_cri_RSRP) { CSI_report_bitlen = &(csi_report->CSI_report_bitlen); // This might need to be moodif for Aperiodic CSI-RS measurements csi_bitlen += ((CSI_report_bitlen->cri_ssbri_bitlen * CSI_report_bitlen->nb_ssbri_cri) + CSI_report_bitlen->rsrp_bitlen +(CSI_report_bitlen->diff_rsrp_bitlen * From 6e371b9e4813bcbe4dcd8eaf9a2f124c76e2933d Mon Sep 17 00:00:00 2001 From: Raghavendra Dinavahi Date: Thu, 13 Feb 2025 17:17:53 +0100 Subject: [PATCH 3/6] UE changes in PHY- Enable SSB based SINR measurement --- .../nfapi/public_inc/fapi_nr_ue_interface.h | 2 ++ openair1/PHY/INIT/nr_init_ue.c | 4 ++- openair1/PHY/NR_UE_ESTIMATION/nr_estimation.h | 10 +++---- .../PHY/NR_UE_ESTIMATION/nr_ue_measurements.c | 27 +++++++++++-------- .../PHY/NR_UE_TRANSPORT/nr_initial_sync.c | 3 ++- openair1/PHY/defs_nr_UE.h | 1 + openair1/SCHED_NR_UE/phy_procedures_nr_ue.c | 1 + openair2/LAYER2/NR_MAC_UE/mac_defs.h | 1 + openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c | 6 +++-- 9 files changed, 35 insertions(+), 20 deletions(-) diff --git a/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h b/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h index a5d6087856..140ed130a4 100644 --- a/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h +++ b/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h @@ -129,6 +129,8 @@ typedef struct { short rsrp_dBm; long arfcn; rlm_t radiolink_monitoring; // -1 no monitoring, 0 out_of_sync, 1 in_sync + // SINR value times 10 as reporting granularity is 0.5 + float sinr_dB; } fapi_nr_ssb_pdu_t; typedef struct { diff --git a/openair1/PHY/INIT/nr_init_ue.c b/openair1/PHY/INIT/nr_init_ue.c index 9f8a463ec7..f4f0f7e50e 100644 --- a/openair1/PHY/INIT/nr_init_ue.c +++ b/openair1/PHY/INIT/nr_init_ue.c @@ -180,8 +180,10 @@ int init_nr_ue_signal(PHY_VARS_NR_UE *ue, int nb_connected_gNB) AssertFatal( nb_connected_gNB <= NUMBER_OF_CONNECTED_gNB_MAX, "n_connected_gNB is too large" ); // init phy_vars_ue - for (int i = 0; i < fp->Lmax; i++) + for (int i = 0; i < fp->Lmax; i++) { ue->measurements.ssb_rsrp_dBm[i] = INT_MIN; + ue->measurements.ssb_sinr_dB[i] = INT_MIN; + } for (int i = 0; i < 4; i++) { ue->rx_gain_max[i] = 135; diff --git a/openair1/PHY/NR_UE_ESTIMATION/nr_estimation.h b/openair1/PHY/NR_UE_ESTIMATION/nr_estimation.h index 835876d4bf..da6fd31eb5 100644 --- a/openair1/PHY/NR_UE_ESTIMATION/nr_estimation.h +++ b/openair1/PHY/NR_UE_ESTIMATION/nr_estimation.h @@ -111,11 +111,11 @@ void nr_ue_measurements(PHY_VARS_NR_UE *ue, uint32_t pdsch_est_size, int32_t dl_ch_estimates[][pdsch_est_size]); -int nr_ue_calculate_ssb_rsrp(const NR_DL_FRAME_PARMS *fp, - const UE_nr_rxtx_proc_t *proc, - const c16_t rxdataF[][fp->samples_per_slot_wCP], - int symbol_offset, - int ssb_start_subcarrier); +uint32_t nr_ue_calculate_ssb_rsrp(const NR_DL_FRAME_PARMS *fp, + const UE_nr_rxtx_proc_t *proc, + const c16_t rxdataF[][fp->samples_per_slot_wCP], + int symbol_offset, + int ssb_start_subcarrier); void nr_ue_ssb_rsrp_measurements(PHY_VARS_NR_UE *ue, uint8_t gNB_index, diff --git a/openair1/PHY/NR_UE_ESTIMATION/nr_ue_measurements.c b/openair1/PHY/NR_UE_ESTIMATION/nr_ue_measurements.c index 0fb94f93f3..b6aeba7f76 100644 --- a/openair1/PHY/NR_UE_ESTIMATION/nr_ue_measurements.c +++ b/openair1/PHY/NR_UE_ESTIMATION/nr_ue_measurements.c @@ -172,11 +172,11 @@ void nr_ue_measurements(PHY_VARS_NR_UE *ue, // This function calculates: // - SS reference signal received digital power in dB/RE -int nr_ue_calculate_ssb_rsrp(const NR_DL_FRAME_PARMS *fp, - const UE_nr_rxtx_proc_t *proc, - const c16_t rxdataF[][fp->samples_per_slot_wCP], - int symbol_offset, - int ssb_start_subcarrier) +uint32_t nr_ue_calculate_ssb_rsrp(const NR_DL_FRAME_PARMS *fp, + const UE_nr_rxtx_proc_t *proc, + const c16_t rxdataF[][fp->samples_per_slot_wCP], + int symbol_offset, + int ssb_start_subcarrier) { int k_start = 56; int k_end = 183; @@ -209,9 +209,7 @@ int nr_ue_calculate_ssb_rsrp(const NR_DL_FRAME_PARMS *fp, LOG_D(PHY, "In %s: RSRP/nb_re: %d nb_re :%d\n", __FUNCTION__, rsrp, nb_re); - int rsrp_db_per_re = 10 * log10(rsrp); - - return rsrp_db_per_re; + return rsrp; } // This function implements: @@ -234,7 +232,8 @@ void nr_ue_ssb_rsrp_measurements(PHY_VARS_NR_UE *ue, if (fp->half_frame_bit) symbol_offset += (fp->slots_per_frame >> 1) * fp->symbols_per_slot; - int rsrp_db_per_re = nr_ue_calculate_ssb_rsrp(fp, proc, rxdataF, symbol_offset, fp->ssb_start_subcarrier); + uint32_t rsrp_avg = nr_ue_calculate_ssb_rsrp(fp, proc, rxdataF, symbol_offset, fp->ssb_start_subcarrier); + float rsrp_db_per_re = 10 * log10(rsrp_avg); openair0_config_t *cfg0 = &openair0_cfg[0]; @@ -242,12 +241,18 @@ void nr_ue_ssb_rsrp_measurements(PHY_VARS_NR_UE *ue, - ((int)cfg0->rx_gain[0] - (int)cfg0->rx_gain_offset[0]) - dB_fixed(fp->ofdm_symbol_size); + // to obtain non-integer dB value with a resoluion of 0.5dB + uint32_t signal_pwr = rsrp_avg > ue->measurements.n0_power_avg ? rsrp_avg - ue->measurements.n0_power_avg : 0; + int SNRtimes10 = dB_fixed_x10(signal_pwr) - dB_fixed_x10(ue->measurements.n0_power_avg); + ue->measurements.ssb_sinr_dB[ssb_index] = SNRtimes10 / 10.0; + LOG_D(PHY, - "[UE %d] ssb %d SS-RSRP: %d dBm/RE (%d dB/RE)\n", + "[UE %d] ssb %d SS-RSRP: %d dBm/RE (%f dB/RE), SS-SINR: %f dB\n", ue->Mod_id, ssb_index, ue->measurements.ssb_rsrp_dBm[ssb_index], - rsrp_db_per_re); + rsrp_db_per_re, + ue->measurements.ssb_sinr_dB[ssb_index]); } // This function computes the received noise power diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_initial_sync.c b/openair1/PHY/NR_UE_TRANSPORT/nr_initial_sync.c index dc634584f6..422e8d6484 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_initial_sync.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_initial_sync.c @@ -285,7 +285,8 @@ void nr_scan_ssb(void *arg) &ssbInfo->pbchResult, rxdataF); // start pbch detection at first symbol after pss if (ssbInfo->syncRes.cell_detected) { - int rsrp_db_per_re = nr_ue_calculate_ssb_rsrp(ssbInfo->fp, ssbInfo->proc, rxdataF, 0, ssbInfo->gscnInfo.ssbFirstSC); + uint32_t rsrp_avg = nr_ue_calculate_ssb_rsrp(ssbInfo->fp, ssbInfo->proc, rxdataF, 0, ssbInfo->gscnInfo.ssbFirstSC); + int rsrp_db_per_re = 10 * log10(rsrp_avg); ssbInfo->adjust_rxgain = TARGET_RX_POWER - rsrp_db_per_re; LOG_I(PHY, "pbch rx ok. rsrp:%d dB/RE, adjust_rxgain:%d dB\n", rsrp_db_per_re, ssbInfo->adjust_rxgain); } diff --git a/openair1/PHY/defs_nr_UE.h b/openair1/PHY/defs_nr_UE.h index a617784e64..f724861e2d 100644 --- a/openair1/PHY/defs_nr_UE.h +++ b/openair1/PHY/defs_nr_UE.h @@ -140,6 +140,7 @@ typedef struct { uint32_t rsrp[7]; short rsrp_dBm[7]; int ssb_rsrp_dBm[64]; + float ssb_sinr_dB[64]; // common measurements //! estimated noise power (linear) unsigned int n0_power[NB_ANTENNAS_RX]; diff --git a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c index d427e9721c..64ee69679a 100644 --- a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c +++ b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c @@ -175,6 +175,7 @@ void nr_fill_rx_indication(fapi_nr_rx_indication_t *rx_ind, rx->ssb_pdu.cell_id = frame_parms->Nid_cell; rx->ssb_pdu.ssb_start_subcarrier = frame_parms->ssb_start_subcarrier; rx->ssb_pdu.rsrp_dBm = ue->measurements.ssb_rsrp_dBm[frame_parms->ssb_index]; + rx->ssb_pdu.sinr_dB = ue->measurements.ssb_sinr_dB[frame_parms->ssb_index]; rx->ssb_pdu.arfcn = get_ssb_arfcn(frame_parms); rx->ssb_pdu.radiolink_monitoring = RLM_in_sync; // TODO to be removed from here rx->ssb_pdu.decoded_pdu = true; diff --git a/openair2/LAYER2/NR_MAC_UE/mac_defs.h b/openair2/LAYER2/NR_MAC_UE/mac_defs.h index 3241235bd3..526e68892c 100644 --- a/openair2/LAYER2/NR_MAC_UE/mac_defs.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_defs.h @@ -417,6 +417,7 @@ typedef struct { uint32_t ssb_index; /// SSB RSRP in dBm short ssb_rsrp_dBm; + float_t ssb_sinr_dB; } NR_SSB_meas_t; typedef enum ta_type { diff --git a/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c b/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c index dfb0a0d942..0d0829181e 100644 --- a/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c +++ b/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c @@ -1133,10 +1133,11 @@ static nr_dci_format_t handle_dci(NR_UE_MAC_INST_t *mac, return nr_ue_process_dci_indication_pdu(mac, frame, slot, dci); } -static void handle_ssb_meas(NR_UE_MAC_INST_t *mac, uint8_t ssb_index, int16_t rsrp_dbm) +static void handle_ssb_meas(NR_UE_MAC_INST_t *mac, uint8_t ssb_index, int16_t rsrp_dbm, float_t sinr_dB) { mac->ssb_measurements.ssb_index = ssb_index; mac->ssb_measurements.ssb_rsrp_dBm = rsrp_dbm; + mac->ssb_measurements.ssb_sinr_dB = sinr_dB; } // L2 Abstraction Layer @@ -1272,7 +1273,8 @@ static uint32_t nr_ue_dl_processing(NR_UE_MAC_INST_t *mac, nr_downlink_indicatio if(rx_indication_body.ssb_pdu.decoded_pdu) { handle_ssb_meas(mac, rx_indication_body.ssb_pdu.ssb_index, - rx_indication_body.ssb_pdu.rsrp_dBm); + rx_indication_body.ssb_pdu.rsrp_dBm, + rx_indication_body.ssb_pdu.sinr_dB); ret_mask |= (handle_bcch_bch(mac, dl_info->cc_id, dl_info->gNB_index, From 516a61881678c120a8553ddf96f1e13d41ccee4e Mon Sep 17 00:00:00 2001 From: Raghavendra Dinavahi Date: Thu, 13 Feb 2025 19:17:42 +0100 Subject: [PATCH 4/6] UE changes- Generate SSB based SINR CSI report --- openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c | 158 ++++++++++++++++--- 1 file changed, 138 insertions(+), 20 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c index 572202d044..f61b6c4514 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c @@ -2643,6 +2643,111 @@ int nr_get_csi_measurements(NR_UE_MAC_INST_t *mac, frame_t frame, int slot, PUCC return num_csi; } +// Referred - Table 10.1.16.1-1 in 38.133 V16.7.0. +static uint8_t get_sinr_index(float sinr) +{ + int index = sinr * 2 + 47; + if (sinr >= 40) + index = 127; + if (sinr < -23) + index = 0; + + return index; +} + +// Reffered Table 10.1.16.1-2 in 38.133 V16.7.0. Differential value is reported. +static uint8_t get_sinr_diff_index(float best_sinr, float current_sinr) +{ + int diff = best_sinr - current_sinr; + if (diff >= 15) + return 15; + else if (diff <= 0) + return 0; + else + return diff; +} + +static csi_payload_t get_ssb_sinr_payload(NR_UE_MAC_INST_t *mac, + struct NR_CSI_ReportConfig *csi_reportconfig, + NR_CSI_ResourceConfigId_t csi_ResourceConfigId, + NR_CSI_MeasConfig_t *csi_MeasConfig) +{ + int nb_ssb = 0; // nb of ssb in the resource + int nb_meas = 0; // nb of ssb to report measurements on + int bits = 0; + uint32_t temp_payload = 0; + + for (int csi_resourceidx = 0; csi_resourceidx < csi_MeasConfig->csi_ResourceConfigToAddModList->list.count; csi_resourceidx++) { + struct NR_CSI_ResourceConfig *csi_resourceconfig = csi_MeasConfig->csi_ResourceConfigToAddModList->list.array[csi_resourceidx]; + if (csi_resourceconfig->csi_ResourceConfigId == csi_ResourceConfigId) { + if (csi_reportconfig->groupBasedBeamReporting.present == NR_CSI_ReportConfig__groupBasedBeamReporting_PR_disabled) { + if (csi_reportconfig->groupBasedBeamReporting.choice.disabled->nrofReportedRS != NULL) + nb_meas = *(csi_reportconfig->groupBasedBeamReporting.choice.disabled->nrofReportedRS) + 1; + else + nb_meas = 1; + } else + nb_meas = 2; + + struct NR_CSI_SSB_ResourceSet__csi_SSB_ResourceList SSB_resource; + for (int csi_ssb_idx = 0; csi_ssb_idx < csi_MeasConfig->csi_SSB_ResourceSetToAddModList->list.count; csi_ssb_idx++) { + if (csi_MeasConfig->csi_SSB_ResourceSetToAddModList->list.array[csi_ssb_idx]->csi_SSB_ResourceSetId + == *(csi_resourceconfig->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB->csi_SSB_ResourceSetList->list.array[0])) { + SSB_resource = csi_MeasConfig->csi_SSB_ResourceSetToAddModList->list.array[csi_ssb_idx]->csi_SSB_ResourceList; + /// only one SSB resource set from spec 38.331 IE CSI-ResourceConfig + nb_ssb = SSB_resource.list.count; + break; + } + } + + AssertFatal(nb_ssb > 0, "No SSB found in the resource set\n"); + AssertFatal(nb_meas == 1, "PHY currently reports only the strongest SSB to MAC. Can't report more than 1 RSRP\n"); + int ssbri_bits = ceil(log2(nb_ssb)); + + int ssb_index[nb_meas]; // the array contains index and RSRP of each SSB to be reported (nb_meas highest RSRPs) + float ssb_sinr[nb_meas]; + + // TODO replace the following 2 lines with a function to order the nb_meas highest SSB RSRPs + for (int i = 0; i < nb_ssb; i++) { + ssb_index[i] = -1;//Invalid index + if (*SSB_resource.list.array[i] == mac->mib_ssb) { + ssb_index[0] = i; + break; + } + } + AssertFatal(ssb_index[0] >= 0, "Couldn't find corresponding SSB in csi_SSB_ResourceList\n"); + ssb_sinr[0] = mac->ssb_measurements.ssb_sinr_dB; + + uint8_t ssbi; + + // TS38.212 v16.5.0: Table 6.3.1.1.2-8A + if (ssbri_bits > 0) { + ssbi = ssb_index[0]; + temp_payload = reverse_bits(ssbi, ssbri_bits); + bits += ssbri_bits; + } + + uint8_t sinr_idx = get_sinr_index(ssb_sinr[0]); + temp_payload |= (reverse_bits(sinr_idx, 7) << bits); + bits += 7; // 7 bits for highest SINR + + // from the second SSB, differential report + for (int i = 1; i < nb_meas; i++) { + ssbi = ssb_index[i]; + temp_payload = reverse_bits(ssbi, ssbri_bits); + bits += ssbri_bits; + + sinr_idx = get_sinr_diff_index(ssb_sinr[0], ssb_sinr[i]); + temp_payload |= (reverse_bits(sinr_idx, 4) << bits); + bits += 4; // 7 bits for highest SINR + } + break; // resource found + } + } + AssertFatal(bits <= 32, "Not supporting CSI report with more than 32 bits\n"); + csi_payload_t csi = {.part1_payload = temp_payload, .p1_bits = bits, csi.p2_bits = 0}; + return csi; +} + csi_payload_t nr_get_csi_payload(NR_UE_MAC_INST_t *mac, int csi_report_id, CSI_mapping_t mapping_type, @@ -2652,26 +2757,39 @@ csi_payload_t nr_get_csi_payload(NR_UE_MAC_INST_t *mac, csi_payload_t csi = {0}; struct NR_CSI_ReportConfig *csi_reportconfig = csi_MeasConfig->csi_ReportConfigToAddModList->list.array[csi_report_id]; NR_CSI_ResourceConfigId_t csi_ResourceConfigId = csi_reportconfig->resourcesForChannelMeasurement; - switch(csi_reportconfig->reportQuantity.present) { - case NR_CSI_ReportConfig__reportQuantity_PR_none: - break; - case NR_CSI_ReportConfig__reportQuantity_PR_ssb_Index_RSRP: - csi = get_ssb_rsrp_payload(mac, csi_reportconfig, csi_ResourceConfigId, csi_MeasConfig); - break; - case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_PMI_CQI: - csi = get_csirs_RI_PMI_CQI_payload(mac, csi_reportconfig, csi_ResourceConfigId, csi_MeasConfig, mapping_type); - break; - case NR_CSI_ReportConfig__reportQuantity_PR_cri_RSRP: - csi = get_csirs_RSRP_payload(mac, csi_reportconfig, csi_ResourceConfigId, csi_MeasConfig); - break; - case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_i1: - case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_i1_CQI: - case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_CQI: - case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_LI_PMI_CQI: - LOG_E(NR_MAC,"Measurement report %d based on CSI-RS is not available\n", csi_reportconfig->reportQuantity.present); - break; - default: - AssertFatal(1==0,"Invalid CSI report quantity type %d\n",csi_reportconfig->reportQuantity.present); + if (csi_reportconfig->ext2 && csi_reportconfig->ext2->reportQuantity_r16) { + switch (csi_reportconfig->ext2->reportQuantity_r16->present) { + case NR_CSI_ReportConfig__ext2__reportQuantity_r16_PR_ssb_Index_SINR_r16: + csi = get_ssb_sinr_payload(mac, csi_reportconfig, csi_ResourceConfigId, csi_MeasConfig); + break; + case NR_CSI_ReportConfig__ext2__reportQuantity_r16_PR_cri_SINR_r16: + LOG_E(NR_MAC, "CSI Reporting of CSI-RS based SINR not yet available\n"); + break; + default: + AssertFatal(1 == 0, "Invalid CSI report quantity r16 type %d\n", csi_reportconfig->ext2->reportQuantity_r16->present); + } + } else { + switch (csi_reportconfig->reportQuantity.present) { + case NR_CSI_ReportConfig__reportQuantity_PR_none: + break; + case NR_CSI_ReportConfig__reportQuantity_PR_ssb_Index_RSRP: + csi = get_ssb_rsrp_payload(mac, csi_reportconfig, csi_ResourceConfigId, csi_MeasConfig); + break; + case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_PMI_CQI: + csi = get_csirs_RI_PMI_CQI_payload(mac, csi_reportconfig, csi_ResourceConfigId, csi_MeasConfig, mapping_type); + break; + case NR_CSI_ReportConfig__reportQuantity_PR_cri_RSRP: + csi = get_csirs_RSRP_payload(mac, csi_reportconfig, csi_ResourceConfigId, csi_MeasConfig); + break; + case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_i1: + case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_i1_CQI: + case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_CQI: + case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_LI_PMI_CQI: + LOG_E(NR_MAC, "Measurement report %d based on CSI-RS is not available\n", csi_reportconfig->reportQuantity.present); + break; + default: + AssertFatal(1 == 0, "Invalid CSI report quantity type %d\n", csi_reportconfig->reportQuantity.present); + } } return csi; } From 1666dced3eb0f9e5f5f2eb81dbfbc779938ecdb9 Mon Sep 17 00:00:00 2001 From: Raghavendra Dinavahi Date: Thu, 13 Feb 2025 21:45:40 +0100 Subject: [PATCH 5/6] gNB changes- Extract SSB-SINR from received CSI report --- .../LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c | 212 ++++++++++++------ openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h | 2 + 2 files changed, 148 insertions(+), 66 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c index 2b5cc97ffe..ddb5ba9ead 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c @@ -429,6 +429,78 @@ static uint8_t pickandreverse_bits(uint8_t *payload, uint16_t bitlen, uint8_t st return rev_bits; } +static void evaluate_sinr_report(gNB_MAC_INST *nrmac, + NR_UE_info_t *UE, + NR_UE_sched_ctrl_t *sched_ctrl, + uint8_t csi_report_id, + uint8_t *payload, + int *cumul_bits, + NR_CSI_ReportConfig__ext2__reportQuantity_r16_PR reportQuantity_type_r16) +{ + /*! As per the spec 38.212 and table: 6.3.1.1.2-12 in a single UCI sequence we can have multiple CSI_report + * the number of CSI_report will depend on number of CSI resource sets that are configured in CSI-ResourceConfig RRC IE + * From spec 38.331 from the IE CSI-ResourceConfig for SSB RSRP reporting we can configure only one resource set + * From spec 38.214 section 5.2.1.2 For periodic and semi-persistent CSI Resource Settings, the number of CSI-RS Resource Sets + * configured is limited to S=1 + */ + + /** from 38.214 sec 5.2.1.4.2 + - if the UE is configured with the higher layer parameter groupBasedBeamReporting set to 'disabled', the UE is + not required to update measurements for more than 64 CSI-RS and/or SSB resources, and the UE shall report in + a single report nrofReportedRS (higher layer configured) different CRI or SSBRI for each report setting + + - if the UE is configured with the higher layer parameter groupBasedBeamReporting set to 'enabled', the UE is not + required to update measurements for more than 64 CSI-RS and/or SSB resources, and the UE shall report in a + single reporting instance two different CRI or SSBRI for each report setting, where CSI-RS and/or SSB + resources can be received simultaneously by the UE either with a single spatial domain receive filter, or with + multiple simultaneous spatial domain receive filter + */ + + nr_csi_report_t *csi_report = &UE->csi_report_template[csi_report_id]; + RSRP_report_t *sinr_report; + long **index_list; + switch (reportQuantity_type_r16) { + case NR_CSI_ReportConfig__ext2__reportQuantity_r16_PR_ssb_Index_SINR_r16: + sinr_report = &sched_ctrl->CSI_report.ssb_rsrp_report; + index_list = csi_report->SSB_Index_list; + break; + case NR_CSI_ReportConfig__ext2__reportQuantity_r16_PR_cri_SINR_r16: + sinr_report = &sched_ctrl->CSI_report.csirs_rsrp_report; + index_list = csi_report->CSI_Index_list; + break; + default: + AssertFatal(false, "Invalid RSRP report type\n"); + } + + sinr_report->nr_reports = csi_report->CSI_report_bitlen.nb_ssbri_cri; + uint16_t curr_payload; + for (int i = 0; i < sinr_report->nr_reports; i++) { + int bitlen = csi_report->CSI_report_bitlen.cri_ssbri_bitlen; + curr_payload = pickandreverse_bits(payload, bitlen, *cumul_bits); + sinr_report->resource_id[i] = *(index_list[bitlen > 0 ? ((curr_payload) & ~(~1U << (bitlen - 1))) : bitlen]); + LOG_D(MAC, "SSB/CSI-RS index = %d\n", sinr_report->resource_id[i]); + *cumul_bits += bitlen; + } + + curr_payload = pickandreverse_bits(payload, 7, *cumul_bits); + sinr_report->SINR_index[0] = 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]); + return; + } + + 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; + *cumul_bits += 4; + } + + LOG_D(MAC, "Reported SSB-SINR index = %d\n", sinr_report->SINR_index[0]); +} + static void evaluate_rsrp_report(gNB_MAC_INST *nrmac, NR_UE_info_t *UE, NR_UE_sched_ctrl_t *sched_ctrl, @@ -627,6 +699,8 @@ static void extract_pucch_csi_report(NR_CSI_MeasConfig_t *csi_MeasConfig, uint8_t *payload = uci_pdu->csi_part1.csi_part1_payload; uint16_t bitlen = uci_pdu->csi_part1.csi_part1_bit_len; NR_CSI_ReportConfig__reportQuantity_PR reportQuantity_type = NR_CSI_ReportConfig__reportQuantity_PR_NOTHING; + NR_CSI_ReportConfig__ext2__reportQuantity_r16_PR reportQuantity_type_r16 = + NR_CSI_ReportConfig__ext2__reportQuantity_r16_PR_NOTHING; NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; NR_UE_UL_BWP_t *ul_bwp = &UE->current_UL_BWP; NR_UE_DL_BWP_t *dl_bwp = &UE->current_DL_BWP; @@ -650,72 +724,78 @@ static void extract_pucch_csi_report(NR_CSI_MeasConfig_t *csi_MeasConfig, // verify if report with current id has been scheduled for this frame and slot if ((n_slots_frame*frame + slot - offset)%period == 0) { reportQuantity_type = csi_report->reportQuantity_type; - // phy-test has hardcoded allocation, so no use to handle CSI reports except RSRP - if (get_softmodem_params()->phy_test - && reportQuantity_type != NR_CSI_ReportConfig__reportQuantity_PR_ssb_Index_RSRP - && reportQuantity_type != NR_CSI_ReportConfig__reportQuantity_PR_cri_RSRP) - continue; - LOG_D(MAC,"SFN/SF:%d/%d reportQuantity type = %d\n",frame,slot,reportQuantity_type); - switch(reportQuantity_type) { - case NR_CSI_ReportConfig__reportQuantity_PR_cri_RSRP: - evaluate_rsrp_report(nrmac, UE, sched_ctrl, csi_report_id, payload, &cumul_bits, reportQuantity_type); - break; - case NR_CSI_ReportConfig__reportQuantity_PR_ssb_Index_RSRP: - evaluate_rsrp_report(nrmac, UE, sched_ctrl, csi_report_id, payload, &cumul_bits, reportQuantity_type); - beam_selection_procedures(nrmac, UE); - break; - case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_CQI: - sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.print_report = true; - cri_bitlen = csi_report->csi_meas_bitlen.cri_bitlen; - if(cri_bitlen) - evaluate_cri_report(payload,cri_bitlen,cumul_bits,sched_ctrl); - cumul_bits += cri_bitlen; - ri_bitlen = csi_report->csi_meas_bitlen.ri_bitlen; - if(ri_bitlen) - r_index = evaluate_ri_report(payload,ri_bitlen,csi_report->csi_meas_bitlen.ri_restriction,cumul_bits,sched_ctrl); - cumul_bits += ri_bitlen; - if (r_index != -1) - skip_zero_padding(&cumul_bits,csi_report,r_index,bitlen); - evaluate_cqi_report(payload,csi_report,cumul_bits,r_index,UE,cqi_table); - break; - case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_PMI_CQI: - sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.print_report = true; - cri_bitlen = csi_report->csi_meas_bitlen.cri_bitlen; - if(cri_bitlen) - evaluate_cri_report(payload,cri_bitlen,cumul_bits,sched_ctrl); - cumul_bits += cri_bitlen; - ri_bitlen = csi_report->csi_meas_bitlen.ri_bitlen; - if(ri_bitlen) - r_index = evaluate_ri_report(payload,ri_bitlen,csi_report->csi_meas_bitlen.ri_restriction,cumul_bits,sched_ctrl); - cumul_bits += ri_bitlen; - if (r_index != -1) - skip_zero_padding(&cumul_bits,csi_report,r_index,bitlen); - pmi_bitlen = evaluate_pmi_report(payload,csi_report,cumul_bits,r_index,sched_ctrl); - sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.csi_report_id = csi_report_id; - cumul_bits += pmi_bitlen; - evaluate_cqi_report(payload,csi_report,cumul_bits,r_index,UE,cqi_table); - break; - case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_LI_PMI_CQI: - sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.print_report = true; - cri_bitlen = csi_report->csi_meas_bitlen.cri_bitlen; - if(cri_bitlen) - evaluate_cri_report(payload,cri_bitlen,cumul_bits,sched_ctrl); - cumul_bits += cri_bitlen; - ri_bitlen = csi_report->csi_meas_bitlen.ri_bitlen; - if(ri_bitlen) - r_index = evaluate_ri_report(payload,ri_bitlen,csi_report->csi_meas_bitlen.ri_restriction,cumul_bits,sched_ctrl); - cumul_bits += ri_bitlen; - li_bitlen = evaluate_li_report(payload,csi_report,cumul_bits,r_index,sched_ctrl); - cumul_bits += li_bitlen; - if (r_index != -1) - skip_zero_padding(&cumul_bits,csi_report,r_index,bitlen); - pmi_bitlen = evaluate_pmi_report(payload,csi_report,cumul_bits,r_index,sched_ctrl); - sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.csi_report_id = csi_report_id; - cumul_bits += pmi_bitlen; - evaluate_cqi_report(payload,csi_report,cumul_bits,r_index,UE,cqi_table); - break; - default: - AssertFatal(1==0, "Invalid or not supported CSI measurement report\n"); + reportQuantity_type_r16 = csi_report->reportQuantity_type_r16; + LOG_D(MAC, "SFN/SF:%d/%d reportQuantity type = %d, type_r16 = %d\n", frame, slot, reportQuantity_type, reportQuantity_type_r16); + if (reportQuantity_type_r16 == NR_CSI_ReportConfig__ext2__reportQuantity_r16_PR_cri_SINR_r16 + || reportQuantity_type_r16 == NR_CSI_ReportConfig__ext2__reportQuantity_r16_PR_ssb_Index_SINR_r16) { + evaluate_sinr_report(nrmac, UE, sched_ctrl, csi_report_id, payload, &cumul_bits, reportQuantity_type_r16); + } else { + // phy-test has hardcoded allocation, so no use to handle CSI reports except RSRP + if (get_softmodem_params()->phy_test + && reportQuantity_type != NR_CSI_ReportConfig__reportQuantity_PR_ssb_Index_RSRP + && reportQuantity_type != NR_CSI_ReportConfig__reportQuantity_PR_cri_RSRP) + continue; + switch (reportQuantity_type) { + case NR_CSI_ReportConfig__reportQuantity_PR_cri_RSRP: + evaluate_rsrp_report(nrmac, UE, sched_ctrl, csi_report_id, payload, &cumul_bits, reportQuantity_type); + break; + case NR_CSI_ReportConfig__reportQuantity_PR_ssb_Index_RSRP: + evaluate_rsrp_report(nrmac, UE, sched_ctrl, csi_report_id, payload, &cumul_bits, reportQuantity_type); + beam_selection_procedures(nrmac, UE); + break; + case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_CQI: + sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.print_report = true; + cri_bitlen = csi_report->csi_meas_bitlen.cri_bitlen; + if (cri_bitlen) + evaluate_cri_report(payload, cri_bitlen, cumul_bits, sched_ctrl); + cumul_bits += cri_bitlen; + ri_bitlen = csi_report->csi_meas_bitlen.ri_bitlen; + if (ri_bitlen) + r_index = evaluate_ri_report(payload, ri_bitlen, csi_report->csi_meas_bitlen.ri_restriction, cumul_bits, sched_ctrl); + cumul_bits += ri_bitlen; + if (r_index != -1) + skip_zero_padding(&cumul_bits, csi_report, r_index, bitlen); + evaluate_cqi_report(payload, csi_report, cumul_bits, r_index, UE, cqi_table); + break; + case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_PMI_CQI: + sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.print_report = true; + cri_bitlen = csi_report->csi_meas_bitlen.cri_bitlen; + if (cri_bitlen) + evaluate_cri_report(payload, cri_bitlen, cumul_bits, sched_ctrl); + cumul_bits += cri_bitlen; + ri_bitlen = csi_report->csi_meas_bitlen.ri_bitlen; + if (ri_bitlen) + r_index = evaluate_ri_report(payload, ri_bitlen, csi_report->csi_meas_bitlen.ri_restriction, cumul_bits, sched_ctrl); + cumul_bits += ri_bitlen; + if (r_index != -1) + skip_zero_padding(&cumul_bits, csi_report, r_index, bitlen); + pmi_bitlen = evaluate_pmi_report(payload, csi_report, cumul_bits, r_index, sched_ctrl); + sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.csi_report_id = csi_report_id; + cumul_bits += pmi_bitlen; + evaluate_cqi_report(payload, csi_report, cumul_bits, r_index, UE, cqi_table); + break; + case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_LI_PMI_CQI: + sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.print_report = true; + cri_bitlen = csi_report->csi_meas_bitlen.cri_bitlen; + if (cri_bitlen) + evaluate_cri_report(payload, cri_bitlen, cumul_bits, sched_ctrl); + cumul_bits += cri_bitlen; + ri_bitlen = csi_report->csi_meas_bitlen.ri_bitlen; + if (ri_bitlen) + r_index = evaluate_ri_report(payload, ri_bitlen, csi_report->csi_meas_bitlen.ri_restriction, cumul_bits, sched_ctrl); + cumul_bits += ri_bitlen; + li_bitlen = evaluate_li_report(payload, csi_report, cumul_bits, r_index, sched_ctrl); + cumul_bits += li_bitlen; + if (r_index != -1) + skip_zero_padding(&cumul_bits, csi_report, r_index, bitlen); + pmi_bitlen = evaluate_pmi_report(payload, csi_report, cumul_bits, r_index, sched_ctrl); + sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.csi_report_id = csi_report_id; + cumul_bits += pmi_bitlen; + evaluate_cqi_report(payload, csi_report, cumul_bits, r_index, UE, cqi_table); + break; + default: + AssertFatal(1 == 0, "Invalid or not supported CSI measurement report\n"); + } } } } diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index 513e62b5ac..0553464338 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -538,6 +538,8 @@ 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]; } RSRP_report_t; struct CSI_Report { From bbcb31f64b8fcb65c498e2cd926396a1fe7a9c11 Mon Sep 17 00:00:00 2001 From: Raghavendra Dinavahi Date: Fri, 11 Apr 2025 14:50:16 +0200 Subject: [PATCH 6/6] Added description for do_SINR --- doc/MAC/mac-usage.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/doc/MAC/mac-usage.md b/doc/MAC/mac-usage.md index e4d6ebc098..ae4f3a626b 100644 --- a/doc/MAC/mac-usage.md +++ b/doc/MAC/mac-usage.md @@ -250,6 +250,8 @@ configuration](../RRC/rrc-usage.md) as well for SIB configuration. * `do_CSIRS` (default 0): flag whether to use channel-state information reference signal (CSI-RS) * `do_SRS` (default 0): flag whether to use sounding reference signal (SRS) +* `do_SINR` (default 0): flag whether to enable CSI reporting of SSB-SINR (introduced in rel16) + Default setting of CSI reporting quantity is SSB-RSRP. * `min_rxtxtime` (default 2): minimum feedback time for UE to respond to transmissions (k1 and k2 in 3GPP spec) * `ul_prbblacklist`: PRBs that should not be used for UL scheduling. Cf with @@ -272,6 +274,18 @@ configuration](../RRC/rrc-usage.md) as well for SIB configuration. - `du_sibs` (default `[]`): list of SIBs to transmit in the cell. Currently, SIB19 (for NTN) is supported. +| DL MIMO |`do_CSIRS`|`do_SINR`| CSI report Quantity | +| ---------------------------- | -------- | ------- | --------------------------------------------------| +| OFF (pdsch_AntennaPorts = 1) | 0 | 0 | SSB-RSRP | +| OFF (pdsch_AntennaPorts = 1) | 0 | 1 | SSB-SINR | +| OFF (pdsch_AntennaPorts = 1) | 1 | 0 | CSI-Reference signal RSRP | +| OFF (pdsch_AntennaPorts = 1) | 1 | 1 | CSI-Reference signal SINR (not supported yet) | +| ON (pdsch_AntennaPorts > 1) | 1 | 0 | cri-RI-PMI-CQI | + +DL-MIMO is configured using following parameters: +`pdsch_AntennaPorts_XP` , `pdsch_AntennaPorts_N1` , `pdsch_AntennaPorts_N2`, `maxMIMO_layers` +(see also [`RUNMODEM.md`](../RUNMODEM.md)) + ## ServingCellConfigCommon parameters The `gNBs` configuration section has a big structure `servingCellConfigCommon`