mirror of https://github.com/PentHertz/srsLTE.git
Created chest UL
This commit is contained in:
parent
675ba2e568
commit
7f8ee935fc
|
@ -35,6 +35,8 @@
|
|||
#include <assert.h>
|
||||
#include <signal.h>
|
||||
|
||||
#define ENABLE_AGC_DEFAULT
|
||||
|
||||
#include "srslte/srslte.h"
|
||||
#include "srslte/rf/rf.h"
|
||||
#include "srslte/rf/rf_utils.h"
|
||||
|
@ -63,7 +65,11 @@ void args_default(prog_args_t *args) {
|
|||
args->force_N_id_2 = -1; // Pick the best
|
||||
args->rf_args = "";
|
||||
args->rf_freq = -1.0;
|
||||
#ifdef ENABLE_AGC_DEFAULT
|
||||
args->rf_gain = -1;
|
||||
#else
|
||||
args->rf_gain = 50;
|
||||
#endif
|
||||
}
|
||||
|
||||
void usage(prog_args_t *args, char *prog) {
|
||||
|
|
|
@ -39,8 +39,7 @@
|
|||
|
||||
#include "srslte/srslte.h"
|
||||
|
||||
// From srsLTE 1.2, AGC is disabled by default
|
||||
//#define ENABLE_AGC_DEFAULT
|
||||
#define ENABLE_AGC_DEFAULT
|
||||
|
||||
#ifndef DISABLE_RF
|
||||
#include "srslte/rf/rf.h"
|
||||
|
@ -130,7 +129,11 @@ void usage(prog_args_t *args, char *prog) {
|
|||
printf("Usage: %s [agpPoOcildDnruv] -f rx_frequency (in Hz) | -i input_file\n", prog);
|
||||
#ifndef DISABLE_RF
|
||||
printf("\t-a RF args [Default %s]\n", args->rf_args);
|
||||
#ifdef ENABLE_AGC_DEFAULT
|
||||
printf("\t-g RF fix RX gain [Default AGC]\n");
|
||||
#else
|
||||
printf("\t-g Set RX gain [Default %.1f dB]\n", args->rf_gain);
|
||||
#endif
|
||||
#else
|
||||
printf("\t RF is disabled.\n");
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2015 Software Radio Systems Limited
|
||||
*
|
||||
* \section LICENSE
|
||||
*
|
||||
* This file is part of the srsLTE library.
|
||||
*
|
||||
* srsLTE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* srsLTE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Affero General Public License can be found in
|
||||
* the LICENSE file in the top-level directory of this distribution
|
||||
* and at http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CHEST_
|
||||
#define CHEST_
|
||||
|
||||
#include "srslte/config.h"
|
||||
|
||||
#define SRSLTE_CHEST_MAX_SMOOTH_FIL_LEN 65
|
||||
|
||||
|
||||
SRSLTE_API void srslte_chest_average_pilots(cf_t *input,
|
||||
cf_t *output,
|
||||
cf_t *filter,
|
||||
uint32_t nof_ref,
|
||||
uint32_t nof_symbols,
|
||||
uint32_t filter_len);
|
||||
|
||||
SRSLTE_API void srslte_chest_set_smooth_filter3_coeff(float *smooth_filter,
|
||||
float w);
|
||||
|
||||
SRSLTE_API float srslte_chest_estimate_noise_pilots(cf_t *noisy,
|
||||
cf_t *noiseless,
|
||||
cf_t *noise_vec,
|
||||
uint32_t nof_pilots);
|
||||
|
||||
SRSLTE_API void srslte_chest_set_triangle_filter(float *fil,
|
||||
int filter_len);
|
||||
|
||||
#endif
|
||||
|
|
@ -45,12 +45,12 @@
|
|||
|
||||
#include "srslte/config.h"
|
||||
|
||||
#include "srslte/ch_estimation/chest_common.h"
|
||||
#include "srslte/resampling/interp.h"
|
||||
#include "srslte/ch_estimation/refsignal_dl.h"
|
||||
#include "srslte/common/phy_common.h"
|
||||
#include "srslte/sync/pss.h"
|
||||
|
||||
#define SRSLTE_CHEST_DL_MAX_SMOOTH_FIL_LEN 65
|
||||
|
||||
typedef struct {
|
||||
srslte_cell_t cell;
|
||||
|
@ -65,7 +65,7 @@ typedef struct {
|
|||
float pilot_power[12000];
|
||||
#endif
|
||||
uint32_t smooth_filter_len;
|
||||
float smooth_filter[SRSLTE_CHEST_DL_MAX_SMOOTH_FIL_LEN];
|
||||
float smooth_filter[SRSLTE_CHEST_MAX_SMOOTH_FIL_LEN];
|
||||
|
||||
srslte_interp_linsrslte_vec_t srslte_interp_linvec;
|
||||
srslte_interp_lin_t srslte_interp_lin;
|
||||
|
|
|
@ -0,0 +1,105 @@
|
|||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2015 Software Radio Systems Limited
|
||||
*
|
||||
* \section LICENSE
|
||||
*
|
||||
* This file is part of the srsLTE library.
|
||||
*
|
||||
* srsLTE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* srsLTE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Affero General Public License can be found in
|
||||
* the LICENSE file in the top-level directory of this distribution
|
||||
* and at http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
|
||||
/**********************************************************************************************
|
||||
* File: chest_ul.h
|
||||
*
|
||||
* Description: 3GPP LTE Uplink channel estimator and equalizer.
|
||||
* Estimates the channel in the resource elements transmitting references and
|
||||
* interpolates for the rest of the resource grid.
|
||||
* The equalizer uses the channel estimates to produce an estimation of the
|
||||
* transmitted symbol.
|
||||
*
|
||||
* Reference:
|
||||
*********************************************************************************************/
|
||||
|
||||
#ifndef CHEST_UL_
|
||||
#define CHEST_UL_
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "srslte/config.h"
|
||||
|
||||
#include "srslte/ch_estimation/chest_common.h"
|
||||
#include "srslte/resampling/interp.h"
|
||||
#include "srslte/ch_estimation/refsignal_ul.h"
|
||||
#include "srslte/common/phy_common.h"
|
||||
|
||||
typedef struct {
|
||||
srslte_cell_t cell;
|
||||
|
||||
srslte_refsignal_ul_t dmrs_signal;
|
||||
srslte_refsignal_ul_dmrs_pregen_t dmrs_pregen;
|
||||
bool dmrs_signal_configured;
|
||||
|
||||
cf_t *pilot_estimates;
|
||||
cf_t *pilot_estimates_average;
|
||||
cf_t *pilot_recv_signal;
|
||||
cf_t *tmp_noise;
|
||||
|
||||
#ifdef FREQ_SEL_SNR
|
||||
float snr_vector[12000];
|
||||
float pilot_power[12000];
|
||||
#endif
|
||||
uint32_t smooth_filter_len;
|
||||
float smooth_filter[SRSLTE_CHEST_MAX_SMOOTH_FIL_LEN];
|
||||
|
||||
srslte_interp_linsrslte_vec_t srslte_interp_linvec;
|
||||
|
||||
float pilot_power;
|
||||
float noise_estimate;
|
||||
|
||||
} srslte_chest_ul_t;
|
||||
|
||||
|
||||
SRSLTE_API int srslte_chest_ul_init(srslte_chest_ul_t *q,
|
||||
srslte_cell_t cell);
|
||||
|
||||
SRSLTE_API void srslte_chest_ul_free(srslte_chest_ul_t *q);
|
||||
|
||||
SRSLTE_API void srslte_chest_ul_set_cfg(srslte_chest_ul_t *q,
|
||||
srslte_refsignal_dmrs_pusch_cfg_t *pusch_cfg,
|
||||
srslte_pucch_cfg_t *pucch_cfg,
|
||||
srslte_refsignal_srs_cfg_t *srs_cfg);
|
||||
|
||||
SRSLTE_API void srslte_chest_ul_set_smooth_filter(srslte_chest_ul_t *q,
|
||||
float *filter,
|
||||
uint32_t filter_len);
|
||||
|
||||
SRSLTE_API void srslte_chest_ul_set_smooth_filter3_coeff(srslte_chest_ul_t* q,
|
||||
float w);
|
||||
|
||||
SRSLTE_API int srslte_chest_ul_estimate(srslte_chest_ul_t *q,
|
||||
cf_t *input,
|
||||
cf_t *ce[SRSLTE_MAX_PORTS],
|
||||
uint32_t sf_idx);
|
||||
|
||||
SRSLTE_API float srslte_chest_ul_get_noise_estimate(srslte_chest_ul_t *q);
|
||||
|
||||
SRSLTE_API float srslte_chest_ul_get_snr(srslte_chest_ul_t *q);
|
||||
|
||||
|
||||
#endif
|
|
@ -44,6 +44,8 @@
|
|||
#define SRSLTE_NOF_DELTA_SS 30
|
||||
#define SRSLTE_NOF_CSHIFT 8
|
||||
|
||||
#define SRSLTE_REFSIGNAL_UL_L(ns_idx, cp) ((ns_idx+1)*SRSLTE_CP_NSYMB(cp)-4)
|
||||
|
||||
typedef struct SRSLTE_API {
|
||||
uint32_t cyclic_shift;
|
||||
uint32_t delta_ss;
|
||||
|
@ -129,6 +131,12 @@ SRSLTE_API void srslte_refsignal_dmrs_pusch_put(srslte_refsignal_ul_t *q,
|
|||
uint32_t n_prb[2],
|
||||
cf_t *sf_symbols);
|
||||
|
||||
SRSLTE_API void srslte_refsignal_dmrs_pusch_get(srslte_refsignal_ul_t *q,
|
||||
cf_t *sf_symbols,
|
||||
uint32_t nof_prb,
|
||||
uint32_t n_prb[2],
|
||||
cf_t *r_pusch);
|
||||
|
||||
SRSLTE_API int srslte_refsignal_dmrs_pucch_gen(srslte_refsignal_ul_t *q,
|
||||
srslte_pucch_format_t format,
|
||||
uint32_t n_pucch, // n_pucch_1 or n_pucch_2 depending on format
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2015 Software Radio Systems Limited
|
||||
*
|
||||
* \section LICENSE
|
||||
*
|
||||
* This file is part of the srsLTE library.
|
||||
*
|
||||
* srsLTE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* srsLTE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Affero General Public License can be found in
|
||||
* the LICENSE file in the top-level directory of this distribution
|
||||
* and at http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <strings.h>
|
||||
#include <string.h>
|
||||
#include <complex.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "srslte/ch_estimation/chest_common.h"
|
||||
#include "srslte/utils/vector.h"
|
||||
#include "srslte/utils/convolution.h"
|
||||
|
||||
void srslte_chest_set_triangle_filter(float *fil, int filter_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;
|
||||
}
|
||||
}
|
||||
|
||||
/* Uses the difference between the averaged and non-averaged pilot estimates */
|
||||
float srslte_chest_estimate_noise_pilots(cf_t *noisy, cf_t *noiseless, cf_t *noise_vec, uint32_t nof_pilots)
|
||||
{
|
||||
/* Substract noisy pilot estimates */
|
||||
srslte_vec_sub_ccc(noiseless, noisy, noise_vec, nof_pilots);
|
||||
|
||||
/* Compute average power */
|
||||
float power = srslte_vec_avg_power_cf(noise_vec, nof_pilots);
|
||||
return power;
|
||||
}
|
||||
|
||||
void srslte_chest_set_smooth_filter3_coeff(float *smooth_filter, float w)
|
||||
{
|
||||
smooth_filter[0] = w;
|
||||
smooth_filter[2] = w;
|
||||
smooth_filter[1] = 1-2*w;
|
||||
}
|
||||
|
||||
void srslte_chest_average_pilots(cf_t *input, cf_t *output, cf_t *filter,
|
||||
uint32_t nof_ref, uint32_t nof_symbols, uint32_t filter_len)
|
||||
{
|
||||
for (int l=0;l<nof_symbols;l++) {
|
||||
srslte_conv_same_cf(&input[l*nof_ref], filter, &output[l*nof_ref], nof_ref, filter_len);
|
||||
}
|
||||
}
|
||||
|
|
@ -35,36 +35,12 @@
|
|||
|
||||
#include "srslte/config.h"
|
||||
|
||||
#include "srslte/ch_estimation/chest_common.h"
|
||||
#include "srslte/ch_estimation/chest_dl.h"
|
||||
#include "srslte/utils/vector.h"
|
||||
#include "srslte/utils/convolution.h"
|
||||
|
||||
#define ESTIMATE_NOISE_LS_PSS
|
||||
|
||||
//#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.
|
||||
* Estimates the channel in the resource elements transmitting references and interpolates for the rest
|
||||
|
@ -163,24 +139,15 @@ void srslte_chest_dl_free(srslte_chest_dl_t *q)
|
|||
}
|
||||
|
||||
/* Uses the difference between the averaged and non-averaged pilot estimates */
|
||||
static float estimate_noise_pilots(srslte_chest_dl_t *q, uint32_t port_id)
|
||||
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);
|
||||
/* Substract noisy pilot estimates */
|
||||
srslte_vec_sub_ccc(q->pilot_estimates_average, q->pilot_estimates, q->tmp_noise, nref);
|
||||
float power = srslte_chest_estimate_noise_pilots(q->pilot_estimates,
|
||||
q->pilot_estimates_average,
|
||||
q->tmp_noise,
|
||||
nref);
|
||||
|
||||
#ifdef FREQ_SEL_SNR
|
||||
/* Compute frequency-selective SNR */
|
||||
srslte_vec_abs_square_cf(q->tmp_noise, q->snr_vector, nref);
|
||||
srslte_vec_abs_square_cf(q->pilot_estimates, q->pilot_power, nref);
|
||||
srslte_vec_div_fff(q->pilot_power, q->snr_vector, q->snr_vector, nref);
|
||||
|
||||
srslte_vec_fprint_f(stdout, q->snr_vector, nref);
|
||||
#endif
|
||||
|
||||
/* Compute average power */
|
||||
float power = (1/q->smooth_filter[0])*q->cell.nof_ports*srslte_vec_avg_power_cf(q->tmp_noise, nref);
|
||||
return power;
|
||||
return (1/q->smooth_filter[0])*q->cell.nof_ports*power;
|
||||
}
|
||||
|
||||
#ifdef ESTIMATE_NOISE_LS_PSS
|
||||
|
@ -264,7 +231,7 @@ 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) {
|
||||
if (filter_len < SRSLTE_CHEST_MAX_SMOOTH_FIL_LEN) {
|
||||
if (filter) {
|
||||
memcpy(q->smooth_filter, filter, filter_len*sizeof(float));
|
||||
q->smooth_filter_len = filter_len;
|
||||
|
@ -273,38 +240,22 @@ void srslte_chest_dl_set_smooth_filter(srslte_chest_dl_t *q, float *filter, uint
|
|||
}
|
||||
} else {
|
||||
fprintf(stderr, "Error setting smoothing filter: filter len exceeds maximum (%d>%d)\n",
|
||||
filter_len, SRSLTE_CHEST_DL_MAX_SMOOTH_FIL_LEN);
|
||||
filter_len, SRSLTE_CHEST_MAX_SMOOTH_FIL_LEN);
|
||||
}
|
||||
}
|
||||
|
||||
void srslte_chest_dl_set_smooth_filter3_coeff(srslte_chest_dl_t* q, float w)
|
||||
{
|
||||
q->smooth_filter_len = 3;
|
||||
q->smooth_filter[0] = w;
|
||||
q->smooth_filter[2] = w;
|
||||
q->smooth_filter[1] = 1-2*w;
|
||||
void srslte_chest_dl_set_smooth_filter3_coeff(srslte_chest_dl_t* q, float w) {
|
||||
srslte_chest_set_smooth_filter3_coeff(q->smooth_filter, w);
|
||||
q->smooth_filter_len = 3;
|
||||
}
|
||||
|
||||
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 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);
|
||||
}
|
||||
srslte_chest_average_pilots(input, output, q->smooth_filter, nref, nsymbols, q->smooth_filter_len);
|
||||
}
|
||||
|
||||
float srslte_chest_dl_rssi(srslte_chest_dl_t *q, cf_t *input, uint32_t port_id) {
|
||||
uint32_t l;
|
||||
|
||||
float rssi = 0;
|
||||
uint32_t nsymbols = srslte_refsignal_cs_nof_symbols(port_id);
|
||||
for (l=0;l<nsymbols;l++) {
|
||||
cf_t *tmp = &input[srslte_refsignal_cs_nsymbol(l, q->cell.cp, port_id) * q->cell.nof_prb * SRSLTE_NRE];
|
||||
rssi += srslte_vec_dot_prod_conj_ccc(tmp, tmp, q->cell.nof_prb * SRSLTE_NRE);
|
||||
}
|
||||
return rssi/nsymbols;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -314,6 +265,7 @@ int srslte_chest_dl_estimate_port(srslte_chest_dl_t *q, cf_t *input, cf_t *ce, u
|
|||
/* Use the known CSR signal to compute Least-squares estimates */
|
||||
srslte_vec_prod_conj_ccc(q->pilot_recv_signal, q->csr_signal.pilots[port_id/2][sf_idx],
|
||||
q->pilot_estimates, SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id));
|
||||
|
||||
if (ce != NULL) {
|
||||
if (q->smooth_filter_len > 0) {
|
||||
average_pilots(q, q->pilot_estimates, q->pilot_estimates_average, port_id);
|
||||
|
@ -370,6 +322,18 @@ float srslte_chest_dl_get_snr(srslte_chest_dl_t *q) {
|
|||
#endif
|
||||
}
|
||||
|
||||
float srslte_chest_dl_rssi(srslte_chest_dl_t *q, cf_t *input, uint32_t port_id) {
|
||||
uint32_t l;
|
||||
|
||||
float rssi = 0;
|
||||
uint32_t nsymbols = srslte_refsignal_cs_nof_symbols(port_id);
|
||||
for (l=0;l<nsymbols;l++) {
|
||||
cf_t *tmp = &input[srslte_refsignal_cs_nsymbol(l, q->cell.cp, port_id) * q->cell.nof_prb * SRSLTE_NRE];
|
||||
rssi += srslte_vec_dot_prod_conj_ccc(tmp, tmp, q->cell.nof_prb * SRSLTE_NRE);
|
||||
}
|
||||
return rssi/nsymbols;
|
||||
}
|
||||
|
||||
float srslte_chest_dl_get_rssi(srslte_chest_dl_t *q) {
|
||||
return 4*q->rssi[0]/q->cell.nof_prb/SRSLTE_NRE;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,239 @@
|
|||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2015 Software Radio Systems Limited
|
||||
*
|
||||
* \section LICENSE
|
||||
*
|
||||
* This file is part of the srsLTE library.
|
||||
*
|
||||
* srsLTE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* srsLTE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Affero General Public License can be found in
|
||||
* the LICENSE file in the top-level directory of this distribution
|
||||
* and at http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <strings.h>
|
||||
#include <string.h>
|
||||
#include <complex.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "srslte/config.h"
|
||||
|
||||
#include "srslte/ch_estimation/chest_ul.h"
|
||||
#include "srslte/utils/vector.h"
|
||||
#include "srslte/utils/convolution.h"
|
||||
|
||||
#define NOF_REFS_SYM (q->cell.nof_prb*SRSLTE_NRE)
|
||||
#define NOF_REFS_SF (NOF_REFS_SYM*2) // 2 reference symbols per subframe
|
||||
|
||||
/** 3GPP LTE Downlink channel estimator and equalizer.
|
||||
* Estimates the channel in the resource elements transmitting references and interpolates for the rest
|
||||
* of the resource grid.
|
||||
*
|
||||
* The equalizer uses the channel estimates to produce an estimation of the transmitted symbol.
|
||||
*
|
||||
* This object depends on the srslte_refsignal_t object for creating the LTE CSR signal.
|
||||
*/
|
||||
|
||||
int srslte_chest_ul_init(srslte_chest_ul_t *q, srslte_cell_t cell)
|
||||
{
|
||||
int ret = SRSLTE_ERROR_INVALID_INPUTS;
|
||||
if (q != NULL &&
|
||||
srslte_cell_isvalid(&cell))
|
||||
{
|
||||
bzero(q, sizeof(srslte_chest_ul_t));
|
||||
|
||||
ret = srslte_refsignal_ul_init(&q->dmrs_signal, cell);
|
||||
if (ret != SRSLTE_SUCCESS) {
|
||||
fprintf(stderr, "Error initializing CSR signal (%d)\n",ret);
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
q->tmp_noise = srslte_vec_malloc(sizeof(cf_t) * NOF_REFS_SF);
|
||||
if (!q->tmp_noise) {
|
||||
perror("malloc");
|
||||
goto clean_exit;
|
||||
}
|
||||
q->pilot_estimates = srslte_vec_malloc(sizeof(cf_t) * NOF_REFS_SF);
|
||||
if (!q->pilot_estimates) {
|
||||
perror("malloc");
|
||||
goto clean_exit;
|
||||
}
|
||||
q->pilot_estimates_average = srslte_vec_malloc(sizeof(cf_t) * NOF_REFS_SF);
|
||||
if (!q->pilot_estimates_average) {
|
||||
perror("malloc");
|
||||
goto clean_exit;
|
||||
}
|
||||
q->pilot_recv_signal = srslte_vec_malloc(sizeof(cf_t) * NOF_REFS_SF);
|
||||
if (!q->pilot_recv_signal) {
|
||||
perror("malloc");
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
if (srslte_interp_linear_vector_init(&q->srslte_interp_linvec, NOF_REFS_SYM)) {
|
||||
fprintf(stderr, "Error initializing vector interpolator\n");
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
q->smooth_filter_len = 3;
|
||||
srslte_chest_ul_set_smooth_filter3_coeff(q, 0.1);
|
||||
|
||||
q->cell = cell;
|
||||
}
|
||||
|
||||
q->dmrs_signal_configured = false;
|
||||
|
||||
ret = SRSLTE_SUCCESS;
|
||||
|
||||
clean_exit:
|
||||
if (ret != SRSLTE_SUCCESS) {
|
||||
srslte_chest_ul_free(q);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void srslte_chest_ul_free(srslte_chest_ul_t *q)
|
||||
{
|
||||
srslte_refsignal_ul_free(&q->dmrs_signal);
|
||||
|
||||
if (q->tmp_noise) {
|
||||
free(q->tmp_noise);
|
||||
}
|
||||
srslte_interp_linear_vector_free(&q->srslte_interp_linvec);
|
||||
|
||||
if (q->pilot_estimates) {
|
||||
free(q->pilot_estimates);
|
||||
}
|
||||
if (q->pilot_estimates_average) {
|
||||
free(q->pilot_estimates_average);
|
||||
}
|
||||
if (q->pilot_recv_signal) {
|
||||
free(q->pilot_recv_signal);
|
||||
}
|
||||
bzero(q, sizeof(srslte_chest_ul_t));
|
||||
}
|
||||
|
||||
void srslte_chest_ul_set_cfg(srslte_chest_ul_t *q,
|
||||
srslte_refsignal_dmrs_pusch_cfg_t *pusch_cfg,
|
||||
srslte_pucch_cfg_t *pucch_cfg,
|
||||
srslte_refsignal_srs_cfg_t *srs_cfg)
|
||||
{
|
||||
srslte_chest_ul_set_cfg(&q->dmrs_signal, pusch_cfg, pucch_cfg, srs_cfg);
|
||||
srslte_refsignal_dmrs_pusch_pregen(&q->dmrs_signal, &q->dmrs_pregen);
|
||||
q->dmrs_signal_configured = true;
|
||||
}
|
||||
|
||||
/* Uses the difference between the averaged and non-averaged pilot estimates */
|
||||
static float estimate_noise_pilots(srslte_chest_ul_t *q)
|
||||
{
|
||||
float power = srslte_chest_estimate_noise_pilots(q->pilot_estimates,
|
||||
q->pilot_estimates_average,
|
||||
q->tmp_noise,
|
||||
NOF_REFS_SF);
|
||||
|
||||
return (1/q->smooth_filter[0])*power;
|
||||
}
|
||||
|
||||
#define cesymb(i) ce[SRSLTE_RE_IDX(q->cell.nof_prb,i,0)]
|
||||
|
||||
static void interpolate_pilots(srslte_chest_ul_t *q, cf_t *pilot_estimates, cf_t *ce)
|
||||
{
|
||||
/* interpolate the symbols with references in the freq domain */
|
||||
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 = 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)-1);
|
||||
srslte_interp_linear_vector( &q->srslte_interp_linvec, &cesymb(L1), &cesymb(L2), &cesymb(L1+1), (L2-L1)-1);
|
||||
srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(L1), &cesymb(L2), &cesymb(L2), &cesymb(L2+1), (NL-L2)-1);
|
||||
|
||||
// TODO: Maybe here need to do some averaging with previous symbols?
|
||||
}
|
||||
|
||||
void srslte_chest_ul_set_smooth_filter(srslte_chest_ul_t *q, float *filter, uint32_t filter_len) {
|
||||
if (filter_len < SRSLTE_CHEST_MAX_SMOOTH_FIL_LEN) {
|
||||
if (filter) {
|
||||
memcpy(q->smooth_filter, filter, filter_len*sizeof(float));
|
||||
q->smooth_filter_len = filter_len;
|
||||
} else {
|
||||
q->smooth_filter_len = 0;
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "Error setting smoothing filter: filter len exceeds maximum (%d>%d)\n",
|
||||
filter_len, SRSLTE_CHEST_MAX_SMOOTH_FIL_LEN);
|
||||
}
|
||||
}
|
||||
|
||||
void srslte_chest_ul_set_smooth_filter3_coeff(srslte_chest_ul_t* q, float w)
|
||||
{
|
||||
srslte_chest_set_smooth_filter3_coeff(q->smooth_filter, w);
|
||||
q->smooth_filter_len = 3;
|
||||
}
|
||||
|
||||
static void average_pilots(srslte_chest_ul_t *q, cf_t *input, cf_t *output) {
|
||||
uint32_t nsymbols = 2;
|
||||
uint32_t nref = NOF_REFS_SYM;
|
||||
srslte_chest_average_pilots(input, output, q->smooth_filter, nref, nsymbols, 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;
|
||||
}
|
||||
|
||||
/* 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, NOF_REFS_SF);
|
||||
|
||||
if (ce != NULL) {
|
||||
if (q->smooth_filter_len > 0) {
|
||||
average_pilots(q, q->pilot_estimates, q->pilot_estimates_average);
|
||||
interpolate_pilots(q, q->pilot_estimates_average, ce);
|
||||
|
||||
/* If averaging, compute noise from difference between received and averaged estimates */
|
||||
if (sf_idx == 0 || sf_idx == 5) {
|
||||
q->noise_estimate = estimate_noise_pilots(q);
|
||||
}
|
||||
} else {
|
||||
interpolate_pilots(q, q->pilot_estimates, ce);
|
||||
q->noise_estimate = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Estimate received pilot power
|
||||
q->pilot_power = srslte_vec_avg_power_cf(q->pilot_recv_signal, NOF_REFS_SF);
|
||||
return 0;
|
||||
}
|
||||
|
||||
float srslte_chest_ul_get_noise_estimate(srslte_chest_ul_t *q) {
|
||||
return q->noise_estimate;
|
||||
}
|
||||
|
||||
float srslte_chest_ul_get_snr(srslte_chest_ul_t *q) {
|
||||
return q->pilot_power/srslte_chest_ul_get_noise_estimate(q);
|
||||
}
|
||||
|
|
@ -320,12 +320,23 @@ void srslte_refsignal_dmrs_pusch_put(srslte_refsignal_ul_t *q, cf_t *r_pusch, ui
|
|||
{
|
||||
for (uint32_t ns_idx=0;ns_idx<2;ns_idx++) {
|
||||
INFO("Putting DRMS to n_prb: %d, L: %d, ns_idx: %d\n", n_prb[ns_idx], nof_prb, ns_idx);
|
||||
uint32_t L = (ns_idx+1)*SRSLTE_CP_NSYMB(q->cell.cp)-4;
|
||||
uint32_t L = SRSLTE_REFSIGNAL_UL_L(ns_idx, q->cell.cp);
|
||||
memcpy(&sf_symbols[SRSLTE_RE_IDX(q->cell.nof_prb, L, n_prb[ns_idx]*SRSLTE_NRE)],
|
||||
&r_pusch[ns_idx*SRSLTE_NRE*nof_prb], nof_prb*SRSLTE_NRE*sizeof(cf_t));
|
||||
}
|
||||
}
|
||||
|
||||
void srslte_refsignal_dmrs_pusch_get(srslte_refsignal_ul_t *q, cf_t *sf_symbols, uint32_t nof_prb, uint32_t n_prb[2], cf_t *r_pusch)
|
||||
{
|
||||
for (uint32_t ns_idx=0;ns_idx<2;ns_idx++) {
|
||||
INFO("Getting DRMS from n_prb: %d, L: %d, ns_idx: %d\n", n_prb[ns_idx], nof_prb, ns_idx);
|
||||
uint32_t L = SRSLTE_REFSIGNAL_UL_L(ns_idx, q->cell.cp);
|
||||
memcpy(&r_pusch[ns_idx*SRSLTE_NRE*nof_prb],
|
||||
&sf_symbols[SRSLTE_RE_IDX(q->cell.nof_prb, L, n_prb[ns_idx]*SRSLTE_NRE)],
|
||||
nof_prb*SRSLTE_NRE*sizeof(cf_t));
|
||||
}
|
||||
}
|
||||
|
||||
/* Computes r sequence */
|
||||
void compute_r(srslte_refsignal_ul_t *q, uint32_t nof_prb, uint32_t ns, uint32_t delta_ss) {
|
||||
// Get group hopping number u
|
||||
|
|
Loading…
Reference in New Issue