PDCCH working branch

This commit is contained in:
ismagom 2014-04-17 11:28:21 +01:00
parent e1334ff028
commit 355ed0386d
28 changed files with 1533 additions and 76 deletions

View File

@ -152,7 +152,7 @@ void base_init() {
fprintf(stderr, "Error creating iFFT object\n");
exit(-1);
}
if (pbch_init(&pbch, cell_id, CPNORM)) {
if (pbch_init(&pbch, 6, cell_id, CPNORM)) {
fprintf(stderr, "Error creating PBCH object\n");
exit(-1);
}
@ -249,7 +249,7 @@ int main(int argc, char **argv) {
sss_put_slot(ns?sss_signal5:sss_signal0, slot_buffer, nof_prb, CPNORM);
break;
case 1: // tx pbch
pbch_encode(&pbch, &mib, slot1_symbols, nof_prb, 1);
pbch_encode(&pbch, &mib, slot1_symbols, 1);
break;
default: // transmit zeros
break;

View File

@ -274,7 +274,7 @@ int mib_decoder_init(int cell_id) {
return -1;
}
if (pbch_init(&pbch, cell_id, CPNORM)) {
if (pbch_init(&pbch, 6, cell_id, CPNORM)) {
fprintf(stderr, "Error initiating PBCH\n");
return -1;
}
@ -292,7 +292,7 @@ int mib_decoder_run(cf_t *input, pbch_mib_t *mib) {
}
DEBUG("Decoding PBCH\n", 0);
n = pbch_decode(&pbch, fft_buffer, ce, 6, 1, mib);
n = pbch_decode(&pbch, fft_buffer, ce, 1, mib);
#ifndef DISABLE_GRAPHICS

View File

@ -325,7 +325,7 @@ int mib_decoder_init(int cell_id) {
return -1;
}
if (pbch_init(&pbch, cell_id, CPNORM)) {
if (pbch_init(&pbch, 6, cell_id, CPNORM)) {
fprintf(stderr, "Error initiating PBCH\n");
return -1;
}
@ -343,7 +343,7 @@ int mib_decoder_run(cf_t *input, pbch_mib_t *mib) {
}
DEBUG("Decoding PBCH\n", 0);
return pbch_decode(&pbch, fft_buffer, ce, 6, 1, mib);
return pbch_decode(&pbch, fft_buffer, ce, 1, mib);
}
int main(int argc, char **argv) {

View File

@ -72,6 +72,8 @@
#include "lte/mimo/layermap.h"
#include "lte/phch/regs.h"
#include "lte/phch/dci.h"
#include "lte/phch/pdcch.h"
#include "lte/phch/pbch.h"
#include "lte/phch/pcfich.h"
#include "lte/phch/phich.h"

View File

@ -32,6 +32,8 @@
#define NSUBFRAMES_X_FRAME 10
#define NSLOTS_X_FRAME (2*NSUBFRAMES_X_FRAME)
#define LTE_NIL_SYMBOL 2
#define MAX_PORTS 4
#define MAX_PORTS_CTRL 4
#define MAX_LAYERS 8
@ -39,6 +41,9 @@
typedef enum {CPNORM, CPEXT} lte_cp_t;
#define SIRNTI 0xFFFF
#define PRNTI 0xFFFE
#define MAX_NSYMB 7
#define CPNORM_NSYMB 7

View File

@ -44,5 +44,6 @@ int sequence_LTEPRS(sequence_t *q, int len, int seed);
int sequence_pbch(sequence_t *seq, lte_cp_t cp, int cell_id);
int sequence_pcfich(sequence_t *seq, int nslot, int cell_id);
int sequence_phich(sequence_t *seq, int nslot, int cell_id);
int sequence_pdcch(sequence_t *seq, int nslot, int cell_id, int len);
#endif

View File

@ -38,11 +38,10 @@ typedef struct {
int R;
int K;
int poly[3];
int framelength;
bool tail_biting;
}convcoder_t;
int convcoder_encode(convcoder_t *q, char *input, char *output);
int convcoder_encode(convcoder_t *q, char *input, char *output, int frame_length);
/* High-level API */

View File

@ -30,6 +30,11 @@
#ifndef CRC_
#define CRC_
#define LTE_CRC24A 0x1864CFB
#define LTE_CRC24B 0X1800063
#define LTE_CRC16 0x11021
#define LTE_CRC8 0x19B
unsigned int crc(unsigned int crc, char *bufptr, int len,
int long_crc,unsigned int poly, int paste_word);

View File

@ -42,16 +42,16 @@ typedef struct {
unsigned int framebits;
bool tail_biting;
int poly[3];
int (*decode) (void*, unsigned char*, char*);
int (*decode) (void*, unsigned char*, char*, int);
void (*free) (void*);
unsigned char *tmp;
unsigned char *symbols_uc;
}viterbi_t;
int viterbi_init(viterbi_t *q, viterbi_type_t type, int poly[3], int framebits, bool tail_bitting);
int viterbi_init(viterbi_t *q, viterbi_type_t type, int poly[3], int max_frame_length, bool tail_bitting);
void viterbi_free(viterbi_t *q);
int viterbi_decode_f(viterbi_t *q, float *symbols, char *data);
int viterbi_decode_uc(viterbi_t *q, unsigned char *symbols, char *data);
int viterbi_decode_f(viterbi_t *q, float *symbols, char *data, int frame_length);
int viterbi_decode_uc(viterbi_t *q, unsigned char *symbols, char *data, int frame_length);
/* High-level API */

113
lte/include/lte/phch/dci.h Normal file
View File

@ -0,0 +1,113 @@
/**
*
* \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 DCI_
#define DCI_
#include "lte/common/base.h"
typedef _Complex float cf_t;
/**
* DCI message generation according to the formats, as specified in
* 36.212 Section 5.3.3.1
*
* Call the function dci_init(&q) to generate a collection of DCI messages
* to be transmitted in a subframe. Each subsequent call to
* dci_add_formatXX(&q, ...) generates the DCI message and appends the data
* to the collection "q".
*
*/
#define DCI_MAX_BITS 45
typedef enum {
FORMAT0,
FORMAT1,
FORMAT1A,
/* ... */
}dci_format_t;
typedef enum {
DCI_COMMON=0, DCI_UE=1
}dci_spec_t;
/** TODO: this is Release 8 */
typedef struct {
/* 36.213 Table 8.4-2: hop_half is 0 for < 10 Mhz and 10 for > 10 Mh.
* hop_quart is 00 for > 10 Mhz and hop_quart_neg is 01 for > 10 Mhz.
*/
enum {hop_disabled, hop_half, hop_quart, hop_quart_neg, hop_type_2} freq_hop_fl;
int n_rb_ul; // number of resource blocks
int riv; // Resource Indication Value (36.213 8.1)
int mcs_and_rv; // MCS and RV value
enum {ndi_true=1, ndi_false=0} ndi; // New Data Indicator
int tpc; // Transmit Power Control
int dm_rs; // DM RS
enum {cqi_true=0, cqi_false=1} cqi_request;
}dci_format0_t;
typedef struct {
}dci_format1_t;
typedef struct {
unsigned char nof_bits;
unsigned char L; // Aggregation level
unsigned char ncce; // Position of first CCE of the dci
unsigned short rnti;
}dci_candidate_t;
typedef struct {
char data[DCI_MAX_BITS];
dci_candidate_t location;
}dci_msg_t;
typedef struct {
dci_msg_t *msg;
int nof_dcis;
}dci_t;
int dci_init(dci_t *q, int nof_dci);
void dci_free(dci_t *q);
void dci_candidate_fprint(FILE *f, dci_candidate_t *q);
int dci_format0_add(dci_t *q, dci_format0_t *msg, int L, int nCCE, unsigned short rnti);
int dci_format0_sizeof(int nof_prb);
int dci_format1_add(dci_t *q, dci_format1_t *msg, int L, int nCCE, unsigned short rnti);
int dci_format1_sizeof(int nof_prb);
int dci_format1A_add(dci_t *q, dci_format1_t *msg, int L, int nCCE, unsigned short rnti);
int dci_format1A_sizeof(int nof_prb);
int dci_format1C_add(dci_t *q, dci_format1_t *msg, int L, int nCCE, unsigned short rnti);
int dci_format1C_sizeof(int nof_prb);
#endif

View File

@ -57,6 +57,7 @@ typedef struct {
typedef struct {
int cell_id;
lte_cp_t cp;
int nof_prb;
int nof_symbols;
/* buffers */
@ -82,11 +83,10 @@ typedef struct {
}pbch_t;
int pbch_init(pbch_t *q, int cell_id, lte_cp_t cp);
int pbch_init(pbch_t *q, int nof_prb, int cell_id, lte_cp_t cp);
void pbch_free(pbch_t *q);
int pbch_decode(pbch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL], int nof_prb, float ebno, pbch_mib_t *mib);
void pbch_encode(pbch_t *q, pbch_mib_t *mib, cf_t *slot1_symbols[MAX_PORTS_CTRL],
int nof_prb, int nof_ports);
int pbch_decode(pbch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL], float ebno, pbch_mib_t *mib);
void pbch_encode(pbch_t *q, pbch_mib_t *mib, cf_t *slot1_symbols[MAX_PORTS_CTRL], int nof_ports);
void pbch_decode_reset(pbch_t *q);
void pbch_mib_fprint(FILE *stream, pbch_mib_t *mib);

View File

@ -0,0 +1,126 @@
/**
*
* \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 PDCCH_
#define PDCCH_
#include "lte/common/base.h"
#include "lte/mimo/precoding.h"
#include "lte/mimo/layermap.h"
#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/convcoder.h"
#include "lte/fec/viterbi.h"
#include "lte/fec/crc.h"
#include "lte/phch/dci.h"
#include "lte/phch/regs.h"
typedef _Complex float cf_t;
#define PDCCH_NOF_SEARCH_MODES 3
typedef enum {
SEARCH_NONE=3, SEARCH_SI=0, SEARCH_RA=1, SEARCH_UE=2
}pdcch_search_mode_t;
/*
* A search mode is indicated by higher layers to look for SI/C/RA-RNTI
* DCI messages as defined in Section 7.1 of 36.213
*/
typedef struct {
int nof_candidates;
dci_candidate_t *candidates[NSUBFRAMES_X_FRAME];
}pdcch_search_t;
/* PDCCH object */
typedef struct {
int cell_id;
lte_cp_t cp;
int nof_prb;
int nof_bits;
int nof_symbols;
int nof_ports;
int nof_regs;
int nof_cce;
pdcch_search_t search_mode[PDCCH_NOF_SEARCH_MODES];
pdcch_search_mode_t current_search_mode;
regs_t *regs;
/* buffers */
cf_t *ce[MAX_PORTS_CTRL];
cf_t *pdcch_symbols[MAX_PORTS_CTRL];
cf_t *pdcch_x[MAX_PORTS_CTRL];
cf_t *pdcch_d;
char *pdcch_e;
float *pdcch_llr;
/* tx & rx objects */
modem_table_t mod;
demod_soft_t demod;
sequence_t seq_pdcch[NSUBFRAMES_X_FRAME];
viterbi_t decoder;
}pdcch_t;
int pdcch_init(pdcch_t *q, regs_t *regs, int nof_prb, int nof_ports, int cell_id, lte_cp_t cp);
void pdcch_free(pdcch_t *q);
/* Encoding functions */
int pdcch_encode(pdcch_t *q, dci_t *dci, cf_t *slot1_symbols[MAX_PORTS_CTRL], int nsubframe);
/* Decoding functions */
/* There are two ways to decode the DCI messages:
* a) call pdcch_set_search_si/ue/ra and then call pdcch_decode()
* b) call pdcch_extract_llr() and then call pdcch_decode_si/ue/ra
*/
int pdcch_decode(pdcch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL],
dci_t *dci, int nsubframe, float ebno);
int pdcch_extract_llr(pdcch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL], float *llr,
int nsubframe, float ebno);
void pdcch_init_search_si(pdcch_t *q);
void pdcch_set_search_si(pdcch_t *q);
int pdcch_decode_si(pdcch_t *q, float *llr, dci_t *dci);
void pdcch_init_search_ue(pdcch_t *q, unsigned short c_rnti);
void pdcch_set_search_ue(pdcch_t *q);
int pdcch_decode_ue(pdcch_t *q, float *llr, dci_t *dci, int nsubframe);
void pdcch_init_search_ra(pdcch_t *q, unsigned short ra_rnti);
void pdcch_set_search_ra(pdcch_t *q);
int pdcch_decode_ra(pdcch_t *q, float *llr, dci_t *dci);
#endif

View File

@ -89,5 +89,6 @@ int regs_phich_get(regs_t *h, cf_t *slot_symbols, cf_t phich_symbols[REGS_PHICH_
int regs_phich_ngroups(regs_t *h);
int regs_phich_reset(regs_t *h, cf_t *slot_symbols);
int regs_pdcch_nregs(regs_t *h);
#endif

View File

@ -33,27 +33,25 @@
#include "lte/fec/convcoder.h"
#include "parity.h"
int convcoder_encode(convcoder_t *q, char *input, char *output) {
int convcoder_encode(convcoder_t *q, char *input, char *output, int frame_length) {
unsigned int sr;
int i,j;
int len = q->tail_biting ? q->framelength : (q->framelength + q->K - 1);
int len = q->tail_biting ? frame_length : (frame_length + q->K - 1);
if (q->tail_biting) {
sr = 0;
for (i=q->framelength - q->K + 1; i<q->framelength; i++) {
for (i=frame_length - q->K + 1; i<frame_length; i++) {
sr = (sr << 1) | (input[i] & 1);
}
} else {
sr = 0;
}
//printf("Start state %d\n", sr);
for (i = 0; i < len; i++) {
int bit = (i < q->framelength) ? (input[i] & 1) : 0;
int bit = (i < frame_length) ? (input[i] & 1) : 0;
sr = (sr << 1) | bit;
for (j=0;j<q->R;j++) {
output[q->R * i + j] = parity(sr & q->poly[j]);
}
//printf("%3d - sr=%u\n", i, sr%64);
}
return q->R*len;
@ -69,12 +67,11 @@ int convcoder_work(convcoder_hl* hl) {
hl->obj.K = hl->ctrl_in.constraint_length;
hl->obj.R = hl->ctrl_in.rate;
hl->obj.framelength = hl->in_len;
hl->obj.poly[0] = hl->ctrl_in.generator_0;
hl->obj.poly[1] = hl->ctrl_in.generator_1;
hl->obj.poly[2] = hl->ctrl_in.generator_2;
hl->obj.tail_biting = hl->ctrl_in.tail_bitting?true:false;
hl->out_len = convcoder_encode(&hl->obj, hl->input, hl->output);
hl->out_len = convcoder_encode(&hl->obj, hl->input, hl->output, hl->in_len);
return 0;
}

View File

@ -38,49 +38,62 @@
#define DEB 0
int decode37(void *o, unsigned char *symbols, char *data) {
int decode37(void *o, unsigned char *symbols, char *data, int frame_length) {
viterbi_t *q = o;
int i;
int best_state;
if (frame_length > q->framebits) {
fprintf(stderr, "Initialized decoder for max frame length %d bits\n",
q->framebits);
return -1;
}
/* Initialize Viterbi decoder */
init_viterbi37_port(q->ptr, q->tail_biting?-1:0);
init_viterbi37_port(q->ptr, q->tail_biting ? -1 : 0);
/* Decode block */
if (q->tail_biting) {
memcpy(q->tmp, symbols, 3 * q->framebits * sizeof(char));
for (i=0;i<3*(q->K-1);i++) {
q->tmp[i+3*q->framebits] = q->tmp[i];
memcpy(q->tmp, symbols, 3 * frame_length * sizeof(char));
for (i = 0; i < 3 * (q->K - 1); i++) {
q->tmp[i + 3 * frame_length] = q->tmp[i];
}
} else {
q->tmp = symbols;
}
update_viterbi37_blk_port(q->ptr, q->tmp, q->framebits + q->K - 1, q->tail_biting?&best_state:NULL);
update_viterbi37_blk_port(q->ptr, q->tmp, frame_length + q->K - 1,
q->tail_biting ? &best_state : NULL);
/* Do Viterbi chainback */
chainback_viterbi37_port(q->ptr, data, q->framebits, q->tail_biting?best_state:0);
chainback_viterbi37_port(q->ptr, data, frame_length,
q->tail_biting ? best_state : 0);
return q->framebits;
}
int decode39(void *o, unsigned char *symbols, char *data) {
int decode39(void *o, unsigned char *symbols, char *data, int frame_length) {
viterbi_t *q = o;
if (frame_length > q->framebits) {
fprintf(stderr, "Initialized decoder for max frame length %d bits\n",
q->framebits);
return -1;
}
/* Initialize Viterbi decoder */
init_viterbi39_port(q->ptr, 0);
/* Decode block */
update_viterbi39_blk_port(q->ptr, symbols,q->framebits + q->K - 1);
update_viterbi39_blk_port(q->ptr, symbols, frame_length + q->K - 1);
/* Do Viterbi chainback */
chainback_viterbi39_port(q->ptr, data, q->framebits, 0);
chainback_viterbi39_port(q->ptr, data, frame_length, 0);
return q->framebits;
}
void free37(void *o) {
viterbi_t *q = o;
if (q->symbols_uc) {
@ -107,13 +120,13 @@ int init37(viterbi_t *q, int poly[3], int framebits, bool tail_biting) {
q->tail_biting = tail_biting;
q->decode = decode37;
q->free = free37;
q->symbols_uc = malloc(3 * (q->framebits + q->K -1) * sizeof(char));
q->symbols_uc = malloc(3 * (q->framebits + q->K - 1) * sizeof(char));
if (!q->symbols_uc) {
perror("malloc");
return -1;
}
if (q->tail_biting) {
q->tmp = malloc(3 * (q->framebits + q->K -1) * sizeof(char));
q->tmp = malloc(3 * (q->framebits + q->K - 1) * sizeof(char));
if (!q->tmp) {
perror("malloc");
free37(q);
@ -140,10 +153,11 @@ int init39(viterbi_t *q, int poly[3], int framebits, bool tail_biting) {
q->decode = decode39;
q->free = free39;
if (q->tail_biting) {
fprintf(stderr, "Error: Tailbitting not supported in 1/3 K=9 decoder\n");
fprintf(stderr,
"Error: Tailbitting not supported in 1/3 K=9 decoder\n");
return -1;
}
q->symbols_uc = malloc(3 * (q->framebits + q->K -1) * sizeof(char));
q->symbols_uc = malloc(3 * (q->framebits + q->K - 1) * sizeof(char));
if (!q->symbols_uc) {
perror("malloc");
return -1;
@ -157,12 +171,13 @@ int init39(viterbi_t *q, int poly[3], int framebits, bool tail_biting) {
}
}
int viterbi_init(viterbi_t *q, viterbi_type_t type, int poly[3], int framebits, bool tail_bitting) {
switch(type) {
int viterbi_init(viterbi_t *q, viterbi_type_t type, int poly[3],
int max_frame_length, bool tail_bitting) {
switch (type) {
case viterbi_37:
return init37(q, poly, framebits, tail_bitting);
return init37(q, poly, max_frame_length, tail_bitting);
case viterbi_39:
return init39(q, poly, framebits, tail_bitting);
return init39(q, poly, max_frame_length, tail_bitting);
default:
fprintf(stderr, "Decoder not implemented\n");
return -1;
@ -174,22 +189,27 @@ void viterbi_free(viterbi_t *q) {
}
/* symbols are real-valued */
int viterbi_decode_f(viterbi_t *q, float *symbols, char *data) {
int viterbi_decode_f(viterbi_t *q, float *symbols, char *data, int frame_length) {
int len;
if (frame_length > q->framebits) {
fprintf(stderr, "Initialized decoder for max frame length %d bits\n",
q->framebits);
return -1;
}
if (q->tail_biting) {
len = 3 * q->framebits;
len = 3 * frame_length;
} else {
len = 3 * (q->framebits + q->K - 1);
len = 3 * (frame_length + q->K - 1);
}
vec_quant_fuc(symbols, q->symbols_uc, 32, 127.5, 255, len);
return q->decode(q, q->symbols_uc, data);
return q->decode(q, q->symbols_uc, data, frame_length);
}
int viterbi_decode_uc(viterbi_t *q, unsigned char *symbols, char *data) {
return q->decode(q, symbols, data);
int viterbi_decode_uc(viterbi_t *q, unsigned char *symbols, char *data,
int frame_length) {
return q->decode(q, symbols, data, frame_length);
}
int viterbi_initialize(viterbi_hl* h) {
int poly[3];
viterbi_type_t type;
@ -222,15 +242,16 @@ int viterbi_initialize(viterbi_hl* h) {
poly[1] = h->init.generator_1;
poly[2] = h->init.generator_2;
return viterbi_init(&h->obj, type, poly, h->init.frame_length,
h->init.tail_bitting?true:false);
h->init.tail_bitting ? true : false);
}
int viterbi_work(viterbi_hl* hl) {
if (hl->in_len != hl->init.frame_length) {
fprintf(stderr, "Expected input length %d but got %d\n", hl->init.frame_length, hl->in_len);
fprintf(stderr, "Expected input length %d but got %d\n",
hl->init.frame_length, hl->in_len);
return -1;
}
return viterbi_decode_f(&hl->obj, hl->input, hl->output);
return viterbi_decode_f(&hl->obj, hl->input, hl->output, hl->init.frame_length);
}
int viterbi_stop(viterbi_hl* h) {

View File

@ -27,6 +27,8 @@
#include <stdbool.h>
#include "lte/fec/crc.h"
typedef struct {
int n;
int l;
@ -37,10 +39,10 @@ typedef struct {
static expected_word_t expected_words[] = {
{5000, 24, 0x1864CFB, 1, 0x4D0836}, // LTE CRC24A (36.212 Sec 5.1.1)
{5000, 24, 0X1800063, 1, 0x9B68F8}, // LTE CRC24B
{5000, 16, 0x11021, 1, 0xBFFA}, // LTE CRC16
{5000, 8, 0x19B, 1, 0xF8}, // LTE CRC8
{5000, 24, LTE_CRC24A, 1, 0x4D0836}, // LTE CRC24A (36.212 Sec 5.1.1)
{5000, 24, LTE_CRC24B, 1, 0x9B68F8}, // LTE CRC24B
{5000, 16, LTE_CRC16, 1, 0xBFFA}, // LTE CRC16
{5000, 8, LTE_CRC8, 1, 0xF8}, // LTE CRC8
{-1, -1, 0, 0, 0}
};

View File

@ -187,7 +187,6 @@ int main(int argc, char **argv) {
max_coded_length = 0;
for (i=0;i<ncods;i++) {
cod[i].R = 3;
cod[i].framelength = frame_length;
coded_length[i] = cod[i].R * (frame_length + ((cod[i].tail_biting) ? 0 : cod[i].K - 1));
if (coded_length[i] > max_coded_length) {
max_coded_length = coded_length[i];
@ -273,7 +272,7 @@ int main(int argc, char **argv) {
/* coded BER */
for (n=0;n<ncods;n++) {
convcoder_encode(&cod[n], data_tx, symbols);
convcoder_encode(&cod[n], data_tx, symbols, frame_length);
for (j = 0; j < coded_length[n]; j++) {
llr[j] = symbols[j] ? sqrt(2) : -sqrt(2);
@ -283,7 +282,7 @@ int main(int argc, char **argv) {
vec_quant_fuc(llr, llr_c, Gain, 127.5, 255, coded_length[n]);
/* decoder 1 */
viterbi_decode_uc(&dec[n], llr_c, data_rx[1+n]);
viterbi_decode_uc(&dec[n], llr_c, data_rx[1+n], frame_length);
}
/* check errors */

122
lte/lib/phch/src/dci.c Normal file
View File

@ -0,0 +1,122 @@
/**
*
* \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 "lte/phch/dci.h"
#include "lte/common/base.h"
#include "lte/utils/bit.h"
#include "lte/utils/vector.h"
#include "lte/utils/debug.h"
int dci_init(dci_t *q, int nof_dcis) {
q->msg = calloc(sizeof(dci_msg_t), nof_dcis);
if (!q->msg) {
perror("malloc");
return -1;
}
q->nof_dcis = nof_dcis;
return 0;
}
void dci_free(dci_t *q) {
if (q->msg) {
free(q->msg);
}
}
void dci_candidate_fprint(FILE *f, dci_candidate_t *q) {
fprintf(f, "L: %d, nCCE: %d, RNTI: 0x%x, nBits: %d\n",
q->L, q->ncce, q->rnti, q->nof_bits);
}
int dci_format1_add(dci_t *q, dci_format1_t *msg) {
int i, j;
i=0;
while(i<q->nof_dcis && q->msg[i].location.nof_bits)
i++;
if (i == q->nof_dcis) {
fprintf(stderr, "No more space in DCI container\n");
return -1;
}
q->msg[i].location.L = 0;
q->msg[i].location.ncce = 0;
q->msg[i].location.nof_bits = dci_format1_sizeof();
q->msg[i].location.rnti = 1234;
for (j=0;j<q->msg[i].location.nof_bits;j++) {
q->msg[i].data[j] = rand()%2;
}
return 0;
}
int dci_format0_add(dci_t *q, dci_format0_t *msg, int L, int nCCE, unsigned short rnti) {
int i, j;
i=0;
while(i<q->nof_dcis && q->msg[i].location.nof_bits)
i++;
if (i == q->nof_dcis) {
fprintf(stderr, "No more space in DCI container\n");
return -1;
}
q->msg[i].location.L = L;
q->msg[i].location.ncce = nCCE;
q->msg[i].location.nof_bits = dci_format0_sizeof(msg->n_rb_ul);
q->msg[i].location.rnti = rnti;
for (j=0;j<q->msg[i].location.nof_bits;j++) {
q->msg[i].data[j] = rand()%2;
}
return 0;
}
int dci_format0_sizeof(int nof_prb) {
return 1+1+(int) ceilf(log2f(nof_prb*(nof_prb+1)/2))+2+3+1;
}
int dci_format1_sizeof(int nof_prb, int P) {
return (nof_prb>10)?1:0+(int) ceilf(log2f(nof_prb/P))+5+3+1+2+2;
}
int dci_format1A_sizeof(int nof_prb, bool random_access_initiated) {
if (random_access_initiated) {
return 1+(int) ceilf(log2f(nof_prb*(nof_prb+1)/2))+6+4;
} else {
return 1+(int) ceilf(log2f(nof_prb*(nof_prb+1)/2))+5+3+1+2+2;
}
}
int dci_format1C_sizeof() {
return 10;
}

View File

@ -109,7 +109,7 @@ int pbch_get(cf_t *slot1_data, cf_t *pbch, int nof_prb, lte_cp_t cp, int cell_id
}
/** Initializes the PBCH transmitter and receiver */
int pbch_init(pbch_t *q, int cell_id, lte_cp_t cp) {
int pbch_init(pbch_t *q, int nof_prb, int cell_id, lte_cp_t cp) {
int ret = -1;
if (cell_id < 0) {
return -1;
@ -117,6 +117,7 @@ int pbch_init(pbch_t *q, int cell_id, lte_cp_t cp) {
bzero(q, sizeof(pbch_t));
q->cell_id = cell_id;
q->cp = cp;
q->nof_prb = nof_prb;
if (modem_table_std(&q->mod, LTE_QPSK, true)) {
goto clean;
@ -134,7 +135,6 @@ int pbch_init(pbch_t *q, int cell_id, lte_cp_t cp) {
}
q->encoder.K = 7;
q->encoder.R = 3;
q->encoder.framelength = 40;
q->encoder.tail_biting = true;
memcpy(q->encoder.poly, poly, 3 * sizeof(int));
@ -360,7 +360,7 @@ int pbch_crc_check(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, 0x11021, 0);
return crc(0, data, 40, 16, LTE_CRC16, 0);
}
int pbch_decode_frame(pbch_t *q, pbch_mib_t *mib, int src, int dst, int n, int nof_bits, int nof_ports) {
@ -389,7 +389,7 @@ int pbch_decode_frame(pbch_t *q, pbch_mib_t *mib, int src, int dst, int n, int n
}
/* decode */
viterbi_decode_f(&q->decoder, q->pbch_rm_f, q->data);
viterbi_decode_f(&q->decoder, q->pbch_rm_f, q->data, 40);
int c=0;
for (j=0;j<40;j++) {
@ -420,7 +420,7 @@ int pbch_decode_frame(pbch_t *q, pbch_mib_t *mib, int src, int dst, int n, int n
*
* Returns 1 if successfully decoded MIB, 0 if not and -1 on error
*/
int pbch_decode(pbch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL], int nof_prb, float ebno, pbch_mib_t *mib) {
int pbch_decode(pbch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL], float ebno, pbch_mib_t *mib) {
int src, dst, res, nb;
int nant_[3] = {1, 2, 4};
int na, nant;
@ -437,7 +437,7 @@ int pbch_decode(pbch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL], int no
memset(&x[MAX_PORTS_CTRL], 0, sizeof(cf_t*) * (MAX_LAYERS - MAX_PORTS_CTRL));
/* extract symbols */
if (q->nof_symbols != pbch_get(slot1_symbols, q->pbch_symbols[0], nof_prb,
if (q->nof_symbols != pbch_get(slot1_symbols, q->pbch_symbols[0], q->nof_prb,
q->cp, q->cell_id)) {
fprintf(stderr, "There was an error getting the PBCH symbols\n");
return -1;
@ -445,7 +445,7 @@ int pbch_decode(pbch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL], int no
/* extract channel estimates */
for (i=0;i<MAX_PORTS_CTRL;i++) {
if (q->nof_symbols != pbch_get(ce[i], q->ce[i], nof_prb,
if (q->nof_symbols != pbch_get(ce[i], q->ce[i], q->nof_prb,
q->cp, q->cell_id)) {
fprintf(stderr, "There was an error getting the PBCH symbols\n");
return -1;
@ -503,8 +503,7 @@ int pbch_decode(pbch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL], int no
/** Converts the MIB message to symbols mapped to SLOT #1 ready for transmission
*/
void pbch_encode(pbch_t *q, pbch_mib_t *mib, cf_t *slot1_symbols[MAX_PORTS_CTRL],
int nof_prb, int nof_ports) {
void pbch_encode(pbch_t *q, pbch_mib_t *mib, cf_t *slot1_symbols[MAX_PORTS_CTRL], int nof_ports) {
int i;
int nof_bits = 2 * q->nof_symbols;
@ -527,7 +526,7 @@ void pbch_encode(pbch_t *q, pbch_mib_t *mib, cf_t *slot1_symbols[MAX_PORTS_CTRL]
crc(0, q->data, 24, 16, 0x11021, 1);
crc_set_mask(q->data, nof_ports);
convcoder_encode(&q->encoder, q->data, q->data_enc);
convcoder_encode(&q->encoder, q->data, q->data_enc, 40);
rm_conv_tx(q->data_enc, q->pbch_rm_b, 120, 4 * nof_bits);
@ -549,7 +548,7 @@ void pbch_encode(pbch_t *q, pbch_mib_t *mib, cf_t *slot1_symbols[MAX_PORTS_CTRL]
/* mapping to resource elements */
for (i=0;i<nof_ports;i++) {
pbch_put(q->pbch_symbols[i], slot1_symbols[i], nof_prb, q->cp, q->cell_id);
pbch_put(q->pbch_symbols[i], slot1_symbols[i], q->nof_prb, q->cp, q->cell_id);
}
q->frame_idx++;
if (q->frame_idx == 4) {

585
lte/lib/phch/src/pdcch.c Normal file
View File

@ -0,0 +1,585 @@
/**
*
* \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 "lte/phch/dci.h"
#include "lte/phch/regs.h"
#include "lte/phch/pdcch.h"
#include "lte/common/base.h"
#include "lte/utils/bit.h"
#include "lte/utils/vector.h"
#include "lte/utils/debug.h"
#define PDCCH_NOF_FORMATS 4
#define PDCCH_FORMAT_NOF_CCE(i) (1<<i)
#define PDCCH_FORMAT_NOF_REGS(i) ((1<<i)*9)
#define PDCCH_FORMAT_NOF_BITS(i) ((1<<i)*72)
int pdcch_put(cf_t *pdcch, cf_t *slot1_data, int nsymbols) {
memcpy(slot1_data, pdcch, sizeof(cf_t) * nsymbols);
return nsymbols;
}
int pdcch_get(cf_t *slot1_data, cf_t *pdcch, int nsymbols) {
memcpy(pdcch, slot1_data, sizeof(cf_t) * nsymbols);
return nsymbols;
}
#define MIN(a,b) ((a>b)?b:a)
/**
* 36.213 9.1
*/
int gen_common_search(dci_candidate_t *c, int nof_cce, int nof_bits, unsigned short rnti) {
int i, L, k;
k = 0;
for (L = 2; L > 0; L--) {
for (i = 0; i < MIN(nof_cce,16) / (4 * L); i++) {
c[k].L = 4 * L;
c[k].nof_bits = nof_bits;
c[k].rnti = rnti;
c[k].ncce = (4 * L) * (i % (nof_cce / (4 * L)));
k++;
INFO(
"Common SS Candidate %d: RNTI: 0x%x, nCCE: %d, Nbits: %d, L: %d\n",
k, c[k].rnti, c[k].ncce, c[k].nof_bits, c[k].L);
}
}
return k;
}
/**
* 36.213 9.1
*/
int gen_ue_search(dci_candidate_t *c, int nof_cce, int nof_bits, unsigned short rnti, int subframe) {
int i, l, L, k, m;
unsigned int Yk;
const int S[4] = { 6, 12, 8, 16 };
k = 0;
for (l = 3; l >= 0; l--) {
L = (1 << l);
for (i = 0; i < MIN(nof_cce/L,16/S[l]); i++) {
c[k].L = l;
c[k].nof_bits = nof_bits;
c[k].rnti = rnti;
Yk = rnti;
for (m = 0; m < subframe; m++) {
Yk = (39827 * Yk) % 65537;
}
c[k].ncce = L * ((Yk + i) % (nof_cce / L));
INFO("UE-specific SS Candidate %d: SF: %d, RNTI: 0x%x, nCCE: %d, Nbits: %d, L: %d\n",
k, subframe, c[k].rnti, c[k].ncce, c[k].nof_bits, c[k].L);
k++;
}
}
return k;
}
void pdcch_init_common(pdcch_t *q, pdcch_search_t *s, unsigned short rnti) {
int k;
s->nof_candidates = 2*(MIN(q->nof_cce,16) / 4 + MIN(q->nof_cce,16) / 8);
if (s->nof_candidates) {
s->candidates[0] = malloc(sizeof(dci_candidate_t) * s->nof_candidates);
dci_candidate_t *c = s->candidates[0];
if (c) {
// Format 1A and 1C L=4 and L=8, 4 and 2 candidates, only if nof_cce > 16
k = 0;
k += gen_common_search(&c[k], q->nof_cce,
dci_format1A_sizeof(q->nof_prb), SIRNTI);
k += gen_common_search(&c[k], q->nof_cce,
dci_format1C_sizeof(q->nof_prb), SIRNTI);
}
}
}
/** 36.213 v9.3 Table 7.1-1: System Information DCI messages
* Expect DCI formats 1C and 1A in the common search space
*/
void pdcch_init_search_si(pdcch_t *q) {
pdcch_init_common(q, &q->search_mode[SEARCH_SI], SIRNTI);
q->current_search_mode = SEARCH_SI;
}
/** 36.213 v9.3 Table 7.1-5
* user-specific search space. Currently supported transmission Mode 1:
* DCI Format 1A and 1 + PUSCH scheduling format 0
*/
void pdcch_init_search_ue(pdcch_t *q, unsigned short c_rnti) {
int l, n, k;
pdcch_search_t *s = &q->search_mode[SEARCH_UE];
s->nof_candidates = 0;
for (l=0;l<3;l++) {
s->nof_candidates += 3*(MIN(q->nof_cce,16) / (1<<l));
}
INFO("Initiating %d candidate(s) in the UE-specific search space for C-RNTI: 0x%x\n", s->nof_candidates, c_rnti);
if (s->nof_candidates) {
for (n=0;n<NSUBFRAMES_X_FRAME;n++) {
s->candidates[n] = malloc(sizeof(dci_candidate_t) * s->nof_candidates);
dci_candidate_t *c = s->candidates[n];
if (c) {
// Expect Formats 1, 1A, 0
k = 0;
k += gen_ue_search(&c[k], q->nof_cce,
dci_format0_sizeof(q->nof_prb), c_rnti, n);
k += gen_ue_search(&c[k], q->nof_cce,
dci_format1_sizeof(q->nof_prb), c_rnti, n);
k += gen_ue_search(&c[k], q->nof_cce,
dci_format1A_sizeof(q->nof_prb), c_rnti, n);
}
}
}
q->current_search_mode = SEARCH_UE;
}
/** 36.213 v9.3 Table 7.1-3
* Expect DCI formats 1C and 1A in the common search space
*/
void pdcch_init_search_ra(pdcch_t *q, unsigned short ra_rnti) {
pdcch_init_common(q, &q->search_mode[SEARCH_RA], ra_rnti);
q->current_search_mode = SEARCH_RA;
}
void pdcch_set_search_si(pdcch_t *q) {
q->current_search_mode = SEARCH_SI;
}
void pdcch_set_search_ue(pdcch_t *q) {
q->current_search_mode = SEARCH_UE;
}
void pdcch_set_search_ra(pdcch_t *q) {
q->current_search_mode = SEARCH_RA;
}
/** Initializes the PDCCH transmitter and receiver */
int pdcch_init(pdcch_t *q, regs_t *regs, int nof_prb, int nof_ports,
int cell_id, lte_cp_t cp) {
int ret = -1;
int i;
if (cell_id < 0) {
return -1;
}
if (nof_ports > MAX_PORTS_CTRL) {
fprintf(stderr, "Invalid number of ports %d\n", nof_ports);
return -1;
}
bzero(q, sizeof(pdcch_t));
q->cell_id = cell_id;
q->cp = cp;
q->regs = regs;
q->nof_ports = nof_ports;
q->current_search_mode = SEARCH_NONE;
q->nof_regs = regs_pdcch_nregs(q->regs);
q->nof_cce = q->nof_regs / 9;
q->nof_symbols = 4 * q->nof_regs;
q->nof_bits = 2 * q->nof_symbols;
INFO("Init PDCCH: %d REGs, %d bits, %d symbols, %d ports\n", q->nof_regs,
q->nof_bits, q->nof_symbols, q->nof_ports);
if (modem_table_std(&q->mod, LTE_QPSK, true)) {
goto clean;
}
demod_soft_init(&q->demod);
demod_soft_table_set(&q->demod, &q->mod);
demod_soft_alg_set(&q->demod, APPROX);
for (i = 0; i < NSUBFRAMES_X_FRAME; i++) {
if (sequence_pdcch(&q->seq_pdcch[i], 2 * i, q->cell_id, q->nof_bits)) {
goto clean;
}
}
int poly[3] = { 0x6D, 0x4F, 0x57 };
if (viterbi_init(&q->decoder, viterbi_37, poly, DCI_MAX_BITS + 16, true)) {
goto clean;
}
q->pdcch_e = malloc(sizeof(char) * q->nof_bits);
if (!q->pdcch_e) {
goto clean;
}
q->pdcch_llr = malloc(sizeof(float) * q->nof_bits);
if (!q->pdcch_llr) {
goto clean;
}
q->pdcch_d = malloc(sizeof(cf_t) * q->nof_symbols);
if (!q->pdcch_d) {
goto clean;
}
for (i = 0; i < MAX_PORTS_CTRL; i++) {
q->ce[i] = malloc(sizeof(cf_t) * q->nof_symbols);
if (!q->ce[i]) {
goto clean;
}
q->pdcch_x[i] = malloc(sizeof(cf_t) * q->nof_symbols);
if (!q->pdcch_x[i]) {
goto clean;
}
q->pdcch_symbols[i] = malloc(sizeof(cf_t) * q->nof_symbols);
if (!q->pdcch_symbols[i]) {
goto clean;
}
}
ret = 0;
clean: if (ret == -1) {
pdcch_free(q);
}
return ret;
}
void pdcch_free(pdcch_t *q) {
int i, j;
for (i=0;i<PDCCH_NOF_SEARCH_MODES;i++) {
for (j = 0; j < NSUBFRAMES_X_FRAME; j++) {
if (q->search_mode[i].candidates[j]) {
free(q->search_mode[i].candidates[j]);
}
}
}
if (q->pdcch_e) {
free(q->pdcch_e);
}
if (q->pdcch_llr) {
free(q->pdcch_llr);
}
if (q->pdcch_d) {
free(q->pdcch_d);
}
for (i = 0; i < MAX_PORTS_CTRL; i++) {
if (q->ce[i]) {
free(q->ce[i]);
}
if (q->pdcch_x[i]) {
free(q->pdcch_x[i]);
}
if (q->pdcch_symbols[i]) {
free(q->pdcch_symbols[i]);
}
}
for (i = 0; i < NSUBFRAMES_X_FRAME; i++) {
sequence_free(&q->seq_pdcch[i]);
}
modem_table_free(&q->mod);
viterbi_free(&q->decoder);
}
/** 36.212 5.3.3.2 to 5.3.3.4
*
* Returns XOR between parity and remainder bits
*
* TODO: UE transmit antenna selection CRC mask
*/
unsigned short dci_decode(viterbi_t *decoder, float *e, char *data, int E,
int nof_bits) {
float tmp[3 * (DCI_MAX_BITS + 16)];
unsigned short p_bits;
char *x;
assert(nof_bits < DCI_MAX_BITS);
/* unrate matching */
rm_conv_rx(e, tmp, E, 3 * (nof_bits + 16));
DEBUG("Viterbi input: ", 0);
if (VERBOSE_ISDEBUG()) {
vec_fprint_f(stdout, tmp, 3 * (nof_bits + 16));
}
/* viterbi decoder */
viterbi_decode_f(decoder, tmp, data, nof_bits + 16);
x = &data[nof_bits];
p_bits = (unsigned short) bit_unpack(&x, 16);
return (p_bits
^ ((unsigned short) crc(0, data, nof_bits, 16, LTE_CRC16, 0)
& 0xffff));
}
int pdcch_decode_candidate(pdcch_t *q, float *llr, dci_candidate_t *c,
dci_msg_t *msg) {
unsigned short crc_res;
crc_res = dci_decode(&q->decoder, &llr[72 * c->ncce], msg->data,
PDCCH_FORMAT_NOF_BITS(c->L), c->nof_bits);
if (c->rnti == crc_res) {
memcpy(&msg->location, c, sizeof(dci_candidate_t));
INFO(
"FOUND CAND: 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);
return 1;
}
return 0;
}
int pdcch_extract_llr(pdcch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL],
float *llr, int nsubframe, float ebno) {
/* Set pointers for layermapping & precoding */
int i;
cf_t *x[MAX_LAYERS];
if (nsubframe < 0 || nsubframe > NSUBFRAMES_X_FRAME) {
fprintf(stderr, "Invalid subframe %d\n", nsubframe);
return -1;
}
if (ebno == 0.0) {
fprintf(stderr, "EbNo is Zero\n");
return -1;
}
/* number of layers equals number of ports */
for (i = 0; i < q->nof_ports; i++) {
x[i] = q->pdcch_x[i];
}
memset(&x[q->nof_ports], 0, sizeof(cf_t*) * (MAX_LAYERS - q->nof_ports));
/* extract symbols */
if (q->nof_symbols
!= pdcch_get(slot1_symbols, q->pdcch_symbols[0], q->nof_symbols)) {
fprintf(stderr, "There was an error getting the PDCCH symbols\n");
return -1;
}
/* extract channel estimates */
for (i = 0; i < q->nof_ports; i++) {
if (q->nof_symbols != pdcch_get(ce[i], q->ce[i], q->nof_symbols)) {
fprintf(stderr, "There was an error getting the PDCCH symbols\n");
return -1;
}
}
DEBUG("pdcch_symbols: ", 0);
if (VERBOSE_ISDEBUG()) {
vec_fprint_c(stdout, q->pdcch_symbols[0], q->nof_symbols);
}
/* in control channels, only diversity is supported */
if (q->nof_ports == 1) {
/* no need for layer demapping */
predecoding_single_zf(q->pdcch_symbols[0], q->ce[0], q->pdcch_d,
q->nof_symbols);
} else {
predecoding_diversity_zf(q->pdcch_symbols, q->ce, x, q->nof_ports,
q->nof_symbols);
layerdemap_diversity(x, q->pdcch_d, q->nof_ports,
q->nof_symbols / q->nof_ports);
}
/* demodulate symbols */
demod_soft_sigma_set(&q->demod, ebno);
demod_soft_demodulate(&q->demod, q->pdcch_d, q->pdcch_llr, q->nof_symbols);
DEBUG("llr: ", 0);
if (VERBOSE_ISDEBUG()) {
vec_fprint_f(stdout, q->pdcch_llr, q->nof_symbols);
}
/* descramble */
scrambling_f_offset(&q->seq_pdcch[nsubframe], llr, 0, q->nof_bits);
return 0;
}
int pdcch_decode_current_mode(pdcch_t *q, float *llr, dci_t *dci, int subframe) {
int dci_cnt;
int k, i;
if (q->current_search_mode == SEARCH_UE) {
k = subframe;
} else {
k = 0;
}
dci_cnt = 0;
for (i = 0; i < q->search_mode[q->current_search_mode].nof_candidates
&& dci_cnt < dci->nof_dcis; i++) {
if (pdcch_decode_candidate(q, q->pdcch_llr,
&q->search_mode[q->current_search_mode].candidates[k][i],
&dci->msg[dci_cnt])) {
dci_cnt++;
}
}
return dci_cnt;
}
int pdcch_decode_si(pdcch_t *q, float *llr, dci_t *dci) {
pdcch_set_search_si(q);
return pdcch_decode_current_mode(q, llr, dci, 0);
}
int pdcch_decode_ra(pdcch_t *q, float *llr, dci_t *dci) {
pdcch_set_search_ra(q);
return pdcch_decode_current_mode(q, llr, dci, 0);
}
int pdcch_decode_ue(pdcch_t *q, float *llr, dci_t *dci, int nsubframe) {
pdcch_set_search_ue(q);
return pdcch_decode_current_mode(q, llr, dci, nsubframe);
}
/* Decodes PDCCH channels
*
* dci->nof_dcis is the size of the dci->msg buffer (ie max number of messages)
*
* Returns number of messages stored in dci
*/
int pdcch_decode(pdcch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL],
dci_t *dci, int nsubframe, float ebno) {
if (pdcch_extract_llr(q, slot1_symbols, ce, q->pdcch_llr, nsubframe,
ebno)) {
return -1;
}
if (q->current_search_mode != SEARCH_NONE) {
return pdcch_decode_current_mode(q, q->pdcch_llr, dci, nsubframe);
}
return 0;
}
void crc_set_mask_rnti(char *crc, unsigned short rnti) {
int i;
char mask[16];
char *r = mask;
INFO("Mask CRC with RNTI 0x%x\n", rnti);
bit_pack(rnti, &r, 16);
for (i = 0; i < 16; i++) {
crc[i] = (crc[i] + mask[i]) % 2;
}
}
/** 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) {
convcoder_t encoder;
char tmp[3 * (DCI_MAX_BITS + 16)];
assert(nof_bits < DCI_MAX_BITS);
int poly[3] = { 0x6D, 0x4F, 0x57 };
encoder.K = 7;
encoder.R = 3;
encoder.tail_biting = true;
memcpy(encoder.poly, poly, 3 * sizeof(int));
crc(0, data, nof_bits, 16, LTE_CRC16, 1);
crc_set_mask_rnti(&data[nof_bits], rnti);
convcoder_encode(&encoder, data, tmp, nof_bits + 16);
DEBUG("CConv output: ", 0);
if (VERBOSE_ISDEBUG()) {
vec_fprint_b(stdout, tmp, 3 * (nof_bits + 16));
}
rm_conv_tx(tmp, e, 3 * (nof_bits + 16), E);
}
/** Converts the MIB message to symbols mapped to SLOT #1 ready for transmission
*/
int pdcch_encode(pdcch_t *q, dci_t *dci, cf_t *slot1_symbols[MAX_PORTS_CTRL],
int nsubframe) {
int i;
/* Set pointers for layermapping & precoding */
cf_t *x[MAX_LAYERS];
if (nsubframe < 0 || nsubframe > NSUBFRAMES_X_FRAME) {
fprintf(stderr, "Invalid subframe %d\n", nsubframe);
return -1;
}
/* number of layers equals number of ports */
for (i = 0; i < q->nof_ports; i++) {
x[i] = q->pdcch_x[i];
}
memset(&x[q->nof_ports], 0, sizeof(cf_t*) * (MAX_LAYERS - q->nof_ports));
/* should add <NIL> elements? Or maybe random bits to facilitate power estimation */
bzero(q->pdcch_e, q->nof_bits);
/* Encode DCIs */
for (i = 0; i < dci->nof_dcis; i++) {
/* do some sanity checks */
if (dci->msg[i].location.ncce + PDCCH_FORMAT_NOF_CCE(dci->msg[i].location.L) > q->nof_cce
|| dci->msg[i].location.L > 3
|| dci->msg[i].location.nof_bits > DCI_MAX_BITS) {
fprintf(stderr, "Illegal DCI message %d\n", i);
return -1;
}
INFO("Encoding DCI %d: Nbits: %d, E: %d, nCCE: %d, L: %d, RNTI: 0x%x\n",
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->msg[i].location.nof_bits, PDCCH_FORMAT_NOF_BITS(dci->msg[i].location.L),
dci->msg[i].location.rnti);
}
scrambling_b_offset(&q->seq_pdcch[nsubframe], q->pdcch_e, 0, q->nof_bits);
mod_modulate(&q->mod, q->pdcch_e, q->pdcch_d, q->nof_bits);
/* layer mapping & precoding */
if (q->nof_ports > 1) {
layermap_diversity(q->pdcch_d, x, q->nof_ports, q->nof_symbols);
precoding_diversity(x, q->pdcch_symbols, q->nof_ports,
q->nof_symbols / q->nof_ports);
} else {
memcpy(q->pdcch_symbols[0], q->pdcch_d, q->nof_symbols * sizeof(cf_t));
}
/* mapping to resource elements */
for (i = 0; i < q->nof_ports; i++) {
pdcch_put(q->pdcch_symbols[i], slot1_symbols[i], q->nof_symbols);
}
return 0;
}

View File

@ -58,6 +58,9 @@ void regs_pdcch_free(regs_t *h) {
}
}
int regs_pdcch_nregs(regs_t *h) {
return 9;
}

View File

@ -54,3 +54,11 @@ int sequence_phich(sequence_t *seq, int nslot, int cell_id) {
bzero(seq, sizeof(sequence_t));
return sequence_LTEPRS(seq, 12, (nslot/2+1) * (2*cell_id + 1) * 512 + cell_id);
}
/**
* 36.211 6.8.2
*/
int sequence_pdcch(sequence_t *seq, int nslot, int cell_id, int len) {
bzero(seq, sizeof(sequence_t));
return sequence_LTEPRS(seq, len, (nslot/2) * 512 + cell_id);
}

View File

@ -68,6 +68,12 @@ ADD_TEST(phich_test_102 phich_test -p 2 -n 10 -g 2)
ADD_TEST(phich_test_104 phich_test -p 4 -n 10 -e -l -g 1/2)
########################################################################
# PDCCH TEST
########################################################################
ADD_EXECUTABLE(pdcch_test pdcch_test.c)
TARGET_LINK_LIBRARIES(pdcch_test lte)
########################################################################
# FILE TEST
@ -79,6 +85,10 @@ TARGET_LINK_LIBRARIES(pbch_file_test lte)
ADD_EXECUTABLE(pcfich_file_test pcfich_file_test.c)
TARGET_LINK_LIBRARIES(pcfich_file_test lte)
ADD_EXECUTABLE(phich_file_test phich_file_test.c)
TARGET_LINK_LIBRARIES(phich_file_test lte)
ADD_TEST(pbch_file_test pbch_file_test -i ${CMAKE_CURRENT_SOURCE_DIR}/signal.1.92M.dat)
ADD_TEST(pcfich_file_test pcfich_file_test -c 150 -n 50 -p 2 -i ${CMAKE_CURRENT_SOURCE_DIR}/signal.10M.dat)
ADD_TEST(phich_file_test phich_file_test -c 150 -n 50 -p 2 -i ${CMAKE_CURRENT_SOURCE_DIR}/signal.10M.dat)

View File

@ -141,7 +141,7 @@ int base_init() {
return -1;
}
if (pbch_init(&pbch, cell_id, cp)) {
if (pbch_init(&pbch, nof_prb, cell_id, cp)) {
fprintf(stderr, "Error initiating PBCH\n");
return -1;
}
@ -209,7 +209,7 @@ int main(int argc, char **argv) {
INFO("Decoding PBCH\n", 0);
n = pbch_decode(&pbch, fft_buffer, ce, nof_prb, 1, &mib);
n = pbch_decode(&pbch, fft_buffer, ce, 1, &mib);
base_free();
fftwf_cleanup();

View File

@ -99,7 +99,7 @@ int main(int argc, char **argv) {
}
}
if (pbch_init(&pbch, cell_id, CPNORM)) {
if (pbch_init(&pbch, nof_prb, cell_id, CPNORM)) {
fprintf(stderr, "Error creating PBCH object\n");
exit(-1);
}
@ -110,7 +110,7 @@ int main(int argc, char **argv) {
mib_tx.phich_resources = R_1_6;
mib_tx.sfn = 124;
pbch_encode(&pbch, &mib_tx, slot1_symbols, nof_prb, nof_ports);
pbch_encode(&pbch, &mib_tx, slot1_symbols, nof_ports);
/* combine outputs */
for (i=1;i<nof_ports;i++) {
@ -120,7 +120,7 @@ int main(int argc, char **argv) {
}
pbch_decode_reset(&pbch);
if (1 != pbch_decode(&pbch, slot1_symbols[0], ce, nof_prb, 1, &mib_rx)) {
if (1 != pbch_decode(&pbch, slot1_symbols[0], ce, 1, &mib_rx)) {
printf("Error decoding\n");
exit(-1);
}

View File

@ -0,0 +1,172 @@
/**
*
* \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 "lte.h"
int cell_id = 1;
int nof_prb = 6;
int nof_ports = 1;
void usage(char *prog) {
printf("Usage: %s [cpv]\n", prog);
printf("\t-c cell id [Default %d]\n", cell_id);
printf("\t-p nof_ports [Default %d]\n", nof_ports);
printf("\t-n nof_prb [Default %d]\n", 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, "cpnv")) != -1) {
switch(opt) {
case 'p':
nof_ports = atoi(argv[optind]);
break;
case 'n':
nof_prb = atoi(argv[optind]);
break;
case 'c':
cell_id = atoi(argv[optind]);
break;
case 'v':
verbose++;
break;
default:
usage(argv[0]);
exit(-1);
}
}
}
int main(int argc, char **argv) {
pdcch_t pdcch;
dci_t dci_tx, dci_rx;
dci_format1_t dci_msg;
regs_t regs;
int i, j;
cf_t *ce[MAX_PORTS_CTRL];
int nof_re;
cf_t *slot1_symbols[MAX_PORTS_CTRL];
int nof_dcis;
int ret = -1;
parse_args(argc,argv);
nof_re = CPNORM_NSYMB * nof_prb * RE_X_RB;
/* init memory */
for (i=0;i<MAX_PORTS_CTRL;i++) {
ce[i] = malloc(sizeof(cf_t) * nof_re);
if (!ce[i]) {
perror("malloc");
exit(-1);
}
for (j=0;j<nof_re;j++) {
ce[i][j] = 1;
}
slot1_symbols[i] = malloc(sizeof(cf_t) * nof_re);
if (!slot1_symbols[i]) {
perror("malloc");
exit(-1);
}
}
if (regs_init(&regs, cell_id, nof_prb, nof_ports, R_1, PHICH_NORM, CPNORM)) {
fprintf(stderr, "Error initiating regs\n");
exit(-1);
}
if (pdcch_init(&pdcch, &regs, nof_prb, nof_ports, cell_id, CPNORM)) {
fprintf(stderr, "Error creating PBCH object\n");
exit(-1);
}
dci_init(&dci_tx, 1);
dci_format1_add(&dci_tx, &dci_msg);
pdcch_encode(&pdcch, &dci_tx, slot1_symbols, 0);
/* combine outputs */
for (i=1;i<nof_ports;i++) {
for (j=0;j<nof_re;j++) {
slot1_symbols[0][j] += slot1_symbols[i][j];
}
}
pdcch_init_search_ue(&pdcch, 1234);
dci_init(&dci_rx, 1);
nof_dcis = pdcch_decode(&pdcch, slot1_symbols[0], ce, &dci_rx, 0, 1);
if (nof_dcis < 0) {
printf("Error decoding\n");
} else if (nof_dcis == dci_tx.nof_dcis) {
for (i=0;i<nof_dcis;i++) {
if (dci_tx.msg[i].location.L != dci_rx.msg[i].location.L
|| dci_tx.msg[i].location.ncce != dci_rx.msg[i].location.ncce
|| dci_tx.msg[i].location.nof_bits != dci_rx.msg[i].location.nof_bits
|| dci_tx.msg[i].location.rnti != dci_rx.msg[i].location.rnti) {
printf("Error in DCI %d: Received location does not match\n", i);
dci_candidate_fprint(stdout, &dci_tx.msg[i].location);
dci_candidate_fprint(stdout, &dci_rx.msg[i].location);
goto quit;
}
if (memcmp(dci_tx.msg[i].data, dci_rx.msg[i].data, dci_tx.msg[i].location.nof_bits)) {
printf("Error in DCI %d: Received data does not match\n", i);
goto quit;
}
/* check more things ... */
}
} else {
printf("Transmitted %d DCIs but got %d\n", dci_tx.nof_dcis, nof_dcis);
goto quit;
}
ret = 0;
quit:
pdcch_free(&pdcch);
regs_free(&regs);
dci_free(&dci_tx);
dci_free(&dci_rx);
for (i=0;i<MAX_PORTS_CTRL;i++) {
free(ce[i]);
free(slot1_symbols[i]);
}
if (ret) {
printf("Error\n");
} else {
printf("Ok\n");
}
exit(ret);
}

View File

@ -0,0 +1,286 @@
/**
*
* \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 "lte.h"
char *input_file_name = NULL;
char *matlab_file_name = NULL;
int cell_id = 150;
lte_cp_t cp = CPNORM;
int nof_prb = 50;
int nof_ports = 2;
int flen;
int nof_ctrl_symbols = 1;
phich_resources_t phich_res = R_1;
phich_length_t phich_length = PHICH_NORM;
int numsubframe = 0;
FILE *fmatlab = NULL;
filesource_t fsrc;
cf_t *input_buffer, *fft_buffer, *ce[MAX_PORTS_CTRL];
phich_t phich;
regs_t regs;
lte_fft_t fft;
chest_t chest;
void usage(char *prog) {
printf("Usage: %s [vcoe] -i input_file\n", prog);
printf("\t-o output matlab file name [Default Disabled]\n");
printf("\t-c cell_id [Default %d]\n", cell_id);
printf("\t-p nof_ports [Default %d]\n", nof_ports);
printf("\t-n nof_prb [Default %d]\n", nof_prb);
printf("\t-f nof control symbols [Default %d]\n", nof_ctrl_symbols);
printf("\t-g phich ng factor: 1/6, 1/2, 1, 2 [Default 1]\n");
printf("\t-e phich extended length [Default normal]\n");
printf("\t-l extended cyclic prefix [Default normal]\n");
printf("\t-v [set verbose to debug, default none]\n");
}
void parse_args(int argc, char **argv) {
int opt;
while ((opt = getopt(argc, argv, "iovcenpfgl")) != -1) {
switch(opt) {
case 'i':
input_file_name = argv[optind];
break;
case 'o':
matlab_file_name = argv[optind];
break;
case 'c':
cell_id = atoi(argv[optind]);
break;
case 'f':
nof_ctrl_symbols = atoi(argv[optind]);
break;
case 'g':
if (!strcmp(argv[optind], "1/6")) {
phich_res = R_1_6;
} else if (!strcmp(argv[optind], "1/2")) {
phich_res = R_1_2;
} else if (!strcmp(argv[optind], "1")) {
phich_res = R_1;
} else if (!strcmp(argv[optind], "2")) {
phich_res = R_2;
} else {
fprintf(stderr, "Invalid phich ng factor %s. Setting to default.\n", argv[optind]);
}
break;
case 'e':
phich_length = PHICH_EXT;
break;
case 'n':
nof_prb = atoi(argv[optind]);
break;
case 'p':
nof_ports = atoi(argv[optind]);
break;
case 'v':
verbose++;
break;
case 'l':
cp = CPEXT;
break;
default:
usage(argv[0]);
exit(-1);
}
}
if (!input_file_name) {
usage(argv[0]);
exit(-1);
}
}
int base_init() {
int i;
if (filesource_init(&fsrc, input_file_name, COMPLEX_FLOAT_BIN)) {
fprintf(stderr, "Error opening file %s\n", input_file_name);
exit(-1);
}
if (matlab_file_name) {
fmatlab = fopen(matlab_file_name, "w");
if (!fmatlab) {
perror("fopen");
return -1;
}
} else {
fmatlab = NULL;
}
flen = SLOT_LEN(lte_symbol_sz(nof_prb), cp);
input_buffer = malloc(flen * sizeof(cf_t));
if (!input_buffer) {
perror("malloc");
exit(-1);
}
fft_buffer = malloc(CP_NSYMB(cp) * nof_prb * RE_X_RB * sizeof(cf_t));
if (!fft_buffer) {
perror("malloc");
return -1;
}
for (i=0;i<MAX_PORTS_CTRL;i++) {
ce[i] = malloc(CP_NSYMB(cp) * nof_prb * RE_X_RB * sizeof(cf_t));
if (!ce[i]) {
perror("malloc");
return -1;
}
}
if (chest_init(&chest, LINEAR, cp, nof_prb, nof_ports)) {
fprintf(stderr, "Error initializing equalizer\n");
return -1;
}
if (chest_ref_LTEDL(&chest, cell_id)) {
fprintf(stderr, "Error initializing reference signal\n");
return -1;
}
if (lte_fft_init(&fft, cp, nof_prb)) {
fprintf(stderr, "Error initializing FFT\n");
return -1;
}
if (regs_init(&regs, cell_id, nof_prb, nof_ports, phich_res, phich_length, cp)) {
fprintf(stderr, "Error initiating regs\n");
return -1;
}
if (phich_init(&phich, &regs, cell_id, nof_prb, nof_ports, cp)) {
fprintf(stderr, "Error creating PBCH object\n");
return -1;
}
DEBUG("Memory init OK\n",0);
return 0;
}
void base_free() {
int i;
filesource_free(&fsrc);
if (fmatlab) {
fclose(fmatlab);
}
free(input_buffer);
free(fft_buffer);
filesource_free(&fsrc);
for (i=0;i<MAX_PORTS_CTRL;i++) {
free(ce[i]);
}
chest_free(&chest);
lte_fft_free(&fft);
phich_free(&phich);
regs_free(&regs);
}
int main(int argc, char **argv) {
int distance;
int i, n;
int ngroup, nseq, max_nseq;
char ack_rx;
if (argc < 3) {
usage(argv[0]);
exit(-1);
}
parse_args(argc,argv);
max_nseq = CP_ISNORM(cp)?PHICH_NORM_NSEQUENCES:PHICH_EXT_NSEQUENCES;
if (base_init()) {
fprintf(stderr, "Error initializing memory\n");
exit(-1);
}
n = filesource_read(&fsrc, input_buffer, flen);
lte_fft_run(&fft, input_buffer, fft_buffer);
if (fmatlab) {
fprintf(fmatlab, "infft=");
vec_fprint_c(fmatlab, input_buffer, flen);
fprintf(fmatlab, ";\n");
fprintf(fmatlab, "outfft=");
vec_fprint_c(fmatlab, fft_buffer, CP_NSYMB(cp) * nof_prb * RE_X_RB);
fprintf(fmatlab, ";\n");
}
/* Get channel estimates for each port */
for (i=0;i<nof_ports;i++) {
chest_ce_slot_port(&chest, fft_buffer, ce[i], 0, i);
if (fmatlab) {
chest_fprint(&chest, fmatlab, 0, i);
}
}
INFO("Decoding PHICH\n", 0);
/* Receive all PHICH groups and sequence numbers */
for (ngroup=0;ngroup<phich_ngroups(&phich);ngroup++) {
for (nseq=0;nseq<max_nseq;nseq++) {
if (phich_decode(&phich, fft_buffer, ce, ngroup, nseq, numsubframe, &ack_rx, &distance)<0) {
printf("Error decoding ACK\n");
exit(-1);
}
INFO("%d/%d, ack_rx: %d, ns: %d, distance: %d\n",
ngroup, nseq, ack_rx, numsubframe, distance);
}
}
base_free();
fftwf_cleanup();
if (n < 0) {
fprintf(stderr, "Error decoding phich\n");
exit(-1);
} else if (n == 0) {
printf("Could not decode phich\n");
exit(-1);
} else {
exit(0);
}
}

View File

@ -41,6 +41,7 @@ int sync_init(sync_t *q, int frame_size) {
q->threshold = 1.5;
q->pss_mode = PEAK_MEAN;
q->detect_cp = true;
q->sss_en = true;
for (N_id_2=0;N_id_2<3;N_id_2++) {
if (pss_synch_init(&q->pss[N_id_2], frame_size)) {