free5g

mail@pastecode.io avatar
unknown
c_cpp
2 years ago
8.1 kB
2
Indexable
Never
void free5GRAN::phy::synchronization::search_pss(int& n_id_2,
                                                 int& synchronisation_index,
                                                 float& peak_value,
                                                 int cp_length,
                                                 vector<complex<float>>& buff,
                                                 int fft_size) {
  /**
   * \fn search_pss
   * \brief Search for PSS correlation peak inside a signal.
   * \details
   * Details:
   * - Generating the three possible PSS sequences (for N_ID_2 in [0,1,2])
   * - Performing iFFT to retreive Time domain PSS sequence
   * - Cross-correlation between received signal and three time domain PSS
   * signals
   * - Return PSS sequence with highest correlation peak.
   *
   * \param[out] n_id_2: Returned N_ID_2
   * \param[out] synchronisation_index: Synchronization index corresponding to
   * correlation peak \param[out] peak_value: Peak height \param[in] cp_length:
   * Cyclic prefix length \param[in] buff: Input IQ signal \param[in] fft_size:
   * FFT size and symbol size
   */

  /*
   * Generate complex arrays to store IFFT signals for the three different PSS
   * sequence
   */
  auto* pss_in_0 = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * fft_size);
  auto* pss_out_0 = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * fft_size);
  auto* pss_in_1 = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * fft_size);
  auto* pss_out_1 = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * fft_size);
  auto* pss_in_2 = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * fft_size);
  auto* pss_out_2 = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * fft_size);

  /*
   * Generate IFFT plans for the three different PSS sequence
   */
  fftw_plan ifft_plan_0 = fftw_plan_dft_1d(fft_size, pss_in_0, pss_out_0,
                                           FFTW_BACKWARD, FFTW_MEASURE);
  fftw_plan ifft_plan_1 = fftw_plan_dft_1d(fft_size, pss_in_1, pss_out_1,
                                           FFTW_BACKWARD, FFTW_MEASURE);
  fftw_plan ifft_plan_2 = fftw_plan_dft_1d(fft_size, pss_in_2, pss_out_2,
                                           FFTW_BACKWARD, FFTW_MEASURE);

  /*
   * Initialize arrays
   */
  for (int i = 0; i < fft_size; i++) {
    pss_in_0[i][0] = 0;
    pss_in_0[i][1] = 0;

    pss_in_1[i][0] = 0;
    pss_in_1[i][1] = 0;

    pss_in_2[i][0] = 0;
    pss_in_2[i][1] = 0;
  }

  /*
   * Generate and get PSS sequences
   */
  int pss_0_seq[free5GRAN::SIZE_PSS_SSS_SIGNAL],
      pss_1_seq[free5GRAN::SIZE_PSS_SSS_SIGNAL],
      pss_2_seq[free5GRAN::SIZE_PSS_SSS_SIGNAL];

  free5GRAN::utils::sequence_generator::generate_pss_sequence(0, pss_0_seq);
  free5GRAN::utils::sequence_generator::generate_pss_sequence(1, pss_1_seq);
  free5GRAN::utils::sequence_generator::generate_pss_sequence(2, pss_2_seq);

  /*
   * Generate frequency domain signal (PSS is BPSK modulated, real part is the
   * pss sequence value and imaginary part is 0)
   */
  for (int i = 0; i < fft_size / 2; i++) {
    if (i < 63) {
      pss_in_0[i][0] = pss_0_seq[i + 64];
      pss_in_0[i][1] = 0;

      pss_in_1[i][0] = pss_1_seq[i + 64];
      pss_in_1[i][1] = 0;

      pss_in_2[i][0] = pss_2_seq[i + 64];
      pss_in_2[i][1] = 0;
    }
    if (i < 64) {
      pss_in_0[fft_size - i - 1][0] = pss_0_seq[64 - i - 1];
      pss_in_0[fft_size - i - 1][1] = 0;

      pss_in_1[fft_size - i - 1][0] = pss_1_seq[64 - i - 1];
      pss_in_1[fft_size - i - 1][1] = 0;

      pss_in_2[fft_size - i - 1][0] = pss_2_seq[64 - i - 1];
      pss_in_2[fft_size - i - 1][1] = 0;
    }
  }

  /*
   * Execute the IFFT
   */
  fftw_execute(ifft_plan_0);
  fftw_execute(ifft_plan_1);
  fftw_execute(ifft_plan_2);

  vector<complex<float>> time_signal_pss_0(cp_length + fft_size),
      time_signal_pss_1(cp_length + fft_size),
      time_signal_pss_2(cp_length + fft_size);
  /*
   * Transform fftw complex signals into vectors of complex values and add
   * cyclic prefix
   */
  for (int i = 0; i < cp_length + fft_size; i++) {
    if (i < cp_length) {
      time_signal_pss_0[i] =
          complex<float>(pss_out_0[fft_size - cp_length + i][0],
                         pss_out_0[fft_size - cp_length + i][1]);

      time_signal_pss_1[i] =
          complex<float>(pss_out_1[fft_size - cp_length + i][0],
                         pss_out_1[fft_size - cp_length + i][1]);

      time_signal_pss_2[i] =
          complex<float>(pss_out_2[fft_size - cp_length + i][0],
                         pss_out_2[fft_size - cp_length + i][1]);
    } else {
      time_signal_pss_0[i] = complex<float>(pss_out_0[i - cp_length][0],
                                            pss_out_0[i - cp_length][1]);

      time_signal_pss_1[i] = complex<float>(pss_out_1[i - cp_length][0],
                                            pss_out_1[i - cp_length][1]);

      time_signal_pss_2[i] = complex<float>(pss_out_2[i - cp_length][0],
                                            pss_out_2[i - cp_length][1]);
    }
  }

  size_t num_samples = buff.size();
  complex<float> corr_0[num_samples + fft_size + cp_length - 1],
      corr_1[num_samples + fft_size + cp_length - 1],
      corr_2[num_samples + fft_size + cp_length - 1];

  /* Correlate the three possible PSS sequences
   with the time-domain signal
   buff is the time-domain signal
   time_signal_pss_0, time_signal_pss_1
   and time_signal_pss_2 are the time domain PSS signals
   corr_0, corr_1 and corr_2 are the cross correlation output
   num_samples is the size of the buffer
   fft_size + cp_length corresponds to
   the size of a symbol (in samples)*/
  cross_correlation(buff, time_signal_pss_0, &corr_0[0], num_samples,
                    fft_size + cp_length);
  cross_correlation(buff, time_signal_pss_1, &corr_1[0], num_samples,
                    fft_size + cp_length);
  cross_correlation(buff, time_signal_pss_2, &corr_2[0], num_samples,
                    fft_size + cp_length);

  float max_value = -1;
  n_id_2 = -1;
  synchronisation_index = -1;

  // Search for the max value and index over the cross correlation
  for (int i = 0; i < num_samples + fft_size + cp_length - 1; i++) {
    float abs_0_short = abs(corr_0[i]);
    float abs_1_short = abs(corr_1[i]);
    float abs_2_short = abs(corr_2[i]);

    if (abs_0_short > max_value) {
      max_value = abs_0_short;
      n_id_2 = 0;
      synchronisation_index = i;
    } else if (abs_1_short > max_value) {
      max_value = abs_1_short;
      n_id_2 = 1;
      synchronisation_index = i;
    } else if (abs_2_short > max_value) {
      max_value = abs_2_short;
      n_id_2 = 2;
      synchronisation_index = i;
    }
  }
  peak_value = max_value;
}

/*
 * cross_correlation method: cross-correlate two signals in1 and in2 which size
 * are size1 and size2 and put the result in out
 */
void free5GRAN::phy::synchronization::cross_correlation(
    vector<complex<float>> in1,
    vector<complex<float>> in2,
    complex<float>* out,
    int size1,
    int size2) {
  /**
   * \fn cross_correlation
   * \brief Perform cross correlation (i.e. moving window correlation) between
   * signal 1 and signal 2 \param[in] in1: Signal 1 \param[in] in2: Signal 2
   * \param[out] out: Correlation result
   * \param[in] size1: Signal 1 size
   * \param[in] size2: Signal 2 size
   */
  int common = 0;
  int base_id1, base_id2;
  for (int m = 0; m < size1 + size2 - 1; m++) {
    if (m < size2) {
      common++;

      base_id1 = 0;
      base_id2 = size2 - common;

    } else if (m > size1 - 1) {
      common--;

      base_id1 = size1 - common;
      base_id2 = 0;
    } else {
      base_id1 = m + 1 - size2;
      base_id2 = 0;
    }
    out[m] = 0;

    for (int n = 0; n < common; n++) {
      out[m] += in1[base_id1 + n] * conj(in2[base_id2 + n]);
    }
  }
}