Merge remote-tracking branch 'origin/better-C-style-pss-sss' into integration_2026_w12 (!3724)
Better c style pss sss there is a commit to simplify code for pss and sss detection then a second commit to test a idea: detect SSS with a advantage for SSS in phase with PSS
This commit is contained in:
@@ -61,38 +61,9 @@
|
|||||||
|
|
||||||
#define SSS_METRIC_FLOOR_NR (30000)
|
#define SSS_METRIC_FLOOR_NR (30000)
|
||||||
|
|
||||||
/************** VARIABLES *****************************************/
|
|
||||||
|
|
||||||
#define PHASE_HYPOTHESIS_NUMBER (16)
|
|
||||||
#define INDEX_NO_PHASE_DIFFERENCE (3) /* this is for no phase shift case */
|
|
||||||
|
|
||||||
/************** FUNCTION ******************************************/
|
|
||||||
|
|
||||||
static const c16_t phase_nr[PHASE_HYPOTHESIS_NUMBER] = {
|
|
||||||
// {pi/3 ---- pi/3, -pi/3 ---- pi/3}
|
|
||||||
{16384, -28377},
|
|
||||||
{20173, -25821},
|
|
||||||
{23571, -22762},
|
|
||||||
{26509, -19260},
|
|
||||||
{28932, -15383},
|
|
||||||
{30791, -11207},
|
|
||||||
{32051, -6813},
|
|
||||||
{32687, -2286},
|
|
||||||
{32687, 2286},
|
|
||||||
{32051, 6813},
|
|
||||||
{30791, 11207},
|
|
||||||
{28932, 15383},
|
|
||||||
{26509, 19260},
|
|
||||||
{23571, 22762},
|
|
||||||
{20173, 25821},
|
|
||||||
{16384, 28377}};
|
|
||||||
|
|
||||||
void init_context_sss_nr(int amp);
|
void init_context_sss_nr(int amp);
|
||||||
void free_context_sss_nr(void);
|
void free_context_sss_nr(void);
|
||||||
|
|
||||||
void insert_sss_nr(int16_t *sss_time,
|
|
||||||
NR_DL_FRAME_PARMS *frame_parms);
|
|
||||||
|
|
||||||
bool rx_sss_nr(const NR_DL_FRAME_PARMS *frame_parms,
|
bool rx_sss_nr(const NR_DL_FRAME_PARMS *frame_parms,
|
||||||
int nid2,
|
int nid2,
|
||||||
int target_Nid_cell,
|
int target_Nid_cell,
|
||||||
|
|||||||
@@ -23,11 +23,7 @@
|
|||||||
|
|
||||||
//#define NR_SSS_DEBUG
|
//#define NR_SSS_DEBUG
|
||||||
|
|
||||||
int nr_generate_sss( c16_t *txdataF,
|
int nr_generate_sss(c16_t *txdataF, int16_t amp, uint8_t ssb_start_symbol, int Nid, NR_DL_FRAME_PARMS *frame_parms)
|
||||||
int16_t amp,
|
|
||||||
uint8_t ssb_start_symbol,
|
|
||||||
nfapi_nr_config_request_scf_t* config,
|
|
||||||
NR_DL_FRAME_PARMS *frame_parms)
|
|
||||||
{
|
{
|
||||||
int16_t x0[NR_SSS_LENGTH];
|
int16_t x0[NR_SSS_LENGTH];
|
||||||
int16_t x1[NR_SSS_LENGTH];
|
int16_t x1[NR_SSS_LENGTH];
|
||||||
@@ -35,7 +31,6 @@ int nr_generate_sss( c16_t *txdataF,
|
|||||||
const int x1_initial[7] = { 1, 0, 0, 0, 0, 0, 0 };
|
const int x1_initial[7] = { 1, 0, 0, 0, 0, 0, 0 };
|
||||||
|
|
||||||
/// Sequence generation
|
/// Sequence generation
|
||||||
int Nid = config->cell_config.phy_cell_id.value;
|
|
||||||
int Nid2 = Nid % 3;
|
int Nid2 = Nid % 3;
|
||||||
int Nid1 = (Nid - Nid2)/3;
|
int Nid1 = (Nid - Nid2)/3;
|
||||||
|
|
||||||
@@ -59,13 +54,11 @@ int nr_generate_sss( c16_t *txdataF,
|
|||||||
/// Resource mapping
|
/// Resource mapping
|
||||||
|
|
||||||
// SSS occupies a predefined position (subcarriers 56-182, symbol 2) within the SSB block starting from
|
// SSS occupies a predefined position (subcarriers 56-182, symbol 2) within the SSB block starting from
|
||||||
int k = frame_parms->ssb_start_subcarrier + 56;
|
c16_t *tx = txdataF + (ssb_start_symbol + 2) * frame_parms->ofdm_symbol_size + frame_parms->ssb_start_subcarrier + 56;
|
||||||
int l = ssb_start_symbol + 2;
|
|
||||||
|
|
||||||
for (int i = 0; i < NR_SSS_LENGTH; i++) {
|
for (int i = 0; i < NR_SSS_LENGTH; i++) {
|
||||||
int16_t d_sss = (1 - 2*x0[(i + m0) % NR_SSS_LENGTH] ) * (1 - 2*x1[(i + m1) % NR_SSS_LENGTH] ) * 23170;
|
int16_t d_sss = (1 - 2*x0[(i + m0) % NR_SSS_LENGTH] ) * (1 - 2*x1[(i + m1) % NR_SSS_LENGTH] ) * 23170;
|
||||||
((int16_t*)txdataF)[2*(l*frame_parms->ofdm_symbol_size + k)] = (((int16_t)amp) * d_sss) >> 15;
|
*tx++ = (c16_t){.r = (amp * d_sss) >> 15};
|
||||||
k++;
|
|
||||||
}
|
}
|
||||||
#ifdef NR_SSS_DEBUG
|
#ifdef NR_SSS_DEBUG
|
||||||
// write_output("sss_0.m", "sss_0", (void*)txdataF[0][l*frame_parms->ofdm_symbol_size], frame_parms->ofdm_symbol_size, 1, 1);
|
// write_output("sss_0.m", "sss_0", (void*)txdataF[0][l*frame_parms->ofdm_symbol_size], frame_parms->ofdm_symbol_size, 1, 1);
|
||||||
|
|||||||
@@ -60,11 +60,7 @@ int nr_generate_pss(c16_t *txdataF,
|
|||||||
@param
|
@param
|
||||||
@returns 0 on success
|
@returns 0 on success
|
||||||
*/
|
*/
|
||||||
int nr_generate_sss(c16_t *txdataF,
|
int nr_generate_sss(c16_t *txdataF, int16_t amp, uint8_t ssb_start_symbol, int nid, NR_DL_FRAME_PARMS *frame_parms);
|
||||||
int16_t amp,
|
|
||||||
uint8_t ssb_start_symbol,
|
|
||||||
nfapi_nr_config_request_scf_t *config,
|
|
||||||
NR_DL_FRAME_PARMS *frame_parms);
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\fn void nr_generate_pbch_dmrs
|
\fn void nr_generate_pbch_dmrs
|
||||||
|
|||||||
@@ -161,7 +161,6 @@ static void sl_nr_extract_sss(PHY_VARS_NR_UE *ue,
|
|||||||
NR_DL_FRAME_PARMS *sl_fp = &ue->SL_UE_PHY_PARAMS.sl_frame_params;
|
NR_DL_FRAME_PARMS *sl_fp = &ue->SL_UE_PHY_PARAMS.sl_frame_params;
|
||||||
int16_t *d;
|
int16_t *d;
|
||||||
uint16_t Nid1 = 0;
|
uint16_t Nid1 = 0;
|
||||||
uint8_t phase;
|
|
||||||
c16_t *rxF_ext;
|
c16_t *rxF_ext;
|
||||||
|
|
||||||
for (int aarx = 0; aarx < sl_fp->nb_antennas_rx; aarx++) {
|
for (int aarx = 0; aarx < sl_fp->nb_antennas_rx; aarx++) {
|
||||||
@@ -260,15 +259,16 @@ static void sl_nr_extract_sss(PHY_VARS_NR_UE *ue,
|
|||||||
c16_t *sss = &sss_ext[0][0][0];
|
c16_t *sss = &sss_ext[0][0][0];
|
||||||
|
|
||||||
for (uint16_t id1 = 0; id1 < SL_NR_NUM_IDs_IN_SSS; id1++) { // all possible SSS Nid1 values
|
for (uint16_t id1 = 0; id1 < SL_NR_NUM_IDs_IN_SSS; id1++) { // all possible SSS Nid1 values
|
||||||
for (phase = 0; phase < PHASE_HYPOTHESIS_NUMBER; phase++) { // phase offset between PSS and SSS
|
for (int phase = -15; phase < 16; phase += 2) { // phase offset between PSS and SSS
|
||||||
|
|
||||||
int32_t metric = 0, metric_re = 0;
|
int32_t metric = 0, metric_re = 0;
|
||||||
|
const c64_t rot = (c64_t){round(cos(M_PI / 3 / 15 * (phase)) * 32767), round(sin(M_PI / 3 / 15 * (phase)) * 32767)};
|
||||||
d = (int16_t *)&ue->SL_UE_PHY_PARAMS.init_params.sl_sss_for_sync[Nid2 * SL_NR_NUM_IDs_IN_SSS + id1];
|
d = (int16_t *)&ue->SL_UE_PHY_PARAMS.init_params.sl_sss_for_sync[Nid2 * SL_NR_NUM_IDs_IN_SSS + id1];
|
||||||
|
|
||||||
// This is the inner product using one particular value of each unknown parameter
|
// This is the inner product using one particular value of each unknown parameter
|
||||||
for (int i = 0; i < SL_NR_SSS_SEQUENCE_LENGTH; i++) {
|
for (int i = 0; i < SL_NR_SSS_SEQUENCE_LENGTH; i++) {
|
||||||
metric_re += d[i] * (((int64_t)phase_nr[phase].r * sss[i].r - phase_nr[phase].i * sss[i].i) >> 15);
|
// metric is only real part because sss is a pure real signal (imaginary is 0)
|
||||||
|
metric_re += d[i] * ((rot.r * sss[i].r - rot.i * sss[i].i) >> 15);
|
||||||
}
|
}
|
||||||
|
|
||||||
metric = metric_re;
|
metric = metric_re;
|
||||||
|
|||||||
@@ -49,24 +49,12 @@
|
|||||||
|
|
||||||
//#define DBG_PSS_NR
|
//#define DBG_PSS_NR
|
||||||
static time_stats_t generic_time[TIME_LAST];
|
static time_stats_t generic_time[TIME_LAST];
|
||||||
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,
|
|
||||||
int search_start,
|
|
||||||
int search_length);
|
|
||||||
|
|
||||||
static int16_t primary_synchro_nr2[NUMBER_PSS_SEQUENCE][LENGTH_PSS_NR] = {0};
|
static int16_t d_pss[NUMBER_PSS_SEQUENCE][LENGTH_PSS_NR] = {0};
|
||||||
static c16_t primary_synchro[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)
|
int16_t *get_primary_synchro_nr2(const int nid2)
|
||||||
{
|
{
|
||||||
return primary_synchro_nr2[nid2];
|
return d_pss[nid2];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*******************************************************************
|
/*******************************************************************
|
||||||
@@ -86,12 +74,9 @@ int16_t *get_primary_synchro_nr2(const int nid2)
|
|||||||
void generate_pss_nr(NR_DL_FRAME_PARMS *fp, int N_ID_2)
|
void generate_pss_nr(NR_DL_FRAME_PARMS *fp, int N_ID_2)
|
||||||
{
|
{
|
||||||
AssertFatal(fp->ofdm_symbol_size > 127,"Illegal ofdm_symbol_size %d\n",fp->ofdm_symbol_size);
|
AssertFatal(fp->ofdm_symbol_size > 127,"Illegal ofdm_symbol_size %d\n",fp->ofdm_symbol_size);
|
||||||
AssertFatal(N_ID_2>=0 && N_ID_2 <=2,"Illegal N_ID_2 %d\n",N_ID_2);
|
AssertFatal(N_ID_2 >= 0 && N_ID_2 <= 2, "Illegal N_ID_2 %d\n", N_ID_2);
|
||||||
int16_t d_pss[LENGTH_PSS_NR];
|
|
||||||
int16_t x[LENGTH_PSS_NR];
|
int16_t x[LENGTH_PSS_NR];
|
||||||
|
|
||||||
int16_t *primary_synchro2 = primary_synchro_nr2[N_ID_2]; /* pss in complex with alternatively i then q */
|
|
||||||
|
|
||||||
#define INITIAL_PSS_NR (7)
|
#define INITIAL_PSS_NR (7)
|
||||||
const int16_t x_initial[INITIAL_PSS_NR] = {0, 1, 1, 0, 1, 1, 1};
|
const int16_t x_initial[INITIAL_PSS_NR] = {0, 1, 1, 0, 1, 1, 1};
|
||||||
assert(N_ID_2 < NUMBER_PSS_SEQUENCE);
|
assert(N_ID_2 < NUMBER_PSS_SEQUENCE);
|
||||||
@@ -99,16 +84,15 @@ void generate_pss_nr(NR_DL_FRAME_PARMS *fp, int N_ID_2)
|
|||||||
|
|
||||||
for (int i = 0; i < (LENGTH_PSS_NR - INITIAL_PSS_NR); i++)
|
for (int i = 0; i < (LENGTH_PSS_NR - INITIAL_PSS_NR); i++)
|
||||||
x[i + INITIAL_PSS_NR] = (x[i + 4] + x[i]) % (2);
|
x[i + INITIAL_PSS_NR] = (x[i + 4] + x[i]) % (2);
|
||||||
|
int16_t *pss = d_pss[N_ID_2];
|
||||||
for (int n=0; n < LENGTH_PSS_NR; n++) {
|
for (int n=0; n < LENGTH_PSS_NR; n++) {
|
||||||
const int m = (n + 43 * N_ID_2) % (LENGTH_PSS_NR);
|
const int m = (n + 43 * N_ID_2) % (LENGTH_PSS_NR);
|
||||||
d_pss[n] = 1 - 2*x[m];
|
pss[n] = 1 - 2 * x[m];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* PSS is directly mapped to subcarrier without modulation 38.211 */
|
/* PSS is directly mapped to subcarrier without modulation 38.211 */
|
||||||
for (int i=0; i < LENGTH_PSS_NR; i++) {
|
for (int i=0; i < LENGTH_PSS_NR; i++) {
|
||||||
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_synchro[N_ID_2][i].r = (pss[i] * SHRT_MAX) >> SCALING_PSS_NR; /* Maximum value for type short int ie int16_t */
|
||||||
primary_synchro2[i] = d_pss[i];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DBG_PSS_NR
|
#ifdef DBG_PSS_NR
|
||||||
@@ -150,12 +134,13 @@ void generate_pss_nr(NR_DL_FRAME_PARMS *fp, int N_ID_2)
|
|||||||
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(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 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 + 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)));
|
c16_t synchroF_tmp[fp->ofdm_symbol_size] __attribute__((aligned(32)));
|
||||||
memset(synchroF_tmp, 0, sizeof(synchroF_tmp));
|
memset(synchroF_tmp, 0, sizeof(synchroF_tmp));
|
||||||
|
unsigned int k = fp->first_carrier_offset + ssbFirstSCS + subcarrier_start;
|
||||||
for (int i=0; i < LENGTH_PSS_NR; i++) {
|
for (int i=0; i < LENGTH_PSS_NR; i++) {
|
||||||
synchroF_tmp[k % fp->ofdm_symbol_size] = primary_synchro[N_ID_2][i];
|
if (k >= fp->ofdm_symbol_size)
|
||||||
|
k -= fp->ofdm_symbol_size;
|
||||||
|
synchroF_tmp[k] = primary_synchro[N_ID_2][i];
|
||||||
k++;
|
k++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,54 +167,6 @@ void generate_pss_nr_time(const NR_DL_FRAME_PARMS *fp, const int N_ID_2, int ssb
|
|||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
|
|
||||||
/* it allows checking that process of idft on a signal and then dft gives same signal with limited errors */
|
|
||||||
|
|
||||||
if ((N_ID_2 == 0) && (length == 256)) {
|
|
||||||
|
|
||||||
LOG_M("pss_f00.m","pss_f00",synchro_tmp,length,1,1);
|
|
||||||
|
|
||||||
|
|
||||||
bzero(synchroF_tmp, size);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* get pss in the time domain by applying an inverse FFT */
|
|
||||||
dft((int16_t)get_dft(length),
|
|
||||||
synchro_tmp, /* complex input */
|
|
||||||
synchroF_tmp, /* complex output */
|
|
||||||
1); /* scaling factor */
|
|
||||||
|
|
||||||
if ((N_ID_2 == 0) && (length == 256)) {
|
|
||||||
LOG_M("pss_f_0.m","pss_f_0",synchroF_tmp,length,1,1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* check Pss */
|
|
||||||
k = length - (LENGTH_PSS_NR/2);
|
|
||||||
|
|
||||||
#define LIMIT_ERROR_FFT (10)
|
|
||||||
|
|
||||||
for (int i=0; i < LENGTH_PSS_NR; i++) {
|
|
||||||
if (abs(synchroF_tmp[2*k] - primary_synchro[i].r) > LIMIT_ERROR_FFT) {
|
|
||||||
printf("Pss Error[%d] Compute %d Reference %d \n", k, synchroF_tmp[2*k], primary_synchro[i].r);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (abs(synchroF_tmp[2*k+1] - primary_synchro[i].i) > LIMIT_ERROR_FFT) {
|
|
||||||
printf("Pss Error[%d] Compute %d Reference %d\n", (2*k+1), synchroF_tmp[2*k+1], primary_synchro[i].i);
|
|
||||||
}
|
|
||||||
|
|
||||||
k++;
|
|
||||||
|
|
||||||
if (k >= length) {
|
|
||||||
k-=length;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*******************************************************************
|
/*******************************************************************
|
||||||
@@ -391,50 +328,32 @@ int pss_synchro_nr(const c16_t **rxdata,
|
|||||||
int *pssAvg)
|
int *pssAvg)
|
||||||
{
|
{
|
||||||
#ifdef DBG_PSS_NR
|
#ifdef DBG_PSS_NR
|
||||||
|
LOG_M("rxdata0_rand.m", "rxd0_rand", &PHY_vars_UE->common_vars.rxdata[0][0], frame_parms->samples_per_frame, 1, 1);
|
||||||
LOG_M("rxdata0_rand.m","rxd0_rand", &PHY_vars_UE->common_vars.rxdata[0][0], frame_parms->samples_per_frame, 1, 1);
|
LOG_M("rxdata0_des.m", "rxd0_des", &rxdata[0][0], frame_parms->samples_per_frame, 1, 1);
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef DBG_PSS_NR
|
|
||||||
|
|
||||||
LOG_M("rxdata0_des.m","rxd0_des", &rxdata[0][0], frame_parms->samples_per_frame,1,1);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
start_meas(&generic_time[TIME_PSS]);
|
start_meas(&generic_time[TIME_PSS]);
|
||||||
|
|
||||||
int synchro_position =
|
int synchro_position =
|
||||||
pss_search_time_nr(rxdata, frame_parms, pssTime, fo_flag, is, target_Nid_cell, nid2, f_off, pssPeak, pssAvg, -1, -1);
|
pss_search_time_nr(rxdata, frame_parms, pssTime, fo_flag, is, target_Nid_cell, nid2, f_off, pssPeak, pssAvg, -1, -1);
|
||||||
|
stop_meas(&generic_time[TIME_PSS]);
|
||||||
|
|
||||||
#if TEST_SYNCHRO_TIMING_PSS
|
#if TEST_SYNCHRO_TIMING_PSS
|
||||||
|
|
||||||
stop_meas(&generic_time[TIME_PSS]);
|
int duration_ms = generic_time[TIME_PSS].p_time / (cpuf * 1000.0);
|
||||||
|
#ifndef NR_UNIT_TEST
|
||||||
int duration_ms = generic_time[TIME_PSS].p_time/(cpuf*1000.0);
|
LOG_D(PHY, "PSS execution duration %4d microseconds \n", duration_ms);
|
||||||
|
#endif
|
||||||
#ifndef NR_UNIT_TEST
|
|
||||||
|
|
||||||
LOG_D(PHY,"PSS execution duration %4d microseconds \n", duration_ms);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef SYNCHRO_DECIMAT
|
#ifdef SYNCHRO_DECIMAT
|
||||||
|
|
||||||
if (rate_change != 1) {
|
if (rate_change != 1) {
|
||||||
|
|
||||||
if (rxdata[0] != NULL) {
|
if (rxdata[0] != NULL) {
|
||||||
|
|
||||||
for (int aa=0;aa<frame_parms->nb_antennas_rx;aa++) {
|
for (int aa=0;aa<frame_parms->nb_antennas_rx;aa++) {
|
||||||
free(rxdata[aa]);
|
free(rxdata[aa]);
|
||||||
}
|
}
|
||||||
|
|
||||||
free(rxdata);
|
free(rxdata);
|
||||||
}
|
}
|
||||||
|
restore_frame_context_pss_nr(frame_parms, rate_change);
|
||||||
restore_frame_context_pss_nr(frame_parms, rate_change);
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -504,11 +423,6 @@ int pss_search_time_nr(const c16_t **rxdata,
|
|||||||
int search_start,
|
int search_start,
|
||||||
int search_length)
|
int search_length)
|
||||||
{
|
{
|
||||||
unsigned int n, ar, peak_position, pss_source;
|
|
||||||
int64_t peak_value;
|
|
||||||
int64_t avg[NUMBER_PSS_SEQUENCE] = {0};
|
|
||||||
double ffo_est = 0;
|
|
||||||
|
|
||||||
// Determine search window
|
// Determine search window
|
||||||
unsigned int start, length;
|
unsigned int start, length;
|
||||||
if (search_start >= 0 && search_length > 0) {
|
if (search_start >= 0 && search_length > 0) {
|
||||||
@@ -524,11 +438,7 @@ int pss_search_time_nr(const c16_t **rxdata,
|
|||||||
length = frame_parms->samples_per_frame;
|
length = frame_parms->samples_per_frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
AssertFatal(length>0,"illegal length %d\n",length);
|
AssertFatal(length > 0, "illegal length %d\n", length);
|
||||||
peak_value = 0;
|
|
||||||
peak_position = 0;
|
|
||||||
pss_source = 0;
|
|
||||||
|
|
||||||
int maxval=0;
|
int maxval=0;
|
||||||
int max_size = get_softmodem_params()->sl_mode == 0 ? NUMBER_PSS_SEQUENCE : NUMBER_PSS_SEQUENCE_SL;
|
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 j = 0; j < max_size; j++)
|
||||||
@@ -542,53 +452,55 @@ int pss_search_time_nr(const c16_t **rxdata,
|
|||||||
/* This is required by SIMD (single instruction Multiple Data) Extensions of Intel processors. */
|
/* This is required by SIMD (single instruction Multiple Data) Extensions of Intel processors. */
|
||||||
/* Correlation computation is based on a a dot product which is realized thank to SIMS extensions */
|
/* Correlation computation is based on a a dot product which is realized thank to SIMS extensions */
|
||||||
|
|
||||||
uint16_t pss_index_start = 0;
|
int pss_index_start;
|
||||||
uint16_t pss_index_end = get_softmodem_params()->sl_mode == 0 ? NUMBER_PSS_SEQUENCE : NUMBER_PSS_SEQUENCE_SL;
|
int pss_index_end;
|
||||||
if (target_Nid_cell != -1) {
|
if (target_Nid_cell != -1) {
|
||||||
pss_index_start = GET_NID2(target_Nid_cell);
|
pss_index_start = GET_NID2(target_Nid_cell);
|
||||||
pss_index_end = pss_index_start + 1;
|
pss_index_end = pss_index_start + 1;
|
||||||
|
} else {
|
||||||
|
pss_index_start = 0;
|
||||||
|
pss_index_end = max_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int64_t avg[NUMBER_PSS_SEQUENCE] = {0};
|
||||||
|
int64_t peak_value = 0;
|
||||||
|
unsigned int peak_position = 0;
|
||||||
|
unsigned int pss_source = 0;
|
||||||
for (int pss_index = pss_index_start; pss_index < pss_index_end; pss_index++) {
|
for (int pss_index = pss_index_start; pss_index < pss_index_end; pss_index++) {
|
||||||
for (n = start; n < start + length; n += 4) { //
|
for (int n = start; n < start + length; n += 4) { //
|
||||||
|
int64_t pss_corr_ue = 0;
|
||||||
int64_t pss_corr_ue=0;
|
|
||||||
/* calculate dot product of primary_synchro_time_nr and rxdata[ar][n]
|
/* calculate dot product of primary_synchro_time_nr and rxdata[ar][n]
|
||||||
* (ar=0..nb_ant_rx) and store the sum in temp[n]; */
|
* (ar=0..nb_ant_rx) and store the sum in temp[n]; */
|
||||||
for (ar=0; ar<frame_parms->nb_antennas_rx; ar++) {
|
for (int ar = 0; ar < frame_parms->nb_antennas_rx; ar++) {
|
||||||
|
|
||||||
/* perform correlation of rx data and pss sequence ie it is a dot product */
|
/* perform correlation of rx data and pss sequence ie it is a dot product */
|
||||||
const c32_t result = dot_product(pssTime[pss_index],
|
const c32_t result = dot_product(pssTime[pss_index],
|
||||||
&(rxdata[ar][n + is * frame_parms->samples_per_frame]),
|
&rxdata[ar][n + is * frame_parms->samples_per_frame],
|
||||||
frame_parms->ofdm_symbol_size,
|
frame_parms->ofdm_symbol_size,
|
||||||
shift);
|
shift);
|
||||||
const c64_t r64 = {.r = result.r, .i = result.i};
|
const c64_t r64 = {.r = result.r, .i = result.i};
|
||||||
pss_corr_ue += squaredMod(r64);
|
pss_corr_ue += squaredMod(r64);
|
||||||
//((short*)pss_corr_ue[pss_index])[2*n] += ((short*) &result)[0]; /* real part */
|
|
||||||
//((short*)pss_corr_ue[pss_index])[2*n+1] += ((short*) &result)[1]; /* imaginary part */
|
|
||||||
//((short*)&synchro_out)[0] += ((int*) &result)[0]; /* real part */
|
|
||||||
//((short*)&synchro_out)[1] += ((int*) &result)[1]; /* imaginary part */
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* calculate the absolute value of sync_corr[n] */
|
/* calculate the absolute value of sync_corr[n] */
|
||||||
avg[pss_index]+=pss_corr_ue;
|
avg[pss_index] += pss_corr_ue;
|
||||||
if (pss_corr_ue > peak_value) {
|
if (pss_corr_ue > peak_value) {
|
||||||
peak_value = pss_corr_ue;
|
peak_value = pss_corr_ue;
|
||||||
peak_position = n;
|
peak_position = n;
|
||||||
pss_source = pss_index;
|
pss_source = pss_index;
|
||||||
|
|
||||||
#ifdef DEBUG_PSS_NR
|
#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 %15llu\n", pss_index, n, (unsigned long long)pss_corr_ue[n]);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
avg[pss_index] /= (length / 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fo_flag){
|
|
||||||
|
|
||||||
// fractional frequency offset computation according to Cross-correlation Synchronization Algorithm Using PSS
|
double ffo_est = 0;
|
||||||
// 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.
|
if (fo_flag) {
|
||||||
|
// fractional frequency offset computation according to Cross-correlation Synchronization Algorithm Using PSS
|
||||||
|
// 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
|
// Computing cross-correlation at peak on half the symbol size for first half of data
|
||||||
c32_t r1 = dot_product(pssTime[pss_source],
|
c32_t r1 = dot_product(pssTime[pss_source],
|
||||||
@@ -606,15 +518,11 @@ int pss_search_time_nr(const c16_t **rxdata,
|
|||||||
ffo_est = atan2(r1d.r * r2d.i - r2d.r * r1d.i, r1d.r * r2d.r + r1d.i * r2d.i) / M_PI;
|
ffo_est = atan2(r1d.r * r2d.i - r2d.r * r1d.i, r1d.r * r2d.r + r1d.i * r2d.i) / M_PI;
|
||||||
|
|
||||||
#ifdef DBG_PSS_NR
|
#ifdef DBG_PSS_NR
|
||||||
printf("ffo %lf\n",ffo_est);
|
printf("ffo %lf\n", ffo_est);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// computing absolute value of frequency offset
|
// computing absolute value of frequency offset
|
||||||
*f_off = ffo_est*frame_parms->subcarrier_spacing;
|
*f_off = ffo_est * frame_parms->subcarrier_spacing;
|
||||||
|
|
||||||
for (int pss_index = pss_index_start; pss_index < pss_index_end; pss_index++)
|
|
||||||
avg[pss_index] /= (length / 4);
|
|
||||||
|
|
||||||
*nid2 = pss_source;
|
*nid2 = pss_source;
|
||||||
*pssPeak = dB_fixed64(peak_value);
|
*pssPeak = dB_fixed64(peak_value);
|
||||||
@@ -631,22 +539,18 @@ int pss_search_time_nr(const c16_t **rxdata,
|
|||||||
ffo_est);
|
ffo_est);
|
||||||
|
|
||||||
if ((search_start < 0 || search_length == 0) && peak_value < 5 * avg[pss_source])
|
if ((search_start < 0 || search_length == 0) && peak_value < 5 * avg[pss_source])
|
||||||
return(-1);
|
return (-1);
|
||||||
|
|
||||||
|
|
||||||
#ifdef DBG_PSS_NR
|
#ifdef DBG_PSS_NR
|
||||||
|
|
||||||
static int debug_cnt = 0;
|
static int debug_cnt = 0;
|
||||||
|
|
||||||
if (debug_cnt == 0) {
|
if (debug_cnt == 0) {
|
||||||
if (is)
|
if (is)
|
||||||
LOG_M("rxdata1.m","rxd0",rxdata[frame_parms->samples_per_frame],length,1,1);
|
LOG_M("rxdata1.m", "rxd0", rxdata[frame_parms->samples_per_frame], length, 1, 1);
|
||||||
else
|
else
|
||||||
LOG_M("rxdata0.m","rxd0",rxdata[0],length,1,1);
|
LOG_M("rxdata0.m", "rxd0", rxdata[0], length, 1, 1);
|
||||||
} else {
|
} else {
|
||||||
debug_cnt++;
|
debug_cnt++;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return peak_position;
|
return peak_position;
|
||||||
|
|||||||
@@ -109,71 +109,8 @@ void init_context_sss_nr(int amp)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/*******************************************************************
|
// #define DEBUG_SSS_NR
|
||||||
*
|
// #define DEBUG_PLOT_SSS
|
||||||
* NAME : insert_sss_nr
|
|
||||||
*
|
|
||||||
* PARAMETERS : pointer to input buffer for which sss in inserted
|
|
||||||
* amp amplitude applied to input
|
|
||||||
* frame parameters for cell identity
|
|
||||||
*
|
|
||||||
* RETURN : none
|
|
||||||
*
|
|
||||||
* DESCRIPTION : Allow to generate a reference sss sequence according to cell identity
|
|
||||||
*
|
|
||||||
*********************************************************************/
|
|
||||||
|
|
||||||
//#define DEBUG_SSS_NR
|
|
||||||
//#define DEBUG_PLOT_SSS
|
|
||||||
void insert_sss_nr(int16_t *sss_time,
|
|
||||||
NR_DL_FRAME_PARMS *frame_parms)
|
|
||||||
{
|
|
||||||
const unsigned int ofdm_symbol_size = frame_parms->ofdm_symbol_size;
|
|
||||||
int Nid2 = GET_NID2(frame_parms->Nid_cell);
|
|
||||||
int Nid1 = GET_NID1(frame_parms->Nid_cell);
|
|
||||||
|
|
||||||
/* call of IDFT should be done with ordered input as below
|
|
||||||
*
|
|
||||||
* n input samples
|
|
||||||
* <------------------------------------------------>
|
|
||||||
* 0 n
|
|
||||||
* are written into input buffer for IFFT in this order
|
|
||||||
* -------------------------------------------------
|
|
||||||
* |xxxxxxx N/2 xxxxxxxx|
|
|
||||||
* --------------------------------------------------
|
|
||||||
* ^ ^ ^ ^ ^
|
|
||||||
* | | | | |
|
|
||||||
* n/2 end of n=0 start of n/2-1
|
|
||||||
* sss sss
|
|
||||||
*
|
|
||||||
* Frequencies
|
|
||||||
* positives negatives
|
|
||||||
* 0 (+N/2)(-N/2)
|
|
||||||
* |-----------------------><-------------------------|
|
|
||||||
*
|
|
||||||
* sample 0 is for continuous frequency which is not used here
|
|
||||||
*/
|
|
||||||
|
|
||||||
unsigned int k = ofdm_symbol_size - ((LENGTH_SSS_NR/2)+1);
|
|
||||||
c16_t synchroF_tmp[2048] __attribute__((aligned(32)));
|
|
||||||
c16_t synchro_tmp[2048] __attribute__((aligned(32)));
|
|
||||||
bzero(synchroF_tmp, sizeof(synchroF_tmp));
|
|
||||||
|
|
||||||
/* SSS is directly mapped to subcarrier */
|
|
||||||
for (int i=0; i<LENGTH_SSS_NR; i++) {
|
|
||||||
synchroF_tmp[k % ofdm_symbol_size].r = d_sss[Nid2][Nid1][i];
|
|
||||||
k++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* get sss in the frequency domain by applying an inverse FFT */
|
|
||||||
idft(IDFT_2048,
|
|
||||||
(int16_t *)synchroF_tmp, /* complex input */
|
|
||||||
(int16_t *)synchro_tmp, /* complex output */
|
|
||||||
1); /* scaling factor */
|
|
||||||
|
|
||||||
/* then get final sss in time */
|
|
||||||
memcpy(sss_time, synchro_tmp, ofdm_symbol_size * sizeof(c16_t));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*******************************************************************
|
/*******************************************************************
|
||||||
*
|
*
|
||||||
@@ -187,7 +124,7 @@ void insert_sss_nr(int16_t *sss_time,
|
|||||||
*
|
*
|
||||||
*********************************************************************/
|
*********************************************************************/
|
||||||
|
|
||||||
static int pss_ch_est_nr(const NR_DL_FRAME_PARMS *frame_parms,
|
static void pss_ch_est_nr(const NR_DL_FRAME_PARMS *frame_parms,
|
||||||
int nid2,
|
int nid2,
|
||||||
c16_t pss_ext[frame_parms->nb_antennas_rx][LENGTH_PSS_NR],
|
c16_t pss_ext[frame_parms->nb_antennas_rx][LENGTH_PSS_NR],
|
||||||
c16_t sss_ext[frame_parms->nb_antennas_rx][LENGTH_SSS_NR])
|
c16_t sss_ext[frame_parms->nb_antennas_rx][LENGTH_SSS_NR])
|
||||||
@@ -199,148 +136,60 @@ static int pss_ch_est_nr(const NR_DL_FRAME_PARMS *frame_parms,
|
|||||||
c16_t *pss_ext2 = pss_ext[aarx];
|
c16_t *pss_ext2 = pss_ext[aarx];
|
||||||
for (int i = 0; i < LENGTH_PSS_NR; i++) {
|
for (int i = 0; i < LENGTH_PSS_NR; i++) {
|
||||||
// This is H*(PSS) = R* \cdot PSS
|
// This is H*(PSS) = R* \cdot PSS
|
||||||
const int tmp_re = pss_ext2[i].r * pss[i];
|
const c16_t tmp = (c16_t){pss_ext2[i].r * pss[i], -pss_ext2[i].i * pss[i]};
|
||||||
const int tmp_im = -pss_ext2[i].i * pss[i];
|
const int32_t amp = squaredMod(tmp);
|
||||||
|
|
||||||
const int32_t amp = tmp_re * tmp_re + tmp_im * tmp_im;
|
|
||||||
const int shift = log2_approx(amp) / 2;
|
const int shift = log2_approx(amp) / 2;
|
||||||
// This is R(SSS) \cdot H*(PSS)
|
// This is R(SSS) \cdot H*(PSS)
|
||||||
const c16_t tmp = {(tmp_re * sss_ext2[i].r - tmp_im * sss_ext2[i].i) >> shift,
|
const c16_t new_sss = c16mulShift(tmp, sss_ext2[i], shift);
|
||||||
(tmp_re * sss_ext2[i].i + tmp_im * sss_ext2[i].r) >> shift};
|
if (aarx == 0)
|
||||||
// printf("SSSi(%d,%d) : (%d,%d)\n",aarx,i,sss_ext2[i<<1],sss_ext2[1+(i<<1)]);
|
sss_ext2[i] = new_sss;
|
||||||
// printf("SSSo(%d,%d) : (%d,%d)\n",aarx,i,tmp_re2,tmp_im2);
|
else
|
||||||
// MRC on RX antennas
|
sss_ext2[i] = c16add(sss_ext2[i], new_sss);
|
||||||
if (aarx == 0) {
|
|
||||||
sss_ext2[i].r = tmp.r;
|
|
||||||
sss_ext2[i].i = tmp.i;
|
|
||||||
} else {
|
|
||||||
sss_ext2[i].r += tmp.r;
|
|
||||||
sss_ext2[i].i += tmp.i;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#if 0
|
// sss_ext[0] now contains the compensated SSS
|
||||||
LOG_M("pssrx.m","pssrx",pss,LENGTH_PSS_NR,1,1);
|
|
||||||
LOG_M("pss_ext.m","pssext",pss_ext2,LENGTH_PSS_NR,1,1);
|
|
||||||
LOG_M("psschest.m","pssch",chest,LENGTH_PSS_NR,1,1);
|
|
||||||
#endif
|
|
||||||
#if 0
|
|
||||||
|
|
||||||
for (int i = 0; i < LENGTH_PSS_NR; i++) {
|
|
||||||
printf(" sss ext 2 [%d] %d %d at address %p\n", i, sss_ext2[2*i], sss_ext2[2*i+1]);
|
|
||||||
printf(" sss ref [%d] %d %d at address %p\n", i, d_sss[0][0][i], d_sss[0][0][i]);
|
|
||||||
printf(" sss ext 3 [%d] %d %d at address %p\n", i, sss_ext3[2*i], sss_ext3[2*i+1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// sss_ext now contains the compensated SSS
|
|
||||||
return(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*******************************************************************
|
/*******************************************************************
|
||||||
*
|
*
|
||||||
* NAME : do_pss_sss_extract
|
* NAME : pss_sss_extract_nr
|
||||||
*
|
*
|
||||||
* PARAMETERS : none
|
* PARAMETERS : none
|
||||||
*
|
*
|
||||||
* RETURN : none
|
* RETURN : none
|
||||||
*
|
*
|
||||||
* DESCRIPTION : it allows extracting sss from samples buffer
|
* DESCRIPTION : it allows extracting sss from samples buffer
|
||||||
*
|
*
|
||||||
*********************************************************************/
|
*********************************************************************/
|
||||||
|
|
||||||
static int do_pss_sss_extract_nr(const NR_DL_FRAME_PARMS *frame_parms,
|
static void pss_sss_extract_nr(const NR_DL_FRAME_PARMS *frame_parms,
|
||||||
c16_t pss_ext[frame_parms->nb_antennas_rx][LENGTH_PSS_NR],
|
c16_t pss_ext[frame_parms->nb_antennas_rx][LENGTH_PSS_NR],
|
||||||
c16_t sss_ext[frame_parms->nb_antennas_rx][LENGTH_SSS_NR],
|
c16_t sss_ext[frame_parms->nb_antennas_rx][LENGTH_SSS_NR],
|
||||||
uint8_t doPss,
|
|
||||||
uint8_t doSss,
|
|
||||||
int ssb_start_subcarrier,
|
int ssb_start_subcarrier,
|
||||||
c16_t rxdataF[][frame_parms->samples_per_slot_wCP]) // add flag to indicate extracting only PSS, only SSS, or both
|
c16_t rxdataF[][frame_parms->samples_per_slot_wCP]) // add flag to indicate extracting only PSS, only SSS, or both
|
||||||
{
|
{
|
||||||
AssertFatal(frame_parms->nb_antennas_rx > 0, "UB as sss_ext is not set to any value\n");
|
AssertFatal(frame_parms->nb_antennas_rx > 0, "nb antennas as sss_ext is not set to any value\n");
|
||||||
|
const unsigned int ofdm_symbol_size = frame_parms->ofdm_symbol_size;
|
||||||
|
const int pss_symbol = 0;
|
||||||
|
const int sss_symbol =
|
||||||
|
get_softmodem_params()->sl_mode == 0 ? (SSS_SYMBOL_NB - PSS_SYMBOL_NB) : (SSS0_SL_SYMBOL_NB - PSS0_SL_SYMBOL_NB);
|
||||||
|
|
||||||
for (int aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++) {
|
for (int aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++) {
|
||||||
int pss_symbol = 0;
|
|
||||||
int sss_symbol = get_softmodem_params()->sl_mode == 0 ?
|
|
||||||
(SSS_SYMBOL_NB - PSS_SYMBOL_NB) :
|
|
||||||
(SSS0_SL_SYMBOL_NB - PSS0_SL_SYMBOL_NB) ;
|
|
||||||
unsigned int ofdm_symbol_size = frame_parms->ofdm_symbol_size;
|
|
||||||
|
|
||||||
c16_t *pss_rxF = rxdataF[aarx] + pss_symbol * ofdm_symbol_size;
|
c16_t *pss_rxF = rxdataF[aarx] + pss_symbol * ofdm_symbol_size;
|
||||||
c16_t *sss_rxF = rxdataF[aarx] + sss_symbol * ofdm_symbol_size;
|
c16_t *sss_rxF = rxdataF[aarx] + sss_symbol * ofdm_symbol_size;
|
||||||
|
|
||||||
c16_t *pss_rxF_ext = pss_ext[aarx];
|
c16_t *pss_rxF_ext = pss_ext[aarx];
|
||||||
c16_t *sss_rxF_ext = sss_ext[aarx];
|
c16_t *sss_rxF_ext = sss_ext[aarx];
|
||||||
|
|
||||||
unsigned int k = frame_parms->first_carrier_offset + ssb_start_subcarrier
|
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);
|
+ ((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;
|
|
||||||
|
|
||||||
for (int i=0; i < LENGTH_PSS_NR; i++) {
|
for (int i=0; i < LENGTH_PSS_NR; i++) {
|
||||||
if (doPss) {
|
if (k >= frame_parms->ofdm_symbol_size)
|
||||||
pss_rxF_ext[i] = pss_rxF[k];
|
k -= frame_parms->ofdm_symbol_size;
|
||||||
}
|
pss_rxF_ext[i] = pss_rxF[k];
|
||||||
|
sss_rxF_ext[i] = sss_rxF[k];
|
||||||
if (doSss) {
|
|
||||||
sss_rxF_ext[i] = sss_rxF[k];
|
|
||||||
}
|
|
||||||
|
|
||||||
k++;
|
k++;
|
||||||
if (k == frame_parms->ofdm_symbol_size) k = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
|
||||||
|
|
||||||
int16_t *p = (int16_t *)sss_rxF_ext;
|
|
||||||
|
|
||||||
for (int i = 0; i < LENGTH_PSS_NR; i++) {
|
|
||||||
printf(" sss ext 2 [%d] %d %d at address %p\n", i, p[2*i], p[2*i+1], &p[2*i]);
|
|
||||||
printf(" sss ref [%d] %d %d at address %p\n", i, d_sss[0][0][i], d_sss[0][0][i], &d_sss[0][0][i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
|
|
||||||
int16_t *p2 = (int16_t *)pss_rxF_ext;
|
|
||||||
|
|
||||||
for (int i = 0; i < LENGTH_PSS_NR; i++) {
|
|
||||||
printf(" pss_rxF_ext [%d] %d %d at address %p\n", i, p2[2*i], p2[2*i+1], &p2[2*i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*******************************************************************
|
|
||||||
*
|
|
||||||
* NAME : pss_sss_extract_nr
|
|
||||||
*
|
|
||||||
* PARAMETERS : none
|
|
||||||
*
|
|
||||||
* RETURN : none
|
|
||||||
*
|
|
||||||
* DESCRIPTION :
|
|
||||||
*
|
|
||||||
*********************************************************************/
|
|
||||||
|
|
||||||
static int pss_sss_extract_nr(const NR_DL_FRAME_PARMS *frame_parms,
|
|
||||||
c16_t pss_ext[frame_parms->nb_antennas_rx][LENGTH_PSS_NR],
|
|
||||||
c16_t sss_ext[frame_parms->nb_antennas_rx][LENGTH_SSS_NR],
|
|
||||||
int ssb_start_subcarrier,
|
|
||||||
c16_t rxdataF[][frame_parms->samples_per_slot_wCP])
|
|
||||||
{
|
|
||||||
return do_pss_sss_extract_nr(frame_parms,
|
|
||||||
pss_ext,
|
|
||||||
sss_ext,
|
|
||||||
1 /* doPss */,
|
|
||||||
1 /* doSss */,
|
|
||||||
ssb_start_subcarrier,
|
|
||||||
rxdataF);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*******************************************************************
|
/*******************************************************************
|
||||||
@@ -366,44 +215,22 @@ bool rx_sss_nr(const NR_DL_FRAME_PARMS *frame_parms,
|
|||||||
int *freq_offset_sss,
|
int *freq_offset_sss,
|
||||||
c16_t rxdataF[][frame_parms->samples_per_slot_wCP])
|
c16_t rxdataF[][frame_parms->samples_per_slot_wCP])
|
||||||
{
|
{
|
||||||
uint8_t i;
|
|
||||||
c16_t pss_ext[frame_parms->nb_antennas_rx][LENGTH_PSS_NR];
|
c16_t pss_ext[frame_parms->nb_antennas_rx][LENGTH_PSS_NR];
|
||||||
c16_t sss_ext[frame_parms->nb_antennas_rx][LENGTH_SSS_NR];
|
c16_t sss_ext[frame_parms->nb_antennas_rx][LENGTH_SSS_NR];
|
||||||
uint8_t Nid2 = GET_NID2(nid2);
|
const int Nid2 = GET_NID2(nid2);
|
||||||
uint16_t Nid1;
|
|
||||||
uint8_t phase;
|
|
||||||
int32_t metric, metric_re;
|
|
||||||
int16_t *d;
|
|
||||||
|
|
||||||
|
|
||||||
// pss sss extraction
|
// pss sss extraction
|
||||||
pss_sss_extract_nr(frame_parms, pss_ext, sss_ext, ssb_start_subcarrier, rxdataF); /* subframe */
|
pss_sss_extract_nr(frame_parms, pss_ext, sss_ext, ssb_start_subcarrier, rxdataF); /* subframe */
|
||||||
|
|
||||||
#ifdef DEBUG_PLOT_SSS
|
#ifdef DEBUG_PLOT_SSS
|
||||||
|
|
||||||
write_output("rxsig0.m","rxs0",&ue->common_vars.rxdata[0][0],ue->frame_parms.samples_per_subframe,1,1);
|
write_output("rxsig0.m","rxs0",&ue->common_vars.rxdata[0][0],ue->frame_parms.samples_per_subframe,1,1);
|
||||||
write_output("rxdataF0_pss.m","rxF0_pss",&ue->common_vars.rxdataF[0][0],frame_parms->ofdm_symbol_size,1,1);
|
write_output("rxdataF0_pss.m","rxF0_pss",&ue->common_vars.rxdataF[0][0],frame_parms->ofdm_symbol_size,1,1);
|
||||||
write_output("rxdataF0_sss.m","rxF0_sss",&ue->common_vars.rxdataF[0][(SSS_SYMBOL_NB-PSS_SYMBOL_NB)*frame_parms->ofdm_symbol_size],frame_parms->ofdm_symbol_size,1,1);
|
write_output("rxdataF0_sss.m","rxF0_sss",&ue->common_vars.rxdataF[0][(SSS_SYMBOL_NB-PSS_SYMBOL_NB)*frame_parms->ofdm_symbol_size],frame_parms->ofdm_symbol_size,1,1);
|
||||||
write_output("pss_ext.m","pss_ext",pss_ext,LENGTH_PSS_NR,1,1);
|
write_output("pss_ext.m", "pss_ext", pss_ext, LENGTH_PSS_NR, 1, 1);
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
int16_t *p = (int16_t *)sss_ext[0];
|
|
||||||
int16_t *p2 = (int16_t *)pss_ext[0];
|
|
||||||
|
|
||||||
for (int i = 0; i < LENGTH_SSS_NR; i++) {
|
|
||||||
printf("sss ref [%i] : %d %d \n", i, d_sss[0][0][i], d_sss[0][0][i]);
|
|
||||||
printf("sss ext [%i] : %d %d \n", i, p[2*i], p[2*i+1]);
|
|
||||||
|
|
||||||
printf("pss ref [%i] : %d %d \n", i, primary_synchro_nr2[0][2*i], primary_synchro_nr2[0][2*i+1]);
|
|
||||||
printf("pss ext [%i] : %d %d \n", i, p2[2*i], p2[2*i+1]);
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// get conjugated channel estimate from PSS, H* = R* \cdot PSS
|
// get conjugated channel estimate from PSS, H* = R* \cdot PSS
|
||||||
// and do channel estimation and compensation based on PSS
|
// and do channel estimation and compensation based on PSS
|
||||||
|
|
||||||
pss_ch_est_nr(frame_parms, nid2, 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
|
// now do the SSS detection based on the precomputed sequences in PHY/LTE_TRANSPORT/sss.h
|
||||||
@@ -411,91 +238,56 @@ bool rx_sss_nr(const NR_DL_FRAME_PARMS *frame_parms,
|
|||||||
|
|
||||||
c16_t *sss = sss_ext[0];
|
c16_t *sss = sss_ext[0];
|
||||||
|
|
||||||
#ifdef DEBUG_PLOT_SSS
|
|
||||||
|
|
||||||
write_output("sss_ext.m","sss_ext",sss_ext[0],LENGTH_SSS_NR,1,1);
|
|
||||||
write_output("sss_ref.m","sss_ref", d_sss,LENGTH_SSS_NR,1,1);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
|
|
||||||
/* simulate of a phase shift on the signal */
|
|
||||||
|
|
||||||
int phase_shift_index = 0;
|
|
||||||
|
|
||||||
phase_shift_samples(sss, LENGTH_SSS_NR, phase_re_nr[phase_shift_index], phase_im_nr[phase_shift_index]);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
int16_t *ps = (int16_t *)pss_ext;
|
|
||||||
|
|
||||||
for (int i = 0; i < LENGTH_SSS_NR; i++) {
|
|
||||||
printf("sss ref [%i] : %d \n", i, d_sss[0][0][i]);
|
|
||||||
printf("sss ext [%i] : %d %d \n", i, sss[i].r, sss[i].i);
|
|
||||||
|
|
||||||
printf("pss ref [%i] : %d %d \n", i, primary_synchro_nr2[0][2*i], primary_synchro_nr2[0][2*i+1]);
|
|
||||||
printf("pss ext [%i] : %d %d \n", i, ps[2*i], ps[2*i+1]);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* for phase evaluation, one uses an array of possible phase shifts */
|
/* for phase evaluation, one uses an array of possible phase shifts */
|
||||||
/* then a correlation is done between received signal with a shift pĥase and the reference signal */
|
/* then a correlation is done between received signal with a shift pĥase and the reference signal */
|
||||||
/* Computation of signal with shift phase is based on below formula */
|
/* Computation of signal with shift phase is based on below formula */
|
||||||
/* cosinus cos(x + y) = cos(x)cos(y) - sin(x)sin(y) */
|
/* cosinus cos(x + y) = cos(x)cos(y) - sin(x)sin(y) */
|
||||||
/* sinus sin(x + y) = sin(x)cos(y) + cos(x)sin(y) */
|
/* sinus sin(x + y) = sin(x)cos(y) + cos(x)sin(y) */
|
||||||
|
|
||||||
uint16_t Nid1_start = 0;
|
int Nid1_start = 0;
|
||||||
uint16_t Nid1_end = N_ID_1_NUMBER;
|
int Nid1_end = N_ID_1_NUMBER;
|
||||||
if (target_Nid_cell != -1) {
|
if (target_Nid_cell != -1) {
|
||||||
Nid1_start = GET_NID1(target_Nid_cell);
|
Nid1_start = GET_NID1(target_Nid_cell);
|
||||||
Nid1_end = Nid1_start + 1;
|
Nid1_end = Nid1_start + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Nid1 = Nid1_start; Nid1 < Nid1_end; Nid1++) { // all possible Nid1 values
|
const int phase_to_try[] = {0, 2, -2, 4, -4, 6, -6, 8, -8, 10, -10, 12, -12, 14, -14};
|
||||||
for (phase = 0; phase < PHASE_HYPOTHESIS_NUMBER; phase++) { // phase offset between PSS and SSS
|
for (int idx = 0; idx < sizeofArray(phase_to_try); idx++) { // phase offset between PSS and SSS
|
||||||
|
const c64_t rot =
|
||||||
metric = 0;
|
(c64_t){round(cos(M_PI / 3 / 15 * (phase_to_try[idx])) * 32767), round(sin(M_PI / 3 / 15 * (phase_to_try[idx])) * 32767)};
|
||||||
metric_re = 0;
|
for (int n1 = Nid1_start; n1 < Nid1_end; n1++) { // all possible Nid1 values
|
||||||
|
int64_t metric = 0;
|
||||||
d = (int16_t *)&d_sss[Nid2][Nid1];
|
int16_t *d = d_sss[Nid2][n1];
|
||||||
|
for (int i = 0; i < LENGTH_SSS_NR; i++) {
|
||||||
// This is the inner product using one particular value of each unknown parameter
|
// metric is only real part because sss is a pure real signal (imaginary is 0)
|
||||||
for (i=0; i < LENGTH_SSS_NR; i++) {
|
metric += d[i] * (rot.r * sss[i].r - rot.i * sss[i].i);
|
||||||
metric_re += d[i] * ((phase_nr[phase].r * sss[i].r - phase_nr[phase].i * sss[i].i) >> SCALING_METRIC_SSS_NR);
|
|
||||||
}
|
}
|
||||||
|
metric >>= SCALING_METRIC_SSS_NR;
|
||||||
metric = metric_re;
|
|
||||||
|
|
||||||
// if the current metric is better than the last save it
|
// if the current metric is better than the last save it
|
||||||
if (metric > *tot_metric) {
|
if (metric > *tot_metric) {
|
||||||
*tot_metric = metric;
|
*tot_metric = metric;
|
||||||
*Nid_cell = Nid2 + (3 * Nid1);
|
*Nid_cell = Nid2 + (3 * n1);
|
||||||
*phase_max = phase;
|
*phase_max = idx;
|
||||||
|
|
||||||
#ifdef DEBUG_SSS_NR
|
#ifdef DEBUG_SSS_NR
|
||||||
|
LOG_D(PHY,
|
||||||
LOG_D(PHY,"(phase,Nid1) (%d,%d), metric_phase %d tot_metric %d, phase_max %d \n",phase, Nid1, metric, *tot_metric, *phase_max);
|
"(phase,Nid1) (%d,%d), metric_phase %d tot_metric %d, phase_max %d \n",
|
||||||
|
phase,
|
||||||
|
n1,
|
||||||
|
metric,
|
||||||
|
*tot_metric,
|
||||||
|
*phase_max);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// we try progressively rotation between pss and sss
|
||||||
|
// but pss and sss are in phase at emission
|
||||||
|
// rotation means doppler variation, or very noisy pss detection
|
||||||
|
if (*tot_metric >= SSS_METRIC_FLOOR_NR)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
//#ifdef DEBUG_SSS_NR
|
if (*tot_metric < SSS_METRIC_FLOOR_NR) {
|
||||||
#define SSS_METRIC_FLOOR_NR (30000)
|
|
||||||
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
|
|
||||||
|
|
||||||
int re = 0;
|
|
||||||
int im = 0;
|
|
||||||
if (Nid1 == Nid1_end) {
|
|
||||||
LOG_D(PHY,
|
LOG_D(PHY,
|
||||||
"Failed to detect SSS after PSS, metric of SSS %d, threshold to consider SSS valid %d, detected PCI: %d\n",
|
"Failed to detect SSS after PSS, metric of SSS %d, threshold to consider SSS valid %d, detected PCI: %d\n",
|
||||||
*tot_metric,
|
*tot_metric,
|
||||||
@@ -503,15 +295,19 @@ bool rx_sss_nr(const NR_DL_FRAME_PARMS *frame_parms,
|
|||||||
*Nid_cell);
|
*Nid_cell);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
d = (int16_t *)&d_sss[Nid2][Nid1];
|
|
||||||
for(i = 0; i<LENGTH_SSS_NR; i++) {
|
int Nid1 = GET_NID1(*Nid_cell);
|
||||||
re += d[i] * sss[i].r;
|
LOG_D(PHY, "Nid2 %d Nid1 %d tot_metric %d, phase_max %d \n", Nid2, Nid1, *tot_metric, *phase_max);
|
||||||
im += d[i] * sss[i].i;
|
int16_t *d = d_sss[Nid2][Nid1];
|
||||||
|
c32_t sig_sum = {};
|
||||||
|
for (int i = 0; i < LENGTH_SSS_NR; i++) {
|
||||||
|
sig_sum.r += d[i] * sss[i].r;
|
||||||
|
sig_sum.i += d[i] * sss[i].i;
|
||||||
}
|
}
|
||||||
double ffo_sss = atan2(im,re)/M_PI/4.3;
|
double ffo_sss = atan2(sig_sum.i, sig_sum.r) / M_PI / 4.3;
|
||||||
*freq_offset_sss = (int)(ffo_sss*frame_parms->subcarrier_spacing);
|
*freq_offset_sss = (int)(ffo_sss*frame_parms->subcarrier_spacing);
|
||||||
|
|
||||||
double ffo_pss = ((double)freq_offset_pss) / frame_parms->subcarrier_spacing;
|
double ffo_pss = (double)freq_offset_pss / frame_parms->subcarrier_spacing;
|
||||||
LOG_D(NR_PHY,
|
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",
|
"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",
|
||||||
*Nid_cell,
|
*Nid_cell,
|
||||||
|
|||||||
@@ -156,7 +156,7 @@ void nr_common_signal_procedures(PHY_VARS_gNB *gNB, int frame, int slot, const n
|
|||||||
bitmap);
|
bitmap);
|
||||||
|
|
||||||
nr_generate_pss(txdataF[beam_nb][0], gNB->TX_AMP, ssb_start_symbol, cfg, fp);
|
nr_generate_pss(txdataF[beam_nb][0], gNB->TX_AMP, ssb_start_symbol, cfg, fp);
|
||||||
nr_generate_sss(txdataF[beam_nb][0], gNB->TX_AMP, ssb_start_symbol, cfg, fp);
|
nr_generate_sss(txdataF[beam_nb][0], gNB->TX_AMP, ssb_start_symbol, cfg->cell_config.phy_cell_id.value, fp);
|
||||||
|
|
||||||
uint16_t slots_per_hf = (fp->slots_per_frame) >> 1;
|
uint16_t slots_per_hf = (fp->slots_per_frame) >> 1;
|
||||||
int n_hf = slot < slots_per_hf ? 0 : 1;
|
int n_hf = slot < slots_per_hf ? 0 : 1;
|
||||||
|
|||||||
Reference in New Issue
Block a user