static void interpolate_pilots(srslte_chest_ul_t *q, cf_t *ce, uint32_t nrefs, uint32_t n_prb[2]) { uint32_t L1 = SRSLTE_REFSIGNAL_UL_L(0, q->cell.cp); uint32_t L2 = SRSLTE_REFSIGNAL_UL_L(1, q->cell.cp); uint32_t NL = 2*SRSLTE_CP_NSYMB(q->cell.cp); /* Interpolate in the time domain between symbols */ srslte_interp_linear_vector3(&q->srslte_interp_linvec, &cesymb(L2), &cesymb(L1), &cesymb(L1), &cesymb(L1-1), (L2-L1), L1, false, nrefs); srslte_interp_linear_vector3(&q->srslte_interp_linvec, &cesymb(L1), &cesymb(L2), NULL, &cesymb(L1+1), (L2-L1), (L2-L1)-1, true, nrefs); srslte_interp_linear_vector3(&q->srslte_interp_linvec, &cesymb(L1), &cesymb(L2), &cesymb(L2), &cesymb(L2+1), (L2-L1), (NL-L2)-1, true, nrefs); }
static void average_pilots(srslte_chest_ul_t *q, cf_t *input, cf_t *ce, uint32_t nrefs, uint32_t n_prb[2]) { for (int i=0;i<2;i++) { srslte_chest_average_pilots(&input[i*nrefs], &ce[SRSLTE_REFSIGNAL_UL_L(i, q->cell.cp)*q->cell.nof_prb*SRSLTE_NRE+n_prb[i]*SRSLTE_NRE], q->smooth_filter, nrefs, 1, q->smooth_filter_len); } }
int srslte_chest_ul_estimate(srslte_chest_ul_t *q, cf_t *input, cf_t *ce, uint32_t nof_prb, uint32_t sf_idx, uint32_t cyclic_shift_for_dmrs, uint32_t n_prb[2]) { if (!q->dmrs_signal_configured) { fprintf(stderr, "Error must call srslte_chest_ul_set_cfg() before using the UL estimator\n"); return SRSLTE_ERROR; } if (!srslte_dft_precoding_valid_prb(nof_prb)) { fprintf(stderr, "Error invalid nof_prb=%d\n", nof_prb); return SRSLTE_ERROR_INVALID_INPUTS; } int nrefs_sym = nof_prb*SRSLTE_NRE; int nrefs_sf = nrefs_sym*2; /* Get references from the input signal */ srslte_refsignal_dmrs_pusch_get(&q->dmrs_signal, input, nof_prb, n_prb, q->pilot_recv_signal); /* Use the known DMRS signal to compute Least-squares estimates */ srslte_vec_prod_conj_ccc(q->pilot_recv_signal, q->dmrs_pregen.r[cyclic_shift_for_dmrs][sf_idx][nof_prb], q->pilot_estimates, nrefs_sf); if (n_prb[0] != n_prb[1]) { printf("ERROR: intra-subframe frequency hopping not supported in the estimator!!\n"); } if (ce != NULL) { if (q->smooth_filter_len > 0) { average_pilots(q, q->pilot_estimates, ce, nrefs_sym, n_prb); interpolate_pilots(q, ce, nrefs_sym, n_prb); /* If averaging, compute noise from difference between received and averaged estimates */ q->noise_estimate = estimate_noise_pilots(q, ce, nrefs_sym, n_prb); } else { // Copy estimates to CE vector without averaging for (int i=0;i<2;i++) { memcpy(&ce[SRSLTE_REFSIGNAL_UL_L(i, q->cell.cp)*q->cell.nof_prb*SRSLTE_NRE+n_prb[i]*SRSLTE_NRE], &q->pilot_estimates[i*nrefs_sym], nrefs_sym*sizeof(cf_t)); } interpolate_pilots(q, ce, nrefs_sym, n_prb); q->noise_estimate = 0; } } // Estimate received pilot power q->pilot_power = srslte_vec_avg_power_cf(q->pilot_recv_signal, nrefs_sf); return 0; }
/* Uses the difference between the averaged and non-averaged pilot estimates */ static float estimate_noise_pilots(srslte_chest_ul_t *q, cf_t *ce, uint32_t nrefs, uint32_t n_prb[2]) { float power = 0; for (int i=0;i<2;i++) { power += srslte_chest_estimate_noise_pilots(&q->pilot_estimates[i*nrefs], &ce[SRSLTE_REFSIGNAL_UL_L(i, q->cell.cp)*q->cell.nof_prb*SRSLTE_NRE+n_prb[i]*SRSLTE_NRE], q->tmp_noise, nrefs); } power/=2; if (q->smooth_filter_len == 3) { // Calibrated for filter length 3 float w=q->smooth_filter[0]; float a=7.419*w*w+0.1117*w-0.005387; return (power/(a*0.8)); } else { return power; } }