mirror of https://github.com/pvnis/srsRAN_4G.git
Added UL SCH interleaver. Fixed issue with rate matching and filler bits
parent
9a614ec9d1
commit
a47461a6f5
@ -0,0 +1,78 @@
|
||||
/**
|
||||
*
|
||||
* \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 HARQ_
|
||||
#define HARQ_
|
||||
|
||||
#include "liblte/config.h"
|
||||
#include "liblte/phy/common/phy_common.h"
|
||||
#include "liblte/phy/phch/ra.h"
|
||||
|
||||
|
||||
struct cb_segm {
|
||||
uint32_t F;
|
||||
uint32_t C;
|
||||
uint32_t K1;
|
||||
uint32_t K2;
|
||||
uint32_t C1;
|
||||
uint32_t C2;
|
||||
};
|
||||
|
||||
typedef struct LIBLTE_API {
|
||||
ra_mcs_t mcs;
|
||||
ra_prb_t prb_alloc;
|
||||
lte_cell_t cell;
|
||||
|
||||
uint32_t N_symb_ul; // Number of symbols for PUSCH transmission
|
||||
uint32_t nof_prb_pusch_init; // Initial resource allocation for PUSCH.
|
||||
|
||||
uint32_t max_cb;
|
||||
uint32_t w_buff_size;
|
||||
float **pdsch_w_buff_f;
|
||||
uint8_t **pdsch_w_buff_c;
|
||||
|
||||
struct cb_segm cb_segm;
|
||||
|
||||
} harq_t;
|
||||
|
||||
LIBLTE_API int harq_init(harq_t * q,
|
||||
lte_cell_t cell);
|
||||
|
||||
LIBLTE_API int harq_setup(harq_t *p,
|
||||
ra_mcs_t mcs,
|
||||
ra_prb_t *prb_alloc);
|
||||
|
||||
LIBLTE_API void harq_reset(harq_t *p);
|
||||
|
||||
LIBLTE_API void harq_free(harq_t *p);
|
||||
|
||||
LIBLTE_API int codeblock_segmentation(struct cb_segm *s,
|
||||
uint32_t tbs);
|
||||
|
||||
|
||||
#endif
|
@ -0,0 +1,120 @@
|
||||
/**
|
||||
*
|
||||
* \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 PUCH_
|
||||
#define PUSCH_
|
||||
|
||||
#include "liblte/config.h"
|
||||
#include "liblte/phy/common/phy_common.h"
|
||||
#include "liblte/phy/mimo/precoding.h"
|
||||
#include "liblte/phy/mimo/layermap.h"
|
||||
#include "liblte/phy/modem/mod.h"
|
||||
#include "liblte/phy/modem/demod_soft.h"
|
||||
#include "liblte/phy/scrambling/scrambling.h"
|
||||
#include "liblte/phy/phch/regs.h"
|
||||
#include "liblte/phy/phch/sch.h"
|
||||
#include "liblte/phy/phch/harq.h"
|
||||
|
||||
#define TDEC_MAX_ITERATIONS 5
|
||||
|
||||
typedef _Complex float cf_t;
|
||||
|
||||
/* PDSCH object */
|
||||
typedef struct LIBLTE_API {
|
||||
lte_cell_t cell;
|
||||
|
||||
uint32_t max_symbols;
|
||||
bool rnti_is_set;
|
||||
uint16_t rnti;
|
||||
|
||||
/* buffers */
|
||||
// void buffers are shared for tx and rx
|
||||
cf_t *ce[MAX_PORTS];
|
||||
cf_t *pusch_symbols[MAX_PORTS];
|
||||
cf_t *pusch_x[MAX_PORTS];
|
||||
cf_t *pusch_d;
|
||||
void *pusch_e;
|
||||
|
||||
uint8_t *pusch_q_ri;
|
||||
uint8_t *pusch_q_ack;
|
||||
|
||||
/* tx & rx objects */
|
||||
modem_table_t mod[4];
|
||||
demod_soft_t demod;
|
||||
sequence_t seq_pusch[NSUBFRAMES_X_FRAME];
|
||||
|
||||
sch_t dl_sch;
|
||||
|
||||
}pusch_t;
|
||||
|
||||
|
||||
|
||||
|
||||
LIBLTE_API int pusch_init(pusch_t *q,
|
||||
lte_cell_t cell);
|
||||
|
||||
LIBLTE_API void pusch_free(pusch_t *q);
|
||||
|
||||
LIBLTE_API int pusch_set_rnti(pusch_t *q,
|
||||
uint16_t rnti);
|
||||
|
||||
LIBLTE_API int pusch_encode(pusch_t *q,
|
||||
uint8_t *data,
|
||||
cf_t *sf_symbols[MAX_PORTS],
|
||||
uint32_t nsubframe,
|
||||
harq_t *harq_process,
|
||||
uint32_t rv_idx);
|
||||
|
||||
LIBLTE_API int pusch_uci_encode(pusch_t *q,
|
||||
uint8_t *data,
|
||||
uci_data_t uci_data,
|
||||
cf_t *sf_symbols[MAX_PORTS],
|
||||
uint32_t subframe,
|
||||
harq_t *harq_process,
|
||||
uint32_t rv_idx);
|
||||
|
||||
LIBLTE_API int pusch_decode(pusch_t *q,
|
||||
cf_t *sf_symbols,
|
||||
cf_t *ce[MAX_PORTS],
|
||||
float noise_estimate,
|
||||
uint8_t *data,
|
||||
uint32_t nsubframe,
|
||||
harq_t *harq_process,
|
||||
uint32_t rv_idx);
|
||||
|
||||
LIBLTE_API float pusch_average_noi(pusch_t *q);
|
||||
|
||||
LIBLTE_API uint32_t pusch_last_noi(pusch_t *q);
|
||||
|
||||
LIBLTE_API int pusch_get(pusch_t *q,
|
||||
cf_t *sf_symbols,
|
||||
cf_t *pusch_symbols,
|
||||
ra_prb_t *prb_alloc,
|
||||
uint32_t subframe);
|
||||
|
||||
#endif
|
@ -0,0 +1,112 @@
|
||||
/**
|
||||
*
|
||||
* \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 SCH_
|
||||
#define SCH_
|
||||
|
||||
#include "liblte/config.h"
|
||||
#include "liblte/phy/common/phy_common.h"
|
||||
#include "liblte/phy/fec/rm_turbo.h"
|
||||
#include "liblte/phy/fec/turbocoder.h"
|
||||
#include "liblte/phy/fec/turbodecoder.h"
|
||||
#include "liblte/phy/fec/crc.h"
|
||||
#include "liblte/phy/phch/harq.h"
|
||||
#include "liblte/phy/phch/uci.h"
|
||||
|
||||
#define TDEC_MAX_ITERATIONS 5
|
||||
|
||||
|
||||
#ifndef RX_NULL
|
||||
#define RX_NULL 10000
|
||||
#endif
|
||||
|
||||
#ifndef TX_NULL
|
||||
#define TX_NULL 100
|
||||
#endif
|
||||
|
||||
/* DL-SCH AND UL-SCH common functions */
|
||||
typedef struct LIBLTE_API {
|
||||
|
||||
uint32_t nof_iterations;
|
||||
float average_nof_iterations;
|
||||
|
||||
/* buffers */
|
||||
uint8_t *cb_in;
|
||||
void *cb_out;
|
||||
void *pdsch_e;
|
||||
|
||||
tcod_t encoder;
|
||||
tdec_t decoder;
|
||||
crc_t crc_tb;
|
||||
crc_t crc_cb;
|
||||
} sch_t;
|
||||
|
||||
LIBLTE_API int sch_init(sch_t *q);
|
||||
|
||||
LIBLTE_API void sch_free(sch_t *q);
|
||||
|
||||
|
||||
LIBLTE_API float sch_average_noi(sch_t *q);
|
||||
|
||||
LIBLTE_API uint32_t sch_last_noi(sch_t *q);
|
||||
|
||||
LIBLTE_API int dlsch_encode(sch_t *q,
|
||||
uint8_t *data,
|
||||
uint8_t *e_bits,
|
||||
uint32_t tbs,
|
||||
uint32_t nb_e,
|
||||
harq_t *harq_process,
|
||||
uint32_t rv_idx);
|
||||
|
||||
LIBLTE_API int dlsch_decode(sch_t *q,
|
||||
float *e_bits,
|
||||
uint8_t *data,
|
||||
uint32_t tbs,
|
||||
uint32_t nb_e,
|
||||
harq_t *harq_process,
|
||||
uint32_t rv_idx);
|
||||
|
||||
LIBLTE_API int ulsch_encode(sch_t *q,
|
||||
uint8_t *data,
|
||||
uci_data_t uci_data,
|
||||
uint8_t *q_bits,
|
||||
uint32_t nb_q,
|
||||
uint8_t *q_bits_ack,
|
||||
uint8_t *q_bits_ri,
|
||||
harq_t *harq_process,
|
||||
uint32_t rv_idx);
|
||||
|
||||
LIBLTE_API int ulsch_decode(sch_t *q,
|
||||
float *e_bits,
|
||||
uint8_t *data,
|
||||
uint32_t tbs,
|
||||
uint32_t nb_e,
|
||||
harq_t *harq_process,
|
||||
uint32_t rv_idx);
|
||||
|
||||
#endif
|
@ -0,0 +1,60 @@
|
||||
/**
|
||||
*
|
||||
* \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 UCI_
|
||||
#define UCI_
|
||||
|
||||
#include "liblte/config.h"
|
||||
#include "liblte/phy/common/phy_common.h"
|
||||
#include "liblte/phy/phch/harq.h"
|
||||
|
||||
typedef struct LIBLTE_API {
|
||||
uint8_t *uci_cqi;
|
||||
uint32_t uci_cqi_len;
|
||||
float beta_cqi;
|
||||
uint8_t uci_ri; // Only 1-bit supported for RI
|
||||
uint32_t uci_ri_len;
|
||||
float beta_ri;
|
||||
uint8_t uci_ack; // Only 1-bit supported for HARQ
|
||||
uint32_t uci_ack_len;
|
||||
float beta_ack;
|
||||
} uci_data_t;
|
||||
|
||||
|
||||
LIBLTE_API int uci_encode_cqi(uint8_t *data,
|
||||
uint8_t *e_bits,
|
||||
uint32_t tbs,
|
||||
uint32_t nb_e);
|
||||
|
||||
/* Encode UCI RI and HARQ ACK/NACK bits */
|
||||
LIBLTE_API uint32_t uci_encode_ri_ack(uint8_t data,
|
||||
float beta,
|
||||
uint8_t q_bits[6],
|
||||
harq_t *harq_process);
|
||||
|
||||
#endif
|
@ -0,0 +1,100 @@
|
||||
/**
|
||||
*
|
||||
* \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 <string.h>
|
||||
#include "liblte/phy/phy.h"
|
||||
#include "liblte/mex/mexutils.h"
|
||||
|
||||
/** MEX function to be called from MATLAB to test the channel estimator
|
||||
*/
|
||||
|
||||
#define INPUT prhs[0]
|
||||
#define TRBLKLEN prhs[1]
|
||||
#define RV prhs[2]
|
||||
#define NOF_INPUTS 3
|
||||
|
||||
|
||||
void help()
|
||||
{
|
||||
mexErrMsgTxt
|
||||
("[out] = liblte_rm_turbo_rx(in, trblkin, rv)\n\n");
|
||||
}
|
||||
|
||||
/* the gateway function */
|
||||
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
|
||||
{
|
||||
|
||||
float *input;
|
||||
float *output;
|
||||
uint32_t in_len, trblklen, cblen, rvidx;
|
||||
float *w_buff_f;
|
||||
|
||||
if (nrhs != NOF_INPUTS) {
|
||||
help();
|
||||
return;
|
||||
}
|
||||
|
||||
// Read input symbols
|
||||
in_len = mexutils_read_f(INPUT, &input);
|
||||
if (in_len < 0) {
|
||||
mexErrMsgTxt("Error reading input bits\n");
|
||||
return;
|
||||
}
|
||||
|
||||
trblklen = (uint32_t) mxGetScalar(TRBLKLEN);
|
||||
rvidx = (uint32_t) mxGetScalar(RV);
|
||||
|
||||
struct cb_segm cbsegm;
|
||||
codeblock_segmentation(&cbsegm, trblklen);
|
||||
cblen = 3*cbsegm.K1+12;
|
||||
|
||||
w_buff_f = calloc(1,sizeof(float) * cblen * 10);
|
||||
if (!w_buff_f) {
|
||||
perror("malloc");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
// allocate memory for output bits
|
||||
output = vec_malloc(cblen * sizeof(float));
|
||||
|
||||
rm_turbo_rx(w_buff_f, cblen * 10, input, in_len, output, cblen,
|
||||
rvidx,cbsegm.F);
|
||||
|
||||
if (nlhs >= 1) {
|
||||
mexutils_write_f(output, &plhs[0], cblen, 1);
|
||||
}
|
||||
if (nlhs >= 2) {
|
||||
mexutils_write_f(input, &plhs[1], in_len, 1);
|
||||
}
|
||||
|
||||
free(input);
|
||||
free(output);
|
||||
free(w_buff_f);
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -0,0 +1,200 @@
|
||||
/**
|
||||
*
|
||||
* \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 <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "liblte/phy/common/phy_common.h"
|
||||
#include "liblte/phy/phch/ra.h"
|
||||
#include "liblte/phy/phch/harq.h"
|
||||
#include "liblte/phy/fec/turbodecoder.h"
|
||||
#include "liblte/phy/utils/vector.h"
|
||||
#include "liblte/phy/utils/debug.h"
|
||||
|
||||
|
||||
#define MAX_PDSCH_RE(cp) (2 * CP_NSYMB(cp) * 12)
|
||||
|
||||
/* Calculate Codeblock Segmentation as in Section 5.1.2 of 36.212 */
|
||||
int codeblock_segmentation(struct cb_segm *s, uint32_t tbs) {
|
||||
uint32_t Bp, B, idx1;
|
||||
int ret;
|
||||
|
||||
B = tbs + 24;
|
||||
|
||||
/* Calculate CB sizes */
|
||||
if (B <= MAX_LONG_CB) {
|
||||
s->C = 1;
|
||||
Bp = B;
|
||||
} else {
|
||||
s->C = (uint32_t) ceilf((float) B / (MAX_LONG_CB - 24));
|
||||
Bp = B + 24 * s->C;
|
||||
}
|
||||
ret = lte_find_cb_index((Bp-1) / s->C + 1);
|
||||
if (ret != LIBLTE_ERROR) {
|
||||
idx1 = (uint32_t) ret;
|
||||
ret = lte_cb_size(idx1);
|
||||
if (ret != LIBLTE_ERROR) {
|
||||
s->K1 = (uint32_t) ret;
|
||||
if (idx1 > 0) {
|
||||
ret = lte_cb_size(idx1 - 1);
|
||||
}
|
||||
if (ret != LIBLTE_ERROR) {
|
||||
if (s->C == 1) {
|
||||
s->K2 = 0;
|
||||
s->C2 = 0;
|
||||
s->C1 = 1;
|
||||
} else {
|
||||
s->K2 = (uint32_t) ret;
|
||||
s->C2 = (s->C * s->K1 - Bp) / (s->K1 - s->K2);
|
||||
s->C1 = s->C - s->C2;
|
||||
}
|
||||
s->F = s->C1 * s->K1 + s->C2 * s->K2 - Bp;
|
||||
INFO("CB Segmentation: TBS: %d, C=%d, C+=%d K+=%d, C-=%d, K-=%d, F=%d, Bp=%d\n",
|
||||
tbs, s->C, s->C1, s->K1, s->C2, s->K2, s->F, Bp);
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int harq_init(harq_t *q, lte_cell_t cell) {
|
||||
int ret = LIBLTE_ERROR_INVALID_INPUTS;
|
||||
|
||||
if (q != NULL) {
|
||||
uint32_t i;
|
||||
bzero(q, sizeof(harq_t));
|
||||
|
||||
memcpy(&q->cell, &cell, sizeof(lte_cell_t));
|
||||
|
||||
ret = ra_tbs_from_idx(26, cell.nof_prb);
|
||||
if (ret != LIBLTE_ERROR) {
|
||||
q->max_cb = (uint32_t) ret / (MAX_LONG_CB - 24) + 1;
|
||||
|
||||
q->pdsch_w_buff_f = malloc(sizeof(float*) * q->max_cb);
|
||||
if (!q->pdsch_w_buff_f) {
|
||||
perror("malloc");
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
|
||||
q->pdsch_w_buff_c = malloc(sizeof(uint8_t*) * q->max_cb);
|
||||
if (!q->pdsch_w_buff_c) {
|
||||
perror("malloc");
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
|
||||
// FIXME: Use HARQ buffer limitation based on UE category
|
||||
q->w_buff_size = cell.nof_prb * MAX_PDSCH_RE(cell.cp) * 6 * 10;
|
||||
for (i=0;i<q->max_cb;i++) {
|
||||
q->pdsch_w_buff_f[i] = vec_malloc(sizeof(float) * q->w_buff_size);
|
||||
if (!q->pdsch_w_buff_f[i]) {
|
||||
perror("malloc");
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
q->pdsch_w_buff_c[i] = vec_malloc(sizeof(uint8_t) * q->w_buff_size);
|
||||
if (!q->pdsch_w_buff_c[i]) {
|
||||
perror("malloc");
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
}
|
||||
ret = LIBLTE_SUCCESS;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void harq_free(harq_t *q) {
|
||||
if (q) {
|
||||
uint32_t i;
|
||||
if (q->pdsch_w_buff_f) {
|
||||
for (i=0;i<q->max_cb;i++) {
|
||||
if (q->pdsch_w_buff_f[i]) {
|
||||
free(q->pdsch_w_buff_f[i]);
|
||||
}
|
||||
}
|
||||
free(q->pdsch_w_buff_f);
|
||||
}
|
||||
if (q->pdsch_w_buff_c) {
|
||||
for (i=0;i<q->max_cb;i++) {
|
||||
if (q->pdsch_w_buff_c[i]) {
|
||||
free(q->pdsch_w_buff_c[i]);
|
||||
}
|
||||
}
|
||||
free(q->pdsch_w_buff_c);
|
||||
}
|
||||
bzero(q, sizeof(harq_t));
|
||||
}
|
||||
}
|
||||
|
||||
void harq_reset(harq_t *q) {
|
||||
int i;
|
||||
if (q->pdsch_w_buff_f) {
|
||||
for (i=0;i<q->max_cb;i++) {
|
||||
if (q->pdsch_w_buff_f[i]) {
|
||||
bzero(q->pdsch_w_buff_f[i], sizeof(float) * q->w_buff_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (q->pdsch_w_buff_c) {
|
||||
for (i=0;i<q->max_cb;i++) {
|
||||
if (q->pdsch_w_buff_c[i]) {
|
||||
bzero(q->pdsch_w_buff_c[i], sizeof(uint8_t) * q->w_buff_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
bzero(&q->mcs, sizeof(ra_mcs_t));
|
||||
bzero(&q->cb_segm, sizeof(struct cb_segm));
|
||||
bzero(&q->prb_alloc, sizeof(ra_prb_t));
|
||||
}
|
||||
|
||||
int harq_setup(harq_t *q, ra_mcs_t mcs, ra_prb_t *prb_alloc) {
|
||||
int ret = LIBLTE_ERROR_INVALID_INPUTS;
|
||||
|
||||
if (q != NULL &&
|
||||
mcs.tbs > 0)
|
||||
{
|
||||
q->mcs = mcs;
|
||||
memcpy(&q->prb_alloc, prb_alloc, sizeof(ra_prb_t));
|
||||
|
||||
q->N_symb_ul = 2*(CP_NSYMB(q->cell.cp)-1);
|
||||
q->nof_prb_pusch_init = q->prb_alloc.slot[0].nof_prb;
|
||||
|
||||
codeblock_segmentation(&q->cb_segm, mcs.tbs);
|
||||
if (q->cb_segm.C > q->max_cb) {
|
||||
fprintf(stderr, "Codeblock segmentation returned more CBs (%d) than allocated (%d)\n",
|
||||
q->cb_segm.C, q->max_cb);
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
ret = LIBLTE_SUCCESS;
|
||||
}
|
||||
return ret;
|
||||
}
|
@ -0,0 +1,375 @@
|
||||
/**
|
||||
*
|
||||
* \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 <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "prb.h"
|
||||
#include "liblte/phy/phch/pusch.h"
|
||||
#include "liblte/phy/phch/uci.h"
|
||||
#include "liblte/phy/common/phy_common.h"
|
||||
#include "liblte/phy/utils/bit.h"
|
||||
#include "liblte/phy/utils/debug.h"
|
||||
#include "liblte/phy/utils/vector.h"
|
||||
|
||||
|
||||
#define MAX_PUSCH_RE(cp) (2 * CP_NSYMB(cp) * 12)
|
||||
|
||||
|
||||
|
||||
const static lte_mod_t modulations[4] =
|
||||
{ LTE_BPSK, LTE_QPSK, LTE_QAM16, LTE_QAM64 };
|
||||
|
||||
//#define DEBUG_IDX
|
||||
|
||||
#ifdef DEBUG_IDX
|
||||
cf_t *offset_original=NULL;
|
||||
extern int indices[100000];
|
||||
extern int indices_ptr;
|
||||
#endif
|
||||
|
||||
|
||||
int pusch_cp(pusch_t *q, cf_t *input, cf_t *output, ra_prb_t *prb_alloc,
|
||||
uint32_t nsubframe, bool put)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts PUSCH in slot number 1
|
||||
*
|
||||
* Returns the number of symbols written to sf_symbols
|
||||
*
|
||||
* 36.211 10.3 section 6.3.5
|
||||
*/
|
||||
int pusch_put(pusch_t *q, cf_t *pusch_symbols, cf_t *sf_symbols,
|
||||
ra_prb_t *prb_alloc, uint32_t subframe) {
|
||||
return pusch_cp(q, pusch_symbols, sf_symbols, prb_alloc, subframe, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts PUSCH from slot number 1
|
||||
*
|
||||
* Returns the number of symbols written to PUSCH
|
||||
*
|
||||
* 36.211 10.3 section 6.3.5
|
||||
*/
|
||||
int pusch_get(pusch_t *q, cf_t *sf_symbols, cf_t *pusch_symbols,
|
||||
ra_prb_t *prb_alloc, uint32_t subframe) {
|
||||
return pusch_cp(q, sf_symbols, pusch_symbols, prb_alloc, subframe, false);
|
||||
}
|
||||
|
||||
/** Initializes the PDCCH transmitter and receiver */
|
||||
int pusch_init(pusch_t *q, lte_cell_t cell) {
|
||||
int ret = LIBLTE_ERROR_INVALID_INPUTS;
|
||||
int i;
|
||||
|
||||
if (q != NULL &&
|
||||
lte_cell_isvalid(&cell))
|
||||
{
|
||||
|
||||
bzero(q, sizeof(pusch_t));
|
||||
ret = LIBLTE_ERROR;
|
||||
|
||||
q->cell = cell;
|
||||
q->max_symbols = q->cell.nof_prb * MAX_PUSCH_RE(q->cell.cp);
|
||||
|
||||
INFO("Init PUSCH: %d ports %d PRBs, max_symbols: %d\n", q->cell.nof_ports,
|
||||
q->cell.nof_prb, q->max_symbols);
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
if (modem_table_lte(&q->mod[i], modulations[i], true)) {
|
||||
goto clean;
|
||||
}
|
||||
}
|
||||
|
||||
demod_soft_init(&q->demod, q->max_symbols);
|
||||
demod_soft_alg_set(&q->demod, APPROX);
|
||||
|
||||
sch_init(&q->dl_sch);
|
||||
|
||||
q->rnti_is_set = false;
|
||||
|
||||
// Allocate floats for reception (LLRs)
|
||||
q->pusch_e = malloc(sizeof(float) * q->max_symbols * lte_mod_bits_x_symbol(LTE_QAM64));
|
||||
if (!q->pusch_e) {
|
||||
goto clean;
|
||||
}
|
||||
|
||||
// Allocate buffers for q bits for coded RI and ACK bits
|
||||
q->pusch_q_ack = malloc(sizeof(uint8_t) * 4 * q->cell.nof_prb * lte_mod_bits_x_symbol(LTE_QAM64));
|
||||
if (!q->pusch_q_ack) {
|
||||
goto clean;
|
||||
}
|
||||
q->pusch_q_ri = malloc(sizeof(uint8_t) * 4 * q->cell.nof_prb * lte_mod_bits_x_symbol(LTE_QAM64));
|
||||
if (!q->pusch_q_ri) {
|
||||
goto clean;
|
||||
}
|
||||
|
||||
q->pusch_d = malloc(sizeof(cf_t) * q->max_symbols);
|
||||
if (!q->pusch_d) {
|
||||
goto clean;
|
||||
}
|
||||
|
||||
for (i = 0; i < q->cell.nof_ports; i++) {
|
||||
q->ce[i] = malloc(sizeof(cf_t) * q->max_symbols);
|
||||
if (!q->ce[i]) {
|
||||
goto clean;
|
||||
}
|
||||
q->pusch_x[i] = malloc(sizeof(cf_t) * q->max_symbols);
|
||||
if (!q->pusch_x[i]) {
|
||||
goto clean;
|
||||
}
|
||||
q->pusch_symbols[i] = malloc(sizeof(cf_t) * q->max_symbols);
|
||||
if (!q->pusch_symbols[i]) {
|
||||
goto clean;
|
||||
}
|
||||
}
|
||||
|
||||
ret = LIBLTE_SUCCESS;
|
||||
}
|
||||
clean:
|
||||
if (ret == LIBLTE_ERROR) {
|
||||
pusch_free(q);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void pusch_free(pusch_t *q) {
|
||||
int i;
|
||||
|
||||
if (q->pusch_e) {
|
||||
free(q->pusch_e);
|
||||
}
|
||||
if (q->pusch_d) {
|
||||
free(q->pusch_d);
|
||||
}
|
||||
for (i = 0; i < q->cell.nof_ports; i++) {
|
||||
if (q->ce[i]) {
|
||||
free(q->ce[i]);
|
||||
}
|
||||
if (q->pusch_x[i]) {
|
||||
free(q->pusch_x[i]);
|
||||
}
|
||||
if (q->pusch_symbols[i]) {
|
||||
free(q->pusch_symbols[i]);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < NSUBFRAMES_X_FRAME; i++) {
|
||||
sequence_free(&q->seq_pusch[i]);
|
||||
}
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
modem_table_free(&q->mod[i]);
|
||||
}
|
||||
demod_soft_free(&q->demod);
|
||||
sch_free(&q->dl_sch);
|
||||
|
||||
bzero(q, sizeof(pusch_t));
|
||||
|
||||
}
|
||||
|
||||
int pusch_set_rnti(pusch_t *q, uint16_t rnti) {
|
||||
uint32_t i;
|
||||
|
||||
for (i = 0; i < NSUBFRAMES_X_FRAME; i++) {
|
||||
if (sequence_pusch(&q->seq_pusch[i], rnti, 2 * i, q->cell.id,
|
||||
q->max_symbols * lte_mod_bits_x_symbol(LTE_QAM64))) {
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
}
|
||||
q->rnti_is_set = true;
|
||||
q->rnti = rnti;
|
||||
return LIBLTE_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/** Decodes the PUSCH from the received symbols
|
||||
*/
|
||||
int pusch_decode(pusch_t *q, cf_t *sf_symbols, cf_t *ce[MAX_PORTS], float noise_estimate, uint8_t *data, uint32_t subframe,
|
||||
harq_t *harq_process, uint32_t rv_idx)
|
||||
{
|
||||
|
||||
/* Set pointers for layermapping & precoding */
|
||||
uint32_t i, n;
|
||||
cf_t *x[MAX_LAYERS];
|
||||
uint32_t nof_symbols, nof_bits, nof_bits_e;
|
||||
|
||||
if (q != NULL &&
|
||||
sf_symbols != NULL &&
|
||||
data != NULL &&
|
||||
subframe < 10 &&
|
||||
harq_process != NULL)
|
||||
{
|
||||
|
||||
if (q->rnti_is_set) {
|
||||
nof_bits = harq_process->mcs.tbs;
|
||||
nof_symbols = harq_process->prb_alloc.re_sf[subframe];
|
||||
nof_bits_e = nof_symbols * lte_mod_bits_x_symbol(harq_process->mcs.mod);
|
||||
|
||||
|
||||
INFO("Decoding PUSCH SF: %d, Mod %s, NofBits: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d\n",
|
||||
subframe, lte_mod_string(harq_process->mcs.mod), nof_bits, nof_symbols, nof_bits_e, rv_idx);
|
||||
|
||||
/* number of layers equals number of ports */
|
||||
for (i = 0; i < q->cell.nof_ports; i++) {
|
||||
x[i] = q->pusch_x[i];
|
||||
}
|
||||
memset(&x[q->cell.nof_ports], 0, sizeof(cf_t*) * (MAX_LAYERS - q->cell.nof_ports));
|
||||
|
||||
/* extract symbols */
|
||||
n = pusch_get(q, sf_symbols, q->pusch_symbols[0], &harq_process->prb_alloc, subframe);
|
||||
if (n != nof_symbols) {
|
||||
fprintf(stderr, "Error expecting %d symbols but got %d\n", nof_symbols, n);
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
|
||||
/* extract channel estimates */
|
||||
for (i = 0; i < q->cell.nof_ports; i++) {
|
||||
n = pusch_get(q, ce[i], q->ce[i], &harq_process->prb_alloc, subframe);
|
||||
if (n != nof_symbols) {
|
||||
fprintf(stderr, "Error expecting %d symbols but got %d\n", nof_symbols, n);
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/* demodulate symbols
|
||||
* The MAX-log-MAP algorithm used in turbo decoding is unsensitive to SNR estimation,
|
||||
* thus we don't need tot set it in the LLRs normalization
|
||||
*/
|
||||
demod_soft_sigma_set(&q->demod, sqrt(0.5));
|
||||
demod_soft_table_set(&q->demod, &q->mod[harq_process->mcs.mod]);
|
||||
demod_soft_demodulate(&q->demod, q->pusch_d, q->pusch_e, nof_symbols);
|
||||
|
||||
/* descramble */
|
||||
scrambling_f_offset(&q->seq_pusch[subframe], q->pusch_e, 0, nof_bits_e);
|
||||
|
||||
return ulsch_decode(&q->dl_sch, q->pusch_e, data, nof_bits, nof_bits_e, harq_process, rv_idx);
|
||||
} else {
|
||||
fprintf(stderr, "Must call pusch_set_rnti() before calling pusch_decode()\n");
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
|
||||
} else {
|
||||
return LIBLTE_ERROR_INVALID_INPUTS;
|
||||
}
|
||||
}
|
||||
|
||||
int pusch_encode(pusch_t *q, uint8_t *data, cf_t *sf_symbols[MAX_PORTS], uint32_t subframe,
|
||||
harq_t *harq_process, uint32_t rv_idx)
|
||||
{
|
||||
uci_data_t uci_data;
|
||||
bzero(&uci_data, sizeof(uci_data_t));
|
||||
return pusch_uci_encode(q, data, uci_data, sf_symbols, subframe, harq_process, rv_idx);
|
||||
}
|
||||
|
||||
/** Converts the PUSCH data bits to symbols mapped to the slot ready for transmission
|
||||
*/
|
||||
int pusch_uci_encode(pusch_t *q, uint8_t *data, uci_data_t uci_data,
|
||||
cf_t *sf_symbols[MAX_PORTS], uint32_t subframe,
|
||||
harq_t *harq_process, uint32_t rv_idx)
|
||||
{
|
||||
int i;
|
||||
uint32_t nof_symbols, nof_bits_ulsch, nof_bits_e;
|
||||
/* Set pointers for layermapping & precoding */
|
||||
cf_t *x[MAX_LAYERS];
|
||||
int ret = LIBLTE_ERROR_INVALID_INPUTS;
|
||||
|
||||
if (q != NULL &&
|
||||
data != NULL &&
|
||||
subframe < 10 &&
|
||||
harq_process != NULL)
|
||||
{
|
||||
|
||||
if (q->rnti_is_set) {
|
||||
for (i=0;i<q->cell.nof_ports;i++) {
|
||||
if (sf_symbols[i] == NULL) {
|
||||
return LIBLTE_ERROR_INVALID_INPUTS;
|
||||
}
|
||||
}
|
||||
|
||||
nof_bits_ulsch = harq_process->mcs.tbs;
|
||||
nof_symbols = 2*harq_process->prb_alloc.slot[0].nof_prb*RE_X_RB*(CP_NSYMB(q->cell.cp)-1);
|
||||
nof_bits_e = nof_symbols * lte_mod_bits_x_symbol(harq_process->mcs.mod);
|
||||
|
||||
if (harq_process->mcs.tbs == 0) {
|
||||
return LIBLTE_ERROR_INVALID_INPUTS;
|
||||
}
|
||||
|
||||
if (nof_bits_ulsch > nof_bits_e) {
|
||||
fprintf(stderr, "Invalid code rate %.2f\n", (float) nof_bits_ulsch / nof_bits_e);
|
||||
return LIBLTE_ERROR_INVALID_INPUTS;
|
||||
}
|
||||
|
||||
if (nof_symbols > q->max_symbols) {
|
||||
fprintf(stderr,
|
||||
"Error too many RE per subframe (%d). PUSCH configured for %d RE (%d PRB)\n",
|
||||
nof_symbols, q->max_symbols, q->cell.nof_prb);
|
||||
return LIBLTE_ERROR_INVALID_INPUTS;
|
||||
}
|
||||
|
||||
INFO("Encoding PUSCH SF: %d, Mod %s, NofBits: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d\n",
|
||||
subframe, lte_mod_string(harq_process->mcs.mod), nof_bits_ulsch, nof_symbols, nof_bits_e, rv_idx);
|
||||
|
||||
/* number of layers equals number of ports */
|
||||
for (i = 0; i < q->cell.nof_ports; i++) {
|
||||
x[i] = q->pusch_x[i];
|
||||
}
|
||||
memset(&x[q->cell.nof_ports], 0, sizeof(cf_t*) * (MAX_LAYERS - q->cell.nof_ports));
|
||||
|
||||
if (ulsch_encode(&q->dl_sch, data, uci_data, q->pusch_e, nof_bits_e,
|
||||
q->pusch_q_ack, q->pusch_q_ri, harq_process, rv_idx))
|
||||
{
|
||||
fprintf(stderr, "Error encoding TB\n");
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
|
||||
scrambling_b_offset_pusch(&q->seq_pusch[subframe], (uint8_t*) q->pusch_e, 0, nof_bits_e);
|
||||
|
||||
mod_modulate(&q->mod[harq_process->mcs.mod], (uint8_t*) q->pusch_e, q->pusch_d, nof_bits_e);
|
||||
|
||||
/* mapping to resource elements */
|
||||
|
||||
for (i = 0; i < q->cell.nof_ports; i++) {
|
||||
pusch_put(q, q->pusch_symbols[i], sf_symbols[i], &harq_process->prb_alloc, subframe);
|
||||
}
|
||||
|
||||
ret = LIBLTE_SUCCESS;
|
||||
} else {
|
||||
fprintf(stderr, "Must call pusch_set_rnti() to set the encoder/decoder RNTI\n");
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
@ -0,0 +1,547 @@
|
||||
/**
|
||||
*
|
||||
* \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 <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "liblte/phy/phch/pusch.h"
|
||||
#include "liblte/phy/phch/sch.h"
|
||||
#include "liblte/phy/phch/uci.h"
|
||||
#include "liblte/phy/common/phy_common.h"
|
||||
#include "liblte/phy/utils/bit.h"
|
||||
#include "liblte/phy/utils/debug.h"
|
||||
#include "liblte/phy/utils/vector.h"
|
||||
|
||||
|
||||
int sch_init(sch_t *q) {
|
||||
int ret = LIBLTE_ERROR_INVALID_INPUTS;
|
||||
if (q) {
|
||||
bzero(q, sizeof(sch_t));
|
||||
|
||||
if (crc_init(&q->crc_tb, LTE_CRC24A, 24)) {
|
||||
fprintf(stderr, "Error initiating CRC\n");
|
||||
goto clean;
|
||||
}
|
||||
if (crc_init(&q->crc_cb, LTE_CRC24B, 24)) {
|
||||
fprintf(stderr, "Error initiating CRC\n");
|
||||
goto clean;
|
||||
}
|
||||
|
||||
if (tcod_init(&q->encoder, MAX_LONG_CB)) {
|
||||
fprintf(stderr, "Error initiating Turbo Coder\n");
|
||||
goto clean;
|
||||
}
|
||||
if (tdec_init(&q->decoder, MAX_LONG_CB)) {
|
||||
fprintf(stderr, "Error initiating Turbo Decoder\n");
|
||||
goto clean;
|
||||
}
|
||||
|
||||
// Allocate floats for reception (LLRs)
|
||||
q->cb_in = malloc(sizeof(uint8_t) * MAX_LONG_CB);
|
||||
if (!q->cb_in) {
|
||||
goto clean;
|
||||
}
|
||||
|
||||
q->cb_out = malloc(sizeof(float) * (3 * MAX_LONG_CB + 12));
|
||||
if (!q->cb_out) {
|
||||
goto clean;
|
||||
}
|
||||
ret = LIBLTE_SUCCESS;
|
||||
}
|
||||
clean:
|
||||
if (ret == LIBLTE_ERROR) {
|
||||
sch_free(q);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void sch_free(sch_t *q) {
|
||||
if (q->cb_in) {
|
||||
free(q->cb_in);
|
||||
}
|
||||
if (q->cb_out) {
|
||||
free(q->cb_out);
|
||||
}
|
||||
tdec_free(&q->decoder);
|
||||
tcod_free(&q->encoder);
|
||||
|
||||
bzero(q, sizeof(sch_t));
|
||||
}
|
||||
|
||||
|
||||
float sch_average_noi(sch_t *q) {
|
||||
return q->average_nof_iterations;
|
||||
}
|
||||
|
||||
uint32_t sch_last_noi(sch_t *q) {
|
||||
return q->nof_iterations;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Encode a transport block according to 36.212 5.3.2
|
||||
*
|
||||
*/
|
||||
static int encode_tb(sch_t *q, uint8_t *data, uint8_t *e_bits, uint32_t tbs, uint32_t nb_e,
|
||||
harq_t *harq_process, uint32_t rv_idx)
|
||||
{
|
||||
uint8_t parity[24];
|
||||
uint8_t *p_parity = parity;
|
||||
uint32_t par;
|
||||
uint32_t i;
|
||||
uint32_t cb_len, rp, wp, rlen, F, n_e;
|
||||
int ret = LIBLTE_ERROR_INVALID_INPUTS;
|
||||
uint32_t Qm = lte_mod_bits_x_symbol(harq_process->mcs.mod);
|
||||
|
||||
if (q != NULL &&
|
||||
data != NULL &&
|
||||
harq_process != NULL)
|
||||
{
|
||||
|
||||
uint32_t Gp = nb_e / Qm;
|
||||
uint32_t gamma = Gp%harq_process->cb_segm.C;
|
||||
|
||||
if (rv_idx == 0) {
|
||||
/* Compute transport block CRC */
|
||||
par = crc_checksum(&q->crc_tb, data, tbs);
|
||||
|
||||
/* parity bits will be appended later */
|
||||
bit_pack(par, &p_parity, 24);
|
||||
|
||||
if (VERBOSE_ISDEBUG()) {
|
||||
DEBUG("DATA: ", 0);
|
||||
vec_fprint_b(stdout, data, tbs);
|
||||
DEBUG("PARITY: ", 0);
|
||||
vec_fprint_b(stdout, parity, 24);
|
||||
}
|
||||
}
|
||||
|
||||
wp = 0;
|
||||
rp = 0;
|
||||
for (i = 0; i < harq_process->cb_segm.C; i++) {
|
||||
|
||||
/* Get read lengths */
|
||||
if (i < harq_process->cb_segm.C2) {
|
||||
cb_len = harq_process->cb_segm.K2;
|
||||
} else {
|
||||
cb_len = harq_process->cb_segm.K1;
|
||||
}
|
||||
if (harq_process->cb_segm.C > 1) {
|
||||
rlen = cb_len - 24;
|
||||
} else {
|
||||
rlen = cb_len;
|
||||
}
|
||||
if (i == 0) {
|
||||
F = harq_process->cb_segm.F;
|
||||
} else {
|
||||
F = 0;
|
||||
}
|
||||
if (i <= harq_process->cb_segm.C - gamma - 1) {
|
||||
n_e = Qm * (Gp/harq_process->cb_segm.C);
|
||||
} else {
|
||||
n_e = Qm * ((uint32_t) ceilf((float) Gp/harq_process->cb_segm.C));
|
||||
}
|
||||
|
||||
INFO("CB#%d: cb_len: %d, rlen: %d, wp: %d, rp: %d, F: %d, E: %d\n", i,
|
||||
cb_len, rlen - F, wp, rp, F, n_e);
|
||||
|
||||
if (rv_idx == 0) {
|
||||
|
||||
/* Copy data to another buffer, making space for the Codeblock CRC */
|
||||
if (i < harq_process->cb_segm.C - 1) {
|
||||
// Copy data
|
||||
memcpy(&q->cb_in[F], &data[rp], (rlen - F) * sizeof(uint8_t));
|
||||
} else {
|
||||
INFO("Last CB, appending parity: %d from %d and 24 to %d\n",
|
||||
rlen - F - 24, rp, rlen - 24);
|
||||
/* Append Transport Block parity bits to the last CB */
|
||||
memcpy(&q->cb_in[F], &data[rp], (rlen - 24 - F) * sizeof(uint8_t));
|
||||
memcpy(&q->cb_in[rlen - 24], parity, 24 * sizeof(uint8_t));
|
||||
}
|
||||
/* Filler bits are treated like zeros for the CB CRC calculation */
|
||||
for (int j = 0; j < F; j++) {
|
||||
q->cb_in[j] = 0;
|
||||
}
|
||||
/* Attach Codeblock CRC */
|
||||
if (harq_process->cb_segm.C > 1) {
|
||||
crc_attach(&q->crc_cb, q->cb_in, rlen);
|
||||
}
|
||||
/* Set the filler bits to <NULL> */
|
||||
for (int j = 0; j < F; j++) {
|
||||
q->cb_in[j] = TX_NULL;
|
||||
}
|
||||
if (VERBOSE_ISDEBUG()) {
|
||||
DEBUG("CB#%d: ", i);
|
||||
vec_fprint_b(stdout, q->cb_in, cb_len);
|
||||
}
|
||||
|
||||
/* Turbo Encoding */
|
||||
tcod_encode(&q->encoder, q->cb_in, (uint8_t*) q->cb_out, cb_len);
|
||||
}
|
||||
|
||||
/* Rate matching */
|
||||
if (rm_turbo_tx(harq_process->pdsch_w_buff_c[i], harq_process->w_buff_size,
|
||||
(uint8_t*) q->cb_out, 3 * cb_len + 12,
|
||||
&e_bits[wp], n_e, rv_idx))
|
||||
{
|
||||
fprintf(stderr, "Error in rate matching\n");
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
|
||||
/* Set read/write pointers */
|
||||
rp += (rlen - F);
|
||||
wp += n_e;
|
||||
}
|
||||
INFO("END CB#%d: wp: %d, rp: %d\n", i, wp, rp);
|
||||
|
||||
ret = LIBLTE_SUCCESS;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Decode a transport block according to 36.212 5.3.2
|
||||
*
|
||||
*/
|
||||
static int decode_tb(sch_t *q, float *e_bits, uint8_t *data, uint32_t tbs, uint32_t nb_e,
|
||||
harq_t *harq_process, uint32_t rv_idx)
|
||||
{
|
||||
uint8_t parity[24];
|
||||
uint8_t *p_parity = parity;
|
||||
uint32_t par_rx, par_tx;
|
||||
uint32_t i;
|
||||
uint32_t cb_len, rp, wp, rlen, F, n_e;
|
||||
uint32_t Qm = lte_mod_bits_x_symbol(harq_process->mcs.mod);
|
||||
|
||||
if (q != NULL &&
|
||||
data != NULL &&
|
||||
harq_process != NULL)
|
||||
{
|
||||
|
||||
rp = 0;
|
||||
rp = 0;
|
||||
wp = 0;
|
||||
uint32_t Gp = nb_e / Qm;
|
||||
uint32_t gamma = Gp%harq_process->cb_segm.C;
|
||||
bool early_stop = true;
|
||||
for (i = 0; i < harq_process->cb_segm.C && early_stop; i++) {
|
||||
|
||||
/* Get read/write lengths */
|
||||
if (i < harq_process->cb_segm.C2) {
|
||||
cb_len = harq_process->cb_segm.K2;
|
||||
} else {
|
||||
cb_len = harq_process->cb_segm.K1;
|
||||
}
|
||||
if (harq_process->cb_segm.C == 1) {
|
||||
rlen = cb_len;
|
||||
} else {
|
||||
rlen = cb_len - 24;
|
||||
}
|
||||
if (i == 0) {
|
||||
F = harq_process->cb_segm.F;
|
||||
} else {
|
||||
F = 0;
|
||||
}
|
||||
|
||||
if (i <= harq_process->cb_segm.C - gamma - 1) {
|
||||
n_e = Qm * (Gp/harq_process->cb_segm.C);
|
||||
} else {
|
||||
n_e = Qm * ((uint32_t) ceilf((float) Gp/harq_process->cb_segm.C));
|
||||
}
|
||||
|
||||
INFO("CB#%d: cb_len: %d, rlen: %d, wp: %d, rp: %d, F: %d, E: %d\n", i,
|
||||
cb_len, rlen - F, wp, rp, F, n_e);
|
||||
|
||||
/* Rate Unmatching */
|
||||
if (rm_turbo_rx(harq_process->pdsch_w_buff_f[i], harq_process->w_buff_size,
|
||||
&e_bits[rp], n_e,
|
||||
(float*) q->cb_out, 3 * cb_len + 12, rv_idx, F)) {
|
||||
fprintf(stderr, "Error in rate matching\n");
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
|
||||
if (VERBOSE_ISDEBUG()) {
|
||||
DEBUG("CB#%d RMOUT: ", i);
|
||||
vec_fprint_f(stdout, q->cb_out, 3*cb_len+12);
|
||||
}
|
||||
|
||||
/* Turbo Decoding with CRC-based early stopping */
|
||||
q->nof_iterations = 0;
|
||||
uint32_t len_crc;
|
||||
uint8_t *cb_in_ptr;
|
||||
crc_t *crc_ptr;
|
||||
early_stop = false;
|
||||
|
||||
tdec_reset(&q->decoder, cb_len);
|
||||
|
||||
do {
|
||||
tdec_iteration(&q->decoder, (float*) q->cb_out, cb_len);
|
||||
q->nof_iterations++;
|
||||
|
||||
if (harq_process->cb_segm.C > 1) {
|
||||
len_crc = cb_len;
|
||||
cb_in_ptr = q->cb_in;
|
||||
crc_ptr = &q->crc_cb;
|
||||
} else {
|
||||
len_crc = tbs+24;
|
||||
cb_in_ptr = &q->cb_in[F];
|
||||
crc_ptr = &q->crc_tb;
|
||||
}
|
||||
|
||||
tdec_decision(&q->decoder, q->cb_in, cb_len);
|
||||
|
||||
/* Check Codeblock CRC and stop early if incorrect */
|
||||
if (!crc_checksum(crc_ptr, cb_in_ptr, len_crc)) {
|
||||
early_stop = true;
|
||||
}
|
||||
|
||||
} while (q->nof_iterations < TDEC_MAX_ITERATIONS && !early_stop);
|
||||
q->average_nof_iterations = VEC_EMA((float) q->nof_iterations, q->average_nof_iterations, 0.2);
|
||||
|
||||
if (VERBOSE_ISDEBUG()) {
|
||||
DEBUG("CB#%d IN: ", i);
|
||||
vec_fprint_b(stdout, q->cb_in, cb_len);
|
||||
}
|
||||
|
||||
// If CB CRC is not correct, early_stop will be false and wont continue with rest of CBs
|
||||
|
||||
/* Copy data to another buffer, removing the Codeblock CRC */
|
||||
if (i < harq_process->cb_segm.C - 1) {
|
||||
memcpy(&data[wp], &q->cb_in[F], (rlen - F) * sizeof(uint8_t));
|
||||
} else {
|
||||
DEBUG("Last CB, appending parity: %d to %d from %d and 24 from %d\n",
|
||||
rlen - F - 24, wp, F, rlen - 24);
|
||||
|
||||
/* Append Transport Block parity bits to the last CB */
|
||||
memcpy(&data[wp], &q->cb_in[F], (rlen - F - 24) * sizeof(uint8_t));
|
||||
memcpy(parity, &q->cb_in[rlen - 24], 24 * sizeof(uint8_t));
|
||||
}
|
||||
|
||||
/* Set read/write pointers */
|
||||
wp += (rlen - F);
|
||||
rp += n_e;
|
||||
}
|
||||
|
||||
if (!early_stop) {
|
||||
INFO("CB %d failed. TB is erroneous.\n",i-1);
|
||||
return LIBLTE_ERROR;
|
||||
} else {
|
||||
INFO("END CB#%d: wp: %d, rp: %d\n", i, wp, rp);
|
||||
|
||||
// Compute transport block CRC
|
||||
par_rx = crc_checksum(&q->crc_tb, data, tbs);
|
||||
|
||||
// check parity bits
|
||||
par_tx = bit_unpack(&p_parity, 24);
|
||||
|
||||
if (!par_rx) {
|
||||
INFO("\n\tCAUTION!! Received all-zero transport block\n\n", 0);
|
||||
}
|
||||
|
||||
if (par_rx == par_tx) {
|
||||
INFO("TB decoded OK\n",i);
|
||||
return LIBLTE_SUCCESS;
|
||||
} else {
|
||||
INFO("Error in TB parity\n",i);
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
|
||||
}
|
||||
} else {
|
||||
return LIBLTE_ERROR_INVALID_INPUTS;
|
||||
}
|
||||
}
|
||||
|
||||
int dlsch_decode(sch_t *q, float *e_bits, uint8_t *data, uint32_t tbs, uint32_t nb_e,
|
||||
harq_t *harq_process, uint32_t rv_idx)
|
||||
{
|
||||
return decode_tb(q, e_bits, data, tbs, nb_e, harq_process, rv_idx);
|
||||
}
|
||||
|
||||
int dlsch_encode(sch_t *q, uint8_t *data, uint8_t *e_bits, uint32_t tbs, uint32_t nb_e,
|
||||
harq_t *harq_process, uint32_t rv_idx) {
|
||||
return encode_tb(q, data, e_bits, tbs, nb_e, harq_process, rv_idx);
|
||||
}
|
||||
|
||||
int ulsch_decode(sch_t *q, float *e_bits, uint8_t *data, uint32_t tbs, uint32_t nb_e,
|
||||
harq_t *harq_process, uint32_t rv_idx)
|
||||
{
|
||||
return decode_tb(q, e_bits, data, tbs, nb_e, harq_process, rv_idx);
|
||||
}
|
||||
|
||||
|
||||
uint8_t ulsch_y_idx[10000];
|
||||
uint8_t ulsch_y_mat[10000];
|
||||
|
||||
/* UL-SCH channel interleaver according to 5.5.2.8 of 36.212 */
|
||||
void ulsch_interleave(uint8_t *q_bits, uint32_t nb_q,
|
||||
uint8_t q_bits_ack[6], uint32_t Q_ack,
|
||||
uint8_t q_bits_ri[6], uint32_t Q_ri,
|
||||
uint32_t Q_m)
|
||||
{
|
||||
uint32_t C_mux;
|
||||
uint32_t H_prime;
|
||||
uint32_t H_prime_total;
|
||||
uint32_t R_mux;
|
||||
uint32_t R_prime_mux;
|
||||
uint32_t i;
|
||||
uint32_t j;
|
||||
uint32_t k;
|
||||
uint32_t r;
|
||||
uint32_t idx;
|
||||
uint32_t ri_column_set[4] = {1, 4, 7, 10};
|
||||
uint32_t ack_column_set[4] = {2, 3, 8, 9};
|
||||
uint32_t C_ri;
|
||||
uint32_t C_ack;
|
||||
uint32_t N_pusch_symbs = 12;
|
||||
|
||||
// Step 1: Define C_mux
|
||||
C_mux = N_pusch_symbs;
|
||||
|
||||
// Step 2: Define R_mux and R_prime_mux
|
||||
H_prime = nb_q;
|
||||
H_prime_total = H_prime + Q_ri;
|
||||
R_mux = (H_prime_total*Q_m)/C_mux;
|
||||
R_prime_mux = R_mux/Q_m;
|
||||
|
||||
// Initialize the matricies
|
||||
//printf("Cmux*R_prime=%d*%d=%d\n",C_mux, R_prime_mux, C_mux*R_prime_mux);
|
||||
for(i=0; i<C_mux*R_prime_mux; i++) {
|
||||
ulsch_y_idx[i] = 100;
|
||||
}
|
||||
for(i=0; i<C_mux*R_mux; i++) {
|
||||
ulsch_y_mat[i] = 0;
|
||||
}
|
||||
|
||||
// Step 3: Interleave the RI control bits
|
||||
i = 0;
|
||||
j = 0;
|
||||
r = R_prime_mux-1;
|
||||
while(i < Q_ri) {
|
||||
C_ri = ri_column_set[j];
|
||||
ulsch_y_idx[r*C_mux + C_ri] = 1;
|
||||
for(k=0; k<Q_m; k++) {
|
||||
ulsch_y_mat[(C_mux*r*Q_m) + C_ri*Q_m + k] = q_bits_ri[Q_m*i+k];
|
||||
}
|
||||
i++;
|
||||
r = R_prime_mux - 1 - i/4;
|
||||
j = (j + 3) % 4;
|
||||
}
|
||||
|
||||
// Step 4: Interleave the data bits
|
||||
i = 0;
|
||||
k = 0;
|
||||
while(k < H_prime) {
|
||||
if(ulsch_y_idx[i] == 100) {
|
||||
ulsch_y_idx[i] = 1;
|
||||
for(j=0; j<Q_m; j++) {
|
||||
ulsch_y_mat[i*Q_m + j] = q_bits[Q_m*k+j];
|
||||
}
|
||||
k++;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
// Step 5: Interleave the ACK control bits
|
||||
i = 0;
|
||||
j = 0;
|
||||
r = R_prime_mux-1;
|
||||
while(i < Q_ack/Q_m) {
|
||||
C_ack = ack_column_set[j];
|
||||
ulsch_y_idx[r*C_mux + C_ack] = 2;
|
||||
for(k=0; k<Q_m; k++) {
|
||||
ulsch_y_mat[(C_mux*r*Q_m) + C_ack*Q_m + k] = q_bits_ack[Q_m*i+k];
|
||||
}
|
||||
i++;
|
||||
r = R_prime_mux - 1 - i/4;
|
||||
j = (j + 3) % 4;
|
||||
}
|
||||
|
||||
// Step 6: Read out the bits
|
||||
idx = 0;
|
||||
for(i=0; i<C_mux; i++) {
|
||||
for(j=0; j<R_prime_mux; j++) {
|
||||
for(k=0; k<Q_m; k++) {
|
||||
q_bits[idx++] = ulsch_y_mat[j*C_mux*Q_m + i*Q_m + k];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
int ulsch_encode(sch_t *q, uint8_t *data, uci_data_t uci_data, uint8_t *q_bits, uint32_t nb_q,
|
||||
uint8_t *q_bits_ack, uint8_t *q_bits_ri,
|
||||
harq_t *harq_process, uint32_t rv_idx)
|
||||
{
|
||||
int ret;
|
||||
|
||||
uint32_t e_offset = 0;
|
||||
uint32_t Q_prime_ack = 0;
|
||||
uint32_t Q_prime_ri = 0;
|
||||
uint32_t Q_m = lte_mod_bits_x_symbol(harq_process->mcs.mod);
|
||||
|
||||
// Encode CQI
|
||||
if (uci_data.uci_cqi_len > 0) {
|
||||
ret = uci_encode_cqi(uci_data.uci_cqi, q_bits, uci_data.uci_cqi_len, nb_q);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
e_offset += uci_data.uci_cqi_len;
|
||||
|
||||
// Encode UL-SCH
|
||||
ret = encode_tb(q, data, &q_bits[e_offset], harq_process->mcs.tbs,
|
||||
nb_q, harq_process, rv_idx);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Encode ACK
|
||||
if (uci_data.uci_ack_len > 0) {
|
||||
Q_prime_ack = uci_encode_ri_ack(uci_data.uci_ack, uci_data.beta_ack, q_bits_ack, harq_process);
|
||||
}
|
||||
|
||||
// Encode RI
|
||||
if (uci_data.uci_ri_len > 0) {
|
||||
Q_prime_ri = uci_encode_ri_ack(uci_data.uci_ri, uci_data.beta_ri, q_bits_ri, harq_process);
|
||||
}
|
||||
|
||||
// Multiplexing and Interleaving
|
||||
ulsch_interleave(q_bits, nb_q/Q_m,
|
||||
q_bits_ack, Q_prime_ack,
|
||||
q_bits_ri, Q_prime_ri,
|
||||
Q_m);
|
||||
return LIBLTE_SUCCESS;
|
||||
}
|
||||
|
@ -0,0 +1,89 @@
|
||||
/**
|
||||
*
|
||||
* \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 <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "liblte/phy/phch/uci.h"
|
||||
#include "liblte/phy/phch/harq.h"
|
||||
#include "liblte/phy/common/phy_common.h"
|
||||
#include "liblte/phy/utils/vector.h"
|
||||
|
||||
|
||||
/* Encode UCI-CQI */
|
||||
int uci_encode_cqi(uint8_t *data, uint8_t *e_bits, uint32_t tbs, uint32_t nb_e)
|
||||
{
|
||||
fprintf(stderr, "Not implemented\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
static uint32_t Q_prime(uint32_t O, float beta, harq_t *harq_process) {
|
||||
uint32_t M_sc = harq_process->prb_alloc.slot[0].nof_prb * RE_X_RB;
|
||||
|
||||
uint32_t K = harq_process->cb_segm.C1*harq_process->cb_segm.K1 +
|
||||
harq_process->cb_segm.C2*harq_process->cb_segm.K2;
|
||||
uint32_t M_sc_init = harq_process->nof_prb_pusch_init * RE_X_RB;
|
||||
|
||||
uint32_t x = (uint32_t) ceilf((float) O*M_sc_init*harq_process->N_symb_ul*beta/K);
|
||||
|
||||
printf("%d=%d*%d*%d*%f/%d\n",x,O,M_sc_init,harq_process->N_symb_ul,beta,K);
|
||||
|
||||
uint32_t Q_prime = MIN(x, 4*M_sc);
|
||||
|
||||
return Q_prime;
|
||||
}
|
||||
|
||||
/* Encode UCI RI and HARQ bits
|
||||
* Currently only supporting 1-bit RI or 1-bit HARQ
|
||||
*/
|
||||
uint32_t uci_encode_ri_ack(uint8_t data, float beta, uint8_t *q_bits, harq_t *harq_process)
|
||||
{
|
||||
uint8_t Q_m = lte_mod_bits_x_symbol(harq_process->mcs.mod);
|
||||
|
||||
q_bits[0] = data;
|
||||
q_bits[1] = 2;
|
||||
for (int i=2;i<Q_m;i++) {
|
||||
q_bits[i] = 3;
|
||||
}
|
||||
|
||||
uint32_t Qprime = Q_prime(1, beta, harq_process);
|
||||
|
||||
for (int i=1;i<Qprime;i++) {
|
||||
memcpy(&q_bits[i*Q_m], q_bits, Q_m*sizeof(uint8_t));
|
||||
}
|
||||
|
||||
printf("Q_m: %d, Qprime: %d, beta: %f\n", Q_m, Qprime, beta);
|
||||
|
||||
return Qprime * Q_m;
|
||||
}
|
||||
|
@ -0,0 +1,124 @@
|
||||
/**
|
||||
*
|
||||
* \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 <string.h>
|
||||
#include "liblte/phy/phy.h"
|
||||
#include "liblte/mex/mexutils.h"
|
||||
|
||||
#define UECFG prhs[0]
|
||||
#define PUSCHCFG prhs[1]
|
||||
#define OUTLEN prhs[2]
|
||||
#define TRBLKIN prhs[3]
|
||||
#define NOF_INPUTS 4
|
||||
|
||||
void help()
|
||||
{
|
||||
mexErrMsgTxt
|
||||
("[cwout] = liblte_dlsch_encode(ue, chs, outlen, trblkin)\n\n");
|
||||
}
|
||||
|
||||
/* the gateway function */
|
||||
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
|
||||
{
|
||||
sch_t dlsch;
|
||||
uint8_t *trblkin;
|
||||
ra_mcs_t mcs;
|
||||
ra_prb_t prb_alloc;
|
||||
harq_t harq_process;
|
||||
uint32_t rv;
|
||||
|
||||
if (nrhs < NOF_INPUTS) {
|
||||
help();
|
||||
return;
|
||||
}
|
||||
|
||||
if (sch_init(&dlsch)) {
|
||||
mexErrMsgTxt("Error initiating DL-SCH\n");
|
||||
return;
|
||||
}
|
||||
lte_cell_t cell;
|
||||
cell.nof_prb = 100;
|
||||
cell.id=1;
|
||||
if (harq_init(&harq_process, cell)) {
|
||||
mexErrMsgTxt("Error initiating HARQ\n");
|
||||
return;
|
||||
}
|
||||
|
||||
mcs.tbs = mexutils_read_uint8(TRBLKIN, &trblkin);
|
||||
if (mcs.tbs == 0) {
|
||||
mexErrMsgTxt("Error trblklen is zero\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (mexutils_read_uint32_struct(PUSCHCFG, "RV", &rv)) {
|
||||
mexErrMsgTxt("Field RV not found in dlsch config\n");
|
||||
return;
|
||||
}
|
||||
|
||||
char *mod_str = mexutils_get_char_struct(PUSCHCFG, "Modulation");
|
||||
|
||||
if (!strcmp(mod_str, "QPSK")) {
|
||||
mcs.mod = LTE_QPSK;
|
||||
} else if (!strcmp(mod_str, "16QAM")) {
|
||||
mcs.mod = LTE_QAM16;
|
||||
} else if (!strcmp(mod_str, "64QAM")) {
|
||||
mcs.mod = LTE_QAM64;
|
||||
} else {
|
||||
mexErrMsgTxt("Unknown modulation\n");
|
||||
return;
|
||||
}
|
||||
|
||||
mxFree(mod_str);
|
||||
|
||||
if (harq_setup(&harq_process, mcs, &prb_alloc)) {
|
||||
mexErrMsgTxt("Error configuring HARQ process\n");
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t nof_bits_e = (uint32_t) mxGetScalar(OUTLEN);
|
||||
uint8_t *e_bits = vec_malloc(nof_bits_e * sizeof(uint8_t));
|
||||
if (!e_bits) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (dlsch_encode(&dlsch, trblkin, e_bits, mcs.tbs, nof_bits_e, &harq_process, rv)) {
|
||||
mexErrMsgTxt("Error encoding TB\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (nlhs >= 1) {
|
||||
mexutils_write_uint8(e_bits, &plhs[0], nof_bits_e, 1);
|
||||
}
|
||||
|
||||
sch_free(&dlsch);
|
||||
|
||||
free(trblkin);
|
||||
free(e_bits);
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -0,0 +1,259 @@
|
||||
/**
|
||||
*
|
||||
* \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 <string.h>
|
||||
#include <strings.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "liblte/phy/phy.h"
|
||||
|
||||
lte_cell_t cell = {
|
||||
6, // nof_prb
|
||||
1, // nof_ports
|
||||
0, // cell_id
|
||||
CPNORM, // cyclic prefix
|
||||
R_1_6, // PHICH resources
|
||||
PHICH_NORM // PHICH length
|
||||
};
|
||||
|
||||
uint32_t cfi = 2;
|
||||
uint32_t tbs = 0;
|
||||
uint32_t subframe = 1;
|
||||
lte_mod_t modulation = LTE_QPSK;
|
||||
uint32_t rv_idx = 0;
|
||||
|
||||
void usage(char *prog) {
|
||||
printf("Usage: %s [cpsrnfvmt] -l TBS \n", prog);
|
||||
printf("\t-m modulation (1: BPSK, 2: QPSK, 3: QAM16, 4: QAM64) [Default BPSK]\n");
|
||||
printf("\t-c cell id [Default %d]\n", cell.id);
|
||||
printf("\t-s subframe [Default %d]\n", subframe);
|
||||
printf("\t-r rv_idx [Default %d]\n", rv_idx);
|
||||
printf("\t-f cfi [Default %d]\n", cfi);
|
||||
printf("\t-p cell.nof_ports [Default %d]\n", cell.nof_ports);
|
||||
printf("\t-n cell.nof_prb [Default %d]\n", cell.nof_prb);
|
||||
printf("\t-v [set verbose to debug, default none]\n");
|
||||
}
|
||||
|
||||
void parse_args(int argc, char **argv) {
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "lcpnfvmtsr")) != -1) {
|
||||
switch(opt) {
|
||||
case 'm':
|
||||
switch(atoi(argv[optind])) {
|
||||
case 1:
|
||||
modulation = LTE_BPSK;
|
||||
break;
|
||||
case 2:
|
||||
modulation = LTE_QPSK;
|
||||
break;
|
||||
case 4:
|
||||
modulation = LTE_QAM16;
|
||||
break;
|
||||
case 6:
|
||||
modulation = LTE_QAM64;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Invalid modulation %d. Possible values: "
|
||||
"(1: BPSK, 2: QPSK, 3: QAM16, 4: QAM64)\n", atoi(argv[optind]));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 's':
|
||||
subframe = atoi(argv[optind]);
|
||||
break;
|
||||
case 'r':
|
||||
rv_idx = atoi(argv[optind]);
|
||||
break;
|
||||
case 'l':
|
||||
tbs = atoi(argv[optind]);
|
||||
break;
|
||||
case 'p':
|
||||
cell.nof_ports = atoi(argv[optind]);
|
||||
break;
|
||||
case 'n':
|
||||
cell.nof_prb = atoi(argv[optind]);
|
||||
break;
|
||||
case 'c':
|
||||
cell.id = atoi(argv[optind]);
|
||||
break;
|
||||
case 'v':
|
||||
verbose++;
|
||||
break;
|
||||
default:
|
||||
usage(argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
if (tbs == 0) {
|
||||
usage(argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
pusch_t pusch;
|
||||
uint32_t i, j;
|
||||
uint8_t *data = NULL;
|
||||
cf_t *ce[MAX_PORTS];
|
||||
uint32_t nof_re;
|
||||
cf_t *slot_symbols[MAX_PORTS];
|
||||
int ret = -1;
|
||||
struct timeval t[3];
|
||||
ra_mcs_t mcs;
|
||||
ra_prb_t prb_alloc;
|
||||
harq_t harq_process;
|
||||
uint32_t rv;
|
||||
|
||||
parse_args(argc,argv);
|
||||
|
||||
nof_re = 2 * CPNORM_NSYMB * cell.nof_prb * RE_X_RB;
|
||||
|
||||
mcs.tbs = tbs;
|
||||
mcs.mod = modulation;
|
||||
|
||||
prb_alloc.slot[0].nof_prb = 1;
|
||||
//for (i=0;i<prb_alloc.slot[0].nof_prb;i++) {
|
||||
// prb_alloc.slot[0].prb_idx[i] = true;
|
||||
//}
|
||||
memcpy(&prb_alloc.slot[1], &prb_alloc.slot[0], sizeof(ra_prb_slot_t));
|
||||
|
||||
/* init memory */
|
||||
for (i=0;i<cell.nof_ports;i++) {
|
||||
ce[i] = malloc(sizeof(cf_t) * nof_re);
|
||||
if (!ce[i]) {
|
||||
perror("malloc");
|
||||
goto quit;
|
||||
}
|
||||
for (j=0;j<nof_re;j++) {
|
||||
ce[i][j] = 1;
|
||||
}
|
||||
slot_symbols[i] = calloc(sizeof(cf_t) , nof_re);
|
||||
if (!slot_symbols[i]) {
|
||||
perror("malloc");
|
||||
goto quit;
|
||||
}
|
||||
}
|
||||
|
||||
data = malloc(sizeof(uint8_t) * mcs.tbs);
|
||||
if (!data) {
|
||||
perror("malloc");
|
||||
goto quit;
|
||||
}
|
||||
|
||||
if (pusch_init(&pusch, cell)) {
|
||||
fprintf(stderr, "Error creating PDSCH object\n");
|
||||
goto quit;
|
||||
}
|
||||
pusch_set_rnti(&pusch, 1234);
|
||||
|
||||
if (harq_init(&harq_process, cell)) {
|
||||
fprintf(stderr, "Error initiating HARQ process\n");
|
||||
goto quit;
|
||||
}
|
||||
|
||||
if (harq_setup(&harq_process, mcs, &prb_alloc)) {
|
||||
fprintf(stderr, "Error configuring HARQ process\n");
|
||||
goto quit;
|
||||
}
|
||||
|
||||
for (i=0;i<mcs.tbs;i++) {
|
||||
data[i] = rand()%2;
|
||||
}
|
||||
|
||||
vec_fprint_b(stdout, data, mcs.tbs);
|
||||
|
||||
for (rv=0;rv<=rv_idx;rv++) {
|
||||
printf("Encoding rv_idx=%d\n",rv);
|
||||
|
||||
uci_data_t uci_data;
|
||||
bzero(&uci_data, sizeof(uci_data_t));
|
||||
uci_data.beta_ack = 2.0;
|
||||
uci_data.uci_ack = 1;
|
||||
uci_data.uci_ack_len = 1;
|
||||
|
||||
uint32_t nof_symbols = 12*harq_process.prb_alloc.slot[0].nof_prb*RE_X_RB;
|
||||
uint32_t nof_bits_e = nof_symbols * lte_mod_bits_x_symbol(harq_process.mcs.mod);
|
||||
|
||||
if (ulsch_encode(&pusch.dl_sch, data, uci_data, pusch.pusch_e, nof_bits_e,
|
||||
pusch.pusch_q_ack, pusch.pusch_q_ri, &harq_process, rv))
|
||||
{
|
||||
fprintf(stderr, "Error encoding TB\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
vec_fprint_b(stdout, pusch.pusch_e, 288);
|
||||
|
||||
/* combine outputs */
|
||||
for (i=0;i<cell.nof_ports;i++) {
|
||||
for (j=0;j<nof_re;j++) {
|
||||
if (i > 0) {
|
||||
slot_symbols[0][j] += slot_symbols[i][j];
|
||||
}
|
||||
ce[i][j] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
gettimeofday(&t[1], NULL);
|
||||
//int r = pusch_decode(&pusch, slot_symbols[0], ce, 0, data, subframe, &harq_process, rv);
|
||||
int r = 0;
|
||||
gettimeofday(&t[2], NULL);
|
||||
get_time_interval(t);
|
||||
if (r) {
|
||||
printf("Error decoding\n");
|
||||
ret = -1;
|
||||
goto quit;
|
||||
} else {
|
||||
printf("DECODED OK in %d:%d (%.2f Mbps)\n", (int) t[0].tv_sec, (int) t[0].tv_usec, (float) mcs.tbs/t[0].tv_usec);
|
||||
}
|
||||
|
||||
}
|
||||
ret = 0;
|
||||
quit:
|
||||
pusch_free(&pusch);
|
||||
harq_free(&harq_process);
|
||||
|
||||
for (i=0;i<cell.nof_ports;i++) {
|
||||
if (ce[i]) {
|
||||
free(ce[i]);
|
||||
}
|
||||
if (slot_symbols[i]) {
|
||||
free(slot_symbols[i]);
|
||||
}
|
||||
}
|
||||
if (data) {
|
||||
free(data);
|
||||
}
|
||||
if (ret) {
|
||||
printf("Error\n");
|
||||
} else {
|
||||
printf("Ok\n");
|
||||
}
|
||||
exit(ret);
|
||||
}
|
@ -0,0 +1,190 @@
|
||||
/**
|
||||
*
|
||||
* \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 <string.h>
|
||||
#include "liblte/phy/phy.h"
|
||||
#include "liblte/mex/mexutils.h"
|
||||
|
||||
#define UECFG prhs[0]
|
||||
#define PUSCHCFG prhs[1]
|
||||
#define TRBLKIN prhs[2]
|
||||
#define CQI prhs[3]
|
||||
#define RI prhs[4]
|
||||
#define ACK prhs[5]
|
||||
#define NOF_INPUTS 6
|
||||
|
||||
void help()
|
||||
{
|
||||
mexErrMsgTxt
|
||||
("[cwout] = liblte_pusch_encode(ue, chs, trblkin, cqi, ri, ack)\n\n");
|
||||
}
|
||||
|
||||
/* the gateway function */
|
||||
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
|
||||
{
|
||||
int i;
|
||||
sch_t ulsch;
|
||||
uint8_t *trblkin;
|
||||
ra_mcs_t mcs;
|
||||
ra_prb_t prb_alloc;
|
||||
harq_t harq_process;
|
||||
uint32_t rv;
|
||||
uci_data_t uci_data;
|
||||
bzero(&uci_data, sizeof(uci_data_t));
|
||||
|
||||
if (nrhs < NOF_INPUTS) {
|
||||
help();
|
||||
return;
|
||||
}
|
||||
if (sch_init(&ulsch)) {
|
||||
mexErrMsgTxt("Error initiating ULSCH\n");
|
||||
return;
|
||||
}
|
||||
lte_cell_t cell;
|
||||
cell.nof_prb = 100;
|
||||
cell.id=1;
|
||||
if (harq_init(&harq_process, cell)) {
|
||||
mexErrMsgTxt("Error initiating HARQ\n");
|
||||
return;
|
||||
}
|
||||
|
||||
mcs.tbs = mexutils_read_uint8(TRBLKIN, &trblkin);
|
||||
if (mcs.tbs == 0) {
|
||||
mexErrMsgTxt("Error trblklen is zero\n");
|
||||
return;
|
||||
}
|
||||
uci_data.uci_cqi_len = mexutils_read_uint8(CQI, &uci_data.uci_cqi);
|
||||
uint8_t *tmp;
|
||||
uci_data.uci_ri_len = mexutils_read_uint8(RI, &tmp);
|
||||
if (uci_data.uci_ri_len > 0) {
|
||||
uci_data.uci_ri = *tmp;
|
||||
}
|
||||
free(tmp);
|
||||
uci_data.uci_ack_len = mexutils_read_uint8(ACK, &tmp);
|
||||
if (uci_data.uci_ack_len > 0) {
|
||||
uci_data.uci_ack = *tmp;
|
||||
}
|
||||
free(tmp);
|
||||
|
||||
mexPrintf("TRBL_len: %d, CQI_len: %d, ACK_len: %d, RI_len: %d\n", mcs.tbs,
|
||||
uci_data.uci_cqi_len, uci_data.uci_ack_len, uci_data.uci_ri_len);
|
||||
|
||||
if (mexutils_read_uint32_struct(PUSCHCFG, "RV", &rv)) {
|
||||
mexErrMsgTxt("Field RV not found in pdsch config\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (mexutils_read_float_struct(PUSCHCFG, "BetaCQI", &uci_data.beta_cqi)) {
|
||||
uci_data.beta_cqi = 2.0;
|
||||
}
|
||||
if (mexutils_read_float_struct(PUSCHCFG, "BetaRI", &uci_data.beta_ri)) {
|
||||
uci_data.beta_ri = 2.0;
|
||||
}
|
||||
if (mexutils_read_float_struct(PUSCHCFG, "BetaACK", &uci_data.beta_ack)) {
|
||||
uci_data.beta_ack = 2.0;
|
||||
}
|
||||
mexPrintf("Beta_CQI: %.1f, Beta_ACK: %.1f, Beta_RI: %.1f\n",
|
||||
uci_data.beta_cqi, uci_data.beta_ack, uci_data.beta_ri);
|
||||
|
||||
char *mod_str = mexutils_get_char_struct(PUSCHCFG, "Modulation");
|
||||
|
||||
if (!strcmp(mod_str, "QPSK")) {
|
||||
mcs.mod = LTE_QPSK;
|
||||
} else if (!strcmp(mod_str, "16QAM")) {
|
||||
mcs.mod = LTE_QAM16;
|
||||
} else if (!strcmp(mod_str, "64QAM")) {
|
||||
mcs.mod = LTE_QAM64;
|
||||
} else {
|
||||
mexErrMsgTxt("Unknown modulation\n");
|
||||
return;
|
||||
}
|
||||
|
||||
mxFree(mod_str);
|
||||
|
||||
float *prbset;
|
||||
mxArray *p;
|
||||
p = mxGetField(PUSCHCFG, 0, "PRBSet");
|
||||
if (!p) {
|
||||
mexErrMsgTxt("Error field PRBSet not found\n");
|
||||
return;
|
||||
}
|
||||
|
||||
prb_alloc.slot[0].nof_prb = mexutils_read_f(p, &prbset);
|
||||
for (i=0;i<MAX_PRB;i++) {
|
||||
prb_alloc.slot[0].prb_idx[i] = false;
|
||||
for (int j=0;j<prb_alloc.slot[0].nof_prb && !prb_alloc.slot[0].prb_idx[i];j++) {
|
||||
if ((int) prbset[j] == i) {
|
||||
prb_alloc.slot[0].prb_idx[i] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
memcpy(&prb_alloc.slot[1], &prb_alloc.slot[0], sizeof(ra_prb_slot_t));
|
||||
|
||||
free(prbset);
|
||||
|
||||
if (harq_setup(&harq_process, mcs, &prb_alloc)) {
|
||||
mexErrMsgTxt("Error configuring HARQ process\n");
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t nof_symbols = 12*harq_process.prb_alloc.slot[0].nof_prb*RE_X_RB;
|
||||
uint32_t nof_q_bits = nof_symbols * lte_mod_bits_x_symbol(harq_process.mcs.mod);
|
||||
|
||||
uint8_t *q_bits = vec_malloc(nof_q_bits * sizeof(uint8_t));
|
||||
if (!q_bits) {
|
||||
return;
|
||||
}
|
||||
uint8_t *q_bits_ack = vec_malloc(nof_q_bits * sizeof(uint8_t));
|
||||
if (!q_bits_ack) {
|
||||
return;
|
||||
}
|
||||
uint8_t *q_bits_ri = vec_malloc(nof_q_bits * sizeof(uint8_t));
|
||||
if (!q_bits_ri) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ulsch_encode(&ulsch, trblkin, uci_data, q_bits, nof_q_bits,
|
||||
q_bits_ack, q_bits_ri, &harq_process, rv))
|
||||
{
|
||||
fprintf(stderr, "Error encoding TB\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (nlhs >= 1) {
|
||||
mexutils_write_uint8(q_bits, &plhs[0], nof_q_bits, 1);
|
||||
}
|
||||
|
||||
sch_free(&ulsch);
|
||||
|
||||
free(trblkin);
|
||||
free(q_bits);
|
||||
free(q_bits_ack);
|
||||
free(q_bits_ri);
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -0,0 +1,27 @@
|
||||
enbConfig=struct('NCellID',1,'CyclicPrefix','Normal','CellRefP',1);
|
||||
pdschConfig=struct('Modulation','QPSK','RV',0,'TxScheme','Port0');
|
||||
|
||||
addpath('../../debug/lte/phy/lib/phch/test')
|
||||
|
||||
TBs=1:111:15000;
|
||||
e_bits=10000;
|
||||
error=zeros(size(TBs));
|
||||
for i=1:length(TBs)
|
||||
trblkin=randi(2,TBs(i),1)-1;
|
||||
%trblkin=ones(104,1);
|
||||
%trblkin=[1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, ];
|
||||
%trblkin=[1, 0];
|
||||
|
||||
[mat, info]=lteDLSCH(enbConfig,pdschConfig,e_bits,trblkin);
|
||||
lib=liblte_dlsch_encode(enbConfig,pdschConfig,e_bits,trblkin);
|
||||
error(i)=mean(abs(double(mat)-double(lib)));
|
||||
end
|
||||
|
||||
if (length(TBs) == 1)
|
||||
%disp(info)
|
||||
disp(error)
|
||||
n=1:length(mat);
|
||||
plot(abs(double(mat)-double(lib)))
|
||||
else
|
||||
plot(error)
|
||||
end
|
Binary file not shown.
File diff suppressed because one or more lines are too long
@ -0,0 +1,33 @@
|
||||
ueConfig=struct('NCellID',1,'CyclicPrefixUL','Normal','NTxAnts',1);
|
||||
puschConfig=struct('NLayers',1,'OrthCover','Off','PRBSet',0,'Modulation','QPSK','RV',0,'Shortened',0);
|
||||
|
||||
addpath('../../debug/lte/phy/lib/phch/test')
|
||||
|
||||
TBs=104;
|
||||
error=zeros(size(TBs));
|
||||
for i=1:length(error)
|
||||
trblkin=randi(2,TBs(i),1)-1;
|
||||
%trblkin=ones(104,1);
|
||||
%trblkin=[1, 0];
|
||||
|
||||
puschConfig.BetaCQI = 2.0;
|
||||
puschConfig.BetaRI = 2.0;
|
||||
puschConfig.BetaACK = 2.0;
|
||||
|
||||
[mat, info]=lteULSCH(ueConfig,puschConfig,trblkin,[],[],[1],[]);
|
||||
mat(mat==-2)=2;
|
||||
[lib]=liblte_ulsch_encode(ueConfig,puschConfig,trblkin,[],[],[1]);
|
||||
error(i)=sum(abs(double(mat)-double(lib)));
|
||||
if (length(TBs) == 1)
|
||||
disp(error(i))
|
||||
end
|
||||
end
|
||||
|
||||
if (length(TBs) == 1)
|
||||
%disp(info)
|
||||
n=1:length(mat);
|
||||
plot(abs(double(mat)-double(lib)))
|
||||
else
|
||||
plot(error)
|
||||
disp(sum(error))
|
||||
end
|
Loading…
Reference in New Issue