chest_dl: subframe averaging with previous

master
Ismael Gomez 8 years ago
parent 58d955ea10
commit 82cfa01468

@ -63,6 +63,7 @@ typedef struct {
srslte_refsignal_cs_t csr_signal; srslte_refsignal_cs_t csr_signal;
cf_t *pilot_estimates; cf_t *pilot_estimates;
cf_t *pilot_estimates_average; cf_t *pilot_estimates_average;
cf_t *pilot_average_last;
cf_t *pilot_recv_signal; cf_t *pilot_recv_signal;
cf_t *tmp_noise; cf_t *tmp_noise;
@ -73,6 +74,9 @@ typedef struct {
uint32_t smooth_filter_len; uint32_t smooth_filter_len;
float smooth_filter[SRSLTE_CHEST_MAX_SMOOTH_FIL_LEN]; float smooth_filter[SRSLTE_CHEST_MAX_SMOOTH_FIL_LEN];
float time_ema_coeff;
bool average_subframe;
srslte_interp_linsrslte_vec_t srslte_interp_linvec; srslte_interp_linsrslte_vec_t srslte_interp_linvec;
srslte_interp_lin_t srslte_interp_lin; srslte_interp_lin_t srslte_interp_lin;
@ -102,6 +106,12 @@ SRSLTE_API void srslte_chest_dl_set_smooth_filter(srslte_chest_dl_t *q,
SRSLTE_API void srslte_chest_dl_set_smooth_filter3_coeff(srslte_chest_dl_t* q, SRSLTE_API void srslte_chest_dl_set_smooth_filter3_coeff(srslte_chest_dl_t* q,
float w); float w);
SRSLTE_API void srslte_chest_dl_set_time_ema_coeff(srslte_chest_dl_t *q,
float t);
SRSLTE_API void srslte_chest_dl_set_average_subframe(srslte_chest_dl_t *q,
bool enable);
SRSLTE_API void srslte_chest_dl_set_noise_alg(srslte_chest_dl_t *q, SRSLTE_API void srslte_chest_dl_set_noise_alg(srslte_chest_dl_t *q,
srslte_chest_dl_noise_alg_t noise_estimation_alg); srslte_chest_dl_noise_alg_t noise_estimation_alg);

@ -39,32 +39,8 @@
#include "srslte/utils/vector.h" #include "srslte/utils/vector.h"
#include "srslte/utils/convolution.h" #include "srslte/utils/convolution.h"
#define AVERAGE_SUBFRAME #define DEFAULT_FILTER_LEN 3
#define DEFAULT_TIME_EMA_COEFF 0.9
//#define DEFAULT_FILTER_LEN 3
#ifdef DEFAULT_FILTER_LEN
static void set_default_filter(srslte_chest_dl_t *q, int filter_len) {
float fil[SRSLTE_CHEST_DL_MAX_SMOOTH_FIL_LEN];
for (int i=0;i<filter_len/2;i++) {
fil[i] = i+1;
fil[i+filter_len/2+1]=filter_len/2-i;
}
fil[filter_len/2]=filter_len/2+1;
float s=0;
for (int i=0;i<filter_len;i++) {
s+=fil[i];
}
for (int i=0;i<filter_len;i++) {
fil[i]/=s;
}
srslte_chest_dl_set_smooth_filter(q, fil, filter_len);
}
#endif
/** 3GPP LTE Downlink channel estimator and equalizer. /** 3GPP LTE Downlink channel estimator and equalizer.
* Estimates the channel in the resource elements transmitting references and interpolates for the rest * Estimates the channel in the resource elements transmitting references and interpolates for the rest
@ -104,6 +80,11 @@ int srslte_chest_dl_init(srslte_chest_dl_t *q, srslte_cell_t cell)
perror("malloc"); perror("malloc");
goto clean_exit; goto clean_exit;
} }
q->pilot_average_last = srslte_vec_malloc(sizeof(cf_t) * 2 * cell.nof_prb);
if (!q->pilot_average_last) {
perror("malloc");
goto clean_exit;
}
q->pilot_recv_signal = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_REFSIGNAL_MAX_NUM_SF(cell.nof_prb)); q->pilot_recv_signal = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_REFSIGNAL_MAX_NUM_SF(cell.nof_prb));
if (!q->pilot_recv_signal) { if (!q->pilot_recv_signal) {
perror("malloc"); perror("malloc");
@ -127,7 +108,14 @@ int srslte_chest_dl_init(srslte_chest_dl_t *q, srslte_cell_t cell)
q->noise_alg = SRSLTE_NOISE_ALG_REFS; q->noise_alg = SRSLTE_NOISE_ALG_REFS;
q->smooth_filter_len = 3; q->time_ema_coeff = 1.0;
#ifdef DEFAULT_TIME_EMA_COEFF
q->time_ema_coeff = DEFAULT_TIME_EMA_COEFF;
#endif
q->average_subframe = true;
q->smooth_filter_len = DEFAULT_FILTER_LEN;
srslte_chest_dl_set_smooth_filter3_coeff(q, 0.1); srslte_chest_dl_set_smooth_filter3_coeff(q, 0.1);
q->cell = cell; q->cell = cell;
@ -158,6 +146,9 @@ void srslte_chest_dl_free(srslte_chest_dl_t *q)
if (q->pilot_estimates_average) { if (q->pilot_estimates_average) {
free(q->pilot_estimates_average); free(q->pilot_estimates_average);
} }
if (q->pilot_average_last) {
free(q->pilot_average_last);
}
if (q->pilot_recv_signal) { if (q->pilot_recv_signal) {
free(q->pilot_recv_signal); free(q->pilot_recv_signal);
} }
@ -233,7 +224,7 @@ static float estimate_noise_empty_sc(srslte_chest_dl_t *q, cf_t *input) {
static void interpolate_pilots(srslte_chest_dl_t *q, cf_t *pilot_estimates, cf_t *ce, uint32_t port_id) static void interpolate_pilots(srslte_chest_dl_t *q, cf_t *pilot_estimates, cf_t *ce, uint32_t port_id)
{ {
#ifdef AVERAGE_SUBFRAME if (q->average_subframe) {
// Interpolate symbol 0 in the frequency domain // Interpolate symbol 0 in the frequency domain
uint32_t fidx_offset = srslte_refsignal_cs_fidx(q->cell, 0, port_id, 0); uint32_t fidx_offset = srslte_refsignal_cs_fidx(q->cell, 0, port_id, 0);
srslte_interp_linear_offset(&q->srslte_interp_lin, pilot_estimates, srslte_interp_linear_offset(&q->srslte_interp_lin, pilot_estimates,
@ -243,7 +234,7 @@ static void interpolate_pilots(srslte_chest_dl_t *q, cf_t *pilot_estimates, cf_t
for (int l=1;l<2*SRSLTE_CP_NSYMB(q->cell.cp);l++) { for (int l=1;l<2*SRSLTE_CP_NSYMB(q->cell.cp);l++) {
memcpy(&ce[l*q->cell.nof_prb*SRSLTE_NRE], ce, q->cell.nof_prb*SRSLTE_NRE*sizeof(cf_t)); memcpy(&ce[l*q->cell.nof_prb*SRSLTE_NRE], ce, q->cell.nof_prb*SRSLTE_NRE*sizeof(cf_t));
} }
#else } else {
uint32_t l=0; uint32_t l=0;
uint32_t nsymbols = srslte_refsignal_cs_nof_symbols(port_id); uint32_t nsymbols = srslte_refsignal_cs_nof_symbols(port_id);
@ -278,7 +269,7 @@ static void interpolate_pilots(srslte_chest_dl_t *q, cf_t *pilot_estimates, cf_t
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(1), &cesymb(7), &cesymb(8), 6, 4); srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(1), &cesymb(7), &cesymb(8), 6, 4);
} }
} }
#endif }
} }
void srslte_chest_dl_set_smooth_filter(srslte_chest_dl_t *q, float *filter, uint32_t filter_len) { void srslte_chest_dl_set_smooth_filter(srslte_chest_dl_t *q, float *filter, uint32_t filter_len) {
@ -307,21 +298,36 @@ void srslte_chest_dl_set_smooth_filter3_coeff(srslte_chest_dl_t* q, float w)
q->smooth_filter[1] = 1-2*w; q->smooth_filter[1] = 1-2*w;
} }
void srslte_chest_dl_set_time_ema_coeff(srslte_chest_dl_t *q, float t) {
if (t > 0.0 && t <= 1.0) {
q->time_ema_coeff = t;
}
}
void srslte_chest_dl_set_average_subframe(srslte_chest_dl_t *q, bool enable) {
q->average_subframe = enable;
}
static void average_pilots(srslte_chest_dl_t *q, cf_t *input, cf_t *output, uint32_t port_id) { static void average_pilots(srslte_chest_dl_t *q, cf_t *input, cf_t *output, uint32_t port_id) {
uint32_t nsymbols = srslte_refsignal_cs_nof_symbols(port_id); uint32_t nsymbols = srslte_refsignal_cs_nof_symbols(port_id);
uint32_t nref = 2*q->cell.nof_prb; uint32_t nref = 2*q->cell.nof_prb;
memcpy(output, input, nref*sizeof(cf_t)); memcpy(output, input, nref*sizeof(cf_t));
for (int l=1;l<nsymbols;l++) { for (int l=1;l<nsymbols;l++) {
#ifdef AVERAGE_SUBFRAME if (q->average_subframe) {
srslte_vec_sum_ccc(output, &input[l*nref], output, nref); srslte_vec_sum_ccc(output, &input[l*nref], output, nref);
#else } else {
srslte_conv_same_cf(&input[l*nref], q->smooth_filter, &output[l*nref], nref, q->smooth_filter_len); srslte_conv_same_cf(&input[l*nref], q->smooth_filter, &output[l*nref], nref, q->smooth_filter_len);
#endif
} }
#ifdef AVERAGE_SUBFRAME }
srslte_vec_sc_prod_cfc(output, (float) 1.0/nsymbols, output, nref); if (q->average_subframe) {
#endif srslte_vec_sc_prod_cfc(output, (float) q->time_ema_coeff/nsymbols, output, nref);
if (q->time_ema_coeff < 1.0) {
srslte_vec_sc_prod_cfc(q->pilot_average_last, 1-q->time_ema_coeff, q->pilot_average_last, nref);
srslte_vec_sum_ccc(q->pilot_average_last, output, output, nref);
memcpy(q->pilot_average_last, output, nref*sizeof(cf_t));
}
}
} }
float srslte_chest_dl_rssi(srslte_chest_dl_t *q, cf_t *input, uint32_t port_id) { float srslte_chest_dl_rssi(srslte_chest_dl_t *q, cf_t *input, uint32_t port_id) {

Loading…
Cancel
Save