From 4f653dc3ab475c5e9a8cf717a3733b5d79790598 Mon Sep 17 00:00:00 2001 From: ismagom Date: Thu, 13 Nov 2014 15:14:22 +0000 Subject: [PATCH] Added MMSE SISO equalizer (predecoding) --- cmake/modules/FindVolk.cmake | 9 +- .../include/liblte/phy/ch_estimation/cheq.h | 57 ---- lte/phy/include/liblte/phy/mimo/precoding.h | 72 ++++- lte/phy/include/liblte/phy/phch/pbch.h | 4 +- lte/phy/include/liblte/phy/phch/pcfich.h | 2 + lte/phy/include/liblte/phy/phch/pdcch.h | 3 + lte/phy/include/liblte/phy/phch/pdsch.h | 3 + lte/phy/include/liblte/phy/phch/phich.h | 2 + lte/phy/include/liblte/phy/utils/vector.h | 10 +- lte/phy/lib/ch_estimation/src/cheq.c | 53 ---- lte/phy/lib/ch_estimation/src/chest_dl.c | 21 +- lte/phy/lib/ch_estimation/test/CMakeLists.txt | 4 + .../lib/ch_estimation/test/chest_test_dl.c | 103 +++---- .../ch_estimation/test/chest_test_dl_mex.c | 60 ++-- lte/phy/lib/fec/src/viterbi.c | 1 + lte/phy/lib/mimo/src/precoding.c | 269 ++++++++++++------ lte/phy/lib/mimo/test/precoding_test.c | 14 +- lte/phy/lib/phch/src/pbch.c | 18 +- lte/phy/lib/phch/src/pcfich.c | 17 +- lte/phy/lib/phch/src/pdcch.c | 16 +- lte/phy/lib/phch/src/pdsch.c | 17 +- lte/phy/lib/phch/src/phich.c | 18 +- lte/phy/lib/phch/src/prach.c | 2 + lte/phy/lib/phch/src/regs.c | 9 + lte/phy/lib/phch/test/pbch_file_test.c | 4 +- lte/phy/lib/phch/test/pbch_test.c | 2 +- lte/phy/lib/phch/test/pcfich_file_test.c | 2 +- lte/phy/lib/phch/test/pcfich_test.c | 2 +- lte/phy/lib/phch/test/pdcch_file_test.c | 2 +- lte/phy/lib/phch/test/pdcch_test.c | 2 +- lte/phy/lib/phch/test/pdsch_file_test.c | 4 +- lte/phy/lib/phch/test/pdsch_test.c | 2 +- lte/phy/lib/phch/test/phich_file_test.c | 2 +- lte/phy/lib/phch/test/phich_test.c | 2 +- lte/phy/lib/resampling/src/interp.c | 12 + lte/phy/lib/ue/src/ue_celldetect.c | 3 + lte/phy/lib/ue/src/ue_dl.c | 9 +- lte/phy/lib/ue/src/ue_mib.c | 7 +- lte/phy/lib/ue/src/ue_sync.c | 2 + lte/phy/lib/utils/src/convolution.c | 3 + lte/phy/lib/utils/src/vector.c | 50 +++- matlab/tests/equalizer_test.m | 55 ++-- 42 files changed, 571 insertions(+), 378 deletions(-) delete mode 100644 lte/phy/include/liblte/phy/ch_estimation/cheq.h delete mode 100644 lte/phy/lib/ch_estimation/src/cheq.c diff --git a/cmake/modules/FindVolk.cmake b/cmake/modules/FindVolk.cmake index d1e554bf2..6603139b9 100644 --- a/cmake/modules/FindVolk.cmake +++ b/cmake/modules/FindVolk.cmake @@ -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() diff --git a/lte/phy/include/liblte/phy/ch_estimation/cheq.h b/lte/phy/include/liblte/phy/ch_estimation/cheq.h deleted file mode 100644 index 847f3e018..000000000 --- a/lte/phy/include/liblte/phy/ch_estimation/cheq.h +++ /dev/null @@ -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 - -#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 \ No newline at end of file diff --git a/lte/phy/include/liblte/phy/mimo/precoding.h b/lte/phy/include/liblte/phy/mimo/precoding.h index b2baf79d8..adecc03b8 100644 --- a/lte/phy/include/liblte/phy/mimo/precoding.h +++ b/lte/phy/include/liblte/phy/mimo/precoding.h @@ -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_ */ diff --git a/lte/phy/include/liblte/phy/phch/pbch.h b/lte/phy/include/liblte/phy/phch/pbch.h index 2716f1d89..d0399a4de 100644 --- a/lte/phy/include/liblte/phy/phch/pbch.h +++ b/lte/phy/include/liblte/phy/phch/pbch.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); diff --git a/lte/phy/include/liblte/phy/phch/pcfich.h b/lte/phy/include/liblte/phy/phch/pcfich.h index cbbf84bf1..cd87c14f9 100644 --- a/lte/phy/include/liblte/phy/phch/pcfich.h +++ b/lte/phy/include/liblte/phy/phch/pcfich.h @@ -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); diff --git a/lte/phy/include/liblte/phy/phch/pdcch.h b/lte/phy/include/liblte/phy/phch/pdcch.h index d854dacf4..d9681784b 100644 --- a/lte/phy/include/liblte/phy/phch/pdcch.h +++ b/lte/phy/include/liblte/phy/phch/pdcch.h @@ -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); diff --git a/lte/phy/include/liblte/phy/phch/pdsch.h b/lte/phy/include/liblte/phy/phch/pdsch.h index fc7b4b0c9..01a2f4ba3 100644 --- a/lte/phy/include/liblte/phy/phch/pdsch.h +++ b/lte/phy/include/liblte/phy/phch/pdsch.h @@ -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, diff --git a/lte/phy/include/liblte/phy/phch/phich.h b/lte/phy/include/liblte/phy/phch/phich.h index 845794e97..a976ee718 100644 --- a/lte/phy/include/liblte/phy/phch/phich.h +++ b/lte/phy/include/liblte/phy/phch/phich.h @@ -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, diff --git a/lte/phy/include/liblte/phy/utils/vector.h b/lte/phy/include/liblte/phy/utils/vector.h index 81c82b4ce..79bdaa819 100644 --- a/lte/phy/include/liblte/phy/utils/vector.h +++ b/lte/phy/include/liblte/phy/utils/vector.h @@ -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); diff --git a/lte/phy/lib/ch_estimation/src/cheq.c b/lte/phy/lib/ch_estimation/src/cheq.c deleted file mode 100644 index c1719892a..000000000 --- a/lte/phy/lib/ch_estimation/src/cheq.c +++ /dev/null @@ -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 -#include -#include -#include -#include -#include - -#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; -} diff --git a/lte/phy/lib/ch_estimation/src/chest_dl.c b/lte/phy/lib/ch_estimation/src/chest_dl.c index c37afd308..7db8877b1 100644 --- a/lte/phy/lib/ch_estimation/src/chest_dl.c +++ b/lte/phy/lib/ch_estimation/src/chest_dl.c @@ -82,17 +82,17 @@ int chest_dl_init(chest_dl_t *q, lte_cell_t cell) } for (int i=0;ipilot_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;itmp_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)); diff --git a/lte/phy/lib/ch_estimation/test/CMakeLists.txt b/lte/phy/lib/ch_estimation/test/CMakeLists.txt index dc67a637a..296997bc0 100644 --- a/lte/phy/lib/ch_estimation/test/CMakeLists.txt +++ b/lte/phy/lib/ch_estimation/test/CMakeLists.txt @@ -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 ######################################################################## diff --git a/lte/phy/lib/ch_estimation/test/chest_test_dl.c b/lte/phy/lib/ch_estimation/test/chest_test_dl.c index 08cca66cc..bf5e216e9 100644 --- a/lte/phy/lib/ch_estimation/test/chest_test_dl.c +++ b/lte/phy/lib/ch_estimation/test/chest_test_dl.c @@ -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 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); } diff --git a/lte/phy/lib/ch_estimation/test/chest_test_dl_mex.c b/lte/phy/lib/ch_estimation/test/chest_test_dl_mex.c index 016624a2f..8c9e320a6 100644 --- a/lte/phy/lib/ch_estimation/test/chest_test_dl_mex.c +++ b/lte/phy/lib/ch_estimation/test/chest_test_dl_mex.c @@ -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= 1) { for (i=0;i= 3) { + for (i=0;i= 3) { - plhs[2] = mxCreateDoubleMatrix(1, 1, mxREAL); - outr1 = mxGetPr(plhs[2]); - *outr1 = vec_acc_ff(noiseAverage,10)/10; - } - - + return; } diff --git a/lte/phy/lib/fec/src/viterbi.c b/lte/phy/lib/fec/src/viterbi.c index cf6b506ce..cb334bd33 100644 --- a/lte/phy/lib/fec/src/viterbi.c +++ b/lte/phy/lib/fec/src/viterbi.c @@ -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 */ diff --git a/lte/phy/lib/mimo/src/precoding.c b/lte/phy/lib/mimo/src/precoding.c index 6b2d52481..e501a5d42 100644 --- a/lte/phy/lib/mimo/src/precoding.c +++ b/lte/phy/lib/mimo/src/precoding.c @@ -25,7 +25,7 @@ * */ -#include +#include #include #include #include @@ -35,47 +35,144 @@ #include "liblte/phy/mimo/precoding.h" #include "liblte/phy/utils/vector.h" -int precoding_single(cf_t *x, cf_t *y, int nof_symbols) { - memcpy(y, x, nof_symbols * sizeof(cf_t)); - return 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; } -int precoding_diversity(cf_t *x[MAX_LAYERS], cf_t *y[MAX_PORTS], int nof_ports, - int nof_symbols) { + +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) { - /* FIXME: Use VOLK here */ - for (i = 0; i < nof_symbols; i++) { - y[0][2 * i] = x[0][i] / sqrtf(2); - y[1][2 * i] = -conjf(x[1][i]) / sqrtf(2); - y[0][2 * i + 1] = x[1][i] / sqrtf(2); - y[1][2 * i + 1] = conjf(x[0][i]) / sqrtf(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 2 * i; + return i; } else if (nof_ports == 4) { - //int m_ap = (nof_symbols%4)?(nof_symbols*4-2):nof_symbols*4; - int m_ap = 4 * nof_symbols; - for (i = 0; i < m_ap / 4; i++) { - y[0][4 * i] = x[0][i] / sqrtf(2); - y[1][4 * i] = 0; - y[2][4 * i] = -conjf(x[1][i]) / sqrtf(2); - y[3][4 * i] = 0; - y[0][4 * i + 1] = x[1][i] / sqrtf(2); - y[1][4 * i + 1] = 0; - y[2][4 * i + 1] = conjf(x[0][i]) / sqrtf(2); - y[3][4 * i + 1] = 0; + 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]; - y[0][4 * i + 2] = 0; - y[1][4 * i + 2] = x[2][i] / sqrtf(2); - y[2][4 * i + 2] = 0; - y[3][4 * i + 2] = -conjf(x[3][i]) / sqrtf(2); + 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); - y[0][4 * i + 3] = 0; - y[1][4 * i + 3] = x[3][i] / sqrtf(2); - y[2][4 * i + 3] = 0; - y[3][4 * i + 3] = conjf(x[2][i]) / sqrtf(2); } - return 4 * i; + return i; } else { fprintf(stderr, "Number of ports must be 2 or 4 for transmit diversity (nof_ports=%d)\n", nof_ports); return -1; @@ -83,8 +180,8 @@ 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 nof_ports, int nof_symbols, lte_mimo_type_t type) { +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, @@ -100,7 +197,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 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"); @@ -109,12 +206,13 @@ 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 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; @@ -123,65 +221,57 @@ int precoding_type(cf_t *x[MAX_LAYERS], cf_t *y[MAX_PORTS], int nof_layers, } -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 MAX_PORTS) { fprintf(stderr, "Maximum number of ports is %d (nof_ports=%d)\n", MAX_PORTS, @@ -206,7 +296,7 @@ int predecoding_type(cf_t *y, cf_t *ce[MAX_PORTS], cf_t *x[MAX_LAYERS], switch (type) { case SINGLE_ANTENNA: if (nof_ports == 1 && nof_layers == 1) { - return predecoding_single_zf(y, ce[0], x[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"); @@ -215,13 +305,12 @@ int predecoding_type(cf_t *y, cf_t *ce[MAX_PORTS], cf_t *x[MAX_LAYERS], break; case TX_DIVERSITY: if (nof_ports == nof_layers) { - return predecoding_diversity_zf(y, ce, x, 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"); return -1; } - break; case SPATIAL_MULTIPLEX: fprintf(stderr, "Spatial multiplexing not supported\n"); return -1; diff --git a/lte/phy/lib/mimo/test/precoding_test.c b/lte/phy/lib/mimo/test/precoding_test.c index bd30e33c2..7efb3e0b1 100644 --- a/lte/phy/lib/mimo/test/precoding_test.c +++ b/lte/phy/lib/mimo/test/precoding_test.c @@ -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); diff --git a/lte/phy/lib/phch/src/pbch.c b/lte/phy/lib/phch/src/pbch.c index d753a6dc2..bedbfb669 100644 --- a/lte/phy/lib/phch/src/pbch.c +++ b/lte/phy/lib/phch/src/pbch.c @@ -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)); diff --git a/lte/phy/lib/phch/src/pcfich.c b/lte/phy/lib/phch/src/pcfich.c index 8a783c104..8db9fbd60 100644 --- a/lte/phy/lib/phch/src/pcfich.c +++ b/lte/phy/lib/phch/src/pcfich.c @@ -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)); diff --git a/lte/phy/lib/phch/src/pdcch.c b/lte/phy/lib/phch/src/pdcch.c index 8775dacc5..d39a282d5 100644 --- a/lte/phy/lib/phch/src/pdcch.c +++ b/lte/phy/lib/phch/src/pdcch.c @@ -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)); } diff --git a/lte/phy/lib/phch/src/pdsch.c b/lte/phy/lib/phch/src/pdsch.c index ec54c8db6..4d4b91d2f 100644 --- a/lte/phy/lib/phch/src/pdsch.c +++ b/lte/phy/lib/phch/src/pdsch.c @@ -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)); diff --git a/lte/phy/lib/phch/src/phich.c b/lte/phy/lib/phch/src/phich.c index 3d6fa182f..8bb45a695 100644 --- a/lte/phy/lib/phch/src/phich.c +++ b/lte/phy/lib/phch/src/phich.c @@ -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 { diff --git a/lte/phy/lib/phch/src/prach.c b/lte/phy/lib/phch/src/prach.c index 9f9cce611..06c1ba20f 100644 --- a/lte/phy/lib/phch/src/prach.c +++ b/lte/phy/lib/phch/src/prach.c @@ -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; } diff --git a/lte/phy/lib/phch/src/regs.c b/lte/phy/lib/phch/src/regs.c index d34c1d898..d752e7d77 100644 --- a/lte/phy/lib/phch/src/regs.c +++ b/lte/phy/lib/phch/src/regs.c @@ -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) { diff --git a/lte/phy/lib/phch/test/pbch_file_test.c b/lte/phy/lib/phch/test/pbch_file_test.c index 0ab0bdc7b..3dd3c5954 100644 --- a/lte/phy/lib/phch/test/pbch_file_test.c +++ b/lte/phy/lib/phch/test/pbch_file_test.c @@ -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) { diff --git a/lte/phy/lib/phch/test/pbch_test.c b/lte/phy/lib/phch/test/pbch_test.c index ffeece5a0..4e40c56d4 100644 --- a/lte/phy/lib/phch/test/pbch_test.c +++ b/lte/phy/lib/phch/test/pbch_test.c @@ -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); } diff --git a/lte/phy/lib/phch/test/pcfich_file_test.c b/lte/phy/lib/phch/test/pcfich_file_test.c index 41b7b7d56..e91fa150b 100644 --- a/lte/phy/lib/phch/test/pcfich_file_test.c +++ b/lte/phy/lib/phch/test/pcfich_file_test.c @@ -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(); diff --git a/lte/phy/lib/phch/test/pcfich_test.c b/lte/phy/lib/phch/test/pcfich_test.c index a58907763..f4f907848 100644 --- a/lte/phy/lib/phch/test/pcfich_test.c +++ b/lte/phy/lib/phch/test/pcfich_test.c @@ -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", diff --git a/lte/phy/lib/phch/test/pdcch_file_test.c b/lte/phy/lib/phch/test/pdcch_file_test.c index e0ef3c4c5..ebba943c4 100644 --- a/lte/phy/lib/phch/test/pdcch_file_test.c +++ b/lte/phy/lib/phch/test/pdcch_file_test.c @@ -262,7 +262,7 @@ int main(int argc, char **argv) { uint16_t crc_rem = 0; for (i=0;idiff_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, diff --git a/lte/phy/lib/ue/src/ue_celldetect.c b/lte/phy/lib/ue/src/ue_celldetect.c index 48711fbaa..51a6386bd 100644 --- a/lte/phy/lib/ue/src/ue_celldetect.c +++ b/lte/phy/lib/ue/src/ue_celldetect.c @@ -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)); + } diff --git a/lte/phy/lib/ue/src/ue_dl.c b/lte/phy/lib/ue/src/ue_dl.c index 4d9ce8094..2e06a057f 100644 --- a/lte/phy/lib/ue/src/ue_dl.c +++ b/lte/phy/lib/ue/src/ue_dl.c @@ -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;ipdcch, 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) { diff --git a/lte/phy/lib/ue/src/ue_mib.c b/lte/phy/lib/ue/src/ue_mib.c index c3c1f831d..764429acf 100644 --- a/lte/phy/lib/ue/src/ue_mib.c +++ b/lte/phy/lib/ue/src/ue_mib.c @@ -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) { diff --git a/lte/phy/lib/ue/src/ue_sync.c b/lte/phy/lib/ue/src/ue_sync.c index 176ba6c26..4943c7dc9 100644 --- a/lte/phy/lib/ue/src/ue_sync.c +++ b/lte/phy/lib/ue/src/ue_sync.c @@ -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) { diff --git a/lte/phy/lib/utils/src/convolution.c b/lte/phy/lib/utils/src/convolution.c index acf7f5c4d..2dcac6e5f 100644 --- a/lte/phy/lib/utils/src/convolution.c +++ b/lte/phy/lib/utils/src/convolution.c @@ -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) { diff --git a/lte/phy/lib/utils/src/vector.c b/lte/phy/lib/utils/src/vector.c index 67555ba46..c264ce5cb 100644 --- a/lte/phy/lib/utils/src/vector.c +++ b/lte/phy/lib/utils/src/vector.c @@ -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