2014-12-17 12:52:58 -08:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
* \section COPYRIGHT
|
|
|
|
*
|
2015-05-08 08:05:40 -07:00
|
|
|
* Copyright 2013-2015 The srsLTE Developers. See the
|
2014-12-17 12:52:58 -08:00
|
|
|
* COPYRIGHT file at the top-level directory of this distribution.
|
|
|
|
*
|
|
|
|
* \section LICENSE
|
|
|
|
*
|
2015-03-18 05:31:13 -07:00
|
|
|
* This file is part of the srsLTE library.
|
2014-12-17 12:52:58 -08:00
|
|
|
*
|
2015-03-18 05:31:13 -07:00
|
|
|
* srsLTE is free software: you can redistribute it and/or modify
|
2015-05-08 08:05:40 -07:00
|
|
|
* it under the terms of the GNU Affero General Public License as
|
2014-12-17 12:52:58 -08:00
|
|
|
* published by the Free Software Foundation, either version 3 of
|
|
|
|
* the License, or (at your option) any later version.
|
|
|
|
*
|
2015-03-18 05:31:13 -07:00
|
|
|
* srsLTE is distributed in the hope that it will be useful,
|
2014-11-05 05:19:35 -08:00
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
2015-05-08 08:05:40 -07:00
|
|
|
* GNU Affero General Public License for more details.
|
2014-12-17 12:52:58 -08:00
|
|
|
*
|
2015-05-08 08:05:40 -07:00
|
|
|
* A copy of the GNU Affero General Public License can be found in
|
2014-12-17 12:52:58 -08:00
|
|
|
* the LICENSE file in the top-level directory of this distribution
|
|
|
|
* and at http://www.gnu.org/licenses/.
|
|
|
|
*
|
2014-11-05 05:19:35 -08:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <string.h>
|
2015-03-18 05:31:13 -07:00
|
|
|
#include "srslte/srslte.h"
|
2015-10-05 00:58:44 -07:00
|
|
|
#include "srslte/mex/mexutils.h"
|
2014-11-05 05:19:35 -08:00
|
|
|
|
|
|
|
|
|
|
|
/** MEX function to be called from MATLAB to test the channel estimator
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define CELLID prhs[0]
|
|
|
|
#define PORTS prhs[1]
|
|
|
|
#define INPUT prhs[2]
|
2014-11-11 10:20:09 -08:00
|
|
|
#define FREQ_FILTER prhs[3]
|
|
|
|
#define TIME_FILTER prhs[4]
|
2014-11-15 04:11:41 -08:00
|
|
|
#define NOF_INPUTS 5
|
|
|
|
#define SFIDX prhs[5]
|
2014-11-05 05:19:35 -08:00
|
|
|
|
|
|
|
void help()
|
|
|
|
{
|
|
|
|
mexErrMsgTxt
|
2015-03-18 05:16:28 -07:00
|
|
|
("[estChannel, avg_refs, output] = srslte_chest(cell_id, nof_ports, inputSignal,[sf_idx|freq_filter],"
|
2014-11-13 07:14:22 -08:00
|
|
|
"[time_filter])\n\n"
|
2014-11-05 05:19:35 -08:00
|
|
|
" 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"
|
2014-11-13 07:14:22 -08:00
|
|
|
"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"
|
|
|
|
);
|
2014-11-05 05:19:35 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* the gateway function */
|
|
|
|
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
|
|
|
|
{
|
|
|
|
|
|
|
|
int i;
|
2015-03-18 05:41:50 -07:00
|
|
|
srslte_cell_t cell;
|
|
|
|
srslte_chest_dl_t chest;
|
2015-03-18 11:14:24 -07:00
|
|
|
srslte_precoding_t cheq;
|
2015-03-18 05:59:29 -07:00
|
|
|
cf_t *input_signal = NULL, *output_signal[SRSLTE_MAX_LAYERS];
|
2014-11-15 04:11:41 -08:00
|
|
|
cf_t *output_signal2 = NULL;
|
2015-03-18 05:41:50 -07:00
|
|
|
cf_t *ce[SRSLTE_MAX_PORTS];
|
2014-11-13 07:14:22 -08:00
|
|
|
double *outr0=NULL, *outi0=NULL;
|
|
|
|
double *outr1=NULL, *outi1=NULL;
|
|
|
|
double *outr2=NULL, *outi2=NULL;
|
2014-11-11 10:20:09 -08:00
|
|
|
|
2014-11-05 05:19:35 -08:00
|
|
|
if (!mxIsDouble(CELLID) && mxGetN(CELLID) != 1 &&
|
|
|
|
!mxIsDouble(PORTS) && mxGetN(PORTS) != 1 &&
|
|
|
|
mxGetM(CELLID) != 1) {
|
|
|
|
help();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
cell.id = (uint32_t) *((double*) mxGetPr(CELLID));
|
2015-03-18 05:59:29 -07:00
|
|
|
cell.nof_prb = mxGetM(INPUT)/SRSLTE_NRE;
|
2014-11-05 05:19:35 -08:00
|
|
|
cell.nof_ports = (uint32_t) *((double*) mxGetPr(PORTS));
|
|
|
|
if ((mxGetN(INPUT)%14) == 0) {
|
2015-04-05 07:32:35 -07:00
|
|
|
cell.cp = SRSLTE_CP_NORM;
|
2014-11-05 05:19:35 -08:00
|
|
|
} else if ((mxGetN(INPUT)%12)!=0) {
|
2015-04-05 07:32:35 -07:00
|
|
|
cell.cp = SRSLTE_CP_EXT;
|
2014-11-05 05:19:35 -08:00
|
|
|
} else {
|
2014-11-11 10:20:09 -08:00
|
|
|
mexErrMsgTxt("Invalid number of symbols\n");
|
2014-11-05 05:19:35 -08:00
|
|
|
help();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-03-18 05:41:50 -07:00
|
|
|
if (srslte_chest_dl_init(&chest, cell)) {
|
2014-11-05 05:19:35 -08:00
|
|
|
mexErrMsgTxt("Error initiating channel estimator\n");
|
|
|
|
return;
|
|
|
|
}
|
2014-11-11 10:20:09 -08:00
|
|
|
|
2014-11-05 05:19:35 -08:00
|
|
|
int nsubframes;
|
2015-04-05 07:32:35 -07:00
|
|
|
if (cell.cp == SRSLTE_CP_NORM) {
|
2014-11-05 05:19:35 -08:00
|
|
|
nsubframes = mxGetN(INPUT)/14;
|
|
|
|
} else {
|
|
|
|
nsubframes = mxGetN(INPUT)/12;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t sf_idx=0;
|
|
|
|
if (nsubframes == 1) {
|
|
|
|
if (nrhs != NOF_INPUTS+1) {
|
2014-11-11 10:20:09 -08:00
|
|
|
mexErrMsgTxt("Received 1 subframe. Need to provide subframe index.\n");
|
2014-11-05 05:19:35 -08:00
|
|
|
help();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
sf_idx = (uint32_t) *((double*) mxGetPr(SFIDX));
|
2015-05-26 02:48:04 -07:00
|
|
|
}
|
2014-11-11 10:20:09 -08:00
|
|
|
|
2015-05-26 02:48:04 -07:00
|
|
|
if (nrhs > 5) {
|
|
|
|
uint32_t filter_len = 0;
|
|
|
|
float *filter;
|
|
|
|
double *f;
|
|
|
|
|
|
|
|
filter_len = mxGetNumberOfElements(FREQ_FILTER);
|
|
|
|
filter = malloc(sizeof(float) * filter_len);
|
|
|
|
f = (double*) mxGetPr(FREQ_FILTER);
|
|
|
|
for (i=0;i<filter_len;i++) {
|
|
|
|
filter[i] = (float) f[i];
|
|
|
|
}
|
2014-11-15 04:11:41 -08:00
|
|
|
|
2015-05-26 02:48:04 -07:00
|
|
|
srslte_chest_dl_set_filter_freq(&chest, filter, filter_len);
|
2014-11-15 04:11:41 -08:00
|
|
|
|
2015-05-26 02:48:04 -07:00
|
|
|
filter_len = mxGetNumberOfElements(TIME_FILTER);
|
|
|
|
filter = malloc(sizeof(float) * filter_len);
|
|
|
|
f = (double*) mxGetPr(TIME_FILTER);
|
|
|
|
for (i=0;i<filter_len;i++) {
|
|
|
|
filter[i] = (float) f[i];
|
|
|
|
}
|
|
|
|
srslte_chest_dl_set_filter_time(&chest, filter, filter_len);
|
|
|
|
}
|
2014-11-15 04:11:41 -08:00
|
|
|
|
2014-11-11 10:20:09 -08:00
|
|
|
|
2014-11-05 05:19:35 -08:00
|
|
|
double *inr=(double *)mxGetPr(INPUT);
|
|
|
|
double *ini=(double *)mxGetPi(INPUT);
|
|
|
|
|
|
|
|
/** Allocate input buffers */
|
2015-03-18 05:59:29 -07:00
|
|
|
int nof_re = 2*SRSLTE_CP_NSYMB(cell.cp)*cell.nof_prb*SRSLTE_NRE;
|
2015-03-18 05:41:50 -07:00
|
|
|
for (i=0;i<SRSLTE_MAX_PORTS;i++) {
|
2015-03-18 11:14:24 -07:00
|
|
|
ce[i] = srslte_vec_malloc(nof_re * sizeof(cf_t));
|
2014-11-05 05:19:35 -08:00
|
|
|
}
|
2015-03-18 11:14:24 -07:00
|
|
|
input_signal = srslte_vec_malloc(nof_re * sizeof(cf_t));
|
2015-03-18 05:41:50 -07:00
|
|
|
for (i=0;i<SRSLTE_MAX_PORTS;i++) {
|
2015-03-18 11:14:24 -07:00
|
|
|
output_signal[i] = srslte_vec_malloc(nof_re * sizeof(cf_t));
|
2014-11-15 04:11:41 -08:00
|
|
|
}
|
2015-03-18 11:14:24 -07:00
|
|
|
output_signal2 = srslte_vec_malloc(nof_re * sizeof(cf_t));
|
2014-11-13 07:14:22 -08:00
|
|
|
|
2015-03-18 11:14:24 -07:00
|
|
|
srslte_precoding_init(&cheq, nof_re);
|
2014-11-13 07:14:22 -08:00
|
|
|
|
2014-11-05 05:19:35 -08:00
|
|
|
/* Create output values */
|
|
|
|
if (nlhs >= 1) {
|
2014-11-15 04:11:41 -08:00
|
|
|
plhs[0] = mxCreateDoubleMatrix(nof_re * nsubframes, cell.nof_ports, mxCOMPLEX);
|
2014-11-05 05:19:35 -08:00
|
|
|
outr0 = mxGetPr(plhs[0]);
|
|
|
|
outi0 = mxGetPi(plhs[0]);
|
|
|
|
}
|
2014-11-11 10:20:09 -08:00
|
|
|
if (nlhs >= 2) {
|
2015-03-18 05:41:50 -07:00
|
|
|
plhs[1] = mxCreateDoubleMatrix(SRSLTE_REFSIGNAL_MAX_NUM_SF(cell.nof_prb)*nsubframes, cell.nof_ports, mxCOMPLEX);
|
2014-11-05 05:19:35 -08:00
|
|
|
outr1 = mxGetPr(plhs[1]);
|
|
|
|
outi1 = mxGetPi(plhs[1]);
|
|
|
|
}
|
2014-11-13 07:14:22 -08:00
|
|
|
if (nlhs >= 3) {
|
2014-11-15 04:11:41 -08:00
|
|
|
plhs[2] = mxCreateDoubleMatrix(nof_re * nsubframes, 1, mxCOMPLEX);
|
2014-11-13 07:14:22 -08:00
|
|
|
outr2 = mxGetPr(plhs[2]);
|
|
|
|
outi2 = mxGetPi(plhs[2]);
|
|
|
|
}
|
2014-12-01 13:15:32 -08:00
|
|
|
|
2014-11-05 05:19:35 -08:00
|
|
|
for (int sf=0;sf<nsubframes;sf++) {
|
|
|
|
/* Convert input to C complex type */
|
|
|
|
for (i=0;i<nof_re;i++) {
|
|
|
|
__real__ input_signal[i] = (float) *inr;
|
|
|
|
if (ini) {
|
|
|
|
__imag__ input_signal[i] = (float) *ini;
|
|
|
|
}
|
|
|
|
inr++;
|
|
|
|
ini++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nsubframes != 1) {
|
|
|
|
sf_idx = sf%10;
|
|
|
|
}
|
|
|
|
|
2015-03-18 05:41:50 -07:00
|
|
|
if (srslte_chest_dl_estimate(&chest, input_signal, ce, sf_idx)) {
|
2014-11-05 05:19:35 -08:00
|
|
|
mexErrMsgTxt("Error running channel estimator\n");
|
|
|
|
return;
|
2014-11-13 07:14:22 -08:00
|
|
|
}
|
2015-01-17 21:33:28 -08:00
|
|
|
|
2014-11-15 04:11:41 -08:00
|
|
|
if (cell.nof_ports == 1) {
|
2015-03-18 11:14:24 -07:00
|
|
|
srslte_predecoding_single(&cheq, input_signal, ce[0], output_signal2, nof_re, srslte_chest_dl_get_noise_estimate(&chest));
|
2014-11-15 04:11:41 -08:00
|
|
|
} else {
|
2015-03-18 11:14:24 -07:00
|
|
|
srslte_predecoding_diversity(&cheq, input_signal, ce, output_signal, cell.nof_ports, nof_re, srslte_chest_dl_get_noise_estimate(&chest));
|
2015-03-18 08:05:38 -07:00
|
|
|
srslte_layerdemap_diversity(output_signal, output_signal2, cell.nof_ports, nof_re/cell.nof_ports);
|
2014-11-15 04:11:41 -08:00
|
|
|
}
|
2014-11-11 10:20:09 -08:00
|
|
|
|
2014-11-05 05:19:35 -08:00
|
|
|
if (nlhs >= 1) {
|
2014-11-15 04:11:41 -08:00
|
|
|
for (int j=0;j<cell.nof_ports;j++) {
|
|
|
|
for (i=0;i<nof_re;i++) {
|
|
|
|
*outr0 = (double) crealf(ce[j][i]);
|
|
|
|
if (outi0) {
|
|
|
|
*outi0 = (double) cimagf(ce[j][i]);
|
|
|
|
}
|
|
|
|
outr0++;
|
|
|
|
outi0++;
|
|
|
|
}
|
|
|
|
}
|
2014-11-05 05:19:35 -08:00
|
|
|
}
|
2014-11-11 10:20:09 -08:00
|
|
|
if (nlhs >= 2) {
|
2014-11-05 05:19:35 -08:00
|
|
|
for (int j=0;j<cell.nof_ports;j++) {
|
2015-03-18 05:41:50 -07:00
|
|
|
for (i=0;i<SRSLTE_REFSIGNAL_NUM_SF(cell.nof_prb,j);i++) {
|
2014-11-11 10:20:09 -08:00
|
|
|
*outr1 = (double) crealf(chest.pilot_estimates_average[j][i]);
|
2014-11-05 05:19:35 -08:00
|
|
|
if (outi1) {
|
2014-11-11 10:20:09 -08:00
|
|
|
*outi1 = (double) cimagf(chest.pilot_estimates_average[j][i]);
|
2014-11-05 05:19:35 -08:00
|
|
|
}
|
|
|
|
outr1++;
|
|
|
|
outi1++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-11-13 07:14:22 -08:00
|
|
|
if (nlhs >= 3) {
|
|
|
|
for (i=0;i<nof_re;i++) {
|
2014-11-15 04:11:41 -08:00
|
|
|
*outr2 = (double) crealf(output_signal2[i]);
|
2014-11-13 07:14:22 -08:00
|
|
|
if (outi2) {
|
2014-11-15 04:11:41 -08:00
|
|
|
*outi2 = (double) cimagf(output_signal2[i]);
|
2014-11-13 07:14:22 -08:00
|
|
|
}
|
|
|
|
outr2++;
|
|
|
|
outi2++;
|
|
|
|
}
|
|
|
|
}
|
2014-11-05 05:19:35 -08:00
|
|
|
}
|
2014-12-01 13:15:32 -08:00
|
|
|
|
|
|
|
if (nlhs >= 4) {
|
2015-05-19 11:22:58 -07:00
|
|
|
plhs[3] = mxCreateDoubleScalar(srslte_chest_dl_get_noise_estimate(&chest));
|
2014-12-01 13:15:32 -08:00
|
|
|
}
|
2015-01-17 21:33:28 -08:00
|
|
|
if (nlhs >= 5) {
|
2015-05-19 11:22:58 -07:00
|
|
|
plhs[4] = mxCreateDoubleScalar(srslte_chest_dl_get_rsrp(&chest));
|
2015-01-17 21:33:28 -08:00
|
|
|
}
|
|
|
|
|
2015-03-18 05:41:50 -07:00
|
|
|
srslte_chest_dl_free(&chest);
|
2015-03-18 11:14:24 -07:00
|
|
|
srslte_precoding_free(&cheq);
|
2014-12-01 13:15:32 -08:00
|
|
|
|
2014-11-05 05:19:35 -08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|