|
|
@ -39,31 +39,29 @@
|
|
|
|
#include "srslte/utils/vector.h"
|
|
|
|
#include "srslte/utils/vector.h"
|
|
|
|
#include "srslte/utils/convolution.h"
|
|
|
|
#include "srslte/utils/convolution.h"
|
|
|
|
|
|
|
|
|
|
|
|
#define NOISE_POWER_METHOD 1 // 0: Difference between noisy received and noiseless; 1: power of empty subcarriers
|
|
|
|
#define ESTIMATE_NOISE_LS_PSS
|
|
|
|
|
|
|
|
|
|
|
|
#define DEFAULT_FILTER_FREQ_LEN 11 // Must be odd
|
|
|
|
#define DEFAULT_FILTER_LEN 3
|
|
|
|
#define DEFAULT_FILTER_TIME_LEN 3
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void init_default_filters(srslte_chest_dl_t *q) {
|
|
|
|
static void set_default_filter(srslte_chest_dl_t *q, int filter_len) {
|
|
|
|
|
|
|
|
|
|
|
|
float f[DEFAULT_FILTER_FREQ_LEN];
|
|
|
|
float fil[SRSLTE_CHEST_DL_MAX_SMOOTH_FIL_LEN];
|
|
|
|
float t[DEFAULT_FILTER_TIME_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;
|
|
|
|
|
|
|
|
|
|
|
|
for (int i=0;i<DEFAULT_FILTER_FREQ_LEN/2+1;i++) {
|
|
|
|
float s=0;
|
|
|
|
f[i] = 1+i;
|
|
|
|
for (int i=0;i<filter_len;i++) {
|
|
|
|
f[DEFAULT_FILTER_FREQ_LEN-i-1] = 1+i;
|
|
|
|
s+=fil[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
float norm = srslte_vec_acc_ff(f, DEFAULT_FILTER_FREQ_LEN);
|
|
|
|
for (int i=0;i<filter_len;i++) {
|
|
|
|
srslte_vec_sc_prod_fff(f, 1.0/norm, f, DEFAULT_FILTER_FREQ_LEN);
|
|
|
|
fil[i]/=s;
|
|
|
|
srslte_chest_dl_set_filter_freq(q, f, DEFAULT_FILTER_FREQ_LEN);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (int i=0;i<DEFAULT_FILTER_TIME_LEN/2+1;i++) {
|
|
|
|
|
|
|
|
t[i] = 1+i;
|
|
|
|
|
|
|
|
t[DEFAULT_FILTER_TIME_LEN-i-1] = 1+i;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
norm = srslte_vec_acc_ff(t, DEFAULT_FILTER_TIME_LEN);
|
|
|
|
|
|
|
|
srslte_vec_sc_prod_fff(t, 1.0/norm, t, DEFAULT_FILTER_TIME_LEN);
|
|
|
|
srslte_chest_dl_set_smooth_filter(q, fil, filter_len);
|
|
|
|
srslte_chest_dl_set_filter_time(q, t, DEFAULT_FILTER_TIME_LEN);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** 3GPP LTE Downlink channel estimator and equalizer.
|
|
|
|
/** 3GPP LTE Downlink channel estimator and equalizer.
|
|
|
@ -89,33 +87,25 @@ int srslte_chest_dl_init(srslte_chest_dl_t *q, srslte_cell_t cell)
|
|
|
|
goto clean_exit;
|
|
|
|
goto clean_exit;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
q->tmp_freqavg = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp));
|
|
|
|
q->tmp_noise = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_REFSIGNAL_MAX_NUM_SF(cell.nof_prb));
|
|
|
|
if (!q->tmp_freqavg) {
|
|
|
|
if (!q->tmp_noise) {
|
|
|
|
perror("malloc");
|
|
|
|
perror("malloc");
|
|
|
|
goto clean_exit;
|
|
|
|
goto clean_exit;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
q->tmp_noise = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp));
|
|
|
|
q->pilot_estimates = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_REFSIGNAL_MAX_NUM_SF(cell.nof_prb));
|
|
|
|
if (!q->tmp_noise) {
|
|
|
|
if (!q->pilot_estimates) {
|
|
|
|
perror("malloc");
|
|
|
|
perror("malloc");
|
|
|
|
goto clean_exit;
|
|
|
|
goto clean_exit;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
q->tmp_timeavg_mult = srslte_vec_malloc(sizeof(cf_t) * 12*cell.nof_prb);
|
|
|
|
q->pilot_estimates_average = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_REFSIGNAL_MAX_NUM_SF(cell.nof_prb));
|
|
|
|
if (!q->tmp_timeavg_mult) {
|
|
|
|
if (!q->pilot_estimates_average) {
|
|
|
|
|
|
|
|
perror("malloc");
|
|
|
|
|
|
|
|
goto clean_exit;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
q->pilot_recv_signal = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_REFSIGNAL_MAX_NUM_SF(cell.nof_prb));
|
|
|
|
|
|
|
|
if (!q->pilot_recv_signal) {
|
|
|
|
perror("malloc");
|
|
|
|
perror("malloc");
|
|
|
|
goto clean_exit;
|
|
|
|
goto clean_exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (int i=0;i<cell.nof_ports;i++) {
|
|
|
|
|
|
|
|
q->pilot_estimates[i] = srslte_vec_malloc(2*sizeof(cf_t) * SRSLTE_REFSIGNAL_NUM_SF(cell.nof_prb, i));
|
|
|
|
|
|
|
|
if (!q->pilot_estimates[i]) {
|
|
|
|
|
|
|
|
perror("malloc");
|
|
|
|
|
|
|
|
goto clean_exit;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
q->pilot_recv_signal[i] = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_REFSIGNAL_NUM_SF(cell.nof_prb, i));
|
|
|
|
|
|
|
|
if (!q->pilot_recv_signal[i]) {
|
|
|
|
|
|
|
|
perror("malloc");
|
|
|
|
|
|
|
|
goto clean_exit;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (srslte_interp_linear_vector_init(&q->srslte_interp_linvec, SRSLTE_NRE*cell.nof_prb)) {
|
|
|
|
if (srslte_interp_linear_vector_init(&q->srslte_interp_linvec, SRSLTE_NRE*cell.nof_prb)) {
|
|
|
@ -128,7 +118,14 @@ int srslte_chest_dl_init(srslte_chest_dl_t *q, srslte_cell_t cell)
|
|
|
|
goto clean_exit;
|
|
|
|
goto clean_exit;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
init_default_filters(q);
|
|
|
|
if (srslte_pss_generate(q->pss_signal, cell.id%3)) {
|
|
|
|
|
|
|
|
fprintf(stderr, "Error initializing PSS signal for noise estimation\n");
|
|
|
|
|
|
|
|
goto clean_exit;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
q->smooth_filter_len = 0;
|
|
|
|
|
|
|
|
set_default_filter(q, DEFAULT_FILTER_LEN);
|
|
|
|
|
|
|
|
|
|
|
|
q->cell = cell;
|
|
|
|
q->cell = cell;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -145,72 +142,62 @@ void srslte_chest_dl_free(srslte_chest_dl_t *q)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
srslte_refsignal_cs_free(&q->csr_signal);
|
|
|
|
srslte_refsignal_cs_free(&q->csr_signal);
|
|
|
|
|
|
|
|
|
|
|
|
if (q->tmp_freqavg) {
|
|
|
|
|
|
|
|
free(q->tmp_freqavg);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (q->tmp_noise) {
|
|
|
|
if (q->tmp_noise) {
|
|
|
|
free(q->tmp_noise);
|
|
|
|
free(q->tmp_noise);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (q->tmp_timeavg_mult) {
|
|
|
|
|
|
|
|
free(q->tmp_timeavg_mult);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
srslte_interp_linear_vector_free(&q->srslte_interp_linvec);
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
|
|
for (int i=0;i<SRSLTE_MAX_PORTS;i++) {
|
|
|
|
if (q->pilot_estimates) {
|
|
|
|
if (q->pilot_estimates[i]) {
|
|
|
|
free(q->pilot_estimates);
|
|
|
|
free(q->pilot_estimates[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (q->pilot_estimates_average) {
|
|
|
|
if (q->pilot_recv_signal[i]) {
|
|
|
|
free(q->pilot_estimates_average);
|
|
|
|
free(q->pilot_recv_signal[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (q->pilot_recv_signal) {
|
|
|
|
|
|
|
|
free(q->pilot_recv_signal);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
bzero(q, sizeof(srslte_chest_dl_t));
|
|
|
|
bzero(q, sizeof(srslte_chest_dl_t));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int srslte_chest_dl_set_filter_freq(srslte_chest_dl_t *q, float *filter, uint32_t filter_len) {
|
|
|
|
/* Uses the difference between the averaged and non-averaged pilot estimates */
|
|
|
|
if (filter_len <= SRSLTE_CHEST_MAX_FILTER_FREQ_LEN) {
|
|
|
|
static float estimate_noise_pilots(srslte_chest_dl_t *q, cf_t *ce, uint32_t port_id)
|
|
|
|
q->filter_freq_len = filter_len;
|
|
|
|
{
|
|
|
|
for (int i=0;i<filter_len;i++) {
|
|
|
|
int nref=SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id);
|
|
|
|
q->filter_freq[i] = filter[i];
|
|
|
|
/* Get averaged pilots from channel estimates */
|
|
|
|
}
|
|
|
|
srslte_refsignal_cs_get_sf(q->cell, port_id, ce, q->tmp_noise);
|
|
|
|
return SRSLTE_SUCCESS;
|
|
|
|
/* Substract noisy pilot estimates */
|
|
|
|
} else {
|
|
|
|
srslte_vec_sub_ccc(q->tmp_noise, q->pilot_estimates, q->tmp_noise, nref);
|
|
|
|
return SRSLTE_ERROR;
|
|
|
|
/* Compute average power */
|
|
|
|
}
|
|
|
|
float power = sqrt(2)*q->cell.nof_ports*srslte_vec_avg_power_cf(q->tmp_noise, nref);
|
|
|
|
}
|
|
|
|
return power;
|
|
|
|
|
|
|
|
|
|
|
|
void srslte_chest_dl_set_filter_time_ema(srslte_chest_dl_t *q, float ema_coefficient) {
|
|
|
|
|
|
|
|
q->filter_time_ema = ema_coefficient;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int srslte_chest_dl_set_filter_time(srslte_chest_dl_t *q, float *filter, uint32_t filter_len) {
|
|
|
|
|
|
|
|
if (filter_len <= SRSLTE_CHEST_MAX_FILTER_TIME_LEN) {
|
|
|
|
|
|
|
|
q->filter_time_len = filter_len;
|
|
|
|
|
|
|
|
for (int i=0;i<filter_len;i++) {
|
|
|
|
|
|
|
|
q->filter_time[i] = filter[i];
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return SRSLTE_SUCCESS;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
return SRSLTE_ERROR;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef ESTIMATE_NOISE_LS_PSS
|
|
|
|
|
|
|
|
static float estimate_noise_pss(srslte_chest_dl_t *q, cf_t *input, cf_t *ce)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
/* Get PSS from received signal */
|
|
|
|
|
|
|
|
srslte_pss_get_slot(input, q->tmp_pss, q->cell.nof_prb, q->cell.cp);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Get channel estimates for PSS position */
|
|
|
|
|
|
|
|
srslte_pss_get_slot(ce, q->tmp_pss_noisy, q->cell.nof_prb, q->cell.cp);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Multiply known PSS by channel estimates */
|
|
|
|
|
|
|
|
srslte_vec_prod_ccc(q->tmp_pss_noisy, q->pss_signal, q->tmp_pss_noisy, SRSLTE_PSS_LEN);
|
|
|
|
|
|
|
|
|
|
|
|
#if NOISE_POWER_METHOD==0
|
|
|
|
/* Substract received signal */
|
|
|
|
/* Uses the difference between the averaged and non-averaged pilot estimates */
|
|
|
|
srslte_vec_sub_ccc(q->tmp_pss_noisy, q->tmp_pss, q->tmp_pss_noisy, SRSLTE_PSS_LEN);
|
|
|
|
static float estimate_noise_port(srslte_chest_dl_t *q, cf_t *average, cf_t *ce, uint32_t len) {
|
|
|
|
|
|
|
|
/* Use difference between averaged and noisy LS pilot estimates */
|
|
|
|
/* Compute average power */
|
|
|
|
srslte_vec_sub_ccc(average, ce, q->tmp_noise, len);
|
|
|
|
float power = 2*q->cell.nof_ports*srslte_vec_avg_power_cf(q->tmp_pss_noisy, SRSLTE_PSS_LEN);
|
|
|
|
return srslte_vec_avg_power_cf(q->tmp_noise, len);
|
|
|
|
return power;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if NOISE_POWER_METHOD==1
|
|
|
|
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
|
|
|
|
/* Uses the 5 empty transmitted SC before and after the SSS and PSS sequences for noise estimation */
|
|
|
|
/* Uses the 5 empty transmitted SC before and after the SSS and PSS sequences for noise estimation */
|
|
|
|
static float estimate_noise_port(srslte_chest_dl_t *q, cf_t *input) {
|
|
|
|
static float estimate_noise_empty_sc(srslte_chest_dl_t *q, cf_t *input) {
|
|
|
|
int k_sss = (SRSLTE_CP_NSYMB(q->cell.cp) - 2) * q->cell.nof_prb * SRSLTE_NRE + q->cell.nof_prb * SRSLTE_NRE / 2 - 31;
|
|
|
|
int k_sss = (SRSLTE_CP_NSYMB(q->cell.cp) - 2) * q->cell.nof_prb * SRSLTE_NRE + q->cell.nof_prb * SRSLTE_NRE / 2 - 31;
|
|
|
|
float noise_power = 0;
|
|
|
|
float noise_power = 0;
|
|
|
|
noise_power += srslte_vec_avg_power_cf(&input[k_sss-5], 5); // 5 empty SC before SSS
|
|
|
|
noise_power += srslte_vec_avg_power_cf(&input[k_sss-5], 5); // 5 empty SC before SSS
|
|
|
@ -224,48 +211,6 @@ static float estimate_noise_port(srslte_chest_dl_t *q, cf_t *input) {
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void average_estimates(srslte_chest_dl_t *q, cf_t *ce, uint32_t port_id)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
int nref=12*q->cell.nof_prb;
|
|
|
|
|
|
|
|
uint32_t l, i;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* For each symbol with pilots in a slot */
|
|
|
|
|
|
|
|
for (l=0;l<SRSLTE_CP_NSYMB(q->cell.cp);l++) {
|
|
|
|
|
|
|
|
if (q->filter_freq_len > 0) {
|
|
|
|
|
|
|
|
/* Filter pilot estimates in frequency */
|
|
|
|
|
|
|
|
srslte_conv_same_cf(&ce[l*12*q->cell.nof_prb], q->filter_freq, &q->tmp_freqavg[l*12*q->cell.nof_prb], nref, q->filter_freq_len);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
memcpy(&q->tmp_freqavg[l*12*q->cell.nof_prb], &ce[l*12*q->cell.nof_prb], nref * sizeof(cf_t));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if NOISE_POWER_METHOD==0
|
|
|
|
|
|
|
|
q->noise_estimate[port_id] = estimate_noise_port(q, q->tmp_freqavg, ce,
|
|
|
|
|
|
|
|
SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp));
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Filter with FIR or don't filter */
|
|
|
|
|
|
|
|
for (l=0;l<SRSLTE_CP_NSYMB(q->cell.cp);l++) {
|
|
|
|
|
|
|
|
/* Filter in time domain. */
|
|
|
|
|
|
|
|
if (q->filter_time_len > 0) {
|
|
|
|
|
|
|
|
/* Multiply symbols by filter and add them */
|
|
|
|
|
|
|
|
bzero(&ce[l*12*q->cell.nof_prb], nref * sizeof(cf_t));
|
|
|
|
|
|
|
|
for (i=0;i<q->filter_time_len;i++) {
|
|
|
|
|
|
|
|
if (l+i-q->filter_time_len/2 < SRSLTE_CP_NSYMB(q->cell.cp) && l+i-q->filter_time_len/2 > 0) {
|
|
|
|
|
|
|
|
srslte_vec_sc_prod_cfc(&q->tmp_freqavg[(l+i-q->filter_time_len/2)*12*q->cell.nof_prb], q->filter_time[i], q->tmp_timeavg_mult, nref);
|
|
|
|
|
|
|
|
srslte_vec_sum_ccc(q->tmp_timeavg_mult, &ce[l*12*q->cell.nof_prb], &ce[l*12*q->cell.nof_prb], nref);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
srslte_vec_sc_prod_cfc(&q->tmp_freqavg[l*12*q->cell.nof_prb], q->filter_time[i], q->tmp_timeavg_mult, nref);
|
|
|
|
|
|
|
|
srslte_vec_sum_ccc(q->tmp_timeavg_mult, &ce[l*12*q->cell.nof_prb], &ce[l*12*q->cell.nof_prb], nref);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
memcpy(&ce[l*12*q->cell.nof_prb], &q->tmp_freqavg[l*12*q->cell.nof_prb], nref * sizeof(cf_t));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define cesymb(i) ce[SRSLTE_RE_IDX(q->cell.nof_prb,i,0)]
|
|
|
|
#define cesymb(i) ce[SRSLTE_RE_IDX(q->cell.nof_prb,i,0)]
|
|
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
@ -285,10 +230,10 @@ static void interpolate_pilots(srslte_chest_dl_t *q, cf_t *pilot_estimates, cf_t
|
|
|
|
/* Now interpolate in the time domain between symbols */
|
|
|
|
/* Now interpolate in the time domain between symbols */
|
|
|
|
if (SRSLTE_CP_ISNORM(q->cell.cp)) {
|
|
|
|
if (SRSLTE_CP_ISNORM(q->cell.cp)) {
|
|
|
|
if (nsymbols == 4) {
|
|
|
|
if (nsymbols == 4) {
|
|
|
|
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(0), &cesymb(4), &cesymb(1), 3);
|
|
|
|
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(0), &cesymb(4), &cesymb(1), 3);
|
|
|
|
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(4), &cesymb(7), &cesymb(5), 2);
|
|
|
|
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(4), &cesymb(7), &cesymb(5), 2);
|
|
|
|
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(7), &cesymb(11), &cesymb(8), 3);
|
|
|
|
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(7), &cesymb(11), &cesymb(8), 3);
|
|
|
|
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(7), &cesymb(11), &cesymb(12), 2);
|
|
|
|
srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(7), &cesymb(11), &cesymb(11), &cesymb(12), 2);
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(8), &cesymb(1), &cesymb(0), 1);
|
|
|
|
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(8), &cesymb(1), &cesymb(0), 1);
|
|
|
|
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(1), &cesymb(8), &cesymb(2), 6);
|
|
|
|
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(1), &cesymb(8), &cesymb(2), 6);
|
|
|
@ -299,7 +244,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(0), &cesymb(3), &cesymb(1), 2);
|
|
|
|
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(0), &cesymb(3), &cesymb(1), 2);
|
|
|
|
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(3), &cesymb(6), &cesymb(4), 2);
|
|
|
|
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(3), &cesymb(6), &cesymb(4), 2);
|
|
|
|
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(6), &cesymb(9), &cesymb(7), 2);
|
|
|
|
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(6), &cesymb(9), &cesymb(7), 2);
|
|
|
|
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(6), &cesymb(9), &cesymb(9), 2);
|
|
|
|
srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(6), &cesymb(9), &cesymb(9), &cesymb(10), 2);
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(7), &cesymb(1), &cesymb(0), 1);
|
|
|
|
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(7), &cesymb(1), &cesymb(0), 1);
|
|
|
|
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(1), &cesymb(7), &cesymb(2), 5);
|
|
|
|
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(1), &cesymb(7), &cesymb(2), 5);
|
|
|
@ -308,6 +253,25 @@ static void interpolate_pilots(srslte_chest_dl_t *q, cf_t *pilot_estimates, cf_t
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void srslte_chest_dl_set_smooth_filter(srslte_chest_dl_t *q, float *filter, uint32_t filter_len) {
|
|
|
|
|
|
|
|
if (filter_len < SRSLTE_CHEST_DL_MAX_SMOOTH_FIL_LEN) {
|
|
|
|
|
|
|
|
memcpy(q->smooth_filter, filter, filter_len*sizeof(float));
|
|
|
|
|
|
|
|
q->smooth_filter_len = filter_len;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
fprintf(stderr, "Error setting smoothing filter: filter len exceeds maximum (%d>%d)\n",
|
|
|
|
|
|
|
|
filter_len, SRSLTE_CHEST_DL_MAX_SMOOTH_FIL_LEN);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 nref = 2*q->cell.nof_prb;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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) {
|
|
|
|
uint32_t l;
|
|
|
|
uint32_t l;
|
|
|
|
|
|
|
|
|
|
|
@ -320,43 +284,39 @@ float srslte_chest_dl_rssi(srslte_chest_dl_t *q, cf_t *input, uint32_t port_id)
|
|
|
|
return rssi/nsymbols;
|
|
|
|
return rssi/nsymbols;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#define RSRP_FROM_ESTIMATES
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
float srslte_chest_dl_rsrp(srslte_chest_dl_t *q, uint32_t port_id) {
|
|
|
|
|
|
|
|
#ifdef RSRP_FROM_ESTIMATES
|
|
|
|
|
|
|
|
return srslte_vec_avg_power_cf(q->pilot_estimates[port_id],
|
|
|
|
|
|
|
|
SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id));
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
return srslte_vec_avg_power_cf(q->pilot_estimates_average[port_id],
|
|
|
|
|
|
|
|
SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id));
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int srslte_chest_dl_estimate_port(srslte_chest_dl_t *q, cf_t *input, cf_t *ce, uint32_t sf_idx, uint32_t port_id)
|
|
|
|
int srslte_chest_dl_estimate_port(srslte_chest_dl_t *q, cf_t *input, cf_t *ce, uint32_t sf_idx, uint32_t port_id)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
/* Get references from the input signal */
|
|
|
|
/* Get references from the input signal */
|
|
|
|
srslte_refsignal_cs_get_sf(q->cell, port_id, input, q->pilot_recv_signal[port_id]);
|
|
|
|
srslte_refsignal_cs_get_sf(q->cell, port_id, input, q->pilot_recv_signal);
|
|
|
|
|
|
|
|
|
|
|
|
/* Use the known CSR signal to compute Least-squares estimates */
|
|
|
|
/* Use the known CSR signal to compute Least-squares estimates */
|
|
|
|
srslte_vec_prod_conj_ccc(q->pilot_recv_signal[port_id], q->csr_signal.pilots[port_id/2][sf_idx],
|
|
|
|
srslte_vec_prod_conj_ccc(q->pilot_recv_signal, q->csr_signal.pilots[port_id/2][sf_idx],
|
|
|
|
q->pilot_estimates[port_id], SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id));
|
|
|
|
q->pilot_estimates, SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id));
|
|
|
|
|
|
|
|
|
|
|
|
if (ce != NULL) {
|
|
|
|
if (ce != NULL) {
|
|
|
|
/* Interpolate to create channel estimates for all resource grid */
|
|
|
|
if (q->smooth_filter_len > 0) {
|
|
|
|
interpolate_pilots(q, q->pilot_estimates[port_id], ce, port_id);
|
|
|
|
average_pilots(q, q->pilot_estimates, q->pilot_estimates_average, port_id);
|
|
|
|
|
|
|
|
interpolate_pilots(q, q->pilot_estimates_average, ce, port_id);
|
|
|
|
/* Average channel estimates */
|
|
|
|
|
|
|
|
average_estimates(q, ce, port_id);
|
|
|
|
/* If averaging, compute noise from difference between received and averaged estimates */
|
|
|
|
}
|
|
|
|
if (sf_idx == 0 || sf_idx == 5) {
|
|
|
|
|
|
|
|
q->noise_estimate[port_id] = estimate_noise_pilots(q, ce, port_id);
|
|
|
|
#if NOISE_POWER_METHOD==1
|
|
|
|
}
|
|
|
|
if (sf_idx == 0 || sf_idx == 5) {
|
|
|
|
} else {
|
|
|
|
q->noise_estimate[port_id] = estimate_noise_port(q, input);
|
|
|
|
interpolate_pilots(q, q->pilot_estimates, ce, port_id);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* If not averaging, compute noise from empty subcarriers */
|
|
|
|
|
|
|
|
if (sf_idx == 0 || sf_idx == 5) {
|
|
|
|
|
|
|
|
#ifdef ESTIMATE_NOISE_LS_PSS
|
|
|
|
|
|
|
|
q->noise_estimate[port_id] = estimate_noise_pss(q, input, ce);
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
q->noise_estimate[port_id] = estimate_noise_empty_sc(q, input);
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Compute RSRP for the channel estimates in this port */
|
|
|
|
/* Compute RSRP for the channel estimates in this port */
|
|
|
|
q->rsrp[port_id] = srslte_chest_dl_rsrp(q, port_id);
|
|
|
|
q->rsrp[port_id] = srslte_vec_avg_power_cf(q->pilot_recv_signal, SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id));
|
|
|
|
if (port_id == 0) {
|
|
|
|
if (port_id == 0) {
|
|
|
|
/* compute rssi only for port 0 */
|
|
|
|
/* compute rssi only for port 0 */
|
|
|
|
q->rssi[port_id] = srslte_chest_dl_rssi(q, input, port_id);
|
|
|
|
q->rssi[port_id] = srslte_chest_dl_rssi(q, input, port_id);
|
|
|
|