Added MMSE SISO equalizer (predecoding)

master
ismagom 10 years ago
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("CHEST: %f us\n", (float) t[0].tv_usec/100);
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("%f us\n", (float) t[0].tv_usec/1000);
printf("CHEQ-ZF: %f us\n", (float) t[0].tv_usec/100);
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_mag = mse_phase = 0;
mse = 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;
mse += cabsf(input[i]-output[i]);
}
mse /= num_re;
printf("MSE: %f\n", mse);
/*if (check_mse(mse_mag, mse_phase, n_port)) {
chest_dl_free(&eq);
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,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<nof_symbols;i++) {
if (ce[i] == 0) {
ce[i] = 0.01;
}
}
vec_div_ccc(y, ce, y_mod, x, nof_symbols);
/************************************************
*
* 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;
}
/* 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 precoding_diversity(precoding_t *q, cf_t *x[MAX_LAYERS], cf_t *y[MAX_PORTS], 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);
/* 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);
}
return i;
return 2 * 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;
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];
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;
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 + 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);
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 i;
return 4 * i;
} else {
fprintf(stderr, "Number of ports must be 2 or 4 for transmit diversity (nof_ports=%d)\n", nof_ports);
return -1;
@ -189,8 +279,8 @@ int predecoding_diversity_zf(cf_t *y, cf_t *ce[MAX_PORTS], cf_t *x[MAX_LAYERS],
}
/* 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) {
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) {
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;

@ -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…
Cancel
Save