diff --git a/common/utils/nr/nr_common.c b/common/utils/nr/nr_common.c
index 6bc9eff5ff39c9587ea86a35509ec8e2f4ffc56d..fb9d9103e6d54d60012034681e96865b22513820 100644
--- a/common/utils/nr/nr_common.c
+++ b/common/utils/nr/nr_common.c
@@ -182,6 +182,123 @@ const nr_bandentry_t nr_bandtable[] = {
   {261,27500040,28350000,27500040,28350000,  2,2070833, 120}
 };
 
+// synchronization raster per band tables (Rel.15)
+// (38.101-1 Table 5.4.3.3-1 and 38.101-2 Table 5.4.3.3-1)
+// band nb, sub-carrier spacing index, Range of gscn (First, Step size, Last)
+// clang-format off
+const sync_raster_t sync_raster[] = {
+  {1, 0, 5279, 1, 5419},
+  {2, 0, 4829, 1, 4969},
+  {3, 0, 4517, 1, 4693},
+  {5, 0, 2177, 1, 2230},
+  {5, 1, 2183, 1, 2224},
+  {7, 0, 6554, 1, 6718},
+  {8, 0, 2318, 1, 2395},
+  {12, 0, 1828, 1, 1858},
+  {13, 0, 1871, 1, 1885},
+  {14, 0, 1901, 1, 1915},
+  {18, 0, 2156, 1, 2182},
+  {20, 0, 1982, 1, 2047},
+  {24, 0, 3818, 1, 3892},
+  {24, 1, 3824, 1, 3886},
+  {25, 0, 4829, 1, 4981},
+  {26, 0, 2153, 1, 2230},
+  {28, 0, 1901, 1, 2002},
+  {29, 0, 1798, 1, 1813},
+  {30, 0, 5879, 1, 5893},
+  {34, 0, 5030, 1, 5056},
+  {34, 1, 5036, 1, 5050},
+  {38, 0, 6431, 1, 6544},
+  {38, 1, 6437, 1, 6538},
+  {39, 0, 4706, 1, 4795},
+  {39, 1, 4712, 1, 4789},
+  {40, 1, 5762, 1, 5989},
+  {41, 0, 6246, 3, 6717},
+  {41, 1, 6252, 3, 6714},
+  {48, 1, 7884, 1, 7982},
+  {50, 0, 3584, 1, 3787},
+  {51, 0, 3572, 1, 3574},
+  {53, 0, 6215, 1, 6232},
+  {53, 1, 6221, 1, 6226},
+  {65, 0, 5279, 1, 5494},
+  {66, 0, 5279, 1, 5494},
+  {66, 1, 5285, 1, 5488},
+  {67, 0, 1850, 1, 1888},
+  {70, 0, 4993, 1, 5044},
+  {71, 0, 1547, 1, 1624},
+  {74, 0, 3692, 1, 3790},
+  {75, 0, 3584, 1, 3787},
+  {76, 0, 3572, 1, 3574},
+  {77, 1, 7711, 1, 8329},
+  {78, 1, 7711, 1, 8051},
+  {79, 1, 8480, 16, 8880},
+  {85, 0, 1826, 1, 1858},
+  {90, 1, 6252, 1, 6714},
+  {91, 0, 3572, 1, 3574},
+  {92, 0, 3584, 1, 3787},
+  {93, 0, 3572, 1, 3574},
+  {94, 0, 3584, 1, 3587},
+  {257, 3, 22388, 1, 22558},
+  {257, 4, 22390, 2, 22556},
+  {258, 3, 22257, 1, 22443},
+  {258, 4, 22258, 2, 22442},
+  {260, 3, 22995, 1, 23166},
+  {260, 4, 22996, 2, 23164},
+  {261, 3, 22446, 1, 22492},
+  {261, 4, 22446, 2, 22490},
+};
+// clang-format on
+
+// Section 5.4.3 of 38.101-1 and -2
+void check_ssb_raster(uint64_t freq, int band, int scs)
+{
+  int start_gscn = 0, step_gscn = 0, end_gscn = 0;
+  for (int i = 0; i < sizeof(sync_raster) / sizeof(sync_raster_t); i++) {
+    if (sync_raster[i].band == band && sync_raster[i].scs_index == scs) {
+      start_gscn = sync_raster[i].first_gscn;
+      step_gscn = sync_raster[i].step_gscn;
+      end_gscn = sync_raster[i].last_gscn;
+      break;
+    }
+  }
+  AssertFatal(start_gscn != 0, "Couldn't find band %d with SCS %d\n", band, scs);
+  int gscn;
+  if (freq < 3000000000) {
+    int N = 0;
+    int M = 0;
+    for (int k = 0; k < 3; k++) {
+      M = (k << 1) + 1;
+      if ((freq - M * 50000) % 1200000 == 0) {
+        N = (freq - M * 50000) / 1200000;
+        break;
+      }
+    }
+    AssertFatal(N != 0, "SSB frequency %lu Hz not on the synchronization raster (N * 1200kHz + M * 50 kHz)\n", freq);
+    gscn = (3 * N) + (M - 3) / 2;
+  } else if (freq < 24250000000) {
+    AssertFatal((freq - 3000000000) % 1440000 == 0,
+                "SSB frequency %lu Hz not on the synchronization raster (3000 MHz + N * 1.44 MHz)\n",
+                freq);
+    gscn = ((freq - 3000000000) / 1440000) + 7499;
+  } else {
+    AssertFatal((freq - 24250080000) % 17280000 == 0,
+                "SSB frequency %lu Hz not on the synchronization raster (24250.08 MHz + N * 17.28 MHz)\n",
+                freq);
+    gscn = ((freq - 24250080000) / 17280000) + 22256;
+  }
+  AssertFatal(gscn >= start_gscn && gscn <= end_gscn,
+              "GSCN %d corresponding to SSB frequency %lu does not belong to GSCN range for band %d\n",
+              gscn,
+              freq,
+              band);
+  int rel_gscn = gscn - start_gscn;
+  AssertFatal(rel_gscn % step_gscn == 0,
+              "GSCN %d corresponding to SSB frequency %lu not in accordance with GSCN step for band %d\n",
+              gscn,
+              freq,
+              band);
+}
+
 int get_supported_bw_mhz(frequency_range_t frequency_range, int scs, int nb_rb)
 {
   int bw_index = get_supported_band_index(scs, frequency_range, nb_rb);
@@ -910,6 +1027,129 @@ uint32_t get_ssb_offset_to_pointA(uint32_t absoluteFrequencySSB,
   return ssb_offset_point_a;
 }
 
+static double get_start_freq(const double fc, const int nbRB, const int mu)
+{
+  const int scs = MU_SCS(mu) * 1000;
+  return fc - (nbRB / 2 * NR_NB_SC_PER_RB * scs);
+}
+
+static double get_stop_freq(const double fc, const int nbRB, const int mu)
+{
+  int scs = MU_SCS(mu) * 1000;
+  return fc + (nbRB / 2 * NR_NB_SC_PER_RB * scs);
+}
+
+static void compute_M_and_N(const int gscn, int *rM, int *rN)
+{
+  if (gscn > 1 && gscn < 7499) {
+    for (int M = 1; M < 6; M += 2) {
+      /* GSCN = 3N + (M-3) / 2
+         N(int) = 2 * GSCN + 3 - M
+      */
+      if (((2 * gscn + 3 - M) % 6) == 0) {
+        *rM = M;
+        *rN = (2 * gscn + 3 - M) / 6;
+        break;
+      }
+    }
+  } else if (gscn > 7498 && gscn < 22256) {
+    *rN = gscn - 7499;
+  } else if (gscn > 22255 && gscn < 26638) {
+    *rN = gscn - 22256;
+  } else {
+    LOG_E(NR_PHY, "Invalid GSCN\n");
+    abort();
+  }
+}
+
+// Section 5.4.3 of 38.101-1 and -2
+static double get_ssref_from_gscn(const int gscn)
+{
+  int M, N = -1;
+  compute_M_and_N(gscn, &M, &N);
+  if (gscn > 1 && gscn < 7499) { // Sub 3GHz
+    AssertFatal(N > 0 && N < 2500, "Invalid N\n");
+    AssertFatal(M > 0 && M < 6 && (M & 0x1), "Invalid M\n");
+    return (N * 1200e3 + M * 50e3);
+  } else if (gscn > 7498 && gscn < 22256) {
+    AssertFatal(N > -1 && N < 14757, "Invalid N\n");
+    return (3000e6 + N * 1.44e6);
+  } else if (gscn > 22255 && gscn < 26638) {
+    AssertFatal(N > -1 && N < 4382, "Invalid N\n");
+    return (24250.08e6 + N * 17.28e6);
+  } else {
+    LOG_E(NR_PHY, "Invalid GSCN\n");
+    abort();
+  }
+}
+
+static void find_gscn_to_scan(const double startFreq,
+                              const double stopFreq,
+                              const sync_raster_t gscn,
+                              int *scanGscnStart,
+                              int *scanGscnStop)
+{
+  const double scs = MU_SCS(gscn.scs_index) * 1e3;
+  const double ssbBW = 20 * NR_NB_SC_PER_RB * scs;
+
+  for (int g = gscn.first_gscn; g < gscn.last_gscn; g += gscn.step_gscn) {
+    const double centerSSBFreq = get_ssref_from_gscn(g);
+    const double startSSBFreq = centerSSBFreq - ssbBW / 2;
+    if (startSSBFreq < startFreq)
+      continue;
+
+    *scanGscnStart = g;
+    break;
+  }
+
+  for (int g = gscn.last_gscn; g > gscn.first_gscn; g -= gscn.step_gscn) {
+    const double centerSSBFreq = get_ssref_from_gscn(g);
+    const double stopSSBFreq = centerSSBFreq + ssbBW / 2 - 1;
+    if (stopSSBFreq > stopFreq)
+      continue;
+
+    *scanGscnStop = g;
+    break;
+  }
+}
+
+static int get_ssb_first_sc(const double pointA, const double ssbCenter, const int mu)
+{
+  const double scs = MU_SCS(mu) * 1e3;
+  const int ssbRBs = 20;
+  return (int)((ssbCenter - pointA) / scs - (ssbRBs / 2 * NR_NB_SC_PER_RB));
+}
+
+/* Returns array of first SCS offset in the scanning window */
+int get_scan_ssb_first_sc(const double fc, const int nbRB, const int nrBand, const int mu, nr_gscn_info_t ssbInfo[MAX_GSCN_BAND])
+{
+  const double startFreq = get_start_freq(fc, nbRB, mu);
+  const double stopFreq = get_stop_freq(fc, nbRB, mu);
+
+  int scanGscnStart = -1;
+  int scanGscnStop = -1;
+  sync_raster_t tmpRaster = {0};
+  for (const sync_raster_t *r = sync_raster; r < r + (sizeof(sync_raster) / sizeof(sync_raster_t)); r++) {
+    if (r->band == nrBand && r->scs_index == mu) {
+      tmpRaster = *r;
+      break;
+    }
+  }
+  find_gscn_to_scan(startFreq, stopFreq, tmpRaster, &scanGscnStart, &scanGscnStop);
+
+  const double scs = MU_SCS(mu) * 1e3;
+  const double pointA = fc - (nbRB / 2 * scs * NR_NB_SC_PER_RB);
+  int numGscn = 0;
+  for (int g = scanGscnStart; (g <= scanGscnStop) && (numGscn < MAX_GSCN_BAND); g += tmpRaster.step_gscn) {
+    ssbInfo[numGscn].ssRef = get_ssref_from_gscn(g);
+    ssbInfo[numGscn].ssbFirstSC = get_ssb_first_sc(pointA, ssbInfo[numGscn].ssRef, mu);
+    ssbInfo[numGscn].gscn = g;
+    numGscn++;
+  }
+
+  return numGscn;
+}
+
 int get_delay_idx(int delay, int max_delay_comp)
 {
   int delay_idx = max_delay_comp + delay;
diff --git a/common/utils/nr/nr_common.h b/common/utils/nr/nr_common.h
index 6882028182aebf68a832d9f7cdc3287e7db685ab..d044130412795a83f767355cc4997a7f3be4da41 100644
--- a/common/utils/nr/nr_common.h
+++ b/common/utils/nr/nr_common.h
@@ -77,6 +77,9 @@ static inline const char *rnti_types(nr_rnti_type_t rr)
 }
 #undef R
 
+#define MU_SCS(m) (15 << m)
+#define MAX_GSCN_BAND 620 // n78 has the highest GSCN range of 619
+
 #define NR_MAX_NB_LAYERS 4 // 8
 
 // Since the IQ samples are represented by SQ15 R+I (see https://en.wikipedia.org/wiki/Q_(number_format)) we need to compensate when
@@ -104,6 +107,12 @@ typedef struct {
   int last_gscn;
 } sync_raster_t;
 
+typedef struct {
+  int gscn;
+  double ssRef;
+  int ssbFirstSC;
+} nr_gscn_info_t;
+
 typedef enum frequency_range_e {
   FR1 = 0,
   FR2
@@ -238,6 +247,14 @@ void freq2time(uint16_t ofdm_symbol_size,
 
 void nr_est_delay(int ofdm_symbol_size, const c16_t *ls_est, c16_t *ch_estimates_time, delay_t *delay);
 
+int get_scan_ssb_first_sc(const double fc,
+                          const int nbRB,
+                          const int nrBand,
+                          const int mu,
+                          nr_gscn_info_t ssbStartSC[MAX_GSCN_BAND]);
+
+void check_ssb_raster(uint64_t freq, int band, int scs);
+
 #define CEILIDIV(a,b) ((a+b-1)/b)
 #define ROUNDIDIV(a,b) (((a<<1)+b)/(b<<1))
 
diff --git a/doc/RUNMODEM.md b/doc/RUNMODEM.md
index 2544dce84560aeae368e8b9a073100fa01ea2b1e..4245ec9ae560d2755971b8fab9d767767652de1d 100644
--- a/doc/RUNMODEM.md
+++ b/doc/RUNMODEM.md
@@ -102,6 +102,9 @@ Command line parameters for UE in `--sa` mode:
 - `--band` : NR band number (default value 78)
 - `--ssb` : SSB start subcarrier (default value 516)
 
+**Optional parameters**:
+- `--ue-scan-carrier` : scan for cells in current bandwidth. This option can be used if the SSB position of the gNB is unknown. If multiple cells are detected, the UE will try to connect to the first cell. By default, this option is disabled and the UE attempts to only decode SSB given by `--ssb`.
+
 To simplify the configuration for the user testing OAI UE with OAI gNB, the latter prints the following LOG that guides the user to correctly set some of the UE command line parameters.
 
 ```
diff --git a/executables/nr-softmodem-common.h b/executables/nr-softmodem-common.h
index f01bf320d7eebde144c90990fc91c384307dc2c5..e84ca015ccaac50e4162535253ca3021f3120efc 100644
--- a/executables/nr-softmodem-common.h
+++ b/executables/nr-softmodem-common.h
@@ -46,7 +46,7 @@
 #define CONFIG_HLP_UETXG         "set UE TX gain\n"
 #define CONFIG_HLP_UENANTR       "set UE number of rx antennas\n"
 #define CONFIG_HLP_UENANTT       "set UE number of tx antennas\n"
-#define CONFIG_HLP_UESCAN        "set UE to scan around carrier\n"
+#define CONFIG_HLP_UESCAN "set UE to scan all possible GSCN in current bandwidth\n"
 #define CONFIG_HLP_UEFO          "set UE to enable estimation and compensation of frequency offset\n"
 #define CONFIG_HLP_DUMPFRAME     "dump UE received frame to rxsig_frame0.dat and exit\n"
 #define CONFIG_HLP_DLSHIFT       "dynamic shift for LLR compuation for TM3/4 (default 0)\n"
diff --git a/executables/nr-softmodem.c b/executables/nr-softmodem.c
index a286347e379d694e0ae4ec1db7ed54a85acc59ab..6663b011e91f521f8e197ad6f9347595a65f3307 100644
--- a/executables/nr-softmodem.c
+++ b/executables/nr-softmodem.c
@@ -49,7 +49,6 @@
 #include "PHY_INTERFACE/phy_interface_vars.h"
 #include "gnb_config.h"
 #include "SIMULATION/TOOLS/sim.h"
-#include "executables/lte-softmodem.h"
 
 #ifdef SMBV
 #include "PHY/TOOLS/smbv.h"
@@ -604,6 +603,7 @@ static void initialize_agent(ngran_node_t node_type, e2_agent_args_t oai_args)
 }
 #endif
 
+void init_eNB_afterRU(void);
 configmodule_interface_t *uniqCfg = NULL;
 int main( int argc, char **argv ) {
   int ru_id, CC_id = 0;
diff --git a/executables/nr-ue.c b/executables/nr-ue.c
index 6012db86e0e10c2d2cbf3e046f2589701faaa341..0a47de2a5991631890c647f1adb5a520f478c497 100644
--- a/executables/nr-ue.c
+++ b/executables/nr-ue.c
@@ -94,12 +94,6 @@
  *
  */
 
-typedef enum {
-  pss = 0,
-  pbch = 1,
-  si = 2
-} sync_mode_t;
-
 static void *NRUE_phy_stub_standalone_pnf_task(void *arg);
 
 static size_t dump_L1_UE_meas_stats(PHY_VARS_NR_UE *ue, char *output, size_t max_len)
@@ -348,134 +342,51 @@ static void *NRUE_phy_stub_standalone_pnf_task(void *arg)
  * \param arg is a pointer to a \ref PHY_VARS_NR_UE structure.
  */
 
-typedef nr_rxtx_thread_data_t syncData_t;
+typedef struct {
+  PHY_VARS_NR_UE *UE;
+  UE_nr_rxtx_proc_t proc;
+  nr_gscn_info_t gscnInfo[MAX_GSCN_BAND];
+  int numGscn;
+  int rx_offset;
+} syncData_t;
 
 static void UE_synch(void *arg) {
-  syncData_t *syncD=(syncData_t *) arg;
-  int i, hw_slot_offset;
+  syncData_t *syncD = (syncData_t *)arg;
   PHY_VARS_NR_UE *UE = syncD->UE;
-  sync_mode_t sync_mode = pbch;
-  //int CC_id = UE->CC_id;
-  static int freq_offset = 0;
   UE->is_synchronized = 0;
 
-  if (UE->UE_scan == 0) {
-
-    for (i=0; i<openair0_cfg[UE->rf_map.card].rx_num_channels; i++) {
-
-      LOG_I( PHY, "[SCHED][UE] Check absolute frequency DL %f, UL %f (RF card %d, oai_exit %d, channel %d, rx_num_channels %d)\n",
-        openair0_cfg[UE->rf_map.card].rx_freq[UE->rf_map.chain+i],
-        openair0_cfg[UE->rf_map.card].tx_freq[UE->rf_map.chain+i],
-        UE->rf_map.card,
-        oai_exit,
-        i,
-        openair0_cfg[0].rx_num_channels);
-
-    }
-
-    sync_mode = pbch;
-  } else {
-    LOG_E(PHY,"Fixme!\n");
-    /*
-    for (i=0; i<openair0_cfg[UE->rf_map.card].rx_num_channels; i++) {
-      downlink_frequency[UE->rf_map.card][UE->rf_map.chain+i] = bands_to_scan.band_info[CC_id].dl_min;
-      uplink_frequency_offset[UE->rf_map.card][UE->rf_map.chain+i] =
-        bands_to_scan.band_info[CC_id].ul_min-bands_to_scan.band_info[CC_id].dl_min;
-      openair0_cfg[UE->rf_map.card].rx_freq[UE->rf_map.chain+i] = downlink_frequency[CC_id][i];
-      openair0_cfg[UE->rf_map.card].tx_freq[UE->rf_map.chain+i] =
-        downlink_frequency[CC_id][i]+uplink_frequency_offset[CC_id][i];
-      openair0_cfg[UE->rf_map.card].rx_gain[UE->rf_map.chain+i] = UE->rx_total_gain_dB;
-    }
-    */
-  }
-
   if (UE->target_Nid_cell != -1) {
     LOG_W(NR_PHY, "Starting re-sync detection for target Nid_cell %i\n", UE->target_Nid_cell);
   } else {
     LOG_W(NR_PHY, "Starting sync detection\n");
   }
 
-  switch (sync_mode) {
-    /*
-    case pss:
-      LOG_I(PHY,"[SCHED][UE] Scanning band %d (%d), freq %u\n",bands_to_scan.band_info[current_band].band, current_band,bands_to_scan.band_info[current_band].dl_min+current_offset);
-      //lte_sync_timefreq(UE,current_band,bands_to_scan.band_info[current_band].dl_min+current_offset);
-      current_offset += 20000000; // increase by 20 MHz
-
-      if (current_offset > bands_to_scan.band_info[current_band].dl_max-bands_to_scan.band_info[current_band].dl_min) {
-        current_band++;
-        current_offset=0;
-      }
-
-      if (current_band==bands_to_scan.nbands) {
-        current_band=0;
-        oai_exit=1;
-      }
-
-      for (i=0; i<openair0_cfg[UE->rf_map.card].rx_num_channels; i++) {
-        downlink_frequency[UE->rf_map.card][UE->rf_map.chain+i] = bands_to_scan.band_info[current_band].dl_min+current_offset;
-        uplink_frequency_offset[UE->rf_map.card][UE->rf_map.chain+i] = bands_to_scan.band_info[current_band].ul_min-bands_to_scan.band_info[0].dl_min + current_offset;
-        openair0_cfg[UE->rf_map.card].rx_freq[UE->rf_map.chain+i] = downlink_frequency[CC_id][i];
-        openair0_cfg[UE->rf_map.card].tx_freq[UE->rf_map.chain+i] = downlink_frequency[CC_id][i]+uplink_frequency_offset[CC_id][i];
-        openair0_cfg[UE->rf_map.card].rx_gain[UE->rf_map.chain+i] = UE->rx_total_gain_dB;
-
-        if (UE->UE_scan_carrier) {
-          openair0_cfg[UE->rf_map.card].autocal[UE->rf_map.chain+i] = 1;
-        }
-      }
-
-      break;
-    */
-    case pbch:
-      LOG_I(PHY, "[UE thread Synch] Running Initial Synch \n");
-
-      uint64_t dl_carrier, ul_carrier;
-      nr_get_carrier_frequencies(UE, &dl_carrier, &ul_carrier);
-      nr_initial_sync_t ret = nr_initial_sync(&syncD->proc, UE, 2, get_softmodem_params()->sa);
-      if (ret.cell_detected) {
-        syncD->rx_offset = ret.rx_offset;
-        freq_offset = UE->common_vars.freq_offset; // frequency offset computed with pss in initial sync
-        hw_slot_offset =
-            ((ret.rx_offset << 1) / UE->frame_parms.samples_per_subframe * UE->frame_parms.slots_per_subframe)
-            + round((float)((ret.rx_offset << 1) % UE->frame_parms.samples_per_subframe) / UE->frame_parms.samples_per_slot0);
-
-        // rerun with new cell parameters and frequency-offset
-        // todo: the freq_offset computed on DL shall be scaled before being applied to UL
-        nr_rf_card_config_freq(&openair0_cfg[UE->rf_map.card], ul_carrier, dl_carrier, freq_offset);
-
-        LOG_I(PHY,"Got synch: hw_slot_offset %d, carrier off %d Hz, rxgain %f (DL %f Hz, UL %f Hz)\n",
-              hw_slot_offset,
-              freq_offset,
-              openair0_cfg[UE->rf_map.card].rx_gain[0],
-              openair0_cfg[UE->rf_map.card].rx_freq[0],
-              openair0_cfg[UE->rf_map.card].tx_freq[0]);
-
-        UE->rfdevice.trx_set_freq_func(&UE->rfdevice,&openair0_cfg[0]);
-        if (UE->UE_scan_carrier == 1)
-          UE->UE_scan_carrier = 0;
-        else
-          UE->is_synchronized = 1;
-      } else {
-        if (UE->UE_scan_carrier == 1) {
-
-          if (freq_offset >= 0)
-            freq_offset += 100;
-
-          freq_offset *= -1;
-
-          nr_rf_card_config_freq(&openair0_cfg[UE->rf_map.card], ul_carrier, dl_carrier, freq_offset);
-
-          LOG_I(PHY, "Initial sync failed: trying carrier off %d Hz\n", freq_offset);
-
-          UE->rfdevice.trx_set_freq_func(&UE->rfdevice,&openair0_cfg[0]);
-        }
-      }
-      break;
-
-    case si:
-    default:
-      break;
-
+  LOG_I(PHY, "[UE thread Synch] Running Initial Synch \n");
+
+  uint64_t dl_carrier, ul_carrier;
+  nr_get_carrier_frequencies(UE, &dl_carrier, &ul_carrier);
+  nr_initial_sync_t ret = nr_initial_sync(&syncD->proc, UE, 2, get_softmodem_params()->sa, syncD->gscnInfo, syncD->numGscn);
+  if (ret.cell_detected) {
+    syncD->rx_offset = ret.rx_offset;
+    const int freq_offset = UE->common_vars.freq_offset; // frequency offset computed with pss in initial sync
+    const int hw_slot_offset =
+        ((ret.rx_offset << 1) / UE->frame_parms.samples_per_subframe * UE->frame_parms.slots_per_subframe)
+        + round((float)((ret.rx_offset << 1) % UE->frame_parms.samples_per_subframe) / UE->frame_parms.samples_per_slot0);
+
+    // rerun with new cell parameters and frequency-offset
+    // todo: the freq_offset computed on DL shall be scaled before being applied to UL
+    nr_rf_card_config_freq(&openair0_cfg[UE->rf_map.card], ul_carrier, dl_carrier, freq_offset);
+
+    LOG_I(PHY,
+          "Got synch: hw_slot_offset %d, carrier off %d Hz, rxgain %f (DL %f Hz, UL %f Hz)\n",
+          hw_slot_offset,
+          freq_offset,
+          openair0_cfg[UE->rf_map.card].rx_gain[0],
+          openair0_cfg[UE->rf_map.card].rx_freq[0],
+          openair0_cfg[UE->rf_map.card].tx_freq[0]);
+
+    UE->rfdevice.trx_set_freq_func(&UE->rfdevice, &openair0_cfg[0]);
+    UE->is_synchronized = 1;
   }
 }
 
@@ -609,6 +520,7 @@ static int UE_dl_preprocessing(PHY_VARS_NR_UE *UE, const UE_nr_rxtx_proc_t *proc
     // Start synchronization with a target gNB
     if (UE->synch_request.received_synch_request == 1) {
       UE->is_synchronized = 0;
+      UE->UE_scan_carrier = UE->synch_request.synch_req.ssb_bw_scan;
       UE->target_Nid_cell = UE->synch_request.synch_req.target_Nid_cell;
       clean_UE_harq(UE);
       UE->synch_request.received_synch_request = 0;
@@ -803,16 +715,16 @@ void *UE_thread(void *arg)
         delNotifiedFIFO_elt(res);
         stream_status = STREAM_STATUS_UNSYNC;
       } else {
-	if (IS_SOFTMODEM_IQPLAYER || IS_SOFTMODEM_IQRECORDER) {
-	  // For IQ recorder-player we force synchronization to happen in 280 ms
-	  while (trashed_frames != 28) {
-	    readFrame(UE, &sync_timestamp, true);
-	    trashed_frames += 2;
-	  }
-	} else {
-	  readFrame(UE, &sync_timestamp, true);
-	  trashed_frames += 2;
-	}
+        if (IS_SOFTMODEM_IQPLAYER || IS_SOFTMODEM_IQRECORDER) {
+          // For IQ recorder-player we force synchronization to happen in 280 ms
+          while (trashed_frames != 28) {
+            readFrame(UE, &sync_timestamp, true);
+            trashed_frames += 2;
+          }
+        } else {
+          readFrame(UE, &sync_timestamp, true);
+          trashed_frames += 2;
+        }
         continue;
       }
     }
@@ -823,6 +735,20 @@ void *UE_thread(void *arg)
       readFrame(UE, &sync_timestamp, false);
       notifiedFIFO_elt_t *Msg = newNotifiedFIFO_elt(sizeof(syncData_t), 0, &nf, UE_synch);
       syncData_t *syncMsg = (syncData_t *)NotifiedFifoData(Msg);
+      NR_DL_FRAME_PARMS *fp = &UE->frame_parms;
+      if (UE->UE_scan_carrier) {
+        // Get list of GSCN in this band for UE's bandwidth and center frequency.
+        LOG_W(PHY, "UE set to scan all GSCN in current bandwidth\n");
+        syncMsg->numGscn =
+            get_scan_ssb_first_sc(fp->dl_CarrierFreq, fp->N_RB_DL, fp->nr_band, fp->numerology_index, syncMsg->gscnInfo);
+      } else {
+        LOG_W(PHY, "SSB position provided\n");
+        nr_gscn_info_t *g = syncMsg->gscnInfo;
+        g->ssbFirstSC = fp->ssb_start_subcarrier;
+        g->gscn = 0;
+        g->ssRef = 0;
+        syncMsg->numGscn = 1;
+      }
       syncMsg->UE = UE;
       memset(&syncMsg->proc, 0, sizeof(syncMsg->proc));
       pushTpool(&(get_nrUE_params()->Tpool), Msg);
diff --git a/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h b/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h
index 8df5e9cc1c7e138df26e5da6fc2101355d5ae5ff..8ff7030af5bcad613e0197fccdfd484c30fc234c 100644
--- a/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h
+++ b/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h
@@ -687,6 +687,7 @@ typedef struct
 
 typedef struct {
   int16_t target_Nid_cell;
+  bool ssb_bw_scan;
 } fapi_nr_synch_request_t;
 
 typedef struct {
diff --git a/openair1/PHY/INIT/nr_init_ue.c b/openair1/PHY/INIT/nr_init_ue.c
index 5c7c667e299182efd7b68902d8ec6d05dc547c6b..0552ddb68b2d3b90370f1679d392f3280eb07732 100644
--- a/openair1/PHY/INIT/nr_init_ue.c
+++ b/openair1/PHY/INIT/nr_init_ue.c
@@ -706,7 +706,6 @@ void phy_init_nr_top(PHY_VARS_NR_UE *ue) {
 void phy_term_nr_top(void)
 {
   free_ul_reference_signal_sequences();
-  free_context_synchro_nr();
 }
 
 static void sl_generate_psbch_dmrs_qpsk_sequences(PHY_VARS_NR_UE *UE, struct complex16 *modulated_dmrs_sym, uint16_t slss_id)
diff --git a/openair1/PHY/INIT/nr_parms.c b/openair1/PHY/INIT/nr_parms.c
index 2e292e470506e8900ce81087c90a450c2a8158eb..d44e2a7537c2e3eeab5fe50efdc1f0d1e401884b 100644
--- a/openair1/PHY/INIT/nr_parms.c
+++ b/openair1/PHY/INIT/nr_parms.c
@@ -109,9 +109,8 @@ void set_Lmax(NR_DL_FRAME_PARMS *fp) {
   }
 }
 
-
-int nr_get_ssb_start_symbol(NR_DL_FRAME_PARMS *fp,uint8_t i_ssb) {
-
+int nr_get_ssb_start_symbol(const NR_DL_FRAME_PARMS *fp, uint8_t i_ssb)
+{
   int mu = fp->numerology_index;
   int symbol = 0;
   uint8_t n, n_temp;
diff --git a/openair1/PHY/INIT/nr_phy_init.h b/openair1/PHY/INIT/nr_phy_init.h
index a39f931de1fa6b7768f6911938a4df3717c8798c..bfbe21ce04bb9406d7ee5b5075137a32febafcbf 100644
--- a/openair1/PHY/INIT/nr_phy_init.h
+++ b/openair1/PHY/INIT/nr_phy_init.h
@@ -25,7 +25,7 @@
 #include "PHY/defs_gNB.h"
 #include "PHY/defs_nr_UE.h"
 
-int nr_get_ssb_start_symbol(NR_DL_FRAME_PARMS *fp,uint8_t i_ssb);
+int nr_get_ssb_start_symbol(const NR_DL_FRAME_PARMS *fp, uint8_t i_ssb);
 void nr_init_frame_parms(nfapi_nr_config_request_scf_t *config, NR_DL_FRAME_PARMS *frame_parms);
 int nr_init_frame_parms_ue(NR_DL_FRAME_PARMS *frame_parms, fapi_nr_config_request_t *config, uint16_t nr_band);
 void nr_init_frame_parms_ue_sa(NR_DL_FRAME_PARMS *frame_parms, uint64_t downlink_frequency, int32_t uplink_frequency_offset, uint8_t mu, uint16_t nr_band);
diff --git a/openair1/PHY/MODULATION/modulation_UE.h b/openair1/PHY/MODULATION/modulation_UE.h
index 03c13db8aea37866c42ce3096a52ad3e271f3b4f..68d4c2c5a213c7cc5f8cf91798ee4ffcc06f10ba 100644
--- a/openair1/PHY/MODULATION/modulation_UE.h
+++ b/openair1/PHY/MODULATION/modulation_UE.h
@@ -61,12 +61,11 @@ int sl_nr_slot_fep(PHY_VARS_NR_UE *ue,
                    uint32_t sample_offset,
                    c16_t rxdataF[][ue->SL_UE_PHY_PARAMS.sl_frame_params.samples_per_slot_wCP]);
 
-int nr_slot_fep_init_sync(PHY_VARS_NR_UE *ue,
-                          const UE_nr_rxtx_proc_t *proc,
+int nr_slot_fep_init_sync(const NR_DL_FRAME_PARMS *frame_parms,
                           unsigned char symbol,
                           int sample_offset,
-                          bool pbch_decoded,
-                          c16_t rxdataF[][ue->frame_parms.samples_per_slot_wCP],
+                          const c16_t **rxdata,
+                          c16_t rxdataF[][frame_parms->samples_per_slot_wCP],
                           int link_type);
 
 int slot_fep_mbsfn(PHY_VARS_UE *phy_vars_ue,
diff --git a/openair1/PHY/MODULATION/slot_fep_nr.c b/openair1/PHY/MODULATION/slot_fep_nr.c
index 4024796bb0cc4374e896c3666565b123ef76f9c1..57d37a2fe609a43730f58b6fac96f255ac07df92 100644
--- a/openair1/PHY/MODULATION/slot_fep_nr.c
+++ b/openair1/PHY/MODULATION/slot_fep_nr.c
@@ -203,31 +203,19 @@ int nr_slot_fep(PHY_VARS_NR_UE *ue,
   return 0;
 }
 
-int nr_slot_fep_init_sync(PHY_VARS_NR_UE *ue,
-                          const UE_nr_rxtx_proc_t *proc,
+int nr_slot_fep_init_sync(const NR_DL_FRAME_PARMS *frame_parms,
                           unsigned char symbol,
                           int sample_offset,
-                          bool pbch_decoded,
-                          c16_t rxdataF[][ue->frame_parms.samples_per_slot_wCP],
+                          const c16_t **rxdata,
+                          c16_t rxdataF[][frame_parms->samples_per_slot_wCP],
                           int link_type)
 {
-  NR_DL_FRAME_PARMS *frame_parms = &ue->frame_parms;
-  NR_UE_COMMON *common_vars   = &ue->common_vars;
-  int Ns = proc->nr_slot_rx;
+  int Ns = 0;
 
   AssertFatal(symbol < frame_parms->symbols_per_slot, "slot_fep: symbol must be between 0 and %d\n", frame_parms->symbols_per_slot-1);
   AssertFatal(Ns < frame_parms->slots_per_frame, "slot_fep: Ns must be between 0 and %d\n", frame_parms->slots_per_frame-1);
 
-  unsigned int nb_prefix_samples;
-  unsigned int nb_prefix_samples0;
-  if (pbch_decoded) {
-    nb_prefix_samples  = frame_parms->nb_prefix_samples;
-    nb_prefix_samples0 = frame_parms->nb_prefix_samples0;
-  }
-  else {
-    nb_prefix_samples  = frame_parms->nb_prefix_samples;
-    nb_prefix_samples0 = frame_parms->nb_prefix_samples;
-  }
+  unsigned int nb_prefix_samples = frame_parms->nb_prefix_samples;
   unsigned int frame_length_samples = frame_parms->samples_per_frame;
 
   dft_size_idx_t dftsize = get_dft(frame_parms->ofdm_symbol_size);
@@ -236,10 +224,7 @@ int nr_slot_fep_init_sync(PHY_VARS_NR_UE *ue,
 
   unsigned int slot_offset = frame_parms->get_samples_slot_timestamp(Ns,frame_parms,0);
   unsigned int rx_offset   = sample_offset + slot_offset;
-  unsigned int abs_symbol  = Ns * frame_parms->symbols_per_slot + symbol;
-  for (int idx_symb = Ns*frame_parms->symbols_per_slot; idx_symb <= abs_symbol; idx_symb++)
-    rx_offset += (idx_symb%(0x7<<frame_parms->numerology_index)) ? nb_prefix_samples : nb_prefix_samples0;
-  rx_offset += frame_parms->ofdm_symbol_size * symbol;
+  rx_offset += (frame_parms->ofdm_symbol_size + nb_prefix_samples) * symbol + nb_prefix_samples;
 
 #ifdef DEBUG_FEP
   //  if (ue->frame <100)
@@ -256,38 +241,29 @@ int nr_slot_fep_init_sync(PHY_VARS_NR_UE *ue,
       // rxdata is 2 frames len
       // we have to wrap on the end
 
-      memcpy((void *)&tmp_dft_in[0],
-             (void *)&common_vars->rxdata[aa][rx_offset],
-             (frame_length_samples*2 - rx_offset) * sizeof(int32_t));
-      memcpy((void *)&tmp_dft_in[frame_length_samples*2 - rx_offset],
-             (void *)&common_vars->rxdata[aa][0],
-             (frame_parms->ofdm_symbol_size - (frame_length_samples*2 - rx_offset)) * sizeof(int32_t));
+      memcpy((void *)&tmp_dft_in[0], (void *)&rxdata[aa][rx_offset], (frame_length_samples * 2 - rx_offset) * sizeof(int32_t));
+      memcpy((void *)&tmp_dft_in[frame_length_samples * 2 - rx_offset],
+             (void *)&rxdata[aa][0],
+             (frame_parms->ofdm_symbol_size - (frame_length_samples * 2 - rx_offset)) * sizeof(int32_t));
       rxdata_ptr = (int16_t *)tmp_dft_in;
 
     } else if ((rx_offset & 7) != 0) {
 
       // if input to dft is not 256-bit aligned
-      memcpy((void *)&tmp_dft_in[0],
-             (void *)&common_vars->rxdata[aa][rx_offset],
-             frame_parms->ofdm_symbol_size * sizeof(int32_t));
+      memcpy((void *)&tmp_dft_in[0], (void *)&rxdata[aa][rx_offset], frame_parms->ofdm_symbol_size * sizeof(int32_t));
       rxdata_ptr = (int16_t *)tmp_dft_in;
 
     } else {
 
       // use dft input from RX buffer directly
-      rxdata_ptr = (int16_t *)&common_vars->rxdata[aa][rx_offset];
-
+      rxdata_ptr = (int16_t *)&rxdata[aa][rx_offset];
     }
 
-    start_meas(&ue->rx_dft_stats);
-
     dft(dftsize,
         rxdata_ptr,
         (int16_t *)&rxdataF[aa][frame_parms->ofdm_symbol_size*symbol],
         1);
 
-    stop_meas(&ue->rx_dft_stats);
-
     int symb_offset = (Ns%frame_parms->slots_per_subframe)*frame_parms->symbols_per_slot;
     c16_t rot2 = frame_parms->symbol_rotation[link_type][symbol + symb_offset];
     rot2.i=-rot2.i;
diff --git a/openair1/PHY/NR_REFSIG/nr_dmrs_rx.c b/openair1/PHY/NR_REFSIG/nr_dmrs_rx.c
index 70381d0bd80772e6d358129ee9d9a77238517c56..4f8d86762fdf797d852b14cbdaf576e234505e21 100644
--- a/openair1/PHY/NR_REFSIG/nr_dmrs_rx.c
+++ b/openair1/PHY/NR_REFSIG/nr_dmrs_rx.c
@@ -202,7 +202,7 @@ int nr_pdcch_dmrs_rx(PHY_VARS_NR_UE *ue,
   return(0);
 }
 
-void nr_pbch_dmrs_rx(int symbol, unsigned int *nr_gold_pbch, c16_t *output, bool sidelink)
+void nr_pbch_dmrs_rx(int symbol, const unsigned int *nr_gold_pbch, c16_t *output, bool sidelink)
 {
   int m,m0,m1;
   uint8_t idx=0;
diff --git a/openair1/PHY/NR_REFSIG/nr_gold_ue.c b/openair1/PHY/NR_REFSIG/nr_gold_ue.c
index 56dd09c0f077e14b27cfbe0b46afcba46b990cf2..3259aa3173036ea341e7faa0951e5d21274c2893 100644
--- a/openair1/PHY/NR_REFSIG/nr_gold_ue.c
+++ b/openair1/PHY/NR_REFSIG/nr_gold_ue.c
@@ -21,15 +21,13 @@
 
 #include "refsig_defs_ue.h"
 
-void nr_gold_pbch(PHY_VARS_NR_UE* ue)
+void nr_gold_pbch(uint32_t nr_gold_pbch[2][64][NR_PBCH_DMRS_LENGTH_DWORD], int Nid, int Lmax)
 {
   unsigned int n = 0, x1 = 0, x2 = 0;
-  unsigned int Nid, i_ssb, i_ssb2;
-  unsigned char Lmax, l, n_hf, N_hf;
+  unsigned int i_ssb, i_ssb2;
+  unsigned char l, n_hf, N_hf;
   uint8_t reset;
 
-  Nid = ue->frame_parms.Nid_cell;
-  Lmax = ue->frame_parms.Lmax;
   N_hf = (Lmax == 4)? 2:1;
 
   for (n_hf = 0; n_hf < N_hf; n_hf++) {
@@ -42,7 +40,7 @@ void nr_gold_pbch(PHY_VARS_NR_UE* ue)
       x2 = (1<<11) * (i_ssb2 + 1) * ((Nid>>2) + 1) + (1<<6) * (i_ssb2 + 1) + (Nid&3);
 
       for (n=0; n<NR_PBCH_DMRS_LENGTH_DWORD; n++) {
-        ue->nr_gold_pbch[n_hf][l][n] = lte_gold_generic(&x1, &x2, reset);
+        nr_gold_pbch[n_hf][l][n] = lte_gold_generic(&x1, &x2, reset);
         reset = 0;
       }
 
diff --git a/openair1/PHY/NR_REFSIG/pss_nr.h b/openair1/PHY/NR_REFSIG/pss_nr.h
index ea098d088bf26d8001392052687ab7ec1a689481..cf705a7ee6d3a3419c54f03821967b39912bb9c0 100644
--- a/openair1/PHY/NR_REFSIG/pss_nr.h
+++ b/openair1/PHY/NR_REFSIG/pss_nr.h
@@ -76,8 +76,17 @@
 #define SYNCF_TMP_SIZE                 (SYNCHRO_FFT_SIZE_MAX*IQ_SIZE)
 
 void init_context_synchro_nr(NR_DL_FRAME_PARMS *frame_parms_ue);
-void free_context_synchro_nr(void);
-int pss_synchro_nr(PHY_VARS_NR_UE *PHY_vars_UE, int is, int rate_change);
+int pss_synchro_nr(const c16_t **rxdata,
+                   const NR_DL_FRAME_PARMS *frame_parms,
+                   const c16_t pssTime[NUMBER_PSS_SEQUENCE][frame_parms->ofdm_symbol_size],
+                   int is,
+                   bool fo_flag,
+                   int target_Nid_cell,
+                   int *nid2,
+                   int *f_off,
+                   int *pssPeak,
+                   int *pssAvg);
+void generate_pss_nr_time(const NR_DL_FRAME_PARMS *fp, const int N_ID_2, int ssbFirstSCS, c16_t pssTime[fp->ofdm_symbol_size]);
 int16_t *get_primary_synchro_nr2(const int nid2);
 
 #endif /* PSS_NR_H */
diff --git a/openair1/PHY/NR_REFSIG/refsig_defs_ue.h b/openair1/PHY/NR_REFSIG/refsig_defs_ue.h
index c7919130b5548790ca76eeb83001383ed6d20819..21d5a116d100db62c697d827e21a3dd6316fe4ed 100644
--- a/openair1/PHY/NR_REFSIG/refsig_defs_ue.h
+++ b/openair1/PHY/NR_REFSIG/refsig_defs_ue.h
@@ -30,7 +30,7 @@
 /*!\brief This function generates the NR Gold sequence (38-211, Sec 5.2.1) for the PBCH DMRS.
 @param PHY_VARS_NR_UE* ue structure provides configuration, frame parameters and the pointers to the 32 bits sequence storage tables
  */
-void nr_pbch_dmrs_rx(int dmrss, unsigned int *nr_gold_pbch, c16_t *output, bool sidelink);
+void nr_pbch_dmrs_rx(int dmrss, const unsigned int *nr_gold_pbch, c16_t *output, bool sidelink);
 
 /*!\brief This function generates the NR Gold sequence (38-211, Sec 5.2.1) for the PDCCH DMRS.
 @param PHY_VARS_NR_UE* ue structure provides configuration, frame parameters and the pointers to the 32 bits sequence storage tables
@@ -51,7 +51,7 @@ int nr_pdsch_dmrs_rx(PHY_VARS_NR_UE *ue,
                      unsigned short nb_pdsch_rb,
                      uint8_t config_type);
 
-void nr_gold_pbch(PHY_VARS_NR_UE* ue);
+void nr_gold_pbch(uint32_t nr_gold_pbch[2][64][NR_PBCH_DMRS_LENGTH_DWORD], int Nid, int Lmax);
 
 void nr_gold_pdcch(PHY_VARS_NR_UE* ue,
                    unsigned short n_idDMRS);
diff --git a/openair1/PHY/NR_REFSIG/sss_nr.h b/openair1/PHY/NR_REFSIG/sss_nr.h
index 1dff9128896db71e18748f8070426df81ad71cf2..8175869205b63ca39c8f5f99f7fe3e4196d173be 100644
--- a/openair1/PHY/NR_REFSIG/sss_nr.h
+++ b/openair1/PHY/NR_REFSIG/sss_nr.h
@@ -95,11 +95,15 @@ void free_context_sss_nr(void);
 void insert_sss_nr(int16_t *sss_time,
                    NR_DL_FRAME_PARMS *frame_parms);
 
-bool rx_sss_nr(PHY_VARS_NR_UE *ue,
-               const UE_nr_rxtx_proc_t *proc,
+bool rx_sss_nr(const NR_DL_FRAME_PARMS *frame_parms,
+               int nid2,
+               int target_Nid_cell,
+               int freq_offset_pss,
+               int ssb_start_subcarrier,
+               int *Nid_cell,
                int32_t *tot_metric,
                uint8_t *phase_max,
                int *freq_offset_sss,
-               c16_t rxdataF[][ue->frame_parms.samples_per_slot_wCP]);
+               c16_t rxdataF[][frame_parms->samples_per_slot_wCP]);
 #endif /* SSS_NR_H */
 
diff --git a/openair1/PHY/NR_UE_ESTIMATION/nr_dl_channel_estimation.c b/openair1/PHY/NR_UE_ESTIMATION/nr_dl_channel_estimation.c
index b4733f69cc98a20e325c0871f669637492ee2ee2..047f022d0201017ddd3af54611fbe51e4884a313 100644
--- a/openair1/PHY/NR_UE_ESTIMATION/nr_dl_channel_estimation.c
+++ b/openair1/PHY/NR_UE_ESTIMATION/nr_dl_channel_estimation.c
@@ -555,21 +555,24 @@ int nr_prs_channel_estimation(uint8_t gNB_id,
   return(0);
 }
 
-c32_t nr_pbch_dmrs_correlation(const PHY_VARS_NR_UE *ue,
+c32_t nr_pbch_dmrs_correlation(const NR_DL_FRAME_PARMS *fp,
                                const UE_nr_rxtx_proc_t *proc,
                                const int symbol,
                                const int dmrss,
+                               const int Nid_cell,
+                               const int ssb_start_subcarrier,
                                const uint32_t nr_gold_pbch[NR_PBCH_DMRS_LENGTH_DWORD],
-                               const c16_t rxdataF[][ue->frame_parms.samples_per_slot_wCP])
+                               const c16_t rxdataF[][fp->samples_per_slot_wCP])
 {
   AssertFatal(dmrss >= 0 && dmrss < 3, "symbol %d is illegal for PBCH DM-RS \n", dmrss);
 
-  unsigned int  ssb_offset = ue->frame_parms.first_carrier_offset + ue->frame_parms.ssb_start_subcarrier;
-  if (ssb_offset>= ue->frame_parms.ofdm_symbol_size) ssb_offset-=ue->frame_parms.ofdm_symbol_size;
+  unsigned int ssb_offset = fp->first_carrier_offset + ssb_start_subcarrier;
+  if (ssb_offset >= fp->ofdm_symbol_size)
+    ssb_offset -= fp->ofdm_symbol_size;
 
-  int symbol_offset = ue->frame_parms.ofdm_symbol_size * symbol;
+  int symbol_offset = fp->ofdm_symbol_size * symbol;
 
-  unsigned int k = ue->frame_parms.Nid_cell % 4;
+  unsigned int k = Nid_cell % 4;
 
   DEBUG_PBCH("PBCH DMRS Correlation : gNB_id %d , OFDM size %d, Ncp=%d, k=%u symbol %d\n",
              proc->gNB_id,
@@ -583,8 +586,7 @@ c32_t nr_pbch_dmrs_correlation(const PHY_VARS_NR_UE *ue,
   c16_t pilot[200] __attribute__((aligned(16)));
   nr_pbch_dmrs_rx(dmrss, (uint32_t *)nr_gold_pbch, pilot, false);
   c32_t computed_val = {0};
-  for (int aarx=0; aarx<ue->frame_parms.nb_antennas_rx; aarx++) {
-
+  for (int aarx = 0; aarx < fp->nb_antennas_rx; aarx++) {
     int re_offset = ssb_offset;
     c16_t *pil = pilot;
     const c16_t *rxF = &rxdataF[aarx][symbol_offset + k];
@@ -599,49 +601,50 @@ c32_t nr_pbch_dmrs_correlation(const PHY_VARS_NR_UE *ue,
     DEBUG_PBCH("pilot 0 : rxF - > (%d,%d)  pil -> (%d,%d) \n", rxF[re_offset].r, rxF[re_offset].i, pil->r, pil->i);
 
     pil++;
-    re_offset = (re_offset+4) % ue->frame_parms.ofdm_symbol_size;
+    re_offset = (re_offset + 4) % fp->ofdm_symbol_size;
     computed_val = c32x16maddShift(*pil, rxF[re_offset], computed_val, 15);
 
     DEBUG_PBCH("pilot 1 : rxF - > (%d,%d)  pil -> (%d,%d) \n", rxF[re_offset].r, rxF[re_offset].i, pil->r, pil->i);
 
     pil++;
-    re_offset = (re_offset+4) % ue->frame_parms.ofdm_symbol_size;
+    re_offset = (re_offset + 4) % fp->ofdm_symbol_size;
     computed_val = c32x16maddShift(*pil, rxF[re_offset], computed_val, 15);
 
     DEBUG_PBCH("pilot 2 : rxF - > (%d,%d), pil -> (%d,%d) \n", rxF[re_offset].r, rxF[re_offset].i, pil->r, pil->i);
 
     pil++;
-    re_offset = (re_offset + 4) % ue->frame_parms.ofdm_symbol_size;
+    re_offset = (re_offset + 4) % fp->ofdm_symbol_size;
 
     for (int pilot_cnt = 3; pilot_cnt < (3 * 20); pilot_cnt += 3) {
       // in 2nd symbol, skip middle  REs (48 with DMRS,  144 for SSS, and another 48 with DMRS) 
       if (dmrss == 1 && pilot_cnt == 12) {
 	pilot_cnt=48;
-  re_offset = (re_offset + 144) % ue->frame_parms.ofdm_symbol_size;
+  re_offset = (re_offset + 144) % fp->ofdm_symbol_size;
       }
       computed_val = c32x16maddShift(*pil, rxF[re_offset], computed_val, 15);
 
       DEBUG_PBCH("pilot %u : rxF= (%d,%d) pil= (%d,%d) \n", pilot_cnt, rxF[re_offset].r, rxF[re_offset].i, pil->r, pil->i);
 
       pil++;
-      re_offset = (re_offset+4) % ue->frame_parms.ofdm_symbol_size;
+      re_offset = (re_offset + 4) % fp->ofdm_symbol_size;
       computed_val = c32x16maddShift(*pil, rxF[re_offset], computed_val, 15);
 
       DEBUG_PBCH("pilot %u : rxF= (%d,%d) pil= (%d,%d) \n", pilot_cnt + 1, rxF[re_offset].r, rxF[re_offset].i, pil->r, pil->i);
       pil++;
-      re_offset = (re_offset+4) % ue->frame_parms.ofdm_symbol_size;
+      re_offset = (re_offset + 4) % fp->ofdm_symbol_size;
       computed_val = c32x16maddShift(*pil, rxF[re_offset], computed_val, 15);
 
       DEBUG_PBCH("pilot %u : rxF= (%d,%d)  pil= (%d,%d) \n", pilot_cnt + 2, rxF[re_offset].r, rxF[re_offset].i, pil->r, pil->i);
       pil++;
-      re_offset = (re_offset + 4) % ue->frame_parms.ofdm_symbol_size;
+      re_offset = (re_offset + 4) % fp->ofdm_symbol_size;
     }
   }
   return computed_val;
 }
 
-int nr_pbch_channel_estimation(PHY_VARS_NR_UE *ue,
-                               NR_DL_FRAME_PARMS *fp,
+int nr_pbch_channel_estimation(const NR_DL_FRAME_PARMS *fp,
+                               const sl_nr_ue_phy_params_t *sl_phy_params,
+                               const uint32_t nr_gold_pbch[2][64][NR_PBCH_DMRS_LENGTH_DWORD],
                                int estimateSz,
                                struct complex16 dl_ch_estimates[][estimateSz],
                                struct complex16 dl_ch_estimates_time[][fp->ofdm_symbol_size],
@@ -650,7 +653,8 @@ int nr_pbch_channel_estimation(PHY_VARS_NR_UE *ue,
                                int dmrss,
                                uint8_t ssb_index,
                                uint8_t n_hf,
-                               c16_t rxdataF[][fp->samples_per_slot_wCP],
+                               int ssb_start_subcarrier,
+                               const c16_t rxdataF[][fp->samples_per_slot_wCP],
                                bool sidelink,
                                uint16_t Nid)
 {
@@ -659,13 +663,11 @@ int nr_pbch_channel_estimation(PHY_VARS_NR_UE *ue,
   //int slot_pbch;
 
   uint8_t nushift = 0, lastsymbol = 0, num_rbs = 0;
-  uint32_t *gold_seq = NULL;
+  const uint32_t *gold_seq = NULL;
 
   if (sidelink) {
     AssertFatal(dmrss == 0 || (dmrss >= 5 && dmrss <= 12), "symbol %d is illegal for PSBCH DM-RS \n", dmrss);
 
-    sl_nr_ue_phy_params_t *sl_phy_params = &ue->SL_UE_PHY_PARAMS;
-
     LOG_D(PHY, "PSBCH Channel Estimation SLSSID:%d\n", Nid);
 
     gold_seq = sl_phy_params->init_params.psbch_dmrs_gold_sequences[Nid];
@@ -673,16 +675,16 @@ int nr_pbch_channel_estimation(PHY_VARS_NR_UE *ue,
     num_rbs = SL_NR_NUM_PSBCH_RBS_IN_ONE_SYMBOL;
 
   } else {
-    nushift = fp->Nid_cell % 4;
+    nushift = Nid % 4;
 
     AssertFatal(dmrss >= 0 && dmrss < 3, "symbol %d is illegal for PBCH DM-RS \n", dmrss);
 
-    gold_seq = ue->nr_gold_pbch[n_hf][ssb_index];
+    gold_seq = nr_gold_pbch[n_hf][ssb_index];
     lastsymbol = 2;
     num_rbs = 20;
   }
 
-  unsigned int ssb_offset = fp->first_carrier_offset + fp->ssb_start_subcarrier;
+  unsigned int ssb_offset = fp->first_carrier_offset + ssb_start_subcarrier;
   if (ssb_offset >= fp->ofdm_symbol_size)
     ssb_offset -= fp->ofdm_symbol_size;
 
@@ -739,7 +741,7 @@ int nr_pbch_channel_estimation(PHY_VARS_NR_UE *ue,
   for (int aarx = 0; aarx < fp->nb_antennas_rx; aarx++) {
     int re_offset = ssb_offset;
     c16_t *pil = pilot;
-    c16_t *rxF = &rxdataF[aarx][symbol_offset + k];
+    const c16_t *rxF = &rxdataF[aarx][symbol_offset + k];
     c16_t *dl_ch = &dl_ch_estimates[aarx][ch_offset];
 
     memset(dl_ch, 0, sizeof(c16_t) * fp->ofdm_symbol_size);
@@ -824,15 +826,10 @@ int nr_pbch_channel_estimation(PHY_VARS_NR_UE *ue,
     {
       // do ifft of channel estimate
       LOG_D(PHY,"Channel Impulse Computation Slot %d Symbol %d ch_offset %d\n", Ns, symbol, ch_offset);
-      freq2time(ue->frame_parms.ofdm_symbol_size,
-                (int16_t *)&dl_ch_estimates[aarx][ch_offset],
-                (int16_t *)&dl_ch_estimates_time[aarx]);
+      freq2time(fp->ofdm_symbol_size, (int16_t *)&dl_ch_estimates[aarx][ch_offset], (int16_t *)&dl_ch_estimates_time[aarx]);
     }
   }
 
-  if (!sidelink && dmrss == lastsymbol)
-    UEscopeCopy(ue, pbchDlChEstimateTime, (void *)dl_ch_estimates_time, sizeof(c16_t), fp->nb_antennas_rx, fp->ofdm_symbol_size, 0);
-
   return(0);
 }
 
diff --git a/openair1/PHY/NR_UE_ESTIMATION/nr_estimation.h b/openair1/PHY/NR_UE_ESTIMATION/nr_estimation.h
index 701967a235c2e445caf78e06cdfd2978b9dfd2ef..65bcd5c7d7a50535bce232143ff681e24cedeab5 100644
--- a/openair1/PHY/NR_UE_ESTIMATION/nr_estimation.h
+++ b/openair1/PHY/NR_UE_ESTIMATION/nr_estimation.h
@@ -57,15 +57,18 @@ void nr_pdcch_channel_estimation(PHY_VARS_NR_UE *ue,
                                  c16_t pdcch_dl_ch_estimates[][pdcch_est_size],
                                  c16_t rxdataF[][ue->frame_parms.samples_per_slot_wCP]);
 
-c32_t nr_pbch_dmrs_correlation(const PHY_VARS_NR_UE *ue,
+c32_t nr_pbch_dmrs_correlation(const NR_DL_FRAME_PARMS *fp,
                                const UE_nr_rxtx_proc_t *proc,
                                const int symbol,
                                const int dmrss,
+                               const int Nid_cell,
+                               const int ssb_start_subcarrier,
                                const uint32_t nr_gold_pbch[NR_PBCH_DMRS_LENGTH_DWORD],
-                               const c16_t rxdataF[][ue->frame_parms.samples_per_slot_wCP]);
+                               const c16_t rxdataF[][fp->samples_per_slot_wCP]);
 
-int nr_pbch_channel_estimation(PHY_VARS_NR_UE *ue,
-                               NR_DL_FRAME_PARMS *fp,
+int nr_pbch_channel_estimation(const NR_DL_FRAME_PARMS *fp,
+                               const sl_nr_ue_phy_params_t *sl_phy_params,
+                               const uint32_t nr_gold_pbch[2][64][NR_PBCH_DMRS_LENGTH_DWORD],
                                int estimateSz,
                                struct complex16 dl_ch_estimates[][estimateSz],
                                struct complex16 dl_ch_estimates_time[][fp->ofdm_symbol_size],
@@ -74,7 +77,8 @@ int nr_pbch_channel_estimation(PHY_VARS_NR_UE *ue,
                                int dmrss,
                                uint8_t ssb_index,
                                uint8_t n_hf,
-                               c16_t rxdataF[][fp->samples_per_slot_wCP],
+                               int ssb_start_subcarrier,
+                               const c16_t rxdataF[][fp->samples_per_slot_wCP],
                                bool sidelink,
                                uint16_t Nid);
 
diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_initial_sync.c b/openair1/PHY/NR_UE_TRANSPORT/nr_initial_sync.c
index c8c7f6e73d0c8174e327fe192175d1a2bcb31e5f..097739d142141eac9aa3dbe15afd071117462be1 100644
--- a/openair1/PHY/NR_UE_TRANSPORT/nr_initial_sync.c
+++ b/openair1/PHY/NR_UE_TRANSPORT/nr_initial_sync.c
@@ -45,6 +45,7 @@
 #include "PHY/NR_REFSIG/sss_nr.h"
 #include "PHY/NR_REFSIG/refsig_defs_ue.h"
 #include "PHY/TOOLS/tools_defs.h"
+#include "nr-uesoftmodem.h"
 
 //static  nfapi_nr_config_request_t config_t;
 //static  nfapi_nr_config_request_t* config =&config_t;
@@ -64,24 +65,35 @@ static int ssb_sort(const void *a, const void *b)
 }
 
 static bool nr_pbch_detection(const UE_nr_rxtx_proc_t *proc,
-                              PHY_VARS_NR_UE *ue,
+                              const NR_DL_FRAME_PARMS *frame_parms,
+                              int Nid_cell,
                               int pbch_initial_symbol,
-                              c16_t rxdataF[][ue->frame_parms.samples_per_slot_wCP])
+                              int ssb_start_subcarrier,
+                              int *half_frame_bit,
+                              int *ssb_index,
+                              int *symbol_offset,
+                              fapiPbch_t *result,
+                              const uint32_t nr_gold_pbch_ref[2][64][NR_PBCH_DMRS_LENGTH_DWORD],
+                              const c16_t rxdataF[][frame_parms->samples_per_slot_wCP])
 {
-  NR_DL_FRAME_PARMS *frame_parms = &ue->frame_parms;
-
   const int N_L = (frame_parms->Lmax == 4) ? 4 : 8;
   const int N_hf = (frame_parms->Lmax == 4) ? 2 : 1;
   NR_UE_SSB best_ssb[N_L * N_hf];
   NR_UE_SSB *current_ssb = best_ssb;
   // loops over possible pbch dmrs cases to retrieve best estimated i_ssb (and n_hf for Lmax=4) for multiple ssb detection
-  start_meas(&ue->dlsch_channel_estimation_stats);
   for (int hf = 0; hf < N_hf; hf++) {
     for (int l = 0; l < N_L; l++) {
       // computing correlation between received DMRS symbols and transmitted sequence for current i_ssb and n_hf
       cd_t cumul = {0};
       for (int i = pbch_initial_symbol; i < pbch_initial_symbol + 3; i++) {
-        c32_t meas = nr_pbch_dmrs_correlation(ue, proc, i, i - pbch_initial_symbol, ue->nr_gold_pbch[hf][l], rxdataF);
+        c32_t meas = nr_pbch_dmrs_correlation(frame_parms,
+                                              proc,
+                                              i,
+                                              i - pbch_initial_symbol,
+                                              Nid_cell,
+                                              ssb_start_subcarrier,
+                                              nr_gold_pbch_ref[hf][l],
+                                              rxdataF);
         csum(cumul, cumul, meas);
       }
       *current_ssb = (NR_UE_SSB){.i_ssb = l, .n_hf = hf, .metric = squaredMod(cumul)};
@@ -89,19 +101,18 @@ static bool nr_pbch_detection(const UE_nr_rxtx_proc_t *proc,
     }
   }
   qsort(best_ssb, N_L * N_hf, sizeof(NR_UE_SSB), ssb_sort);
-  stop_meas(&ue->dlsch_channel_estimation_stats);
 
   const int nb_ant = frame_parms->nb_antennas_rx;
   for (NR_UE_SSB *ssb = best_ssb; ssb < best_ssb + N_L * N_hf; ssb++) {
-    start_meas(&ue->dlsch_channel_estimation_stats);
     // computing channel estimation for selected best ssb
     const int estimateSz = frame_parms->symbols_per_slot * frame_parms->ofdm_symbol_size;
     __attribute__((aligned(32))) c16_t dl_ch_estimates[nb_ant][estimateSz];
     __attribute__((aligned(32))) c16_t dl_ch_estimates_time[nb_ant][frame_parms->ofdm_symbol_size];
 
     for(int i=pbch_initial_symbol; i<pbch_initial_symbol+3;i++)
-      nr_pbch_channel_estimation(ue,
-                                 &ue->frame_parms,
+      nr_pbch_channel_estimation(frame_parms,
+                                 NULL,
+                                 nr_gold_pbch_ref,
                                  estimateSz,
                                  dl_ch_estimates,
                                  dl_ch_estimates_time,
@@ -110,13 +121,27 @@ static bool nr_pbch_detection(const UE_nr_rxtx_proc_t *proc,
                                  i - pbch_initial_symbol,
                                  ssb->i_ssb,
                                  ssb->n_hf,
+                                 ssb_start_subcarrier,
                                  rxdataF,
                                  false,
-                                 frame_parms->Nid_cell);
-
-    stop_meas(&ue->dlsch_channel_estimation_stats);
-    fapiPbch_t result = {0};
-    if (0 == nr_rx_pbch(ue, proc, estimateSz, dl_ch_estimates, frame_parms, ssb->i_ssb, &result, rxdataF)) {
+                                 Nid_cell);
+
+    if (0
+        == nr_rx_pbch(NULL,
+                      proc,
+                      false,
+                      estimateSz,
+                      dl_ch_estimates,
+                      frame_parms,
+                      ssb->i_ssb,
+                      ssb_start_subcarrier,
+                      Nid_cell,
+                      result,
+                      half_frame_bit,
+                      ssb_index,
+                      symbol_offset,
+                      frame_parms->samples_per_frame_wCP,
+                      rxdataF)) {
       if (DUMP_PBCH_CH_ESTIMATES) {
         write_output("pbch_ch_estimates.m", "pbch_ch_estimates", dl_ch_estimates, nb_ant * estimateSz, 1, 1);
         write_output("pbch_ch_estimates_time.m",
@@ -126,26 +151,32 @@ static bool nr_pbch_detection(const UE_nr_rxtx_proc_t *proc,
                      1,
                      1);
       }
-      LOG_I(PHY, "[UE%d] Initial sync: pbch decoded sucessfully, ssb index %d\n", ue->Mod_id, frame_parms->ssb_index);
+      LOG_I(PHY, "Initial sync: pbch decoded sucessfully, ssb index %d\n", *ssb_index);
       return true;
     }
   }
 
-  LOG_W(PHY, "[UE%d] Initial sync: pbch not decoded, ssb index %d\n", ue->Mod_id, frame_parms->ssb_index);
+  LOG_W(PHY, "Initial sync: pbch not decoded, ssb index %d\n", frame_parms->ssb_index);
   return false;
 }
 
-nr_initial_sync_t nr_initial_sync(UE_nr_rxtx_proc_t *proc, PHY_VARS_NR_UE *ue, int n_frames, int sa)
+static void compensate_freq_offset(c16_t **x, const NR_DL_FRAME_PARMS *fp, const int offset, const int sn)
 {
-  int32_t sync_pos, sync_pos_frame; // k_ssb, N_ssb_crb, sync_pos2,
-
-  NR_DL_FRAME_PARMS *fp = &ue->frame_parms;
-  nr_initial_sync_t ret = {.cell_detected = false};
-
-  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_NR_INITIAL_UE_SYNC, VCD_FUNCTION_IN);
-
-  LOG_D(PHY, "nr_initial sync ue RB_DL %d\n", fp->N_RB_DL);
+  double s_time = 1 / (1.0e3 * fp->samples_per_subframe); // sampling time
+  double off_angle = -2 * M_PI * s_time * (offset); // offset rotation angle compensation per sample
+
+  for (int n = sn * fp->samples_per_frame; n < (sn + 1) * fp->samples_per_frame; n++) {
+    for (int ar = 0; ar < fp->nb_antennas_rx; ar++) {
+      const double re = x[ar][n].r;
+      const double im = x[ar][n].i;
+      x[ar][n].r = (short)(round(re * cos(n * off_angle) - im * sin(n * off_angle)));
+      x[ar][n].i = (short)(round(re * sin(n * off_angle) + im * cos(n * off_angle)));
+    }
+  }
+}
 
+void nr_scan_ssb(void *arg)
+{
   /*   Initial synchronisation
    *
    *                                 1 radio frame = 10 ms
@@ -159,45 +190,51 @@ nr_initial_sync_t nr_initial_sync(UE_nr_rxtx_proc_t *proc, PHY_VARS_NR_UE *ue, i
    *          sync_pos            SS/PBCH block
    */
 
-  const uint32_t rxdataF_sz = ue->frame_parms.samples_per_slot_wCP;
-  __attribute__((aligned(32))) c16_t rxdataF[ue->frame_parms.nb_antennas_rx][rxdataF_sz];
+  nr_ue_ssb_scan_t *ssbInfo = (nr_ue_ssb_scan_t *)arg;
+  c16_t **rxdata = ssbInfo->rxdata;
+  const NR_DL_FRAME_PARMS *fp = ssbInfo->fp;
+
+  // Generate PSS time signal for this GSCN.
+  __attribute__((aligned(32))) c16_t pssTime[NUMBER_PSS_SEQUENCE][fp->ofdm_symbol_size];
+  const int pss_sequence = get_softmodem_params()->sl_mode == 0 ? NUMBER_PSS_SEQUENCE : NUMBER_PSS_SEQUENCE_SL;
+  for (int nid2 = 0; nid2 < pss_sequence; nid2++)
+    generate_pss_nr_time(fp, nid2, ssbInfo->gscnInfo.ssbFirstSC, pssTime[nid2]);
 
   // initial sync performed on two successive frames, if pbch passes on first frame, no need to process second frame
-  // only one frame is used for symulation tools
-  for (int frame_id = 0; frame_id < n_frames && !ret.cell_detected; frame_id++) {
+  // only one frame is used for simulation tools
+  for (int frame_id = 0; frame_id < ssbInfo->nFrames && !ssbInfo->syncRes.cell_detected; frame_id++) {
     /* process pss search on received buffer */
-    sync_pos = pss_synchro_nr(ue, frame_id, NO_RATE_CHANGE);
+    ssbInfo->syncRes.frame_id = frame_id;
+    int nid2;
+    int freq_offset_pss;
+    const int sync_pos = pss_synchro_nr((const c16_t **)rxdata,
+                                        fp,
+                                        pssTime,
+                                        frame_id,
+                                        ssbInfo->foFlag,
+                                        ssbInfo->targetNidCell,
+                                        &nid2,
+                                        &freq_offset_pss,
+                                        &ssbInfo->pssCorrPeakPower,
+                                        &ssbInfo->pssCorrAvgPower);
     if (sync_pos < fp->nb_prefix_samples)
       continue;
 
-    ue->ssb_offset = sync_pos - fp->nb_prefix_samples;
+    ssbInfo->ssbOffset = sync_pos - fp->nb_prefix_samples;
 
 #ifdef DEBUG_INITIAL_SYNCH
     LOG_I(PHY, "[UE%d] Initial sync : Estimated PSS position %d, Nid2 %d\n", ue->Mod_id, sync_pos, ue->common_vars.nid2);
     LOG_I(PHY, "sync_pos %d ssb_offset %d \n", sync_pos, ue->ssb_offset);
 #endif
     /* check that SSS/PBCH block is continuous inside the received buffer */
-    if (ue->ssb_offset + NR_N_SYMBOLS_SSB * (fp->ofdm_symbol_size + fp->nb_prefix_samples) >= fp->samples_per_frame) {
-      LOG_I(PHY, "Can't try to decode SSS from PSS position, will retry (PSS circular buffer wrapping): sync_pos %d\n", sync_pos);
+    if (ssbInfo->ssbOffset + NR_N_SYMBOLS_SSB * (fp->ofdm_symbol_size + fp->nb_prefix_samples) >= fp->samples_per_frame) {
+      LOG_D(PHY, "Can't try to decode SSS from PSS position, will retry (PSS circular buffer wrapping): sync_pos %d\n", sync_pos);
       continue;
     }
 
     // digital compensation of FFO for SSB symbols
-    if (ue->UE_fo_compensation) {
-      double s_time = 1 / (1.0e3 * fp->samples_per_subframe); // sampling time
-      double off_angle = -2 * M_PI * s_time * (ue->common_vars.freq_offset); // offset rotation angle compensation per sample
-
-      // In SA we need to perform frequency offset correction until the end of buffer because we need to decode SIB1
-      // and we do not know yet in which slot it goes.
-
-      for (int n = frame_id * fp->samples_per_frame; n < (frame_id + 1) * fp->samples_per_frame; n++) {
-        for (int ar = 0; ar < fp->nb_antennas_rx; ar++) {
-          const double re = ue->common_vars.rxdata[ar][n].r;
-          const double im = ue->common_vars.rxdata[ar][n].i;
-          ue->common_vars.rxdata[ar][n].r = (short)(round(re * cos(n * off_angle) - im * sin(n * off_angle)));
-          ue->common_vars.rxdata[ar][n].i = (short)(round(re * sin(n * off_angle) + im * cos(n * off_angle)));
-        }
-      }
+    if (ssbInfo->foFlag) {
+      compensate_freq_offset(rxdata, fp, freq_offset_pss, frame_id);
     }
 
     /* slot_fep function works for lte and takes into account begining of frame with prefix for subframe 0 */
@@ -209,8 +246,15 @@ nr_initial_sync_t nr_initial_sync(UE_nr_rxtx_proc_t *proc, PHY_VARS_NR_UE *ue, i
     /* time samples in buffer rxdata are used as input of FFT -> FFT results are stored in the frequency buffer rxdataF */
     /* rxdataF stores SS/PBCH from beginning of buffers in the same symbol order as in time domain */
 
+    const uint32_t rxdataF_sz = fp->samples_per_slot_wCP;
+    __attribute__((aligned(32))) c16_t rxdataF[fp->nb_antennas_rx][rxdataF_sz];
     for (int i = 0; i < NR_N_SYMBOLS_SSB; i++)
-      nr_slot_fep_init_sync(ue, proc, i, frame_id * fp->samples_per_frame + ue->ssb_offset, false, rxdataF, link_type_dl);
+      nr_slot_fep_init_sync(fp,
+                            i,
+                            frame_id * fp->samples_per_frame + ssbInfo->ssbOffset,
+                            (const c16_t **)rxdata,
+                            rxdataF,
+                            link_type_dl);
 
 #ifdef DEBUG_INITIAL_SYNCH
     LOG_I(PHY, "Calling sss detection (normal CP)\n");
@@ -219,69 +263,179 @@ nr_initial_sync_t nr_initial_sync(UE_nr_rxtx_proc_t *proc, PHY_VARS_NR_UE *ue, i
     int freq_offset_sss = 0;
     int32_t metric_tdd_ncp = 0;
     uint8_t phase_tdd_ncp;
-    ret.cell_detected = rx_sss_nr(ue, proc, &metric_tdd_ncp, &phase_tdd_ncp, &freq_offset_sss, rxdataF);
-    
-    // digital compensation of FFO for SSB symbols
-    if (freq_offset_sss && ue->UE_fo_compensation) {
-      double s_time = 1 / (1.0e3 * fp->samples_per_subframe); // sampling time
-      double off_angle = -2 * M_PI * s_time * freq_offset_sss; // offset rotation angle compensation per sample
-
-      // In SA we need to perform frequency offset correction until the end of buffer because we need to decode SIB1
-      // and we do not know yet in which slot it goes.
-      for (int n = frame_id * fp->samples_per_frame; n < (frame_id + 1) * fp->samples_per_frame; n++) {
-        for (int ar = 0; ar < fp->nb_antennas_rx; ar++) {
-          const double re = ue->common_vars.rxdata[ar][n].r;
-          const double im = ue->common_vars.rxdata[ar][n].i;
-          ue->common_vars.rxdata[ar][n].r = (short)(round(re * cos(n * off_angle) - im * sin(n * off_angle)));
-          ue->common_vars.rxdata[ar][n].i = (short)(round(re * sin(n * off_angle) + im * cos(n * off_angle)));
-        }
-      }
-      ue->common_vars.freq_offset += freq_offset_sss;
+    ssbInfo->syncRes.cell_detected = rx_sss_nr(fp,
+                                               nid2,
+                                               ssbInfo->targetNidCell,
+                                               freq_offset_pss,
+                                               ssbInfo->gscnInfo.ssbFirstSC,
+                                               &ssbInfo->nidCell,
+                                               &metric_tdd_ncp,
+                                               &phase_tdd_ncp,
+                                               &freq_offset_sss,
+                                               rxdataF);
+
+    ssbInfo->freqOffset = freq_offset_pss + freq_offset_sss;
+
+    uint32_t nr_gold_pbch_ref[2][64][NR_PBCH_DMRS_LENGTH_DWORD];
+    if (ssbInfo->syncRes.cell_detected) { // we got sss channel
+      nr_gold_pbch(nr_gold_pbch_ref, ssbInfo->nidCell, fp->Lmax);
+      ssbInfo->syncRes.cell_detected = nr_pbch_detection(ssbInfo->proc,
+                                                         ssbInfo->fp,
+                                                         ssbInfo->nidCell,
+                                                         1,
+                                                         ssbInfo->gscnInfo.ssbFirstSC,
+                                                         &ssbInfo->halfFrameBit,
+                                                         &ssbInfo->ssbIndex,
+                                                         &ssbInfo->symbolOffset,
+                                                         &ssbInfo->pbchResult,
+                                                         nr_gold_pbch_ref,
+                                                         rxdataF); // start pbch detection at first symbol after pss
     }
+  }
+}
 
-    if (ret.cell_detected) { // we got sss channel
-      nr_gold_pbch(ue);
-      ret.cell_detected = nr_pbch_detection(proc, ue, 1, rxdataF); // start pbch detection at first symbol after pss
+nr_initial_sync_t nr_initial_sync(UE_nr_rxtx_proc_t *proc,
+                                  PHY_VARS_NR_UE *ue,
+                                  int n_frames,
+                                  int sa,
+                                  nr_gscn_info_t gscnInfo[MAX_GSCN_BAND],
+                                  int numGscn)
+{
+  NR_DL_FRAME_PARMS *fp = &ue->frame_parms;
+
+  notifiedFIFO_t nf;
+  initNotifiedFIFO(&nf);
+
+  // Perform SSB scanning in parallel. One GSCN per thread.
+  LOG_I(NR_PHY,
+        "Starting cell search with center freq: %ld, bandwidth: %d. Scanning for %d number of GSCN.\n",
+        fp->dl_CarrierFreq,
+        fp->N_RB_DL,
+        numGscn);
+  for (int s = 0; s < numGscn; s++) {
+    notifiedFIFO_elt_t *req = newNotifiedFIFO_elt(sizeof(nr_ue_ssb_scan_t), gscnInfo[s].gscn, &nf, &nr_scan_ssb);
+    nr_ue_ssb_scan_t *ssbInfo = (nr_ue_ssb_scan_t *)NotifiedFifoData(req);
+    ssbInfo->gscnInfo = gscnInfo[s];
+    ssbInfo->rxdata = malloc16_clear(fp->nb_antennas_rx * sizeof(c16_t *));
+    for (int ant = 0; ant < fp->nb_antennas_rx; ant++) {
+      ssbInfo->rxdata[ant] = malloc16_clear((fp->samples_per_frame * 2 + fp->ofdm_symbol_size) * sizeof(c16_t));
+      memcpy(ssbInfo->rxdata[ant], ue->common_vars.rxdata[ant], sizeof(c16_t) * fp->samples_per_frame * 2);
     }
+    LOG_I(NR_PHY,
+          "Scanning GSCN: %d, with SSB offset: %d, SSB Freq: %lf\n",
+          ssbInfo->gscnInfo.gscn,
+          ssbInfo->gscnInfo.ssbFirstSC,
+          ssbInfo->gscnInfo.ssRef);
+    ssbInfo->fp = &ue->frame_parms;
+    ssbInfo->proc = proc;
+    ssbInfo->syncRes.cell_detected = false;
+    ssbInfo->nFrames = n_frames;
+    ssbInfo->foFlag = ue->UE_fo_compensation;
+    ssbInfo->targetNidCell = ue->target_Nid_cell;
+    pushTpool(&get_nrUE_params()->Tpool, req);
+  }
 
-    if (ret.cell_detected) {
-      // sync at symbol ue->symbol_offset
-      // computing the offset wrt the beginning of the frame
-      int mu = fp->numerology_index;
-      // number of symbols with different prefix length
-      // every 7*(1<<mu) symbols there is a different prefix length (38.211 5.3.1)
-      int n_symb_prefix0 = (ue->symbol_offset / (7 * (1 << mu))) + 1;
-      sync_pos_frame = n_symb_prefix0 * (fp->ofdm_symbol_size + fp->nb_prefix_samples0)
-                       + (ue->symbol_offset - n_symb_prefix0) * (fp->ofdm_symbol_size + fp->nb_prefix_samples);
-      // for a correct computation of frame number to sync with the one decoded at MIB we need to take into account in which of
-      // the n_frames we got sync
-      ue->init_sync_frame = n_frames - 1 - frame_id;
-
-      // compute the scramblingID_pdcch and the gold pdcch
-      ue->scramblingID_pdcch = fp->Nid_cell;
-      nr_gold_pdcch(ue, fp->Nid_cell);
-
-      // compute the scrambling IDs for PDSCH DMRS
-      for (int i = 0; i < NR_NB_NSCID; i++) {
-        ue->scramblingID_dlsch[i] = fp->Nid_cell;
-        nr_gold_pdsch(ue, i, ue->scramblingID_dlsch[i]);
+  // Collect the scan results
+  nr_ue_ssb_scan_t res = {0};
+  while (numGscn) {
+    notifiedFIFO_elt_t *req = pullTpool(&nf, &get_nrUE_params()->Tpool);
+    nr_ue_ssb_scan_t *ssbInfo = (nr_ue_ssb_scan_t *)NotifiedFifoData(req);
+    if (ssbInfo->syncRes.cell_detected) {
+      LOG_A(NR_PHY,
+            "Cell Detected with GSCN: %d, SSB SC offset: %d, SSB Ref: %lf, PSS Corr peak: %d dB, PSS Corr Average: %d\n",
+            ssbInfo->gscnInfo.gscn,
+            ssbInfo->gscnInfo.ssbFirstSC,
+            ssbInfo->gscnInfo.ssRef,
+            ssbInfo->pssCorrPeakPower,
+            ssbInfo->pssCorrAvgPower);
+      if (!res.syncRes.cell_detected) { // take the first cell detected
+        res = *ssbInfo;
       }
+    }
+    for (int ant = 0; ant < fp->nb_antennas_rx; ant++) {
+      free(ssbInfo->rxdata[ant]);
+    }
+    free(ssbInfo->rxdata);
+    delNotifiedFIFO_elt(req);
+    numGscn--;
+  }
 
-      nr_init_csi_rs(fp, ue->nr_csi_info->nr_gold_csi_rs, fp->Nid_cell);
+  // Set globals based on detected cell
+  if (res.syncRes.cell_detected) {
+    fp->Nid_cell = res.nidCell;
+    fp->ssb_start_subcarrier = res.gscnInfo.ssbFirstSC;
+    fp->half_frame_bit = res.halfFrameBit;
+    fp->ssb_index = res.ssbIndex;
+    ue->symbol_offset = res.symbolOffset;
+    ue->common_vars.freq_offset = res.freqOffset;
+  }
 
-      // initialize the pusch dmrs
-      for (int i = 0; i < NR_NB_NSCID; i++) {
-        ue->scramblingID_ulsch[i] = fp->Nid_cell;
-        nr_init_pusch_dmrs(ue, ue->scramblingID_ulsch[i], i);
-      }
+  // In initial sync, we indicate PBCH to MAC after the scan is complete.
+  nr_downlink_indication_t dl_indication;
+  fapi_nr_rx_indication_t rx_ind = {0};
+  uint16_t number_pdus = 1;
+  nr_fill_dl_indication(&dl_indication, NULL, &rx_ind, proc, ue, NULL);
+  nr_fill_rx_indication(&rx_ind,
+                        FAPI_NR_RX_PDU_TYPE_SSB,
+                        ue,
+                        NULL,
+                        NULL,
+                        number_pdus,
+                        proc,
+                        res.syncRes.cell_detected ? (void *)&res.pbchResult : NULL,
+                        NULL);
+
+  if (ue->if_inst && ue->if_inst->dl_indication)
+    ue->if_inst->dl_indication(&dl_indication);
+  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_NR_INITIAL_UE_SYNC, VCD_FUNCTION_IN);
+
+  LOG_D(PHY, "nr_initial sync ue RB_DL %d\n", fp->N_RB_DL);
 
-      // we also need to take into account the shift by samples_per_frame in case the if is true
-      if (ue->ssb_offset < sync_pos_frame) {
-        ret.rx_offset = fp->samples_per_frame - sync_pos_frame + ue->ssb_offset;
-        ue->init_sync_frame += 1;
-      } else
-        ret.rx_offset = ue->ssb_offset - sync_pos_frame;
+  if (res.syncRes.cell_detected) {
+    // digital compensation of FFO for SSB symbols
+    if (res.freqOffset && ue->UE_fo_compensation) {
+      // In SA we need to perform frequency offset correction until the end of buffer because we need to decode SIB1
+      // and we do not know yet in which slot it goes.
+      compensate_freq_offset(ue->common_vars.rxdata, fp, res.freqOffset, res.syncRes.frame_id);
     }
+    nr_gold_pbch(ue->nr_gold_pbch, fp->Nid_cell, fp->Lmax);
+    // sync at symbol ue->symbol_offset
+    // computing the offset wrt the beginning of the frame
+    int mu = fp->numerology_index;
+    // number of symbols with different prefix length
+    // every 7*(1<<mu) symbols there is a different prefix length (38.211 5.3.1)
+    int n_symb_prefix0 = (res.symbolOffset / (7 * (1 << mu))) + 1;
+    const int sync_pos_frame = n_symb_prefix0 * (fp->ofdm_symbol_size + fp->nb_prefix_samples0)
+                               + (res.symbolOffset - n_symb_prefix0) * (fp->ofdm_symbol_size + fp->nb_prefix_samples);
+    // for a correct computation of frame number to sync with the one decoded at MIB we need to take into account in which of
+    // the n_frames we got sync
+    ue->init_sync_frame = n_frames - 1 - res.syncRes.frame_id;
+
+    // compute the scramblingID_pdcch and the gold pdcch
+    ue->scramblingID_pdcch = fp->Nid_cell;
+    nr_gold_pdcch(ue, fp->Nid_cell);
+
+    // compute the scrambling IDs for PDSCH DMRS
+    for (int i = 0; i < NR_NB_NSCID; i++) {
+      ue->scramblingID_dlsch[i] = fp->Nid_cell;
+      nr_gold_pdsch(ue, i, ue->scramblingID_dlsch[i]);
+    }
+
+    nr_init_csi_rs(fp, ue->nr_csi_info->nr_gold_csi_rs, fp->Nid_cell);
+
+    // initialize the pusch dmrs
+    for (int i = 0; i < NR_NB_NSCID; i++) {
+      ue->scramblingID_ulsch[i] = fp->Nid_cell;
+      nr_init_pusch_dmrs(ue, ue->scramblingID_ulsch[i], i);
+    }
+
+    // we also need to take into account the shift by samples_per_frame in case the if is true
+    if (res.ssbOffset < sync_pos_frame) {
+      res.syncRes.rx_offset = fp->samples_per_frame - sync_pos_frame + res.ssbOffset;
+      ue->init_sync_frame += 1;
+    } else
+      res.syncRes.rx_offset = res.ssbOffset - sync_pos_frame;
+  }
 
 #ifdef DEBUG_INITIAL_SYNCH
     LOG_I(PHY,
@@ -292,74 +446,47 @@ nr_initial_sync_t nr_initial_sync(UE_nr_rxtx_proc_t *proc, PHY_VARS_NR_UE *ue, i
           ret.cell_detected,
           ret.rx_offset);
 #endif
-  }
-
-  /* Consider this is a false detection if the offset is > 1000 Hz
-     Not to be used now that offest estimation is in place
-     if( (abs(ue->common_vars.freq_offset) > 150) && (ret == 0) )
-     {
-     ret=-1;
-     LOG_E(HW, "Ignore MIB with high freq offset [%d Hz] estimation \n",ue->common_vars.freq_offset);
-     }*/
-
-  if (ret.cell_detected) { // PBCH found so indicate sync to higher layers and configure frame parameters
 
-    //#ifdef DEBUG_INITIAL_SYNCH
-
-    LOG_I(PHY, "[UE%d] In synch, rx_offset %d samples\n", ue->Mod_id, ret.rx_offset);
-
-    //#endif
-
-    if (ue->UE_scan_carrier == 0) {
-#if UE_AUTOTEST_TRACE
-      LOG_I(PHY,
-            "[UE  %d] AUTOTEST Cell Sync : rx_offset %d, freq_offset %d \n",
-            ue->Mod_id,
-            ue->rx_offset,
-            ue->common_vars.freq_offset);
-#endif
-
-      // send sync status to higher layers later when timing offset converge to target timing
-    }
-
-    LOG_I(PHY, "[UE %d] Measured Carrier Frequency offset %d Hz\n", ue->Mod_id, ue->common_vars.freq_offset);
-  } else {
+    if (res.syncRes.cell_detected) {
+      LOG_I(PHY, "[UE%d] In synch, rx_offset %d samples\n", ue->Mod_id, res.syncRes.rx_offset);
+      LOG_I(PHY, "[UE %d] Measured Carrier Frequency offset %d Hz\n", ue->Mod_id, res.freqOffset);
+    } else {
 #ifdef DEBUG_INITIAL_SYNC
     LOG_I(PHY,"[UE%d] Initial sync : PBCH not ok\n",ue->Mod_id);
     LOG_I(PHY, "[UE%d] Initial sync : Estimated PSS position %d, Nid2 %d\n", ue->Mod_id, sync_pos, ue->common_vars.nid2);
     LOG_I(PHY,"[UE%d] Initial sync : Estimated Nid_cell %d, Frame_type %d\n",ue->Mod_id,
           frame_parms->Nid_cell,frame_parms->frame_type);
 #endif
-  }
+    }
 
   // gain control
-  if (!ret.cell_detected) { // we are not synched, so we cannot use rssi measurement (which is based on channel estimates)
-    int rx_power = 0;
+    if (!res.syncRes.cell_detected) { // we are not synched, so we cannot use rssi measurement (which is based on channel estimates)
+      int rx_power = 0;
 
-    // do a measurement on the best guess of the PSS
-    // for (aarx=0; aarx<frame_parms->nb_antennas_rx; aarx++)
-    //  rx_power += signal_energy(&ue->common_vars.rxdata[aarx][sync_pos2],
-    //			frame_parms->ofdm_symbol_size+frame_parms->nb_prefix_samples);
+      // do a measurement on the best guess of the PSS
+      // for (aarx=0; aarx<frame_parms->nb_antennas_rx; aarx++)
+      //  rx_power += signal_energy(&ue->common_vars.rxdata[aarx][sync_pos2],
+      //			frame_parms->ofdm_symbol_size+frame_parms->nb_prefix_samples);
 
-    /*
-    // do a measurement on the full frame
-    for (aarx=0; aarx<frame_parms->nb_antennas_rx; aarx++)
-    rx_power += signal_energy(&ue->common_vars.rxdata[aarx][0],
-    frame_parms->samples_per_subframe*10);
-    */
+      /*
+      // do a measurement on the full frame
+      for (aarx=0; aarx<frame_parms->nb_antennas_rx; aarx++)
+      rx_power += signal_energy(&ue->common_vars.rxdata[aarx][0],
+      frame_parms->samples_per_subframe*10);
+      */
 
-    // we might add a low-pass filter here later
-    ue->measurements.rx_power_avg[0] = rx_power/fp->nb_antennas_rx;
+      // we might add a low-pass filter here later
+      ue->measurements.rx_power_avg[0] = rx_power / fp->nb_antennas_rx;
 
-    ue->measurements.rx_power_avg_dB[0] = dB_fixed(ue->measurements.rx_power_avg[0]);
+      ue->measurements.rx_power_avg_dB[0] = dB_fixed(ue->measurements.rx_power_avg[0]);
 
 #ifdef DEBUG_INITIAL_SYNCH
     LOG_I(PHY, "[UE%d] Initial sync : Estimated power: %d dB\n", ue->Mod_id, ue->measurements.rx_power_avg_dB[0]);
 #endif
-  } else {
-    LOG_A(PHY, "Initial sync successful\n");
-  }
+    } else {
+      LOG_A(PHY, "Initial sync successful\n");
+    }
   //  exit_fun("debug exit");
   VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_NR_INITIAL_UE_SYNC, VCD_FUNCTION_OUT);
-  return ret;
+  return res.syncRes;
 }
diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_initial_sync_sl.c b/openair1/PHY/NR_UE_TRANSPORT/nr_initial_sync_sl.c
index e18a6a163346f077769c1b340f48edbf372fec5a..96c2638c9e7683efd19f19f10a123addfb626c0a 100644
--- a/openair1/PHY/NR_UE_TRANSPORT/nr_initial_sync_sl.c
+++ b/openair1/PHY/NR_UE_TRANSPORT/nr_initial_sync_sl.c
@@ -462,8 +462,9 @@ nr_initial_sync_t sl_nr_slss_search(PHY_VARS_NR_UE *UE, UE_nr_rxtx_proc_t *proc,
         uint8_t decoded_output[4];
 
         for (int symbol = 0; symbol < SL_NR_NUMSYM_SLSS_NORMAL_CP - 1;) {
-          nr_pbch_channel_estimation(UE,
-                                     frame_parms,
+          nr_pbch_channel_estimation(frame_parms,
+                                     &UE->SL_UE_PHY_PARAMS,
+                                     UE->nr_gold_pbch,
                                      rxdataF_sz,
                                      dl_ch_estimates,
                                      dl_ch_estimates_time,
@@ -472,6 +473,7 @@ nr_initial_sync_t sl_nr_slss_search(PHY_VARS_NR_UE *UE, UE_nr_rxtx_proc_t *proc,
                                      symbol,
                                      0,
                                      0,
+                                     frame_parms->ssb_start_subcarrier,
                                      rxdataF,
                                      1,
                                      rx_slss_id);
diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_pbch.c b/openair1/PHY/NR_UE_TRANSPORT/nr_pbch.c
index b87fc9267c6bbe1021c489981c8c05542070b5cb..e2f9e03cb3889292070c8fc2af29ae9004a471d5 100644
--- a/openair1/PHY/NR_UE_TRANSPORT/nr_pbch.c
+++ b/openair1/PHY/NR_UE_TRANSPORT/nr_pbch.c
@@ -47,14 +47,15 @@
 #define print_shorts(s,x) printf("%s : %d,%d,%d,%d,%d,%d,%d,%d\n",s,((int16_t*)x)[0],((int16_t*)x)[1],((int16_t*)x)[2],((int16_t*)x)[3],((int16_t*)x)[4],((int16_t*)x)[5],((int16_t*)x)[6],((int16_t*)x)[7])
 
 static uint16_t nr_pbch_extract(uint32_t rxdataF_sz,
-                                c16_t rxdataF[][rxdataF_sz],
+                                const c16_t rxdataF[][rxdataF_sz],
                                 const int estimateSz,
                                 struct complex16 dl_ch_estimates[][estimateSz],
                                 struct complex16 rxdataF_ext[][PBCH_MAX_RE_PER_SYMBOL],
                                 struct complex16 dl_ch_estimates_ext[][PBCH_MAX_RE_PER_SYMBOL],
                                 uint32_t symbol,
                                 uint32_t s_offset,
-                                NR_DL_FRAME_PARMS *frame_parms)
+                                int ssb_start_subcarrier,
+                                const NR_DL_FRAME_PARMS *frame_parms)
 {
   uint16_t rb;
   uint8_t i, j, aarx;
@@ -64,9 +65,9 @@ static uint16_t nr_pbch_extract(uint32_t rxdataF_sz,
               symbol);
 
   for (aarx=0; aarx<frame_parms->nb_antennas_rx; aarx++) {
-    unsigned int rx_offset = frame_parms->first_carrier_offset + frame_parms->ssb_start_subcarrier;
+    unsigned int rx_offset = frame_parms->first_carrier_offset + ssb_start_subcarrier;
     rx_offset = (rx_offset)%(frame_parms->ofdm_symbol_size);
-    struct complex16 *rxF = &rxdataF[aarx][(symbol+s_offset)*frame_parms->ofdm_symbol_size];
+    const struct complex16 *rxF = &rxdataF[aarx][(symbol + s_offset) * frame_parms->ofdm_symbol_size];
     struct complex16 *rxF_ext = rxdataF_ext[aarx];
 #ifdef DEBUG_PBCH
     printf("extract_rbs (nushift %d): rx_offset=%d, symbol %u\n",
@@ -203,8 +204,9 @@ static uint16_t nr_pbch_extract(uint32_t rxdataF_sz,
 
 //compute average channel_level on each (TX,RX) antenna pair
 int nr_pbch_channel_level(struct complex16 dl_ch_estimates_ext[][PBCH_MAX_RE_PER_SYMBOL],
-                          NR_DL_FRAME_PARMS *frame_parms,
-			  int nb_re) {
+                          const NR_DL_FRAME_PARMS *frame_parms,
+                          int nb_re)
+{
   int16_t nb_rb=nb_re/12;
   simde__m128i avg128;
   simde__m128i *dl_ch128;
@@ -244,7 +246,7 @@ void nr_pbch_channel_compensation(struct complex16 rxdataF_ext[][PBCH_MAX_RE_PER
                                   struct complex16 dl_ch_estimates_ext[][PBCH_MAX_RE_PER_SYMBOL],
                                   int nb_re,
                                   struct complex16 rxdataF_comp[][PBCH_MAX_RE_PER_SYMBOL],
-                                  NR_DL_FRAME_PARMS *frame_parms,
+                                  const NR_DL_FRAME_PARMS *frame_parms,
                                   uint8_t output_shift)
 {
   for (int aarx=0; aarx<frame_parms->nb_antennas_rx; aarx++) {
@@ -365,35 +367,31 @@ const uint8_t pbch_deinterleaving_pattern[32] = {28, 0, 31, 30, 7,  29, 25, 27,
 
 int nr_rx_pbch(PHY_VARS_NR_UE *ue,
                const UE_nr_rxtx_proc_t *proc,
+               bool is_synchronized,
                int estimateSz,
                struct complex16 dl_ch_estimates[][estimateSz],
-               NR_DL_FRAME_PARMS *frame_parms,
+               const NR_DL_FRAME_PARMS *frame_parms,
                uint8_t i_ssb,
+               int ssb_start_subcarrier,
+               int Nid_cell,
                fapiPbch_t *result,
-               c16_t rxdataF[][ue->frame_parms.samples_per_slot_wCP])
+               int *half_frame_bit,
+               int *ssb_index,
+               int *ret_symbol_offset,
+               int rxdataFSize,
+               const struct complex16 rxdataF[][rxdataFSize])
 {
   int max_h=0;
   int symbol;
-  // uint8_t pbch_a[64];
-  // FT ?? cppcheck doesn't like pbch_a allocation because of line 525..and i don't get what this variable is for..
-  // uint8_t *pbch_a = malloc(sizeof(uint8_t) * NR_POLAR_PBCH_PAYLOAD_BITS);
   uint8_t Lmax=frame_parms->Lmax;
   int M = NR_POLAR_PBCH_E;
   int nushift = (Lmax == 4) ? i_ssb & 3 : i_ssb & 7;
-  //uint16_t crc;
-  //unsigned short idx_demod =0;
-  uint32_t decoderState=0;
-  //uint8_t decoderListSize = 8, pathMetricAppr = 0;
-  //time_stats_t polar_decoder_init,polar_rate_matching,decoding,bit_extraction,deinterleaving;
-  //time_stats_t path_metric,sorting,update_LLR;
-  // FT ?? cppcheck fix  memset(&pbch_a[0], 0, sizeof(uint8_t) * NR_POLAR_PBCH_PAYLOAD_BITS);
-  //printf("nr_pbch_ue nid_cell %d\n",frame_parms->Nid_cell);
   int16_t pbch_e_rx[960]= {0}; //Fixme: previous version erase only NR_POLAR_PBCH_E bytes
   int16_t pbch_unClipped[960]= {0};
   int pbch_e_rx_idx=0;
   int symbol_offset=1;
 
-  if (ue->is_synchronized > 0)
+  if (is_synchronized)
     symbol_offset=nr_get_ssb_start_symbol(frame_parms, i_ssb)%(frame_parms->symbols_per_slot);
   else
     symbol_offset=0;
@@ -411,7 +409,7 @@ int nr_rx_pbch(PHY_VARS_NR_UE *ue,
     __attribute__ ((aligned(32))) struct complex16 rxdataF_ext[frame_parms->nb_antennas_rx][PBCH_MAX_RE_PER_SYMBOL];
     __attribute__ ((aligned(32))) struct complex16 dl_ch_estimates_ext[frame_parms->nb_antennas_rx][PBCH_MAX_RE_PER_SYMBOL];
     memset(dl_ch_estimates_ext,0, sizeof  dl_ch_estimates_ext);
-    nr_pbch_extract(ue->frame_parms.samples_per_slot_wCP,
+    nr_pbch_extract(frame_parms->samples_per_slot_wCP,
                     rxdataF,
                     estimateSz,
                     dl_ch_estimates,
@@ -419,6 +417,7 @@ int nr_rx_pbch(PHY_VARS_NR_UE *ue,
                     dl_ch_estimates_ext,
                     symbol,
                     symbol_offset,
+                    ssb_start_subcarrier,
                     frame_parms);
 #ifdef DEBUG_PBCH
     LOG_I(PHY,"[PHY] PBCH Symbol %d ofdm size %d\n",symbol, frame_parms->ofdm_symbol_size);
@@ -457,8 +456,10 @@ int nr_rx_pbch(PHY_VARS_NR_UE *ue,
   }
 
   // legacy code use int16, but it is complex16
-  UEscopeCopy(ue, pbchRxdataF_comp, pbch_unClipped, sizeof(struct complex16), frame_parms->nb_antennas_rx, pbch_e_rx_idx / 2, 0);
-  UEscopeCopy(ue, pbchLlr, pbch_e_rx, sizeof(int16_t), frame_parms->nb_antennas_rx, pbch_e_rx_idx, 0);
+  if (ue) {
+    UEscopeCopy(ue, pbchRxdataF_comp, pbch_unClipped, sizeof(struct complex16), frame_parms->nb_antennas_rx, pbch_e_rx_idx / 2, 0);
+    UEscopeCopy(ue, pbchLlr, pbch_e_rx, sizeof(int16_t), frame_parms->nb_antennas_rx, pbch_e_rx_idx, 0);
+  }
 #ifdef DEBUG_PBCH
   for (int cnt = 0; cnt < 864  ; cnt++)
     printf("pbch rx llr %d\n", *(pbch_e_rx + cnt));
@@ -467,23 +468,29 @@ int nr_rx_pbch(PHY_VARS_NR_UE *ue,
   uint32_t unscrambling_mask = (Lmax==64)?0x100006D:0x1000041;
   uint32_t pbch_a_interleaved=0;
   uint32_t pbch_a_prime=0;
-  nr_pbch_unscrambling(pbch_e_rx, frame_parms->Nid_cell, nushift, M, NR_POLAR_PBCH_E,
+  nr_pbch_unscrambling(pbch_e_rx, Nid_cell, nushift, M, NR_POLAR_PBCH_E,
 		       0, 0,  pbch_a_prime, &pbch_a_interleaved);
   //polar decoding de-rate matching
   uint64_t tmp=0;
-  decoderState = polar_decoder_int16(pbch_e_rx,(uint64_t *)&tmp,0,
-                                     NR_POLAR_PBCH_MESSAGE_TYPE, NR_POLAR_PBCH_PAYLOAD_BITS, NR_POLAR_PBCH_AGGREGATION_LEVEL);
+  const uint32_t decoderState = polar_decoder_int16(pbch_e_rx,
+                                                    (uint64_t *)&tmp,
+                                                    0,
+                                                    NR_POLAR_PBCH_MESSAGE_TYPE,
+                                                    NR_POLAR_PBCH_PAYLOAD_BITS,
+                                                    NR_POLAR_PBCH_AGGREGATION_LEVEL);
   pbch_a_prime = tmp;
 
   nr_downlink_indication_t dl_indication;
   fapi_nr_rx_indication_t rx_ind = {0};
   uint16_t number_pdus = 1;
 
-  if(decoderState) {
-    nr_fill_dl_indication(&dl_indication, NULL, &rx_ind, proc, ue, NULL);
-    nr_fill_rx_indication(&rx_ind, FAPI_NR_RX_PDU_TYPE_SSB, ue, NULL, NULL, number_pdus, proc, NULL, NULL);
-    if (ue->if_inst && ue->if_inst->dl_indication)
-      ue->if_inst->dl_indication(&dl_indication);
+  if (decoderState) {
+    if (ue) { // decoding failed in synced state
+      nr_fill_dl_indication(&dl_indication, NULL, &rx_ind, proc, ue, NULL);
+      nr_fill_rx_indication(&rx_ind, FAPI_NR_RX_PDU_TYPE_SSB, ue, NULL, NULL, number_pdus, proc, NULL, NULL);
+      if (ue->if_inst && ue->if_inst->dl_indication)
+        ue->if_inst->dl_indication(&dl_indication);
+    }
     return(decoderState);
   }
   //  printf("polar decoder output 0x%08x\n",pbch_a_prime);
@@ -494,7 +501,7 @@ int nr_rx_pbch(PHY_VARS_NR_UE *ue,
   M = (Lmax == 64)? (NR_POLAR_PBCH_PAYLOAD_BITS - 6) : (NR_POLAR_PBCH_PAYLOAD_BITS - 3);
   nushift = ((pbch_a_prime>>24)&1) ^ (((pbch_a_prime>>6)&1)<<1);
   pbch_a_interleaved=0;
-  nr_pbch_unscrambling(pbch_e_rx, frame_parms->Nid_cell, nushift, M, NR_POLAR_PBCH_PAYLOAD_BITS,
+  nr_pbch_unscrambling(pbch_e_rx, Nid_cell, nushift, M, NR_POLAR_PBCH_PAYLOAD_BITS,
 		       1, unscrambling_mask, pbch_a_prime, &pbch_a_interleaved);
   //printf("nushift %d sfn 3rd %d 2nd %d", nushift,((pbch_a_prime>>6)&1), ((pbch_a_prime>>24)&1) );
   //payload deinterleaving
@@ -514,19 +521,19 @@ int nr_rx_pbch(PHY_VARS_NR_UE *ue,
 
   for (int i=0; i<3; i++)
     result->decoded_output[i] = (uint8_t)((payload>>((3-i)<<3))&0xff);
-  
-  frame_parms->half_frame_bit = (result->xtra_byte>>4)&0x01; // computing the half frame index from the extra byte
-  frame_parms->ssb_index = i_ssb;  // ssb index corresponds to i_ssb for Lmax = 4,8
-  
+
+  *half_frame_bit = (result->xtra_byte >> 4) & 0x01; // computing the half frame index from the extra byte
+  *ssb_index = i_ssb; // ssb index corresponds to i_ssb for Lmax = 4,8
+
   if (Lmax == 64) {   // for Lmax = 64 ssb index 4th,5th and 6th bits are in extra byte
     for (int i=0; i<3; i++)
-      frame_parms->ssb_index += (((result->xtra_byte>>(7-i))&0x01)<<(3+i));
+      *ssb_index += (((result->xtra_byte >> (7 - i)) & 0x01) << (3 + i));
   }
 
-  ue->symbol_offset = nr_get_ssb_start_symbol(frame_parms,frame_parms->ssb_index);
+  *ret_symbol_offset = nr_get_ssb_start_symbol(frame_parms, *ssb_index);
 
-  if (frame_parms->half_frame_bit)
-  ue->symbol_offset += (frame_parms->slots_per_frame>>1)*frame_parms->symbols_per_slot;
+  if (*half_frame_bit)
+    *ret_symbol_offset += (frame_parms->slots_per_frame >> 1) * frame_parms->symbols_per_slot;
 
 #ifdef DEBUG_PBCH
   printf("xtra_byte %x payload %x\n", result->xtra_byte, payload);
@@ -538,11 +545,13 @@ int nr_rx_pbch(PHY_VARS_NR_UE *ue,
 
 #endif
 
-  nr_fill_dl_indication(&dl_indication, NULL, &rx_ind, proc, ue, NULL);
-  nr_fill_rx_indication(&rx_ind, FAPI_NR_RX_PDU_TYPE_SSB, ue, NULL, NULL, number_pdus, proc, (void *)result, NULL);
+  if (ue) {
+    nr_fill_dl_indication(&dl_indication, NULL, &rx_ind, proc, ue, NULL);
+    nr_fill_rx_indication(&rx_ind, FAPI_NR_RX_PDU_TYPE_SSB, ue, NULL, NULL, number_pdus, proc, (void *)result, NULL);
 
-  if (ue->if_inst && ue->if_inst->dl_indication)
-    ue->if_inst->dl_indication(&dl_indication);
+    if (ue->if_inst && ue->if_inst->dl_indication)
+      ue->if_inst->dl_indication(&dl_indication);
+  }
 
   return 0;
 }
diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h
index 111e457c05e4bb6ebaaf485bdd2c5e7adfb12c0b..9f46ae38ce410388b5ae51038f11cbd0a14d85a6 100644
--- a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h
+++ b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h
@@ -291,12 +291,19 @@ int rx_sss(PHY_VARS_NR_UE *phy_vars_ue,int32_t *tot_metric,uint8_t *flip_max,uin
 
 int nr_rx_pbch(PHY_VARS_NR_UE *ue,
                const UE_nr_rxtx_proc_t *proc,
-               const int estimateSz,
+               bool is_synchronized,
+               int estimateSz,
                struct complex16 dl_ch_estimates[][estimateSz],
-               NR_DL_FRAME_PARMS *frame_parms,
+               const NR_DL_FRAME_PARMS *frame_parms,
                uint8_t i_ssb,
+               int ssb_start_subcarrier,
+               int Nid_cell,
                fapiPbch_t *result,
-               c16_t rxdataF[][ue->frame_parms.samples_per_slot_wCP]);
+               int *half_frame_bit,
+               int *ssb_index,
+               int *ret_symbol_offset,
+               int rxdataFSize,
+               const struct complex16 rxdataF[][rxdataFSize]);
 
 #ifndef modOrder
 #define modOrder(I_MCS,I_TBS) ((I_MCS-I_TBS)*2+2) // Find modulation order from I_TBS and I_MCS
@@ -319,11 +326,12 @@ int dump_ue_stats(PHY_VARS_NR_UE *phy_vars_ue,
 @param n_frames
   @param sa current running mode
 */
-typedef struct {
-  bool cell_detected;
-  int rx_offset;
-} nr_initial_sync_t;
-nr_initial_sync_t nr_initial_sync(UE_nr_rxtx_proc_t *proc, PHY_VARS_NR_UE *phy_vars_ue, int n_frames, int sa);
+nr_initial_sync_t nr_initial_sync(UE_nr_rxtx_proc_t *proc,
+                                  PHY_VARS_NR_UE *phy_vars_ue,
+                                  int n_frames,
+                                  int sa,
+                                  nr_gscn_info_t gscnInfo[MAX_GSCN_BAND],
+                                  int numGscn);
 
 /*!
   \brief This function gets the carrier frequencies either from FP or command-line-set global variables, depending on the
@@ -435,13 +443,13 @@ nr_initial_sync_t sl_nr_slss_search(PHY_VARS_NR_UE *UE, UE_nr_rxtx_proc_t *proc,
 
 // Reuse already existing PBCH functions
 int nr_pbch_channel_level(struct complex16 dl_ch_estimates_ext[][PBCH_MAX_RE_PER_SYMBOL],
-                          NR_DL_FRAME_PARMS *frame_parms,
+                          const NR_DL_FRAME_PARMS *frame_parms,
                           int nb_re);
 void nr_pbch_channel_compensation(struct complex16 rxdataF_ext[][PBCH_MAX_RE_PER_SYMBOL],
                                   struct complex16 dl_ch_estimates_ext[][PBCH_MAX_RE_PER_SYMBOL],
                                   int nb_re,
                                   struct complex16 rxdataF_comp[][PBCH_MAX_RE_PER_SYMBOL],
-                                  NR_DL_FRAME_PARMS *frame_parms,
+                                  const NR_DL_FRAME_PARMS *frame_parms,
                                   uint8_t output_shift);
 void nr_pbch_unscrambling(int16_t *demod_pbch_e,
                           uint16_t Nid,
diff --git a/openair1/PHY/NR_UE_TRANSPORT/pss_nr.c b/openair1/PHY/NR_UE_TRANSPORT/pss_nr.c
index 721697e248b73a5ca063f5ac4b02b1bfe2ae6272..6d9aaf7f9ad7ed8357d43783a4463bd81a7d2584 100644
--- a/openair1/PHY/NR_UE_TRANSPORT/pss_nr.c
+++ b/openair1/PHY/NR_UE_TRANSPORT/pss_nr.c
@@ -50,10 +50,19 @@
 
 //#define DBG_PSS_NR
 static time_stats_t generic_time[TIME_LAST];
-static int pss_search_time_nr(c16_t **rxdata, PHY_VARS_NR_UE *ue, int fo_flag, int is);
-
-static int16_t *primary_synchro_nr2[NUMBER_PSS_SEQUENCE] = {0};
-static c16_t *primary_synchro_time_nr[NUMBER_PSS_SEQUENCE] = {0};
+static int pss_search_time_nr(const c16_t **rxdata,
+                              const NR_DL_FRAME_PARMS *frame_parms,
+                              const c16_t pssTime[NUMBER_PSS_SEQUENCE][frame_parms->ofdm_symbol_size],
+                              bool fo_flag,
+                              int is,
+                              int target_Nid_cell,
+                              int *nid2,
+                              int *f_off,
+                              int *pssPeak,
+                              int *pssAvg);
+
+static int16_t primary_synchro_nr2[NUMBER_PSS_SEQUENCE][LENGTH_PSS_NR] = {0};
+static c16_t primary_synchro[NUMBER_PSS_SEQUENCE][LENGTH_PSS_NR] = {0};
 int16_t *get_primary_synchro_nr2(const int nid2)
 {
   return primary_synchro_nr2[nid2];
@@ -80,7 +89,6 @@ void generate_pss_nr(NR_DL_FRAME_PARMS *fp, int N_ID_2)
   int16_t d_pss[LENGTH_PSS_NR];
   int16_t x[LENGTH_PSS_NR];
 
-  c16_t primary_synchro[LENGTH_PSS_NR] = {0};
   int16_t *primary_synchro2 = primary_synchro_nr2[N_ID_2]; /* pss in complex with alternatively i then q */
 
 #define INITIAL_PSS_NR (7)
@@ -98,7 +106,7 @@ void generate_pss_nr(NR_DL_FRAME_PARMS *fp, int N_ID_2)
 
   /* PSS is directly mapped to subcarrier without modulation 38.211 */
   for (int i=0; i < LENGTH_PSS_NR; i++) {
-    primary_synchro[i].r = (d_pss[i] * SHRT_MAX) >> SCALING_PSS_NR; /* Maximum value for type short int ie int16_t */
+    primary_synchro[N_ID_2][i].r = (d_pss[i] * SHRT_MAX) >> SCALING_PSS_NR; /* Maximum value for type short int ie int16_t */
     primary_synchro2[i] = d_pss[i];
   }
 
@@ -115,6 +123,7 @@ void generate_pss_nr(NR_DL_FRAME_PARMS *fp, int N_ID_2)
   }
 
 #endif
+}
 
   /* call of IDFT should be done with ordered input as below
   *
@@ -137,21 +146,22 @@ void generate_pss_nr(NR_DL_FRAME_PARMS *fp, int N_ID_2)
   *
   * sample 0 is for continuous frequency which is used here
   */
-
+void generate_pss_nr_time(const NR_DL_FRAME_PARMS *fp, const int N_ID_2, int ssbFirstSCS, c16_t pssTime[fp->ofdm_symbol_size])
+{
   unsigned int subcarrier_start = get_softmodem_params()->sl_mode == 0 ? PSS_SSS_SUB_CARRIER_START : PSS_SSS_SUB_CARRIER_START_SL;
-  unsigned int  k = fp->first_carrier_offset + fp->ssb_start_subcarrier + subcarrier_start;
+  unsigned int k = fp->first_carrier_offset + ssbFirstSCS + subcarrier_start;
   if (k>= fp->ofdm_symbol_size) k-=fp->ofdm_symbol_size;
   c16_t synchroF_tmp[fp->ofdm_symbol_size] __attribute__((aligned(32)));
   memset(synchroF_tmp, 0, sizeof(synchroF_tmp));
   for (int i=0; i < LENGTH_PSS_NR; i++) {
-    synchroF_tmp[k % fp->ofdm_symbol_size] = primary_synchro[i];
+    synchroF_tmp[k % fp->ofdm_symbol_size] = primary_synchro[N_ID_2][i];
     k++;
   }
 
   /* IFFT will give temporal signal of Pss */
   idft((int16_t)get_idft(fp->ofdm_symbol_size),
        (int16_t *)synchroF_tmp, /* complex input but legacy type is wrong*/
-       (int16_t *)primary_synchro_time_nr[N_ID_2], /* complex output */
+       (int16_t *)pssTime, /* complex output */
        1); /* scaling factor */
 
 #ifdef DBG_PSS_NR
@@ -239,34 +249,10 @@ static void init_context_pss_nr(NR_DL_FRAME_PARMS *frame_parms_ue)
   AssertFatal(frame_parms_ue->ofdm_symbol_size > 127, "illegal ofdm_symbol_size %d\n", frame_parms_ue->ofdm_symbol_size);
   int pss_sequence = get_softmodem_params()->sl_mode == 0 ? NUMBER_PSS_SEQUENCE : NUMBER_PSS_SEQUENCE_SL;
   for (int i = 0; i < pss_sequence; i++) {
-    primary_synchro_nr2[i] = malloc16_clear(LENGTH_PSS_NR * sizeof(int16_t));
-    AssertFatal(primary_synchro_nr2[i], "Fatal memory allocation problem \n");
-    primary_synchro_time_nr[i] = malloc16_clear(frame_parms_ue->ofdm_symbol_size * sizeof(c16_t));
-    AssertFatal(primary_synchro_time_nr[i], "Fatal memory allocation problem \n");
     generate_pss_nr(frame_parms_ue,i);
   }
 }
 
-/*******************************************************************
-*
-* NAME :         free_context_pss_nr
-*
-* PARAMETERS :   none
-*
-* RETURN :       none
-*
-* DESCRIPTION :  free context related to pss
-*
-*********************************************************************/
-
-static void free_context_pss_nr(void)
-{
-  for (int i = 0; i < NUMBER_PSS_SEQUENCE; i++) {
-    free_and_zero(primary_synchro_nr2[i]);
-    free_and_zero(primary_synchro_time_nr[i]);
-  }
-}
-
 /*******************************************************************
 *
 * NAME :         init_context_synchro_nr
@@ -286,23 +272,6 @@ void init_context_synchro_nr(NR_DL_FRAME_PARMS *frame_parms_ue)
   init_context_sss_nr(AMP);
 }
 
-/*******************************************************************
-*
-* NAME :         free_context_synchro_nr
-*
-* PARAMETERS :   none
-*
-* RETURN :       free context for pss and sss
-*
-* DESCRIPTION :  deallocate memory of synchronisation
-*
-*********************************************************************/
-
-void free_context_synchro_nr(void)
-{
-  free_context_pss_nr();
-}
-
 /*******************************************************************
 *
 * NAME :         set_frame_context_pss_nr
@@ -321,8 +290,6 @@ void set_frame_context_pss_nr(NR_DL_FRAME_PARMS *frame_parms_ue, int rate_change
   frame_parms_ue->ofdm_symbol_size = (frame_parms_ue->ofdm_symbol_size / rate_change);
   frame_parms_ue->samples_per_subframe = (frame_parms_ue->samples_per_subframe / rate_change);
 
-  free_context_pss_nr();
-
   /* pss reference have to be rebuild with new parameters ie ofdm symbol size */
   init_context_synchro_nr(frame_parms_ue);
 
@@ -348,8 +315,6 @@ void restore_frame_context_pss_nr(NR_DL_FRAME_PARMS *frame_parms_ue, int rate_ch
   frame_parms_ue->ofdm_symbol_size = frame_parms_ue->ofdm_symbol_size * rate_change;
   frame_parms_ue->samples_per_subframe = frame_parms_ue->samples_per_subframe * rate_change;
 
-  free_context_pss_nr();
-
   /* pss reference have to be rebuild with new parameters ie ofdm symbol size */
   init_context_synchro_nr(frame_parms_ue);
 #ifdef SYNCHRO_DECIMAT
@@ -420,13 +385,17 @@ void decimation_synchro_nr(PHY_VARS_NR_UE *PHY_vars_UE, int rate_change, int **r
 *
 *********************************************************************/
 
-int pss_synchro_nr(PHY_VARS_NR_UE *PHY_vars_UE, int is, int rate_change)
+int pss_synchro_nr(const c16_t **rxdata,
+                   const NR_DL_FRAME_PARMS *frame_parms,
+                   const c16_t pssTime[NUMBER_PSS_SEQUENCE][frame_parms->ofdm_symbol_size],
+                   int is,
+                   bool fo_flag,
+                   int target_Nid_cell,
+                   int *nid2,
+                   int *f_off,
+                   int *pssPeak,
+                   int *pssAvg)
 {
-  NR_DL_FRAME_PARMS *frame_parms = &(PHY_vars_UE->frame_parms);
-  int synchro_position;
-  c16_t **rxdata = NULL;
-  int fo_flag = PHY_vars_UE->UE_fo_compensation;  // flag to enable freq offset estimation and compensation
-
   VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PSS_SYNCHRO_NR, VCD_FUNCTION_IN);
 #ifdef DBG_PSS_NR
 
@@ -434,24 +403,6 @@ int pss_synchro_nr(PHY_VARS_NR_UE *PHY_vars_UE, int is, int rate_change)
 
 #endif
 
-  if (rate_change != 1) {
-
-    rxdata = (c16_t**)malloc16(frame_parms->nb_antennas_rx * sizeof(c16_t*));
-
-    for (int aa = 0; aa < frame_parms->nb_antennas_rx; aa++) {
-      rxdata[aa] = (c16_t*)malloc16_clear((frame_parms->samples_per_frame + 8192) * sizeof(c16_t));
-    }
-#ifdef SYNCHRO_DECIMAT
-
-    decimation_synchro_nr(PHY_vars_UE, rate_change, rxdata);
-
-#endif
-  }
-  else {
-
-    rxdata = PHY_vars_UE->common_vars.rxdata;
-  }
-
 #ifdef DBG_PSS_NR
 
   LOG_M("rxdata0_des.m","rxd0_des", &rxdata[0][0], frame_parms->samples_per_frame,1,1);
@@ -468,7 +419,8 @@ int pss_synchro_nr(PHY_VARS_NR_UE *PHY_vars_UE, int is, int rate_change)
 
   VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PSS_SEARCH_TIME_NR, VCD_FUNCTION_IN);
 
-  synchro_position = pss_search_time_nr(rxdata, PHY_vars_UE, fo_flag, is);
+  int synchro_position =
+      pss_search_time_nr(rxdata, frame_parms, pssTime, fo_flag, is, target_Nid_cell, nid2, f_off, pssPeak, pssAvg);
 
   VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PSS_SEARCH_TIME_NR, VCD_FUNCTION_OUT);
 
@@ -480,7 +432,7 @@ int pss_synchro_nr(PHY_VARS_NR_UE *PHY_vars_UE, int is, int rate_change)
 
   #ifndef NR_UNIT_TEST
 
-  LOG_I(PHY,"PSS execution duration %4d microseconds \n", duration_ms);
+  LOG_D(PHY,"PSS execution duration %4d microseconds \n", duration_ms);
 
   #endif
 
@@ -507,8 +459,6 @@ int pss_synchro_nr(PHY_VARS_NR_UE *PHY_vars_UE, int is, int rate_change)
   return synchro_position;
 }
 
-
-
 /*******************************************************************
 *
 * NAME :         pss_search_time_nr
@@ -559,11 +509,17 @@ int pss_synchro_nr(PHY_VARS_NR_UE *PHY_vars_UE, int is, int rate_change)
 *
 *********************************************************************/
 
-static int pss_search_time_nr(c16_t **rxdata, PHY_VARS_NR_UE *ue, int fo_flag, int is)
+static int pss_search_time_nr(const c16_t **rxdata,
+                              const NR_DL_FRAME_PARMS *frame_parms,
+                              const c16_t pssTime[NUMBER_PSS_SEQUENCE][frame_parms->ofdm_symbol_size],
+                              bool fo_flag,
+                              int is,
+                              int target_Nid_cell,
+                              int *nid2,
+                              int *f_off,
+                              int *pssPeak,
+                              int *pssAvg)
 {
-  NR_DL_FRAME_PARMS *frame_parms = &ue->frame_parms;
-  int *nid2 = (int *)&ue->common_vars.nid2;
-  int *f_off = (int *)&ue->common_vars.freq_offset;
   unsigned int n, ar, peak_position, pss_source;
   int64_t peak_value;
   int64_t avg[NUMBER_PSS_SEQUENCE] = {0};
@@ -587,8 +543,8 @@ static int pss_search_time_nr(c16_t **rxdata, PHY_VARS_NR_UE *ue, int fo_flag, i
   int max_size = get_softmodem_params()->sl_mode == 0 ?  NUMBER_PSS_SEQUENCE : NUMBER_PSS_SEQUENCE_SL;
   for (int j = 0; j < max_size; j++)
     for (int i = 0; i < frame_parms->ofdm_symbol_size; i++) {
-      maxval = max(maxval, abs(primary_synchro_time_nr[j][i].r));
-      maxval = max(maxval, abs(primary_synchro_time_nr[j][i].i));
+      maxval = max(maxval, abs(pssTime[j][i].r));
+      maxval = max(maxval, abs(pssTime[j][i].i));
     }
   int shift = log2_approx(maxval);//*(frame_parms->ofdm_symbol_size+frame_parms->nb_prefix_samples)*2);
 
@@ -598,8 +554,8 @@ static int pss_search_time_nr(c16_t **rxdata, PHY_VARS_NR_UE *ue, int fo_flag, i
 
   uint16_t pss_index_start = 0;
   uint16_t pss_index_end = get_softmodem_params()->sl_mode == 0 ? NUMBER_PSS_SEQUENCE : NUMBER_PSS_SEQUENCE_SL;
-  if (ue->target_Nid_cell != -1) {
-    pss_index_start = GET_NID2(ue->target_Nid_cell);
+  if (target_Nid_cell != -1) {
+    pss_index_start = GET_NID2(target_Nid_cell);
     pss_index_end = pss_index_start + 1;
   }
 
@@ -612,7 +568,7 @@ static int pss_search_time_nr(c16_t **rxdata, PHY_VARS_NR_UE *ue, int fo_flag, i
       for (ar=0; ar<frame_parms->nb_antennas_rx; ar++) {
 
         /* perform correlation of rx data and pss sequence ie it is a dot product */
-        const c32_t result = dot_product(primary_synchro_time_nr[pss_index],
+        const c32_t result = dot_product(pssTime[pss_index],
                                          &(rxdata[ar][n + is * frame_parms->samples_per_frame]),
                                          frame_parms->ofdm_symbol_size,
                                          shift);
@@ -645,13 +601,13 @@ static int pss_search_time_nr(c16_t **rxdata, PHY_VARS_NR_UE *ue, int fo_flag, i
 	  // Shoujun Huang, Yongtao Su, Ying He and Shan Tang, "Joint time and frequency offset estimation in LTE downlink," 7th International Conference on Communications and Networking in China, 2012.
 
     // Computing cross-correlation at peak on half the symbol size for first half of data
-    c32_t r1 = dot_product(primary_synchro_time_nr[pss_source],
+    c32_t r1 = dot_product(pssTime[pss_source],
                            &(rxdata[0][peak_position + is * frame_parms->samples_per_frame]),
                            frame_parms->ofdm_symbol_size >> 1,
                            shift);
     // Computing cross-correlation at peak on half the symbol size for data shifted by half symbol size
     // as it is real and complex it is necessary to shift by a value equal to symbol size to obtain such shift
-    c32_t r2 = dot_product(primary_synchro_time_nr[pss_source] + (frame_parms->ofdm_symbol_size >> 1),
+    c32_t r2 = dot_product(pssTime[pss_source] + (frame_parms->ofdm_symbol_size >> 1),
                            &(rxdata[0][peak_position + is * frame_parms->samples_per_frame]) + (frame_parms->ofdm_symbol_size >> 1),
                            frame_parms->ofdm_symbol_size >> 1,
                            shift);
@@ -671,8 +627,10 @@ static int pss_search_time_nr(c16_t **rxdata, PHY_VARS_NR_UE *ue, int fo_flag, i
     avg[pss_index] /= (length / 4);
 
   *nid2 = pss_source;
+  *pssPeak = dB_fixed64(peak_value);
+  *pssAvg = dB_fixed64(avg[pss_source]);
 
-  LOG_I(PHY,
+  LOG_D(PHY,
         "[UE] nr_synchro_time: Sync source (nid2) = %d, Peak found at pos %d, val = %ld (%d dB power over signal avg %d dB), ffo "
         "%lf\n",
         pss_source,
diff --git a/openair1/PHY/NR_UE_TRANSPORT/sss_nr.c b/openair1/PHY/NR_UE_TRANSPORT/sss_nr.c
index 09d8ce4f4ab64da198dbeadac44d4c4be82fcb59..0a13462d8c37de53dcd82489327ee8e97bf0f37f 100644
--- a/openair1/PHY/NR_UE_TRANSPORT/sss_nr.c
+++ b/openair1/PHY/NR_UE_TRANSPORT/sss_nr.c
@@ -187,13 +187,14 @@ void insert_sss_nr(int16_t *sss_time,
 *
 *********************************************************************/
 
-static int pss_ch_est_nr(PHY_VARS_NR_UE *ue,
+static int pss_ch_est_nr(const NR_DL_FRAME_PARMS *frame_parms,
+                         int nid2,
                          c16_t pss_ext[NB_ANTENNAS_RX][LENGTH_PSS_NR],
                          c16_t sss_ext[NB_ANTENNAS_RX][LENGTH_SSS_NR])
 {
-  int16_t *pss = get_primary_synchro_nr2(ue->common_vars.nid2);
+  int16_t *pss = get_primary_synchro_nr2(nid2);
 
-  for (int aarx = 0; aarx < ue->frame_parms.nb_antennas_rx; aarx++) {
+  for (int aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++) {
     c16_t *sss_ext2 = sss_ext[aarx];
     c16_t *pss_ext2 = pss_ext[aarx];
     for (int i = 0; i < LENGTH_PSS_NR; i++) {
@@ -250,16 +251,15 @@ static int pss_ch_est_nr(PHY_VARS_NR_UE *ue,
 *********************************************************************/
 
 static int do_pss_sss_extract_nr(
-    PHY_VARS_NR_UE *ue,
-    const UE_nr_rxtx_proc_t *proc,
+    const NR_DL_FRAME_PARMS *frame_parms,
     c16_t pss_ext[NB_ANTENNAS_RX][LENGTH_PSS_NR],
     c16_t sss_ext[NB_ANTENNAS_RX][LENGTH_SSS_NR],
     uint8_t doPss,
     uint8_t doSss,
     uint8_t subframe,
-    c16_t rxdataF[][ue->frame_parms.samples_per_slot_wCP]) // add flag to indicate extracting only PSS, only SSS, or both
+    int ssb_start_subcarrier,
+    c16_t rxdataF[][frame_parms->samples_per_slot_wCP]) // add flag to indicate extracting only PSS, only SSS, or both
 {
-  NR_DL_FRAME_PARMS *frame_parms = &ue->frame_parms;
   AssertFatal(frame_parms->nb_antennas_rx > 0, "UB as sss_ext is not set to any value\n");
 
   for (int aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++) {
@@ -275,11 +275,8 @@ static int do_pss_sss_extract_nr(
     c16_t *pss_rxF_ext = pss_ext[aarx];
     c16_t *sss_rxF_ext = sss_ext[aarx];
 
-    unsigned int k = frame_parms->first_carrier_offset +
-                     frame_parms->ssb_start_subcarrier +
-                     ((get_softmodem_params()->sl_mode == 0) ?
-                     PSS_SSS_SUB_CARRIER_START :
-                     PSS_SSS_SUB_CARRIER_START_SL);
+    unsigned int k = frame_parms->first_carrier_offset + ssb_start_subcarrier
+                     + ((get_softmodem_params()->sl_mode == 0) ? PSS_SSS_SUB_CARRIER_START : PSS_SSS_SUB_CARRIER_START_SL);
 
     if (k>= frame_parms->ofdm_symbol_size) k-=frame_parms->ofdm_symbol_size;
 
@@ -333,14 +330,21 @@ static int do_pss_sss_extract_nr(
 *
 *********************************************************************/
 
-static int pss_sss_extract_nr(PHY_VARS_NR_UE *phy_vars_ue,
-                              const UE_nr_rxtx_proc_t *proc,
+static int pss_sss_extract_nr(const NR_DL_FRAME_PARMS *frame_parms,
                               c16_t pss_ext[NB_ANTENNAS_RX][LENGTH_PSS_NR],
                               c16_t sss_ext[NB_ANTENNAS_RX][LENGTH_SSS_NR],
                               uint8_t subframe,
-                              c16_t rxdataF[][phy_vars_ue->frame_parms.samples_per_slot_wCP])
+                              int ssb_start_subcarrier,
+                              c16_t rxdataF[][frame_parms->samples_per_slot_wCP])
 {
-  return do_pss_sss_extract_nr(phy_vars_ue, proc, pss_ext, sss_ext, 1 /* doPss */, 1 /* doSss */, subframe, rxdataF);
+  return do_pss_sss_extract_nr(frame_parms,
+                               pss_ext,
+                               sss_ext,
+                               1 /* doPss */,
+                               1 /* doSss */,
+                               subframe,
+                               ssb_start_subcarrier,
+                               rxdataF);
 }
 
 /*******************************************************************
@@ -355,31 +359,29 @@ static int pss_sss_extract_nr(PHY_VARS_NR_UE *phy_vars_ue,
  *                so Nid_cell in ue context is set according to Nid1 & Nid2
  *
  *********************************************************************/
-bool rx_sss_nr(PHY_VARS_NR_UE *ue,
-               const UE_nr_rxtx_proc_t *proc,
+bool rx_sss_nr(const NR_DL_FRAME_PARMS *frame_parms,
+               int nid2,
+               int target_Nid_cell,
+               int freq_offset_pss,
+               int ssb_start_subcarrier,
+               int *Nid_cell,
                int32_t *tot_metric,
                uint8_t *phase_max,
                int *freq_offset_sss,
-               c16_t rxdataF[][ue->frame_parms.samples_per_slot_wCP])
+               c16_t rxdataF[][frame_parms->samples_per_slot_wCP])
 {
   uint8_t i;
   c16_t pss_ext[NB_ANTENNAS_RX][LENGTH_PSS_NR] = {0};
   c16_t sss_ext[NB_ANTENNAS_RX][LENGTH_SSS_NR] = {0};
-  uint8_t Nid2 = GET_NID2(ue->common_vars.nid2);
+  uint8_t Nid2 = GET_NID2(nid2);
   uint16_t Nid1;
   uint8_t phase;
-  NR_DL_FRAME_PARMS *frame_parms=&ue->frame_parms;
   int32_t metric, metric_re;
   int16_t *d;
 
 
   // pss sss extraction
-  pss_sss_extract_nr(ue,
-                     proc,
-                     pss_ext,
-                     sss_ext,
-                     0,
-                     rxdataF);          /* subframe */
+  pss_sss_extract_nr(frame_parms, pss_ext, sss_ext, 0, ssb_start_subcarrier, rxdataF); /* subframe */
 
 #ifdef DEBUG_PLOT_SSS
 
@@ -406,9 +408,7 @@ bool rx_sss_nr(PHY_VARS_NR_UE *ue,
   // get conjugated channel estimate from PSS, H* = R* \cdot PSS
   // and do channel estimation and compensation based on PSS
 
-  pss_ch_est_nr(ue,
-                pss_ext,
-                sss_ext);
+  pss_ch_est_nr(frame_parms, nid2, pss_ext, sss_ext);
 
   // now do the SSS detection based on the precomputed sequences in PHY/LTE_TRANSPORT/sss.h
   *tot_metric = INT_MIN;
@@ -453,8 +453,8 @@ bool rx_sss_nr(PHY_VARS_NR_UE *ue,
 
   uint16_t Nid1_start = 0;
   uint16_t Nid1_end = N_ID_1_NUMBER;
-  if (ue->target_Nid_cell != -1) {
-    Nid1_start = GET_NID1(ue->target_Nid_cell);
+  if (target_Nid_cell != -1) {
+    Nid1_start = GET_NID1(target_Nid_cell);
     Nid1_end = Nid1_start + 1;
   }
 
@@ -476,7 +476,7 @@ bool rx_sss_nr(PHY_VARS_NR_UE *ue,
       // if the current metric is better than the last save it
       if (metric > *tot_metric) {
         *tot_metric = metric;
-        ue->frame_parms.Nid_cell = Nid2+(3*Nid1);
+        *Nid_cell = Nid2 + (3 * Nid1);
         *phase_max = phase;
 
 #ifdef DEBUG_SSS_NR
@@ -490,9 +490,9 @@ bool rx_sss_nr(PHY_VARS_NR_UE *ue,
 
 //#ifdef DEBUG_SSS_NR
 #define SSS_METRIC_FLOOR_NR   (30000)
-  if (*tot_metric > SSS_METRIC_FLOOR_NR) {	
-    Nid2 = GET_NID2(frame_parms->Nid_cell);
-    Nid1 = GET_NID1(frame_parms->Nid_cell);
+  if (*tot_metric > SSS_METRIC_FLOOR_NR) {
+    Nid2 = GET_NID2(*Nid_cell);
+    Nid1 = GET_NID1(*Nid_cell);
     LOG_D(PHY,"Nid2 %d Nid1 %d tot_metric %d, phase_max %d \n", Nid2, Nid1, *tot_metric, *phase_max);
   }
 // #endif
@@ -500,11 +500,11 @@ bool rx_sss_nr(PHY_VARS_NR_UE *ue,
   int re = 0;
   int im = 0;
   if (Nid1 == N_ID_1_NUMBER) {
-    LOG_W(PHY,
+    LOG_D(PHY,
           "Failed to detect SSS after PSS, metric of SSS %d, threshold to consider SSS valid %d, detected PCI: %d\n",
           *tot_metric,
           SSS_METRIC_FLOOR_NR,
-          frame_parms->Nid_cell);
+          *Nid_cell);
     return false;
   }
   d = (int16_t *)&d_sss[Nid2][Nid1];
@@ -515,10 +515,10 @@ bool rx_sss_nr(PHY_VARS_NR_UE *ue,
   double ffo_sss = atan2(im,re)/M_PI/4.3;
   *freq_offset_sss = (int)(ffo_sss*frame_parms->subcarrier_spacing);
 
-  double ffo_pss = ((double)ue->common_vars.freq_offset)/frame_parms->subcarrier_spacing;
-  LOG_W(NR_PHY,
+  double ffo_pss = ((double)freq_offset_pss) / frame_parms->subcarrier_spacing;
+  LOG_D(NR_PHY,
         "SSS detected, PCI: %d, ffo_pss %f (%i Hz), ffo_sss %f (%i Hz),  ffo_pss+ffo_sss %f (%i Hz), nid1: %d, nid2: %d\n",
-        frame_parms->Nid_cell,
+        *Nid_cell,
         ffo_pss,
         (int)(ffo_pss * frame_parms->subcarrier_spacing),
         ffo_sss,
diff --git a/openair1/PHY/defs_nr_UE.h b/openair1/PHY/defs_nr_UE.h
index f7eedcef3b31c58145bd8848e3727a02f4bb089f..38f840526c4a891121387858b77e2767e7929f53 100644
--- a/openair1/PHY/defs_nr_UE.h
+++ b/openair1/PHY/defs_nr_UE.h
@@ -49,6 +49,7 @@
 #include "common_lib.h"
 #include "fapi_nr_ue_interface.h"
 #include "assertions.h"
+//#include "openair1/SCHED_NR_UE/defs.h"
 
 #ifdef MEX
   #define msg mexPrintf
@@ -60,9 +61,9 @@
     #endif
     #define msg(aRGS...) LOG_D(PHY, ##aRGS)
 #endif
-//use msg in the real-time thread context
+// use msg in the real-time thread context
 #define msg_nrt printf
-//use msg_nrt in the non real-time context (for initialization, ...)
+// use msg_nrt in the non real-time context (for initialization, ...)
 #ifndef malloc16
     #define malloc16(x) memalign(32,x)
 #endif
@@ -123,6 +124,11 @@ typedef enum {
 
 #define debug_msg if (((mac_xface->frame%100) == 0) || (mac_xface->frame < 50)) msg
 
+typedef struct {
+  uint8_t decoded_output[3]; // PBCH paylod not larger than 3B
+  uint8_t xtra_byte;
+} fapiPbch_t;
+
 typedef struct {
 
   // RRC measurements
@@ -614,6 +620,32 @@ typedef struct {
   int frame_rx;
 } UE_nr_rxtx_proc_t;
 
+typedef struct {
+  bool cell_detected;
+  int rx_offset;
+  int frame_id;
+} nr_initial_sync_t;
+
+typedef struct {
+  nr_gscn_info_t gscnInfo;
+  int foFlag;
+  int targetNidCell;
+  c16_t **rxdata;
+  NR_DL_FRAME_PARMS *fp;
+  UE_nr_rxtx_proc_t *proc;
+  int nFrames;
+  int halfFrameBit;
+  int symbolOffset;
+  int ssbIndex;
+  int ssbOffset;
+  int nidCell;
+  int freqOffset;
+  nr_initial_sync_t syncRes;
+  fapiPbch_t pbchResult;
+  int pssCorrPeakPower;
+  int pssCorrAvgPower;
+} nr_ue_ssb_scan_t;
+
 typedef struct nr_phy_data_tx_s {
   NR_UE_ULSCH_t ulsch;
   NR_UE_PUCCH pucch_vars;
diff --git a/openair1/SCHED_NR_UE/defs.h b/openair1/SCHED_NR_UE/defs.h
index b34d021390a55c1973f0c44df95c02d138254706..bdb334138778fbf8e024b7dd0b8c099dffb1e69a 100644
--- a/openair1/SCHED_NR_UE/defs.h
+++ b/openair1/SCHED_NR_UE/defs.h
@@ -81,12 +81,6 @@
 #define DAQ_AGC_ON 1
 #define DAQ_AGC_OFF 0
 
-
-typedef struct {
-  uint8_t decoded_output[3]; // PBCH paylod not larger than 3B
-  uint8_t xtra_byte;
-} fapiPbch_t;
-
 /** @addtogroup _PHY_PROCEDURES_
  * @{
  */
diff --git a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c
index 422069548187b05186b66e29c8bcb7e96200ec20..cbeda2e106174b217f39d67a93c875c0b2980c15 100644
--- a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c
+++ b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c
@@ -371,13 +371,21 @@ static int nr_ue_pbch_procedures(PHY_VARS_NR_UE *ue,
 
   LOG_D(PHY,"[UE  %d] Frame %d Slot %d, Trying PBCH (NidCell %d, gNB_id %d)\n",ue->Mod_id,frame_rx,nr_slot_rx,ue->frame_parms.Nid_cell,gNB_id);
   fapiPbch_t result;
+  int hf_frame_bit, ssb_index, symb_offset;
   ret = nr_rx_pbch(ue,
                    proc,
+                   ue->is_synchronized,
                    estimateSz,
                    dl_ch_estimates,
                    &ue->frame_parms,
-                   (ue->frame_parms.ssb_index)&7,
+                   (ue->frame_parms.ssb_index) & 7,
+                   ue->frame_parms.ssb_start_subcarrier,
+                   ue->frame_parms.Nid_cell,
                    &result,
+                   &hf_frame_bit,
+                   &ssb_index,
+                   &symb_offset,
+                   ue->frame_parms.samples_per_frame_wCP,
                    rxdataF);
 
   if (ret==0) {
@@ -868,8 +876,9 @@ int pbch_pdcch_processing(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, nr_
             nr_slot_fep(ue, fp, proc, (ssb_start_symbol + i) % (fp->symbols_per_slot), rxdataF, link_type_dl);
 
             start_meas(&ue->dlsch_channel_estimation_stats);
-            nr_pbch_channel_estimation(ue,
-                                       &ue->frame_parms,
+            nr_pbch_channel_estimation(&ue->frame_parms,
+                                       NULL,
+                                       ue->nr_gold_pbch,
                                        estimateSz,
                                        dl_ch_estimates,
                                        dl_ch_estimates_time,
@@ -878,10 +887,20 @@ int pbch_pdcch_processing(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, nr_
                                        i - 1,
                                        ssb_index & 7,
                                        ssb_slot_2 == nr_slot_rx,
+                                       fp->ssb_start_subcarrier,
                                        rxdataF,
                                        false,
                                        fp->Nid_cell);
             stop_meas(&ue->dlsch_channel_estimation_stats);
+
+            if (i - 1 == 2)
+              UEscopeCopy(ue,
+                          pbchDlChEstimateTime,
+                          (void *)dl_ch_estimates_time,
+                          sizeof(c16_t),
+                          fp->nb_antennas_rx,
+                          fp->ofdm_symbol_size,
+                          0);
           }
 
           nr_ue_ssb_rsrp_measurements(ue, ssb_index, proc, rxdataF);
diff --git a/openair1/SCHED_NR_UE/phy_procedures_nr_ue_sl.c b/openair1/SCHED_NR_UE/phy_procedures_nr_ue_sl.c
index 2bf8ee6cb936565857fb86554eaad123059c9587..d9a3d5126718b76ffa4b90be3c1a07637e8b6242 100644
--- a/openair1/SCHED_NR_UE/phy_procedures_nr_ue_sl.c
+++ b/openair1/SCHED_NR_UE/phy_procedures_nr_ue_sl.c
@@ -193,8 +193,9 @@ int psbch_pscch_processing(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, nr_phy_d
       nr_slot_fep(ue, fp, proc, sym, rxdataF, link_type_ul);
 
       start_meas(&sl_phy_params->channel_estimation_stats);
-      nr_pbch_channel_estimation(ue,
-                                 fp,
+      nr_pbch_channel_estimation(fp,
+                                 &ue->SL_UE_PHY_PARAMS,
+                                 ue->nr_gold_pbch,
                                  estimateSz,
                                  dl_ch_estimates,
                                  dl_ch_estimates_time,
@@ -203,10 +204,19 @@ int psbch_pscch_processing(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, nr_phy_d
                                  sym,
                                  0,
                                  0,
+                                 fp->ssb_start_subcarrier,
                                  rxdataF,
                                  true,
                                  sl_phy_params->sl_config.sl_sync_source.rx_slss_id);
       stop_meas(&sl_phy_params->channel_estimation_stats);
+      if (sym == 12)
+        UEscopeCopy(ue,
+                    pbchDlChEstimateTime,
+                    (void *)dl_ch_estimates_time,
+                    sizeof(c16_t),
+                    fp->nb_antennas_rx,
+                    fp->ofdm_symbol_size,
+                    0);
 
       // PSBCH present in symbols 0, 5-12 for normal cp
       sym = (sym == 0) ? 5 : sym + 1;
diff --git a/openair1/SIMULATION/NR_PHY/dlsim.c b/openair1/SIMULATION/NR_PHY/dlsim.c
index ac37c033364817d9648bf4d43b4fd54868c4a55e..9928d25557d3e97107cf6a4f651f4c6cd1a37a00 100644
--- a/openair1/SIMULATION/NR_PHY/dlsim.c
+++ b/openair1/SIMULATION/NR_PHY/dlsim.c
@@ -830,7 +830,7 @@ int main(int argc, char **argv)
 
   init_nr_ue_transport(UE);
 
-  nr_gold_pbch(UE);
+  nr_gold_pbch(UE->nr_gold_pbch, frame_parms->Nid_cell, frame_parms->Lmax);
 
   // compute the scramblingID_pdcch and the gold pdcch
   UE->scramblingID_pdcch = frame_parms->Nid_cell;
diff --git a/openair1/SIMULATION/NR_PHY/pbchsim.c b/openair1/SIMULATION/NR_PHY/pbchsim.c
index ae452b66ff77ca98b82cbf5bb78d43ae4266e228..d294bd6052526080009a530c7adb8fdd80e289c1 100644
--- a/openair1/SIMULATION/NR_PHY/pbchsim.c
+++ b/openair1/SIMULATION/NR_PHY/pbchsim.c
@@ -199,6 +199,7 @@ int main(int argc, char **argv)
   uint16_t Nid_cell=0;
   uint64_t SSB_positions=0x01;
   int ssb_subcarrier_offset = 0;
+  int ssb_scan_threads = 0;
 
   channel_desc_t *gNB2UE;
   get_softmodem_params()->sa = 1;
@@ -500,8 +501,9 @@ int main(int argc, char **argv)
   set_tdd_config_nr(&gNB->gNB_config, mu, 7, 6, 2, 4);
   phy_init_nr_gNB(gNB);
   frame_parms->ssb_start_subcarrier = 12 * gNB->gNB_config.ssb_table.ssb_offset_point_a.value + ssb_subcarrier_offset;
+  initFloatingCoresTpool(ssb_scan_threads, &nrUE_params.Tpool, false, "UE-tpool");
 
-  uint8_t n_hf = 0;
+  int n_hf = 0;
   int cyclic_prefix_type = NFAPI_CP_NORMAL;
 
   double fs=0, eps;
@@ -615,7 +617,7 @@ int main(int argc, char **argv)
     exit(-1);
   }
 
-  nr_gold_pbch(UE);
+  nr_gold_pbch(UE->nr_gold_pbch, Nid_cell, frame_parms->Lmax);
 
   processingData_L1tx_t msgDataTx;
   // generate signal
@@ -766,13 +768,16 @@ int main(int argc, char **argv)
       }
 
       if (n_trials==1) {
-	LOG_M("rxsig0.m","rxs0", UE->common_vars.rxdata[0],frame_parms->samples_per_frame,1,1);
-	if (gNB->frame_parms.nb_antennas_tx>1)
-	  LOG_M("rxsig1.m","rxs1", UE->common_vars.rxdata[1],frame_parms->samples_per_frame,1,1);
+        LOG_M("rxsig0.m", "rxs0", UE->common_vars.rxdata[0], frame_parms->samples_per_frame, 1, 1);
+        if (gNB->frame_parms.nb_antennas_tx > 1)
+          LOG_M("rxsig1.m", "rxs1", UE->common_vars.rxdata[1], frame_parms->samples_per_frame, 1, 1);
       }
       if (UE->is_synchronized == 0) {
-	UE_nr_rxtx_proc_t proc={0};
-        nr_initial_sync_t ret = nr_initial_sync(&proc, UE, 1, 0);
+        UE_nr_rxtx_proc_t proc = {0};
+        nr_gscn_info_t gscnInfo[MAX_GSCN_BAND] = {0};
+        const int numGscn = 1;
+        gscnInfo[0].ssbFirstSC = frame_parms->ssb_start_subcarrier;
+        nr_initial_sync_t ret = nr_initial_sync(&proc, UE, 1, 0, gscnInfo, numGscn);
         printf("nr_initial_sync1 returns %s\n", ret.cell_detected ? "cell detected" : "cell not detected");
         if (!ret.cell_detected)
           n_errors++;
@@ -795,8 +800,9 @@ int main(int argc, char **argv)
         for (int i = UE->symbol_offset + 1; i < UE->symbol_offset + 4; i++) {
           nr_slot_fep(UE, frame_parms, &proc, i % frame_parms->symbols_per_slot, rxdataF, link_type_dl);
 
-          nr_pbch_channel_estimation(UE,
-                                     &UE->frame_parms,
+          nr_pbch_channel_estimation(&UE->frame_parms,
+                                     &UE->SL_UE_PHY_PARAMS,
+                                     UE->nr_gold_pbch,
                                      estimateSz,
                                      dl_ch_estimates,
                                      dl_ch_estimates_time,
@@ -805,12 +811,29 @@ int main(int argc, char **argv)
                                      i - (UE->symbol_offset + 1),
                                      ssb_index % 8,
                                      n_hf,
+                                     frame_parms->ssb_start_subcarrier,
                                      rxdataF,
                                      false,
                                      frame_parms->Nid_cell);
         }
         fapiPbch_t result;
-        ret = nr_rx_pbch(UE, &proc, estimateSz, dl_ch_estimates, frame_parms, ssb_index % 8, &result, rxdataF);
+        int ret_ssb_idx;
+        int ret_symbol_offset;
+        ret = nr_rx_pbch(UE,
+                         &proc,
+                         true,
+                         estimateSz,
+                         dl_ch_estimates,
+                         frame_parms,
+                         ssb_index % 8,
+                         frame_parms->ssb_start_subcarrier,
+                         Nid_cell,
+                         &result,
+                         &n_hf,
+                         &ret_ssb_idx,
+                         &ret_symbol_offset,
+                         frame_parms->samples_per_frame_wCP,
+                         rxdataF);
 
         if (ret == 0) {
           // UE->rx_ind.rx_indication_body->mib_pdu.ssb_index;  //not yet detected automatically
diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c
index c1d15d810b7a0c550aa905999ec8ee4b186b2dba..4a244fe34845fa72b3a2254af55c1305639f883c 100644
--- a/openair2/GNB_APP/gnb_config.c
+++ b/openair2/GNB_APP/gnb_config.c
@@ -96,71 +96,6 @@
 
 extern uint16_t sf_ahead;
 
-// synchronization raster per band tables (Rel.15)
-// (38.101-1 Table 5.4.3.3-1 and 38.101-2 Table 5.4.3.3-1)
-// band nb, sub-carrier spacing index, Range of gscn (First, Step size, Last)
-const sync_raster_t sync_raster[] = {
-  {1, 0, 5279, 1, 5419},
-  {2, 0, 4829, 1, 4969},
-  {3, 0, 4517, 1, 4693},
-  {5, 0, 2177, 1, 2230},
-  {5, 1, 2183, 1, 2224},
-  {7, 0, 6554, 1, 6718},
-  {8, 0, 2318, 1, 2395},
-  {12, 0, 1828, 1, 1858},
-  {13, 0, 1871, 1, 1885},
-  {14, 0, 1901, 1, 1915},
-  {18, 0, 2156, 1, 2182},
-  {20, 0, 1982, 1, 2047},
-  {24, 0, 3818, 1, 3892},
-  {24, 1, 3824, 1, 3886},
-  {25, 0, 4829, 1, 4981},
-  {26, 0, 2153, 1, 2230},
-  {28, 0, 1901, 1, 2002},
-  {29, 0, 1798, 1, 1813},
-  {30, 0, 5879, 1, 5893},
-  {34, 0, 5030, 1, 5056},
-  {34, 1, 5036, 1, 5050},
-  {38, 0, 6431, 1, 6544},
-  {38, 1, 6437, 1, 6538},
-  {39, 0, 4706, 1, 4795},
-  {39, 1, 4712, 1, 4789},
-  {40, 1, 5762, 1, 5989},
-  {41, 0, 6246, 3, 6717},
-  {41, 1, 6252, 3, 6714},
-  {48, 1, 7884, 1, 7982},
-  {50, 0, 3584, 1, 3787},
-  {51, 0, 3572, 1, 3574},
-  {53, 0, 6215, 1, 6232},
-  {53, 1, 6221, 1, 6226},
-  {65, 0, 5279, 1, 5494},
-  {66, 0, 5279, 1, 5494},
-  {66, 1, 5285, 1, 5488},
-  {67, 0, 1850, 1, 1888},
-  {70, 0, 4993, 1, 5044},
-  {71, 0, 1547, 1, 1624},
-  {74, 0, 3692, 1, 3790},
-  {75, 0, 3584, 1, 3787},
-  {76, 0, 3572, 1, 3574},
-  {77, 1, 7711, 1, 8329},
-  {78, 1, 7711, 1, 8051},
-  {79, 1, 8480, 16, 8880},
-  {85, 0, 1826, 1, 1858},
-  {90, 1, 6252, 1, 6714},
-  {91, 0, 3572, 1, 3574},
-  {92, 0, 3584, 1, 3787},
-  {93, 0, 3572, 1, 3574},
-  {94, 0, 3584, 1, 3587},
-  {257, 3, 22388, 1, 22558},
-  {257, 4, 22390, 2, 22556},
-  {258, 3, 22257, 1, 22443},
-  {258, 4, 22258, 2, 22442},
-  {260, 3, 22995, 1, 23166},
-  {260, 4, 22996, 2, 23164},
-  {261, 3, 22446, 1, 22492},
-  {261, 4, 22446, 2, 22490},
-};
-
 extern int config_check_band_frequencies(int ind, int16_t band, uint64_t downlink_frequency,
                                          int32_t uplink_frequency_offset, uint32_t  frame_type);
 
@@ -960,8 +895,6 @@ void RCconfig_NR_L1(void)
   }
 }
 
-static void check_ssb_raster(uint64_t freq, int band, int scs);
-
 static NR_ServingCellConfigCommon_t *get_scc_config(configmodule_interface_t *cfg, int minRXTXTIME)
 {
   NR_ServingCellConfigCommon_t *scc = calloc(1,sizeof(*scc));
@@ -1543,56 +1476,6 @@ void config_security(gNB_RRC_INST *rrc)
   }
 }
 
-// Section 5.4.3 of 38.101-1 and -2
-static void check_ssb_raster(uint64_t freq, int band, int scs)
-{
-  int start_gscn = 0, step_gscn = 0, end_gscn = 0;
-  for (int i = 0; i < sizeof(sync_raster) / sizeof(sync_raster_t); i++) {
-    if (sync_raster[i].band == band &&
-        sync_raster[i].scs_index == scs) {
-      start_gscn = sync_raster[i].first_gscn;
-      step_gscn = sync_raster[i].step_gscn;
-      end_gscn = sync_raster[i].last_gscn;
-      break;
-    }
-  }
-  AssertFatal(start_gscn != 0, "Couldn't find band %d with SCS %d\n", band, scs);
-  int gscn;
-  if (freq < 3000000000) {
-    int N = 0;
-    int M = 0;
-    for (int k = 0; k < 3; k++) {
-      M = (k << 1) + 1;
-      if ((freq - M * 50000) % 1200000 == 0) {
-        N = (freq - M * 50000) / 1200000;
-        break;
-      }
-    }
-    AssertFatal(N != 0, "SSB frequency %lu Hz not on the synchronization raster (N * 1200kHz + M * 50 kHz)\n",
-                freq);
-    gscn = (3 * N) + (M - 3) / 2;
-  }
-  else if (freq < 24250000000) {
-    AssertFatal((freq - 3000000000) % 1440000 == 0,
-                "SSB frequency %lu Hz not on the synchronization raster (3000 MHz + N * 1.44 MHz)\n",
-                freq);
-    gscn = ((freq - 3000000000) / 1440000) + 7499;
-  }
-  else {
-    AssertFatal((freq - 24250080000) % 17280000 == 0,
-                "SSB frequency %lu Hz not on the synchronization raster (24250.08 MHz + N * 17.28 MHz)\n",
-                freq);
-    gscn = ((freq - 24250080000) / 17280000) + 22256;
-  }
-  AssertFatal(gscn >= start_gscn && gscn <= end_gscn,
-              "GSCN %d corresponding to SSB frequency %lu does not belong to GSCN range for band %d\n",
-              gscn, freq, band);
-  int rel_gscn = gscn - start_gscn;
-  AssertFatal(rel_gscn % step_gscn == 0,
-              "GSCN %d corresponding to SSB frequency %lu not in accordance with GSCN step for band %d\n",
-               gscn, freq, band);
-}
-
 void RCconfig_NRRRC(gNB_RRC_INST *rrc)
 {
 
diff --git a/openair2/LAYER2/NR_MAC_UE/config_ue.c b/openair2/LAYER2/NR_MAC_UE/config_ue.c
index 8e245069cc6021af3fb0f3cef1df5363f206850f..77f53a32a5fb570435d1f950eff6aa6a47f2ff5e 100644
--- a/openair2/LAYER2/NR_MAC_UE/config_ue.c
+++ b/openair2/LAYER2/NR_MAC_UE/config_ue.c
@@ -1420,6 +1420,7 @@ void nr_rrc_mac_config_req_reset(module_id_t module_id,
                                  NR_UE_MAC_reset_cause_t cause)
 {
   NR_UE_MAC_INST_t *mac = get_mac_inst(module_id);
+  fapi_nr_synch_request_t sync_req = {.target_Nid_cell = -1, .ssb_bw_scan = true};
   switch (cause) {
     case GO_TO_IDLE:
       reset_ra(mac, true);
@@ -1427,7 +1428,7 @@ void nr_rrc_mac_config_req_reset(module_id_t module_id,
       nr_ue_init_mac(mac);
       nr_ue_mac_default_configs(mac);
       // new sync but no target cell id -> -1
-      nr_ue_send_synch_request(mac, module_id, 0, -1);
+      nr_ue_send_synch_request(mac, module_id, 0, &sync_req);
       break;
     case DETACH:
       LOG_A(NR_MAC, "Received detach indication\n");
@@ -1448,7 +1449,9 @@ void nr_rrc_mac_config_req_reset(module_id_t module_id,
       nr_ue_reset_sync_state(mac);
       release_mac_configuration(mac, cause);
       // new sync with old cell ID (re-establishment on the same cell)
-      nr_ue_send_synch_request(mac, module_id, 0, mac->physCellId);
+      sync_req.target_Nid_cell = mac->physCellId;
+      sync_req.ssb_bw_scan = false;
+      nr_ue_send_synch_request(mac, module_id, 0, &sync_req);
       break;
     default:
       AssertFatal(false, "Invalid MAC reset cause %d\n", cause);
diff --git a/openair2/LAYER2/NR_MAC_UE/mac_proto.h b/openair2/LAYER2/NR_MAC_UE/mac_proto.h
index ea300520585f9160cc86ebb2b517f56ad4304e86..1eac68350c1ad349e71a4cee651d6306a22b89fc 100644
--- a/openair2/LAYER2/NR_MAC_UE/mac_proto.h
+++ b/openair2/LAYER2/NR_MAC_UE/mac_proto.h
@@ -295,7 +295,7 @@ void prepare_msg4_feedback(NR_UE_MAC_INST_t *mac, int pid, int ack_nack);
 void configure_initial_pucch(PUCCH_sched_t *pucch, int res_ind);
 void release_PUCCH_SRS(NR_UE_MAC_INST_t *mac);
 void nr_ue_reset_sync_state(NR_UE_MAC_INST_t *mac);
-void nr_ue_send_synch_request(NR_UE_MAC_INST_t *mac, module_id_t module_id, int cc_id, int cell_id);
+void nr_ue_send_synch_request(NR_UE_MAC_INST_t *mac, module_id_t module_id, int cc_id, const fapi_nr_synch_request_t *sync_req);
 
 /**
  * @brief   Get UE sync state
diff --git a/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c b/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c
index 79086da5a91254ba0d8d2ef345265c875c1b222a..cc602ed24055da68c82fe33afc11a91f44304e15 100644
--- a/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c
+++ b/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c
@@ -98,12 +98,12 @@ void nr_ue_mac_default_configs(NR_UE_MAC_INST_t *mac)
   mac->scheduling_info.prohibitPHR_Timer = NR_PHR_Config__phr_ProhibitTimer_sf10;
 }
 
-void nr_ue_send_synch_request(NR_UE_MAC_INST_t *mac, module_id_t module_id, int cc_id, int cell_id)
+void nr_ue_send_synch_request(NR_UE_MAC_INST_t *mac, module_id_t module_id, int cc_id, const fapi_nr_synch_request_t *sync_req)
 {
   // Sending to PHY a request to resync
   mac->synch_request.Mod_id = module_id;
   mac->synch_request.CC_id = cc_id;
-  mac->synch_request.synch_req.target_Nid_cell = cell_id;
+  mac->synch_request.synch_req = *sync_req;
   mac->if_module->synch_request(&mac->synch_request);
 }
 
diff --git a/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c b/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c
index 16f35f6c927033b9347b1b6e7da0276cb360fc0c..e599ec5608b9fce035efd96d2e91fc888973f5ef 100644
--- a/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c
+++ b/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c
@@ -1038,6 +1038,7 @@ static int handle_bcch_bch(NR_UE_MAC_INST_t *mac,
   mac->mib_ssb = ssb_index;
   mac->physCellId = cell_id;
   mac->mib_additional_bits = additional_bits;
+  mac->ssb_start_subcarrier = ssb_start_subcarrier;
   if(ssb_length == 64)
     mac->frequency_range = FR2;
   else