diff --git a/.gitignore b/.gitignore
index 8f8ff1f4548dc35d14b66d973dabe4b652aedbb8..ff947966a2b9c7814a8ca64228810130cabe96f6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -12,3 +12,9 @@ targets/bin/
 
 # vscode
 .vscode
+
+# Tags for vim/global
+GPATH
+GRTAGS
+GTAGS
+tags
diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt
index e540c3f95d7b52b49c67f25a48167905accb0c6e..0977f6c0d9971cf10f29b6bc15b36ef586fd4cec 100644
--- a/cmake_targets/CMakeLists.txt
+++ b/cmake_targets/CMakeLists.txt
@@ -2377,6 +2377,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/autotests/test_case_list.xml b/cmake_targets/autotests/test_case_list.xml
index 786002e9823b6a0a866c11947b061489d5d85c89..7e43a9d01c7f1db7d6a0035babdf62b9675d5d24 100644
--- a/cmake_targets/autotests/test_case_list.xml
+++ b/cmake_targets/autotests/test_case_list.xml
@@ -1276,7 +1276,10 @@
                                  (Test2: MCS 16 50 PRBs),
                                  (Test3: MCS 28 50 PRBs),
                                  (Test4: MCS 9 217 PRBs),
-                                 (Test5: MCS 9 273 PRBs)</desc>
+                                 (Test5: MCS 9 273 PRBs),
+                                 (Test6: DMRS Type A, 3 DMRS, 4 PTRS, 5 Interpolated Symbols),
+                                 (Test7: DMRS Type B, 3 DMRS, 2 PTRS, 7 Interpolated Symbols),
+                                 (Test8: DMRS Type B, 3 DMRS, 2 PTRS, 3 Interpolated Symbols)</desc>
       <pre_compile_prog></pre_compile_prog>
       <compile_prog>$OPENAIR_DIR/cmake_targets/build_oai</compile_prog>
       <compile_prog_args> --phy_simulators  -c </compile_prog_args>
@@ -1287,8 +1290,11 @@
                       -n100 -m16 -s10
                       -n100 -m28 -s20
                       -n100 -m9 -R217 -r217 -s5
-                      -n100 -m9 -R273 -r273 -s5</main_exec_args>
-      <tags>nr_ulsim.test1 nr_ulsim.test2 nr_ulsim.test3 nr_ulsim.test4 nr_ulsim.test5</tags>
+                      -n100 -m9 -R273 -r273 -s5
+                      -n100 -s5 -T 2 1 2 -U 2 0 2
+                      -n100 -s5 -T 2 2 2 -U 2 1 2
+                      -n100 -s5 -a4 -b8 -T 2 1 2 -U 2 1 3</main_exec_args>
+      <tags>nr_ulsim.test1 nr_ulsim.test2 nr_ulsim.test3 nr_ulsim.test4 nr_ulsim.test5 nr_ulsim.test6 nr_ulsim.test7 nr_ulsim.test8</tags>
       <search_expr_true>PUSCH test OK</search_expr_true>
       <search_expr_false>segmentation fault|assertion|exiting|fatal</search_expr_false>
       <nruns>3</nruns>
diff --git a/cmake_targets/build_oai b/cmake_targets/build_oai
index 36af9eaee4cd3538d1a8914a55b0ebb34b3bfa27..f301908495e1e1f6e74b5dd0743ba26d7de990b7 100755
--- a/cmake_targets/build_oai
+++ b/cmake_targets/build_oai
@@ -211,7 +211,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 35a9a159618b1c1370d8b5a682f854abeeabdc2d..057d259baad6cf52b0597d4c4d741fb20c0279f9 100644
--- a/openair1/PHY/INIT/nr_init.c
+++ b/openair1/PHY/INIT/nr_init.c
@@ -251,10 +251,11 @@ 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]->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]->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*) );
@@ -268,16 +269,18 @@ 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]->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]->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) );
     }
     printf("ULSCH_id %d (before llr alloc) : %p\n",ULSCH_id,gNB->dlsch[0][0]->harq_processes[0]);
     pusch_vars[ULSCH_id]->llr = (int16_t *)malloc16_clear( (8*((3*8*6144)+12))*sizeof(int16_t) ); // [hna] 6144 is LTE and (8*((3*8*6144)+12)) is not clear
