mirror of https://github.com/PentHertz/srsLTE.git
Added CRC. Changed ratematching to FEC directory
This commit is contained in:
parent
887c3a8e80
commit
6fe5a05952
|
@ -57,6 +57,8 @@
|
|||
#include "lte/fec/tc_interl.h"
|
||||
#include "lte/fec/turbocoder.h"
|
||||
#include "lte/fec/turbodecoder.h"
|
||||
#include "lte/fec/rm_conv.h"
|
||||
#include "lte/fec/rm_turbo.h"
|
||||
|
||||
#include "lte/filter/filter2d.h"
|
||||
|
||||
|
@ -81,8 +83,6 @@
|
|||
#include "lte/phch/pcfich.h"
|
||||
#include "lte/phch/phich.h"
|
||||
|
||||
#include "lte/ratematching/rm_conv.h"
|
||||
|
||||
#include "lte/scrambling/scrambling.h"
|
||||
|
||||
#include "lte/resampling/interp.h"
|
||||
|
|
|
@ -39,6 +39,11 @@
|
|||
#define MAX_LAYERS 8
|
||||
#define MAX_CODEWORDS 2
|
||||
|
||||
#define LTE_CRC24A 0x1864CFB
|
||||
#define LTE_CRC24B 0X1800063
|
||||
#define LTE_CRC16 0x11021
|
||||
#define LTE_CRC8 0x19B
|
||||
|
||||
typedef enum {CPNORM, CPEXT} lte_cp_t;
|
||||
|
||||
#define SIRNTI 0xFFFF
|
||||
|
|
|
@ -26,42 +26,23 @@
|
|||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef CRC_
|
||||
#define CRC_
|
||||
|
||||
#define LTE_CRC24A 0x1864CFB
|
||||
#define LTE_CRC24B 0X1800063
|
||||
#define LTE_CRC16 0x11021
|
||||
#define LTE_CRC8 0x19B
|
||||
|
||||
|
||||
#define _WITHMALLOC
|
||||
|
||||
#ifndef _WITHMALLOC
|
||||
#define MAX_LENGTH 1024*16
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
unsigned long table[256];
|
||||
#ifdef _WITHMALLOC
|
||||
unsigned char *data0;
|
||||
#else
|
||||
unsigned char data0[MAX_LENGTH];
|
||||
#endif
|
||||
unsigned char byte;
|
||||
int polynom;
|
||||
int order;
|
||||
unsigned long crcinit;
|
||||
unsigned long crcxor;
|
||||
unsigned long crcmask;
|
||||
unsigned long crchighbit;
|
||||
unsigned int crc_out;
|
||||
} crc_t;
|
||||
|
||||
|
||||
int crc_init(crc_t *crc_par);
|
||||
unsigned int crc_attach(char *bufptr, int len, crc_t *crc_params);
|
||||
unsigned int crc(unsigned int crc, char *bufptr, int len,
|
||||
int long_crc,unsigned int poly, int paste_word);
|
||||
int crc_init(crc_t *h, unsigned int crc_poly, int crc_order);
|
||||
int crc_set_init(crc_t *h, unsigned long crc_init_value);
|
||||
void crc_attach(crc_t *h, char *data, int len);
|
||||
unsigned int crc_checksum(crc_t *h, char *data, int len);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -25,44 +25,35 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#define RATE 3
|
||||
#define TOTALTAIL 12
|
||||
|
||||
#define LOG18 -2.07944
|
||||
#ifndef RM_CONV_
|
||||
#define RM_CONV_
|
||||
|
||||
#define NUMSTATES 8
|
||||
#define NINPUTS 2
|
||||
#define TOTALTAIL 12
|
||||
#define RX_NULL 10000
|
||||
#define TX_NULL 80
|
||||
|
||||
#define SCALE 80
|
||||
|
||||
#define INF 9e4
|
||||
#define ZERO 9e-4
|
||||
int rm_turbo_tx(char *input, char *output, int in_len, int out_len);
|
||||
int rm_turbo_rx(float *input, float *output, int in_len, int out_len);
|
||||
|
||||
#define MAX_LONG_CB 6114
|
||||
#define MAX_LONG_CODED (RATE*MAX_LONG_CB+TOTALTAIL)
|
||||
|
||||
typedef float llr_t;
|
||||
|
||||
/* High-level API */
|
||||
typedef struct {
|
||||
int long_cb;
|
||||
int max_iterations;
|
||||
int halt_threshold;
|
||||
enum { HALT_MIN = 2, HALT_MEAN = 1, HALT_NONE = 0} halt_mode;
|
||||
llr_t alfa[NUMSTATES];
|
||||
llr_t beta[(MAX_LONG_CB + 1) * NUMSTATES];
|
||||
llr_t LLR1[MAX_LONG_CB + TOTALTAIL];
|
||||
llr_t LLR2[MAX_LONG_CB + TOTALTAIL];
|
||||
llr_t W[MAX_LONG_CB + TOTALTAIL];
|
||||
llr_t data[RATE*(MAX_LONG_CB + TOTALTAIL)];
|
||||
llr_t *parity;
|
||||
struct permute_t permuta;
|
||||
int iteration;
|
||||
int HALT_min;
|
||||
struct rm_turbo_init {
|
||||
int direction;
|
||||
} init;
|
||||
void *input; // input type may be char or float depending on hard
|
||||
int in_len;
|
||||
struct rm_turbo_ctrl_in {
|
||||
int E;
|
||||
int S;
|
||||
} ctrl_in;
|
||||
void *output;
|
||||
int out_len;
|
||||
}rm_turbo_hl;
|
||||
|
||||
}tdec_t;
|
||||
|
||||
int tdec_init(tdec_t *h);
|
||||
|
||||
int turbo_decoder(tdec_t *h, llr_t *input, char *output, int *halt);
|
||||
int rm_turbo_initialize(rm_turbo_hl* h);
|
||||
int rm_turbo_work(rm_turbo_hl* hl);
|
||||
int rm_turbo_stop(rm_turbo_hl* hl);
|
||||
|
||||
#endif
|
|
@ -35,7 +35,7 @@
|
|||
#include "lte/modem/mod.h"
|
||||
#include "lte/modem/demod_soft.h"
|
||||
#include "lte/scrambling/scrambling.h"
|
||||
#include "lte/ratematching/rm_conv.h"
|
||||
#include "lte/fec/rm_conv.h"
|
||||
#include "lte/fec/convcoder.h"
|
||||
#include "lte/fec/viterbi.h"
|
||||
#include "lte/fec/crc.h"
|
||||
|
@ -79,6 +79,7 @@ typedef struct {
|
|||
demod_soft_t demod;
|
||||
sequence_t seq_pbch;
|
||||
viterbi_t decoder;
|
||||
crc_t crc;
|
||||
convcoder_t encoder;
|
||||
|
||||
}pbch_t;
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
#include "lte/modem/mod.h"
|
||||
#include "lte/modem/demod_soft.h"
|
||||
#include "lte/scrambling/scrambling.h"
|
||||
#include "lte/ratematching/rm_conv.h"
|
||||
#include "lte/fec/rm_conv.h"
|
||||
#include "lte/fec/convcoder.h"
|
||||
#include "lte/fec/viterbi.h"
|
||||
#include "lte/fec/crc.h"
|
||||
|
@ -88,7 +88,7 @@ typedef struct {
|
|||
demod_soft_t demod;
|
||||
sequence_t seq_pdcch[NSUBFRAMES_X_FRAME];
|
||||
viterbi_t decoder;
|
||||
|
||||
crc_t crc;
|
||||
}pdcch_t;
|
||||
|
||||
int pdcch_init(pdcch_t *q, regs_t *regs, int nof_prb, int nof_ports, int cell_id, lte_cp_t cp);
|
||||
|
|
|
@ -25,191 +25,141 @@
|
|||
*
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "lte/utils/pack.h"
|
||||
|
||||
#include "lte/utils/pack.h"
|
||||
#include "lte/fec/crc.h"
|
||||
|
||||
void gen_crc_table(crc_t *h) {
|
||||
|
||||
void gen_crc_table(crc_t *crc_params) {
|
||||
|
||||
int i, j, ord=(crc_params->order-8);
|
||||
int i, j, ord = (h->order - 8);
|
||||
unsigned long bit, crc;
|
||||
|
||||
for (i=0; i<256; i++) {
|
||||
crc = ((unsigned long)i)<<ord;
|
||||
for (j=0; j<8; j++) {
|
||||
bit = crc & crc_params->crchighbit;
|
||||
crc<<= 1;
|
||||
if (bit) crc^= crc_params->polynom;
|
||||
for (i = 0; i < 256; i++) {
|
||||
crc = ((unsigned long) i) << ord;
|
||||
for (j = 0; j < 8; j++) {
|
||||
bit = crc & h->crchighbit;
|
||||
crc <<= 1;
|
||||
if (bit)
|
||||
crc ^= h->polynom;
|
||||
}
|
||||
crc_params->table[i]=crc & crc_params->crcmask;
|
||||
h->table[i] = crc & h->crcmask;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
unsigned long crctable (unsigned long length, crc_t *crc_params) {
|
||||
unsigned long crctable(crc_t *h) {
|
||||
|
||||
// Polynom order 8, 16, 24 or 32 only.
|
||||
int ord=crc_params->order-8;
|
||||
unsigned long crc = crc_params->crcinit;
|
||||
unsigned char* data = crc_params->data0;
|
||||
int ord = h->order - 8;
|
||||
unsigned long crc = h->crcinit;
|
||||
unsigned char byte = h->byte;
|
||||
|
||||
while (length--){
|
||||
crc = (crc << 8) ^ crc_params->table[ ((crc >> (ord)) & 0xff) ^ *data++];
|
||||
}
|
||||
return((crc ^ crc_params->crcxor) & crc_params->crcmask);
|
||||
crc = (crc << 8) ^ h->table[((crc >> (ord)) & 0xff) ^ byte];
|
||||
h->crcinit = crc;
|
||||
return (crc & h->crcmask);
|
||||
}
|
||||
|
||||
unsigned long reversecrcbit(unsigned int crc, int nbits, crc_t *crc_params) {
|
||||
unsigned long reversecrcbit(unsigned int crc, int nbits, crc_t *h) {
|
||||
|
||||
unsigned long m, rmask=0x1;
|
||||
unsigned long m, rmask = 0x1;
|
||||
|
||||
for(m=0; m<nbits; m++){
|
||||
if((rmask & crc) == 0x01 )crc = (crc ^ crc_params->polynom)>>1;
|
||||
else crc = crc >> 1;
|
||||
for (m = 0; m < nbits; m++) {
|
||||
if ((rmask & crc) == 0x01)
|
||||
crc = (crc ^ h->polynom) >> 1;
|
||||
else
|
||||
crc = crc >> 1;
|
||||
}
|
||||
return((crc ^ crc_params->crcxor) & crc_params->crcmask);
|
||||
return (crc & h->crcmask);
|
||||
}
|
||||
|
||||
int crc_set_init(crc_t *crc_par, unsigned long crc_init_value) {
|
||||
|
||||
int crc_init(crc_t *crc_par){
|
||||
crc_par->crcinit = crc_init_value;
|
||||
if (crc_par->crcinit != (crc_par->crcinit & crc_par->crcmask)) {
|
||||
printf("ERROR, invalid crcinit in crc_set_init().\n");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crc_init(crc_t *h, unsigned int crc_poly, int crc_order) {
|
||||
|
||||
// Set crc working default parameters
|
||||
h->polynom = crc_poly;
|
||||
h->order = crc_order;
|
||||
h->crcinit = 0x00000000;
|
||||
|
||||
// Compute bit masks for whole CRC and CRC high bit
|
||||
crc_par->crcmask = ((((unsigned long)1<<(crc_par->order-1))-1)<<1)|1;
|
||||
crc_par->crchighbit = (unsigned long)1<<(crc_par->order-1);
|
||||
|
||||
printf("crcmask=%x, crchightbit=%x\n",
|
||||
(unsigned int)crc_par->crcmask, (unsigned int)crc_par->crchighbit);
|
||||
h->crcmask = ((((unsigned long) 1 << (h->order - 1)) - 1) << 1)
|
||||
| 1;
|
||||
h->crchighbit = (unsigned long) 1 << (h->order - 1);
|
||||
|
||||
// check parameters
|
||||
if (crc_par->order%8 != 0) {
|
||||
printf("ERROR, invalid order=%d, it must be 8, 16, 24 or 32.\n", crc_par->order);
|
||||
return(0);
|
||||
if (h->order % 8 != 0) {
|
||||
fprintf(stderr, "ERROR, invalid order=%d, it must be 8, 16, 24 or 32.\n",
|
||||
h->order);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (crc_par->crcinit != (crc_par->crcinit & crc_par->crcmask)) {
|
||||
printf("ERROR, invalid crcinit.\n");
|
||||
return(0);
|
||||
}
|
||||
if (crc_par->crcxor != (crc_par->crcxor & crc_par->crcmask)) {
|
||||
printf("ERROR, invalid crcxor.\n");
|
||||
return(0);
|
||||
if (crc_set_init(h, h->crcinit)) {
|
||||
fprintf(stderr, "Error setting CRC init word\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// generate lookup table
|
||||
gen_crc_table(crc_par);
|
||||
gen_crc_table(h);
|
||||
|
||||
return(1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
unsigned int crc_attach(char *bufptr, int len, crc_t *crc_params) {
|
||||
|
||||
int i, len8, res8, a;
|
||||
unsigned int crc;
|
||||
unsigned int crc_checksum(crc_t *h, char *data, int len) {
|
||||
int i, k, len8, res8, a = 0;
|
||||
unsigned int crc = 0;
|
||||
char *pter;
|
||||
|
||||
#ifdef _WITHMALLOC
|
||||
crc_params->data0 = (unsigned char *)malloc(sizeof(*crc_params->data0) * (len+crc_params->order)*2);
|
||||
if (!crc_params->data0) {
|
||||
perror("malloc ERROR: Allocating memory for data pointer in crc() function");
|
||||
return(-1);
|
||||
}
|
||||
#else
|
||||
if((((len+crc_params->order)>>3) + 1) > MAX_LENGTH){
|
||||
printf("ERROR: Not enough memory allocated\n");
|
||||
return(-1);
|
||||
}
|
||||
#endif
|
||||
//# Pack bits into bytes
|
||||
len8=(len>>3);
|
||||
res8=8-(len - (len8<<3));
|
||||
if(res8>0)a=1;
|
||||
else a=0;
|
||||
crc_set_init(h, 0);
|
||||
|
||||
// Zeroed additional bits
|
||||
memset((char *)(bufptr+len),0,(32)*sizeof(char));
|
||||
|
||||
for(i=0; i<len8+a; i++){
|
||||
pter=(char *)(bufptr+8*i);
|
||||
crc_params->data0[i]=(unsigned char)(unpack_bits(&pter, 8)&0xFF);
|
||||
// Pack bits into bytes
|
||||
len8 = (len >> 3);
|
||||
res8 = (len - (len8 << 3));
|
||||
if (res8 > 0) {
|
||||
a = 1;
|
||||
}
|
||||
|
||||
// Calculate CRC
|
||||
crc=crctable(len8+a, crc_params);
|
||||
for (i = 0; i < len8 + a; i++) {
|
||||
pter = (char *) (data + 8 * i);
|
||||
if (i == len8) {
|
||||
h->byte = 0x00;
|
||||
for (k = 0; k < res8; k++) {
|
||||
h->byte |= ((unsigned char) *(pter + k)) << (7 - k);
|
||||
}
|
||||
} else {
|
||||
h->byte = (unsigned char) (unpack_bits(&pter, 8) & 0xFF);
|
||||
}
|
||||
crc = crctable(h);
|
||||
}
|
||||
|
||||
// Reverse CRC res8 positions
|
||||
if(a==1)crc=reversecrcbit(crc, res8, crc_params);
|
||||
if (a == 1) {
|
||||
crc = reversecrcbit(crc, 8 - res8, h);
|
||||
}
|
||||
|
||||
// Add CRC
|
||||
pter=(char *)(bufptr+len);
|
||||
pack_bits(crc, &pter, crc_params->order);
|
||||
|
||||
#ifdef _WITHMALLOC
|
||||
free(crc_params->data0);
|
||||
crc_params->data0=NULL;
|
||||
#endif
|
||||
//Return CRC value
|
||||
return crc;
|
||||
|
||||
}
|
||||
|
||||
/** Appends crc_order checksum bits to the buffer data.
|
||||
* The buffer data must be len + crc_order bytes
|
||||
*/
|
||||
void crc_attach(crc_t *h, char *data, int len) {
|
||||
unsigned int checksum = crc_checksum(h, data, len);
|
||||
|
||||
unsigned int cword;
|
||||
|
||||
unsigned int icrc1(unsigned int crc, unsigned short onech,int long_crc,
|
||||
int left_shift,unsigned int poly)
|
||||
{
|
||||
int i;
|
||||
unsigned int tmp=(unsigned int) (crc ^ (onech << (long_crc >> 1) ));
|
||||
|
||||
for (i=0;i<left_shift;i++) {
|
||||
if (tmp & (0x1<<(long_crc-1)))
|
||||
tmp=(tmp<<1)^poly;
|
||||
else
|
||||
tmp <<= 1;
|
||||
}
|
||||
|
||||
return tmp;
|
||||
// Add CRC
|
||||
char *ptr = &data[len];
|
||||
pack_bits(checksum, &ptr, h->order);
|
||||
}
|
||||
|
||||
unsigned int crc(unsigned int crc, char *bufptr, int len,
|
||||
int long_crc,unsigned int poly, int paste_word) {
|
||||
|
||||
int i,k;
|
||||
unsigned int data;
|
||||
int stop;
|
||||
unsigned int ret;
|
||||
|
||||
cword=crc;
|
||||
|
||||
k=0;
|
||||
stop=0;
|
||||
while(!stop) {
|
||||
data=0;
|
||||
for (i=0;i<long_crc/2;i++) {
|
||||
if (bufptr[k] && k<len)
|
||||
data|=(0x1<<(long_crc/2-1-i));
|
||||
k++;
|
||||
if (k==len) {
|
||||
stop=1;
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
cword=(unsigned int) (icrc1((unsigned int) (cword<<long_crc>>long_crc),
|
||||
data,long_crc,i,poly)<<long_crc)>>long_crc;
|
||||
}
|
||||
|
||||
ret=cword;
|
||||
if (paste_word) {
|
||||
cword<<=32-long_crc;
|
||||
for (i=0;i<long_crc;i++) {
|
||||
bufptr[i+len]=((cword&(0x1<<31))>>31);
|
||||
cword<<=1;
|
||||
}
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "lte/ratematching/rm_conv.h"
|
||||
#include "lte/fec/rm_conv.h"
|
||||
|
||||
#define NCOLS 32
|
||||
#define NROWS_MAX NCOLS
|
||||
|
@ -59,6 +59,7 @@ int rm_conv_tx(char *input, char *output, int in_len, int out_len) {
|
|||
if (ndummy < 0) {
|
||||
ndummy = 0;
|
||||
}
|
||||
/* Sub-block interleaver 5.1.4.2.1 */
|
||||
k=0;
|
||||
for (s = 0; s < 3; s++) {
|
||||
for (j = 0; j < NCOLS; j++) {
|
||||
|
@ -72,6 +73,7 @@ int rm_conv_tx(char *input, char *output, int in_len, int out_len) {
|
|||
}
|
||||
}
|
||||
}
|
||||
/* Bit collection, selection and transmission 5.1.4.2.2 */
|
||||
k = 0;
|
||||
j = 0;
|
||||
while (k < out_len) {
|
|
@ -0,0 +1,180 @@
|
|||
/**
|
||||
*
|
||||
* \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 <stdio.h>
|
||||
#include "lte/fec/rm_turbo.h"
|
||||
|
||||
#define NCOLS 32
|
||||
#define NROWS_MAX NCOLS
|
||||
#define RATE 3
|
||||
|
||||
unsigned char RM_PERM_CC[NCOLS] =
|
||||
{ 0, 16, 8, 24, 4, 20, 12, 28, 2, 18, 10, 26, 6, 22, 14, 30, 1, 17, 9,
|
||||
25, 5, 21, 13, 29, 3, 19, 11, 27, 7, 23, 15, 31 };
|
||||
|
||||
unsigned char RM_PERM_CC_INV[NCOLS] = { 16, 0, 24, 8, 20, 4, 28, 12, 18, 2, 26,
|
||||
10, 22, 6, 30, 14, 17, 1, 25, 9, 21, 5, 29, 13, 19, 3, 27, 11, 23, 7,
|
||||
31, 15 };
|
||||
|
||||
int rm_turbo_tx(char *input, char *output, int in_len, int out_len) {
|
||||
|
||||
char tmp[RATE * NCOLS * NROWS_MAX];
|
||||
int nrows, ndummy, K_p;
|
||||
|
||||
int i, j, k, s;
|
||||
|
||||
nrows = (int) (in_len / RATE - 1) / NCOLS + 1;
|
||||
if (nrows > NROWS_MAX) {
|
||||
fprintf(stderr, "Input too large. Max input length is %d\n",
|
||||
RATE * NCOLS * NROWS_MAX);
|
||||
return -1;
|
||||
}
|
||||
K_p = nrows * NCOLS;
|
||||
ndummy = K_p - in_len / RATE;
|
||||
if (ndummy < 0) {
|
||||
ndummy = 0;
|
||||
}
|
||||
|
||||
/* Sub-block interleaver 5.1.4.1.1 */
|
||||
k = 0;
|
||||
for (s = 0; s < 3; s++) {
|
||||
for (j = 0; j < NCOLS; j++) {
|
||||
for (i = 0; i < nrows; i++) {
|
||||
if (i * NCOLS + RM_PERM_CC[j] < ndummy) {
|
||||
tmp[k] = TX_NULL;
|
||||
} else {
|
||||
tmp[k] = input[(i * NCOLS + RM_PERM_CC[j] - ndummy) * 3 + s];
|
||||
}
|
||||
k++;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Bit collection, selection and transmission 5.1.4.1.2 */
|
||||
k = 0;
|
||||
j = 0;
|
||||
while (k < out_len) {
|
||||
if (tmp[j] != TX_NULL) {
|
||||
output[k] = tmp[j];
|
||||
k++;
|
||||
}
|
||||
j++;
|
||||
if (j == RATE * K_p) {
|
||||
j = 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Undoes Convolutional Code Rate Matching.
|
||||
* 3GPP TS 36.212 v10.1.0 section 5.1.4.2
|
||||
*/
|
||||
int rm_turbo_rx(float *input, float *output, int in_len, int out_len) {
|
||||
|
||||
int nrows, ndummy, K_p;
|
||||
int i, j, k;
|
||||
int d_i, d_j;
|
||||
|
||||
float tmp[RATE * NCOLS * NROWS_MAX];
|
||||
|
||||
nrows = (int) (out_len / RATE - 1) / NCOLS + 1;
|
||||
if (nrows > NROWS_MAX) {
|
||||
fprintf(stderr, "Output too large. Max output length is %d\n",
|
||||
RATE * NCOLS * NROWS_MAX);
|
||||
return -1;
|
||||
}
|
||||
K_p = nrows * NCOLS;
|
||||
|
||||
ndummy = K_p - out_len / RATE;
|
||||
if (ndummy < 0) {
|
||||
ndummy = 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < RATE * K_p; i++) {
|
||||
tmp[i] = RX_NULL;
|
||||
}
|
||||
|
||||
/* Undo bit collection. Account for dummy bits */
|
||||
k = 0;
|
||||
j = 0;
|
||||
while (k < in_len) {
|
||||
d_i = (j % K_p) / nrows;
|
||||
d_j = (j % K_p) % nrows;
|
||||
|
||||
if (d_j * NCOLS + RM_PERM_CC[d_i] >= ndummy) {
|
||||
if (tmp[j] == RX_NULL) {
|
||||
tmp[j] = input[k];
|
||||
} else if (input[k] != RX_NULL) {
|
||||
tmp[j] += input[k]; /* soft combine LLRs */
|
||||
}
|
||||
k++;
|
||||
}
|
||||
j++;
|
||||
if (j == RATE * K_p) {
|
||||
j = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* interleaving and bit selection */
|
||||
for (i = 0; i < out_len / RATE; i++) {
|
||||
d_i = (i + ndummy) / NCOLS;
|
||||
d_j = (i + ndummy) % NCOLS;
|
||||
for (j = 0; j < RATE; j++) {
|
||||
float o = tmp[K_p * j + RM_PERM_CC_INV[d_j] * nrows + d_i];
|
||||
if (o != RX_NULL) {
|
||||
output[i * RATE + j] = o;
|
||||
} else {
|
||||
output[i * RATE + j] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** High-level API */
|
||||
|
||||
int rm_turbo_initialize(rm_turbo_hl* h) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** This function can be called in a subframe (1ms) basis */
|
||||
int rm_turbo_work(rm_turbo_hl* hl) {
|
||||
if (hl->init.direction) {
|
||||
//rm_turbo_tx(hl->input, hl->output, hl->in_len, hl->ctrl_in.S);
|
||||
hl->out_len = hl->ctrl_in.S;
|
||||
} else {
|
||||
rm_turbo_rx(hl->input, hl->output, hl->in_len, hl->ctrl_in.E);
|
||||
hl->out_len = hl->ctrl_in.E;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rm_turbo_stop(rm_turbo_hl* hl) {
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -20,6 +20,17 @@
|
|||
#
|
||||
|
||||
|
||||
########################################################################
|
||||
# RATEMATCHING TEST
|
||||
########################################################################
|
||||
|
||||
ADD_EXECUTABLE(rm_conv_test rm_conv_test.c)
|
||||
TARGET_LINK_LIBRARIES(rm_conv_test lte)
|
||||
|
||||
ADD_TEST(rm_conv_test_1 rm_conv_test -t 480 -r 1920)
|
||||
ADD_TEST(rm_conv_test_2 rm_conv_test -t 1920 -r 480)
|
||||
|
||||
|
||||
########################################################################
|
||||
# Turbo Coder TEST
|
||||
########################################################################
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
*
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
@ -37,11 +36,10 @@
|
|||
#include "lte.h"
|
||||
#include "crc_test.h"
|
||||
|
||||
int num_bits = 5000, crc_length = 24;
|
||||
int num_bits = 5001, crc_length = 24;
|
||||
unsigned int crc_poly = 0x1864CFB;
|
||||
unsigned int seed = 1;
|
||||
|
||||
|
||||
void usage(char *prog) {
|
||||
printf("Usage: %s [nlps]\n", prog);
|
||||
printf("\t-n num_bits [Default %d]\n", num_bits);
|
||||
|
@ -81,7 +79,7 @@ int main(int argc, char **argv) {
|
|||
|
||||
parse_args(argc, argv);
|
||||
|
||||
data = malloc(sizeof(char) * (num_bits+crc_length)*2);
|
||||
data = malloc(sizeof(char) * (num_bits + crc_length * 2));
|
||||
if (!data) {
|
||||
perror("malloc");
|
||||
exit(-1);
|
||||
|
@ -93,30 +91,23 @@ int main(int argc, char **argv) {
|
|||
srand(seed);
|
||||
|
||||
// Generate data
|
||||
for (i=0;i<num_bits;i++) {
|
||||
data[i] = rand()%2;
|
||||
for (i = 0; i < num_bits; i++) {
|
||||
data[i] = rand() % 2;
|
||||
}
|
||||
|
||||
//Initialize CRC params and tables
|
||||
crc_p.polynom=crc_poly;
|
||||
crc_p.order=crc_length;
|
||||
crc_p.crcinit=0x00000000;
|
||||
crc_p.crcxor=0x00000000;
|
||||
if(!crc_init(&crc_p))exit(0);
|
||||
|
||||
// generate CRC word
|
||||
crc_word = crc_attach(data, num_bits, &crc_p);
|
||||
|
||||
// check if result is zero
|
||||
if (crc_attach(data, num_bits + crc_length, &crc_p)) {
|
||||
printf("CRC check is non-zero\n");
|
||||
if (crc_init(&crc_p, crc_poly, crc_length)) {
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
// generate CRC word
|
||||
crc_word = crc_checksum(&crc_p, data, num_bits);
|
||||
|
||||
free(data);
|
||||
|
||||
// check if generated word is as expected
|
||||
if (get_expected_word(num_bits, crc_length, crc_poly, seed, &expected_word)) {
|
||||
if (get_expected_word(num_bits, crc_length, crc_poly, seed,
|
||||
&expected_word)) {
|
||||
fprintf(stderr, "Test parameters not defined in test_results.h\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,135 @@
|
|||
/**
|
||||
*
|
||||
* \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 <math.h>
|
||||
#include <time.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "lte.h"
|
||||
|
||||
int nof_tx_bits=-1, nof_rx_bits=-1;
|
||||
|
||||
void usage(char *prog) {
|
||||
printf("Usage: %s -t nof_tx_bits -r nof_rx_bits\n", prog);
|
||||
}
|
||||
|
||||
void parse_args(int argc, char **argv) {
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "tr")) != -1) {
|
||||
switch (opt) {
|
||||
case 't':
|
||||
nof_tx_bits = atoi(argv[optind]);
|
||||
break;
|
||||
case 'r':
|
||||
nof_rx_bits = atoi(argv[optind]);
|
||||
break;
|
||||
default:
|
||||
usage(argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
if (nof_tx_bits == -1) {
|
||||
usage(argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
if (nof_rx_bits == -1) {
|
||||
usage(argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int i;
|
||||
char *bits, *rm_bits;
|
||||
float *rm_symbols, *unrm_symbols;
|
||||
int nof_errors;
|
||||
|
||||
parse_args(argc, argv);
|
||||
|
||||
bits = malloc(sizeof(char) * nof_tx_bits);
|
||||
if (!bits) {
|
||||
perror("malloc");
|
||||
exit(-1);
|
||||
}
|
||||
rm_bits = malloc(sizeof(char) * nof_rx_bits);
|
||||
if (!rm_bits) {
|
||||
perror("malloc");
|
||||
exit(-1);
|
||||
}
|
||||
rm_symbols = malloc(sizeof(float) * nof_rx_bits);
|
||||
if (!rm_symbols) {
|
||||
perror("malloc");
|
||||
exit(-1);
|
||||
}
|
||||
unrm_symbols = malloc(sizeof(float) * nof_tx_bits);
|
||||
if (!unrm_symbols) {
|
||||
perror("malloc");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
for (i=0;i<nof_tx_bits;i++) {
|
||||
bits[i] = rand()%2;
|
||||
}
|
||||
|
||||
if (rm_conv_tx(bits, rm_bits, nof_tx_bits, nof_rx_bits)) {
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
for (i=0;i<nof_rx_bits;i++) {
|
||||
rm_symbols[i] = rm_bits[i]?1:-1;
|
||||
}
|
||||
|
||||
if (rm_conv_rx(rm_symbols, unrm_symbols, nof_rx_bits, nof_tx_bits)) {
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
nof_errors = 0;
|
||||
for (i=0;i<nof_tx_bits;i++) {
|
||||
if ((unrm_symbols[i] > 0) != bits[i]) {
|
||||
nof_errors++;
|
||||
}
|
||||
}
|
||||
if (nof_rx_bits > nof_tx_bits) {
|
||||
if (nof_errors) {
|
||||
printf("nof_errors=%d\n", nof_errors);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
free(bits);
|
||||
free(rm_bits);
|
||||
free(rm_symbols);
|
||||
free(unrm_symbols);
|
||||
|
||||
printf("Ok\n");
|
||||
exit(0);
|
||||
}
|
|
@ -133,6 +133,9 @@ int pbch_init(pbch_t *q, int nof_prb, int cell_id, lte_cp_t cp) {
|
|||
if (viterbi_init(&q->decoder, viterbi_37, poly, 40, true)) {
|
||||
goto clean;
|
||||
}
|
||||
if (crc_init(&q->crc, LTE_CRC16, 16)) {
|
||||
goto clean;
|
||||
}
|
||||
q->encoder.K = 7;
|
||||
q->encoder.R = 3;
|
||||
q->encoder.tail_biting = true;
|
||||
|
@ -356,11 +359,11 @@ void crc_set_mask(char *data, int nof_ports) {
|
|||
*
|
||||
* Returns 0 if the data is correct, -1 otherwise
|
||||
*/
|
||||
int pbch_crc_check(char *bits, int nof_ports) {
|
||||
int pbch_crc_check(pbch_t *q, char *bits, int nof_ports) {
|
||||
char data[40];
|
||||
memcpy(data, bits, 40 * sizeof(char));
|
||||
crc_set_mask(data, nof_ports);
|
||||
return crc(0, data, 40, 16, LTE_CRC16, 0);
|
||||
return crc_checksum(&q->crc, data, 40);
|
||||
}
|
||||
|
||||
int pbch_decode_frame(pbch_t *q, pbch_mib_t *mib, int src, int dst, int n, int nof_bits, int nof_ports) {
|
||||
|
@ -399,7 +402,7 @@ int pbch_decode_frame(pbch_t *q, pbch_mib_t *mib, int src, int dst, int n, int n
|
|||
c=1;
|
||||
}
|
||||
|
||||
if (!pbch_crc_check(q->data, nof_ports)) {
|
||||
if (!pbch_crc_check(q, q->data, nof_ports)) {
|
||||
/* unpack MIB */
|
||||
pbch_mib_unpack(q->data, mib);
|
||||
|
||||
|
@ -523,7 +526,7 @@ void pbch_encode(pbch_t *q, pbch_mib_t *mib, cf_t *slot1_symbols[MAX_PORTS_CTRL]
|
|||
pbch_mib_pack(mib, q->data);
|
||||
|
||||
/* encode & modulate */
|
||||
crc(0, q->data, 24, 16, 0x11021, 1);
|
||||
crc_attach(&q->crc, q->data, 24);
|
||||
crc_set_mask(q->data, nof_ports);
|
||||
|
||||
convcoder_encode(&q->encoder, q->data, q->data_enc, 40);
|
||||
|
|
|
@ -221,6 +221,9 @@ int pdcch_init(pdcch_t *q, regs_t *regs, int nof_prb, int nof_ports,
|
|||
if (modem_table_std(&q->mod, LTE_QPSK, true)) {
|
||||
goto clean;
|
||||
}
|
||||
if (crc_init(&q->crc, LTE_CRC16, 16)) {
|
||||
goto clean;
|
||||
}
|
||||
|
||||
demod_soft_init(&q->demod);
|
||||
demod_soft_table_set(&q->demod, &q->mod);
|
||||
|
@ -318,7 +321,7 @@ void pdcch_free(pdcch_t *q) {
|
|||
*
|
||||
* TODO: UE transmit antenna selection CRC mask
|
||||
*/
|
||||
unsigned short dci_decode(viterbi_t *decoder, float *e, char *data, int E,
|
||||
unsigned short dci_decode(pdcch_t *q, float *e, char *data, int E,
|
||||
int nof_bits) {
|
||||
|
||||
float tmp[3 * (DCI_MAX_BITS + 16)];
|
||||
|
@ -343,7 +346,7 @@ unsigned short dci_decode(viterbi_t *decoder, float *e, char *data, int E,
|
|||
}
|
||||
|
||||
/* viterbi decoder */
|
||||
viterbi_decode_f(decoder, tmp, data, nof_bits + 16);
|
||||
viterbi_decode_f(&q->decoder, tmp, data, nof_bits + 16);
|
||||
|
||||
if (VERBOSE_ISDEBUG()) {
|
||||
bit_fprint(stdout, data, nof_bits+16);
|
||||
|
@ -351,8 +354,7 @@ unsigned short dci_decode(viterbi_t *decoder, float *e, char *data, int E,
|
|||
|
||||
x = &data[nof_bits];
|
||||
p_bits = (unsigned short) bit_unpack(&x, 16);
|
||||
crc_res = ((unsigned short) crc(0, data, nof_bits, 16, LTE_CRC16, 0)
|
||||
& 0xffff);
|
||||
crc_res = ((unsigned short) crc_checksum(&q->crc, data, nof_bits) & 0xffff);
|
||||
DEBUG("p_bits: 0x%x, crc_res: 0x%x, tot: 0x%x\n", p_bits, crc_res, p_bits ^ crc_res);
|
||||
return (p_bits ^ crc_res);
|
||||
}
|
||||
|
@ -363,7 +365,7 @@ int pdcch_decode_candidate(pdcch_t *q, float *llr, dci_candidate_t *c,
|
|||
DEBUG("Trying Candidate: Nbits: %d, E: %d, nCCE: %d, L: %d, RNTI: 0x%x\n",
|
||||
c->nof_bits, PDCCH_FORMAT_NOF_BITS(c->L), c->ncce, c->L,
|
||||
c->rnti);
|
||||
crc_res = dci_decode(&q->decoder, &llr[72 * c->ncce], msg->data,
|
||||
crc_res = dci_decode(q, &llr[72 * c->ncce], msg->data,
|
||||
PDCCH_FORMAT_NOF_BITS(c->L), c->nof_bits);
|
||||
|
||||
if (c->rnti == crc_res) {
|
||||
|
@ -519,7 +521,7 @@ void crc_set_mask_rnti(char *crc, unsigned short rnti) {
|
|||
/** 36.212 5.3.3.2 to 5.3.3.4
|
||||
* TODO: UE transmit antenna selection CRC mask
|
||||
*/
|
||||
void dci_encode(char *data, char *e, int nof_bits, int E, unsigned short rnti) {
|
||||
void dci_encode(pdcch_t *q, char *data, char *e, int nof_bits, int E, unsigned short rnti) {
|
||||
convcoder_t encoder;
|
||||
char tmp[3 * (DCI_MAX_BITS + 16)];
|
||||
|
||||
|
@ -531,7 +533,7 @@ void dci_encode(char *data, char *e, int nof_bits, int E, unsigned short rnti) {
|
|||
encoder.tail_biting = true;
|
||||
memcpy(encoder.poly, poly, 3 * sizeof(int));
|
||||
|
||||
crc(0, data, nof_bits, 16, LTE_CRC16, 1);
|
||||
crc_attach(&q->crc, data, nof_bits);
|
||||
crc_set_mask_rnti(&data[nof_bits], rnti);
|
||||
|
||||
convcoder_encode(&encoder, data, tmp, nof_bits + 16);
|
||||
|
@ -579,7 +581,7 @@ int pdcch_encode(pdcch_t *q, dci_t *dci, cf_t *slot1_symbols[MAX_PORTS_CTRL],
|
|||
i, dci->msg[i].location.nof_bits, PDCCH_FORMAT_NOF_BITS(dci->msg[i].location.L),
|
||||
dci->msg[i].location.ncce, dci->msg[i].location.L, dci->msg[i].location.rnti);
|
||||
|
||||
dci_encode(dci->msg[i].data, &q->pdcch_e[72 * dci->msg[i].location.ncce],
|
||||
dci_encode(q, dci->msg[i].data, &q->pdcch_e[72 * dci->msg[i].location.ncce],
|
||||
dci->msg[i].location.nof_bits, PDCCH_FORMAT_NOF_BITS(dci->msg[i].location.L),
|
||||
dci->msg[i].location.rnti);
|
||||
}
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
#
|
||||
# Copyright 2012-2013 The libLTE Developers. See the
|
||||
# COPYRIGHT file at the top-level directory of this distribution.
|
||||
#
|
||||
# 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/.
|
||||
#
|
||||
|
||||
########################################################################
|
||||
# RATEMATCHING TEST
|
||||
########################################################################
|
||||
|
||||
ADD_EXECUTABLE(rm_conv_test rm_conv_test.c)
|
||||
TARGET_LINK_LIBRARIES(rm_conv_test lte)
|
||||
|
||||
ADD_TEST(rm_conv_test_1 rm_conv_test -t 480 -r 1920)
|
||||
ADD_TEST(rm_conv_test_2 rm_conv_test -t 1920 -r 480)
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue