mirror of https://github.com/PentHertz/srsLTE.git
Added MMSE SISO equalizer (predecoding)
This commit is contained in:
parent
f505a75382
commit
4f653dc3ab
|
@ -35,7 +35,7 @@ CHECK_FUNCTION_EXISTS_MATH(volk_32fc_x2_multiply_conjugate_32fc HAVE_VOLK_MULT2_
|
|||
CHECK_FUNCTION_EXISTS_MATH(volk_32fc_32f_multiply_32fc HAVE_VOLK_MULT_REAL_FUNCTION)
|
||||
CHECK_FUNCTION_EXISTS_MATH(volk_32f_s32f_multiply_32f HAVE_VOLK_MULT_FLOAT_FUNCTION)
|
||||
CHECK_FUNCTION_EXISTS_MATH(volk_32fc_magnitude_32f HAVE_VOLK_MAG_FUNCTION)
|
||||
CHECK_FUNCTION_EXISTS_MATH(volk_32fc_magnitude_square_32f HAVE_VOLK_MAG_SQUARE_FUNCTION)
|
||||
CHECK_FUNCTION_EXISTS_MATH(volk_32fc_magnitude_squared_32f HAVE_VOLK_MAG_SQUARE_FUNCTION)
|
||||
CHECK_FUNCTION_EXISTS_MATH(volk_32f_x2_divide_32f HAVE_VOLK_DIVIDE_FUNCTION)
|
||||
CHECK_FUNCTION_EXISTS_MATH(volk_32fc_x2_dot_prod_32fc HAVE_VOLK_DOTPROD_FC_FUNCTION)
|
||||
CHECK_FUNCTION_EXISTS_MATH(volk_32fc_32f_dot_prod_32fc HAVE_VOLK_DOTPROD_CFC_FUNCTION)
|
||||
|
@ -44,6 +44,7 @@ CHECK_FUNCTION_EXISTS_MATH(volk_32f_x2_dot_prod_32f HAVE_VOLK_DOTPROD_F_FUNCTION
|
|||
CHECK_FUNCTION_EXISTS_MATH(volk_32fc_s32f_atan2_32f HAVE_VOLK_ATAN_FUNCTION)
|
||||
CHECK_FUNCTION_EXISTS_MATH(volk_32f_s32f_convert_16i HAVE_VOLK_CONVERT_FI_FUNCTION)
|
||||
CHECK_FUNCTION_EXISTS_MATH(volk_32fc_deinterleave_32f_x2 HAVE_VOLK_DEINTERLEAVE_FUNCTION)
|
||||
CHECK_FUNCTION_EXISTS_MATH(volk_32f_x2_interleave_32fc HAVE_VOLK_INTERLEAVE_FUNCTION)
|
||||
CHECK_FUNCTION_EXISTS_MATH(volk_32f_x2_subtract_32f HAVE_VOLK_SUB_FLOAT_FUNCTION)
|
||||
CHECK_FUNCTION_EXISTS_MATH(volk_32f_x2_add_32f HAVE_VOLK_ADD_FLOAT_FUNCTION)
|
||||
CHECK_FUNCTION_EXISTS_MATH(volk_32fc_x2_square_dist_32f HAVE_VOLK_SQUARE_DIST_FUNCTION)
|
||||
|
@ -59,12 +60,18 @@ ENDIF()
|
|||
IF(${HAVE_VOLK_DOTPROD_CONJ_FC_FUNCTION})
|
||||
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_DOTPROD_CONJ_FC_FUNCTION")
|
||||
ENDIF()
|
||||
IF(${HAVE_VOLK_MAG_SQUARE_FUNCTION})
|
||||
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MAG_SQUARE_FUNCTION")
|
||||
ENDIF()
|
||||
IF(${HAVE_VOLK_SQUARE_DIST_FUNCTION})
|
||||
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_SQUARE_DIST_FUNCTION")
|
||||
ENDIF()
|
||||
IF(${HAVE_VOLK_DEINTERLEAVE_FUNCTION})
|
||||
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_DEINTERLEAVE_FUNCTION")
|
||||
ENDIF()
|
||||
IF(${HAVE_VOLK_INTERLEAVE_FUNCTION})
|
||||
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_INTERLEAVE_FUNCTION")
|
||||
ENDIF()
|
||||
IF(${HAVE_VOLK_SUB_FLOAT_FUNCTION})
|
||||
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_SUB_FLOAT_FUNCTION")
|
||||
ENDIF()
|
||||
|
|
|
@ -1,57 +0,0 @@
|
|||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2014 The libLTE Developers. See the
|
||||
* COPYRIGHT file at the top-level directory of this distribution.
|
||||
*
|
||||
* \section LICENSE
|
||||
*
|
||||
* This file is part of the libLTE library.
|
||||
*
|
||||
* libLTE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* libLTE 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 Lesser General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Lesser 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 CHEQ_DL_
|
||||
#define CHEQ_DL_
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "liblte/config.h"
|
||||
#include "liblte/phy/common/phy_common.h"
|
||||
|
||||
typedef _Complex float cf_t;
|
||||
|
||||
/** Generic OFDM channel equalizer
|
||||
*/
|
||||
|
||||
|
||||
LIBLTE_API int cheq_zf(cf_t *input,
|
||||
cf_t *ce,
|
||||
cf_t *output,
|
||||
uint32_t len);
|
||||
|
||||
LIBLTE_API int cheq_mmse(cf_t *input,
|
||||
cf_t *ce,
|
||||
cf_t *output,
|
||||
uint32_t len,
|
||||
float noise_estimate);
|
||||
|
||||
|
||||
|
||||
#endif
|
|
@ -37,20 +37,70 @@ typedef _Complex float cf_t;
|
|||
* resources on each of the antenna ports.
|
||||
*/
|
||||
|
||||
|
||||
typedef struct {
|
||||
cf_t *h_mod;
|
||||
float *y_mod;
|
||||
float *z_real;
|
||||
float *z_imag;
|
||||
uint32_t max_frame_len;
|
||||
}precoding_t;
|
||||
|
||||
|
||||
LIBLTE_API int precoding_init(precoding_t *q,
|
||||
uint32_t max_frame_len);
|
||||
|
||||
LIBLTE_API void precoding_free(precoding_t *q);
|
||||
|
||||
/* Generates the vector "y" from the input vector "x"
|
||||
*/
|
||||
LIBLTE_API int precoding_single(cf_t *x, cf_t *y, int nof_symbols);
|
||||
LIBLTE_API int precoding_diversity(cf_t *x[MAX_LAYERS], cf_t *y[MAX_PORTS], int nof_ports,
|
||||
int nof_symbols);
|
||||
LIBLTE_API int precoding_type(cf_t *x[MAX_LAYERS], cf_t *y[MAX_PORTS], int nof_layers,
|
||||
int nof_ports, int nof_symbols, lte_mimo_type_t type);
|
||||
LIBLTE_API int precoding_single(precoding_t *q,
|
||||
cf_t *x,
|
||||
cf_t *y,
|
||||
int nof_symbols);
|
||||
|
||||
/* Estimates the vector "x" based on the received signal "y" and the channel estimates "ce"
|
||||
LIBLTE_API int precoding_diversity(precoding_t *q,
|
||||
cf_t *x[MAX_LAYERS],
|
||||
cf_t *y[MAX_PORTS],
|
||||
int nof_ports, int nof_symbols);
|
||||
|
||||
LIBLTE_API int precoding_type(precoding_t *q,
|
||||
cf_t *x[MAX_LAYERS],
|
||||
cf_t *y[MAX_PORTS],
|
||||
int nof_layers,
|
||||
int nof_ports,
|
||||
int nof_symbols,
|
||||
lte_mimo_type_t type);
|
||||
|
||||
/* Estimates the vector "x" based on the received signal "y" and the channel estimates "h"
|
||||
*/
|
||||
LIBLTE_API int predecoding_single_zf(cf_t *y, cf_t *ce, cf_t *x, int nof_symbols);
|
||||
LIBLTE_API int predecoding_diversity_zf(cf_t *y, cf_t *ce[MAX_PORTS], cf_t *x[MAX_LAYERS],
|
||||
int nof_ports, int nof_symbols);
|
||||
LIBLTE_API int predecoding_type(cf_t *y, cf_t *ce[MAX_PORTS], cf_t *x[MAX_LAYERS],
|
||||
int nof_ports, int nof_layers, int nof_symbols, lte_mimo_type_t type);
|
||||
LIBLTE_API int predecoding_single_zf(precoding_t *q,
|
||||
cf_t *y,
|
||||
cf_t *h,
|
||||
cf_t *x,
|
||||
int nof_symbols);
|
||||
|
||||
LIBLTE_API int predecoding_single_mmse(precoding_t *q,
|
||||
cf_t *y,
|
||||
cf_t *h,
|
||||
cf_t *x,
|
||||
int nof_symbols,
|
||||
float noise_estimate);
|
||||
|
||||
LIBLTE_API int predecoding_diversity_zf(precoding_t *q,
|
||||
cf_t *y,
|
||||
cf_t *h[MAX_PORTS],
|
||||
cf_t *x[MAX_LAYERS],
|
||||
int nof_ports,
|
||||
int nof_symbols);
|
||||
|
||||
LIBLTE_API int predecoding_type(precoding_t *q,
|
||||
cf_t *y,
|
||||
cf_t *h[MAX_PORTS],
|
||||
cf_t *x[MAX_LAYERS],
|
||||
int nof_ports,
|
||||
int nof_layers,
|
||||
int nof_symbols,
|
||||
lte_mimo_type_t type);
|
||||
|
||||
#endif /* PRECODING_H_ */
|
||||
|
|
|
@ -77,7 +77,8 @@ typedef struct LIBLTE_API {
|
|||
viterbi_t decoder;
|
||||
crc_t crc;
|
||||
convcoder_t encoder;
|
||||
|
||||
precoding_t precoding;
|
||||
|
||||
} pbch_t;
|
||||
|
||||
LIBLTE_API int pbch_init(pbch_t *q,
|
||||
|
@ -87,6 +88,7 @@ LIBLTE_API void pbch_free(pbch_t *q);
|
|||
LIBLTE_API int pbch_decode(pbch_t *q,
|
||||
cf_t *slot1_symbols,
|
||||
cf_t *ce_slot1[MAX_PORTS],
|
||||
float noise_estimate,
|
||||
uint8_t bch_payload[BCH_PAYLOAD_LEN],
|
||||
uint32_t *nof_tx_ports,
|
||||
uint32_t *sfn_offset);
|
||||
|
|
|
@ -64,6 +64,7 @@ typedef struct LIBLTE_API {
|
|||
modem_table_t mod;
|
||||
demod_hard_t demod;
|
||||
sequence_t seq_pcfich[NSUBFRAMES_X_FRAME];
|
||||
precoding_t precoding;
|
||||
|
||||
} pcfich_t;
|
||||
|
||||
|
@ -76,6 +77,7 @@ LIBLTE_API void pcfich_free(pcfich_t *q);
|
|||
LIBLTE_API int pcfich_decode(pcfich_t *q,
|
||||
cf_t *sf_symbols,
|
||||
cf_t *ce[MAX_PORTS],
|
||||
float noise_estimate,
|
||||
uint32_t subframe,
|
||||
uint32_t *cfi,
|
||||
uint32_t *distance);
|
||||
|
|
|
@ -74,6 +74,8 @@ typedef struct LIBLTE_API {
|
|||
sequence_t seq_pdcch[NSUBFRAMES_X_FRAME];
|
||||
viterbi_t decoder;
|
||||
crc_t crc;
|
||||
precoding_t precoding;
|
||||
|
||||
} pdcch_t;
|
||||
|
||||
LIBLTE_API int pdcch_init(pdcch_t *q,
|
||||
|
@ -96,6 +98,7 @@ LIBLTE_API int pdcch_encode(pdcch_t *q,
|
|||
LIBLTE_API int pdcch_extract_llr(pdcch_t *q,
|
||||
cf_t *sf_symbols,
|
||||
cf_t *ce[MAX_PORTS],
|
||||
float noise_estimate,
|
||||
dci_location_t location,
|
||||
uint32_t nsubframe,
|
||||
uint32_t cfi);
|
||||
|
|
|
@ -97,6 +97,8 @@ typedef struct LIBLTE_API {
|
|||
tdec_t decoder;
|
||||
crc_t crc_tb;
|
||||
crc_t crc_cb;
|
||||
precoding_t precoding;
|
||||
|
||||
}pdsch_t;
|
||||
|
||||
LIBLTE_API int pdsch_init(pdsch_t *q,
|
||||
|
@ -126,6 +128,7 @@ LIBLTE_API int pdsch_encode(pdsch_t *q,
|
|||
LIBLTE_API int pdsch_decode(pdsch_t *q,
|
||||
cf_t *sf_symbols,
|
||||
cf_t *ce[MAX_PORTS],
|
||||
float noise_estimate,
|
||||
uint8_t *data,
|
||||
uint32_t nsubframe,
|
||||
pdsch_harq_t *harq_process,
|
||||
|
|
|
@ -75,6 +75,7 @@ typedef struct LIBLTE_API {
|
|||
modem_table_t mod;
|
||||
demod_hard_t demod;
|
||||
sequence_t seq_phich[NSUBFRAMES_X_FRAME];
|
||||
precoding_t precoding;
|
||||
|
||||
}phich_t;
|
||||
|
||||
|
@ -87,6 +88,7 @@ LIBLTE_API void phich_free(phich_t *q);
|
|||
LIBLTE_API int phich_decode(phich_t *q,
|
||||
cf_t *slot_symbols,
|
||||
cf_t *ce[MAX_PORTS],
|
||||
float noise_estimate,
|
||||
uint32_t ngroup,
|
||||
uint32_t nseq,
|
||||
uint32_t nsubframe,
|
||||
|
|
|
@ -73,6 +73,11 @@ LIBLTE_API void vec_sub_ccc(cf_t *x, cf_t *y, cf_t *z, uint32_t len);
|
|||
/* Square distance */
|
||||
LIBLTE_API void vec_square_dist(cf_t symbol, cf_t *points, float *distance, uint32_t npoints);
|
||||
|
||||
/* scalar addition */
|
||||
LIBLTE_API void vec_sc_add_fff(float *x, float h, float *z, uint32_t len);
|
||||
LIBLTE_API void vec_sc_add_cfc(cf_t *x, float h, cf_t *z, uint32_t len);
|
||||
LIBLTE_API void vec_sc_add_ccc(cf_t *x, cf_t h, cf_t *z, uint32_t len);
|
||||
|
||||
/* scalar product */
|
||||
LIBLTE_API void vec_sc_prod_cfc(cf_t *x, float h, cf_t *z, uint32_t len);
|
||||
LIBLTE_API void vec_sc_prod_ccc(cf_t *x, cf_t h, cf_t *z, uint32_t len);
|
||||
|
@ -83,6 +88,8 @@ LIBLTE_API void vec_convert_fi(float *x, int16_t *z, float scale, uint32_t len);
|
|||
LIBLTE_API void vec_deinterleave_cf(cf_t *x, float *real, float *imag, uint32_t len);
|
||||
LIBLTE_API void vec_deinterleave_real_cf(cf_t *x, float *real, uint32_t len);
|
||||
|
||||
LIBLTE_API void vec_interleave_cf(float *real, float *imag, cf_t *x, uint32_t len);
|
||||
|
||||
/* vector product (element-wise) */
|
||||
LIBLTE_API void vec_prod_ccc(cf_t *x, cf_t *y, cf_t *z, uint32_t len);
|
||||
|
||||
|
@ -99,7 +106,8 @@ LIBLTE_API cf_t vec_dot_prod_conj_ccc(cf_t *x, cf_t *y, uint32_t len);
|
|||
LIBLTE_API float vec_dot_prod_fff(float *x, float *y, uint32_t len);
|
||||
|
||||
/* z=x/y vector division (element-wise) */
|
||||
LIBLTE_API void vec_div_ccc(cf_t *x, cf_t *y, float *y_mod, cf_t *z, uint32_t len);
|
||||
LIBLTE_API void vec_div_ccc(cf_t *x, cf_t *y, float *y_mod, cf_t *z, float *z_real, float *z_imag, uint32_t len);
|
||||
LIBLTE_API void vec_div_fff(float *x, float *y, float *z, uint32_t len);
|
||||
|
||||
/* conjugate */
|
||||
LIBLTE_API void vec_conj_cc(cf_t *x, cf_t *y, uint32_t len);
|
||||
|
|
|
@ -1,53 +0,0 @@
|
|||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2014 The libLTE Developers. See the
|
||||
* COPYRIGHT file at the top-level directory of this distribution.
|
||||
*
|
||||
* \section LICENSE
|
||||
*
|
||||
* This file is part of the libLTE library.
|
||||
*
|
||||
* libLTE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* libLTE 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 Lesser General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Lesser 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 "liblte/config.h"
|
||||
|
||||
#include "liblte/phy/ch_estimation/cheq.h"
|
||||
#include "liblte/phy/utils/vector.h"
|
||||
|
||||
|
||||
int cheq_zf(cf_t *input, cf_t *ce, cf_t *output, uint32_t len)
|
||||
{
|
||||
fprintf(stderr, "Not implemented\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int cheq_mmse(cf_t *input, cf_t *ce, cf_t *output, uint32_t len, float noise_estimate)
|
||||
{
|
||||
fprintf(stderr, "Not implemented\n");
|
||||
return -1;
|
||||
}
|
|
@ -82,17 +82,17 @@ int chest_dl_init(chest_dl_t *q, lte_cell_t cell)
|
|||
}
|
||||
|
||||
for (int i=0;i<cell.nof_ports;i++) {
|
||||
q->pilot_estimates[i] = vec_malloc(sizeof(cf_t) * REFSIGNAL_MAX_NUM_SF(cell.nof_prb));
|
||||
q->pilot_estimates[i] = vec_malloc(sizeof(cf_t) * REFSIGNAL_NUM_SF(cell.nof_prb, i));
|
||||
if (!q->pilot_estimates[i]) {
|
||||
perror("malloc");
|
||||
goto clean_exit;
|
||||
}
|
||||
q->pilot_estimates_average[i] = vec_malloc(sizeof(cf_t) * REFSIGNAL_MAX_NUM_SF(cell.nof_prb));
|
||||
q->pilot_estimates_average[i] = vec_malloc(sizeof(cf_t) * REFSIGNAL_NUM_SF(cell.nof_prb, i));
|
||||
if (!q->pilot_estimates_average[i]) {
|
||||
perror("malloc");
|
||||
goto clean_exit;
|
||||
}
|
||||
q->pilot_recv_signal[i] = vec_malloc(sizeof(cf_t) * REFSIGNAL_MAX_NUM_SF(cell.nof_prb));
|
||||
q->pilot_recv_signal[i] = vec_malloc(sizeof(cf_t) * REFSIGNAL_NUM_SF(cell.nof_prb, i));
|
||||
if (!q->pilot_recv_signal[i]) {
|
||||
perror("malloc");
|
||||
goto clean_exit;
|
||||
|
@ -135,7 +135,11 @@ void chest_dl_free(chest_dl_t *q)
|
|||
if (q->tmp_freqavg) {
|
||||
free(q->tmp_freqavg);
|
||||
}
|
||||
|
||||
for (int i=0;i<CHEST_MAX_FILTER_TIME_LEN;i++) {
|
||||
if (q->tmp_timeavg[i]) {
|
||||
free(q->tmp_timeavg[i]);
|
||||
}
|
||||
}
|
||||
interp_linear_vector_free(&q->interp_linvec);
|
||||
interp_linear_free(&q->interp_lin);
|
||||
|
||||
|
@ -143,10 +147,14 @@ void chest_dl_free(chest_dl_t *q)
|
|||
if (q->pilot_estimates[i]) {
|
||||
free(q->pilot_estimates[i]);
|
||||
}
|
||||
if (q->pilot_estimates_average[i]) {
|
||||
free(q->pilot_estimates_average[i]);
|
||||
}
|
||||
if (q->pilot_recv_signal[i]) {
|
||||
free(q->pilot_recv_signal[i]);
|
||||
}
|
||||
}
|
||||
bzero(q, sizeof(chest_dl_t));
|
||||
}
|
||||
|
||||
int chest_dl_set_filter_freq(chest_dl_t *q, float *filter, uint32_t filter_len) {
|
||||
|
@ -219,9 +227,10 @@ static void average_pilots(chest_dl_t *q, uint32_t port_id)
|
|||
|
||||
static float estimate_noise_port(chest_dl_t *q, uint32_t port_id) {
|
||||
/* Use difference between averaged and noisy LS pilot estimates */
|
||||
vec_sub_fff((float*) q->pilot_estimates_average[port_id], (float*) q->pilot_estimates[port_id],
|
||||
(float*) q->pilot_estimates[port_id], 2*REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id));
|
||||
vec_sub_ccc(q->pilot_estimates_average[port_id], q->pilot_estimates[port_id],
|
||||
q->pilot_estimates[port_id], REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id));
|
||||
/* compute noise power */
|
||||
|
||||
float noiseEst = vec_dot_prod_conj_ccc(q->pilot_estimates[port_id],
|
||||
q->pilot_estimates[port_id],
|
||||
REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id));
|
||||
|
|
|
@ -30,6 +30,10 @@ ADD_TEST(chest_test_dl_cellid0 chest_test_dl -c 0)
|
|||
ADD_TEST(chest_test_dl_cellid1 chest_test_dl -c 1)
|
||||
ADD_TEST(chest_test_dl_cellid2 chest_test_dl -c 2)
|
||||
|
||||
ADD_TEST(chest_test_dl_cellid0 chest_test_dl -c 0 -r 50)
|
||||
ADD_TEST(chest_test_dl_cellid1 chest_test_dl -c 1 -r 50)
|
||||
ADD_TEST(chest_test_dl_cellid2 chest_test_dl -c 2 -r 50)
|
||||
|
||||
########################################################################
|
||||
# Downlink MEX libs
|
||||
########################################################################
|
||||
|
|
|
@ -80,48 +80,15 @@ void parse_args(int argc, char **argv) {
|
|||
}
|
||||
}
|
||||
|
||||
int check_mse(float mod, float arg, int n_port) {
|
||||
INFO("mod=%.4f, arg=%.4f, n_port=%d\n", mod, arg, n_port);
|
||||
switch(n_port) {
|
||||
case 0:
|
||||
if (mod > 0.029) {
|
||||
return -1;
|
||||
}
|
||||
if (arg > 0.029) {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if (mod > 0.012) {
|
||||
return -1;
|
||||
}
|
||||
if (arg > 0.012) {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
if (mod > 3.33) {
|
||||
return -1;
|
||||
}
|
||||
if (arg > 0.63) {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
chest_dl_t eq;
|
||||
cf_t *input = NULL, *ce = NULL, *h = NULL;
|
||||
chest_dl_t est;
|
||||
precoding_t cheq;
|
||||
cf_t *input = NULL, *ce = NULL, *h = NULL, *output = NULL;
|
||||
int i, j, n_port, sf_idx, cid, num_re;
|
||||
int ret = -1;
|
||||
int max_cid;
|
||||
FILE *fmatlab = NULL;
|
||||
float mse_mag, mse_phase;
|
||||
|
||||
parse_args(argc,argv);
|
||||
|
||||
|
@ -140,6 +107,11 @@ int main(int argc, char **argv) {
|
|||
perror("malloc");
|
||||
goto do_exit;
|
||||
}
|
||||
output = malloc(num_re * sizeof(cf_t));
|
||||
if (!output) {
|
||||
perror("malloc");
|
||||
goto do_exit;
|
||||
}
|
||||
h = malloc(num_re * sizeof(cf_t));
|
||||
if (!h) {
|
||||
perror("malloc");
|
||||
|
@ -158,15 +130,17 @@ int main(int argc, char **argv) {
|
|||
cid = cell.id;
|
||||
max_cid = cell.id;
|
||||
}
|
||||
|
||||
precoding_init(&cheq, num_re);
|
||||
|
||||
while(cid <= max_cid) {
|
||||
cell.id = cid;
|
||||
if (chest_dl_init(&eq, cell)) {
|
||||
if (chest_dl_init(&est, cell)) {
|
||||
fprintf(stderr, "Error initializing equalizer\n");
|
||||
goto do_exit;
|
||||
}
|
||||
|
||||
for (sf_idx=0;sf_idx<NSUBFRAMES_X_FRAME;sf_idx++) {
|
||||
for (sf_idx=0;sf_idx<1;sf_idx++) {
|
||||
for (n_port=0;n_port<cell.nof_ports;n_port++) {
|
||||
|
||||
bzero(input, sizeof(cf_t) * num_re);
|
||||
|
@ -177,7 +151,8 @@ int main(int argc, char **argv) {
|
|||
bzero(ce, sizeof(cf_t) * num_re);
|
||||
bzero(h, sizeof(cf_t) * num_re);
|
||||
|
||||
refsignal_cs_put_sf(cell, n_port, eq.csr_signal.pilots[n_port/2][sf_idx], input);
|
||||
refsignal_cs_put_sf(cell, n_port,
|
||||
est.csr_signal.pilots[n_port/2][sf_idx], input);
|
||||
|
||||
for (i=0;i<2*CP_NSYMB(cell.cp);i++) {
|
||||
for (j=0;j<cell.nof_prb * RE_X_RB;j++) {
|
||||
|
@ -189,24 +164,47 @@ int main(int argc, char **argv) {
|
|||
|
||||
struct timeval t[3];
|
||||
gettimeofday(&t[1], NULL);
|
||||
for (int j=0;j<1000;j++) {
|
||||
chest_dl_estimate_port(&eq, input, ce, sf_idx, n_port);
|
||||
for (int j=0;j<100;j++) {
|
||||
chest_dl_estimate_port(&est, input, ce, sf_idx, n_port);
|
||||
}
|
||||
gettimeofday(&t[2], NULL);
|
||||
get_time_interval(t);
|
||||
printf("%f us\n", (float) t[0].tv_usec/1000);
|
||||
printf("CHEST: %f us\n", (float) t[0].tv_usec/100);
|
||||
|
||||
mse_mag = mse_phase = 0;
|
||||
for (i=0;i<num_re;i++) {
|
||||
mse_mag += (cabsf(h[i]) - cabsf(ce[i])) * (cabsf(h[i]) - cabsf(ce[i])) / num_re;
|
||||
mse_phase += (cargf(h[i]) - cargf(ce[i])) * (cargf(h[i]) - cargf(ce[i])) / num_re;
|
||||
gettimeofday(&t[1], NULL);
|
||||
for (int j=0;j<100;j++) {
|
||||
predecoding_single_zf(&cheq, input, ce, output, num_re);
|
||||
}
|
||||
gettimeofday(&t[2], NULL);
|
||||
get_time_interval(t);
|
||||
printf("CHEQ-ZF: %f us\n", (float) t[0].tv_usec/100);
|
||||
|
||||
/*if (check_mse(mse_mag, mse_phase, n_port)) {
|
||||
chest_dl_free(&eq);
|
||||
float mse = 0;
|
||||
for (i=0;i<num_re;i++) {
|
||||
mse += cabsf(input[i]-output[i]);
|
||||
}
|
||||
mse /= num_re;
|
||||
printf("MSE: %f\n", mse);
|
||||
|
||||
gettimeofday(&t[1], NULL);
|
||||
for (int j=0;j<100;j++) {
|
||||
predecoding_single_mmse(&cheq, input, ce, output, num_re, chest_dl_get_noise_estimate(&est));
|
||||
}
|
||||
gettimeofday(&t[2], NULL);
|
||||
get_time_interval(t);
|
||||
printf("CHEQ-MMSE: %f us\n", (float) t[0].tv_usec/100);
|
||||
|
||||
mse = 0;
|
||||
for (i=0;i<num_re;i++) {
|
||||
mse += cabsf(input[i]-output[i]);
|
||||
}
|
||||
mse /= num_re;
|
||||
printf("MSE: %f\n", mse);
|
||||
|
||||
if (mse > 1.7) {
|
||||
goto do_exit;
|
||||
}*/
|
||||
|
||||
}
|
||||
|
||||
if (fmatlab) {
|
||||
fprintf(fmatlab, "input=");
|
||||
vec_fprint_c(fmatlab, input, num_re);
|
||||
|
@ -220,7 +218,7 @@ int main(int argc, char **argv) {
|
|||
}
|
||||
}
|
||||
}
|
||||
chest_dl_free(&eq);
|
||||
chest_dl_free(&est);
|
||||
cid+=10;
|
||||
INFO("cid=%d\n", cid);
|
||||
}
|
||||
|
@ -230,6 +228,11 @@ int main(int argc, char **argv) {
|
|||
|
||||
do_exit:
|
||||
|
||||
precoding_free(&cheq);
|
||||
|
||||
if (output) {
|
||||
free(output);
|
||||
}
|
||||
if (ce) {
|
||||
free(ce);
|
||||
}
|
||||
|
|
|
@ -25,15 +25,6 @@
|
|||
|
||||
|
||||
/** MEX function to be called from MATLAB to test the channel estimator
|
||||
*
|
||||
* [estChannel] = liblte_chest(cell_id, nof_ports, inputSignal, (optional) sf_idx)
|
||||
*
|
||||
* Returns a matrix of size equal to the inputSignal matrix with the channel estimates
|
||||
* for each resource element in inputSignal. The inputSignal matrix is the received Grid
|
||||
* of size nof_resource_elements x nof_ofdm_symbols_in_subframe.
|
||||
*
|
||||
* The sf_idx is the subframe index only used if inputSignal is 1 subframe length.
|
||||
*
|
||||
*/
|
||||
|
||||
#define CELLID prhs[0]
|
||||
|
@ -47,11 +38,14 @@
|
|||
void help()
|
||||
{
|
||||
mexErrMsgTxt
|
||||
("[estChannel] = liblte_chest(cell_id, nof_ports, inputSignal,[sf_idx|freq_filter], [time_filter])\n\n"
|
||||
("[estChannel, avg_refs, output] = liblte_chest(cell_id, nof_ports, inputSignal,[sf_idx|freq_filter],"
|
||||
"[time_filter])\n\n"
|
||||
" Returns a matrix of size equal to the inputSignal matrix with the channel estimates\n "
|
||||
"for each resource element in inputSignal. The inputSignal matrix is the received Grid\n"
|
||||
"of size nof_resource_elements x nof_ofdm_symbols.\n"
|
||||
"The sf_idx is the subframe index only used if inputSignal is 1 subframe length.\n");
|
||||
"The sf_idx is the subframe index only used if inputSignal is 1 subframe length.\n"
|
||||
"Returns the averaged references and output signal after ZF/MMSE equalization\n"
|
||||
);
|
||||
}
|
||||
|
||||
/* the gateway function */
|
||||
|
@ -61,10 +55,12 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
|
|||
int i;
|
||||
lte_cell_t cell;
|
||||
chest_dl_t chest;
|
||||
cf_t *input_signal;
|
||||
precoding_t cheq;
|
||||
cf_t *input_signal = NULL, *output_signal = NULL;
|
||||
cf_t *ce[MAX_PORTS];
|
||||
double *outr0, *outi0, *outr1, *outi1;
|
||||
float noiseAverage[10];
|
||||
double *outr0=NULL, *outi0=NULL;
|
||||
double *outr1=NULL, *outi1=NULL;
|
||||
double *outr2=NULL, *outi2=NULL;
|
||||
|
||||
if (nrhs < NOF_INPUTS) {
|
||||
help();
|
||||
|
@ -147,7 +143,11 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
|
|||
ce[i] = vec_malloc(nof_re * sizeof(cf_t));
|
||||
}
|
||||
input_signal = vec_malloc(nof_re * sizeof(cf_t));
|
||||
output_signal = vec_malloc(nof_re * sizeof(cf_t));
|
||||
|
||||
|
||||
precoding_init(&cheq, nof_re);
|
||||
|
||||
/* Create output values */
|
||||
if (nlhs >= 1) {
|
||||
plhs[0] = mxCreateDoubleMatrix(1,nof_re * nsubframes, mxCOMPLEX);
|
||||
|
@ -159,6 +159,11 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
|
|||
outr1 = mxGetPr(plhs[1]);
|
||||
outi1 = mxGetPi(plhs[1]);
|
||||
}
|
||||
if (nlhs >= 3) {
|
||||
plhs[2] = mxCreateDoubleMatrix(1,nof_re * nsubframes, mxCOMPLEX);
|
||||
outr2 = mxGetPr(plhs[2]);
|
||||
outi2 = mxGetPi(plhs[2]);
|
||||
}
|
||||
|
||||
for (int sf=0;sf<nsubframes;sf++) {
|
||||
/* Convert input to C complex type */
|
||||
|
@ -176,12 +181,12 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
|
|||
}
|
||||
|
||||
/* Loop through the 10 subframes */
|
||||
if (chest_dl_estimate(&chest, input_signal, ce, sf_idx)) {
|
||||
if (chest_dl_estimate(&chest, input_signal, ce, sf_idx)) {
|
||||
mexErrMsgTxt("Error running channel estimator\n");
|
||||
return;
|
||||
}
|
||||
|
||||
noiseAverage[sf]=chest_dl_get_noise_estimate(&chest);
|
||||
}
|
||||
//predecoding_single_zf(&cheq, input_signal, ce[0], output_signal, nof_re);
|
||||
predecoding_single_mmse(&cheq, input_signal, ce[0], output_signal, nof_re, chest_dl_get_noise_estimate(&chest));
|
||||
|
||||
if (nlhs >= 1) {
|
||||
for (i=0;i<nof_re;i++) {
|
||||
|
@ -205,15 +210,18 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
|
|||
}
|
||||
}
|
||||
}
|
||||
if (nlhs >= 3) {
|
||||
for (i=0;i<nof_re;i++) {
|
||||
*outr2 = (double) crealf(output_signal[i]);
|
||||
if (outi2) {
|
||||
*outi2 = (double) cimagf(output_signal[i]);
|
||||
}
|
||||
outr2++;
|
||||
outi2++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (nlhs >= 3) {
|
||||
plhs[2] = mxCreateDoubleMatrix(1, 1, mxREAL);
|
||||
outr1 = mxGetPr(plhs[2]);
|
||||
*outr1 = vec_acc_ff(noiseAverage,10)/10;
|
||||
}
|
||||
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -190,6 +190,7 @@ void viterbi_free(viterbi_t *q) {
|
|||
if (q->free) {
|
||||
q->free(q);
|
||||
}
|
||||
bzero(q, sizeof(viterbi_t));
|
||||
}
|
||||
|
||||
/* symbols are real-valued */
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <complex.h>
|
||||
#include <string.h>
|
||||
|
@ -35,11 +35,207 @@
|
|||
#include "liblte/phy/mimo/precoding.h"
|
||||
#include "liblte/phy/utils/vector.h"
|
||||
|
||||
int precoding_single(cf_t *x, cf_t *y, int nof_symbols) {
|
||||
|
||||
/************************************************
|
||||
*
|
||||
* RECEIVER SIDE FUNCTIONS
|
||||
*
|
||||
**************************************************/
|
||||
|
||||
int precoding_init(precoding_t *q, uint32_t max_frame_len) {
|
||||
if (q) {
|
||||
bzero(q, sizeof(precoding_t));
|
||||
|
||||
q->h_mod = vec_malloc(sizeof(cf_t) * max_frame_len);
|
||||
if (!q->h_mod) {
|
||||
perror("malloc");
|
||||
goto clean_exit;
|
||||
}
|
||||
q->y_mod = vec_malloc(sizeof(float) * max_frame_len);
|
||||
if (!q->y_mod) {
|
||||
perror("malloc");
|
||||
goto clean_exit;
|
||||
}
|
||||
q->z_real = vec_malloc(sizeof(float) * max_frame_len);
|
||||
if (!q->z_real) {
|
||||
perror("malloc");
|
||||
goto clean_exit;
|
||||
}
|
||||
q->z_imag = vec_malloc(sizeof(float) * max_frame_len);
|
||||
if (!q->z_imag) {
|
||||
perror("malloc");
|
||||
goto clean_exit;
|
||||
}
|
||||
q->max_frame_len = max_frame_len;
|
||||
return LIBLTE_SUCCESS;
|
||||
} else {
|
||||
return LIBLTE_ERROR_INVALID_INPUTS;
|
||||
}
|
||||
clean_exit:
|
||||
precoding_free(q);
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
|
||||
void precoding_free(precoding_t *q) {
|
||||
if (q->h_mod) {
|
||||
free(q->h_mod);
|
||||
}
|
||||
if (q->y_mod) {
|
||||
free(q->y_mod);
|
||||
}
|
||||
if (q->z_real) {
|
||||
free(q->z_real);
|
||||
}
|
||||
if (q->z_imag) {
|
||||
free(q->z_imag);
|
||||
}
|
||||
bzero(q, sizeof(precoding_t));
|
||||
}
|
||||
|
||||
|
||||
/* ZF SISO equalizer: x=y/h */
|
||||
int predecoding_single_zf(precoding_t *q, cf_t *y, cf_t *h, cf_t *x, int nof_symbols) {
|
||||
if (nof_symbols <= q->max_frame_len) {
|
||||
vec_div_ccc(y, h, q->y_mod, x, q->z_real, q->z_imag, nof_symbols);
|
||||
return nof_symbols;
|
||||
} else {
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/* MMSE SISO equalizer x=y*h'/(h*h'+no) */
|
||||
int predecoding_single_mmse(precoding_t *q, cf_t *y, cf_t *h, cf_t *x, int nof_symbols, float noise_estimate) {
|
||||
if (nof_symbols <= q->max_frame_len) {
|
||||
// h*h'
|
||||
vec_prod_conj_ccc(h, h, q->h_mod, nof_symbols);
|
||||
// real(h*h')
|
||||
vec_deinterleave_real_cf(q->h_mod, q->y_mod, nof_symbols);
|
||||
// (h*h' + n0)
|
||||
vec_sc_add_fff(q->y_mod, noise_estimate, q->y_mod, nof_symbols);
|
||||
// y*h'
|
||||
vec_prod_conj_ccc(y, h, x, nof_symbols);
|
||||
// decompose real/imag parts
|
||||
vec_deinterleave_cf(x, q->z_real, q->z_imag, nof_symbols);
|
||||
// real and imag division
|
||||
vec_div_fff(q->z_real, q->y_mod, q->z_real, nof_symbols);
|
||||
vec_div_fff(q->z_imag, q->y_mod, q->z_imag, nof_symbols);
|
||||
// interleave again
|
||||
vec_interleave_cf(q->z_real, q->z_imag, x, nof_symbols);
|
||||
return nof_symbols;
|
||||
} else {
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/* ZF STBC equalizer */
|
||||
int predecoding_diversity_zf(precoding_t *q, cf_t *y, cf_t *h[MAX_PORTS], cf_t *x[MAX_LAYERS],
|
||||
int nof_ports, int nof_symbols) {
|
||||
int i;
|
||||
cf_t h0, h1, h2, h3, r0, r1, r2, r3;
|
||||
float hh, hh02, hh13;
|
||||
if (nof_ports == 2) {
|
||||
/* TODO: Use VOLK here */
|
||||
for (i = 0; i < nof_symbols / 2; i++) {
|
||||
h0 = h[0][2 * i];
|
||||
h1 = h[1][2 * i];
|
||||
hh = crealf(h0) * crealf(h0) + cimagf(h0) * cimagf(h0)
|
||||
+ crealf(h1) * crealf(h1) + cimagf(h1) * cimagf(h1);
|
||||
r0 = y[2 * i];
|
||||
r1 = y[2 * i + 1];
|
||||
if (hh == 0) {
|
||||
hh = 1e-2;
|
||||
}
|
||||
x[0][i] = (conjf(h0) * r0 + h1 * conjf(r1)) / hh * sqrt(2);
|
||||
x[1][i] = (-h1 * conj(r0) + conj(h0) * r1) / hh * sqrt(2);
|
||||
}
|
||||
return i;
|
||||
} else if (nof_ports == 4) {
|
||||
|
||||
int m_ap = (nof_symbols % 4) ? ((nof_symbols - 2) / 4) : nof_symbols / 4;
|
||||
for (i = 0; i < m_ap; i++) {
|
||||
h0 = h[0][4 * i];
|
||||
h1 = h[1][4 * i + 2];
|
||||
h2 = h[2][4 * i];
|
||||
h3 = h[3][4 * i + 2];
|
||||
hh02 = crealf(h0) * crealf(h0) + cimagf(h0) * cimagf(h0)
|
||||
+ crealf(h2) * crealf(h2) + cimagf(h2) * cimagf(h2);
|
||||
hh13 = crealf(h1) * crealf(h1) + cimagf(h1) * cimagf(h1)
|
||||
+ crealf(h3) * crealf(h3) + cimagf(h3) * cimagf(h3);
|
||||
r0 = y[4 * i];
|
||||
r1 = y[4 * i + 1];
|
||||
r2 = y[4 * i + 2];
|
||||
r3 = y[4 * i + 3];
|
||||
|
||||
x[0][i] = (conjf(h0) * r0 + h2 * conjf(r1)) / hh02 * sqrt(2);
|
||||
x[1][i] = (-h2 * conjf(r0) + conjf(h0) * r1) / hh02 * sqrt(2);
|
||||
x[2][i] = (conjf(h1) * r2 + h3 * conjf(r3)) / hh13 * sqrt(2);
|
||||
x[3][i] = (-h3 * conjf(r2) + conjf(h1) * r3) / hh13 * sqrt(2);
|
||||
|
||||
}
|
||||
return i;
|
||||
} else {
|
||||
fprintf(stderr, "Number of ports must be 2 or 4 for transmit diversity (nof_ports=%d)\n", nof_ports);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* 36.211 v10.3.0 Section 6.3.4 */
|
||||
int predecoding_type(precoding_t *q, cf_t *y, cf_t *h[MAX_PORTS], cf_t *x[MAX_LAYERS],
|
||||
int nof_ports, int nof_layers, int nof_symbols, lte_mimo_type_t type) {
|
||||
|
||||
if (nof_ports > MAX_PORTS) {
|
||||
fprintf(stderr, "Maximum number of ports is %d (nof_ports=%d)\n", MAX_PORTS,
|
||||
nof_ports);
|
||||
return -1;
|
||||
}
|
||||
if (nof_layers > MAX_LAYERS) {
|
||||
fprintf(stderr, "Maximum number of layers is %d (nof_layers=%d)\n",
|
||||
MAX_LAYERS, nof_layers);
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case SINGLE_ANTENNA:
|
||||
if (nof_ports == 1 && nof_layers == 1) {
|
||||
return predecoding_single_zf(q, y, h[0], x[0], nof_symbols);
|
||||
} else {
|
||||
fprintf(stderr,
|
||||
"Number of ports and layers must be 1 for transmission on single antenna ports\n");
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case TX_DIVERSITY:
|
||||
if (nof_ports == nof_layers) {
|
||||
return predecoding_diversity_zf(q, y, h, x, nof_ports, nof_symbols);
|
||||
} else {
|
||||
fprintf(stderr,
|
||||
"Error number of layers must equal number of ports in transmit diversity\n");
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case SPATIAL_MULTIPLEX:
|
||||
fprintf(stderr, "Spatial multiplexing not supported\n");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/************************************************
|
||||
*
|
||||
* TRANSMITTER SIDE FUNCTIONS
|
||||
*
|
||||
**************************************************/
|
||||
|
||||
int precoding_single(precoding_t *q, cf_t *x, cf_t *y, int nof_symbols) {
|
||||
memcpy(y, x, nof_symbols * sizeof(cf_t));
|
||||
return nof_symbols;
|
||||
}
|
||||
int precoding_diversity(cf_t *x[MAX_LAYERS], cf_t *y[MAX_PORTS], int nof_ports,
|
||||
int precoding_diversity(precoding_t *q, cf_t *x[MAX_LAYERS], cf_t *y[MAX_PORTS], int nof_ports,
|
||||
int nof_symbols) {
|
||||
int i;
|
||||
if (nof_ports == 2) {
|
||||
|
@ -83,7 +279,7 @@ int precoding_diversity(cf_t *x[MAX_LAYERS], cf_t *y[MAX_PORTS], int nof_ports,
|
|||
}
|
||||
|
||||
/* 36.211 v10.3.0 Section 6.3.4 */
|
||||
int precoding_type(cf_t *x[MAX_LAYERS], cf_t *y[MAX_PORTS], int nof_layers,
|
||||
int precoding_type(precoding_t *q, cf_t *x[MAX_LAYERS], cf_t *y[MAX_PORTS], int nof_layers,
|
||||
int nof_ports, int nof_symbols, lte_mimo_type_t type) {
|
||||
|
||||
if (nof_ports > MAX_PORTS) {
|
||||
|
@ -100,7 +296,7 @@ int precoding_type(cf_t *x[MAX_LAYERS], cf_t *y[MAX_PORTS], int nof_layers,
|
|||
switch (type) {
|
||||
case SINGLE_ANTENNA:
|
||||
if (nof_ports == 1 && nof_layers == 1) {
|
||||
return precoding_single(x[0], y[0], nof_symbols);
|
||||
return precoding_single(q, x[0], y[0], nof_symbols);
|
||||
} else {
|
||||
fprintf(stderr,
|
||||
"Number of ports and layers must be 1 for transmission on single antenna ports\n");
|
||||
|
@ -109,7 +305,7 @@ int precoding_type(cf_t *x[MAX_LAYERS], cf_t *y[MAX_PORTS], int nof_layers,
|
|||
break;
|
||||
case TX_DIVERSITY:
|
||||
if (nof_ports == nof_layers) {
|
||||
return precoding_diversity(x, y, nof_ports, nof_symbols);
|
||||
return precoding_diversity(q, x, y, nof_ports, nof_symbols);
|
||||
} else {
|
||||
fprintf(stderr,
|
||||
"Error number of layers must equal number of ports in transmit diversity\n");
|
||||
|
@ -122,110 +318,3 @@ int precoding_type(cf_t *x[MAX_LAYERS], cf_t *y[MAX_PORTS], int nof_layers,
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
float y_mod[110*12*14];
|
||||
|
||||
/* ZF detector */
|
||||
int predecoding_single_zf(cf_t *y, cf_t *ce, cf_t *x, int nof_symbols) {
|
||||
for (int i=0;i<nof_symbols;i++) {
|
||||
if (ce[i] == 0) {
|
||||
ce[i] = 0.01;
|
||||
}
|
||||
}
|
||||
vec_div_ccc(y, ce, y_mod, x, nof_symbols);
|
||||
return nof_symbols;
|
||||
}
|
||||
|
||||
/* ZF detector */
|
||||
int predecoding_diversity_zf(cf_t *y, cf_t *ce[MAX_PORTS], cf_t *x[MAX_LAYERS],
|
||||
int nof_ports, int nof_symbols) {
|
||||
int i;
|
||||
cf_t h0, h1, h2, h3, r0, r1, r2, r3;
|
||||
float hh, hh02, hh13;
|
||||
if (nof_ports == 2) {
|
||||
/* TODO: Use VOLK here */
|
||||
for (i = 0; i < nof_symbols / 2; i++) {
|
||||
h0 = ce[0][2 * i];
|
||||
h1 = ce[1][2 * i];
|
||||
hh = crealf(h0) * crealf(h0) + cimagf(h0) * cimagf(h0)
|
||||
+ crealf(h1) * crealf(h1) + cimagf(h1) * cimagf(h1);
|
||||
r0 = y[2 * i];
|
||||
r1 = y[2 * i + 1];
|
||||
if (hh == 0) {
|
||||
hh = 1e-2;
|
||||
}
|
||||
x[0][i] = (conjf(h0) * r0 + h1 * conjf(r1)) / hh * sqrt(2);
|
||||
x[1][i] = (-h1 * conj(r0) + conj(h0) * r1) / hh * sqrt(2);
|
||||
}
|
||||
return i;
|
||||
} else if (nof_ports == 4) {
|
||||
|
||||
int m_ap = (nof_symbols % 4) ? ((nof_symbols - 2) / 4) : nof_symbols / 4;
|
||||
for (i = 0; i < m_ap; i++) {
|
||||
h0 = ce[0][4 * i];
|
||||
h1 = ce[1][4 * i + 2];
|
||||
h2 = ce[2][4 * i];
|
||||
h3 = ce[3][4 * i + 2];
|
||||
hh02 = crealf(h0) * crealf(h0) + cimagf(h0) * cimagf(h0)
|
||||
+ crealf(h2) * crealf(h2) + cimagf(h2) * cimagf(h2);
|
||||
hh13 = crealf(h1) * crealf(h1) + cimagf(h1) * cimagf(h1)
|
||||
+ crealf(h3) * crealf(h3) + cimagf(h3) * cimagf(h3);
|
||||
r0 = y[4 * i];
|
||||
r1 = y[4 * i + 1];
|
||||
r2 = y[4 * i + 2];
|
||||
r3 = y[4 * i + 3];
|
||||
|
||||
x[0][i] = (conjf(h0) * r0 + h2 * conjf(r1)) / hh02 * sqrt(2);
|
||||
x[1][i] = (-h2 * conjf(r0) + conjf(h0) * r1) / hh02 * sqrt(2);
|
||||
x[2][i] = (conjf(h1) * r2 + h3 * conjf(r3)) / hh13 * sqrt(2);
|
||||
x[3][i] = (-h3 * conjf(r2) + conjf(h1) * r3) / hh13 * sqrt(2);
|
||||
|
||||
}
|
||||
return i;
|
||||
} else {
|
||||
fprintf(stderr, "Number of ports must be 2 or 4 for transmit diversity (nof_ports=%d)\n", nof_ports);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* 36.211 v10.3.0 Section 6.3.4 */
|
||||
int predecoding_type(cf_t *y, cf_t *ce[MAX_PORTS], cf_t *x[MAX_LAYERS],
|
||||
int nof_ports, int nof_layers, int nof_symbols, lte_mimo_type_t type) {
|
||||
|
||||
if (nof_ports > MAX_PORTS) {
|
||||
fprintf(stderr, "Maximum number of ports is %d (nof_ports=%d)\n", MAX_PORTS,
|
||||
nof_ports);
|
||||
return -1;
|
||||
}
|
||||
if (nof_layers > MAX_LAYERS) {
|
||||
fprintf(stderr, "Maximum number of layers is %d (nof_layers=%d)\n",
|
||||
MAX_LAYERS, nof_layers);
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case SINGLE_ANTENNA:
|
||||
if (nof_ports == 1 && nof_layers == 1) {
|
||||
return predecoding_single_zf(y, ce[0], x[0], nof_symbols);
|
||||
} else {
|
||||
fprintf(stderr,
|
||||
"Number of ports and layers must be 1 for transmission on single antenna ports\n");
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case TX_DIVERSITY:
|
||||
if (nof_ports == nof_layers) {
|
||||
return predecoding_diversity_zf(y, ce, x, nof_ports, nof_symbols);
|
||||
} else {
|
||||
fprintf(stderr,
|
||||
"Error number of layers must equal number of ports in transmit diversity\n");
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case SPATIAL_MULTIPLEX:
|
||||
fprintf(stderr, "Spatial multiplexing not supported\n");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -82,7 +82,8 @@ int main(int argc, char **argv) {
|
|||
cf_t *x[MAX_LAYERS], *r[MAX_PORTS], *y[MAX_PORTS], *h[MAX_PORTS],
|
||||
*xr[MAX_LAYERS];
|
||||
lte_mimo_type_t type;
|
||||
|
||||
precoding_t precoding;
|
||||
|
||||
parse_args(argc, argv);
|
||||
|
||||
if (nof_ports > MAX_PORTS || nof_layers > MAX_LAYERS) {
|
||||
|
@ -135,9 +136,14 @@ int main(int argc, char **argv) {
|
|||
* ((float) rand() / RAND_MAX + (float) I * rand() / RAND_MAX);
|
||||
}
|
||||
}
|
||||
|
||||
if (precoding_init(&precoding, nof_symbols)) {
|
||||
fprintf(stderr, "Error initializing precoding\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
/* precoding */
|
||||
if (precoding_type(x, y, nof_layers, nof_ports, nof_symbols, type) < 0) {
|
||||
if (precoding_type(&precoding, x, y, nof_layers, nof_ports, nof_symbols, type) < 0) {
|
||||
fprintf(stderr, "Error layer mapper encoder\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
@ -163,7 +169,7 @@ int main(int argc, char **argv) {
|
|||
}
|
||||
|
||||
/* predecoding / equalization */
|
||||
if (predecoding_type(r[0], h, xr, nof_ports, nof_layers,
|
||||
if (predecoding_type(&precoding, r[0], h, xr, nof_ports, nof_layers,
|
||||
nof_symbols * nof_layers, type) < 0) {
|
||||
fprintf(stderr, "Error layer mapper encoder\n");
|
||||
exit(-1);
|
||||
|
@ -187,6 +193,8 @@ int main(int argc, char **argv) {
|
|||
}
|
||||
|
||||
free(r[0]);
|
||||
|
||||
precoding_free(&precoding);
|
||||
|
||||
if (mse > MSE_THRESHOLD) {
|
||||
printf("MSE: %f\n", mse);
|
||||
|
|
|
@ -133,6 +133,10 @@ int pbch_init(pbch_t *q, lte_cell_t cell) {
|
|||
|
||||
bzero(q, sizeof(pbch_t));
|
||||
q->cell = cell;
|
||||
|
||||
if (precoding_init(&q->precoding, SF_LEN_RE(cell.nof_prb, cell.cp))) {
|
||||
fprintf(stderr, "Error initializing precoding\n");
|
||||
}
|
||||
|
||||
if (modem_table_lte(&q->mod, LTE_QPSK, true)) {
|
||||
goto clean;
|
||||
|
@ -223,9 +227,13 @@ void pbch_free(pbch_t *q) {
|
|||
if (q->pbch_rm_b) {
|
||||
free(q->pbch_rm_b);
|
||||
}
|
||||
precoding_free(&q->precoding);
|
||||
sequence_free(&q->seq_pbch);
|
||||
modem_table_free(&q->mod);
|
||||
viterbi_free(&q->decoder);
|
||||
|
||||
bzero(q, sizeof(pbch_t));
|
||||
|
||||
}
|
||||
|
||||
void pbch_decode_reset(pbch_t *q) {
|
||||
|
@ -315,7 +323,7 @@ int pbch_decode_frame(pbch_t *q, uint32_t src, uint32_t dst, uint32_t n,
|
|||
*
|
||||
* Returns 1 if successfully decoded MIB, 0 if not and -1 on error
|
||||
*/
|
||||
int pbch_decode(pbch_t *q, cf_t *slot1_symbols, cf_t *ce_slot1[MAX_PORTS],
|
||||
int pbch_decode(pbch_t *q, cf_t *slot1_symbols, cf_t *ce_slot1[MAX_PORTS], float noise_estimate,
|
||||
uint8_t bch_payload[BCH_PAYLOAD_LEN], uint32_t *nof_tx_ports, uint32_t *sfn_offset)
|
||||
{
|
||||
uint32_t src, dst, nb;
|
||||
|
@ -369,10 +377,10 @@ int pbch_decode(pbch_t *q, cf_t *slot1_symbols, cf_t *ce_slot1[MAX_PORTS],
|
|||
/* in conctrol channels, only diversity is supported */
|
||||
if (nant == 1) {
|
||||
/* no need for layer demapping */
|
||||
predecoding_single_zf(q->pbch_symbols[0], q->ce[0], q->pbch_d,
|
||||
q->nof_symbols);
|
||||
predecoding_single_mmse(&q->precoding, q->pbch_symbols[0], q->ce[0], q->pbch_d,
|
||||
q->nof_symbols, noise_estimate);
|
||||
} else {
|
||||
predecoding_diversity_zf(q->pbch_symbols[0], q->ce, x, nant,
|
||||
predecoding_diversity_zf(&q->precoding, q->pbch_symbols[0], q->ce, x, nant,
|
||||
q->nof_symbols);
|
||||
layerdemap_diversity(x, q->pbch_d, nant, q->nof_symbols / nant);
|
||||
}
|
||||
|
@ -465,7 +473,7 @@ int pbch_encode(pbch_t *q, uint8_t bch_payload[BCH_PAYLOAD_LEN], cf_t *slot1_sym
|
|||
/* layer mapping & precoding */
|
||||
if (q->cell.nof_ports > 1) {
|
||||
layermap_diversity(q->pbch_d, x, q->cell.nof_ports, q->nof_symbols);
|
||||
precoding_diversity(x, q->pbch_symbols, q->cell.nof_ports,
|
||||
precoding_diversity(&q->precoding, x, q->pbch_symbols, q->cell.nof_ports,
|
||||
q->nof_symbols / q->cell.nof_ports);
|
||||
} else {
|
||||
memcpy(q->pbch_symbols[0], q->pbch_d, q->nof_symbols * sizeof(cf_t));
|
||||
|
|
|
@ -69,6 +69,10 @@ int pcfich_init(pcfich_t *q, regs_t *regs, lte_cell_t cell) {
|
|||
bzero(q, sizeof(pcfich_t));
|
||||
q->cell = cell;
|
||||
q->regs = regs;
|
||||
|
||||
if (precoding_init(&q->precoding, SF_LEN_RE(cell.nof_prb, cell.cp))) {
|
||||
fprintf(stderr, "Error initializing precoding\n");
|
||||
}
|
||||
|
||||
if (modem_table_lte(&q->mod, LTE_QPSK, false)) {
|
||||
goto clean;
|
||||
|
@ -100,6 +104,9 @@ void pcfich_free(pcfich_t *q) {
|
|||
sequence_free(&q->seq_pcfich[ns]);
|
||||
}
|
||||
modem_table_free(&q->mod);
|
||||
precoding_free(&q->precoding);
|
||||
|
||||
bzero(q, sizeof(pcfich_t));
|
||||
}
|
||||
|
||||
/** Finds the CFI with minimum distance with the vector of received 32 bits.
|
||||
|
@ -143,7 +150,7 @@ int pcfich_cfi_encode(int cfi, uint8_t bits[PCFICH_CFI_LEN]) {
|
|||
*
|
||||
* Returns 1 if successfully decoded the CFI, 0 if not and -1 on error
|
||||
*/
|
||||
int pcfich_decode(pcfich_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS],
|
||||
int pcfich_decode(pcfich_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS], float noise_estimate,
|
||||
uint32_t nsubframe, uint32_t *cfi, uint32_t *distance) {
|
||||
int dist;
|
||||
|
||||
|
@ -183,10 +190,10 @@ int pcfich_decode(pcfich_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS],
|
|||
/* in control channels, only diversity is supported */
|
||||
if (q->cell.nof_ports == 1) {
|
||||
/* no need for layer demapping */
|
||||
predecoding_single_zf(q->pcfich_symbols[0], q->ce[0], q->pcfich_d,
|
||||
q->nof_symbols);
|
||||
predecoding_single_mmse(&q->precoding, q->pcfich_symbols[0], q->ce[0], q->pcfich_d,
|
||||
q->nof_symbols, noise_estimate);
|
||||
} else {
|
||||
predecoding_diversity_zf(q->pcfich_symbols[0], ce_precoding, x,
|
||||
predecoding_diversity_zf(&q->precoding, q->pcfich_symbols[0], ce_precoding, x,
|
||||
q->cell.nof_ports, q->nof_symbols);
|
||||
layerdemap_diversity(x, q->pcfich_d, q->cell.nof_ports,
|
||||
q->nof_symbols / q->cell.nof_ports);
|
||||
|
@ -249,7 +256,7 @@ int pcfich_encode(pcfich_t *q, uint32_t cfi, cf_t *slot_symbols[MAX_PORTS],
|
|||
/* layer mapping & precoding */
|
||||
if (q->cell.nof_ports > 1) {
|
||||
layermap_diversity(q->pcfich_d, x, q->cell.nof_ports, q->nof_symbols);
|
||||
precoding_diversity(x, symbols_precoding, q->cell.nof_ports,
|
||||
precoding_diversity(&q->precoding, x, symbols_precoding, q->cell.nof_ports,
|
||||
q->nof_symbols / q->cell.nof_ports);
|
||||
} else {
|
||||
memcpy(q->pcfich_symbols[0], q->pcfich_d, q->nof_symbols * sizeof(cf_t));
|
||||
|
|
|
@ -78,6 +78,10 @@ int pdcch_init(pdcch_t *q, regs_t *regs, lte_cell_t cell) {
|
|||
bzero(q, sizeof(pdcch_t));
|
||||
q->cell = cell;
|
||||
q->regs = regs;
|
||||
|
||||
if (precoding_init(&q->precoding, SF_LEN_RE(cell.nof_prb, cell.cp))) {
|
||||
fprintf(stderr, "Error initializing precoding\n");
|
||||
}
|
||||
|
||||
/* Allocate memory for the largest aggregation level L=3 */
|
||||
q->max_bits = PDCCH_FORMAT_NOF_BITS(3);
|
||||
|
@ -175,8 +179,12 @@ void pdcch_free(pdcch_t *q) {
|
|||
sequence_free(&q->seq_pdcch[i]);
|
||||
}
|
||||
|
||||
precoding_free(&q->precoding);
|
||||
modem_table_free(&q->mod);
|
||||
viterbi_free(&q->decoder);
|
||||
|
||||
bzero(q, sizeof(pdcch_t));
|
||||
|
||||
}
|
||||
|
||||
/** 36.213 v9.1.1
|
||||
|
@ -341,7 +349,7 @@ int pdcch_decode_msg(pdcch_t *q, dci_msg_t *msg, dci_format_t format, uint16_t *
|
|||
* Every time this function is called (with a different location), the last demodulated symbols are overwritten and
|
||||
* new messages from other locations can be decoded
|
||||
*/
|
||||
int pdcch_extract_llr(pdcch_t *q, cf_t *sf_symbols, cf_t *ce[MAX_PORTS],
|
||||
int pdcch_extract_llr(pdcch_t *q, cf_t *sf_symbols, cf_t *ce[MAX_PORTS], float noise_estimate,
|
||||
dci_location_t location, uint32_t nsubframe, uint32_t cfi) {
|
||||
|
||||
int ret = LIBLTE_ERROR_INVALID_INPUTS;
|
||||
|
@ -394,9 +402,9 @@ int pdcch_extract_llr(pdcch_t *q, cf_t *sf_symbols, cf_t *ce[MAX_PORTS],
|
|||
/* in control channels, only diversity is supported */
|
||||
if (q->cell.nof_ports == 1) {
|
||||
/* no need for layer demapping */
|
||||
predecoding_single_zf(q->pdcch_symbols[0], q->ce[0], q->pdcch_d, nof_symbols);
|
||||
predecoding_single_mmse(&q->precoding, q->pdcch_symbols[0], q->ce[0], q->pdcch_d, nof_symbols, noise_estimate);
|
||||
} else {
|
||||
predecoding_diversity_zf(q->pdcch_symbols[0], q->ce, x, q->cell.nof_ports, nof_symbols);
|
||||
predecoding_diversity_zf(&q->precoding, q->pdcch_symbols[0], q->ce, x, q->cell.nof_ports, nof_symbols);
|
||||
layerdemap_diversity(x, q->pdcch_d, q->cell.nof_ports, nof_symbols / q->cell.nof_ports);
|
||||
}
|
||||
|
||||
|
@ -536,7 +544,7 @@ int pdcch_encode(pdcch_t *q, dci_msg_t *msg, dci_location_t location, uint16_t r
|
|||
/* layer mapping & precoding */
|
||||
if (q->cell.nof_ports > 1) {
|
||||
layermap_diversity(q->pdcch_d, x, q->cell.nof_ports, nof_symbols);
|
||||
precoding_diversity(x, q->pdcch_symbols, q->cell.nof_ports, nof_symbols / q->cell.nof_ports);
|
||||
precoding_diversity(&q->precoding, x, q->pdcch_symbols, q->cell.nof_ports, nof_symbols / q->cell.nof_ports);
|
||||
} else {
|
||||
memcpy(q->pdcch_symbols[0], q->pdcch_d, nof_symbols * sizeof(cf_t));
|
||||
}
|
||||
|
|
|
@ -189,6 +189,10 @@ int pdsch_init(pdsch_t *q, lte_cell_t cell) {
|
|||
INFO("Init PDSCH: %d ports %d PRBs, max_symbols: %d\n", q->cell.nof_ports,
|
||||
q->cell.nof_prb, q->max_symbols);
|
||||
|
||||
if (precoding_init(&q->precoding, SF_LEN_RE(cell.nof_prb, cell.cp))) {
|
||||
fprintf(stderr, "Error initializing precoding\n");
|
||||
}
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
if (modem_table_lte(&q->mod[i], modulations[i], true)) {
|
||||
goto clean;
|
||||
|
@ -295,6 +299,9 @@ void pdsch_free(pdsch_t *q) {
|
|||
}
|
||||
tdec_free(&q->decoder);
|
||||
tcod_free(&q->encoder);
|
||||
precoding_free(&q->precoding);
|
||||
|
||||
bzero(q, sizeof(pdsch_t));
|
||||
|
||||
}
|
||||
|
||||
|
@ -607,7 +614,7 @@ int pdsch_decode_tb(pdsch_t *q, uint8_t *data, uint32_t tbs, uint32_t nb_e,
|
|||
|
||||
/** Decodes the PDSCH from the received symbols
|
||||
*/
|
||||
int pdsch_decode(pdsch_t *q, cf_t *sf_symbols, cf_t *ce[MAX_PORTS], uint8_t *data, uint32_t subframe,
|
||||
int pdsch_decode(pdsch_t *q, cf_t *sf_symbols, cf_t *ce[MAX_PORTS], float noise_estimate, uint8_t *data, uint32_t subframe,
|
||||
pdsch_harq_t *harq_process, uint32_t rv_idx)
|
||||
{
|
||||
|
||||
|
@ -657,10 +664,10 @@ int pdsch_decode(pdsch_t *q, cf_t *sf_symbols, cf_t *ce[MAX_PORTS], uint8_t *dat
|
|||
/* TODO: only diversity is supported */
|
||||
if (q->cell.nof_ports == 1) {
|
||||
/* no need for layer demapping */
|
||||
predecoding_single_zf(q->pdsch_symbols[0], q->ce[0], q->pdsch_d,
|
||||
nof_symbols);
|
||||
predecoding_single_mmse(&q->precoding, q->pdsch_symbols[0], q->ce[0], q->pdsch_d,
|
||||
nof_symbols, noise_estimate);
|
||||
} else {
|
||||
predecoding_diversity_zf(q->pdsch_symbols[0], q->ce, x, q->cell.nof_ports,
|
||||
predecoding_diversity_zf(&q->precoding, q->pdsch_symbols[0], q->ce, x, q->cell.nof_ports,
|
||||
nof_symbols);
|
||||
layerdemap_diversity(x, q->pdsch_d, q->cell.nof_ports,
|
||||
nof_symbols / q->cell.nof_ports);
|
||||
|
@ -878,7 +885,7 @@ int pdsch_encode(pdsch_t *q, uint8_t *data, cf_t *sf_symbols[MAX_PORTS], uint32_
|
|||
/* TODO: only diversity supported */
|
||||
if (q->cell.nof_ports > 1) {
|
||||
layermap_diversity(q->pdsch_d, x, q->cell.nof_ports, nof_symbols);
|
||||
precoding_diversity(x, q->pdsch_symbols, q->cell.nof_ports,
|
||||
precoding_diversity(&q->precoding, x, q->pdsch_symbols, q->cell.nof_ports,
|
||||
nof_symbols / q->cell.nof_ports);
|
||||
} else {
|
||||
memcpy(q->pdsch_symbols[0], q->pdsch_d, nof_symbols * sizeof(cf_t));
|
||||
|
|
|
@ -75,6 +75,10 @@ int phich_init(phich_t *q, regs_t *regs, lte_cell_t cell) {
|
|||
|
||||
q->cell = cell;
|
||||
q->regs = regs;
|
||||
|
||||
if (precoding_init(&q->precoding, SF_LEN_RE(cell.nof_prb, cell.cp))) {
|
||||
fprintf(stderr, "Error initializing precoding\n");
|
||||
}
|
||||
|
||||
if (modem_table_lte(&q->mod, LTE_BPSK, false)) {
|
||||
goto clean;
|
||||
|
@ -102,6 +106,10 @@ void phich_free(phich_t *q) {
|
|||
sequence_free(&q->seq_phich[ns]);
|
||||
}
|
||||
modem_table_free(&q->mod);
|
||||
precoding_free(&q->precoding);
|
||||
|
||||
bzero(q, sizeof(phich_t));
|
||||
|
||||
}
|
||||
|
||||
/* Decodes ACK
|
||||
|
@ -139,7 +147,7 @@ void phich_ack_encode(uint8_t ack, uint8_t bits[PHICH_NBITS]) {
|
|||
*
|
||||
* Returns 1 if successfully decoded the CFI, 0 if not and -1 on error
|
||||
*/
|
||||
int phich_decode(phich_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS],
|
||||
int phich_decode(phich_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS], float noise_estimate,
|
||||
uint32_t ngroup, uint32_t nseq, uint32_t subframe, uint8_t *ack, uint32_t *distance) {
|
||||
|
||||
/* Set pointers for layermapping & precoding */
|
||||
|
@ -200,10 +208,10 @@ int phich_decode(phich_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS],
|
|||
/* in control channels, only diversity is supported */
|
||||
if (q->cell.nof_ports == 1) {
|
||||
/* no need for layer demapping */
|
||||
predecoding_single_zf(q->phich_symbols[0], q->ce[0], q->phich_d0,
|
||||
PHICH_MAX_NSYMB);
|
||||
predecoding_single_mmse(&q->precoding, q->phich_symbols[0], q->ce[0], q->phich_d0,
|
||||
PHICH_MAX_NSYMB, noise_estimate);
|
||||
} else {
|
||||
predecoding_diversity_zf(q->phich_symbols[0], ce_precoding, x,
|
||||
predecoding_diversity_zf(&q->precoding, q->phich_symbols[0], ce_precoding, x,
|
||||
q->cell.nof_ports, PHICH_MAX_NSYMB);
|
||||
layerdemap_diversity(x, q->phich_d0, q->cell.nof_ports,
|
||||
PHICH_MAX_NSYMB / q->cell.nof_ports);
|
||||
|
@ -368,7 +376,7 @@ int phich_encode(phich_t *q, uint8_t ack, uint32_t ngroup, uint32_t nseq, uint32
|
|||
/* layer mapping & precoding */
|
||||
if (q->cell.nof_ports > 1) {
|
||||
layermap_diversity(q->phich_d0, x, q->cell.nof_ports, PHICH_MAX_NSYMB);
|
||||
precoding_diversity(x, symbols_precoding, q->cell.nof_ports,
|
||||
precoding_diversity(&q->precoding, x, symbols_precoding, q->cell.nof_ports,
|
||||
PHICH_MAX_NSYMB / q->cell.nof_ports);
|
||||
/**FIXME: According to 6.9.2, Precoding for 4 tx ports is different! */
|
||||
} else {
|
||||
|
|
|
@ -503,6 +503,8 @@ int prach_free(prach_t *p){
|
|||
dft_plan_free(p->zc_ifft);
|
||||
free(p->zc_ifft);
|
||||
|
||||
bzero(p, sizeof(prach_t));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -69,6 +69,9 @@ void regs_pdcch_free(regs_t *h) {
|
|||
free(h->pdcch[i].regs);
|
||||
}
|
||||
}
|
||||
|
||||
bzero(h, sizeof(regs_t));
|
||||
|
||||
}
|
||||
|
||||
#define PDCCH_NCOLS 32
|
||||
|
@ -349,6 +352,9 @@ void regs_phich_free(regs_t *h) {
|
|||
}
|
||||
free(h->phich);
|
||||
}
|
||||
|
||||
bzero(h, sizeof(regs_t));
|
||||
|
||||
}
|
||||
|
||||
uint32_t regs_phich_nregs(regs_t *h) {
|
||||
|
@ -492,6 +498,9 @@ void regs_pcfich_free(regs_t *h) {
|
|||
if (h->pcfich.regs) {
|
||||
free(h->pcfich.regs);
|
||||
}
|
||||
|
||||
bzero(h, sizeof(regs_t));
|
||||
|
||||
}
|
||||
|
||||
uint32_t regs_pcfich_nregs(regs_t *h) {
|
||||
|
|
|
@ -219,7 +219,9 @@ int main(int argc, char **argv) {
|
|||
ce_slot1[i] = &ce[i][SLOT_LEN_RE(cell.nof_prb, cell.cp)];
|
||||
}
|
||||
|
||||
n = pbch_decode(&pbch, &fft_buffer[SLOT_LEN_RE(cell.nof_prb, cell.cp)], ce_slot1, bch_payload, &nof_tx_ports, &sfn_offset);
|
||||
n = pbch_decode(&pbch, &fft_buffer[SLOT_LEN_RE(cell.nof_prb, cell.cp)],
|
||||
ce_slot1, chest_dl_get_noise_estimate(&chest),
|
||||
bch_payload, &nof_tx_ports, &sfn_offset);
|
||||
|
||||
base_free();
|
||||
if (n < 0) {
|
||||
|
|
|
@ -125,7 +125,7 @@ int main(int argc, char **argv) {
|
|||
}
|
||||
|
||||
pbch_decode_reset(&pbch);
|
||||
if (1 != pbch_decode(&pbch, slot1_symbols[0], ce, bch_payload_rx, &nof_rx_ports, NULL)) {
|
||||
if (1 != pbch_decode(&pbch, slot1_symbols[0], ce, 0, bch_payload_rx, &nof_rx_ports, NULL)) {
|
||||
printf("Error decoding\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
|
|
@ -226,7 +226,7 @@ int main(int argc, char **argv) {
|
|||
|
||||
INFO("Decoding PCFICH\n", 0);
|
||||
|
||||
n = pcfich_decode(&pcfich, fft_buffer, ce, 0, &cfi, &distance);
|
||||
n = pcfich_decode(&pcfich, fft_buffer, ce, chest_dl_get_noise_estimate(&chest), 0, &cfi, &distance);
|
||||
printf("cfi: %d, distance: %d\n", cfi, distance);
|
||||
|
||||
base_free();
|
||||
|
|
|
@ -139,7 +139,7 @@ int main(int argc, char **argv) {
|
|||
slot_symbols[0][j] += slot_symbols[i][j];
|
||||
}
|
||||
}
|
||||
if (pcfich_decode(&pcfich, slot_symbols[0], ce, nsf, &cfi_rx, &distance)<0) {
|
||||
if (pcfich_decode(&pcfich, slot_symbols[0], ce, 0, nsf, &cfi_rx, &distance)<0) {
|
||||
exit(-1);
|
||||
}
|
||||
INFO("cfi_tx: %d, cfi_rx: %d, ns: %d, distance: %d\n",
|
||||
|
|
|
@ -262,7 +262,7 @@ int main(int argc, char **argv) {
|
|||
|
||||
uint16_t crc_rem = 0;
|
||||
for (i=0;i<nof_locations && crc_rem != rnti;i++) {
|
||||
if (pdcch_extract_llr(&pdcch, fft_buffer, ce, locations[i], nof_frames, cfi)) {
|
||||
if (pdcch_extract_llr(&pdcch, fft_buffer, ce, chest_dl_get_noise_estimate(&chest), locations[i], nof_frames, cfi)) {
|
||||
fprintf(stderr, "Error extracting LLRs\n");
|
||||
return -1;
|
||||
}
|
||||
|
|
|
@ -190,7 +190,7 @@ int main(int argc, char **argv) {
|
|||
}
|
||||
|
||||
for (i=0;i<2;i++) {
|
||||
if (pdcch_extract_llr(&pdcch, slot_symbols[0], ce, dci_locations[i], 0, cfi)) {
|
||||
if (pdcch_extract_llr(&pdcch, slot_symbols[0], ce, 0, dci_locations[i], 0, cfi)) {
|
||||
fprintf(stderr, "Error extracting LLRs\n");
|
||||
goto quit;
|
||||
}
|
||||
|
|
|
@ -283,7 +283,7 @@ int main(int argc, char **argv) {
|
|||
|
||||
uint16_t crc_rem = 0;
|
||||
for (i=0;i<nof_locations && crc_rem != rnti;i++) {
|
||||
if (pdcch_extract_llr(&pdcch, fft_buffer, ce, locations[i], nof_frames, cfi)) {
|
||||
if (pdcch_extract_llr(&pdcch, fft_buffer, ce, chest_dl_get_noise_estimate(&chest), locations[i], nof_frames, cfi)) {
|
||||
fprintf(stderr, "Error extracting LLRs\n");
|
||||
return -1;
|
||||
}
|
||||
|
@ -302,7 +302,7 @@ int main(int argc, char **argv) {
|
|||
fprintf(stderr, "Error configuring HARQ process\n");
|
||||
goto goout;
|
||||
}
|
||||
if (pdsch_decode(&pdsch, fft_buffer, ce, data, nof_frames%10, &harq_process, ra_dl.rv_idx)) {
|
||||
if (pdsch_decode(&pdsch, fft_buffer, ce, chest_dl_get_noise_estimate(&chest), data, nof_frames%10, &harq_process, ra_dl.rv_idx)) {
|
||||
fprintf(stderr, "Error decoding PDSCH\n");
|
||||
goto goout;
|
||||
} else {
|
||||
|
|
|
@ -207,7 +207,7 @@ int main(int argc, char **argv) {
|
|||
}
|
||||
|
||||
gettimeofday(&t[1], NULL);
|
||||
int r = pdsch_decode(&pdsch, slot_symbols[0], ce, data, subframe, &harq_process, rv);
|
||||
int r = pdsch_decode(&pdsch, slot_symbols[0], ce, 0, data, subframe, &harq_process, rv);
|
||||
gettimeofday(&t[2], NULL);
|
||||
get_time_interval(t);
|
||||
if (r) {
|
||||
|
|
|
@ -255,7 +255,7 @@ int main(int argc, char **argv) {
|
|||
for (ngroup=0;ngroup<phich_ngroups(&phich);ngroup++) {
|
||||
for (nseq=0;nseq<max_nseq;nseq++) {
|
||||
|
||||
if (phich_decode(&phich, fft_buffer, ce, ngroup, nseq, numsubframe, &ack_rx, &distance)<0) {
|
||||
if (phich_decode(&phich, fft_buffer, ce, chest_dl_get_noise_estimate(&chest), ngroup, nseq, numsubframe, &ack_rx, &distance)<0) {
|
||||
printf("Error decoding ACK\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
|
|
@ -181,7 +181,7 @@ int main(int argc, char **argv) {
|
|||
for (ngroup=0;ngroup<phich_ngroups(&phich);ngroup++) {
|
||||
for (nseq=0;nseq<max_nseq;nseq++) {
|
||||
|
||||
if (phich_decode(&phich, slot_symbols[0], ce, ngroup, nseq, nsf, &ack_rx, &distance)<0) {
|
||||
if (phich_decode(&phich, slot_symbols[0], ce, 0, ngroup, nseq, nsf, &ack_rx, &distance)<0) {
|
||||
printf("Error decoding ACK\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
|
|
@ -125,6 +125,9 @@ void interp_linear_vector_free(interp_linvec_t *q) {
|
|||
if (q->diff_vec) {
|
||||
free(q->diff_vec);
|
||||
}
|
||||
|
||||
bzero(q, sizeof(interp_linvec_t));
|
||||
|
||||
}
|
||||
|
||||
void interp_linear_vector(interp_linvec_t *q, cf_t *in0, cf_t *in1, cf_t *between, uint32_t M)
|
||||
|
@ -179,6 +182,15 @@ void interp_linear_free(interp_lin_t *q) {
|
|||
if (q->diff_vec) {
|
||||
free(q->diff_vec);
|
||||
}
|
||||
if (q->diff_vec2) {
|
||||
free(q->diff_vec2);
|
||||
}
|
||||
if (q->ramp) {
|
||||
free(q->ramp);
|
||||
}
|
||||
|
||||
bzero(q, sizeof(interp_lin_t));
|
||||
|
||||
}
|
||||
|
||||
void interp_linear_offset(interp_lin_t *q, cf_t *input, cf_t *output,
|
||||
|
|
|
@ -102,6 +102,9 @@ void ue_celldetect_free(ue_celldetect_t * q)
|
|||
free(q->mode_ntimes);
|
||||
}
|
||||
sync_free(&q->sfind);
|
||||
|
||||
bzero(q, sizeof(ue_celldetect_t));
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -137,6 +137,9 @@ void ue_dl_free(ue_dl_t *q) {
|
|||
free(q->ce[i]);
|
||||
}
|
||||
}
|
||||
|
||||
bzero(q, sizeof(ue_dl_t));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -171,7 +174,7 @@ int ue_dl_decode(ue_dl_t *q, cf_t *input, uint8_t *data, uint32_t sf_idx, uint32
|
|||
|
||||
|
||||
/* First decode PCFICH and obtain CFI */
|
||||
if (pcfich_decode(&q->pcfich, q->sf_symbols, q->ce, sf_idx, &cfi, &cfi_distance)<0) {
|
||||
if (pcfich_decode(&q->pcfich, q->sf_symbols, q->ce, chest_dl_get_noise_estimate(&q->chest), sf_idx, &cfi, &cfi_distance)<0) {
|
||||
fprintf(stderr, "Error decoding PCFICH\n");
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
|
@ -194,7 +197,7 @@ int ue_dl_decode(ue_dl_t *q, cf_t *input, uint8_t *data, uint32_t sf_idx, uint32
|
|||
|
||||
crc_rem = 0;
|
||||
for (i=0;i<nof_locations && crc_rem != rnti;i++) {
|
||||
if (pdcch_extract_llr(&q->pdcch, q->sf_symbols, q->ce, locations[i], sf_idx, cfi)) {
|
||||
if (pdcch_extract_llr(&q->pdcch, q->sf_symbols, q->ce, chest_dl_get_noise_estimate(&q->chest), locations[i], sf_idx, cfi)) {
|
||||
fprintf(stderr, "Error extracting LLRs\n");
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
|
@ -239,7 +242,7 @@ int ue_dl_decode(ue_dl_t *q, cf_t *input, uint8_t *data, uint32_t sf_idx, uint32
|
|||
}
|
||||
}
|
||||
if (q->harq_process[0].mcs.mod > 0) {
|
||||
ret = pdsch_decode(&q->pdsch, q->sf_symbols, q->ce, data, sf_idx,
|
||||
ret = pdsch_decode(&q->pdsch, q->sf_symbols, q->ce, chest_dl_get_noise_estimate(&q->chest), data, sf_idx,
|
||||
&q->harq_process[0], rvidx);
|
||||
if (ret == LIBLTE_ERROR) {
|
||||
if (rnti == SIRNTI && rvidx == 1) {
|
||||
|
|
|
@ -128,6 +128,9 @@ void ue_mib_free(ue_mib_t * q)
|
|||
chest_dl_free(&q->chest);
|
||||
pbch_free(&q->pbch);
|
||||
lte_fft_free(&q->fft);
|
||||
|
||||
bzero(q, sizeof(ue_mib_t));
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -173,7 +176,9 @@ int ue_mib_decode_aligned_frame(ue_mib_t * q, cf_t *input,
|
|||
}
|
||||
|
||||
/* Decode PBCH */
|
||||
ret = pbch_decode(&q->pbch, &q->sf_symbols[SLOT_LEN_RE(q->chest.cell.nof_prb, q->chest.cell.cp)], ce_slot1, bch_payload, nof_tx_ports, sfn_offset);
|
||||
ret = pbch_decode(&q->pbch, &q->sf_symbols[SLOT_LEN_RE(q->chest.cell.nof_prb, q->chest.cell.cp)],
|
||||
ce_slot1, chest_dl_get_noise_estimate(&q->chest),
|
||||
bch_payload, nof_tx_ports, sfn_offset);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Error decoding PBCH (%d)\n", ret);
|
||||
} else if (ret == 1) {
|
||||
|
|
|
@ -124,6 +124,8 @@ void ue_sync_free(ue_sync_t *q) {
|
|||
cfo_free(&q->cfocorr);
|
||||
sync_free(&q->sfind);
|
||||
sync_free(&q->strack);
|
||||
|
||||
bzero(q, sizeof(ue_sync_t));
|
||||
}
|
||||
|
||||
uint32_t ue_sync_peak_idx(ue_sync_t *q) {
|
||||
|
|
|
@ -72,6 +72,9 @@ void conv_fft_cc_free(conv_fft_cc_t *q) {
|
|||
dft_plan_free(&q->input_plan);
|
||||
dft_plan_free(&q->filter_plan);
|
||||
dft_plan_free(&q->output_plan);
|
||||
|
||||
bzero(q, sizeof(conv_fft_cc_t));
|
||||
|
||||
}
|
||||
|
||||
uint32_t conv_fft_cc_run(conv_fft_cc_t *q, cf_t *input, cf_t *filter, cf_t *output) {
|
||||
|
|
|
@ -121,6 +121,27 @@ void vec_sum_bbb(uint8_t *x, uint8_t *y, uint8_t *z, uint32_t len) {
|
|||
}
|
||||
}
|
||||
|
||||
void vec_sc_add_fff(float *x, float h, float *z, uint32_t len) {
|
||||
int i;
|
||||
for (i=0;i<len;i++) {
|
||||
z[i] += h;
|
||||
}
|
||||
}
|
||||
|
||||
void vec_sc_add_cfc(cf_t *x, float h, cf_t *z, uint32_t len) {
|
||||
int i;
|
||||
for (i=0;i<len;i++) {
|
||||
z[i] += h;
|
||||
}
|
||||
}
|
||||
|
||||
void vec_sc_add_ccc(cf_t *x, cf_t h, cf_t *z, uint32_t len) {
|
||||
int i;
|
||||
for (i=0;i<len;i++) {
|
||||
z[i] += h;
|
||||
}
|
||||
}
|
||||
|
||||
void vec_sc_prod_fff(float *x, float h, float *z, uint32_t len) {
|
||||
#ifndef HAVE_VOLK_MULT_FLOAT_FUNCTION
|
||||
int i;
|
||||
|
@ -168,6 +189,17 @@ void vec_convert_fi(float *x, int16_t *z, float scale, uint32_t len) {
|
|||
#endif
|
||||
}
|
||||
|
||||
void vec_interleave_cf(float *real, float *imag, cf_t *x, uint32_t len) {
|
||||
#ifdef HAVE_VOLK_INTERLEAVE_FUNCTION
|
||||
volk_32f_x2_interleave_32fc(x, real, imag, len);
|
||||
#else
|
||||
int i;
|
||||
for (i=0;i<len;i++) {
|
||||
x[i] = real[i] + _Complex_I*imag[i];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void vec_deinterleave_cf(cf_t *x, float *real, float *imag, uint32_t len) {
|
||||
#ifdef HAVE_VOLK_DEINTERLEAVE_FUNCTION
|
||||
volk_32fc_deinterleave_32f_x2(real, imag, x, len);
|
||||
|
@ -315,7 +347,6 @@ void vec_prod_cfc(cf_t *x, float *y, cf_t *z, uint32_t len) {
|
|||
#endif
|
||||
}
|
||||
|
||||
|
||||
void vec_prod_ccc(cf_t *x,cf_t *y, cf_t *z, uint32_t len) {
|
||||
#ifndef HAVE_VOLK_MULT2_FUNCTION
|
||||
int i;
|
||||
|
@ -339,14 +370,23 @@ void vec_prod_conj_ccc(cf_t *x,cf_t *y, cf_t *z, uint32_t len) {
|
|||
#endif
|
||||
}
|
||||
|
||||
#define DIV_USE_VEC
|
||||
|
||||
/* Complex division is conjugate multiplication + real division */
|
||||
void vec_div_ccc(cf_t *x, cf_t *y, float *y_mod, cf_t *z, uint32_t len) {
|
||||
void vec_div_ccc(cf_t *x, cf_t *y, float *y_mod, cf_t *z, float *z_real, float *z_imag, uint32_t len) {
|
||||
#ifdef DIV_USE_VEC
|
||||
vec_prod_conj_ccc(x,y,z,len);
|
||||
vec_abs_square_cf(y,y_mod,len);
|
||||
int i;
|
||||
vec_deinterleave_cf(z, z_real, z_imag, len);
|
||||
vec_div_fff(z_real, y_mod, z_real, len);
|
||||
vec_div_fff(z_imag, y_mod, z_imag, len);
|
||||
vec_interleave_cf(z_real, z_imag, z, len);
|
||||
#else
|
||||
int i;
|
||||
for (i=0;i<len;i++) {
|
||||
z[i] = z[i] / y_mod[i];
|
||||
z[i] = x[i] / y[i];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void vec_div_fff(float *x, float *y, float *z, uint32_t len) {
|
||||
|
@ -445,7 +485,7 @@ void vec_abs_square_cf(cf_t *x, float *abs_square, uint32_t len) {
|
|||
#ifndef HAVE_VOLK_MAG_SQUARE_FUNCTION
|
||||
int i;
|
||||
for (i=0;i<len;i++) {
|
||||
abs_square[i] = cabsf(x[i]) * cabsf(x[i]);
|
||||
abs_square[i] = crealf(x[i])*crealf(x[i])+cimagf(x[i]*cimagf(x[i]));
|
||||
}
|
||||
#else
|
||||
volk_32fc_magnitude_squared_32f(abs_square,x,len);
|
||||
|
|
|
@ -4,14 +4,13 @@
|
|||
|
||||
clear
|
||||
|
||||
SNR_values_db=20;%linspace(5,20,8);
|
||||
SNR_values_db=linspace(0,20,8);
|
||||
Nrealizations=1;
|
||||
|
||||
preEVM = zeros(length(SNR_values_db),Nrealizations);
|
||||
postEVM_mmse = zeros(length(SNR_values_db),Nrealizations);
|
||||
postEVM_mmse2 = zeros(length(SNR_values_db),Nrealizations);
|
||||
postEVM_zf = zeros(length(SNR_values_db),Nrealizations);
|
||||
postEVM_zf2 = zeros(length(SNR_values_db),Nrealizations);
|
||||
postEVM_mmse_lin = zeros(length(SNR_values_db),Nrealizations);
|
||||
postEVM_liblte = zeros(length(SNR_values_db),Nrealizations);
|
||||
|
||||
|
||||
enb.NDLRB = 6; % Number of resource blocks
|
||||
|
@ -137,8 +136,6 @@ rxWaveform = lteFadingChannel(cfg,txWaveform);
|
|||
% Calculate noise gain
|
||||
N0 = 1/(sqrt(2.0*enb.CellRefP*double(info.Nfft))*SNR);
|
||||
|
||||
realNoise(snr_idx)=N0;
|
||||
|
||||
% Create additive white Gaussian noise
|
||||
noise = N0*complex(randn(size(rxWaveform)),randn(size(rxWaveform)));
|
||||
|
||||
|
@ -152,24 +149,18 @@ rxWaveform = rxWaveform(1+offset:end,:);
|
|||
|
||||
%% OFDM Demodulation
|
||||
rxGrid = lteOFDMDemodulate(enb,rxWaveform);
|
||||
%rxGrid = txGrid;
|
||||
|
||||
addpath('../../debug/lte/phy/lib/ch_estimation/test')
|
||||
%% Channel Estimation
|
||||
[estChannel, noiseEst, avg_ref1, noavg_ref1] = lteDLChannelEstimate2(enb,cec2,rxGrid);
|
||||
[estChannel2, refs, noiseEst2] = liblte_chest(enb.NCellID,enb.CellRefP,rxGrid,[0.15 0.7 0.15],[0.1 0.9]);
|
||||
estChannel2=reshape(estChannel2,size(estChannel));
|
||||
noiseEstimation(snr_idx)=noiseEst;
|
||||
noiseEstimation2(snr_idx)=noiseEst2;
|
||||
|
||||
%error(snr_idx,nreal) = mean(mean(abs(avg_ref-transpose(refs)),2));
|
||||
[estChannel, noiseEst] = lteDLChannelEstimate(enb,cec,rxGrid);
|
||||
[estChannel_lin, noiseEst_lin] = lteDLChannelEstimate(enb,cec2,rxGrid);
|
||||
[d, a, output] = liblte_chest(enb.NCellID,enb.CellRefP,rxGrid,[0.15 0.7 0.15],[0.1 0.9]);
|
||||
|
||||
%% MMSE Equalization
|
||||
eqGrid_mmse = lteEqualizeMMSE(rxGrid, estChannel, noiseEst);
|
||||
eqGrid_mmse2 = lteEqualizeMMSE(rxGrid, estChannel2, noiseEst2);
|
||||
eqGrid_mmse_lin = lteEqualizeMMSE(rxGrid, estChannel_lin, noiseEst_lin);
|
||||
|
||||
eqGrid_zf = lteEqualizeZF(rxGrid, estChannel);
|
||||
eqGrid_zf2 = lteEqualizeZF(rxGrid, estChannel2);
|
||||
eqGrid_liblte = reshape(output,size(eqGrid_mmse));
|
||||
|
||||
%% Analysis
|
||||
|
||||
|
@ -183,23 +174,19 @@ fprintf('%d-%d: Pre-EQ: %0.3f%%\n', ...
|
|||
postEqualisedEVM_mmse = lteEVM(txGrid,eqGrid_mmse);
|
||||
fprintf('%d-%d: MMSE: %0.3f%%\n', ...
|
||||
snr_idx,nreal,postEqualisedEVM_mmse.RMS*100);
|
||||
postEqualisedEVM_mmse2 = lteEVM(txGrid,eqGrid_mmse2);
|
||||
fprintf('%d-%d: MMSE-lin: %0.3f%%\n', ...
|
||||
snr_idx,nreal,postEqualisedEVM_mmse2.RMS*100);
|
||||
|
||||
|
||||
postEqualisedEVM_zf = lteEVM(txGrid,eqGrid_zf);
|
||||
fprintf('%d-%d: zf: %0.3f%%\n', ...
|
||||
snr_idx,nreal,postEqualisedEVM_zf.RMS*100);
|
||||
postEqualisedEVM_zf2 = lteEVM(txGrid,eqGrid_zf2);
|
||||
fprintf('%d-%d: zf-linear: %0.3f%%\n', ...
|
||||
snr_idx,nreal,postEqualisedEVM_zf2.RMS*100);
|
||||
postEqualisedEVM_mmse_lin = lteEVM(txGrid,eqGrid_mmse_lin);
|
||||
fprintf('%d-%d: MMSE-LIN: %0.3f%%\n', ...
|
||||
snr_idx,nreal,postEqualisedEVM_mmse_lin.RMS*100);
|
||||
|
||||
postEqualisedEVM_liblte = lteEVM(txGrid,eqGrid_liblte);
|
||||
fprintf('%d-%d: liblte: %0.3f%%\n', ...
|
||||
snr_idx,nreal,postEqualisedEVM_liblte.RMS*100);
|
||||
|
||||
preEVM(snr_idx,nreal) =preEqualisedEVM.RMS;
|
||||
postEVM_mmse(snr_idx,nreal) = postEqualisedEVM_mmse.RMS;
|
||||
postEVM_mmse2(snr_idx,nreal) = postEqualisedEVM_mmse2.RMS;
|
||||
postEVM_zf(snr_idx,nreal) = postEqualisedEVM_zf.RMS;
|
||||
postEVM_zf2(snr_idx,nreal) = postEqualisedEVM_zf2.RMS;
|
||||
postEVM_mmse_lin(snr_idx,nreal) = postEqualisedEVM_mmse_lin.RMS;
|
||||
postEVM_liblte(snr_idx,nreal) = postEqualisedEVM_liblte.RMS;
|
||||
|
||||
end
|
||||
end
|
||||
|
@ -208,10 +195,8 @@ end
|
|||
% legend('real','seu','meu')
|
||||
plot(SNR_values_db, mean(preEVM,2), ...
|
||||
SNR_values_db, mean(postEVM_mmse,2), ...
|
||||
SNR_values_db, mean(postEVM_mmse2,2), ...
|
||||
SNR_values_db, mean(postEVM_zf,2), ...
|
||||
SNR_values_db, mean(postEVM_zf2,2))
|
||||
legend('No Eq','MMSE','MMSE-linear','ZF','ZF-linear')
|
||||
%plot(SNR_values_db, mean(error,2))
|
||||
SNR_values_db, mean(postEVM_mmse_lin,2), ...
|
||||
SNR_values_db, mean(postEVM_liblte,2))
|
||||
legend('No Eq','MMSE-cubic','MMSE-lin','MMSE-liblte')
|
||||
grid on
|
||||
|
||||
|
|
Loading…
Reference in New Issue