make all functions for pss detection independant of global context such as frame_parms

Signed-off-by: Laurent THOMAS <laurent.thomas@open-cells.com>
This commit is contained in:
Laurent THOMAS
2026-05-05 21:45:03 +02:00
committed by Robert Schmidt
parent ad44ee75f6
commit 8eeb1b125f
5 changed files with 203 additions and 104 deletions

View File

@@ -54,20 +54,24 @@
#endif
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,
int nb_ant,
int ofdm_symbol_size,
int rxdata_size,
int subcarrier_spacing,
const c16_t pssTime[NUMBER_PSS_SEQUENCE][ofdm_symbol_size],
bool fo_flag,
int target_Nid_cell,
int *nid2,
int *f_off,
int *pssPeak,
int *pssAvg);
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],
int ofdm_symbol_size,
int nb_antennas_rx,
int subcarrier_spacing,
const c16_t pssTime[NUMBER_PSS_SEQUENCE][ofdm_symbol_size],
bool fo_flag,
int is,
int target_Nid_cell,
int *nid2,
int *f_off,
@@ -75,7 +79,11 @@ int pss_search_time_nr(const c16_t **rxdata,
int *pssAvg,
int search_start,
int search_length);
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]);
void generate_pss_nr_time(int ofdm_symbol_size,
int first_carrier_offset,
const int N_ID_2,
int ssbFirstSCS,
c16_t pssTime[ofdm_symbol_size]);
void generate_pss_nr(const int N_ID_2, int16_t *pss);
#endif /* PSS_NR_H */

View File

