diff --git a/openair1/PHY/INIT/nr_init_ue.c b/openair1/PHY/INIT/nr_init_ue.c index 39e99e6ec3..45d003ac0a 100644 --- a/openair1/PHY/INIT/nr_init_ue.c +++ b/openair1/PHY/INIT/nr_init_ue.c @@ -604,6 +604,9 @@ void phy_init_nr_ue__PDSCH(NR_UE_PDSCH *const pdsch, //pdsch->dl_ch_rho2_ext = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) ); pdsch->dl_ch_mag0 = (int32_t **)malloc16_clear( 8*sizeof(int32_t *) ); pdsch->dl_ch_magb0 = (int32_t **)malloc16_clear( 8*sizeof(int32_t *) ); + pdsch->ptrs_phase_per_slot = (int32_t **)malloc16_clear( 8*sizeof(int32_t *) ); + pdsch->ptrs_re_per_slot = (int32_t **)malloc16_clear( 8*sizeof(int32_t *) ); + pdsch->dl_ch_ptrs_estimates_ext = (int32_t **)malloc16_clear( 8*sizeof(int32_t *) ); // the allocated memory size is fixed: AssertFatal( fp->nb_antennas_rx <= 2, "nb_antennas_rx > 2" ); @@ -624,6 +627,9 @@ void phy_init_nr_ue__PDSCH(NR_UE_PDSCH *const pdsch, //pdsch->dl_ch_rho2_ext[idx] = (int32_t*)malloc16_clear( sizeof(int32_t) * num ); pdsch->dl_ch_mag0[idx] = (int32_t *)malloc16_clear( sizeof(int32_t) * num ); pdsch->dl_ch_magb0[idx] = (int32_t *)malloc16_clear( sizeof(int32_t) * num ); + pdsch->ptrs_re_per_slot[idx] = (int32_t *)malloc16_clear(sizeof(int32_t) * 14); + pdsch->ptrs_phase_per_slot[idx] = (int32_t *)malloc16_clear( sizeof(int32_t) * 14 ); + pdsch->dl_ch_ptrs_estimates_ext[idx]= (int32_t *)malloc16_clear( sizeof(int32_t) * num); } } } diff --git a/openair1/PHY/NR_REFSIG/ptrs_nr.c b/openair1/PHY/NR_REFSIG/ptrs_nr.c index 785252126a..1dba1b6c16 100644 --- a/openair1/PHY/NR_REFSIG/ptrs_nr.c +++ b/openair1/PHY/NR_REFSIG/ptrs_nr.c @@ -34,7 +34,7 @@ #include #include "dmrs_nr.h" #include "PHY/NR_REFSIG/ptrs_nr.h" - +#include "PHY/NR_REFSIG/nr_refsig.h" /***********************************************************************/ @@ -180,93 +180,265 @@ uint8_t is_ptrs_subcarrier(uint16_t k, return 0; } - -/* -int main(int argc, char const *argv[]) +/* return the total number of ptrs symbol in a slot */ +uint8_t get_ptrs_symbols_in_slot(uint16_t l_prime_mask, uint16_t start_symb, uint16_t nb_symb) { - - dmrs_UplinkConfig_t dmrs_Uplink_Config; - ptrs_UplinkConfig_t ptrs_Uplink_Config; - uint8_t resourceElementOffset; - uint8_t dmrs_antenna_port; - uint8_t L_ptrs, K_ptrs; - int16_t k_RE_ref; - uint16_t N_RB, ptrs_symbols, ofdm_symbol_size, k; - uint8_t duration_in_symbols, I_mcs; - uint8_t start_symbol, l; - uint8_t ptrs_symbol_flag; - uint16_t n_rnti; - - dmrs_Uplink_Config.pusch_dmrs_type = pusch_dmrs_type1; - dmrs_Uplink_Config.pusch_dmrs_AdditionalPosition = pusch_dmrs_pos1; - dmrs_Uplink_Config.pusch_maxLength = pusch_len2; - - ptrs_Uplink_Config.timeDensity.ptrs_mcs1 = 0; // setting MCS values to 0 indicate abscence of time_density field in the configuration - ptrs_Uplink_Config.timeDensity.ptrs_mcs2 = 0; - ptrs_Uplink_Config.timeDensity.ptrs_mcs3 = 0; - ptrs_Uplink_Config.frequencyDensity.n_rb0 = 0; // setting N_RB values to 0 indicate abscence of frequency_density field in the configuration - ptrs_Uplink_Config.frequencyDensity.n_rb1 = 0; - ptrs_Uplink_Config.resourceElementOffset = 0; - - n_rnti = 0x1234; - resourceElementOffset = 0; - ptrs_symbols = 0; - dmrs_antenna_port = 0; - N_RB = 50; - duration_in_symbols = 14; - ofdm_symbol_size = 2048; - I_mcs = 9; - start_symbol = 0; - ptrs_symbol_flag = 0; - - k_RE_ref = get_kRE_ref(dmrs_antenna_port, dmrs_Uplink_Config.pusch_dmrs_type, resourceElementOffset); - - K_ptrs = get_K_ptrs(&ptrs_Uplink_Config, N_RB); - - L_ptrs = get_L_ptrs(&ptrs_Uplink_Config, I_mcs); - - set_ptrs_symb_idx(&ptrs_symbols, - &ptrs_Uplink_Config, - &dmrs_Uplink_Config, - 1, - duration_in_symbols, - start_symbol, - L_ptrs, - ofdm_symbol_size); - - printf("PTRS OFDM symbol indicies: "); - - for (l = start_symbol; l < start_symbol + duration_in_symbols; l++){ - - ptrs_symbol_flag = is_ptrs_symbol(l, - 0, - n_rnti, - N_RB, - duration_in_symbols, - dmrs_antenna_port, - K_ptrs, - ptrs_symbols, - dmrs_Uplink_Config.pusch_dmrs_type, - &ptrs_Uplink_Config); - - if (ptrs_symbol_flag == 1) - printf(" %d ", l); - + uint8_t tmp = 0; + for (int i = start_symb; i <= nb_symb; i++) + { + tmp += (l_prime_mask >> i) & 0x01; } + return tmp; +} - printf("\n"); - - printf("PTRS subcarrier indicies: "); - - for (k = 0; k < N_RB*12; k++){ - - if (is_ptrs_subcarrier(k, K_ptrs, n_rnti, N_RB, k_RE_ref) == 1) - printf(" %d ", k); - +/* return the position of next ptrs symbol in a slot */ +uint8_t get_next_ptrs_symbol_in_slot(uint16_t ptrs_symb_pos, uint8_t counter, uint8_t nb_symb) +{ + for(uint8_t symbol = counter; symbol < nb_symb; symbol++) + { + if((ptrs_symb_pos >>symbol)&0x01 ) + { + return symbol; + } } - - printf("\n"); - return 0; } -*/ + +/* get the next nearest estimate from DMRS or PTRS */ +uint8_t get_next_estimate_in_slot(uint16_t ptrsSymbPos,uint16_t dmrsSymbPos, uint8_t counter,uint8_t nb_symb) +{ + uint8_t nextPtrs = get_next_ptrs_symbol_in_slot(ptrsSymbPos, counter,nb_symb); + uint8_t nextDmrs = get_next_dmrs_symbol_in_slot(dmrsSymbPos, counter,nb_symb); + if(nextDmrs == 0) + { + return nextPtrs; + } + return (nextPtrs > nextDmrs)?nextDmrs:nextPtrs; +} + +/******************************************************************* + * + * NAME : nr_ptrs_cpe_estimation + * + * PARAMETERS : K_ptrs : K value for PTRS + * ptrsReOffset : RE offset for PTRS + * dmrsConfigType: DMRS configuration type + * nb_rb : No. of resource blocks + * rnti : RNTI + * ptrs_ch_p : pointer to ptrs channel structure + * Ns : + * symbol : OFDM symbol + * ofdm_symbol_size: OFDM Symbol Size + * rxF_comp : pointer to channel compensated signal + * gold_seq : Gold sequence pointer + * error_est : Estimated error output vector [Re Im] + * ptrs_sc : Total PTRS RE in a symbol + * RETURN : nothing + * + * DESCRIPTION : + * perform phase estimation from regenerated PTRS SC and channel compensated + * signal + *********************************************************************/ +void nr_ptrs_cpe_estimation(uint8_t K_ptrs, + uint8_t ptrsReOffset, + uint8_t dmrsConfigType, + uint16_t nb_rb, + uint16_t rnti, + int16_t *ptrs_ch_p, + unsigned char Ns, + unsigned char symbol, + uint16_t ofdm_symbol_size, + int16_t *rxF_comp, + uint32_t *gold_seq, + int16_t *error_est, + int32_t *ptrs_sc) +{ +//#define DEBUG_PTRS 1 + uint8_t is_ptrs_re = 0; + uint16_t re_cnt = 0; + uint16_t cnt = 0; + unsigned short nb_re_pdsch = NR_NB_SC_PER_RB * nb_rb; + uint16_t sc_per_symbol = (nb_rb + K_ptrs - 1)/K_ptrs; + int16_t *ptrs_p = (int16_t *)malloc(sizeof(int32_t)*(sc_per_symbol)); + int16_t *dmrs_comp_p = (int16_t *)malloc(sizeof(int32_t)*(sc_per_symbol)); + double abs = 0.0; + double real = 0.0; + double imag = 0.0; +#ifdef DEBUG_PTRS + double alpha = 0; +#endif + /* generate PTRS RE for the symbol */ + nr_gen_ref_conj_symbols(gold_seq,sc_per_symbol*2,ptrs_p, NR_MOD_TABLE_QPSK_OFFSET,2);// 2 for QPSK + + /* loop over all sub carriers to get compensated RE on ptrs symbols*/ + for (int re = 0; re < nb_re_pdsch; re++) + { + is_ptrs_re = is_ptrs_subcarrier(re, + rnti, + 0, + dmrsConfigType, + K_ptrs, + nb_rb, + ptrsReOffset, + 0,// start_re is 0 here + ofdm_symbol_size); + if(is_ptrs_re) + { + dmrs_comp_p[re_cnt*2] = rxF_comp[re *2]; + dmrs_comp_p[(re_cnt*2)+1] = rxF_comp[(re *2)+1]; + re_cnt++; + } + else + { + /* Skip PTRS symbols and keep data in a continuous vector */ + rxF_comp[cnt *2]= rxF_comp[re *2]; + rxF_comp[(cnt *2)+1]= rxF_comp[(re *2)+1]; + cnt++; + } + }/* RE loop */ + /* update the total ptrs RE in a symbol */ + *ptrs_sc = re_cnt; + + /*Multiple compensated data with conj of PTRS */ + mult_cpx_vector(dmrs_comp_p, ptrs_p, ptrs_ch_p,(1 + sc_per_symbol/4)*4,15); // 2^15 shifted + + /* loop over all ptrs sub carriers in a symbol */ + /* sum the error vector */ + for(int i = 0;i < sc_per_symbol; i++) + { + real+= ptrs_ch_p[(2*i)]; + imag+= ptrs_ch_p[(2*i)+1]; + } +#ifdef DEBUG_PTRS + alpha = atan(imag/real); + printf("[PHY][PTRS]: Symbol %d atan(Im,real):= %f \n",symbol, alpha ); +#endif + /* mean */ + real /= sc_per_symbol; + imag /= sc_per_symbol; + /* absolute calculation */ + abs = sqrt(((real * real) + (imag * imag))); + /* normalized error estimation */ + error_est[0]= (real / abs)*(1<<15); + /* compensation in given by conjugate of estimated phase (e^-j*2*pi*fd*t)*/ + error_est[1]= (-1)*(imag / abs)*(1<<15); +#ifdef DEBUG_PTRS + printf("[PHY][PTRS]: Estimated Symbol %d -> %d + j* %d \n",symbol, error_est[0], error_est[1] ); +#endif + /* free vectors */ + free(ptrs_p); + free(dmrs_comp_p); +} + + +/******************************************************************* + * + * NAME : nr_ptrs_process_slot + * + * PARAMETERS : dmrsSymbPos DMRS symbol index mask per slot + * ptrsSymbpos PTRS symbol index mask per slot + * estPerSymb Estimated CPE pointer + * startSymbIdx First symbol index in a slot + * noSymb total number of OFDM symbols in a slot + * RETURN : True if slot is process correctly + * DESCRIPTION : + * Process whole slot and interpolate or extrapolate estimation for the symbols + * where there is neither PTRS nor DMRS configured + * + *********************************************************************/ +int8_t nr_ptrs_process_slot(uint16_t dmrsSymbPos, + uint16_t ptrsSymbPos, + int16_t *estPerSymb, + uint16_t startSymbIdx, + uint16_t noSymb) +{ + int32_t slope = 0; + int16_t *slope_p = (int16_t*)&slope; + uint8_t symbInSlot = startSymbIdx + noSymb; + uint8_t rightRef = 0; + uint8_t leftRef = 0; + uint8_t tmp = 0; + for(uint8_t symb = startSymbIdx; symb %4d %4d from Slope (%4d %4d)\n", start+i,error_est[(start+i)*2],error_est[((start +i)*2)+1], + slope_p[0],slope_p[1]); +#endif + } +} diff --git a/openair1/PHY/NR_REFSIG/ptrs_nr.h b/openair1/PHY/NR_REFSIG/ptrs_nr.h index e8a4e61232..d83ab662e9 100644 --- a/openair1/PHY/NR_REFSIG/ptrs_nr.h +++ b/openair1/PHY/NR_REFSIG/ptrs_nr.h @@ -80,6 +80,31 @@ uint8_t is_ptrs_subcarrier(uint16_t k, static inline uint8_t is_ptrs_symbol(uint8_t l, uint16_t ptrs_symbols) { return ((ptrs_symbols >> l) & 1); } +uint8_t get_ptrs_symbols_in_slot(uint16_t l_prime_mask, uint16_t start_symb, uint16_t nb_symb); +uint8_t get_next_ptrs_symbol_in_slot(uint16_t ptrsSymbPos, uint8_t counter, uint8_t nb_symb); +uint8_t get_next_estimate_in_slot(uint16_t ptrsSymbPos,uint16_t dmrsSymbPos, uint8_t counter,uint8_t nb_symb); +void get_slope_from_estimates(uint8_t leftSide, uint8_t rightSide, int16_t *est_p, int16_t *slope_p); +int8_t nr_ptrs_process_slot(uint16_t dmrsSymbPos, + uint16_t ptrsSymbPos, + int16_t *estPerSymb, + uint16_t startSymbIdx, + uint16_t noSymb + ); +/* general function to estimate common phase error based upon PTRS */ +void nr_ptrs_cpe_estimation(uint8_t K_ptrs, + uint8_t ptrsReOffset, + uint8_t dmrsConfigType, + uint16_t nb_rb, + uint16_t rnti, + int16_t *ptrs_ch_p, + unsigned char Ns, + unsigned char symbol, + uint16_t ofdm_symbol_size, + int16_t *rxF_comp, + uint32_t *gold_seq, + int16_t *error_est, + int32_t *ptrs_sc); - +void get_slope_from_estimates(uint8_t start, uint8_t end, int16_t *est_p, int16_t *slope_p); +void ptrs_estimate_from_slope(int16_t *error_est, int16_t *slope_p, uint8_t start, uint8_t end); #endif /* PTRS_NR_H */ 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 fac8b9dede..5890dd63c5 100644 --- a/openair1/PHY/NR_UE_ESTIMATION/nr_dl_channel_estimation.c +++ b/openair1/PHY/NR_UE_ESTIMATION/nr_dl_channel_estimation.c @@ -24,6 +24,8 @@ #include "SCHED_NR_UE/defs.h" #include "nr_estimation.h" #include "PHY/NR_REFSIG/refsig_defs_ue.h" +#include "PHY/NR_REFSIG/nr_refsig.h" +#include "PHY/NR_REFSIG/ptrs_nr.h" #include "filt16a_32.h" //#define DEBUG_PDSCH @@ -937,3 +939,171 @@ int nr_pdsch_channel_estimation(PHY_VARS_NR_UE *ue, return(0); } +/******************************************************************* + * + * NAME : nr_pdsch_ptrs_processing + * + * PARAMETERS : ue : ue data structure + * NR_UE_PDSCH : pdsch_vars pointer + * NR_DL_FRAME_PARMS : frame_parms pointer + * NR_DL_UE_HARQ_t : dlsch0_harq pointer + * NR_DL_UE_HARQ_t : dlsch1_harq pointer + * uint8_t : eNB_id, + * uint8_t : nr_tti_rx, + * unsigned char : symbol, + * uint32_t : nb_re_pdsch, + * unsigned char : harq_pid + * uint16_t : rnti + * RX_type_t : rx_type + * RETURN : Nothing + * + * DESCRIPTION : + * If ptrs is enabled process the symbol accordingly + * 1) Estimate common phase error per PTRS symbol + * 2) Interpolate PTRS estimated value in TD after all PTRS symbols + * 3) Compensate signal with PTRS estimation for slot + *********************************************************************/ +void nr_pdsch_ptrs_processing(PHY_VARS_NR_UE *ue, + NR_UE_PDSCH **pdsch_vars, + NR_DL_FRAME_PARMS *frame_parms, + NR_DL_UE_HARQ_t *dlsch0_harq, + NR_DL_UE_HARQ_t *dlsch1_harq, + uint8_t eNB_id, + uint8_t nr_tti_rx, + unsigned char symbol, + uint32_t nb_re_pdsch, + unsigned char harq_pid, + uint16_t rnti, + RX_type_t rx_type) +{ + //#define DEBUG_DL_PTRS 1 + int16_t *phase_per_symbol = NULL; + int32_t *ptrs_re_symbol = NULL; + int8_t ret = 0; + /* harq specific variables */ + uint8_t symbInSlot = 0; + uint16_t *startSymbIndex = NULL; + uint16_t *nbSymb = NULL; + uint8_t *L_ptrs = NULL; + uint8_t *K_ptrs = NULL; + uint16_t *dmrsSymbPos = NULL; + uint16_t *ptrsSymbPos = NULL; + uint8_t *ptrsSymbIdx = NULL; + uint8_t *ptrsReOffset = NULL; + uint8_t *dmrsConfigType = NULL; + uint16_t *nb_rb = NULL; + + if(dlsch0_harq->status == ACTIVE) + { + symbInSlot = dlsch0_harq->start_symbol + dlsch0_harq->nb_symbols; + startSymbIndex = &dlsch0_harq->start_symbol; + nbSymb = &dlsch0_harq->nb_symbols; + L_ptrs = &dlsch0_harq->PTRSTimeDensity; + K_ptrs = &dlsch0_harq->PTRSFreqDensity; + dmrsSymbPos = &dlsch0_harq->dlDmrsSymbPos; + ptrsSymbPos = &dlsch0_harq->ptrs_symbols; + ptrsSymbIdx = &dlsch0_harq->ptrs_symbol_index; + ptrsReOffset = &dlsch0_harq->PTRSReOffset; + dmrsConfigType = &dlsch0_harq->ptrs_symbol_index; + nb_rb = &dlsch0_harq->nb_rb; + } + if(dlsch1_harq) + { + symbInSlot = dlsch1_harq->start_symbol + dlsch0_harq->nb_symbols; + startSymbIndex = &dlsch1_harq->start_symbol; + nbSymb = &dlsch1_harq->nb_symbols; + L_ptrs = &dlsch1_harq->PTRSTimeDensity; + K_ptrs = &dlsch1_harq->PTRSFreqDensity; + dmrsSymbPos = &dlsch1_harq->dlDmrsSymbPos; + ptrsSymbPos = &dlsch1_harq->ptrs_symbols; + ptrsSymbIdx = &dlsch1_harq->ptrs_symbol_index; + ptrsReOffset = &dlsch1_harq->PTRSReOffset; + dmrsConfigType = &dlsch1_harq->ptrs_symbol_index; + nb_rb = &dlsch1_harq->nb_rb; + } + /* loop over antennas */ + for (int aarx=0; aarxnb_antennas_rx; aarx++) + { + phase_per_symbol = (int16_t*)pdsch_vars[eNB_id]->ptrs_phase_per_slot[aarx]; + ptrs_re_symbol = (int32_t*)pdsch_vars[eNB_id]->ptrs_re_per_slot[aarx]; + ptrs_re_symbol[symbol] = 0; + phase_per_symbol[2*symbol] = 0; // Real + phase_per_symbol[(2*symbol)+1] = 0; // Imag + if(dlsch0_harq->status == ACTIVE) + { + if(symbol == *startSymbIndex) + { + *ptrsSymbPos = 0; + set_ptrs_symb_idx(ptrsSymbPos, + *nbSymb, + *startSymbIndex, + 1<< *L_ptrs, + *dmrsSymbPos); + } + /* if not PTRS symbol set current ptrs symbol index to zero*/ + *ptrsSymbIdx = 0; + /* Check if current symbol contains PTRS */ + if(is_ptrs_symbol(symbol, *ptrsSymbPos)) + { + *ptrsSymbIdx = symbol; + /*------------------------------------------------------------------------------------------------------- */ + /* 1) Estimate common phase error per PTRS symbol */ + /*------------------------------------------------------------------------------------------------------- */ + nr_ptrs_cpe_estimation(*K_ptrs,*ptrsReOffset,*dmrsConfigType,*nb_rb, + rnti, + (int16_t *)&pdsch_vars[eNB_id]->dl_ch_ptrs_estimates_ext[aarx][symbol*nb_re_pdsch], + nr_tti_rx, + symbol,frame_parms->ofdm_symbol_size, + (int16_t*)&pdsch_vars[eNB_id]->rxdataF_comp0[aarx][(symbol * nb_re_pdsch)], + ue->nr_gold_pdsch[eNB_id][nr_tti_rx][symbol], + &phase_per_symbol[2* symbol], + &ptrs_re_symbol[symbol]); + /* if very first symbol is PTRS then we need to undo conjugate done in estimation */ + if(symbol == *startSymbIndex) + { + phase_per_symbol[(2* symbol)+1] = (-1) * phase_per_symbol[(2* symbol)+1]; + } + } + }// HARQ 0 + + /* For last OFDM symbol at each antenna perform interpolation and compensation for the slot*/ + if(symbol == (symbInSlot -1)) + { + /*------------------------------------------------------------------------------------------------------- */ + /* 2) Interpolate PTRS estimated value in TD */ + /*------------------------------------------------------------------------------------------------------- */ + /* If L-PTRS is > 0 then we need interpolation */ + if(*L_ptrs > 0) + { + ret = nr_ptrs_process_slot(*dmrsSymbPos, *ptrsSymbPos, phase_per_symbol, *startSymbIndex, *nbSymb); + if(ret != 0) + { + LOG_W(PHY,"[PTRS] Compensation is skipped due to error in PTRS slot processing !!\n"); + } + } +#ifdef DEBUG_DL_PTRS + LOG_M("ptrsEst.m","est",pdsch_vars[eNB_id]->ptrs_phase_per_slot[aarx],frame_parms->symbols_per_slot,1,1 ); + LOG_M("rxdataF_bf_ptrs_comp.m","bf_ptrs_cmp", + &pdsch_vars[eNB_id]->rxdataF_comp0[aarx][(*startSymbIndex) * NR_NB_SC_PER_RB * (*nb_rb) ], + (*nb_rb) * NR_NB_SC_PER_RB * (*nbSymb),1,1); +#endif + /*------------------------------------------------------------------------------------------------------- */ + /* 3) Compensated DMRS based estimated signal with PTRS estimation */ + /*--------------------------------------------------------------------------------------------------------*/ + for(uint8_t i = *startSymbIndex; i< symbInSlot ;i++) + { + /* DMRS Symbol has 0 phase so no need to rotate the respective symbol */ + if(!is_dmrs_symbol(i,*dmrsSymbPos)) + { +#ifdef DEBUG_DL_PTRS + printf("[PHY][DL][PTRS]: Rotate Symbol %2d with %d + j* %d\n", i, phase_per_symbol[2* i],phase_per_symbol[(2* i) +1]); +#endif + rotate_cpx_vector((int16_t*)&pdsch_vars[eNB_id]->rxdataF_comp0[aarx][(i * (*nb_rb) * NR_NB_SC_PER_RB)], + &phase_per_symbol[2* i], + (int16_t*)&pdsch_vars[eNB_id]->rxdataF_comp0[aarx][(i * (*nb_rb) * NR_NB_SC_PER_RB)], + ((*nb_rb) * NR_NB_SC_PER_RB), 15); + }// if not DMRS Symbol + }// symbol loop + }// last symbol check + }//Antenna loop +}//main function diff --git a/openair1/PHY/NR_UE_ESTIMATION/nr_estimation.h b/openair1/PHY/NR_UE_ESTIMATION/nr_estimation.h index 1837664391..40e1f11802 100644 --- a/openair1/PHY/NR_UE_ESTIMATION/nr_estimation.h +++ b/openair1/PHY/NR_UE_ESTIMATION/nr_estimation.h @@ -93,5 +93,17 @@ void phy_adjust_gain_nr(PHY_VARS_NR_UE *ue, int16_t get_nr_PL(uint8_t Mod_id, uint8_t CC_id, uint8_t gNB_index); +void nr_pdsch_ptrs_processing(PHY_VARS_NR_UE *ue, + NR_UE_PDSCH **pdsch_vars, + NR_DL_FRAME_PARMS *frame_parms, + NR_DL_UE_HARQ_t *dlsch0_harq, + NR_DL_UE_HARQ_t *dlsch1_harq, + uint8_t eNB_id, + uint8_t nr_tti_rx, + unsigned char symbol, + uint32_t nb_re_pdsch, + unsigned char harq_pid, + uint16_t rnti, + RX_type_t rx_type); #endif diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c index 953bd8070a..601c60b7b4 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c @@ -37,6 +37,7 @@ //#include "extern.h" #include "PHY/sse_intrin.h" #include "T.h" +#include "openair1/PHY/NR_UE_ESTIMATION/nr_estimation.h" #include "openair1/PHY/NR_TRANSPORT/nr_dlsch.h" #ifndef USER_MODE @@ -140,12 +141,10 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue, NR_DL_FRAME_PARMS *frame_parms = &ue->frame_parms; PHY_NR_MEASUREMENTS *measurements = &ue->measurements; NR_UE_DLSCH_t **dlsch; - uint16_t startSymbIdx=0; - uint16_t nbSymb=0; - + int avg[4]; -// int avg_0[2]; -// int avg_1[2]; + // int avg_0[2]; + // int avg_1[2]; #if UE_TIMING_TRACE uint8_t slot = 0; @@ -174,6 +173,9 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue, uint16_t n_tx=1, n_rx=1; int32_t median[16]; uint32_t len; + uint16_t startSymbIdx=0; + uint16_t nbSymb=0; + uint16_t pduBitmap=0x0; switch (type) { case SI_PDSCH: @@ -693,49 +695,56 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue, { startSymbIdx = dlsch0_harq->start_symbol; nbSymb = dlsch0_harq->nb_symbols; + pduBitmap = dlsch0_harq->pduBitmap; } if(dlsch1_harq) { startSymbIdx = dlsch1_harq->start_symbol; nbSymb = dlsch1_harq->nb_symbols; + pduBitmap = dlsch1_harq->pduBitmap; } - //printf("LLR dlsch0_harq->Qm %d rx_type %d cw0 %d cw1 %d symbol %d \n",dlsch0_harq->Qm,rx_type,codeword_TB0,codeword_TB1,symbol); - // compute LLRs - // -> // compute @pointer where llrs should filled for this ofdm-symbol + + /* Check for PTRS bitmap and process it respectively */ + if((pduBitmap & 0x1) && (type == PDSCH)) + { + nr_pdsch_ptrs_processing(ue, + pdsch_vars, + frame_parms, + dlsch0_harq, dlsch1_harq, + eNB_id, nr_tti_rx, + symbol, (nb_rb*12), + harq_pid, + dlsch[0]->rnti,rx_type); + pdsch_vars[eNB_id]->dl_valid_re[symbol-1] -= pdsch_vars[eNB_id]->ptrs_re_per_slot[0][symbol]; + } + + /* at last symbol in a slot calculate LLR's for whole slot */ if(symbol == (startSymbIdx + nbSymb -1)) { for(uint8_t i =startSymbIdx; i <= nbSymb;i++) { /* re evaluating the first symbol flag as LLR's are done in symbol loop */ if(i == startSymbIdx && i < 3) - { - first_symbol_flag =1; - } + { + first_symbol_flag =1; + } else - { - first_symbol_flag=0; - } - /* Calculate LLR's for ech symbol */ - nr_dlsch_llr(pdsch_vars, - frame_parms, - rxdataF_comp_ptr, - dl_ch_mag_ptr, - dlsch0_harq, - dlsch1_harq, - rx_type, - harq_pid, - eNB_id, - eNB_id_i, + { + first_symbol_flag=0; + } + /* Calculate LLR's for each symbol */ + nr_dlsch_llr(pdsch_vars, frame_parms, + rxdataF_comp_ptr, dl_ch_mag_ptr, + dlsch0_harq, dlsch1_harq, + rx_type, harq_pid, + eNB_id, eNB_id_i, first_symbol_flag, - i, - nb_rb, - round, - codeword_TB0, - codeword_TB1, + i, nb_rb, round, + codeword_TB0, codeword_TB1, pdsch_vars[eNB_id]->dl_valid_re[i-1], - nr_tti_rx, - beamforming_mode); + nr_tti_rx, beamforming_mode); } + //nr_dlsch_deinterleaving(symbol,bundle_L,(int16_t*)pllr_symbol_cw0,(int16_t*)pllr_symbol_cw0_deint, nb_rb_pdsch); if (rx_type==rx_IC_dual_stream) { nr_dlsch_layer_demapping(pdsch_vars[eNB_id]->llr, diff --git a/openair1/SIMULATION/NR_PHY/dlsim.c b/openair1/SIMULATION/NR_PHY/dlsim.c index 79b5884a13..d4db1631ac 100644 --- a/openair1/SIMULATION/NR_PHY/dlsim.c +++ b/openair1/SIMULATION/NR_PHY/dlsim.c @@ -61,7 +61,7 @@ #include "openair1/SIMULATION/TOOLS/sim.h" #include "openair1/SIMULATION/NR_PHY/nr_unitary_defs.h" //#include "openair1/SIMULATION/NR_PHY/nr_dummy_functions.c" - +#include "PHY/NR_REFSIG/ptrs_nr.h" #include "NR_RRCReconfiguration.h" #define inMicroS(a) (((double)(a))/(cpu_freq_GHz*1000.0)) #include "SIMULATION/LTE_PHY/common_sim.h" @@ -143,8 +143,7 @@ int generate_dlsch_header(unsigned char *mac_header, // needed for some functions openair0_config_t openair0_cfg[MAX_CARDS]; - - +void update_ptrs_config(NR_CellGroupConfig_t *secondaryCellGroup, uint16_t *rbSize, uint8_t *mcsIndex, uint8_t *K_ptrs, uint8_t *L_ptrs); int main(int argc, char **argv) { @@ -214,6 +213,16 @@ int main(int argc, char **argv) int css_flag=0; cpuf = get_cpu_freq_GHz(); + int enable_ptrs = 0; + + /* L_PTRS = ptrs_arg[0], K_PTRS = ptrs_arg[1] */ + uint8_t ptrs_arg[2] = {-1,-1};// Invalid values + uint16_t ptrsRePerSymb = 0; + uint16_t pdu_bit_map = 0x0; + uint16_t dlPtrsSymPos = 0; + uint16_t ptrsSymbPerSlot = 0; + uint16_t rbSize = 106; + uint8_t mcsIndex = 9; if ( load_configmodule(argc,argv,CONFIG_ENABLECMDLINEONLY) == 0) { exit_fun("[NR_DLSIM] Error, configuration module init failed\n"); @@ -226,7 +235,7 @@ int main(int argc, char **argv) FILE *scg_fd=NULL; - while ((c = getopt (argc, argv, "f:hA:pf:g:i:j:n:s:S:t:x:y:z:M:N:F:GR:dPIL:Ea:b:e:m:w")) != -1) { + while ((c = getopt (argc, argv, "f:hA:pf:g:i:j:n:s:S:t:x:y:z:M:N:F:GR:dPIL:Ea:b:e:m:w:T:")) != -1) { switch (c) { case 'f': scg_fd = fopen(optarg,"r"); @@ -409,9 +418,16 @@ int main(int argc, char **argv) eff_tp_check = (float)atoi(optarg)/100; break; - case 'w': - output_fd = fopen("txdata.dat", "w+"); - break; + case 'w': + output_fd = fopen("txdata.dat", "w+"); + break; + + case 'T': + enable_ptrs=1; + for(i=0; i < atoi(optarg); i++){ + ptrs_arg[i] = atoi(argv[optind++]); + } + break; default: case 'h': @@ -443,6 +459,7 @@ int main(int argc, char **argv) printf("-j Number of symbols for PDSCH (fixed for now)\n"); printf("-e MSC index\n"); printf("-t Acceptable effective throughput (in percentage)\n"); + printf("-T Enable PTRS, arguments list L_PTRS{0,1,2} K_PTRS{2,4}, e.g. -T 2 0 2 \n"); printf("-P Print DLSCH performances\n"); printf("-w Write txdata to binary file (one frame)\n"); exit (-1); @@ -539,7 +556,14 @@ int main(int argc, char **argv) 0); fix_scc(scc,ssb_bitmap); - xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, (const void*)secondaryCellGroup); + /* -T option enable PTRS */ + if(enable_ptrs) + { + printf("[DLSIM] PTRS Enabled with L %d, K %d \n", 1<if_inst = NR_IF_Module_init(0))!=NULL,"Cannot register interface"); gNB->if_inst->NR_PHY_config_req = nr_phy_config_request; @@ -792,7 +816,22 @@ int main(int argc, char **argv) Sched_INFO.UL_dci_req = NULL; Sched_INFO.TX_req = &gNB_mac->TX_req[0]; nr_schedule_response(&Sched_INFO); - + + /* PTRS values for DLSIM calculations */ + nfapi_nr_dl_tti_request_body_t *dl_req = &gNB_mac->DL_req[Sched_INFO.CC_id].dl_tti_request_body; + nfapi_nr_dl_tti_request_pdu_t *dl_tti_pdsch_pdu = &dl_req->dl_tti_pdu_list[1]; + nfapi_nr_dl_tti_pdsch_pdu_rel15_t *pdsch_pdu_rel15 = &dl_tti_pdsch_pdu->pdsch_pdu.pdsch_pdu_rel15; + pdu_bit_map = pdsch_pdu_rel15->pduBitmap; + if(pdu_bit_map & 0x1){ + set_ptrs_symb_idx(&dlPtrsSymPos, + pdsch_pdu_rel15->NrOfSymbols, + pdsch_pdu_rel15->StartSymbolIndex, + 1<PTRSTimeDensity, + pdsch_pdu_rel15->dlDmrsSymbPos); + ptrsSymbPerSlot = get_ptrs_symbols_in_slot(dlPtrsSymPos, pdsch_pdu_rel15->StartSymbolIndex, pdsch_pdu_rel15->NrOfSymbols); + ptrsRePerSymb = ((rel15->rbSize + rel15->PTRSFreqDensity - 1)/rel15->PTRSFreqDensity); + printf("[DLSIM] PTRS Symbols in a slot: %2d, RE per Symbol: %3d, RE in a slot %4d\n", ptrsSymbPerSlot,ptrsRePerSymb, ptrsSymbPerSlot*ptrsRePerSymb ); + } if (run_initial_sync) nr_common_signal_procedures(gNB,frame,slot); else @@ -876,7 +915,7 @@ int main(int argc, char **argv) r_im[aa][i] = ((double)(((short *)txdata[aa]))[(i<<1)+1]); } } - + double ts = 1.0/(frame_parms->subcarrier_spacing * frame_parms->ofdm_symbol_size); //AWGN sigma2_dB = 10 * log10((double)txlev * ((double)UE->frame_parms.ofdm_symbol_size/(12*rel15->rbSize))) - SNR; sigma2 = pow(10, sigma2_dB/10); @@ -889,6 +928,12 @@ int main(int argc, char **argv) for (aa=0; aanb_antennas_rx; aa++) { ((short*) UE->common_vars.rxdata[aa])[2*i] = (short) ((r_re[aa][i] + sqrt(sigma2/2)*gaussdouble(0.0,1.0))); ((short*) UE->common_vars.rxdata[aa])[2*i+1] = (short) ((r_im[aa][i] + sqrt(sigma2/2)*gaussdouble(0.0,1.0))); + /* Add phase noise if enabled */ + if (pdu_bit_map & 0x1) + { + phase_noise(ts, &((short*) UE->common_vars.rxdata[aa])[2*i], + &((short*) UE->common_vars.rxdata[aa])[2*i+1]); + } } } @@ -923,6 +968,11 @@ int main(int argc, char **argv) uint8_t nb_symb_sch = rel15->NrOfSymbols; available_bits = nr_get_G(nb_rb, nb_symb_sch, nb_re_dmrs, length_dmrs, mod_order, rel15->nrOfLayers); + if(pdu_bit_map & 0x1) + { + available_bits-= (ptrsSymbPerSlot * ptrsRePerSymb *rel15->nrOfLayers* 2); + printf("[DLSIM][PTRS] Available bits are: %5d, removed PTRS bits are: %5d \n",available_bits, (ptrsSymbPerSlot * ptrsRePerSymb *rel15->nrOfLayers* 2) ); + } for (i = 0; i < available_bits; i++) { @@ -1084,3 +1134,57 @@ int main(int argc, char **argv) return(n_errors); } + + +void update_ptrs_config(NR_CellGroupConfig_t *secondaryCellGroup, uint16_t *rbSize, uint8_t *mcsIndex, uint8_t *K_ptrs, uint8_t *L_ptrs) +{ + NR_BWP_Downlink_t *bwp=secondaryCellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.array[0]; + int *ptrsFreqDenst = calloc(2, sizeof(long)); + ptrsFreqDenst[0]= 25; + ptrsFreqDenst[1]= 115; + int *ptrsTimeDenst = calloc(3, sizeof(long)); + ptrsTimeDenst[0]= 2; + ptrsTimeDenst[1]= 4; + ptrsTimeDenst[2]= 10; + + int epre_Ratio = 0; + int reOffset = 0; + + if(*L_ptrs ==0) + { + ptrsTimeDenst[2]= *mcsIndex -1; + } + else if(*L_ptrs == 1) + { + ptrsTimeDenst[1]= *mcsIndex - 1; + ptrsTimeDenst[2]= *mcsIndex + 1; + } + else if(*L_ptrs ==2) + { + ptrsTimeDenst[0]= *mcsIndex - 1; + ptrsTimeDenst[1]= *mcsIndex + 1; + } + else + { + printf("[DLSIM] Wrong L_PTRS value, using default values 1\n"); + } + /* L = 4 if Imcs < MCS4 */ + if(*K_ptrs ==2) + { + ptrsFreqDenst[0]= *rbSize - 1; + ptrsFreqDenst[1]= *rbSize + 1; + } + else if(*K_ptrs == 4) + { + ptrsFreqDenst[1]= *rbSize - 1; + } + else + { + printf("[DLSIM] Wrong K_PTRS value, using default values 2\n"); + } + + /* overwrite the values */ + rrc_config_dl_ptrs_params(bwp, ptrsFreqDenst, ptrsTimeDenst, &epre_Ratio, &reOffset); +} + +