code cleaning pss and sss detection, no functional change
This commit is contained in:
@@ -90,9 +90,6 @@ static const c16_t phase_nr[PHASE_HYPOTHESIS_NUMBER] = {
|
||||
void init_context_sss_nr(int amp);
|
||||
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,
|
||||
int nid2,
|
||||
int target_Nid_cell,
|
||||
|
||||
@@ -23,11 +23,7 @@
|
||||
|
||||
//#define NR_SSS_DEBUG
|
||||
|
||||
int nr_generate_sss( c16_t *txdataF,
|
||||
int16_t amp,
|
||||
uint8_t ssb_start_symbol,
|
||||
nfapi_nr_config_request_scf_t* config,
|
||||
NR_DL_FRAME_PARMS *frame_parms)
|
||||
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 x0[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 };
|
||||
|
||||
/// Sequence generation
|
||||
int Nid = config->cell_config.phy_cell_id.value;
|
||||
int Nid2 = Nid % 3;
|
||||
int Nid1 = (Nid - Nid2)/3;
|
||||
|
||||
@@ -59,13 +54,11 @@ int nr_generate_sss( c16_t *txdataF,
|
||||
/// Resource mapping
|
||||
|
||||
// SSS occupies a predefined position (subcarriers 56-182, symbol 2) within the SSB block starting from
|
||||
int k = frame_parms->ssb_start_subcarrier + 56;
|
||||
int l = ssb_start_symbol + 2;
|
||||
c16_t *tx = txdataF + (ssb_start_symbol + 2) * frame_parms->ofdm_symbol_size + frame_parms->ssb_start_subcarrier + 56;
|
||||
|
||||
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*)txdataF)[2*(l*frame_parms->ofdm_symbol_size + k)] = (((int16_t)amp) * d_sss) >> 15;
|
||||
k++;
|
||||
*tx++ = (c16_t){.r = (amp * d_sss) >> 15};
|
||||
}
|
||||
#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);
|
||||
|
||||
@@ -60,11 +60,7 @@ int nr_generate_pss(c16_t *txdataF,
|
||||
@param
|
||||
@returns 0 on success
|
||||
*/
|
||||
int nr_generate_sss(c16_t *txdataF,
|
||||
int16_t amp,
|
||||
uint8_t ssb_start_symbol,
|
||||
nfapi_nr_config_request_scf_t *config,
|
||||
NR_DL_FRAME_PARMS *frame_parms);
|
||||
int nr_generate_sss(c16_t *txdataF, int16_t amp, uint8_t ssb_start_symbol, int nid, NR_DL_FRAME_PARMS *frame_parms);
|
||||
|
||||
/*!
|
||||
\fn void nr_generate_pbch_dmrs
|
||||
|
||||
@@ -260,7 +260,7 @@ static void sl_nr_extract_sss(PHY_VARS_NR_UE *ue,
|
||||
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 (phase = 0; phase < PHASE_HYPOTHESIS_NUMBER; phase++) { // phase offset between PSS and SSS
|
||||
for (phase = 0; phase < sizeofArray(phase_nr); phase++) { // phase offset between PSS and SSS
|
||||
|
||||
int32_t metric = 0, metric_re = 0;
|
||||
|
||||
|
||||
@@ -49,24 +49,12 @@
|
||||
|
||||
//#define DBG_PSS_NR
|
||||
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};
|
||||
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)
|
||||
{
|
||||
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);
|
||||
int16_t d_pss[LENGTH_PSS_NR];
|
||||
AssertFatal(N_ID_2 >= 0 && N_ID_2 <= 2, "Illegal N_ID_2 %d\n", N_ID_2);
|
||||
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)
|
||||
const int16_t x_initial[INITIAL_PSS_NR] = {0, 1, 1, 0, 1, 1, 1};
|
||||
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++)
|
||||
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++) {
|
||||
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 */
|
||||
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_synchro2[i] = d_pss[i];
|
||||
primary_synchro[N_ID_2][i].r = (pss[i] * SHRT_MAX) >> SCALING_PSS_NR; /* Maximum value for type short int ie int16_t */
|
||||
}
|
||||
|
||||
#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])
|
||||
{
|
||||
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)));
|
||||
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++) {
|
||||
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++;
|
||||
}
|
||||
|
||||
@@ -182,54 +167,6 @@ void generate_pss_nr_time(const NR_DL_FRAME_PARMS *fp, const int N_ID_2, int ssb
|
||||
}
|
||||
|
||||
#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)
|
||||
{
|
||||
#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);
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef DBG_PSS_NR
|
||||
|
||||
LOG_M("rxdata0_des.m","rxd0_des", &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
|
||||
|
||||
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);
|
||||
stop_meas(&generic_time[TIME_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
|
||||
|
||||
LOG_D(PHY,"PSS execution duration %4d microseconds \n", duration_ms);
|
||||
|
||||
#endif
|
||||
|
||||
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
|
||||
|
||||
#ifdef SYNCHRO_DECIMAT
|
||||
|
||||
if (rate_change != 1) {
|
||||
|
||||
if (rxdata[0] != NULL) {
|
||||
|
||||
for (int aa=0;aa<frame_parms->nb_antennas_rx;aa++) {
|
||||
free(rxdata[aa]);
|
||||
}
|
||||
|
||||
free(rxdata);
|
||||
}
|
||||
|
||||
restore_frame_context_pss_nr(frame_parms, rate_change);
|
||||
restore_frame_context_pss_nr(frame_parms, rate_change);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -504,11 +423,6 @@ int pss_search_time_nr(const c16_t **rxdata,
|
||||
int search_start,
|
||||
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
|
||||
unsigned int start, length;
|
||||
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;
|
||||
}
|
||||
|
||||
AssertFatal(length>0,"illegal length %d\n",length);
|
||||
peak_value = 0;
|
||||
peak_position = 0;
|
||||
pss_source = 0;
|
||||
|
||||
AssertFatal(length > 0, "illegal length %d\n", 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++)
|
||||
@@ -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. */
|
||||
/* Correlation computation is based on a a dot product which is realized thank to SIMS extensions */
|
||||
|
||||
uint16_t pss_index_start = 0;
|
||||
uint16_t pss_index_end = get_softmodem_params()->sl_mode == 0 ? NUMBER_PSS_SEQUENCE : NUMBER_PSS_SEQUENCE_SL;
|
||||
int pss_index_start;
|
||||
int pss_index_end;
|
||||
if (target_Nid_cell != -1) {
|
||||
pss_index_start = GET_NID2(target_Nid_cell);
|
||||
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 (n = start; n < start + length; n += 4) { //
|
||||
|
||||
int64_t pss_corr_ue=0;
|
||||
for (int n = start; n < start + length; n += 4) { //
|
||||
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 (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 */
|
||||
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,
|
||||
shift);
|
||||
const c64_t r64 = {.r = result.r, .i = result.i};
|
||||
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] */
|
||||
avg[pss_index]+=pss_corr_ue;
|
||||
avg[pss_index] += pss_corr_ue;
|
||||
if (pss_corr_ue > peak_value) {
|
||||
peak_value = pss_corr_ue;
|
||||
peak_position = n;
|
||||
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]);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
avg[pss_index] /= (length / 4);
|
||||
}
|
||||
|
||||
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.
|
||||
double ffo_est = 0;
|
||||
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
|
||||
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;
|
||||
|
||||
#ifdef DBG_PSS_NR
|
||||
printf("ffo %lf\n",ffo_est);
|
||||
printf("ffo %lf\n", ffo_est);
|
||||
#endif
|
||||
}
|
||||
|
||||
// computing absolute value of frequency offset
|
||||
*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);
|
||||
*f_off = ffo_est * frame_parms->subcarrier_spacing;
|
||||
|
||||
*nid2 = pss_source;
|
||||
*pssPeak = dB_fixed64(peak_value);
|
||||
@@ -631,22 +539,18 @@ int pss_search_time_nr(const c16_t **rxdata,
|
||||
ffo_est);
|
||||
|
||||
if ((search_start < 0 || search_length == 0) && peak_value < 5 * avg[pss_source])
|
||||
return(-1);
|
||||
|
||||
return (-1);
|
||||
|
||||
#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);
|
||||
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++;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return peak_position;
|
||||
|
||||
@@ -109,71 +109,8 @@ void init_context_sss_nr(int amp)
|
||||
#endif
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
*
|
||||
* 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));
|
||||
}
|
||||
// #define DEBUG_SSS_NR
|
||||
// #define DEBUG_PLOT_SSS
|
||||
|
||||
/*******************************************************************
|
||||
*
|
||||
@@ -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,
|
||||
c16_t pss_ext[frame_parms->nb_antennas_rx][LENGTH_PSS_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];
|
||||
for (int i = 0; i < LENGTH_PSS_NR; i++) {
|
||||
// This is H*(PSS) = R* \cdot PSS
|
||||
const int tmp_re = pss_ext2[i].r * pss[i];
|
||||
const int tmp_im = -pss_ext2[i].i * pss[i];
|
||||
|
||||
const int32_t amp = tmp_re * tmp_re + tmp_im * tmp_im;
|
||||
const c16_t tmp = (c16_t){pss_ext2[i].r * pss[i], -pss_ext2[i].i * pss[i]};
|
||||
const int32_t amp = squaredMod(tmp);
|
||||
const int shift = log2_approx(amp) / 2;
|
||||
// This is R(SSS) \cdot H*(PSS)
|
||||
const c16_t tmp = {(tmp_re * sss_ext2[i].r - tmp_im * sss_ext2[i].i) >> shift,
|
||||
(tmp_re * sss_ext2[i].i + tmp_im * sss_ext2[i].r) >> shift};
|
||||
// printf("SSSi(%d,%d) : (%d,%d)\n",aarx,i,sss_ext2[i<<1],sss_ext2[1+(i<<1)]);
|
||||
// printf("SSSo(%d,%d) : (%d,%d)\n",aarx,i,tmp_re2,tmp_im2);
|
||||
// MRC on RX antennas
|
||||
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;
|
||||
}
|
||||
const c16_t new_sss = c16mulShift(tmp, sss_ext2[i], shift);
|
||||
if (aarx == 0)
|
||||
sss_ext2[i] = new_sss;
|
||||
else
|
||||
sss_ext2[i] = c16add(sss_ext2[i], new_sss);
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
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);
|
||||
// sss_ext[0] now contains the compensated SSS
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
*
|
||||
* NAME : do_pss_sss_extract
|
||||
*
|
||||
* PARAMETERS : none
|
||||
*
|
||||
* RETURN : none
|
||||
*
|
||||
* DESCRIPTION : it allows extracting sss from samples buffer
|
||||
*
|
||||
*********************************************************************/
|
||||
*
|
||||
* NAME : pss_sss_extract_nr
|
||||
*
|
||||
* PARAMETERS : none
|
||||
*
|
||||
* RETURN : none
|
||||
*
|
||||
* 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 sss_ext[frame_parms->nb_antennas_rx][LENGTH_SSS_NR],
|
||||
uint8_t doPss,
|
||||
uint8_t doSss,
|
||||
int ssb_start_subcarrier,
|
||||
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++) {
|
||||
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 *sss_rxF = rxdataF[aarx] + sss_symbol * ofdm_symbol_size;
|
||||
|
||||
c16_t *pss_rxF_ext = pss_ext[aarx];
|
||||
c16_t *sss_rxF_ext = sss_ext[aarx];
|
||||
|
||||
unsigned int k = frame_parms->first_carrier_offset + ssb_start_subcarrier
|
||||
+ ((get_softmodem_params()->sl_mode == 0) ? PSS_SSS_SUB_CARRIER_START : PSS_SSS_SUB_CARRIER_START_SL);
|
||||
|
||||
if (k>= frame_parms->ofdm_symbol_size) k-=frame_parms->ofdm_symbol_size;
|
||||
|
||||
for (int i=0; i < LENGTH_PSS_NR; i++) {
|
||||
if (doPss) {
|
||||
pss_rxF_ext[i] = pss_rxF[k];
|
||||
}
|
||||
|
||||
if (doSss) {
|
||||
sss_rxF_ext[i] = sss_rxF[k];
|
||||
}
|
||||
|
||||
if (k >= frame_parms->ofdm_symbol_size)
|
||||
k -= frame_parms->ofdm_symbol_size;
|
||||
pss_rxF_ext[i] = pss_rxF[k];
|
||||
sss_rxF_ext[i] = sss_rxF[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,
|
||||
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 sss_ext[frame_parms->nb_antennas_rx][LENGTH_SSS_NR];
|
||||
uint8_t Nid2 = GET_NID2(nid2);
|
||||
uint16_t Nid1;
|
||||
uint8_t phase;
|
||||
int32_t metric, metric_re;
|
||||
int16_t *d;
|
||||
|
||||
const int Nid2 = GET_NID2(nid2);
|
||||
|
||||
// pss sss extraction
|
||||
pss_sss_extract_nr(frame_parms, pss_ext, sss_ext, ssb_start_subcarrier, rxdataF); /* subframe */
|
||||
|
||||
#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("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("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]);
|
||||
}
|
||||
write_output("pss_ext.m", "pss_ext", pss_ext, LENGTH_PSS_NR, 1, 1);
|
||||
#endif
|
||||
|
||||
// get conjugated channel estimate from PSS, H* = R* \cdot PSS
|
||||
// and do channel estimation and compensation based on PSS
|
||||
|
||||
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
|
||||
@@ -411,91 +238,49 @@ bool rx_sss_nr(const NR_DL_FRAME_PARMS *frame_parms,
|
||||
|
||||
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 */
|
||||
/* 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 */
|
||||
/* cosinus cos(x + y) = cos(x)cos(y) - sin(x)sin(y) */
|
||||
/* sinus sin(x + y) = sin(x)cos(y) + cos(x)sin(y) */
|
||||
|
||||
uint16_t Nid1_start = 0;
|
||||
uint16_t Nid1_end = N_ID_1_NUMBER;
|
||||
int Nid1_start = 0;
|
||||
int Nid1_end = N_ID_1_NUMBER;
|
||||
if (target_Nid_cell != -1) {
|
||||
Nid1_start = GET_NID1(target_Nid_cell);
|
||||
Nid1_end = Nid1_start + 1;
|
||||
}
|
||||
|
||||
for (Nid1 = Nid1_start; Nid1 < Nid1_end; Nid1++) { // all possible Nid1 values
|
||||
for (phase = 0; phase < PHASE_HYPOTHESIS_NUMBER; phase++) { // phase offset between PSS and SSS
|
||||
|
||||
metric = 0;
|
||||
metric_re = 0;
|
||||
|
||||
d = (int16_t *)&d_sss[Nid2][Nid1];
|
||||
|
||||
for (int n1 = Nid1_start; n1 < Nid1_end; n1++) { // all possible Nid1 values
|
||||
for (int phase = 0; phase < sizeofArray(phase_nr); phase++) { // phase offset between PSS and SSS
|
||||
int64_t metric = 0;
|
||||
int16_t *d = d_sss[Nid2][n1];
|
||||
// This is the inner product using one particular value of each unknown parameter
|
||||
for (i=0; i < LENGTH_SSS_NR; i++) {
|
||||
metric_re += d[i] * ((phase_nr[phase].r * sss[i].r - phase_nr[phase].i * sss[i].i) >> SCALING_METRIC_SSS_NR);
|
||||
for (int i = 0; i < LENGTH_SSS_NR; i++) {
|
||||
metric += d[i] * (phase_nr[phase].r * sss[i].r - phase_nr[phase].i * sss[i].i);
|
||||
}
|
||||
|
||||
metric = metric_re;
|
||||
|
||||
metric >>= SCALING_METRIC_SSS_NR;
|
||||
// if the current metric is better than the last save it
|
||||
if (metric > *tot_metric) {
|
||||
*tot_metric = metric;
|
||||
*Nid_cell = Nid2 + (3 * Nid1);
|
||||
*Nid_cell = Nid2 + (3 * n1);
|
||||
*phase_max = phase;
|
||||
|
||||
#ifdef DEBUG_SSS_NR
|
||||
|
||||
LOG_D(PHY,"(phase,Nid1) (%d,%d), metric_phase %d tot_metric %d, phase_max %d \n",phase, Nid1, metric, *tot_metric, *phase_max);
|
||||
|
||||
LOG_D(PHY,
|
||||
"(phase,Nid1) (%d,%d), metric_phase %d tot_metric %d, phase_max %d \n",
|
||||
phase,
|
||||
n1,
|
||||
metric,
|
||||
*tot_metric,
|
||||
*phase_max);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//#ifdef DEBUG_SSS_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) {
|
||||
if (*tot_metric < SSS_METRIC_FLOOR_NR) {
|
||||
LOG_D(PHY,
|
||||
"Failed to detect SSS after PSS, metric of SSS %d, threshold to consider SSS valid %d, detected PCI: %d\n",
|
||||
*tot_metric,
|
||||
@@ -503,15 +288,19 @@ bool rx_sss_nr(const NR_DL_FRAME_PARMS *frame_parms,
|
||||
*Nid_cell);
|
||||
return false;
|
||||
}
|
||||
d = (int16_t *)&d_sss[Nid2][Nid1];
|
||||
for(i = 0; i<LENGTH_SSS_NR; i++) {
|
||||
re += d[i] * sss[i].r;
|
||||
im += d[i] * sss[i].i;
|
||||
|
||||
int 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);
|
||||
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);
|
||||
|
||||
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,
|
||||
"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,
|
||||
|
||||
@@ -156,7 +156,7 @@ void nr_common_signal_procedures(PHY_VARS_gNB *gNB, int frame, int slot, const n
|
||||
bitmap);
|
||||
|
||||
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;
|
||||
int n_hf = slot < slots_per_hf ? 0 : 1;
|
||||
|
||||
Reference in New Issue
Block a user