Beispiel #1
0
/* Partial correlation SSS estimation. 
 * Returns m0 and m1 estimates 
 *
 * Source: "SSS Detection Method for Initial Cell Search in 3GPP LTE FDD/TDD Dual Mode Receiver"
 *       Jung-In Kim, Jung-Su Han, Hee-Jin Roh and Hyung-Jin Choi

 */
int srslte_sss_synch_m0m1_partial(srslte_sss_synch_t *q, cf_t *input, uint32_t M, cf_t ce[2*SRSLTE_SSS_N], uint32_t *m0, float *m0_value,
    uint32_t *m1, float *m1_value) 
{

  int ret = SRSLTE_ERROR_INVALID_INPUTS; 

  if (q                 != NULL   &&
      input             != NULL   &&
      m0                != NULL   && 
      m1                != NULL   && 
      M                 <= MAX_M)
  {
    cf_t y[2][SRSLTE_SSS_N];
    
    extract_pair_sss(q, input, ce, y);
    
    corr_all_sz_partial(y[0], q->fc_tables[q->N_id_2].s, M, q->corr_output_m0);    
    *m0 = srslte_vec_max_fi(q->corr_output_m0, SRSLTE_SSS_N);
    if (m0_value) {
      *m0_value = q->corr_output_m0[*m0];
    }
    srslte_vec_prod_cfc(y[1], q->fc_tables[q->N_id_2].z1[*m0], y[1], SRSLTE_SSS_N);
    corr_all_sz_partial(y[1], q->fc_tables[q->N_id_2].s, M, q->corr_output_m1);
    *m1 = srslte_vec_max_fi(q->corr_output_m1, SRSLTE_SSS_N);
    if (m1_value) {
      *m1_value = q->corr_output_m1[*m1];
    }    
    ret = SRSLTE_SUCCESS;
  } 
  return ret; 
}
Beispiel #2
0
float compute_peak_sidelobe(srslte_pss_t *q, uint32_t corr_peak_pos, uint32_t conv_output_len)
{
  // 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]);

  return q->conv_output_avg[corr_peak_pos]/side_lobe_value;
}
Beispiel #3
0
/* Differential SSS estimation. 
 * Returns m0 and m1 estimates 
 *
 * Source: "SSS Detection Method for Initial Cell Search in 3GPP LTE FDD/TDD Dual Mode Receiver"
 *       Jung-In Kim, Jung-Su Han, Hee-Jin Roh and Hyung-Jin Choi

 *
 */
