int srslte_prach_gen(srslte_prach_t *p, uint32_t seq_index, uint32_t freq_offset, cf_t *signal) { int ret = SRSLTE_ERROR; if(p != NULL && seq_index < N_SEQS && signal != NULL) { // Calculate parameters uint32_t N_rb_ul = srslte_nof_prb(p->N_ifft_ul); uint32_t k_0 = freq_offset*N_RB_SC - N_rb_ul*N_RB_SC/2 + p->N_ifft_ul/2; uint32_t K = DELTA_F/DELTA_F_RA; uint32_t begin = PHI + (K*k_0) + (K/2); if (6 + freq_offset > N_rb_ul) { fprintf(stderr, "Error no space for PRACH: frequency offset=%d, N_rb_ul=%d\n", freq_offset, N_rb_ul); return ret; } DEBUG("N_zc: %d, N_cp: %d, N_seq: %d, N_ifft_prach=%d begin: %d\n", p->N_zc, p->N_cp, p->N_seq, p->N_ifft_prach, begin); // Map dft-precoded sequence to ifft bins memset(p->ifft_in, 0, begin*sizeof(cf_t)); memcpy(&p->ifft_in[begin], p->dft_seqs[seq_index], p->N_zc * sizeof(cf_t)); memset(&p->ifft_in[begin+p->N_zc], 0, (p->N_ifft_prach - begin - p->N_zc) * sizeof(cf_t)); srslte_dft_run(p->ifft, p->ifft_in, p->ifft_out); // Copy CP into buffer memcpy(signal, &p->ifft_out[p->N_ifft_prach-p->N_cp], p->N_cp*sizeof(cf_t)); // Copy preamble sequence into buffer for(int i=0;i<p->N_seq;i++){ signal[p->N_cp+i] = p->ifft_out[i%p->N_ifft_prach]; } ret = SRSLTE_SUCCESS; } return ret; }
int srslte_prach_detect(srslte_prach_t *p, uint32_t freq_offset, cf_t *signal, uint32_t sig_len, uint32_t *indices, uint32_t *n_indices) { int ret = SRSLTE_ERROR; if(p != NULL && signal != NULL && sig_len > 0 && indices != NULL) { if(sig_len != p->N_ifft_prach){ INFO("srslte_prach_detect: Signal is not of length %d", p->N_ifft_prach); return SRSLTE_ERROR_INVALID_INPUTS; } // FFT incoming signal srslte_dft_run(p->fft, signal, signal); memset(p->prach_bins, 0, sizeof(cf_t)*p->N_zc); *n_indices = 0; // Extract bins of interest uint32_t N_rb_ul = prach_get_rb_ul(p->N_ifft_ul); uint32_t k_0 = freq_offset*N_RB_SC - N_rb_ul*N_RB_SC/2 + p->N_ifft_ul/2; uint32_t K = DELTA_F/DELTA_F_RA; uint32_t begin = PHI + (K*k_0) + (K/2); for(int i=0;i<p->N_zc;i++){ p->prach_bins[i] = signal[begin+i]; } for(int i=0;i<p->N_roots;i++){ memset(p->corr_spec, 0, sizeof(cf_t)*p->N_zc); memset(p->corr, 0, sizeof(float)*p->N_zc); float corr_max = 0; float corr_ave = 0; cf_t *root_spec = p->dft_seqs[p->root_seqs_idx[i]]; for(int j=0;j<p->N_zc;j++){ p->corr_spec[j] = p->prach_bins[j]*conjf(root_spec[j]); } srslte_dft_run(p->zc_ifft, p->corr_spec, p->corr_spec); float norm = sqrtf(p->N_zc); for(int j=0;j<p->N_zc;j++){ p->corr[j] = cabsf(p->corr_spec[j])/norm; corr_ave += p->corr[j]; } corr_ave /= 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; 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; corr_max = 0; for(int k=start;k<end;k++){ if(p->corr[k] > corr_max){ corr_max = p->corr[k]; } } if(corr_max > PRACH_DETECT_FACTOR*corr_ave){ indices[*n_indices] = (i*n_wins)+j; (*n_indices)++; } } } ret = SRSLTE_SUCCESS; } return ret; }
int srslte_prach_init(srslte_prach_t *p, uint32_t N_ifft_ul, uint32_t preamble_format, uint32_t root_seq_index, bool high_speed_flag, uint32_t zero_corr_zone_config) { int ret = SRSLTE_ERROR; if(p != NULL && N_ifft_ul < 2049 && preamble_format < 4 && // Currently supporting formats 0-3 root_seq_index < MAX_ROOTS && zero_corr_zone_config < 16) { p->f = preamble_format; p->rsi = root_seq_index; p->hs = high_speed_flag; p->zczc = zero_corr_zone_config; // Determine N_zc and N_cs if(4 == preamble_format){ p->N_zc = 139; p->N_cs = prach_Ncs_format4[p->zczc]; }else{ p->N_zc = 839; if(p->hs){ p->N_cs = prach_Ncs_restricted[p->zczc]; }else{ p->N_cs = prach_Ncs_unrestricted[p->zczc]; } } // Set up containers p->prach_bins = srslte_vec_malloc(sizeof(cf_t)*p->N_zc); p->corr_spec = srslte_vec_malloc(sizeof(cf_t)*p->N_zc); p->corr = srslte_vec_malloc(sizeof(float)*p->N_zc); // Set up ZC FFTS p->zc_fft = (srslte_dft_plan_t*)srslte_vec_malloc(sizeof(srslte_dft_plan_t)); if(srslte_dft_plan(p->zc_fft, p->N_zc, 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); p->zc_ifft = (srslte_dft_plan_t*)srslte_vec_malloc(sizeof(srslte_dft_plan_t)); if(srslte_dft_plan(p->zc_ifft, p->N_zc, SRSLTE_DFT_BACKWARD, SRSLTE_DFT_COMPLEX)){ return SRSLTE_ERROR; } srslte_dft_plan_set_mirror(p->zc_ifft, false); srslte_dft_plan_set_norm(p->zc_ifft, true); // Generate our 64 sequences p->N_roots = 0; srslte_prach_gen_seqs(p); // Generate sequence FFTs for(int i=0;i<N_SEQS;i++){ srslte_dft_run(p->zc_fft, p->seqs[i], p->dft_seqs[i]); } // Create our FFT objects and buffers p->N_ifft_ul = N_ifft_ul; if(4 == preamble_format){ p->N_ifft_prach = p->N_ifft_ul * DELTA_F/DELTA_F_RA_4; }else{ p->N_ifft_prach = p->N_ifft_ul * DELTA_F/DELTA_F_RA; } p->ifft_in = (cf_t*)srslte_vec_malloc(p->N_ifft_prach*sizeof(cf_t)); p->ifft_out = (cf_t*)srslte_vec_malloc(p->N_ifft_prach*sizeof(cf_t)); p->ifft = (srslte_dft_plan_t*)srslte_vec_malloc(sizeof(srslte_dft_plan_t)); if(srslte_dft_plan(p->ifft, p->N_ifft_prach, SRSLTE_DFT_BACKWARD, SRSLTE_DFT_COMPLEX)) { fprintf(stderr, "Error creating DFT plan\n"); return -1; } srslte_dft_plan_set_mirror(p->ifft, true); srslte_dft_plan_set_norm(p->ifft, true); p->fft = (srslte_dft_plan_t*)srslte_vec_malloc(sizeof(srslte_dft_plan_t)); if(srslte_dft_plan(p->fft, p->N_ifft_prach, SRSLTE_DFT_FORWARD, SRSLTE_DFT_COMPLEX)){ fprintf(stderr, "Error creating DFT plan\n"); return -1; } srslte_dft_plan_set_mirror(p->fft, true); srslte_dft_plan_set_norm(p->fft, true); p->N_seq = prach_Tseq[p->f]*p->N_ifft_ul/2048; p->N_cp = prach_Tcp[p->f]*p->N_ifft_ul/2048; ret = SRSLTE_SUCCESS; } else { fprintf(stderr, "Invalid parameters\n"); } return ret; }
int srslte_prach_detect_offset(srslte_prach_t *p, uint32_t freq_offset, cf_t *signal, uint32_t sig_len, uint32_t *indices, float *t_offsets, float *peak_to_avg, uint32_t *n_indices) { int ret = SRSLTE_ERROR; if(p != NULL && signal != NULL && sig_len > 0 && indices != NULL) { if(sig_len < p->N_ifft_prach){ fprintf(stderr, "srslte_prach_detect: Signal length is %d and should be %d\n", sig_len, p->N_ifft_prach); return SRSLTE_ERROR_INVALID_INPUTS; } // FFT incoming signal srslte_dft_run(p->fft, signal, p->signal_fft); *n_indices = 0; // Extract bins of interest uint32_t N_rb_ul = srslte_nof_prb(p->N_ifft_ul); uint32_t k_0 = freq_offset*N_RB_SC - N_rb_ul*N_RB_SC/2 + p->N_ifft_ul/2; uint32_t K = DELTA_F/DELTA_F_RA; uint32_t begin = PHI + (K*k_0) + (K/2); memcpy(p->prach_bins, &p->signal_fft[begin], p->N_zc*sizeof(cf_t)); for(int i=0;i<p->N_roots;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) { printf("ncs=%d, nzc=%d, nwins=%d, Nroot=%d, i=%d, j=%d, start=%d, peak_value=%f, peak_offset=%d, tseq=%f\n", p->N_cs, p->N_zc, n_wins, p->N_roots, i, j, (p->N_zc-(j*p->N_cs))%p->N_zc, p->peak_values[j], p->peak_offsets[j], p->T_seq*1e6); memcpy(save_corr, p->corr, p->N_zc*sizeof(float)); if (indices) { 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] = (float) p->peak_offsets[j]*p->T_seq/p->N_zc; } (*n_indices)++; } } } } ret = SRSLTE_SUCCESS; } return ret; }
int srslte_prach_init(srslte_prach_t *p, uint32_t N_ifft_ul, uint32_t config_idx, uint32_t root_seq_index, bool high_speed_flag, uint32_t zero_corr_zone_config) { int ret = SRSLTE_ERROR; if(p != NULL && N_ifft_ul < 2049 && config_idx < 16 && root_seq_index < MAX_ROOTS) { uint32_t preamble_format = srslte_prach_get_preamble_format(config_idx); p->config_idx = config_idx; p->f = preamble_format; p->rsi = root_seq_index; p->hs = high_speed_flag; p->zczc = zero_corr_zone_config; p->detect_factor = PRACH_DETECT_FACTOR; // Determine N_zc and N_cs if(4 == preamble_format){ if (p->zczc < 7) { p->N_zc = 139; p->N_cs = prach_Ncs_format4[p->zczc]; } else { fprintf(stderr, "Invalid zeroCorrelationZoneConfig=%d for format4\n", p->zczc); return SRSLTE_ERROR; } }else{ p->N_zc = 839; if(p->hs){ if (p->zczc < 15) { p->N_cs = prach_Ncs_restricted[p->zczc]; } else { fprintf(stderr, "Invalid zeroCorrelationZoneConfig=%d for restricted set\n", p->zczc); return SRSLTE_ERROR; } }else{ if (p->zczc < 16) { p->N_cs = prach_Ncs_unrestricted[p->zczc]; } else { fprintf(stderr, "Invalid zeroCorrelationZoneConfig=%d\n", p->zczc); return SRSLTE_ERROR; } } } // Set up containers p->prach_bins = srslte_vec_malloc(sizeof(cf_t)*p->N_zc); p->corr_spec = srslte_vec_malloc(sizeof(cf_t)*p->N_zc); p->corr = srslte_vec_malloc(sizeof(float)*p->N_zc); // Set up ZC FFTS p->zc_fft = (srslte_dft_plan_t*)srslte_vec_malloc(sizeof(srslte_dft_plan_t)); if(srslte_dft_plan(p->zc_fft, p->N_zc, 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); p->zc_ifft = (srslte_dft_plan_t*)srslte_vec_malloc(sizeof(srslte_dft_plan_t)); if(srslte_dft_plan(p->zc_ifft, p->N_zc, SRSLTE_DFT_BACKWARD, SRSLTE_DFT_COMPLEX)){ return SRSLTE_ERROR; } srslte_dft_plan_set_mirror(p->zc_ifft, false); srslte_dft_plan_set_norm(p->zc_ifft, false); // Generate our 64 sequences p->N_roots = 0; srslte_prach_gen_seqs(p); // Generate sequence FFTs for(int i=0;i<N_SEQS;i++){ srslte_dft_run(p->zc_fft, p->seqs[i], p->dft_seqs[i]); } // Create our FFT objects and buffers p->N_ifft_ul = N_ifft_ul; if(4 == preamble_format){ p->N_ifft_prach = p->N_ifft_ul * DELTA_F/DELTA_F_RA_4; }else{ p->N_ifft_prach = p->N_ifft_ul * DELTA_F/DELTA_F_RA; } /* The deadzone specifies the number of samples at the end of the correlation window * that will be considered as belonging to the next preamble */ p->deadzone = 0; /* if(p->N_cs != 0) { float samp_rate=15000*p->N_ifft_ul; p->deadzone = (uint32_t) ceil((float) samp_rate/((float) p->N_zc*subcarrier_spacing)); }*/ p->ifft_in = (cf_t*)srslte_vec_malloc(p->N_ifft_prach*sizeof(cf_t)); p->ifft_out = (cf_t*)srslte_vec_malloc(p->N_ifft_prach*sizeof(cf_t)); p->ifft = (srslte_dft_plan_t*)srslte_vec_malloc(sizeof(srslte_dft_plan_t)); if(srslte_dft_plan(p->ifft, p->N_ifft_prach, SRSLTE_DFT_BACKWARD, SRSLTE_DFT_COMPLEX)) { fprintf(stderr, "Error creating DFT plan\n"); return -1; } srslte_dft_plan_set_mirror(p->ifft, true); srslte_dft_plan_set_norm(p->ifft, true); p->fft = (srslte_dft_plan_t*)srslte_vec_malloc(sizeof(srslte_dft_plan_t)); if(srslte_dft_plan(p->fft, p->N_ifft_prach, SRSLTE_DFT_FORWARD, SRSLTE_DFT_COMPLEX)){ fprintf(stderr, "Error creating DFT plan\n"); return -1; } p->signal_fft = srslte_vec_malloc(sizeof(cf_t)*p->N_ifft_prach); if (!p->signal_fft) { fprintf(stderr, "Error allocating memory\n"); return -1; } srslte_dft_plan_set_mirror(p->fft, true); srslte_dft_plan_set_norm(p->fft, false); p->N_seq = prach_Tseq[p->f]*p->N_ifft_ul/2048; p->N_cp = prach_Tcp[p->f]*p->N_ifft_ul/2048; p->T_seq = prach_Tseq[p->f]*SRSLTE_LTE_TS; ret = SRSLTE_SUCCESS; } else { fprintf(stderr, "Invalid parameters\n"); } return ret; }