diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_initial_sync.c b/openair1/PHY/NR_UE_TRANSPORT/nr_initial_sync.c index c8c67c017f..97c3af3b1e 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_initial_sync.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_initial_sync.c @@ -48,8 +48,6 @@ //static nfapi_nr_config_request_t config_t; //static nfapi_nr_config_request_t* config =&config_t; -int cnt=0; - // #define DEBUG_INITIAL_SYNCH #define DUMP_PBCH_CH_ESTIMATES 0 @@ -137,12 +135,9 @@ static bool nr_pbch_detection(const UE_nr_rxtx_proc_t *proc, nr_initial_sync_t nr_initial_sync(UE_nr_rxtx_proc_t *proc, PHY_VARS_NR_UE *ue, int n_frames, int sa) { int32_t sync_pos, sync_pos_frame; // k_ssb, N_ssb_crb, sync_pos2, - int32_t metric_tdd_ncp = 0; - uint8_t phase_tdd_ncp; - int frame_id; NR_DL_FRAME_PARMS *fp = &ue->frame_parms; - nr_initial_sync_t ret = {true, 0}; + 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); @@ -163,162 +158,137 @@ nr_initial_sync_t nr_initial_sync(UE_nr_rxtx_proc_t *proc, PHY_VARS_NR_UE *ue, i 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]; - cnt++; - if (1) { // (cnt>100) - cnt = 0; - // 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 (frame_id = 0; frame_id < n_frames; frame_id++) { - /* process pss search on received buffer */ - sync_pos = pss_synchro_nr(ue, frame_id, NO_RATE_CHANGE); - if (sync_pos < fp->nb_prefix_samples) - continue; + // 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++) { + /* process pss search on received buffer */ + sync_pos = pss_synchro_nr(ue, frame_id, NO_RATE_CHANGE); + if (sync_pos < fp->nb_prefix_samples) + continue; - ue->ssb_offset = sync_pos - fp->nb_prefix_samples; + ue->ssb_offset = 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); + 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) { - // 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))); - } - } - } - - /* slot_fep function works for lte and takes into account begining of frame with prefix for subframe 0 */ - /* for NR this is not the case but slot_fep is still used for computing FFT of samples */ - /* in order to achieve correct processing for NR prefix samples is forced to 0 and then restored after function call */ - /* symbol number are from beginning of SS/PBCH blocks as below: */ - /* Signal PSS PBCH SSS PBCH */ - /* symbol number 0 1 2 3 */ - /* 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 */ - - 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); - -#ifdef DEBUG_INITIAL_SYNCH - LOG_I(PHY, "Calling sss detection (normal CP)\n"); -#endif - - int freq_offset_sss = 0; - bool ret_sss = rx_sss_nr(ue, proc, &metric_tdd_ncp, &phase_tdd_ncp, &freq_offset_sss, rxdataF); - ret.cell_detected = ret_sss; // rx_sss_nr returns true if success - // 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 * 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; - } - - 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 - } - - 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<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]); - } - - 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 (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; - } - - /* - int nb_prefix_samples0 = fp->nb_prefix_samples0; - fp->nb_prefix_samples0 = fp->nb_prefix_samples; - - nr_slot_fep(ue, proc, 0, 0, ue->ssb_offset, 0, NR_PDCCH_EST); - nr_slot_fep(ue, proc, 1, 0, ue->ssb_offset, 0, NR_PDCCH_EST); - fp->nb_prefix_samples0 = nb_prefix_samples0; - - LOG_I(PHY,"[UE %d] AUTOTEST Cell Sync : frame = %d, rx_offset %d, freq_offset %d \n", - ue->Mod_id, - ue->proc.proc_rxtx[0].frame_rx, - ue->rx_offset, - ue->common_vars.freq_offset ); - */ - -#ifdef DEBUG_INITIAL_SYNCH - LOG_I(PHY, - "TDD Normal prefix: CellId %d metric %d, phase %d, pbch detected %d, measured offset %d\n", - fp->Nid_cell, - metric_tdd_ncp, - phase_tdd_ncp, - ret.cell_detected, - ret.rx_offset); -#endif - - } else { -#ifdef DEBUG_INITIAL_SYNCH - LOG_I(PHY, "TDD Normal prefix: SSS error condition: sync_pos %d\n", sync_pos); -#endif - } - if (ret.cell_detected) - break; + /* 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); + continue; } - } else { - ret.cell_detected = false; + + // 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))); + } + } + } + + /* slot_fep function works for lte and takes into account begining of frame with prefix for subframe 0 */ + /* for NR this is not the case but slot_fep is still used for computing FFT of samples */ + /* in order to achieve correct processing for NR prefix samples is forced to 0 and then restored after function call */ + /* symbol number are from beginning of SS/PBCH blocks as below: */ + /* Signal PSS PBCH SSS PBCH */ + /* symbol number 0 1 2 3 */ + /* 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 */ + + 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); + +#ifdef DEBUG_INITIAL_SYNCH + LOG_I(PHY, "Calling sss detection (normal CP)\n"); +#endif + + 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; + } + + 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 + } + + 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<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]); + } + + 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 (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; + } + +#ifdef DEBUG_INITIAL_SYNCH + LOG_I(PHY, + "TDD Normal prefix: CellId %d metric %d, phase %d, pbch detected %d, measured offset %d\n", + fp->Nid_cell, + metric_tdd_ncp, + phase_tdd_ncp, + ret.cell_detected, + ret.rx_offset); +#endif } /* Consider this is a false detection if the offset is > 1000 Hz