PRACH: avoid general cexp for sequence generation using LUT

master
Xavier Arteaga 4 years ago committed by Xavier Arteaga
parent c1adaec038
commit 1e073b8b67

@ -31,6 +31,12 @@
#define SRSLTE_PRACH_MAX_LEN (2 * 24576 + 21024) // Maximum Tcp + Tseq
// Long PRACH ZC sequence sequence length
#define SRSLTE_PRACH_N_ZC_LONG 839
// Short PRACH ZC sequence sequence length
#define SRSLTE_PRACH_N_ZC_SHORT 139
/** Generation and detection of RACH signals for uplink.
* Currently only supports preamble formats 0-3.
* Does not currently support high speed flag.
@ -40,7 +46,7 @@
typedef struct {
int idx;
float factor;
cf_t phase_array[2 * 839];
cf_t phase_array[2 * SRSLTE_PRACH_N_ZC_LONG];
} srslte_prach_cancellation_t;
typedef struct SRSLTE_API {
@ -65,8 +71,8 @@ typedef struct SRSLTE_API {
uint32_t N_cp; // Cyclic prefix length
// Generated tables
cf_t seqs[64][839]; // Our set of 64 preamble sequences
cf_t dft_seqs[64][839]; // DFT-precoded seqs
cf_t seqs[64][SRSLTE_PRACH_N_ZC_LONG]; // Our set of 64 preamble sequences
cf_t dft_seqs[64][SRSLTE_PRACH_N_ZC_LONG]; // DFT-precoded seqs
uint64_t dft_gen_bitmap; // Bitmap where each bit Indicates if the dft has been generated for sequence i.
uint32_t root_seqs_idx[64]; // Indices of root seqs in seqs table
uint32_t N_roots; // Number of root sequences used in this configuration

@ -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));

@ -25,8 +25,6 @@ uint32_t prach_Tseq[5] = {24576, 24576, 2 * 24576, 2 * 24576, 4096};
// Table 5.7.2-2 - N_cs values for unrestricted sets
uint32_t prach_Ncs_unrestricted[16] = {0, 13, 15, 18, 22, 26, 32, 38, 46, 59, 76, 93, 119, 167, 279, 419};
#define MAX_N_zc 839
// Table 5.7.2-2 - N_cs values for restricted sets
uint32_t prach_Ncs_restricted[15] = {15, 18, 22, 26, 32, 38, 46, 55, 68, 82, 100, 128, 158, 202, 237};

@ -23,12 +23,13 @@
#define MAX_LEN 70176
uint32_t nof_prb = 50;
uint32_t config_idx = 3;
uint32_t root_seq_idx = 0;
uint32_t zero_corr_zone = 15;
uint32_t num_ra_preambles = 0; // use default
void usage(char* prog)
static uint32_t nof_prb = 50;
static uint32_t config_idx = 3;
static uint32_t root_seq_idx = 0;
static uint32_t zero_corr_zone = 15;
static uint32_t num_ra_preambles = 0; // use default
static void usage(char* prog)
{
printf("Usage: %s\n", prog);
printf("\t-n Uplink number of PRB [Default %d]\n", nof_prb);
@ -37,7 +38,7 @@ void usage(char* prog)
printf("\t-z Zero correlation zone config [Default 1]\n");
}
void parse_args(int argc, char** argv)
static void parse_args(int argc, char** argv)
{
int opt;
while ((opt = getopt(argc, argv, "nfrz")) != -1) {
@ -83,10 +84,16 @@ int main(int argc, char** argv)
if (srslte_prach_init(&prach, srslte_symbol_sz(nof_prb))) {
return -1;
}
struct timeval t[3] = {};
gettimeofday(&t[1], NULL);
if (srslte_prach_set_cfg(&prach, &prach_cfg, nof_prb)) {
ERROR("Error initiating PRACH object");
return -1;
}
gettimeofday(&t[2], NULL);
get_time_interval(t);
printf("It took %ld microseconds to configure\n", t[0].tv_usec + t[0].tv_sec * 1000000UL);
uint32_t seq_index = 0;
uint32_t indices[64];
@ -99,7 +106,6 @@ int main(int argc, char** argv)
uint32_t prach_len = prach.N_seq;
struct timeval t[3];
gettimeofday(&t[1], NULL);
srslte_prach_detect(&prach, 0, &preamble[prach.N_cp], prach_len, indices, &n_indices);
gettimeofday(&t[2], NULL);

Loading…
Cancel
Save