From 99e4f54d61c7fe2bf354a3e021cad445d16c3a20 Mon Sep 17 00:00:00 2001 From: francescomani Date: Tue, 24 Jun 2025 13:54:35 +0200 Subject: [PATCH] type0 DLSCH frequency allocation for channel estimation --- .../nr_dl_channel_estimation.c | 114 ++++++++++-------- openair1/PHY/NR_UE_ESTIMATION/nr_estimation.h | 1 + .../NR_UE_TRANSPORT/nr_transport_proto_ue.h | 1 - .../PHY/NR_UE_TRANSPORT/nr_transport_ue.h | 6 + openair1/SCHED_NR_UE/phy_procedures_nr_ue.c | 51 +++++++- 5 files changed, 122 insertions(+), 51 deletions(-) diff --git a/openair1/PHY/NR_UE_ESTIMATION/nr_dl_channel_estimation.c b/openair1/PHY/NR_UE_ESTIMATION/nr_dl_channel_estimation.c index 4c59da3cb0..9e76b2f85f 100644 --- a/openair1/PHY/NR_UE_ESTIMATION/nr_dl_channel_estimation.c +++ b/openair1/PHY/NR_UE_ESTIMATION/nr_dl_channel_estimation.c @@ -938,6 +938,7 @@ void nr_pdcch_channel_estimation(PHY_VARS_NR_UE *ue, } void NFAPI_NR_DMRS_TYPE1_linear_interp(NR_DL_FRAME_PARMS *frame_parms, + const freq_alloc_bitmap_t *freq_alloc, c16_t *rxF, c16_t *pil, c16_t *dl_ch, @@ -948,45 +949,49 @@ void NFAPI_NR_DMRS_TYPE1_linear_interp(NR_DL_FRAME_PARMS *frame_parms, { c16_t *dl_ch0 = dl_ch; int re_offset = bwp_start_subcarrier % frame_parms->ofdm_symbol_size; - c16_t dl_ls_est[frame_parms->ofdm_symbol_size] __attribute__((aligned(32))); memset(dl_ls_est, 0, sizeof(dl_ls_est)); - - int nest_count = 0; - uint64_t noise_amp2 = 0; - - for (int pilot_cnt = 0; pilot_cnt < 6 * nb_rb_pdsch; pilot_cnt += 2) { - c16_t ch_l = c16mulShift(*pil, rxF[re_offset], 15); + int idx = 0; + for (int rb = freq_alloc->start; rb < freq_alloc->start + nb_rb_pdsch; rb++) { + bool allocated_rb = (freq_alloc->bitmap[rb / 8] >> (rb % 8)) & 0x01; + if (allocated_rb) { + for (int pilot_cnt = 0; pilot_cnt < 6; pilot_cnt += 2) { + c16_t ch_l = c16mulShift(*pil, rxF[re_offset], 15); #ifdef DEBUG_PDSCH - printf("pilot %3d: pil -> (%6d,%6d), rxF -> (%4d,%4d), ch -> (%4d,%4d) \n", pilot_cnt, pil->r, pil->i, rxF[re_offset].r, rxF[re_offset].i, ch_l.r, ch_l.i); + printf("pilot %3d: pil -> (%6d,%6d), rxF -> (%4d,%4d), ch -> (%4d,%4d) \n", pilot_cnt, pil->r, pil->i, rxF[re_offset].r, rxF[re_offset].i, ch_l.r, ch_l.i); #endif - pil++; - re_offset = (re_offset + 2) % frame_parms->ofdm_symbol_size; - c16_t ch_r = c16mulShift(*pil, rxF[re_offset], 15); + pil++; + re_offset = (re_offset + 2) % frame_parms->ofdm_symbol_size; + c16_t ch_r = c16mulShift(*pil, rxF[re_offset], 15); #ifdef DEBUG_PDSCH - printf("pilot %3d: pil -> (%6d,%6d), rxF -> (%4d,%4d), ch -> (%4d,%4d) \n", pilot_cnt + 1, pil->r, pil->i, rxF[re_offset].r, rxF[re_offset].i, ch_r.r, ch_r.i); + printf("pilot %3d: pil -> (%6d,%6d), rxF -> (%4d,%4d), ch -> (%4d,%4d) \n", pilot_cnt + 1, pil->r, pil->i, rxF[re_offset].r, rxF[re_offset].i, ch_r.r, ch_r.i); #endif - c16_t ch = c16addShift(ch_l, ch_r, 1); - pil++; - re_offset = (re_offset + 2) % frame_parms->ofdm_symbol_size; - for (int k = pilot_cnt << 1; k < (pilot_cnt << 1) + 4; k++) { - dl_ls_est[k] = ch; + c16_t ch = c16addShift(ch_l, ch_r, 1); + pil++; + re_offset = (re_offset + 2) % frame_parms->ofdm_symbol_size; + for (int k = 0; k < 4; k++) { + dl_ls_est[idx] = ch; + idx++; + } + } + } else { + pil += 6; + re_offset = (re_offset + 12) % frame_parms->ofdm_symbol_size; } } - c16_t ch_estimates_time[frame_parms->ofdm_symbol_size] __attribute__((aligned(32))); nr_est_delay(frame_parms->ofdm_symbol_size, dl_ls_est, ch_estimates_time, delay); int delay_idx = get_delay_idx(delay->est_delay, MAX_DELAY_COMP); c16_t *dl_delay_table = frame_parms->delay_table[delay_idx]; - for (int pilot_cnt = 0; pilot_cnt < 6 * nb_rb_pdsch; pilot_cnt++) { + for (int pilot_cnt = 0; pilot_cnt < idx >> 1; pilot_cnt++) { int k = pilot_cnt << 1; c16_t ch = c16mulShift(dl_ls_est[k], dl_delay_table[k], 8); if (pilot_cnt == 0) { // Treat first pilot c16multaddVectRealComplex(filt16_ul_p0, &ch, dl_ch, 16); } else if (pilot_cnt == 1 || pilot_cnt == 2) { c16multaddVectRealComplex(filt16_ul_p1p2, &ch, dl_ch, 16); - } else if (pilot_cnt == 6 * nb_rb_pdsch - 1) { // Treat last pilot + } else if (pilot_cnt == (idx >> 1) - 1) { // Treat last pilot c16multaddVectRealComplex(filt16_ul_last, &ch, dl_ch, 16); } else { // Treat middle pilots c16multaddVectRealComplex(filt16_ul_middle, &ch, dl_ch, 16); @@ -998,9 +1003,11 @@ void NFAPI_NR_DMRS_TYPE1_linear_interp(NR_DL_FRAME_PARMS *frame_parms, // Revert delay dl_ch = dl_ch0; + int nest_count = 0; + uint64_t noise_amp2 = 0; int inv_delay_idx = get_delay_idx(-delay->est_delay, MAX_DELAY_COMP); c16_t *dl_inv_delay_table = frame_parms->delay_table[inv_delay_idx]; - for (int k = 0; k < 12 * nb_rb_pdsch; k++) { + for (int k = 0; k < idx; k++) { dl_ch[k] = c16mulShift(dl_ch[k], dl_inv_delay_table[k], 8); noise_amp2 += c16amp2(c16sub(dl_ls_est[k], dl_ch[k])); nest_count++; @@ -1096,6 +1103,7 @@ void NFAPI_NR_DMRS_TYPE1_average_prb(NR_DL_FRAME_PARMS *frame_parms, } void NFAPI_NR_DMRS_TYPE2_linear_interp(NR_DL_FRAME_PARMS *frame_parms, + const freq_alloc_bitmap_t *freq_alloc, c16_t *rxF, c16_t *pil, c16_t *dl_ch, @@ -1106,45 +1114,50 @@ void NFAPI_NR_DMRS_TYPE2_linear_interp(NR_DL_FRAME_PARMS *frame_parms, { int re_offset = bwp_start_subcarrier % frame_parms->ofdm_symbol_size; c16_t *dl_ch0 = dl_ch; - c16_t dl_ls_est[frame_parms->ofdm_symbol_size] __attribute__((aligned(32))); memset(dl_ls_est, 0, sizeof(dl_ls_est)); - - int nest_count = 0; - uint64_t noise_amp2 = 0; - - for (int pilot_cnt = 0; pilot_cnt < 4 * nb_rb_pdsch; pilot_cnt += 2) { - c16_t ch_l = c16mulShift(*pil, rxF[re_offset], 15); + int idx = 0; + for (int rb = freq_alloc->start; rb < freq_alloc->start + nb_rb_pdsch; rb++) { + bool allocated_rb = (freq_alloc->bitmap[rb / 8] >> (rb % 8)) & 0x01; + if (allocated_rb) { + for (int pilot_cnt = 0; pilot_cnt < 4; pilot_cnt += 2) { + c16_t ch_l = c16mulShift(*pil, rxF[re_offset], 15); #ifdef DEBUG_PDSCH - printf("pilot %3d: pil -> (%6d,%6d), rxF -> (%4d,%4d), ch -> (%4d,%4d) \n", pilot_cnt, pil->r, pil->i, rxF[re_offset].r, rxF[re_offset].i, ch_l.r, ch_l.i); + printf("pilot %3d: pil -> (%6d,%6d), rxF -> (%4d,%4d), ch -> (%4d,%4d) \n", pilot_cnt, pil->r, pil->i, rxF[re_offset].r, rxF[re_offset].i, ch_l.r, ch_l.i); #endif - pil++; - re_offset = (re_offset + 1) % frame_parms->ofdm_symbol_size; - c16_t ch_r = c16mulShift(*pil, rxF[re_offset], 15); + pil++; + re_offset = (re_offset + 1) % frame_parms->ofdm_symbol_size; + c16_t ch_r = c16mulShift(*pil, rxF[re_offset], 15); #ifdef DEBUG_PDSCH - printf("pilot %3d: pil -> (%6d,%6d), rxF -> (%4d,%4d), ch -> (%4d,%4d) \n", pilot_cnt + 1, pil->r, pil->i, rxF[re_offset].r, rxF[re_offset].i, ch_r.r, ch_r.i); + printf("pilot %3d: pil -> (%6d,%6d), rxF -> (%4d,%4d), ch -> (%4d,%4d) \n", pilot_cnt + 1, pil->r, pil->i, rxF[re_offset].r, rxF[re_offset].i, ch_r.r, ch_r.i); #endif - c16_t ch = c16addShift(ch_l, ch_r, 1); - for (int k = 3 * pilot_cnt; k < (3 * pilot_cnt) + 6; k++) { - dl_ls_est[k] = ch; + c16_t ch = c16addShift(ch_l, ch_r, 1); + pil++; + re_offset = (re_offset + 5) % frame_parms->ofdm_symbol_size; + for (int k = 0; k < 6; k++) { + dl_ls_est[idx] = ch; + idx++; + } + } + } else { + pil += 4; + re_offset = (re_offset + 12) % frame_parms->ofdm_symbol_size; } - pil++; - re_offset = (re_offset + 5) % frame_parms->ofdm_symbol_size; } c16_t ch_estimates_time[frame_parms->ofdm_symbol_size] __attribute__((aligned(32))); nr_est_delay(frame_parms->ofdm_symbol_size, dl_ls_est, ch_estimates_time, delay); int delay_idx = get_delay_idx(delay->est_delay, MAX_DELAY_COMP); c16_t *dl_delay_table = frame_parms->delay_table[delay_idx]; - - for (int pilot_cnt = 0; pilot_cnt < 6 * nb_rb_pdsch; pilot_cnt++) { - int k = (pilot_cnt / 3) * 6; + // kept the same as before but unclear why would it be nb_rb_pdsch / 2 and not / 3 + for (int pilot_cnt = 0; pilot_cnt < idx >> 1; pilot_cnt++) { + int k = pilot_cnt << 1; c16_t ch = c16mulShift(dl_ls_est[k], dl_delay_table[k], 8); if (pilot_cnt == 0) { // Treat first pilot c16multaddVectRealComplex(filt16_ul_p0, &ch, dl_ch, 16); } else if (pilot_cnt == 1 || pilot_cnt == 2) { c16multaddVectRealComplex(filt16_ul_p1p2, &ch, dl_ch, 16); - } else if (pilot_cnt == 6 * nb_rb_pdsch - 1) { // Treat last pilot + } else if (pilot_cnt == (idx >> 1) - 1) { // Treat last pilot c16multaddVectRealComplex(filt16_ul_last, &ch, dl_ch, 16); } else { // Treat middle pilots c16multaddVectRealComplex(filt16_ul_middle, &ch, dl_ch, 16); @@ -1156,9 +1169,11 @@ void NFAPI_NR_DMRS_TYPE2_linear_interp(NR_DL_FRAME_PARMS *frame_parms, // Revert delay dl_ch = dl_ch0; + int nest_count = 0; + uint64_t noise_amp2 = 0; int inv_delay_idx = get_delay_idx(-delay->est_delay, MAX_DELAY_COMP); c16_t *dl_inv_delay_table = frame_parms->delay_table[inv_delay_idx]; - for (int k = 0; k < 12 * nb_rb_pdsch; k++) { + for (int k = 0; k < idx; k++) { dl_ch[k] = c16mulShift(dl_ch[k], dl_inv_delay_table[k], 8); noise_amp2 += c16amp2(c16sub(dl_ls_est[k], dl_ch[k])); nest_count++; @@ -1256,6 +1271,7 @@ void NFAPI_NR_DMRS_TYPE2_average_prb(NR_DL_FRAME_PARMS *frame_parms, void nr_pdsch_channel_estimation(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, const fapi_nr_dl_config_dlsch_pdu_rel15_t *dlsch, + const freq_alloc_bitmap_t *freq_alloc, int nl, unsigned short p, unsigned char symbol, @@ -1270,7 +1286,7 @@ void nr_pdsch_channel_estimation(PHY_VARS_NR_UE *ue, NR_DL_FRAME_PARMS *fp = &ue->frame_parms; const int ch_offset = fp->ofdm_symbol_size * symbol; const int symbol_offset = fp->ofdm_symbol_size * symbol; - int bwp_start_subcarrier = ue->frame_parms.first_carrier_offset + (dlsch->BWPStart + dlsch->start_rb) * 12; + int bwp_start_subcarrier = fp->first_carrier_offset + (dlsch->BWPStart + freq_alloc->start) * 12; #ifdef DEBUG_PDSCH printf( @@ -1287,8 +1303,8 @@ void nr_pdsch_channel_estimation(PHY_VARS_NR_UE *ue, // generate pilot for gNB port number 1000+p int config_type = dlsch->dmrsConfigType; - int rb_offset = dlsch->start_rb + (dlsch->refPoint ? 0 : dlsch->BWPStart); - int nb_rb_pdsch = dlsch->number_rbs; + int rb_offset = freq_alloc->start + (dlsch->refPoint ? 0 : dlsch->BWPStart); + int nb_rb_pdsch = freq_alloc->end - freq_alloc->start + 1; int8_t delta = get_delta(p, config_type); c16_t pilot[3280] __attribute__((aligned(16))); // Note: pilot returned by the following function is already the complex conjugate of the transmitted DMRS @@ -1311,7 +1327,8 @@ void nr_pdsch_channel_estimation(PHY_VARS_NR_UE *ue, memset(dl_ch, 0, sizeof(*dl_ch) * fp->ofdm_symbol_size); if (config_type == NFAPI_NR_DMRS_TYPE1 && ue->chest_freq == 0) { - NFAPI_NR_DMRS_TYPE1_linear_interp(&ue->frame_parms, + NFAPI_NR_DMRS_TYPE1_linear_interp(fp, + freq_alloc, rxF, &pilot[6 * rb_offset], dl_ch, @@ -1322,6 +1339,7 @@ void nr_pdsch_channel_estimation(PHY_VARS_NR_UE *ue, } else if (config_type == NFAPI_NR_DMRS_TYPE2 && ue->chest_freq == 0) { NFAPI_NR_DMRS_TYPE2_linear_interp(fp, + freq_alloc, rxF, &pilot[4 * rb_offset], dl_ch, @@ -1331,9 +1349,11 @@ void nr_pdsch_channel_estimation(PHY_VARS_NR_UE *ue, nvar); } else if (config_type == NFAPI_NR_DMRS_TYPE1) { + AssertFatal(dlsch->resource_alloc == 1, "PRB average in channel estimation not supported for type0 DLSCH\n"); NFAPI_NR_DMRS_TYPE1_average_prb(fp, rxF, &pilot[6 * rb_offset], dl_ch, bwp_start_subcarrier, nb_rb_pdsch); } else { + AssertFatal(dlsch->resource_alloc == 1, "PRB average in channel estimation not supported for type0 DLSCH\n"); NFAPI_NR_DMRS_TYPE2_average_prb(fp, rxF, &pilot[4 * rb_offset], dl_ch, bwp_start_subcarrier, nb_rb_pdsch); } diff --git a/openair1/PHY/NR_UE_ESTIMATION/nr_estimation.h b/openair1/PHY/NR_UE_ESTIMATION/nr_estimation.h index 09ed452830..9f38b49903 100644 --- a/openair1/PHY/NR_UE_ESTIMATION/nr_estimation.h +++ b/openair1/PHY/NR_UE_ESTIMATION/nr_estimation.h @@ -81,6 +81,7 @@ int nr_pbch_channel_estimation(const NR_DL_FRAME_PARMS *fp, void nr_pdsch_channel_estimation(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, const fapi_nr_dl_config_dlsch_pdu_rel15_t *dlsch, + const freq_alloc_bitmap_t *freq_alloc, int nl, unsigned short p, unsigned char symbol, diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h index 0c519451a5..6eaa0ecec1 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h @@ -67,7 +67,6 @@ typedef struct pdsch_scope_req_s { /** \brief This function initialises structures for DLSCH at UE */ void nr_ue_dlsch_init(NR_UE_DLSCH_t *dlsch_list, int num_dlsch, uint8_t max_ldpc_iterations); - void nr_conjch0_mult_ch1(c16_t *ch0, c16_t *ch1, c16_t *ch0conj_ch1, unsigned short nb_rb, unsigned char output_shift0); /** \brief This is the alternative top-level entry point for DLSCH decoding in UE. diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_ue.h b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_ue.h index 26f41b1fd3..67d5f45cef 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_ue.h +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_ue.h @@ -38,6 +38,12 @@ #include "nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h" #include "../NR_TRANSPORT/nr_transport_common_proto.h" +typedef struct { + int start; + int end; + uint8_t bitmap[36]; +} freq_alloc_bitmap_t; + typedef struct { /// Index of current HARQ round for this ULSCH uint8_t round; diff --git a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c index 8d56cf65ff..d442bc6207 100644 --- a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c +++ b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c @@ -577,6 +577,43 @@ int nr_ue_pdcch_procedures(PHY_VARS_NR_UE *ue, return (dci_ind.number_of_dcis); } +static freq_alloc_bitmap_t set_start_end_from_bitmap(int size, int alloc_size, const uint8_t bitmap[alloc_size]) +{ + freq_alloc_bitmap_t alloc = { + .start = size, + .end = 0 + }; + + for (int start = 0; start < size; start++) { + if ((bitmap[start / 8] >> start % 8) & 0x1) { + alloc.start = start; + break; + } + } + AssertFatal(alloc.start < size, "Frequency allocation bitmap empty\n"); + for (int end = size - 1; end > 0; end--) { + if ((bitmap[end / 8] >> end % 8) & 0x1) { + alloc.end = end; + break; + } + } + AssertFatal(alloc.end > 0, "Frequency allocation bitmap empty\n"); + memcpy(alloc.bitmap, bitmap, alloc_size * sizeof(uint8_t)); + return alloc; +} + +static freq_alloc_bitmap_t set_bitmap_from_start_size(int start, int size) +{ + freq_alloc_bitmap_t alloc = { + .start = start, + .end = start + size - 1 + }; + memset(alloc.bitmap, 0, 36 * sizeof(uint8_t)); + for (int i = start; i < size + start; i++) + alloc.bitmap[i / 8] += 1 << (i % 8); + return alloc; +} + static int nr_ue_pdsch_procedures(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, NR_UE_DLSCH_t dlsch[2], @@ -595,8 +632,15 @@ static int nr_ue_pdsch_procedures(PHY_VARS_NR_UE *ue, // dlsch0_harq contains the previous transmissions data for this harq pid NR_DL_UE_HARQ_t *dlsch0_harq = &ue->dl_harq_processes[0][harq_pid]; + freq_alloc_bitmap_t freq_alloc = {0}; + if (dlschCfg->resource_alloc == 0) { + int alloc_size = (dlschCfg->BWPSize / 8) + (dlschCfg->BWPSize % 8 > 0); + freq_alloc = set_start_end_from_bitmap(dlschCfg->BWPSize, alloc_size, dlschCfg->rb_bitmap); + } else + freq_alloc = set_bitmap_from_start_size(dlschCfg->start_rb, dlschCfg->number_rbs); + LOG_D(PHY, - "[UE %d] frame_rx %d, nr_slot_rx %d, harq_pid %d (%d), BWP start %d, rb_start %d, nb_rb %d, symbol_start %d, nb_symbols %d, DMRS mask " + "[UE %d] frame_rx %d, nr_slot_rx %d, harq_pid %d (%d), BWP start %d, start RB %d, end RB %d, symbol_start %d, nb_symbols %d, DMRS mask " "%x, Nl %d\n", ue->Mod_id, frame_rx, @@ -604,8 +648,8 @@ static int nr_ue_pdsch_procedures(PHY_VARS_NR_UE *ue, harq_pid, dlsch0_harq->status, dlschCfg->BWPStart, - dlschCfg->start_rb, - dlschCfg->number_rbs, + freq_alloc.start, + freq_alloc.end, dlschCfg->start_symbol, dlschCfg->number_symbols, dlschCfg->dlDmrsSymbPos, @@ -642,6 +686,7 @@ static int nr_ue_pdsch_procedures(PHY_VARS_NR_UE *ue, nr_pdsch_channel_estimation(ue, proc, dlschCfg, + &freq_alloc, nl, get_dmrs_port(nl, dlschCfg->dmrs_ports), m,