int srslte_sss_synch_m0m1_diff_coh(srslte_sss_synch_t *q, cf_t *input, cf_t ce[2*SRSLTE_SSS_N], uint32_t *m0, float *m0_value,
    uint32_t *m1, float *m1_value) 
{

  int ret = SRSLTE_ERROR_INVALID_INPUTS; 

  if (q                 != NULL   &&
      input             != NULL   &&
      m0                != NULL   && 
      m1                != NULL)
  {
    
    cf_t yprod[SRSLTE_SSS_N];
    cf_t y[2][SRSLTE_SSS_N];

    extract_pair_sss(q, input, ce, y);
    
    srslte_vec_prod_conj_ccc(&y[0][1], y[0], yprod, SRSLTE_SSS_N - 1);    
    corr_all_zs(yprod, q->fc_tables[q->N_id_2].sd, q->corr_output_m0);
    *m0 = srslte_vec_max_fi(q->corr_output_m0, SRSLTE_SSS_N);
    if (m0_value) {
      *m0_value = q->corr_output_m0[*m0];
    }    
    
    srslte_vec_prod_cfc(y[1], q->fc_tables[q->N_id_2].z1[*m0], y[1], SRSLTE_SSS_N);
    srslte_vec_prod_conj_ccc(&y[1][1], y[1], yprod, SRSLTE_SSS_N - 1);
    corr_all_zs(yprod, q->fc_tables[q->N_id_2].sd, q->corr_output_m1);
    *m1 = srslte_vec_max_fi(q->corr_output_m1, SRSLTE_SSS_N);
    if (m1_value) {
      *m1_value = q->corr_output_m1[*m1];
    }    
    ret = SRSLTE_SUCCESS;
  } 
  return ret; 
}
Beispiel #4
0
// TODO: Improve this implementation
void srslte_vec_norm_cfc(cf_t *x, float amplitude, cf_t *y, uint32_t len) {
  // We should use fabs() here but is statistically should be similar
  float *xp = (float*) x; 
  uint32_t idx = srslte_vec_max_fi(xp, 2*len);
  float max = xp[idx]; 

  // Normalize before TX 
  srslte_vec_sc_prod_cfc(x, amplitude/max, y, len);
}
Beispiel #5
0
/** 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;
}
Beispiel #6
0
/** 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;
}
Beispiel #7
0
void srslte_agc_process(srslte_agc_t *q, cf_t *signal, uint32_t len) {
  float gain_db = 10*log10(q->gain); 
  float gain_uhd_db = 1.0;
  //float gain_uhd = 1.0;  
  float y = 0; 
  // Apply current gain to input signal 
  if (!q->uhd_handler) {
    srslte_vec_sc_prod_cfc(signal, q->gain, signal, len);
  } else {
    if (q->gain < 1) {
      q->gain = 1.0; 
    }
    if (isinf(gain_db) || isnan(gain_db)) {
      q->gain = 10.0; 
    } else {
      gain_uhd_db = q->set_gain_callback(q->uhd_handler, gain_db);        
      q->gain = pow(10, gain_uhd_db/10);
    }
  }
  float *t; 
  switch(q->mode) {
    case SRSLTE_AGC_MODE_ENERGY:
      y = sqrtf(crealf(srslte_vec_dot_prod_conj_ccc(signal, signal, len))/len);
      break;
    case SRSLTE_AGC_MODE_PEAK_AMPLITUDE:
      t = (float*) signal; 
      y = t[srslte_vec_max_fi(t, 2*len)];// take only positive max to avoid abs() (should be similar) 
      break;
    default: 
      fprintf(stderr, "Unsupported AGC mode\n");
      return; 
  }
  
  if (q->nof_frames > 0) {
    q->y_tmp[q->frame_cnt++] = y; 
    if (q->frame_cnt == q->nof_frames) {
      q->frame_cnt = 0; 
      switch(q->mode) {
        case SRSLTE_AGC_MODE_ENERGY:
          y = srslte_vec_acc_ff(q->y_tmp, q->nof_frames)/q->nof_frames;
          break;
        case SRSLTE_AGC_MODE_PEAK_AMPLITUDE:
          y = q->y_tmp[srslte_vec_max_fi(q->y_tmp, q->nof_frames)];
          break;
        default: 
          fprintf(stderr, "Unsupported AGC mode\n");
          return; 
      }
    }
  }
  
  double gg = 1.0; 
  if (q->isfirst) {
    q->y_out = y; 
    q->isfirst = false; 
  } else {
    if (q->frame_cnt == 0) {
      q->y_out = (1-q->bandwidth) * q->y_out + q->bandwidth * y;
      if (!q->lock) {
        gg = expf(-0.5*q->bandwidth*logf(q->y_out/q->target));
        q->gain *= gg; 
      }          
      INFO("AGC gain: %.2f (%.2f) y_out=%.3f, y=%.3f target=%.1f gg=%.2f\n", gain_db, gain_uhd_db, q->y_out, y, q->target, gg);      
    }
  }
}
Beispiel #8
0
static int srslte_pdsch_codeword_decode(srslte_pdsch_t *q, srslte_pdsch_cfg_t *cfg,
                                               srslte_softbuffer_rx_t *softbuffer, uint16_t rnti, uint8_t *data,
                                               uint32_t codeword_idx, uint32_t tb_idx, bool *ack) {
  srslte_ra_nbits_t *nbits = &cfg->nbits[tb_idx];
  srslte_ra_mcs_t *mcs = &cfg->grant.mcs[tb_idx];
  uint32_t rv = cfg->rv[tb_idx];
  int ret = SRSLTE_ERROR_INVALID_INPUTS;

  if (softbuffer && data && ack) {
    INFO("Decoding PDSCH SF: %d (CW%d -> TB%d), Mod %s, NofBits: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d\n",
         cfg->sf_idx, codeword_idx, tb_idx, srslte_mod_string(mcs->mod), mcs->tbs,
         nbits->nof_re, nbits->nof_bits, rv);

    /* demodulate symbols
     * The MAX-log-MAP algorithm used in turbo decoding is unsensitive to SNR estimation,
     * thus we don't need tot set it in the LLRs normalization
     */
    srslte_demod_soft_demodulate_s(mcs->mod, q->d[codeword_idx], q->e[codeword_idx], nbits->nof_re);

    /* Select scrambling sequence */
    srslte_sequence_t *seq = get_user_sequence(q, rnti, codeword_idx, cfg->sf_idx, nbits->nof_bits);

    /* Bit scrambling */
    srslte_scrambling_s_offset(seq, q->e[codeword_idx], 0, nbits->nof_bits);

    uint32_t qm = nbits->nof_bits/nbits->nof_re;
    switch(cfg->grant.mcs[tb_idx].mod) {

      case SRSLTE_MOD_BPSK:
        qm = 1;
        break;
      case SRSLTE_MOD_QPSK:
        qm = 2;
        break;
      case SRSLTE_MOD_16QAM:
        qm = 4;
        break;
      case SRSLTE_MOD_64QAM:
        qm = 6;
        break;
      default:
        ERROR("No modulation");
    }

    int16_t *e = q->e[codeword_idx];

    if (q->csi_enabled) {
      const uint32_t csi_max_idx = srslte_vec_max_fi(q->csi[codeword_idx], nbits->nof_bits / qm);
      float csi_max = 1.0f;
      if (csi_max_idx < nbits->nof_bits / qm) {
        csi_max = q->csi[codeword_idx][csi_max_idx];
      }
      for (int i = 0; i < nbits->nof_bits / qm; i++) {
        const float csi = q->csi[codeword_idx][i] / csi_max;
        for (int k = 0; k < qm; k++) {
          e[qm * i + k] = (int16_t) ((float) e[qm * i + k] * csi);
        }
      }
    }

    /* Return  */
    ret = srslte_dlsch_decode2(&q->dl_sch, cfg, softbuffer, q->e[codeword_idx], data, tb_idx);

    q->last_nof_iterations[codeword_idx] = srslte_sch_last_noi(&q->dl_sch);

    if (ret == SRSLTE_SUCCESS) {
      *ack = true;
    } else if (ret == SRSLTE_ERROR) {
      *ack = false;
      ret = SRSLTE_SUCCESS;
    } else if (ret == SRSLTE_ERROR_INVALID_INPUTS) {
      *ack = false;
      ret = SRSLTE_ERROR;
    }
  } else {
    ERROR("Detected NULL pointer in TB%d &softbuffer=%p &data=%p &ack=%p", codeword_idx, softbuffer, (void*)data, ack);
  }

  return ret;
}