diff --git a/openair1/PHY/NR_UE_ESTIMATION/nr_dl_channel_estimation.c b/openair1/PHY/NR_UE_ESTIMATION/nr_dl_channel_estimation.c
index 3feeec46148690894387d6c9c67e554480a75078..5d2709d755e945e9356602027ec84fcf979f43cc 100644
--- a/openair1/PHY/NR_UE_ESTIMATION/nr_dl_channel_estimation.c
+++ b/openair1/PHY/NR_UE_ESTIMATION/nr_dl_channel_estimation.c
@@ -1054,7 +1054,7 @@ void nr_pdcch_channel_estimation(PHY_VARS_NR_UE *ue,
     rxF   = (int16_t *)&rxdataF[aarx][(symbol_offset+k+1)];
     dl_ch = (int16_t *)&pdcch_dl_ch_estimates[aarx][ch_offset];
 
-    memset(dl_ch, 0, sizeof(*dl_ch) * ue->frame_parms.ofdm_symbol_size);
+    memset(dl_ch,0,4*(ue->frame_parms.ofdm_symbol_size));
 
 #ifdef DEBUG_PDCCH
     printf("pdcch ch est pilot addr %p RB_DL %d\n",&pilot[dmrs_ref*3], ue->frame_parms.N_RB_DL);
@@ -1230,6 +1230,361 @@ void nr_pdcch_channel_estimation(PHY_VARS_NR_UE *ue,
   }
 }
 
