|
|
|
@ -102,25 +102,30 @@ int srslte_chest_dl_init(srslte_chest_dl_t *q, uint32_t max_prb)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
q->tmp_noise = srslte_vec_malloc(sizeof(cf_t) * pilot_vec_size);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!q->tmp_noise) {
|
|
|
|
|
perror("malloc");
|
|
|
|
|
goto clean_exit;
|
|
|
|
|
}
|
|
|
|
|
q->pilot_estimates = srslte_vec_malloc(sizeof(cf_t) * pilot_vec_size);
|
|
|
|
|
|
|
|
|
|
q->tmp_cfo_estimate = srslte_vec_malloc(sizeof(cf_t) * pilot_vec_size);
|
|
|
|
|
if (!q->tmp_cfo_estimate) {
|
|
|
|
|
perror("malloc");
|
|
|
|
|
goto clean_exit;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
q->pilot_estimates = srslte_vec_malloc(sizeof(cf_t) * pilot_vec_size);
|
|
|
|
|
if (!q->pilot_estimates) {
|
|
|
|
|
perror("malloc");
|
|
|
|
|
goto clean_exit;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
q->pilot_estimates_average = srslte_vec_malloc(sizeof(cf_t) * pilot_vec_size);
|
|
|
|
|
if (!q->pilot_estimates_average) {
|
|
|
|
|
perror("malloc");
|
|
|
|
|
goto clean_exit;
|
|
|
|
|
}
|
|
|
|
|
q->pilot_recv_signal = srslte_vec_malloc(sizeof(cf_t) * pilot_vec_size);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
q->pilot_recv_signal = srslte_vec_malloc(sizeof(cf_t) * pilot_vec_size);
|
|
|
|
|
if (!q->pilot_recv_signal) {
|
|
|
|
|
perror("malloc");
|
|
|
|
|
goto clean_exit;
|
|
|
|
@ -175,6 +180,9 @@ void srslte_chest_dl_free(srslte_chest_dl_t *q)
|
|
|
|
|
if (q->tmp_noise) {
|
|
|
|
|
free(q->tmp_noise);
|
|
|
|
|
}
|
|
|
|
|
if (q->tmp_cfo_estimate) {
|
|
|
|
|
free(q->tmp_cfo_estimate);
|
|
|
|
|
}
|
|
|
|
|
srslte_interp_linear_vector_free(&q->srslte_interp_linvec);
|
|
|
|
|
srslte_interp_linear_free(&q->srslte_interp_lin);
|
|
|
|
|
srslte_interp_linear_free(&q->srslte_interp_lin_mbsfn);
|
|
|
|
@ -241,6 +249,10 @@ static float estimate_noise_pilots(srslte_chest_dl_t *q, uint32_t port_id)
|
|
|
|
|
{
|
|
|
|
|
int nref=SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id);
|
|
|
|
|
|
|
|
|
|
if (q->average_subframe) {
|
|
|
|
|
nref /= 4;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Substract noisy pilot estimates */
|
|
|
|
|
srslte_vec_sub_ccc(q->pilot_estimates_average, q->pilot_estimates, q->tmp_noise, nref);
|
|
|
|
|
|
|
|
|
@ -305,9 +317,13 @@ static void interpolate_pilots(srslte_chest_dl_t *q, cf_t *pilot_estimates, cf_t
|
|
|
|
|
uint32_t nsymbols = (ch_mode == SRSLTE_SF_MBSFN ) ? srslte_refsignal_mbsfn_nof_symbols() + 1 : srslte_refsignal_cs_nof_symbols(port_id);
|
|
|
|
|
uint32_t fidx_offset = 0;
|
|
|
|
|
/* Interpolate in the frequency domain */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (q->average_subframe) {
|
|
|
|
|
nsymbols = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// we add one to nsymbols to allow for inclusion of the non-mbms references in the channel estimation
|
|
|
|
|
for (l=0;l<(nsymbols);l++) {
|
|
|
|
|
for (l=0;l<nsymbols;l++) {
|
|
|
|
|
if (ch_mode == SRSLTE_SF_MBSFN) {
|
|
|
|
|
if (l == 0) {
|
|
|
|
|
fidx_offset = srslte_refsignal_cs_fidx(q->cell, l, port_id, 0);
|
|
|
|
@ -329,34 +345,41 @@ static void interpolate_pilots(srslte_chest_dl_t *q, cf_t *pilot_estimates, cf_t
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Now interpolate in the time domain between symbols */
|
|
|
|
|
if (ch_mode == SRSLTE_SF_MBSFN) {
|
|
|
|
|
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(0), &cesymb(2), &cesymb(1), 2, 1);
|
|
|
|
|
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(2), &cesymb(6), &cesymb(3), 4, 3);
|
|
|
|
|
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(6), &cesymb(10), &cesymb(7), 4, 3);
|
|
|
|
|
srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(6), &cesymb(10), &cesymb(10), &cesymb(11), 4, 1);
|
|
|
|
|
} else {
|
|
|
|
|
if (SRSLTE_CP_ISNORM(q->cell.cp)) {
|
|
|
|
|
if (nsymbols == 4) {
|
|
|
|
|
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(0), &cesymb(4), &cesymb(1), 4, 3);
|
|
|
|
|
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(4), &cesymb(7), &cesymb(5), 3, 2);
|
|
|
|
|
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(7), &cesymb(11), &cesymb(8), 4, 3);
|
|
|
|
|
srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(7), &cesymb(11), &cesymb(11), &cesymb(12), 4, 2);
|
|
|
|
|
} else {
|
|
|
|
|
srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(8), &cesymb(1), &cesymb(1), &cesymb(0), 7, 1);
|
|
|
|
|
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(1), &cesymb(8), &cesymb(2), 7, 6);
|
|
|
|
|
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(1), &cesymb(8), &cesymb(9), 7, 5);
|
|
|
|
|
}
|
|
|
|
|
if (q->average_subframe) {
|
|
|
|
|
// If we average per subframe, just copy the estimates in the time domain
|
|
|
|
|
for (l=0;l<2*SRSLTE_CP_NSYMB(q->cell.cp);l++) {
|
|
|
|
|
memcpy(&ce[l*SRSLTE_NRE*q->cell.nof_prb], ce, sizeof(cf_t)*SRSLTE_NRE*q->cell.nof_prb);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if (ch_mode == SRSLTE_SF_MBSFN) {
|
|
|
|
|
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(0), &cesymb(2), &cesymb(1), 2, 1);
|
|
|
|
|
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(2), &cesymb(6), &cesymb(3), 4, 3);
|
|
|
|
|
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(6), &cesymb(10), &cesymb(7), 4, 3);
|
|
|
|
|
srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(6), &cesymb(10), &cesymb(10), &cesymb(11), 4, 1);
|
|
|
|
|
} else {
|
|
|
|
|
if (nsymbols == 4) {
|
|
|
|
|
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(0), &cesymb(3), &cesymb(1), 3, 2);
|
|
|
|
|
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(3), &cesymb(6), &cesymb(4), 3, 2);
|
|
|
|
|
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(6), &cesymb(9), &cesymb(7), 3, 2);
|
|
|
|
|
srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(6), &cesymb(9), &cesymb(9), &cesymb(10), 3, 2);
|
|
|
|
|
if (SRSLTE_CP_ISNORM(q->cell.cp)) {
|
|
|
|
|
if (nsymbols == 4) {
|
|
|
|
|
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(0), &cesymb(4), &cesymb(1), 4, 3);
|
|
|
|
|
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(4), &cesymb(7), &cesymb(5), 3, 2);
|
|
|
|
|
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(7), &cesymb(11), &cesymb(8), 4, 3);
|
|
|
|
|
srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(7), &cesymb(11), &cesymb(11), &cesymb(12), 4, 2);
|
|
|
|
|
} else {
|
|
|
|
|
srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(8), &cesymb(1), &cesymb(1), &cesymb(0), 7, 1);
|
|
|
|
|
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(1), &cesymb(8), &cesymb(2), 7, 6);
|
|
|
|
|
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(1), &cesymb(8), &cesymb(9), 7, 5);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(7), &cesymb(1), &cesymb(1), &cesymb(0), 6, 1);
|
|
|
|
|
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(1), &cesymb(7), &cesymb(2), 6, 5);
|
|
|
|
|
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(1), &cesymb(7), &cesymb(8), 6, 4);
|
|
|
|
|
}
|
|
|
|
|
if (nsymbols == 4) {
|
|
|
|
|
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(0), &cesymb(3), &cesymb(1), 3, 2);
|
|
|
|
|
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(3), &cesymb(6), &cesymb(4), 3, 2);
|
|
|
|
|
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(6), &cesymb(9), &cesymb(7), 3, 2);
|
|
|
|
|
srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(6), &cesymb(9), &cesymb(9), &cesymb(10), 3, 2);
|
|
|
|
|
} else {
|
|
|
|
|
srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(7), &cesymb(1), &cesymb(1), &cesymb(0), 6, 1);
|
|
|
|
|
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(1), &cesymb(7), &cesymb(2), 6, 5);
|
|
|
|
|
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(1), &cesymb(7), &cesymb(8), 6, 4);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -392,6 +415,15 @@ static void average_pilots(srslte_chest_dl_t *q, cf_t *input, cf_t *output, uint
|
|
|
|
|
uint32_t nsymbols = (ch_mode == SRSLTE_SF_MBSFN)?srslte_refsignal_mbsfn_nof_symbols(port_id):srslte_refsignal_cs_nof_symbols(port_id);
|
|
|
|
|
uint32_t nref = (ch_mode == SRSLTE_SF_MBSFN)?6*q->cell.nof_prb:2*q->cell.nof_prb;
|
|
|
|
|
|
|
|
|
|
// Average in the time domain if enabled
|
|
|
|
|
if (q->average_subframe) {
|
|
|
|
|
for (int l=1;l<nsymbols;l++) {
|
|
|
|
|
srslte_vec_sum_ccc(&input[l*nref], input, input, nref);
|
|
|
|
|
}
|
|
|
|
|
srslte_vec_sc_prod_cfc(input, 1.0/((float) nsymbols), input, nref);
|
|
|
|
|
nsymbols = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Average in the frequency domain
|
|
|
|
|
for (int l=0;l<nsymbols;l++) {
|
|
|
|
|
srslte_conv_same_cf(&input[l*nref], q->smooth_filter, &output[l*nref], nref, q->smooth_filter_len);
|
|
|
|
@ -424,11 +456,11 @@ float chest_estimate_cfo(srslte_chest_dl_t *q)
|
|
|
|
|
for (int i=0;i<2;i++) {
|
|
|
|
|
srslte_vec_prod_conj_ccc(&q->pilot_estimates[i*npilots/4],
|
|
|
|
|
&q->pilot_estimates[(i+2)*npilots/4],
|
|
|
|
|
&q->tmp_noise[i*npilots/4],
|
|
|
|
|
&q->tmp_cfo_estimate[i*npilots/4],
|
|
|
|
|
npilots/4);
|
|
|
|
|
}
|
|
|
|
|
// Average all angles
|
|
|
|
|
cf_t sum = srslte_vec_acc_cc(q->tmp_noise, npilots/2);
|
|
|
|
|
cf_t sum = srslte_vec_acc_cc(q->tmp_cfo_estimate, npilots/2);
|
|
|
|
|
|
|
|
|
|
// Compute CFO
|
|
|
|
|
return -cargf(sum)*n/(ns*(n+ng))/2/M_PI;
|
|
|
|
@ -459,7 +491,7 @@ void chest_interpolate_noise_est(srslte_chest_dl_t *q, cf_t *input, cf_t *ce, ui
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (q->cfo_estimate_enable && ((1<<sf_idx) & q->cfo_estimate_sf_mask)) {
|
|
|
|
|
q->cfo = chest_estimate_cfo(q);
|
|
|
|
|
q->cfo = SRSLTE_VEC_EMA(chest_estimate_cfo(q), q->cfo, q->cfo_ema);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Compute RSRP for the channel estimates in this port */
|
|
|
|
@ -542,8 +574,14 @@ int srslte_chest_dl_estimate_multi_mbsfn(srslte_chest_dl_t *q, cf_t *input[SRSLT
|
|
|
|
|
return SRSLTE_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void srslte_chest_dl_cfo_estimate_enable(srslte_chest_dl_t *q, bool enable, uint32_t mask)
|
|
|
|
|
void srslte_chest_dl_average_subframe(srslte_chest_dl_t *q, bool enable)
|
|
|
|
|
{
|
|
|
|
|
q->average_subframe = enable;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void srslte_chest_dl_cfo_estimate_enable(srslte_chest_dl_t *q, bool enable, uint32_t mask, float ema)
|
|
|
|
|
{
|
|
|
|
|
q->cfo_ema = ema;
|
|
|
|
|
q->cfo_estimate_enable = enable;
|
|
|
|
|
q->cfo_estimate_sf_mask = mask;
|
|
|
|
|
}
|
|
|
|
|