|
|
|
@ -10,7 +10,6 @@
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "srslte/srslte.h"
|
|
|
|
|
#include <assert.h>
|
|
|
|
|
#include <math.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
@ -22,8 +21,6 @@
|
|
|
|
|
|
|
|
|
|
#include "prach_tables.h"
|
|
|
|
|
|
|
|
|
|
float save_corr[4096];
|
|
|
|
|
|
|
|
|
|
// PRACH detection threshold is PRACH_DETECT_FACTOR*average
|
|
|
|
|
#define PRACH_DETECT_FACTOR 18
|
|
|
|
|
#define SUCCESSIVE_CANCELLATION_ITS 4
|
|
|
|
@ -38,6 +35,59 @@ float save_corr[4096];
|
|
|
|
|
//#define PRACH_CANCELLATION_HARD
|
|
|
|
|
#define PRACH_AMP 1.0
|
|
|
|
|
|
|
|
|
|
// Comment following line for disabling complex exponential look-up table
|
|
|
|
|
#define PRACH_USE_CEXP_LUT
|
|
|
|
|
|
|
|
|
|
#ifdef PRACH_USE_CEXP_LUT
|
|
|
|
|
|
|
|
|
|
// Define read-only complex exponential tables for two possibles size of sequences, common for all possible PRACH
|
|
|
|
|
// objects
|
|
|
|
|
static cf_t cexp_table_long[SRSLTE_PRACH_N_ZC_LONG] = {};
|
|
|
|
|
static cf_t cexp_table_short[SRSLTE_PRACH_N_ZC_SHORT] = {};
|
|
|
|
|
|
|
|
|
|
// Use constructor attribute for writing complex exponential tables
|
|
|
|
|
__attribute__((constructor)) static void prach_cexp_init()
|
|
|
|
|
{
|
|
|
|
|
for (uint32_t i = 0; i < SRSLTE_PRACH_N_ZC_LONG; i++) {
|
|
|
|
|
cexp_table_long[i] = cexpf(-I * 2.0f * M_PI * (float)i / (float)SRSLTE_PRACH_N_ZC_LONG);
|
|
|
|
|
}
|
|
|
|
|
for (uint32_t i = 0; i < SRSLTE_PRACH_N_ZC_SHORT; i++) {
|
|
|
|
|
cexp_table_short[i] = cexpf(-I * 2.0f * M_PI * (float)i / (float)SRSLTE_PRACH_N_ZC_SHORT);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endif // PRACH_USE_CEXP_LUT
|
|
|
|
|
|
|
|
|
|
// Generate ZC sequence using either look-up tables or conventional cexp function
|
|
|
|
|
static void prach_cexp(uint32_t N_zc, uint32_t u, cf_t* root)
|
|
|
|
|
{
|
|
|
|
|
#ifdef PRACH_USE_CEXP_LUT
|
|
|
|
|
// Use long N_zc table (839 length)
|
|
|
|
|
if (N_zc == SRSLTE_PRACH_N_ZC_LONG) {
|
|
|
|
|
for (int j = 0; j < SRSLTE_PRACH_N_ZC_LONG; j++) {
|
|
|
|
|
uint32_t phase_idx = u * j * (j + 1);
|
|
|
|
|
root[j] = cexp_table_long[phase_idx % SRSLTE_PRACH_N_ZC_LONG];
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Use short N_zc table (139 length)
|
|
|
|
|
if (N_zc == SRSLTE_PRACH_N_ZC_SHORT) {
|
|
|
|
|
for (int j = 0; j < SRSLTE_PRACH_N_ZC_SHORT; j++) {
|
|
|
|
|
uint32_t phase_idx = u * j * (j + 1);
|
|
|
|
|
root[j] = cexp_table_short[phase_idx % SRSLTE_PRACH_N_ZC_SHORT];
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
#endif // PRACH_USE_CEXP_LUT
|
|
|
|
|
|
|
|
|
|
// If the N_zc does not match any of the tables, use conventional exponential function
|
|
|
|
|
for (int j = 0; j < N_zc; j++) {
|
|
|
|
|
double phase = -M_PI * u * j * (j + 1) / N_zc;
|
|
|
|
|
root[j] = cexp(phase * I);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int srslte_prach_set_cell_(srslte_prach_t* p,
|
|
|
|
|
uint32_t N_ifft_ul,
|
|
|
|
|
srslte_prach_cfg_t* cfg,
|
|
|
|
@ -251,10 +301,9 @@ int srslte_prach_gen_seqs(srslte_prach_t* p)
|
|
|
|
|
u = prach_zc_roots[(p->rsi + p->N_roots) % 838];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (int j = 0; j < p->N_zc; j++) {
|
|
|
|
|
double phase = -M_PI * u * j * (j + 1) / p->N_zc;
|
|
|
|
|
root[j] = cexp(phase * I);
|
|
|
|
|
}
|
|
|
|
|
// Generate actual sequence
|
|
|
|
|
prach_cexp(p->N_zc, u, root);
|
|
|
|
|
|
|
|
|
|
p->root_seqs_idx[p->N_roots++] = i;
|
|
|
|
|
|
|
|
|
|
// Determine v_max
|
|
|
|
@ -341,20 +390,20 @@ int srslte_prach_init(srslte_prach_t* p, uint32_t max_N_ifft_ul)
|
|
|
|
|
p->max_N_ifft_ul = max_N_ifft_ul;
|
|
|
|
|
|
|
|
|
|
// Set up containers
|
|
|
|
|
p->prach_bins = srslte_vec_cf_malloc(MAX_N_zc);
|
|
|
|
|
p->corr_spec = srslte_vec_cf_malloc(MAX_N_zc);
|
|
|
|
|
p->corr = srslte_vec_f_malloc(MAX_N_zc);
|
|
|
|
|
p->cross = srslte_vec_cf_malloc(MAX_N_zc);
|
|
|
|
|
p->corr_freq = srslte_vec_cf_malloc(MAX_N_zc);
|
|
|
|
|
p->prach_bins = srslte_vec_cf_malloc(SRSLTE_PRACH_N_ZC_LONG);
|
|
|
|
|
p->corr_spec = srslte_vec_cf_malloc(SRSLTE_PRACH_N_ZC_LONG);
|
|
|
|
|
p->corr = srslte_vec_f_malloc(SRSLTE_PRACH_N_ZC_LONG);
|
|
|
|
|
p->cross = srslte_vec_cf_malloc(SRSLTE_PRACH_N_ZC_LONG);
|
|
|
|
|
p->corr_freq = srslte_vec_cf_malloc(SRSLTE_PRACH_N_ZC_LONG);
|
|
|
|
|
|
|
|
|
|
// Set up ZC FFTS
|
|
|
|
|
if (srslte_dft_plan(&p->zc_fft, MAX_N_zc, SRSLTE_DFT_FORWARD, SRSLTE_DFT_COMPLEX)) {
|
|
|
|
|
if (srslte_dft_plan(&p->zc_fft, SRSLTE_PRACH_N_ZC_LONG, SRSLTE_DFT_FORWARD, SRSLTE_DFT_COMPLEX)) {
|
|
|
|
|
return SRSLTE_ERROR;
|
|
|
|
|
}
|
|
|
|
|
srslte_dft_plan_set_mirror(&p->zc_fft, false);
|
|
|
|
|
srslte_dft_plan_set_norm(&p->zc_fft, true);
|
|
|
|
|
|
|
|
|
|
if (srslte_dft_plan(&p->zc_ifft, MAX_N_zc, SRSLTE_DFT_BACKWARD, SRSLTE_DFT_COMPLEX)) {
|
|
|
|
|
if (srslte_dft_plan(&p->zc_ifft, SRSLTE_PRACH_N_ZC_LONG, SRSLTE_DFT_BACKWARD, SRSLTE_DFT_COMPLEX)) {
|
|
|
|
|
return SRSLTE_ERROR;
|
|
|
|
|
}
|
|
|
|
|
srslte_dft_plan_set_mirror(&p->zc_ifft, false);
|
|
|
|
@ -428,14 +477,14 @@ int srslte_prach_set_cell_(srslte_prach_t* p,
|
|
|
|
|
// Determine N_zc and N_cs
|
|
|
|
|
if (4 == preamble_format) {
|
|
|
|
|
if (p->zczc < 7) {
|
|
|
|
|
p->N_zc = 139;
|
|
|
|
|
p->N_zc = SRSLTE_PRACH_N_ZC_SHORT;
|
|
|
|
|
p->N_cs = prach_Ncs_format4[p->zczc];
|
|
|
|
|
} else {
|
|
|
|
|
ERROR("Invalid zeroCorrelationZoneConfig=%d for format4", p->zczc);
|
|
|
|
|
return SRSLTE_ERROR;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
p->N_zc = MAX_N_zc;
|
|
|
|
|
p->N_zc = SRSLTE_PRACH_N_ZC_LONG;
|
|
|
|
|
if (p->hs) {
|
|
|
|
|
if (p->zczc < 15) {
|
|
|
|
|
p->N_cs = prach_Ncs_restricted[p->zczc];
|
|
|
|
@ -454,7 +503,7 @@ int srslte_prach_set_cell_(srslte_prach_t* p,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Set up ZC FFTS
|
|
|
|
|
if (p->N_zc != MAX_N_zc) {
|
|
|
|
|
if (p->N_zc != SRSLTE_PRACH_N_ZC_LONG) {
|
|
|
|
|
if (srslte_dft_replan(&p->zc_fft, p->N_zc)) {
|
|
|
|
|
return SRSLTE_ERROR;
|
|
|
|
|
}
|
|
|
|
@ -619,7 +668,7 @@ float srslte_prach_calculate_time_offset_secs(srslte_prach_t* p, cf_t* cross)
|
|
|
|
|
{
|
|
|
|
|
// calculate the phase of the cross correlation
|
|
|
|
|
float freq_domain_phase = cargf(srslte_vec_acc_cc(cross, p->N_zc));
|
|
|
|
|
float ratio = (float)(p->N_ifft_ul * DELTA_F) / (float)(MAX_N_zc * DELTA_F_RA);
|
|
|
|
|
float ratio = (float)(p->N_ifft_ul * DELTA_F) / (float)(SRSLTE_PRACH_N_ZC_LONG * DELTA_F_RA);
|
|
|
|
|
// converting from phase to number of samples
|
|
|
|
|
float num_samples = roundf((ratio * freq_domain_phase * p->N_zc) / (2 * M_PI));
|
|
|
|
|
|
|
|
|
|