From b288eafd1ec5afb85643e6f236f6774ca1be5456 Mon Sep 17 00:00:00 2001 From: Parminder Singh <parminder.singh@iis.fraunhofer.de> Date: Fri, 21 Aug 2020 14:34:44 +0200 Subject: [PATCH] Common Phase error estimation and compensation in uplink. FEATURE STATEMENT: - Introduce linear phase error noise model in Uplink at UE - Perform common phase error (CPE) estimation and compensation at gNB SOLUTION: - A linear phase shift model is introduced in simulation. - PTRS symbols are used to perform estimation of CPE from DMRS compensated signal - The estimated values are interpolated in time domain and signal is compensated for the CPE. - PTRS processing is done in Frequency Domain for each symbol in a slot and LLR's are calculated for each symbol accordingly. IMPLEMENTATION: * sim.h/channle_sim.c - Linear Phase Noise Generation model definition. * nr_ul_channel_estimation.c/nr_ul_estimation.h - CPE estimation from PTRS and DMRS compensated signal. * nr_dmrs_rx.c/nr_refsig.h - Regenerate PTRS symbols at gNB. * nr_ulsch_demodulation.c - Removed old PTRS processing code and move to a common PTRS processing function * defs_gNB.h/init.c - New PTRS variables definition and initialization * nr_ulsch_ue.c - Corrected PTRS parameter to get new PTRS symbols for each OFDM symbol TESTING * ulsim.c - Added Phase noise, Enable PTRS signal and verified the output. VERIFICATION - The LLR are rotated back with estimated CPE and no error is observed in scrambling/decoding --- cmake_targets/CMakeLists.txt | 1 + cmake_targets/build_oai | 2 +- openair1/PHY/INIT/nr_init.c | 20 +- .../NR_ESTIMATION/nr_ul_channel_estimation.c | 405 ++++++++++++++++++ openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h | 26 ++ openair1/PHY/NR_REFSIG/dmrs_nr.c | 21 + openair1/PHY/NR_REFSIG/nr_dmrs_rx.c | 27 ++ openair1/PHY/NR_REFSIG/nr_refsig.h | 3 + .../PHY/NR_TRANSPORT/nr_ulsch_demodulation.c | 155 ++++--- openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c | 2 +- openair1/PHY/defs_gNB.h | 14 + openair1/SIMULATION/NR_PHY/ulsim.c | 46 +- openair1/SIMULATION/TOOLS/phase_noise.c | 42 ++ openair1/SIMULATION/TOOLS/sim.h | 8 + 14 files changed, 666 insertions(+), 106 deletions(-) create mode 100644 openair1/SIMULATION/TOOLS/phase_noise.c diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 0b601727472..8ff3663eab5 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -2303,6 +2303,7 @@ add_library(LFDS7 add_library(SIMU_COMMON ${OPENAIR1_DIR}/SIMULATION/TOOLS/random_channel.c ${OPENAIR1_DIR}/SIMULATION/TOOLS/rangen_double.c + ${OPENAIR1_DIR}/SIMULATION/TOOLS/phase_noise.c ) # Simulation library diff --git a/cmake_targets/build_oai b/cmake_targets/build_oai index 88b8811575b..89f945a6949 100755 --- a/cmake_targets/build_oai +++ b/cmake_targets/build_oai @@ -209,7 +209,7 @@ function main() { GDB=0 CMAKE_BUILD_TYPE="RelWithDebInfo" echo_info "Will Compile with gdb symbols" - CMAKE_CMD="$CMAKE_CMD -DCMAKE_BUILD_TYPE=RelWithDebInfo" + CMAKE_CMD="$CMAKE_CMD -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_EXPORT_COMPILE_COMMANDS=1" shift ;; "MinSizeRel") diff --git a/openair1/PHY/INIT/nr_init.c b/openair1/PHY/INIT/nr_init.c index 9e095d5ab5b..604e17ecfcf 100644 --- a/openair1/PHY/INIT/nr_init.c +++ b/openair1/PHY/INIT/nr_init.c @@ -247,10 +247,13 @@ int phy_init_nr_gNB(PHY_VARS_gNB *gNB, pusch_vars[ULSCH_id]->ul_ch_estimates_ext = (int32_t **)malloc16(Prx*sizeof(int32_t *) ); pusch_vars[ULSCH_id]->ul_ch_ptrs_estimates = (int32_t **)malloc16(Prx*sizeof(int32_t *) ); pusch_vars[ULSCH_id]->ul_ch_ptrs_estimates_ext = (int32_t **)malloc16(Prx*sizeof(int32_t *) ); + pusch_vars[ULSCH_id]->ptrs_phase_per_slot = (int32_t **)malloc16(Prx*sizeof(int32_t *) ); + pusch_vars[ULSCH_id]->ptrs_valid_re_per_slot= (int16_t **)malloc16(Prx*sizeof(int16_t *) ); pusch_vars[ULSCH_id]->ul_ch_estimates_time = (int32_t **)malloc16(Prx*sizeof(int32_t *) ); pusch_vars[ULSCH_id]->rxdataF_comp = (int32_t **)malloc16(Prx*sizeof(int32_t *) ); - pusch_vars[ULSCH_id]->ul_ch_mag0 = (int32_t **)malloc16(Prx*sizeof(int32_t *) ); - pusch_vars[ULSCH_id]->ul_ch_magb0 = (int32_t **)malloc16(Prx*sizeof(int32_t *) ); + pusch_vars[ULSCH_id]->rxdataF_ptrs_comp = (int32_t **)malloc16(Prx*sizeof(int32_t *) ); + pusch_vars[ULSCH_id]->ul_ch_mag0 = (int32_t **)malloc16(Prx*sizeof(int32_t *) ); + pusch_vars[ULSCH_id]->ul_ch_magb0 = (int32_t **)malloc16(Prx*sizeof(int32_t *) ); pusch_vars[ULSCH_id]->ul_ch_mag = (int32_t **)malloc16(Prx*sizeof(int32_t *) ); pusch_vars[ULSCH_id]->ul_ch_magb = (int32_t **)malloc16(Prx*sizeof(int32_t *) ); pusch_vars[ULSCH_id]->rho = (int32_t **)malloc16_clear(Prx*sizeof(int32_t*) ); @@ -264,9 +267,12 @@ int phy_init_nr_gNB(PHY_VARS_gNB *gNB, pusch_vars[ULSCH_id]->ul_ch_estimates_time[i] = (int32_t *)malloc16_clear( 2*sizeof(int32_t)*fp->ofdm_symbol_size ); pusch_vars[ULSCH_id]->ul_ch_ptrs_estimates[i] = (int32_t *)malloc16_clear( sizeof(int32_t)*fp->ofdm_symbol_size*2*fp->symbols_per_slot ); // max intensity in freq is 1 sc every 2 RBs pusch_vars[ULSCH_id]->ul_ch_ptrs_estimates_ext[i] = (int32_t *)malloc16_clear( sizeof(int32_t)*fp->ofdm_symbol_size*2*fp->symbols_per_slot ); + pusch_vars[ULSCH_id]->ptrs_phase_per_slot[i] = (int32_t *)malloc16_clear( sizeof(int32_t)*fp->symbols_per_slot); // symbols per slot + pusch_vars[ULSCH_id]->ptrs_valid_re_per_slot[i]= (int16_t *)malloc16_clear( sizeof(int16_t)*fp->symbols_per_slot); pusch_vars[ULSCH_id]->rxdataF_comp[i] = (int32_t *)malloc16_clear( sizeof(int32_t)*N_RB_UL*12*fp->symbols_per_slot ); - pusch_vars[ULSCH_id]->ul_ch_mag0[i] = (int32_t *)malloc16_clear( fp->symbols_per_slot*sizeof(int32_t)*N_RB_UL*12 ); - pusch_vars[ULSCH_id]->ul_ch_magb0[i] = (int32_t *)malloc16_clear( fp->symbols_per_slot*sizeof(int32_t)*N_RB_UL*12 ); + pusch_vars[ULSCH_id]->rxdataF_ptrs_comp[i] = (int32_t *)malloc16_clear( sizeof(int32_t)*N_RB_UL*12*fp->symbols_per_slot ); + pusch_vars[ULSCH_id]->ul_ch_mag0[i] = (int32_t *)malloc16_clear( fp->symbols_per_slot*sizeof(int32_t)*N_RB_UL*12 ); + pusch_vars[ULSCH_id]->ul_ch_magb0[i] = (int32_t *)malloc16_clear( fp->symbols_per_slot*sizeof(int32_t)*N_RB_UL*12 ); pusch_vars[ULSCH_id]->ul_ch_mag[i] = (int32_t *)malloc16_clear( fp->symbols_per_slot*sizeof(int32_t)*N_RB_UL*12 ); pusch_vars[ULSCH_id]->ul_ch_magb[i] = (int32_t *)malloc16_clear( fp->symbols_per_slot*sizeof(int32_t)*N_RB_UL*12 ); pusch_vars[ULSCH_id]->rho[i] = (int32_t *)malloc16_clear( sizeof(int32_t)*(fp->N_RB_UL*12*7*2) ); @@ -334,7 +340,10 @@ void phy_free_nr_gNB(PHY_VARS_gNB *gNB) free_and_zero(pusch_vars[ULSCH_id]->ul_ch_estimates_time[i]); free_and_zero(pusch_vars[ULSCH_id]->ul_ch_ptrs_estimates[i]); free_and_zero(pusch_vars[ULSCH_id]->ul_ch_ptrs_estimates_ext[i]); + free_and_zero(pusch_vars[ULSCH_id]->ptrs_phase_per_slot[i]); + free_and_zero(pusch_vars[ULSCH_id]->ptrs_valid_re_per_slot[i]); free_and_zero(pusch_vars[ULSCH_id]->rxdataF_comp[i]); + free_and_zero(pusch_vars[ULSCH_id]->rxdataF_ptrs_comp[i]); free_and_zero(pusch_vars[ULSCH_id]->ul_ch_mag0[i]); free_and_zero(pusch_vars[ULSCH_id]->ul_ch_magb0[i]); free_and_zero(pusch_vars[ULSCH_id]->ul_ch_mag[i]); @@ -349,7 +358,10 @@ void phy_free_nr_gNB(PHY_VARS_gNB *gNB) free_and_zero(pusch_vars[ULSCH_id]->ul_ch_ptrs_estimates); free_and_zero(pusch_vars[ULSCH_id]->ul_ch_ptrs_estimates_ext); free_and_zero(pusch_vars[ULSCH_id]->ul_ch_estimates_time); + free_and_zero(pusch_vars[ULSCH_id]->ptrs_phase_per_slot); + free_and_zero(pusch_vars[ULSCH_id]->ptrs_valid_re_per_slot); free_and_zero(pusch_vars[ULSCH_id]->rxdataF_comp); + free_and_zero(pusch_vars[ULSCH_id]->rxdataF_ptrs_comp); free_and_zero(pusch_vars[ULSCH_id]->ul_ch_mag0); free_and_zero(pusch_vars[ULSCH_id]->ul_ch_magb0); free_and_zero(pusch_vars[ULSCH_id]->ul_ch_mag); diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c index 3f7c7817f77..1e2a0e64cd5 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c +++ b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c @@ -25,6 +25,8 @@ #include "nr_ul_estimation.h" #include "PHY/sse_intrin.h" #include "PHY/NR_REFSIG/nr_refsig.h" +#include "PHY/NR_REFSIG/ptrs_nr.h" +#include "PHY/NR_TRANSPORT/nr_transport_proto.h" #include "PHY/NR_UE_ESTIMATION/filt16a_32.h" //#define DEBUG_CH @@ -501,3 +503,406 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, return(0); } + + +/******************************************************************* + * + * NAME : nr_pusch_ptrs_processing + * + * PARAMETERS : gNB : gNB data structure + * rel15_ul : UL parameters + * UE_id : UE ID + * nr_tti_rx : slot rx TTI + * dmrs_symbol_flag: DMRS Symbol Flag + * symbol : OFDM Symbol + * nb_re_pusch : PUSCH RE's + * nb_re_pusch : PUSCH RE's + * + * RETURN : nothing + * + * DESCRIPTION : + * If ptrs is enabled process the symbol accordingly + * 1) Estimate phase noise per PTRS symbol + * 2) Interpolate PTRS estimated value in TD after all PTRS symbols + * 3) Compensated DMRS based estimated signal with PTRS estimation for slot + *********************************************************************/ +void nr_pusch_ptrs_processing(PHY_VARS_gNB *gNB, + nfapi_nr_pusch_pdu_t *rel15_ul, + uint8_t ulsch_id, + uint8_t nr_tti_rx, + uint8_t dmrs_symbol_flag, + unsigned char symbol, + uint32_t nb_re_pusch) +{ + NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms; + int16_t *phase_per_symbol; + int16_t *no_re_per_symbol; + + uint8_t L_ptrs = 0; + uint8_t right_side_ref = 0; + uint8_t left_side_ref = 0; + uint8_t nb_dmrs_in_slot = 0; + + //#define DEBUG_UL_PTRS 1 + /* First symbol calculate PTRS symbol index for slot & set the variables */ + if(symbol == rel15_ul->start_symbol_index) + { + gNB->pusch_vars[ulsch_id]->ptrs_symbols = 0; + L_ptrs = 1<<(rel15_ul->pusch_ptrs.ptrs_time_density); + set_ptrs_symb_idx(&gNB->pusch_vars[ulsch_id]->ptrs_symbols, + rel15_ul->nr_of_symbols, + rel15_ul->start_symbol_index, + L_ptrs, + rel15_ul->ul_dmrs_symb_pos); + }/* First symbol check */ + + /* loop over antennas */ + for (int aarx=0; aarx< frame_parms->nb_antennas_rx; aarx++) + { + phase_per_symbol = (int16_t*)gNB->pusch_vars[ulsch_id]->ptrs_phase_per_slot[aarx]; + no_re_per_symbol = gNB->pusch_vars[ulsch_id]->ptrs_valid_re_per_slot[aarx]; + no_re_per_symbol[symbol] = nb_re_pusch; + /* if not PTRS symbol set current ptrs symbol index to zero*/ + gNB->pusch_vars[ulsch_id]->ptrs_symbol_index = 0; + gNB->pusch_vars[ulsch_id]->ptrs_sc_per_ofdm_symbol = 0; + /* Check if current symbol contains PTRS */ + if(is_ptrs_symbol(symbol, gNB->pusch_vars[ulsch_id]->ptrs_symbols)) + { + gNB->pusch_vars[ulsch_id]->ptrs_symbol_index = symbol; + /*------------------------------------------------------------------------------------------------------- */ + /* 1) Estimate phase noise per PTRS symbol */ + /*------------------------------------------------------------------------------------------------------- */ + nr_pusch_phase_estimation(frame_parms, + rel15_ul, + (int16_t *)&gNB->pusch_vars[ulsch_id]->ul_ch_ptrs_estimates_ext[aarx][symbol*nb_re_pusch], + nr_tti_rx, + symbol, + (int16_t*)&gNB->pusch_vars[ulsch_id]->rxdataF_comp[aarx][(symbol * nb_re_pusch)], + gNB->nr_gold_pusch_dmrs[rel15_ul->scid], + &phase_per_symbol[2* symbol], + &gNB->pusch_vars[ulsch_id]->ptrs_sc_per_ofdm_symbol); + /* Subtract total PTRS RE's in the symbol from PUSCH RE's */ + no_re_per_symbol[symbol] = nb_re_pusch - gNB->pusch_vars[ulsch_id]->ptrs_sc_per_ofdm_symbol; + } + /* DMRS Symbol channel estimates extraction */ + else if(dmrs_symbol_flag) + { + phase_per_symbol[2* symbol]= (int16_t)((1<<15)-1); // 32767 + phase_per_symbol[2* symbol +1]= 0;// no angle + } + /* For last OFDM symbol at each antenna perform interpolation and compensation for the slot*/ + if(symbol == (rel15_ul->start_symbol_index + rel15_ul->nr_of_symbols -1)) + { + nb_dmrs_in_slot = get_dmrs_symbols_in_slot(rel15_ul->ul_dmrs_symb_pos,(rel15_ul->start_symbol_index + rel15_ul->nr_of_symbols)); + for(uint8_t dmrs_sym = 0; dmrs_sym < nb_dmrs_in_slot; dmrs_sym ++) + { + if(dmrs_sym == 0) + { + /* get first DMRS position */ + left_side_ref = get_next_dmrs_symbol_in_slot(rel15_ul->ul_dmrs_symb_pos, rel15_ul->start_symbol_index, (rel15_ul->start_symbol_index + rel15_ul->nr_of_symbols)); + /* get first DMRS position is not at start symbol position then we need to extrapolate left side */ + if(left_side_ref > rel15_ul->start_symbol_index) + { + left_side_ref = rel15_ul->start_symbol_index; + } + } + /* get the next symbol from left_side_ref value */ + right_side_ref = get_next_dmrs_symbol_in_slot(rel15_ul->ul_dmrs_symb_pos, left_side_ref+1, (rel15_ul->start_symbol_index + rel15_ul->nr_of_symbols)); + /* if no symbol found then interpolate till end of slot*/ + if(right_side_ref == 0) + { + right_side_ref = (rel15_ul->start_symbol_index + rel15_ul->nr_of_symbols); + } + /*------------------------------------------------------------------------------------------------------- */ + /* 2) Interpolate PTRS estimated value in TD */ + /*------------------------------------------------------------------------------------------------------- */ + nr_pusch_phase_interpolation(phase_per_symbol,left_side_ref,right_side_ref); + /* set left to last dmrs */ + left_side_ref = right_side_ref; + } /*loop over dmrs positions */ + + //nr_pusch_phase_interpolation(phase_per_symbol,rel15_ul->start_symbol_index,frame_parms->symbols_per_slot ); +#ifdef DEBUG_UL_PTRS + LOG_M("ptrsEst.m","est",gNB->pusch_vars[ulsch_id]->ptrs_phase_per_slot[aarx],frame_parms->symbols_per_slot,1,1 ); +#endif + + /*------------------------------------------------------------------------------------------------------- */ + /* 3) Compensated DMRS based estimated signal with PTRS estimation */ + /*--------------------------------------------------------------------------------------------------------*/ + for(uint8_t i =rel15_ul->start_symbol_index; i< (rel15_ul->start_symbol_index + rel15_ul->nr_of_symbols);i++) + { +#ifdef DEBUG_UL_PTRS + printf("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*)&gNB->pusch_vars[ulsch_id]->rxdataF_comp[aarx][(i * rel15_ul->rb_size * NR_NB_SC_PER_RB)], + &phase_per_symbol[2* i], + (int16_t*)&gNB->pusch_vars[ulsch_id]->rxdataF_ptrs_comp[aarx][(i * rel15_ul->rb_size * NR_NB_SC_PER_RB)], + (rel15_ul->rb_size * NR_NB_SC_PER_RB), + 15); + }// symbol loop + }//interpolation and compensation + }// Antenna loop +} + +/******************************************************************* + * + * NAME : nr_pusch_phase_estimation + * + * PARAMETERS : frame_parms : UL frame parameters + * rel15_ul : UL PDU Structure + * Ns : + * Symbol : OFDM symbol index + * rxF : Channel compensated signal + * ptrs_gold_seq: Gold sequence for PTRS regeneration + * error_est : Estimated error output vector [Re Im] + * RETURN : nothing + * + * DESCRIPTION : + * perform phase estimation from regenerated PTRS SC and channel compensated + * signal + *********************************************************************/ +void nr_pusch_phase_estimation(NR_DL_FRAME_PARMS *frame_parms, + nfapi_nr_pusch_pdu_t *rel15_ul, + int16_t *ptrs_ch_p, + unsigned char Ns, + unsigned char symbol, + int16_t *rxF_comp, + uint32_t ***ptrs_gold_seq, + int16_t *error_est, + uint16_t *ptrs_sc) +{ + uint8_t is_ptrs_re = 0; + uint16_t re_cnt = 0; + uint16_t cnt = 0; + unsigned short nb_re_pusch = NR_NB_SC_PER_RB * rel15_ul->rb_size; + uint8_t K_ptrs = (rel15_ul->pusch_ptrs.ptrs_freq_density)?4:2; + uint16_t sc_per_symbol = rel15_ul->rb_size/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_UL_PTRS + double alpha = 0; +#endif + /* generate PTRS RE for the symbol */ + nr_ptrs_rx_gen(ptrs_gold_seq[Ns][symbol],rel15_ul->rb_size,ptrs_p); + + /* loop over all sub carriers to get compensated RE on ptrs symbols*/ + for (int re = 0; re < nb_re_pusch; re++) + { + is_ptrs_re = is_ptrs_subcarrier(re, + rel15_ul->rnti, + 0, + rel15_ul->dmrs_config_type, + K_ptrs, + rel15_ul->rb_size, + rel15_ul->pusch_ptrs.ptrs_ports_list[0].ptrs_re_offset, + 0,// start_re is 0 here + frame_parms->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_UL_PTRS + alpha = atan(imag/real); + printf("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_UL_PTRS + printf("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_pusch_phase_interpolation + * + * PARAMETERS : *error_est : Data Pointer [Re Im Re Im ...] + * start_symbol : Start Symbol + * end_symbol : End Symbol + * RETURN : nothing + * + * DESCRIPTION : + * Perform Interpolation, extrapolation based upon the estimation + * location between the data Pointer Array. + * + *********************************************************************/ +void nr_pusch_phase_interpolation(int16_t *error_est, + uint8_t start_symbol, + uint8_t end_symbol + ) +{ + + int next = 0, prev = 0, candidates= 0, distance=0, leftEdge= 0, rightEdge = 0, getDiff =0 ; + double weight = 0.0; + double scale = 0.125 ; // to avoid saturation due to fixed point multiplication +#ifdef DEBUG_UL_PTRS + printf("PTRS: INT: Left limit %d, Right limit %d, Loop over %d Symbols \n", + start_symbol,end_symbol-1, (end_symbol -start_symbol)-1); +#endif + for(int i =start_symbol; i< end_symbol;i++) + { + /* Only update when an estimation is found */ + if( error_est[i*2] != 0 ) + { + /* if found a symbol then set next symbol also */ + next = nr_ptrs_find_next_estimate(error_est, i, end_symbol); + /* left extrapolation, if first estimate value is zero */ + if( error_est[i*2] == 0 ) + { + leftEdge = 1; + } + /* right extrapolation, if next is 0 before end symbol */ + if((next == 0) && (end_symbol > i)) + { + rightEdge = 1; + /* special case as no right extrapolation possible with DMRS on left */ + /* In this case take mean of most recent 2 estimated points */ + if(prev ==0) + { + prev = start_symbol -1; + next = start_symbol -2; + getDiff =1; + }else + { + /* for right edge previous is second last from right side */ + next = prev; + /* Set the current as recent estimation reference */ + prev = i; + } + } + /* update current symbol as prev for next symbol */ + if (rightEdge==0) + /* Set the current as recent estimation reference */ + prev = i; + } + /*extrapolation left side*/ + if(leftEdge) + { + distance = next - prev; + weight = 1.0/distance; + candidates = i; + for(int j = 1; j <= candidates; j++) + { + error_est[(i-j)*2] = 8 *(((double)(error_est[prev*2]) * scale * (distance + j) * weight) - + ((double)(error_est[next*2]) * scale * j * weight)); + error_est[((i-j)*2)+1]= 8 *(((double)(error_est[(prev*2)+1]) * scale* (distance + j) * weight) - + ((double)(error_est[((next*2)+1)]) * scale * j * weight)); +#ifdef DEBUG_UL_PTRS + printf("PTRS: INT: Left Edge i= %d weight= %f %d + j*%d, Prev %d Next %d \n", + (i-j),weight, error_est[(i-j)*2],error_est[((i-j)*2)+1], prev,next); +#endif + } + leftEdge = 0; + } + /* extrapolation at right side */ + else if (rightEdge ) + { + if(getDiff) + { + error_est[(i+1)*2] = ((1<<15) +(error_est[prev*2]) - error_est[next*2]); + error_est[((i+1)*2)+1]= error_est[(prev*2)+1] - error_est[(next*2)+1]; +#ifdef DEBUG_UL_PTRS + printf("PTRS: INT: Right Edge Special Case i= %d weight= %f %d + j*%d, Prev %d Next %d \n", + (i+1),weight, error_est[(i+1)*2],error_est[((i+1)*2)+1], prev,next); +#endif + i++; + } + else + { + distance = prev - next; + candidates = (end_symbol -1) - i; + weight = 1.0/distance; + for(int j = 1; j <= candidates; j++) + { + error_est[(i+j)*2] = 8 *(((double)(error_est[prev*2]) * scale * (distance + j) * weight) - + ((double)(error_est[next*2]) * scale * j * weight)); + error_est[((i+j)*2)+1]= 8 *(((double)(error_est[(prev*2)+1]) * scale * (distance + j) * weight) - + ((double)(error_est[((next*2)+1)]) * scale *j * weight)); +#ifdef DEBUG_UL_PTRS + printf("PTRS: INT: Right Edge i= %d weight= %f %d + j*%d, Prev %d Next %d \n", + (i+j),weight, error_est[(i+j)*2],error_est[((i+j)*2)+1], prev,next); +#endif + } + if(candidates > 1) + { + i+=candidates; + } + } + } + /* Interpolation between 2 estimated points */ + else if(next != 0 && ( error_est[2*i] == 0 )) + { + distance = next - prev; + weight = 1.0/distance; + candidates = next - i ; + for(int j = 0; j < candidates; j++) + { + + error_est[(i+j)*2] = 8 *(((double)(error_est[prev*2]) * scale * (distance - (j+1)) * weight) + + ((double)(error_est[next*2]) * scale * (j+1) * weight)); + error_est[((i+j)*2)+1]= 8 *(((double)(error_est[(prev*2)+1]) * scale *(distance - (j+1)) * weight) + + ((double)(error_est[((next*2)+1)]) * scale *(j+1) * weight)); +#ifdef DEBUG_UL_PTRS + printf("PTRS: INT: Interpolation i= %d weight= %f %d + j*%d, Prev %d Next %d\n", + (i+j),weight, error_est[(i+j)*2],error_est[((i+j)*2)+1],prev,next); +#endif + } + if(candidates > 1) + { + i+=candidates-1; + } + }// interpolation + }// symbol loop +} + +/* Find the next non zero Real value in a complex vector */ +int nr_ptrs_find_next_estimate(int16_t *error_est, + uint8_t counter, + uint8_t end_symbol) +{ + for (int i = counter +1 ; i< end_symbol; i++) + { + if( error_est[2*i] != 0) + { + return i; + } + } + return 0; +} diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h b/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h index a7789c92249..33ce319d801 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h +++ b/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h @@ -48,4 +48,30 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, int nr_est_timing_advance_pusch(PHY_VARS_gNB* phy_vars_gNB, int UE_id); + +void nr_pusch_ptrs_processing(PHY_VARS_gNB *gNB, + nfapi_nr_pusch_pdu_t *rel15_ul, + uint8_t ulsch_id, + uint8_t nr_tti_rx, + uint8_t dmrs_symbol_flag, + unsigned char symbol, + uint32_t nb_re_pusch); + +void nr_pusch_phase_estimation(NR_DL_FRAME_PARMS *frame_parms, + nfapi_nr_pusch_pdu_t *rel15_ul, + int16_t *ptrs_ch_p, + unsigned char Ns, + unsigned char symbol, + int16_t *rxF_comp, + uint32_t ***ptrs_gold_seq, + int16_t *error_est, + uint16_t *ptrs_sc); + +void nr_pusch_phase_interpolation(int16_t *error_est, + uint8_t start_symbol, + uint8_t end_symbol); + +int nr_ptrs_find_next_estimate(int16_t *error_est, + uint8_t counter, + uint8_t end_symbol); #endif diff --git a/openair1/PHY/NR_REFSIG/dmrs_nr.c b/openair1/PHY/NR_REFSIG/dmrs_nr.c index 7042c152fdf..415e6adfa28 100644 --- a/openair1/PHY/NR_REFSIG/dmrs_nr.c +++ b/openair1/PHY/NR_REFSIG/dmrs_nr.c @@ -362,4 +362,25 @@ void generate_dmrs_pbch(uint32_t dmrs_pbch_bitmap[DMRS_PBCH_I_SSB][DMRS_PBCH_N_H free(dmrs_sequence); #endif } +/* return the position of next dmrs symbol in a slot */ +int get_next_dmrs_symbol_in_slot(uint16_t ul_dmrs_symb_pos, uint8_t counter, uint8_t end_symbol) +{ + for(uint8_t symbol = counter; symbol < end_symbol; symbol++) + if((ul_dmrs_symb_pos >>symbol)&0x01 ) + { + return symbol; + } + return 0; +} + +/* return the total number of dmrs symbol in a slot */ +uint8_t get_dmrs_symbols_in_slot(uint16_t l_prime_mask, uint16_t nb_symb) +{ + uint8_t tmp = 0; + for (int i = 0; i < nb_symb; i++) + { + tmp += (l_prime_mask >> i) & 0x01; + } + return tmp; +} diff --git a/openair1/PHY/NR_REFSIG/nr_dmrs_rx.c b/openair1/PHY/NR_REFSIG/nr_dmrs_rx.c index 4eeb8a6e96f..ac97ee3993b 100644 --- a/openair1/PHY/NR_REFSIG/nr_dmrs_rx.c +++ b/openair1/PHY/NR_REFSIG/nr_dmrs_rx.c @@ -223,3 +223,30 @@ int nr_pbch_dmrs_rx(int symbol, return(0); } + +/*! + \brief This function generate gold ptrs sequence for each OFDM symbol + \param *in gold sequence for ptrs per OFDM symbol + \param length is number of RE in a OFDM symbol + \param *output pointer to all ptrs RE in a OFDM symbol +*/ +void nr_ptrs_rx_gen(uint32_t *in, uint32_t length, int16_t *output) +{ + uint16_t offset; + uint8_t idx, b_idx; + int mod_order = 2; + offset = NR_MOD_TABLE_QPSK_OFFSET; + for (int i=0; i<length/mod_order; i++) + { + idx = 0; + for (int j=0; j<mod_order; j++) + { + b_idx = (i*mod_order+j)&0x1f; + if (i && (!b_idx)) + in++; + idx ^= (((*in)>>b_idx)&1)<<(mod_order-j-1); + } + output[i<<1] = nr_rx_mod_table[(offset+idx)<<1]; + output[(i<<1)+1] = nr_rx_mod_table[((offset+idx)<<1)+1]; + } +} diff --git a/openair1/PHY/NR_REFSIG/nr_refsig.h b/openair1/PHY/NR_REFSIG/nr_refsig.h index 1bf2ef4fb2d..eddadc45d98 100644 --- a/openair1/PHY/NR_REFSIG/nr_refsig.h +++ b/openair1/PHY/NR_REFSIG/nr_refsig.h @@ -52,6 +52,9 @@ int nr_pusch_dmrs_rx(PHY_VARS_gNB *gNB, uint8_t dmrs_type); void init_scrambling_luts(void); +void nr_ptrs_rx_gen(uint32_t *in, uint32_t length, int16_t *output); +uint8_t get_next_dmrs_symbol_in_slot(uint16_t ul_dmrs_symb_pos, uint8_t counter, uint8_t end_symbol); +uint8_t get_dmrs_symbols_in_slot(uint16_t l_prime_mask, uint16_t nb_symb); extern __m64 byte2m64_re[256]; extern __m64 byte2m64_im[256]; diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c index 824d933d5c8..dd31ee3471b 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c +++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c @@ -232,18 +232,13 @@ void nr_ulsch_extract_rbs_single(int32_t **rxdataF, unsigned short start_re, re, nb_re_pusch; unsigned char aarx; - uint8_t K_ptrs = 0; uint32_t rxF_ext_index = 0; uint32_t ul_ch0_ext_index = 0; uint32_t ul_ch0_index = 0; - uint32_t ul_ch0_ptrs_ext_index = 0; - uint32_t ul_ch0_ptrs_index = 0; - uint8_t is_ptrs_symbol_flag,k_prime; - uint16_t n=0, num_ptrs_symbols; + uint8_t k_prime; + uint16_t n=0; int16_t *rxF,*rxF_ext; int *ul_ch0,*ul_ch0_ext; - int *ul_ch0_ptrs,*ul_ch0_ptrs_ext; - uint16_t n_rnti = pusch_pdu->rnti; uint8_t delta = 0; #ifdef DEBUG_RB_EXT @@ -252,15 +247,13 @@ void nr_ulsch_extract_rbs_single(int32_t **rxdataF, printf("--------------------ch_ext_index = %d-----------------------\n", symbol*NR_NB_SC_PER_RB * pusch_pdu->rb_size); #endif - + uint8_t is_dmrs_re; start_re = (frame_parms->first_carrier_offset + (pusch_pdu->rb_start * NR_NB_SC_PER_RB))%frame_parms->ofdm_symbol_size; nb_re_pusch = NR_NB_SC_PER_RB * pusch_pdu->rb_size; - is_ptrs_symbol_flag = 0; - num_ptrs_symbols = 0; for (aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++) { - + rxF = (int16_t *)&rxdataF[aarx][symbol * frame_parms->ofdm_symbol_size]; rxF_ext = (int16_t *)&pusch_vars->rxdataF_ext[aarx][symbol * nb_re_pusch]; // [hna] rxdataF_ext isn't contiguous in order to solve an alignment problem ib llr computation in case of mod_order = 4, 6 @@ -268,10 +261,6 @@ void nr_ulsch_extract_rbs_single(int32_t **rxdataF, ul_ch0_ext = &pusch_vars->ul_ch_estimates_ext[aarx][symbol*nb_re_pusch]; - ul_ch0_ptrs = &pusch_vars->ul_ch_ptrs_estimates[aarx][pusch_vars->ptrs_symbol_index*frame_parms->ofdm_symbol_size]; // update channel estimates if new dmrs symbol are available - - ul_ch0_ptrs_ext = &pusch_vars->ul_ch_ptrs_estimates_ext[aarx][symbol*nb_re_pusch]; - n = 0; k_prime = 0; @@ -282,54 +271,28 @@ void nr_ulsch_extract_rbs_single(int32_t **rxdataF, else is_dmrs_re = 0; - if (pusch_pdu->pdu_bit_map & PUSCH_PDU_BITMAP_PUSCH_PTRS) { - K_ptrs = (pusch_pdu->pusch_ptrs.ptrs_freq_density)?4:2; - if(is_ptrs_symbol(symbol, pusch_vars->ptrs_symbols)) - is_ptrs_symbol_flag = is_ptrs_subcarrier((start_re + re) % frame_parms->ofdm_symbol_size, - n_rnti, - aarx, - pusch_pdu->dmrs_config_type, - K_ptrs, - pusch_pdu->rb_size, - pusch_pdu->pusch_ptrs.ptrs_ports_list[0].ptrs_re_offset, - start_re, - frame_parms->ofdm_symbol_size); - - if (is_ptrs_symbol_flag == 1) - num_ptrs_symbols++; - - } - - #ifdef DEBUG_RB_EXT - printf("re = %d, is_ptrs_symbol_flag = %d, symbol = %d\n", re, is_ptrs_symbol_flag, symbol); - #endif - - if ( is_dmrs_re == 0 && is_ptrs_symbol_flag == 0) { + /* save only data and respective channel estimates */ + if ( is_dmrs_re == 0) { - rxF_ext[rxF_ext_index] = (rxF[ ((start_re + re)*2) % (frame_parms->ofdm_symbol_size*2)]); - rxF_ext[rxF_ext_index + 1] = (rxF[(((start_re + re)*2) + 1) % (frame_parms->ofdm_symbol_size*2)]); + rxF_ext[rxF_ext_index] = (rxF[ ((start_re + re)*2) % (frame_parms->ofdm_symbol_size*2)]); + rxF_ext[rxF_ext_index + 1] = (rxF[(((start_re + re)*2) + 1) % (frame_parms->ofdm_symbol_size*2)]); ul_ch0_ext[ul_ch0_ext_index] = ul_ch0[ul_ch0_index]; - ul_ch0_ptrs_ext[ul_ch0_ptrs_ext_index] = ul_ch0_ptrs[ul_ch0_ptrs_index]; - #ifdef DEBUG_RB_EXT +#ifdef DEBUG_RB_EXT printf("rxF_ext[%d] = (%d,%d)\n", rxF_ext_index>>1, rxF_ext[rxF_ext_index],rxF_ext[rxF_ext_index+1]); - #endif +#endif ul_ch0_ext_index++; - ul_ch0_ptrs_ext_index++; rxF_ext_index +=2; - } else { + } else + { k_prime++; k_prime&=1; n+=(k_prime)?0:1; } ul_ch0_index++; - ul_ch0_ptrs_index++; } } - - pusch_vars->ptrs_sc_per_ofdm_symbol = num_ptrs_symbols; - } void nr_ulsch_scale_channel(int **ul_ch_estimates_ext, @@ -1018,32 +981,19 @@ int nr_rx_pusch(PHY_VARS_gNB *gNB, unsigned char harq_pid) { - uint8_t aarx, aatx, dmrs_symbol_flag, ptrs_symbol_flag; // dmrs_symbol_flag, a flag to indicate DMRS REs in current symbol + uint8_t aarx, aatx, dmrs_symbol_flag; // dmrs_symbol_flag, a flag to indicate DMRS REs in current symbol uint32_t nb_re_pusch, bwp_start_subcarrier; - uint8_t L_ptrs = 0; // PTRS parameter int avgs; int avg[4]; NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms; nfapi_nr_pusch_pdu_t *rel15_ul = &gNB->ulsch[ulsch_id][0]->harq_processes[harq_pid]->ulsch_pdu; dmrs_symbol_flag = 0; - ptrs_symbol_flag = 0; if(symbol == rel15_ul->start_symbol_index){ gNB->pusch_vars[ulsch_id]->rxdataF_ext_offset = 0; gNB->pusch_vars[ulsch_id]->dmrs_symbol = 0; gNB->pusch_vars[ulsch_id]->cl_done = 0; - gNB->pusch_vars[ulsch_id]->ptrs_symbols = 0; - - if (rel15_ul->pdu_bit_map & PUSCH_PDU_BITMAP_PUSCH_PTRS) { // if there is ptrs pdu - L_ptrs = 1<<(rel15_ul->pusch_ptrs.ptrs_time_density); - - set_ptrs_symb_idx(&gNB->pusch_vars[ulsch_id]->ptrs_symbols, - rel15_ul->nr_of_symbols, - rel15_ul->start_symbol_index, - L_ptrs, - rel15_ul->ul_dmrs_symb_pos); - } } bwp_start_subcarrier = (rel15_ul->rb_start*NR_NB_SC_PER_RB + frame_parms->first_carrier_offset) % frame_parms->ofdm_symbol_size; @@ -1067,15 +1017,6 @@ int nr_rx_pusch(PHY_VARS_gNB *gNB, nb_re_pusch = rel15_ul->rb_size * NR_NB_SC_PER_RB; } - if (rel15_ul->pdu_bit_map & PUSCH_PDU_BITMAP_PUSCH_PTRS) { // if there is ptrs pdu - if(is_ptrs_symbol(symbol, gNB->pusch_vars[ulsch_id]->ptrs_symbols)) - { - ptrs_symbol_flag = 1; - gNB->pusch_vars[ulsch_id]->ptrs_symbol_index = symbol; - } - } - - //---------------------------------------------------------- //--------------------- Channel estimation --------------------- //---------------------------------------------------------- @@ -1103,11 +1044,9 @@ int nr_rx_pusch(PHY_VARS_gNB *gNB, frame_parms); stop_meas(&gNB->ulsch_rbs_extraction_stats); - if(ptrs_symbol_flag == 1) - { - /* Subtract total PTRS RE's in the smybol from PUSCH RE's */ - nb_re_pusch -= gNB->pusch_vars[ulsch_id]->ptrs_sc_per_ofdm_symbol; - } + //---------------------------------------------------------- + //--------------------- Channel Scaling -------------------- + //---------------------------------------------------------- nr_ulsch_scale_channel(gNB->pusch_vars[ulsch_id]->ul_ch_estimates_ext, frame_parms, @@ -1137,6 +1076,10 @@ int nr_rx_pusch(PHY_VARS_gNB *gNB, gNB->pusch_vars[ulsch_id]->cl_done = 1; } + //---------------------------------------------------------- + //--------------------- Channel Compensation --------------- + //---------------------------------------------------------- + start_meas(&gNB->ulsch_channel_compensation_stats); nr_ulsch_channel_compensation(gNB->pusch_vars[ulsch_id]->rxdataF_ext, gNB->pusch_vars[ulsch_id]->ul_ch_estimates_ext, @@ -1162,9 +1105,57 @@ int nr_rx_pusch(PHY_VARS_gNB *gNB, nr_idft(&((uint32_t*)gNB->pusch_vars[ulsch_id]->rxdataF_ext[0])[symbol * rel15_ul->rb_size * NR_NB_SC_PER_RB], nb_re_pusch); #endif - //---------------------------------------------------------- - //-------------------- LLRs computation -------------------- - //---------------------------------------------------------- + + + //---------------------------------------------------------- + //--------------------- PTRS Processing -------------------- + //---------------------------------------------------------- + + /* In case PTRS is enabled then LLR will be calculated after PTRS symbols are processed * + * otherwise LLR are calculated for each symbol based upon DMRS channel estimates only. */ + if (rel15_ul->pdu_bit_map & PUSCH_PDU_BITMAP_PUSCH_PTRS) + { + start_meas(&gNB->ulsch_ptrs_processing_stats); + nr_pusch_ptrs_processing(gNB, + rel15_ul, + ulsch_id, + nr_tti_rx, + dmrs_symbol_flag, + symbol, + nb_re_pusch); + stop_meas(&gNB->ulsch_ptrs_processing_stats); + /*---------------------------------------------------------------------------------------------------- */ + /* Calculate LLR based upon new compensated data after all PTRS symbols are processed */ + /*-----------------------------------------------------------------------------------------------------*/ + if(symbol == (rel15_ul->start_symbol_index + rel15_ul->nr_of_symbols -1)) + { + for (int aarx=0; aarx< frame_parms->nb_antennas_rx; aarx++) + { + for(uint8_t i =rel15_ul->start_symbol_index; i< (rel15_ul->start_symbol_index + rel15_ul->nr_of_symbols);i++) + { + start_meas(&gNB->ulsch_llr_stats); + nr_ulsch_compute_llr(&gNB->pusch_vars[ulsch_id]->rxdataF_ptrs_comp[aarx][i * (rel15_ul->rb_size * NR_NB_SC_PER_RB)], + gNB->pusch_vars[ulsch_id]->ul_ch_mag0, + gNB->pusch_vars[ulsch_id]->ul_ch_magb0, + &gNB->pusch_vars[ulsch_id]->llr[gNB->pusch_vars[ulsch_id]->rxdataF_ext_offset * rel15_ul->qam_mod_order], + rel15_ul->rb_size, + gNB->pusch_vars[ulsch_id]->ptrs_valid_re_per_slot[aarx][i], + i, + rel15_ul->qam_mod_order); + stop_meas(&gNB->ulsch_llr_stats); + gNB->pusch_vars[ulsch_id]->rxdataF_ext_offset = gNB->pusch_vars[ulsch_id]->rxdataF_ext_offset + gNB->pusch_vars[ulsch_id]->ptrs_valid_re_per_slot[aarx][i]; + }// symbol loop + /* For scope library rxdataF_comp is used so in PTRS case we point it to correct data pointer */ + gNB->pusch_vars[ulsch_id]->rxdataF_comp[aarx] = gNB->pusch_vars[ulsch_id]->rxdataF_ptrs_comp[aarx]; + }// antenna loop + }// last symbol check + }// PTRS processing + else // if no ptrs is enabled + { + //---------------------------------------------------------- + //-------------------- LLRs computation -------------------- + //---------------------------------------------------------- + start_meas(&gNB->ulsch_llr_stats); AssertFatal(gNB->pusch_vars[ulsch_id]->rxdataF_ext_offset * rel15_ul->qam_mod_order+nb_re_pusch*rel15_ul->qam_mod_order < (8*((3*8*6144)+12)) , "Mysterious llr buffer size check"); nr_ulsch_compute_llr(&gNB->pusch_vars[ulsch_id]->rxdataF_comp[0][symbol * rel15_ul->rb_size * NR_NB_SC_PER_RB], @@ -1177,9 +1168,9 @@ int nr_rx_pusch(PHY_VARS_gNB *gNB, rel15_ul->qam_mod_order); stop_meas(&gNB->ulsch_llr_stats); + gNB->pusch_vars[ulsch_id]->rxdataF_ext_offset = gNB->pusch_vars[ulsch_id]->rxdataF_ext_offset + nb_re_pusch; + }/* End for PTRS Condition */ } - - gNB->pusch_vars[ulsch_id]->rxdataF_ext_offset = gNB->pusch_vars[ulsch_id]->rxdataF_ext_offset + nb_re_pusch; return (0); } diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c index 93acda23f8b..07114be0803 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c @@ -372,7 +372,7 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, uint16_t m=0, n=0, dmrs_idx=0, ptrs_idx = 0; for (l=start_symbol; l<start_symbol+number_of_symbols; l++) { - + ptrs_idx = 0; // every PTRS symbol has a new gold sequence k = start_sc; n = 0; dmrs_idx = 0; diff --git a/openair1/PHY/defs_gNB.h b/openair1/PHY/defs_gNB.h index e2cdebff3ad..04c832fc3a1 100644 --- a/openair1/PHY/defs_gNB.h +++ b/openair1/PHY/defs_gNB.h @@ -403,6 +403,10 @@ typedef struct { /// - first index: rx antenna id [0..nb_antennas_rx[ /// - second index: ? [0..12*N_RB_UL*frame_parms->symbols_per_tti[ int32_t **rxdataF_comp; + /// \brief Holds the PTRS compensated signal. + /// - first index: rx antenna id [0..nb_antennas_rx[ + /// - second index: ? [0..12*N_RB_UL*frame_parms->symbols_per_tti[ + int32_t **rxdataF_ptrs_comp; /// \brief Magnitude of the UL channel estimates. Used for 2nd-bit level thresholds in LLR computation /// - first index: rx antenna id [0..nb_antennas_rx[ /// - second index: ? [0..12*N_RB_UL*frame_parms->symbols_per_tti[ @@ -446,6 +450,14 @@ typedef struct { uint16_t ptrs_symbols; // PTRS subcarriers per OFDM symbol uint16_t ptrs_sc_per_ofdm_symbol; + /// \brief Estimated phase error based upon PTRS on each symbol . + /// - first index: ? [0..7] Number of Antenna + /// - second index: ? [0...14] smybol per slot + int32_t **ptrs_phase_per_slot; + /// \brief Total RE count after PTRS RE's are extracted from respective symbol. + /// - first index: ? [0..7] Number of Antenna + /// - second index: ? [0...14] smybol per slot + int16_t **ptrs_valid_re_per_slot; /// flag to verify if channel level computation is done uint8_t cl_done; } NR_gNB_PUSCH; @@ -775,9 +787,11 @@ typedef struct PHY_VARS_gNB_s { time_stats_t ulsch_deinterleaving_stats; time_stats_t ulsch_unscrambling_stats; time_stats_t ulsch_channel_estimation_stats; + time_stats_t ulsch_ptrs_processing_stats; time_stats_t ulsch_channel_compensation_stats; time_stats_t ulsch_rbs_extraction_stats; time_stats_t ulsch_llr_stats; + /* time_stats_t rx_dft_stats; time_stats_t ulsch_freq_offset_estimation_stats; diff --git a/openair1/SIMULATION/NR_PHY/ulsim.c b/openair1/SIMULATION/NR_PHY/ulsim.c index e3cd504c3b7..999eb179ae6 100644 --- a/openair1/SIMULATION/NR_PHY/ulsim.c +++ b/openair1/SIMULATION/NR_PHY/ulsim.c @@ -447,7 +447,7 @@ int main(int argc, char **argv) 0); fix_scc(scc,ssb_bitmap); - xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, (const void*)secondaryCellGroup); + // xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, (const void*)secondaryCellGroup); AssertFatal((gNB->if_inst = NR_IF_Module_init(0))!=NULL,"Cannot register interface"); @@ -562,14 +562,13 @@ int main(int argc, char **argv) uint8_t ptrs_time_density = get_L_ptrs(ptrs_mcs1, ptrs_mcs2, ptrs_mcs3, Imcs, mcs_table); uint8_t ptrs_freq_density = get_K_ptrs(n_rb0, n_rb1, nb_rb); int ptrs_symbols = 0; // to calculate total PTRS RE's in a slot + double ts = 1.0/(frame_parms->subcarrier_spacing * frame_parms->ofdm_symbol_size); + + number_dmrs_symbols = get_dmrs_symbols_in_slot(l_prime_mask, nb_symb_sch); if(1<<ptrs_time_density >= nb_symb_sch) pdu_bit_map &= ~PUSCH_PDU_BITMAP_PUSCH_PTRS; // disable PUSCH PTRS - for (i = 0; i < nb_symb_sch; i++) { - number_dmrs_symbols += (l_prime_mask >> i) & 0x01; - } - mod_order = nr_get_Qm_ul(Imcs, 0); code_rate = nr_get_code_rate_ul(Imcs, 0); @@ -586,6 +585,7 @@ int main(int argc, char **argv) reset_meas(&gNB->ulsch_ldpc_decoding_stats); reset_meas(&gNB->ulsch_unscrambling_stats); reset_meas(&gNB->ulsch_channel_estimation_stats); + reset_meas(&gNB->ulsch_ptrs_processing_stats); reset_meas(&gNB->ulsch_llr_stats); reset_meas(&gNB->ulsch_channel_compensation_stats); reset_meas(&gNB->ulsch_rbs_extraction_stats); @@ -765,19 +765,24 @@ int main(int argc, char **argv) int error_flag; for (trial = 0; trial < n_trials; trial++) { - - error_flag = 0; - //---------------------------------------------------------- - //------------------------ add noise ----------------------- - //---------------------------------------------------------- - if (input_fd == NULL ) { - for (i=0; i<slot_length; i++) { - for (ap=0; ap<frame_parms->nb_antennas_rx; ap++) { - ((int16_t*) &gNB->common_vars.rxdata[ap][slot_offset])[(2*i) + (delay*2)] = (int16_t)((double)(((int16_t *)&UE->common_vars.txdata[ap][slot_offset])[(i<<1)])/sqrt(scale) + (sqrt(sigma/2)*gaussdouble(0.0,1.0))); // convert to fixed point - ((int16_t*) &gNB->common_vars.rxdata[ap][slot_offset])[(2*i)+1 + (delay*2)] = (int16_t)((double)(((int16_t *)&UE->common_vars.txdata[ap][slot_offset])[(i<<1)+1])/sqrt(scale) + (sqrt(sigma/2)*gaussdouble(0.0,1.0))); - } - } - } + + error_flag = 0; + //---------------------------------------------------------- + //------------------------ add noise ----------------------- + //---------------------------------------------------------- + if (input_fd == NULL ) { + for (i=0; i<slot_length; i++) { + for (ap=0; ap<frame_parms->nb_antennas_rx; ap++) { + /* Add phase noise if enabled */ + if (pdu_bit_map & PUSCH_PDU_BITMAP_PUSCH_PTRS) { + phase_noise(ts, &((int16_t*)&UE->common_vars.txdata[ap][slot_offset])[(i<<1)], + &((int16_t*)&UE->common_vars.txdata[ap][slot_offset])[(i<<1)+1]); + } + ((int16_t*) &gNB->common_vars.rxdata[ap][slot_offset])[(2*i) + (delay*2)] = (int16_t)((double)(((int16_t *)&UE->common_vars.txdata[ap][slot_offset])[(i<<1)])/sqrt(scale) + (sqrt(sigma/2)*gaussdouble(0.0,1.0))); // convert to fixed point + ((int16_t*) &gNB->common_vars.rxdata[ap][slot_offset])[(2*i)+1 + (delay*2)] = (int16_t)((double)(((int16_t *)&UE->common_vars.txdata[ap][slot_offset])[(i<<1)+1])/sqrt(scale) + (sqrt(sigma/2)*gaussdouble(0.0,1.0))); + } + } + } else { AssertFatal(frame_parms->nb_antennas_rx == 1, "nb_ant != 1\n"); // 800 samples is N_TA_OFFSET for FR1 @ 30.72 Ms/s, @@ -825,6 +830,10 @@ int main(int argc, char **argv) &gNB->pusch_vars[0]->ul_ch_estimates_ext[0][(start_symbol+1)*NR_NB_SC_PER_RB * pusch_pdu->rb_size],(nb_symb_sch-1)*NR_NB_SC_PER_RB * pusch_pdu->rb_size,1,1); LOG_M("rxsigF0_comp.m","rxsF0_comp", &gNB->pusch_vars[0]->rxdataF_comp[0][(start_symbol+1)*NR_NB_SC_PER_RB * pusch_pdu->rb_size],(nb_symb_sch-1)*NR_NB_SC_PER_RB * pusch_pdu->rb_size,1,1); +#ifdef DEBUG_UL_PTRS + LOG_M("rxdataF_ptrs_comp.m","ptrs_comp", + &gNB->pusch_vars[0]->rxdataF_ptrs_comp[0][(start_symbol+1)*NR_NB_SC_PER_RB * pusch_pdu->rb_size],(nb_symb_sch-1)*NR_NB_SC_PER_RB * pusch_pdu->rb_size,1,1); +#endif } start_meas(&gNB->phy_proc_rx); //////////////////////////////////////////////////////////// @@ -902,6 +911,7 @@ int main(int argc, char **argv) if (print_perf==1) { printDistribution(&gNB->phy_proc_rx,table_rx,"Total PHY proc rx"); printStatIndent(&gNB->ulsch_channel_estimation_stats,"ULSCH channel estimation time"); + printStatIndent(&gNB->ulsch_ptrs_processing_stats,"ULSCH PTRS Processing time"); printStatIndent(&gNB->ulsch_rbs_extraction_stats,"ULSCH rbs extraction time"); printStatIndent(&gNB->ulsch_channel_compensation_stats,"ULSCH channel compensation time"); printStatIndent(&gNB->ulsch_llr_stats,"ULSCH llr computation"); diff --git a/openair1/SIMULATION/TOOLS/phase_noise.c b/openair1/SIMULATION/TOOLS/phase_noise.c new file mode 100644 index 00000000000..f243a09c59e --- /dev/null +++ b/openair1/SIMULATION/TOOLS/phase_noise.c @@ -0,0 +1,42 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#include <stdio.h> +#include <stdlib.h> +#include <math.h> +#include <time.h> +#include "sim.h" + + +/* linear phase noise model */ +void phase_noise(double ts, int16_t * InRe, int16_t * InIm) +{ + double fd = 300;//0.01*30000 + static double i=0; + double real, imag,x ,y; + i++; + real = cos(fd * 2 * M_PI * i * ts); + imag = sin (fd * 2 * M_PI * i * ts); + x = ((real * (double)InRe[0]) - (imag * (double)InIm[0])) ; + y= ((real * (double)InIm[0]) + (imag * (double)InRe[0])) ; + InRe[0]= (int16_t)(x); + InIm[0]= (int16_t)(y); +} diff --git a/openair1/SIMULATION/TOOLS/sim.h b/openair1/SIMULATION/TOOLS/sim.h index 6071e1e7438..29f4234a382 100644 --- a/openair1/SIMULATION/TOOLS/sim.h +++ b/openair1/SIMULATION/TOOLS/sim.h @@ -440,6 +440,14 @@ void init_channelmod(void) ; double N_RB2sampling_rate(uint16_t N_RB); double N_RB2channel_bandwidth(uint16_t N_RB); +/* Linear phase noise model */ +/*! + \brief This function produce phase noise and add to input signal + \param ts Sampling time + \param *Re *Im Real and Imag part of the signal +*/ +void phase_noise(double ts, int16_t * InRe, int16_t * InIm); + #include "targets/RT/USER/rfsim.h" void do_DL_sig(sim_t *sim, -- GitLab