@@ -237,14 +237,27 @@ static bool search_neighboring_cell(NR_DL_FRAME_PARMS *frame_parms,
int freq_offset_sss = 0;
nr_ssb_search_params_t search_params = {
.frame_parms = frame_parms,
.rxdata = rxdata,
.dl_CarrierFreq = frame_parms->dl_CarrierFreq,
.sampling_rate = frame_parms->samples_per_subframe * 1000,
.slots_per_frame = frame_parms->slots_per_frame,
.slots_per_subframe = frame_parms->slots_per_subframe,
.numerology_index = frame_parms->numerology_index,
.ofdm_symbol_size = frame_parms->ofdm_symbol_size,
.ofdm_offset_divisor = frame_parms->ofdm_offset_divisor,
.nb_antennas_rx = frame_parms->nb_antennas_rx,
.symbols_per_slot = frame_parms->symbols_per_slot,
.first_carrier_offset = frame_parms->first_carrier_offset,
.N_RB_DL = frame_parms->N_RB_DL,
.rxdata_size = rxdata_size,
.rxdata = rxdata,
.nb_prefix_samples = frame_parms->nb_prefix_samples,
.nb_prefix_samples0 = frame_parms->nb_prefix_samples0,
.ssb_start_subcarrier = frame_parms->ssb_start_subcarrier,
.subcarrier_spacing = frame_parms->subcarrier_spacing,
.samples_per_slot_wCP = frame_parms->samples_per_slot_wCP,
.target_nid_cell = -1, // Blind search
.exclude_nid_cell = frame_parms->Nid_cell, // Exclude serving cell
.apply_freq_offset = false,
.search_frame_id = 0, // Search in first frame of buffer
.fo_flag = false,
.rxdataF = rxdataF,
.pssTime = pssTime,
@@ -295,10 +308,11 @@ static bool validate_known_pci(NR_DL_FRAME_PARMS *frame_parms,
int length = neighboring_cell_info->pss_search_length;
int peak_position = pss_search_time_nr((const c16_t **)rxdata,
frame_parms,
frame_parms->ofdm_symbol_size,
frame_parms->nb_antennas_rx,
frame_parms->subcarrier_spacing,
pssTime,
false, // no frequency offset estimation for tracking
0, // first frame
known_pci,
&pss_index,
&f_off,
@@ -378,7 +392,11 @@ void do_neighboring_cell_measurements(UE_nr_rxtx_proc_t *proc, PHY_VARS_NR_UE *u
// Generate PSS time-domain sequences once for all neighbor cells
__attribute__((aligned(32))) c16_t pssTime[NUMBER_PSS_SEQUENCE][frame_parms->ofdm_symbol_size];
for (int nid2_idx = 0; nid2_idx < NUMBER_PSS_SEQUENCE; nid2_idx++) {
generate_pss_nr_time(frame_parms, nid2_idx, frame_parms->ssb_start_subcarrier, pssTime[nid2_idx]);
generate_pss_nr_time(frame_parms->ofdm_symbol_size,
frame_parms->first_carrier_offset,
nid2_idx,
frame_parms->ssb_start_subcarrier,
pssTime[nid2_idx]);
}
__attribute__((aligned(32))) c16_t rxdataF[NR_N_SYMBOLS_SSB][frame_parms->nb_antennas_rx][rxdataF_sz];

View File

@@ -130,13 +130,13 @@ static bool nr_pbch_detection(const UE_nr_rxtx_proc_t *proc,
return false;
}
static void compensate_freq_offset(c16_t **x, const NR_DL_FRAME_PARMS *fp, const int offset, const int sn)
static void compensate_freq_offset(c16_t **x, const int nb_antennas_rx, const int x_len, const int offset, const int sampling_rate)
{
double s_time = 1 / (1.0e3 * fp->samples_per_subframe); // sampling time
double s_time = 1.0 / sampling_rate; // 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++) {
for (int n = 0; n < x_len; n++) {
for (int ar = 0; ar < 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)));
@@ -145,14 +145,59 @@ static void compensate_freq_offset(c16_t **x, const NR_DL_FRAME_PARMS *fp, const
}
}
/* rxdataF should be 16 bytes aligned */
static void generate_table(nr_ssb_search_params_t *params,
c16_t timeshift_symbol_rotation[params->ofdm_symbol_size],
c16_t symbol_rotation[224])
{
init_timeshift_rotation(params->ofdm_symbol_size,
params->nb_prefix_samples,
params->ofdm_offset_divisor,
timeshift_symbol_rotation);
perform_symbol_rotation(params->symbols_per_slot * params->slots_per_frame / 10,
params->numerology_index,
params->dl_CarrierFreq,
symbol_rotation);
}
static void do_time_to_freq(nr_ssb_search_params_t *params, uint32_t sample_offset)
{
c16_t timeshift_symbol_rotation[params->ofdm_symbol_size];
c16_t symbol_rotation[224];
generate_table(params, timeshift_symbol_rotation, symbol_rotation);
c16_t(*rxdataF)[params->nb_antennas_rx][params->ofdm_symbol_size] =
(c16_t(*)[params->nb_antennas_rx][params->ofdm_symbol_size])params->rxdataF;
dft_size_idx_t dftsize = get_dft(params->ofdm_symbol_size);
for (int symb = 0; symb < NR_N_SYMBOLS_SSB; symb++) {
// For Sidelink 16 frames worth of samples is processed to find SSB, for 5G-NR 2.
unsigned int rx_offset = sample_offset + params->nb_prefix_samples;
rx_offset += symb * (params->nb_prefix_samples + params->ofdm_symbol_size);
// use OFDM symbol from within 1/8th of the CP to avoid ISI
rx_offset -= params->nb_prefix_samples / params->ofdm_offset_divisor;
for (unsigned char aa = 0; aa < params->nb_antennas_rx; aa++) {
c16_t *rxF = rxdataF[symb][aa];
dft(dftsize, (int16_t *)&params->rxdata[aa][rx_offset], (int16_t *)rxF, 1);
apply_nr_rotation_symbol_RX(params->symbols_per_slot,
params->slots_per_subframe,
timeshift_symbol_rotation,
params->first_carrier_offset,
rxF,
symbol_rotation,
params->N_RB_DL,
0,
symb);
}
}
}
/*
* Common SSB search function used by both initial sync and neighbor cell search
*/
bool nr_search_ssb_common(nr_ssb_search_params_t *params)
{
const NR_DL_FRAME_PARMS *fp = params->frame_parms;
const uint32_t pssTime_sz = fp->ofdm_symbol_size;
const uint32_t pssTime_sz = params->ofdm_symbol_size;
c16_t(*pssTime)[pssTime_sz] = (c16_t(*)[pssTime_sz])params->pssTime;
// Perform PSS search
@@ -161,9 +206,11 @@ bool nr_search_ssb_common(nr_ssb_search_params_t *params)
int pss_peak = 0;
int pss_avg = 0;
const int sync_pos = pss_synchro_nr((const c16_t **)params->rxdata,
fp,
params->nb_antennas_rx,
params->ofdm_symbol_size,
params->rxdata_size,
params->subcarrier_spacing,
pssTime,
params->search_frame_id,
params->fo_flag,
params->target_nid_cell,
&nid2,
@@ -178,11 +225,11 @@ bool nr_search_ssb_common(nr_ssb_search_params_t *params)
if (params->freq_offset_pss)
*params->freq_offset_pss = freq_offset_pss;
if (sync_pos < fp->nb_prefix_samples || nid2 < 0) {
if (sync_pos < params->nb_prefix_samples || nid2 < 0) {
return false;
}
const int ssb_offset = sync_pos - fp->nb_prefix_samples;
const int ssb_offset = sync_pos - params->nb_prefix_samples;
if (params->ssb_offset)
*params->ssb_offset = ssb_offset;
@@ -191,7 +238,7 @@ bool nr_search_ssb_common(nr_ssb_search_params_t *params)
#endif
// Check that SSB fits within buffer
if (ssb_offset + NR_N_SYMBOLS_SSB * (fp->ofdm_symbol_size + fp->nb_prefix_samples) >= params->rxdata_size) {
if (ssb_offset + NR_N_SYMBOLS_SSB * (params->ofdm_symbol_size + params->nb_prefix_samples) >= params->rxdata_size) {
LOG_D(PHY,
"SSB extends beyond buffer boundary (sync_pos %d, ssb_offset %d, buffer_size %d)\n",
sync_pos,
@@ -202,35 +249,27 @@ bool nr_search_ssb_common(nr_ssb_search_params_t *params)
// Apply frequency offset compensation if requested
if (params->apply_freq_offset && freq_offset_pss != 0) {
compensate_freq_offset(params->rxdata, fp, freq_offset_pss, params->search_frame_id);
compensate_freq_offset(params->rxdata, params->nb_antennas_rx, params->rxdata_size, freq_offset_pss, params->sampling_rate);
}
// Extract SSB symbols to frequency domain
// Symbol ordering: 0=PSS, 1=PBCH, 2=SSS, 3=PBCH
c16_t(*rxdataF)[fp->nb_antennas_rx][fp->ofdm_symbol_size] = (c16_t(*)[fp->nb_antennas_rx][fp->ofdm_symbol_size])params->rxdataF;
__attribute__((aligned(32))) c16_t rxdataF_tmp[fp->nb_antennas_rx][fp->samples_per_slot_wCP];
for (int i = 0; i < NR_N_SYMBOLS_SSB; i++) {
const int sample_offset = params->search_frame_id * fp->samples_per_frame + ssb_offset;
nr_slot_fep(NULL, fp, 0, i, rxdataF_tmp, link_type_dl, sample_offset, (c16_t **)params->rxdata);
// TODO: In later commit, call the modified symbol demod function and remove the following memcpy.
for (int aarx = 0; aarx < fp->nb_antennas_rx; aarx++)
memcpy(rxdataF[i][aarx], &rxdataF_tmp[aarx][i * fp->ofdm_symbol_size], sizeof(c16_t) * fp->ofdm_symbol_size);
}
do_time_to_freq(params, ssb_offset);
// Perform SSS detection
int detected_nid_cell = -1;
int32_t sss_metric = 0;
uint8_t sss_phase = 0;
int freq_offset_sss = 0;
nr_sss_params_t p = (nr_sss_params_t){.nb_antennas_rx = fp->nb_antennas_rx,
.samples_per_slot_wCP = fp->samples_per_slot_wCP,
.ofdm_symbol_size = fp->ofdm_symbol_size,
.first_carrier_offset = fp->first_carrier_offset,
.ssb_start_subcarrier = fp->ssb_start_subcarrier,
.subcarrier_spacing = fp->subcarrier_spacing};
nr_sss_params_t p = (nr_sss_params_t){.nb_antennas_rx = params->nb_antennas_rx,
.samples_per_slot_wCP = params->samples_per_slot_wCP,
.ofdm_symbol_size = params->ofdm_symbol_size,
.first_carrier_offset = params->first_carrier_offset,
.ssb_start_subcarrier = params->ssb_start_subcarrier,
.subcarrier_spacing = params->subcarrier_spacing};
c16_t(*rxdataF)[params->nb_antennas_rx][params->ofdm_symbol_size] =
(c16_t(*)[params->nb_antennas_rx][params->ofdm_symbol_size])params->rxdataF;
bool sss_detected =
rx_sss_nr(&p, nid2, -1, freq_offset_pss, &detected_nid_cell, &sss_metric, &sss_phase, &freq_offset_sss, rxdataF);
@@ -279,16 +318,16 @@ void nr_scan_ssb(void *arg)
__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]);
generate_pss_nr_time(fp->ofdm_symbol_size, fp->first_carrier_offset, nid2, ssbInfo->gscnInfo.ssbFirstSC, pssTime[nid2]);
__attribute__((aligned(32))) c16_t rxdataF[NR_N_SYMBOLS_SSB][fp->nb_antennas_rx][fp->ofdm_symbol_size];
// 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 simulation tools
for (int frame_id = 0; frame_id < ssbInfo->nFrames && !ssbInfo->syncRes.cell_detected; frame_id++) {
if (ssbInfo->freqOffset)
compensate_freq_offset(rxdata, fp, ssbInfo->freqOffset, frame_id);
if (ssbInfo->freqOffset)
compensate_freq_offset(rxdata, fp->nb_antennas_rx, ssbInfo->rxdata_sz, ssbInfo->freqOffset, fp->samples_per_subframe * 1000);
for (int frame_id = 0; frame_id < ssbInfo->nFrames && !ssbInfo->syncRes.cell_detected; frame_id++) {
int detected_nid_cell = -1;
int ssb_offset = 0;
int freq_offset_pss = 0;
@@ -296,15 +335,32 @@ void nr_scan_ssb(void *arg)
int32_t sss_metric = 0;
uint8_t sss_phase = 0;
c16_t *rxdataShift[fp->nb_antennas_rx];
for (int i = 0; i < fp->nb_antennas_rx; i++)
rxdataShift[i] = rxdata[i] + fp->samples_per_frame * frame_id;
nr_ssb_search_params_t search_params = {
.frame_parms = fp,
.rxdata = rxdata,
.dl_CarrierFreq = fp->dl_CarrierFreq,
.sampling_rate = fp->samples_per_subframe * 1000,
.slots_per_frame = fp->slots_per_frame,
.slots_per_subframe = fp->slots_per_subframe,
.numerology_index = fp->numerology_index,
.ofdm_symbol_size = fp->ofdm_symbol_size,
.ofdm_offset_divisor = fp->ofdm_offset_divisor,
.nb_antennas_rx = fp->nb_antennas_rx,
.symbols_per_slot = fp->symbols_per_slot,
.first_carrier_offset = fp->first_carrier_offset,
.N_RB_DL = fp->N_RB_DL,
.rxdata_size = fp->samples_per_frame,
.rxdata = rxdataShift,
.nb_prefix_samples = fp->nb_prefix_samples,
.nb_prefix_samples0 = fp->nb_prefix_samples0,
.ssb_start_subcarrier = ssbInfo->gscnInfo.ssbFirstSC,
.subcarrier_spacing = fp->subcarrier_spacing,
.samples_per_slot_wCP = fp->samples_per_slot_wCP,
.target_nid_cell = ssbInfo->targetNidCell,
.exclude_nid_cell = -1, // No exclusion for initial sync
.apply_freq_offset = ssbInfo->foFlag,
.search_frame_id = frame_id,
.fo_flag = ssbInfo->foFlag,
.rxdataF = rxdataF,
.pssTime = pssTime,
@@ -392,9 +448,10 @@ nr_initial_sync_t nr_initial_sync(UE_nr_rxtx_proc_t *proc,
.targetNidCell = ue->target_Nid_cell};
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(sizeof(c16_t) * (fp->samples_per_frame * 2 + fp->ofdm_symbol_size));
memcpy(ssbInfo->rxdata[ant], ue->common_vars.rxdata[ant], sizeof(c16_t) * fp->samples_per_frame * 2);
memset(ssbInfo->rxdata[ant] + fp->samples_per_frame * 2, 0, fp->ofdm_symbol_size * sizeof(c16_t));
ssbInfo->rxdata[ant] = malloc16(sizeof(c16_t) * (fp->samples_per_frame * n_frames + fp->ofdm_symbol_size));
memcpy(ssbInfo->rxdata[ant], ue->common_vars.rxdata[ant], sizeof(c16_t) * fp->samples_per_frame * n_frames);
memset(ssbInfo->rxdata[ant] + fp->samples_per_frame * n_frames, 0, fp->ofdm_symbol_size * sizeof(c16_t));
ssbInfo->rxdata_sz = fp->samples_per_frame * n_frames + fp->ofdm_symbol_size;
}
LOG_I(NR_PHY,
"Scanning GSCN: %d, with SSB offset: %d, SSB Freq: %lf\n",
@@ -467,7 +524,11 @@ nr_initial_sync_t nr_initial_sync(UE_nr_rxtx_proc_t *proc,
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);
compensate_freq_offset(ue->common_vars.rxdata,
fp->nb_antennas_rx,
fp->samples_per_frame,
res->freqOffset,
fp->samples_per_subframe * 1000);
}
// sync at symbol ue->symbol_offset
// computing the offset wrt the beginning of the frame

View File

@@ -84,23 +84,27 @@ void generate_pss_nr(const int N_ID_2, int16_t *pss)
*
* 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])
void generate_pss_nr_time(int ofdm_symbol_size,
int first_carrier_offset,
const int N_ID_2,
int ssbFirstSCS,
c16_t pssTime[ofdm_symbol_size])
{
unsigned int subcarrier_start = get_softmodem_params()->sl_mode == 0 ? PSS_SSS_SUB_CARRIER_START : PSS_SSS_SUB_CARRIER_START_SL;
c16_t synchroF_tmp[fp->ofdm_symbol_size] __attribute__((aligned(32)));
c16_t synchroF_tmp[ofdm_symbol_size] __attribute__((aligned(32)));
memset(synchroF_tmp, 0, sizeof(synchroF_tmp));
unsigned int k = fp->first_carrier_offset + ssbFirstSCS + subcarrier_start;
unsigned int k = first_carrier_offset + ssbFirstSCS + subcarrier_start;
int16_t pss[LENGTH_PSS_NR];
generate_pss_nr(N_ID_2, pss);
for (int i=0; i < LENGTH_PSS_NR; i++) {
if (k >= fp->ofdm_symbol_size)
k -= fp->ofdm_symbol_size;
if (k >= ofdm_symbol_size)
k -= ofdm_symbol_size;
synchroF_tmp[k] = (c16_t){.r = (pss[i] * SHRT_MAX) >> SCALING_PSS_NR}; /* Maximum value for type short int ie int16_t */
k++;
}
/* IFFT will give temporal signal of Pss */
idft((int16_t)get_idft(fp->ofdm_symbol_size),
idft((int16_t)get_idft(ofdm_symbol_size),
(int16_t *)synchroF_tmp, /* complex input but legacy type is wrong*/
(int16_t *)pssTime, /* complex output */
1); /* scaling factor */
@@ -119,9 +123,11 @@ void generate_pss_nr_time(const NR_DL_FRAME_PARMS *fp, const int N_ID_2, int ssb
*********************************************************************/
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,
int nb_ant,
int ofdm_symbol_size,
int rxdata_size,
int subcarrier_spacing,
const c16_t pssTime[NUMBER_PSS_SEQUENCE][ofdm_symbol_size],
bool fo_flag,
int target_Nid_cell,
int *nid2,
@@ -130,8 +136,19 @@ int pss_synchro_nr(const c16_t **rxdata,
int *pssAvg)
{
start_meas(&generic_time[TIME_PSS]);
int synchro_position =
pss_search_time_nr(rxdata, frame_parms, pssTime, fo_flag, is, target_Nid_cell, nid2, f_off, pssPeak, pssAvg, -1, -1);
int synchro_position = pss_search_time_nr(rxdata,
ofdm_symbol_size,
nb_ant,
subcarrier_spacing,
pssTime,
fo_flag,
target_Nid_cell,
nid2,
f_off,
pssPeak,
pssAvg,
0,
rxdata_size - ofdm_symbol_size);
stop_meas(&generic_time[TIME_PSS]);
#if TEST_SYNCHRO_TIMING_PSS
@@ -196,10 +213,11 @@ int pss_synchro_nr(const c16_t **rxdata,
*********************************************************************/
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],
int ofdm_symbol_size,
int nb_antennas_rx,
int subcarrier_spacing,
const c16_t pssTime[NUMBER_PSS_SEQUENCE][ofdm_symbol_size],
bool fo_flag,
int is,
int target_Nid_cell,
int *nid2,
int *f_off,
@@ -210,24 +228,13 @@ int pss_search_time_nr(const c16_t **rxdata,
{
// Determine search window
unsigned int start, length;
if (search_start >= 0 && search_length > 0) {
// Use provided search window for known neighboring cells
start = search_start;
length = search_length;
} else {
// For initial cell search
start = 0;
if (is == 0)
length = frame_parms->samples_per_frame + (2 * frame_parms->ofdm_symbol_size);
else
length = frame_parms->samples_per_frame;
}
AssertFatal(length > 0, "illegal length %d\n", length);
// Use provided search window for known neighboring cells
start = search_start;
length = search_length;
int maxval=0;
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++) {
for (int i = 0; i < ofdm_symbol_size; i++) {
maxval = max(maxval, abs(pssTime[j][i].r));
maxval = max(maxval, abs(pssTime[j][i].i));
}
@@ -256,12 +263,9 @@ int pss_search_time_nr(const c16_t **rxdata,
int64_t pss_corr_ue = 0;
/* calculate dot product of primary_synchro_time_nr and rxdata[ar][n]
* (ar=0..nb_ant_rx) and store the sum in temp[n]; */
for (int ar = 0; ar < frame_parms->nb_antennas_rx; ar++) {
for (int ar = 0; ar < nb_antennas_rx; ar++) {
/* perform correlation of rx data and pss sequence ie it is a dot product */
const c32_t result = dot_product(pssTime[pss_index],
&rxdata[ar][n + is * frame_parms->samples_per_frame],
frame_parms->ofdm_symbol_size,
shift);
const c32_t result = dot_product(pssTime[pss_index], &rxdata[ar][n], ofdm_symbol_size, shift);
const c64_t r64 = {.r = result.r, .i = result.i};
pss_corr_ue += squaredMod(r64);
}
@@ -274,7 +278,7 @@ int pss_search_time_nr(const c16_t **rxdata,
pss_source = pss_index;
#ifdef DEBUG_PSS_NR
printf("pss_index %d: n %6u peak_value %15llu\n", pss_index, n, (unsigned long long)pss_corr_ue[n]);
printf("pss_index %d: n %6u peak_value %lu\n", pss_index, n, pss_corr_ue);
#endif
}
}
@@ -288,15 +292,12 @@ int pss_search_time_nr(const c16_t **rxdata,
// 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(pssTime[pss_source],
&(rxdata[0][peak_position + is * frame_parms->samples_per_frame]),
frame_parms->ofdm_symbol_size >> 1,
shift);
c32_t r1 = dot_product(pssTime[pss_source], &(rxdata[0][peak_position]), 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(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,
c32_t r2 = dot_product(pssTime[pss_source] + (ofdm_symbol_size >> 1),
&(rxdata[0][peak_position]) + (ofdm_symbol_size >> 1),
ofdm_symbol_size >> 1,
shift);
cd_t r1d = {r1.r, r1.i}, r2d = {r2.r, r2.i};
// estimation of fractional frequency offset: angle[(result1)'*(result2)]/pi
@@ -307,7 +308,7 @@ int pss_search_time_nr(const c16_t **rxdata,
#endif
}
// computing absolute value of frequency offset
*f_off = ffo_est * frame_parms->subcarrier_spacing;
*f_off = ffo_est * subcarrier_spacing;
*nid2 = pss_source;
*pssPeak = dB_fixed64(peak_value);
@@ -329,10 +330,7 @@ int pss_search_time_nr(const c16_t **rxdata,
#ifdef DBG_PSS_NR
static int debug_cnt = 0;
if (debug_cnt == 0) {
if (is)
LOG_M("rxdata1.m", "rxd0", rxdata[frame_parms->samples_per_frame], length, 1, 1);
else
LOG_M("rxdata0.m", "rxd0", rxdata[0], length, 1, 1);
LOG_M("rxdata0.m", "rxd0", rxdata[0], length, 1, 1);
} else {
debug_cnt++;
}

View File

@@ -468,6 +468,7 @@ typedef struct {
int foFlag;
int targetNidCell;
c16_t **rxdata;
int rxdata_sz;
NR_DL_FRAME_PARMS *fp;
UE_nr_rxtx_proc_t *proc;
int nFrames;
@@ -487,14 +488,27 @@ typedef struct {
// Common SSB search parameters - used by both initial sync and neighbor cell search
typedef struct {
const NR_DL_FRAME_PARMS *frame_parms;
c16_t **rxdata;
uint64_t dl_CarrierFreq;
uint sampling_rate;
int slots_per_frame;
int slots_per_subframe;
int numerology_index;
int ofdm_symbol_size;
uint ofdm_offset_divisor;
int nb_antennas_rx;
int symbols_per_slot;
int first_carrier_offset;
int N_RB_DL;
uint32_t rxdata_size;
c16_t **rxdata;
int nb_prefix_samples;
int nb_prefix_samples0;
int ssb_start_subcarrier;
int subcarrier_spacing;
int samples_per_slot_wCP;
int target_nid_cell; // -1 for blind search, specific PCI for targeted search
int exclude_nid_cell; // -1 for no exclusion, or serving cell PCI to exclude
bool apply_freq_offset; // whether to compensate frequency offset
int search_frame_id; // Frame index to search (0, 1, 2...) within rxdata buffer
bool fo_flag; // frequency offset estimation flag for pss_synchro_nr()
void *rxdataF; // Pre-allocated rxdataF buffer
void *pssTime; // Pre-generated PSS time sequences