+void NFAPI_NR_DMRS_TYPE1_linear_interp(NR_DL_FRAME_PARMS *frame_parms,
+                                       c16_t *rxF,
+                                       c16_t *pil,
+                                       c16_t *dl_ch,
+                                       unsigned short bwp_start_subcarrier,
+                                       unsigned short nb_rb_pdsch,
+                                       int8_t delta)
+{
+  int re_offset = bwp_start_subcarrier % frame_parms->ofdm_symbol_size;
+  c16_t *pil0 = pil;
+  c16_t *dl_ch0 = dl_ch;
+  c16_t ch = {0};
+
+  int16_t *fdcl = NULL;
+  int16_t *fdcr = NULL;
+  int16_t *fdclh = NULL;
+  int16_t *fdcrh = NULL;
+  switch (delta) {
+    case 0: // port 0,1
+      fdcl = filt8_dcl0; // left DC interpolation Filter (even RB)
+      fdcr = filt8_dcr0; // right DC interpolation Filter (even RB)
+      fdclh = filt8_dcl0_h; // left DC interpolation Filter (odd RB)
+      fdcrh = filt8_dcr0_h; // right DC interpolation Filter (odd RB)
+      break;
+
+    case 1: // port2,3
+      fdcl = filt8_dcl1;
+      fdcr = filt8_dcr1;
+      fdclh = filt8_dcl1_h;
+      fdcrh = filt8_dcr1_h;
+      break;
+
+    default:
+      AssertFatal(1 == 0, "pdsch_channel_estimation: Invalid delta %i\n", delta);
+      break;
+  }
+
+  for (int pilot_cnt = 0; pilot_cnt < 6 * nb_rb_pdsch; pilot_cnt++) {
+    if (pilot_cnt % 2 == 0) {
+      ch = c16mulShift(*pil, rxF[re_offset], 15);
+      pil++;
+      re_offset = (re_offset + 2) % frame_parms->ofdm_symbol_size;
+      ch = c16maddShift(*pil, rxF[re_offset], ch, 15);
+      ch = c16Shift(ch, 1);
+      pil++;
+      re_offset = (re_offset + 2) % frame_parms->ofdm_symbol_size;
+    }
+
+#ifdef DEBUG_PDSCH
+    printf("pilot %3u: pil -> (%6d,%6d), rxF -> (%4d,%4d), ch -> (%4d,%4d) \n", pilot_cnt, pil->r, pil->i, rxF[re_offset].r, rxF[re_offset].i, ch.r, ch.i);
+#endif
+
+    if (pilot_cnt == 0) { // Treat first pilot
+      c16multaddVectRealComplex(filt16_dl_first, &ch, dl_ch, 16);
+    } else if (pilot_cnt == 6 * nb_rb_pdsch - 1) { // Treat last pilot
+      c16multaddVectRealComplex(filt16_dl_last, &ch, dl_ch, 16);
+    } else { // Treat middle pilots
+      c16multaddVectRealComplex(filt16_dl_middle, &ch, dl_ch, 16);
+      if (pilot_cnt % 2 == 0) {
+      dl_ch += 4;
+      }
+    }
+  }
+
+  // check if PRB crosses DC and improve estimates around DC
+  if ((bwp_start_subcarrier < frame_parms->ofdm_symbol_size) && (bwp_start_subcarrier + nb_rb_pdsch * 12 >= frame_parms->ofdm_symbol_size)) {
+    dl_ch = dl_ch0;
+    uint16_t idxDC = 2 * (frame_parms->ofdm_symbol_size - bwp_start_subcarrier);
+    uint16_t idxPil = idxDC / 4;
+    re_offset = bwp_start_subcarrier % frame_parms->ofdm_symbol_size;
+    pil = pil0;
+    pil += (idxPil - 1);
+    dl_ch += (idxDC / 2 - 2);
+    dl_ch = memset(dl_ch, 0, sizeof(c16_t) * 5);
+    re_offset = (re_offset + idxDC / 2 - 2) % frame_parms->ofdm_symbol_size;
+    ch = c16mulShift(*pil, rxF[re_offset], 15);
+    pil++;
+    re_offset = (re_offset + 2) % frame_parms->ofdm_symbol_size;
+    ch = c16maddShift(*pil, rxF[re_offset], ch, 15);
+    ch = c16Shift(ch, 1);
+
+    // for proper allignment of SIMD vectors
+    if ((frame_parms->N_RB_DL & 1) == 0) {
+      c16multaddVectRealComplex(fdcl, &ch, dl_ch - 2, 8);
+      pil++;
+      re_offset = (re_offset + 2) % frame_parms->ofdm_symbol_size;
+      ch = c16mulShift(*pil, rxF[re_offset], 15);
+      pil++;
+      re_offset = (re_offset + 2) % frame_parms->ofdm_symbol_size;
+      ch = c16maddShift(*pil, rxF[re_offset], ch, 15);
+      ch = c16Shift(ch, 1);
+      c16multaddVectRealComplex(fdcr, &ch, dl_ch - 2, 8);
+    } else {
+      c16multaddVectRealComplex(fdclh, &ch, dl_ch, 8);
+      pil++;
+      re_offset = (re_offset + 2) % frame_parms->ofdm_symbol_size;
+      ch = c16mulShift(*pil, rxF[re_offset], 15);
+      pil++;
+      re_offset = (re_offset + 2) % frame_parms->ofdm_symbol_size;
+      ch = c16maddShift(*pil, rxF[re_offset], ch, 15);
+      ch = c16Shift(ch, 1);
+      c16multaddVectRealComplex(fdcrh, &ch, dl_ch, 8);
+    }
+  }
+}
+
+void NFAPI_NR_DMRS_TYPE1_average_prb(NR_DL_FRAME_PARMS *frame_parms,
+                                     c16_t *rxF,
+                                     c16_t *pil,
+                                     c16_t *dl_ch,
+                                     unsigned short bwp_start_subcarrier,
+                                     unsigned short nb_rb_pdsch)
+{
+  int re_offset = bwp_start_subcarrier % frame_parms->ofdm_symbol_size;
+  c16_t ch = {0};
+  int P_average = 6;
+
+  c32_t ch32 = {0};
+  for (int p_av = 0; p_av < P_average; p_av++) {
+    ch32 = c32x16maddShift(*pil, rxF[re_offset], ch32, 15);
+    pil++;
+    re_offset = (re_offset + 2) % frame_parms->ofdm_symbol_size;
+  }
+  ch = c16x32div(ch32, P_average);
+
+#if NO_INTERP
+  for (int i = 0; i < 2 * P_average; i++) {
+    dl_ch[i] = ch;
+  }
+  dl_ch += 2 * P_average;
+#else
+  c16multaddVectRealComplex(filt8_avlip0, &ch, dl_ch, 8);
+  dl_ch += 16;
+  c16multaddVectRealComplex(filt8_avlip1, &ch, dl_ch, 8);
+  dl_ch += 16;
+  c16multaddVectRealComplex(filt8_avlip2, &ch, dl_ch, 8);
+  dl_ch -= 24;
+#endif
+
+  for (int pilot_cnt = P_average; pilot_cnt < 6 * (nb_rb_pdsch - 1); pilot_cnt += P_average) {
+    ch32.r = 0;
+    ch32.i = 0;
+    for (int p_av = 0; p_av < P_average; p_av++) {
+      ch32 = c32x16maddShift(*pil, rxF[re_offset], ch32, 15);
+      pil++;
+      re_offset = (re_offset + 2) % frame_parms->ofdm_symbol_size;
+    }
+    ch = c16x32div(ch32, P_average);
+
+#if NO_INTERP
+    for (int i = 0; i < 2 * P_average; i++) {
+      dl_ch[i] = ch;
+    }
+    dl_ch += 2 * P_average;
+#else
+    dl_ch[3].r += (ch.r * 1365) >> 15; // 1/12*16384
+    dl_ch[3].i += (ch.i * 1365) >> 15; // 1/12*16384
+    dl_ch += 4;
+    c16multaddVectRealComplex(filt8_avlip3, &ch, dl_ch, 8);
+    dl_ch += 8;
+    c16multaddVectRealComplex(filt8_avlip4, &ch, dl_ch, 8);
+    dl_ch += 8;
+    c16multaddVectRealComplex(filt8_avlip5, &ch, dl_ch, 8);
+    dl_ch -= 8;
+#endif
+  }
+
+  ch32.r = 0;
+  ch32.i = 0;
+  for (int p_av = 0; p_av < P_average; p_av++) {
+    ch32 = c32x16maddShift(*pil, rxF[re_offset], ch32, 15);
+    pil++;
+    re_offset = (re_offset + 2) % frame_parms->ofdm_symbol_size;
+  }
+  ch = c16x32div(ch32, P_average);
+
+#if NO_INTERP
+  for (int i = 0; i < 2 * P_average; i++) {
+    dl_ch[i] = ch;
+  }
+  dl_ch += 2 * P_average;
+#else
+  dl_ch[3].r += (ch.r * 1365) >> 15; // 1/12*16384
+  dl_ch[3].i += (ch.i * 1365) >> 15; // 1/12*16384
+  dl_ch += 4;
+  c16multaddVectRealComplex(filt8_avlip3, &ch, dl_ch, 8);
+  dl_ch += 8;
+  c16multaddVectRealComplex(filt8_avlip6, &ch, dl_ch, 8);
+#endif
+}
+
+void NFAPI_NR_DMRS_TYPE2_linear_interp(NR_DL_FRAME_PARMS *frame_parms,
+                                       c16_t *rxF,
+                                       c16_t *pil,
+                                       c16_t *dl_ch,
+                                       unsigned short bwp_start_subcarrier,
+                                       unsigned short nb_rb_pdsch,
+                                       int8_t delta,
+                                       unsigned short p)
+{
+  int re_offset = bwp_start_subcarrier % frame_parms->ofdm_symbol_size;
+  c16_t *dl_ch0 = dl_ch;
+  c16_t ch = {0};
+  c16_t ch_l = {0};
+  c16_t ch_r = {0};
+
+  for (int pilot_cnt = 0; pilot_cnt < 4 * nb_rb_pdsch; pilot_cnt += 2) {
+    ch_l = c16mulShift(*pil, rxF[re_offset], 15);
+#ifdef DEBUG_PDSCH
+    printf("pilot %3u: pil -> (%6d,%6d), rxF -> (%4d,%4d), ch -> (%4d,%4d) \n", pilot_cnt, pil->r, pil->i, rxF[re_offset].r, rxF[re_offset].i, ch_l.r, ch_l.i);
+#endif
+    pil++;
+    re_offset = (re_offset + 1) % frame_parms->ofdm_symbol_size;
+    ch_r = c16mulShift(*pil, rxF[re_offset], 15);
+#ifdef DEBUG_PDSCH
+    printf("pilot %3u: pil -> (%6d,%6d), rxF -> (%4d,%4d), ch -> (%4d,%4d) \n", pilot_cnt, pil->r, pil->i, rxF[re_offset].r, rxF[re_offset].i, ch_r.r, ch_r.i);
+#endif
+    ch = c16addShift(ch_l, ch_r, 1);
+    if (pilot_cnt == 1) {
+      multadd_real_vector_complex_scalar(filt16_dl_first_type2, (int16_t *)&ch, (int16_t *)dl_ch, 16);
+      dl_ch += 3;
+    } else if (pilot_cnt == (4 * nb_rb_pdsch - 1)) {
+      multadd_real_vector_complex_scalar(filt16_dl_last_type2, (int16_t *)&ch, (int16_t *)dl_ch, 16);
+    } else {
+      multadd_real_vector_complex_scalar(filt16_dl_middle_type2, (int16_t *)&ch, (int16_t *)dl_ch, 16);
+      dl_ch += 6;
+    }
+    pil++;
+    re_offset = (re_offset + 5) % frame_parms->ofdm_symbol_size;
+  }
+
+  // check if PRB crosses DC and improve estimates around DC
+  if ((bwp_start_subcarrier < frame_parms->ofdm_symbol_size) && (bwp_start_subcarrier + nb_rb_pdsch * 12 >= frame_parms->ofdm_symbol_size) && (p < 2)) {
+    dl_ch = dl_ch0;
+    uint16_t idxDC = 2 * (frame_parms->ofdm_symbol_size - bwp_start_subcarrier);
+    dl_ch += (idxDC / 2 - 4);
+    dl_ch = memset(dl_ch, 0, sizeof(c16_t) * 10);
+
+    dl_ch--;
+    ch_r = *dl_ch;
+    dl_ch += 11;
+    ch_l = *dl_ch;
+
+    // for proper allignment of SIMD vectors
+    if ((frame_parms->N_RB_DL & 1) == 0) {
+      dl_ch -= 10;
+      // Interpolate fdcrl1 with ch_r
+      c16multaddVectRealComplex(filt8_dcrl1, &ch_r, dl_ch, 8);
+      // Interpolate fdclh1 with ch_l
+      c16multaddVectRealComplex(filt8_dclh1, &ch_l, dl_ch, 8);
+      dl_ch += 8;
+      // Interpolate fdcrh1 with ch_r
+      c16multaddVectRealComplex(filt8_dcrh1, &ch_r, dl_ch, 8);
+      // Interpolate fdcll1 with ch_l
+      c16multaddVectRealComplex(filt8_dcll1, &ch_l, dl_ch, 8);
+    } else {
+      dl_ch -= 14;
+      // Interpolate fdcrl1 with ch_r
+      c16multaddVectRealComplex(filt8_dcrl2, &ch_r, dl_ch, 8);
+      // Interpolate fdclh1 with ch_l
+      c16multaddVectRealComplex(filt8_dclh2, &ch_l, dl_ch, 8);
+      dl_ch += 8;
+      // Interpolate fdcrh1 with ch_r
+      c16multaddVectRealComplex(filt8_dcrh2, &ch_r, dl_ch, 8);
+      // Interpolate fdcll1 with ch_l
+      c16multaddVectRealComplex(filt8_dcll2, &ch_l, dl_ch, 8);
+    }
+  }
+}
+
+void NFAPI_NR_DMRS_TYPE2_average_prb(NR_DL_FRAME_PARMS *frame_parms,
+                                     c16_t *rxF,
+                                     c16_t *pil,
+                                     c16_t *dl_ch,
+                                     unsigned short bwp_start_subcarrier,
+                                     unsigned short nb_rb_pdsch)
+{
+  int re_offset = bwp_start_subcarrier % frame_parms->ofdm_symbol_size;
+  c16_t ch = {0};
+  int P_average = 4;
+
+  c32_t ch32 = {0};
+  for (int p_av = 0; p_av < P_average; p_av++) {
+    ch32 = c32x16maddShift(*pil, rxF[re_offset], ch32, 15);
+    pil++;
+    re_offset = (re_offset + 1) % frame_parms->ofdm_symbol_size;
+  }
+  ch = c16x32div(ch32, P_average);
+
+#if NO_INTERP
+  for (int i = 0; i < 3 * P_average; i++) {
+    dl_ch[i] = ch;
+  }
+  dl_ch += 3 * P_average;
+#else
+  c16multaddVectRealComplex(filt8_avlip0, &ch, dl_ch, 8);
+  dl_ch += 8;
+  c16multaddVectRealComplex(filt8_avlip1, &ch, dl_ch, 8);
+  dl_ch += 8;
+  c16multaddVectRealComplex(filt8_avlip2, &ch, dl_ch, 8);
+  dl_ch -= 12;
+#endif
+
+  for (int pilot_cnt = P_average; pilot_cnt < 4 * (nb_rb_pdsch - 1); pilot_cnt += P_average) {
+    ch32.r = 0;
+    ch32.i = 0;
+    for (int p_av = 0; p_av < P_average; p_av++) {
+      ch32 = c32x16maddShift(*pil, rxF[re_offset], ch32, 15);
+      pil++;
+      re_offset = (re_offset + 5) % frame_parms->ofdm_symbol_size;
+    }
+    ch = c16x32div(ch32, P_average);
+
+#if NO_INTERP
+    for (int i = 0; i < 3 * P_average; i++) {
+      dl_ch[i] = ch;
+    }
+    dl_ch += 3 * P_average;
+#else
+    dl_ch[3].r += (ch.r * 1365) >> 15; // 1/12*16384
+    dl_ch[3].i += (ch.i * 1365) >> 15; // 1/12*16384
+    dl_ch += 4;
+    c16multaddVectRealComplex(filt8_avlip3, &ch, dl_ch, 8);
+    dl_ch += 8;
+    c16multaddVectRealComplex(filt8_avlip4, &ch, dl_ch, 8);
+    dl_ch += 8;
+    c16multaddVectRealComplex(filt8_avlip5, &ch, dl_ch, 8);
+    dl_ch -= 8;
+#endif
+  }
+
+  ch32.r = 0;
+  ch32.i = 0;
+  for (int p_av = 0; p_av < P_average; p_av++) {
+    ch32 = c32x16maddShift(*pil, rxF[re_offset], ch32, 15);
+    pil++;
+    re_offset = (re_offset + 5) % frame_parms->ofdm_symbol_size;
+  }
+  ch = c16x32div(ch32, P_average);
+
+#if NO_INTERP
+  for (int i = 0; i < 3 * P_average; i++) {
+    dl_ch[i] = ch;
+  }
+  dl_ch += 3 * P_average;
+#else
+  dl_ch[3].r += (ch.r * 1365) >> 15; // 1/12*16384
+  dl_ch[3].i += (ch.i * 1365) >> 15; // 1/12*16384
+  dl_ch += 4;
+  c16multaddVectRealComplex(filt8_avlip3, &ch, dl_ch, 8);
+  dl_ch += 8;
+  c16multaddVectRealComplex(filt8_avlip6, &ch, dl_ch, 8);
+#endif
+}
+
 int nr_pdsch_channel_estimation(PHY_VARS_NR_UE *ue,
                                 UE_nr_rxtx_proc_t *proc,
                                 bool is_SI,
@@ -1278,67 +1633,15 @@ int nr_pdsch_channel_estimation(PHY_VARS_NR_UE *ue,
   c16_t pilot[3280] __attribute__((aligned(16)));
   nr_pdsch_dmrs_rx(ue, Ns, ue->nr_gold_pdsch[gNB_id][Ns][symbol][0], (int32_t *)pilot, 1000 + p, 0, nb_rb_pdsch + rb_offset, config_type);
 
-  int16_t *fdcl = NULL;
-  int16_t *fdcr = NULL;
-  int16_t *fdclh = NULL;
-  int16_t *fdcrh = NULL;
   uint8_t nushift = 0;
-
   if (config_type == NFAPI_NR_DMRS_TYPE1) {
-
     nushift = (p >> 1) & 1;
-
     if (p < 4)
       ue->frame_parms.nushift = nushift;
-
-    switch (delta) {
-      case 0: // port 0,1
-      fdcl = filt8_dcl0; // left DC interpolation Filter (even RB)
-      fdcr = filt8_dcr0; // right DC interpolation Filter (even RB)
-      fdclh = filt8_dcl0_h; // left DC interpolation Filter (odd RB)
-      fdcrh = filt8_dcr0_h; // right DC interpolation Filter (odd RB)
-      break;
-
-      case 1: // port2,3
-      fdcl = filt8_dcl1;
-      fdcr = filt8_dcr1;
-      fdclh = filt8_dcl1_h;
-      fdcrh = filt8_dcr1_h;
-      break;
-
-      default:
-      LOG_E(PHY, "pdsch_channel_estimation: nushift=%d -> ERROR\n", nushift);
-      return -1;
-      break;
-    }
-
   } else { // NFAPI_NR_DMRS_TYPE2
-
     nushift = delta;
-
     if (p < 6)
       ue->frame_parms.nushift = nushift;
-
-    switch (delta) {
-      case 0: // ports 0,1
-      fdcl = filt8_dcl1;
-      fdcr = filt8_dcr1;
-      fdclh = filt8_dcl1_h;
-      fdcrh = filt8_dcr1_h;
-      break;
-
-      case 2: // ports 2,3
-      fdcl = NULL;
-      fdcr = NULL;
-      fdclh = NULL;
-      fdcrh = NULL;
-      break;
-
-      default:
-      LOG_E(PHY, "pdsch_channel_estimation: nushift=%d -> ERROR\n", nushift);
-      return -1;
-      break;
-    }
   }
 
   for (int aarx = 0; aarx < ue->frame_parms.nb_antennas_rx; aarx++) {
@@ -1349,321 +1652,46 @@ int nr_pdsch_channel_estimation(PHY_VARS_NR_UE *ue,
     printf("============================================\n");
 #endif
 
-    int re_offset = bwp_start_subcarrier % ue->frame_parms.ofdm_symbol_size;
-    c16_t *pil = &pilot[rb_offset * ((config_type == NFAPI_NR_DMRS_TYPE1) ? 6 : 4)];
-    c16_t *rxF = &rxdataF[aarx][(symbol_offset + re_offset + nushift)];
+    c16_t *rxF = &rxdataF[aarx][symbol_offset + nushift];
     c16_t *dl_ch = (c16_t *)&dl_ch_estimates[p * ue->frame_parms.nb_antennas_rx + aarx][ch_offset];
     memset(dl_ch, 0, sizeof(*dl_ch) * ue->frame_parms.ofdm_symbol_size);
-    c16_t ch = {0};
 
     if (config_type == NFAPI_NR_DMRS_TYPE1 && ue->chest_freq == 0) {
+      NFAPI_NR_DMRS_TYPE1_linear_interp(&ue->frame_parms,
+                                        rxF,
+                                        &pilot[6 * rb_offset],
+                                        dl_ch,
+                                        bwp_start_subcarrier,
+                                        nb_rb_pdsch,
+                                        delta);
 
-      for (int pilot_cnt = 0; pilot_cnt < 6 * nb_rb_pdsch; pilot_cnt++) {
-        if (pilot_cnt % 2 == 0) {
-          ch = c16mulShift(*pil, *rxF, 15);
-          pil++;
-          re_offset = (re_offset + 2) % ue->frame_parms.ofdm_symbol_size;
-          rxF = &rxdataF[aarx][(symbol_offset + nushift + re_offset)];
-          ch = c16maddShift(*pil, *rxF, ch, 15);
-          ch = c16Shift(ch, 1);
-          pil++;
-          re_offset = (re_offset + 2) % ue->frame_parms.ofdm_symbol_size;
-          rxF = &rxdataF[aarx][(symbol_offset + nushift + re_offset)];
-        }
-
-#ifdef DEBUG_PDSCH
-      printf("pilot %3u: pil -> (%6d,%6d), rxF -> (%4d,%4d), ch -> (%4d,%4d) \n", pilot_cnt, pil->r, pil->i, rxF->r, rxF->i, ch.r, ch.i);
-#endif
-
-        if (pilot_cnt == 0) { // Treat first pilot
-          c16multaddVectRealComplex(filt16_dl_first, &ch, dl_ch, 16);
-        } else if (pilot_cnt == 6 * nb_rb_pdsch - 1) { // Treat last pilot
-          c16multaddVectRealComplex(filt16_dl_last, &ch, dl_ch, 16);
-        } else { // Treat middle pilots
-          c16multaddVectRealComplex(filt16_dl_middle, &ch, dl_ch, 16);
-          if (pilot_cnt % 2 == 0) {
-            dl_ch += 4;
-          }
-        }
-      }
-
-      // check if PRB crosses DC and improve estimates around DC
-      if ((bwp_start_subcarrier < ue->frame_parms.ofdm_symbol_size) && (bwp_start_subcarrier + nb_rb_pdsch * 12 >= ue->frame_parms.ofdm_symbol_size)) {
-        dl_ch = (c16_t *)&dl_ch_estimates[aarx][ch_offset];
-        uint16_t idxDC = 2 * (ue->frame_parms.ofdm_symbol_size - bwp_start_subcarrier);
-        uint16_t idxPil = idxDC / 4;
-        re_offset = bwp_start_subcarrier % ue->frame_parms.ofdm_symbol_size;
-        pil = &pilot[rb_offset * ((config_type == NFAPI_NR_DMRS_TYPE1) ? 6 : 4)];
-        pil += (idxPil - 1);
-        dl_ch += (idxDC / 2 - 2);
-        dl_ch = memset(dl_ch, 0, sizeof(c16_t) * 5);
-        re_offset = (re_offset + idxDC / 2 - 2) % ue->frame_parms.ofdm_symbol_size;
-        rxF = &rxdataF[aarx][(symbol_offset + nushift + re_offset)];
-        ch = c16mulShift(*pil, *rxF, 15);
-        pil++;
-        re_offset = (re_offset + 2) % ue->frame_parms.ofdm_symbol_size;
-        rxF = &rxdataF[aarx][(symbol_offset + nushift + re_offset)];
-        ch = c16maddShift(*pil, *rxF, ch, 15);
-        ch = c16Shift(ch, 1);
-
-        // for proper allignment of SIMD vectors
-        if ((ue->frame_parms.N_RB_DL & 1) == 0) {
-          c16multaddVectRealComplex(fdcl, &ch, dl_ch - 2, 8);
-          pil++;
-          re_offset = (re_offset + 2) % ue->frame_parms.ofdm_symbol_size;
-          rxF = &rxdataF[aarx][(symbol_offset + nushift + re_offset)];
-          ch = c16mulShift(*pil, *rxF, 15);
-          pil++;
-          re_offset = (re_offset + 2) % ue->frame_parms.ofdm_symbol_size;
-          rxF = &rxdataF[aarx][(symbol_offset + nushift + re_offset)];
-          ch = c16maddShift(*pil, *rxF, ch, 15);
-          ch = c16Shift(ch, 1);
-          c16multaddVectRealComplex(fdcr, &ch, dl_ch - 2, 8);
-        } else {
-          c16multaddVectRealComplex(fdclh, &ch, dl_ch, 8);
-          pil++;
-          re_offset = (re_offset + 2) % ue->frame_parms.ofdm_symbol_size;
-          rxF = &rxdataF[aarx][(symbol_offset + nushift + re_offset)];
-          ch = c16mulShift(*pil, *rxF, 15);
-          pil++;
-          re_offset = (re_offset + 2) % ue->frame_parms.ofdm_symbol_size;
-          rxF = &rxdataF[aarx][(symbol_offset + nushift + re_offset)];
-          ch = c16maddShift(*pil, *rxF, ch, 15);
-          ch = c16Shift(ch, 1);
-          c16multaddVectRealComplex(fdcrh, &ch, dl_ch, 8);
-        }
-      }
-
-    // pdsch_dmrs_type2  |dmrs_r,dmrs_l,0,0,0,0,dmrs_r,dmrs_l,0,0,0,0|
     } else if (config_type == NFAPI_NR_DMRS_TYPE2 && ue->chest_freq == 0) {
+      NFAPI_NR_DMRS_TYPE2_linear_interp(&ue->frame_parms,
+                                        rxF,
+                                        &pilot[4 * rb_offset],
+                                        dl_ch,
+                                        bwp_start_subcarrier,
+                                        nb_rb_pdsch,
+                                        delta,
+                                        p);
 
-      c16_t ch_l = {0};
-      c16_t ch_r = {0};
-      for (int pilot_cnt = 0; pilot_cnt < 4 * nb_rb_pdsch; pilot_cnt += 2) {
-        ch_l = c16mulShift(*pil, *rxF, 15);
-#ifdef DEBUG_PDSCH
-        printf("pilot %3u: pil -> (%6d,%6d), rxF -> (%4d,%4d), ch -> (%4d,%4d) \n", pilot_cnt, pil->r, pil->i, rxF->r, rxF->i, ch_l.r, ch_l.i);
-#endif
-        pil++;
-        re_offset = (re_offset + 1) % ue->frame_parms.ofdm_symbol_size;
-        rxF = &rxdataF[aarx][(symbol_offset + nushift + re_offset)];
-        ch_r = c16mulShift(*pil, *rxF, 15);
-#ifdef DEBUG_PDSCH
-        printf("pilot %3u: pil -> (%6d,%6d), rxF -> (%4d,%4d), ch -> (%4d,%4d) \n", pilot_cnt, pil->r, pil->i, rxF->r, rxF->i, ch_r.r, ch_r.i);
-#endif
-        ch = c16addShift(ch_l, ch_r, 1);
-        if (pilot_cnt == 1) {
-          multadd_real_vector_complex_scalar(filt16_dl_first_type2, (int16_t *)&ch, (int16_t *)dl_ch, 16);
-          dl_ch += 3;
-        } else if (pilot_cnt == (4 * nb_rb_pdsch - 1)) {
-          multadd_real_vector_complex_scalar(filt16_dl_last_type2, (int16_t *)&ch, (int16_t *)dl_ch, 16);
-        } else {
-          multadd_real_vector_complex_scalar(filt16_dl_middle_type2, (int16_t *)&ch, (int16_t *)dl_ch, 16);
-          dl_ch += 6;
-        }
-        pil++;
-        re_offset = (re_offset + 5) % ue->frame_parms.ofdm_symbol_size;
-        rxF = &rxdataF[aarx][(symbol_offset + nushift + re_offset)];
-      }
-
-      // check if PRB crosses DC and improve estimates around DC
-      if ((bwp_start_subcarrier < ue->frame_parms.ofdm_symbol_size) && (bwp_start_subcarrier + nb_rb_pdsch * 12 >= ue->frame_parms.ofdm_symbol_size) && (p < 2)) {
-        dl_ch = (c16_t *)&dl_ch_estimates[p * ue->frame_parms.nb_antennas_rx + aarx][ch_offset];
-        uint16_t idxDC = 2 * (ue->frame_parms.ofdm_symbol_size - bwp_start_subcarrier);
-        dl_ch += (idxDC / 2 - 4);
-        dl_ch = memset(dl_ch, 0, sizeof(c16_t) * 10);
-
-        dl_ch--;
-        ch_r = *dl_ch;
-        dl_ch += 11;
-        ch_l = *dl_ch;
-
-        // for proper allignment of SIMD vectors
-        if ((ue->frame_parms.N_RB_DL & 1) == 0) {
-          dl_ch -= 10;
-          // Interpolate fdcrl1 with ch_r
-          c16multaddVectRealComplex(filt8_dcrl1, &ch_r, dl_ch, 8);
-          // Interpolate fdclh1 with ch_l
-          c16multaddVectRealComplex(filt8_dclh1, &ch_l, dl_ch, 8);
-          dl_ch += 8;
-          // Interpolate fdcrh1 with ch_r
-          c16multaddVectRealComplex(filt8_dcrh1, &ch_r, dl_ch, 8);
-          // Interpolate fdcll1 with ch_l
-          c16multaddVectRealComplex(filt8_dcll1, &ch_l, dl_ch, 8);
-        } else {
-          dl_ch -= 14;
-          // Interpolate fdcrl1 with ch_r
-          c16multaddVectRealComplex(filt8_dcrl2, &ch_r, dl_ch, 8);
-          // Interpolate fdclh1 with ch_l
-          c16multaddVectRealComplex(filt8_dclh2, &ch_l, dl_ch, 8);
-          dl_ch += 8;
-          // Interpolate fdcrh1 with ch_r
-          c16multaddVectRealComplex(filt8_dcrh2, &ch_r, dl_ch, 8);
-          // Interpolate fdcll1 with ch_l
-          c16multaddVectRealComplex(filt8_dcll2, &ch_l, dl_ch, 8);
-        }
-      }
-
-    // this is case without frequency-domain linear interpolation, just take average of LS channel estimates of 6 DMRS REs and use a common value for the whole PRB
     } else if (config_type == NFAPI_NR_DMRS_TYPE1) {
+      NFAPI_NR_DMRS_TYPE1_average_prb(&ue->frame_parms,
+                                      rxF,
+                                      &pilot[6 * rb_offset],
+                                      dl_ch,
+                                      bwp_start_subcarrier,
+                                      nb_rb_pdsch);
 
-      int P_average = 6;
-      c32_t ch32 = {0};
-      for (int p_av = 0; p_av < P_average; p_av++) {
-        ch32 = c32x16maddShift(*pil, *rxF, ch32, 15);
-        pil++;
-        re_offset = (re_offset + 2) % ue->frame_parms.ofdm_symbol_size;
-        rxF = &rxdataF[aarx][(symbol_offset + nushift + re_offset)];
-      }
-      ch = c16x32div(ch32, P_average);
-
-#if NO_INTERP
-      for (int i = 0; i < 2 * P_average; i++) {
-        dl_ch[i] = ch;
-      }
-      dl_ch += 2 * P_average;
-#else
-      c16multaddVectRealComplex(filt8_avlip0, &ch, dl_ch, 8);
-      dl_ch += 16;
-      c16multaddVectRealComplex(filt8_avlip1, &ch, dl_ch, 8);
-      dl_ch += 16;
-      c16multaddVectRealComplex(filt8_avlip2, &ch, dl_ch, 8);
-      dl_ch -= 24;
-#endif
-
-      for (int pilot_cnt = P_average; pilot_cnt < 6 * (nb_rb_pdsch - 1); pilot_cnt += P_average) {
-        ch32.r = 0;
-        ch32.i = 0;
-        for (int p_av = 0; p_av < P_average; p_av++) {
-          ch32 = c32x16maddShift(*pil, *rxF, ch32, 15);
-          pil++;
-          re_offset = (re_offset + 2) % ue->frame_parms.ofdm_symbol_size;
-          rxF = &rxdataF[aarx][(symbol_offset + nushift + re_offset)];
-        }
-        ch = c16x32div(ch32, P_average);
-
-#if NO_INTERP
-        for (int i = 0; i < 2 * P_average; i++) {
-          dl_ch[i] = ch;
-        }
-        dl_ch += 2 * P_average;
-#else
-        dl_ch[3].r += (ch.r * 1365) >> 15; // 1/12*16384
-        dl_ch[3].i += (ch.i * 1365) >> 15; // 1/12*16384
-        dl_ch += 4;
-        c16multaddVectRealComplex(filt8_avlip3, &ch, dl_ch, 8);
-        dl_ch += 8;
-        c16multaddVectRealComplex(filt8_avlip4, &ch, dl_ch, 8);
-        dl_ch += 8;
-        c16multaddVectRealComplex(filt8_avlip5, &ch, dl_ch, 8);
-        dl_ch -= 8;
-#endif
-      }
-
-      ch32.r = 0;
-      ch32.i = 0;
-      for (int p_av = 0; p_av < P_average; p_av++) {
-        ch32 = c32x16maddShift(*pil, *rxF, ch32, 15);
-        pil++;
-        re_offset = (re_offset + 2) % ue->frame_parms.ofdm_symbol_size;
-        rxF = &rxdataF[aarx][(symbol_offset + nushift + re_offset)];
-      }
-      ch = c16x32div(ch32, P_average);
-
-#if NO_INTERP
-      for (int i = 0; i < 2 * P_average; i++) {
-        dl_ch[i] = ch;
-      }
-      dl_ch += 2 * P_average;
-#else
-      dl_ch[3].r += (ch.r * 1365) >> 15; // 1/12*16384
-      dl_ch[3].i += (ch.i * 1365) >> 15; // 1/12*16384
-      dl_ch += 4;
-      c16multaddVectRealComplex(filt8_avlip3, &ch, dl_ch, 8);
-      dl_ch += 8;
-      c16multaddVectRealComplex(filt8_avlip6, &ch, dl_ch, 8);
-#endif
-
-    // this is case without frequency-domain linear interpolation, just take average of LS channel estimates of 4 DMRS REs and use a common value for the whole PRB
     } else {
-
-      int P_average = 4;
-      c32_t ch32 = {0};
-      for (int p_av = 0; p_av < P_average; p_av++) {
-        ch32 = c32x16maddShift(*pil, *rxF, ch32, 15);
-        pil++;
-        re_offset = (re_offset + 1) % ue->frame_parms.ofdm_symbol_size;
-        rxF = &rxdataF[aarx][(symbol_offset + nushift + re_offset)];
-      }
-      ch = c16x32div(ch32, P_average);
-
-#if NO_INTERP
-      for (int i = 0; i < 3 * P_average; i++) {
-        dl_ch[i] = ch;
-      }
-      dl_ch += 3 * P_average;
-#else
-      c16multaddVectRealComplex(filt8_avlip0, &ch, dl_ch, 8);
-      dl_ch += 8;
-      c16multaddVectRealComplex(filt8_avlip1, &ch, dl_ch, 8);
-      dl_ch += 8;
-      c16multaddVectRealComplex(filt8_avlip2, &ch, dl_ch, 8);
-      dl_ch -= 12;
-#endif
-
-      for (int pilot_cnt = P_average; pilot_cnt < 4 * (nb_rb_pdsch - 1); pilot_cnt += P_average) {
-        ch32.r = 0;
-        ch32.i = 0;
-        for (int p_av = 0; p_av < P_average; p_av++) {
-          ch32 = c32x16maddShift(*pil, *rxF, ch32, 15);
-          pil++;
-          re_offset = (re_offset + 5) % ue->frame_parms.ofdm_symbol_size;
-          rxF = &rxdataF[aarx][(symbol_offset + nushift + re_offset)];
-        }
-        ch = c16x32div(ch32, P_average);
-
-#if NO_INTERP
-        for (int i = 0; i < 3 * P_average; i++) {
-          dl_ch[i] = ch;
-        }
-        dl_ch += 3 * P_average;
-#else
-        dl_ch[3].r += (ch.r * 1365) >> 15; // 1/12*16384
-        dl_ch[3].i += (ch.i * 1365) >> 15; // 1/12*16384
-        dl_ch += 4;
-        c16multaddVectRealComplex(filt8_avlip3, &ch, dl_ch, 8);
-        dl_ch += 8;
-        c16multaddVectRealComplex(filt8_avlip4, &ch, dl_ch, 8);
-        dl_ch += 8;
-        c16multaddVectRealComplex(filt8_avlip5, &ch, dl_ch, 8);
-        dl_ch -= 8;
-#endif
-      }
-
-      ch32.r = 0;
-      ch32.i = 0;
-      for (int p_av = 0; p_av < P_average; p_av++) {
-        ch32 = c32x16maddShift(*pil, *rxF, ch32, 15);
-        pil++;
-        re_offset = (re_offset + 5) % ue->frame_parms.ofdm_symbol_size;
-        rxF = &rxdataF[aarx][(symbol_offset + nushift + re_offset)];
-      }
-      ch = c16x32div(ch32, P_average);
-
-#if NO_INTERP
-      for (int i = 0; i < 3 * P_average; i++) {
-        dl_ch[i] = ch;
-      }
-      dl_ch += 3 * P_average;
-#else
-      dl_ch[3].r += (ch.r * 1365) >> 15; // 1/12*16384
-      dl_ch[3].i += (ch.i * 1365) >> 15; // 1/12*16384
-      dl_ch += 4;
-      c16multaddVectRealComplex(filt8_avlip3, &ch, dl_ch, 8);
-      dl_ch += 8;
-      c16multaddVectRealComplex(filt8_avlip6, &ch, dl_ch, 8);
-#endif
+      NFAPI_NR_DMRS_TYPE2_average_prb(&ue->frame_parms,
+                                      rxF,
+                                      &pilot[4 * rb_offset],
+                                      dl_ch,
+                                      bwp_start_subcarrier,
+                                      nb_rb_pdsch);
     }
+
 #ifdef DEBUG_PDSCH
     dl_ch = (c16_t *)&dl_ch_estimates[p * ue->frame_parms.nb_antennas_rx + aarx][ch_offset];
     for (uint16_t idxP = 0; idxP < ceil((float)nb_rb_pdsch * 12 / 8); idxP++) {