From ec7873e7cc39a37710c127b53f9bbf2599913060 Mon Sep 17 00:00:00 2001 From: yagoda Date: Wed, 15 Jul 2020 11:59:12 +0200 Subject: [PATCH] refactoring PRACH, adding phase correction to successive cancellation --- lib/include/srslte/phy/phch/prach.h | 14 +- lib/include/srslte/phy/utils/vector.h | 2 + lib/src/phy/phch/prach.c | 181 ++++++++++++++--------- lib/src/phy/phch/test/prach_test_multi.c | 23 ++- 4 files changed, 138 insertions(+), 82 deletions(-) diff --git a/lib/include/srslte/phy/phch/prach.h b/lib/include/srslte/phy/phch/prach.h index a8c98a19e..f301c4433 100644 --- a/lib/include/srslte/phy/phch/prach.h +++ b/lib/include/srslte/phy/phch/prach.h @@ -123,8 +123,9 @@ typedef struct { typedef struct { int idx; - float offset; + float offset; float factor; + float phase; } srslte_prach_cancellation_t; typedef struct SRSLTE_API { @@ -209,4 +210,15 @@ SRSLTE_API int srslte_prach_free(srslte_prach_t* p); SRSLTE_API int srslte_prach_print_seqs(srslte_prach_t* p); +SRSLTE_API int srslte_prach_process(srslte_prach_t* p, + cf_t* signal, + uint32_t* indices, + float* t_offsets, + float* peak_to_avg, + uint32_t* n_indices, + int cancellation_idx, + srslte_prach_cancellation_t prach_cancel, + uint32_t begin, + uint32_t sig_len); + #endif // SRSLTE_PRACH_H diff --git a/lib/include/srslte/phy/utils/vector.h b/lib/include/srslte/phy/utils/vector.h index 1b5dbdeef..c3a94a115 100644 --- a/lib/include/srslte/phy/utils/vector.h +++ b/lib/include/srslte/phy/utils/vector.h @@ -274,6 +274,8 @@ SRSLTE_API void srslte_vec_abs_dB_cf(const cf_t* x, float default_value, float* */ SRSLTE_API void srslte_vec_arg_deg_cf(const cf_t* x, float default_value, float* arg, const uint32_t len); +SRSLTE_API float srslte_mean_arg_cf(const cf_t* x, uint32_t len); + SRSLTE_API void srslte_vec_interleave(const cf_t* x, const cf_t* y, cf_t* z, const int len); SRSLTE_API void srslte_vec_interleave_add(const cf_t* x, const cf_t* y, cf_t* z, const int len); diff --git a/lib/src/phy/phch/prach.c b/lib/src/phy/phch/prach.c index a24c62c68..842621113 100644 --- a/lib/src/phy/phch/prach.c +++ b/lib/src/phy/phch/prach.c @@ -566,17 +566,23 @@ int srslte_prach_detect(srslte_prach_t* p, { return srslte_prach_detect_offset(p, freq_offset, signal, sig_len, indices, NULL, NULL, n_indices); } + +/// this function subtracts the detected prach preamble from the signal so as to allow for lower power prach signals to +/// be detected more easily in the subsequent searches void srslte_prach_cancellation (srslte_prach_t* p, cf_t *signal, uint32_t begin, int sig_len, srslte_prach_cancellation_t prach_cancel) { cf_t sub[sig_len]; memcpy(sub,&p->td_signals[p->root_seqs_idx[prach_cancel.idx]][p->N_cp], sig_len*sizeof(cf_t)); srslte_vec_sc_prod_cfc(sub, prach_cancel.factor, sub, p->N_seq); int offset = (int) (prach_cancel.offset*sig_len*DELTA_F_RA); + srslte_vec_sc_prod_ccc(sub, cexpf(_Complex_I * prach_cancel.phase), sub, sig_len); srslte_vec_sub_ccc(&signal[offset], sub, &signal[offset], sig_len); srslte_dft_run(&p->fft, signal, p->signal_fft); memcpy(p->prach_bins, &p->signal_fft[begin], p->N_zc * sizeof(cf_t)); } +// this function checks if we have already detected and stored this particular PRACH index and if so, doesnt store it +// again in the detected prachs array bool srslte_prach_have_stored(srslte_prach_t* p,int current_idx, uint32_t* indices, uint32_t n_indices) { for(int i = 0; i < n_indices; i++) { if (indices[i] == current_idx) { @@ -597,6 +603,101 @@ float srslte_prach_set_offset(srslte_prach_t* p, int n_win) { return corr * p->peak_offsets[n_win] / (DELTA_F_RA * p->N_zc); } +// This function carries out the main processing on the incomming PRACH signal +int srslte_prach_process(srslte_prach_t* p, + cf_t* signal, + uint32_t* indices, + float* t_offsets, + float* peak_to_avg, + uint32_t* n_indices, + int cancellation_idx, + srslte_prach_cancellation_t prach_cancel, + uint32_t begin, + uint32_t sig_len) +{ + float max_to_cancel = 0; + cancellation_idx = -1; + int max_idx = 0; + for (int i = 0; i < p->num_ra_preambles; i++) { + cf_t* root_spec = p->dft_seqs[p->root_seqs_idx[i]]; + + srslte_vec_prod_conj_ccc(p->prach_bins, root_spec, p->corr_spec, p->N_zc); + + srslte_dft_run(&p->zc_ifft, p->corr_spec, p->corr_spec); + + srslte_vec_abs_square_cf(p->corr_spec, p->corr, p->N_zc); + + float corr_ave = srslte_vec_acc_ff(p->corr, p->N_zc) / p->N_zc; + + uint32_t winsize = 0; + if (p->N_cs != 0) { + winsize = p->N_cs; + } else { + winsize = p->N_zc; + } + uint32_t n_wins = p->N_zc / winsize; + + float max_peak = 0; + for (int j = 0; j < n_wins; j++) { + uint32_t start = (p->N_zc - (j * p->N_cs)) % p->N_zc; + uint32_t end = start + winsize; + if (end > p->deadzone) { + end -= p->deadzone; + } + start += p->deadzone; + p->peak_values[j] = 0; + for (int k = start; k < end; k++) { + if (p->corr[k] > p->peak_values[j]) { + p->peak_values[j] = p->corr[k]; + p->peak_offsets[j] = k - start; + if (p->peak_values[j] > max_peak) { + max_peak = p->peak_values[j]; + max_idx = k; + } + } + } + } + if (max_peak > p->detect_factor * corr_ave) { + for (int j = 0; j < n_wins; j++) { + if (p->peak_values[j] > p->detect_factor * corr_ave) { + if (indices) { + if (p->successive_cancellation) { + if (max_peak > max_to_cancel) { + cancellation_idx = (i * n_wins) + j; + max_to_cancel = max_peak; + prach_cancel.idx = cancellation_idx; + prach_cancel.offset = srslte_prach_set_offset(p, j); + prach_cancel.factor = sqrt((max_peak / 2) / ((sig_len / 2) * p->N_zc * p->N_zc)); + prach_cancel.phase = cargf(p->corr_spec[max_idx]); + } + if (srslte_prach_have_stored(p, ((i * n_wins) + j), indices, *n_indices)) { + break; + } + } + srslte_vec_fprint_c(stdout, p->corr_spec, 10) printf("max_idx %d\n", max_idx); + printf("cargf(p->corr_spec[max_idx]) %f\n", cargf(p->corr_spec[max_idx])); + indices[*n_indices] = (i * n_wins) + j; + } + if (peak_to_avg) { + peak_to_avg[*n_indices] = p->peak_values[j] / corr_ave; + } + if (t_offsets) { + t_offsets[*n_indices] = srslte_prach_set_offset(p, j); + printf("t_offsets[*n_indices] %f\n", t_offsets[*n_indices]); + } + (*n_indices)++; + } + } + } + } + if (cancellation_idx != -1) { + srslte_prach_cancellation(p, signal, begin, sig_len, prach_cancel); + } else { + return 1; + } + return 0; +} + int srslte_prach_detect_offset(srslte_prach_t* p, uint32_t freq_offset, cf_t* signal, @@ -614,7 +715,7 @@ int srslte_prach_detect_offset(srslte_prach_t* p, return SRSLTE_ERROR_INVALID_INPUTS; } int cancellation_idx = -2; - srslte_prach_cancellation_t prach_cancel; + srslte_prach_cancellation_t prach_cancel = {}; // FFT incoming signal srslte_dft_run(&p->fft, signal, p->signal_fft); @@ -628,80 +729,12 @@ int srslte_prach_detect_offset(srslte_prach_t* p, uint32_t begin = PHI + (K * k_0) + (K / 2); memcpy(p->prach_bins, &p->signal_fft[begin], p->N_zc * sizeof(cf_t)); - int loops = (p->successive_cancellation)?p->num_ra_preambles:1; + int loops = (p->successive_cancellation) ? p->num_ra_preambles : 1; + // if successive cancellation is enabled, we perform the entire search process p->num_ra_preambles times, removing + // the highest power PRACH preamble each time. for (int l = 0; l < loops; l++) { - float max_to_cancel = 0; - cancellation_idx = -1; - for (int i = 0; i < p->num_ra_preambles; i++) { - cf_t* root_spec = p->dft_seqs[p->root_seqs_idx[i]]; - - srslte_vec_prod_conj_ccc(p->prach_bins, root_spec, p->corr_spec, p->N_zc); - - srslte_dft_run(&p->zc_ifft, p->corr_spec, p->corr_spec); - - srslte_vec_abs_square_cf(p->corr_spec, p->corr, p->N_zc); - - float corr_ave = srslte_vec_acc_ff(p->corr, p->N_zc) / p->N_zc; - - uint32_t winsize = 0; - if (p->N_cs != 0) { - winsize = p->N_cs; - } else { - winsize = p->N_zc; - } - uint32_t n_wins = p->N_zc / winsize; - - float max_peak = 0; - for (int j = 0; j < n_wins; j++) { - uint32_t start = (p->N_zc - (j * p->N_cs)) % p->N_zc; - uint32_t end = start + winsize; - if (end > p->deadzone) { - end -= p->deadzone; - } - start += p->deadzone; - p->peak_values[j] = 0; - for (int k = start; k < end; k++) { - if (p->corr[k] > p->peak_values[j]) { - p->peak_values[j] = p->corr[k]; - p->peak_offsets[j] = k - start; - if (p->peak_values[j] > max_peak) { - max_peak = p->peak_values[j]; - } - } - } - } - if (max_peak > p->detect_factor * corr_ave) { - for (int j = 0; j < n_wins; j++) { - if (p->peak_values[j] > p->detect_factor * corr_ave) { - if (indices) { - if (p->successive_cancellation) { - if (max_peak > max_to_cancel) { - cancellation_idx = (i * n_wins) + j; - max_to_cancel = max_peak; - prach_cancel.idx = cancellation_idx; - prach_cancel.offset = srslte_prach_set_offset(p,j); - prach_cancel.factor = sqrt((max_peak/2)/((sig_len/2)*p->N_zc*p->N_zc)); - } - if (srslte_prach_have_stored(p,((i * n_wins) + j),indices, *n_indices)) { - break; - } - } - indices[*n_indices] = (i * n_wins) + j; - } - if (peak_to_avg) { - peak_to_avg[*n_indices] = p->peak_values[j] / corr_ave; - } - if (t_offsets) { - t_offsets[*n_indices] = srslte_prach_set_offset(p,j); - } - (*n_indices)++; - } - } - } - } - if (cancellation_idx != -1) { - srslte_prach_cancellation(p, signal, begin, sig_len, prach_cancel); - } else { + if (srslte_prach_process( + p, signal, indices, t_offsets, peak_to_avg, n_indices, cancellation_idx, prach_cancel, begin, sig_len)) { break; } } diff --git a/lib/src/phy/phch/test/prach_test_multi.c b/lib/src/phy/phch/test/prach_test_multi.c index 8ca2133ba..b6320eff0 100644 --- a/lib/src/phy/phch/test/prach_test_multi.c +++ b/lib/src/phy/phch/test/prach_test_multi.c @@ -33,7 +33,7 @@ #include "srslte/phy/phch/prach.h" #include "srslte/phy/utils/debug.h" char* input_file_name = NULL; - +#define PRACH_SRATE 1048750 #define MAX_LEN 70176 int offset = -1; @@ -45,7 +45,7 @@ uint32_t n_seqs = 64; uint32_t num_ra_preambles = 0; // use default bool test_successive_cancellation = false; -bool test_offset_calculation = false; +bool test_offset_calculation = true; srslte_filesource_t fsrc; void usage(char* prog) @@ -96,18 +96,23 @@ void stagger_prach_powers(srslte_prach_t prach, cf_t *preamble, cf_t* preamble_s for (int seq_index = 0; seq_index < n_seqs; seq_index++) { srslte_prach_gen(&prach, seq_index, freq_offset, preamble); if (seq_index == 0) { + srslte_vec_sc_prod_ccc(preamble, cexpf(_Complex_I * 0.1), preamble, prach.N_cp + prach.N_seq); srslte_vec_sc_prod_cfc(preamble, 0.1, preamble, prach.N_cp + prach.N_seq); } if (seq_index == 1) { + srslte_vec_sc_prod_ccc(preamble, cexpf(_Complex_I * 0.4), preamble, prach.N_cp + prach.N_seq); srslte_vec_sc_prod_cfc(preamble, 0.4, preamble, prach.N_cp + prach.N_seq); } if (seq_index == 2) { + srslte_vec_sc_prod_ccc(preamble, cexpf(_Complex_I * 0.1), preamble, prach.N_cp + prach.N_seq); srslte_vec_sc_prod_cfc(preamble, 0.07, preamble, prach.N_cp + prach.N_seq); } if (seq_index == 3) { + srslte_vec_sc_prod_ccc(preamble, cexpf(_Complex_I * 0.9), preamble, prach.N_cp + prach.N_seq); srslte_vec_sc_prod_cfc(preamble,0.6, preamble, prach.N_cp + prach.N_seq); } if (seq_index == 4) { + srslte_vec_sc_prod_ccc(preamble, cexpf(_Complex_I * 0.3), preamble, prach.N_cp + prach.N_seq); srslte_vec_sc_prod_cfc(preamble, 1, preamble, prach.N_cp + prach.N_seq); } if (seq_index == 5) { @@ -151,15 +156,16 @@ int main(int argc, char** argv) int srate = srslte_sampling_freq_hz(nof_prb); - int divisor = srate/1048750; + int divisor = srate / PRACH_SRATE; if (test_offset_calculation) { - n_seqs = 15; - prach_cfg.num_ra_preambles = 15; + n_seqs = 1; + prach_cfg.num_ra_preambles = 4; prach_cfg.zero_corr_zone = 0; printf("limiting number of preambles to 15 for offset calculation test\n"); for (int i = 0; i < 15; i++) { offsets[i] = ((rand()%(25*divisor))); } + memset(offsets, 0, sizeof(int) * 64); } if (test_successive_cancellation) { printf("limiting number of preambles to 6 for successive cancellation test\n"); @@ -206,9 +212,12 @@ int main(int argc, char** argv) if (preamble_format == 2 || preamble_format == 3) { prach_len /= 2; } - + struct timeval t[3]; + gettimeofday(&t[1], NULL); srslte_prach_detect_offset(&prach, 0, &preamble_sum[prach.N_cp], prach_len, indices, t_offsets , NULL, &n_indices); - + gettimeofday(&t[2], NULL); + get_time_interval(t); + printf("texec=%ld us\n", t[0].tv_usec); int err = 0; if (n_indices != n_seqs) { printf("n_indices %d n_seq %d\n", n_indices, n_seqs);