static void corr_all_zs(cf_t z[SRSLTE_SSS_N], float s[SRSLTE_SSS_N][SRSLTE_SSS_N-1], float output[SRSLTE_SSS_N]) { uint32_t m; cf_t tmp[SRSLTE_SSS_N]; for (m = 0; m < SRSLTE_SSS_N; m++) { tmp[m] = srslte_vec_dot_prod_cfc(z, s[m], SRSLTE_SSS_N - 1); } srslte_vec_abs_square_cf(tmp, output, SRSLTE_SSS_N); }
/* Complex division is conjugate multiplication + real division */ void srslte_vec_div_ccc(cf_t *x, cf_t *y, float *y_mod, cf_t *z, float *z_real, float *z_imag, uint32_t len) { #ifdef DIV_USE_VEC srslte_vec_prod_conj_ccc(x,y,z,len); srslte_vec_abs_square_cf(y,y_mod,len); srslte_vec_div_cfc(z,y_mod,z,z_real,z_imag,len); #else int i; for (i=0;i<len;i++) { z[i] = x[i] / y[i]; } #endif }
static void corr_all_sz_partial(cf_t z[SRSLTE_SSS_N], float s[SRSLTE_SSS_N][SRSLTE_SSS_N], uint32_t M, float output[SRSLTE_SSS_N]) { uint32_t Nm = SRSLTE_SSS_N/M; cf_t tmp[SRSLTE_SSS_N]; float tmp_abs[MAX_M-1][SRSLTE_SSS_N]; int j, m; float *ptr; for (j=0;j<M;j++) { for (m = 0; m < SRSLTE_SSS_N; m++) { tmp[m] = srslte_vec_dot_prod_cfc(&z[j*Nm], &s[m][j*Nm], Nm); } if (j == 0) { ptr = output; } else { ptr = tmp_abs[j-1]; } srslte_vec_abs_square_cf(tmp, ptr, SRSLTE_SSS_N); } for (j=1;j<M;j++) { srslte_vec_sum_fff(tmp_abs[j-1], output, output, SRSLTE_SSS_N); } }
/** Performs time-domain PSS correlation. * Returns the index of the PSS correlation peak in a subframe. * The frame starts at corr_peak_pos-subframe_size/2. * The value of the correlation is stored in corr_peak_value. * * Input buffer must be subframe_size long. */ int srslte_pss_synch_find_pss(srslte_pss_synch_t *q, cf_t *input, float *corr_peak_value) { int ret = SRSLTE_ERROR_INVALID_INPUTS; if (q != NULL && input != NULL) { uint32_t corr_peak_pos; uint32_t conv_output_len; if (!srslte_N_id_2_isvalid(q->N_id_2)) { fprintf(stderr, "Error finding PSS peak, Must set N_id_2 first\n"); return SRSLTE_ERROR; } /* Correlate input with PSS sequence */ if (q->frame_size >= q->fft_size) { #ifdef CONVOLUTION_FFT memcpy(q->tmp_input, input, q->frame_size * sizeof(cf_t)); conv_output_len = srslte_conv_fft_cc_run(&q->conv_fft, q->tmp_input, q->pss_signal_time[q->N_id_2], q->conv_output); #else conv_output_len = srslte_conv_cc(input, q->pss_signal_time[q->N_id_2], q->conv_output, q->frame_size, q->fft_size); #endif } else { for (int i=0;i<q->frame_size;i++) { q->conv_output[i] = srslte_vec_dot_prod_ccc(q->pss_signal_time[q->N_id_2], &input[i], q->fft_size); } conv_output_len = q->frame_size; } #ifdef SRSLTE_PSS_ABS_SQUARE srslte_vec_abs_square_cf(q->conv_output, q->conv_output_abs, conv_output_len-1); #else srslte_vec_abs_cf(q->conv_output, q->conv_output_abs, conv_output_len-1); #endif srslte_vec_sc_prod_fff(q->conv_output_abs, q->ema_alpha, q->conv_output_abs, conv_output_len-1); srslte_vec_sc_prod_fff(q->conv_output_avg, 1-q->ema_alpha, q->conv_output_avg, conv_output_len-1); srslte_vec_sum_fff(q->conv_output_abs, q->conv_output_avg, q->conv_output_avg, conv_output_len-1); /* Find maximum of the absolute value of the correlation */ corr_peak_pos = srslte_vec_max_fi(q->conv_output_avg, conv_output_len-1); // save absolute value q->peak_value = q->conv_output_avg[corr_peak_pos]; #ifdef SRSLTE_PSS_RETURN_PSR // Find second side lobe // Find end of peak lobe to the right int pl_ub = corr_peak_pos+1; while(q->conv_output_avg[pl_ub+1] <= q->conv_output_avg[pl_ub] && pl_ub < conv_output_len) { pl_ub ++; } // Find end of peak lobe to the left int pl_lb; if (corr_peak_pos > 2) { pl_lb = corr_peak_pos-1; while(q->conv_output_avg[pl_lb-1] <= q->conv_output_avg[pl_lb] && pl_lb > 1) { pl_lb --; } } else { pl_lb = 0; } int sl_distance_right = conv_output_len-1-pl_ub; if (sl_distance_right < 0) { sl_distance_right = 0; } int sl_distance_left = pl_lb; int sl_right = pl_ub+srslte_vec_max_fi(&q->conv_output_avg[pl_ub], sl_distance_right); int sl_left = srslte_vec_max_fi(q->conv_output_avg, sl_distance_left); float side_lobe_value = SRSLTE_MAX(q->conv_output_avg[sl_right], q->conv_output_avg[sl_left]); if (corr_peak_value) { *corr_peak_value = q->conv_output_avg[corr_peak_pos]/side_lobe_value; DEBUG("peak_pos=%2d, pl_ub=%2d, pl_lb=%2d, sl_right: %2d, sl_left: %2d, PSR: %.2f/%.2f=%.2f\n", corr_peak_pos, pl_ub, pl_lb, sl_right,sl_left, q->conv_output_avg[corr_peak_pos], side_lobe_value,*corr_peak_value); } #else if (corr_peak_value) { *corr_peak_value = q->conv_output_avg[corr_peak_pos]; } #endif if (q->frame_size >= q->fft_size) { ret = (int) corr_peak_pos; } else { ret = (int) corr_peak_pos + q->fft_size; } } return ret; }
/** Performs time-domain PSS correlation. * Returns the index of the PSS correlation peak in a subframe. * The frame starts at corr_peak_pos-subframe_size/2. * The value of the correlation is stored in corr_peak_value. * * Input buffer must be subframe_size long. */ int srslte_pss_find_pss(srslte_pss_t *q, const cf_t *input, float *corr_peak_value) { int ret = SRSLTE_ERROR_INVALID_INPUTS; if (q != NULL && input != NULL) { uint32_t corr_peak_pos; uint32_t conv_output_len; if (!srslte_N_id_2_isvalid(q->N_id_2)) { ERROR("Error finding PSS peak, Must set N_id_2 first\n"); return SRSLTE_ERROR; } /* Correlate input with PSS sequence * * We do not reverse time-domain PSS signal because it's conjugate is symmetric. * The conjugate operation on pss_signal_time has been done in srslte_pss_init_N_id_2 * This is why we can use FFT-based convolution */ if (q->frame_size >= q->fft_size) { #ifdef CONVOLUTION_FFT memcpy(q->tmp_input, input, (q->frame_size * q->decimate) * sizeof(cf_t)); if(q->decimate > 1) { srslte_filt_decim_cc_execute(&(q->filter), q->tmp_input, q->filter.downsampled_input, q->filter.filter_output , (q->frame_size * q->decimate)); conv_output_len = srslte_conv_fft_cc_run_opt(&q->conv_fft, q->filter.filter_output,q->pss_signal_freq_full[q->N_id_2], q->conv_output); } else { conv_output_len = srslte_conv_fft_cc_run_opt(&q->conv_fft, q->tmp_input, q->pss_signal_freq_full[q->N_id_2], q->conv_output); } #else conv_output_len = srslte_conv_cc(input, q->pss_signal_time[q->N_id_2], q->conv_output, q->frame_size, q->fft_size); #endif } else { for (int i=0;i<q->frame_size;i++) { q->conv_output[i] = srslte_vec_dot_prod_ccc(q->pss_signal_time[q->N_id_2], &input[i], q->fft_size); } conv_output_len = q->frame_size; } // Compute modulus square srslte_vec_abs_square_cf(q->conv_output, q->conv_output_abs, conv_output_len-1); // If enabled, average the absolute value from previous calls if (q->ema_alpha < 1.0 && q->ema_alpha > 0.0) { srslte_vec_sc_prod_fff(q->conv_output_abs, q->ema_alpha, q->conv_output_abs, conv_output_len-1); srslte_vec_sc_prod_fff(q->conv_output_avg, 1-q->ema_alpha, q->conv_output_avg, conv_output_len-1); srslte_vec_sum_fff(q->conv_output_abs, q->conv_output_avg, q->conv_output_avg, conv_output_len-1); } else { memcpy(q->conv_output_avg, q->conv_output_abs, sizeof(float)*(conv_output_len-1)); } /* Find maximum of the absolute value of the correlation */ corr_peak_pos = srslte_vec_max_fi(q->conv_output_avg, conv_output_len-1); // save absolute value q->peak_value = q->conv_output_avg[corr_peak_pos]; #ifdef SRSLTE_PSS_RETURN_PSR if (corr_peak_value) { *corr_peak_value = compute_peak_sidelobe(q, corr_peak_pos, conv_output_len); } #else if (corr_peak_value) { *corr_peak_value = q->conv_output_avg[corr_peak_pos]; } #endif if(q->decimate >1) { int decimation_correction = (q->filter.num_taps - 2); corr_peak_pos = corr_peak_pos - decimation_correction; corr_peak_pos = corr_peak_pos*q->decimate; } if (q->frame_size >= q->fft_size) { ret = (int) corr_peak_pos; } else { ret = (int) corr_peak_pos + q->fft_size; } } 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; }