Merge pull request #131 from softwareradiosystems/subframe_averaging

Fixes #119: channel estimation subframe averaging
This commit is contained in:
Ismael Gomez 2018-01-09 10:00:20 +01:00 committed by GitHub
commit 1c6fec9d1d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 149 additions and 8 deletions

View File

@ -79,6 +79,7 @@ typedef struct {
srslte_interp_linsrslte_vec_t srslte_interp_linvec;
srslte_interp_lin_t srslte_interp_lin;
srslte_interp_lin_t srslte_interp_lin_3;
srslte_interp_lin_t srslte_interp_lin_mbsfn;
float rssi[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS];
float rsrp[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS];

View File

@ -150,6 +150,10 @@ SRSLTE_API void srslte_vec_abs_square_cf(const cf_t *x, float *abs_square, const
/* Copy 256 bit aligned vector */
SRSLTE_API void srs_vec_cf_cpy(const cf_t *src, cf_t *dst, const int len);
SRSLTE_API void srslte_vec_interleave(const cf_t *x, const cf_t *y, cf_t *z, const int len);
SRSLTE_API void srslte_vec_interleave_add(const cf_t *x, const cf_t *y, cf_t *z, const int len);
#ifdef __cplusplus
}
#endif

View File

@ -122,6 +122,9 @@ SRSLTE_API void srslte_vec_convert_fi_simd(const float *x, int16_t *z, const flo
SRSLTE_API void srslte_vec_cp_simd(const cf_t *src, cf_t *dst, int len);
SRSLTE_API void srslte_vec_interleave_simd(const cf_t *x, const cf_t *y, cf_t *z, const int len);
SRSLTE_API void srslte_vec_interleave_add_simd(const cf_t *x, const cf_t *y, cf_t *z, const int len);
/* SIMD Find Max functions */
SRSLTE_API uint32_t srslte_vec_max_fi_simd(const float *x, const int len);

View File

@ -141,6 +141,11 @@ int srslte_chest_dl_init(srslte_chest_dl_t *q, uint32_t max_prb)
goto clean_exit;
}
if (srslte_interp_linear_init(&q->srslte_interp_lin_3, 4*max_prb, SRSLTE_NRE/4)) {
fprintf(stderr, "Error initializing interpolator\n");
goto clean_exit;
}
if (srslte_interp_linear_init(&q->srslte_interp_lin_mbsfn, 6*max_prb, SRSLTE_NRE/6)) {
fprintf(stderr, "Error initializing interpolator\n");
goto clean_exit;
@ -185,6 +190,7 @@ void srslte_chest_dl_free(srslte_chest_dl_t *q)
}
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_3);
srslte_interp_linear_free(&q->srslte_interp_lin_mbsfn);
if (q->pilot_estimates) {
free(q->pilot_estimates);
@ -238,6 +244,11 @@ int srslte_chest_dl_set_cell(srslte_chest_dl_t *q, srslte_cell_t cell)
return SRSLTE_ERROR;
}
if (srslte_interp_linear_resize(&q->srslte_interp_lin_3, 4 * q->cell.nof_prb, SRSLTE_NRE / 4)) {
fprintf(stderr, "Error initializing interpolator\n");
return SRSLTE_ERROR;
}
}
ret = SRSLTE_SUCCESS;
}
@ -337,10 +348,18 @@ static void interpolate_pilots(srslte_chest_dl_t *q, cf_t *pilot_estimates, cf_t
fidx_offset, SRSLTE_NRE/6-fidx_offset);
}
} else {
fidx_offset = srslte_refsignal_cs_fidx(q->cell, l, port_id, 0);
srslte_interp_linear_offset(&q->srslte_interp_lin, &pilot_estimates[2*q->cell.nof_prb*l],
&ce[srslte_refsignal_cs_nsymbol(l,q->cell.cp, port_id) * q->cell.nof_prb * SRSLTE_NRE],
fidx_offset, SRSLTE_NRE/2-fidx_offset);
if (q->average_subframe) {
fidx_offset = SRSLTE_MIN(srslte_refsignal_cs_fidx(q->cell, 0, port_id, 0),
srslte_refsignal_cs_fidx(q->cell, 1, port_id, 0));
srslte_interp_linear_offset(&q->srslte_interp_lin_3, &pilot_estimates[q->cell.nof_prb * l],
&ce[srslte_refsignal_cs_nsymbol(l, q->cell.cp, port_id) * q->cell.nof_prb
* SRSLTE_NRE], fidx_offset, SRSLTE_NRE / 4 - fidx_offset);
} else {
fidx_offset = srslte_refsignal_cs_fidx(q->cell, l, port_id, 0);
srslte_interp_linear_offset(&q->srslte_interp_lin, &pilot_estimates[2 * q->cell.nof_prb * l],
&ce[srslte_refsignal_cs_nsymbol(l, q->cell.cp, port_id) * q->cell.nof_prb
* SRSLTE_NRE], fidx_offset, SRSLTE_NRE / 2 - fidx_offset);
}
}
}
@ -417,11 +436,31 @@ static void average_pilots(srslte_chest_dl_t *q, cf_t *input, cf_t *output, uint
// 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);
if (ch_mode == SRSLTE_SF_MBSFN) {
for (int l = 1; l < nsymbols; l++) {
srslte_vec_sum_ccc(&input[l * nref], input, input, nref);
}
srslte_vec_sc_prod_cfc(input, 1.0f / ((float) nsymbols), input, nref);
nsymbols = 1;
} else {
cf_t *temp = &output[nref * 2];
if (srslte_refsignal_cs_fidx(q->cell, 0, port_id, 0) < 3) {
srslte_vec_interleave(input, &input[nref], temp, nref);
for (int l = 2; l < nsymbols - 1; l += 2) {
srslte_vec_interleave_add(&input[l * nref], &input[(l + 1) * nref], temp, nref);
}
} else {
srslte_vec_interleave(&input[nref], input, temp, nref);
for (int l = 2; l < nsymbols - 1; l += 2) {
srslte_vec_interleave_add(&input[(l + 1) * nref], &input[l * nref], temp, nref);
}
}
srslte_vec_sc_prod_cfc(temp, 2.0f / (float) nsymbols, temp, 2 * nref);
srslte_conv_same_cf(temp, q->smooth_filter, output, 2 * nref, q->smooth_filter_len);
return;
}
srslte_vec_sc_prod_cfc(input, 1.0/((float) nsymbols), input, nref);
nsymbols = 1;
}
// Average in the frequency domain

