From 8222fa27e5a2e358e351cb522122cc8433dfc3c2 Mon Sep 17 00:00:00 2001 From: alexjiao Date: Fri, 13 Jun 2025 16:31:45 +0800 Subject: [PATCH] Add functions to calculate rate matching information for UCI on PUSCH Use betaOffset and alpha scaling etc. to get rate matching information of UCI on PUSCH (e.g. max bit capacity of encoded UCI and encoded ULSCH) according to TS 38.212 section 6.3.2.4 and 6.2.7. --- .../PHY/NR_UE_TRANSPORT/nr_transport_ue.h | 9 + openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c | 169 ++++++++++++++++++ 2 files changed, 178 insertions(+) diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_ue.h b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_ue.h index c63754b583..7252663d41 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_ue.h +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_ue.h @@ -135,4 +135,13 @@ typedef struct { // PTRS symbol index, to be updated every PTRS symbol within a slot. uint8_t ptrs_symbol_index; } NR_UE_DLSCH_t; + +typedef struct { + uint16_t Q_dash_ACK; // number of coded HARQ-ACK symbols + uint16_t E_uci_ACK; // number of coded HARQ-ACK bits + uint16_t Q_dash_ACK_rvd; // number of coded HARQ-ACK symbols reserved + uint16_t E_uci_ACK_rvd; // number of coded HARQ-ACK bits reserved + uint32_t G_ulsch; // bit capacity of ULSCH +} rate_match_info_uci_t; + #endif diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c index 435716919a..bd51b0641c 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c @@ -472,6 +472,175 @@ static void map_symbols(const nr_phy_pxsch_params_t p, } } +// Function to lookup beta offset value from Table 9.3-1 in TS 38.213 +static double get_beta_offset_harq_ack(uint8_t beta_offset_index) +{ + static const double beta_offset_values[21] = { + 1.000, // Index 0 + 2.000, // Index 1 + 2.500, // Index 2 + 3.125, // Index 3 + 4.000, // Index 4 + 5.000, // Index 5 + 6.250, // Index 6 + 8.000, // Index 7 + 10.000, // Index 8 + 12.625, // Index 9 + 15.875, // Index 10 + 20.000, // Index 11 + 31.000, // Index 12 + 50.000, // Index 13 + 80.000, // Index 14 + 126.000, // Index 15 + 0.6, // Index 16 + 0.4, // Index 17 + 0.2, // Index 18 + 0.1, // Index 19 + 0.05, // Index 20 + }; + + if (beta_offset_index > 20) { + LOG_E(PHY, "Invalid beta_offset_index %d, using default value\n", beta_offset_index); + return 20.000; // Default value using index 11 + } + + return beta_offset_values[beta_offset_index]; +} + +static double get_alpha_scaling_value(uint8_t alpha_scaling) +{ + switch (alpha_scaling) { + case 0: + return 0.5; + case 1: + return 0.65; + case 2: + return 0.8; + case 3: + return 1.0; + default: + AssertFatal(false, "Invalid alpha_scaling value %d, valid range is 0-3", alpha_scaling); + return 1.0; + } +} + +/* + * This function gets the CRC size of UCI + */ +static int get_crc_uci(const uint16_t ouci) +{ + int L = 0; + if (ouci > 19) { + L = 11; + } else if (ouci > 11) { + L = 6; + } else { + L = 0; // no ACK/NACK + } + + return L; +} + +static uint16_t get_Qd(const uint16_t oack, double beta, double alpha, const uint32_t sumKr, const uint32_t s1, const uint32_t s2) +{ + if (oack == 0) + return 0; + + uint16_t first_term = ceil(((double)oack + get_crc_uci(oack)) * (double)beta * s1 / sumKr); + uint16_t second_term = ceil(alpha * s2); + + return (first_term < second_term) ? first_term : second_term; +} + +/* + * This function calculates the rate matching information for UCI multiplexing with PUSCH + */ +static rate_match_info_uci_t calc_rate_match_info_uci(const nfapi_nr_ue_pusch_pdu_t *pusch_pdu, + const NR_UL_UE_HARQ_t *harq_process_ul_ue, + const uint8_t nlqm, + unsigned int *G) +{ + // get beta offset + uint8_t beta_offset_index = pusch_pdu->pusch_uci.beta_offset_harq_ack; + double beta = get_beta_offset_harq_ack(beta_offset_index); + + // get alpha scaling value + uint8_t alpha_scaling = pusch_pdu->pusch_uci.alpha_scaling; + double alpha = get_alpha_scaling_value(alpha_scaling); + + // Calculate sumKr (total bits in all code blocks) + uint32_t sumKr = 0; + if (harq_process_ul_ue->C == 0) { + sumKr = 0; + } else if (harq_process_ul_ue->C == 1) { + sumKr = harq_process_ul_ue->K; + } else { + sumKr = harq_process_ul_ue->K * harq_process_ul_ue->C; + } + + // Calculate s1: total number of non-DMRS REs in allocation + uint16_t nb_rb = pusch_pdu->rb_size; + uint8_t start_symbol = pusch_pdu->start_symbol_index; + uint8_t number_of_symbols = pusch_pdu->nr_of_symbols; + uint16_t ul_dmrs_symb_pos = pusch_pdu->ul_dmrs_symb_pos; + + uint32_t s1 = 0; + for (int l = start_symbol; l < start_symbol + number_of_symbols; l++) { + if (!((ul_dmrs_symb_pos >> l) & 0x01)) { + s1 += nb_rb * NR_NB_SC_PER_RB; + } + } + + // Calculate s2: number of non-DMRS REs after first DMRS symbol + int first_dmrs_symbol = -1; + for (int l = start_symbol; l < start_symbol + number_of_symbols; l++) { + if ((ul_dmrs_symb_pos >> l) & 0x01) { + first_dmrs_symbol = l; + break; + } + } + int l0 = -1; + if (first_dmrs_symbol >= 0 && first_dmrs_symbol < start_symbol + number_of_symbols - 1) { + l0 = first_dmrs_symbol + 1; + } + uint32_t s2 = 0; + for (int l = l0; l < start_symbol + number_of_symbols; l++) { + if (!((ul_dmrs_symb_pos >> l) & 0x01)) { + s2 += nb_rb * NR_NB_SC_PER_RB; + } + } + + uint16_t oack = pusch_pdu->pusch_uci.harq_ack_bit_length; + uint16_t oack_rvd = (oack <= 2) ? 2 : 0; // get the reserved bits when oACK <= 2 according to TS 38.212 section 6.2.7, step 1 + + rate_match_info_uci_t rminfo = {0}; + + // get the number of coded HARQ-ACK symbols and bits, TS 38.212 section 6.3.2.4.1.1 + rminfo.Q_dash_ACK = get_Qd(oack, beta, alpha, sumKr, s1, s2); + rminfo.E_uci_ACK = rminfo.Q_dash_ACK * nlqm; + + if (oack_rvd > 0) { + rminfo.Q_dash_ACK_rvd = get_Qd(oack_rvd, beta, alpha, sumKr, s1, s2); + rminfo.E_uci_ACK_rvd = rminfo.Q_dash_ACK_rvd * nlqm; + } + + if (oack_rvd == 0) { + rminfo.G_ulsch = *G - rminfo.E_uci_ACK; + } else { + rminfo.G_ulsch = *G; + } + + *G = rminfo.G_ulsch; + LOG_D(PHY, "[UCI_RATE_MATCH] sumKr=%u, s1=%u, s2=%u, Final G_ulsch (output G): %u\n", sumKr, s1, s2, *G); + LOG_D(PHY, + "[UCI_RATE_MATCH] rate matching info returned: E_uci_ACK=%u, E_uci_ACK_rvd=%u, G_ulsch=%u\n", + rminfo.E_uci_ACK, + rminfo.E_uci_ACK_rvd, + rminfo.G_ulsch); + + return rminfo; +} + void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, const uint32_t frame, const uint8_t slot,