|
|
|
/**
|
|
|
|
*
|
|
|
|
* \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 "lte.h"
|
|
|
|
|
|
|
|
typedef _Complex float cf_t;
|
|
|
|
|
|
|
|
int frame_length = 1000, nof_frames = 128;
|
|
|
|
float ebno_db = 100.0;
|
|
|
|
unsigned int seed = 0;
|
|
|
|
bool tail_biting = false;
|
|
|
|
int K = -1;
|
|
|
|
|
|
|
|
#define SNR_POINTS 10
|
|
|
|
#define SNR_MIN 0.0
|
|
|
|
#define SNR_MAX 5.0
|
|
|
|
|
|
|
|
#define NCODS 3
|
|
|
|
#define NTYPES 1+NCODS
|
|
|
|
|
|
|
|
void usage(char *prog) {
|
|
|
|
printf("Usage: %s [nlestk]\n", prog);
|
|
|
|
printf("\t-n nof_frames [Default %d]\n", nof_frames);
|
|
|
|
printf("\t-l frame_length [Default %d]\n", frame_length);
|
|
|
|
printf("\t-e ebno in dB [Default scan]\n");
|
|
|
|
printf("\t-s seed [Default 0=time]\n");
|
|
|
|
printf("\t-t tail_bitting [Default %s]\n", tail_biting ? "yes" : "no");
|
|
|
|
printf("\t-k constraint length [Default both]\n", K);
|
|
|
|
}
|
|
|
|
|
|
|
|
void parse_args(int argc, char **argv) {
|
|
|
|
int opt;
|
|
|
|
while ((opt = getopt(argc, argv, "nlstek")) != -1) {
|
|
|
|
switch (opt) {
|
|
|
|
case 'n':
|
|
|
|
nof_frames = atoi(argv[optind]);
|
|
|
|
break;
|
|
|
|
case 'l':
|
|
|
|
frame_length = atoi(argv[optind]);
|
|
|
|
break;
|
|
|
|
case 'e':
|
|
|
|
ebno_db = atof(argv[optind]);
|
|
|
|
break;
|
|
|
|
case 's':
|
|
|
|
seed = atoi(argv[optind]);
|
|
|
|
break;
|
|
|
|
case 't':
|
|
|
|
tail_biting = true;
|
|
|
|
break;
|
|
|
|
case 'k':
|
|
|
|
K = atoi(argv[optind]);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
usage(argv[0]);
|
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int main(int argc, char **argv) {
|
|
|
|
int frame_cnt;
|
|
|
|
float *llr;
|
|
|
|
unsigned char *llr_c;
|
|
|
|
char *data_tx, *data_rx[NTYPES], *symbols;
|
|
|
|
int i, j;
|
|
|
|
float var[SNR_POINTS], varunc[SNR_POINTS];
|
|
|
|
int snr_points;
|
|
|
|
float ber[NTYPES][SNR_POINTS];
|
|
|
|
unsigned int errors[NTYPES];
|
|
|
|
viterbi_type_t viterbi_type[NCODS];
|
|
|
|
viterbi_t dec[NCODS];
|
|
|
|
convcoder_t cod[NCODS];
|
|
|
|
int coded_length[NCODS];
|
|
|
|
int n, ncods, max_coded_length;
|
|
|
|
|
|
|
|
|
|
|
|
parse_args(argc, argv);
|
|
|
|
|
|
|
|
if (!seed) {
|
|
|
|
seed = time(NULL);
|
|
|
|
}
|
|
|
|
srand(seed);
|
|
|
|
|
|
|
|
switch (K) {
|
|
|
|
case 9:
|
|
|
|
cod[0].poly[0] = 0x1ed;
|
|
|
|
cod[0].poly[1] = 0x19b;
|
|
|
|
cod[0].poly[2] = 0x127;
|
|
|
|
cod[0].tail_biting = false;
|
|
|
|
cod[0].K = 9;
|
|
|
|
viterbi_type[0] = viterbi_39;
|
|
|
|
ncods=1;
|
|
|
|
break;
|
|
|
|
case 7:
|
|
|
|
cod[0].poly[0] = 0x6D;
|
|
|
|
cod[0].poly[1] = 0x4F;
|
|
|
|
cod[0].poly[2] = 0x57;
|
|
|
|
cod[0].K = 7;
|
|
|
|
cod[0].tail_biting = tail_biting;
|
|
|
|
viterbi_type[0] = viterbi_37;
|
|
|
|
ncods=1;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
cod[0].poly[0] = 0x1ed;
|
|
|
|
cod[0].poly[1] = 0x19b;
|
|
|
|
cod[0].poly[2] = 0x127;
|
|
|
|
cod[0].tail_biting = false;
|
|
|
|
cod[0].K = 9;
|
|
|
|
viterbi_type[0] = viterbi_39;
|
|
|
|
cod[1].poly[0] = 0x6D;
|
|
|
|
cod[1].poly[1] = 0x4F;
|
|
|
|
cod[1].poly[2] = 0x57;
|
|
|
|
cod[1].tail_biting = false;
|
|
|
|
cod[1].K = 7;
|
|
|
|
viterbi_type[1] = viterbi_37;
|
|
|
|
cod[2].poly[0] = 0x6D;
|
|
|
|
cod[2].poly[1] = 0x4F;
|
|
|
|
cod[2].poly[2] = 0x57;
|
|
|
|
cod[2].tail_biting = true;
|
|
|
|
cod[2].K = 7;
|
|
|
|
viterbi_type[2] = viterbi_37;
|
|
|
|
ncods=3;
|
|
|
|
}
|
|
|
|
|
|
|
|
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];
|
|
|
|
}
|
|
|
|
viterbi_init(&dec[i], viterbi_type[i], cod[i].poly, frame_length, cod[i].tail_biting);
|
|
|
|
printf("Convolutional Code 1/3 K=%d Tail bitting: %s\n", cod[i].K, cod[i].tail_biting ? "yes" : "no");
|
|
|
|
}
|
|
|
|
|
|
|
|
printf(" Frame length: %d\n", frame_length);
|
|
|
|
if (ebno_db < 100.0) {
|
|
|
|
printf(" EbNo: %.2f\n", ebno_db);
|
|
|
|
}
|
|
|
|
|
|
|
|
data_tx = malloc(frame_length * sizeof(char));
|
|
|
|
if (!data_tx) {
|
|
|
|
perror("malloc");
|
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < NTYPES; i++) {
|
|
|
|
data_rx[i] = malloc(frame_length * sizeof(char));
|
|
|
|
if (!data_rx[i]) {
|
|
|
|
perror("malloc");
|
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
symbols = malloc(max_coded_length * sizeof(char));
|
|
|
|
if (!symbols) {
|
|
|
|
perror("malloc");
|
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
llr = malloc(max_coded_length * sizeof(float));
|
|
|
|
if (!llr) {
|
|
|
|
perror("malloc");
|
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
llr_c = malloc(2 * max_coded_length * sizeof(char));
|
|
|
|
if (!llr_c) {
|
|
|
|
perror("malloc");
|
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
float ebno_inc, esno_db;
|
|
|
|
ebno_inc = (SNR_MAX - SNR_MIN) / SNR_POINTS;
|
|
|
|
if (ebno_db == 100.0) {
|
|
|
|
snr_points = SNR_POINTS;
|
|
|
|
for (i = 0; i < snr_points; i++) {
|
|
|
|
ebno_db = SNR_MIN + i * ebno_inc;
|
|
|
|
esno_db = ebno_db + 10 * log10((double) 1 / 3);
|
|
|
|
var[i] = sqrt(1 / (pow(10, esno_db / 10)));
|
|
|
|
varunc[i] = sqrt(1 / (pow(10, ebno_db / 10)));
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
esno_db = ebno_db + 10 * log10((double) 1 / 3);
|
|
|
|
var[0] = sqrt(1 / (pow(10, esno_db / 10)));
|
|
|
|
varunc[0] = sqrt(1 / (pow(10, ebno_db / 10)));
|
|
|
|
snr_points = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
float Gain = 32;
|
|
|
|
|
|
|
|
for (i = 0; i < snr_points; i++) {
|
|
|
|
frame_cnt = 0;
|
|
|
|
for (j = 0; j < NTYPES; j++) {
|
|
|
|
errors[j] = 0;
|
|
|
|
}
|
|
|
|
while (frame_cnt < nof_frames) {
|
|
|
|
|
|
|
|
/* generate data_tx */
|
|
|
|
for (j = 0; j < frame_length; j++) {
|
|
|
|
data_tx[j] = rand() % 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* uncoded BER */
|
|
|
|
for (j = 0; j < frame_length; j++) {
|
|
|
|
llr[j] = data_tx[j] ? sqrt(2) : -sqrt(2);
|
|
|
|
}
|
|
|
|
ch_awgn_f(llr, llr, varunc[i], frame_length);
|
|
|
|
for (j = 0; j < frame_length; j++) {
|
|
|
|
data_rx[0][j] = llr[j] > 0 ? 1 : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* coded BER */
|
|
|
|
for (n=0;n<ncods;n++) {
|
|
|
|
convcoder_encode(&cod[n], data_tx, symbols);
|
|
|
|
|
|
|
|
for (j = 0; j < coded_length[n]; j++) {
|
|
|
|
llr[j] = symbols[j] ? sqrt(2) : -sqrt(2);
|
|
|
|
}
|
|
|
|
|
|
|
|
ch_awgn_f(llr, llr, var[i], coded_length[n]);
|
|
|
|
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]);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* check errors */
|
|
|
|
for (j = 0; j < NTYPES; j++) {
|
|
|
|
errors[j] += bit_diff(data_tx, data_rx[j], frame_length);
|
|
|
|
}
|
|
|
|
frame_cnt++;
|
|
|
|
printf("Eb/No: %3.2f %10d/%d ",
|
|
|
|
SNR_MIN + i * ebno_inc,frame_cnt,nof_frames);
|
|
|
|
for (n=0;n<NTYPES;n++) {
|
|
|
|
printf("BER: %.2e ",(float) errors[n] / (frame_cnt * frame_length));
|
|
|
|
}
|
|
|
|
printf("\r");
|
|
|
|
}
|
|
|
|
printf("\n");
|
|
|
|
for (j = 0; j < NTYPES; j++) {
|
|
|
|
ber[j][i] = (float) errors[j] / (frame_cnt * frame_length);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (snr_points == 1) {
|
|
|
|
printf("BER uncoded: %g\t%u errors\n",
|
|
|
|
(float) errors[0] / (frame_cnt * frame_length), errors[0]);
|
|
|
|
for (n=0;n<ncods;n++) {
|
|
|
|
printf("BER K=%d: %g\t%u errors\n",cod[n].K,
|
|
|
|
(float) errors[1+n] / (frame_cnt * frame_length), errors[1+n]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (snr_points > 1) {
|
|
|
|
printf("\n");
|
|
|
|
|
|
|
|
FILE *f = fopen("output.m", "w");
|
|
|
|
if (!f) {
|
|
|
|
perror("fopen");
|
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
fprintf(f, "ber=[");
|
|
|
|
for (j = 0; j < NTYPES; j++) {
|
|
|
|
for (i = 0; i < snr_points; i++) {
|
|
|
|
fprintf(f, "%g ", ber[j][i]);
|
|
|
|
}
|
|
|
|
fprintf(f, "; ");
|
|
|
|
}
|
|
|
|
fprintf(f, "];\n");
|
|
|
|
fprintf(f, "snr=linspace(%g,%g-%g/%d,%d);\n", SNR_MIN, SNR_MAX, SNR_MAX,
|
|
|
|
snr_points, snr_points);
|
|
|
|
fprintf(f, "semilogy(snr,ber,snr,0.5*erfc(sqrt(10.^(snr/10))));\n");
|
|
|
|
fprintf(f, "legend('uncoded',");
|
|
|
|
for (n=0;n<ncods;n++) {
|
|
|
|
fprintf(f,"'1/3 K=%d%s',",cod[n].K,cod[n].tail_biting?" tb":"");
|
|
|
|
}
|
|
|
|
fprintf(f,"'theory-uncoded');");
|
|
|
|
fprintf(f, "grid on;\n");
|
|
|
|
fclose(f);
|
|
|
|
}
|
|
|
|
for (n=0;n<ncods;n++) {
|
|
|
|
viterbi_free(&dec[n]);
|
|
|
|
}
|
|
|
|
|
|
|
|
free(data_tx);
|
|
|
|
free(symbols);
|
|
|
|
free(llr);
|
|
|
|
for (i = 0; i < NTYPES; i++) {
|
|
|
|
free(data_rx[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
printf("Done\n");
|
|
|
|
exit(0);
|
|
|
|
}
|