View File

@ -394,3 +394,11 @@ void srslte_vec_quant_suc(const int16_t *in, uint8_t *out, const float gain, con
void srs_vec_cf_cpy(const cf_t *dst, cf_t *src, int len) {
srslte_vec_cp_simd(dst, src, len);
}
void srslte_vec_interleave(const cf_t *x, const cf_t *y, cf_t *z, const int len) {
srslte_vec_interleave_simd(x, y, z, len);
}
void srslte_vec_interleave_add(const cf_t *x, const cf_t *y, cf_t *z, const int len) {
srslte_vec_interleave_add_simd(x, y, z, len);
}

View File

@ -1131,3 +1131,89 @@ uint32_t srslte_vec_max_ci_simd(const cf_t *x, const int len) {
return max_index;
}
void srslte_vec_interleave_simd(const cf_t *x, const cf_t *y, cf_t *z, const int len) {
uint32_t i = 0, k = 0;
#ifdef LV_HAVE_SSE
if (SRSLTE_IS_ALIGNED(x) && SRSLTE_IS_ALIGNED(y) && SRSLTE_IS_ALIGNED(z)) {
for (; i < len - 2 + 1; i += 2) {
__m128i a = _mm_load_si128((__m128i *) &x[i]);
__m128i b = _mm_load_si128((__m128i *) &y[i]);
__m128i r1 = _mm_unpacklo_epi64(a, b);
_mm_store_si128((__m128i *) &z[k], r1);
k += 2;
__m128i r2 = _mm_unpackhi_epi64(a, b);
_mm_store_si128((__m128i *) &z[k], r2);
k += 2;
}
} else {
for (; i < len - 2 + 1; i += 2) {
__m128i a = _mm_loadu_si128((__m128i *) &x[i]);
__m128i b = _mm_loadu_si128((__m128i *) &y[i]);
__m128i r1 = _mm_unpacklo_epi64(a, b);
_mm_storeu_si128((__m128i *) &z[k], r1);
k += 2;
__m128i r2 = _mm_unpackhi_epi64(a, b);
_mm_storeu_si128((__m128i *) &z[k], r2);
k += 2;
}
}
#endif /* LV_HAVE_SSE */
for (;i < len; i++) {
z[k++] = x[i];
z[k++] = y[i];
}
}
void srslte_vec_interleave_add_simd(const cf_t *x, const cf_t *y, cf_t *z, const int len) {
uint32_t i = 0, k = 0;
#ifdef LV_HAVE_SSE
if (SRSLTE_IS_ALIGNED(x) && SRSLTE_IS_ALIGNED(y) && SRSLTE_IS_ALIGNED(z)) {
for (; i < len - 2 + 1; i += 2) {
__m128i a = _mm_load_si128((__m128i *) &x[i]);
__m128i b = _mm_load_si128((__m128i *) &y[i]);
__m128 r1 = (__m128) _mm_unpacklo_epi64(a, b);
__m128 z1 = _mm_load_ps((float *) &z[k]);
r1 = _mm_add_ps((__m128) r1, z1);
_mm_store_ps((float *) &z[k], r1);
k += 2;
__m128 r2 = (__m128) _mm_unpackhi_epi64(a, b);
__m128 z2 = _mm_load_ps((float *) &z[k]);
r2 = _mm_add_ps((__m128) r2, z2);
_mm_store_ps((float *) &z[k], r2);
k += 2;
}
} else {
for (; i < len - 2 + 1; i += 2) {
__m128i a = _mm_loadu_si128((__m128i *) &x[i]);
__m128i b = _mm_loadu_si128((__m128i *) &y[i]);
__m128 r1 = (__m128) _mm_unpacklo_epi64(a, b);
__m128 z1 = _mm_loadu_ps((float *) &z[k]);
r1 = _mm_add_ps((__m128) r1, z1);
_mm_storeu_ps((float *) &z[k], r1);
k += 2;
__m128 r2 = (__m128) _mm_unpackhi_epi64(a, b);
__m128 z2 = _mm_loadu_ps((float *) &z[k]);
r2 = _mm_add_ps((__m128) r2, z2);
_mm_storeu_ps((float *) &z[k], r2);
k += 2;
}
}
#endif /* LV_HAVE_SSE */
for (;i < len; i++) {
z[k++] += x[i];
z[k++] += y[i];
}
}