make a decent struct for pss detection results instead of a mess

Signed-off-by: Laurent THOMAS <laurent.thomas@open-cells.com>
This commit is contained in:
Laurent THOMAS
2026-05-06 14:57:30 +02:00
committed by Robert Schmidt
parent 8eeb1b125f
commit 11b8ba54ea
5 changed files with 94 additions and 189 deletions

View File

@@ -17,7 +17,7 @@
#include "PHY/defs_nr_common.h"
#include "PHY/NR_REFSIG/ss_pbch_nr.h"
#include "PHY/defs_nr_UE.h"
/************** CODE GENERATION ***********************************/
//#define PSS_DECIMATOR /* decimation of sample is done between time correlation */
@@ -53,32 +53,16 @@
#define SYNCHRO_RATE_CHANGE_FACTOR (1)
#endif
int pss_synchro_nr(const c16_t **rxdata,
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,
pss_detection_result_t pss_search_time_nr(const c16_t **rxdata,
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 target_Nid_cell,
int *nid2,
int *f_off,
int *pssPeak,
int *pssAvg,
int search_start,
int search_length);
void generate_pss_nr_time(int ofdm_symbol_size,
int first_carrier_offset,
const int N_ID_2,

View File

@@ -228,10 +228,6 @@ static bool search_neighboring_cell(NR_DL_FRAME_PARMS *frame_parms,
c16_t pssTime[][frame_parms->ofdm_symbol_size])
{
int detected_nid_cell = -1;
int ssb_offset = 0;
int freq_offset_pss = 0;
int pss_peak = 0;
int pss_avg = 0;
int32_t sss_metric = 0;
uint8_t sss_phase = 0;
int freq_offset_sss = 0;
@@ -262,13 +258,9 @@ static bool search_neighboring_cell(NR_DL_FRAME_PARMS *frame_parms,
.rxdataF = rxdataF,
.pssTime = pssTime,
.detected_nid_cell = &detected_nid_cell,
.ssb_offset = &ssb_offset,
.sss_metric = &sss_metric,
.freq_offset_pss = &freq_offset_pss,
.freq_offset_sss = &freq_offset_sss,
.sss_phase = &sss_phase,
.pss_peak = &pss_peak,
.pss_avg = &pss_avg,
};
bool found = nr_search_ssb_common(&search_params);
@@ -276,15 +268,15 @@ static bool search_neighboring_cell(NR_DL_FRAME_PARMS *frame_parms,
if (found) {
nr_neighboring_cell->Nid_cell = detected_nid_cell;
LOG_I(NR_PHY,
"Found neighbor cell PCI=%d (sss_metric=%d, ssb_offset=%d, pss_peak=%d dB, pss_avg=%d dB)\n",
"Found neighbor cell PCI=%d (sss_metric=%d, pss peak pos =%d, pss_peak=%d dB, pss_avg=%d dB)\n",
detected_nid_cell,
sss_metric,
ssb_offset,
pss_peak,
pss_avg);
search_params.pss_res.pos,
search_params.pss_res.peak,
search_params.pss_res.avg);
// Update search window
neighboring_cell_info->pss_search_start = ssb_offset + frame_parms->nb_prefix_samples - 16;
neighboring_cell_info->pss_search_start = search_params.pss_res.pos - 16;
neighboring_cell_info->pss_search_length = 32;
}
@@ -300,28 +292,21 @@ static bool validate_known_pci(NR_DL_FRAME_PARMS *frame_parms,
{
int known_pci = nr_neighboring_cell->Nid_cell;
int pss_index = GET_NID2(known_pci);
int f_off = 0;
int pss_peak = 0;
int pss_avg = 0;
int start = neighboring_cell_info->pss_search_start;
int length = neighboring_cell_info->pss_search_length;
int peak_position = pss_search_time_nr((const c16_t **)rxdata,
pss_detection_result_t pss_res = pss_search_time_nr((const c16_t **)rxdata,
frame_parms->ofdm_symbol_size,
frame_parms->nb_antennas_rx,
frame_parms->subcarrier_spacing,
pssTime,
false, // no frequency offset estimation for tracking
known_pci,
&pss_index,
&f_off,
&pss_peak,
&pss_avg,
start,
length);
if (peak_position < frame_parms->nb_prefix_samples) {
if (!pss_res.success) {
if (neighboring_cell_info->valid_meas)
neighboring_cell_info->consec_fail++;
LOG_D(NR_PHY,
@@ -329,18 +314,20 @@ static bool validate_known_pci(NR_DL_FRAME_PARMS *frame_parms,
known_pci,
start,
length,
pss_peak,
pss_avg,
pss_res.peak,
pss_res.avg,
neighboring_cell_info->consec_fail);
return false;
}
int ssb_offset = peak_position - frame_parms->nb_prefix_samples;
int ssb_time_offset = pss_res.pos - frame_parms->nb_prefix_samples;
if (ssb_time_offset < 0)
return false; // pss position is too close to buffer begining
__attribute__((aligned(32))) c16_t rxdataF_tmp[frame_parms->nb_antennas_rx][frame_parms->samples_per_slot_wCP];
uint8_t sss_symbol = SSS_SYMBOL_NB - PSS_SYMBOL_NB;
nr_slot_fep(NULL, frame_parms, 0, 0, rxdataF_tmp, link_type_dl, ssb_offset, (c16_t **)rxdata);
nr_slot_fep(NULL, frame_parms, 0, sss_symbol, rxdataF_tmp, link_type_dl, ssb_offset, (c16_t **)rxdata);
nr_slot_fep(NULL, frame_parms, 0, 0, rxdataF_tmp, link_type_dl, ssb_time_offset, (c16_t **)rxdata);
nr_slot_fep(NULL, frame_parms, 0, sss_symbol, rxdataF_tmp, link_type_dl, ssb_time_offset, (c16_t **)rxdata);
/* TODO: Once symbol based PDSCH proc is imeplemented, nr_slot_fep() will use
the new rxdataF buffer format so the following memcpy can be removed. */
for (int aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++) {
@@ -377,7 +364,7 @@ static bool validate_known_pci(NR_DL_FRAME_PARMS *frame_parms,
LOG_D(NR_PHY, "Known PCI validation completed for PCI=%d, metric=%d\n", known_pci, sss_metric);
neighboring_cell_info->consec_fail = 0;
neighboring_cell_info->valid_meas = true;
neighboring_cell_info->pss_search_start = peak_position - 16;
neighboring_cell_info->pss_search_start = pss_res.pos - 16;
neighboring_cell_info->pss_search_length = 32;
return true;

View File

@@ -201,60 +201,43 @@ bool nr_search_ssb_common(nr_ssb_search_params_t *params)
c16_t(*pssTime)[pssTime_sz] = (c16_t(*)[pssTime_sz])params->pssTime;
// Perform PSS search
int nid2 = -1;
int freq_offset_pss = 0;
int pss_peak = 0;
int pss_avg = 0;
const int sync_pos = pss_synchro_nr((const c16_t **)params->rxdata,
params->nb_antennas_rx,
params->pss_res = pss_search_time_nr((const c16_t **)params->rxdata,
params->ofdm_symbol_size,
params->rxdata_size,
params->nb_antennas_rx,
params->subcarrier_spacing,
pssTime,
params->fo_flag,
params->target_nid_cell,
&nid2,
&freq_offset_pss,
&pss_peak,
&pss_avg);
0,
params->rxdata_size);
if (params->pss_peak)
*params->pss_peak = pss_peak;
if (params->pss_avg)
*params->pss_avg = pss_avg;
if (params->freq_offset_pss)
*params->freq_offset_pss = freq_offset_pss;
if (sync_pos < params->nb_prefix_samples || nid2 < 0) {
if (!params->pss_res.success)
return false;
}
const int ssb_offset = sync_pos - params->nb_prefix_samples;
if (params->ssb_offset)
*params->ssb_offset = ssb_offset;
const int ssb_time_offset = params->pss_res.pos - params->nb_prefix_samples;
#ifdef DEBUG_INITIAL_SYNCH
LOG_I(PHY, "Initial sync : Estimated PSS position %d, Nid2 %d, ssb offset %d\n", sync_pos, nid2, ssb_offset);
#endif
// Check that SSB fits within buffer
if (ssb_offset + NR_N_SYMBOLS_SSB * (params->ofdm_symbol_size + params->nb_prefix_samples) >= params->rxdata_size) {
if (ssb_time_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,
ssb_offset,
params->pss_res.pos,
ssb_time_offset,
params->rxdata_size);
return false;
}
// Apply frequency offset compensation if requested
if (params->apply_freq_offset && freq_offset_pss != 0) {
compensate_freq_offset(params->rxdata, params->nb_antennas_rx, params->rxdata_size, freq_offset_pss, params->sampling_rate);
if (params->apply_freq_offset && params->pss_res.freq_offset != 0) {
compensate_freq_offset(params->rxdata, params->nb_antennas_rx, params->rxdata_size, params->pss_res.freq_offset, params->sampling_rate);
}
// Extract SSB symbols to frequency domain
// Symbol ordering: 0=PSS, 1=PBCH, 2=SSS, 3=PBCH
do_time_to_freq(params, ssb_offset);
do_time_to_freq(params, ssb_time_offset);
// Perform SSS detection
int detected_nid_cell = -1;
@@ -270,8 +253,15 @@ bool nr_search_ssb_common(nr_ssb_search_params_t *params)
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);
bool sss_detected = rx_sss_nr(&p,
params->pss_res.nid2,
-1,
params->pss_res.freq_offset,
&detected_nid_cell,
&sss_metric,
&sss_phase,
&freq_offset_sss,
rxdataF);
if (params->sss_metric)
*params->sss_metric = sss_metric;
@@ -329,7 +319,6 @@ void nr_scan_ssb(void *arg)
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;
int freq_offset_sss = 0;
int32_t sss_metric = 0;
@@ -365,13 +354,9 @@ void nr_scan_ssb(void *arg)
.rxdataF = rxdataF,
.pssTime = pssTime,
.detected_nid_cell = &detected_nid_cell,
.ssb_offset = &ssb_offset,
.sss_metric = &sss_metric,
.freq_offset_pss = &freq_offset_pss,
.freq_offset_sss = &freq_offset_sss,
.sss_phase = &sss_phase,
.pss_peak = &ssbInfo->pssCorrPeakPower,
.pss_avg = &ssbInfo->pssCorrAvgPower,
};
ssbInfo->syncRes.frame_id = frame_id;
@@ -381,7 +366,8 @@ void nr_scan_ssb(void *arg)
continue;
}
ssbInfo->ssbOffset = ssb_offset;
ssbInfo->ssbOffset = search_params.pss_res.pos - search_params.nb_prefix_samples;
;
ssbInfo->nidCell = detected_nid_cell;
#ifdef DEBUG_INITIAL_SYNCH

View File

@@ -30,8 +30,7 @@
#include "PHY/NR_REFSIG/sss_nr.h"
#include "PHY/NR_UE_TRANSPORT/cic_filter_nr.h"
//#define DBG_PSS_NR
static time_stats_t generic_time[TIME_LAST];
// #define DBG_PSS_NR
/*******************************************************************
*
@@ -110,58 +109,6 @@ void generate_pss_nr_time(int ofdm_symbol_size,
1); /* scaling factor */
}
/*******************************************************************
*
* NAME : pss_synchro_nr
*
* PARAMETERS : int rate_change
*
* RETURN : position of detected pss
*
* DESCRIPTION : pss search can be done with sampling decimation.*
*
*********************************************************************/
int pss_synchro_nr(const c16_t **rxdata,
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)
{
start_meas(&generic_time[TIME_PSS]);
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
int duration_ms = generic_time[TIME_PSS].p_time / (cpuf * 1000.0);
#ifndef NR_UNIT_TEST
LOG_D(PHY, "PSS execution duration %4d microseconds \n", duration_ms);
#endif
#endif
return synchro_position;
}
/*******************************************************************
*
* NAME : pss_search_time_nr
@@ -212,25 +159,21 @@ int pss_synchro_nr(const c16_t **rxdata,
*
*********************************************************************/
int pss_search_time_nr(const c16_t **rxdata,
pss_detection_result_t pss_search_time_nr(const c16_t **rxdata,
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 target_Nid_cell,
int *nid2,
int *f_off,
int *pssPeak,
int *pssAvg,
int search_start,
int search_length)
int start,
int length)
{
// Determine search window
unsigned int start, length;
// Use provided search window for known neighboring cells
start = search_start;
length = search_length;
if (start < 0 || length == 0) {
LOG_E(PHY, "inconsistent call to pss_search_time_nr %d, %d\n", start, length);
return (pss_detection_result_t){.success = false};
}
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++)
@@ -307,12 +250,6 @@ int pss_search_time_nr(const c16_t **rxdata,
printf("ffo %lf\n", ffo_est);
#endif
}
// computing absolute value of frequency offset
*f_off = ffo_est * subcarrier_spacing;
*nid2 = pss_source;
*pssPeak = dB_fixed64(peak_value);
*pssAvg = dB_fixed64(avg[pss_source]);
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 "
@@ -324,8 +261,8 @@ int pss_search_time_nr(const c16_t **rxdata,
dB_fixed64(avg[pss_source]),
ffo_est);
if ((search_start < 0 || search_length == 0) && peak_value < 5 * avg[pss_source])
return (-1);
if (peak_value == 0 || peak_value < 5 * avg[pss_source])
return (pss_detection_result_t){.success = false};
#ifdef DBG_PSS_NR
static int debug_cnt = 0;
@@ -336,7 +273,12 @@ int pss_search_time_nr(const c16_t **rxdata,
}
#endif
return peak_position;
return (pss_detection_result_t){.success = true,
.nid2 = pss_source,
.pos = peak_position,
.freq_offset = ffo_est * subcarrier_spacing,
.peak = dB_fixed64(peak_value),
.avg = dB_fixed64(avg[pss_source])};
}
void sl_generate_pss(SL_NR_UE_INIT_PARAMS_t *sl_init_params, uint8_t n_sl_id2, uint16_t scaling)

View File

@@ -486,6 +486,15 @@ typedef struct {
task_ans_t *ans;
} nr_ue_ssb_scan_t;
typedef struct {
bool success;
int pos;
int nid2;
int freq_offset; // PSS frequency offset estimate
int peak; // PSS correlation peak power
int avg; // PSS correlation average power
} pss_detection_result_t;
// Common SSB search parameters - used by both initial sync and neighbor cell search
typedef struct {
uint64_t dl_CarrierFreq;
@@ -513,14 +522,11 @@ typedef struct {
void *rxdataF; // Pre-allocated rxdataF buffer
void *pssTime; // Pre-generated PSS time sequences
// Output parameters
pss_detection_result_t pss_res;
int *detected_nid_cell; // detected PCI
int *ssb_offset; // SSB offset in samples
int32_t *sss_metric; // SSS detection metric
int *freq_offset_pss; // PSS frequency offset estimate
int *freq_offset_sss; // SSS frequency offset estimate
uint8_t *sss_phase; // SSS phase
int *pss_peak; // PSS correlation peak power
int *pss_avg; // PSS correlation average power
} nr_ssb_search_params_t;
typedef struct nr_phy_data_tx_s {