-    printf("ULSCH_id %d (after llr alloc) : %p\n",ULSCH_id,gNB->dlsch[0][0]->harq_processes[0]); 
+    printf("ULSCH_id %d (after llr alloc) : %p\n",ULSCH_id,gNB->dlsch[0][0]->harq_processes[0]);
+    pusch_vars[ULSCH_id]->ul_valid_re_per_slot  = (int16_t *)malloc16_clear( sizeof(int16_t)*fp->symbols_per_slot);
   } //ulsch_id
 /*
   for (ulsch_id=0; ulsch_id<NUMBER_OF_UE_MAX; ulsch_id++)
@@ -338,6 +341,7 @@ 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]->rxdataF_comp[i]);
       free_and_zero(pusch_vars[ULSCH_id]->ul_ch_mag0[i]);
       free_and_zero(pusch_vars[ULSCH_id]->ul_ch_magb0[i]);
@@ -353,6 +357,8 @@ 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]->ul_valid_re_per_slot);
     free_and_zero(pusch_vars[ULSCH_id]->rxdataF_comp);
     free_and_zero(pusch_vars[ULSCH_id]->ul_ch_mag0);
     free_and_zero(pusch_vars[ULSCH_id]->ul_ch_magb0);
diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c
index bfc29ab4f528a97cf64046a325ab80e87f97f0bd..b6388fb903d50be7b0ecae827c47c42183dd6146 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
@@ -507,3 +509,408 @@ 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;
+
+  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];
+    /* set the previous estimations to zero at first symbol */
+    if(symbol == rel15_ul->start_symbol_index)
+    {
+      memset(phase_per_symbol,0,sizeof(int32_t)*frame_parms->symbols_per_slot);
+    }
+    /* 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);
+    }
+    /* 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 */
+
+#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 );
+      LOG_M("rxdataF_bf_ptrs_comp.m","bf_ptrs_cmp",
+            &gNB->pusch_vars[0]->rxdataF_comp[aarx][rel15_ul->start_symbol_index * NR_NB_SC_PER_RB * rel15_ul->rb_size],
+            rel15_ul->nr_of_symbols * NR_NB_SC_PER_RB * rel15_ul->rb_size,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_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;
+  uint16_t              sc_per_symbol    = (rel15_ul->rb_size + 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_UL_PTRS
+  double                alpha            = 0;
+#endif
+  /* generate PTRS RE for the symbol */
+  nr_gen_ref_conj_symbols(ptrs_gold_seq[Ns][symbol],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_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 17d8c998c9c926e1c896c72dbaed74233461916b..0f71487e36366b740f3ee49a25ff2ec58dea2d89 100644
--- a/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h
+++ b/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h
@@ -51,4 +51,30 @@ void gNB_I0_measurements(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 7042c152fdf8ee0544b7d4f68c0cb0bcb64414cc..415e6adfa288f463a1eacfed4f2729ad1e2eed13 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 4eeb8a6e96f18214cfdcf2877e15b64b9328ba84..3e758c4fa5e9297c599b297704021ac5dabf3117 100644
--- a/openair1/PHY/NR_REFSIG/nr_dmrs_rx.c
+++ b/openair1/PHY/NR_REFSIG/nr_dmrs_rx.c
@@ -223,3 +223,27 @@ 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_gen_ref_conj_symbols(uint32_t *in, uint32_t length, int16_t *output, uint16_t offset, int mod_order)
+{
+  uint8_t idx, b_idx;
+  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 ab9beb780a409593ff3c08bc2528ffdbd5af44fc..ced7f9eb667b69d14ef8ec532bc24bc5bba0fed9 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_gen_ref_conj_symbols(uint32_t *in, uint32_t length, int16_t *output, uint16_t offset, int mod_order);
+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);
 
 void nr_generate_modulation_table(void);
 
diff --git a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h
index b8025a828b516d1e7dc82eb8c5f2fe3bae9bfe52..8cb7ad45e7444935c1b5a23c22614af213147b35 100644
--- a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h
+++ b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h
@@ -157,7 +157,6 @@ void nr_ulsch_extract_rbs_single(int32_t **rxdataF,
                                  NR_gNB_PUSCH *pusch_vars,
                                  unsigned char symbol,
                                  uint8_t is_dmrs_symbol,
-				 uint8_t is_ptrs_symbol,
                                  nfapi_nr_pusch_pdu_t *pusch_pdu,
                                  NR_DL_FRAME_PARMS *frame_parms);
 
diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c
index 622e18f08295256f3b0e6ff364a3b11e26b85e6c..3fd7966ce74d7fba7732442a452c0d5e68a3a552 100644
--- a/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c
+++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c
@@ -226,25 +226,19 @@ void nr_ulsch_extract_rbs_single(int32_t **rxdataF,
                                  NR_gNB_PUSCH *pusch_vars,
                                  unsigned char symbol,
                                  uint8_t is_dmrs_symbol,
-				 uint8_t is_ptrs_symbol,
                                  nfapi_nr_pusch_pdu_t *pusch_pdu,
                                  NR_DL_FRAME_PARMS *frame_parms)
 {
 
   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 k_prime;
-  uint16_t n=0, num_ptrs_symbols;
+  uint16_t n;
   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
@@ -253,8 +247,8 @@ 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=0,is_ptrs_re=0;
+
+  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;
 #ifdef __AVX2__
@@ -263,10 +257,8 @@ void nr_ulsch_extract_rbs_single(int32_t **rxdataF,
   int nb_re_pusch2 = nb_re_pusch;
 #endif
 
-  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_pusch2]; // [hna] rxdataF_ext isn't contiguous in order to solve an alignment problem ib llr computation in case of mod_order = 4, 6
 
@@ -274,20 +266,17 @@ void nr_ulsch_extract_rbs_single(int32_t **rxdataF,
 
     ul_ch0_ext = &pusch_vars->ul_ch_estimates_ext[aarx][symbol*nb_re_pusch2];
 
-    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;
 
-    if (is_dmrs_symbol == 0 && is_ptrs_symbol == 0) {
+    if (is_dmrs_symbol == 0) {
       //
       //rxF[ ((start_re + re)*2)      % (frame_parms->ofdm_symbol_size*2)]);
-      if (start_re + nb_re_pusch < frame_parms->ofdm_symbol_size) memcpy1((void*)rxF_ext,
-									 (void*)&rxF[start_re*2],
-									 nb_re_pusch*sizeof(int32_t));
-      else {
+      if (start_re + nb_re_pusch < frame_parms->ofdm_symbol_size) {
+        memcpy1((void*)rxF_ext,
+                (void*)&rxF[start_re*2],
+                nb_re_pusch*sizeof(int32_t));
+      } else {
 	int neg_length = frame_parms->ofdm_symbol_size-start_re;
 	int pos_length = nb_re_pusch-neg_length;
 
@@ -298,58 +287,36 @@ void nr_ulsch_extract_rbs_single(int32_t **rxdataF,
     }
     else {
       for (re = 0; re < nb_re_pusch; re++) {
-	
-	if (is_dmrs_symbol) is_dmrs_re = (re == get_dmrs_freq_idx_ul(n, k_prime, delta, pusch_pdu->dmrs_config_type));
-	
-	if (is_ptrs_symbol) {
-	  K_ptrs = (pusch_pdu->pusch_ptrs.ptrs_freq_density)?4:2;
-	  is_ptrs_re = 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);
-	  
-	  num_ptrs_symbols+=is_ptrs_re;
-	  
-	}
-	
+
+        is_dmrs_re = (re == get_dmrs_freq_idx_ul(n, k_prime, delta, pusch_pdu->dmrs_config_type));
+
 #ifdef DEBUG_RB_EXT
-	printf("re = %d, kprime %d, n %d, is_ptrs_symbol = %d, symbol = %d\n", re, k_prime,n,is_ptrs_symbol, symbol);
+        printf("re = %d, kprime %d, n %d, is_dmrs_symbol = %d, symbol = %d\n", re, k_prime, n, is_dmrs_symbol, symbol);
 #endif
 
-	if ( is_dmrs_re == 0 && is_ptrs_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)]);
-	  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];
-	  
+        /* 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)]);
+          ul_ch0_ext[ul_ch0_ext_index] = ul_ch0[ul_ch0_index];
+
 #ifdef DEBUG_RB_EXT
-	  printf("dmrs symb %d: rxF_ext[%d] = (%d,%d), ul_ch0_ext[%d] = (%d,%d)\n", 
-		 is_dmrs_symbol,rxF_ext_index>>1, rxF_ext[rxF_ext_index],rxF_ext[rxF_ext_index+1],
-		 ul_ch0_ext_index,  ((int16_t*)&ul_ch0_ext[ul_ch0_ext_index])[0],  ((int16_t*)&ul_ch0_ext[ul_ch0_ext_index])[1]);
+          printf("dmrs symb %d: rxF_ext[%d] = (%d,%d), ul_ch0_ext[%d] = (%d,%d)\n",
+                 is_dmrs_symbol,rxF_ext_index>>1, rxF_ext[rxF_ext_index],rxF_ext[rxF_ext_index+1],
+                 ul_ch0_ext_index,  ((int16_t*)&ul_ch0_ext[ul_ch0_ext_index])[0],  ((int16_t*)&ul_ch0_ext[ul_ch0_ext_index])[1]);
 #endif
-	  ul_ch0_ext_index++;
-	  ul_ch0_ptrs_ext_index++;
-	  rxF_ext_index +=2;
-	} else {
-	  k_prime++;
-	  k_prime&=1;
-	  n+=(k_prime)?0:1;
-	}
-	ul_ch0_index++;
-	ul_ch0_ptrs_index++;
+          ul_ch0_ext_index++;
+          rxF_ext_index +=2;
+        } else {
+          n += k_prime;
+          k_prime ^= 1;
+        }
+        ul_ch0_index++;
       }
-    } // is_dmrs_symbol ==0 && is_ptrs_symbol == 0
-  }  
-  pusch_vars->ptrs_sc_per_ofdm_symbol = num_ptrs_symbols;
-    
+    }
+  }
 }
-  
+
 void nr_ulsch_scale_channel(int **ul_ch_estimates_ext,
                             NR_DL_FRAME_PARMS *frame_parms,
                             NR_gNB_ULSCH_t **ulsch_gNB,
@@ -1116,34 +1083,17 @@ int nr_rx_pusch(PHY_VARS_gNB *gNB,
 {
 
   uint8_t aarx, aatx, dmrs_symbol_flag; // dmrs_symbol_flag, a flag to indicate DMRS REs in current symbol
-  uint8_t ptrs_symbol_flag; // a flag to indicate PTRS 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;
-
-  gNB->pusch_vars[ulsch_id]->ptrs_sc_per_ofdm_symbol = 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);
-    }
   }
 
 
@@ -1172,13 +1122,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)) {
-      gNB->pusch_vars[ulsch_id]->ptrs_symbol_index = symbol;
-      ptrs_symbol_flag = 1;
-    }
-  }
-
   //----------------------------------------------------------
   //--------------------- Channel estimation ---------------------
   //----------------------------------------------------------
@@ -1206,16 +1149,21 @@ int nr_rx_pusch(PHY_VARS_gNB *gNB,
 
   if (nb_re_pusch > 0) {
 
+    gNB->pusch_vars[ulsch_id]->ul_valid_re_per_slot[symbol] = nb_re_pusch;
+
     start_meas(&gNB->ulsch_rbs_extraction_stats);
     nr_ulsch_extract_rbs_single(gNB->common_vars.rxdataF,
                                 gNB->pusch_vars[ulsch_id],
                                 symbol,
                                 dmrs_symbol_flag,
-				ptrs_symbol_flag,
                                 rel15_ul,
                                 frame_parms);
     stop_meas(&gNB->ulsch_rbs_extraction_stats);
 
+    //----------------------------------------------------------
+    //--------------------- Channel Scaling --------------------
+    //----------------------------------------------------------
+
     nr_ulsch_scale_channel(gNB->pusch_vars[ulsch_id]->ul_ch_estimates_ext,
                            frame_parms,
                            gNB->ulsch[ulsch_id],
@@ -1244,6 +1192,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,
@@ -1271,29 +1223,54 @@ 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 --------------------
-  //----------------------------------------------------------
-    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");
+
+    //----------------------------------------------------------
+    //--------------------- 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);
+
+      /*  Subtract total PTRS RE's in the symbol from PUSCH RE's */
+      gNB->pusch_vars[ulsch_id]->ul_valid_re_per_slot[symbol] -= gNB->pusch_vars[ulsch_id]->ptrs_sc_per_ofdm_symbol;
+    }
+
+    /*---------------------------------------------------------------------------------------------------- */
+    /*--------------------  LLRs computation  -------------------------------------------------------------*/
+    /*-----------------------------------------------------------------------------------------------------*/
+    if(symbol == (rel15_ul->start_symbol_index + rel15_ul->nr_of_symbols -1))
+    {
 #ifdef __AVX2__
-    int off = ((rel15_ul->rb_size&1) == 1)? 4:0;
+      int off = ((rel15_ul->rb_size&1) == 1)? 4:0;
 #else
-    int off = 0;
+      int off = 0;
 #endif
-    nr_ulsch_compute_llr(&gNB->pusch_vars[ulsch_id]->rxdataF_comp[0][symbol * (off+(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,
-                         nb_re_pusch,
-                         symbol,
-                         rel15_ul->qam_mod_order);
-    stop_meas(&gNB->ulsch_llr_stats);
-
+      uint32_t rxdataF_ext_offset = 0;
+      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_comp[0][i * (off + 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[rxdataF_ext_offset * rel15_ul->qam_mod_order],
+                             rel15_ul->rb_size,
+                             gNB->pusch_vars[ulsch_id]->ul_valid_re_per_slot[i],
+                             i,
+                             rel15_ul->qam_mod_order);
+        stop_meas(&gNB->ulsch_llr_stats);
+        rxdataF_ext_offset += gNB->pusch_vars[ulsch_id]->ul_valid_re_per_slot[i];
+      }// symbol loop
+    }// last symbol check
   }
-
-  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 bb82140905e09d50f8b5def6810717d6171b43d3..c85a7691f6f39f447ba0d314db727ffb044dd785 100644
--- a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c
+++ b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c
@@ -226,12 +226,12 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE,
   /////////////////////////PTRS parameters' initialization/////////////////////////
   ///////////
 
-  int16_t mod_ptrs[(nb_rb/2)*(NR_SYMBOLS_PER_SLOT-1)*2]; // assume maximum number of PTRS per pusch allocation
+  int16_t mod_ptrs[nb_rb] __attribute((aligned(16))); // assume maximum number of PTRS per pusch allocation
   K_ptrs = 0; // just to avoid a warning
 
   if (harq_process_ul_ue->pusch_pdu.pdu_bit_map & PUSCH_PDU_BITMAP_PUSCH_PTRS) {
 
-    K_ptrs = (harq_process_ul_ue->pusch_pdu.pusch_ptrs.ptrs_freq_density)?4:2;
+    K_ptrs = harq_process_ul_ue->pusch_pdu.pusch_ptrs.ptrs_freq_density;
     L_ptrs = 1<<harq_process_ul_ue->pusch_pdu.pusch_ptrs.ptrs_time_density;
 
     beta_ptrs = 1; // temp value until power control is implemented
@@ -322,7 +322,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 6c2561a45436a751ca4a3c827529372a0c40b585..179ca0331f5e9fd4064a696c5c229157a5f1fb1a 100644
--- a/openair1/PHY/defs_gNB.h
+++ b/openair1/PHY/defs_gNB.h
@@ -397,8 +397,6 @@ typedef struct {
   /// - first index: rx antenna id [0..nb_antennas_rx[
   /// - second index (definition from phy_init_lte_eNB()): ? [0..12*N_RB_UL*frame_parms->symbols_per_tti[
   int32_t **rxdataF_ext2;
-  /// \brief Offset for calculating the index of rxdataF_ext for the current symbol
-  uint32_t rxdataF_ext_offset;
   /// \brief Hold the channel estimates in time domain based on DRS.
   /// - first index: rx antenna id [0..nb_antennas_rx[
   /// - second index: ? [0..4*ofdm_symbol_size[
@@ -466,6 +464,13 @@ 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 DMRS/PTRS RE's are extracted from respective symbol.
+  /// - first index: ? [0...14] smybol per slot
+  int16_t *ul_valid_re_per_slot;
   /// flag to verify if channel level computation is done
   uint8_t cl_done;
 } NR_gNB_PUSCH;
@@ -807,10 +812,12 @@ 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_mrc_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 6e4970525d4bf98f2919c523ca078234067b8cbe..9dd6d61557bd3986f7312ed7848cda8ed7db8c24 100644
--- a/openair1/SIMULATION/NR_PHY/ulsim.c
+++ b/openair1/SIMULATION/NR_PHY/ulsim.c
@@ -165,6 +165,13 @@ int main(int argc, char **argv)
   //float eff_tp_check = 0.7;
   uint8_t snrRun;
 
+  int enable_ptrs = 0;
+  int modify_dmrs = 0;
+  /* L_PTRS = ptrs_arg[0], K_PTRS = ptrs_arg[1] */
+  int ptrs_arg[2] = {-1,-1};// Invalid values
+  /* DMRS TYPE = dmrs_arg[0], Add Pos = dmrs_arg[1] */
+  int dmrs_arg[2] = {-1,-1};// Invalid values
+
   UE_nr_rxtx_proc_t UE_proc;
   FILE *scg_fd=NULL;
   int file_offset = 0;
@@ -181,7 +188,7 @@ int main(int argc, char **argv)
   //logInit();
   randominit(0);
 
-  while ((c = getopt(argc, argv, "a:b:c:d:ef:g:h:i:j:kl:m:n:p:r:s:y:z:F:M:N:PR:S:L:G:H:")) != -1) {
+  while ((c = getopt(argc, argv, "a:b:c:d:ef:g:h:i:j:kl:m:n:p:r:s:y:z:F:G:H:M:N:PR:S:T:U:L:")) != -1) {
     printf("handling optarg %c\n",c);
     switch (c) {
 
@@ -359,7 +366,15 @@ int main(int argc, char **argv)
       }
       
       break;
-      
+
+    case 'G':
+      file_offset = atoi(optarg);
+      break;
+
+    case 'H':
+      slot = atoi(optarg);
+      break;
+
     case 'M':
      // SSB_positions = atoi(optarg);
       break;
@@ -388,14 +403,20 @@ int main(int argc, char **argv)
       loglvl = atoi(optarg);
       break;
 
-    case 'G':
-      file_offset = atoi(optarg);
+   case 'T':
+      enable_ptrs=1;
+      for(i=0; i < atoi(optarg); i++){
+        ptrs_arg[i] = atoi(argv[optind++]);
+      }
       break;
 
-    case 'H':
-      slot = atoi(optarg);
+    case 'U':
+      modify_dmrs = 1;
+      for(i=0; i < atoi(optarg); i++){
+        dmrs_arg[i] = atoi(argv[optind++]);
+      }
       break;
-  
+
     default:
     case 'h':
       printf("%s -h(elp) -p(extended_prefix) -N cell_id -f output_filename -F input_filename -g channel_model -n n_frames -t Delayspread -s snr0 -S snr1 -x transmission_mode -y TXant -z RXant -i Intefrence0 -j Interference1 -A interpolation_file -C(alibration offset dB) -N CellId\n", argv[0]);
@@ -425,6 +446,8 @@ int main(int argc, char **argv)
       printf("-t Acceptable effective throughput (in percentage)\n");
       printf("-S Ending SNR, runs from SNR0 to SNR1\n");
       printf("-P Print ULSCH performances\n");
+      printf("-T Enable PTRS, arguments list L_PTRS{0,1,2} K_PTRS{2,4}, e.g. -T 2 0 2 \n");
+      printf("-U Change DMRS Config, arguments list DMRS TYPE{0=A,1=B} DMRS AddPos{0:3}, e.g. -U 2 0 2 \n");
       exit(-1);
       break;
 
@@ -469,7 +492,7 @@ int main(int argc, char **argv)
   UE2gNB->max_Doppler = maxDoppler;
 
   RC.gNB = (PHY_VARS_gNB **) malloc(sizeof(PHY_VARS_gNB *));
-  RC.gNB[0] = malloc(sizeof(PHY_VARS_gNB));
+  RC.gNB[0] = calloc(1,sizeof(PHY_VARS_gNB));
   gNB = RC.gNB[0];
   //gNB_config = &gNB->gNB_config;
 
@@ -513,7 +536,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");
 
@@ -607,13 +630,9 @@ int main(int argc, char **argv)
 
   nr_scheduled_response_t scheduled_response;
   fapi_nr_ul_config_request_t ul_config;
+  fapi_nr_tx_request_t tx_req;
+  fapi_nr_tx_request_body_t tx_req_body;
 
-  unsigned int TBS;
-  uint16_t number_dmrs_symbols = 0;
-  unsigned int available_bits;
-  uint8_t nb_re_dmrs;
-  unsigned char mod_order;
-  uint16_t code_rate;
   uint8_t ptrs_mcs1 = 2;
   uint8_t ptrs_mcs2 = 4;
   uint8_t ptrs_mcs3 = 10;
@@ -624,23 +643,74 @@ int main(int argc, char **argv)
   uint8_t max_rounds = 4;
   uint8_t crc_status = 0;
 
-  uint8_t length_dmrs = pusch_len1; // [hna] remove dmrs struct
-  uint16_t l_prime_mask = get_l_prime(nb_symb_sch, typeB, pusch_dmrs_pos0, length_dmrs);  // [hna] remove dmrs struct
+  unsigned char mod_order = nr_get_Qm_ul(Imcs, 0);
+  uint16_t      code_rate = nr_get_code_rate_ul(Imcs, 0);
+
+  uint8_t mapping_type = typeB; // Default Values
+  pusch_dmrs_type_t dmrs_config_type = pusch_dmrs_type1; // Default Values
+  pusch_dmrs_AdditionalPosition_t add_pos = pusch_dmrs_pos0; // Default Values
+
+  /* validate parameters othwerwise default values are used */
+  /* -U flag can be used to set DMRS parameters*/
+  if(modify_dmrs)
+  {
+    if(dmrs_arg[0] == 0)
+    {
+      mapping_type = typeA;
+    }
+    else if (dmrs_arg[0] == 1)
+    {
+      mapping_type = typeB;
+    }
+    /* Additional DMRS positions */
+    if(dmrs_arg[1] >= 0 && dmrs_arg[1] <=3 )
+    {
+      add_pos = dmrs_arg[1];
+    }
+    printf("NOTE: DMRS config is modified with Mapping Type %d , Additional Position %d \n", mapping_type, add_pos );
+  }
+
+  uint8_t  length_dmrs         = pusch_len1;
+  uint16_t l_prime_mask        = get_l_prime(nb_symb_sch, mapping_type, add_pos, length_dmrs);
+  uint16_t number_dmrs_symbols = get_dmrs_symbols_in_slot(l_prime_mask, nb_symb_sch);
+  uint8_t  nb_re_dmrs          = (dmrs_config_type == pusch_dmrs_type1) ? 6 : 4;
+  unsigned int available_bits  = nr_get_G(nb_rb, nb_symb_sch, nb_re_dmrs, number_dmrs_symbols, mod_order, 1);
+  unsigned int TBS             = nr_compute_tbs(mod_order, code_rate, nb_rb, nb_symb_sch, nb_re_dmrs * number_dmrs_symbols, 0, 0, precod_nbr_layers);
+
+  uint8_t ulsch_input_buffer[TBS/8];
+
+  ulsch_input_buffer[0] = 0x31;
+  for (i = 1; i < TBS/8; i++) {
+    ulsch_input_buffer[i] = (unsigned char) rand();
+  }
+
   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);
+
+  /* -T option enable PTRS */
+  if(enable_ptrs)
+  {
+    /* validate parameters othwerwise default values are used */
+    if(ptrs_arg[0] == 0 || ptrs_arg[0] == 1 || ptrs_arg[0] == 2 )
+    {
+      ptrs_time_density = ptrs_arg[0];
+    }
+    if(ptrs_arg[1] == 2 || ptrs_arg[1] == 4 )
+    {
+      ptrs_freq_density = ptrs_arg[1];
+    }
+    pdu_bit_map |= PUSCH_PDU_BITMAP_PUSCH_PTRS;
+    printf("NOTE: PTRS Enabled with L %d, K %d \n", ptrs_time_density, ptrs_freq_density );
+  }
 
   if (input_fd != NULL) max_rounds=1;
 
   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);
-
   printf("\n");
 
   //for (int i=0;i<16;i++) printf("%f\n",gaussdouble(0.0,1.0));
@@ -715,6 +785,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_mrc_stats);
       reset_meas(&gNB->ulsch_channel_compensation_stats);
@@ -723,23 +794,6 @@ int main(int argc, char **argv)
       UE_proc.nr_tti_tx = slot;
       UE_proc.frame_tx = frame;
 
-      // --------- setting parameters for gNB --------
-      /*
-      rel15_ul->rnti                           = n_rnti;
-      rel15_ul->ulsch_pdu_rel15.start_rb       = start_rb;
-      rel15_ul->ulsch_pdu_rel15.number_rbs     = nb_rb;
-      rel15_ul->ulsch_pdu_rel15.start_symbol   = start_symbol;
-      rel15_ul->ulsch_pdu_rel15.number_symbols = nb_symb_sch;
-      rel15_ul->ulsch_pdu_rel15.length_dmrs    = length_dmrs;
-      rel15_ul->ulsch_pdu_rel15.Qm             = mod_order;
-      rel15_ul->ulsch_pdu_rel15.mcs            = Imcs;
-      rel15_ul->ulsch_pdu_rel15.rv             = 0;
-      rel15_ul->ulsch_pdu_rel15.ndi            = 0;
-      rel15_ul->ulsch_pdu_rel15.n_layers       = precod_nbr_layers;
-      rel15_ul->ulsch_pdu_rel15.R              = code_rate; 
-      ///////////////////////////////////////////////////
-      */
-
       UL_tti_req->SFN = frame;
       UL_tti_req->Slot = slot;
       UL_tti_req->n_pdus = 1;
@@ -766,6 +820,7 @@ int main(int argc, char **argv)
 	pusch_pdu->bwp_size = abwp_size;
       }
 
+      pusch_pdu->pusch_data.tb_size = TBS/8;
       pusch_pdu->pdu_bit_map = pdu_bit_map;
       pusch_pdu->rnti = n_rnti;
       pusch_pdu->mcs_index = Imcs;
@@ -776,7 +831,7 @@ int main(int argc, char **argv)
       pusch_pdu->data_scrambling_id = *scc->physCellId;
       pusch_pdu->nrOfLayers = 1;
       pusch_pdu->ul_dmrs_symb_pos = l_prime_mask << start_symbol;
-      pusch_pdu->dmrs_config_type = 0;
+      pusch_pdu->dmrs_config_type = dmrs_config_type;
       pusch_pdu->ul_dmrs_scrambling_id =  *scc->physCellId;
       pusch_pdu->scid = 0;
       pusch_pdu->dmrs_ports = 1;
@@ -809,8 +864,17 @@ int main(int argc, char **argv)
       scheduled_response.slot = slot;
       scheduled_response.dl_config = NULL;
       scheduled_response.ul_config = &ul_config;
-      scheduled_response.tx_request = (fapi_nr_tx_request_t *) malloc(sizeof(fapi_nr_tx_request_t));
-      scheduled_response.tx_request->tx_request_body = (fapi_nr_tx_request_body_t *) malloc(sizeof(fapi_nr_tx_request_body_t));
+      scheduled_response.tx_request = &tx_req;
+      scheduled_response.tx_request->tx_request_body = &tx_req_body;
+
+      // Config UL TX PDU
+      tx_req.slot = slot;
+      tx_req.sfn = frame;
+      // tx_req->tx_config // TbD
+      tx_req.number_of_pdus = 1;
+      tx_req_body.pdu_length = TBS/8;
+      tx_req_body.pdu_index = 0;
+      tx_req_body.pdu = &ulsch_input_buffer[0];
 
       ul_config.slot = slot;
       ul_config.number_pdus = 1;
@@ -822,27 +886,22 @@ int main(int argc, char **argv)
       ul_config.ul_config_list[0].pusch_config_pdu.nr_of_symbols = nb_symb_sch;
       ul_config.ul_config_list[0].pusch_config_pdu.start_symbol_index = start_symbol;
       ul_config.ul_config_list[0].pusch_config_pdu.ul_dmrs_symb_pos = l_prime_mask << start_symbol;
-      ul_config.ul_config_list[0].pusch_config_pdu.dmrs_config_type = 0;
+      ul_config.ul_config_list[0].pusch_config_pdu.dmrs_config_type = dmrs_config_type;
       ul_config.ul_config_list[0].pusch_config_pdu.mcs_index = Imcs;
       ul_config.ul_config_list[0].pusch_config_pdu.mcs_table = mcs_table;
-      ul_config.ul_config_list[0].pusch_config_pdu.num_dmrs_cdm_grps_no_data = 1;
+      ul_config.ul_config_list[0].pusch_config_pdu.num_dmrs_cdm_grps_no_data = msg3_flag == 0 ? 1 : 2;
+      ul_config.ul_config_list[0].pusch_config_pdu.nrOfLayers = precod_nbr_layers;
+      ul_config.ul_config_list[0].pusch_config_pdu.absolute_delta_PUSCH = 0;
+
+      ul_config.ul_config_list[0].pusch_config_pdu.pusch_data.tb_size = TBS;
       ul_config.ul_config_list[0].pusch_config_pdu.pusch_data.new_data_indicator = trial & 0x1;
       ul_config.ul_config_list[0].pusch_config_pdu.pusch_data.rv_index = rv_index;
-      ul_config.ul_config_list[0].pusch_config_pdu.nrOfLayers = precod_nbr_layers;
       ul_config.ul_config_list[0].pusch_config_pdu.pusch_data.harq_process_id = harq_pid;
+
       ul_config.ul_config_list[0].pusch_config_pdu.pusch_ptrs.ptrs_time_density = ptrs_time_density;
       ul_config.ul_config_list[0].pusch_config_pdu.pusch_ptrs.ptrs_freq_density = ptrs_freq_density;
       ul_config.ul_config_list[0].pusch_config_pdu.pusch_ptrs.ptrs_ports_list   = (nfapi_nr_ue_ptrs_ports_t *) malloc(2*sizeof(nfapi_nr_ue_ptrs_ports_t));
       ul_config.ul_config_list[0].pusch_config_pdu.pusch_ptrs.ptrs_ports_list[0].ptrs_re_offset = 0;
-      //there are plenty of other parameters that we don't seem to be using for now. e.g.
-      ul_config.ul_config_list[0].pusch_config_pdu.absolute_delta_PUSCH = 0;
-
-      nb_re_dmrs = ((ul_config.ul_config_list[0].pusch_config_pdu.dmrs_config_type == pusch_dmrs_type1) ? 6 : 4);
-
-      available_bits = nr_get_G(nb_rb, nb_symb_sch, nb_re_dmrs, number_dmrs_symbols, mod_order, 1);
-      TBS            = nr_compute_tbs(mod_order, code_rate, nb_rb, nb_symb_sch, nb_re_dmrs * number_dmrs_symbols, 0, 0, precod_nbr_layers);
-      pusch_pdu->pusch_data.tb_size = TBS>>3;
-      ul_config.ul_config_list[0].pusch_config_pdu.pusch_data.tb_size = TBS;
 
       nr_fill_ulsch(gNB,frame,slot,pusch_pdu);
 
@@ -905,10 +964,15 @@ int main(int argc, char **argv)
 	  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)((tx_gain*r_re[ap][i])   + (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)((tx_gain*r_im[ap][i]) + (sqrt(sigma/2)*gaussdouble(0.0,1.0)));
+            /* Add phase noise if enabled */
+            if (pdu_bit_map & PUSCH_PDU_BITMAP_PUSCH_PTRS) {
+              phase_noise(ts, &((int16_t*)&gNB->common_vars.rxdata[ap][slot_offset])[(2*i)],
+                          &((int16_t*)&gNB->common_vars.rxdata[ap][slot_offset])[(2*i)+1]);
+            }
 	  }
 	}
-	
-	}
+
+      }
 
 	////////////////////////////////////////////////////////////
 	
@@ -963,6 +1027,20 @@ int main(int argc, char **argv)
 	}
 	if(n_trials==1) printf("end of round %d rv_index %d\n",round, rv_index);
 
+        //----------------------------------------------------------
+        //----------------- count and print errors -----------------
+        //----------------------------------------------------------
+
+        if ((pusch_pdu->pdu_bit_map & PUSCH_PDU_BITMAP_PUSCH_PTRS) && (SNR==snr0) && (trial==0) && (round==0)) {
+            ptrs_symbols = 0;
+            for (int i = pusch_pdu->start_symbol_index; i < pusch_pdu->start_symbol_index + pusch_pdu->nr_of_symbols; i++){
+               ptrs_symbols += ((gNB->pusch_vars[UE_id]->ptrs_symbols) >> i) & 1;
+            }
+            /*  2*5*(50/2), for RB = 50,K = 2 for 5 OFDM PTRS symbols */
+            available_bits -= 2 * ptrs_symbols * ((nb_rb + ptrs_freq_density - 1) /ptrs_freq_density);
+            printf("After PTRS subtraction available_bits are : %u \n", available_bits);
+        }
+
 	for (i = 0; i < available_bits; i++) {
 	  
 	  if(((ulsch_ue[0]->g[i] == 0) && (gNB->pusch_vars[UE_id]->llr[i] <= 0)) ||
@@ -977,12 +1055,6 @@ int main(int argc, char **argv)
 
     } // round
     
-        //----------------------------------------------------------
-        //----------------- count and print errors -----------------
-        //----------------------------------------------------------
-
-
-    
     if (n_trials == 1 && errors_scrambling[0] > 0) {
       printf("\x1B[31m""[frame %d][trial %d]\tnumber of errors in unscrambling = %u\n" "\x1B[0m", frame, trial, errors_scrambling[0]);
     }
@@ -1044,6 +1116,7 @@ int main(int argc, char **argv)
       printDistribution(&gNB->phy_proc_rx,table_rx,"Total PHY proc rx");
       printStatIndent(&gNB->rx_pusch_stats,"RX PUSCH time");
       printStatIndent2(&gNB->ulsch_channel_estimation_stats,"ULSCH channel estimation time");
+      printStatIndent2(&gNB->ulsch_ptrs_processing_stats,"ULSCH PTRS Processing time");
       printStatIndent2(&gNB->ulsch_rbs_extraction_stats,"ULSCH rbs extraction time");
       printStatIndent2(&gNB->ulsch_channel_compensation_stats,"ULSCH channel compensation time");
       printStatIndent2(&gNB->ulsch_mrc_stats,"ULSCH mrc computation");
@@ -1055,17 +1128,17 @@ int main(int argc, char **argv)
       printStatIndent2(&gNB->ulsch_ldpc_decoding_stats,"ULSCH ldpc decoding");
       printf("\n");
     }
-    
+
     if(n_trials==1)
       break;
-    
+
     if ((float)n_errors[0]/(float)n_trials <= target_error_rate) {
       printf("*************\n");
       printf("PUSCH test OK\n");
       printf("*************\n");
       break;
     }
-      
+
     snrRun++;
     n_errs = n_errors[0];
   } // SNR loop
diff --git a/openair1/SIMULATION/TOOLS/phase_noise.c b/openair1/SIMULATION/TOOLS/phase_noise.c
new file mode 100644
index 0000000000000000000000000000000000000000..f243a09c59ee1912a31c5609554f0de682ced6cb
--- /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 2f5ab99b41af7c37724dc2e2c6ca3fe237e2eac4..d2684b15c1fd0602e553e9f9dc5d4d0355003a01 100644
--- a/openair1/SIMULATION/TOOLS/sim.h
+++ b/openair1/SIMULATION/TOOLS/sim.h
@@ -460,6 +460,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,
diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c
index 8220d088d0ad710652a0a18154fb58a48e5594bf..bc105b9080502ec76c29541347561daff542b86b 100644
--- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c
+++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c
@@ -1940,9 +1940,9 @@ uint8_t get_K_ptrs(uint16_t nrb0, uint16_t nrb1, uint16_t N_RB) {
     LOG_I(PHY,"PUSH PT-RS is not present.\n");
     return -1;
   } else if (N_RB >= nrb0 && N_RB < nrb1)
-    return 0;
+    return 2;
   else
-    return 1;
+    return 4;
 }
 
 uint16_t nr_dci_size(NR_ServingCellConfigCommon_t *scc,