From 1e073b8b678a8793171afeaa62dc93ce19ad1cbb Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Tue, 16 Feb 2021 10:37:33 +0100 Subject: [PATCH] PRACH: avoid general cexp for sequence generation using LUT --- lib/include/srslte/phy/phch/prach.h | 12 +++- lib/src/phy/phch/prach.c | 85 +++++++++++++++++++++++------ lib/src/phy/phch/prach_tables.h | 2 - lib/src/phy/phch/test/prach_test.c | 22 +++++--- 4 files changed, 90 insertions(+), 31 deletions(-) diff --git a/lib/include/srslte/phy/phch/prach.h b/lib/include/srslte/phy/phch/prach.h index 00fa4ffe1..2e83db3d0 100644 --- a/lib/include/srslte/phy/phch/prach.h +++ b/lib/include/srslte/phy/phch/prach.h @@ -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 diff --git a/lib/src/phy/phch/prach.c b/lib/src/phy/phch/prach.c index 154840518..1ed136945 100644 --- a/lib/src/phy/phch/prach.c +++ b/lib/src/phy/phch/prach.c @@ -10,7 +10,6 @@ * */ -#include "srslte/srslte.h" #include #include #include @@ -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)); diff --git a/lib/src/phy/phch/prach_tables.h b/lib/src/phy/phch/prach_tables.h index 04f5e45c8..92aaadb84 100644 --- a/lib/src/phy/phch/prach_tables.h +++ b/lib/src/phy/phch/prach_tables.h @@ -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}; diff --git a/lib/src/phy/phch/test/prach_test.c b/lib/src/phy/phch/test/prach_test.c index 707648215..53b03b9ea 100644 --- a/lib/src/phy/phch/test/prach_test.c +++ b/lib/src/phy/phch/test/prach_test.c @@ -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);