Replacing tabs with spaces

master
Paul Sutton 11 years ago
parent c762cd6f0f
commit 5679797ed2

@ -36,44 +36,44 @@
#include "lte/utils/debug.h" #include "lte/utils/debug.h"
int cuhd_rssi_scan(void *uhd, float *freqs, float *rssi, int nof_bands, double fs, int nsamp) { int cuhd_rssi_scan(void *uhd, float *freqs, float *rssi, int nof_bands, double fs, int nsamp) {
int i, j; int i, j;
int ret = -1; int ret = -1;
_Complex float *buffer; _Complex float *buffer;
double f; double f;
buffer = calloc(nsamp, sizeof(_Complex float)); buffer = calloc(nsamp, sizeof(_Complex float));
if (!buffer) { if (!buffer) {
goto free_and_exit; goto free_and_exit;
} }
cuhd_set_rx_gain(uhd, 0.0); cuhd_set_rx_gain(uhd, 0.0);
cuhd_set_rx_srate(uhd, fs); cuhd_set_rx_srate(uhd, fs);
for (i=0;i<nof_bands;i++) { for (i=0;i<nof_bands;i++) {
cuhd_stop_rx_stream(uhd); cuhd_stop_rx_stream(uhd);
f = (double) freqs[i]; f = (double) freqs[i];
cuhd_set_rx_freq(uhd, f); cuhd_set_rx_freq(uhd, f);
cuhd_rx_wait_lo_locked(uhd); cuhd_rx_wait_lo_locked(uhd);
cuhd_start_rx_stream(uhd); cuhd_start_rx_stream(uhd);
/* discard first samples */ /* discard first samples */
for (j=0;j<2;j++) { for (j=0;j<2;j++) {
if (cuhd_recv(uhd, buffer, nsamp, 1) != nsamp) { if (cuhd_recv(uhd, buffer, nsamp, 1) != nsamp) {
goto free_and_exit; goto free_and_exit;
} }
} }
rssi[i] = vec_avg_power_cf(buffer, nsamp); rssi[i] = vec_avg_power_cf(buffer, nsamp);
printf("[%3d]: Freq %4.1f Mhz - RSSI: %3.2f dBm\r", i, f/1000000, 10*log10f(rssi[i]) + 30); fflush(stdout); printf("[%3d]: Freq %4.1f Mhz - RSSI: %3.2f dBm\r", i, f/1000000, 10*log10f(rssi[i]) + 30); fflush(stdout);
if (VERBOSE_ISINFO()) { if (VERBOSE_ISINFO()) {
printf("\n"); printf("\n");
} }
} }
cuhd_stop_rx_stream(uhd); cuhd_stop_rx_stream(uhd);
ret = 0; ret = 0;
free_and_exit: free_and_exit:
free(buffer); free(buffer);
return ret; return ret;
} }

@ -34,90 +34,90 @@
#include "lte.h" #include "lte.h"
void usage(char *arg) { void usage(char *arg) {
printf("Usage: %s nbits snr_db\n",arg); printf("Usage: %s nbits snr_db\n",arg);
} }
int main(int argc, char **argv) { int main(int argc, char **argv) {
binsource_hl bs; binsource_hl bs;
mod_hl mod; mod_hl mod;
ch_awgn_hl ch; ch_awgn_hl ch;
demod_soft_hl demod_s; demod_soft_hl demod_s;
demod_hard_hl demod_h; demod_hard_hl demod_h;
bzero(&bs,sizeof(bs)); bzero(&bs,sizeof(bs));
bzero(&mod,sizeof(mod)); bzero(&mod,sizeof(mod));
bzero(&ch,sizeof(ch)); bzero(&ch,sizeof(ch));
bzero(&demod_s,sizeof(demod_s)); bzero(&demod_s,sizeof(demod_s));
bzero(&demod_h,sizeof(demod_h)); bzero(&demod_h,sizeof(demod_h));
if (argc<3) { if (argc<3) {
usage(argv[0]); usage(argv[0]);
exit(-1); exit(-1);
} }
int nbits = atoi(argv[1]); int nbits = atoi(argv[1]);
float snr_db = atof(argv[2]); float snr_db = atof(argv[2]);
float var = sqrt(pow(10,-snr_db/10)); float var = sqrt(pow(10,-snr_db/10));
bs.init.seed = 0; bs.init.seed = 0;
bs.init.cache_seq_nbits = 0; bs.init.cache_seq_nbits = 0;
bs.ctrl_in.nbits = nbits; bs.ctrl_in.nbits = nbits;
bs.output = malloc(nbits); bs.output = malloc(nbits);
mod.in_len = nbits; mod.in_len = nbits;
mod.init.std = LTE_BPSK; mod.init.std = LTE_BPSK;
mod.input = bs.output; mod.input = bs.output;
mod.output = malloc(nbits*sizeof(_Complex float)); mod.output = malloc(nbits*sizeof(_Complex float));
ch.in_len = nbits; ch.in_len = nbits;
ch.input = mod.output; ch.input = mod.output;
ch.ctrl_in.variance = var; ch.ctrl_in.variance = var;
ch.output = malloc(nbits*sizeof(_Complex float)); ch.output = malloc(nbits*sizeof(_Complex float));
demod_h.in_len = nbits; demod_h.in_len = nbits;
demod_h.init.std = LTE_BPSK; demod_h.init.std = LTE_BPSK;
demod_h.input = ch.output; demod_h.input = ch.output;
demod_h.output = malloc(nbits); demod_h.output = malloc(nbits);
demod_s.in_len = nbits; demod_s.in_len = nbits;
demod_s.init.std = LTE_BPSK; demod_s.init.std = LTE_BPSK;
demod_s.input = ch.output; demod_s.input = ch.output;
demod_s.output = malloc(sizeof(float)*nbits); demod_s.output = malloc(sizeof(float)*nbits);
demod_s.ctrl_in.alg_type = APPROX; demod_s.ctrl_in.alg_type = APPROX;
demod_s.ctrl_in.sigma = var; demod_s.ctrl_in.sigma = var;
if ( binsource_initialize(&bs) || if ( binsource_initialize(&bs) ||
mod_initialize(&mod) || mod_initialize(&mod) ||
ch_awgn_initialize(&ch) || ch_awgn_initialize(&ch) ||
demod_hard_initialize(&demod_h) || demod_hard_initialize(&demod_h) ||
demod_soft_initialize(&demod_s) demod_soft_initialize(&demod_s)
) { ) {
printf("Error initializing modules\n"); printf("Error initializing modules\n");
exit(-1); exit(-1);
} }
binsource_work(&bs); binsource_work(&bs);
mod_work(&mod); mod_work(&mod);
ch_awgn_work(&ch); ch_awgn_work(&ch);
demod_hard_work(&demod_h); demod_hard_work(&demod_h);
demod_soft_work(&demod_s); demod_soft_work(&demod_s);
/* hard decision for soft demodulation */ /* hard decision for soft demodulation */
char* tmp = malloc(nbits); char* tmp = malloc(nbits);
for (int i=0;i<nbits;i++) { for (int i=0;i<nbits;i++) {
tmp[i] = demod_s.output[i]>0?1:0; tmp[i] = demod_s.output[i]>0?1:0;
} }
printf("Hard errors: %u/%d\n",bit_diff(bs.output,demod_h.output,nbits),nbits); printf("Hard errors: %u/%d\n",bit_diff(bs.output,demod_h.output,nbits),nbits);
printf("Soft errors: %u/%d\n",bit_diff(bs.output,tmp,nbits),nbits); printf("Soft errors: %u/%d\n",bit_diff(bs.output,tmp,nbits),nbits);
free(bs.output); free(bs.output);
free(mod.output); free(mod.output);
free(ch.output); free(ch.output);
free(demod_h.output); free(demod_h.output);
free(demod_s.output); free(demod_s.output);
free(tmp); free(tmp);
printf("Exit\n"); printf("Exit\n");
exit(0); exit(0);
} }

@ -32,20 +32,20 @@
#include "lte.h" #include "lte.h"
int main(int argc, char **argv) { int main(int argc, char **argv) {
binsource_t bs; binsource_t bs;
char* output; char* output;
binsource_init(&bs); binsource_init(&bs);
binsource_seed_time(&bs); binsource_seed_time(&bs);
output = malloc(100); output = malloc(100);
if (binsource_generate(&bs,output,100)) { if (binsource_generate(&bs,output,100)) {
printf("Error generating bits\n"); printf("Error generating bits\n");
exit(-1); exit(-1);
} }
printf("output: "); printf("output: ");
bit_fprint(stdout,output,100); bit_fprint(stdout,output,100);
printf("Done\n"); printf("Done\n");
exit(0); exit(0);
} }

@ -34,8 +34,8 @@
#include "lte.h" #include "lte.h"
#ifndef DISABLE_UHD #ifndef DISABLE_UHD
#include "cuhd.h" #include "cuhd.h"
void *uhd; void *uhd;
#endif #endif
char *output_file_name = NULL; char *output_file_name = NULL;
@ -53,231 +53,231 @@ pbch_t pbch;
cf_t *slot_buffer = NULL, *output_buffer = NULL; cf_t *slot_buffer = NULL, *output_buffer = NULL;
int slot_n_re, slot_n_samples; int slot_n_re, slot_n_samples;
#define UHD_SAMP_FREQ 1920000 #define UHD_SAMP_FREQ 1920000
void usage(char *prog) { void usage(char *prog) {
printf("Usage: %s [agmfoncvp]\n", prog); printf("Usage: %s [agmfoncvp]\n", prog);
#ifndef DISABLE_UHD #ifndef DISABLE_UHD
printf("\t-a UHD args [Default %s]\n", uhd_args); printf("\t-a UHD args [Default %s]\n", uhd_args);
printf("\t-g UHD TX gain [Default %.2f dB]\n", uhd_gain); printf("\t-g UHD TX gain [Default %.2f dB]\n", uhd_gain);
printf("\t-m UHD signal amplitude [Default %.2f]\n", uhd_amp); printf("\t-m UHD signal amplitude [Default %.2f]\n", uhd_amp);
printf("\t-f UHD TX frequency [Default %.1f MHz]\n", uhd_freq/1000000); printf("\t-f UHD TX frequency [Default %.1f MHz]\n", uhd_freq/1000000);
#else #else
printf("\t UHD is disabled. CUHD library not available\n"); printf("\t UHD is disabled. CUHD library not available\n");
#endif #endif
printf("\t-o output_file [Default USRP]\n"); printf("\t-o output_file [Default USRP]\n");
printf("\t-n number of frames [Default %d]\n", nof_frames); printf("\t-n number of frames [Default %d]\n", nof_frames);
printf("\t-c cell id [Default %d]\n", cell_id); printf("\t-c cell id [Default %d]\n", cell_id);
printf("\t-p nof_prb [Default %d]\n", nof_prb); printf("\t-p nof_prb [Default %d]\n", nof_prb);
printf("\t-v [set verbose to debug, default none]\n"); printf("\t-v [set verbose to debug, default none]\n");
} }
void parse_args(int argc, char **argv) { void parse_args(int argc, char **argv) {
int opt; int opt;
while ((opt = getopt(argc, argv, "agfmoncpv")) != -1) { while ((opt = getopt(argc, argv, "agfmoncpv")) != -1) {
switch(opt) { switch(opt) {
case 'a': case 'a':
uhd_args = argv[optind]; uhd_args = argv[optind];
break; break;
case 'g': case 'g':
uhd_gain = atof(argv[optind]); uhd_gain = atof(argv[optind]);
break; break;
case 'm': case 'm':
uhd_amp = atof(argv[optind]); uhd_amp = atof(argv[optind]);
break; break;
case 'f': case 'f':
uhd_freq = atof(argv[optind]); uhd_freq = atof(argv[optind]);
break; break;
case 'o': case 'o':
output_file_name = argv[optind]; output_file_name = argv[optind];
break; break;
case 'n': case 'n':
nof_frames = atoi(argv[optind]); nof_frames = atoi(argv[optind]);
break; break;
case 'p': case 'p':
nof_prb = atoi(argv[optind]); nof_prb = atoi(argv[optind]);
break; break;
case 'c': case 'c':
cell_id = atoi(argv[optind]); cell_id = atoi(argv[optind]);
break; break;
case 'v': case 'v':
verbose++; verbose++;
break; break;
default: default:
usage(argv[0]); usage(argv[0]);
exit(-1); exit(-1);
} }
} }
#ifdef DISABLE_UHD #ifdef DISABLE_UHD
if (!output_file_name) { if (!output_file_name) {
usage(argv[0]); usage(argv[0]);
exit(-1); exit(-1);
} }
#endif #endif
} }
void base_init() { void base_init() {
/* init memory */ /* init memory */
slot_buffer = malloc(sizeof(cf_t) * slot_n_re); slot_buffer = malloc(sizeof(cf_t) * slot_n_re);
if (!slot_buffer) { if (!slot_buffer) {
perror("malloc"); perror("malloc");
exit(-1); exit(-1);
} }
output_buffer = malloc(sizeof(cf_t) * slot_n_samples); output_buffer = malloc(sizeof(cf_t) * slot_n_samples);
if (!output_buffer) { if (!output_buffer) {
perror("malloc"); perror("malloc");
exit(-1); exit(-1);
} }
/* open file or USRP */ /* open file or USRP */
if (output_file_name) { if (output_file_name) {
if (filesink_init(&fsink, output_file_name, COMPLEX_FLOAT_BIN)) { if (filesink_init(&fsink, output_file_name, COMPLEX_FLOAT_BIN)) {
fprintf(stderr, "Error opening file %s\n", output_file_name); fprintf(stderr, "Error opening file %s\n", output_file_name);
exit(-1); exit(-1);
} }
} else { } else {
#ifndef DISABLE_UHD #ifndef DISABLE_UHD
printf("Opening UHD device...\n"); printf("Opening UHD device...\n");
if (cuhd_open(uhd_args,&uhd)) { if (cuhd_open(uhd_args,&uhd)) {
fprintf(stderr, "Error opening uhd\n"); fprintf(stderr, "Error opening uhd\n");
exit(-1); exit(-1);
} }
#else #else
printf("Error UHD not available. Select an output file\n"); printf("Error UHD not available. Select an output file\n");
exit(-1); exit(-1);
#endif #endif
} }
/* create ifft object */ /* create ifft object */
if (lte_ifft_init(&ifft, CPNORM, nof_prb)) { if (lte_ifft_init(&ifft, CPNORM, nof_prb)) {
fprintf(stderr, "Error creating iFFT object\n"); fprintf(stderr, "Error creating iFFT object\n");
exit(-1); exit(-1);
} }
if (pbch_init(&pbch, 6, cell_id, CPNORM)) { if (pbch_init(&pbch, 6, cell_id, CPNORM)) {
fprintf(stderr, "Error creating PBCH object\n"); fprintf(stderr, "Error creating PBCH object\n");
exit(-1); exit(-1);
} }
} }
void base_free() { void base_free() {
pbch_free(&pbch); pbch_free(&pbch);
lte_ifft_free(&ifft); lte_ifft_free(&ifft);
if (slot_buffer) { if (slot_buffer) {
free(slot_buffer); free(slot_buffer);
} }
if (output_buffer) { if (output_buffer) {
free(output_buffer); free(output_buffer);
} }
if (output_file_name) { if (output_file_name) {
filesink_free(&fsink); filesink_free(&fsink);
} else { } else {
#ifndef DISABLE_UHD #ifndef DISABLE_UHD
cuhd_close(&uhd); cuhd_close(&uhd);
#endif #endif
} }
} }
int main(int argc, char **argv) { int main(int argc, char **argv) {
int nf, ns, N_id_2; int nf, ns, N_id_2;
cf_t pss_signal[PSS_LEN]; cf_t pss_signal[PSS_LEN];
float sss_signal0[SSS_LEN]; // for subframe 0 float sss_signal0[SSS_LEN]; // for subframe 0
float sss_signal5[SSS_LEN]; // for subframe 5 float sss_signal5[SSS_LEN]; // for subframe 5
pbch_mib_t mib; pbch_mib_t mib;
refsignal_t refs[NSLOTS_X_FRAME]; refsignal_t refs[NSLOTS_X_FRAME];
int i; int i;
cf_t *slot1_symbols[MAX_PORTS_CTRL]; cf_t *slot1_symbols[MAX_PORTS_CTRL];
#ifdef DISABLE_UHD #ifdef DISABLE_UHD
if (argc < 3) { if (argc < 3) {
usage(argv[0]); usage(argv[0]);
exit(-1); exit(-1);
} }
#endif #endif
parse_args(argc,argv); parse_args(argc,argv);
N_id_2 = cell_id%3; N_id_2 = cell_id%3;
slot_n_re = CPNORM_NSYMB * nof_prb * RE_X_RB; slot_n_re = CPNORM_NSYMB * nof_prb * RE_X_RB;
slot_n_samples = SLOT_LEN_CPNORM(lte_symbol_sz(nof_prb)); slot_n_samples = SLOT_LEN_CPNORM(lte_symbol_sz(nof_prb));
/* this *must* be called after setting slot_len_* */ /* this *must* be called after setting slot_len_* */
base_init(); base_init();
/* Generate PSS/SSS signals */ /* Generate PSS/SSS signals */
pss_generate(pss_signal, N_id_2); pss_generate(pss_signal, N_id_2);
sss_generate(sss_signal0, sss_signal5, cell_id); sss_generate(sss_signal0, sss_signal5, cell_id);
/* Generate CRS signals */ /* Generate CRS signals */
for (i=0;i<NSLOTS_X_FRAME;i++) { for (i=0;i<NSLOTS_X_FRAME;i++) {
if (refsignal_init_LTEDL(&refs[i], 0, i, cell_id, CPNORM, nof_prb)) { if (refsignal_init_LTEDL(&refs[i], 0, i, cell_id, CPNORM, nof_prb)) {
fprintf(stderr, "Error initiating CRS slot=%d\n", i); fprintf(stderr, "Error initiating CRS slot=%d\n", i);
return -1; return -1;
} }
} }
mib.nof_ports = 1; mib.nof_ports = 1;
mib.nof_prb = 6; mib.nof_prb = 6;
mib.phich_length = PHICH_NORM; mib.phich_length = PHICH_NORM;
mib.phich_resources = R_1; mib.phich_resources = R_1;
mib.sfn = 0; mib.sfn = 0;
for (i=0;i<MAX_PORTS_CTRL;i++) { // now there's only 1 port for (i=0;i<MAX_PORTS_CTRL;i++) { // now there's only 1 port
slot1_symbols[i] = slot_buffer; slot1_symbols[i] = slot_buffer;
} }
#ifndef DISABLE_UHD #ifndef DISABLE_UHD
if (!output_file_name) { if (!output_file_name) {
printf("Set TX rate: %.2f MHz\n", cuhd_set_tx_srate(uhd, UHD_SAMP_FREQ)/1000000); printf("Set TX rate: %.2f MHz\n", cuhd_set_tx_srate(uhd, UHD_SAMP_FREQ)/1000000);
printf("Set TX gain: %.1f dB\n", cuhd_set_tx_gain(uhd, uhd_gain)); printf("Set TX gain: %.1f dB\n", cuhd_set_tx_gain(uhd, uhd_gain));
printf("Set TX freq: %.2f MHz\n", cuhd_set_tx_freq(uhd, uhd_freq)/1000000); printf("Set TX freq: %.2f MHz\n", cuhd_set_tx_freq(uhd, uhd_freq)/1000000);
} }
#endif #endif
nf = 0; nf = 0;
while(nf<nof_frames || nof_frames == -1) { while(nf<nof_frames || nof_frames == -1) {
for (ns=0;ns<NSLOTS_X_FRAME;ns++) { for (ns=0;ns<NSLOTS_X_FRAME;ns++) {
bzero(slot_buffer, sizeof(cf_t) * slot_n_re); bzero(slot_buffer, sizeof(cf_t) * slot_n_re);
switch(ns) { switch(ns) {
case 0: // tx pss/sss case 0: // tx pss/sss
case 10: // tx pss/sss case 10: // tx pss/sss
pss_put_slot(pss_signal, slot_buffer, nof_prb, CPNORM); pss_put_slot(pss_signal, slot_buffer, nof_prb, CPNORM);
sss_put_slot(ns?sss_signal5:sss_signal0, slot_buffer, nof_prb, CPNORM); sss_put_slot(ns?sss_signal5:sss_signal0, slot_buffer, nof_prb, CPNORM);
break; break;
case 1: // tx pbch case 1: // tx pbch
pbch_encode(&pbch, &mib, slot1_symbols, 1); pbch_encode(&pbch, &mib, slot1_symbols, 1);
break; break;
default: // transmit zeros default: // transmit zeros
break; break;
} }
refsignal_put(&refs[ns], slot_buffer); refsignal_put(&refs[ns], slot_buffer);
/* Transform to OFDM symbols */ /* Transform to OFDM symbols */
lte_ifft_run(&ifft, slot_buffer, output_buffer); lte_ifft_run(&ifft, slot_buffer, output_buffer);
/* send to file or usrp */ /* send to file or usrp */
if (output_file_name) { if (output_file_name) {
filesink_write(&fsink, output_buffer, slot_n_samples); filesink_write(&fsink, output_buffer, slot_n_samples);
usleep(5000); usleep(5000);
} else { } else {
#ifndef DISABLE_UHD #ifndef DISABLE_UHD
vec_sc_prod_cfc(output_buffer, uhd_amp, output_buffer, slot_n_samples); vec_sc_prod_cfc(output_buffer, uhd_amp, output_buffer, slot_n_samples);
cuhd_send(uhd, output_buffer, slot_n_samples, 1); cuhd_send(uhd, output_buffer, slot_n_samples, 1);
#endif #endif
} }
} }
mib.sfn=(mib.sfn+1)%1024; mib.sfn=(mib.sfn+1)%1024;
printf("SFN: %4d\r", mib.sfn);fflush(stdout); printf("SFN: %4d\r", mib.sfn);fflush(stdout);
nf++; nf++;
} }
base_free(); base_free();
printf("Done\n"); printf("Done\n");
exit(0); exit(0);
} }

@ -39,21 +39,21 @@
#include "lte.h" #include "lte.h"
#ifndef DISABLE_UHD #ifndef DISABLE_UHD
#include "cuhd.h" #include "cuhd.h"
void *uhd; void *uhd;
#endif #endif
#ifndef DISABLE_GRAPHICS #ifndef DISABLE_GRAPHICS
#include "plot.h" #include "plot.h"
plot_real_t poutfft; plot_real_t poutfft;
plot_complex_t pce; plot_complex_t pce;
plot_scatter_t pscatrecv, pscatequal; plot_scatter_t pscatrecv, pscatequal;
#endif #endif
#define MHZ 1000000 #define MHZ 1000000
#define SAMP_FREQ 1920000 #define SAMP_FREQ 1920000
#define FLEN 9600 #define FLEN 9600
#define FLEN_PERIOD 0.005 #define FLEN_PERIOD 0.005
#define NOF_PORTS 2 #define NOF_PORTS 2
@ -80,422 +80,422 @@ cfo_t cfocorr;
enum sync_state {FIND, TRACK}; enum sync_state {FIND, TRACK};
void usage(char *prog) { void usage(char *prog) {
printf("Usage: %s [iagfndvp]\n", prog); printf("Usage: %s [iagfndvp]\n", prog);
printf("\t-i input_file [Default use USRP]\n"); printf("\t-i input_file [Default use USRP]\n");
#ifndef DISABLE_UHD #ifndef DISABLE_UHD
printf("\t-a UHD args [Default %s]\n", uhd_args); printf("\t-a UHD args [Default %s]\n", uhd_args);
printf("\t-g UHD RX gain [Default %.2f dB]\n", uhd_gain); printf("\t-g UHD RX gain [Default %.2f dB]\n", uhd_gain);
printf("\t-f UHD RX frequency [Default %.1f MHz]\n", uhd_freq/1000000); printf("\t-f UHD RX frequency [Default %.1f MHz]\n", uhd_freq/1000000);
#else #else
printf("\t UHD is disabled. CUHD library not available\n"); printf("\t UHD is disabled. CUHD library not available\n");
#endif #endif
printf("\t-n nof_frames [Default %d]\n", nof_frames); printf("\t-n nof_frames [Default %d]\n", nof_frames);
printf("\t-p PSS threshold [Default %f]\n", find_threshold); printf("\t-p PSS threshold [Default %f]\n", find_threshold);
#ifndef DISABLE_GRAPHICS #ifndef DISABLE_GRAPHICS
printf("\t-d disable plots [Default enabled]\n"); printf("\t-d disable plots [Default enabled]\n");
#else #else
printf("\t plots are disabled. Graphics library not available\n"); printf("\t plots are disabled. Graphics library not available\n");
#endif #endif
printf("\t-v [set verbose to debug, default none]\n"); printf("\t-v [set verbose to debug, default none]\n");
} }
void parse_args(int argc, char **argv) { void parse_args(int argc, char **argv) {
int opt; int opt;
while ((opt = getopt(argc, argv, "iagfndvp")) != -1) { while ((opt = getopt(argc, argv, "iagfndvp")) != -1) {
switch(opt) { switch(opt) {
case 'i': case 'i':
input_file_name = argv[optind]; input_file_name = argv[optind];
break; break;
case 'a': case 'a':
uhd_args = argv[optind]; uhd_args = argv[optind];
break; break;
case 'g': case 'g':
uhd_gain = atof(argv[optind]); uhd_gain = atof(argv[optind]);
break; break;
case 'f': case 'f':
uhd_freq = atof(argv[optind]); uhd_freq = atof(argv[optind]);
break; break;
case 'p': case 'p':
find_threshold = atof(argv[optind]); find_threshold = atof(argv[optind]);
break; break;
case 'n': case 'n':
nof_frames = atoi(argv[optind]); nof_frames = atoi(argv[optind]);
break; break;
case 'd': case 'd':
disable_plots = 1; disable_plots = 1;
break; break;
case 'v': case 'v':
verbose++; verbose++;
break; break;
default: default:
usage(argv[0]); usage(argv[0]);
exit(-1); exit(-1);
} }
} }
} }
#ifndef DISABLE_GRAPHICS #ifndef DISABLE_GRAPHICS
void init_plots() { void init_plots() {
plot_init(); plot_init();
plot_real_init(&poutfft); plot_real_init(&poutfft);
plot_real_setTitle(&poutfft, "Output FFT - Magnitude"); plot_real_setTitle(&poutfft, "Output FFT - Magnitude");
plot_real_setLabels(&poutfft, "Index", "dB"); plot_real_setLabels(&poutfft, "Index", "dB");
plot_real_setYAxisScale(&poutfft, -60, 0); plot_real_setYAxisScale(&poutfft, -60, 0);
plot_real_setXAxisScale(&poutfft, 1, 504); plot_real_setXAxisScale(&poutfft, 1, 504);
plot_complex_init(&pce); plot_complex_init(&pce);
plot_complex_setTitle(&pce, "Channel Estimates"); plot_complex_setTitle(&pce, "Channel Estimates");
plot_complex_setYAxisScale(&pce, Ip, -0.01, 0.01); plot_complex_setYAxisScale(&pce, Ip, -0.01, 0.01);
plot_complex_setYAxisScale(&pce, Q, -0.01, 0.01); plot_complex_setYAxisScale(&pce, Q, -0.01, 0.01);
plot_complex_setYAxisScale(&pce, Magnitude, 0, 0.01); plot_complex_setYAxisScale(&pce, Magnitude, 0, 0.01);
plot_complex_setYAxisScale(&pce, Phase, -M_PI, M_PI); plot_complex_setYAxisScale(&pce, Phase, -M_PI, M_PI);
plot_scatter_init(&pscatrecv); plot_scatter_init(&pscatrecv);
plot_scatter_setTitle(&pscatrecv, "Received Symbols"); plot_scatter_setTitle(&pscatrecv, "Received Symbols");
plot_scatter_setXAxisScale(&pscatrecv, -0.01, 0.01); plot_scatter_setXAxisScale(&pscatrecv, -0.01, 0.01);
plot_scatter_setYAxisScale(&pscatrecv, -0.01, 0.01); plot_scatter_setYAxisScale(&pscatrecv, -0.01, 0.01);
plot_scatter_init(&pscatequal); plot_scatter_init(&pscatequal);
plot_scatter_setTitle(&pscatequal, "Equalized Symbols"); plot_scatter_setTitle(&pscatequal, "Equalized Symbols");
plot_scatter_setXAxisScale(&pscatequal, -1, 1); plot_scatter_setXAxisScale(&pscatequal, -1, 1);
plot_scatter_setYAxisScale(&pscatequal, -1, 1); plot_scatter_setYAxisScale(&pscatequal, -1, 1);
} }
#endif #endif
int base_init(int frame_length) { int base_init(int frame_length) {
int i; int i;
#ifndef DISABLE_GRAPHICS #ifndef DISABLE_GRAPHICS
if (!disable_plots) { if (!disable_plots) {
init_plots(); init_plots();
} }
#else #else
printf("-- PLOTS are disabled. Graphics library not available --\n\n"); printf("-- PLOTS are disabled. Graphics library not available --\n\n");
#endif #endif
if (input_file_name) { if (input_file_name) {
if (filesource_init(&fsrc, input_file_name, COMPLEX_FLOAT_BIN)) { if (filesource_init(&fsrc, input_file_name, COMPLEX_FLOAT_BIN)) {
return -1; return -1;
} }
} else { } else {
/* open UHD device */ /* open UHD device */
#ifndef DISABLE_UHD #ifndef DISABLE_UHD
printf("Opening UHD device...\n"); printf("Opening UHD device...\n");
if (cuhd_open(uhd_args,&uhd)) { if (cuhd_open(uhd_args,&uhd)) {
fprintf(stderr, "Error opening uhd\n"); fprintf(stderr, "Error opening uhd\n");
return -1; return -1;
} }
#else #else
printf("Error UHD not available. Select an input file\n"); printf("Error UHD not available. Select an input file\n");
return -1; return -1;
#endif #endif
} }
input_buffer = (cf_t*) malloc(frame_length * sizeof(cf_t)); input_buffer = (cf_t*) malloc(frame_length * sizeof(cf_t));
if (!input_buffer) { if (!input_buffer) {
perror("malloc"); perror("malloc");
return -1; return -1;
} }
fft_buffer = (cf_t*) malloc(CPNORM_NSYMB * 72 * sizeof(cf_t)); fft_buffer = (cf_t*) malloc(CPNORM_NSYMB * 72 * sizeof(cf_t));
if (!fft_buffer) { if (!fft_buffer) {
perror("malloc"); perror("malloc");
return -1; return -1;
} }
for (i=0;i<MAX_PORTS_CTRL;i++) { for (i=0;i<MAX_PORTS_CTRL;i++) {
ce[i] = (cf_t*) malloc(CPNORM_NSYMB * 72 * sizeof(cf_t)); ce[i] = (cf_t*) malloc(CPNORM_NSYMB * 72 * sizeof(cf_t));
if (!ce[i]) { if (!ce[i]) {
perror("malloc"); perror("malloc");
return -1; return -1;
} }
} }
if (sync_init(&sfind, FLEN)) { if (sync_init(&sfind, FLEN)) {
fprintf(stderr, "Error initiating PSS/SSS\n"); fprintf(stderr, "Error initiating PSS/SSS\n");
return -1; return -1;
} }
if (sync_init(&strack, track_len)) { if (sync_init(&strack, track_len)) {
fprintf(stderr, "Error initiating PSS/SSS\n"); fprintf(stderr, "Error initiating PSS/SSS\n");
return -1; return -1;
} }
if (chest_init(&chest, LINEAR, CPNORM, 6, NOF_PORTS)) { if (chest_init(&chest, LINEAR, CPNORM, 6, NOF_PORTS)) {
fprintf(stderr, "Error initializing equalizer\n"); fprintf(stderr, "Error initializing equalizer\n");
return -1; return -1;
} }
if (cfo_init(&cfocorr, FLEN)) { if (cfo_init(&cfocorr, FLEN)) {
fprintf(stderr, "Error initiating CFO\n"); fprintf(stderr, "Error initiating CFO\n");
return -1; return -1;
} }
if (lte_fft_init(&fft, CPNORM, 6)) { if (lte_fft_init(&fft, CPNORM, 6)) {
fprintf(stderr, "Error initializing FFT\n"); fprintf(stderr, "Error initializing FFT\n");
return -1; return -1;
} }
return 0; return 0;
} }
void base_free() { void base_free() {
int i; int i;
if (input_file_name) { if (input_file_name) {
filesource_free(&fsrc); filesource_free(&fsrc);
} else { } else {
#ifndef DISABLE_UHD #ifndef DISABLE_UHD
cuhd_close(uhd); cuhd_close(uhd);
#endif #endif
} }
#ifndef DISABLE_GRAPHICS #ifndef DISABLE_GRAPHICS
plot_exit(); plot_exit();
#endif #endif
sync_free(&sfind); sync_free(&sfind);
sync_free(&strack); sync_free(&strack);
lte_fft_free(&fft); lte_fft_free(&fft);
chest_free(&chest); chest_free(&chest);
cfo_free(&cfocorr); cfo_free(&cfocorr);
free(input_buffer); free(input_buffer);
free(fft_buffer); free(fft_buffer);
for (i=0;i<MAX_PORTS_CTRL;i++) { for (i=0;i<MAX_PORTS_CTRL;i++) {
free(ce[i]); free(ce[i]);
} }
} }
int mib_decoder_init(int cell_id) { int mib_decoder_init(int cell_id) {
if (chest_ref_LTEDL(&chest, cell_id)) { if (chest_ref_LTEDL(&chest, cell_id)) {
fprintf(stderr, "Error initializing reference signal\n"); fprintf(stderr, "Error initializing reference signal\n");
return -1; return -1;
} }
if (pbch_init(&pbch, 6, cell_id, CPNORM)) { if (pbch_init(&pbch, 6, cell_id, CPNORM)) {
fprintf(stderr, "Error initiating PBCH\n"); fprintf(stderr, "Error initiating PBCH\n");
return -1; return -1;
} }
DEBUG("PBCH initiated cell_id=%d\n", cell_id); DEBUG("PBCH initiated cell_id=%d\n", cell_id);
return 0; return 0;
} }
int mib_decoder_run(cf_t *input, pbch_mib_t *mib) { int mib_decoder_run(cf_t *input, pbch_mib_t *mib) {
int i, n; int i, n;
lte_fft_run(&fft, input, fft_buffer); lte_fft_run(&fft, input, fft_buffer);
/* Get channel estimates for each port */ /* Get channel estimates for each port */
for (i=0;i<NOF_PORTS;i++) { for (i=0;i<NOF_PORTS;i++) {
chest_ce_slot_port(&chest, fft_buffer, ce[i], 1, i); chest_ce_slot_port(&chest, fft_buffer, ce[i], 1, i);
} }
DEBUG("Decoding PBCH\n", 0); DEBUG("Decoding PBCH\n", 0);
n = pbch_decode(&pbch, fft_buffer, ce, 1, mib); n = pbch_decode(&pbch, fft_buffer, ce, 1, mib);
#ifndef DISABLE_GRAPHICS #ifndef DISABLE_GRAPHICS
float tmp[72*7]; float tmp[72*7];
if (!disable_plots) { if (!disable_plots) {
for (i=0;i<72*7;i++) { for (i=0;i<72*7;i++) {
tmp[i] = 10*log10f(cabsf(fft_buffer[i])); tmp[i] = 10*log10f(cabsf(fft_buffer[i]));
} }
plot_real_setNewData(&poutfft, tmp, 72*7); plot_real_setNewData(&poutfft, tmp, 72*7);
plot_complex_setNewData(&pce, ce[0], 72*7); plot_complex_setNewData(&pce, ce[0], 72*7);
plot_scatter_setNewData(&pscatrecv, pbch.pbch_symbols[0], pbch.nof_symbols); plot_scatter_setNewData(&pscatrecv, pbch.pbch_symbols[0], pbch.nof_symbols);
if (n) { if (n) {
plot_scatter_setNewData(&pscatequal, pbch.pbch_d, pbch.nof_symbols); plot_scatter_setNewData(&pscatequal, pbch.pbch_d, pbch.nof_symbols);
} }
} }
#endif #endif
return n; return n;
} }
void sigintHandler(int sig_num) void sigintHandler(int sig_num)
{ {
go_exit=1; go_exit=1;
} }
int main(int argc, char **argv) { int main(int argc, char **argv) {
int frame_cnt; int frame_cnt;
int cell_id; int cell_id;
int find_idx, track_idx, last_found; int find_idx, track_idx, last_found;
enum sync_state state; enum sync_state state;
int nslot; int nslot;
pbch_mib_t mib; pbch_mib_t mib;
float cfo; float cfo;
int n; int n;
int nof_found_mib = 0; int nof_found_mib = 0;
float timeoffset = 0; float timeoffset = 0;
#ifdef DISABLE_UHD #ifdef DISABLE_UHD
if (argc < 3) { if (argc < 3) {
usage(argv[0]); usage(argv[0]);
exit(-1); exit(-1);
} }
#endif #endif
parse_args(argc,argv); parse_args(argc,argv);
if (base_init(FLEN)) { if (base_init(FLEN)) {
fprintf(stderr, "Error initializing memory\n"); fprintf(stderr, "Error initializing memory\n");
exit(-1); exit(-1);
} }
sync_pss_det_peak_to_avg(&sfind); sync_pss_det_peak_to_avg(&sfind);
sync_pss_det_peak_to_avg(&strack); sync_pss_det_peak_to_avg(&strack);
if (!input_file_name) { if (!input_file_name) {
#ifndef DISABLE_UHD #ifndef DISABLE_UHD
INFO("Setting sampling frequency %.2f MHz\n", (float) SAMP_FREQ/MHZ); INFO("Setting sampling frequency %.2f MHz\n", (float) SAMP_FREQ/MHZ);
cuhd_set_rx_srate(uhd, SAMP_FREQ); cuhd_set_rx_srate(uhd, SAMP_FREQ);
cuhd_set_rx_gain(uhd, uhd_gain); cuhd_set_rx_gain(uhd, uhd_gain);
/* set uhd_freq */ /* set uhd_freq */
cuhd_set_rx_freq(uhd, (double) uhd_freq); cuhd_set_rx_freq(uhd, (double) uhd_freq);
cuhd_rx_wait_lo_locked(uhd); cuhd_rx_wait_lo_locked(uhd);
DEBUG("Set uhd_freq to %.3f MHz\n", (double) uhd_freq); DEBUG("Set uhd_freq to %.3f MHz\n", (double) uhd_freq);
DEBUG("Starting receiver...\n",0); DEBUG("Starting receiver...\n",0);
cuhd_start_rx_stream(uhd); cuhd_start_rx_stream(uhd);
#endif #endif
} }
printf("\n --- Press Ctrl+C to exit --- \n"); printf("\n --- Press Ctrl+C to exit --- \n");
signal(SIGINT, sigintHandler); signal(SIGINT, sigintHandler);
state = FIND; state = FIND;
nslot = 0; nslot = 0;
find_idx = 0; find_idx = 0;
cfo = 0; cfo = 0;
mib.sfn = -1; mib.sfn = -1;
frame_cnt = 0; frame_cnt = 0;
last_found = 0; last_found = 0;
sync_set_threshold(&sfind, find_threshold); sync_set_threshold(&sfind, find_threshold);
sync_force_N_id_2(&sfind, -1); sync_force_N_id_2(&sfind, -1);
while(!go_exit && (frame_cnt < nof_frames || nof_frames==-1)) { while(!go_exit && (frame_cnt < nof_frames || nof_frames==-1)) {
INFO(" ----- RECEIVING %d SAMPLES ---- \n", FLEN); INFO(" ----- RECEIVING %d SAMPLES ---- \n", FLEN);
if (input_file_name) { if (input_file_name) {
n = filesource_read(&fsrc, input_buffer, FLEN); n = filesource_read(&fsrc, input_buffer, FLEN);
if (n == -1) { if (n == -1) {
fprintf(stderr, "Error reading file\n"); fprintf(stderr, "Error reading file\n");
exit(-1); exit(-1);
} else if (n < FLEN) { } else if (n < FLEN) {
filesource_seek(&fsrc, 0); filesource_seek(&fsrc, 0);
filesource_read(&fsrc, input_buffer, FLEN); filesource_read(&fsrc, input_buffer, FLEN);
} }
} else { } else {
#ifndef DISABLE_UHD #ifndef DISABLE_UHD
cuhd_recv(uhd, input_buffer, FLEN, 1); cuhd_recv(uhd, input_buffer, FLEN, 1);
#endif #endif
} }
switch(state) { switch(state) {
case FIND: case FIND:
/* find peak in all frame */ /* find peak in all frame */
find_idx = sync_run(&sfind, input_buffer); find_idx = sync_run(&sfind, input_buffer);
INFO("FIND %3d:\tPAR=%.2f\n", frame_cnt, sync_get_peak_to_avg(&sfind)); INFO("FIND %3d:\tPAR=%.2f\n", frame_cnt, sync_get_peak_to_avg(&sfind));
if (find_idx != -1) { if (find_idx != -1) {
/* if found peak, go to track and set track threshold */ /* if found peak, go to track and set track threshold */
cell_id = sync_get_cell_id(&sfind); cell_id = sync_get_cell_id(&sfind);
if (cell_id != -1) { if (cell_id != -1) {
frame_cnt = -1; frame_cnt = -1;
last_found = 0; last_found = 0;
sync_set_threshold(&strack, track_threshold); sync_set_threshold(&strack, track_threshold);
sync_force_N_id_2(&strack, sync_get_N_id_2(&sfind)); sync_force_N_id_2(&strack, sync_get_N_id_2(&sfind));
sync_force_cp(&strack, sync_get_cp(&sfind)); sync_force_cp(&strack, sync_get_cp(&sfind));
mib_decoder_init(cell_id); mib_decoder_init(cell_id);
nof_found_mib = 0; nof_found_mib = 0;
nslot = sync_get_slot_id(&sfind); nslot = sync_get_slot_id(&sfind);
nslot=(nslot+10)%20; nslot=(nslot+10)%20;
cfo = 0; cfo = 0;
timeoffset = 0; timeoffset = 0;
printf("\n"); printf("\n");
state = TRACK; state = TRACK;
} else { } else {
printf("cellid=-1\n"); printf("cellid=-1\n");
} }
} }
if (verbose == VERBOSE_NONE) { if (verbose == VERBOSE_NONE) {
printf("Finding PSS... PAR=%.2f\r", sync_get_peak_to_avg(&sfind)); printf("Finding PSS... PAR=%.2f\r", sync_get_peak_to_avg(&sfind));
} }
break; break;
case TRACK: case TRACK:
/* Find peak around known position find_idx */ /* Find peak around known position find_idx */
INFO("TRACK %3d: PSS find_idx %d offset %d\n", frame_cnt, find_idx, find_idx - track_len); INFO("TRACK %3d: PSS find_idx %d offset %d\n", frame_cnt, find_idx, find_idx - track_len);
track_idx = sync_run(&strack, &input_buffer[find_idx - track_len]); track_idx = sync_run(&strack, &input_buffer[find_idx - track_len]);
if (track_idx != -1) { if (track_idx != -1) {
/* compute cumulative moving average CFO */ /* compute cumulative moving average CFO */
cfo = (sync_get_cfo(&strack) + frame_cnt * cfo) / (frame_cnt + 1); cfo = (sync_get_cfo(&strack) + frame_cnt * cfo) / (frame_cnt + 1);
/* compute cumulative moving average time offset */ /* compute cumulative moving average time offset */
timeoffset = (float) (track_idx-track_len + timeoffset * frame_cnt) / (frame_cnt + 1); timeoffset = (float) (track_idx-track_len + timeoffset * frame_cnt) / (frame_cnt + 1);
last_found = frame_cnt; last_found = frame_cnt;
find_idx = (find_idx + track_idx - track_len)%FLEN; find_idx = (find_idx + track_idx - track_len)%FLEN;
if (nslot != sync_get_slot_id(&strack)) { if (nslot != sync_get_slot_id(&strack)) {
INFO("Expected slot %d but got %d\n", nslot, sync_get_slot_id(&strack)); INFO("Expected slot %d but got %d\n", nslot, sync_get_slot_id(&strack));
printf("\r\n"); printf("\r\n");
fflush(stdout); fflush(stdout);
printf("\r\n"); printf("\r\n");
state = FIND; state = FIND;
} }
} else { } else {
/* if sync not found, adjust time offset with the averaged value */ /* if sync not found, adjust time offset with the averaged value */
find_idx = (find_idx + (int) timeoffset)%FLEN; find_idx = (find_idx + (int) timeoffset)%FLEN;
} }
/* if we missed too many PSS go back to FIND */ /* if we missed too many PSS go back to FIND */
if (frame_cnt - last_found > max_track_lost) { if (frame_cnt - last_found > max_track_lost) {
INFO("%d frames lost. Going back to FIND", frame_cnt - last_found); INFO("%d frames lost. Going back to FIND", frame_cnt - last_found);
printf("\r\n"); printf("\r\n");
fflush(stdout); fflush(stdout);
printf("\r\n"); printf("\r\n");
state = FIND; state = FIND;
} }
// Correct CFO // Correct CFO
INFO("Correcting CFO=%.4f\n", cfo); INFO("Correcting CFO=%.4f\n", cfo);
cfo_correct(&cfocorr, input_buffer, -cfo/128); cfo_correct(&cfocorr, input_buffer, -cfo/128);
if (nslot == 0 && find_idx + 960 < FLEN) { if (nslot == 0 && find_idx + 960 < FLEN) {
INFO("Finding MIB at idx %d\n", find_idx); INFO("Finding MIB at idx %d\n", find_idx);
if (mib_decoder_run(&input_buffer[find_idx], &mib)) { if (mib_decoder_run(&input_buffer[find_idx], &mib)) {
INFO("MIB detected attempt=%d\n", frame_cnt); INFO("MIB detected attempt=%d\n", frame_cnt);
if (verbose == VERBOSE_NONE) { if (verbose == VERBOSE_NONE) {
if (!nof_found_mib) { if (!nof_found_mib) {
printf("\r\n"); printf("\r\n");
fflush(stdout); fflush(stdout);
printf("\r\n"); printf("\r\n");
printf(" - Phy. CellId:\t%d\n", cell_id); printf(" - Phy. CellId:\t%d\n", cell_id);
pbch_mib_fprint(stdout, &mib); pbch_mib_fprint(stdout, &mib);
} }
} }
nof_found_mib++; nof_found_mib++;
} else { } else {
INFO("MIB not found attempt %d\n",frame_cnt); INFO("MIB not found attempt %d\n",frame_cnt);
} }
if (frame_cnt) { if (frame_cnt) {
printf("SFN: %4d, CFO: %+.4f KHz, SFO: %+.4f Khz, TimeOffset: %4d, Errors: %4d/%4d, ErrorRate: %.1e\r", mib.sfn, printf("SFN: %4d, CFO: %+.4f KHz, SFO: %+.4f Khz, TimeOffset: %4d, Errors: %4d/%4d, ErrorRate: %.1e\r", mib.sfn,
cfo*15, timeoffset/5, find_idx, frame_cnt-2*(nof_found_mib-1), frame_cnt, cfo*15, timeoffset/5, find_idx, frame_cnt-2*(nof_found_mib-1), frame_cnt,
(float) (frame_cnt-2*(nof_found_mib-1))/frame_cnt); (float) (frame_cnt-2*(nof_found_mib-1))/frame_cnt);
fflush(stdout); fflush(stdout);
} }
} }
if (input_file_name) { if (input_file_name) {
usleep(5000); usleep(5000);
} }
nslot = (nslot+10)%20; nslot = (nslot+10)%20;
break; break;
} }
frame_cnt++; frame_cnt++;
} }
base_free(); base_free();
printf("\nBye\n"); printf("\nBye\n");
exit(0); exit(0);
} }

@ -42,13 +42,13 @@
#include "cuhd.h" #include "cuhd.h"
#endif #endif
#define MHZ 1000000 #define MHZ 1000000
#define SAMP_FREQ 1920000 #define SAMP_FREQ 1920000
#define RSSI_FS 1000000 #define RSSI_FS 1000000
#define FLEN 9600 #define FLEN 9600
#define FLEN_PERIOD 0.005 #define FLEN_PERIOD 0.005
#define RSSI_DECIM 20 #define RSSI_DECIM 20
#define IS_SIGNAL(i) (10*log10f(rssi[i]) + 30 > rssi_threshold) #define IS_SIGNAL(i) (10*log10f(rssi[i]) + 30 > rssi_threshold)
@ -86,474 +86,474 @@ enum sync_state {INIT, FIND, TRACK, MIB, DONE};
void usage(char *prog) { void usage(char *prog) {
printf("Usage: %s [seRrFfTtgv] -b band\n", prog); printf("Usage: %s [seRrFfTtgv] -b band\n", prog);
printf("\t-s earfcn_start [Default All]\n"); printf("\t-s earfcn_start [Default All]\n");
printf("\t-e earfcn_end [Default All]\n"); printf("\t-e earfcn_end [Default All]\n");
printf("\t-R rssi_nof_samples [Default %d]\n", nof_samples_rssi); printf("\t-R rssi_nof_samples [Default %d]\n", nof_samples_rssi);
printf("\t-r rssi_threshold [Default %.2f dBm]\n", rssi_threshold); printf("\t-r rssi_threshold [Default %.2f dBm]\n", rssi_threshold);
printf("\t-F pss_find_nof_frames [Default %d]\n", nof_frames_find); printf("\t-F pss_find_nof_frames [Default %d]\n", nof_frames_find);
printf("\t-f pss_find_threshold [Default %.2f]\n", find_threshold); printf("\t-f pss_find_threshold [Default %.2f]\n", find_threshold);
printf("\t-T pss_track_nof_frames [Default %d]\n", nof_frames_track); printf("\t-T pss_track_nof_frames [Default %d]\n", nof_frames_track);
printf("\t-t pss_track_threshold [Default %.2f]\n", track_threshold); printf("\t-t pss_track_threshold [Default %.2f]\n", track_threshold);
printf("\t-l pss_track_len [Default %d]\n", track_len); printf("\t-l pss_track_len [Default %d]\n", track_len);
printf("\t-g gain [Default %.2f dB]\n", uhd_gain); printf("\t-g gain [Default %.2f dB]\n", uhd_gain);
printf("\t-v [set verbose to debug, default none]\n"); printf("\t-v [set verbose to debug, default none]\n");
} }
void parse_args(int argc, char **argv) { void parse_args(int argc, char **argv) {
int opt; int opt;
while ((opt = getopt(argc, argv, "bseRrFfTtgv")) != -1) { while ((opt = getopt(argc, argv, "bseRrFfTtgv")) != -1) {
switch(opt) { switch(opt) {
case 'b': case 'b':
band = atoi(argv[optind]); band = atoi(argv[optind]);
break; break;
case 's': case 's':
earfcn_start = atoi(argv[optind]); earfcn_start = atoi(argv[optind]);
break; break;
case 'e': case 'e':
earfcn_end = atoi(argv[optind]); earfcn_end = atoi(argv[optind]);
break; break;
case 'R': case 'R':
nof_samples_rssi = atoi(argv[optind]); nof_samples_rssi = atoi(argv[optind]);
break; break;
case 'r': case 'r':
rssi_threshold = -atof(argv[optind]); rssi_threshold = -atof(argv[optind]);
break; break;
case 'F': case 'F':
nof_frames_find = atoi(argv[optind]); nof_frames_find = atoi(argv[optind]);
break; break;
case 'f': case 'f':
find_threshold = atof(argv[optind]); find_threshold = atof(argv[optind]);
break; break;
case 'T': case 'T':
nof_frames_track = atoi(argv[optind]); nof_frames_track = atoi(argv[optind]);
break; break;
case 't': case 't':
track_threshold = atof(argv[optind]); track_threshold = atof(argv[optind]);
break; break;
case 'g': case 'g':
uhd_gain = atof(argv[optind]); uhd_gain = atof(argv[optind]);
break; break;
case 'v': case 'v':
verbose++; verbose++;
break; break;
default: default:
usage(argv[0]); usage(argv[0]);
exit(-1); exit(-1);
} }
} }
} }
int base_init(int frame_length) { int base_init(int frame_length) {
int i; int i;
input_buffer = malloc(2 * frame_length * sizeof(cf_t)); input_buffer = malloc(2 * frame_length * sizeof(cf_t));
if (!input_buffer) { if (!input_buffer) {
perror("malloc"); perror("malloc");
return -1; return -1;
} }
fft_buffer = malloc(CPNORM_NSYMB * 72 * sizeof(cf_t)); fft_buffer = malloc(CPNORM_NSYMB * 72 * sizeof(cf_t));
if (!fft_buffer) { if (!fft_buffer) {
perror("malloc"); perror("malloc");
return -1; return -1;
} }
for (i=0;i<MAX_PORTS;i++) { for (i=0;i<MAX_PORTS;i++) {
ce[i] = malloc(CPNORM_NSYMB * 72 * sizeof(cf_t)); ce[i] = malloc(CPNORM_NSYMB * 72 * sizeof(cf_t));
if (!ce[i]) { if (!ce[i]) {
perror("malloc"); perror("malloc");
return -1; return -1;
} }
} }
if (sync_init(&sfind, FLEN)) { if (sync_init(&sfind, FLEN)) {
fprintf(stderr, "Error initiating PSS/SSS\n"); fprintf(stderr, "Error initiating PSS/SSS\n");
return -1; return -1;
} }
if (sync_init(&strack, track_len)) { if (sync_init(&strack, track_len)) {
fprintf(stderr, "Error initiating PSS/SSS\n"); fprintf(stderr, "Error initiating PSS/SSS\n");
return -1; return -1;
} }
if (chest_init(&chest, LINEAR, CPNORM, 6, MAX_PORTS)) { if (chest_init(&chest, LINEAR, CPNORM, 6, MAX_PORTS)) {
fprintf(stderr, "Error initializing equalizer\n"); fprintf(stderr, "Error initializing equalizer\n");
return -1; return -1;
} }
if (lte_fft_init(&fft, CPNORM, 6)) { if (lte_fft_init(&fft, CPNORM, 6)) {
fprintf(stderr, "Error initializing FFT\n"); fprintf(stderr, "Error initializing FFT\n");
return -1; return -1;
} }
if (cfo_init(&cfocorr, FLEN)) { if (cfo_init(&cfocorr, FLEN)) {
fprintf(stderr, "Error initiating CFO\n"); fprintf(stderr, "Error initiating CFO\n");
return -1; return -1;
} }
idx_v = malloc(nof_frames_track * sizeof(int)); idx_v = malloc(nof_frames_track * sizeof(int));
if (!idx_v) { if (!idx_v) {
perror("malloc"); perror("malloc");
return -1; return -1;
} }
idx_valid = malloc(nof_frames_track * sizeof(int)); idx_valid = malloc(nof_frames_track * sizeof(int));
if (!idx_valid) { if (!idx_valid) {
perror("malloc"); perror("malloc");
return -1; return -1;
} }
t = malloc(nof_frames_track * sizeof(int)); t = malloc(nof_frames_track * sizeof(int));
if (!t) { if (!t) {
perror("malloc"); perror("malloc");
return -1; return -1;
} }
cfo_v = malloc(nof_frames_track * sizeof(float)); cfo_v = malloc(nof_frames_track * sizeof(float));
if (!cfo_v) { if (!cfo_v) {
perror("malloc"); perror("malloc");
return -1; return -1;
} }
p2a_v = malloc(nof_frames_track * sizeof(float)); p2a_v = malloc(nof_frames_track * sizeof(float));
if (!p2a_v) { if (!p2a_v) {
perror("malloc"); perror("malloc");
return -1; return -1;
} }
bzero(cfo, sizeof(float) * MAX_EARFCN); bzero(cfo, sizeof(float) * MAX_EARFCN);
bzero(p2a, sizeof(float) * MAX_EARFCN); bzero(p2a, sizeof(float) * MAX_EARFCN);
/* open UHD device */ /* open UHD device */
#ifndef DISABLE_UHD #ifndef DISABLE_UHD
printf("Opening UHD device...\n"); printf("Opening UHD device...\n");
if (cuhd_open("",&uhd)) { if (cuhd_open("",&uhd)) {
fprintf(stderr, "Error opening uhd\n"); fprintf(stderr, "Error opening uhd\n");
return -1; return -1;
} }
#endif #endif
return 0; return 0;
} }
void base_free() { void base_free() {
int i; int i;
#ifndef DISABLE_UHD #ifndef DISABLE_UHD
cuhd_close(uhd); cuhd_close(uhd);
#endif #endif
sync_free(&sfind); sync_free(&sfind);
sync_free(&strack); sync_free(&strack);
lte_fft_free(&fft); lte_fft_free(&fft);
chest_free(&chest); chest_free(&chest);
cfo_free(&cfocorr); cfo_free(&cfocorr);
free(input_buffer); free(input_buffer);
free(fft_buffer); free(fft_buffer);
for (i=0;i<MAX_PORTS;i++) { for (i=0;i<MAX_PORTS;i++) {
free(ce[i]); free(ce[i]);
} }
free(idx_v); free(idx_v);
free(idx_valid); free(idx_valid);
free(t); free(t);
free(cfo_v); free(cfo_v);
free(p2a_v); free(p2a_v);
} }
float mean_valid(int *idx_v, float *x, int nof_frames) { float mean_valid(int *idx_v, float *x, int nof_frames) {
int i; int i;
float mean = 0; float mean = 0;
int n = 0; int n = 0;
for (i=0;i<nof_frames;i++) { for (i=0;i<nof_frames;i++) {
if (idx_v[i] != -1) { if (idx_v[i] != -1) {
mean += x[i]; mean += x[i];
n++; n++;
} }
} }
if (n > 0) { if (n > 0) {
return mean/n; return mean/n;
} else { } else {
return 0.0; return 0.0;
} }
} }
int preprocess_idx(int *in, int *out, int *period, int len) { int preprocess_idx(int *in, int *out, int *period, int len) {
int i, n; int i, n;
n=0; n=0;
for (i=0;i<len;i++) { for (i=0;i<len;i++) {
if (in[i] != -1) { if (in[i] != -1) {
out[n] = in[i]; out[n] = in[i];
period[n] = i; period[n] = i;
n++; n++;
} }
} }
return n; return n;
} }
int rssi_scan() { int rssi_scan() {
int n=0; int n=0;
int i; int i;
if (nof_bands > 100) { if (nof_bands > 100) {
/* scan every Mhz, that is 10 freqs */ /* scan every Mhz, that is 10 freqs */
for (i=0;i<nof_bands;i+=RSSI_DECIM) { for (i=0;i<nof_bands;i+=RSSI_DECIM) {
freqs[n] = channels[i].fd * MHZ; freqs[n] = channels[i].fd * MHZ;
n++; n++;
} }
#ifndef DISABLE_UHD #ifndef DISABLE_UHD
if (cuhd_rssi_scan(uhd, freqs, rssi_d, n, (double) RSSI_FS, nof_samples_rssi)) { if (cuhd_rssi_scan(uhd, freqs, rssi_d, n, (double) RSSI_FS, nof_samples_rssi)) {
fprintf(stderr, "Error while doing RSSI scan\n"); fprintf(stderr, "Error while doing RSSI scan\n");
return -1; return -1;
} }
#endif #endif
/* linearly interpolate the rssi vector */ /* linearly interpolate the rssi vector */
interp_linear_f(rssi_d, rssi, RSSI_DECIM, n); interp_linear_f(rssi_d, rssi, RSSI_DECIM, n);
} else { } else {
for (i=0;i<nof_bands;i++) { for (i=0;i<nof_bands;i++) {
freqs[i] = channels[i].fd * MHZ; freqs[i] = channels[i].fd * MHZ;
} }
#ifndef DISABLE_UHD #ifndef DISABLE_UHD
if (cuhd_rssi_scan(uhd, freqs, rssi, nof_bands, (double) RSSI_FS, nof_samples_rssi)) { if (cuhd_rssi_scan(uhd, freqs, rssi, nof_bands, (double) RSSI_FS, nof_samples_rssi)) {
fprintf(stderr, "Error while doing RSSI scan\n"); fprintf(stderr, "Error while doing RSSI scan\n");
return -1; return -1;
} }
#endif #endif
n = nof_bands; n = nof_bands;
} }
return n; return n;
} }
int mib_decoder_init(int cell_id) { int mib_decoder_init(int cell_id) {
if (chest_ref_LTEDL(&chest, cell_id)) { if (chest_ref_LTEDL(&chest, cell_id)) {
fprintf(stderr, "Error initializing reference signal\n"); fprintf(stderr, "Error initializing reference signal\n");
return -1; return -1;
} }
if (pbch_init(&pbch, 6, cell_id, CPNORM)) { if (pbch_init(&pbch, 6, cell_id, CPNORM)) {
fprintf(stderr, "Error initiating PBCH\n"); fprintf(stderr, "Error initiating PBCH\n");
return -1; return -1;
} }
DEBUG("PBCH initiated cell_id=%d\n", cell_id); DEBUG("PBCH initiated cell_id=%d\n", cell_id);
return 0; return 0;
} }
int mib_decoder_run(cf_t *input, pbch_mib_t *mib) { int mib_decoder_run(cf_t *input, pbch_mib_t *mib) {
int i; int i;
lte_fft_run(&fft, input, fft_buffer); lte_fft_run(&fft, input, fft_buffer);
/* Get channel estimates for each port */ /* Get channel estimates for each port */
for (i=0;i<MAX_PORTS;i++) { for (i=0;i<MAX_PORTS;i++) {
chest_ce_slot_port(&chest, fft_buffer, ce[i], 1, i); chest_ce_slot_port(&chest, fft_buffer, ce[i], 1, i);
} }
DEBUG("Decoding PBCH\n", 0); DEBUG("Decoding PBCH\n", 0);
return pbch_decode(&pbch, fft_buffer, ce, 1, mib); return pbch_decode(&pbch, fft_buffer, ce, 1, mib);
} }
int main(int argc, char **argv) { int main(int argc, char **argv) {
int frame_cnt, valid_frames; int frame_cnt, valid_frames;
int freq; int freq;
int cell_id; int cell_id;
float max_peak_to_avg; float max_peak_to_avg;
float sfo; float sfo;
int find_idx, track_idx, last_found; int find_idx, track_idx, last_found;
enum sync_state state; enum sync_state state;
int n; int n;
int mib_attempts; int mib_attempts;
int nslot; int nslot;
pbch_mib_t mib; pbch_mib_t mib;
if (argc < 3) { if (argc < 3) {
usage(argv[0]); usage(argv[0]);
exit(-1); exit(-1);
} }
parse_args(argc,argv); parse_args(argc,argv);
if (base_init(FLEN)) { if (base_init(FLEN)) {
fprintf(stderr, "Error initializing memory\n"); fprintf(stderr, "Error initializing memory\n");
exit(-1); exit(-1);
} }
sync_pss_det_peak_to_avg(&sfind); sync_pss_det_peak_to_avg(&sfind);
sync_pss_det_peak_to_avg(&strack); sync_pss_det_peak_to_avg(&strack);
nof_bands = lte_band_get_fd_band(band, channels, earfcn_start, earfcn_end, MAX_EARFCN); nof_bands = lte_band_get_fd_band(band, channels, earfcn_start, earfcn_end, MAX_EARFCN);
printf("RSSI scan: %d freqs in band %d, RSSI threshold %.2f dBm\n", nof_bands, band, rssi_threshold); printf("RSSI scan: %d freqs in band %d, RSSI threshold %.2f dBm\n", nof_bands, band, rssi_threshold);
n = rssi_scan(); n = rssi_scan();
if (n == -1) { if (n == -1) {
exit(-1); exit(-1);
} }
printf("\nDone. Starting PSS search on %d channels\n", n); printf("\nDone. Starting PSS search on %d channels\n", n);
usleep(500000); usleep(500000);
INFO("Setting sampling frequency %.2f MHz\n", (float) SAMP_FREQ/MHZ); INFO("Setting sampling frequency %.2f MHz\n", (float) SAMP_FREQ/MHZ);
#ifndef DISABLE_UHD #ifndef DISABLE_UHD
cuhd_set_rx_srate(uhd, SAMP_FREQ); cuhd_set_rx_srate(uhd, SAMP_FREQ);
cuhd_set_rx_gain(uhd, uhd_gain); cuhd_set_rx_gain(uhd, uhd_gain);
#endif #endif
freq=0; freq=0;
state = INIT; state = INIT;
nslot = 0; nslot = 0;
sfo = 0; sfo = 0;
find_idx = 0; find_idx = 0;
frame_cnt = 0; frame_cnt = 0;
max_peak_to_avg = -1; max_peak_to_avg = -1;
last_found = 0; last_found = 0;
cell_id = 0; cell_id = 0;
while(freq<nof_bands) { while(freq<nof_bands) {
/* scan only bands above rssi_threshold */ /* scan only bands above rssi_threshold */
if (!IS_SIGNAL(freq)) { if (!IS_SIGNAL(freq)) {
INFO("[%3d/%d]: Skipping EARFCN %d %.2f MHz RSSI %.2f dB\n", freq, nof_bands, INFO("[%3d/%d]: Skipping EARFCN %d %.2f MHz RSSI %.2f dB\n", freq, nof_bands,
channels[freq].id, channels[freq].fd,10*log10f(rssi[freq]) + 30); channels[freq].id, channels[freq].fd,10*log10f(rssi[freq]) + 30);
freq++; freq++;
} else { } else {
if (state != INIT && state != DONE) { if (state != INIT && state != DONE) {
#ifndef DISABLE_UHD #ifndef DISABLE_UHD
DEBUG(" ----- RECEIVING %d SAMPLES ---- \n", FLEN); DEBUG(" ----- RECEIVING %d SAMPLES ---- \n", FLEN);
cuhd_recv(uhd, &input_buffer[FLEN], FLEN, 1); cuhd_recv(uhd, &input_buffer[FLEN], FLEN, 1);
#endif #endif
} }
switch(state) { switch(state) {
case INIT: case INIT:
DEBUG("Stopping receiver...\n",0); DEBUG("Stopping receiver...\n",0);
#ifndef DISABLE_UHD #ifndef DISABLE_UHD
cuhd_stop_rx_stream(uhd); cuhd_stop_rx_stream(uhd);
/* set freq */ /* set freq */
cuhd_set_rx_freq(uhd, (double) channels[freq].fd * MHZ); cuhd_set_rx_freq(uhd, (double) channels[freq].fd * MHZ);
cuhd_rx_wait_lo_locked(uhd); cuhd_rx_wait_lo_locked(uhd);
DEBUG("Set freq to %.3f MHz\n", (double) channels[freq].fd); DEBUG("Set freq to %.3f MHz\n", (double) channels[freq].fd);
DEBUG("Starting receiver...\n",0); DEBUG("Starting receiver...\n",0);
cuhd_start_rx_stream(uhd); cuhd_start_rx_stream(uhd);
#endif #endif
/* init variables */ /* init variables */
frame_cnt = 0; frame_cnt = 0;
max_peak_to_avg = -1; max_peak_to_avg = -1;
cell_id = -1; cell_id = -1;
/* receive first frame */ /* receive first frame */
#ifndef DISABLE_UHD #ifndef DISABLE_UHD
cuhd_recv(uhd, input_buffer, FLEN, 1); cuhd_recv(uhd, input_buffer, FLEN, 1);
#endif #endif
/* set find_threshold and go to FIND state */ /* set find_threshold and go to FIND state */
sync_set_threshold(&sfind, find_threshold); sync_set_threshold(&sfind, find_threshold);
sync_force_N_id_2(&sfind, -1); sync_force_N_id_2(&sfind, -1);
state = FIND; state = FIND;
break; break;
case FIND: case FIND:
/* find peak in all frame */ /* find peak in all frame */
find_idx = sync_run(&sfind, &input_buffer[FLEN]); find_idx = sync_run(&sfind, &input_buffer[FLEN]);
DEBUG("[%3d/%d]: PAR=%.2f\n", freq, nof_bands, sync_get_peak_to_avg(&sfind)); DEBUG("[%3d/%d]: PAR=%.2f\n", freq, nof_bands, sync_get_peak_to_avg(&sfind));
if (find_idx != -1) { if (find_idx != -1) {
/* if found peak, go to track and set lower threshold */ /* if found peak, go to track and set lower threshold */
frame_cnt = -1; frame_cnt = -1;
last_found = 0; last_found = 0;
max_peak_to_avg = -1; max_peak_to_avg = -1;
sync_set_threshold(&strack, track_threshold); sync_set_threshold(&strack, track_threshold);
sync_force_N_id_2(&strack, sync_get_N_id_2(&sfind)); sync_force_N_id_2(&strack, sync_get_N_id_2(&sfind));
cell_id = sync_get_cell_id(&sfind); cell_id = sync_get_cell_id(&sfind);
state = TRACK; state = TRACK;
INFO("[%3d/%d]: EARFCN %d Freq. %.2f MHz PSS found PAR %.2f dB\n", freq, nof_bands, INFO("[%3d/%d]: EARFCN %d Freq. %.2f MHz PSS found PAR %.2f dB\n", freq, nof_bands,
channels[freq].id, channels[freq].fd, channels[freq].id, channels[freq].fd,
10*log10f(sync_get_peak_to_avg(&sfind))); 10*log10f(sync_get_peak_to_avg(&sfind)));
} else { } else {
if (frame_cnt >= nof_frames_find) { if (frame_cnt >= nof_frames_find) {
state = INIT; state = INIT;
freq++; freq++;
} }
} }
break; break;
case TRACK: case TRACK:
INFO("Tracking PSS find_idx %d offset %d\n", find_idx, find_idx - track_len); INFO("Tracking PSS find_idx %d offset %d\n", find_idx, find_idx - track_len);
track_idx = sync_run(&strack, &input_buffer[FLEN + find_idx - track_len]); track_idx = sync_run(&strack, &input_buffer[FLEN + find_idx - track_len]);
p2a_v[frame_cnt] = sync_get_peak_to_avg(&strack); p2a_v[frame_cnt] = sync_get_peak_to_avg(&strack);
/* save cell id for the best peak-to-avg */ /* save cell id for the best peak-to-avg */
if (p2a_v[frame_cnt] > max_peak_to_avg) { if (p2a_v[frame_cnt] > max_peak_to_avg) {
max_peak_to_avg = p2a_v[frame_cnt]; max_peak_to_avg = p2a_v[frame_cnt];
cell_id = sync_get_cell_id(&strack); cell_id = sync_get_cell_id(&strack);
} }
if (track_idx != -1) { if (track_idx != -1) {
cfo_v[frame_cnt] = sync_get_cfo(&strack); cfo_v[frame_cnt] = sync_get_cfo(&strack);
last_found = frame_cnt; last_found = frame_cnt;
find_idx += track_idx - track_len; find_idx += track_idx - track_len;
idx_v[frame_cnt] = find_idx; idx_v[frame_cnt] = find_idx;
nslot = sync_get_slot_id(&strack); nslot = sync_get_slot_id(&strack);
} else { } else {
idx_v[frame_cnt] = -1; idx_v[frame_cnt] = -1;
cfo_v[frame_cnt] = 0.0; cfo_v[frame_cnt] = 0.0;
} }
/* if we missed to many PSS it is not a cell, next freq */ /* if we missed to many PSS it is not a cell, next freq */
if (frame_cnt - last_found > max_track_lost) { if (frame_cnt - last_found > max_track_lost) {
INFO("\n[%3d/%d]: EARFCN %d Freq. %.2f MHz %d frames lost\n", freq, nof_bands, INFO("\n[%3d/%d]: EARFCN %d Freq. %.2f MHz %d frames lost\n", freq, nof_bands,
channels[freq].id, channels[freq].fd, frame_cnt - last_found); channels[freq].id, channels[freq].fd, frame_cnt - last_found);
state = INIT; state = INIT;
freq++; freq++;
} else if (frame_cnt >= nof_frames_track) { } else if (frame_cnt >= nof_frames_track) {
mib_decoder_init(cell_id); mib_decoder_init(cell_id);
cfo[freq] = mean_valid(idx_v, cfo_v, frame_cnt); cfo[freq] = mean_valid(idx_v, cfo_v, frame_cnt);
p2a[freq] = mean_valid(idx_v, p2a_v, frame_cnt); p2a[freq] = mean_valid(idx_v, p2a_v, frame_cnt);
valid_frames = preprocess_idx(idx_v, idx_valid, t, frame_cnt); valid_frames = preprocess_idx(idx_v, idx_valid, t, frame_cnt);
sfo = sfo_estimate_period(idx_valid, t, valid_frames, FLEN_PERIOD); sfo = sfo_estimate_period(idx_valid, t, valid_frames, FLEN_PERIOD);
state = MIB; state = MIB;
nslot=(nslot+10)%20; nslot=(nslot+10)%20;
} }
break; break;
case MIB: case MIB:
INFO("Finding MIB at freq %.2f Mhz offset=%d, cell_id=%d, slot_idx=%d\n", channels[freq].fd, find_idx, cell_id, nslot); INFO("Finding MIB at freq %.2f Mhz offset=%d, cell_id=%d, slot_idx=%d\n", channels[freq].fd, find_idx, cell_id, nslot);
// TODO: Correct SFO // TODO: Correct SFO
// Correct CFO // Correct CFO
INFO("Correcting CFO=%.4f\n", cfo[freq]); INFO("Correcting CFO=%.4f\n", cfo[freq]);
cfo_correct(&cfocorr, &input_buffer[FLEN], (-cfo[freq])/128); cfo_correct(&cfocorr, &input_buffer[FLEN], (-cfo[freq])/128);
if (nslot == 0) { if (nslot == 0) {
if (mib_decoder_run(&input_buffer[FLEN+find_idx], &mib)) { if (mib_decoder_run(&input_buffer[FLEN+find_idx], &mib)) {
INFO("MIB detected attempt=%d\n", mib_attempts); INFO("MIB detected attempt=%d\n", mib_attempts);
state = DONE; state = DONE;
} else { } else {
INFO("MIB not detected attempt=%d\n", mib_attempts); INFO("MIB not detected attempt=%d\n", mib_attempts);
if (mib_attempts == 0) { if (mib_attempts == 0) {
freq++; freq++;
state = INIT; state = INIT;
} }
} }
mib_attempts++; mib_attempts++;
} }
nslot = (nslot+10)%20; nslot = (nslot+10)%20;
break; break;
case DONE: case DONE:
printf("\n[%3d/%d]: FOUND EARFCN %d Freq. %.2f MHz. " printf("\n[%3d/%d]: FOUND EARFCN %d Freq. %.2f MHz. "
"PAR %2.2f dB, CFO=%+.2f KHz, SFO=%+2.3f KHz, CELL_ID=%3d\n", freq, nof_bands, "PAR %2.2f dB, CFO=%+.2f KHz, SFO=%+2.3f KHz, CELL_ID=%3d\n", freq, nof_bands,
channels[freq].id, channels[freq].fd, channels[freq].id, channels[freq].fd,
10*log10f(p2a[freq]), cfo[freq] * 15, sfo / 1000, cell_id); 10*log10f(p2a[freq]), cfo[freq] * 15, sfo / 1000, cell_id);
pbch_mib_fprint(stdout, &mib); pbch_mib_fprint(stdout, &mib);
state = INIT; state = INIT;
freq++; freq++;
break; break;
} }
/** FIXME: This is not necessary at all */ /** FIXME: This is not necessary at all */
if (state == TRACK || state == FIND) { if (state == TRACK || state == FIND) {
memcpy(input_buffer, &input_buffer[FLEN], FLEN * sizeof(cf_t)); memcpy(input_buffer, &input_buffer[FLEN], FLEN * sizeof(cf_t));
} }
frame_cnt++; frame_cnt++;
} }
} }
base_free(); base_free();
printf("\n\nDone\n"); printf("\n\nDone\n");
exit(0); exit(0);
} }

@ -37,13 +37,13 @@
#include "lte.h" #include "lte.h"
#include "cuhd.h" #include "cuhd.h"
#define MHZ 1000000 #define MHZ 1000000
#define SAMP_FREQ 1920000 #define SAMP_FREQ 1920000
#define RSSI_FS 1000000 #define RSSI_FS 1000000
#define FLEN 9600 #define FLEN 9600
#define FLEN_PERIOD 0.005 #define FLEN_PERIOD 0.005
#define RSSI_DECIM 20 #define RSSI_DECIM 20
#define IS_SIGNAL(i) (10*log10f(rssi[i]) + 30 > rssi_threshold) #define IS_SIGNAL(i) (10*log10f(rssi[i]) + 30 > rssi_threshold)
@ -77,433 +77,433 @@ enum sync_state {INIT, FIND, TRACK, DONE};
void print_to_matlab(); void print_to_matlab();
void usage(char *prog) { void usage(char *prog) {
printf("Usage: %s [seRrFfTtgv] -b band\n", prog); printf("Usage: %s [seRrFfTtgv] -b band\n", prog);
printf("\t-s earfcn_start [Default All]\n"); printf("\t-s earfcn_start [Default All]\n");
printf("\t-e earfcn_end [Default All]\n"); printf("\t-e earfcn_end [Default All]\n");
printf("\t-R rssi_nof_samples [Default %d]\n", nof_samples_rssi); printf("\t-R rssi_nof_samples [Default %d]\n", nof_samples_rssi);
printf("\t-r rssi_threshold [Default %.2f dBm]\n", rssi_threshold); printf("\t-r rssi_threshold [Default %.2f dBm]\n", rssi_threshold);
printf("\t-F pss_find_nof_frames [Default %d]\n", nof_frames_find); printf("\t-F pss_find_nof_frames [Default %d]\n", nof_frames_find);
printf("\t-f pss_find_threshold [Default %.2f]\n", find_threshold); printf("\t-f pss_find_threshold [Default %.2f]\n", find_threshold);
printf("\t-T pss_track_nof_frames [Default %d]\n", nof_frames_track); printf("\t-T pss_track_nof_frames [Default %d]\n", nof_frames_track);
printf("\t-t pss_track_threshold [Default %.2f]\n", track_threshold); printf("\t-t pss_track_threshold [Default %.2f]\n", track_threshold);
printf("\t-l pss_track_len [Default %d]\n", track_len); printf("\t-l pss_track_len [Default %d]\n", track_len);
printf("\t-g gain [Default %.2f dB]\n", uhd_gain); printf("\t-g gain [Default %.2f dB]\n", uhd_gain);
printf("\t-v [set verbose to debug, default none]\n"); printf("\t-v [set verbose to debug, default none]\n");
} }
void parse_args(int argc, char **argv) { void parse_args(int argc, char **argv) {
int opt; int opt;
while ((opt = getopt(argc, argv, "bseRrFfTtgv")) != -1) { while ((opt = getopt(argc, argv, "bseRrFfTtgv")) != -1) {
switch(opt) { switch(opt) {
case 'b': case 'b':
band = atoi(argv[optind]); band = atoi(argv[optind]);
break; break;
case 's': case 's':
earfcn_start = atoi(argv[optind]); earfcn_start = atoi(argv[optind]);
break; break;
case 'e': case 'e':
earfcn_end = atoi(argv[optind]); earfcn_end = atoi(argv[optind]);
break; break;
case 'R': case 'R':
nof_samples_rssi = atoi(argv[optind]); nof_samples_rssi = atoi(argv[optind]);
break; break;
case 'r': case 'r':
rssi_threshold = -atof(argv[optind]); rssi_threshold = -atof(argv[optind]);
break; break;
case 'F': case 'F':
nof_frames_find = atoi(argv[optind]); nof_frames_find = atoi(argv[optind]);
break; break;
case 'f': case 'f':
find_threshold = atof(argv[optind]); find_threshold = atof(argv[optind]);
break; break;
case 'T': case 'T':
nof_frames_track = atoi(argv[optind]); nof_frames_track = atoi(argv[optind]);
break; break;
case 't': case 't':
track_threshold = atof(argv[optind]); track_threshold = atof(argv[optind]);
break; break;
case 'g': case 'g':
uhd_gain = atof(argv[optind]); uhd_gain = atof(argv[optind]);
break; break;
case 'v': case 'v':
verbose++; verbose++;
break; break;
default: default:
usage(argv[0]); usage(argv[0]);
exit(-1); exit(-1);
} }
} }
} }
int base_init(int frame_length) { int base_init(int frame_length) {
input_buffer = malloc(2 * frame_length * sizeof(cf_t)); input_buffer = malloc(2 * frame_length * sizeof(cf_t));
if (!input_buffer) { if (!input_buffer) {
perror("malloc"); perror("malloc");
exit(-1); exit(-1);
} }
idx_v = malloc(nof_frames_track * sizeof(int)); idx_v = malloc(nof_frames_track * sizeof(int));
if (!idx_v) { if (!idx_v) {
perror("malloc"); perror("malloc");
exit(-1); exit(-1);
} }
idx_valid = malloc(nof_frames_track * sizeof(int)); idx_valid = malloc(nof_frames_track * sizeof(int));
if (!idx_valid) { if (!idx_valid) {
perror("malloc"); perror("malloc");
exit(-1); exit(-1);
} }
t = malloc(nof_frames_track * sizeof(int)); t = malloc(nof_frames_track * sizeof(int));
if (!t) { if (!t) {
perror("malloc"); perror("malloc");
exit(-1); exit(-1);
} }
cfo_v = malloc(nof_frames_track * sizeof(float)); cfo_v = malloc(nof_frames_track * sizeof(float));
if (!cfo_v) { if (!cfo_v) {
perror("malloc"); perror("malloc");
exit(-1); exit(-1);
} }
p2a_v = malloc(nof_frames_track * sizeof(float)); p2a_v = malloc(nof_frames_track * sizeof(float));
if (!p2a_v) { if (!p2a_v) {
perror("malloc"); perror("malloc");
exit(-1); exit(-1);
} }
bzero(cfo, sizeof(float) * MAX_EARFCN); bzero(cfo, sizeof(float) * MAX_EARFCN);
bzero(p2a, sizeof(float) * MAX_EARFCN); bzero(p2a, sizeof(float) * MAX_EARFCN);
/* open UHD device */ /* open UHD device */
printf("Opening UHD device...\n"); printf("Opening UHD device...\n");
if (cuhd_open("",&uhd)) { if (cuhd_open("",&uhd)) {
fprintf(stderr, "Error opening uhd\n"); fprintf(stderr, "Error opening uhd\n");
exit(-1); exit(-1);
} }
return 0; return 0;
} }
void base_free() { void base_free() {
cuhd_close(uhd); cuhd_close(uhd);
free(input_buffer); free(input_buffer);
free(idx_v); free(idx_v);
free(idx_valid); free(idx_valid);
free(t); free(t);
free(cfo_v); free(cfo_v);
free(p2a_v); free(p2a_v);
} }
float mean_valid(int *idx_v, float *x, int nof_frames) { float mean_valid(int *idx_v, float *x, int nof_frames) {
int i; int i;
float mean = 0; float mean = 0;
int n = 0; int n = 0;
for (i=0;i<nof_frames;i++) { for (i=0;i<nof_frames;i++) {
if (idx_v[i] != -1) { if (idx_v[i] != -1) {
mean += x[i]; mean += x[i];
n++; n++;
} }
} }
if (n > 0) { if (n > 0) {
return mean/n; return mean/n;
} else { } else {
return 0.0; return 0.0;
} }
} }
int preprocess_idx(int *in, int *out, int *period, int len) { int preprocess_idx(int *in, int *out, int *period, int len) {
int i, n; int i, n;
n=0; n=0;
for (i=0;i<len;i++) { for (i=0;i<len;i++) {
if (in[i] != -1) { if (in[i] != -1) {
out[n] = in[i]; out[n] = in[i];
period[n] = i; period[n] = i;
n++; n++;
} }
} }
return n; return n;
} }
int rssi_scan() { int rssi_scan() {
int n=0; int n=0;
int i; int i;
if (nof_bands > 100) { if (nof_bands > 100) {
/* scan every Mhz, that is 10 freqs */ /* scan every Mhz, that is 10 freqs */
for (i=0;i<nof_bands;i+=RSSI_DECIM) { for (i=0;i<nof_bands;i+=RSSI_DECIM) {
freqs[n] = channels[i].fd * MHZ; freqs[n] = channels[i].fd * MHZ;
n++; n++;
} }
if (cuhd_rssi_scan(uhd, freqs, rssi_d, n, (double) RSSI_FS, nof_samples_rssi)) { if (cuhd_rssi_scan(uhd, freqs, rssi_d, n, (double) RSSI_FS, nof_samples_rssi)) {
fprintf(stderr, "Error while doing RSSI scan\n"); fprintf(stderr, "Error while doing RSSI scan\n");
return -1; return -1;
} }
/* linearly interpolate the rssi vector */ /* linearly interpolate the rssi vector */
interp_linear_f(rssi_d, rssi, RSSI_DECIM, n); interp_linear_f(rssi_d, rssi, RSSI_DECIM, n);
} else { } else {
for (i=0;i<nof_bands;i++) { for (i=0;i<nof_bands;i++) {
freqs[i] = channels[i].fd * MHZ; freqs[i] = channels[i].fd * MHZ;
} }
if (cuhd_rssi_scan(uhd, freqs, rssi, nof_bands, (double) RSSI_FS, nof_samples_rssi)) { if (cuhd_rssi_scan(uhd, freqs, rssi, nof_bands, (double) RSSI_FS, nof_samples_rssi)) {
fprintf(stderr, "Error while doing RSSI scan\n"); fprintf(stderr, "Error while doing RSSI scan\n");
return -1; return -1;
} }
n = nof_bands; n = nof_bands;
} }
return n; return n;
} }
int main(int argc, char **argv) { int main(int argc, char **argv) {
int frame_cnt, valid_frames; int frame_cnt, valid_frames;
int freq; int freq;
int cell_id; int cell_id;
sync_t sfind, strack; sync_t sfind, strack;
float max_peak_to_avg; float max_peak_to_avg;
float sfo; float sfo;
int find_idx, track_idx, last_found; int find_idx, track_idx, last_found;
enum sync_state state; enum sync_state state;
int n; int n;
filesink_t fs; filesink_t fs;
if (argc < 3) { if (argc < 3) {
usage(argv[0]); usage(argv[0]);
exit(-1); exit(-1);
} }
parse_args(argc,argv); parse_args(argc,argv);
if (base_init(FLEN)) { if (base_init(FLEN)) {
fprintf(stderr, "Error initializing memory\n"); fprintf(stderr, "Error initializing memory\n");
exit(-1); exit(-1);
} }
if (sync_init(&sfind, FLEN)) { if (sync_init(&sfind, FLEN)) {
fprintf(stderr, "Error initiating PSS/SSS\n"); fprintf(stderr, "Error initiating PSS/SSS\n");
exit(-1); exit(-1);
} }
sync_pss_det_peak_to_avg(&sfind); sync_pss_det_peak_to_avg(&sfind);
if (sync_init(&strack, track_len)) { if (sync_init(&strack, track_len)) {
fprintf(stderr, "Error initiating PSS/SSS\n"); fprintf(stderr, "Error initiating PSS/SSS\n");
exit(-1); exit(-1);
} }
sync_pss_det_peak_to_avg(&strack); sync_pss_det_peak_to_avg(&strack);
nof_bands = lte_band_get_fd_band(band, channels, earfcn_start, earfcn_end, MAX_EARFCN); nof_bands = lte_band_get_fd_band(band, channels, earfcn_start, earfcn_end, MAX_EARFCN);
printf("RSSI scan: %d freqs in band %d, RSSI threshold %.2f dBm\n", nof_bands, band, rssi_threshold); printf("RSSI scan: %d freqs in band %d, RSSI threshold %.2f dBm\n", nof_bands, band, rssi_threshold);
n = rssi_scan(); n = rssi_scan();
if (n == -1) { if (n == -1) {
exit(-1); exit(-1);
} }
printf("\nDone. Starting PSS search on %d channels\n", n); printf("\nDone. Starting PSS search on %d channels\n", n);
usleep(500000); usleep(500000);
INFO("Setting sampling frequency %.2f MHz\n", (float) SAMP_FREQ/MHZ); INFO("Setting sampling frequency %.2f MHz\n", (float) SAMP_FREQ/MHZ);
cuhd_set_rx_srate(uhd, SAMP_FREQ); cuhd_set_rx_srate(uhd, SAMP_FREQ);
cuhd_set_rx_gain(uhd, uhd_gain); cuhd_set_rx_gain(uhd, uhd_gain);
print_to_matlab(); print_to_matlab();
filesink_init(&fs, "test.dat", COMPLEX_FLOAT_BIN); filesink_init(&fs, "test.dat", COMPLEX_FLOAT_BIN);
freq=0; freq=0;
state = INIT; state = INIT;
find_idx = 0; find_idx = 0;
max_peak_to_avg = 0; max_peak_to_avg = 0;
last_found = 0; last_found = 0;
frame_cnt = 0; frame_cnt = 0;
while(freq<nof_bands) { while(freq<nof_bands) {
/* scan only bands above rssi_threshold */ /* scan only bands above rssi_threshold */
if (!IS_SIGNAL(freq)) { if (!IS_SIGNAL(freq)) {
INFO("[%3d/%d]: Skipping EARFCN %d %.2f MHz RSSI %.2f dB\n", freq, nof_bands, INFO("[%3d/%d]: Skipping EARFCN %d %.2f MHz RSSI %.2f dB\n", freq, nof_bands,
channels[freq].id, channels[freq].fd,10*log10f(rssi[freq]) + 30); channels[freq].id, channels[freq].fd,10*log10f(rssi[freq]) + 30);
freq++; freq++;
} else { } else {
if (state == TRACK || state == FIND) { if (state == TRACK || state == FIND) {
cuhd_recv(uhd, &input_buffer[FLEN], FLEN, 1); cuhd_recv(uhd, &input_buffer[FLEN], FLEN, 1);
} }
switch(state) { switch(state) {
case INIT: case INIT:
DEBUG("Stopping receiver...\n",0); DEBUG("Stopping receiver...\n",0);
cuhd_stop_rx_stream(uhd); cuhd_stop_rx_stream(uhd);
/* set freq */ /* set freq */
cuhd_set_rx_freq(uhd, (double) channels[freq].fd * MHZ); cuhd_set_rx_freq(uhd, (double) channels[freq].fd * MHZ);
cuhd_rx_wait_lo_locked(uhd); cuhd_rx_wait_lo_locked(uhd);
DEBUG("Set freq to %.3f MHz\n", (double) channels[freq].fd); DEBUG("Set freq to %.3f MHz\n", (double) channels[freq].fd);
DEBUG("Starting receiver...\n",0); DEBUG("Starting receiver...\n",0);
cuhd_start_rx_stream(uhd); cuhd_start_rx_stream(uhd);
/* init variables */ /* init variables */
frame_cnt = 0; frame_cnt = 0;
max_peak_to_avg = -99; max_peak_to_avg = -99;
cell_id = -1; cell_id = -1;
/* receive first frame */ /* receive first frame */
cuhd_recv(uhd, input_buffer, FLEN, 1); cuhd_recv(uhd, input_buffer, FLEN, 1);
/* set find_threshold and go to FIND state */ /* set find_threshold and go to FIND state */
sync_set_threshold(&sfind, find_threshold); sync_set_threshold(&sfind, find_threshold);
sync_force_N_id_2(&sfind, -1); sync_force_N_id_2(&sfind, -1);
state = FIND; state = FIND;
break; break;
case FIND: case FIND:
/* find peak in all frame */ /* find peak in all frame */
find_idx = sync_run(&sfind, &input_buffer[FLEN]); find_idx = sync_run(&sfind, &input_buffer[FLEN]);
DEBUG("[%3d/%d]: PAR=%.2f\n", freq, nof_bands, sync_get_peak_to_avg(&sfind)); DEBUG("[%3d/%d]: PAR=%.2f\n", freq, nof_bands, sync_get_peak_to_avg(&sfind));
if (find_idx != -1) { if (find_idx != -1) {
/* if found peak, go to track and set lower threshold */ /* if found peak, go to track and set lower threshold */
frame_cnt = -1; frame_cnt = -1;
last_found = 0; last_found = 0;
sync_set_threshold(&strack, track_threshold); sync_set_threshold(&strack, track_threshold);
sync_force_N_id_2(&strack, sync_get_N_id_2(&sfind)); sync_force_N_id_2(&strack, sync_get_N_id_2(&sfind));
state = TRACK; state = TRACK;
INFO("[%3d/%d]: EARFCN %d Freq. %.2f MHz PSS found PAR %.2f dB\n", freq, nof_bands, INFO("[%3d/%d]: EARFCN %d Freq. %.2f MHz PSS found PAR %.2f dB\n", freq, nof_bands,
channels[freq].id, channels[freq].fd, channels[freq].id, channels[freq].fd,
10*log10f(sync_get_peak_to_avg(&sfind))); 10*log10f(sync_get_peak_to_avg(&sfind)));
} else { } else {
if (frame_cnt >= nof_frames_find) { if (frame_cnt >= nof_frames_find) {
state = INIT; state = INIT;
printf("[%3d/%d]: EARFCN %d Freq. %.2f MHz No PSS found\r", freq, nof_bands, printf("[%3d/%d]: EARFCN %d Freq. %.2f MHz No PSS found\r", freq, nof_bands,
channels[freq].id, channels[freq].fd, frame_cnt - last_found); channels[freq].id, channels[freq].fd, frame_cnt - last_found);
if (VERBOSE_ISINFO()) { if (VERBOSE_ISINFO()) {
printf("\n"); printf("\n");
} }
freq++; freq++;
} }
} }
break; break;
case TRACK: case TRACK:
INFO("Tracking PSS find_idx %d offset %d\n", find_idx, find_idx + track_len); INFO("Tracking PSS find_idx %d offset %d\n", find_idx, find_idx + track_len);
filesink_write(&fs, &input_buffer[FLEN+find_idx+track_len], track_len); filesink_write(&fs, &input_buffer[FLEN+find_idx+track_len], track_len);
track_idx = sync_run(&strack, &input_buffer[FLEN + find_idx - track_len]); track_idx = sync_run(&strack, &input_buffer[FLEN + find_idx - track_len]);
p2a_v[frame_cnt] = sync_get_peak_to_avg(&strack); p2a_v[frame_cnt] = sync_get_peak_to_avg(&strack);
/* save cell id for the best peak-to-avg */ /* save cell id for the best peak-to-avg */
if (p2a_v[frame_cnt] > max_peak_to_avg) { if (p2a_v[frame_cnt] > max_peak_to_avg) {
max_peak_to_avg = p2a_v[frame_cnt]; max_peak_to_avg = p2a_v[frame_cnt];
cell_id = sync_get_cell_id(&strack); cell_id = sync_get_cell_id(&strack);
} }
if (track_idx != -1) { if (track_idx != -1) {
cfo_v[frame_cnt] = sync_get_cfo(&strack); cfo_v[frame_cnt] = sync_get_cfo(&strack);
last_found = frame_cnt; last_found = frame_cnt;
find_idx += track_idx - track_len; find_idx += track_idx - track_len;
idx_v[frame_cnt] = find_idx; idx_v[frame_cnt] = find_idx;
} else { } else {
idx_v[frame_cnt] = -1; idx_v[frame_cnt] = -1;
cfo_v[frame_cnt] = 0.0; cfo_v[frame_cnt] = 0.0;
} }
/* if we missed to many PSS it is not a cell, next freq */ /* if we missed to many PSS it is not a cell, next freq */
if (frame_cnt - last_found > max_track_lost) { if (frame_cnt - last_found > max_track_lost) {
INFO("\n[%3d/%d]: EARFCN %d Freq. %.2f MHz %d frames lost\n", freq, nof_bands, INFO("\n[%3d/%d]: EARFCN %d Freq. %.2f MHz %d frames lost\n", freq, nof_bands,
channels[freq].id, channels[freq].fd, frame_cnt - last_found); channels[freq].id, channels[freq].fd, frame_cnt - last_found);
state = INIT; state = INIT;
freq++; freq++;
} else if (frame_cnt >= nof_frames_track) { } else if (frame_cnt >= nof_frames_track) {
state = DONE; state = DONE;
} }
break; break;
case DONE: case DONE:
cfo[freq] = mean_valid(idx_v, cfo_v, frame_cnt); cfo[freq] = mean_valid(idx_v, cfo_v, frame_cnt);
p2a[freq] = mean_valid(idx_v, p2a_v, frame_cnt); p2a[freq] = mean_valid(idx_v, p2a_v, frame_cnt);
valid_frames = preprocess_idx(idx_v, idx_valid, t, frame_cnt); valid_frames = preprocess_idx(idx_v, idx_valid, t, frame_cnt);
sfo = sfo_estimate_period(idx_valid, t, valid_frames, FLEN_PERIOD); sfo = sfo_estimate_period(idx_valid, t, valid_frames, FLEN_PERIOD);
printf("\n[%3d/%d]: FOUND EARFCN %d Freq. %.2f MHz. " printf("\n[%3d/%d]: FOUND EARFCN %d Freq. %.2f MHz. "
"PAR %2.2f dB, CFO=%+.2f KHz, SFO=%+2.3f KHz, CELL_ID=%3d\n", freq, nof_bands, "PAR %2.2f dB, CFO=%+.2f KHz, SFO=%+2.3f KHz, CELL_ID=%3d\n", freq, nof_bands,
channels[freq].id, channels[freq].fd, channels[freq].id, channels[freq].fd,
10*log10f(p2a[freq]), cfo[freq] * 15, sfo / 1000, cell_id); 10*log10f(p2a[freq]), cfo[freq] * 15, sfo / 1000, cell_id);
state = INIT; state = INIT;
freq++; freq++;
break; break;
} }
if (state == TRACK || (state == FIND && frame_cnt)) { if (state == TRACK || (state == FIND && frame_cnt)) {
memcpy(input_buffer, &input_buffer[FLEN], FLEN * sizeof(cf_t)); memcpy(input_buffer, &input_buffer[FLEN], FLEN * sizeof(cf_t));
} }
frame_cnt++; frame_cnt++;
} }
} }
print_to_matlab(); print_to_matlab();
sync_free(&sfind); sync_free(&sfind);
base_free(); base_free();
printf("\n\nDone\n"); printf("\n\nDone\n");
exit(0); exit(0);
} }
void print_to_matlab() { void print_to_matlab() {
int i; int i;
FILE *f = fopen("output.m", "w"); FILE *f = fopen("output.m", "w");
if (!f) { if (!f) {
perror("fopen"); perror("fopen");
exit(-1); exit(-1);
} }
fprintf(f, "fd=["); fprintf(f, "fd=[");
for (i=0;i<nof_bands;i++) { for (i=0;i<nof_bands;i++) {
fprintf(f, "%g, ", channels[i].fd); fprintf(f, "%g, ", channels[i].fd);
} }
fprintf(f, "];\n"); fprintf(f, "];\n");
fprintf(f, "rssi=["); fprintf(f, "rssi=[");
for (i=0;i<nof_bands;i++) { for (i=0;i<nof_bands;i++) {
fprintf(f, "%g, ", rssi[i]); fprintf(f, "%g, ", rssi[i]);
} }
fprintf(f, "];\n"); fprintf(f, "];\n");
fprintf(f, "rssi_d=["); fprintf(f, "rssi_d=[");
for (i=0;i<nof_bands/RSSI_DECIM;i++) { for (i=0;i<nof_bands/RSSI_DECIM;i++) {
fprintf(f, "%g, ", rssi_d[i]); fprintf(f, "%g, ", rssi_d[i]);
} }
fprintf(f, "];\n"); fprintf(f, "];\n");
/* /*
fprintf(f, "cfo=["); fprintf(f, "cfo=[");
for (i=0;i<nof_bands;i++) { for (i=0;i<nof_bands;i++) {
if (IS_SIGNAL(i)) { if (IS_SIGNAL(i)) {
fprintf(f, "%g, ", cfo[i]); fprintf(f, "%g, ", cfo[i]);
} else { } else {
fprintf(f, "NaN, "); fprintf(f, "NaN, ");
} }
} }
fprintf(f, "];\n"); fprintf(f, "];\n");
*/ */
fprintf(f, "p2a=["); fprintf(f, "p2a=[");
for (i=0;i<nof_bands;i++) { for (i=0;i<nof_bands;i++) {
if (IS_SIGNAL(i)) { if (IS_SIGNAL(i)) {
fprintf(f, "%g, ", p2a[i]); fprintf(f, "%g, ", p2a[i]);
} else { } else {
fprintf(f, "0, "); fprintf(f, "0, ");
} }
} }
fprintf(f, "];\n"); fprintf(f, "];\n");
fprintf(f, "clf;\n\n"); fprintf(f, "clf;\n\n");
fprintf(f, "subplot(1,2,1)\n"); fprintf(f, "subplot(1,2,1)\n");
fprintf(f, "plot(fd, 10*log10(rssi)+30)\n"); fprintf(f, "plot(fd, 10*log10(rssi)+30)\n");
fprintf(f, "grid on; xlabel('f [Mhz]'); ylabel('RSSI [dBm]');\n"); fprintf(f, "grid on; xlabel('f [Mhz]'); ylabel('RSSI [dBm]');\n");
fprintf(f, "title('RSSI Estimation')\n"); fprintf(f, "title('RSSI Estimation')\n");
fprintf(f, "subplot(1,2,2)\n"); fprintf(f, "subplot(1,2,2)\n");
fprintf(f, "plot(fd, p2a)\n"); fprintf(f, "plot(fd, p2a)\n");
fprintf(f, "grid on; xlabel('f [Mhz]'); ylabel('Peak-to-Avg [dB]');\n"); fprintf(f, "grid on; xlabel('f [Mhz]'); ylabel('Peak-to-Avg [dB]');\n");
fprintf(f, "title('PSS Correlation')\n"); fprintf(f, "title('PSS Correlation')\n");
/* /*
fprintf(f, "subplot(1,3,3)\n"); fprintf(f, "subplot(1,3,3)\n");
fprintf(f, "plot(fd, cfo)\n"); fprintf(f, "plot(fd, cfo)\n");
fprintf(f, "grid on; xlabel('f [Mhz]'); ylabel(''); axis([min(fd) max(fd) -0.5 0.5]);\n"); fprintf(f, "grid on; xlabel('f [Mhz]'); ylabel(''); axis([min(fd) max(fd) -0.5 0.5]);\n");
fprintf(f, "title('CFO Estimation')\n"); fprintf(f, "title('CFO Estimation')\n");
*/ */
fprintf(f, "drawnow;\n"); fprintf(f, "drawnow;\n");
fclose(f); fclose(f);
} }

@ -49,119 +49,119 @@ lte_earfcn_t channels[MAX_EARFCN];
#define SAMP_FREQ 1920000 #define SAMP_FREQ 1920000
void usage(char *prog) { void usage(char *prog) {
printf("Usage: %s [nvse] -b band\n", prog); printf("Usage: %s [nvse] -b band\n", prog);
printf("\t-s earfcn_start [Default All]\n"); printf("\t-s earfcn_start [Default All]\n");
printf("\t-e earfcn_end [Default All]\n"); printf("\t-e earfcn_end [Default All]\n");
printf("\t-n number of frames [Default %d]\n", nof_frames); printf("\t-n number of frames [Default %d]\n", nof_frames);
printf("\t-v [set verbose to debug, default none]\n"); printf("\t-v [set verbose to debug, default none]\n");
} }
void parse_args(int argc, char **argv) { void parse_args(int argc, char **argv) {
int opt; int opt;
while ((opt = getopt(argc, argv, "sebnv")) != -1) { while ((opt = getopt(argc, argv, "sebnv")) != -1) {
switch(opt) { switch(opt) {
case 'b': case 'b':
band = atoi(argv[optind]); band = atoi(argv[optind]);
break; break;
case 's': case 's':
earfcn_start = atoi(argv[optind]); earfcn_start = atoi(argv[optind]);
break; break;
case 'e': case 'e':
earfcn_end = atoi(argv[optind]); earfcn_end = atoi(argv[optind]);
break; break;
case 'n': case 'n':
nof_frames = atoi(argv[optind]); nof_frames = atoi(argv[optind]);
break; break;
case 'v': case 'v':
verbose++; verbose++;
break; break;
default: default:
usage(argv[0]); usage(argv[0]);
exit(-1); exit(-1);
} }
} }
} }
int base_init() { int base_init() {
input_buffer = malloc(4 * 960 * sizeof(cf_t)); input_buffer = malloc(4 * 960 * sizeof(cf_t));
if (!input_buffer) { if (!input_buffer) {
perror("malloc"); perror("malloc");
exit(-1); exit(-1);
} }
/* open UHD device */ /* open UHD device */
printf("Opening UHD device...\n"); printf("Opening UHD device...\n");
if (cuhd_open("",&uhd)) { if (cuhd_open("",&uhd)) {
fprintf(stderr, "Error opening uhd\n"); fprintf(stderr, "Error opening uhd\n");
exit(-1); exit(-1);
} }
printf("Setting sampling frequency %.2f MHz\n", (float) SAMP_FREQ/MHZ); printf("Setting sampling frequency %.2f MHz\n", (float) SAMP_FREQ/MHZ);
cuhd_set_rx_srate(uhd, SAMP_FREQ); cuhd_set_rx_srate(uhd, SAMP_FREQ);
printf("Starting receiver...\n"); printf("Starting receiver...\n");
cuhd_start_rx_stream(uhd); cuhd_start_rx_stream(uhd);
return 0; return 0;
} }
int main(int argc, char **argv) { int main(int argc, char **argv) {
int frame_cnt; int frame_cnt;
int i; int i;
int nsamples; int nsamples;
float rssi[MAX_EARFCN]; float rssi[MAX_EARFCN];
if (argc < 3) { if (argc < 3) {
usage(argv[0]); usage(argv[0]);
exit(-1); exit(-1);
} }
parse_args(argc,argv); parse_args(argc,argv);
if (base_init()) { if (base_init()) {
fprintf(stderr, "Error initializing memory\n"); fprintf(stderr, "Error initializing memory\n");
exit(-1); exit(-1);
} }
int nof_bands = lte_band_get_fd_band(band, channels, earfcn_start, earfcn_end, MAX_EARFCN); int nof_bands = lte_band_get_fd_band(band, channels, earfcn_start, earfcn_end, MAX_EARFCN);
printf("Scanning %d freqs in band %d\n", nof_bands, band); printf("Scanning %d freqs in band %d\n", nof_bands, band);
for (i=0;i<nof_bands;i++) { for (i=0;i<nof_bands;i++) {
cuhd_set_rx_freq(uhd, (double) channels[i].fd * MHZ); cuhd_set_rx_freq(uhd, (double) channels[i].fd * MHZ);
frame_cnt = 0; frame_cnt = 0;
nsamples=0; nsamples=0;
rssi[i]=0; rssi[i]=0;
while(frame_cnt < nof_frames) { while(frame_cnt < nof_frames) {
nsamples += cuhd_recv(uhd, input_buffer, 1920, 1); nsamples += cuhd_recv(uhd, input_buffer, 1920, 1);
rssi[i] += vec_avg_power_cf(input_buffer, 1920); rssi[i] += vec_avg_power_cf(input_buffer, 1920);
frame_cnt++; frame_cnt++;
} }
printf("[%3d/%d]: Scanning earfcn %d freq %.2f MHz RSSI %.2f dBm\n", i, nof_bands, printf("[%3d/%d]: Scanning earfcn %d freq %.2f MHz RSSI %.2f dBm\n", i, nof_bands,
channels[i].id, channels[i].fd, 10*log10f(rssi[i]) + 30); channels[i].id, channels[i].fd, 10*log10f(rssi[i]) + 30);
} }
FILE *f = fopen("output.m", "w"); FILE *f = fopen("output.m", "w");
if (!f) { if (!f) {
perror("fopen"); perror("fopen");
exit(-1); exit(-1);
} }
fprintf(f, "fd=["); fprintf(f, "fd=[");
for (i=0;i<nof_bands;i++) { for (i=0;i<nof_bands;i++) {
fprintf(f, "%g, ", channels[i].fd); fprintf(f, "%g, ", channels[i].fd);
} }
fprintf(f, "];\n"); fprintf(f, "];\n");
fprintf(f, "rssi=["); fprintf(f, "rssi=[");
for (i=0;i<nof_bands;i++) { for (i=0;i<nof_bands;i++) {
fprintf(f, "%g, ", rssi[i]); fprintf(f, "%g, ", rssi[i]);
} }
fprintf(f, "];\n"); fprintf(f, "];\n");
fprintf(f, "plot(fd/1000, 10*log10(rssi)+30)\ngrid on\nxlabel('f_d [Ghz]')\nylabel('RSSI [dBm]')\n"); fprintf(f, "plot(fd/1000, 10*log10(rssi)+30)\ngrid on\nxlabel('f_d [Ghz]')\nylabel('RSSI [dBm]')\n");
fclose(f); fclose(f);
free(input_buffer); free(input_buffer);
printf("Done\n"); printf("Done\n");
exit(0); exit(0);
} }

@ -39,233 +39,233 @@ int nof_frames=100, frame_length=9600, symbol_sz=128;
float corr_peak_threshold=25.0; float corr_peak_threshold=25.0;
int out_N_id_2 = 0, force_N_id_2=-1; int out_N_id_2 = 0, force_N_id_2=-1;
#define CFO_AUTO -9999.0 #define CFO_AUTO -9999.0
float force_cfo = CFO_AUTO; float force_cfo = CFO_AUTO;
void usage(char *prog) { void usage(char *prog) {
printf("Usage: %s [olntsNfcv] -i input_file\n", prog); printf("Usage: %s [olntsNfcv] -i input_file\n", prog);
printf("\t-o output_file [Default %s]\n", output_file_name); printf("\t-o output_file [Default %s]\n", output_file_name);
printf("\t-l frame_length [Default %d]\n", frame_length); printf("\t-l frame_length [Default %d]\n", frame_length);
printf("\t-n number of frames [Default %d]\n", nof_frames); printf("\t-n number of frames [Default %d]\n", nof_frames);
printf("\t-t correlation threshold [Default %g]\n", corr_peak_threshold); printf("\t-t correlation threshold [Default %g]\n", corr_peak_threshold);
printf("\t-s symbol_sz [Default %d]\n", symbol_sz); printf("\t-s symbol_sz [Default %d]\n", symbol_sz);
printf("\t-N out_N_id_2 [Default %d]\n", out_N_id_2); printf("\t-N out_N_id_2 [Default %d]\n", out_N_id_2);
printf("\t-f force_N_id_2 [Default %d]\n", force_N_id_2); printf("\t-f force_N_id_2 [Default %d]\n", force_N_id_2);
printf("\t-c force_cfo [Default disabled]\n"); printf("\t-c force_cfo [Default disabled]\n");
printf("\t-v verbose\n"); printf("\t-v verbose\n");
} }
void parse_args(int argc, char **argv) { void parse_args(int argc, char **argv) {
int opt; int opt;
while ((opt = getopt(argc, argv, "ionltsNfcv")) != -1) { while ((opt = getopt(argc, argv, "ionltsNfcv")) != -1) {
switch(opt) { switch(opt) {
case 'i': case 'i':
input_file_name = argv[optind]; input_file_name = argv[optind];
break; break;
case 'o': case 'o':
output_file_name = argv[optind]; output_file_name = argv[optind];
break; break;
case 'n': case 'n':
nof_frames = atoi(argv[optind]); nof_frames = atoi(argv[optind]);
break; break;
case 'l': case 'l':
frame_length = atoi(argv[optind]); frame_length = atoi(argv[optind]);
break; break;
case 't': case 't':
corr_peak_threshold = atof(argv[optind]); corr_peak_threshold = atof(argv[optind]);
break; break;
case 's': case 's':
symbol_sz = atof(argv[optind]); symbol_sz = atof(argv[optind]);
break; break;
case 'N': case 'N':
out_N_id_2 = atoi(argv[optind]); out_N_id_2 = atoi(argv[optind]);
break; break;
case 'f': case 'f':
force_N_id_2 = atoi(argv[optind]); force_N_id_2 = atoi(argv[optind]);
break; break;
case 'c': case 'c':
force_cfo = atof(argv[optind]); force_cfo = atof(argv[optind]);
break; break;
case 'v': case 'v':
verbose++; verbose++;
break; break;
default: default:
usage(argv[0]); usage(argv[0]);
exit(-1); exit(-1);
} }
} }
if (!input_file_name) { if (!input_file_name) {
usage(argv[0]); usage(argv[0]);
exit(-1); exit(-1);
} }
} }
int main(int argc, char **argv) { int main(int argc, char **argv) {
filesource_t fsrc; filesource_t fsrc;
filesink_t fsink; filesink_t fsink;
pss_synch_t pss[3]; // One for each N_id_2 pss_synch_t pss[3]; // One for each N_id_2
sss_synch_t sss[3]; // One for each N_id_2 sss_synch_t sss[3]; // One for each N_id_2
cfo_t cfocorr; cfo_t cfocorr;
int peak_pos[3]; int peak_pos[3];
float *cfo; float *cfo;
float peak_value[3]; float peak_value[3];
float mean_value[3]; float mean_value[3];
int frame_cnt; int frame_cnt;
cf_t *input; cf_t *input;
int m0, m1; int m0, m1;
float m0_value, m1_value; float m0_value, m1_value;
int N_id_2; int N_id_2;
int sss_idx; int sss_idx;
struct timeval tdata[3]; struct timeval tdata[3];
int *exec_time; int *exec_time;
if (argc < 3) { if (argc < 3) {
usage(argv[0]); usage(argv[0]);
exit(-1); exit(-1);
} }
parse_args(argc,argv); parse_args(argc,argv);
gettimeofday(&tdata[1], NULL); gettimeofday(&tdata[1], NULL);
printf("Initializing...");fflush(stdout); printf("Initializing...");fflush(stdout);
if (filesource_init(&fsrc, input_file_name, COMPLEX_FLOAT_BIN)) { if (filesource_init(&fsrc, input_file_name, COMPLEX_FLOAT_BIN)) {
fprintf(stderr, "Error opening file %s\n", input_file_name); fprintf(stderr, "Error opening file %s\n", input_file_name);
exit(-1); exit(-1);
} }
if (filesink_init(&fsink, output_file_name, COMPLEX_FLOAT_BIN)) { if (filesink_init(&fsink, output_file_name, COMPLEX_FLOAT_BIN)) {
fprintf(stderr, "Error opening file %s\n", output_file_name); fprintf(stderr, "Error opening file %s\n", output_file_name);
exit(-1); exit(-1);
} }
input = malloc(frame_length*sizeof(cf_t)); input = malloc(frame_length*sizeof(cf_t));
if (!input) { if (!input) {
perror("malloc"); perror("malloc");
exit(-1); exit(-1);
} }
cfo = malloc(nof_frames*sizeof(float)); cfo = malloc(nof_frames*sizeof(float));
if (!cfo) { if (!cfo) {
perror("malloc"); perror("malloc");
exit(-1); exit(-1);
} }
exec_time = malloc(nof_frames*sizeof(int)); exec_time = malloc(nof_frames*sizeof(int));
if (!exec_time) { if (!exec_time) {
perror("malloc"); perror("malloc");
exit(-1); exit(-1);
} }
if (cfo_init(&cfocorr, frame_length)) { if (cfo_init(&cfocorr, frame_length)) {
fprintf(stderr, "Error initiating CFO\n"); fprintf(stderr, "Error initiating CFO\n");
return -1; return -1;
} }
/* We have 2 options here: /* We have 2 options here:
* a) We create 3 pss objects, each initialized with a different N_id_2 * a) We create 3 pss objects, each initialized with a different N_id_2
* b) We create 1 pss object which scans for each N_id_2 one after another. * b) We create 1 pss object which scans for each N_id_2 one after another.
* a) requries more memory but has less latency and is paralellizable. * a) requries more memory but has less latency and is paralellizable.
*/ */
for (N_id_2=0;N_id_2<3;N_id_2++) { for (N_id_2=0;N_id_2<3;N_id_2++) {
if (pss_synch_init(&pss[N_id_2], frame_length)) { if (pss_synch_init(&pss[N_id_2], frame_length)) {
fprintf(stderr, "Error initializing PSS object\n"); fprintf(stderr, "Error initializing PSS object\n");
exit(-1); exit(-1);
} }
if (pss_synch_set_N_id_2(&pss[N_id_2], N_id_2)) { if (pss_synch_set_N_id_2(&pss[N_id_2], N_id_2)) {
fprintf(stderr, "Error initializing N_id_2\n"); fprintf(stderr, "Error initializing N_id_2\n");
exit(-1); exit(-1);
} }
if (sss_synch_init(&sss[N_id_2])) { if (sss_synch_init(&sss[N_id_2])) {
fprintf(stderr, "Error initializing SSS object\n"); fprintf(stderr, "Error initializing SSS object\n");
exit(-1); exit(-1);
} }
if (sss_synch_set_N_id_2(&sss[N_id_2], N_id_2)) { if (sss_synch_set_N_id_2(&sss[N_id_2], N_id_2)) {
fprintf(stderr, "Error initializing N_id_2\n"); fprintf(stderr, "Error initializing N_id_2\n");
exit(-1); exit(-1);
} }
} }
gettimeofday(&tdata[2], NULL); gettimeofday(&tdata[2], NULL);
get_time_interval(tdata); get_time_interval(tdata);
printf("done in %d s %d ms\n", (int) tdata[0].tv_sec, (int) tdata[0].tv_usec/1000); printf("done in %d s %d ms\n", (int) tdata[0].tv_sec, (int) tdata[0].tv_usec/1000);
printf("\n\tFr.Cnt\tN_id_2\tN_id_1\tSubf\tPSS Peak/Avg\tIdx\tm0\tm1\tCFO\n"); printf("\n\tFr.Cnt\tN_id_2\tN_id_1\tSubf\tPSS Peak/Avg\tIdx\tm0\tm1\tCFO\n");
printf("\t===============================================================================\n"); printf("\t===============================================================================\n");
/* read all file or nof_frames */ /* read all file or nof_frames */
frame_cnt = 0; frame_cnt = 0;
while (frame_length == filesource_read(&fsrc, input, frame_length) while (frame_length == filesource_read(&fsrc, input, frame_length)
&& frame_cnt < nof_frames) { && frame_cnt < nof_frames) {
gettimeofday(&tdata[1], NULL); gettimeofday(&tdata[1], NULL);
if (force_cfo != CFO_AUTO) { if (force_cfo != CFO_AUTO) {
cfo_correct(&cfocorr, input, -force_cfo/128); cfo_correct(&cfocorr, input, -force_cfo/128);
} }
if (force_N_id_2 != -1) { if (force_N_id_2 != -1) {
N_id_2 = force_N_id_2; N_id_2 = force_N_id_2;
peak_pos[N_id_2] = pss_synch_find_pss(&pss[N_id_2], input, &peak_value[N_id_2], &mean_value[N_id_2]); peak_pos[N_id_2] = pss_synch_find_pss(&pss[N_id_2], input, &peak_value[N_id_2], &mean_value[N_id_2]);
} else { } else {
for (N_id_2=0;N_id_2<3;N_id_2++) { for (N_id_2=0;N_id_2<3;N_id_2++) {
peak_pos[N_id_2] = pss_synch_find_pss(&pss[N_id_2], input, &peak_value[N_id_2], &mean_value[N_id_2]); peak_pos[N_id_2] = pss_synch_find_pss(&pss[N_id_2], input, &peak_value[N_id_2], &mean_value[N_id_2]);
} }
float max_value=-99999; float max_value=-99999;
N_id_2=-1; N_id_2=-1;
int i; int i;
for (i=0;i<3;i++) { for (i=0;i<3;i++) {
if (peak_value[i] > max_value) { if (peak_value[i] > max_value) {
max_value = peak_value[i]; max_value = peak_value[i];
N_id_2 = i; N_id_2 = i;
} }
} }
} }
/* If peak detected */ /* If peak detected */
if (peak_value[N_id_2]/mean_value[N_id_2] > corr_peak_threshold) { if (peak_value[N_id_2]/mean_value[N_id_2] > corr_peak_threshold) {
sss_idx = peak_pos[N_id_2]-2*(symbol_sz+CP(symbol_sz,CPNORM_LEN)); sss_idx = peak_pos[N_id_2]-2*(symbol_sz+CP(symbol_sz,CPNORM_LEN));
if (sss_idx >= 0) { if (sss_idx >= 0) {
sss_synch_m0m1(&sss[N_id_2], &input[sss_idx], sss_synch_m0m1(&sss[N_id_2], &input[sss_idx],
&m0, &m0_value, &m1, &m1_value); &m0, &m0_value, &m1, &m1_value);
cfo[frame_cnt] = pss_synch_cfo_compute(&pss[N_id_2], &input[peak_pos[N_id_2]-128]); cfo[frame_cnt] = pss_synch_cfo_compute(&pss[N_id_2], &input[peak_pos[N_id_2]-128]);
printf("\t%d\t%d\t%d\t%d\t%.3f\t\t%3d\t%d\t%d\t%.3f\n", printf("\t%d\t%d\t%d\t%d\t%.3f\t\t%3d\t%d\t%d\t%.3f\n",
frame_cnt,N_id_2, sss_synch_N_id_1(&sss[N_id_2], m0, m1), frame_cnt,N_id_2, sss_synch_N_id_1(&sss[N_id_2], m0, m1),
sss_synch_subframe(m0, m1), peak_value[N_id_2]/mean_value[N_id_2], sss_synch_subframe(m0, m1), peak_value[N_id_2]/mean_value[N_id_2],
peak_pos[N_id_2], m0, m1, peak_pos[N_id_2], m0, m1,
cfo[frame_cnt]); cfo[frame_cnt]);
} }
} }
gettimeofday(&tdata[2], NULL); gettimeofday(&tdata[2], NULL);
get_time_interval(tdata); get_time_interval(tdata);
exec_time[frame_cnt] = tdata[0].tv_usec; exec_time[frame_cnt] = tdata[0].tv_usec;
frame_cnt++; frame_cnt++;
} }
int i; int i;
float avg_time=0; float avg_time=0;
for (i=0;i<frame_cnt;i++) { for (i=0;i<frame_cnt;i++) {
avg_time += (float) exec_time[i]; avg_time += (float) exec_time[i];
} }
avg_time /= frame_cnt; avg_time /= frame_cnt;
printf("\n"); printf("\n");
printf("Average exec time: %.3f ms / frame. %.3f Msamp/s (%.3f\%% CPU)\n", printf("Average exec time: %.3f ms / frame. %.3f Msamp/s (%.3f\%% CPU)\n",
avg_time / 1000, frame_length / avg_time, 100 * avg_time / 5000 * (9600 / (float) frame_length )); avg_time / 1000, frame_length / avg_time, 100 * avg_time / 5000 * (9600 / (float) frame_length ));
float cfo_mean=0; float cfo_mean=0;
for (i=0;i<frame_cnt;i++) { for (i=0;i<frame_cnt;i++) {
cfo_mean += cfo[i] / frame_cnt * (9600 / frame_length); cfo_mean += cfo[i] / frame_cnt * (9600 / frame_length);
} }
printf("Average CFO: %.3f\n", cfo_mean); printf("Average CFO: %.3f\n", cfo_mean);
for (N_id_2=0;N_id_2<3;N_id_2++) { for (N_id_2=0;N_id_2<3;N_id_2++) {
pss_synch_free(&pss[N_id_2]); pss_synch_free(&pss[N_id_2]);
sss_synch_free(&sss[N_id_2]); sss_synch_free(&sss[N_id_2]);
} }
filesource_free(&fsrc); filesource_free(&fsrc);
filesink_free(&fsink); filesink_free(&fsink);
free(input); free(input);
free(cfo); free(cfo);
printf("Done\n"); printf("Done\n");
exit(0); exit(0);
} }

@ -38,7 +38,7 @@ extern "C" {
#include "lte/config.h" #include "lte/config.h"
typedef enum { typedef enum {
Ip, Q, Magnitude, Phase Ip, Q, Magnitude, Phase
} plot_complex_id_t; } plot_complex_id_t;
typedef void* plot_complex_t; typedef void* plot_complex_t;
@ -46,7 +46,7 @@ typedef void* plot_complex_t;
LIBLTE_API int plot_complex_init(plot_complex_t *h); LIBLTE_API int plot_complex_init(plot_complex_t *h);
LIBLTE_API void plot_complex_setTitle(plot_complex_t *h, char *title); LIBLTE_API void plot_complex_setTitle(plot_complex_t *h, char *title);
LIBLTE_API void plot_complex_setNewData(plot_complex_t *h, _Complex float *data, LIBLTE_API void plot_complex_setNewData(plot_complex_t *h, _Complex float *data,
int num_points); int num_points);
LIBLTE_API void plot_complex_setXAxisAutoScale(plot_complex_t *h, plot_complex_id_t id, bool on); LIBLTE_API void plot_complex_setXAxisAutoScale(plot_complex_t *h, plot_complex_id_t id, bool on);
LIBLTE_API void plot_complex_setYAxisAutoScale(plot_complex_t *h, plot_complex_id_t id, bool on); LIBLTE_API void plot_complex_setYAxisAutoScale(plot_complex_t *h, plot_complex_id_t id, bool on);
LIBLTE_API void plot_complex_setXAxisScale(plot_complex_t *h, plot_complex_id_t id, double xMin, double xMax); LIBLTE_API void plot_complex_setXAxisScale(plot_complex_t *h, plot_complex_id_t id, double xMin, double xMax);

@ -41,7 +41,7 @@ typedef void* plot_real_t;
LIBLTE_API int plot_real_init(plot_real_t *h); LIBLTE_API int plot_real_init(plot_real_t *h);
LIBLTE_API void plot_real_setTitle(plot_real_t *h, char *title); LIBLTE_API void plot_real_setTitle(plot_real_t *h, char *title);
LIBLTE_API void plot_real_setNewData(plot_real_t *h, float *data, LIBLTE_API void plot_real_setNewData(plot_real_t *h, float *data,
int num_points); int num_points);
LIBLTE_API void plot_real_setXAxisAutoScale(plot_real_t *h, bool on); LIBLTE_API void plot_real_setXAxisAutoScale(plot_real_t *h, bool on);
LIBLTE_API void plot_real_setYAxisAutoScale(plot_real_t *h, bool on); LIBLTE_API void plot_real_setYAxisAutoScale(plot_real_t *h, bool on);
LIBLTE_API void plot_real_setXAxisScale(plot_real_t *h, double xMin, double xMax); LIBLTE_API void plot_real_setXAxisScale(plot_real_t *h, double xMin, double xMax);

@ -41,7 +41,7 @@ typedef void* plot_scatter_t;
LIBLTE_API int plot_scatter_init(plot_scatter_t *h); LIBLTE_API int plot_scatter_init(plot_scatter_t *h);
LIBLTE_API void plot_scatter_setTitle(plot_scatter_t *h, char *title); LIBLTE_API void plot_scatter_setTitle(plot_scatter_t *h, char *title);
LIBLTE_API void plot_scatter_setNewData(plot_scatter_t *h, _Complex float *data, LIBLTE_API void plot_scatter_setNewData(plot_scatter_t *h, _Complex float *data,
int num_points); int num_points);
LIBLTE_API void plot_scatter_setXAxisAutoScale(plot_scatter_t *h, bool on); LIBLTE_API void plot_scatter_setXAxisAutoScale(plot_scatter_t *h, bool on);
LIBLTE_API void plot_scatter_setYAxisAutoScale(plot_scatter_t *h, bool on); LIBLTE_API void plot_scatter_setYAxisAutoScale(plot_scatter_t *h, bool on);
LIBLTE_API void plot_scatter_setXAxisScale(plot_scatter_t *h, double xMin, double xMax); LIBLTE_API void plot_scatter_setXAxisScale(plot_scatter_t *h, double xMin, double xMax);

@ -41,7 +41,7 @@ typedef void* plot_waterfall_t;
LIBLTE_API int plot_waterfall_init(plot_waterfall_t *h); LIBLTE_API int plot_waterfall_init(plot_waterfall_t *h);
LIBLTE_API void plot_waterfall_setTitle(plot_waterfall_t *h, char *title); LIBLTE_API void plot_waterfall_setTitle(plot_waterfall_t *h, char *title);
LIBLTE_API void plot_waterfall_appendNewData(plot_waterfall_t *h, float *data, LIBLTE_API void plot_waterfall_appendNewData(plot_waterfall_t *h, float *data,
int num_points); int num_points);
LIBLTE_API void plot_complex_setPlotXLabel(plot_waterfall_t *h, char *xLabel); LIBLTE_API void plot_complex_setPlotXLabel(plot_waterfall_t *h, char *xLabel);
LIBLTE_API void plot_complex_setPlotYLabel(plot_waterfall_t *h, char *yLabel); LIBLTE_API void plot_complex_setPlotYLabel(plot_waterfall_t *h, char *yLabel);
LIBLTE_API void plot_waterfall_setPlotXAxisRange(plot_waterfall_t *h, double xMin, double xMax); LIBLTE_API void plot_waterfall_setPlotXAxisRange(plot_waterfall_t *h, double xMin, double xMax);

@ -51,12 +51,12 @@ typedef void (*interpolate_fnc_t) (cf_t *input, cf_t *output, int M, int len, in
/* Low-level API */ /* Low-level API */
typedef struct LIBLTE_API{ typedef struct LIBLTE_API{
int nof_ports; int nof_ports;
int nof_symbols; int nof_symbols;
int nof_prb; int nof_prb;
lte_cp_t cp; lte_cp_t cp;
refsignal_t refsignal[MAX_PORTS][NSLOTS_X_FRAME]; refsignal_t refsignal[MAX_PORTS][NSLOTS_X_FRAME];
interpolate_fnc_t interp; interpolate_fnc_t interp;
}chest_t; }chest_t;
LIBLTE_API int chest_init(chest_t *q, chest_interp_t interp, lte_cp_t cp, int nof_prb, int nof_ports); LIBLTE_API int chest_init(chest_t *q, chest_interp_t interp, lte_cp_t cp, int nof_prb, int nof_ports);
@ -81,24 +81,24 @@ LIBLTE_API int chest_ref_symbols(chest_t *q, int port_id, int nslot, int l[2]);
/** TODO: The high-level API has N interfaces, one for each port */ /** TODO: The high-level API has N interfaces, one for each port */
typedef struct LIBLTE_API{ typedef struct LIBLTE_API{
chest_t obj; chest_t obj;
struct chest_init { struct chest_init {
int nof_symbols; // 7 for normal cp, 6 for extended int nof_symbols; // 7 for normal cp, 6 for extended
int nof_ports; int nof_ports;
int nof_prb; int nof_prb;
int cell_id; // set to -1 to init at runtime int cell_id; // set to -1 to init at runtime
} init; } init;
cf_t *input; cf_t *input;
int in_len; int in_len;
struct chest_ctrl_in { struct chest_ctrl_in {
int slot_id; // slot id in the 10ms frame int slot_id; // slot id in the 10ms frame
int cell_id; int cell_id;
} ctrl_in; } ctrl_in;
cf_t *output[MAX_PORTS]; cf_t *output[MAX_PORTS];
int out_len[MAX_PORTS]; int out_len[MAX_PORTS];
}chest_hl; }chest_hl;
#define DEFAULT_FRAME_SIZE 2048 #define DEFAULT_FRAME_SIZE 2048
LIBLTE_API int chest_initialize(chest_hl* h); LIBLTE_API int chest_initialize(chest_hl* h);
LIBLTE_API int chest_work(chest_hl* hl); LIBLTE_API int chest_work(chest_hl* hl);

@ -43,24 +43,24 @@
typedef _Complex float cf_t; typedef _Complex float cf_t;
typedef struct LIBLTE_API{ typedef struct LIBLTE_API{
int time_idx; int time_idx;
int freq_idx; int freq_idx;
cf_t simbol; cf_t simbol;
cf_t recv_simbol; cf_t recv_simbol;
}ref_t; }ref_t;
typedef struct LIBLTE_API{ typedef struct LIBLTE_API{
int nof_refs; // number of reference signals int nof_refs; // number of reference signals
int *symbols_ref; // symbols with at least one reference int *symbols_ref; // symbols with at least one reference
int nsymbols; // number of symbols with at least one reference int nsymbols; // number of symbols with at least one reference
int voffset; // offset of the first reference in the freq domain int voffset; // offset of the first reference in the freq domain
int nof_prb; int nof_prb;
ref_t *refs; ref_t *refs;
cf_t *ch_est; cf_t *ch_est;
} refsignal_t; } refsignal_t;
LIBLTE_API int refsignal_init_LTEDL(refsignal_t *q, int port_id, int nslot, LIBLTE_API int refsignal_init_LTEDL(refsignal_t *q, int port_id, int nslot,
int cell_id, lte_cp_t cp, int nof_prb); int cell_id, lte_cp_t cp, int nof_prb);
LIBLTE_API void refsignal_free(refsignal_t *q); LIBLTE_API void refsignal_free(refsignal_t *q);
LIBLTE_API void refsignal_put(refsignal_t *q, cf_t *slot_symbols); LIBLTE_API void refsignal_put(refsignal_t *q, cf_t *slot_symbols);

@ -40,14 +40,14 @@ LIBLTE_API void ch_awgn_f(const float* x, float* y, float variance, int buff_sz)
/* High-level API */ /* High-level API */
typedef struct LIBLTE_API{ typedef struct LIBLTE_API{
const cf_t* input; const cf_t* input;
int in_len; int in_len;
struct ch_awgn_ctrl_in { struct ch_awgn_ctrl_in {
float variance; // Noise variance float variance; // Noise variance
} ctrl_in; } ctrl_in;
cf_t* output; cf_t* output;
int out_len; int out_len;
}ch_awgn_hl; }ch_awgn_hl;
LIBLTE_API int ch_awgn_initialize(ch_awgn_hl* hl); LIBLTE_API int ch_awgn_initialize(ch_awgn_hl* hl);

@ -31,38 +31,38 @@
#include "lte/config.h" #include "lte/config.h"
#define NSUBFRAMES_X_FRAME 10 #define NSUBFRAMES_X_FRAME 10
#define NSLOTS_X_FRAME (2*NSUBFRAMES_X_FRAME) #define NSLOTS_X_FRAME (2*NSUBFRAMES_X_FRAME)
#define LTE_NIL_SYMBOL 2 #define LTE_NIL_SYMBOL 2
#define MAX_PORTS 4 #define MAX_PORTS 4
#define MAX_PORTS_CTRL 4 #define MAX_PORTS_CTRL 4
#define MAX_LAYERS 8 #define MAX_LAYERS 8
#define MAX_CODEWORDS 2 #define MAX_CODEWORDS 2
#define LTE_CRC24A 0x1864CFB #define LTE_CRC24A 0x1864CFB
#define LTE_CRC24B 0X1800063 #define LTE_CRC24B 0X1800063
#define LTE_CRC16 0x11021 #define LTE_CRC16 0x11021
#define LTE_CRC8 0x19B #define LTE_CRC8 0x19B
typedef enum {CPNORM, CPEXT} lte_cp_t; typedef enum {CPNORM, CPEXT} lte_cp_t;
#define SIRNTI 0xFFFF #define SIRNTI 0xFFFF
#define PRNTI 0xFFFE #define PRNTI 0xFFFE
#define MRNTI 0xFFFD #define MRNTI 0xFFFD
#define MAX_NSYMB 7 #define MAX_NSYMB 7
#define CPNORM_NSYMB 7 #define CPNORM_NSYMB 7
#define CPNORM_SF_NSYMB 2*CPNORM_NSYMB #define CPNORM_SF_NSYMB 2*CPNORM_NSYMB
#define CPNORM_0_LEN 160 #define CPNORM_0_LEN 160
#define CPNORM_LEN 144 #define CPNORM_LEN 144
#define CPEXT_NSYMB 6 #define CPEXT_NSYMB 6
#define CPEXT_SF_NSYMB 2*CPEXT_NSYMB #define CPEXT_SF_NSYMB 2*CPEXT_NSYMB
#define CPEXT_LEN 512 #define CPEXT_LEN 512
#define CPEXT_7_5_LEN 1024 #define CPEXT_7_5_LEN 1024
#define CP_ISNORM(cp) (cp==CPNORM) #define CP_ISNORM(cp) (cp==CPNORM)
#define CP_ISEXT(cp) (cp==CPEXT) #define CP_ISEXT(cp) (cp==CPEXT)
@ -83,12 +83,12 @@ typedef enum {CPNORM, CPEXT} lte_cp_t;
#define SLOT_IDX_CPNORM(idx, symbol_sz) (idx==0?(CP(symbol_sz, CPNORM_0_LEN)):(CP(symbol_sz, CPNORM_0_LEN)+idx*(symbol_sz+CP(symbol_sz, CPNORM_LEN)))) #define SLOT_IDX_CPNORM(idx, symbol_sz) (idx==0?(CP(symbol_sz, CPNORM_0_LEN)):(CP(symbol_sz, CPNORM_0_LEN)+idx*(symbol_sz+CP(symbol_sz, CPNORM_LEN))))
#define SLOT_IDX_CPEXT(idx, symbol_sz) (idx*(symbol_sz+CP(symbol_sz, CPEXT_LEN))) #define SLOT_IDX_CPEXT(idx, symbol_sz) (idx*(symbol_sz+CP(symbol_sz, CPEXT_LEN)))
#define MAX_PRB 110 #define MAX_PRB 110
#define RE_X_RB 12 #define RE_X_RB 12
#define RS_VSHIFT(cell_id) (cell_id%6) #define RS_VSHIFT(cell_id) (cell_id%6)
#define GUARD_RE(nof_prb) ((lte_symbol_sz(nof_prb)-nof_prb*RE_X_RB)/2) #define GUARD_RE(nof_prb) ((lte_symbol_sz(nof_prb)-nof_prb*RE_X_RB)/2)
#define SAMPLE_IDX(nof_prb, symbol_idx, sample_idx) (symbol_idx*nof_prb*RE_X_RB + sample_idx) #define SAMPLE_IDX(nof_prb, symbol_idx, sample_idx) (symbol_idx*nof_prb*RE_X_RB + sample_idx)
@ -96,13 +96,13 @@ LIBLTE_API const int lte_symbol_sz(int nof_prb);
LIBLTE_API int lte_re_x_prb(int ns, int symbol, int nof_ports, int nof_symbols); LIBLTE_API int lte_re_x_prb(int ns, int symbol, int nof_ports, int nof_symbols);
LIBLTE_API int lte_voffset(int symbol_id, int cell_id, int nof_ports); LIBLTE_API int lte_voffset(int symbol_id, int cell_id, int nof_ports);
#define NOF_LTE_BANDS 29 #define NOF_LTE_BANDS 29
#define NOF_TC_CB_SIZES 188 #define NOF_TC_CB_SIZES 188
typedef enum { typedef enum {
SINGLE_ANTENNA,TX_DIVERSITY, SPATIAL_MULTIPLEX SINGLE_ANTENNA,TX_DIVERSITY, SPATIAL_MULTIPLEX
} lte_mimo_type_t; } lte_mimo_type_t;
typedef enum { PHICH_NORM, PHICH_EXT} phich_length_t; typedef enum { PHICH_NORM, PHICH_EXT} phich_length_t;
@ -110,12 +110,12 @@ typedef enum { R_1_6, R_1_2, R_1, R_2} phich_resources_t;
typedef struct LIBLTE_API{ typedef struct LIBLTE_API{
int id; int id;
float fd; float fd;
}lte_earfcn_t; }lte_earfcn_t;
enum band_geographical_area { enum band_geographical_area {
ALL, NAR, APAC, EMEA, JAPAN, CALA, NA ALL, NAR, APAC, EMEA, JAPAN, CALA, NA
}; };
LIBLTE_API int lte_cb_size(int index); LIBLTE_API int lte_cb_size(int index);

@ -41,13 +41,13 @@ typedef _Complex float cf_t; /* this is only a shortcut */
/* This is common for both directions */ /* This is common for both directions */
typedef struct LIBLTE_API{ typedef struct LIBLTE_API{
dft_plan_t fft_plan; dft_plan_t fft_plan;
int nof_symbols; int nof_symbols;
int symbol_sz; int symbol_sz;
int nof_guards; int nof_guards;
int nof_re; int nof_re;
lte_cp_t cp_type; lte_cp_t cp_type;
cf_t *tmp; // for removing zero padding cf_t *tmp; // for removing zero padding
}lte_fft_t; }lte_fft_t;
LIBLTE_API int lte_fft_init(lte_fft_t *q, lte_cp_t cp_type, int nof_prb); LIBLTE_API int lte_fft_init(lte_fft_t *q, lte_cp_t cp_type, int nof_prb);

@ -33,8 +33,8 @@
#include "lte/common/base.h" #include "lte/common/base.h"
typedef struct LIBLTE_API{ typedef struct LIBLTE_API{
char *c; char *c;
int len; int len;
}sequence_t; }sequence_t;
LIBLTE_API int sequence_init(sequence_t *q, int len); LIBLTE_API int sequence_init(sequence_t *q, int len);

@ -34,10 +34,10 @@
#include "lte/config.h" #include "lte/config.h"
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
int R; int R;
int K; int K;
int poly[3]; int poly[3];
bool tail_biting; bool tail_biting;
}convcoder_t; }convcoder_t;
LIBLTE_API int convcoder_encode(convcoder_t *q, char *input, char *output, int frame_length); LIBLTE_API int convcoder_encode(convcoder_t *q, char *input, char *output, int frame_length);
@ -45,20 +45,20 @@ LIBLTE_API int convcoder_encode(convcoder_t *q, char *input, char *output, int f
/* High-level API */ /* High-level API */
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
convcoder_t obj; convcoder_t obj;
struct convcoder_ctrl_in { struct convcoder_ctrl_in {
int rate; int rate;
int constraint_length; int constraint_length;
int tail_bitting; int tail_bitting;
int generator_0; int generator_0;
int generator_1; int generator_1;
int generator_2; int generator_2;
int frame_length; int frame_length;
} ctrl_in; } ctrl_in;
char *input; char *input;
int in_len; int in_len;
char *output; char *output;
int out_len; int out_len;
}convcoder_hl; }convcoder_hl;
LIBLTE_API int convcoder_initialize(convcoder_hl* h); LIBLTE_API int convcoder_initialize(convcoder_hl* h);

@ -32,14 +32,14 @@
#include "lte/config.h" #include "lte/config.h"
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
unsigned long table[256]; unsigned long table[256];
unsigned char byte; unsigned char byte;
int polynom; int polynom;
int order; int order;
unsigned long crcinit; unsigned long crcinit;
unsigned long crcmask; unsigned long crcmask;
unsigned long crchighbit; unsigned long crchighbit;
unsigned int crc_out; unsigned int crc_out;
} crc_t; } crc_t;
LIBLTE_API int crc_init(crc_t *h, unsigned int crc_poly, int crc_order); LIBLTE_API int crc_init(crc_t *h, unsigned int crc_poly, int crc_order);

@ -41,17 +41,17 @@ LIBLTE_API int rm_conv_rx(float *input, int in_len, float *output, int out_len);
/* High-level API */ /* High-level API */
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
struct rm_conv_init { struct rm_conv_init {
int direction; int direction;
} init; } init;
void *input; // input type may be char or float depending on hard void *input; // input type may be char or float depending on hard
int in_len; int in_len;
struct rm_conv_ctrl_in { struct rm_conv_ctrl_in {
int E; int E;
int S; int S;
} ctrl_in; } ctrl_in;
void *output; void *output;
int out_len; int out_len;
}rm_conv_hl; }rm_conv_hl;
LIBLTE_API int rm_conv_initialize(rm_conv_hl* h); LIBLTE_API int rm_conv_initialize(rm_conv_hl* h);

@ -40,9 +40,9 @@
#endif #endif
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
int buffer_len; int buffer_len;
char *buffer; char *buffer;
int *d2_perm; int *d2_perm;
} rm_turbo_t; } rm_turbo_t;
LIBLTE_API int rm_turbo_init(rm_turbo_t *q, int max_codeblock_len); LIBLTE_API int rm_turbo_init(rm_turbo_t *q, int max_codeblock_len);
@ -53,19 +53,19 @@ LIBLTE_API int rm_turbo_rx(rm_turbo_t *q, float *input, int in_len, float *outpu
/* High-level API */ /* High-level API */
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
rm_turbo_t q; rm_turbo_t q;
struct rm_turbo_init { struct rm_turbo_init {
int direction; int direction;
} init; } init;
void *input; // input type may be char or float depending on hard void *input; // input type may be char or float depending on hard
int in_len; int in_len;
struct rm_turbo_ctrl_in { struct rm_turbo_ctrl_in {
int E; int E;
int S; int S;
int rv_idx; int rv_idx;
} ctrl_in; } ctrl_in;
void *output; void *output;
int out_len; int out_len;
}rm_turbo_hl; }rm_turbo_hl;
LIBLTE_API int rm_turbo_initialize(rm_turbo_hl* h); LIBLTE_API int rm_turbo_initialize(rm_turbo_hl* h);

@ -31,8 +31,8 @@
#include "lte/config.h" #include "lte/config.h"
typedef struct LIBLTE_API{ typedef struct LIBLTE_API{
int *forward; int *forward;
int *reverse; int *reverse;
}tc_interl_t; }tc_interl_t;
LIBLTE_API int tc_interl_LTE_init(tc_interl_t *h, int long_cb); LIBLTE_API int tc_interl_LTE_init(tc_interl_t *h, int long_cb);

@ -36,8 +36,8 @@
#define TOTALTAIL 12 #define TOTALTAIL 12
typedef struct LIBLTE_API{ typedef struct LIBLTE_API{
int long_cb; int long_cb;
tc_interl_t interl; tc_interl_t interl;
}tcod_t; }tcod_t;

@ -22,22 +22,22 @@
typedef float llr_t; typedef float llr_t;
typedef struct LIBLTE_API{ typedef struct LIBLTE_API{
int long_cb; int long_cb;
llr_t *beta; llr_t *beta;
}map_gen_t; }map_gen_t;
typedef struct LIBLTE_API{ typedef struct LIBLTE_API{
int long_cb; int long_cb;
map_gen_t dec; map_gen_t dec;
llr_t *llr1; llr_t *llr1;
llr_t *llr2; llr_t *llr2;
llr_t *w; llr_t *w;
llr_t *syst; llr_t *syst;
llr_t *parity; llr_t *parity;
tc_interl_t interleaver; tc_interl_t interleaver;
}tdec_t; }tdec_t;
LIBLTE_API int tdec_init(tdec_t *h, int long_cb); LIBLTE_API int tdec_init(tdec_t *h, int long_cb);

@ -33,20 +33,20 @@
#include "lte/config.h" #include "lte/config.h"
typedef enum { typedef enum {
viterbi_27, viterbi_29, viterbi_37, viterbi_39 viterbi_27, viterbi_29, viterbi_37, viterbi_39
}viterbi_type_t; }viterbi_type_t;
typedef struct LIBLTE_API{ typedef struct LIBLTE_API{
void *ptr; void *ptr;
int R; int R;
int K; int K;
unsigned int framebits; unsigned int framebits;
bool tail_biting; bool tail_biting;
int poly[3]; int poly[3];
int (*decode) (void*, unsigned char*, char*, int); int (*decode) (void*, unsigned char*, char*, int);
void (*free) (void*); void (*free) (void*);
unsigned char *tmp; unsigned char *tmp;
unsigned char *symbols_uc; unsigned char *symbols_uc;
}viterbi_t; }viterbi_t;
LIBLTE_API int viterbi_init(viterbi_t *q, viterbi_type_t type, int poly[3], int max_frame_length, bool tail_bitting); LIBLTE_API int viterbi_init(viterbi_t *q, viterbi_type_t type, int poly[3], int max_frame_length, bool tail_bitting);
@ -57,20 +57,20 @@ LIBLTE_API int viterbi_decode_uc(viterbi_t *q, unsigned char *symbols, char *dat
/* High-level API */ /* High-level API */
typedef struct LIBLTE_API{ typedef struct LIBLTE_API{
viterbi_t obj; viterbi_t obj;
struct viterbi_init { struct viterbi_init {
int rate; int rate;
int constraint_length; int constraint_length;
int tail_bitting; int tail_bitting;
int generator_0; int generator_0;
int generator_1; int generator_1;
int generator_2; int generator_2;
int frame_length; int frame_length;
} init; } init;
float *input; float *input;
int in_len; int in_len;
char *output; char *output;
int out_len; int out_len;
}viterbi_hl; }viterbi_hl;
LIBLTE_API int viterbi_initialize(viterbi_hl* h); LIBLTE_API int viterbi_initialize(viterbi_hl* h);

@ -38,12 +38,12 @@
typedef _Complex float cf_t; typedef _Complex float cf_t;
typedef struct LIBLTE_API{ typedef struct LIBLTE_API{
int sztime; // Output signal size in the time domain int sztime; // Output signal size in the time domain
int szfreq; // Output signal size in the freq domain int szfreq; // Output signal size in the freq domain
int ntime; // 2-D Filter size in time domain int ntime; // 2-D Filter size in time domain
int nfreq; // 2-D Filter size in frequency domain int nfreq; // 2-D Filter size in frequency domain
float **taps; // 2-D filter coefficients float **taps; // 2-D filter coefficients
cf_t *output; // Output signal cf_t *output; // Output signal
} filter2d_t; } filter2d_t;
LIBLTE_API int filter2d_init (filter2d_t* q, float **taps, int ntime, int nfreq, int sztime, int szfreq); LIBLTE_API int filter2d_init (filter2d_t* q, float **taps, int ntime, int nfreq, int sztime, int szfreq);

@ -35,11 +35,11 @@
/* Low-level API */ /* Low-level API */
typedef struct LIBLTE_API{ typedef struct LIBLTE_API{
unsigned int seed; unsigned int seed;
uint32_t *seq_buff; uint32_t *seq_buff;
int seq_buff_nwords; int seq_buff_nwords;
int seq_cache_nbits; int seq_cache_nbits;
int seq_cache_rp; int seq_cache_rp;
}binsource_t; }binsource_t;
LIBLTE_API void binsource_init(binsource_t* q); LIBLTE_API void binsource_init(binsource_t* q);
@ -52,20 +52,20 @@ LIBLTE_API int binsource_generate(binsource_t* q, char *bits, int nbits);
/* High-level API */ /* High-level API */
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
binsource_t obj; binsource_t obj;
struct binsource_init { struct binsource_init {
int cache_seq_nbits; // If non-zero, generates random bits on init int cache_seq_nbits; // If non-zero, generates random bits on init
unsigned int seed; // If non-zero, uses as random seed, otherwise local time is used. unsigned int seed; // If non-zero, uses as random seed, otherwise local time is used.
} init; } init;
struct binsource_ctrl_in { struct binsource_ctrl_in {
int nbits; // Number of bits to generate int nbits; // Number of bits to generate
} ctrl_in; } ctrl_in;
char* output; char* output;
int out_len; int out_len;
}binsource_hl; }binsource_hl;
LIBLTE_API int binsource_initialize(binsource_hl* h); LIBLTE_API int binsource_initialize(binsource_hl* h);
LIBLTE_API int binsource_work( binsource_hl* hl); LIBLTE_API int binsource_work( binsource_hl* hl);
LIBLTE_API int binsource_stop(binsource_hl* hl); LIBLTE_API int binsource_stop(binsource_hl* hl);
#endif // BINSOURCE_ #endif // BINSOURCE_

@ -37,8 +37,8 @@
/* Low-level API */ /* Low-level API */
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
FILE *f; FILE *f;
data_type_t type; data_type_t type;
}filesink_t; }filesink_t;
LIBLTE_API int filesink_init(filesink_t *q, char *filename, data_type_t type); LIBLTE_API int filesink_init(filesink_t *q, char *filename, data_type_t type);
@ -49,18 +49,18 @@ LIBLTE_API int filesink_write(filesink_t *q, void *buffer, int nsamples);
/* High-level API */ /* High-level API */
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
filesink_t obj; filesink_t obj;
struct filesink_init { struct filesink_init {
char *file_name; char *file_name;
int block_length; int block_length;
int data_type; int data_type;
} init; } init;
void* input; void* input;
int in_len; int in_len;
}filesink_hl; }filesink_hl;
LIBLTE_API int filesink_initialize(filesink_hl* h); LIBLTE_API int filesink_initialize(filesink_hl* h);
LIBLTE_API int filesink_work( filesink_hl* hl); LIBLTE_API int filesink_work( filesink_hl* hl);
LIBLTE_API int filesink_stop(filesink_hl* h); LIBLTE_API int filesink_stop(filesink_hl* h);
#endif // FILESINK_ #endif // FILESINK_

@ -37,8 +37,8 @@
/* Low-level API */ /* Low-level API */
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
FILE *f; FILE *f;
data_type_t type; data_type_t type;
}filesource_t; }filesource_t;
LIBLTE_API int filesource_init(filesource_t *q, char *filename, data_type_t type); LIBLTE_API int filesource_init(filesource_t *q, char *filename, data_type_t type);
@ -50,21 +50,21 @@ LIBLTE_API int filesource_read(filesource_t *q, void *buffer, int nsamples);
/* High-level API */ /* High-level API */
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
filesource_t obj; filesource_t obj;
struct filesource_init { struct filesource_init {
char *file_name; char *file_name;
int block_length; int block_length;
int data_type; int data_type;
} init; } init;
struct filesource_ctrl_in { struct filesource_ctrl_in {
int nsamples; // Number of samples to read int nsamples; // Number of samples to read
} ctrl_in; } ctrl_in;
void* output; void* output;
int out_len; int out_len;
}filesource_hl; }filesource_hl;
LIBLTE_API int filesource_initialize(filesource_hl* h); LIBLTE_API int filesource_initialize(filesource_hl* h);
LIBLTE_API int filesource_work( filesource_hl* hl); LIBLTE_API int filesource_work( filesource_hl* hl);
LIBLTE_API int filesource_stop(filesource_hl* h); LIBLTE_API int filesource_stop(filesource_hl* h);
#endif // FILESOURCE_ #endif // FILESOURCE_

@ -40,9 +40,9 @@
/* Low-level API */ /* Low-level API */
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
int sockfd; int sockfd;
struct sockaddr_in servaddr; struct sockaddr_in servaddr;
data_type_t type; data_type_t type;
}udpsink_t; }udpsink_t;
LIBLTE_API int udpsink_init(udpsink_t *q, char *address, int port, data_type_t type); LIBLTE_API int udpsink_init(udpsink_t *q, char *address, int port, data_type_t type);
@ -53,19 +53,19 @@ LIBLTE_API int udpsink_write(udpsink_t *q, void *buffer, int nsamples);
/* High-level API */ /* High-level API */
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
udpsink_t obj; udpsink_t obj;
struct udpsink_init { struct udpsink_init {
char *address; char *address;
int port; int port;
int block_length; int block_length;
int data_type; int data_type;
} init; } init;
void* input; void* input;
int in_len; int in_len;
}udpsink_hl; }udpsink_hl;
LIBLTE_API int udpsink_initialize(udpsink_hl* h); LIBLTE_API int udpsink_initialize(udpsink_hl* h);
LIBLTE_API int udpsink_work( udpsink_hl* hl); LIBLTE_API int udpsink_work( udpsink_hl* hl);
LIBLTE_API int udpsink_stop(udpsink_hl* h); LIBLTE_API int udpsink_stop(udpsink_hl* h);
#endif // UDPSINK_ #endif // UDPSINK_

@ -41,9 +41,9 @@
/* Low-level API */ /* Low-level API */
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
int sockfd; int sockfd;
struct sockaddr_in servaddr; struct sockaddr_in servaddr;
data_type_t type; data_type_t type;
}udpsource_t; }udpsource_t;
LIBLTE_API int udpsource_init(udpsource_t *q, char *address, int port, data_type_t type); LIBLTE_API int udpsource_init(udpsource_t *q, char *address, int port, data_type_t type);
@ -54,21 +54,21 @@ LIBLTE_API int udpsource_read(udpsource_t *q, void *buffer, int nsamples);
/* High-level API */ /* High-level API */
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
udpsource_t obj; udpsource_t obj;
struct udpsource_init { struct udpsource_init {
char *address; char *address;
int port; int port;
int data_type; int data_type;
} init; } init;
struct udpsource_ctrl_in { struct udpsource_ctrl_in {
int nsamples; // Number of samples to read int nsamples; // Number of samples to read
} ctrl_in; } ctrl_in;
void* output; void* output;
int out_len; int out_len;
}udpsource_hl; }udpsource_hl;
LIBLTE_API int udpsource_initialize(udpsource_hl* h); LIBLTE_API int udpsource_initialize(udpsource_hl* h);
LIBLTE_API int udpsource_work( udpsource_hl* hl); LIBLTE_API int udpsource_work( udpsource_hl* hl);
LIBLTE_API int udpsource_stop(udpsource_hl* h); LIBLTE_API int udpsource_stop(udpsource_hl* h);
#endif // UDPSOURCE_ #endif // UDPSOURCE_

@ -38,9 +38,9 @@ typedef _Complex float cf_t;
LIBLTE_API int layermap_single(cf_t *d, cf_t *x, int nof_symbols); LIBLTE_API int layermap_single(cf_t *d, cf_t *x, int nof_symbols);
LIBLTE_API int layermap_diversity(cf_t *d, cf_t *x[MAX_LAYERS], int nof_layers, int nof_symbols); LIBLTE_API int layermap_diversity(cf_t *d, cf_t *x[MAX_LAYERS], int nof_layers, int nof_symbols);
LIBLTE_API int layermap_multiplex(cf_t *d[MAX_CODEWORDS], cf_t *x[MAX_LAYERS], int nof_cw, int nof_layers, LIBLTE_API int layermap_multiplex(cf_t *d[MAX_CODEWORDS], cf_t *x[MAX_LAYERS], int nof_cw, int nof_layers,
int nof_symbols[MAX_CODEWORDS]); int nof_symbols[MAX_CODEWORDS]);
LIBLTE_API int layermap_type(cf_t *d[MAX_CODEWORDS], cf_t *x[MAX_LAYERS], int nof_cw, int nof_layers, LIBLTE_API int layermap_type(cf_t *d[MAX_CODEWORDS], cf_t *x[MAX_LAYERS], int nof_cw, int nof_layers,
int nof_symbols[MAX_CODEWORDS], lte_mimo_type_t type); int nof_symbols[MAX_CODEWORDS], lte_mimo_type_t type);
/* Generates the vector of data symbols "d" based on the vector of layer-mapped symbols "x" /* Generates the vector of data symbols "d" based on the vector of layer-mapped symbols "x"
@ -48,8 +48,8 @@ LIBLTE_API int layermap_type(cf_t *d[MAX_CODEWORDS], cf_t *x[MAX_LAYERS], int no
LIBLTE_API int layerdemap_single(cf_t *x, cf_t *d, int nof_symbols); LIBLTE_API int layerdemap_single(cf_t *x, cf_t *d, int nof_symbols);
LIBLTE_API int layerdemap_diversity(cf_t *x[MAX_LAYERS], cf_t *d, int nof_layers, int nof_layer_symbols); LIBLTE_API int layerdemap_diversity(cf_t *x[MAX_LAYERS], cf_t *d, int nof_layers, int nof_layer_symbols);
LIBLTE_API int layerdemap_multiplex(cf_t *x[MAX_LAYERS], cf_t *d[MAX_CODEWORDS], int nof_layers, int nof_cw, LIBLTE_API int layerdemap_multiplex(cf_t *x[MAX_LAYERS], cf_t *d[MAX_CODEWORDS], int nof_layers, int nof_cw,
int nof_layer_symbols, int nof_symbols[MAX_CODEWORDS]); int nof_layer_symbols, int nof_symbols[MAX_CODEWORDS]);
LIBLTE_API int layerdemap_type(cf_t *x[MAX_LAYERS], cf_t *d[MAX_CODEWORDS], int nof_layers, int nof_cw, LIBLTE_API int layerdemap_type(cf_t *x[MAX_LAYERS], cf_t *d[MAX_CODEWORDS], int nof_layers, int nof_cw,
int nof_layer_symbols, int nof_symbols[MAX_CODEWORDS], lte_mimo_type_t type); int nof_layer_symbols, int nof_symbols[MAX_CODEWORDS], lte_mimo_type_t type);
#endif // LAYERMAP_H_ #endif // LAYERMAP_H_

@ -43,16 +43,16 @@ typedef _Complex float cf_t;
LIBLTE_API int precoding_single(cf_t *x, cf_t *y, int nof_symbols); LIBLTE_API int precoding_single(cf_t *x, cf_t *y, int nof_symbols);
LIBLTE_API int precoding_diversity(cf_t *x[MAX_LAYERS], cf_t *y[MAX_PORTS], int nof_ports, int nof_symbols); LIBLTE_API int precoding_diversity(cf_t *x[MAX_LAYERS], cf_t *y[MAX_PORTS], int nof_ports, int nof_symbols);
LIBLTE_API int precoding_type(cf_t *x[MAX_LAYERS], cf_t *y[MAX_PORTS], int nof_layers, int nof_ports, LIBLTE_API int precoding_type(cf_t *x[MAX_LAYERS], cf_t *y[MAX_PORTS], int nof_layers, int nof_ports,
int nof_symbols, lte_mimo_type_t type); int nof_symbols, lte_mimo_type_t type);
/* Estimates the vector "x" based on the received signal "y" and the channel estimates "ce" /* Estimates the vector "x" based on the received signal "y" and the channel estimates "ce"
*/ */
LIBLTE_API int predecoding_single_zf(cf_t *y, cf_t *ce, cf_t *x, int nof_symbols); LIBLTE_API int predecoding_single_zf(cf_t *y, cf_t *ce, cf_t *x, int nof_symbols);
LIBLTE_API int predecoding_diversity_zf(cf_t *y[MAX_PORTS], cf_t *ce[MAX_PORTS], LIBLTE_API int predecoding_diversity_zf(cf_t *y[MAX_PORTS], cf_t *ce[MAX_PORTS],
cf_t *x[MAX_LAYERS], int nof_ports, int nof_symbols); cf_t *x[MAX_LAYERS], int nof_ports, int nof_symbols);
LIBLTE_API int predecoding_type(cf_t *y[MAX_PORTS], cf_t *ce[MAX_PORTS], LIBLTE_API int predecoding_type(cf_t *y[MAX_PORTS], cf_t *ce[MAX_PORTS],
cf_t *x[MAX_LAYERS], int nof_ports, int nof_layers, int nof_symbols, cf_t *x[MAX_LAYERS], int nof_ports, int nof_layers, int nof_symbols,
lte_mimo_type_t type); lte_mimo_type_t type);
#endif // PRECODING_H_ #endif // PRECODING_H_

@ -38,7 +38,7 @@
typedef _Complex float cf_t; typedef _Complex float cf_t;
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
enum modem_std table; /* In this implementation, mapping table is hard-coded */ enum modem_std table; /* In this implementation, mapping table is hard-coded */
}demod_hard_t; }demod_hard_t;
@ -50,16 +50,16 @@ LIBLTE_API int demod_hard_demodulate(demod_hard_t* q, cf_t* symbols, char *bits,
/* High-level API */ /* High-level API */
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
demod_hard_t obj; demod_hard_t obj;
struct demod_hard_init { struct demod_hard_init {
enum modem_std std; // Symbol mapping standard (see modem_table.h) enum modem_std std; // Symbol mapping standard (see modem_table.h)
} init; } init;
cf_t* input; cf_t* input;
int in_len; int in_len;
char* output; char* output;
int out_len; int out_len;
}demod_hard_hl; }demod_hard_hl;
LIBLTE_API int demod_hard_initialize(demod_hard_hl* hl); LIBLTE_API int demod_hard_initialize(demod_hard_hl* hl);

@ -38,9 +38,9 @@
enum alg { EXACT, APPROX }; enum alg { EXACT, APPROX };
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
float sigma; // noise power float sigma; // noise power
enum alg alg_type; // soft demapping algorithm (EXACT or APPROX) enum alg alg_type; // soft demapping algorithm (EXACT or APPROX)
modem_table_t *table; // symbol mapping table (see modem_table.h) modem_table_t *table; // symbol mapping table (see modem_table.h)
}demod_soft_t; }demod_soft_t;
LIBLTE_API void demod_soft_init(demod_soft_t *q); LIBLTE_API void demod_soft_init(demod_soft_t *q);
@ -52,23 +52,23 @@ LIBLTE_API int demod_soft_demodulate(demod_soft_t *q, const cf_t* symbols, float
/* High-level API */ /* High-level API */
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
demod_soft_t obj; demod_soft_t obj;
modem_table_t table; modem_table_t table;
struct demod_soft_init{ struct demod_soft_init{
enum modem_std std; // symbol mapping standard (see modem_table.h) enum modem_std std; // symbol mapping standard (see modem_table.h)
} init; } init;
const cf_t* input; const cf_t* input;
int in_len; int in_len;
struct demod_soft_ctrl_in { struct demod_soft_ctrl_in {
float sigma; // Estimated noise variance float sigma; // Estimated noise variance
enum alg alg_type; // soft demapping algorithm (EXACT or APPROX) enum alg alg_type; // soft demapping algorithm (EXACT or APPROX)
}ctrl_in; }ctrl_in;
float* output; float* output;
int out_len; int out_len;
}demod_soft_hl; }demod_soft_hl;

@ -41,16 +41,16 @@ LIBLTE_API int mod_modulate(modem_table_t* table, const char *bits, cf_t* symbol
/* High-level API */ /* High-level API */
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
modem_table_t obj; modem_table_t obj;
struct mod_init { struct mod_init {
enum modem_std std; // symbol mapping standard (see modem_table.h) enum modem_std std; // symbol mapping standard (see modem_table.h)
} init; } init;
const char* input; const char* input;
int in_len; int in_len;
cf_t* output; cf_t* output;
int out_len; int out_len;
}mod_hl; }mod_hl;
LIBLTE_API int mod_initialize(mod_hl* hl); LIBLTE_API int mod_initialize(mod_hl* hl);

@ -38,20 +38,20 @@
typedef _Complex float cf_t; typedef _Complex float cf_t;
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
int idx[2][6][32]; int idx[2][6][32];
}soft_table_t; }soft_table_t;
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
cf_t* symbol_table; // bit-to-symbol mapping cf_t* symbol_table; // bit-to-symbol mapping
soft_table_t soft_table; // symbol-to-bit mapping (used in soft demodulating) soft_table_t soft_table; // symbol-to-bit mapping (used in soft demodulating)
int nsymbols; // number of modulation symbols int nsymbols; // number of modulation symbols
int nbits_x_symbol; // number of bits per symbol int nbits_x_symbol; // number of bits per symbol
}modem_table_t; }modem_table_t;
// Modulation standards // Modulation standards
enum modem_std { enum modem_std {
LTE_BPSK = 1, LTE_QPSK = 2, LTE_QAM16 = 4, LTE_QAM64 = 6 LTE_BPSK = 1, LTE_QPSK = 2, LTE_QAM16 = 4, LTE_QAM64 = 6
}; };
LIBLTE_API void modem_table_init(modem_table_t* q); LIBLTE_API void modem_table_init(modem_table_t* q);

@ -43,40 +43,40 @@ typedef _Complex float cf_t;
*/ */
#define DCI_MAX_BITS 57 #define DCI_MAX_BITS 57
typedef enum { typedef enum {
Format0, Format1, Format1A, Format1C Format0, Format1, Format1A, Format1C
} dci_format_t; } dci_format_t;
// Each type is for a different interface to packing/unpacking functions // Each type is for a different interface to packing/unpacking functions
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
enum { enum {
PUSCH_SCHED, PDSCH_SCHED, MCCH_CHANGE, TPC_COMMAND, RA_PROC_PDCCH PUSCH_SCHED, PDSCH_SCHED, MCCH_CHANGE, TPC_COMMAND, RA_PROC_PDCCH
} type; } type;
dci_format_t format; dci_format_t format;
}dci_msg_type_t; }dci_msg_type_t;
typedef enum { typedef enum {
DCI_COMMON = 0, DCI_UE = 1 DCI_COMMON = 0, DCI_UE = 1
} dci_spec_t; } dci_spec_t;
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
unsigned char nof_bits; unsigned char nof_bits;
unsigned char L; // Aggregation level unsigned char L; // Aggregation level
unsigned char ncce; // Position of first CCE of the dci unsigned char ncce; // Position of first CCE of the dci
unsigned short rnti; unsigned short rnti;
} dci_candidate_t; } dci_candidate_t;
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
char data[DCI_MAX_BITS]; char data[DCI_MAX_BITS];
dci_candidate_t location; dci_candidate_t location;
} dci_msg_t; } dci_msg_t;
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
dci_msg_t *msg; dci_msg_t *msg;
int nof_dcis; int nof_dcis;
int max_dcis; int max_dcis;
} dci_t; } dci_t;
LIBLTE_API int dci_init(dci_t *q, int max_dci); LIBLTE_API int dci_init(dci_t *q, int max_dci);

@ -41,47 +41,47 @@
#include "lte/fec/viterbi.h" #include "lte/fec/viterbi.h"
#include "lte/fec/crc.h" #include "lte/fec/crc.h"
#define PBCH_RE_CPNORM 240 #define PBCH_RE_CPNORM 240
#define PBCH_RE_CPEXT 216 #define PBCH_RE_CPEXT 216
typedef _Complex float cf_t; typedef _Complex float cf_t;
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
int nof_ports; int nof_ports;
int nof_prb; int nof_prb;
int sfn; int sfn;
phich_length_t phich_length; phich_length_t phich_length;
phich_resources_t phich_resources; phich_resources_t phich_resources;
}pbch_mib_t; }pbch_mib_t;
/* PBCH object */ /* PBCH object */
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
int cell_id; int cell_id;
lte_cp_t cp; lte_cp_t cp;
int nof_prb; int nof_prb;
int nof_symbols; int nof_symbols;
/* buffers */ /* buffers */
cf_t *ce[MAX_PORTS_CTRL]; cf_t *ce[MAX_PORTS_CTRL];
cf_t *pbch_symbols[MAX_PORTS_CTRL]; cf_t *pbch_symbols[MAX_PORTS_CTRL];
cf_t *pbch_x[MAX_PORTS_CTRL]; cf_t *pbch_x[MAX_PORTS_CTRL];
cf_t *pbch_d; cf_t *pbch_d;
float *pbch_llr; float *pbch_llr;
float *temp; float *temp;
float *pbch_rm_f; float *pbch_rm_f;
char *pbch_rm_b; char *pbch_rm_b;
char *data; char *data;
char *data_enc; char *data_enc;
int frame_idx; int frame_idx;
/* tx & rx objects */ /* tx & rx objects */
modem_table_t mod; modem_table_t mod;
demod_soft_t demod; demod_soft_t demod;
sequence_t seq_pbch; sequence_t seq_pbch;
viterbi_t decoder; viterbi_t decoder;
crc_t crc; crc_t crc;
convcoder_t encoder; convcoder_t encoder;
}pbch_t; }pbch_t;

@ -38,36 +38,36 @@
#include "lte/scrambling/scrambling.h" #include "lte/scrambling/scrambling.h"
#include "lte/phch/regs.h" #include "lte/phch/regs.h"
#define PCFICH_CFI_LEN 32 #define PCFICH_CFI_LEN 32
#define PCFICH_RE PCFICH_CFI_LEN/2 #define PCFICH_RE PCFICH_CFI_LEN/2
#define PCFICH_MAX_DISTANCE 5 #define PCFICH_MAX_DISTANCE 5
typedef _Complex float cf_t; typedef _Complex float cf_t;
/* PCFICH object */ /* PCFICH object */
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
int cell_id; int cell_id;
lte_cp_t cp; lte_cp_t cp;
int nof_symbols; int nof_symbols;
int nof_prb; int nof_prb;
int nof_tx_ports; int nof_tx_ports;
/* handler to REGs resource mapper */ /* handler to REGs resource mapper */
regs_t *regs; regs_t *regs;
/* buffers */ /* buffers */
cf_t ce[MAX_PORTS_CTRL][PCFICH_RE]; cf_t ce[MAX_PORTS_CTRL][PCFICH_RE];
cf_t pcfich_symbols[MAX_PORTS_CTRL][PCFICH_RE]; cf_t pcfich_symbols[MAX_PORTS_CTRL][PCFICH_RE];
cf_t pcfich_x[MAX_PORTS_CTRL][PCFICH_RE]; cf_t pcfich_x[MAX_PORTS_CTRL][PCFICH_RE];
cf_t pcfich_d[PCFICH_RE]; cf_t pcfich_d[PCFICH_RE];
/* bit message */ /* bit message */
char data[PCFICH_CFI_LEN]; char data[PCFICH_CFI_LEN];
/* tx & rx objects */ /* tx & rx objects */
modem_table_t mod; modem_table_t mod;
demod_hard_t demod; demod_hard_t demod;
sequence_t seq_pcfich[NSUBFRAMES_X_FRAME]; sequence_t seq_pcfich[NSUBFRAMES_X_FRAME];
}pcfich_t; }pcfich_t;

@ -45,10 +45,10 @@
typedef _Complex float cf_t; typedef _Complex float cf_t;
#define PDCCH_NOF_SEARCH_MODES 3 #define PDCCH_NOF_SEARCH_MODES 3
typedef enum { typedef enum {
SEARCH_NONE=3, SEARCH_SI=0, SEARCH_RA=1, SEARCH_UE=2 SEARCH_NONE=3, SEARCH_SI=0, SEARCH_RA=1, SEARCH_UE=2
}pdcch_search_mode_t; }pdcch_search_mode_t;
/* /*
@ -56,40 +56,40 @@ typedef enum {
* DCI messages as defined in Section 7.1 of 36.213 * DCI messages as defined in Section 7.1 of 36.213
*/ */
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
int nof_candidates; int nof_candidates;
dci_candidate_t *candidates[NSUBFRAMES_X_FRAME]; dci_candidate_t *candidates[NSUBFRAMES_X_FRAME];
}pdcch_search_t; }pdcch_search_t;
/* PDCCH object */ /* PDCCH object */
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
int cell_id; int cell_id;
lte_cp_t cp; lte_cp_t cp;
int nof_prb; int nof_prb;
int nof_bits; int nof_bits;
int nof_symbols; int nof_symbols;
int nof_ports; int nof_ports;
int nof_regs; int nof_regs;
int nof_cce; int nof_cce;
pdcch_search_t search_mode[PDCCH_NOF_SEARCH_MODES]; pdcch_search_t search_mode[PDCCH_NOF_SEARCH_MODES];
pdcch_search_mode_t current_search_mode; pdcch_search_mode_t current_search_mode;
regs_t *regs; regs_t *regs;
/* buffers */ /* buffers */
cf_t *ce[MAX_PORTS_CTRL]; cf_t *ce[MAX_PORTS_CTRL];
cf_t *pdcch_symbols[MAX_PORTS_CTRL]; cf_t *pdcch_symbols[MAX_PORTS_CTRL];
cf_t *pdcch_x[MAX_PORTS_CTRL]; cf_t *pdcch_x[MAX_PORTS_CTRL];
cf_t *pdcch_d; cf_t *pdcch_d;
char *pdcch_e; char *pdcch_e;
float *pdcch_llr; float *pdcch_llr;
/* tx & rx objects */ /* tx & rx objects */
modem_table_t mod; modem_table_t mod;
demod_soft_t demod; demod_soft_t demod;
sequence_t seq_pdcch[NSUBFRAMES_X_FRAME]; sequence_t seq_pdcch[NSUBFRAMES_X_FRAME];
viterbi_t decoder; viterbi_t decoder;
crc_t crc; crc_t crc;
}pdcch_t; }pdcch_t;
LIBLTE_API int pdcch_init(pdcch_t *q, regs_t *regs, int nof_prb, int nof_ports, int cell_id, lte_cp_t cp); LIBLTE_API int pdcch_init(pdcch_t *q, regs_t *regs, int nof_prb, int nof_ports, int cell_id, lte_cp_t cp);
@ -107,9 +107,9 @@ LIBLTE_API int pdcch_encode(pdcch_t *q, dci_t *dci, cf_t *slot1_symbols[MAX_PORT
*/ */
LIBLTE_API int pdcch_decode(pdcch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL], LIBLTE_API int pdcch_decode(pdcch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL],
dci_t *dci, int nsubframe, float ebno); dci_t *dci, int nsubframe, float ebno);
LIBLTE_API int pdcch_extract_llr(pdcch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL], float *llr, LIBLTE_API int pdcch_extract_llr(pdcch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL], float *llr,
int nsubframe, float ebno); int nsubframe, float ebno);
LIBLTE_API void pdcch_init_search_si(pdcch_t *q); LIBLTE_API void pdcch_init_search_si(pdcch_t *q);
LIBLTE_API void pdcch_set_search_si(pdcch_t *q); LIBLTE_API void pdcch_set_search_si(pdcch_t *q);

@ -40,52 +40,52 @@
typedef _Complex float cf_t; typedef _Complex float cf_t;
#define PHICH_NORM_NSEQUENCES 8 #define PHICH_NORM_NSEQUENCES 8
#define PHICH_EXT_NSEQUENCES 4 #define PHICH_EXT_NSEQUENCES 4
#define PHICH_MAX_SEQUENCES PHICH_NORM_NSEQUENCES #define PHICH_MAX_SEQUENCES PHICH_NORM_NSEQUENCES
#define PHICH_NBITS 3 #define PHICH_NBITS 3
#define PHICH_NORM_MSYMB PHICH_NBITS * 4 #define PHICH_NORM_MSYMB PHICH_NBITS * 4
#define PHICH_EXT_MSYMB PHICH_NBITS * 2 #define PHICH_EXT_MSYMB PHICH_NBITS * 2
#define PHICH_MAX_NSYMB PHICH_NORM_MSYMB #define PHICH_MAX_NSYMB PHICH_NORM_MSYMB
#define PHICH_NORM_C 1 #define PHICH_NORM_C 1
#define PHICH_EXT_C 2 #define PHICH_EXT_C 2
#define PHICH_NORM_NSF 4 #define PHICH_NORM_NSF 4
#define PHICH_EXT_NSF 2 #define PHICH_EXT_NSF 2
/* phich object */ /* phich object */
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
lte_cp_t cp; lte_cp_t cp;
int nof_prb; int nof_prb;
int nof_tx_ports; int nof_tx_ports;
/* handler to REGs resource mapper */ /* handler to REGs resource mapper */
regs_t *regs; regs_t *regs;
/* buffers */ /* buffers */
cf_t ce[MAX_PORTS_CTRL][PHICH_MAX_NSYMB]; cf_t ce[MAX_PORTS_CTRL][PHICH_MAX_NSYMB];
cf_t phich_symbols[MAX_PORTS_CTRL][PHICH_MAX_NSYMB]; cf_t phich_symbols[MAX_PORTS_CTRL][PHICH_MAX_NSYMB];
cf_t phich_x[MAX_PORTS_CTRL][PHICH_MAX_NSYMB]; cf_t phich_x[MAX_PORTS_CTRL][PHICH_MAX_NSYMB];
cf_t phich_d[PHICH_MAX_NSYMB]; cf_t phich_d[PHICH_MAX_NSYMB];
cf_t phich_d0[PHICH_MAX_NSYMB]; cf_t phich_d0[PHICH_MAX_NSYMB];
cf_t phich_z[PHICH_NBITS]; cf_t phich_z[PHICH_NBITS];
/* bit message */ /* bit message */
char data[PHICH_NBITS]; char data[PHICH_NBITS];
/* tx & rx objects */ /* tx & rx objects */
modem_table_t mod; modem_table_t mod;
demod_hard_t demod; demod_hard_t demod;
sequence_t seq_phich[NSUBFRAMES_X_FRAME]; sequence_t seq_phich[NSUBFRAMES_X_FRAME];
}phich_t; }phich_t;
LIBLTE_API int phich_init(phich_t *q, regs_t *regs, int cell_id, int nof_prb, int nof_tx_ports, lte_cp_t cp); LIBLTE_API int phich_init(phich_t *q, regs_t *regs, int cell_id, int nof_prb, int nof_tx_ports, lte_cp_t cp);
LIBLTE_API void phich_free(phich_t *q); LIBLTE_API void phich_free(phich_t *q);
LIBLTE_API int phich_decode(phich_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS_CTRL], LIBLTE_API int phich_decode(phich_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS_CTRL],
int ngroup, int nseq, int nsubframe, char *ack, int *distance); int ngroup, int nseq, int nsubframe, char *ack, int *distance);
LIBLTE_API int phich_encode(phich_t *q, char ack, int ngroup, int nseq, int nsubframe, LIBLTE_API int phich_encode(phich_t *q, char ack, int ngroup, int nseq, int nsubframe,
cf_t *slot_symbols[MAX_PORTS_CTRL]); cf_t *slot_symbols[MAX_PORTS_CTRL]);
LIBLTE_API void phich_reset(phich_t *q, cf_t *slot_symbols[MAX_PORTS_CTRL]); LIBLTE_API void phich_reset(phich_t *q, cf_t *slot_symbols[MAX_PORTS_CTRL]);

@ -38,86 +38,86 @@
*/ */
typedef enum { typedef enum {
MOD_NULL = 0, BPSK = 1, QPSK = 2, QAM16 = 4, QAM64 = 16 MOD_NULL = 0, BPSK = 1, QPSK = 2, QAM16 = 4, QAM64 = 16
} ra_mod_t; } ra_mod_t;
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
ra_mod_t mod; // By default, mod = MOD_NULL and the mcs_idx value is taken by the packing functions ra_mod_t mod; // By default, mod = MOD_NULL and the mcs_idx value is taken by the packing functions
// otherwise mod + tbs values are used to generate the mcs_idx automatically. // otherwise mod + tbs values are used to generate the mcs_idx automatically.
uint8_t tbs_idx; uint8_t tbs_idx;
uint8_t mcs_idx; uint8_t mcs_idx;
int tbs; // If tbs<=0, the tbs_idx value is taken by the packing functions to generate the DCI int tbs; // If tbs<=0, the tbs_idx value is taken by the packing functions to generate the DCI
// message. Otherwise the tbs_idx corresponding to the lower nearest TBS is taken. // message. Otherwise the tbs_idx corresponding to the lower nearest TBS is taken.
}ra_mcs_t; }ra_mcs_t;
typedef enum { typedef enum {
alloc_type0 = 0, alloc_type1 = 1, alloc_type2 = 2 alloc_type0 = 0, alloc_type1 = 1, alloc_type2 = 2
}ra_type_t; }ra_type_t;
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
uint32_t rbg_bitmask; uint32_t rbg_bitmask;
}ra_type0_t; }ra_type0_t;
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
uint32_t vrb_bitmask; uint32_t vrb_bitmask;
uint8_t rbg_subset; uint8_t rbg_subset;
bool shift; bool shift;
}ra_type1_t; }ra_type1_t;
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
uint32_t riv; // if L_crb==0, DCI message packer will take this value directly uint32_t riv; // if L_crb==0, DCI message packer will take this value directly
uint16_t L_crb; uint16_t L_crb;
uint16_t RB_start; uint16_t RB_start;
enum {nprb1a_2 = 0, nprb1a_3 = 1} n_prb1a; enum {nprb1a_2 = 0, nprb1a_3 = 1} n_prb1a;
enum {t2_ng1 = 0, t2_ng2 = 1} n_gap; enum {t2_ng1 = 0, t2_ng2 = 1} n_gap;
enum {t2_loc = 0, t2_dist = 1} mode; enum {t2_loc = 0, t2_dist = 1} mode;
}ra_type2_t; }ra_type2_t;
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
unsigned short rnti; unsigned short rnti;
ra_type_t alloc_type; ra_type_t alloc_type;
union { union {
ra_type0_t type0_alloc; ra_type0_t type0_alloc;
ra_type1_t type1_alloc; ra_type1_t type1_alloc;
ra_type2_t type2_alloc; ra_type2_t type2_alloc;
}; };
ra_mcs_t mcs; ra_mcs_t mcs;
uint8_t harq_process; uint8_t harq_process;
uint8_t rv_idx; uint8_t rv_idx;
bool ndi; bool ndi;
} ra_pdsch_t; } ra_pdsch_t;
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
/* 36.213 Table 8.4-2: hop_half is 0 for < 10 Mhz and 10 for > 10 Mh. /* 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. * hop_quart is 00 for > 10 Mhz and hop_quart_neg is 01 for > 10 Mhz.
*/ */
enum { enum {
hop_disabled = -1, hop_disabled = -1,
hop_quart = 0, hop_quart = 0,
hop_quart_neg = 1, hop_quart_neg = 1,
hop_half = 2, hop_half = 2,
hop_type_2 = 3 hop_type_2 = 3
} freq_hop_fl; } freq_hop_fl;
ra_type2_t type2_alloc; ra_type2_t type2_alloc;
ra_mcs_t mcs; ra_mcs_t mcs;
uint8_t rv_idx; // If set to non-zero, a retransmission is requested with the same modulation uint8_t rv_idx; // If set to non-zero, a retransmission is requested with the same modulation
// than before (Format0 message, see also 8.6.1 in 36.2313). // than before (Format0 message, see also 8.6.1 in 36.2313).
bool ndi; bool ndi;
bool cqi_request; bool cqi_request;
} ra_pusch_t; } ra_pusch_t;
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
uint8_t prb_idx[110]; uint8_t prb_idx[110];
int nof_prb; int nof_prb;
}ra_prb_slot_t; }ra_prb_slot_t;
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
ra_prb_slot_t slot1; ra_prb_slot_t slot1;
ra_prb_slot_t slot2; ra_prb_slot_t slot2;
bool is_dist; bool is_dist;
}ra_prb_t; }ra_prb_t;

@ -33,49 +33,49 @@
#include "lte/config.h" #include "lte/config.h"
#include "lte/common/base.h" #include "lte/common/base.h"
#define REGS_PHICH_NSYM 12 #define REGS_PHICH_NSYM 12
#define REGS_PHICH_REGS_X_GROUP 3 #define REGS_PHICH_REGS_X_GROUP 3
#define REGS_PCFICH_NSYM 16 #define REGS_PCFICH_NSYM 16
#define REGS_PCFICH_NREGS 4 #define REGS_PCFICH_NREGS 4
#define REGS_RE_X_REG 4 #define REGS_RE_X_REG 4
typedef _Complex float cf_t; typedef _Complex float cf_t;
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
int k[4]; int k[4];
int k0; int k0;
int l; int l;
bool assigned; bool assigned;
}regs_reg_t; }regs_reg_t;
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
int nof_regs; int nof_regs;
regs_reg_t **regs; regs_reg_t **regs;
}regs_ch_t; }regs_ch_t;
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
int cell_id; int cell_id;
int nof_prb; int nof_prb;
int max_ctrl_symbols; int max_ctrl_symbols;
int cfi; int cfi;
int ngroups_phich; int ngroups_phich;
int nof_ports; int nof_ports;
lte_cp_t cp; lte_cp_t cp;
phich_resources_t phich_res; phich_resources_t phich_res;
phich_length_t phich_len; phich_length_t phich_len;
regs_ch_t pcfich; regs_ch_t pcfich;
regs_ch_t *phich; // there are several phich regs_ch_t *phich; // there are several phich
regs_ch_t pdcch[3]; /* PDCCH indexing, permutation and interleaving is computed for regs_ch_t pdcch[3]; /* PDCCH indexing, permutation and interleaving is computed for
the three possible CFI value */ the three possible CFI value */
int nof_regs; int nof_regs;
regs_reg_t *regs; regs_reg_t *regs;
}regs_t; }regs_t;
LIBLTE_API int regs_init(regs_t *h, int cell_id, int nof_prb, int nof_ports, LIBLTE_API int regs_init(regs_t *h, int cell_id, int nof_prb, int nof_ports,
phich_resources_t phich_res, phich_length_t phich_len, lte_cp_t cp); phich_resources_t phich_res, phich_length_t phich_len, lte_cp_t cp);
LIBLTE_API void regs_free(regs_t *h); LIBLTE_API void regs_free(regs_t *h);
LIBLTE_API int regs_set_cfi(regs_t *h, int nof_ctrl_symbols); LIBLTE_API int regs_set_cfi(regs_t *h, int nof_ctrl_symbols);

@ -49,35 +49,35 @@ LIBLTE_API void scrambling_c_offset(sequence_t *s, cf_t *data, int offset, int l
/* High-level API */ /* High-level API */
/* channel integer values */ /* channel integer values */
#define SCRAMBLING_PDSCH 0 /* also PUSCH */ #define SCRAMBLING_PDSCH 0 /* also PUSCH */
#define SCRAMBLING_PCFICH 1 #define SCRAMBLING_PCFICH 1
#define SCRAMBLING_PDCCH 2 #define SCRAMBLING_PDCCH 2
#define SCRAMBLING_PBCH 3 #define SCRAMBLING_PBCH 3
#define SCRAMBLING_PMCH 4 #define SCRAMBLING_PMCH 4
#define SCRAMBLING_PUCCH 5 #define SCRAMBLING_PUCCH 5
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
sequence_t seq[NSUBFRAMES_X_FRAME]; sequence_t seq[NSUBFRAMES_X_FRAME];
}scrambling_t; }scrambling_t;
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
scrambling_t obj; scrambling_t obj;
struct scrambling_init { struct scrambling_init {
int hard; int hard;
int q; int q;
int cell_id; int cell_id;
int nrnti; int nrnti;
int nMBSFN; int nMBSFN;
int channel; int channel;
int nof_symbols; // 7 normal 6 extended int nof_symbols; // 7 normal 6 extended
} init; } init;
void *input; // input type may be char or float depending on hard void *input; // input type may be char or float depending on hard
int in_len; int in_len;
struct scrambling_ctrl_in { struct scrambling_ctrl_in {
int subframe; int subframe;
} ctrl_in; } ctrl_in;
void *output; void *output;
int out_len; int out_len;
}scrambling_hl; }scrambling_hl;
#endif // SCRAMBLING_ #endif // SCRAMBLING_

@ -41,11 +41,11 @@ typedef _Complex float cf_t;
#define CFO_CEXPTAB_SIZE 4096 #define CFO_CEXPTAB_SIZE 4096
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
float last_freq; float last_freq;
float tol; float tol;
int nsamples; int nsamples;
cexptab_t tab; cexptab_t tab;
cf_t *cur_cexp; cf_t *cur_cexp;
}cfo_t; }cfo_t;
LIBLTE_API int cfo_init(cfo_t *h, int nsamples); LIBLTE_API int cfo_init(cfo_t *h, int nsamples);

@ -40,11 +40,11 @@ typedef _Complex float cf_t; /* this is only a shortcut */
#define CONVOLUTION_FFT #define CONVOLUTION_FFT
#define DEFAULT_CORRELATION_TH 10000 #define DEFAULT_CORRELATION_TH 10000
#define DEFAULT_NOSYNC_TIMEOUT 5 #define DEFAULT_NOSYNC_TIMEOUT 5
#define PSS_LEN_FREQ 129 // FFT-based convolution removes 1 leaving it in 128 #define PSS_LEN_FREQ 129 // FFT-based convolution removes 1 leaving it in 128
#define PSS_LEN 62 #define PSS_LEN 62
#define PSS_RE 6*12 #define PSS_RE 6*12
@ -64,25 +64,25 @@ typedef _Complex float cf_t; /* this is only a shortcut */
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
#ifdef CONVOLUTION_FFT #ifdef CONVOLUTION_FFT
conv_fft_cc_t conv_fft; conv_fft_cc_t conv_fft;
#endif #endif
int frame_size; int frame_size;
int N_id_2; int N_id_2;
float current_cfo; float current_cfo;
bool cfo_auto; // default true bool cfo_auto; // default true
int nof_nosync_frames; int nof_nosync_frames;
int nosync_timeout_frames; // default 5 int nosync_timeout_frames; // default 5
float correlation_threshold; // default 10000 float correlation_threshold; // default 10000
int frame_start_idx; int frame_start_idx;
int fb_wp; int fb_wp;
cf_t *pss_signal_freq; cf_t *pss_signal_freq;
cf_t *tmp_input; cf_t *tmp_input;
float *conv_abs; float *conv_abs;
cf_t *frame_buffer; cf_t *frame_buffer;
cf_t *conv_output; cf_t *conv_output;
cf_t *tmp_nco; cf_t *tmp_nco;
}pss_synch_t; }pss_synch_t;
typedef enum { PSS_TX, PSS_RX } pss_direction_t; typedef enum { PSS_TX, PSS_RX } pss_direction_t;
@ -111,24 +111,24 @@ LIBLTE_API int pss_synch_get_frame_start_idx(pss_synch_t *q);
/* High-level API */ /* High-level API */
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
pss_synch_t obj; pss_synch_t obj;
struct pss_synch_init { struct pss_synch_init {
int frame_size; // if 0, 2048 int frame_size; // if 0, 2048
int unsync_nof_pkts; int unsync_nof_pkts;
int N_id_2; int N_id_2;
int do_cfo; int do_cfo;
} init; } init;
cf_t *input; cf_t *input;
int in_len; int in_len;
struct pss_synch_ctrl_in { struct pss_synch_ctrl_in {
int correlation_threshold; int correlation_threshold;
float manual_cfo; float manual_cfo;
} ctrl_in; } ctrl_in;
cf_t *output; cf_t *output;
int out_len; int out_len;
}pss_synch_hl; }pss_synch_hl;
#define DEFAULT_FRAME_SIZE 2048 #define DEFAULT_FRAME_SIZE 2048
LIBLTE_API int pss_synch_initialize(pss_synch_hl* h); LIBLTE_API int pss_synch_initialize(pss_synch_hl* h);
LIBLTE_API int pss_synch_work(pss_synch_hl* hl); LIBLTE_API int pss_synch_work(pss_synch_hl* hl);

@ -43,40 +43,40 @@ typedef _Complex float cf_t; /* this is only a shortcut */
* symbol_sz is the OFDM symbol size (including CP), e.g. 137 for the 1.9 MHz * symbol_sz is the OFDM symbol size (including CP), e.g. 137 for the 1.9 MHz
*/ */
#define SSS_SYMBOL_ST(subframe_sz, symbol_sz) (subframe_sz/2-2*symbol_sz) #define SSS_SYMBOL_ST(subframe_sz, symbol_sz) (subframe_sz/2-2*symbol_sz)
#define SSS_POS_SYMBOL 33 #define SSS_POS_SYMBOL 33
#define SSS_DFT_LEN 128 #define SSS_DFT_LEN 128
#define N_SSS 31 #define N_SSS 31
#define SSS_LEN 2*N_SSS #define SSS_LEN 2*N_SSS
struct sss_tables{ struct sss_tables{
int z1[N_SSS][N_SSS]; int z1[N_SSS][N_SSS];
int c[2][N_SSS]; int c[2][N_SSS];
int s[N_SSS][N_SSS]; int s[N_SSS][N_SSS];
int N_id_2; int N_id_2;
}; };
/* Allocate 32 complex to make it multiple of 32-byte AVX instructions alignment requirement. /* Allocate 32 complex to make it multiple of 32-byte AVX instructions alignment requirement.
* Should use vect_malloc() to make it platform agnostic. * Should use vect_malloc() to make it platform agnostic.
*/ */
struct fc_tables{ struct fc_tables{
cf_t z1[N_SSS+1][N_SSS+1]; cf_t z1[N_SSS+1][N_SSS+1];
cf_t c[2][N_SSS+1]; cf_t c[2][N_SSS+1];
cf_t s[N_SSS+1][N_SSS+1]; cf_t s[N_SSS+1][N_SSS+1];
}; };
/* Low-level API */ /* Low-level API */
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
dft_plan_t dftp_input; dft_plan_t dftp_input;
float corr_peak_threshold; float corr_peak_threshold;
int symbol_sz; int symbol_sz;
int subframe_sz; int subframe_sz;
int N_id_1_table[30][30]; int N_id_1_table[30][30];
struct fc_tables fc_tables; struct fc_tables fc_tables;
}sss_synch_t; }sss_synch_t;
@ -90,7 +90,7 @@ LIBLTE_API void sss_put_slot(float *sss, cf_t *symbol, int nof_prb, lte_cp_t cp)
LIBLTE_API int sss_synch_set_N_id_2(sss_synch_t *q, int N_id_2); LIBLTE_API int sss_synch_set_N_id_2(sss_synch_t *q, int N_id_2);
LIBLTE_API void sss_synch_m0m1(sss_synch_t *q, cf_t *input, int *m0, float *m0_value, LIBLTE_API void sss_synch_m0m1(sss_synch_t *q, cf_t *input, int *m0, float *m0_value,
int *m1, float *m1_value); int *m1, float *m1_value);
LIBLTE_API int sss_synch_subframe(int m0, int m1); LIBLTE_API int sss_synch_subframe(int m0, int m1);
LIBLTE_API int sss_synch_N_id_1(sss_synch_t *q, int m0, int m1); LIBLTE_API int sss_synch_N_id_1(sss_synch_t *q, int m0, int m1);
@ -103,24 +103,24 @@ LIBLTE_API void sss_synch_set_subframe_sz(sss_synch_t *q, int subframe_sz);
/* High-level API */ /* High-level API */
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
sss_synch_t obj; sss_synch_t obj;
struct sss_synch_init { struct sss_synch_init {
int N_id_2; int N_id_2;
} init; } init;
cf_t *input; cf_t *input;
int in_len; int in_len;
struct sss_synch_ctrl_in { struct sss_synch_ctrl_in {
int symbol_sz; int symbol_sz;
int subframe_sz; int subframe_sz;
int correlation_threshold; int correlation_threshold;
} ctrl_in; } ctrl_in;
struct sss_synch_ctrl_out { struct sss_synch_ctrl_out {
int subframe_idx; int subframe_idx;
int N_id_1; int N_id_1;
} ctrl_out; } ctrl_out;
}sss_synch_hl; }sss_synch_hl;
#define DEFAULT_FRAME_SIZE 2048 #define DEFAULT_FRAME_SIZE 2048
LIBLTE_API int sss_synch_initialize(sss_synch_hl* h); LIBLTE_API int sss_synch_initialize(sss_synch_hl* h);
LIBLTE_API int sss_synch_work(sss_synch_hl* hl); LIBLTE_API int sss_synch_work(sss_synch_hl* hl);

@ -50,19 +50,19 @@
enum sync_pss_det { ABSOLUTE, PEAK_MEAN}; enum sync_pss_det { ABSOLUTE, PEAK_MEAN};
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
pss_synch_t pss[3]; // One for each N_id_2 pss_synch_t pss[3]; // One for each N_id_2
sss_synch_t sss[3]; // One for each N_id_2 sss_synch_t sss[3]; // One for each N_id_2
enum sync_pss_det pss_mode; enum sync_pss_det pss_mode;
float threshold; float threshold;
float peak_to_avg; float peak_to_avg;
int force_N_id_2; int force_N_id_2;
int N_id_2; int N_id_2;
int N_id_1; int N_id_1;
int slot_id; int slot_id;
float cfo; float cfo;
lte_cp_t cp; lte_cp_t cp;
bool detect_cp; bool detect_cp;
bool sss_en; bool sss_en;
}sync_t; }sync_t;

@ -35,8 +35,8 @@
typedef _Complex float cf_t; typedef _Complex float cf_t;
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
int size; int size;
cf_t *tab; cf_t *tab;
}cexptab_t; }cexptab_t;
LIBLTE_API int cexptab_init(cexptab_t *nco, int size); LIBLTE_API int cexptab_init(cexptab_t *nco, int size);

@ -33,16 +33,16 @@
#include "lte/utils/dft.h" #include "lte/utils/dft.h"
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
_Complex float *input_fft; _Complex float *input_fft;
_Complex float *filter_fft; _Complex float *filter_fft;
_Complex float *output_fft; _Complex float *output_fft;
_Complex float *output_fft2; _Complex float *output_fft2;
int input_len; int input_len;
int filter_len; int filter_len;
int output_len; int output_len;
dft_plan_t input_plan; dft_plan_t input_plan;
dft_plan_t filter_plan; dft_plan_t filter_plan;
dft_plan_t output_plan; dft_plan_t output_plan;
}conv_fft_cc_t; }conv_fft_cc_t;
LIBLTE_API int conv_fft_cc_init(conv_fft_cc_t *state, int input_len, int filter_len); LIBLTE_API int conv_fft_cc_init(conv_fft_cc_t *state, int input_len, int filter_len);

@ -31,9 +31,9 @@
#include <stdio.h> #include <stdio.h>
#include "lte/config.h" #include "lte/config.h"
#define VERBOSE_DEBUG 2 #define VERBOSE_DEBUG 2
#define VERBOSE_INFO 1 #define VERBOSE_INFO 1
#define VERBOSE_NONE 0 #define VERBOSE_NONE 0
#include <sys/time.h> #include <sys/time.h>
LIBLTE_API void get_time_interval(struct timeval * tdata); LIBLTE_API void get_time_interval(struct timeval * tdata);
@ -50,10 +50,10 @@ LIBLTE_API extern int verbose;
#define PRINT_NONE verbose=VERBOSE_NONE #define PRINT_NONE verbose=VERBOSE_NONE
#define DEBUG(_fmt, ...) if (verbose >= VERBOSE_DEBUG) \ #define DEBUG(_fmt, ...) if (verbose >= VERBOSE_DEBUG) \
fprintf(stdout, "[DEBUG]: " _fmt, __VA_ARGS__) fprintf(stdout, "[DEBUG]: " _fmt, __VA_ARGS__)
#define INFO(_fmt, ...) if (verbose >= VERBOSE_INFO) \ #define INFO(_fmt, ...) if (verbose >= VERBOSE_INFO) \
fprintf(stdout, "[INFO]: " _fmt, __VA_ARGS__) fprintf(stdout, "[INFO]: " _fmt, __VA_ARGS__)
#else // DEBUG_DISABLED #else // DEBUG_DISABLED

@ -41,30 +41,30 @@
typedef enum { typedef enum {
COMPLEX_2_COMPLEX, REAL_2_REAL, COMPLEX_2_REAL COMPLEX_2_COMPLEX, REAL_2_REAL, COMPLEX_2_REAL
}dft_mode_t; }dft_mode_t;
typedef enum { typedef enum {
FORWARD, BACKWARD FORWARD, BACKWARD
}dft_dir_t; }dft_dir_t;
#define DFT_MIRROR_PRE 1 #define DFT_MIRROR_PRE 1
#define DFT_PSD 2 #define DFT_PSD 2
#define DFT_OUT_DB 4 #define DFT_OUT_DB 4
#define DFT_MIRROR_POS 8 #define DFT_MIRROR_POS 8
#define DFT_NORMALIZE 16 #define DFT_NORMALIZE 16
#define DFT_DC_OFFSET 32 #define DFT_DC_OFFSET 32
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
int size; int size;
int sign; int sign;
void *in; void *in;
void *out; void *out;
void *p; void *p;
int options; int options;
dft_dir_t dir; dft_dir_t dir;
dft_mode_t mode; dft_mode_t mode;
}dft_plan_t; }dft_plan_t;
typedef _Complex float dft_c_t; typedef _Complex float dft_c_t;

@ -31,10 +31,10 @@
#include "lte/config.h" #include "lte/config.h"
LIBLTE_API void mux(void **input, void *output, int *input_lengths, int *input_padding_pre, int nof_inputs, LIBLTE_API void mux(void **input, void *output, int *input_lengths, int *input_padding_pre, int nof_inputs,
int sample_sz); int sample_sz);
LIBLTE_API void demux(void *input, void **output, int *output_lengths, LIBLTE_API void demux(void *input, void **output, int *output_lengths,
int *output_padding_pre, int *output_padding_post, int nof_outputs, int *output_padding_pre, int *output_padding_post, int nof_outputs,
int sample_sz); int sample_sz);
#endif // MUX_ #endif // MUX_

@ -41,203 +41,203 @@
#define SF_SZ(q) (2 * SLOT_SZ(q)) #define SF_SZ(q) (2 * SLOT_SZ(q))
void chest_fprint(chest_t *q, FILE *stream, int nslot, int port_id) { void chest_fprint(chest_t *q, FILE *stream, int nslot, int port_id) {
chest_ref_fprint(q, stream, nslot, port_id); chest_ref_fprint(q, stream, nslot, port_id);
chest_recvsig_fprint(q, stream, nslot, port_id); chest_recvsig_fprint(q, stream, nslot, port_id);
chest_ce_fprint(q, stream, nslot, port_id); chest_ce_fprint(q, stream, nslot, port_id);
} }
void chest_ref_fprint(chest_t *q, FILE *stream, int nslot, int port_id) { void chest_ref_fprint(chest_t *q, FILE *stream, int nslot, int port_id) {
int i; int i;
fprintf(stream, "refs%d=[",port_id); fprintf(stream, "refs%d=[",port_id);
for (i=0;i<q->refsignal[port_id][nslot].nof_refs;i++) { for (i=0;i<q->refsignal[port_id][nslot].nof_refs;i++) {
fprintf(stream, "%3.3f%+3.3fi, ", __real__ q->refsignal[port_id][nslot].refs[i].simbol, fprintf(stream, "%3.3f%+3.3fi, ", __real__ q->refsignal[port_id][nslot].refs[i].simbol,
__imag__ q->refsignal[port_id][nslot].refs[i].simbol); __imag__ q->refsignal[port_id][nslot].refs[i].simbol);
} }
fprintf(stream, "];\n"); fprintf(stream, "];\n");
} }
void chest_recvsig_fprint(chest_t *q, FILE *stream, int nslot, int port_id) { void chest_recvsig_fprint(chest_t *q, FILE *stream, int nslot, int port_id) {
int i; int i;
fprintf(stream, "recvsig%d=[",port_id); fprintf(stream, "recvsig%d=[",port_id);
for (i=0;i<q->refsignal[port_id][nslot].nof_refs;i++) { for (i=0;i<q->refsignal[port_id][nslot].nof_refs;i++) {
fprintf(stream, "%3.3f%+3.3fi, ", __real__ q->refsignal[port_id][nslot].refs[i].recv_simbol, fprintf(stream, "%3.3f%+3.3fi, ", __real__ q->refsignal[port_id][nslot].refs[i].recv_simbol,
__imag__ q->refsignal[port_id][nslot].refs[i].recv_simbol); __imag__ q->refsignal[port_id][nslot].refs[i].recv_simbol);
} }
fprintf(stream, "];\n"); fprintf(stream, "];\n");
} }
void chest_ce_fprint(chest_t *q, FILE *stream, int nslot, int port_id) { void chest_ce_fprint(chest_t *q, FILE *stream, int nslot, int port_id) {
int i; int i;
fprintf(stream, "mag%d=[",port_id); fprintf(stream, "mag%d=[",port_id);
for (i=0;i<q->refsignal[port_id][nslot].nof_refs;i++) { for (i=0;i<q->refsignal[port_id][nslot].nof_refs;i++) {
fprintf(stream, "%3.3f, ", cabsf(q->refsignal[port_id][nslot].ch_est[i])); fprintf(stream, "%3.3f, ", cabsf(q->refsignal[port_id][nslot].ch_est[i]));
} }
fprintf(stream, "];\nphase%d=[",port_id); fprintf(stream, "];\nphase%d=[",port_id);
for (i=0;i<q->refsignal[port_id][nslot].nof_refs;i++) { for (i=0;i<q->refsignal[port_id][nslot].nof_refs;i++) {
fprintf(stream, "%3.3f, ", atan2f(__imag__ q->refsignal[port_id][nslot].ch_est[i], fprintf(stream, "%3.3f, ", atan2f(__imag__ q->refsignal[port_id][nslot].ch_est[i],
__real__ q->refsignal[port_id][nslot].ch_est[i])); __real__ q->refsignal[port_id][nslot].ch_est[i]));
} }
fprintf(stream, "];\n"); fprintf(stream, "];\n");
} }
void chest_ce_ref(chest_t *q, cf_t *input, int nslot, int port_id, int nref) { void chest_ce_ref(chest_t *q, cf_t *input, int nslot, int port_id, int nref) {
int fidx, tidx; int fidx, tidx;
cf_t known_ref, channel_ref; cf_t known_ref, channel_ref;
fidx = q->refsignal[port_id][nslot].refs[nref].freq_idx; // reference frequency index fidx = q->refsignal[port_id][nslot].refs[nref].freq_idx; // reference frequency index
tidx = q->refsignal[port_id][nslot].refs[nref].time_idx; // reference time index tidx = q->refsignal[port_id][nslot].refs[nref].time_idx; // reference time index
known_ref = q->refsignal[port_id][nslot].refs[nref].simbol; known_ref = q->refsignal[port_id][nslot].refs[nref].simbol;
channel_ref = input[SAMPLE_IDX(q->nof_prb, tidx, fidx)]; channel_ref = input[SAMPLE_IDX(q->nof_prb, tidx, fidx)];
q->refsignal[port_id][nslot].refs[nref].recv_simbol = channel_ref; q->refsignal[port_id][nslot].refs[nref].recv_simbol = channel_ref;
DEBUG("Reference %2d pos (%2d,%2d)=%3d %.2f dB %.2f/%.2f=%.2f\n", nref, tidx, fidx, SAMPLE_IDX(q->nof_prb, tidx, fidx), DEBUG("Reference %2d pos (%2d,%2d)=%3d %.2f dB %.2f/%.2f=%.2f\n", nref, tidx, fidx, SAMPLE_IDX(q->nof_prb, tidx, fidx),
10*log10f(cabsf(channel_ref/known_ref)), 10*log10f(cabsf(channel_ref/known_ref)),
cargf(channel_ref)/M_PI,cargf(known_ref)/M_PI,cargf(channel_ref/known_ref)/M_PI); cargf(channel_ref)/M_PI,cargf(known_ref)/M_PI,cargf(channel_ref/known_ref)/M_PI);
/* FIXME: compare with threshold */ /* FIXME: compare with threshold */
if (channel_ref != 0) { if (channel_ref != 0) {
q->refsignal[port_id][nslot].ch_est[nref] = channel_ref/known_ref; q->refsignal[port_id][nslot].ch_est[nref] = channel_ref/known_ref;
} else { } else {
q->refsignal[port_id][nslot].ch_est[nref] = 0; q->refsignal[port_id][nslot].ch_est[nref] = 0;
} }
} }
/* Computes channel estimates for each reference in a slot and port. /* Computes channel estimates for each reference in a slot and port.
* Saves the nof_prb * 12 * nof_symbols channel estimates in the array ce * Saves the nof_prb * 12 * nof_symbols channel estimates in the array ce
*/ */
void chest_ce_slot_port(chest_t *q, cf_t *input, cf_t *ce, int nslot, int port_id) { void chest_ce_slot_port(chest_t *q, cf_t *input, cf_t *ce, int nslot, int port_id) {
int i, j; int i, j;
cf_t x[2], y[MAX_NSYMB]; cf_t x[2], y[MAX_NSYMB];
assert(nslot >= 0 && nslot < NSLOTS_X_FRAME); assert(nslot >= 0 && nslot < NSLOTS_X_FRAME);
assert(port_id >= 0 && port_id < q->nof_ports); assert(port_id >= 0 && port_id < q->nof_ports);
assert(q->refsignal[port_id][nslot].nsymbols <= 2); assert(q->refsignal[port_id][nslot].nsymbols <= 2);
refsignal_t *r = &q->refsignal[port_id][nslot]; refsignal_t *r = &q->refsignal[port_id][nslot];
INFO("Estimating channel slot=%d port=%d using %d reference signals\n", INFO("Estimating channel slot=%d port=%d using %d reference signals\n",
nslot, port_id, r->nof_refs); nslot, port_id, r->nof_refs);
for (i=0;i<r->nof_refs;i++) { for (i=0;i<r->nof_refs;i++) {
chest_ce_ref(q, input, nslot, port_id, i); chest_ce_ref(q, input, nslot, port_id, i);
} }
/* interpolate the symbols with references /* interpolate the symbols with references
* in the freq domain */ * in the freq domain */
for (i=0;i<r->nsymbols;i++) { for (i=0;i<r->nsymbols;i++) {
interp_linear_offset(&r->ch_est[i * r->nof_refs/2], interp_linear_offset(&r->ch_est[i * r->nof_refs/2],
&ce[r->symbols_ref[i] * q->nof_prb * RE_X_RB], RE_X_RB/2, &ce[r->symbols_ref[i] * q->nof_prb * RE_X_RB], RE_X_RB/2,
r->nof_refs/2, r->voffset, RE_X_RB/2-r->voffset); r->nof_refs/2, r->voffset, RE_X_RB/2-r->voffset);
} }
/* now interpolate in the time domain */ /* now interpolate in the time domain */
for (i=0;i<q->nof_prb * RE_X_RB; i++) { for (i=0;i<q->nof_prb * RE_X_RB; i++) {
if (r->nsymbols > 1) { if (r->nsymbols > 1) {
for (j=0;j<r->nsymbols;j++) { for (j=0;j<r->nsymbols;j++) {
x[j] = ce[r->symbols_ref[j] * q->nof_prb * RE_X_RB + i]; x[j] = ce[r->symbols_ref[j] * q->nof_prb * RE_X_RB + i];
} }
interp_linear_offset(x, y, r->symbols_ref[1]-r->symbols_ref[0], interp_linear_offset(x, y, r->symbols_ref[1]-r->symbols_ref[0],
2, r->symbols_ref[0], 3); 2, r->symbols_ref[0], 3);
} else { } else {
for (j=0;j<MAX_NSYMB;j++) { for (j=0;j<MAX_NSYMB;j++) {
y[j] = ce[r->symbols_ref[0] * q->nof_prb * RE_X_RB + i]; y[j] = ce[r->symbols_ref[0] * q->nof_prb * RE_X_RB + i];
} }
} }
for (j=0;j<q->nof_symbols;j++) { for (j=0;j<q->nof_symbols;j++) {
ce[j * q->nof_prb * RE_X_RB + i] = y[j]; ce[j * q->nof_prb * RE_X_RB + i] = y[j];
} }
} }
} }
/* Computes channel estimates for each reference in a slot. /* Computes channel estimates for each reference in a slot.
* Saves the result for the p-th port to the pointer ce[p] * Saves the result for the p-th port to the pointer ce[p]
*/ */
void chest_ce_slot(chest_t *q, cf_t *input, cf_t **ce, int nslot) { void chest_ce_slot(chest_t *q, cf_t *input, cf_t **ce, int nslot) {
int p; int p;
for (p=0;p<q->nof_ports;p++) { for (p=0;p<q->nof_ports;p++) {
chest_ce_slot_port(q, input, ce[p], nslot, p); chest_ce_slot_port(q, input, ce[p], nslot, p);
} }
} }
int chest_init(chest_t *q, chest_interp_t interp, lte_cp_t cp, int nof_prb, int nof_ports) { int chest_init(chest_t *q, chest_interp_t interp, lte_cp_t cp, int nof_prb, int nof_ports) {
if (nof_ports > MAX_PORTS) { if (nof_ports > MAX_PORTS) {
fprintf(stderr, "Error: Maximum ports %d\n", MAX_PORTS); fprintf(stderr, "Error: Maximum ports %d\n", MAX_PORTS);
return -1; return -1;
} }
bzero(q, sizeof(chest_t)); bzero(q, sizeof(chest_t));
q->nof_ports = nof_ports; q->nof_ports = nof_ports;
q->nof_symbols = CP_NSYMB(cp); q->nof_symbols = CP_NSYMB(cp);
q->cp = cp; q->cp = cp;
q->nof_prb = nof_prb; q->nof_prb = nof_prb;
switch(interp) { switch(interp) {
case LINEAR: case LINEAR:
q->interp = interp_linear_offset; q->interp = interp_linear_offset;
} }
INFO("Initializing channel estimator size %dx%d, nof_ports=%d\n", INFO("Initializing channel estimator size %dx%d, nof_ports=%d\n",
q->nof_symbols, nof_prb, nof_ports); q->nof_symbols, nof_prb, nof_ports);
return 0; return 0;
} }
int chest_ref_LTEDL_slot_port(chest_t *q, int port, int nslot, int cell_id) { int chest_ref_LTEDL_slot_port(chest_t *q, int port, int nslot, int cell_id) {
if (port < 0 || port > q->nof_ports) { if (port < 0 || port > q->nof_ports) {
return -1; return -1;
} }
if (nslot < 0 || nslot > NSLOTS_X_FRAME) { if (nslot < 0 || nslot > NSLOTS_X_FRAME) {
return -1; return -1;
} }
if (refsignal_init_LTEDL(&q->refsignal[port][nslot], port, nslot, cell_id, q->cp, q->nof_prb)) { if (refsignal_init_LTEDL(&q->refsignal[port][nslot], port, nslot, cell_id, q->cp, q->nof_prb)) {
fprintf(stderr, "Error initiating CRS port=%d, slot=%d\n", port, nslot); fprintf(stderr, "Error initiating CRS port=%d, slot=%d\n", port, nslot);
return -1; return -1;
} }
return 0; return 0;
} }
int chest_ref_LTEDL_slot(chest_t *q, int nslot, int cell_id) { int chest_ref_LTEDL_slot(chest_t *q, int nslot, int cell_id) {
int p; int p;
for (p=0;p<q->nof_ports;p++) { for (p=0;p<q->nof_ports;p++) {
if (chest_ref_LTEDL_slot_port(q, p, nslot, cell_id)) { if (chest_ref_LTEDL_slot_port(q, p, nslot, cell_id)) {
return -1; return -1;
} }
} }
return 0; return 0;
} }
int chest_ref_LTEDL(chest_t *q, int cell_id) { int chest_ref_LTEDL(chest_t *q, int cell_id) {
int n; int n;
for (n=0;n<NSLOTS_X_FRAME;n++) { for (n=0;n<NSLOTS_X_FRAME;n++) {
if (chest_ref_LTEDL_slot(q, n, cell_id)) { if (chest_ref_LTEDL_slot(q, n, cell_id)) {
return -1; return -1;
} }
} }
return 0; return 0;
} }
void chest_free(chest_t *q) { void chest_free(chest_t *q) {
int p, n; int p, n;
for (p=0;p<q->nof_ports;p++) { for (p=0;p<q->nof_ports;p++) {
for (n=0;n<NSLOTS_X_FRAME;n++) { for (n=0;n<NSLOTS_X_FRAME;n++) {
refsignal_free(&q->refsignal[p][n]); refsignal_free(&q->refsignal[p][n]);
} }
} }
bzero(q, sizeof(chest_t)); bzero(q, sizeof(chest_t));
} }
/* Fills l[2] with the symbols in the slot nslot that contain references. /* Fills l[2] with the symbols in the slot nslot that contain references.
* returns the number of symbols with references (in the slot) * returns the number of symbols with references (in the slot)
*/ */
int chest_ref_symbols(chest_t *q, int port_id, int nslot, int l[2]) { int chest_ref_symbols(chest_t *q, int port_id, int nslot, int l[2]) {
if (nslot < 0 || nslot > NSLOTS_X_FRAME) { if (nslot < 0 || nslot > NSLOTS_X_FRAME) {
return -1; return -1;
} }
memcpy(l, q->refsignal[port_id][nslot].symbols_ref, sizeof(int) * q->refsignal[port_id][nslot].nsymbols); memcpy(l, q->refsignal[port_id][nslot].symbols_ref, sizeof(int) * q->refsignal[port_id][nslot].nsymbols);
return q->refsignal[port_id][nslot].nsymbols; return q->refsignal[port_id][nslot].nsymbols;
} }
@ -245,50 +245,50 @@ int chest_ref_symbols(chest_t *q, int port_id, int nslot, int l[2]) {
*/ */
int chest_initialize(chest_hl* h) { int chest_initialize(chest_hl* h) {
if (!h->init.nof_symbols) { if (!h->init.nof_symbols) {
h->init.nof_symbols = CPNORM_NSYMB; // Normal CP h->init.nof_symbols = CPNORM_NSYMB; // Normal CP
} }
if (!h->init.nof_prb) { if (!h->init.nof_prb) {
h->init.nof_prb = 6; h->init.nof_prb = 6;
} }
if (chest_init(&h->obj, LINEAR, (h->init.nof_symbols==CPNORM_NSYMB)?CPNORM:CPEXT, if (chest_init(&h->obj, LINEAR, (h->init.nof_symbols==CPNORM_NSYMB)?CPNORM:CPEXT,
h->init.nof_prb, h->init.nof_ports)) { h->init.nof_prb, h->init.nof_ports)) {
fprintf(stderr, "Error initializing equalizer\n"); fprintf(stderr, "Error initializing equalizer\n");
return -1; return -1;
} }
if (h->init.cell_id != -1) { if (h->init.cell_id != -1) {
if (chest_ref_LTEDL(&h->obj, h->init.cell_id)) { if (chest_ref_LTEDL(&h->obj, h->init.cell_id)) {
fprintf(stderr, "Error initializing reference signal\n"); fprintf(stderr, "Error initializing reference signal\n");
return -1; return -1;
} }
} }
return 0; return 0;
} }
/** This function must be called in an slot basis (0.5ms) for LTE */ /** This function must be called in an slot basis (0.5ms) for LTE */
int chest_work(chest_hl* hl) { int chest_work(chest_hl* hl) {
int i; int i;
chest_t *q = &hl->obj; chest_t *q = &hl->obj;
if (hl->init.cell_id != hl->ctrl_in.cell_id) { if (hl->init.cell_id != hl->ctrl_in.cell_id) {
if (chest_ref_LTEDL(q, hl->init.cell_id)) { if (chest_ref_LTEDL(q, hl->init.cell_id)) {
fprintf(stderr, "Error initializing reference signal\n"); fprintf(stderr, "Error initializing reference signal\n");
return -1; return -1;
} }
} }
for (i=0;i<hl->init.nof_ports;i++) { for (i=0;i<hl->init.nof_ports;i++) {
chest_ce_slot_port(q, hl->input, hl->output[i], 1, 0); chest_ce_slot_port(q, hl->input, hl->output[i], 1, 0);
hl->out_len[i] = hl->in_len; hl->out_len[i] = hl->in_len;
} }
return 0; return 0;
} }
int chest_stop(chest_hl* hl) { int chest_stop(chest_hl* hl) {
chest_free(&hl->obj); chest_free(&hl->obj);
return 0; return 0;
} }

@ -41,150 +41,150 @@
#define idx(x, y) (l*nof_refs_x_symbol+i) #define idx(x, y) (l*nof_refs_x_symbol+i)
int refsignal_v(int port_id, int ns, int symbol_id) { int refsignal_v(int port_id, int ns, int symbol_id) {
int v=-1; int v=-1;
switch(port_id) { switch(port_id) {
case 0: case 0:
if (symbol_id == 0) { if (symbol_id == 0) {
v=0; v=0;
} else { } else {
v=3; v=3;
} }
break; break;
case 1: case 1:
if (symbol_id == 0) { if (symbol_id == 0) {
v=3; v=3;
} else { } else {
v=0; v=0;
} }
break; break;
case 2: case 2:
v=3*(ns%2); v=3*(ns%2);
break; break;
case 3: case 3:
v=3+3*(ns%2); v=3+3*(ns%2);
break; break;
} }
return v; return v;
} }
int refsignal_k(int m, int v, int cell_id) { int refsignal_k(int m, int v, int cell_id) {
return 6*m+((v+(cell_id%6))%6); return 6*m+((v+(cell_id%6))%6);
} }
void refsignal_put(refsignal_t *q, cf_t *slot_symbols) { void refsignal_put(refsignal_t *q, cf_t *slot_symbols) {
int i; int i;
int fidx, tidx; int fidx, tidx;
for (i=0;i<q->nof_refs;i++) { for (i=0;i<q->nof_refs;i++) {
fidx = q->refs[i].freq_idx; // reference frequency index fidx = q->refs[i].freq_idx; // reference frequency index
tidx = q->refs[i].time_idx; // reference time index tidx = q->refs[i].time_idx; // reference time index
slot_symbols[SAMPLE_IDX(q->nof_prb, tidx, fidx)] = q->refs[i].simbol; slot_symbols[SAMPLE_IDX(q->nof_prb, tidx, fidx)] = q->refs[i].simbol;
} }
} }
/** Initializes refsignal_t object according to 3GPP 36.211 6.10.1 /** Initializes refsignal_t object according to 3GPP 36.211 6.10.1
* *
*/ */
int refsignal_init_LTEDL(refsignal_t *q, int port_id, int nslot, int refsignal_init_LTEDL(refsignal_t *q, int port_id, int nslot,
int cell_id, lte_cp_t cp, int nof_prb) { int cell_id, lte_cp_t cp, int nof_prb) {
unsigned int c_init; unsigned int c_init;
int ns, l, lp[2]; int ns, l, lp[2];
int N_cp; int N_cp;
int i; int i;
int ret = -1; int ret = -1;
sequence_t seq; sequence_t seq;
int v; int v;
int mp; int mp;
int nof_refs_x_symbol, nof_ref_symbols; int nof_refs_x_symbol, nof_ref_symbols;
bzero(q, sizeof(refsignal_t)); bzero(q, sizeof(refsignal_t));
bzero(&seq, sizeof(sequence_t)); bzero(&seq, sizeof(sequence_t));
if (CP_ISNORM(cp)) { if (CP_ISNORM(cp)) {
N_cp = 1; N_cp = 1;
} else { } else {
N_cp = 0; N_cp = 0;
} }
if (port_id < 0 || port_id > (MAX_PORTS - 1)) { if (port_id < 0 || port_id > (MAX_PORTS - 1)) {
fprintf(stderr, "Invalid port id %d\n", port_id); fprintf(stderr, "Invalid port id %d\n", port_id);
return -1; return -1;
} }
if (port_id < 2) { if (port_id < 2) {
nof_ref_symbols = 2; nof_ref_symbols = 2;
lp[0] = 0; lp[0] = 0;
lp[1] = CP_NSYMB(cp) - 3; lp[1] = CP_NSYMB(cp) - 3;
} else { } else {
nof_ref_symbols = 1; nof_ref_symbols = 1;
lp[0] = 1; lp[0] = 1;
} }
nof_refs_x_symbol = 2 * nof_prb; nof_refs_x_symbol = 2 * nof_prb;
q->nof_refs = nof_refs_x_symbol * nof_ref_symbols; q->nof_refs = nof_refs_x_symbol * nof_ref_symbols;
q->nsymbols = nof_ref_symbols; q->nsymbols = nof_ref_symbols;
q->symbols_ref = malloc(sizeof(int) * nof_ref_symbols); q->symbols_ref = malloc(sizeof(int) * nof_ref_symbols);
q->voffset = cell_id%6; q->voffset = cell_id%6;
q->nof_prb = nof_prb; q->nof_prb = nof_prb;
if (!q->symbols_ref) { if (!q->symbols_ref) {
return -1; return -1;
} }
memcpy(q->symbols_ref, lp, sizeof(int) * nof_ref_symbols); memcpy(q->symbols_ref, lp, sizeof(int) * nof_ref_symbols);
q->refs = vec_malloc(q->nof_refs * sizeof(ref_t)); q->refs = vec_malloc(q->nof_refs * sizeof(ref_t));
if (!q->refs) { if (!q->refs) {
goto free_and_exit; goto free_and_exit;
} }
q->ch_est = vec_malloc(q->nof_refs * sizeof(cf_t)); q->ch_est = vec_malloc(q->nof_refs * sizeof(cf_t));
if (!q->ch_est) { if (!q->ch_est) {
goto free_and_exit; goto free_and_exit;
} }
ns = nslot; ns = nslot;
for (l = 0; l < nof_ref_symbols; l++) { for (l = 0; l < nof_ref_symbols; l++) {
c_init = 1024 * (7 * (ns + 1) + lp[l] + 1) * (2 * cell_id + 1) c_init = 1024 * (7 * (ns + 1) + lp[l] + 1) * (2 * cell_id + 1)
+ 2 * cell_id + N_cp; + 2 * cell_id + N_cp;
if (sequence_LTEPRS(&seq, 2 * 2 * MAX_PRB, c_init)) { if (sequence_LTEPRS(&seq, 2 * 2 * MAX_PRB, c_init)) {
goto free_and_exit; goto free_and_exit;
} }
v = refsignal_v(port_id, ns, lp[l]); v = refsignal_v(port_id, ns, lp[l]);
for (i = 0; i < nof_refs_x_symbol; i++) { for (i = 0; i < nof_refs_x_symbol; i++) {
mp = i + MAX_PRB - nof_prb; mp = i + MAX_PRB - nof_prb;
/* generate signal */ /* generate signal */
__real__ q->refs[idx(l,i)].simbol = (1 - 2 * (float) seq.c[2 * mp]) / sqrt(2); __real__ q->refs[idx(l,i)].simbol = (1 - 2 * (float) seq.c[2 * mp]) / sqrt(2);
__imag__ q->refs[idx(l,i)].simbol = (1 - 2 * (float) seq.c[2 * mp + 1]) / sqrt(2); __imag__ q->refs[idx(l,i)].simbol = (1 - 2 * (float) seq.c[2 * mp + 1]) / sqrt(2);
/* mapping to resource elements */ /* mapping to resource elements */
q->refs[idx(l,i)].freq_idx = refsignal_k(i, v, cell_id); q->refs[idx(l,i)].freq_idx = refsignal_k(i, v, cell_id);
q->refs[idx(l,i)].time_idx = lp[l]; q->refs[idx(l,i)].time_idx = lp[l];
} }
} }
ret = 0; ret = 0;
free_and_exit: free_and_exit:
sequence_free(&seq); sequence_free(&seq);
if (ret == -1) { if (ret == -1) {
refsignal_free(q); refsignal_free(q);
} }
return ret; return ret;
} }
void refsignal_free(refsignal_t *q) { void refsignal_free(refsignal_t *q) {
if (q->symbols_ref) { if (q->symbols_ref) {
free(q->symbols_ref); free(q->symbols_ref);
} }
if (q->refs) { if (q->refs) {
free(q->refs); free(q->refs);
} }
if (q->ch_est) { if (q->ch_est) {
free(q->ch_est); free(q->ch_est);
} }
bzero(q, sizeof(refsignal_t)); bzero(q, sizeof(refsignal_t));
} }

@ -40,212 +40,212 @@ lte_cp_t cp = CPNORM;
char *output_matlab = NULL; char *output_matlab = NULL;
void usage(char *prog) { void usage(char *prog) {
printf("Usage: %s [recov]\n", prog); printf("Usage: %s [recov]\n", prog);
printf("\t-r nof_prb [Default %d]\n", nof_prb); printf("\t-r nof_prb [Default %d]\n", nof_prb);
printf("\t-e extended cyclic prefix [Default normal]\n"); printf("\t-e extended cyclic prefix [Default normal]\n");
printf("\t-c cell_id (-1 tests all). [Default %d]\n", cell_id); printf("\t-c cell_id (-1 tests all). [Default %d]\n", cell_id);
printf("\t-o output matlab file [Default %s]\n",output_matlab?output_matlab:"None"); printf("\t-o output matlab file [Default %s]\n",output_matlab?output_matlab:"None");
printf("\t-v increase verbosity\n"); printf("\t-v increase verbosity\n");
} }
void parse_args(int argc, char **argv) { void parse_args(int argc, char **argv) {
int opt; int opt;
while ((opt = getopt(argc, argv, "recov")) != -1) { while ((opt = getopt(argc, argv, "recov")) != -1) {
switch(opt) { switch(opt) {
case 'r': case 'r':
nof_prb = atoi(argv[optind]); nof_prb = atoi(argv[optind]);
break; break;
case 'e': case 'e':
cp = CPEXT; cp = CPEXT;
break; break;
case 'c': case 'c':
cell_id = atoi(argv[optind]); cell_id = atoi(argv[optind]);
break; break;
case 'o': case 'o':
output_matlab = argv[optind]; output_matlab = argv[optind];
break; break;
case 'v': case 'v':
verbose++; verbose++;
break; break;
default: default:
usage(argv[0]); usage(argv[0]);
exit(-1); exit(-1);
} }
} }
} }
int check_mse(float mod, float arg, int n_port) { int check_mse(float mod, float arg, int n_port) {
INFO("mod=%.4f, arg=%.4f, n_port=%d\n", mod, arg, n_port); INFO("mod=%.4f, arg=%.4f, n_port=%d\n", mod, arg, n_port);
switch(n_port) { switch(n_port) {
case 0: case 0:
if (mod > 0.029) { if (mod > 0.029) {
return -1; return -1;
} }
if (arg > 0.029) { if (arg > 0.029) {
return -1; return -1;
} }
break; break;
case 1: case 1:
if (mod > 0.012) { if (mod > 0.012) {
return -1; return -1;
} }
if (arg > 0.012) { if (arg > 0.012) {
return -1; return -1;
} }
break; break;
case 2: case 2:
case 3: case 3:
if (mod > 3.33) { if (mod > 3.33) {
return -1; return -1;
} }
if (arg > 0.63) { if (arg > 0.63) {
return -1; return -1;
} }
break; break;
default: default:
return -1; return -1;
} }
return 0; return 0;
} }
int main(int argc, char **argv) { int main(int argc, char **argv) {
chest_t eq; chest_t eq;
cf_t *input = NULL, *ce = NULL, *h = NULL; cf_t *input = NULL, *ce = NULL, *h = NULL;
refsignal_t refs; refsignal_t refs;
int i, j, n_port, n_slot, cid, num_re; int i, j, n_port, n_slot, cid, num_re;
int ret = -1; int ret = -1;
int max_cid; int max_cid;
FILE *fmatlab = NULL; FILE *fmatlab = NULL;
float mse_mag, mse_phase; float mse_mag, mse_phase;
parse_args(argc,argv); parse_args(argc,argv);
if (output_matlab) { if (output_matlab) {
fmatlab=fopen(output_matlab, "w"); fmatlab=fopen(output_matlab, "w");
if (!fmatlab) { if (!fmatlab) {
perror("fopen"); perror("fopen");
goto do_exit; goto do_exit;
} }
} }
num_re = nof_prb * RE_X_RB * CP_NSYMB(cp); num_re = nof_prb * RE_X_RB * CP_NSYMB(cp);
input = malloc(num_re * sizeof(cf_t)); input = malloc(num_re * sizeof(cf_t));
if (!input) { if (!input) {
perror("malloc"); perror("malloc");
goto do_exit; goto do_exit;
} }
h = malloc(num_re * sizeof(cf_t)); h = malloc(num_re * sizeof(cf_t));
if (!h) { if (!h) {
perror("malloc"); perror("malloc");
goto do_exit; goto do_exit;
} }
ce = malloc(num_re * sizeof(cf_t)); ce = malloc(num_re * sizeof(cf_t));
if (!ce) { if (!ce) {
perror("malloc"); perror("malloc");
goto do_exit; goto do_exit;
} }
if (cell_id == -1) { if (cell_id == -1) {
cid = 0; cid = 0;
max_cid = 504; max_cid = 504;
} else { } else {
cid = cell_id; cid = cell_id;
max_cid = cell_id; max_cid = cell_id;
} }
while(cid <= max_cid) { while(cid <= max_cid) {
if (chest_init(&eq, LINEAR, cp, nof_prb, MAX_PORTS)) { if (chest_init(&eq, LINEAR, cp, nof_prb, MAX_PORTS)) {
fprintf(stderr, "Error initializing equalizer\n"); fprintf(stderr, "Error initializing equalizer\n");
goto do_exit; goto do_exit;
} }
if (chest_ref_LTEDL(&eq, cid)) { if (chest_ref_LTEDL(&eq, cid)) {
fprintf(stderr, "Error initializing reference signal\n"); fprintf(stderr, "Error initializing reference signal\n");
goto do_exit; goto do_exit;
} }
for (n_slot=0;n_slot<NSLOTS_X_FRAME;n_slot++) { for (n_slot=0;n_slot<NSLOTS_X_FRAME;n_slot++) {
for (n_port=0;n_port<MAX_PORTS;n_port++) { for (n_port=0;n_port<MAX_PORTS;n_port++) {
if (refsignal_init_LTEDL(&refs, n_port, n_slot, cid, cp, nof_prb)) { if (refsignal_init_LTEDL(&refs, n_port, n_slot, cid, cp, nof_prb)) {
fprintf(stderr, "Error initiating CRS slot=%d\n", i); fprintf(stderr, "Error initiating CRS slot=%d\n", i);
return -1; return -1;
} }
bzero(input, sizeof(cf_t) * num_re); bzero(input, sizeof(cf_t) * num_re);
for (i=0;i<num_re;i++) { for (i=0;i<num_re;i++) {
input[i] = 0.5-rand()/RAND_MAX+I*(0.5-rand()/RAND_MAX); input[i] = 0.5-rand()/RAND_MAX+I*(0.5-rand()/RAND_MAX);
} }
bzero(ce, sizeof(cf_t) * num_re); bzero(ce, sizeof(cf_t) * num_re);
bzero(h, sizeof(cf_t) * num_re); bzero(h, sizeof(cf_t) * num_re);
refsignal_put(&refs, input); refsignal_put(&refs, input);
refsignal_free(&refs); refsignal_free(&refs);
for (i=0;i<CP_NSYMB(cp);i++) { for (i=0;i<CP_NSYMB(cp);i++) {
for (j=0;j<nof_prb * RE_X_RB;j++) { for (j=0;j<nof_prb * RE_X_RB;j++) {
float x = -1+(float) i/CP_NSYMB(cp) + cosf(2 * M_PI * (float) j/nof_prb/RE_X_RB); float x = -1+(float) i/CP_NSYMB(cp) + cosf(2 * M_PI * (float) j/nof_prb/RE_X_RB);
h[i*nof_prb * RE_X_RB+j] = (3+x) * cexpf(I * x); h[i*nof_prb * RE_X_RB+j] = (3+x) * cexpf(I * x);
input[i*nof_prb * RE_X_RB+j] *= h[i*nof_prb * RE_X_RB+j]; input[i*nof_prb * RE_X_RB+j] *= h[i*nof_prb * RE_X_RB+j];
} }
} }
chest_ce_slot_port(&eq, input, ce, n_slot, n_port); chest_ce_slot_port(&eq, input, ce, n_slot, n_port);
mse_mag = mse_phase = 0; mse_mag = mse_phase = 0;
for (i=0;i<num_re;i++) { for (i=0;i<num_re;i++) {
mse_mag += (cabsf(h[i]) - cabsf(ce[i])) * (cabsf(h[i]) - cabsf(ce[i])) / num_re; mse_mag += (cabsf(h[i]) - cabsf(ce[i])) * (cabsf(h[i]) - cabsf(ce[i])) / num_re;
mse_phase += (cargf(h[i]) - cargf(ce[i])) * (cargf(h[i]) - cargf(ce[i])) / num_re; mse_phase += (cargf(h[i]) - cargf(ce[i])) * (cargf(h[i]) - cargf(ce[i])) / num_re;
} }
if (check_mse(mse_mag, mse_phase, n_port)) { if (check_mse(mse_mag, mse_phase, n_port)) {
goto do_exit; goto do_exit;
} }
if (fmatlab) { if (fmatlab) {
fprintf(fmatlab, "input="); fprintf(fmatlab, "input=");
vec_fprint_c(fmatlab, input, num_re); vec_fprint_c(fmatlab, input, num_re);
fprintf(fmatlab, ";\n"); fprintf(fmatlab, ";\n");
fprintf(fmatlab, "h="); fprintf(fmatlab, "h=");
vec_fprint_c(fmatlab, h, num_re); vec_fprint_c(fmatlab, h, num_re);
fprintf(fmatlab, ";\n"); fprintf(fmatlab, ";\n");
fprintf(fmatlab, "ce="); fprintf(fmatlab, "ce=");
vec_fprint_c(fmatlab, ce, num_re); vec_fprint_c(fmatlab, ce, num_re);
fprintf(fmatlab, ";\n"); fprintf(fmatlab, ";\n");
chest_fprint(&eq, fmatlab, n_slot, n_port); chest_fprint(&eq, fmatlab, n_slot, n_port);
} }
} }
} }
chest_free(&eq); chest_free(&eq);
cid+=10; cid+=10;
INFO("cid=%d\n", cid); INFO("cid=%d\n", cid);
} }
ret = 0; ret = 0;
do_exit: do_exit:
if (ce) { if (ce) {
free(ce); free(ce);
} }
if (input) { if (input) {
free(input); free(input);
} }
if (h) { if (h) {
free(h); free(h);
} }
if (!ret) { if (!ret) {
printf("OK\n"); printf("OK\n");
} else { } else {
printf("Error at cid=%d, slot=%d, port=%d\n",cid, n_slot, n_port); printf("Error at cid=%d, slot=%d, port=%d\n",cid, n_slot, n_port);
} }
exit(ret); exit(ret);
} }

@ -34,36 +34,36 @@
#include "lte/channel/ch_awgn.h" #include "lte/channel/ch_awgn.h"
void ch_awgn_c(const cf_t* x, cf_t* y, float variance, int buff_sz) { void ch_awgn_c(const cf_t* x, cf_t* y, float variance, int buff_sz) {
_Complex float tmp; _Complex float tmp;
int i; int i;
for (i=0;i<buff_sz;i++) { for (i=0;i<buff_sz;i++) {
__real__ tmp = rand_gauss(); __real__ tmp = rand_gauss();
__imag__ tmp = rand_gauss(); __imag__ tmp = rand_gauss();
tmp *= variance; tmp *= variance;
y[i] = tmp + x[i]; y[i] = tmp + x[i];
} }
} }
void ch_awgn_f(const float* x, float* y, float variance, int buff_sz) { void ch_awgn_f(const float* x, float* y, float variance, int buff_sz) {
int i; int i;
for (i=0;i<buff_sz;i++) { for (i=0;i<buff_sz;i++) {
y[i] = x[i] + variance * rand_gauss(); y[i] = x[i] + variance * rand_gauss();
} }
} }
/* High-level API */ /* High-level API */
int ch_awgn_initialize(ch_awgn_hl* hl) { int ch_awgn_initialize(ch_awgn_hl* hl) {
return 0; return 0;
} }
int ch_awgn_work(ch_awgn_hl* hl) { int ch_awgn_work(ch_awgn_hl* hl) {
ch_awgn_c(hl->input,hl->output,hl->ctrl_in.variance,hl->in_len); ch_awgn_c(hl->input,hl->output,hl->ctrl_in.variance,hl->in_len);
hl->out_len = hl->in_len; hl->out_len = hl->in_len;
return 0; return 0;
} }
int ch_awgn_stop(ch_awgn_hl* hl) { int ch_awgn_stop(ch_awgn_hl* hl) {
return 0; return 0;
} }

@ -36,99 +36,99 @@
#include "lte/utils/vector.h" #include "lte/utils/vector.h"
int lte_fft_init_(lte_fft_t *q, lte_cp_t cp_type, int nof_prb, dft_dir_t dir) { int lte_fft_init_(lte_fft_t *q, lte_cp_t cp_type, int nof_prb, dft_dir_t dir) {
int symbol_sz = lte_symbol_sz(nof_prb); int symbol_sz = lte_symbol_sz(nof_prb);
if (symbol_sz == -1) { if (symbol_sz == -1) {
fprintf(stderr, "Error: Invalid nof_prb=%d\n", nof_prb); fprintf(stderr, "Error: Invalid nof_prb=%d\n", nof_prb);
return -1; return -1;
} }
if (dft_plan_c2c(&q->fft_plan, symbol_sz, dir)) { if (dft_plan_c2c(&q->fft_plan, symbol_sz, dir)) {
fprintf(stderr, "Error: Creating DFT plan\n"); fprintf(stderr, "Error: Creating DFT plan\n");
return -1; return -1;
} }
q->tmp = malloc(symbol_sz * sizeof(cf_t)); q->tmp = malloc(symbol_sz * sizeof(cf_t));
if (!q->tmp) { if (!q->tmp) {
perror("malloc"); perror("malloc");
return -1; return -1;
} }
q->fft_plan.options = DFT_NORMALIZE; q->fft_plan.options = DFT_NORMALIZE;
if (dir==FORWARD) { if (dir==FORWARD) {
q->fft_plan.options |= DFT_DC_OFFSET | DFT_MIRROR_POS; q->fft_plan.options |= DFT_DC_OFFSET | DFT_MIRROR_POS;
} else { } else {
q->fft_plan.options |= DFT_DC_OFFSET | DFT_MIRROR_PRE; q->fft_plan.options |= DFT_DC_OFFSET | DFT_MIRROR_PRE;
} }
q->symbol_sz = symbol_sz; q->symbol_sz = symbol_sz;
q->nof_symbols = CP_NSYMB(cp_type); q->nof_symbols = CP_NSYMB(cp_type);
q->cp_type = cp_type; q->cp_type = cp_type;
q->nof_re = nof_prb * RE_X_RB; q->nof_re = nof_prb * RE_X_RB;
q->nof_guards = ((symbol_sz - q->nof_re) / 2); q->nof_guards = ((symbol_sz - q->nof_re) / 2);
DEBUG("Init %s symbol_sz=%d, nof_symbols=%d, cp_type=%s, nof_re=%d, nof_guards=%d\n", DEBUG("Init %s symbol_sz=%d, nof_symbols=%d, cp_type=%s, nof_re=%d, nof_guards=%d\n",
dir==FORWARD?"FFT":"iFFT", q->symbol_sz, q->nof_symbols, dir==FORWARD?"FFT":"iFFT", q->symbol_sz, q->nof_symbols,
q->cp_type==CPNORM?"Normal":"Extended", q->nof_re, q->nof_guards); q->cp_type==CPNORM?"Normal":"Extended", q->nof_re, q->nof_guards);
return 0; return 0;
} }
void lte_fft_free_(lte_fft_t *q) { void lte_fft_free_(lte_fft_t *q) {
dft_plan_free(&q->fft_plan); dft_plan_free(&q->fft_plan);
if (q->tmp) { if (q->tmp) {
free(q->tmp); free(q->tmp);
} }
bzero(q, sizeof(lte_fft_t)); bzero(q, sizeof(lte_fft_t));
} }
int lte_fft_init(lte_fft_t *q, lte_cp_t cp_type, int nof_prb) { int lte_fft_init(lte_fft_t *q, lte_cp_t cp_type, int nof_prb) {
return lte_fft_init_(q, cp_type, nof_prb, FORWARD); return lte_fft_init_(q, cp_type, nof_prb, FORWARD);
} }
void lte_fft_free(lte_fft_t *q) { void lte_fft_free(lte_fft_t *q) {
lte_fft_free_(q); lte_fft_free_(q);
} }
int lte_ifft_init(lte_fft_t *q, lte_cp_t cp_type, int nof_prb) { int lte_ifft_init(lte_fft_t *q, lte_cp_t cp_type, int nof_prb) {
int i; int i;
if (lte_fft_init_(q, cp_type, nof_prb, BACKWARD)) { if (lte_fft_init_(q, cp_type, nof_prb, BACKWARD)) {
return -1; return -1;
} }
/* set now zeros at CP */ /* set now zeros at CP */
for (i=0;i<q->nof_symbols;i++) { for (i=0;i<q->nof_symbols;i++) {
bzero(q->tmp, q->nof_guards * sizeof(cf_t)); bzero(q->tmp, q->nof_guards * sizeof(cf_t));
bzero(&q->tmp[q->nof_re + q->nof_guards], q->nof_guards * sizeof(cf_t)); bzero(&q->tmp[q->nof_re + q->nof_guards], q->nof_guards * sizeof(cf_t));
} }
return 0; return 0;
} }
void lte_ifft_free(lte_fft_t *q) { void lte_ifft_free(lte_fft_t *q) {
lte_fft_free_(q); lte_fft_free_(q);
} }
/* Transforms input samples into output OFDM symbols. /* Transforms input samples into output OFDM symbols.
* Performs FFT on a each symbol and removes CP. * Performs FFT on a each symbol and removes CP.
*/ */
void lte_fft_run(lte_fft_t *q, cf_t *input, cf_t *output) { void lte_fft_run(lte_fft_t *q, cf_t *input, cf_t *output) {
int i; int i;
for (i=0;i<q->nof_symbols;i++) { for (i=0;i<q->nof_symbols;i++) {
input += CP_ISNORM(q->cp_type)?CP_NORM(i, q->symbol_sz):CP_EXT(q->symbol_sz); input += CP_ISNORM(q->cp_type)?CP_NORM(i, q->symbol_sz):CP_EXT(q->symbol_sz);
dft_run_c2c(&q->fft_plan, input, q->tmp); dft_run_c2c(&q->fft_plan, input, q->tmp);
memcpy(output, &q->tmp[q->nof_guards], q->nof_re * sizeof(cf_t)); memcpy(output, &q->tmp[q->nof_guards], q->nof_re * sizeof(cf_t));
input += q->symbol_sz; input += q->symbol_sz;
output += q->nof_re; output += q->nof_re;
} }
} }
/* Transforms input OFDM symbols into output samples. /* Transforms input OFDM symbols into output samples.
* Performs FFT on a each symbol and adds CP. * Performs FFT on a each symbol and adds CP.
*/ */
void lte_ifft_run(lte_fft_t *q, cf_t *input, cf_t *output) { void lte_ifft_run(lte_fft_t *q, cf_t *input, cf_t *output) {
int i, cp_len; int i, cp_len;
for (i=0;i<q->nof_symbols;i++) { for (i=0;i<q->nof_symbols;i++) {
cp_len = CP_ISNORM(q->cp_type)?CP_NORM(i, q->symbol_sz):CP_EXT(q->symbol_sz); cp_len = CP_ISNORM(q->cp_type)?CP_NORM(i, q->symbol_sz):CP_EXT(q->symbol_sz);
memcpy(&q->tmp[q->nof_guards], input, q->nof_re * sizeof(cf_t)); memcpy(&q->tmp[q->nof_guards], input, q->nof_re * sizeof(cf_t));
dft_run_c2c(&q->fft_plan, q->tmp, &output[cp_len]); dft_run_c2c(&q->fft_plan, q->tmp, &output[cp_len]);
input += q->nof_re; input += q->nof_re;
/* add CP */ /* add CP */
memcpy(output, &output[q->symbol_sz], cp_len * sizeof(cf_t)); memcpy(output, &output[q->symbol_sz], cp_len * sizeof(cf_t));
output += q->symbol_sz + cp_len; output += q->symbol_sz + cp_len;
} }
} }

@ -35,243 +35,243 @@
#include "lte/common/base.h" #include "lte/common/base.h"
const int tc_cb_sizes[NOF_TC_CB_SIZES] = { 40, 48, 56, 64, 72, 80, 88, 96, 104, 112, 120, const int tc_cb_sizes[NOF_TC_CB_SIZES] = { 40, 48, 56, 64, 72, 80, 88, 96, 104, 112, 120,
128, 136, 144, 152, 160, 168, 176, 184, 192, 200, 208, 216, 224, 232, 128, 136, 144, 152, 160, 168, 176, 184, 192, 200, 208, 216, 224, 232,
240, 248, 256, 264, 272, 280, 288, 296, 304, 312, 320, 328, 336, 344, 240, 248, 256, 264, 272, 280, 288, 296, 304, 312, 320, 328, 336, 344,
352, 360, 368, 376, 384, 392, 400, 408, 416, 424, 432, 440, 448, 456, 352, 360, 368, 376, 384, 392, 400, 408, 416, 424, 432, 440, 448, 456,
464, 472, 480, 488, 496, 504, 512, 528, 544, 560, 576, 592, 608, 624, 464, 472, 480, 488, 496, 504, 512, 528, 544, 560, 576, 592, 608, 624,
640, 656, 672, 688, 704, 720, 736, 752, 768, 784, 800, 816, 832, 848, 640, 656, 672, 688, 704, 720, 736, 752, 768, 784, 800, 816, 832, 848,
864, 880, 896, 912, 928, 944, 960, 976, 992, 1008, 1024, 1056, 1088, 864, 880, 896, 912, 928, 944, 960, 976, 992, 1008, 1024, 1056, 1088,
1120, 1152, 1184, 1216, 1248, 1280, 1312, 1344, 1376, 1408, 1440, 1472, 1120, 1152, 1184, 1216, 1248, 1280, 1312, 1344, 1376, 1408, 1440, 1472,
1504, 1536, 1568, 1600, 1632, 1664, 1696, 1728, 1760, 1792, 1824, 1856, 1504, 1536, 1568, 1600, 1632, 1664, 1696, 1728, 1760, 1792, 1824, 1856,
1888, 1920, 1952, 1984, 2016, 2048, 2112, 2176, 2240, 2304, 2368, 2432, 1888, 1920, 1952, 1984, 2016, 2048, 2112, 2176, 2240, 2304, 2368, 2432,
2496, 2560, 2624, 2688, 2752, 2816, 2880, 2944, 3008, 3072, 3136, 3200, 2496, 2560, 2624, 2688, 2752, 2816, 2880, 2944, 3008, 3072, 3136, 3200,
3264, 3328, 3392, 3456, 3520, 3584, 3648, 3712, 3776, 3840, 3904, 3968, 3264, 3328, 3392, 3456, 3520, 3584, 3648, 3712, 3776, 3840, 3904, 3968,
4032, 4096, 4160, 4224, 4288, 4352, 4416, 4480, 4544, 4608, 4672, 4736, 4032, 4096, 4160, 4224, 4288, 4352, 4416, 4480, 4544, 4608, 4672, 4736,
4800, 4864, 4928, 4992, 5056, 5120, 5184, 5248, 5312, 5376, 5440, 5504, 4800, 4864, 4928, 4992, 5056, 5120, 5184, 5248, 5312, 5376, 5440, 5504,
5568, 5632, 5696, 5760, 5824, 5888, 5952, 6016, 6080, 6144 }; 5568, 5632, 5696, 5760, 5824, 5888, 5952, 6016, 6080, 6144 };
int lte_cb_size(int index) { int lte_cb_size(int index) {
if (index >= 0 && index < NOF_TC_CB_SIZES) { if (index >= 0 && index < NOF_TC_CB_SIZES) {
return tc_cb_sizes[index]; return tc_cb_sizes[index];
} else { } else {
return -1; return -1;
} }
} }
int lte_find_cb_index(int long_cb) { int lte_find_cb_index(int long_cb) {
int j = 0; int j = 0;
while (j < NOF_TC_CB_SIZES && tc_cb_sizes[j] < long_cb) { while (j < NOF_TC_CB_SIZES && tc_cb_sizes[j] < long_cb) {
j++; j++;
} }
if (j == NOF_TC_CB_SIZES) { if (j == NOF_TC_CB_SIZES) {
return -1; return -1;
} else { } else {
return j; return j;
} }
} }
const int lte_symbol_sz(int nof_prb) { const int lte_symbol_sz(int nof_prb) {
if (nof_prb<=0) { if (nof_prb<=0) {
return -1; return -1;
} }
if (nof_prb<=6) { if (nof_prb<=6) {
return 128; return 128;
} else if (nof_prb<=15) { } else if (nof_prb<=15) {
return 256; return 256;
} else if (nof_prb<=25) { } else if (nof_prb<=25) {
return 512; return 512;
} else if (nof_prb<=50) { } else if (nof_prb<=50) {
return 1024; return 1024;
} else if (nof_prb<=75) { } else if (nof_prb<=75) {
return 1536; return 1536;
} else if (nof_prb<=100) { } else if (nof_prb<=100) {
return 2048; return 2048;
} }
return -1; return -1;
} }
int lte_voffset(int symbol_id, int cell_id, int nof_ports) { int lte_voffset(int symbol_id, int cell_id, int nof_ports) {
if (nof_ports == 1 && symbol_id==0) { if (nof_ports == 1 && symbol_id==0) {
return (cell_id+3) % 6; return (cell_id+3) % 6;
} else { } else {
return cell_id % 6; return cell_id % 6;
} }
} }
/* Returns the number of available RE per PRB */ /* Returns the number of available RE per PRB */
int lte_re_x_prb(int ns, int symbol, int nof_ports, int nof_symbols) { int lte_re_x_prb(int ns, int symbol, int nof_ports, int nof_symbols) {
if (symbol == 0) { if (symbol == 0) {
if (((ns % 2) == 0) || (ns == 1)) { if (((ns % 2) == 0) || (ns == 1)) {
return RE_X_RB - 4; return RE_X_RB - 4;
} else { } else {
if (nof_ports == 1) { if (nof_ports == 1) {
return RE_X_RB - 2; return RE_X_RB - 2;
} else { } else {
return RE_X_RB - 4; return RE_X_RB - 4;
} }
} }
} else if (symbol == 1) { } else if (symbol == 1) {
if (ns == 1) { if (ns == 1) {
return RE_X_RB - 4; return RE_X_RB - 4;
} else if (nof_ports == 4) { } else if (nof_ports == 4) {
return RE_X_RB - 4; return RE_X_RB - 4;
} else { } else {
return RE_X_RB; return RE_X_RB;
} }
} else if (symbol == nof_symbols - 3) { } else if (symbol == nof_symbols - 3) {
if (nof_ports == 1) { if (nof_ports == 1) {
return RE_X_RB - 2; return RE_X_RB - 2;
} else { } else {
return RE_X_RB - 4; return RE_X_RB - 4;
} }
} else { } else {
return RE_X_RB; return RE_X_RB;
} }
} }
struct lte_band { struct lte_band {
int band; int band;
float fd_low_mhz; float fd_low_mhz;
int earfcn_offset; int earfcn_offset;
int earfcn_max; int earfcn_max;
enum band_geographical_area area; enum band_geographical_area area;
}; };
struct lte_band lte_bands[NOF_LTE_BANDS] = { struct lte_band lte_bands[NOF_LTE_BANDS] = {
{1, 2110, 0, 599, ALL}, {1, 2110, 0, 599, ALL},
{2, 1930, 600, 1199, NAR}, {2, 1930, 600, 1199, NAR},
{3, 1805, 1200, 1949, ALL}, {3, 1805, 1200, 1949, ALL},
{4, 2110, 1950, 2399, NAR}, {4, 2110, 1950, 2399, NAR},
{5, 869, 2400, 2649, NAR}, {5, 869, 2400, 2649, NAR},
{6, 875, 2650, 2749, APAC}, {6, 875, 2650, 2749, APAC},
{7, 2620, 2750, 3449, EMEA}, {7, 2620, 2750, 3449, EMEA},
{8, 925, 3450, 3799, ALL}, {8, 925, 3450, 3799, ALL},
{9, 1844.9, 3800, 4149, APAC}, {9, 1844.9, 3800, 4149, APAC},
{10, 2110, 4150, 4749, NAR}, {10, 2110, 4150, 4749, NAR},
{11, 1475.9, 4750, 4949, JAPAN}, {11, 1475.9, 4750, 4949, JAPAN},
{12, 729, 5010, 5179, NAR}, {12, 729, 5010, 5179, NAR},
{13, 746, 5180, 5279, NAR}, {13, 746, 5180, 5279, NAR},
{14, 758, 5280, 5379, NAR}, {14, 758, 5280, 5379, NAR},
{17, 734, 5730, 5849, NAR}, {17, 734, 5730, 5849, NAR},
{18, 860, 5850, 5999, JAPAN}, {18, 860, 5850, 5999, JAPAN},
{19, 875, 6000, 6149, JAPAN}, {19, 875, 6000, 6149, JAPAN},
{20, 791, 6150, 6449, EMEA}, {20, 791, 6150, 6449, EMEA},
{21, 1495.9, 6450, 6599, JAPAN}, {21, 1495.9, 6450, 6599, JAPAN},
{22, 3500, 6600, 7399, NA}, {22, 3500, 6600, 7399, NA},
{23, 2180, 7500, 7699, NAR}, {23, 2180, 7500, 7699, NAR},
{24, 1525, 7700, 8039, NAR}, {24, 1525, 7700, 8039, NAR},
{25, 1930, 8040, 8689, NAR}, {25, 1930, 8040, 8689, NAR},
{26, 859, 8690, 9039, NAR}, {26, 859, 8690, 9039, NAR},
{27, 852, 9040, 9209, NAR}, {27, 852, 9040, 9209, NAR},
{28, 758, 9210, 9659, APAC}, {28, 758, 9210, 9659, APAC},
{29, 717, 9660, 9769, NAR}, {29, 717, 9660, 9769, NAR},
{30, 2350, 9770, 9869, NAR}, {30, 2350, 9770, 9869, NAR},
{31, 462.5, 9870, 9919, CALA} {31, 462.5, 9870, 9919, CALA}
}; };
#define EOF_BAND 9919 #define EOF_BAND 9919
int lte_str2mimotype(char *mimo_type_str, lte_mimo_type_t *type) { int lte_str2mimotype(char *mimo_type_str, lte_mimo_type_t *type) {
if (!strcmp(mimo_type_str, "single")) { if (!strcmp(mimo_type_str, "single")) {
*type = SINGLE_ANTENNA; *type = SINGLE_ANTENNA;
} else if (!strcmp(mimo_type_str, "diversity")) { } else if (!strcmp(mimo_type_str, "diversity")) {
*type = TX_DIVERSITY; *type = TX_DIVERSITY;
} else if (!strcmp(mimo_type_str, "multiplex")) { } else if (!strcmp(mimo_type_str, "multiplex")) {
*type = SPATIAL_MULTIPLEX; *type = SPATIAL_MULTIPLEX;
} else { } else {
return -1; return -1;
} }
return 0; return 0;
} }
char *lte_mimotype2str(lte_mimo_type_t type) { char *lte_mimotype2str(lte_mimo_type_t type) {
switch(type) { switch(type) {
case SINGLE_ANTENNA: case SINGLE_ANTENNA:
return "single"; return "single";
case TX_DIVERSITY: case TX_DIVERSITY:
return "diversity"; return "diversity";
case SPATIAL_MULTIPLEX: case SPATIAL_MULTIPLEX:
return "multiplex"; return "multiplex";
} }
return NULL; return NULL;
} }
float get_fd(struct lte_band *band, int earfcn) { float get_fd(struct lte_band *band, int earfcn) {
return band->fd_low_mhz + 0.1*(earfcn - band->earfcn_offset); return band->fd_low_mhz + 0.1*(earfcn - band->earfcn_offset);
} }
float lte_band_fd(int earfcn) { float lte_band_fd(int earfcn) {
int i; int i;
i=0; i=0;
while(i < NOF_LTE_BANDS && lte_bands[i].earfcn_offset<earfcn) { while(i < NOF_LTE_BANDS && lte_bands[i].earfcn_offset<earfcn) {
i++; i++;
} }
if (i == NOF_LTE_BANDS) { if (i == NOF_LTE_BANDS) {
fprintf(stderr, "Error: EARFCN %d not found\n", earfcn); fprintf(stderr, "Error: EARFCN %d not found\n", earfcn);
return -1.0; return -1.0;
} }
return get_fd(&lte_bands[i], earfcn); return get_fd(&lte_bands[i], earfcn);
} }
int lte_band_get_fd_band_all(int band, lte_earfcn_t *earfcn, int max_elems) { int lte_band_get_fd_band_all(int band, lte_earfcn_t *earfcn, int max_elems) {
return lte_band_get_fd_band(band, earfcn, -1, -1, max_elems); return lte_band_get_fd_band(band, earfcn, -1, -1, max_elems);
} }
int lte_band_get_fd_band(int band, lte_earfcn_t *earfcn, int start_earfcn, int end_earfcn, int max_elems) { int lte_band_get_fd_band(int band, lte_earfcn_t *earfcn, int start_earfcn, int end_earfcn, int max_elems) {
int i, j; int i, j;
int nof_earfcn; int nof_earfcn;
i=0; i=0;
while(i < NOF_LTE_BANDS && lte_bands[i].band != band) { while(i < NOF_LTE_BANDS && lte_bands[i].band != band) {
i++; i++;
} }
if (i == NOF_LTE_BANDS) { if (i == NOF_LTE_BANDS) {
fprintf(stderr, "Error: Invalid band %d\n", band); fprintf(stderr, "Error: Invalid band %d\n", band);
return -1; return -1;
} }
if (end_earfcn == -1) { if (end_earfcn == -1) {
end_earfcn = lte_bands[i].earfcn_max; end_earfcn = lte_bands[i].earfcn_max;
} else { } else {
if (end_earfcn > lte_bands[i].earfcn_max) { if (end_earfcn > lte_bands[i].earfcn_max) {
fprintf(stderr, "Error: Invalid end earfcn %d. Max is %d\n", end_earfcn, lte_bands[i].earfcn_max); fprintf(stderr, "Error: Invalid end earfcn %d. Max is %d\n", end_earfcn, lte_bands[i].earfcn_max);
return -1; return -1;
} }
} }
if (start_earfcn == -1) { if (start_earfcn == -1) {
start_earfcn = lte_bands[i].earfcn_offset; start_earfcn = lte_bands[i].earfcn_offset;
} else { } else {
if (start_earfcn < lte_bands[i].earfcn_offset) { if (start_earfcn < lte_bands[i].earfcn_offset) {
fprintf(stderr, "Error: Invalid start earfcn %d. Min is %d\n", start_earfcn, lte_bands[i].earfcn_offset); fprintf(stderr, "Error: Invalid start earfcn %d. Min is %d\n", start_earfcn, lte_bands[i].earfcn_offset);
return -1; return -1;
} }
} }
nof_earfcn = end_earfcn - start_earfcn; nof_earfcn = end_earfcn - start_earfcn;
if (nof_earfcn > max_elems) { if (nof_earfcn > max_elems) {
nof_earfcn = max_elems; nof_earfcn = max_elems;
} }
for (j=0;j<nof_earfcn;j++) { for (j=0;j<nof_earfcn;j++) {
earfcn[j].id = j + start_earfcn; earfcn[j].id = j + start_earfcn;
earfcn[j].fd = get_fd(&lte_bands[i], earfcn[j].id); earfcn[j].fd = get_fd(&lte_bands[i], earfcn[j].id);
} }
return j; return j;
} }
int lte_band_get_fd_region(enum band_geographical_area region, lte_earfcn_t *earfcn, int max_elems) { int lte_band_get_fd_region(enum band_geographical_area region, lte_earfcn_t *earfcn, int max_elems) {
int i; int i;
int n; int n;
int nof_fd = 0; int nof_fd = 0;
for (i=0;i<NOF_LTE_BANDS && max_elems > 0;i++) { for (i=0;i<NOF_LTE_BANDS && max_elems > 0;i++) {
if (lte_bands[i].area == region) { if (lte_bands[i].area == region) {
n = lte_band_get_fd_band(i, &earfcn[nof_fd], -1, -1, max_elems); n = lte_band_get_fd_band(i, &earfcn[nof_fd], -1, -1, max_elems);
if (n != -1) { if (n != -1) {
nof_fd += n; nof_fd += n;
max_elems -= n; max_elems -= n;
} else { } else {
return -1; return -1;
} }
} }
} }
return nof_fd; return nof_fd;
} }

@ -42,67 +42,67 @@
* Section 7.2 * Section 7.2
*/ */
void generate_prs_c(sequence_t *q, unsigned int seed) { void generate_prs_c(sequence_t *q, unsigned int seed) {
int n; int n;
unsigned int *x1; unsigned int *x1;
unsigned int *x2; unsigned int *x2;
x1 = calloc(Nc + q->len + 31, sizeof(unsigned int)); x1 = calloc(Nc + q->len + 31, sizeof(unsigned int));
if (!x1) { if (!x1) {
perror("calloc"); perror("calloc");
return; return;
} }
x2 = calloc(Nc + q->len + 31, sizeof(unsigned int)); x2 = calloc(Nc + q->len + 31, sizeof(unsigned int));
if (!x2) { if (!x2) {
free(x1); free(x1);
perror("calloc"); perror("calloc");
return; return;
} }
for (n = 0; n < 31; n++) { for (n = 0; n < 31; n++) {
x2[n] = (seed >> n) & 0x1; x2[n] = (seed >> n) & 0x1;
} }
x1[0] = 1; x1[0] = 1;
for (n = 0; n < Nc + q->len; n++) { for (n = 0; n < Nc + q->len; n++) {
x1[n + 31] = (x1[n + 3] + x1[n]) & 0x1; x1[n + 31] = (x1[n + 3] + x1[n]) & 0x1;
x2[n + 31] = (x2[n + 3] + x2[n + 2] + +x2[n+1] + x2[n]) & 0x1; x2[n + 31] = (x2[n + 3] + x2[n + 2] + +x2[n+1] + x2[n]) & 0x1;
} }
for (n = 0; n < q->len; n++) { for (n = 0; n < q->len; n++) {
q->c[n] = (x1[n + Nc] + x2[n + Nc]) & 0x1; q->c[n] = (x1[n + Nc] + x2[n + Nc]) & 0x1;
} }
free(x1); free(x1);
free(x2); free(x2);
} }
int sequence_LTEPRS(sequence_t *q, int len, int seed) { int sequence_LTEPRS(sequence_t *q, int len, int seed) {
if (sequence_init(q, len)) { if (sequence_init(q, len)) {
return -1; return -1;
} }
q->len = len; q->len = len;
generate_prs_c(q, seed); generate_prs_c(q, seed);
return 0; return 0;
} }
int sequence_init(sequence_t *q, int len) { int sequence_init(sequence_t *q, int len) {
if (q->c && (q->len != len)) { if (q->c && (q->len != len)) {
free(q->c); free(q->c);
} }
if (!q->c) { if (!q->c) {
q->c = malloc(len * sizeof(char)); q->c = malloc(len * sizeof(char));
if (!q->c) { if (!q->c) {
return -1; return -1;
} }
} }
return 0; return 0;
} }
void sequence_free(sequence_t *q) { void sequence_free(sequence_t *q) {
if (q->c) { if (q->c) {
free(q->c); free(q->c);
} }
bzero(q, sizeof(sequence_t)); bzero(q, sizeof(sequence_t));
} }

@ -38,104 +38,104 @@ int nof_prb = -1;
lte_cp_t cp = CPNORM; lte_cp_t cp = CPNORM;
void usage(char *prog) { void usage(char *prog) {
printf("Usage: %s\n", prog); printf("Usage: %s\n", prog);
printf("\t-n nof_prb [Default All]\n"); printf("\t-n nof_prb [Default All]\n");
printf("\t-e extended cyclic prefix [Default Normal]\n"); printf("\t-e extended cyclic prefix [Default Normal]\n");
} }
void parse_args(int argc, char **argv) { void parse_args(int argc, char **argv) {
int opt; int opt;
while ((opt = getopt(argc, argv, "ne")) != -1) { while ((opt = getopt(argc, argv, "ne")) != -1) {
switch (opt) { switch (opt) {
case 'n': case 'n':
nof_prb = atoi(argv[optind]); nof_prb = atoi(argv[optind]);
break; break;
case 'e': case 'e':
cp = CPEXT; cp = CPEXT;
break; break;
default: default:
usage(argv[0]); usage(argv[0]);
exit(-1); exit(-1);
} }
} }
} }
int main(int argc, char **argv) { int main(int argc, char **argv) {
lte_fft_t fft, ifft; lte_fft_t fft, ifft;
cf_t *input, *outfft, *outifft; cf_t *input, *outfft, *outifft;
float mse; float mse;
int n_prb, max_prb, n_re; int n_prb, max_prb, n_re;
int i; int i;
parse_args(argc, argv); parse_args(argc, argv);
if (nof_prb == -1) { if (nof_prb == -1) {
n_prb = 6; n_prb = 6;
max_prb = 100; max_prb = 100;
} else { } else {
n_prb = nof_prb; n_prb = nof_prb;
max_prb = nof_prb; max_prb = nof_prb;
} }
while(n_prb <= max_prb) { while(n_prb <= max_prb) {
n_re = CP_NSYMB(cp) * n_prb * RE_X_RB; n_re = CP_NSYMB(cp) * n_prb * RE_X_RB;
printf("Running test for %d PRB, %d RE... ", n_prb, n_re);fflush(stdout); printf("Running test for %d PRB, %d RE... ", n_prb, n_re);fflush(stdout);
input = malloc(sizeof(cf_t) * n_re); input = malloc(sizeof(cf_t) * n_re);
if (!input) { if (!input) {
perror("malloc"); perror("malloc");
exit(-1); exit(-1);
} }
outfft = malloc(sizeof(cf_t) * SLOT_LEN_CPNORM(lte_symbol_sz(n_prb))); outfft = malloc(sizeof(cf_t) * SLOT_LEN_CPNORM(lte_symbol_sz(n_prb)));
if (!outfft) { if (!outfft) {
perror("malloc"); perror("malloc");
exit(-1); exit(-1);
} }
outifft = malloc(sizeof(cf_t) * n_re); outifft = malloc(sizeof(cf_t) * n_re);
if (!outifft) { if (!outifft) {
perror("malloc"); perror("malloc");
exit(-1); exit(-1);
} }
if (lte_fft_init(&fft, cp, n_prb)) { if (lte_fft_init(&fft, cp, n_prb)) {
fprintf(stderr, "Error initializing FFT\n"); fprintf(stderr, "Error initializing FFT\n");
exit(-1); exit(-1);
} }
if (lte_ifft_init(&ifft, cp, n_prb)) { if (lte_ifft_init(&ifft, cp, n_prb)) {
fprintf(stderr, "Error initializing iFFT\n"); fprintf(stderr, "Error initializing iFFT\n");
exit(-1); exit(-1);
} }
for (i=0;i<n_re;i++) { for (i=0;i<n_re;i++) {
input[i] = 100 * ((float) rand()/RAND_MAX + (float) I*rand()/RAND_MAX); input[i] = 100 * ((float) rand()/RAND_MAX + (float) I*rand()/RAND_MAX);
} }
lte_ifft_run(&ifft, input, outfft); lte_ifft_run(&ifft, input, outfft);
lte_fft_run(&fft, outfft, outifft); lte_fft_run(&fft, outfft, outifft);
/* compute MSE */ /* compute MSE */
mse = 0; mse = 0;
for (i=0;i<n_re;i++) { for (i=0;i<n_re;i++) {
mse += cabsf(input[i] - outifft[i]); mse += cabsf(input[i] - outifft[i]);
} }
printf("MSE=%f\n", mse); printf("MSE=%f\n", mse);
if (mse >= 0.07) { if (mse >= 0.07) {
printf("MSE too large\n"); printf("MSE too large\n");
exit(-1); exit(-1);
} }
lte_fft_free(&fft); lte_fft_free(&fft);
lte_ifft_free(&ifft); lte_ifft_free(&ifft);
free(input); free(input);
free(outfft); free(outfft);
free(outifft); free(outifft);
n_prb++; n_prb++;
} }
fftwf_cleanup(); fftwf_cleanup();
exit(0); exit(0);
} }

@ -34,47 +34,47 @@
#include "parity.h" #include "parity.h"
int convcoder_encode(convcoder_t *q, char *input, char *output, int frame_length) { int convcoder_encode(convcoder_t *q, char *input, char *output, int frame_length) {
unsigned int sr; unsigned int sr;
int i,j; int i,j;
int len = q->tail_biting ? frame_length : (frame_length + q->K - 1); int len = q->tail_biting ? frame_length : (frame_length + q->K - 1);
if (q->tail_biting) { if (q->tail_biting) {
sr = 0; sr = 0;
for (i=frame_length - q->K + 1; i<frame_length; i++) { for (i=frame_length - q->K + 1; i<frame_length; i++) {
sr = (sr << 1) | (input[i] & 1); sr = (sr << 1) | (input[i] & 1);
} }
} else { } else {
sr = 0; sr = 0;
} }
for (i = 0; i < len; i++) { for (i = 0; i < len; i++) {
int bit = (i < frame_length) ? (input[i] & 1) : 0; int bit = (i < frame_length) ? (input[i] & 1) : 0;
sr = (sr << 1) | bit; sr = (sr << 1) | bit;
for (j=0;j<q->R;j++) { for (j=0;j<q->R;j++) {
output[q->R * i + j] = parity(sr & q->poly[j]); output[q->R * i + j] = parity(sr & q->poly[j]);
} }
} }
return q->R*len; return q->R*len;
} }
int convcoder_initialize(convcoder_hl* h) { int convcoder_initialize(convcoder_hl* h) {
return 0; return 0;
} }
int convcoder_work(convcoder_hl* hl) { int convcoder_work(convcoder_hl* hl) {
hl->obj.K = hl->ctrl_in.constraint_length; hl->obj.K = hl->ctrl_in.constraint_length;
hl->obj.R = hl->ctrl_in.rate; hl->obj.R = hl->ctrl_in.rate;
hl->obj.poly[0] = hl->ctrl_in.generator_0; hl->obj.poly[0] = hl->ctrl_in.generator_0;
hl->obj.poly[1] = hl->ctrl_in.generator_1; hl->obj.poly[1] = hl->ctrl_in.generator_1;
hl->obj.poly[2] = hl->ctrl_in.generator_2; hl->obj.poly[2] = hl->ctrl_in.generator_2;
hl->obj.tail_biting = hl->ctrl_in.tail_bitting?true:false; hl->obj.tail_biting = hl->ctrl_in.tail_bitting?true:false;
hl->out_len = convcoder_encode(&hl->obj, hl->input, hl->output, hl->in_len); hl->out_len = convcoder_encode(&hl->obj, hl->input, hl->output, hl->in_len);
return 0; return 0;
} }
int convcoder_stop(convcoder_hl* h) { int convcoder_stop(convcoder_hl* h) {
return 0; return 0;
} }

@ -34,121 +34,121 @@
void gen_crc_table(crc_t *h) { void gen_crc_table(crc_t *h) {
int i, j, ord = (h->order - 8); int i, j, ord = (h->order - 8);
unsigned long bit, crc; unsigned long bit, crc;
for (i = 0; i < 256; i++) { for (i = 0; i < 256; i++) {
crc = ((unsigned long) i) << ord; crc = ((unsigned long) i) << ord;
for (j = 0; j < 8; j++) { for (j = 0; j < 8; j++) {
bit = crc & h->crchighbit; bit = crc & h->crchighbit;
crc <<= 1; crc <<= 1;
if (bit) if (bit)
crc ^= h->polynom; crc ^= h->polynom;
} }
h->table[i] = crc & h->crcmask; h->table[i] = crc & h->crcmask;
} }
} }
unsigned long crctable(crc_t *h) { unsigned long crctable(crc_t *h) {
// Polynom order 8, 16, 24 or 32 only. // Polynom order 8, 16, 24 or 32 only.
int ord = h->order - 8; int ord = h->order - 8;
unsigned long crc = h->crcinit; unsigned long crc = h->crcinit;
unsigned char byte = h->byte; unsigned char byte = h->byte;
crc = (crc << 8) ^ h->table[((crc >> (ord)) & 0xff) ^ byte]; crc = (crc << 8) ^ h->table[((crc >> (ord)) & 0xff) ^ byte];
h->crcinit = crc; h->crcinit = crc;
return (crc & h->crcmask); return (crc & h->crcmask);
} }
unsigned long reversecrcbit(unsigned int crc, int nbits, crc_t *h) { 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++) { for (m = 0; m < nbits; m++) {
if ((rmask & crc) == 0x01) if ((rmask & crc) == 0x01)
crc = (crc ^ h->polynom) >> 1; crc = (crc ^ h->polynom) >> 1;
else else
crc = crc >> 1; crc = crc >> 1;
} }
return (crc & h->crcmask); return (crc & h->crcmask);
} }
int crc_set_init(crc_t *crc_par, unsigned long crc_init_value) { int crc_set_init(crc_t *crc_par, unsigned long crc_init_value) {
crc_par->crcinit = crc_init_value; crc_par->crcinit = crc_init_value;
if (crc_par->crcinit != (crc_par->crcinit & crc_par->crcmask)) { if (crc_par->crcinit != (crc_par->crcinit & crc_par->crcmask)) {
printf("ERROR, invalid crcinit in crc_set_init().\n"); printf("ERROR, invalid crcinit in crc_set_init().\n");
return -1; return -1;
} }
return 0; return 0;
} }
int crc_init(crc_t *h, unsigned int crc_poly, int crc_order) { int crc_init(crc_t *h, unsigned int crc_poly, int crc_order) {
// Set crc working default parameters // Set crc working default parameters
h->polynom = crc_poly; h->polynom = crc_poly;
h->order = crc_order; h->order = crc_order;
h->crcinit = 0x00000000; h->crcinit = 0x00000000;
// Compute bit masks for whole CRC and CRC high bit // Compute bit masks for whole CRC and CRC high bit
h->crcmask = ((((unsigned long) 1 << (h->order - 1)) - 1) << 1) h->crcmask = ((((unsigned long) 1 << (h->order - 1)) - 1) << 1)
| 1; | 1;
h->crchighbit = (unsigned long) 1 << (h->order - 1); h->crchighbit = (unsigned long) 1 << (h->order - 1);
// check parameters // check parameters
if (h->order % 8 != 0) { if (h->order % 8 != 0) {
fprintf(stderr, "ERROR, invalid order=%d, it must be 8, 16, 24 or 32.\n", fprintf(stderr, "ERROR, invalid order=%d, it must be 8, 16, 24 or 32.\n",
h->order); h->order);
return -1; return -1;
} }
if (crc_set_init(h, h->crcinit)) { if (crc_set_init(h, h->crcinit)) {
fprintf(stderr, "Error setting CRC init word\n"); fprintf(stderr, "Error setting CRC init word\n");
return -1; return -1;
} }
// generate lookup table // generate lookup table
gen_crc_table(h); gen_crc_table(h);
return 0; return 0;
} }
unsigned int crc_checksum(crc_t *h, char *data, int len) { unsigned int crc_checksum(crc_t *h, char *data, int len) {
int i, k, len8, res8, a = 0; int i, k, len8, res8, a = 0;
unsigned int crc = 0; unsigned int crc = 0;
char *pter; char *pter;
crc_set_init(h, 0); crc_set_init(h, 0);
// Pack bits into bytes // Pack bits into bytes
len8 = (len >> 3); len8 = (len >> 3);
res8 = (len - (len8 << 3)); res8 = (len - (len8 << 3));
if (res8 > 0) { if (res8 > 0) {
a = 1; a = 1;
} }
// Calculate CRC // Calculate CRC
for (i = 0; i < len8 + a; i++) { for (i = 0; i < len8 + a; i++) {
pter = (char *) (data + 8 * i); pter = (char *) (data + 8 * i);
if (i == len8) { if (i == len8) {
h->byte = 0x00; h->byte = 0x00;
for (k = 0; k < res8; k++) { for (k = 0; k < res8; k++) {
h->byte |= ((unsigned char) *(pter + k)) << (7 - k); h->byte |= ((unsigned char) *(pter + k)) << (7 - k);
} }
} else { } else {
h->byte = (unsigned char) (unpack_bits(&pter, 8) & 0xFF); h->byte = (unsigned char) (unpack_bits(&pter, 8) & 0xFF);
} }
crc = crctable(h); crc = crctable(h);
} }
// Reverse CRC res8 positions // Reverse CRC res8 positions
if (a == 1) { if (a == 1) {
crc = reversecrcbit(crc, 8 - res8, h); crc = reversecrcbit(crc, 8 - res8, h);
} }
//Return CRC value //Return CRC value
return crc; return crc;
} }
@ -156,10 +156,10 @@ unsigned int crc_checksum(crc_t *h, char *data, int len) {
* The buffer data must be len + crc_order bytes * The buffer data must be len + crc_order bytes
*/ */
void crc_attach(crc_t *h, char *data, int len) { void crc_attach(crc_t *h, char *data, int len) {
unsigned int checksum = crc_checksum(h, data, len); unsigned int checksum = crc_checksum(h, data, len);
// Add CRC // Add CRC
char *ptr = &data[len]; char *ptr = &data[len];
pack_bits(checksum, &ptr, h->order); pack_bits(checksum, &ptr, h->order);
} }

@ -35,58 +35,58 @@
#define RATE 3 #define RATE 3
unsigned char RM_CONV_PERM_TC[NCOLS] = unsigned char RM_CONV_PERM_TC[NCOLS] =
{ 1, 17, 9, 25, 5, 21, 13, 29, 3, 19, 11, 27, 7, 23, 15, 31, 0, 16, 8, { 1, 17, 9, 25, 5, 21, 13, 29, 3, 19, 11, 27, 7, 23, 15, 31, 0, 16, 8,
24, 4, 20, 12, 28, 2, 18, 10, 26, 6, 22, 14, 30 }; 24, 4, 20, 12, 28, 2, 18, 10, 26, 6, 22, 14, 30 };
unsigned char RM_CONV_PERM_TC_INV[NCOLS] = { 16, 0, 24, 8, 20, 4, 28, 12, 18, 2, 26, unsigned char RM_CONV_PERM_TC_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, 10, 22, 6, 30, 14, 17, 1, 25, 9, 21, 5, 29, 13, 19, 3, 27, 11, 23, 7,
31, 15 }; 31, 15 };
int rm_conv_tx(char *input, int in_len, char *output, int out_len) { int rm_conv_tx(char *input, int in_len, char *output, int out_len) {
char tmp[RATE * NCOLS * NROWS_MAX]; char tmp[RATE * NCOLS * NROWS_MAX];
int nrows, ndummy, K_p; int nrows, ndummy, K_p;
int i, j, k, s; int i, j, k, s;
nrows = (int) (in_len / RATE - 1) / NCOLS + 1; nrows = (int) (in_len / RATE - 1) / NCOLS + 1;
if (nrows > NROWS_MAX) { if (nrows > NROWS_MAX) {
fprintf(stderr, "Input too large. Max input length is %d\n", fprintf(stderr, "Input too large. Max input length is %d\n",
RATE * NCOLS * NROWS_MAX); RATE * NCOLS * NROWS_MAX);
return -1; return -1;
} }
K_p = nrows * NCOLS; K_p = nrows * NCOLS;
ndummy = K_p - in_len / RATE; ndummy = K_p - in_len / RATE;
if (ndummy < 0) { if (ndummy < 0) {
ndummy = 0; ndummy = 0;
} }
/* Sub-block interleaver 5.1.4.2.1 */ /* Sub-block interleaver 5.1.4.2.1 */
k=0; k=0;
for (s = 0; s < 3; s++) { for (s = 0; s < 3; s++) {
for (j = 0; j < NCOLS; j++) { for (j = 0; j < NCOLS; j++) {
for (i = 0; i < nrows; i++) { for (i = 0; i < nrows; i++) {
if (i*NCOLS + RM_CONV_PERM_TC[j] < ndummy) { if (i*NCOLS + RM_CONV_PERM_TC[j] < ndummy) {
tmp[k] = TX_NULL; tmp[k] = TX_NULL;
} else { } else {
tmp[k] = input[(i*NCOLS + RM_CONV_PERM_TC[j]-ndummy)*3+s]; tmp[k] = input[(i*NCOLS + RM_CONV_PERM_TC[j]-ndummy)*3+s];
} }
k++; k++;
} }
} }
} }
/* Bit collection, selection and transmission 5.1.4.2.2 */ /* Bit collection, selection and transmission 5.1.4.2.2 */
k = 0; k = 0;
j = 0; j = 0;
while (k < out_len) { while (k < out_len) {
if (tmp[j] != TX_NULL) { if (tmp[j] != TX_NULL) {
output[k] = tmp[j]; output[k] = tmp[j];
k++; k++;
} }
j++; j++;
if (j == RATE * K_p) { if (j == RATE * K_p) {
j = 0; j = 0;
} }
} }
return 0; return 0;
} }
@ -95,87 +95,87 @@ int rm_conv_tx(char *input, int in_len, char *output, int out_len) {
*/ */
int rm_conv_rx(float *input, int in_len, float *output, int out_len) { int rm_conv_rx(float *input, int in_len, float *output, int out_len) {
int nrows, ndummy, K_p; int nrows, ndummy, K_p;
int i, j, k; int i, j, k;
int d_i, d_j; int d_i, d_j;
float tmp[RATE * NCOLS * NROWS_MAX]; float tmp[RATE * NCOLS * NROWS_MAX];
nrows = (int) (out_len / RATE - 1) / NCOLS + 1; nrows = (int) (out_len / RATE - 1) / NCOLS + 1;
if (nrows > NROWS_MAX) { if (nrows > NROWS_MAX) {
fprintf(stderr, "Output too large. Max output length is %d\n", fprintf(stderr, "Output too large. Max output length is %d\n",
RATE * NCOLS * NROWS_MAX); RATE * NCOLS * NROWS_MAX);
return -1; return -1;
} }
K_p = nrows * NCOLS; K_p = nrows * NCOLS;
ndummy = K_p - out_len / RATE; ndummy = K_p - out_len / RATE;
if (ndummy < 0) { if (ndummy < 0) {
ndummy = 0; ndummy = 0;
} }
for (i = 0; i < RATE * K_p; i++) { for (i = 0; i < RATE * K_p; i++) {
tmp[i] = RX_NULL; tmp[i] = RX_NULL;
} }
/* Undo bit collection. Account for dummy bits */ /* Undo bit collection. Account for dummy bits */
k = 0; k = 0;
j = 0; j = 0;
while (k < in_len) { while (k < in_len) {
d_i = (j % K_p) / nrows; d_i = (j % K_p) / nrows;
d_j = (j % K_p) % nrows; d_j = (j % K_p) % nrows;
if (d_j * NCOLS + RM_CONV_PERM_TC[d_i] >= ndummy) { if (d_j * NCOLS + RM_CONV_PERM_TC[d_i] >= ndummy) {
if (tmp[j] == RX_NULL) { if (tmp[j] == RX_NULL) {
tmp[j] = input[k]; tmp[j] = input[k];
} else if (input[k] != RX_NULL) { } else if (input[k] != RX_NULL) {
tmp[j] += input[k]; /* soft combine LLRs */ tmp[j] += input[k]; /* soft combine LLRs */
} }
k++; k++;
} }
j++; j++;
if (j == RATE * K_p) { if (j == RATE * K_p) {
j = 0; j = 0;
} }
} }
/* interleaving and bit selection */ /* interleaving and bit selection */
for (i = 0; i < out_len / RATE; i++) { for (i = 0; i < out_len / RATE; i++) {
d_i = (i + ndummy) / NCOLS; d_i = (i + ndummy) / NCOLS;
d_j = (i + ndummy) % NCOLS; d_j = (i + ndummy) % NCOLS;
for (j = 0; j < RATE; j++) { for (j = 0; j < RATE; j++) {
float o = tmp[K_p * j + RM_CONV_PERM_TC_INV[d_j] * nrows float o = tmp[K_p * j + RM_CONV_PERM_TC_INV[d_j] * nrows
+ d_i]; + d_i];
if (o != RX_NULL) { if (o != RX_NULL) {
output[i * RATE + j] = o; output[i * RATE + j] = o;
} else { } else {
output[i * RATE + j] = 0; output[i * RATE + j] = 0;
} }
} }
} }
return 0; return 0;
} }
/** High-level API */ /** High-level API */
int rm_conv_initialize(rm_conv_hl* h) { int rm_conv_initialize(rm_conv_hl* h) {
return 0; return 0;
} }
/** This function can be called in a subframe (1ms) basis */ /** This function can be called in a subframe (1ms) basis */
int rm_conv_work(rm_conv_hl* hl) { int rm_conv_work(rm_conv_hl* hl) {
if (hl->init.direction) { if (hl->init.direction) {
//rm_conv_tx(hl->input, hl->output, hl->in_len, hl->ctrl_in.S); //rm_conv_tx(hl->input, hl->output, hl->in_len, hl->ctrl_in.S);
hl->out_len = hl->ctrl_in.S; hl->out_len = hl->ctrl_in.S;
} else { } else {
rm_conv_rx(hl->input, hl->output, hl->in_len, hl->ctrl_in.E); rm_conv_rx(hl->input, hl->output, hl->in_len, hl->ctrl_in.E);
hl->out_len = hl->ctrl_in.E; hl->out_len = hl->ctrl_in.E;
} }
return 0; return 0;
} }
int rm_conv_stop(rm_conv_hl* hl) { int rm_conv_stop(rm_conv_hl* hl) {
return 0; return 0;
} }

@ -38,28 +38,28 @@
#define RATE 3 #define RATE 3
unsigned char RM_PERM_TC[NCOLS] = unsigned char RM_PERM_TC[NCOLS] =
{ 0, 16, 8, 24, 4, 20, 12, 28, 2, 18, 10, 26, 6, 22, 14, 30, 1, 17, 9, { 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 }; 25, 5, 21, 13, 29, 3, 19, 11, 27, 7, 23, 15, 31 };
int rm_turbo_init(rm_turbo_t *q, int buffer_len) { int rm_turbo_init(rm_turbo_t *q, int buffer_len) {
q->buffer_len = buffer_len; q->buffer_len = buffer_len;
q->buffer = malloc(buffer_len * sizeof(float)); q->buffer = malloc(buffer_len * sizeof(float));
if (!q->buffer) { if (!q->buffer) {
perror("malloc"); perror("malloc");
return -1; return -1;
} }
q->d2_perm = malloc(buffer_len * sizeof(int) / 3 + 1); q->d2_perm = malloc(buffer_len * sizeof(int) / 3 + 1);
if (!q->d2_perm) { if (!q->d2_perm) {
perror("malloc"); perror("malloc");
return -1; return -1;
} }
return 0; return 0;
} }
void rm_turbo_free(rm_turbo_t *q) { void rm_turbo_free(rm_turbo_t *q) {
if (q->buffer) { if (q->buffer) {
free(q->buffer); free(q->buffer);
} }
} }
/* Turbo Code Rate Matching. /* Turbo Code Rate Matching.
@ -69,71 +69,71 @@ void rm_turbo_free(rm_turbo_t *q) {
*/ */
int rm_turbo_tx(rm_turbo_t *q, char *input, int in_len, char *output, int out_len, int rv_idx) { int rm_turbo_tx(rm_turbo_t *q, char *input, int in_len, char *output, int out_len, int rv_idx) {
char *tmp = (char*) q->buffer; char *tmp = (char*) q->buffer;
int nrows, ndummy, K_p; int nrows, ndummy, K_p;
int i, j, k, s, kidx, N_cb, k0; int i, j, k, s, kidx, N_cb, k0;
nrows = (int) (in_len / RATE - 1) / NCOLS + 1; nrows = (int) (in_len / RATE - 1) / NCOLS + 1;
K_p = nrows * NCOLS; K_p = nrows * NCOLS;
if (3 * K_p > q->buffer_len) { if (3 * K_p > q->buffer_len) {
fprintf(stderr, fprintf(stderr,
"Input too large. Max input length including dummy bits is %d\n", "Input too large. Max input length including dummy bits is %d\n",
q->buffer_len); q->buffer_len);
return -1; return -1;
} }
ndummy = K_p - in_len / RATE; ndummy = K_p - in_len / RATE;
if (ndummy < 0) { if (ndummy < 0) {
ndummy = 0; ndummy = 0;
} }
/* Sub-block interleaver (5.1.4.1.1) and bit collection */ /* Sub-block interleaver (5.1.4.1.1) and bit collection */
k = 0; k = 0;
for (s = 0; s < 2; s++) { for (s = 0; s < 2; s++) {
for (j = 0; j < NCOLS; j++) { for (j = 0; j < NCOLS; j++) {
for (i = 0; i < nrows; i++) { for (i = 0; i < nrows; i++) {
if (s == 0) { if (s == 0) {
kidx = k%K_p; kidx = k%K_p;
} else { } else {
kidx = K_p + 2 * (k%K_p); kidx = K_p + 2 * (k%K_p);
} }
if (i * NCOLS + RM_PERM_TC[j] < ndummy) { if (i * NCOLS + RM_PERM_TC[j] < ndummy) {
tmp[kidx] = TX_NULL; tmp[kidx] = TX_NULL;
} else { } else {
tmp[kidx] = input[(i * NCOLS + RM_PERM_TC[j] - ndummy) * 3 + s]; tmp[kidx] = input[(i * NCOLS + RM_PERM_TC[j] - ndummy) * 3 + s];
} }
k++; k++;
} }
} }
} }
// d_k^(2) goes through special permutation // d_k^(2) goes through special permutation
for (k = 0; k < K_p; k++) { for (k = 0; k < K_p; k++) {
kidx = (RM_PERM_TC[k / nrows] + NCOLS * (k % nrows) + 1) % K_p; kidx = (RM_PERM_TC[k / nrows] + NCOLS * (k % nrows) + 1) % K_p;
if ((kidx - ndummy) < 0) { if ((kidx - ndummy) < 0) {
tmp[K_p + 2 * k + 1] = TX_NULL; tmp[K_p + 2 * k + 1] = TX_NULL;
} else { } else {
tmp[K_p + 2 * k + 1] = input[3 * (kidx - ndummy) + 2]; tmp[K_p + 2 * k + 1] = input[3 * (kidx - ndummy) + 2];
} }
} }
/* Bit selection and transmission 5.1.4.1.2 */ /* Bit selection and transmission 5.1.4.1.2 */
N_cb = 3 * K_p; // TODO: Soft buffer size limitation N_cb = 3 * K_p; // TODO: Soft buffer size limitation
k0 = nrows * (2 * (int) ceilf((float) N_cb / (float) (8 * nrows)) k0 = nrows * (2 * (int) ceilf((float) N_cb / (float) (8 * nrows))
* rv_idx + 2); * rv_idx + 2);
k = 0; k = 0;
j = 0; j = 0;
while (k < out_len) { while (k < out_len) {
if (tmp[(k0 + j) % N_cb] != TX_NULL) { if (tmp[(k0 + j) % N_cb] != TX_NULL) {
output[k] = tmp[(k0 + j) % N_cb]; output[k] = tmp[(k0 + j) % N_cb];
k++; k++;
} }
j++; j++;
} }
return 0; return 0;
} }
/* Undoes Turbo Code Rate Matching. /* Undoes Turbo Code Rate Matching.
@ -141,122 +141,122 @@ int rm_turbo_tx(rm_turbo_t *q, char *input, int in_len, char *output, int out_le
*/ */
int rm_turbo_rx(rm_turbo_t *q, float *input, int in_len, float *output, int out_len, int rv_idx) { int rm_turbo_rx(rm_turbo_t *q, float *input, int in_len, float *output, int out_len, int rv_idx) {
int nrows, ndummy, K_p, k0, N_cb, jp, kidx; int nrows, ndummy, K_p, k0, N_cb, jp, kidx;
int i, j, k; int i, j, k;
int d_i, d_j; int d_i, d_j;
bool isdummy; bool isdummy;
float *tmp = (float*) q->buffer; float *tmp = (float*) q->buffer;
nrows = (int) (out_len / RATE - 1) / NCOLS + 1; nrows = (int) (out_len / RATE - 1) / NCOLS + 1;
K_p = nrows * NCOLS; K_p = nrows * NCOLS;
if (3 * K_p > q->buffer_len) { if (3 * K_p > q->buffer_len) {
fprintf(stderr, fprintf(stderr,
"Input too large. Max input length including dummy bits is %d\n", "Input too large. Max input length including dummy bits is %d\n",
q->buffer_len); q->buffer_len);
return -1; return -1;
} }
ndummy = K_p - out_len / RATE; ndummy = K_p - out_len / RATE;
if (ndummy < 0) { if (ndummy < 0) {
ndummy = 0; ndummy = 0;
} }
for (i = 0; i < RATE * K_p; i++) { for (i = 0; i < RATE * K_p; i++) {
tmp[i] = RX_NULL; tmp[i] = RX_NULL;
} }
/* Undo bit collection. Account for dummy bits */ /* Undo bit collection. Account for dummy bits */
N_cb = 3 * K_p; // TODO: Soft buffer size limitation N_cb = 3 * K_p; // TODO: Soft buffer size limitation
k0 = nrows * (2 * (int) ceilf((float) N_cb / (float) (8 * nrows)) k0 = nrows * (2 * (int) ceilf((float) N_cb / (float) (8 * nrows))
* rv_idx + 2); * rv_idx + 2);
k = 0; k = 0;
j = 0; j = 0;
while (k < in_len) { while (k < in_len) {
jp = (k0 + j) % N_cb; jp = (k0 + j) % N_cb;
if (jp == 32 || jp == 95 || jp == 0) { if (jp == 32 || jp == 95 || jp == 0) {
i=0; i=0;
} }
if (jp < K_p || !(jp%2)) { if (jp < K_p || !(jp%2)) {
if (jp >= K_p) { if (jp >= K_p) {
d_i = ((jp-K_p) / 2) / nrows; d_i = ((jp-K_p) / 2) / nrows;
d_j = ((jp-K_p) / 2) % nrows; d_j = ((jp-K_p) / 2) % nrows;
} else { } else {
d_i = jp / nrows; d_i = jp / nrows;
d_j = jp % nrows; d_j = jp % nrows;
} }
if (d_j * NCOLS + RM_PERM_TC[d_i] >= ndummy) { if (d_j * NCOLS + RM_PERM_TC[d_i] >= ndummy) {
isdummy = false; isdummy = false;
} else { } else {
isdummy = true; isdummy = true;
} }
} else { } else {
int jpp = (jp-K_p-1)/2; int jpp = (jp-K_p-1)/2;
kidx = (RM_PERM_TC[jpp / nrows] + NCOLS * (jpp % nrows) + 1) % K_p; kidx = (RM_PERM_TC[jpp / nrows] + NCOLS * (jpp % nrows) + 1) % K_p;
q->d2_perm[kidx] = jpp; // save the permutation in a temporary buffer q->d2_perm[kidx] = jpp; // save the permutation in a temporary buffer
if ((kidx - ndummy) < 0) { if ((kidx - ndummy) < 0) {
isdummy = true; isdummy = true;
} else { } else {
isdummy = false; isdummy = false;
} }
} }
if (!isdummy) { if (!isdummy) {
if (tmp[jp] == RX_NULL) { if (tmp[jp] == RX_NULL) {
tmp[jp] = input[k]; tmp[jp] = input[k];
} else if (input[k] != RX_NULL) { } else if (input[k] != RX_NULL) {
tmp[jp] += input[k]; /* soft combine LLRs */ tmp[jp] += input[k]; /* soft combine LLRs */
} }
k++; k++;
} }
j++; j++;
} }
/* interleaving and bit selection */ /* interleaving and bit selection */
for (i = 0; i < out_len / RATE; i++) { for (i = 0; i < out_len / RATE; i++) {
d_i = (i + ndummy) / NCOLS; d_i = (i + ndummy) / NCOLS;
d_j = (i + ndummy) % NCOLS; d_j = (i + ndummy) % NCOLS;
for (j = 0; j < RATE; j++) { for (j = 0; j < RATE; j++) {
if (j != 2) { if (j != 2) {
kidx = K_p * j + (j+1)*(RM_PERM_TC[d_j] * nrows + d_i); kidx = K_p * j + (j+1)*(RM_PERM_TC[d_j] * nrows + d_i);
} else { } else {
// use the saved permuatation function to avoid computing the inverse // use the saved permuatation function to avoid computing the inverse
kidx = 2*q->d2_perm[(i+ndummy)%K_p]+K_p+1; kidx = 2*q->d2_perm[(i+ndummy)%K_p]+K_p+1;
} }
float o = tmp[kidx]; float o = tmp[kidx];
if (o != RX_NULL) { if (o != RX_NULL) {
output[i * RATE + j] = o; output[i * RATE + j] = o;
} else { } else {
output[i * RATE + j] = 0; output[i * RATE + j] = 0;
} }
} }
} }
return 0; return 0;
} }
/** High-level API */ /** High-level API */
int rm_turbo_initialize(rm_turbo_hl* h) { int rm_turbo_initialize(rm_turbo_hl* h) {
return rm_turbo_init(&h->q, 7000); return rm_turbo_init(&h->q, 7000);
} }
/** This function can be called in a subframe (1ms) basis */ /** This function can be called in a subframe (1ms) basis */
int rm_turbo_work(rm_turbo_hl* hl) { int rm_turbo_work(rm_turbo_hl* hl) {
if (hl->init.direction) { if (hl->init.direction) {
rm_turbo_tx(&hl->q, hl->input, hl->in_len, hl->output, hl->ctrl_in.E, hl->ctrl_in.rv_idx); rm_turbo_tx(&hl->q, hl->input, hl->in_len, hl->output, hl->ctrl_in.E, hl->ctrl_in.rv_idx);
hl->out_len = hl->ctrl_in.E; hl->out_len = hl->ctrl_in.E;
} else { } else {
rm_turbo_rx(&hl->q, hl->input, hl->in_len, hl->output, hl->ctrl_in.S, hl->ctrl_in.rv_idx); rm_turbo_rx(&hl->q, hl->input, hl->in_len, hl->output, hl->ctrl_in.S, hl->ctrl_in.rv_idx);
hl->out_len = hl->ctrl_in.S; hl->out_len = hl->ctrl_in.S;
} }
return 0; return 0;
} }
int rm_turbo_stop(rm_turbo_hl* hl) { int rm_turbo_stop(rm_turbo_hl* hl) {
rm_turbo_free(&hl->q); rm_turbo_free(&hl->q);
return 0; return 0;
} }

@ -40,68 +40,68 @@
************************************************/ ************************************************/
const int f1_list[NOF_TC_CB_SIZES] = { 3, 7, 19, 7, 7, 11, 5, 11, 7, 41, 103, 15, 9, 17, const int f1_list[NOF_TC_CB_SIZES] = { 3, 7, 19, 7, 7, 11, 5, 11, 7, 41, 103, 15, 9, 17,
9, 21, 101, 21, 57, 23, 13, 27, 11, 27, 85, 29, 33, 15, 17, 33, 103, 19, 9, 21, 101, 21, 57, 23, 13, 27, 11, 27, 85, 29, 33, 15, 17, 33, 103, 19,
19, 37, 19, 21, 21, 115, 193, 21, 133, 81, 45, 23, 243, 151, 155, 25, 19, 37, 19, 21, 21, 115, 193, 21, 133, 81, 45, 23, 243, 151, 155, 25,
51, 47, 91, 29, 29, 247, 29, 89, 91, 157, 55, 31, 17, 35, 227, 65, 19, 51, 47, 91, 29, 29, 247, 29, 89, 91, 157, 55, 31, 17, 35, 227, 65, 19,
37, 41, 39, 185, 43, 21, 155, 79, 139, 23, 217, 25, 17, 127, 25, 239, 37, 41, 39, 185, 43, 21, 155, 79, 139, 23, 217, 25, 17, 127, 25, 239,
17, 137, 215, 29, 15, 147, 29, 59, 65, 55, 31, 17, 171, 67, 35, 19, 39, 17, 137, 215, 29, 15, 147, 29, 59, 65, 55, 31, 17, 171, 67, 35, 19, 39,
19, 199, 21, 211, 21, 43, 149, 45, 49, 71, 13, 17, 25, 183, 55, 127, 27, 19, 199, 21, 211, 21, 43, 149, 45, 49, 71, 13, 17, 25, 183, 55, 127, 27,
29, 29, 57, 45, 31, 59, 185, 113, 31, 17, 171, 209, 253, 367, 265, 181, 29, 29, 57, 45, 31, 59, 185, 113, 31, 17, 171, 209, 253, 367, 265, 181,
39, 27, 127, 143, 43, 29, 45, 157, 47, 13, 111, 443, 51, 51, 451, 257, 39, 27, 127, 143, 43, 29, 45, 157, 47, 13, 111, 443, 51, 51, 451, 257,
57, 313, 271, 179, 331, 363, 375, 127, 31, 33, 43, 33, 477, 35, 233, 57, 313, 271, 179, 331, 363, 375, 127, 31, 33, 43, 33, 477, 35, 233,
357, 337, 37, 71, 71, 37, 39, 127, 39, 39, 31, 113, 41, 251, 43, 21, 43, 357, 337, 37, 71, 71, 37, 39, 127, 39, 39, 31, 113, 41, 251, 43, 21, 43,
45, 45, 161, 89, 323, 47, 23, 47, 263 }; 45, 45, 161, 89, 323, 47, 23, 47, 263 };
const int f2_list[NOF_TC_CB_SIZES] = { 10, 12, 42, 16, 18, 20, 22, 24, 26, 84, 90, 32, const int f2_list[NOF_TC_CB_SIZES] = { 10, 12, 42, 16, 18, 20, 22, 24, 26, 84, 90, 32,
34, 108, 38, 120, 84, 44, 46, 48, 50, 52, 36, 56, 58, 60, 62, 32, 198, 34, 108, 38, 120, 84, 44, 46, 48, 50, 52, 36, 56, 58, 60, 62, 32, 198,
68, 210, 36, 74, 76, 78, 120, 82, 84, 86, 44, 90, 46, 94, 48, 98, 40, 68, 210, 36, 74, 76, 78, 120, 82, 84, 86, 44, 90, 46, 94, 48, 98, 40,
102, 52, 106, 72, 110, 168, 114, 58, 118, 180, 122, 62, 84, 64, 66, 68, 102, 52, 106, 72, 110, 168, 114, 58, 118, 180, 122, 62, 84, 64, 66, 68,
420, 96, 74, 76, 234, 80, 82, 252, 86, 44, 120, 92, 94, 48, 98, 80, 102, 420, 96, 74, 76, 234, 80, 82, 252, 86, 44, 120, 92, 94, 48, 98, 80, 102,
52, 106, 48, 110, 112, 114, 58, 118, 60, 122, 124, 84, 64, 66, 204, 140, 52, 106, 48, 110, 112, 114, 58, 118, 60, 122, 124, 84, 64, 66, 204, 140,
72, 74, 76, 78, 240, 82, 252, 86, 88, 60, 92, 846, 48, 28, 80, 102, 104, 72, 74, 76, 78, 240, 82, 252, 86, 88, 60, 92, 846, 48, 28, 80, 102, 104,
954, 96, 110, 112, 114, 116, 354, 120, 610, 124, 420, 64, 66, 136, 420, 954, 96, 110, 112, 114, 116, 354, 120, 610, 124, 420, 64, 66, 136, 420,
216, 444, 456, 468, 80, 164, 504, 172, 88, 300, 92, 188, 96, 28, 240, 216, 444, 456, 468, 80, 164, 504, 172, 88, 300, 92, 188, 96, 28, 240,
204, 104, 212, 192, 220, 336, 228, 232, 236, 120, 244, 248, 168, 64, 204, 104, 212, 192, 220, 336, 228, 232, 236, 120, 244, 248, 168, 64,
130, 264, 134, 408, 138, 280, 142, 480, 146, 444, 120, 152, 462, 234, 130, 264, 134, 408, 138, 280, 142, 480, 146, 444, 120, 152, 462, 234,
158, 80, 96, 902, 166, 336, 170, 86, 174, 176, 178, 120, 182, 184, 186, 158, 80, 96, 902, 166, 336, 170, 86, 174, 176, 178, 120, 182, 184, 186,
94, 190, 480 }; 94, 190, 480 };
int tc_interl_LTE_init(tc_interl_t *h, int long_cb) { int tc_interl_LTE_init(tc_interl_t *h, int long_cb) {
int cb_table_idx, f1, f2; int cb_table_idx, f1, f2;
unsigned long long i, j; unsigned long long i, j;
cb_table_idx = lte_find_cb_index(long_cb); cb_table_idx = lte_find_cb_index(long_cb);
if (cb_table_idx == -1) { if (cb_table_idx == -1) {
fprintf(stderr, "Can't find long_cb=%d in valid TC CB table\n", long_cb); fprintf(stderr, "Can't find long_cb=%d in valid TC CB table\n", long_cb);
return -1; return -1;
} }
h->forward = h->reverse = NULL; h->forward = h->reverse = NULL;
h->forward = malloc(sizeof(int) * (long_cb)); h->forward = malloc(sizeof(int) * (long_cb));
if (!h->forward) { if (!h->forward) {
return -1; return -1;
} }
h->reverse = malloc(sizeof(int) * (long_cb)); h->reverse = malloc(sizeof(int) * (long_cb));
if (!h->reverse) { if (!h->reverse) {
perror("malloc"); perror("malloc");
free(h->forward); free(h->forward);
h->forward = h->reverse = NULL; h->forward = h->reverse = NULL;
return -1; return -1;
} }
f1 = f1_list[cb_table_idx]; f1 = f1_list[cb_table_idx];
f2 = f2_list[cb_table_idx]; f2 = f2_list[cb_table_idx];
DEBUG("table_idx: %d, f1: %d, f2: %d\n", cb_table_idx, f1, f2); DEBUG("table_idx: %d, f1: %d, f2: %d\n", cb_table_idx, f1, f2);
h->forward[0] = 0; h->forward[0] = 0;
h->reverse[0] = 0; h->reverse[0] = 0;
for (i = 1; i < long_cb; i++) { for (i = 1; i < long_cb; i++) {
j = (f1*i + f2*i*i) % (long_cb); j = (f1*i + f2*i*i) % (long_cb);
h->forward[i] = j; h->forward[i] = j;
h->reverse[j] = i; h->reverse[j] = i;
} }
return 0; return 0;
} }

@ -31,7 +31,7 @@
#include "lte/fec/tc_interl.h" #include "lte/fec/tc_interl.h"
#include "lte/fec/turbocoder.h" #include "lte/fec/turbocoder.h"
#define TURBO_RATE 3 #define TURBO_RATE 3
int mcd(int x, int y); int mcd(int x, int y);
@ -41,217 +41,217 @@ int mcd(int x, int y);
* *
************************************************/ ************************************************/
#define MAX_ROWS 20 #define MAX_ROWS 20
#define MAX_COLS 256 #define MAX_COLS 256
const unsigned short table_p[52] = { 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, const unsigned short table_p[52] = { 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43,
47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113,
127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193,
197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257 }; 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257 };
const unsigned char table_v[52] = { 3, 2, 2, 3, 2, 5, 2, 3, 2, 6, 3, 5, 2, 2, 2, const unsigned char table_v[52] = { 3, 2, 2, 3, 2, 5, 2, 3, 2, 6, 3, 5, 2, 2, 2,
2, 7, 5, 3, 2, 3, 5, 2, 5, 2, 6, 3, 3, 2, 3, 2, 2, 6, 5, 2, 5, 2, 2, 2, 2, 7, 5, 3, 2, 3, 5, 2, 5, 2, 6, 3, 3, 2, 3, 2, 2, 6, 5, 2, 5, 2, 2, 2,
19, 5, 2, 3, 2, 3, 2, 6, 3, 7, 7, 6, 3 }; 19, 5, 2, 3, 2, 3, 2, 6, 3, 7, 7, 6, 3 };
void tc_interl_free(tc_interl_t *h) { void tc_interl_free(tc_interl_t *h) {
if (h->forward) { if (h->forward) {
free(h->forward); free(h->forward);
} }
if (h->reverse) { if (h->reverse) {
free(h->reverse); free(h->reverse);
} }
h->forward = h->reverse = NULL; h->forward = h->reverse = NULL;
} }
int tc_interl_UMTS_init(tc_interl_t *h, int long_cb) { int tc_interl_UMTS_init(tc_interl_t *h, int long_cb) {
int i, j; int i, j;
int res, prim, aux; int res, prim, aux;
int kp, k; int kp, k;
int *per, *desper; int *per, *desper;
unsigned char v; unsigned char v;
unsigned short p; unsigned short p;
unsigned short s[MAX_COLS], q[MAX_ROWS], r[MAX_ROWS], T[MAX_ROWS]; unsigned short s[MAX_COLS], q[MAX_ROWS], r[MAX_ROWS], T[MAX_ROWS];
unsigned short U[MAX_COLS * MAX_ROWS]; unsigned short U[MAX_COLS * MAX_ROWS];
int M_Rows, M_Cols, M_long; int M_Rows, M_Cols, M_long;
h->forward = h->reverse = NULL; h->forward = h->reverse = NULL;
h->forward = malloc(sizeof(int) * (long_cb)); h->forward = malloc(sizeof(int) * (long_cb));
if (!h->forward) { if (!h->forward) {
return -1; return -1;
} }
h->reverse = malloc(sizeof(int) * (long_cb)); h->reverse = malloc(sizeof(int) * (long_cb));
if (!h->reverse) { if (!h->reverse) {
perror("malloc"); perror("malloc");
free(h->forward); free(h->forward);
h->forward = h->reverse = NULL; h->forward = h->reverse = NULL;
return -1; return -1;
} }
M_long = long_cb; M_long = long_cb;
/* Find R*/ /* Find R*/
if ((40 <= M_long) && (M_long <= 159)) if ((40 <= M_long) && (M_long <= 159))
M_Rows = 5; M_Rows = 5;
else if (((160 <= M_long) && (M_long <= 200)) else if (((160 <= M_long) && (M_long <= 200))
|| ((481 <= M_long) && (M_long <= 530))) || ((481 <= M_long) && (M_long <= 530)))
M_Rows = 10; M_Rows = 10;
else else
M_Rows = 20; M_Rows = 20;
/* Find p i v*/ /* Find p i v*/
if ((481 <= M_long) && (M_long <= 530)) { if ((481 <= M_long) && (M_long <= 530)) {
p = 53; p = 53;
v = 2; v = 2;
M_Cols = p; M_Cols = p;
} else { } else {
i = 0; i = 0;
do { do {
p = table_p[i]; p = table_p[i];
v = table_v[i]; v = table_v[i];
i++; i++;
} while (M_long > (M_Rows * (p + 1))); } while (M_long > (M_Rows * (p + 1)));
} }
/* Find C*/ /* Find C*/
if ((M_long) <= (M_Rows) * ((p) - 1)) if ((M_long) <= (M_Rows) * ((p) - 1))
M_Cols = (p) - 1; M_Cols = (p) - 1;
else if (((M_Rows) * (p - 1) < M_long) && (M_long <= (M_Rows) * (p))) else if (((M_Rows) * (p - 1) < M_long) && (M_long <= (M_Rows) * (p)))
M_Cols = p; M_Cols = p;
else if ((M_Rows) * (p) < M_long) else if ((M_Rows) * (p) < M_long)
M_Cols = (p) + 1; M_Cols = (p) + 1;
q[0] = 1; q[0] = 1;
prim = 6; prim = 6;
for (i = 1; i < M_Rows; i++) { for (i = 1; i < M_Rows; i++) {
do { do {
prim++; prim++;
res = mcd(prim, p - 1); res = mcd(prim, p - 1);
} while (res != 1); } while (res != 1);
q[i] = prim; q[i] = prim;
} }
s[0] = 1; s[0] = 1;
for (i = 1; i < p - 1; i++) { for (i = 1; i < p - 1; i++) {
s[i] = (v * s[i - 1]) % p; s[i] = (v * s[i - 1]) % p;
} }
if (M_long <= 159 && M_long >= 40) { if (M_long <= 159 && M_long >= 40) {
T[0] = 4; T[0] = 4;
T[1] = 3; T[1] = 3;
T[2] = 2; T[2] = 2;
T[3] = 1; T[3] = 1;
T[4] = 0; T[4] = 0;
} else if ((M_long <= 200 && M_long >= 160) } else if ((M_long <= 200 && M_long >= 160)
|| (M_long <= 530 && M_long >= 481)) { || (M_long <= 530 && M_long >= 481)) {
T[0] = 9; T[0] = 9;
T[1] = 8; T[1] = 8;
T[2] = 7; T[2] = 7;
T[3] = 6; T[3] = 6;
T[4] = 5; T[4] = 5;
T[5] = 4; T[5] = 4;
T[6] = 3; T[6] = 3;
T[7] = 2; T[7] = 2;
T[8] = 1; T[8] = 1;
T[9] = 0; T[9] = 0;
} else if ((M_long <= 2480 && M_long >= 2281) } else if ((M_long <= 2480 && M_long >= 2281)
|| (M_long <= 3210 && M_long >= 3161)) { || (M_long <= 3210 && M_long >= 3161)) {
T[0] = 19; T[0] = 19;
T[1] = 9; T[1] = 9;
T[2] = 14; T[2] = 14;
T[3] = 4; T[3] = 4;
T[4] = 0; T[4] = 0;
T[5] = 2; T[5] = 2;
T[6] = 5; T[6] = 5;
T[7] = 7; T[7] = 7;
T[8] = 12; T[8] = 12;
T[9] = 18; T[9] = 18;
T[10] = 16; T[10] = 16;
T[11] = 13; T[11] = 13;
T[12] = 17; T[12] = 17;
T[13] = 15; T[13] = 15;
T[14] = 3; T[14] = 3;
T[15] = 1; T[15] = 1;
T[16] = 6; T[16] = 6;
T[17] = 11; T[17] = 11;
T[18] = 8; T[18] = 8;
T[19] = 10; T[19] = 10;
} else { } else {
T[0] = 19; T[0] = 19;
T[1] = 9; T[1] = 9;
T[2] = 14; T[2] = 14;
T[3] = 4; T[3] = 4;
T[4] = 0; T[4] = 0;
T[5] = 2; T[5] = 2;
T[6] = 5; T[6] = 5;
T[7] = 7; T[7] = 7;
T[8] = 12; T[8] = 12;
T[9] = 18; T[9] = 18;
T[10] = 10; T[10] = 10;
T[11] = 8; T[11] = 8;
T[12] = 13; T[12] = 13;
T[13] = 17; T[13] = 17;
T[14] = 3; T[14] = 3;
T[15] = 1; T[15] = 1;
T[16] = 16; T[16] = 16;
T[17] = 6; T[17] = 6;
T[18] = 15; T[18] = 15;
T[19] = 11; T[19] = 11;
} }
for (i = 0; i < M_Rows; i++) { for (i = 0; i < M_Rows; i++) {
r[T[i]] = q[i]; r[T[i]] = q[i];
} }
for (i = 0; i < M_Rows; i++) { for (i = 0; i < M_Rows; i++) {
for (j = 0; j < p - 1; j++) { for (j = 0; j < p - 1; j++) {
U[i * M_Cols + j] = s[(j * r[i]) % (p - 1)]; U[i * M_Cols + j] = s[(j * r[i]) % (p - 1)];
if (M_Cols == (p - 1)) if (M_Cols == (p - 1))
U[i * M_Cols + j] -= 1; U[i * M_Cols + j] -= 1;
} }
} }
if (M_Cols == p) { if (M_Cols == p) {
for (i = 0; i < M_Rows; i++) for (i = 0; i < M_Rows; i++)
U[i * M_Cols + p - 1] = 0; U[i * M_Cols + p - 1] = 0;
} else if (M_Cols == p + 1) { } else if (M_Cols == p + 1) {
for (i = 0; i < M_Rows; i++) { for (i = 0; i < M_Rows; i++) {
U[i * M_Cols + p - 1] = 0; U[i * M_Cols + p - 1] = 0;
U[i * M_Cols + p] = p; U[i * M_Cols + p] = p;
} }
if (M_long == M_Cols * M_Rows) { if (M_long == M_Cols * M_Rows) {
aux = U[(M_Rows - 1) * M_Cols + p]; aux = U[(M_Rows - 1) * M_Cols + p];
U[(M_Rows - 1) * M_Cols + p] = U[(M_Rows - 1) * M_Cols + 0]; U[(M_Rows - 1) * M_Cols + p] = U[(M_Rows - 1) * M_Cols + 0];
U[(M_Rows - 1) * M_Cols + 0] = aux; U[(M_Rows - 1) * M_Cols + 0] = aux;
} }
} }
per = h->forward; per = h->forward;
desper = h->reverse; desper = h->reverse;
k = 0; k = 0;
for (j = 0; j < M_Cols; j++) { for (j = 0; j < M_Cols; j++) {
for (i = 0; i < M_Rows; i++) { for (i = 0; i < M_Rows; i++) {
kp = T[i] * M_Cols + U[i * M_Cols + j]; kp = T[i] * M_Cols + U[i * M_Cols + j];
if (kp < M_long) { if (kp < M_long) {
desper[kp] = k; desper[kp] = k;
per[k] = kp; per[k] = kp;
k++; k++;
} }
} }
} }
return 0; return 0;
} }
int mcd(int x, int y) { int mcd(int x, int y) {
int r = 1; int r = 1;
while (r) { while (r) {
r = x % y; r = x % y;
x = y; x = y;
y = r; y = r;
} }
return x; return x;
} }

@ -33,102 +33,102 @@
int tcod_init(tcod_t *h, int long_cb) { int tcod_init(tcod_t *h, int long_cb) {
if (tc_interl_LTE_init(&h->interl, long_cb)) { if (tc_interl_LTE_init(&h->interl, long_cb)) {
return -1; return -1;
} }
h->long_cb = long_cb; h->long_cb = long_cb;
return 0; return 0;
} }
void tcod_free(tcod_t *h) { void tcod_free(tcod_t *h) {
tc_interl_free(&h->interl); tc_interl_free(&h->interl);
h->long_cb = 0; h->long_cb = 0;
} }
void tcod_encode(tcod_t *h, char *input, char *output) { void tcod_encode(tcod_t *h, char *input, char *output) {
char reg1_0,reg1_1,reg1_2, reg2_0,reg2_1,reg2_2; char reg1_0,reg1_1,reg1_2, reg2_0,reg2_1,reg2_2;
int i,k=0,j; int i,k=0,j;
char bit; char bit;
char in,out; char in,out;
int *per; int *per;
per=h->interl.forward; per=h->interl.forward;
reg1_0=0; reg1_0=0;
reg1_1=0; reg1_1=0;
reg1_2=0; reg1_2=0;
reg2_0=0; reg2_0=0;
reg2_1=0; reg2_1=0;
reg2_2=0; reg2_2=0;
k=0; k=0;
for (i=0;i<h->long_cb;i++) { for (i=0;i<h->long_cb;i++) {
bit=input[i]; bit=input[i];
output[k]=bit; output[k]=bit;
k++; k++;
in=bit^(reg1_2^reg1_1); in=bit^(reg1_2^reg1_1);
out=reg1_2^(reg1_0^in); out=reg1_2^(reg1_0^in);
reg1_2=reg1_1; reg1_2=reg1_1;
reg1_1=reg1_0; reg1_1=reg1_0;
reg1_0=in; reg1_0=in;
output[k]=out; output[k]=out;
k++; k++;
bit=input[per[i]]; bit=input[per[i]];
in=bit^(reg2_2^reg2_1); in=bit^(reg2_2^reg2_1);
out=reg2_2^(reg2_0^in); out=reg2_2^(reg2_0^in);
reg2_2=reg2_1; reg2_2=reg2_1;
reg2_1=reg2_0; reg2_1=reg2_0;
reg2_0=in; reg2_0=in;
output[k]=out; output[k]=out;
k++; k++;
} }
k=3*h->long_cb; k=3*h->long_cb;
/* TAILING CODER #1 */ /* TAILING CODER #1 */
for (j=0;j<NOF_REGS;j++) { for (j=0;j<NOF_REGS;j++) {
bit=reg1_2^reg1_1; bit=reg1_2^reg1_1;
output[k]=bit; output[k]=bit;
k++; k++;
in=bit^(reg1_2^reg1_1); in=bit^(reg1_2^reg1_1);
out=reg1_2^(reg1_0^in); out=reg1_2^(reg1_0^in);
reg1_2=reg1_1; reg1_2=reg1_1;
reg1_1=reg1_0; reg1_1=reg1_0;
reg1_0=in; reg1_0=in;
output[k]=out; output[k]=out;
k++; k++;
} }
/* TAILING CODER #2 */ /* TAILING CODER #2 */
for (j=0;j<NOF_REGS;j++) { for (j=0;j<NOF_REGS;j++) {
bit=reg2_2^reg2_1; bit=reg2_2^reg2_1;
output[k]=bit; output[k]=bit;
k++; k++;
in=bit^(reg2_2^reg2_1); in=bit^(reg2_2^reg2_1);
out=reg2_2^(reg2_0^in); out=reg2_2^(reg2_0^in);
reg2_2=reg2_1; reg2_2=reg2_1;
reg2_1=reg2_0; reg2_1=reg2_0;
reg2_0=in; reg2_0=in;
output[k]=out; output[k]=out;
k++; k++;
} }
} }

@ -13,142 +13,142 @@
* *
************************************************/ ************************************************/
void map_gen_beta(map_gen_t *s, llr_t *input, llr_t *parity) { void map_gen_beta(map_gen_t *s, llr_t *input, llr_t *parity) {
llr_t m_b[8], new[8], old[8]; llr_t m_b[8], new[8], old[8];
llr_t x, y, xy; llr_t x, y, xy;
int k; int k;
int end = s->long_cb + RATE; int end = s->long_cb + RATE;
llr_t *beta = s->beta; llr_t *beta = s->beta;
int i; int i;
for (i=0;i<8;i++) { for (i=0;i<8;i++) {
old[i] = beta[8 * (end) + i]; old[i] = beta[8 * (end) + i];
} }
for (k = end - 1; k >= 0; k--) { for (k = end - 1; k >= 0; k--) {
x = input[k]; x = input[k];
y = parity[k]; y = parity[k];
xy = x + y; xy = x + y;
m_b[0] = old[4] + xy; m_b[0] = old[4] + xy;
m_b[1] = old[4]; m_b[1] = old[4];
m_b[2] = old[5] + y; m_b[2] = old[5] + y;
m_b[3] = old[5] + x; m_b[3] = old[5] + x;
m_b[4] = old[6] + x; m_b[4] = old[6] + x;
m_b[5] = old[6] + y; m_b[5] = old[6] + y;
m_b[6] = old[7]; m_b[6] = old[7];
m_b[7] = old[7] + xy; m_b[7] = old[7] + xy;
new[0] = old[0]; new[0] = old[0];
new[1] = old[0] + xy; new[1] = old[0] + xy;
new[2] = old[1] + x; new[2] = old[1] + x;
new[3] = old[1] + y; new[3] = old[1] + y;
new[4] = old[2] + y; new[4] = old[2] + y;
new[5] = old[2] + x; new[5] = old[2] + x;
new[6] = old[3] + xy; new[6] = old[3] + xy;
new[7] = old[3]; new[7] = old[3];
for (i=0;i<8;i++) { for (i=0;i<8;i++) {
if (m_b[i] > new[i]) if (m_b[i] > new[i])
new[i] = m_b[i]; new[i] = m_b[i];
beta[8 * k + i] = new[i]; beta[8 * k + i] = new[i];
old[i] = new[i]; old[i] = new[i];
} }
} }
} }
void map_gen_alpha(map_gen_t *s, llr_t *input, llr_t *parity, llr_t *output) { void map_gen_alpha(map_gen_t *s, llr_t *input, llr_t *parity, llr_t *output) {
llr_t m_b[8], new[8], old[8], max1[8], max0[8]; llr_t m_b[8], new[8], old[8], max1[8], max0[8];
llr_t m1, m0; llr_t m1, m0;
llr_t x, y, xy; llr_t x, y, xy;
llr_t out; llr_t out;
int k; int k;
int end = s->long_cb; int end = s->long_cb;
llr_t *beta = s->beta; llr_t *beta = s->beta;
int i; int i;
old[0] = 0; old[0] = 0;
for (i=1;i<8;i++) { for (i=1;i<8;i++) {
old[i] = -INF; old[i] = -INF;
} }
for (k = 1; k < end + 1; k++) { for (k = 1; k < end + 1; k++) {
x = input[k - 1]; x = input[k - 1];
y = parity[k - 1]; y = parity[k - 1];
xy = x + y; xy = x + y;
m_b[0] = old[0]; m_b[0] = old[0];
m_b[1] = old[3] + y; m_b[1] = old[3] + y;
m_b[2] = old[4] + y; m_b[2] = old[4] + y;
m_b[3] = old[7]; m_b[3] = old[7];
m_b[4] = old[1]; m_b[4] = old[1];
m_b[5] = old[2] + y; m_b[5] = old[2] + y;
m_b[6] = old[5] + y; m_b[6] = old[5] + y;
m_b[7] = old[6]; m_b[7] = old[6];
new[0] = old[1] + xy; new[0] = old[1] + xy;
new[1] = old[2] + x; new[1] = old[2] + x;
new[2] = old[5] + x; new[2] = old[5] + x;
new[3] = old[6] + xy; new[3] = old[6] + xy;
new[4] = old[0] + xy; new[4] = old[0] + xy;
new[5] = old[3] + x; new[5] = old[3] + x;
new[6] = old[4] + x; new[6] = old[4] + x;
new[7] = old[7] + xy; new[7] = old[7] + xy;
for (i=0;i<8;i++) { for (i=0;i<8;i++) {
max0[i] = m_b[i] + beta[8 * k + i]; max0[i] = m_b[i] + beta[8 * k + i];
max1[i] = new[i] + beta[8 * k + i]; max1[i] = new[i] + beta[8 * k + i];
} }
m1 = max1[0]; m1 = max1[0];
m0 = max0[0]; m0 = max0[0];
for (i=1;i<8;i++) { for (i=1;i<8;i++) {
if (max1[i] > m1) if (max1[i] > m1)
m1 = max1[i]; m1 = max1[i];
if (max0[i] > m0) if (max0[i] > m0)
m0 = max0[i]; m0 = max0[i];
} }
for (i=0;i<8;i++) { for (i=0;i<8;i++) {
if (m_b[i] > new[i]) if (m_b[i] > new[i])
new[i] = m_b[i]; new[i] = m_b[i];
old[i] = new[i]; old[i] = new[i];
} }
out = m1 - m0; out = m1 - m0;
output[k - 1] = out; output[k - 1] = out;
} }
} }
int map_gen_init(map_gen_t *h, int long_cb) { int map_gen_init(map_gen_t *h, int long_cb) {
bzero(h, sizeof(map_gen_t)); bzero(h, sizeof(map_gen_t));
h->beta = malloc(sizeof(llr_t) * (long_cb + TOTALTAIL + 1)* NUMSTATES); h->beta = malloc(sizeof(llr_t) * (long_cb + TOTALTAIL + 1)* NUMSTATES);
if (!h->beta) { if (!h->beta) {
perror("malloc"); perror("malloc");
return -1; return -1;
} }
h->long_cb = long_cb; h->long_cb = long_cb;
return 0; return 0;
} }
void map_gen_free(map_gen_t *h) { void map_gen_free(map_gen_t *h) {
if (h->beta) { if (h->beta) {
free(h->beta); free(h->beta);
} }
bzero(h, sizeof(map_gen_t)); bzero(h, sizeof(map_gen_t));
} }
void map_gen_dec(map_gen_t *h, llr_t *input, llr_t *parity, llr_t *output) { void map_gen_dec(map_gen_t *h, llr_t *input, llr_t *parity, llr_t *output) {
int k; int k;
h->beta[(h->long_cb + TAIL) * NUMSTATES] = 0; h->beta[(h->long_cb + TAIL) * NUMSTATES] = 0;
for (k = 1; k < NUMSTATES; k++) for (k = 1; k < NUMSTATES; k++)
h->beta[(h->long_cb + TAIL) * NUMSTATES + k] = -INF; h->beta[(h->long_cb + TAIL) * NUMSTATES + k] = -INF;
map_gen_beta(h, input, parity); map_gen_beta(h, input, parity);
map_gen_alpha(h, input, parity, output); map_gen_alpha(h, input, parity, output);
} }
@ -165,135 +165,135 @@ void map_gen_dec(map_gen_t *h, llr_t *input, llr_t *parity, llr_t *output) {
* *
************************************************/ ************************************************/
int tdec_init(tdec_t *h, int long_cb) { int tdec_init(tdec_t *h, int long_cb) {
int ret = -1; int ret = -1;
bzero(h, sizeof(tdec_t)); bzero(h, sizeof(tdec_t));
int len = long_cb + TOTALTAIL; int len = long_cb + TOTALTAIL;
h->llr1 = malloc(sizeof(llr_t) * len); h->llr1 = malloc(sizeof(llr_t) * len);
if (!h->llr1) { if (!h->llr1) {
perror("malloc"); perror("malloc");
goto clean_and_exit; goto clean_and_exit;
} }
h->llr2 = malloc(sizeof(llr_t) * len); h->llr2 = malloc(sizeof(llr_t) * len);
if (!h->llr2) { if (!h->llr2) {
perror("malloc"); perror("malloc");
goto clean_and_exit; goto clean_and_exit;
} }
h->w = malloc(sizeof(llr_t) * len); h->w = malloc(sizeof(llr_t) * len);
if (!h->w) { if (!h->w) {
perror("malloc"); perror("malloc");
goto clean_and_exit; goto clean_and_exit;
} }
h->syst = malloc(sizeof(llr_t) * len); h->syst = malloc(sizeof(llr_t) * len);
if (!h->syst) { if (!h->syst) {
perror("malloc"); perror("malloc");
goto clean_and_exit; goto clean_and_exit;
} }
h->parity = malloc(sizeof(llr_t) * len); h->parity = malloc(sizeof(llr_t) * len);
if (!h->parity) { if (!h->parity) {
perror("malloc"); perror("malloc");
goto clean_and_exit; goto clean_and_exit;
} }
if (map_gen_init(&h->dec, long_cb)) { if (map_gen_init(&h->dec, long_cb)) {
goto clean_and_exit; goto clean_and_exit;
} }
h->long_cb = long_cb; h->long_cb = long_cb;
if (tc_interl_LTE_init(&h->interleaver, h->long_cb) < 0) { if (tc_interl_LTE_init(&h->interleaver, h->long_cb) < 0) {
goto clean_and_exit; goto clean_and_exit;
} }
ret = 0; ret = 0;
clean_and_exit: clean_and_exit:
if (ret == -1) { if (ret == -1) {
tdec_free(h); tdec_free(h);
} }
return ret; return ret;
} }
void tdec_free(tdec_t *h) { void tdec_free(tdec_t *h) {
if (h->llr1) { if (h->llr1) {
free(h->llr1); free(h->llr1);
} }
if (h->llr2) { if (h->llr2) {
free(h->llr2); free(h->llr2);
} }
if (h->w) { if (h->w) {
free(h->w); free(h->w);
} }
if (h->syst) { if (h->syst) {
free(h->syst); free(h->syst);
} }
if (h->parity) { if (h->parity) {
free(h->parity); free(h->parity);
} }
map_gen_free(&h->dec); map_gen_free(&h->dec);
tc_interl_free(&h->interleaver); tc_interl_free(&h->interleaver);
bzero(h, sizeof(tdec_t)); bzero(h, sizeof(tdec_t));
} }
void tdec_iteration(tdec_t *h, llr_t *input) { void tdec_iteration(tdec_t *h, llr_t *input) {
int i; int i;
// Prepare systematic and parity bits for MAP DEC #1 // Prepare systematic and parity bits for MAP DEC #1
for (i = 0; i < h->long_cb; i++) { for (i = 0; i < h->long_cb; i++) {
h->syst[i] = input[RATE * i] + h->w[i]; h->syst[i] = input[RATE * i] + h->w[i];
h->parity[i] = input[RATE * i + 1]; h->parity[i] = input[RATE * i + 1];
} }
for (i=h->long_cb;i<h->long_cb+RATE;i++) { for (i=h->long_cb;i<h->long_cb+RATE;i++) {
h->syst[i] = input[RATE * h->long_cb + NINPUTS * (i - h->long_cb)]; h->syst[i] = input[RATE * h->long_cb + NINPUTS * (i - h->long_cb)];
h->parity[i] = input[RATE * h->long_cb + NINPUTS * (i - h->long_cb) + 1]; h->parity[i] = input[RATE * h->long_cb + NINPUTS * (i - h->long_cb) + 1];
} }
// Run MAP DEC #1 // Run MAP DEC #1
map_gen_dec(&h->dec, h->syst, h->parity, h->llr1); map_gen_dec(&h->dec, h->syst, h->parity, h->llr1);
// Prepare systematic and parity bits for MAP DEC #1 // Prepare systematic and parity bits for MAP DEC #1
for (i = 0; i < h->long_cb; i++) { for (i = 0; i < h->long_cb; i++) {
h->syst[i] = h->llr1[h->interleaver.forward[i]] - h->w[h->interleaver.forward[i]]; h->syst[i] = h->llr1[h->interleaver.forward[i]] - h->w[h->interleaver.forward[i]];
h->parity[i] = input[RATE * i + 2]; h->parity[i] = input[RATE * i + 2];
} }
for (i=h->long_cb;i<h->long_cb+RATE;i++) { for (i=h->long_cb;i<h->long_cb+RATE;i++) {
h->syst[i] = input[RATE * h->long_cb + NINPUTS * RATE + NINPUTS * (i - h->long_cb)]; h->syst[i] = input[RATE * h->long_cb + NINPUTS * RATE + NINPUTS * (i - h->long_cb)];
h->parity[i] = input[RATE * h->long_cb + NINPUTS * RATE + NINPUTS * (i - h->long_cb) + 1]; h->parity[i] = input[RATE * h->long_cb + NINPUTS * RATE + NINPUTS * (i - h->long_cb) + 1];
} }
// Run MAP DEC #1 // Run MAP DEC #1
map_gen_dec(&h->dec, h->syst, h->parity, h->llr2); map_gen_dec(&h->dec, h->syst, h->parity, h->llr2);
// Update a-priori LLR from the last iteration // Update a-priori LLR from the last iteration
for (i = 0; i < h->long_cb; i++) { for (i = 0; i < h->long_cb; i++) {
h->w[i] += h->llr2[h->interleaver.reverse[i]] - h->llr1[i]; h->w[i] += h->llr2[h->interleaver.reverse[i]] - h->llr1[i];
} }
} }
void tdec_reset(tdec_t *h) { void tdec_reset(tdec_t *h) {
memset(h->w, 0, sizeof(llr_t) * h->long_cb); memset(h->w, 0, sizeof(llr_t) * h->long_cb);
} }
void tdec_decision(tdec_t *h, char *output) { void tdec_decision(tdec_t *h, char *output) {
int i; int i;
for (i = 0; i < h->long_cb; i++) { for (i = 0; i < h->long_cb; i++) {
output[i] = (h->llr2[h->interleaver.reverse[i]] > 0) ? 1 : 0; output[i] = (h->llr2[h->interleaver.reverse[i]] > 0) ? 1 : 0;
} }
} }
void tdec_run_all(tdec_t *h, llr_t *input, char *output, int nof_iterations) { void tdec_run_all(tdec_t *h, llr_t *input, char *output, int nof_iterations) {
int iter = 0; int iter = 0;
tdec_reset(h); tdec_reset(h);
do { do {
tdec_iteration(h, input); tdec_iteration(h, input);
iter++; iter++;
} while (iter < nof_iterations); } while (iter < nof_iterations);
tdec_decision(h, output); tdec_decision(h, output);
} }

@ -39,222 +39,222 @@
#define DEB 0 #define DEB 0
int decode37(void *o, unsigned char *symbols, char *data, int frame_length) { int decode37(void *o, unsigned char *symbols, char *data, int frame_length) {
viterbi_t *q = o; viterbi_t *q = o;
int i; int i;
int best_state; int best_state;
if (frame_length > q->framebits) { if (frame_length > q->framebits) {
fprintf(stderr, "Initialized decoder for max frame length %d bits\n", fprintf(stderr, "Initialized decoder for max frame length %d bits\n",
q->framebits); q->framebits);
return -1; return -1;
} }
/* Initialize Viterbi decoder */ /* 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 */ /* Decode block */
if (q->tail_biting) { if (q->tail_biting) {
memcpy(q->tmp, symbols, 3 * frame_length * sizeof(char)); memcpy(q->tmp, symbols, 3 * frame_length * sizeof(char));
for (i = 0; i < 3 * (q->K - 1); i++) { for (i = 0; i < 3 * (q->K - 1); i++) {
q->tmp[i + 3 * frame_length] = q->tmp[i]; q->tmp[i + 3 * frame_length] = q->tmp[i];
} }
} else { } else {
q->tmp = symbols; q->tmp = symbols;
} }
update_viterbi37_blk_port(q->ptr, q->tmp, frame_length + q->K - 1, update_viterbi37_blk_port(q->ptr, q->tmp, frame_length + q->K - 1,
q->tail_biting ? &best_state : NULL); q->tail_biting ? &best_state : NULL);
/* Do Viterbi chainback */ /* Do Viterbi chainback */
chainback_viterbi37_port(q->ptr, data, frame_length, chainback_viterbi37_port(q->ptr, data, frame_length,
q->tail_biting ? best_state : 0); q->tail_biting ? best_state : 0);
return q->framebits; return q->framebits;
} }
int decode39(void *o, unsigned char *symbols, char *data, int frame_length) { int decode39(void *o, unsigned char *symbols, char *data, int frame_length) {
viterbi_t *q = o; viterbi_t *q = o;
if (frame_length > q->framebits) { if (frame_length > q->framebits) {
fprintf(stderr, "Initialized decoder for max frame length %d bits\n", fprintf(stderr, "Initialized decoder for max frame length %d bits\n",
q->framebits); q->framebits);
return -1; return -1;
} }
/* Initialize Viterbi decoder */ /* Initialize Viterbi decoder */
init_viterbi39_port(q->ptr, 0); init_viterbi39_port(q->ptr, 0);
/* Decode block */ /* Decode block */
update_viterbi39_blk_port(q->ptr, symbols, frame_length + q->K - 1); update_viterbi39_blk_port(q->ptr, symbols, frame_length + q->K - 1);
/* Do Viterbi chainback */ /* Do Viterbi chainback */
chainback_viterbi39_port(q->ptr, data, frame_length, 0); chainback_viterbi39_port(q->ptr, data, frame_length, 0);
return q->framebits; return q->framebits;
} }
void free37(void *o) { void free37(void *o) {
viterbi_t *q = o; viterbi_t *q = o;
if (q->symbols_uc) { if (q->symbols_uc) {
free(q->symbols_uc); free(q->symbols_uc);
} }
if (q->tmp) { if (q->tmp) {
free(q->tmp); free(q->tmp);
} }
delete_viterbi37_port(q->ptr); delete_viterbi37_port(q->ptr);
} }
void free39(void *o) { void free39(void *o) {
viterbi_t *q = o; viterbi_t *q = o;
if (q->symbols_uc) { if (q->symbols_uc) {
free(q->symbols_uc); free(q->symbols_uc);
} }
delete_viterbi39_port(q->ptr); delete_viterbi39_port(q->ptr);
} }
int init37(viterbi_t *q, int poly[3], int framebits, bool tail_biting) { int init37(viterbi_t *q, int poly[3], int framebits, bool tail_biting) {
q->K = 7; q->K = 7;
q->R = 3; q->R = 3;
q->framebits = framebits; q->framebits = framebits;
q->tail_biting = tail_biting; q->tail_biting = tail_biting;
q->decode = decode37; q->decode = decode37;
q->free = free37; 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) { if (!q->symbols_uc) {
perror("malloc"); perror("malloc");
return -1; return -1;
} }
if (q->tail_biting) { 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) { if (!q->tmp) {
perror("malloc"); perror("malloc");
free37(q); free37(q);
return -1; return -1;
} }
} else { } else {
q->tmp = NULL; q->tmp = NULL;
} }
if ((q->ptr = create_viterbi37_port(poly, framebits)) == NULL) { if ((q->ptr = create_viterbi37_port(poly, framebits)) == NULL) {
fprintf(stderr, "create_viterbi37 failed\n"); fprintf(stderr, "create_viterbi37 failed\n");
free37(q); free37(q);
return -1; return -1;
} else { } else {
return 0; return 0;
} }
} }
int init39(viterbi_t *q, int poly[3], int framebits, bool tail_biting) { int init39(viterbi_t *q, int poly[3], int framebits, bool tail_biting) {
q->K = 9; q->K = 9;
q->R = 3; q->R = 3;
q->framebits = framebits; q->framebits = framebits;
q->tail_biting = tail_biting; q->tail_biting = tail_biting;
q->decode = decode39; q->decode = decode39;
q->free = free39; q->free = free39;
if (q->tail_biting) { if (q->tail_biting) {
fprintf(stderr, fprintf(stderr,
"Error: Tailbitting not supported in 1/3 K=9 decoder\n"); "Error: Tailbitting not supported in 1/3 K=9 decoder\n");
return -1; 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) { if (!q->symbols_uc) {
perror("malloc"); perror("malloc");
return -1; return -1;
} }
if ((q->ptr = create_viterbi39_port(poly, framebits)) == NULL) { if ((q->ptr = create_viterbi39_port(poly, framebits)) == NULL) {
fprintf(stderr, "create_viterbi37 failed\n"); fprintf(stderr, "create_viterbi37 failed\n");
free39(q); free39(q);
return -1; return -1;
} else { } else {
return 0; return 0;
} }
} }
int viterbi_init(viterbi_t *q, viterbi_type_t type, int poly[3], int viterbi_init(viterbi_t *q, viterbi_type_t type, int poly[3],
int max_frame_length, bool tail_bitting) { int max_frame_length, bool tail_bitting) {
switch (type) { switch (type) {
case viterbi_37: case viterbi_37:
return init37(q, poly, max_frame_length, tail_bitting); return init37(q, poly, max_frame_length, tail_bitting);
case viterbi_39: case viterbi_39:
return init39(q, poly, max_frame_length, tail_bitting); return init39(q, poly, max_frame_length, tail_bitting);
default: default:
fprintf(stderr, "Decoder not implemented\n"); fprintf(stderr, "Decoder not implemented\n");
return -1; return -1;
} }
} }
void viterbi_free(viterbi_t *q) { void viterbi_free(viterbi_t *q) {
q->free(q); q->free(q);
} }
/* symbols are real-valued */ /* symbols are real-valued */
int viterbi_decode_f(viterbi_t *q, float *symbols, char *data, int frame_length) { int viterbi_decode_f(viterbi_t *q, float *symbols, char *data, int frame_length) {
int len; int len;
if (frame_length > q->framebits) { if (frame_length > q->framebits) {
fprintf(stderr, "Initialized decoder for max frame length %d bits\n", fprintf(stderr, "Initialized decoder for max frame length %d bits\n",
q->framebits); q->framebits);
return -1; return -1;
} }
if (q->tail_biting) { if (q->tail_biting) {
len = 3 * frame_length; len = 3 * frame_length;
} else { } else {
len = 3 * (frame_length + q->K - 1); len = 3 * (frame_length + q->K - 1);
} }
vec_quant_fuc(symbols, q->symbols_uc, 32, 127.5, 255, len); vec_quant_fuc(symbols, q->symbols_uc, 32, 127.5, 255, len);
return q->decode(q, q->symbols_uc, data, frame_length); return q->decode(q, q->symbols_uc, data, frame_length);
} }
int viterbi_decode_uc(viterbi_t *q, unsigned char *symbols, char *data, int viterbi_decode_uc(viterbi_t *q, unsigned char *symbols, char *data,
int frame_length) { int frame_length) {
return q->decode(q, symbols, data, frame_length); return q->decode(q, symbols, data, frame_length);
} }
int viterbi_initialize(viterbi_hl* h) { int viterbi_initialize(viterbi_hl* h) {
int poly[3]; int poly[3];
viterbi_type_t type; viterbi_type_t type;
if (h->init.rate == 2) { if (h->init.rate == 2) {
if (h->init.constraint_length == 7) { if (h->init.constraint_length == 7) {
type = viterbi_27; type = viterbi_27;
} else if (h->init.constraint_length == 9) { } else if (h->init.constraint_length == 9) {
type = viterbi_29; type = viterbi_29;
} else { } else {
fprintf(stderr, "Unsupported decoder %d/%d\n", h->init.rate, fprintf(stderr, "Unsupported decoder %d/%d\n", h->init.rate,
h->init.constraint_length); h->init.constraint_length);
return -1; return -1;
} }
} else if (h->init.rate == 3) { } else if (h->init.rate == 3) {
if (h->init.constraint_length == 7) { if (h->init.constraint_length == 7) {
type = viterbi_37; type = viterbi_37;
} else if (h->init.constraint_length == 9) { } else if (h->init.constraint_length == 9) {
type = viterbi_39; type = viterbi_39;
} else { } else {
fprintf(stderr, "Unsupported decoder %d/%d\n", h->init.rate, fprintf(stderr, "Unsupported decoder %d/%d\n", h->init.rate,
h->init.constraint_length); h->init.constraint_length);
return -1; return -1;
} }
} else { } else {
fprintf(stderr, "Unsupported decoder %d/%d\n", h->init.rate, fprintf(stderr, "Unsupported decoder %d/%d\n", h->init.rate,
h->init.constraint_length); h->init.constraint_length);
return -1; return -1;
} }
poly[0] = h->init.generator_0; poly[0] = h->init.generator_0;
poly[1] = h->init.generator_1; poly[1] = h->init.generator_1;
poly[2] = h->init.generator_2; poly[2] = h->init.generator_2;
return viterbi_init(&h->obj, type, poly, h->init.frame_length, 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) { int viterbi_work(viterbi_hl* hl) {
if (hl->in_len != hl->init.frame_length) { if (hl->in_len != hl->init.frame_length) {
fprintf(stderr, "Expected input length %d but got %d\n", fprintf(stderr, "Expected input length %d but got %d\n",
hl->init.frame_length, hl->in_len); hl->init.frame_length, hl->in_len);
return -1; return -1;
} }
return viterbi_decode_f(&hl->obj, hl->input, hl->output, hl->init.frame_length); return viterbi_decode_f(&hl->obj, hl->input, hl->output, hl->init.frame_length);
} }
int viterbi_stop(viterbi_hl* h) { int viterbi_stop(viterbi_hl* h) {
viterbi_free(&h->obj); viterbi_free(&h->obj);
return 0; return 0;
} }

@ -10,117 +10,117 @@
#include <limits.h> #include <limits.h>
typedef union { typedef union {
unsigned int w[64]; unsigned int w[64];
} metric_t; } metric_t;
typedef union { typedef union {
unsigned long w[2]; unsigned long w[2];
} decision_t; } decision_t;
static union { static union {
unsigned char c[128]; unsigned char c[128];
} Branchtab37[3]; } Branchtab37[3];
/* State info for instance of Viterbi decoder */ /* State info for instance of Viterbi decoder */
struct v37 { struct v37 {
metric_t metrics1; /* path metric buffer 1 */ metric_t metrics1; /* path metric buffer 1 */
metric_t metrics2; /* path metric buffer 2 */ metric_t metrics2; /* path metric buffer 2 */
decision_t *dp; /* Pointer to current decision */ decision_t *dp; /* Pointer to current decision */
metric_t *old_metrics, *new_metrics; /* Pointers to path metrics, swapped on every bit */ metric_t *old_metrics, *new_metrics; /* Pointers to path metrics, swapped on every bit */
decision_t *decisions; /* Beginning of decisions for block */ decision_t *decisions; /* Beginning of decisions for block */
}; };
/* Initialize Viterbi decoder for start of new frame */ /* Initialize Viterbi decoder for start of new frame */
int init_viterbi37_port(void *p, int starting_state) { int init_viterbi37_port(void *p, int starting_state) {
struct v37 *vp = p; struct v37 *vp = p;
int i; int i;
if (p == NULL) if (p == NULL)
return -1; return -1;
for (i = 0; i < 64; i++) for (i = 0; i < 64; i++)
vp->metrics1.w[i] = 63; vp->metrics1.w[i] = 63;
vp->old_metrics = &vp->metrics1; vp->old_metrics = &vp->metrics1;
vp->new_metrics = &vp->metrics2; vp->new_metrics = &vp->metrics2;
vp->dp = vp->decisions; vp->dp = vp->decisions;
if (starting_state != -1) { if (starting_state != -1) {
vp->old_metrics->w[starting_state & 255] = 0; /* Bias known start state */ vp->old_metrics->w[starting_state & 255] = 0; /* Bias known start state */
} }
return 0; return 0;
} }
void set_viterbi37_polynomial_port(int polys[3]) { void set_viterbi37_polynomial_port(int polys[3]) {
int state; int state;
for (state = 0; state < 32; state++) { for (state = 0; state < 32; state++) {
Branchtab37[0].c[state] = Branchtab37[0].c[state] =
(polys[0] < 0) ^ parity((2 * state) & abs(polys[0])) ? 255 : 0; (polys[0] < 0) ^ parity((2 * state) & abs(polys[0])) ? 255 : 0;
Branchtab37[1].c[state] = Branchtab37[1].c[state] =
(polys[1] < 0) ^ parity((2 * state) & abs(polys[1])) ? 255 : 0; (polys[1] < 0) ^ parity((2 * state) & abs(polys[1])) ? 255 : 0;
Branchtab37[2].c[state] = Branchtab37[2].c[state] =
(polys[2] < 0) ^ parity((2 * state) & abs(polys[2])) ? 255 : 0; (polys[2] < 0) ^ parity((2 * state) & abs(polys[2])) ? 255 : 0;
} }
} }
/* Create a new instance of a Viterbi decoder */ /* Create a new instance of a Viterbi decoder */
void *create_viterbi37_port(int polys[3], int len) { void *create_viterbi37_port(int polys[3], int len) {
struct v37 *vp; struct v37 *vp;
set_viterbi37_polynomial_port(polys); set_viterbi37_polynomial_port(polys);
if ((vp = (struct v37 *) malloc(sizeof(struct v37))) == NULL) if ((vp = (struct v37 *) malloc(sizeof(struct v37))) == NULL)
return NULL ; return NULL ;
if ((vp->decisions = (decision_t *) malloc((len + 6) * sizeof(decision_t))) if ((vp->decisions = (decision_t *) malloc((len + 6) * sizeof(decision_t)))
== NULL) { == NULL) {
free(vp); free(vp);
return NULL ; return NULL ;
} }
init_viterbi37_port(vp, 0); init_viterbi37_port(vp, 0);
return vp; return vp;
} }
/* Viterbi chainback */ /* Viterbi chainback */
int chainback_viterbi37_port(void *p, char *data, /* Decoded output data */ int chainback_viterbi37_port(void *p, char *data, /* Decoded output data */
unsigned int nbits, /* Number of data bits */ unsigned int nbits, /* Number of data bits */
unsigned int endstate) { /* Terminal encoder state */ unsigned int endstate) { /* Terminal encoder state */
struct v37 *vp = p; struct v37 *vp = p;
decision_t *d; decision_t *d;
if (p == NULL) if (p == NULL)
return -1; return -1;
d = vp->decisions; d = vp->decisions;
/* Make room beyond the end of the encoder register so we can /* Make room beyond the end of the encoder register so we can
* accumulate a full byte of decoded data * accumulate a full byte of decoded data
*/ */
endstate %= 64; endstate %= 64;
endstate <<= 2; endstate <<= 2;
/* The store into data[] only needs to be done every 8 bits. /* The store into data[] only needs to be done every 8 bits.
* But this avoids a conditional branch, and the writes will * But this avoids a conditional branch, and the writes will
* combine in the cache anyway * combine in the cache anyway
*/ */
d += 6; /* Look past tail */ d += 6; /* Look past tail */
while (nbits-- != 0) { while (nbits-- != 0) {
int k; int k;
k = (d[nbits].w[(endstate >> 2) / 32] >> ((endstate >> 2) % 32)) & 1; k = (d[nbits].w[(endstate >> 2) / 32] >> ((endstate >> 2) % 32)) & 1;
endstate = (endstate >> 1) | (k << 7); endstate = (endstate >> 1) | (k << 7);
data[nbits] = k; data[nbits] = k;
} }
return 0; return 0;
} }
/* Delete instance of a Viterbi decoder */ /* Delete instance of a Viterbi decoder */
void delete_viterbi37_port(void *p) { void delete_viterbi37_port(void *p) {
struct v37 *vp = p; struct v37 *vp = p;
if (vp != NULL) { if (vp != NULL) {
free(vp->decisions); free(vp->decisions);
free(vp); free(vp);
} }
} }
/* C-language butterfly */ /* C-language butterfly */
@ -146,44 +146,44 @@ unsigned int metric,m0,m1,decision;\
*/ */
int update_viterbi37_blk_port(void *p, unsigned char *syms, int nbits, int *best_state) { int update_viterbi37_blk_port(void *p, unsigned char *syms, int nbits, int *best_state) {
struct v37 *vp = p; struct v37 *vp = p;
decision_t *d; decision_t *d;
if (p == NULL) if (p == NULL)
return -1; return -1;
int k=0; int k=0;
d = (decision_t *) vp->dp; d = (decision_t *) vp->dp;
while (nbits--) { while (nbits--) {
void *tmp; void *tmp;
unsigned char sym0, sym1, sym2; unsigned char sym0, sym1, sym2;
int i; int i;
d->w[0] = d->w[1] = 0; d->w[0] = d->w[1] = 0;
sym0 = *syms++; sym0 = *syms++;
sym1 = *syms++; sym1 = *syms++;
sym2 = *syms++; sym2 = *syms++;
k++; k++;
for (i = 0; i < 32; i++) for (i = 0; i < 32; i++)
BFLY(i); BFLY(i);
d++; d++;
tmp = vp->old_metrics; tmp = vp->old_metrics;
vp->old_metrics = vp->new_metrics; vp->old_metrics = vp->new_metrics;
vp->new_metrics = tmp; vp->new_metrics = tmp;
} }
if (best_state) { if (best_state) {
int i, bst=0; int i, bst=0;
unsigned int minmetric=UINT_MAX; unsigned int minmetric=UINT_MAX;
for (i=0;i<64;i++) { for (i=0;i<64;i++) {
if (vp->old_metrics->w[i] < minmetric) { if (vp->old_metrics->w[i] < minmetric) {
bst = i; bst = i;
minmetric = vp->old_metrics->w[i]; minmetric = vp->old_metrics->w[i];
} }
} }
*best_state = bst; *best_state = bst;
} }
vp->dp = d; vp->dp = d;
return 0; return 0;
} }

@ -30,7 +30,7 @@
void *create_viterbi39_port(int polys[3], int len); void *create_viterbi39_port(int polys[3], int len);
int init_viterbi39_port(void *p, int starting_state); int init_viterbi39_port(void *p, int starting_state);
int chainback_viterbi39_port(void *p, char *data, /* Decoded output data */ int chainback_viterbi39_port(void *p, char *data, /* Decoded output data */
unsigned int nbits, /* Number of data bits */ unsigned int nbits, /* Number of data bits */
unsigned int endstate); unsigned int endstate);
void delete_viterbi39_port(void *p); void delete_viterbi39_port(void *p);
int update_viterbi39_blk_port(void *p, unsigned char *syms, int nbits); int update_viterbi39_blk_port(void *p, unsigned char *syms, int nbits);

@ -9,113 +9,113 @@
#include "parity.h" #include "parity.h"
typedef union { typedef union {
unsigned int w[256]; unsigned int w[256];
} metric_t; } metric_t;
typedef union { typedef union {
unsigned long w[8]; unsigned long w[8];
} decision_t; } decision_t;
static union { static union {
unsigned char c[128]; unsigned char c[128];
} Branchtab39[3]; } Branchtab39[3];
/* State info for instance of Viterbi decoder */ /* State info for instance of Viterbi decoder */
struct v39 { struct v39 {
metric_t metrics1; /* path metric buffer 1 */ metric_t metrics1; /* path metric buffer 1 */
metric_t metrics2; /* path metric buffer 2 */ metric_t metrics2; /* path metric buffer 2 */
decision_t *dp; /* Pointer to current decision */ decision_t *dp; /* Pointer to current decision */
metric_t *old_metrics, *new_metrics; /* Pointers to path metrics, swapped on every bit */ metric_t *old_metrics, *new_metrics; /* Pointers to path metrics, swapped on every bit */
decision_t *decisions; /* Beginning of decisions for block */ decision_t *decisions; /* Beginning of decisions for block */
}; };
/* Initialize Viterbi decoder for start of new frame */ /* Initialize Viterbi decoder for start of new frame */
int init_viterbi39_port(void *p, int starting_state) { int init_viterbi39_port(void *p, int starting_state) {
struct v39 *vp = p; struct v39 *vp = p;
int i; int i;
if (p == NULL) if (p == NULL)
return -1; return -1;
for (i = 0; i < 256; i++) for (i = 0; i < 256; i++)
vp->metrics1.w[i] = 63; vp->metrics1.w[i] = 63;
vp->old_metrics = &vp->metrics1; vp->old_metrics = &vp->metrics1;
vp->new_metrics = &vp->metrics2; vp->new_metrics = &vp->metrics2;
vp->dp = vp->decisions; vp->dp = vp->decisions;
vp->old_metrics->w[starting_state & 255] = 0; /* Bias known start state */ vp->old_metrics->w[starting_state & 255] = 0; /* Bias known start state */
return 0; return 0;
} }
void set_viterbi39_polynomial_port(int polys[3]) { void set_viterbi39_polynomial_port(int polys[3]) {
int state; int state;
for (state = 0; state < 128; state++) { for (state = 0; state < 128; state++) {
Branchtab39[0].c[state] = Branchtab39[0].c[state] =
(polys[0] < 0) ^ parity((2 * state) & abs(polys[0])) ? 255 : 0; (polys[0] < 0) ^ parity((2 * state) & abs(polys[0])) ? 255 : 0;
Branchtab39[1].c[state] = Branchtab39[1].c[state] =
(polys[1] < 0) ^ parity((2 * state) & abs(polys[1])) ? 255 : 0; (polys[1] < 0) ^ parity((2 * state) & abs(polys[1])) ? 255 : 0;
Branchtab39[2].c[state] = Branchtab39[2].c[state] =
(polys[2] < 0) ^ parity((2 * state) & abs(polys[2])) ? 255 : 0; (polys[2] < 0) ^ parity((2 * state) & abs(polys[2])) ? 255 : 0;
} }
} }
/* Create a new instance of a Viterbi decoder */ /* Create a new instance of a Viterbi decoder */
void *create_viterbi39_port(int polys[3], int len) { void *create_viterbi39_port(int polys[3], int len) {
struct v39 *vp; struct v39 *vp;
set_viterbi39_polynomial_port(polys); set_viterbi39_polynomial_port(polys);
if ((vp = (struct v39 *) malloc(sizeof(struct v39))) == NULL) if ((vp = (struct v39 *) malloc(sizeof(struct v39))) == NULL)
return NULL ; return NULL ;
if ((vp->decisions = (decision_t *) malloc((len + 8) * sizeof(decision_t))) if ((vp->decisions = (decision_t *) malloc((len + 8) * sizeof(decision_t)))
== NULL) { == NULL) {
free(vp); free(vp);
return NULL ; return NULL ;
} }
init_viterbi39_port(vp, 0); init_viterbi39_port(vp, 0);
return vp; return vp;
} }
/* Viterbi chainback */ /* Viterbi chainback */
int chainback_viterbi39_port(void *p, char *data, /* Decoded output data */ int chainback_viterbi39_port(void *p, char *data, /* Decoded output data */
unsigned int nbits, /* Number of data bits */ unsigned int nbits, /* Number of data bits */
unsigned int endstate) { /* Terminal encoder state */ unsigned int endstate) { /* Terminal encoder state */
struct v39 *vp = p; struct v39 *vp = p;
decision_t *d; decision_t *d;
if (p == NULL) if (p == NULL)
return -1; return -1;
d = vp->decisions; d = vp->decisions;
/* Make room beyond the end of the encoder register so we can /* Make room beyond the end of the encoder register so we can
* accumulate a full byte of decoded data * accumulate a full byte of decoded data
*/ */
endstate %= 256; endstate %= 256;
/* The store into data[] only needs to be done every 8 bits. /* The store into data[] only needs to be done every 8 bits.
* But this avoids a conditional branch, and the writes will * But this avoids a conditional branch, and the writes will
* combine in the cache anyway * combine in the cache anyway
*/ */
d += 8; /* Look past tail */ d += 8; /* Look past tail */
while (nbits-- != 0) { while (nbits-- != 0) {
int k; int k;
k = (d[nbits].w[(endstate) / 32] >> (endstate % 32)) & 1; k = (d[nbits].w[(endstate) / 32] >> (endstate % 32)) & 1;
endstate = (endstate >> 1) | (k << 7); endstate = (endstate >> 1) | (k << 7);
data[nbits] = k; data[nbits] = k;
} }
return 0; return 0;
} }
/* Delete instance of a Viterbi decoder */ /* Delete instance of a Viterbi decoder */
void delete_viterbi39_port(void *p) { void delete_viterbi39_port(void *p) {
struct v39 *vp = p; struct v39 *vp = p;
if (vp != NULL) { if (vp != NULL) {
free(vp->decisions); free(vp->decisions);
free(vp); free(vp);
} }
} }
/* C-language butterfly */ /* C-language butterfly */
@ -141,32 +141,32 @@ unsigned int metric,m0,m1,decision;\
*/ */
int update_viterbi39_blk_port(void *p, unsigned char *syms, int nbits) { int update_viterbi39_blk_port(void *p, unsigned char *syms, int nbits) {
struct v39 *vp = p; struct v39 *vp = p;
decision_t *d; decision_t *d;
if (p == NULL) if (p == NULL)
return -1; return -1;
d = (decision_t *) vp->dp; d = (decision_t *) vp->dp;
while (nbits--) { while (nbits--) {
void *tmp; void *tmp;
unsigned char sym0, sym1, sym2; unsigned char sym0, sym1, sym2;
int i; int i;
for (i = 0; i < 8; i++) for (i = 0; i < 8; i++)
d->w[i] = 0; d->w[i] = 0;
sym0 = *syms++; sym0 = *syms++;
sym1 = *syms++; sym1 = *syms++;
sym2 = *syms++; sym2 = *syms++;
for (i = 0; i < 128; i++) for (i = 0; i < 128; i++)
BFLY(i); BFLY(i);
d++; d++;
tmp = vp->old_metrics; tmp = vp->old_metrics;
vp->old_metrics = vp->new_metrics; vp->old_metrics = vp->new_metrics;
vp->new_metrics = tmp; vp->new_metrics = tmp;
} }
vp->dp = d; vp->dp = d;
return 0; return 0;
} }

@ -41,75 +41,75 @@ unsigned int crc_poly = 0x1864CFB;
unsigned int seed = 1; unsigned int seed = 1;
void usage(char *prog) { void usage(char *prog) {
printf("Usage: %s [nlps]\n", prog); printf("Usage: %s [nlps]\n", prog);
printf("\t-n num_bits [Default %d]\n", num_bits); printf("\t-n num_bits [Default %d]\n", num_bits);
printf("\t-l crc_length [Default %d]\n", crc_length); printf("\t-l crc_length [Default %d]\n", crc_length);
printf("\t-p crc_poly (Hex) [Default 0x%x]\n", crc_poly); printf("\t-p crc_poly (Hex) [Default 0x%x]\n", crc_poly);
printf("\t-s seed [Default 0=time]\n"); printf("\t-s seed [Default 0=time]\n");
} }
void parse_args(int argc, char **argv) { void parse_args(int argc, char **argv) {
int opt; int opt;
while ((opt = getopt(argc, argv, "nlps")) != -1) { while ((opt = getopt(argc, argv, "nlps")) != -1) {
switch (opt) { switch (opt) {
case 'n': case 'n':
num_bits = atoi(argv[optind]); num_bits = atoi(argv[optind]);
break; break;
case 'l': case 'l':
crc_length = atoi(argv[optind]); crc_length = atoi(argv[optind]);
break; break;
case 'p': case 'p':
crc_poly = (unsigned int) strtoul(argv[optind], NULL, 16); crc_poly = (unsigned int) strtoul(argv[optind], NULL, 16);
break; break;
case 's': case 's':
seed = (unsigned int) strtoul(argv[optind], NULL, 0); seed = (unsigned int) strtoul(argv[optind], NULL, 0);
break; break;
default: default:
usage(argv[0]); usage(argv[0]);
exit(-1); exit(-1);
} }
} }
} }
int main(int argc, char **argv) { int main(int argc, char **argv) {
int i; int i;
char *data; char *data;
unsigned int crc_word, expected_word; unsigned int crc_word, expected_word;
crc_t crc_p; crc_t crc_p;
parse_args(argc, 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) { if (!data) {
perror("malloc"); perror("malloc");
exit(-1); exit(-1);
} }
if (!seed) { if (!seed) {
seed = time(NULL); seed = time(NULL);
} }
srand(seed); srand(seed);
// Generate data // Generate data
for (i = 0; i < num_bits; i++) { for (i = 0; i < num_bits; i++) {
data[i] = rand() % 2; data[i] = rand() % 2;
} }
//Initialize CRC params and tables //Initialize CRC params and tables
if (crc_init(&crc_p, crc_poly, crc_length)) { if (crc_init(&crc_p, crc_poly, crc_length)) {
exit(-1); exit(-1);
} }
// generate CRC word // generate CRC word
crc_word = crc_checksum(&crc_p, data, num_bits); crc_word = crc_checksum(&crc_p, data, num_bits);
free(data); free(data);
// check if generated word is as expected // check if generated word is as expected
if (get_expected_word(num_bits, crc_length, crc_poly, seed, if (get_expected_word(num_bits, crc_length, crc_poly, seed,
&expected_word)) { &expected_word)) {
fprintf(stderr, "Test parameters not defined in test_results.h\n"); fprintf(stderr, "Test parameters not defined in test_results.h\n");
exit(-1); exit(-1);
} }
exit(expected_word != crc_word); exit(expected_word != crc_word);
} }

@ -30,42 +30,42 @@
#include "lte/fec/crc.h" #include "lte/fec/crc.h"
typedef struct { typedef struct {
int n; int n;
int l; int l;
unsigned int p; unsigned int p;
unsigned int s; unsigned int s;
unsigned int word; unsigned int word;
}expected_word_t; }expected_word_t;
static expected_word_t expected_words[] = { static expected_word_t expected_words[] = {
{5001, 24, LTE_CRC24A, 1, 0x1C5C97}, // LTE CRC24A (36.212 Sec 5.1.1) {5001, 24, LTE_CRC24A, 1, 0x1C5C97}, // LTE CRC24A (36.212 Sec 5.1.1)
{5001, 24, LTE_CRC24B, 1, 0x36D1F0}, // LTE CRC24B {5001, 24, LTE_CRC24B, 1, 0x36D1F0}, // LTE CRC24B
{5001, 16, LTE_CRC16, 1, 0x7FF4}, // LTE CRC16: 0x7FF4 {5001, 16, LTE_CRC16, 1, 0x7FF4}, // LTE CRC16: 0x7FF4
{5001, 8, LTE_CRC8, 1, 0xF0}, // LTE CRC8 0xF8 {5001, 8, LTE_CRC8, 1, 0xF0}, // LTE CRC8 0xF8
{-1, -1, 0, 0, 0} {-1, -1, 0, 0, 0}
}; };
int get_expected_word(int n, int l, unsigned int p, unsigned int s, unsigned int *word) { int get_expected_word(int n, int l, unsigned int p, unsigned int s, unsigned int *word) {
int i; int i;
i=0; i=0;
while(expected_words[i].n != -1) { while(expected_words[i].n != -1) {
if (expected_words[i].l == l if (expected_words[i].l == l
&& expected_words[i].p == p && expected_words[i].p == p
&& expected_words[i].s == s) { && expected_words[i].s == s) {
break; break;
} else { } else {
i++; i++;
} }
} }
if (expected_words[i].n == -1) { if (expected_words[i].n == -1) {
return -1; return -1;
} else { } else {
if (word) { if (word) {
*word = expected_words[i].word; *word = expected_words[i].word;
} }
return 0; return 0;
} }
} }

@ -39,97 +39,97 @@
int nof_tx_bits=-1, nof_rx_bits=-1; int nof_tx_bits=-1, nof_rx_bits=-1;
void usage(char *prog) { void usage(char *prog) {
printf("Usage: %s -t nof_tx_bits -r nof_rx_bits\n", prog); printf("Usage: %s -t nof_tx_bits -r nof_rx_bits\n", prog);
} }
void parse_args(int argc, char **argv) { void parse_args(int argc, char **argv) {
int opt; int opt;
while ((opt = getopt(argc, argv, "tr")) != -1) { while ((opt = getopt(argc, argv, "tr")) != -1) {
switch (opt) { switch (opt) {
case 't': case 't':
nof_tx_bits = atoi(argv[optind]); nof_tx_bits = atoi(argv[optind]);
break; break;
case 'r': case 'r':
nof_rx_bits = atoi(argv[optind]); nof_rx_bits = atoi(argv[optind]);
break; break;
default: default:
usage(argv[0]); usage(argv[0]);
exit(-1); exit(-1);
} }
} }
if (nof_tx_bits == -1) { if (nof_tx_bits == -1) {
usage(argv[0]); usage(argv[0]);
exit(-1); exit(-1);
} }
if (nof_rx_bits == -1) { if (nof_rx_bits == -1) {
usage(argv[0]); usage(argv[0]);
exit(-1); exit(-1);
} }
} }
int main(int argc, char **argv) { int main(int argc, char **argv) {
int i; int i;
char *bits, *rm_bits; char *bits, *rm_bits;
float *rm_symbols, *unrm_symbols; float *rm_symbols, *unrm_symbols;
int nof_errors; int nof_errors;
parse_args(argc, argv); parse_args(argc, argv);
bits = malloc(sizeof(char) * nof_tx_bits); bits = malloc(sizeof(char) * nof_tx_bits);
if (!bits) { if (!bits) {
perror("malloc"); perror("malloc");
exit(-1); exit(-1);
} }
rm_bits = malloc(sizeof(char) * nof_rx_bits); rm_bits = malloc(sizeof(char) * nof_rx_bits);
if (!rm_bits) { if (!rm_bits) {
perror("malloc"); perror("malloc");
exit(-1); exit(-1);
} }
rm_symbols = malloc(sizeof(float) * nof_rx_bits); rm_symbols = malloc(sizeof(float) * nof_rx_bits);
if (!rm_symbols) { if (!rm_symbols) {
perror("malloc"); perror("malloc");
exit(-1); exit(-1);
} }
unrm_symbols = malloc(sizeof(float) * nof_tx_bits); unrm_symbols = malloc(sizeof(float) * nof_tx_bits);
if (!unrm_symbols) { if (!unrm_symbols) {
perror("malloc"); perror("malloc");
exit(-1); exit(-1);
} }
for (i=0;i<nof_tx_bits;i++) { for (i=0;i<nof_tx_bits;i++) {
bits[i] = rand()%2; bits[i] = rand()%2;
} }
if (rm_conv_tx(bits, nof_tx_bits, rm_bits, nof_rx_bits)) { if (rm_conv_tx(bits, nof_tx_bits, rm_bits, nof_rx_bits)) {
exit(-1); exit(-1);
} }
for (i=0;i<nof_rx_bits;i++) { for (i=0;i<nof_rx_bits;i++) {
rm_symbols[i] = rm_bits[i]?1:-1; rm_symbols[i] = rm_bits[i]?1:-1;
} }
if (rm_conv_rx(rm_symbols, nof_rx_bits, unrm_symbols, nof_tx_bits)) { if (rm_conv_rx(rm_symbols, nof_rx_bits, unrm_symbols, nof_tx_bits)) {
exit(-1); exit(-1);
} }
nof_errors = 0; nof_errors = 0;
for (i=0;i<nof_tx_bits;i++) { for (i=0;i<nof_tx_bits;i++) {
if ((unrm_symbols[i] > 0) != bits[i]) { if ((unrm_symbols[i] > 0) != bits[i]) {
nof_errors++; nof_errors++;
} }
} }
if (nof_rx_bits > nof_tx_bits) { if (nof_rx_bits > nof_tx_bits) {
if (nof_errors) { if (nof_errors) {
printf("nof_errors=%d\n", nof_errors); printf("nof_errors=%d\n", nof_errors);
exit(-1); exit(-1);
} }
} }
free(bits); free(bits);
free(rm_bits); free(rm_bits);
free(rm_symbols); free(rm_symbols);
free(unrm_symbols); free(unrm_symbols);
printf("Ok\n"); printf("Ok\n");
exit(0); exit(0);
} }

@ -40,103 +40,103 @@ int nof_tx_bits=-1, nof_rx_bits=-1;
int rv_idx = 0; int rv_idx = 0;
void usage(char *prog) { void usage(char *prog) {
printf("Usage: %s -t nof_tx_bits -r nof_rx_bits [-i rv_idx]\n", prog); printf("Usage: %s -t nof_tx_bits -r nof_rx_bits [-i rv_idx]\n", prog);
} }
void parse_args(int argc, char **argv) { void parse_args(int argc, char **argv) {
int opt; int opt;
while ((opt = getopt(argc, argv, "tri")) != -1) { while ((opt = getopt(argc, argv, "tri")) != -1) {
switch (opt) { switch (opt) {
case 't': case 't':
nof_tx_bits = atoi(argv[optind]); nof_tx_bits = atoi(argv[optind]);
break; break;
case 'r': case 'r':
nof_rx_bits = atoi(argv[optind]); nof_rx_bits = atoi(argv[optind]);
break; break;
case 'i': case 'i':
rv_idx = atoi(argv[optind]); rv_idx = atoi(argv[optind]);
break; break;
default: default:
usage(argv[0]); usage(argv[0]);
exit(-1); exit(-1);
} }
} }
if (nof_tx_bits == -1) { if (nof_tx_bits == -1) {
usage(argv[0]); usage(argv[0]);
exit(-1); exit(-1);
} }
if (nof_rx_bits == -1) { if (nof_rx_bits == -1) {
usage(argv[0]); usage(argv[0]);
exit(-1); exit(-1);
} }
} }
int main(int argc, char **argv) { int main(int argc, char **argv) {
int i; int i;
char *bits, *rm_bits; char *bits, *rm_bits;
float *rm_symbols, *unrm_symbols; float *rm_symbols, *unrm_symbols;
int nof_errors; int nof_errors;
rm_turbo_t rm_turbo; rm_turbo_t rm_turbo;
parse_args(argc, argv); parse_args(argc, argv);
bits = malloc(sizeof(char) * nof_tx_bits); bits = malloc(sizeof(char) * nof_tx_bits);
if (!bits) { if (!bits) {
perror("malloc"); perror("malloc");
exit(-1); exit(-1);
} }
rm_bits = malloc(sizeof(char) * nof_rx_bits); rm_bits = malloc(sizeof(char) * nof_rx_bits);
if (!rm_bits) { if (!rm_bits) {
perror("malloc"); perror("malloc");
exit(-1); exit(-1);
} }
rm_symbols = malloc(sizeof(float) * nof_rx_bits); rm_symbols = malloc(sizeof(float) * nof_rx_bits);
if (!rm_symbols) { if (!rm_symbols) {
perror("malloc"); perror("malloc");
exit(-1); exit(-1);
} }
unrm_symbols = malloc(sizeof(float) * nof_tx_bits); unrm_symbols = malloc(sizeof(float) * nof_tx_bits);
if (!unrm_symbols) { if (!unrm_symbols) {
perror("malloc"); perror("malloc");
exit(-1); exit(-1);
} }
for (i=0;i<nof_tx_bits;i++) { for (i=0;i<nof_tx_bits;i++) {
bits[i] = rand()%2; bits[i] = rand()%2;
} }
rm_turbo_init(&rm_turbo, 1000); rm_turbo_init(&rm_turbo, 1000);
rm_turbo_tx(&rm_turbo, bits, nof_tx_bits, rm_bits, nof_rx_bits, rv_idx); rm_turbo_tx(&rm_turbo, bits, nof_tx_bits, rm_bits, nof_rx_bits, rv_idx);
for (i=0;i<nof_rx_bits;i++) { for (i=0;i<nof_rx_bits;i++) {
rm_symbols[i] = (float) rm_bits[i]?1:-1; rm_symbols[i] = (float) rm_bits[i]?1:-1;
} }
rm_turbo_rx(&rm_turbo, rm_symbols, nof_rx_bits, unrm_symbols, nof_tx_bits, rv_idx); rm_turbo_rx(&rm_turbo, rm_symbols, nof_rx_bits, unrm_symbols, nof_tx_bits, rv_idx);
nof_errors = 0; nof_errors = 0;
for (i=0;i<nof_tx_bits;i++) { for (i=0;i<nof_tx_bits;i++) {
if ((unrm_symbols[i] > 0) != bits[i]) { if ((unrm_symbols[i] > 0) != bits[i]) {
nof_errors++; nof_errors++;
printf("%.2f != %d\n", unrm_symbols[i], bits[i]); printf("%.2f != %d\n", unrm_symbols[i], bits[i]);
} }
} }
rm_turbo_free(&rm_turbo); rm_turbo_free(&rm_turbo);
free(bits); free(bits);
free(rm_bits); free(rm_bits);
free(rm_symbols); free(rm_symbols);
free(unrm_symbols); free(unrm_symbols);
if (nof_tx_bits >= nof_rx_bits) { if (nof_tx_bits >= nof_rx_bits) {
if (nof_errors) { if (nof_errors) {
printf("nof_errors=%d\n", nof_errors); printf("nof_errors=%d\n", nof_errors);
exit(-1); exit(-1);
} }
} }
printf("Ok\n"); printf("Ok\n");
exit(0); exit(0);
} }

@ -46,279 +46,279 @@ float ebno_db = 100.0;
unsigned int seed = 0; unsigned int seed = 0;
int K = -1; int K = -1;
#define MAX_ITERATIONS 4 #define MAX_ITERATIONS 4
int nof_iterations = MAX_ITERATIONS; int nof_iterations = MAX_ITERATIONS;
int test_known_data = 0; int test_known_data = 0;
int test_errors = 0; int test_errors = 0;
#define SNR_POINTS 8 #define SNR_POINTS 8
#define SNR_MIN 0.0 #define SNR_MIN 0.0
#define SNR_MAX 4.0 #define SNR_MAX 4.0
void usage(char *prog) { void usage(char *prog) {
printf("Usage: %s [nlesv]\n", prog); printf("Usage: %s [nlesv]\n", prog);
printf("\t-k Test with known data (ignores frame_length) [Default disabled]\n"); printf("\t-k Test with known data (ignores frame_length) [Default disabled]\n");
printf("\t-i nof_iterations [Default %d]\n", nof_iterations); printf("\t-i nof_iterations [Default %d]\n", nof_iterations);
printf("\t-n nof_frames [Default %d]\n", nof_frames); printf("\t-n nof_frames [Default %d]\n", nof_frames);
printf("\t-l frame_length [Default %d]\n", frame_length); printf("\t-l frame_length [Default %d]\n", frame_length);
printf("\t-e ebno in dB [Default scan]\n"); printf("\t-e ebno in dB [Default scan]\n");
printf("\t-t test: check errors on exit [Default disabled]\n"); printf("\t-t test: check errors on exit [Default disabled]\n");
printf("\t-s seed [Default 0=time]\n"); printf("\t-s seed [Default 0=time]\n");
} }
void parse_args(int argc, char **argv) { void parse_args(int argc, char **argv) {
int opt; int opt;
while ((opt = getopt(argc, argv, "inlstvekt")) != -1) { while ((opt = getopt(argc, argv, "inlstvekt")) != -1) {
switch (opt) { switch (opt) {
case 'n': case 'n':
nof_frames = atoi(argv[optind]); nof_frames = atoi(argv[optind]);
break; break;
case 'k': case 'k':
test_known_data = 1; test_known_data = 1;
break; break;
case 't': case 't':
test_errors = 1; test_errors = 1;
break; break;
case 'i': case 'i':
nof_iterations = atoi(argv[optind]); nof_iterations = atoi(argv[optind]);
break; break;
case 'l': case 'l':
frame_length = atoi(argv[optind]); frame_length = atoi(argv[optind]);
break; break;
case 'e': case 'e':
ebno_db = atof(argv[optind]); ebno_db = atof(argv[optind]);
break; break;
case 's': case 's':
seed = (unsigned int) strtoul(argv[optind], NULL, 0); seed = (unsigned int) strtoul(argv[optind], NULL, 0);
break; break;
case 'v': case 'v':
verbose++; verbose++;
break; break;
default: default:
usage(argv[0]); usage(argv[0]);
exit(-1); exit(-1);
} }
} }
} }
void output_matlab(float ber[MAX_ITERATIONS][SNR_POINTS], int snr_points) { void output_matlab(float ber[MAX_ITERATIONS][SNR_POINTS], int snr_points) {
int i, j; int i, j;
FILE *f = fopen("turbocoder_snr.m", "w"); FILE *f = fopen("turbocoder_snr.m", "w");
if (!f) { if (!f) {
perror("fopen"); perror("fopen");
exit(-1); exit(-1);
} }
fprintf(f, "ber=["); fprintf(f, "ber=[");
for (j=0;j<MAX_ITERATIONS;j++) { for (j=0;j<MAX_ITERATIONS;j++) {
for (i = 0; i < snr_points; i++) { for (i = 0; i < snr_points; i++) {
fprintf(f, "%g ", ber[j][i]); fprintf(f, "%g ", ber[j][i]);
} }
fprintf(f, ";\n"); fprintf(f, ";\n");
} }
fprintf(f, "];\n"); fprintf(f, "];\n");
fprintf(f, "snr=linspace(%g,%g-%g/%d,%d);\n", SNR_MIN, SNR_MAX, SNR_MAX, fprintf(f, "snr=linspace(%g,%g-%g/%d,%d);\n", SNR_MIN, SNR_MAX, SNR_MAX,
snr_points, snr_points); snr_points, snr_points);
fprintf(f, "semilogy(snr,ber,snr,0.5*erfc(sqrt(10.^(snr/10))));\n"); fprintf(f, "semilogy(snr,ber,snr,0.5*erfc(sqrt(10.^(snr/10))));\n");
fprintf(f, "legend('1 iter','2 iter', '3 iter', '4 iter', 'theory-uncoded');"); fprintf(f, "legend('1 iter','2 iter', '3 iter', '4 iter', 'theory-uncoded');");
fprintf(f, "grid on;\n"); fprintf(f, "grid on;\n");
fclose(f); fclose(f);
} }
int main(int argc, char **argv) { int main(int argc, char **argv) {
int frame_cnt; int frame_cnt;
float *llr; float *llr;
unsigned char *llr_c; unsigned char *llr_c;
char *data_tx, *data_rx, *symbols; char *data_tx, *data_rx, *symbols;
int i, j; int i, j;
float var[SNR_POINTS]; float var[SNR_POINTS];
int snr_points; int snr_points;
float ber[MAX_ITERATIONS][SNR_POINTS]; float ber[MAX_ITERATIONS][SNR_POINTS];
unsigned int errors[100]; unsigned int errors[100];
int coded_length; int coded_length;
struct timeval tdata[3]; struct timeval tdata[3];
float mean_usec; float mean_usec;
tdec_t tdec; tdec_t tdec;
tcod_t tcod; tcod_t tcod;
parse_args(argc, argv); parse_args(argc, argv);
if (!seed) { if (!seed) {
seed = time(NULL); seed = time(NULL);
} }
srand(seed); srand(seed);
if (test_known_data) { if (test_known_data) {
frame_length = KNOWN_DATA_LEN; frame_length = KNOWN_DATA_LEN;
} else { } else {
frame_length = lte_cb_size(lte_find_cb_index(frame_length)); frame_length = lte_cb_size(lte_find_cb_index(frame_length));
} }
coded_length = 3*(frame_length)+TOTALTAIL; coded_length = 3*(frame_length)+TOTALTAIL;
printf(" Frame length: %d\n", frame_length); printf(" Frame length: %d\n", frame_length);
if (ebno_db < 100.0) { if (ebno_db < 100.0) {
printf(" EbNo: %.2f\n", ebno_db); printf(" EbNo: %.2f\n", ebno_db);
} }
data_tx = malloc(frame_length * sizeof(char)); data_tx = malloc(frame_length * sizeof(char));
if (!data_tx) { if (!data_tx) {
perror("malloc"); perror("malloc");
exit(-1); exit(-1);
} }
data_rx = malloc(frame_length * sizeof(char)); data_rx = malloc(frame_length * sizeof(char));
if (!data_rx) { if (!data_rx) {
perror("malloc"); perror("malloc");
exit(-1); exit(-1);
} }
symbols = malloc(coded_length * sizeof(char)); symbols = malloc(coded_length * sizeof(char));
if (!symbols) { if (!symbols) {
perror("malloc"); perror("malloc");
exit(-1); exit(-1);
} }
llr = malloc(coded_length * sizeof(float)); llr = malloc(coded_length * sizeof(float));
if (!llr) { if (!llr) {
perror("malloc"); perror("malloc");
exit(-1); exit(-1);
} }
llr_c = malloc(coded_length * sizeof(char)); llr_c = malloc(coded_length * sizeof(char));
if (!llr_c) { if (!llr_c) {
perror("malloc"); perror("malloc");
exit(-1); exit(-1);
} }
if (tcod_init(&tcod, frame_length)) { if (tcod_init(&tcod, frame_length)) {
fprintf(stderr, "Error initiating Turbo coder\n"); fprintf(stderr, "Error initiating Turbo coder\n");
exit(-1); exit(-1);
} }
if (tdec_init(&tdec, frame_length)) { if (tdec_init(&tdec, frame_length)) {
fprintf(stderr, "Error initiating Turbo decoder\n"); fprintf(stderr, "Error initiating Turbo decoder\n");
exit(-1); exit(-1);
} }
float ebno_inc, esno_db; float ebno_inc, esno_db;
ebno_inc = (SNR_MAX - SNR_MIN) / SNR_POINTS; ebno_inc = (SNR_MAX - SNR_MIN) / SNR_POINTS;
if (ebno_db == 100.0) { if (ebno_db == 100.0) {
snr_points = SNR_POINTS; snr_points = SNR_POINTS;
for (i = 0; i < snr_points; i++) { for (i = 0; i < snr_points; i++) {
ebno_db = SNR_MIN + i * ebno_inc; ebno_db = SNR_MIN + i * ebno_inc;
esno_db = ebno_db + 10 * log10((double) 1 / 3); esno_db = ebno_db + 10 * log10((double) 1 / 3);
var[i] = sqrt(1 / (pow(10, esno_db / 10))); var[i] = sqrt(1 / (pow(10, esno_db / 10)));
} }
} else { } else {
esno_db = ebno_db + 10 * log10((double) 1 / 3); esno_db = ebno_db + 10 * log10((double) 1 / 3);
var[0] = sqrt(1 / (pow(10, esno_db / 10))); var[0] = sqrt(1 / (pow(10, esno_db / 10)));
snr_points = 1; snr_points = 1;
} }
for (i = 0; i < snr_points; i++) { for (i = 0; i < snr_points; i++) {
mean_usec = 0; mean_usec = 0;
frame_cnt = 0; frame_cnt = 0;
bzero(errors, sizeof(int) * MAX_ITERATIONS); bzero(errors, sizeof(int) * MAX_ITERATIONS);
while (frame_cnt < nof_frames) { while (frame_cnt < nof_frames) {
/* generate data_tx */ /* generate data_tx */
for (j = 0; j < frame_length; j++) { for (j = 0; j < frame_length; j++) {
if (test_known_data) { if (test_known_data) {
data_tx[j] = known_data[j]; data_tx[j] = known_data[j];
} else { } else {
data_tx[j] = rand() % 2; data_tx[j] = rand() % 2;
} }
} }
/* coded BER */ /* coded BER */
if (test_known_data) { if (test_known_data) {
for (j=0;j<coded_length;j++) { for (j=0;j<coded_length;j++) {
symbols[j] = known_data_encoded[j]; symbols[j] = known_data_encoded[j];
} }
} else { } else {
tcod_encode(&tcod, data_tx, symbols); tcod_encode(&tcod, data_tx, symbols);
} }
for (j = 0; j < coded_length; j++) { for (j = 0; j < coded_length; j++) {
llr[j] = symbols[j] ? sqrt(2) : -sqrt(2); llr[j] = symbols[j] ? sqrt(2) : -sqrt(2);
} }
ch_awgn_f(llr, llr, var[i], coded_length); ch_awgn_f(llr, llr, var[i], coded_length);
/* decoder */ /* decoder */
tdec_reset(&tdec); tdec_reset(&tdec);
int t; int t;
if (nof_iterations == -1) { if (nof_iterations == -1) {
t = MAX_ITERATIONS; t = MAX_ITERATIONS;
} else { } else {
t = nof_iterations; t = nof_iterations;
} }
for (j=0;j<t;j++) { for (j=0;j<t;j++) {
if (!j) gettimeofday(&tdata[1],NULL); // Only measure 1 iteration if (!j) gettimeofday(&tdata[1],NULL); // Only measure 1 iteration
tdec_iteration(&tdec, llr); tdec_iteration(&tdec, llr);
tdec_decision(&tdec, data_rx); tdec_decision(&tdec, data_rx);
if (!j) gettimeofday(&tdata[2],NULL); if (!j) gettimeofday(&tdata[2],NULL);
if (!j) get_time_interval(tdata); if (!j) get_time_interval(tdata);
if (!j) mean_usec = (float) mean_usec*0.9+(float) tdata[0].tv_usec*0.1; if (!j) mean_usec = (float) mean_usec*0.9+(float) tdata[0].tv_usec*0.1;
/* check errors */ /* check errors */
errors[j] += bit_diff(data_tx, data_rx, frame_length); errors[j] += bit_diff(data_tx, data_rx, frame_length);
if (j < MAX_ITERATIONS) { if (j < MAX_ITERATIONS) {
ber[j][i] = (float) errors[j] /(frame_cnt * frame_length); ber[j][i] = (float) errors[j] /(frame_cnt * frame_length);
} }
} }
frame_cnt++; frame_cnt++;
printf("Eb/No: %3.2f %10d/%d ", printf("Eb/No: %3.2f %10d/%d ",
SNR_MIN + i * ebno_inc,frame_cnt,nof_frames); SNR_MIN + i * ebno_inc,frame_cnt,nof_frames);
printf("BER: %.2e ",(float) errors[j-1] / (frame_cnt * frame_length)); printf("BER: %.2e ",(float) errors[j-1] / (frame_cnt * frame_length));
printf("%3.1f Mbps (%6.2f usec)", (float) frame_length/mean_usec, mean_usec); printf("%3.1f Mbps (%6.2f usec)", (float) frame_length/mean_usec, mean_usec);
printf("\r"); printf("\r");
} }
printf("\n"); printf("\n");
if (snr_points == 1) { if (snr_points == 1) {
if (test_known_data && seed == KNOWN_DATA_SEED if (test_known_data && seed == KNOWN_DATA_SEED
&& ebno_db == KNOWN_DATA_EBNO && ebno_db == KNOWN_DATA_EBNO
&& frame_cnt == KNOWN_DATA_NFRAMES) { && frame_cnt == KNOWN_DATA_NFRAMES) {
for (j=0;j<MAX_ITERATIONS;j++) { for (j=0;j<MAX_ITERATIONS;j++) {
if (errors[j] > known_data_errors[j]) { if (errors[j] > known_data_errors[j]) {
fprintf(stderr, "Expected %d errors but got %d\n", fprintf(stderr, "Expected %d errors but got %d\n",
known_data_errors[j], errors[j]); known_data_errors[j], errors[j]);
exit(-1); exit(-1);
}else { }else {
printf("Iter %d ok\n", j+1); printf("Iter %d ok\n", j+1);
} }
} }
} else { } else {
for (j=0;j<MAX_ITERATIONS;j++) { for (j=0;j<MAX_ITERATIONS;j++) {
printf("BER: %g\t%u errors\n", printf("BER: %g\t%u errors\n",
(float) errors[j] / (frame_cnt * frame_length), errors[j]); (float) errors[j] / (frame_cnt * frame_length), errors[j]);
if (test_errors) { if (test_errors) {
if (errors[j] > get_expected_errors(frame_cnt, seed, j+1, frame_length, ebno_db)) { if (errors[j] > get_expected_errors(frame_cnt, seed, j+1, frame_length, ebno_db)) {
fprintf(stderr, "Expected %d errors but got %d\n", fprintf(stderr, "Expected %d errors but got %d\n",
get_expected_errors(frame_cnt, seed, j+1, frame_length, ebno_db), get_expected_errors(frame_cnt, seed, j+1, frame_length, ebno_db),
errors[j]); errors[j]);
exit(-1); exit(-1);
} else { } else {
printf("Iter %d ok\n", j+1); printf("Iter %d ok\n", j+1);
} }
} }
} }
} }
} }
} }
free(data_tx); free(data_tx);
free(symbols); free(symbols);
free(llr); free(llr);
free(llr_c); free(llr_c);
free(data_rx); free(data_rx);
tdec_free(&tdec); tdec_free(&tdec);
tcod_free(&tcod); tcod_free(&tcod);
printf("\n"); printf("\n");
output_matlab(ber, snr_points); output_matlab(ber, snr_points);
printf("Done\n"); printf("Done\n");
exit(0); exit(0);
} }

@ -28,141 +28,141 @@
#include <stdbool.h> #include <stdbool.h>
typedef struct { typedef struct {
int n; int n;
unsigned int s; unsigned int s;
int iterations; int iterations;
int len; int len;
float ebno; float ebno;
int errors; int errors;
} expected_errors_t; } expected_errors_t;
static expected_errors_t expected_errors[] = { static expected_errors_t expected_errors[] = {
{ 100, 1, 1, 504, 1.0, 3989 }, { 100, 1, 1, 504, 1.0, 3989 },
{ 100, 1, 2, 504, 1.0, 1922 }, { 100, 1, 2, 504, 1.0, 1922 },
{ 100, 1, 3, 504, 1.0, 1096 }, { 100, 1, 3, 504, 1.0, 1096 },
{ 100, 1, 4, 504, 1.0, 957 }, { 100, 1, 4, 504, 1.0, 957 },
{ 100, 1, 1, 504, 2.0, 803 }, { 100, 1, 1, 504, 2.0, 803 },
{ 100, 1, 2, 504, 2.0, 47 }, { 100, 1, 2, 504, 2.0, 47 },
{ 100, 1, 3, 504, 2.0, 7 }, { 100, 1, 3, 504, 2.0, 7 },
{ 100, 1, 4, 504, 2.0, 0 }, { 100, 1, 4, 504, 2.0, 0 },
{ 100, 1, 1, 6144, 1.5, 24719 }, { 100, 1, 1, 6144, 1.5, 24719 },
{ 100, 1, 2, 6144, 1.5, 897 }, { 100, 1, 2, 6144, 1.5, 897 },
{ 100, 1, 3, 6144, 1.5, 2 }, { 100, 1, 3, 6144, 1.5, 2 },
{ 100, 1, 4, 6144, 1.5, 0 }, { 100, 1, 4, 6144, 1.5, 0 },
{ -1, 0, -1, -1, -1.0, -1} { -1, 0, -1, -1, -1.0, -1}
}; };
int get_expected_errors(int n, unsigned int s, int iterations, int len, float ebno) { int get_expected_errors(int n, unsigned int s, int iterations, int len, float ebno) {
int i; int i;
i = 0; i = 0;
while (expected_errors[i].n != -1) { while (expected_errors[i].n != -1) {
if (expected_errors[i].n == n if (expected_errors[i].n == n
&& expected_errors[i].s == s && expected_errors[i].s == s
&& expected_errors[i].len == len && expected_errors[i].len == len
&& expected_errors[i].iterations == iterations && expected_errors[i].iterations == iterations
&& expected_errors[i].ebno == ebno) { && expected_errors[i].ebno == ebno) {
break; break;
} else { } else {
i++; i++;
} }
} }
return expected_errors[i].errors; return expected_errors[i].errors;
} }
#define KNOWN_DATA_NFRAMES 1 #define KNOWN_DATA_NFRAMES 1
#define KNOWN_DATA_SEED 1 #define KNOWN_DATA_SEED 1
#define KNOWN_DATA_EBNO 0.5 #define KNOWN_DATA_EBNO 0.5
const int known_data_errors[4] = {47, 18, 0, 0}; const int known_data_errors[4] = {47, 18, 0, 0};
#define KNOWN_DATA_LEN 504 #define KNOWN_DATA_LEN 504
const char known_data[KNOWN_DATA_LEN] = { 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, const char known_data[KNOWN_DATA_LEN] = { 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1,
0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1,
0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1,
1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0,
0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1,
1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0,
1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0,
1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0,
1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1,
0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0,
0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0,
1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1,
1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0,
0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0,
0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1,
1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1,
1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0,
0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0,
1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1,
1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1,
1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0,
0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1 }; 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1 };
const char known_data_encoded[3 * KNOWN_DATA_LEN + 12] = { 0, 0, 0, 0, 0, 1, 1, const char known_data_encoded[3 * KNOWN_DATA_LEN + 12] = { 0, 0, 0, 0, 0, 1, 1,
1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1,
1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0,
0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0,
0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1,
1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1,
0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1,
1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1,
0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1,
1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0,
1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1,
0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0,
1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1,
0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1,
0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0,
0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0,
0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0,
0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0,
0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1,
0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0,
1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0,
1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0,
1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1,
1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1,
1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0,
0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1,
1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1,
0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1,
1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1,
1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0,
0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0,
1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0,
0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1,
1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0,
0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1,
0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0,
0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1,
0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0,
0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0,
0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0,
0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1,
1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0,
0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1,
1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1,
1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1,
0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1,
0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0,
1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0,
1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1,
1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1,
1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1,
1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0,
0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0,
1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1,
1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1,
1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0,
0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0,
0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0,
1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0,
1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0,
0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0,
1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1,
1, 0, 1, 1, 1 }; 1, 0, 1, 1, 1 };

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

@ -28,44 +28,44 @@
#include <stdbool.h> #include <stdbool.h>
typedef struct { typedef struct {
int n; int n;
unsigned int s; unsigned int s;
int len; int len;
int k; int k;
bool tail; bool tail;
float ebno; float ebno;
int errors; int errors;
}expected_errors_t; }expected_errors_t;
static expected_errors_t expected_errors[] = { static expected_errors_t expected_errors[] = {
{1000, 1, 40, 7, true, 0.0, 5363}, {1000, 1, 40, 7, true, 0.0, 5363},
{1000, 1, 40, 7, true, 2.0, 356}, {1000, 1, 40, 7, true, 2.0, 356},
{1000, 1, 40, 7, true, 3.0, 48}, {1000, 1, 40, 7, true, 3.0, 48},
{1000, 1, 40, 7, true, 4.5, 0}, {1000, 1, 40, 7, true, 4.5, 0},
{100, 1, 1000, 7, true, 0.0, 8753}, {100, 1, 1000, 7, true, 0.0, 8753},
{100, 1, 1000, 7, true, 2.0, 350}, {100, 1, 1000, 7, true, 2.0, 350},
{100, 1, 1000, 7, true, 3.0, 33}, {100, 1, 1000, 7, true, 3.0, 33},
{100, 1, 1000, 7, true, 4.5, 0}, {100, 1, 1000, 7, true, 4.5, 0},
{-1, -1, -1, -1, true, -1.0, -1} {-1, -1, -1, -1, true, -1.0, -1}
}; };
int get_expected_errors(int n, unsigned int s, int len, int k, bool tail, float ebno) { int get_expected_errors(int n, unsigned int s, int len, int k, bool tail, float ebno) {
int i; int i;
i=0; i=0;
while(expected_errors[i].n != -1) { while(expected_errors[i].n != -1) {
if (expected_errors[i].n == n if (expected_errors[i].n == n
&& expected_errors[i].s == s && expected_errors[i].s == s
&& expected_errors[i].len == len && expected_errors[i].len == len
&& expected_errors[i].k == k && expected_errors[i].k == k
&& expected_errors[i].tail == tail && expected_errors[i].tail == tail
&& expected_errors[i].ebno == ebno) { && expected_errors[i].ebno == ebno) {
break; break;
} else { } else {
i++; i++;
} }
} }
return expected_errors[i].errors; return expected_errors[i].errors;
} }

@ -43,113 +43,113 @@
#define idx(a, b) ((a)*(q->szfreq)+b) #define idx(a, b) ((a)*(q->szfreq)+b)
int filter2d_init(filter2d_t* q, float **taps, int ntime, int nfreq, int sztime, int filter2d_init(filter2d_t* q, float **taps, int ntime, int nfreq, int sztime,
int szfreq) { int szfreq) {
int ret = -1; int ret = -1;
bzero(q, sizeof(filter2d_t)); bzero(q, sizeof(filter2d_t));
if (matrix_init((void***)&q->taps, ntime, nfreq, sizeof(float))) { if (matrix_init((void***)&q->taps, ntime, nfreq, sizeof(float))) {
goto free_and_exit; goto free_and_exit;
} }
matrix_copy((void**) q->taps, (void**) taps, ntime, nfreq, sizeof(float)); matrix_copy((void**) q->taps, (void**) taps, ntime, nfreq, sizeof(float));
q->output = vec_malloc((ntime+sztime)*(szfreq)*sizeof(cf_t)); q->output = vec_malloc((ntime+sztime)*(szfreq)*sizeof(cf_t));
if (!q->output) { if (!q->output) {
goto free_and_exit; goto free_and_exit;
} }
bzero(q->output, (ntime+sztime)*(szfreq)*sizeof(cf_t)); bzero(q->output, (ntime+sztime)*(szfreq)*sizeof(cf_t));
q->nfreq = nfreq; q->nfreq = nfreq;
q->ntime = ntime; q->ntime = ntime;
q->szfreq = szfreq; q->szfreq = szfreq;
q->sztime = sztime; q->sztime = sztime;
ret = 0; ret = 0;
free_and_exit: if (ret == -1) { free_and_exit: if (ret == -1) {
filter2d_free(q); filter2d_free(q);
} }
return ret; return ret;
} }
void filter2d_free(filter2d_t *q) { void filter2d_free(filter2d_t *q) {
matrix_free((void**) q->taps, q->ntime); matrix_free((void**) q->taps, q->ntime);
if (q->output) { if (q->output) {
free(q->output); free(q->output);
} }
bzero(q, sizeof(filter2d_t)); bzero(q, sizeof(filter2d_t));
} }
int filter2d_init_default(filter2d_t* q, int ntime, int nfreq, int sztime, int filter2d_init_default(filter2d_t* q, int ntime, int nfreq, int sztime,
int szfreq) { int szfreq) {
int i, j; int i, j;
int ret = -1; int ret = -1;
float **taps; float **taps;
if (matrix_init((void***) &taps, ntime, nfreq, sizeof(float))) { if (matrix_init((void***) &taps, ntime, nfreq, sizeof(float))) {
goto free_and_exit; goto free_and_exit;
} }
/* Compute the default 2-D interpolation mesh */ /* Compute the default 2-D interpolation mesh */
for (i = 0; i < ntime; i++) { for (i = 0; i < ntime; i++) {
for (j = 0; j < nfreq; j++) { for (j = 0; j < nfreq; j++) {
if (j < nfreq / 2) if (j < nfreq / 2)
taps[i][j] = (j + 1.0) / (2.0 * intceil(nfreq, 2)); taps[i][j] = (j + 1.0) / (2.0 * intceil(nfreq, 2));
else if (j == nfreq / 2) else if (j == nfreq / 2)
taps[i][j] = 0.5; taps[i][j] = 0.5;
else if (j > nfreq / 2) else if (j > nfreq / 2)
taps[i][j] = (nfreq - j) / (2.0 * intceil(nfreq, 2)); taps[i][j] = (nfreq - j) / (2.0 * intceil(nfreq, 2));
} }
} }
INFO("Using default interpolation matrix of size %dx%d\n", ntime, nfreq); INFO("Using default interpolation matrix of size %dx%d\n", ntime, nfreq);
if (verbose >= VERBOSE_DEBUG) { if (verbose >= VERBOSE_DEBUG) {
matrix_fprintf_f(stdout, taps, ntime, nfreq); matrix_fprintf_f(stdout, taps, ntime, nfreq);
} }
if (filter2d_init(q, taps, ntime, nfreq, sztime, szfreq)) { if (filter2d_init(q, taps, ntime, nfreq, sztime, szfreq)) {
goto free_and_exit; goto free_and_exit;
} }
ret = 0; ret = 0;
free_and_exit: free_and_exit:
matrix_free((void**) taps, ntime); matrix_free((void**) taps, ntime);
return ret; return ret;
} }
/* Moves the last ntime symbols to the start and clears the remaining of the output. /* Moves the last ntime symbols to the start and clears the remaining of the output.
* Should be called, for instance, before filtering each OFDM frame. * Should be called, for instance, before filtering each OFDM frame.
*/ */
void filter2d_reset(filter2d_t *q) { void filter2d_reset(filter2d_t *q) {
int i; int i;
for (i = 0; i < q->ntime; i++) { for (i = 0; i < q->ntime; i++) {
memcpy(&q->output[idx(i,0)], &q->output[idx(q->sztime + i,0)], memcpy(&q->output[idx(i,0)], &q->output[idx(q->sztime + i,0)],
sizeof(cf_t) * (q->szfreq)); sizeof(cf_t) * (q->szfreq));
} }
for (; i < q->ntime + q->sztime; i++) { for (; i < q->ntime + q->sztime; i++) {
memset(&q->output[idx(i,0)], 0, sizeof(cf_t) * (q->szfreq)); memset(&q->output[idx(i,0)], 0, sizeof(cf_t) * (q->szfreq));
} }
} }
/** Adds samples x to the from the given time/freq indexes to the filter /** Adds samples x to the from the given time/freq indexes to the filter
* and computes the output. * and computes the output.
*/ */
void filter2d_add(filter2d_t *q, cf_t x, int time_idx, int freq_idx) { void filter2d_add(filter2d_t *q, cf_t x, int time_idx, int freq_idx) {
int i, j; int i, j;
int ntime = q->ntime; int ntime = q->ntime;
int nfreq = q->nfreq; int nfreq = q->nfreq;
for (i = 0; i < ntime; i++) { for (i = 0; i < ntime; i++) {
for (j = 0; j < nfreq; j++) { for (j = 0; j < nfreq; j++) {
q->output[idx(i+time_idx, j+freq_idx - nfreq/2)] += x * (cf_t)(q->taps[i][j]); q->output[idx(i+time_idx, j+freq_idx - nfreq/2)] += x * (cf_t)(q->taps[i][j]);
} }
} }
} }

@ -38,21 +38,21 @@
/* Internal functions */ /* Internal functions */
static int gen_seq_buff(binsource_t* q, int nwords) { static int gen_seq_buff(binsource_t* q, int nwords) {
if (q->seq_buff_nwords != nwords) { if (q->seq_buff_nwords != nwords) {
free(q->seq_buff); free(q->seq_buff);
q->seq_buff_nwords = 0; q->seq_buff_nwords = 0;
} }
if (!q->seq_buff_nwords) { if (!q->seq_buff_nwords) {
q->seq_buff = malloc(nwords*sizeof(uint32_t)); q->seq_buff = malloc(nwords*sizeof(uint32_t));
if (!q->seq_buff) { if (!q->seq_buff) {
return -1; return -1;
} }
q->seq_buff_nwords = nwords; q->seq_buff_nwords = nwords;
} }
for (int i=0;i<q->seq_buff_nwords;i++) { for (int i=0;i<q->seq_buff_nwords;i++) {
q->seq_buff[i] = rand_r(&q->seed); q->seq_buff[i] = rand_r(&q->seed);
} }
return 0; return 0;
} }
/* Low-level API */ /* Low-level API */
@ -61,62 +61,62 @@ static int gen_seq_buff(binsource_t* q, int nwords) {
* Initializes the binsource object. * Initializes the binsource object.
*/ */
void binsource_init(binsource_t* q) { void binsource_init(binsource_t* q) {
bzero((void*) q,sizeof(binsource_t)); bzero((void*) q,sizeof(binsource_t));
} }
/** /**
* Destroys binsource object * Destroys binsource object
*/ */
void binsource_free(binsource_t* q) { void binsource_free(binsource_t* q) {
if (q->seq_buff) { if (q->seq_buff) {
free(q->seq_buff); free(q->seq_buff);
} }
bzero(q, sizeof(binsource_t)); bzero(q, sizeof(binsource_t));
} }
/** /**
* Sets a new seed * Sets a new seed
*/ */
void binsource_seed_set(binsource_t* q, unsigned int seed) { void binsource_seed_set(binsource_t* q, unsigned int seed) {
q->seed = seed; q->seed = seed;
} }
/** /**
* Sets local time as seed. * Sets local time as seed.
*/ */
void binsource_seed_time(binsource_t *q) { void binsource_seed_time(binsource_t *q) {
struct timeval t1; struct timeval t1;
gettimeofday(&t1, NULL); gettimeofday(&t1, NULL);
q->seed = t1.tv_usec * t1.tv_sec; q->seed = t1.tv_usec * t1.tv_sec;
} }
/** /**
* Generates a sequence of nbits random bits * Generates a sequence of nbits random bits
*/ */
int binsource_cache_gen(binsource_t* q, int nbits) { int binsource_cache_gen(binsource_t* q, int nbits) {
if (gen_seq_buff(q,DIV(nbits,32))) { if (gen_seq_buff(q,DIV(nbits,32))) {
return -1; return -1;
} }
q->seq_cache_nbits = nbits; q->seq_cache_nbits = nbits;
q->seq_cache_rp = 0; q->seq_cache_rp = 0;
return 0; return 0;
} }
static int int_2_bits(uint32_t* src, char* dst, int nbits) { static int int_2_bits(uint32_t* src, char* dst, int nbits) {
int n; int n;
n=nbits/32; n=nbits/32;
for (int i=0;i<n;i++) { for (int i=0;i<n;i++) {
bit_pack(src[i],&dst,32); bit_pack(src[i],&dst,32);
} }
bit_pack(src[n],&dst,nbits-n*32); bit_pack(src[n],&dst,nbits-n*32);
return n; return n;
} }
/** /**
* Copies the next random bits to the buffer bits from the array generated by binsource_cache_gen * Copies the next random bits to the buffer bits from the array generated by binsource_cache_gen
*/ */
void binsource_cache_cpy(binsource_t* q, char *bits, int nbits) { void binsource_cache_cpy(binsource_t* q, char *bits, int nbits) {
q->seq_cache_rp += int_2_bits(&q->seq_buff[q->seq_cache_rp],bits,nbits); q->seq_cache_rp += int_2_bits(&q->seq_buff[q->seq_cache_rp],bits,nbits);
} }
/** /**
@ -125,11 +125,11 @@ void binsource_cache_cpy(binsource_t* q, char *bits, int nbits) {
*/ */
int binsource_generate(binsource_t* q, char *bits, int nbits) { int binsource_generate(binsource_t* q, char *bits, int nbits) {
if (gen_seq_buff(q,DIV(nbits,32))) { if (gen_seq_buff(q,DIV(nbits,32))) {
return -1; return -1;
} }
int_2_bits(q->seq_buff,bits,nbits); int_2_bits(q->seq_buff,bits,nbits);
return 0; return 0;
} }
@ -139,42 +139,42 @@ int binsource_generate(binsource_t* q, char *bits, int nbits) {
/* High-Level API */ /* High-Level API */
int binsource_initialize(binsource_hl* hl) { int binsource_initialize(binsource_hl* hl) {
binsource_init(&hl->obj); binsource_init(&hl->obj);
if (hl->init.seed) { if (hl->init.seed) {
binsource_seed_set(&hl->obj,hl->init.seed); binsource_seed_set(&hl->obj,hl->init.seed);
} else { } else {
binsource_seed_time(&hl->obj); binsource_seed_time(&hl->obj);
} }
if (hl->init.cache_seq_nbits) { if (hl->init.cache_seq_nbits) {
if (binsource_cache_gen(&hl->obj,hl->init.cache_seq_nbits)) { if (binsource_cache_gen(&hl->obj,hl->init.cache_seq_nbits)) {
return -1; return -1;
} }
} }
return 0; return 0;
} }
int binsource_work(binsource_hl* hl) { int binsource_work(binsource_hl* hl) {
int ret = -1; int ret = -1;
if (hl->init.cache_seq_nbits) { if (hl->init.cache_seq_nbits) {
binsource_cache_cpy(&hl->obj,hl->output,hl->ctrl_in.nbits); binsource_cache_cpy(&hl->obj,hl->output,hl->ctrl_in.nbits);
ret = 0; ret = 0;
} else { } else {
ret = binsource_generate(&hl->obj,hl->output,hl->ctrl_in.nbits); ret = binsource_generate(&hl->obj,hl->output,hl->ctrl_in.nbits);
} }
if (!ret) { if (!ret) {
hl->out_len = hl->ctrl_in.nbits; hl->out_len = hl->ctrl_in.nbits;
} else { } else {
hl->out_len = 0; hl->out_len = 0;
} }
return ret; return ret;
} }
int binsource_stop(binsource_hl* hl) { int binsource_stop(binsource_hl* hl) {
binsource_free(&hl->obj); binsource_free(&hl->obj);
return 0; return 0;
} }

@ -35,85 +35,85 @@
#include "lte/io/filesink.h" #include "lte/io/filesink.h"
int filesink_init(filesink_t *q, char *filename, data_type_t type) { int filesink_init(filesink_t *q, char *filename, data_type_t type) {
bzero(q, sizeof(filesink_t)); bzero(q, sizeof(filesink_t));
q->f = fopen(filename, "w"); q->f = fopen(filename, "w");
if (!q->f) { if (!q->f) {
perror("fopen"); perror("fopen");
return -1; return -1;
} }
q->type = type; q->type = type;
return 0; return 0;
} }
void filesink_free(filesink_t *q) { void filesink_free(filesink_t *q) {
if (q->f) { if (q->f) {
fclose(q->f); fclose(q->f);
} }
bzero(q, sizeof(filesink_t)); bzero(q, sizeof(filesink_t));
} }
int filesink_write(filesink_t *q, void *buffer, int nsamples) { int filesink_write(filesink_t *q, void *buffer, int nsamples) {
int i; int i;
float *fbuf = (float*) buffer; float *fbuf = (float*) buffer;
_Complex float *cbuf = (_Complex float*) buffer; _Complex float *cbuf = (_Complex float*) buffer;
_Complex short *sbuf = (_Complex short*) buffer; _Complex short *sbuf = (_Complex short*) buffer;
int size; int size;
switch(q->type) { switch(q->type) {
case FLOAT: case FLOAT:
for (i=0;i<nsamples;i++) { for (i=0;i<nsamples;i++) {
fprintf(q->f,"%g\n",fbuf[i]); fprintf(q->f,"%g\n",fbuf[i]);
} }
break; break;
case COMPLEX_FLOAT: case COMPLEX_FLOAT:
for (i=0;i<nsamples;i++) { for (i=0;i<nsamples;i++) {
if (__imag__ cbuf[i] >= 0) if (__imag__ cbuf[i] >= 0)
fprintf(q->f,"%g+%gi\n",__real__ cbuf[i],__imag__ cbuf[i]); fprintf(q->f,"%g+%gi\n",__real__ cbuf[i],__imag__ cbuf[i]);
else else
fprintf(q->f,"%g-%gi\n",__real__ cbuf[i],fabsf(__imag__ cbuf[i])); fprintf(q->f,"%g-%gi\n",__real__ cbuf[i],fabsf(__imag__ cbuf[i]));
} }
break; break;
case COMPLEX_SHORT: case COMPLEX_SHORT:
for (i=0;i<nsamples;i++) { for (i=0;i<nsamples;i++) {
if (__imag__ sbuf[i] >= 0) if (__imag__ sbuf[i] >= 0)
fprintf(q->f,"%hd+%hdi\n",__real__ sbuf[i],__imag__ sbuf[i]); fprintf(q->f,"%hd+%hdi\n",__real__ sbuf[i],__imag__ sbuf[i]);
else else
fprintf(q->f,"%hd-%hdi\n",__real__ sbuf[i],(short) abs(__imag__ sbuf[i])); fprintf(q->f,"%hd-%hdi\n",__real__ sbuf[i],(short) abs(__imag__ sbuf[i]));
} }
break; break;
case FLOAT_BIN: case FLOAT_BIN:
case COMPLEX_FLOAT_BIN: case COMPLEX_FLOAT_BIN:
case COMPLEX_SHORT_BIN: case COMPLEX_SHORT_BIN:
if (q->type == FLOAT_BIN) { if (q->type == FLOAT_BIN) {
size = sizeof(float); size = sizeof(float);
} else if (q->type == COMPLEX_FLOAT_BIN) { } else if (q->type == COMPLEX_FLOAT_BIN) {
size = sizeof(_Complex float); size = sizeof(_Complex float);
} else if (q->type == COMPLEX_SHORT_BIN) { } else if (q->type == COMPLEX_SHORT_BIN) {
size = sizeof(_Complex short); size = sizeof(_Complex short);
} }
return fwrite(buffer, size, nsamples, q->f); return fwrite(buffer, size, nsamples, q->f);
break; break;
default: default:
i = -1; i = -1;
break; break;
} }
return i; return i;
} }
int filesink_initialize(filesink_hl* h) { int filesink_initialize(filesink_hl* h) {
return filesink_init(&h->obj, h->init.file_name, h->init.data_type); return filesink_init(&h->obj, h->init.file_name, h->init.data_type);
} }
int filesink_work(filesink_hl* h) { int filesink_work(filesink_hl* h) {
if (filesink_write(&h->obj, h->input, h->in_len)<0) { if (filesink_write(&h->obj, h->input, h->in_len)<0) {
return -1; return -1;
} }
return 0; return 0;
} }
int filesink_stop(filesink_hl* h) { int filesink_stop(filesink_hl* h) {
filesink_free(&h->obj); filesink_free(&h->obj);
return 0; return 0;
} }

@ -33,104 +33,104 @@
#include "lte/io/filesource.h" #include "lte/io/filesource.h"
int filesource_init(filesource_t *q, char *filename, data_type_t type) { int filesource_init(filesource_t *q, char *filename, data_type_t type) {
bzero(q, sizeof(filesource_t)); bzero(q, sizeof(filesource_t));
q->f = fopen(filename, "r"); q->f = fopen(filename, "r");
if (!q->f) { if (!q->f) {
perror("fopen"); perror("fopen");
return -1; return -1;
} }
q->type = type; q->type = type;
return 0; return 0;
} }
void filesource_free(filesource_t *q) { void filesource_free(filesource_t *q) {
if (q->f) { if (q->f) {
fclose(q->f); fclose(q->f);
} }
bzero(q, sizeof(filesource_t)); bzero(q, sizeof(filesource_t));
} }
void filesource_seek(filesource_t *q, int pos) { void filesource_seek(filesource_t *q, int pos) {
fseek(q->f, pos, SEEK_SET); fseek(q->f, pos, SEEK_SET);
} }
int read_complex_f(FILE *f, _Complex float *y) { int read_complex_f(FILE *f, _Complex float *y) {
char in_str[64]; char in_str[64];
_Complex float x; _Complex float x;
if (NULL == fgets(in_str, 64, f)) { if (NULL == fgets(in_str, 64, f)) {
return -1; return -1;
} else { } else {
if (index(in_str, 'i') || index(in_str, 'j')) { if (index(in_str, 'i') || index(in_str, 'j')) {
sscanf(in_str,"%f%fi",&(__real__ x),&(__imag__ x)); sscanf(in_str,"%f%fi",&(__real__ x),&(__imag__ x));
} else { } else {
__imag__ x = 0; __imag__ x = 0;
sscanf(in_str,"%f",&(__real__ x)); sscanf(in_str,"%f",&(__real__ x));
} }
*y = x; *y = x;
return 0; return 0;
} }
} }
int filesource_read(filesource_t *q, void *buffer, int nsamples) { int filesource_read(filesource_t *q, void *buffer, int nsamples) {
int i; int i;
float *fbuf = (float*) buffer; float *fbuf = (float*) buffer;
_Complex float *cbuf = (_Complex float*) buffer; _Complex float *cbuf = (_Complex float*) buffer;
_Complex short *sbuf = (_Complex short*) buffer; _Complex short *sbuf = (_Complex short*) buffer;
int size; int size;
switch(q->type) { switch(q->type) {
case FLOAT: case FLOAT:
for (i=0;i<nsamples;i++) { for (i=0;i<nsamples;i++) {
if (EOF == fscanf(q->f,"%g\n",&fbuf[i])) if (EOF == fscanf(q->f,"%g\n",&fbuf[i]))
break; break;
} }
break; break;
case COMPLEX_FLOAT: case COMPLEX_FLOAT:
for (i=0;i<nsamples;i++) { for (i=0;i<nsamples;i++) {
if (read_complex_f(q->f, &cbuf[i])) { if (read_complex_f(q->f, &cbuf[i])) {
break; break;
} }
} }
break; break;
case COMPLEX_SHORT: case COMPLEX_SHORT:
for (i=0;i<nsamples;i++) { for (i=0;i<nsamples;i++) {
if (EOF == fscanf(q->f,"%hd%hdi\n",&(__real__ sbuf[i]),&(__imag__ sbuf[i]))) if (EOF == fscanf(q->f,"%hd%hdi\n",&(__real__ sbuf[i]),&(__imag__ sbuf[i])))
break; break;
} }
break; break;
case FLOAT_BIN: case FLOAT_BIN:
case COMPLEX_FLOAT_BIN: case COMPLEX_FLOAT_BIN:
case COMPLEX_SHORT_BIN: case COMPLEX_SHORT_BIN:
if (q->type == FLOAT_BIN) { if (q->type == FLOAT_BIN) {
size = sizeof(float); size = sizeof(float);
} else if (q->type == COMPLEX_FLOAT_BIN) { } else if (q->type == COMPLEX_FLOAT_BIN) {
size = sizeof(_Complex float); size = sizeof(_Complex float);
} else if (q->type == COMPLEX_SHORT_BIN) { } else if (q->type == COMPLEX_SHORT_BIN) {
size = sizeof(_Complex short); size = sizeof(_Complex short);
} }
return fread(buffer, size, nsamples, q->f); return fread(buffer, size, nsamples, q->f);
break; break;
default: default:
i = -1; i = -1;
break; break;
} }
return i; return i;
} }
int filesource_initialize(filesource_hl* h) { int filesource_initialize(filesource_hl* h) {
return filesource_init(&h->obj, h->init.file_name, h->init.data_type); return filesource_init(&h->obj, h->init.file_name, h->init.data_type);
} }
int filesource_work(filesource_hl* h) { int filesource_work(filesource_hl* h) {
h->out_len = filesource_read(&h->obj, h->output, h->ctrl_in.nsamples); h->out_len = filesource_read(&h->obj, h->output, h->ctrl_in.nsamples);
if (h->out_len < 0) { if (h->out_len < 0) {
return -1; return -1;
} }
return 0; return 0;
} }
int filesource_stop(filesource_hl* h) { int filesource_stop(filesource_hl* h) {
filesource_free(&h->obj); filesource_free(&h->obj);
return 0; return 0;
} }

@ -38,65 +38,65 @@
#include "lte/io/udpsink.h" #include "lte/io/udpsink.h"
int udpsink_init(udpsink_t *q, char *address, int port, data_type_t type) { int udpsink_init(udpsink_t *q, char *address, int port, data_type_t type) {
bzero(q, sizeof(udpsink_t)); bzero(q, sizeof(udpsink_t));
q->sockfd=socket(AF_INET,SOCK_DGRAM,0); q->sockfd=socket(AF_INET,SOCK_DGRAM,0);
q->servaddr.sin_family = AF_INET; q->servaddr.sin_family = AF_INET;
q->servaddr.sin_addr.s_addr=inet_addr(address); q->servaddr.sin_addr.s_addr=inet_addr(address);
q->servaddr.sin_port=htons(port); q->servaddr.sin_port=htons(port);
q->type = type; q->type = type;
return 0; return 0;
} }
void udpsink_free(udpsink_t *q) { void udpsink_free(udpsink_t *q) {
if (q->sockfd) { if (q->sockfd) {
close(q->sockfd); close(q->sockfd);
} }
bzero(q, sizeof(udpsink_t)); bzero(q, sizeof(udpsink_t));
} }
int udpsink_write(udpsink_t *q, void *buffer, int nsamples) { int udpsink_write(udpsink_t *q, void *buffer, int nsamples) {
int size; int size;
switch(q->type) { switch(q->type) {
case FLOAT: case FLOAT:
case COMPLEX_FLOAT: case COMPLEX_FLOAT:
case COMPLEX_SHORT: case COMPLEX_SHORT:
fprintf(stderr, "Not implemented\n"); fprintf(stderr, "Not implemented\n");
return -1; return -1;
case FLOAT_BIN: case FLOAT_BIN:
case COMPLEX_FLOAT_BIN: case COMPLEX_FLOAT_BIN:
case COMPLEX_SHORT_BIN: case COMPLEX_SHORT_BIN:
if (q->type == FLOAT_BIN) { if (q->type == FLOAT_BIN) {
size = sizeof(float); size = sizeof(float);
} else if (q->type == COMPLEX_FLOAT_BIN) { } else if (q->type == COMPLEX_FLOAT_BIN) {
size = sizeof(_Complex float); size = sizeof(_Complex float);
} else if (q->type == COMPLEX_SHORT_BIN) { } else if (q->type == COMPLEX_SHORT_BIN) {
size = sizeof(_Complex short); size = sizeof(_Complex short);
} }
return sendto(q->sockfd, buffer, nsamples * size, 0, return sendto(q->sockfd, buffer, nsamples * size, 0,
&q->servaddr, sizeof(struct sockaddr_in)); &q->servaddr, sizeof(struct sockaddr_in));
break; break;
} }
return -1; return -1;
} }
int udpsink_initialize(udpsink_hl* h) { int udpsink_initialize(udpsink_hl* h) {
return udpsink_init(&h->obj, h->init.address, h->init.port, h->init.data_type); return udpsink_init(&h->obj, h->init.address, h->init.port, h->init.data_type);
} }
int udpsink_work(udpsink_hl* h) { int udpsink_work(udpsink_hl* h) {
if (udpsink_write(&h->obj, h->input, h->in_len)<0) { if (udpsink_write(&h->obj, h->input, h->in_len)<0) {
return -1; return -1;
} }
return 0; return 0;
} }
int udpsink_stop(udpsink_hl* h) { int udpsink_stop(udpsink_hl* h) {
udpsink_free(&h->obj); udpsink_free(&h->obj);
return 0; return 0;
} }

@ -36,65 +36,65 @@
#include "lte/io/udpsource.h" #include "lte/io/udpsource.h"
int udpsource_init(udpsource_t *q, char *address, int port, data_type_t type) { int udpsource_init(udpsource_t *q, char *address, int port, data_type_t type) {
bzero(q, sizeof(udpsource_t)); bzero(q, sizeof(udpsource_t));
q->sockfd=socket(AF_INET,SOCK_DGRAM,0); q->sockfd=socket(AF_INET,SOCK_DGRAM,0);
q->servaddr.sin_family = AF_INET; q->servaddr.sin_family = AF_INET;
q->servaddr.sin_addr.s_addr=inet_addr(address); q->servaddr.sin_addr.s_addr=inet_addr(address);
q->servaddr.sin_port=htons(port); q->servaddr.sin_port=htons(port);
bind(q->sockfd,(struct sockaddr *)&q->servaddr,sizeof(struct sockaddr_in)); bind(q->sockfd,(struct sockaddr *)&q->servaddr,sizeof(struct sockaddr_in));
q->type = type; q->type = type;
return 0; return 0;
} }
void udpsource_free(udpsource_t *q) { void udpsource_free(udpsource_t *q) {
if (q->sockfd) { if (q->sockfd) {
close(q->sockfd); close(q->sockfd);
} }
bzero(q, sizeof(udpsource_t)); bzero(q, sizeof(udpsource_t));
} }
int udpsource_read(udpsource_t *q, void *buffer, int nsamples) { int udpsource_read(udpsource_t *q, void *buffer, int nsamples) {
int size; int size;
switch(q->type) { switch(q->type) {
case FLOAT: case FLOAT:
case COMPLEX_FLOAT: case COMPLEX_FLOAT:
case COMPLEX_SHORT: case COMPLEX_SHORT:
fprintf(stderr, "Not implemented\n"); fprintf(stderr, "Not implemented\n");
return -1; return -1;
case FLOAT_BIN: case FLOAT_BIN:
case COMPLEX_FLOAT_BIN: case COMPLEX_FLOAT_BIN:
case COMPLEX_SHORT_BIN: case COMPLEX_SHORT_BIN:
if (q->type == FLOAT_BIN) { if (q->type == FLOAT_BIN) {
size = sizeof(float); size = sizeof(float);
} else if (q->type == COMPLEX_FLOAT_BIN) { } else if (q->type == COMPLEX_FLOAT_BIN) {
size = sizeof(_Complex float); size = sizeof(_Complex float);
} else if (q->type == COMPLEX_SHORT_BIN) { } else if (q->type == COMPLEX_SHORT_BIN) {
size = sizeof(_Complex short); size = sizeof(_Complex short);
} }
return recv(q->sockfd, buffer, size * nsamples, 0); return recv(q->sockfd, buffer, size * nsamples, 0);
break; break;
} }
return -1; return -1;
} }
int udpsource_initialize(udpsource_hl* h) { int udpsource_initialize(udpsource_hl* h) {
return udpsource_init(&h->obj, h->init.address, h->init.port, h->init.data_type); return udpsource_init(&h->obj, h->init.address, h->init.port, h->init.data_type);
} }
int udpsource_work(udpsource_hl* h) { int udpsource_work(udpsource_hl* h) {
h->out_len = udpsource_read(&h->obj, h->output, h->ctrl_in.nsamples); h->out_len = udpsource_read(&h->obj, h->output, h->ctrl_in.nsamples);
if (h->out_len < 0) { if (h->out_len < 0) {
return -1; return -1;
} }
return 0; return 0;
} }
int udpsource_stop(udpsource_hl* h) { int udpsource_stop(udpsource_hl* h) {
udpsource_free(&h->obj); udpsource_free(&h->obj);
return 0; return 0;
} }

@ -36,41 +36,41 @@
int layermap_single(cf_t *d, cf_t *x, int nof_symbols) { int layermap_single(cf_t *d, cf_t *x, int nof_symbols) {
memcpy(x, d, sizeof(cf_t) * nof_symbols); memcpy(x, d, sizeof(cf_t) * nof_symbols);
return nof_symbols; return nof_symbols;
} }
int layermap_diversity(cf_t *d, cf_t *x[MAX_LAYERS], int nof_layers, int nof_symbols) { int layermap_diversity(cf_t *d, cf_t *x[MAX_LAYERS], int nof_layers, int nof_symbols) {
int i, j; int i, j;
for (i=0;i<nof_symbols/nof_layers;i++) { for (i=0;i<nof_symbols/nof_layers;i++) {
for (j=0;j<nof_layers;j++) { for (j=0;j<nof_layers;j++) {
x[j][i] = d[nof_layers*i+j]; x[j][i] = d[nof_layers*i+j];
} }
} }
return i; return i;
} }
int layermap_multiplex(cf_t *d[MAX_CODEWORDS], cf_t *x[MAX_LAYERS], int nof_cw, int nof_layers, int layermap_multiplex(cf_t *d[MAX_CODEWORDS], cf_t *x[MAX_LAYERS], int nof_cw, int nof_layers,
int nof_symbols[MAX_CODEWORDS]) { int nof_symbols[MAX_CODEWORDS]) {
if (nof_cw == 1) { if (nof_cw == 1) {
return layermap_diversity(d[0], x, nof_layers, nof_symbols[0]); return layermap_diversity(d[0], x, nof_layers, nof_symbols[0]);
} else { } else {
int n[2]; int n[2];
n[0] = nof_layers / nof_cw; n[0] = nof_layers / nof_cw;
n[1] = nof_layers - n[0]; n[1] = nof_layers - n[0];
if (nof_symbols[0] / n[0] == nof_symbols[1] / n[1]) { if (nof_symbols[0] / n[0] == nof_symbols[1] / n[1]) {
layermap_diversity(d[0], x, n[0], nof_symbols[0]); layermap_diversity(d[0], x, n[0], nof_symbols[0]);
layermap_diversity(d[1], &x[n[0]], n[1], nof_symbols[1]); layermap_diversity(d[1], &x[n[0]], n[1], nof_symbols[1]);
return nof_symbols[0] / n[0]; return nof_symbols[0] / n[0];
} else { } else {
fprintf(stderr, "Number of symbols in codewords 0 and 1 is not consistent (%d, %d)\n", fprintf(stderr, "Number of symbols in codewords 0 and 1 is not consistent (%d, %d)\n",
nof_symbols[0], nof_symbols[1]); nof_symbols[0], nof_symbols[1]);
return -1; return -1;
} }
} }
return 0; return 0;
} }
/* Layer mapping generates the vector of layer-mapped symbols "x" based on the vector of data symbols "d" /* Layer mapping generates the vector of layer-mapped symbols "x" based on the vector of data symbols "d"
@ -78,48 +78,48 @@ int layermap_multiplex(cf_t *d[MAX_CODEWORDS], cf_t *x[MAX_LAYERS], int nof_cw,
* Returns the number of symbols per layer (M_symb^layer in the specs) * Returns the number of symbols per layer (M_symb^layer in the specs)
*/ */
int layermap_type(cf_t *d[MAX_CODEWORDS], cf_t *x[MAX_LAYERS], int nof_cw, int nof_layers, int layermap_type(cf_t *d[MAX_CODEWORDS], cf_t *x[MAX_LAYERS], int nof_cw, int nof_layers,
int nof_symbols[MAX_CODEWORDS], lte_mimo_type_t type) { int nof_symbols[MAX_CODEWORDS], lte_mimo_type_t type) {
if (nof_cw > MAX_CODEWORDS) { if (nof_cw > MAX_CODEWORDS) {
fprintf(stderr, "Maximum number of codewords is %d (nof_cw=%d)\n", MAX_CODEWORDS, nof_cw); fprintf(stderr, "Maximum number of codewords is %d (nof_cw=%d)\n", MAX_CODEWORDS, nof_cw);
return -1; return -1;
} }
if (nof_layers > MAX_LAYERS) { if (nof_layers > MAX_LAYERS) {
fprintf(stderr, "Maximum number of layers is %d (nof_layers=%d)\n", MAX_LAYERS, nof_layers); fprintf(stderr, "Maximum number of layers is %d (nof_layers=%d)\n", MAX_LAYERS, nof_layers);
return -1; return -1;
} }
if (nof_layers < nof_cw) { if (nof_layers < nof_cw) {
fprintf(stderr, "Number of codewords must be lower or equal than number of layers\n"); fprintf(stderr, "Number of codewords must be lower or equal than number of layers\n");
return -1; return -1;
} }
switch(type) { switch(type) {
case SINGLE_ANTENNA: case SINGLE_ANTENNA:
if (nof_cw == 1 && nof_layers == 1) { if (nof_cw == 1 && nof_layers == 1) {
return layermap_single(x[0], d[0], nof_symbols[0]); return layermap_single(x[0], d[0], nof_symbols[0]);
} else { } else {
fprintf(stderr, "Number of codewords and layers must be 1 for transmission on single antenna ports\n"); fprintf(stderr, "Number of codewords and layers must be 1 for transmission on single antenna ports\n");
return -1; return -1;
} }
break; break;
case TX_DIVERSITY: case TX_DIVERSITY:
if (nof_cw == 1) { if (nof_cw == 1) {
if (nof_layers == 2 || nof_layers == 4) { if (nof_layers == 2 || nof_layers == 4) {
return layermap_diversity(d[0], x, nof_layers, nof_symbols[0]); return layermap_diversity(d[0], x, nof_layers, nof_symbols[0]);
} else { } else {
fprintf(stderr, "Number of layers must be 2 or 4 for transmit diversity\n"); fprintf(stderr, "Number of layers must be 2 or 4 for transmit diversity\n");
return -1; return -1;
} }
} else { } else {
fprintf(stderr, "Number of codewords must be 1 for transmit diversity\n"); fprintf(stderr, "Number of codewords must be 1 for transmit diversity\n");
return -1; return -1;
} }
break; break;
case SPATIAL_MULTIPLEX: case SPATIAL_MULTIPLEX:
return layermap_multiplex(d, x, nof_cw, nof_layers, nof_symbols); return layermap_multiplex(d, x, nof_cw, nof_layers, nof_symbols);
break; break;
} }
return 0; return 0;
} }
@ -131,34 +131,34 @@ int layermap_type(cf_t *d[MAX_CODEWORDS], cf_t *x[MAX_LAYERS], int nof_cw, int n
int layerdemap_single(cf_t *x, cf_t *d, int nof_symbols) { int layerdemap_single(cf_t *x, cf_t *d, int nof_symbols) {
memcpy(d, x, sizeof(cf_t) * nof_symbols); memcpy(d, x, sizeof(cf_t) * nof_symbols);
return nof_symbols; return nof_symbols;
} }
int layerdemap_diversity(cf_t *x[MAX_LAYERS], cf_t *d, int nof_layers, int nof_layer_symbols) { int layerdemap_diversity(cf_t *x[MAX_LAYERS], cf_t *d, int nof_layers, int nof_layer_symbols) {
int i, j; int i, j;
for (i=0;i<nof_layer_symbols;i++) { for (i=0;i<nof_layer_symbols;i++) {
for (j=0;j<nof_layers;j++) { for (j=0;j<nof_layers;j++) {
d[nof_layers*i+j] = x[j][i]; d[nof_layers*i+j] = x[j][i];
} }
} }
return nof_layer_symbols * nof_layers; return nof_layer_symbols * nof_layers;
} }
int layerdemap_multiplex(cf_t *x[MAX_LAYERS], cf_t *d[MAX_CODEWORDS], int nof_layers, int nof_cw, int layerdemap_multiplex(cf_t *x[MAX_LAYERS], cf_t *d[MAX_CODEWORDS], int nof_layers, int nof_cw,
int nof_layer_symbols, int nof_symbols[MAX_CODEWORDS]) { int nof_layer_symbols, int nof_symbols[MAX_CODEWORDS]) {
if (nof_cw == 1) { if (nof_cw == 1) {
return layerdemap_diversity(x, d[0], nof_layers, nof_layer_symbols); return layerdemap_diversity(x, d[0], nof_layers, nof_layer_symbols);
} else { } else {
int n[2]; int n[2];
n[0] = nof_layers / nof_cw; n[0] = nof_layers / nof_cw;
n[1] = nof_layers - n[0]; n[1] = nof_layers - n[0];
nof_symbols[0] = n[0] * nof_layer_symbols; nof_symbols[0] = n[0] * nof_layer_symbols;
nof_symbols[1] = n[1] * nof_layer_symbols; nof_symbols[1] = n[1] * nof_layer_symbols;
nof_symbols[0] = layerdemap_diversity(x, d[0], n[0], nof_layer_symbols); nof_symbols[0] = layerdemap_diversity(x, d[0], n[0], nof_layer_symbols);
nof_symbols[1] = layerdemap_diversity(&x[n[0]], d[1], n[1], nof_layer_symbols); nof_symbols[1] = layerdemap_diversity(&x[n[0]], d[1], n[1], nof_layer_symbols);
} }
return 0; return 0;
} }
/* Generates the vector of data symbols "d" based on the vector of layer-mapped symbols "x" /* Generates the vector of data symbols "d" based on the vector of layer-mapped symbols "x"
@ -167,48 +167,48 @@ int layerdemap_multiplex(cf_t *x[MAX_LAYERS], cf_t *d[MAX_CODEWORDS], int nof_la
* nof_symbols. Returns -1 on error * nof_symbols. Returns -1 on error
*/ */
int layerdemap_type(cf_t *x[MAX_LAYERS], cf_t *d[MAX_CODEWORDS], int nof_layers, int nof_cw, int layerdemap_type(cf_t *x[MAX_LAYERS], cf_t *d[MAX_CODEWORDS], int nof_layers, int nof_cw,
int nof_layer_symbols, int nof_symbols[MAX_CODEWORDS], lte_mimo_type_t type) { int nof_layer_symbols, int nof_symbols[MAX_CODEWORDS], lte_mimo_type_t type) {
if (nof_cw > MAX_CODEWORDS) { if (nof_cw > MAX_CODEWORDS) {
fprintf(stderr, "Maximum number of codewords is %d (nof_cw=%d)\n", MAX_CODEWORDS, nof_cw); fprintf(stderr, "Maximum number of codewords is %d (nof_cw=%d)\n", MAX_CODEWORDS, nof_cw);
return -1; return -1;
} }
if (nof_layers > MAX_LAYERS) { if (nof_layers > MAX_LAYERS) {
fprintf(stderr, "Maximum number of layers is %d (nof_layers=%d)\n", MAX_LAYERS, nof_layers); fprintf(stderr, "Maximum number of layers is %d (nof_layers=%d)\n", MAX_LAYERS, nof_layers);
return -1; return -1;
} }
if (nof_layers < nof_cw) { if (nof_layers < nof_cw) {
fprintf(stderr, "Number of codewords must be lower or equal than number of layers\n"); fprintf(stderr, "Number of codewords must be lower or equal than number of layers\n");
return -1; return -1;
} }
switch(type) { switch(type) {
case SINGLE_ANTENNA: case SINGLE_ANTENNA:
if (nof_cw == 1 && nof_layers == 1) { if (nof_cw == 1 && nof_layers == 1) {
nof_symbols[0] = layerdemap_single(x[0], d[0], nof_layer_symbols); nof_symbols[0] = layerdemap_single(x[0], d[0], nof_layer_symbols);
nof_symbols[1] = 0; nof_symbols[1] = 0;
} else { } else {
fprintf(stderr, "Number of codewords and layers must be 1 for transmission on single antenna ports\n"); fprintf(stderr, "Number of codewords and layers must be 1 for transmission on single antenna ports\n");
return -1; return -1;
} }
break; break;
case TX_DIVERSITY: case TX_DIVERSITY:
if (nof_cw == 1) { if (nof_cw == 1) {
if (nof_layers == 2 || nof_layers == 4) { if (nof_layers == 2 || nof_layers == 4) {
nof_symbols[0] = layerdemap_diversity(x, d[0], nof_layers, nof_layer_symbols); nof_symbols[0] = layerdemap_diversity(x, d[0], nof_layers, nof_layer_symbols);
nof_symbols[1] = 0; nof_symbols[1] = 0;
} else { } else {
fprintf(stderr, "Number of layers must be 2 or 4 for transmit diversity\n"); fprintf(stderr, "Number of layers must be 2 or 4 for transmit diversity\n");
return -1; return -1;
} }
} else { } else {
fprintf(stderr, "Number of codewords must be 1 for transmit diversity\n"); fprintf(stderr, "Number of codewords must be 1 for transmit diversity\n");
return -1; return -1;
} }
break; break;
case SPATIAL_MULTIPLEX: case SPATIAL_MULTIPLEX:
return layerdemap_multiplex(x, d, nof_layers, nof_cw, nof_layer_symbols, nof_symbols); return layerdemap_multiplex(x, d, nof_layers, nof_cw, nof_layer_symbols, nof_symbols);
break; break;
} }
return 0; return 0;
} }

@ -38,178 +38,178 @@
#include "lte/utils/vector.h" #include "lte/utils/vector.h"
int precoding_single(cf_t *x, cf_t *y, int nof_symbols) { int precoding_single(cf_t *x, cf_t *y, int nof_symbols) {
memcpy(y, x, nof_symbols * sizeof(cf_t)); memcpy(y, x, nof_symbols * sizeof(cf_t));
return nof_symbols; return nof_symbols;
} }
int precoding_diversity(cf_t *x[MAX_LAYERS], cf_t *y[MAX_PORTS], int nof_ports, int nof_symbols) { int precoding_diversity(cf_t *x[MAX_LAYERS], cf_t *y[MAX_PORTS], int nof_ports, int nof_symbols) {
int i; int i;
if (nof_ports == 2) { if (nof_ports == 2) {
/* FIXME: Use VOLK here */ /* FIXME: Use VOLK here */
for (i=0;i<nof_symbols;i++) { for (i=0;i<nof_symbols;i++) {
y[0][2*i] = x[0][i]/sqrtf(2); y[0][2*i] = x[0][i]/sqrtf(2);
y[1][2*i] = -conjf(x[1][i])/sqrtf(2); y[1][2*i] = -conjf(x[1][i])/sqrtf(2);
y[0][2*i+1] = x[1][i]/sqrtf(2); y[0][2*i+1] = x[1][i]/sqrtf(2);
y[1][2*i+1] = conjf(x[0][i])/sqrtf(2); y[1][2*i+1] = conjf(x[0][i])/sqrtf(2);
} }
return 2*i; return 2*i;
} else if (nof_ports == 4) { } else if (nof_ports == 4) {
//int m_ap = (nof_symbols%4)?(nof_symbols*4-2):nof_symbols*4; //int m_ap = (nof_symbols%4)?(nof_symbols*4-2):nof_symbols*4;
int m_ap = 4 * nof_symbols; int m_ap = 4 * nof_symbols;
for (i=0;i<m_ap/4;i++) { for (i=0;i<m_ap/4;i++) {
y[0][4*i] = x[0][i]/sqrtf(2); y[0][4*i] = x[0][i]/sqrtf(2);
y[1][4*i] = 0; y[1][4*i] = 0;
y[2][4*i] = -conjf(x[1][i])/sqrtf(2); y[2][4*i] = -conjf(x[1][i])/sqrtf(2);
y[3][4*i] = 0; y[3][4*i] = 0;
y[0][4*i+1] = x[1][i]/sqrtf(2); y[0][4*i+1] = x[1][i]/sqrtf(2);
y[1][4*i+1] = 0; y[1][4*i+1] = 0;
y[2][4*i+1] = conjf(x[0][i])/sqrtf(2); y[2][4*i+1] = conjf(x[0][i])/sqrtf(2);
y[3][4*i+1] = 0; y[3][4*i+1] = 0;
y[0][4*i+2] = 0; y[0][4*i+2] = 0;
y[1][4*i+2] = x[2][i]/sqrtf(2); y[1][4*i+2] = x[2][i]/sqrtf(2);
y[2][4*i+2] = 0; y[2][4*i+2] = 0;
y[3][4*i+2] = -conjf(x[3][i])/sqrtf(2); y[3][4*i+2] = -conjf(x[3][i])/sqrtf(2);
y[0][4*i+3] = 0; y[0][4*i+3] = 0;
y[1][4*i+3] = x[3][i]/sqrtf(2); y[1][4*i+3] = x[3][i]/sqrtf(2);
y[2][4*i+3] = 0; y[2][4*i+3] = 0;
y[3][4*i+3] = conjf(x[2][i])/sqrtf(2); y[3][4*i+3] = conjf(x[2][i])/sqrtf(2);
} }
return 4*i; return 4*i;
} else { } else {
fprintf(stderr, "Number of ports must be 2 or 4 for transmit diversity\n"); fprintf(stderr, "Number of ports must be 2 or 4 for transmit diversity\n");
return -1; return -1;
} }
} }
/* 36.211 v10.3.0 Section 6.3.4 */ /* 36.211 v10.3.0 Section 6.3.4 */
int precoding_type(cf_t *x[MAX_LAYERS], cf_t *y[MAX_PORTS], int nof_layers, int nof_ports, int nof_symbols, int precoding_type(cf_t *x[MAX_LAYERS], cf_t *y[MAX_PORTS], int nof_layers, int nof_ports, int nof_symbols,
lte_mimo_type_t type) { lte_mimo_type_t type) {
if (nof_ports > MAX_PORTS) { if (nof_ports > MAX_PORTS) {
fprintf(stderr, "Maximum number of ports is %d (nof_ports=%d)\n", MAX_PORTS, nof_ports); fprintf(stderr, "Maximum number of ports is %d (nof_ports=%d)\n", MAX_PORTS, nof_ports);
return -1; return -1;
} }
if (nof_layers > MAX_LAYERS) { if (nof_layers > MAX_LAYERS) {
fprintf(stderr, "Maximum number of layers is %d (nof_layers=%d)\n", MAX_LAYERS, nof_layers); fprintf(stderr, "Maximum number of layers is %d (nof_layers=%d)\n", MAX_LAYERS, nof_layers);
return -1; return -1;
} }
switch(type) { switch(type) {
case SINGLE_ANTENNA: case SINGLE_ANTENNA:
if (nof_ports == 1 && nof_layers == 1) { if (nof_ports == 1 && nof_layers == 1) {
return precoding_single(x[0], y[0], nof_symbols); return precoding_single(x[0], y[0], nof_symbols);
} else { } else {
fprintf(stderr, "Number of ports and layers must be 1 for transmission on single antenna ports\n"); fprintf(stderr, "Number of ports and layers must be 1 for transmission on single antenna ports\n");
return -1; return -1;
} }
break; break;
case TX_DIVERSITY: case TX_DIVERSITY:
if (nof_ports == nof_layers) { if (nof_ports == nof_layers) {
return precoding_diversity(x, y, nof_ports, nof_symbols); return precoding_diversity(x, y, nof_ports, nof_symbols);
} else { } else {
fprintf(stderr, "Error number of layers must equal number of ports in transmit diversity\n"); fprintf(stderr, "Error number of layers must equal number of ports in transmit diversity\n");
return -1; return -1;
} }
case SPATIAL_MULTIPLEX: case SPATIAL_MULTIPLEX:
fprintf(stderr, "Spatial multiplexing not supported\n"); fprintf(stderr, "Spatial multiplexing not supported\n");
return -1; return -1;
} }
return 0; return 0;
} }
/* ZF detector */ /* ZF detector */
int predecoding_single_zf(cf_t *y, cf_t *ce, cf_t *x, int nof_symbols) { int predecoding_single_zf(cf_t *y, cf_t *ce, cf_t *x, int nof_symbols) {
vec_div_ccc(y, ce, x, nof_symbols); vec_div_ccc(y, ce, x, nof_symbols);
return nof_symbols; return nof_symbols;
} }
/* ZF detector */ /* ZF detector */
int predecoding_diversity_zf(cf_t *y[MAX_PORTS], cf_t *ce[MAX_PORTS], int predecoding_diversity_zf(cf_t *y[MAX_PORTS], cf_t *ce[MAX_PORTS],
cf_t *x[MAX_LAYERS], int nof_ports, int nof_symbols) { cf_t *x[MAX_LAYERS], int nof_ports, int nof_symbols) {
int i; int i;
cf_t h0, h1, h2, h3, r0, r1, r2, r3; cf_t h0, h1, h2, h3, r0, r1, r2, r3;
float hh, hh02, hh13; float hh, hh02, hh13;
if (nof_ports == 2) { if (nof_ports == 2) {
/* TODO: Use VOLK here */ /* TODO: Use VOLK here */
for (i=0;i<nof_symbols/2;i++) { for (i=0;i<nof_symbols/2;i++) {
h0 = ce[0][2*i]; h0 = ce[0][2*i];
h1 = ce[1][2*i]; h1 = ce[1][2*i];
hh = crealf(h0)*crealf(h0)+cimagf(h0)*cimagf(h0)+ hh = crealf(h0)*crealf(h0)+cimagf(h0)*cimagf(h0)+
crealf(h1)*crealf(h1)+cimagf(h1)*cimagf(h1); crealf(h1)*crealf(h1)+cimagf(h1)*cimagf(h1);
r0 = y[0][2*i]; r0 = y[0][2*i];
r1 = y[0][2*i+1]; r1 = y[0][2*i+1];
x[0][i] = (conjf(h0)*r0 + h1*conjf(r1))/hh * sqrt(2); x[0][i] = (conjf(h0)*r0 + h1*conjf(r1))/hh * sqrt(2);
x[1][i] = (-h1*conj(r0) + conj(h0)*r1)/hh * sqrt(2); x[1][i] = (-h1*conj(r0) + conj(h0)*r1)/hh * sqrt(2);
} }
return i; return i;
} else if (nof_ports == 4) { } else if (nof_ports == 4) {
int m_ap = (nof_symbols%4)?((nof_symbols-2)/4):nof_symbols/4; int m_ap = (nof_symbols%4)?((nof_symbols-2)/4):nof_symbols/4;
for (i=0;i<m_ap;i++) { for (i=0;i<m_ap;i++) {
h0 = ce[0][4*i]; h0 = ce[0][4*i];
h1 = ce[1][4*i+2]; h1 = ce[1][4*i+2];
h2 = ce[2][4*i]; h2 = ce[2][4*i];
h3 = ce[3][4*i+2]; h3 = ce[3][4*i+2];
hh02 = crealf(h0)*crealf(h0)+cimagf(h0)*cimagf(h0) hh02 = crealf(h0)*crealf(h0)+cimagf(h0)*cimagf(h0)
+ crealf(h2)*crealf(h2)+cimagf(h2)*cimagf(h2); + crealf(h2)*crealf(h2)+cimagf(h2)*cimagf(h2);
hh13 = crealf(h1)*crealf(h1)+cimagf(h1)*cimagf(h1) hh13 = crealf(h1)*crealf(h1)+cimagf(h1)*cimagf(h1)
+ crealf(h3)*crealf(h3)+cimagf(h3)*cimagf(h3); + crealf(h3)*crealf(h3)+cimagf(h3)*cimagf(h3);
r0 = y[0][4*i]; r0 = y[0][4*i];
r1 = y[0][4*i+1]; r1 = y[0][4*i+1];
r2 = y[0][4*i+2]; r2 = y[0][4*i+2];
r3 = y[0][4*i+3]; r3 = y[0][4*i+3];
x[0][i] = (conjf(h0)*r0 + h2*conjf(r1))/hh02 * sqrt(2); x[0][i] = (conjf(h0)*r0 + h2*conjf(r1))/hh02 * sqrt(2);
x[1][i] = (-h2*conjf(r0) + conjf(h0)*r1)/hh02 * sqrt(2); x[1][i] = (-h2*conjf(r0) + conjf(h0)*r1)/hh02 * sqrt(2);
x[2][i] = (conjf(h1)*r2 + h3*conjf(r3))/hh13 * sqrt(2); x[2][i] = (conjf(h1)*r2 + h3*conjf(r3))/hh13 * sqrt(2);
x[3][i] = (-h3*conjf(r2) + conjf(h1)*r3)/hh13 * sqrt(2); x[3][i] = (-h3*conjf(r2) + conjf(h1)*r3)/hh13 * sqrt(2);
} }
return i; return i;
} else { } else {
fprintf(stderr, "Number of ports must be 2 or 4 for transmit diversity\n"); fprintf(stderr, "Number of ports must be 2 or 4 for transmit diversity\n");
return -1; return -1;
} }
} }
/* 36.211 v10.3.0 Section 6.3.4 */ /* 36.211 v10.3.0 Section 6.3.4 */
int predecoding_type(cf_t *y[MAX_PORTS], cf_t *ce[MAX_PORTS], int predecoding_type(cf_t *y[MAX_PORTS], cf_t *ce[MAX_PORTS],
cf_t *x[MAX_LAYERS], int nof_ports, int nof_layers, int nof_symbols, lte_mimo_type_t type) { cf_t *x[MAX_LAYERS], int nof_ports, int nof_layers, int nof_symbols, lte_mimo_type_t type) {
if (nof_ports > MAX_PORTS) { if (nof_ports > MAX_PORTS) {
fprintf(stderr, "Maximum number of ports is %d (nof_ports=%d)\n", MAX_PORTS, nof_ports); fprintf(stderr, "Maximum number of ports is %d (nof_ports=%d)\n", MAX_PORTS, nof_ports);
return -1; return -1;
} }
if (nof_layers > MAX_LAYERS) { if (nof_layers > MAX_LAYERS) {
fprintf(stderr, "Maximum number of layers is %d (nof_layers=%d)\n", MAX_LAYERS, nof_layers); fprintf(stderr, "Maximum number of layers is %d (nof_layers=%d)\n", MAX_LAYERS, nof_layers);
return -1; return -1;
} }
switch(type) { switch(type) {
case SINGLE_ANTENNA: case SINGLE_ANTENNA:
if (nof_ports == 1 && nof_layers == 1) { if (nof_ports == 1 && nof_layers == 1) {
return predecoding_single_zf(y[0], ce[0], x[0], nof_symbols); return predecoding_single_zf(y[0], ce[0], x[0], nof_symbols);
} else{ } else{
fprintf(stderr, "Number of ports and layers must be 1 for transmission on single antenna ports\n"); fprintf(stderr, "Number of ports and layers must be 1 for transmission on single antenna ports\n");
return -1; return -1;
} }
break; break;
case TX_DIVERSITY: case TX_DIVERSITY:
if (nof_ports == nof_layers) { if (nof_ports == nof_layers) {
return predecoding_diversity_zf(y, ce, x, nof_ports, nof_symbols); return predecoding_diversity_zf(y, ce, x, nof_ports, nof_symbols);
} else { } else {
fprintf(stderr, "Error number of layers must equal number of ports in transmit diversity\n"); fprintf(stderr, "Error number of layers must equal number of ports in transmit diversity\n");
return -1; return -1;
} }
break; break;
case SPATIAL_MULTIPLEX: case SPATIAL_MULTIPLEX:
fprintf(stderr, "Spatial multiplexing not supported\n"); fprintf(stderr, "Spatial multiplexing not supported\n");
return -1; return -1;
} }
return 0; return 0;
} }

@ -41,123 +41,123 @@ int nof_cw = 1, nof_layers = 1;
char *mimo_type_name = NULL; char *mimo_type_name = NULL;
void usage(char *prog) { void usage(char *prog) {
printf("Usage: %s -m [single|diversity|multiplex] -c [nof_cw] -l [nof_layers]\n", prog); printf("Usage: %s -m [single|diversity|multiplex] -c [nof_cw] -l [nof_layers]\n", prog);
printf("\t-n num_symbols [Default %d]\n", nof_symbols); printf("\t-n num_symbols [Default %d]\n", nof_symbols);
} }
void parse_args(int argc, char **argv) { void parse_args(int argc, char **argv) {
int opt; int opt;
while ((opt = getopt(argc, argv, "mcln")) != -1) { while ((opt = getopt(argc, argv, "mcln")) != -1) {
switch (opt) { switch (opt) {
case 'n': case 'n':
nof_symbols = atoi(argv[optind]); nof_symbols = atoi(argv[optind]);
break; break;
case 'c': case 'c':
nof_cw = atoi(argv[optind]); nof_cw = atoi(argv[optind]);
break; break;
case 'l': case 'l':
nof_layers = atoi(argv[optind]); nof_layers = atoi(argv[optind]);
break; break;
case 'm': case 'm':
mimo_type_name = argv[optind]; mimo_type_name = argv[optind];
break; break;
default: default:
usage(argv[0]); usage(argv[0]);
exit(-1); exit(-1);
} }
} }
if (!mimo_type_name) { if (!mimo_type_name) {
usage(argv[0]); usage(argv[0]);
exit(-1); exit(-1);
} }
} }
int main(int argc, char **argv) { int main(int argc, char **argv) {
int i, j, num_errors, symbols_layer; int i, j, num_errors, symbols_layer;
cf_t *d[MAX_CODEWORDS], *x[MAX_LAYERS], *dp[MAX_CODEWORDS]; cf_t *d[MAX_CODEWORDS], *x[MAX_LAYERS], *dp[MAX_CODEWORDS];
lte_mimo_type_t type; lte_mimo_type_t type;
int nof_symb_cw[MAX_CODEWORDS]; int nof_symb_cw[MAX_CODEWORDS];
int n[2]; int n[2];
parse_args(argc, argv); parse_args(argc, argv);
if (lte_str2mimotype(mimo_type_name, &type)) { if (lte_str2mimotype(mimo_type_name, &type)) {
fprintf(stderr, "Invalid MIMO type %s\n", mimo_type_name); fprintf(stderr, "Invalid MIMO type %s\n", mimo_type_name);
exit(-1); exit(-1);
} }
if (nof_cw > 1) { if (nof_cw > 1) {
n[0] = nof_layers / nof_cw; n[0] = nof_layers / nof_cw;
n[1] = nof_layers - n[0]; n[1] = nof_layers - n[0];
nof_symb_cw[0] = nof_symbols * n[0]; nof_symb_cw[0] = nof_symbols * n[0];
nof_symb_cw[1] = nof_symbols * n[1]; nof_symb_cw[1] = nof_symbols * n[1];
} else { } else {
nof_symb_cw[0] = nof_symbols; nof_symb_cw[0] = nof_symbols;
nof_symb_cw[1] = 0; nof_symb_cw[1] = 0;
} }
for (i=0;i<nof_cw;i++) { for (i=0;i<nof_cw;i++) {
d[i] = malloc(sizeof(cf_t) * nof_symb_cw[i]); d[i] = malloc(sizeof(cf_t) * nof_symb_cw[i]);
if (!d[i]) { if (!d[i]) {
perror("malloc"); perror("malloc");
exit(-1); exit(-1);
} }
dp[i] = malloc(sizeof(cf_t) * nof_symb_cw[i]); dp[i] = malloc(sizeof(cf_t) * nof_symb_cw[i]);
if (!dp[i]) { if (!dp[i]) {
perror("malloc"); perror("malloc");
exit(-1); exit(-1);
} }
} }
for (i=0;i<nof_layers;i++) { for (i=0;i<nof_layers;i++) {
x[i] = malloc(sizeof(cf_t) * nof_symbols); x[i] = malloc(sizeof(cf_t) * nof_symbols);
if (!x[i]) { if (!x[i]) {
perror("malloc"); perror("malloc");
exit(-1); exit(-1);
} }
} }
/* generate random data */ /* generate random data */
for (i=0;i<nof_cw;i++) { for (i=0;i<nof_cw;i++) {
for (j=0;j<nof_symb_cw[i];j++) { for (j=0;j<nof_symb_cw[i];j++) {
d[i][j] = 100 * (rand()/RAND_MAX + I*rand()/RAND_MAX); d[i][j] = 100 * (rand()/RAND_MAX + I*rand()/RAND_MAX);
} }
} }
/* layer mapping */ /* layer mapping */
if ((symbols_layer = layermap_type(d, x, nof_cw, nof_layers, nof_symb_cw, type)) < 0) { if ((symbols_layer = layermap_type(d, x, nof_cw, nof_layers, nof_symb_cw, type)) < 0) {
fprintf(stderr, "Error layer mapper encoder\n"); fprintf(stderr, "Error layer mapper encoder\n");
exit(-1); exit(-1);
} }
/* layer de-mapping */ /* layer de-mapping */
if (layerdemap_type(x, dp, nof_layers, nof_cw, nof_symbols/nof_layers, nof_symb_cw, type) < 0) { if (layerdemap_type(x, dp, nof_layers, nof_cw, nof_symbols/nof_layers, nof_symb_cw, type) < 0) {
fprintf(stderr, "Error layer mapper encoder\n"); fprintf(stderr, "Error layer mapper encoder\n");
exit(-1); exit(-1);
} }
/* check errors */ /* check errors */
num_errors = 0; num_errors = 0;
for (i=0;i<nof_cw;i++) { for (i=0;i<nof_cw;i++) {
for (j=0;j<nof_symb_cw[i];j++) { for (j=0;j<nof_symb_cw[i];j++) {
if (d[i][j] != dp[i][j]) { if (d[i][j] != dp[i][j]) {
num_errors++; num_errors++;
} }
} }
} }
for (i=0;i<nof_cw;i++) { for (i=0;i<nof_cw;i++) {
free(d[i]); free(d[i]);
free(dp[i]); free(dp[i]);
} }
for (i=0;i<nof_layers;i++) { for (i=0;i<nof_layers;i++) {
free(x[i]); free(x[i]);
} }
if (num_errors) { if (num_errors) {
printf("%d Errors\n", num_errors); printf("%d Errors\n", num_errors);
exit(-1); exit(-1);
} else { } else {
printf("Ok\n"); printf("Ok\n");
exit(0); exit(0);
} }
} }

@ -36,158 +36,158 @@
#include "lte.h" #include "lte.h"
#define MSE_THRESHOLD 0.00001 #define MSE_THRESHOLD 0.00001
int nof_symbols = 1000; int nof_symbols = 1000;
int nof_layers = 1, nof_ports = 1; int nof_layers = 1, nof_ports = 1;
char *mimo_type_name = NULL; char *mimo_type_name = NULL;
void usage(char *prog) { void usage(char *prog) {
printf("Usage: %s -m [single|diversity|multiplex] -l [nof_layers] -p [nof_ports]\n", prog); printf("Usage: %s -m [single|diversity|multiplex] -l [nof_layers] -p [nof_ports]\n", prog);
printf("\t-n num_symbols [Default %d]\n", nof_symbols); printf("\t-n num_symbols [Default %d]\n", nof_symbols);
} }
void parse_args(int argc, char **argv) { void parse_args(int argc, char **argv) {
int opt; int opt;
while ((opt = getopt(argc, argv, "mpln")) != -1) { while ((opt = getopt(argc, argv, "mpln")) != -1) {
switch (opt) { switch (opt) {
case 'n': case 'n':
nof_symbols = atoi(argv[optind]); nof_symbols = atoi(argv[optind]);
break; break;
case 'p': case 'p':
nof_ports = atoi(argv[optind]); nof_ports = atoi(argv[optind]);
break; break;
case 'l': case 'l':
nof_layers = atoi(argv[optind]); nof_layers = atoi(argv[optind]);
break; break;
case 'm': case 'm':
mimo_type_name = argv[optind]; mimo_type_name = argv[optind];
break; break;
default: default:
usage(argv[0]); usage(argv[0]);
exit(-1); exit(-1);
} }
} }
if (!mimo_type_name) { if (!mimo_type_name) {
usage(argv[0]); usage(argv[0]);
exit(-1); exit(-1);
} }
} }
int main(int argc, char **argv) { int main(int argc, char **argv) {
int i, j; int i, j;
float mse; float mse;
cf_t *x[MAX_LAYERS], *r[MAX_PORTS], *y[MAX_PORTS], *h[MAX_PORTS], *xr[MAX_LAYERS]; cf_t *x[MAX_LAYERS], *r[MAX_PORTS], *y[MAX_PORTS], *h[MAX_PORTS], *xr[MAX_LAYERS];
lte_mimo_type_t type; lte_mimo_type_t type;
parse_args(argc, argv); parse_args(argc, argv);
if (nof_ports > MAX_PORTS || nof_layers > MAX_LAYERS) { if (nof_ports > MAX_PORTS || nof_layers > MAX_LAYERS) {
fprintf(stderr, "Invalid number of layers or ports\n"); fprintf(stderr, "Invalid number of layers or ports\n");
exit(-1); exit(-1);
} }
if (lte_str2mimotype(mimo_type_name, &type)) { if (lte_str2mimotype(mimo_type_name, &type)) {
fprintf(stderr, "Invalid MIMO type %s\n", mimo_type_name); fprintf(stderr, "Invalid MIMO type %s\n", mimo_type_name);
exit(-1); exit(-1);
} }
for (i=0;i<nof_layers;i++) { for (i=0;i<nof_layers;i++) {
x[i] = malloc(sizeof(cf_t) * nof_symbols); x[i] = malloc(sizeof(cf_t) * nof_symbols);
if (!x[i]) { if (!x[i]) {
perror("malloc"); perror("malloc");
exit(-1); exit(-1);
} }
xr[i] = malloc(sizeof(cf_t) * nof_symbols); xr[i] = malloc(sizeof(cf_t) * nof_symbols);
if (!xr[i]) { if (!xr[i]) {
perror("malloc"); perror("malloc");
exit(-1); exit(-1);
} }
} }
for (i=0;i<nof_ports;i++) { for (i=0;i<nof_ports;i++) {
y[i] = malloc(sizeof(cf_t) * nof_symbols * nof_layers); y[i] = malloc(sizeof(cf_t) * nof_symbols * nof_layers);
// TODO: The number of symbols per port is different in spatial multiplexing. // TODO: The number of symbols per port is different in spatial multiplexing.
if (!y[i]) { if (!y[i]) {
perror("malloc"); perror("malloc");
exit(-1); exit(-1);
} }
h[i] = malloc(sizeof(cf_t) * nof_symbols * nof_layers); h[i] = malloc(sizeof(cf_t) * nof_symbols * nof_layers);
if (!h[i]) { if (!h[i]) {
perror("malloc"); perror("malloc");
exit(-1); exit(-1);
} }
} }
/* only 1 receiver antenna supported now */ /* only 1 receiver antenna supported now */
r[0] = malloc(sizeof(cf_t) * nof_symbols * nof_layers); r[0] = malloc(sizeof(cf_t) * nof_symbols * nof_layers);
if (!r[0]) { if (!r[0]) {
perror("malloc"); perror("malloc");
exit(-1); exit(-1);
} }
/* generate random data */ /* generate random data */
for (i=0;i<nof_layers;i++) { for (i=0;i<nof_layers;i++) {
for (j=0;j<nof_symbols;j++) { for (j=0;j<nof_symbols;j++) {
x[i][j] = 100 * ((float) rand()/RAND_MAX + (float) I*rand()/RAND_MAX); x[i][j] = 100 * ((float) rand()/RAND_MAX + (float) I*rand()/RAND_MAX);
} }
} }
/* precoding */ /* precoding */
if (precoding_type(x, y, nof_layers, nof_ports, nof_symbols, type) < 0) { if (precoding_type(x, y, nof_layers, nof_ports, nof_symbols, type) < 0) {
fprintf(stderr, "Error layer mapper encoder\n"); fprintf(stderr, "Error layer mapper encoder\n");
exit(-1); exit(-1);
} }
/* generate channel */ /* generate channel */
for (i=0;i<nof_ports;i++) { for (i=0;i<nof_ports;i++) {
for (j=0;j<nof_symbols * nof_layers;j++) { for (j=0;j<nof_symbols * nof_layers;j++) {
float hc = -1+(float) i/nof_ports; float hc = -1+(float) i/nof_ports;
h[i][j] = (3+hc) * cexpf(I * hc); h[i][j] = (3+hc) * cexpf(I * hc);
} }
} }
/* pass signal through channel /* pass signal through channel
(we are in the frequency domain so it's a multiplication) */ (we are in the frequency domain so it's a multiplication) */
/* there's only one receiver antenna, signals from different transmitter /* there's only one receiver antenna, signals from different transmitter
* ports are simply combined at the receiver * ports are simply combined at the receiver
*/ */
for (j=0;j<nof_symbols * nof_layers;j++) { for (j=0;j<nof_symbols * nof_layers;j++) {
r[0][j] = 0; r[0][j] = 0;
for (i=0;i<nof_ports;i++) { for (i=0;i<nof_ports;i++) {
r[0][j] += y[i][j] * h[i][j]; r[0][j] += y[i][j] * h[i][j];
} }
} }
/* predecoding / equalization */ /* predecoding / equalization */
if (predecoding_type(r, h, xr, nof_ports, nof_layers, nof_symbols * nof_layers, type) < 0) { if (predecoding_type(r, h, xr, nof_ports, nof_layers, nof_symbols * nof_layers, type) < 0) {
fprintf(stderr, "Error layer mapper encoder\n"); fprintf(stderr, "Error layer mapper encoder\n");
exit(-1); exit(-1);
} }
/* check errors */ /* check errors */
mse = 0; mse = 0;
for (i=0;i<nof_layers;i++) { for (i=0;i<nof_layers;i++) {
for (j=0;j<nof_symbols;j++) { for (j=0;j<nof_symbols;j++) {
mse += cabsf(xr[i][j] - x[i][j])/nof_layers/nof_symbols; mse += cabsf(xr[i][j] - x[i][j])/nof_layers/nof_symbols;
} }
} }
for (i=0;i<nof_layers;i++) { for (i=0;i<nof_layers;i++) {
free(x[i]); free(x[i]);
free(xr[i]); free(xr[i]);
} }
for (i=0;i<nof_ports;i++) { for (i=0;i<nof_ports;i++) {
free(y[i]); free(y[i]);
free(h[i]); free(h[i]);
} }
free(r[0]); free(r[0]);
if (mse > MSE_THRESHOLD) { if (mse > MSE_THRESHOLD) {
printf("MSE: %f\n", mse); printf("MSE: %f\n", mse);
exit(-1); exit(-1);
} else { } else {
printf("Ok\n"); printf("Ok\n");
exit(0); exit(0);
} }
} }

@ -34,53 +34,53 @@
void demod_hard_init(demod_hard_t* q) { void demod_hard_init(demod_hard_t* q) {
bzero((void*) q, sizeof(demod_hard_t)); bzero((void*) q, sizeof(demod_hard_t));
} }
void demod_hard_table_set(demod_hard_t* q, enum modem_std table) { void demod_hard_table_set(demod_hard_t* q, enum modem_std table) {
q->table = table; q->table = table;
} }
int demod_hard_demodulate(demod_hard_t* q, cf_t* symbols, char *bits, int nsymbols) { int demod_hard_demodulate(demod_hard_t* q, cf_t* symbols, char *bits, int nsymbols) {
int nbits=-1; int nbits=-1;
switch(q->table) { switch(q->table) {
case LTE_BPSK: case LTE_BPSK:
hard_bpsk_demod(symbols,bits,nsymbols); hard_bpsk_demod(symbols,bits,nsymbols);
nbits=nsymbols; nbits=nsymbols;
break; break;
case LTE_QPSK: case LTE_QPSK:
hard_qpsk_demod(symbols,bits,nsymbols); hard_qpsk_demod(symbols,bits,nsymbols);
nbits=nsymbols*2; nbits=nsymbols*2;
break; break;
case LTE_QAM16: case LTE_QAM16:
hard_qam16_demod(symbols,bits,nsymbols); hard_qam16_demod(symbols,bits,nsymbols);
nbits=nsymbols*4; nbits=nsymbols*4;
break; break;
case LTE_QAM64: case LTE_QAM64:
hard_qam64_demod(symbols,bits,nsymbols); hard_qam64_demod(symbols,bits,nsymbols);
nbits=nsymbols*6; nbits=nsymbols*6;
break; break;
} }
return nbits; return nbits;
} }
int demod_hard_initialize(demod_hard_hl* hl) { int demod_hard_initialize(demod_hard_hl* hl) {
demod_hard_init(&hl->obj); demod_hard_init(&hl->obj);
demod_hard_table_set(&hl->obj,hl->init.std); demod_hard_table_set(&hl->obj,hl->init.std);
return 0; return 0;
} }
int demod_hard_work(demod_hard_hl* hl) { int demod_hard_work(demod_hard_hl* hl) {
int ret = demod_hard_demodulate(&hl->obj,hl->input,hl->output,hl->in_len); int ret = demod_hard_demodulate(&hl->obj,hl->input,hl->output,hl->in_len);
hl->out_len = ret; hl->out_len = ret;
return 0; return 0;
} }
int demod_hard_stop(demod_hard_hl* hl) { int demod_hard_stop(demod_hard_hl* hl) {
return 0; return 0;
} }

@ -35,58 +35,58 @@
void demod_soft_init(demod_soft_t *q) { void demod_soft_init(demod_soft_t *q) {
bzero((void*)q,sizeof(demod_soft_t)); bzero((void*)q,sizeof(demod_soft_t));
} }
void demod_soft_table_set(demod_soft_t *q, modem_table_t *table) { void demod_soft_table_set(demod_soft_t *q, modem_table_t *table) {
q->table = table; q->table = table;
} }
void demod_soft_alg_set(demod_soft_t *q, enum alg alg_type) { void demod_soft_alg_set(demod_soft_t *q, enum alg alg_type) {
q->alg_type = alg_type; q->alg_type = alg_type;
} }
void demod_soft_sigma_set(demod_soft_t *q, float sigma) { void demod_soft_sigma_set(demod_soft_t *q, float sigma) {
q->sigma = 2*sigma; q->sigma = 2*sigma;
} }
int demod_soft_demodulate(demod_soft_t *q, const cf_t* symbols, float* llr, int nsymbols) { int demod_soft_demodulate(demod_soft_t *q, const cf_t* symbols, float* llr, int nsymbols) {
switch(q->alg_type) { switch(q->alg_type) {
case EXACT: case EXACT:
llr_exact(symbols, llr, nsymbols, q->table->nsymbols, q->table->nbits_x_symbol, llr_exact(symbols, llr, nsymbols, q->table->nsymbols, q->table->nbits_x_symbol,
q->table->symbol_table, q->table->soft_table.idx, q->sigma); q->table->symbol_table, q->table->soft_table.idx, q->sigma);
break; break;
case APPROX: case APPROX:
llr_approx(symbols, llr, nsymbols, q->table->nsymbols, q->table->nbits_x_symbol, llr_approx(symbols, llr, nsymbols, q->table->nsymbols, q->table->nbits_x_symbol,
q->table->symbol_table, q->table->soft_table.idx, q->sigma); q->table->symbol_table, q->table->soft_table.idx, q->sigma);
break; break;
} }
return nsymbols*q->table->nbits_x_symbol; return nsymbols*q->table->nbits_x_symbol;
} }
/* High-Level API */ /* High-Level API */
int demod_soft_initialize(demod_soft_hl* hl) { int demod_soft_initialize(demod_soft_hl* hl) {
modem_table_init(&hl->table); modem_table_init(&hl->table);
if (modem_table_std(&hl->table,hl->init.std,true)) { if (modem_table_std(&hl->table,hl->init.std,true)) {
return -1; return -1;
} }
demod_soft_init(&hl->obj); demod_soft_init(&hl->obj);
hl->obj.table = &hl->table; hl->obj.table = &hl->table;
return 0; return 0;
} }
int demod_soft_work(demod_soft_hl* hl) { int demod_soft_work(demod_soft_hl* hl) {
hl->obj.sigma = hl->ctrl_in.sigma; hl->obj.sigma = hl->ctrl_in.sigma;
hl->obj.alg_type = hl->ctrl_in.alg_type; hl->obj.alg_type = hl->ctrl_in.alg_type;
int ret = demod_soft_demodulate(&hl->obj,hl->input,hl->output,hl->in_len); int ret = demod_soft_demodulate(&hl->obj,hl->input,hl->output,hl->in_len);
hl->out_len = ret; hl->out_len = ret;
return 0; return 0;
} }
int demod_soft_stop(demod_soft_hl* hl) { int demod_soft_stop(demod_soft_hl* hl) {
modem_table_free(&hl->table); modem_table_free(&hl->table);
return 0; return 0;
} }

@ -48,23 +48,23 @@
*/ */
inline void hard_bpsk_demod(const cf_t* in, char* out, int N) inline void hard_bpsk_demod(const cf_t* in, char* out, int N)
{ {
int s; int s;
for (s=0; s<N; s++) { /* received symbols */ for (s=0; s<N; s++) { /* received symbols */
if (__real__ in[s] > 0) { if (__real__ in[s] > 0) {
if ((__imag__ in[s] > 0) || (__real__ in[s] > -__imag__ in[s])) { if ((__imag__ in[s] > 0) || (__real__ in[s] > -__imag__ in[s])) {
out[s] = 0x0; out[s] = 0x0;
} else { } else {
out[s] = 0x1; out[s] = 0x1;
} }
} else { } else {
if ((__imag__ in[s] < 0) || (__imag__ in[s] < -__real__ in[s])) { if ((__imag__ in[s] < 0) || (__imag__ in[s] < -__real__ in[s])) {
out[s] = 0x1; out[s] = 0x1;
} else { } else {
out[s] = 0x0; out[s] = 0x0;
} }
} }
} }
} }
/** /**
@ -83,20 +83,20 @@ inline void hard_bpsk_demod(const cf_t* in, char* out, int N)
*/ */
inline void hard_qpsk_demod(const cf_t* in, char* out, int N) inline void hard_qpsk_demod(const cf_t* in, char* out, int N)
{ {
int s; int s;
for (s=0; s<N; s++) { for (s=0; s<N; s++) {
if (__real__ in[s] > 0) { if (__real__ in[s] > 0) {
out[2*s] = 0x0; out[2*s] = 0x0;
} else { } else {
out[2*s] = 0x1; out[2*s] = 0x1;
} }
if (__imag__ in[s] > 0) { if (__imag__ in[s] > 0) {
out[2*s+1] = 0x0; out[2*s+1] = 0x0;
} else { } else {
out[2*s+1] = 0x1; out[2*s+1] = 0x1;
} }
} }
} }
/** /**
@ -117,33 +117,33 @@ inline void hard_qpsk_demod(const cf_t* in, char* out, int N)
*/ */
inline void hard_qam16_demod(const cf_t* in, char* out, int N) inline void hard_qam16_demod(const cf_t* in, char* out, int N)
{ {
int s; int s;
for (s=0; s<N; s++) { for (s=0; s<N; s++) {
if (__real__ in[s] > 0) { if (__real__ in[s] > 0) {
out[4*s] = 0x0; out[4*s] = 0x0;
} else { } else {
out[4*s] = 0x1; out[4*s] = 0x1;
} }
if ((__real__ in[s] > QAM16_THRESHOLD) || (__real__ in[s] < -QAM16_THRESHOLD)) { if ((__real__ in[s] > QAM16_THRESHOLD) || (__real__ in[s] < -QAM16_THRESHOLD)) {
out[4*s+2] = 0x1; out[4*s+2] = 0x1;
} else { } else {
out[4*s+2] = 0x0; out[4*s+2] = 0x0;
} }
if (__imag__ in[s] > 0) { if (__imag__ in[s] > 0) {
out[4*s+1] = 0x0; out[4*s+1] = 0x0;
} else { } else {
out[4*s+1] = 0x1; out[4*s+1] = 0x1;
} }
if ((__imag__ in[s] > QAM16_THRESHOLD) || (__imag__ in[s] < -QAM16_THRESHOLD)) { if ((__imag__ in[s] > QAM16_THRESHOLD) || (__imag__ in[s] < -QAM16_THRESHOLD)) {
out[4*s+3] = 0x1; out[4*s+3] = 0x1;
} else { } else {
out[4*s+3] = 0x0; out[4*s+3] = 0x0;
} }
} }
} }
/** /**
@ -159,47 +159,47 @@ inline void hard_qam16_demod(const cf_t* in, char* out, int N)
*/ */
inline void hard_qam64_demod(const cf_t* in, char* out, int N) inline void hard_qam64_demod(const cf_t* in, char* out, int N)
{ {
int s; int s;
for (s=0; s<N; s++) { for (s=0; s<N; s++) {
/* bits associated with/obtained from in-phase component: b0, b2, b4 */ /* bits associated with/obtained from in-phase component: b0, b2, b4 */
if (__real__ in[s] > 0){ if (__real__ in[s] > 0){
out[6*s] = 0x0; out[6*s] = 0x0;
} else { } else {
out[6*s] = 0x1; out[6*s] = 0x1;
} }
if ((__real__ in[s] > QAM64_THRESHOLD_3) || (__real__ in[s] < -QAM64_THRESHOLD_3)) { if ((__real__ in[s] > QAM64_THRESHOLD_3) || (__real__ in[s] < -QAM64_THRESHOLD_3)) {
out[6*s+2] = 0x1; out[6*s+2] = 0x1;
out[6*s+4] = 0x1; out[6*s+4] = 0x1;
} else if ((__real__ in[s] > QAM64_THRESHOLD_2) || (__real__ in[s] < -QAM64_THRESHOLD_2)) { } else if ((__real__ in[s] > QAM64_THRESHOLD_2) || (__real__ in[s] < -QAM64_THRESHOLD_2)) {
out[6*s+2] = 0x1; out[6*s+2] = 0x1;
out[6*s+4] = 0x0; out[6*s+4] = 0x0;
} else if ((__real__ in[s] > QAM64_THRESHOLD_1) || (__real__ in[s] < -QAM64_THRESHOLD_1)) { } else if ((__real__ in[s] > QAM64_THRESHOLD_1) || (__real__ in[s] < -QAM64_THRESHOLD_1)) {
out[6*s+2] = 0x0; out[6*s+2] = 0x0;
out[6*s+4] = 0x0; out[6*s+4] = 0x0;
} else { } else {
out[6*s+2] = 0x0; out[6*s+2] = 0x0;
out[6*s+4] = 0x1; out[6*s+4] = 0x1;
} }
/* bits associated with/obtained from quadrature component: b1, b3, b5 */ /* bits associated with/obtained from quadrature component: b1, b3, b5 */
if (__imag__ in[s] > 0){ if (__imag__ in[s] > 0){
out[6*s+1] = 0x0; out[6*s+1] = 0x0;
} else { } else {
out[6*s+1] = 0x1; out[6*s+1] = 0x1;
} }
if ((__imag__ in[s] > QAM64_THRESHOLD_3) || (__imag__ in[s] < -QAM64_THRESHOLD_3)) { if ((__imag__ in[s] > QAM64_THRESHOLD_3) || (__imag__ in[s] < -QAM64_THRESHOLD_3)) {
out[6*s+3] = 0x1; out[6*s+3] = 0x1;
out[6*s+5] = 0x1; out[6*s+5] = 0x1;
} else if ((__imag__ in[s] > QAM64_THRESHOLD_2) || (__imag__ in[s] < -QAM64_THRESHOLD_2)) { } else if ((__imag__ in[s] > QAM64_THRESHOLD_2) || (__imag__ in[s] < -QAM64_THRESHOLD_2)) {
out[6*s+3] = 0x1; out[6*s+3] = 0x1;
out[6*s+5] = 0x0; out[6*s+5] = 0x0;
} else if ((__imag__ in[s] > QAM64_THRESHOLD_1) || (__imag__ in[s] < -QAM64_THRESHOLD_1)) { } else if ((__imag__ in[s] > QAM64_THRESHOLD_1) || (__imag__ in[s] < -QAM64_THRESHOLD_1)) {
out[6*s+3] = 0x0; out[6*s+3] = 0x0;
out[6*s+5] = 0x0; out[6*s+5] = 0x0;
} else { } else {
out[6*s+3] = 0x0; out[6*s+3] = 0x0;
out[6*s+5] = 0x1; out[6*s+5] = 0x1;
} }
} }
} }

@ -30,10 +30,10 @@
/* Assume perfect amplitude and phase alignment. /* Assume perfect amplitude and phase alignment.
* Check threshold values for real case * Check threshold values for real case
* or implement dynamic threshold adjustent as a function of received symbol amplitudes */ * or implement dynamic threshold adjustent as a function of received symbol amplitudes */
#define QAM16_THRESHOLD 2/sqrt(10) #define QAM16_THRESHOLD 2/sqrt(10)
#define QAM64_THRESHOLD_1 2/sqrt(42) #define QAM64_THRESHOLD_1 2/sqrt(42)
#define QAM64_THRESHOLD_2 4/sqrt(42) #define QAM64_THRESHOLD_2 4/sqrt(42)
#define QAM64_THRESHOLD_3 6/sqrt(42) #define QAM64_THRESHOLD_3 6/sqrt(42)
void hard_bpsk_demod(const cf_t* in, char* out, int N); void hard_bpsk_demod(const cf_t* in, char* out, int N);
void hard_qpsk_demod(const cf_t* in, char* out, int N); void hard_qpsk_demod(const cf_t* in, char* out, int N);

@ -38,243 +38,243 @@
* Set the BPSK modulation table */ * Set the BPSK modulation table */
void set_BPSKtable(cf_t* table, soft_table_t *soft_table, bool compute_soft_demod) void set_BPSKtable(cf_t* table, soft_table_t *soft_table, bool compute_soft_demod)
{ {
// LTE-BPSK constellation: // LTE-BPSK constellation:
// Q // Q
// | 0 // | 0
//---------> I //---------> I
// 1 | // 1 |
table[0] = BPSK_LEVEL + BPSK_LEVEL*_Complex_I; table[0] = BPSK_LEVEL + BPSK_LEVEL*_Complex_I;
table[1] = -BPSK_LEVEL -BPSK_LEVEL*_Complex_I; table[1] = -BPSK_LEVEL -BPSK_LEVEL*_Complex_I;
if (!compute_soft_demod) { if (!compute_soft_demod) {
return; return;
} }
/* BSPK symbols containing a '0' and a '1' (only two symbols, 1 bit) */ /* BSPK symbols containing a '0' and a '1' (only two symbols, 1 bit) */
soft_table->idx[0][0][0] = 0; soft_table->idx[0][0][0] = 0;
soft_table->idx[1][0][0] = 1; soft_table->idx[1][0][0] = 1;
} }
/** /**
* Set the QPSK modulation table */ * Set the QPSK modulation table */
void set_QPSKtable(cf_t* table, soft_table_t *soft_table, bool compute_soft_demod) void set_QPSKtable(cf_t* table, soft_table_t *soft_table, bool compute_soft_demod)
{ {
int i,j; int i,j;
// LTE-QPSK constellation: // LTE-QPSK constellation:
// Q // Q
// 10 | 00 // 10 | 00
//-----------> I //-----------> I
// 11 | 01 // 11 | 01
table[0] = QPSK_LEVEL + QPSK_LEVEL*_Complex_I; table[0] = QPSK_LEVEL + QPSK_LEVEL*_Complex_I;
table[1] = QPSK_LEVEL - QPSK_LEVEL*_Complex_I; table[1] = QPSK_LEVEL - QPSK_LEVEL*_Complex_I;
table[2] = -QPSK_LEVEL + QPSK_LEVEL*_Complex_I; table[2] = -QPSK_LEVEL + QPSK_LEVEL*_Complex_I;
table[3] = -QPSK_LEVEL - QPSK_LEVEL*_Complex_I; table[3] = -QPSK_LEVEL - QPSK_LEVEL*_Complex_I;
for (i=0;i<6;i++) { for (i=0;i<6;i++) {
for (j=0;j<32;j++) { for (j=0;j<32;j++) {
soft_table->idx[0][i][j] = 0; soft_table->idx[0][i][j] = 0;
soft_table->idx[1][i][j] = 0; soft_table->idx[1][i][j] = 0;
} }
} }
if (!compute_soft_demod) { if (!compute_soft_demod) {
return; return;
} }
/* QSPK symbols containing a '0' at the different bit positions */ /* QSPK symbols containing a '0' at the different bit positions */
soft_table->idx[0][0][0] = 0; soft_table->idx[0][0][0] = 0;
soft_table->idx[0][0][1] = 1; soft_table->idx[0][0][1] = 1;
soft_table->idx[0][1][0] = 0; soft_table->idx[0][1][0] = 0;
soft_table->idx[0][1][1] = 2; soft_table->idx[0][1][1] = 2;
/* QSPK symbols containing a '1' at the different bit positions */ /* QSPK symbols containing a '1' at the different bit positions */
soft_table->idx[1][0][0] = 2; soft_table->idx[1][0][0] = 2;
soft_table->idx[1][0][1] = 3; soft_table->idx[1][0][1] = 3;
soft_table->idx[1][1][0] = 1; soft_table->idx[1][1][0] = 1;
soft_table->idx[1][1][1] = 3; soft_table->idx[1][1][1] = 3;
} }
/** /**
* Set the 16QAM modulation table */ * Set the 16QAM modulation table */
void set_16QAMtable(cf_t* table, soft_table_t *soft_table, bool compute_soft_demod) void set_16QAMtable(cf_t* table, soft_table_t *soft_table, bool compute_soft_demod)
{ {
int i,j; int i,j;
// LTE-16QAM constellation: // LTE-16QAM constellation:
// Q // Q
// 1011 1001 | 0001 0011 // 1011 1001 | 0001 0011
// 1010 1000 | 0000 0010 // 1010 1000 | 0000 0010
//---------------------------------> I //---------------------------------> I
// 1110 1100 | 0100 0110 // 1110 1100 | 0100 0110
// 1111 1101 | 0101 0111 // 1111 1101 | 0101 0111
table[0] = QAM16_LEVEL_1 + QAM16_LEVEL_1*_Complex_I; table[0] = QAM16_LEVEL_1 + QAM16_LEVEL_1*_Complex_I;
table[1] = QAM16_LEVEL_1 + QAM16_LEVEL_2*_Complex_I; table[1] = QAM16_LEVEL_1 + QAM16_LEVEL_2*_Complex_I;
table[2] = QAM16_LEVEL_2 + QAM16_LEVEL_1*_Complex_I; table[2] = QAM16_LEVEL_2 + QAM16_LEVEL_1*_Complex_I;
table[3] = QAM16_LEVEL_2 + QAM16_LEVEL_2*_Complex_I; table[3] = QAM16_LEVEL_2 + QAM16_LEVEL_2*_Complex_I;
table[4] = QAM16_LEVEL_1 - QAM16_LEVEL_1*_Complex_I; table[4] = QAM16_LEVEL_1 - QAM16_LEVEL_1*_Complex_I;
table[5] = QAM16_LEVEL_1 - QAM16_LEVEL_2*_Complex_I; table[5] = QAM16_LEVEL_1 - QAM16_LEVEL_2*_Complex_I;
table[6] = QAM16_LEVEL_2 - QAM16_LEVEL_1*_Complex_I; table[6] = QAM16_LEVEL_2 - QAM16_LEVEL_1*_Complex_I;
table[7] = QAM16_LEVEL_2 - QAM16_LEVEL_2*_Complex_I; table[7] = QAM16_LEVEL_2 - QAM16_LEVEL_2*_Complex_I;
table[8] = -QAM16_LEVEL_1 + QAM16_LEVEL_1*_Complex_I; table[8] = -QAM16_LEVEL_1 + QAM16_LEVEL_1*_Complex_I;
table[9] = -QAM16_LEVEL_1 + QAM16_LEVEL_2*_Complex_I; table[9] = -QAM16_LEVEL_1 + QAM16_LEVEL_2*_Complex_I;
table[10] = -QAM16_LEVEL_2 + QAM16_LEVEL_1*_Complex_I; table[10] = -QAM16_LEVEL_2 + QAM16_LEVEL_1*_Complex_I;
table[11] = -QAM16_LEVEL_2 + QAM16_LEVEL_2*_Complex_I; table[11] = -QAM16_LEVEL_2 + QAM16_LEVEL_2*_Complex_I;
table[12] = -QAM16_LEVEL_1 - QAM16_LEVEL_1*_Complex_I; table[12] = -QAM16_LEVEL_1 - QAM16_LEVEL_1*_Complex_I;
table[13] = -QAM16_LEVEL_1 - QAM16_LEVEL_2*_Complex_I; table[13] = -QAM16_LEVEL_1 - QAM16_LEVEL_2*_Complex_I;
table[14] = -QAM16_LEVEL_2 - QAM16_LEVEL_1*_Complex_I; table[14] = -QAM16_LEVEL_2 - QAM16_LEVEL_1*_Complex_I;
table[15] = -QAM16_LEVEL_2 - QAM16_LEVEL_2*_Complex_I; table[15] = -QAM16_LEVEL_2 - QAM16_LEVEL_2*_Complex_I;
for (i=0;i<6;i++) { for (i=0;i<6;i++) {
for (j=0;j<32;j++) { for (j=0;j<32;j++) {
soft_table->idx[0][i][j] = 0; soft_table->idx[0][i][j] = 0;
soft_table->idx[1][i][j] = 0; soft_table->idx[1][i][j] = 0;
} }
} }
if (!compute_soft_demod) { if (!compute_soft_demod) {
return; return;
} }
/* Matrices identifying the zeros and ones of LTE-16QAM constellation */ /* Matrices identifying the zeros and ones of LTE-16QAM constellation */
for (i=0;i<8;i++) { for (i=0;i<8;i++) {
soft_table->idx[0][0][i] = i; /* symbols with a '0' at the bit0 (leftmost)*/ soft_table->idx[0][0][i] = i; /* symbols with a '0' at the bit0 (leftmost)*/
soft_table->idx[1][0][i] = i+8; /* symbols with a '1' at the bit0 (leftmost)*/ soft_table->idx[1][0][i] = i+8; /* symbols with a '1' at the bit0 (leftmost)*/
} }
/* symbols with a '0' ans '1' at the bit position 1: */ /* symbols with a '0' ans '1' at the bit position 1: */
for (i=0;i<4;i++) { for (i=0;i<4;i++) {
soft_table->idx[0][1][i] = i; soft_table->idx[0][1][i] = i;
soft_table->idx[0][1][i+4] = i+8; soft_table->idx[0][1][i+4] = i+8;
soft_table->idx[1][1][i] = i+4; soft_table->idx[1][1][i] = i+4;
soft_table->idx[1][1][i+4] = i+12; soft_table->idx[1][1][i+4] = i+12;
} }
/* symbols with a '0' ans '1' at the bit position 2: */ /* symbols with a '0' ans '1' at the bit position 2: */
for (j=0;j<4;j++) { for (j=0;j<4;j++) {
for (i=0;i<2;i++) { for (i=0;i<2;i++) {
soft_table->idx[0][2][i+2*j] = i + 4*j; soft_table->idx[0][2][i+2*j] = i + 4*j;
soft_table->idx[1][2][i+2*j] = i+2 + 4*j; soft_table->idx[1][2][i+2*j] = i+2 + 4*j;
} }
} }
/* symbols with a '0' ans '1' at the bit position 3: */ /* symbols with a '0' ans '1' at the bit position 3: */
for (i=0;i<8;i++) { for (i=0;i<8;i++) {
soft_table->idx[0][3][i] = 2*i; soft_table->idx[0][3][i] = 2*i;
soft_table->idx[1][3][i] = 2*i+1; soft_table->idx[1][3][i] = 2*i+1;
} }
} }
/** /**
* Set the 64QAM modulation table */ * Set the 64QAM modulation table */
void set_64QAMtable(cf_t* table, soft_table_t *soft_table, bool compute_soft_demod) void set_64QAMtable(cf_t* table, soft_table_t *soft_table, bool compute_soft_demod)
{ {
int i,j; int i,j;
// LTE-64QAM constellation: // LTE-64QAM constellation:
// see [3GPP TS 36.211 version 10.5.0 Release 10, Section 7.1.4] // see [3GPP TS 36.211 version 10.5.0 Release 10, Section 7.1.4]
table[0] = QAM64_LEVEL_2 + QAM64_LEVEL_2*_Complex_I; table[0] = QAM64_LEVEL_2 + QAM64_LEVEL_2*_Complex_I;
table[1] = QAM64_LEVEL_2 + QAM64_LEVEL_1*_Complex_I; table[1] = QAM64_LEVEL_2 + QAM64_LEVEL_1*_Complex_I;
table[2] = QAM64_LEVEL_1 + QAM64_LEVEL_2*_Complex_I; table[2] = QAM64_LEVEL_1 + QAM64_LEVEL_2*_Complex_I;
table[3] = QAM64_LEVEL_1 + QAM64_LEVEL_1*_Complex_I; table[3] = QAM64_LEVEL_1 + QAM64_LEVEL_1*_Complex_I;
table[4] = QAM64_LEVEL_2 + QAM64_LEVEL_3*_Complex_I; table[4] = QAM64_LEVEL_2 + QAM64_LEVEL_3*_Complex_I;
table[5] = QAM64_LEVEL_2 + QAM64_LEVEL_4*_Complex_I; table[5] = QAM64_LEVEL_2 + QAM64_LEVEL_4*_Complex_I;
table[6] = QAM64_LEVEL_1 + QAM64_LEVEL_3*_Complex_I; table[6] = QAM64_LEVEL_1 + QAM64_LEVEL_3*_Complex_I;
table[7] = QAM64_LEVEL_1 + QAM64_LEVEL_4*_Complex_I; table[7] = QAM64_LEVEL_1 + QAM64_LEVEL_4*_Complex_I;
table[8] = QAM64_LEVEL_3 + QAM64_LEVEL_2*_Complex_I; table[8] = QAM64_LEVEL_3 + QAM64_LEVEL_2*_Complex_I;
table[9] = QAM64_LEVEL_3 + QAM64_LEVEL_1*_Complex_I; table[9] = QAM64_LEVEL_3 + QAM64_LEVEL_1*_Complex_I;
table[10] = QAM64_LEVEL_4 + QAM64_LEVEL_2*_Complex_I; table[10] = QAM64_LEVEL_4 + QAM64_LEVEL_2*_Complex_I;
table[11] = QAM64_LEVEL_4 + QAM64_LEVEL_1*_Complex_I; table[11] = QAM64_LEVEL_4 + QAM64_LEVEL_1*_Complex_I;
table[12] = QAM64_LEVEL_3 + QAM64_LEVEL_3*_Complex_I; table[12] = QAM64_LEVEL_3 + QAM64_LEVEL_3*_Complex_I;
table[13] = QAM64_LEVEL_3 + QAM64_LEVEL_4*_Complex_I; table[13] = QAM64_LEVEL_3 + QAM64_LEVEL_4*_Complex_I;
table[14] = QAM64_LEVEL_4 + QAM64_LEVEL_3*_Complex_I; table[14] = QAM64_LEVEL_4 + QAM64_LEVEL_3*_Complex_I;
table[15] = QAM64_LEVEL_4 + QAM64_LEVEL_4*_Complex_I; table[15] = QAM64_LEVEL_4 + QAM64_LEVEL_4*_Complex_I;
table[16] = QAM64_LEVEL_2 - QAM64_LEVEL_2*_Complex_I; table[16] = QAM64_LEVEL_2 - QAM64_LEVEL_2*_Complex_I;
table[17] = QAM64_LEVEL_2 - QAM64_LEVEL_1*_Complex_I; table[17] = QAM64_LEVEL_2 - QAM64_LEVEL_1*_Complex_I;
table[18] = QAM64_LEVEL_1 - QAM64_LEVEL_2*_Complex_I; table[18] = QAM64_LEVEL_1 - QAM64_LEVEL_2*_Complex_I;
table[19] = QAM64_LEVEL_1 - QAM64_LEVEL_1*_Complex_I; table[19] = QAM64_LEVEL_1 - QAM64_LEVEL_1*_Complex_I;
table[20] = QAM64_LEVEL_2 - QAM64_LEVEL_3*_Complex_I; table[20] = QAM64_LEVEL_2 - QAM64_LEVEL_3*_Complex_I;
table[21] = QAM64_LEVEL_2 - QAM64_LEVEL_4*_Complex_I; table[21] = QAM64_LEVEL_2 - QAM64_LEVEL_4*_Complex_I;
table[22] = QAM64_LEVEL_1 - QAM64_LEVEL_3*_Complex_I; table[22] = QAM64_LEVEL_1 - QAM64_LEVEL_3*_Complex_I;
table[23] = QAM64_LEVEL_1 - QAM64_LEVEL_4*_Complex_I; table[23] = QAM64_LEVEL_1 - QAM64_LEVEL_4*_Complex_I;
table[24] = QAM64_LEVEL_3 - QAM64_LEVEL_2*_Complex_I; table[24] = QAM64_LEVEL_3 - QAM64_LEVEL_2*_Complex_I;
table[25] = QAM64_LEVEL_3 - QAM64_LEVEL_1*_Complex_I; table[25] = QAM64_LEVEL_3 - QAM64_LEVEL_1*_Complex_I;
table[26] = QAM64_LEVEL_4 - QAM64_LEVEL_2*_Complex_I; table[26] = QAM64_LEVEL_4 - QAM64_LEVEL_2*_Complex_I;
table[27] = QAM64_LEVEL_4 - QAM64_LEVEL_1*_Complex_I; table[27] = QAM64_LEVEL_4 - QAM64_LEVEL_1*_Complex_I;
table[28] = QAM64_LEVEL_3 - QAM64_LEVEL_3*_Complex_I; table[28] = QAM64_LEVEL_3 - QAM64_LEVEL_3*_Complex_I;
table[29] = QAM64_LEVEL_3 - QAM64_LEVEL_4*_Complex_I; table[29] = QAM64_LEVEL_3 - QAM64_LEVEL_4*_Complex_I;
table[30] = QAM64_LEVEL_4 - QAM64_LEVEL_3*_Complex_I; table[30] = QAM64_LEVEL_4 - QAM64_LEVEL_3*_Complex_I;
table[31] = QAM64_LEVEL_4 - QAM64_LEVEL_4*_Complex_I; table[31] = QAM64_LEVEL_4 - QAM64_LEVEL_4*_Complex_I;
table[32] = -QAM64_LEVEL_2 + QAM64_LEVEL_2*_Complex_I; table[32] = -QAM64_LEVEL_2 + QAM64_LEVEL_2*_Complex_I;
table[33] = -QAM64_LEVEL_2 + QAM64_LEVEL_1*_Complex_I; table[33] = -QAM64_LEVEL_2 + QAM64_LEVEL_1*_Complex_I;
table[34] = -QAM64_LEVEL_1 + QAM64_LEVEL_2*_Complex_I; table[34] = -QAM64_LEVEL_1 + QAM64_LEVEL_2*_Complex_I;
table[35] = -QAM64_LEVEL_1 + QAM64_LEVEL_1*_Complex_I; table[35] = -QAM64_LEVEL_1 + QAM64_LEVEL_1*_Complex_I;
table[36] = -QAM64_LEVEL_2 + QAM64_LEVEL_3*_Complex_I; table[36] = -QAM64_LEVEL_2 + QAM64_LEVEL_3*_Complex_I;
table[37] = -QAM64_LEVEL_2 + QAM64_LEVEL_4*_Complex_I; table[37] = -QAM64_LEVEL_2 + QAM64_LEVEL_4*_Complex_I;
table[38] = -QAM64_LEVEL_1 + QAM64_LEVEL_3*_Complex_I; table[38] = -QAM64_LEVEL_1 + QAM64_LEVEL_3*_Complex_I;
table[39] = -QAM64_LEVEL_1 + QAM64_LEVEL_4*_Complex_I; table[39] = -QAM64_LEVEL_1 + QAM64_LEVEL_4*_Complex_I;
table[40] = -QAM64_LEVEL_3 + QAM64_LEVEL_2*_Complex_I; table[40] = -QAM64_LEVEL_3 + QAM64_LEVEL_2*_Complex_I;
table[41] = -QAM64_LEVEL_3 + QAM64_LEVEL_1*_Complex_I; table[41] = -QAM64_LEVEL_3 + QAM64_LEVEL_1*_Complex_I;
table[42] = -QAM64_LEVEL_4 + QAM64_LEVEL_2*_Complex_I; table[42] = -QAM64_LEVEL_4 + QAM64_LEVEL_2*_Complex_I;
table[43] = -QAM64_LEVEL_4 + QAM64_LEVEL_1*_Complex_I; table[43] = -QAM64_LEVEL_4 + QAM64_LEVEL_1*_Complex_I;
table[44] = -QAM64_LEVEL_3 + QAM64_LEVEL_3*_Complex_I; table[44] = -QAM64_LEVEL_3 + QAM64_LEVEL_3*_Complex_I;
table[45] = -QAM64_LEVEL_3 + QAM64_LEVEL_4*_Complex_I; table[45] = -QAM64_LEVEL_3 + QAM64_LEVEL_4*_Complex_I;
table[46] = -QAM64_LEVEL_4 + QAM64_LEVEL_3*_Complex_I; table[46] = -QAM64_LEVEL_4 + QAM64_LEVEL_3*_Complex_I;
table[47] = -QAM64_LEVEL_4 + QAM64_LEVEL_4*_Complex_I; table[47] = -QAM64_LEVEL_4 + QAM64_LEVEL_4*_Complex_I;
table[48] = -QAM64_LEVEL_2 - QAM64_LEVEL_2*_Complex_I; table[48] = -QAM64_LEVEL_2 - QAM64_LEVEL_2*_Complex_I;
table[49] = -QAM64_LEVEL_2 - QAM64_LEVEL_1*_Complex_I; table[49] = -QAM64_LEVEL_2 - QAM64_LEVEL_1*_Complex_I;
table[50] = -QAM64_LEVEL_1 - QAM64_LEVEL_2*_Complex_I; table[50] = -QAM64_LEVEL_1 - QAM64_LEVEL_2*_Complex_I;
table[51] = -QAM64_LEVEL_1 - QAM64_LEVEL_1*_Complex_I; table[51] = -QAM64_LEVEL_1 - QAM64_LEVEL_1*_Complex_I;
table[52] = -QAM64_LEVEL_2 - QAM64_LEVEL_3*_Complex_I; table[52] = -QAM64_LEVEL_2 - QAM64_LEVEL_3*_Complex_I;
table[53] = -QAM64_LEVEL_2 - QAM64_LEVEL_4*_Complex_I; table[53] = -QAM64_LEVEL_2 - QAM64_LEVEL_4*_Complex_I;
table[54] = -QAM64_LEVEL_1 - QAM64_LEVEL_3*_Complex_I; table[54] = -QAM64_LEVEL_1 - QAM64_LEVEL_3*_Complex_I;
table[55] = -QAM64_LEVEL_1 - QAM64_LEVEL_4*_Complex_I; table[55] = -QAM64_LEVEL_1 - QAM64_LEVEL_4*_Complex_I;
table[56] = -QAM64_LEVEL_3 - QAM64_LEVEL_2*_Complex_I; table[56] = -QAM64_LEVEL_3 - QAM64_LEVEL_2*_Complex_I;
table[57] = -QAM64_LEVEL_3 - QAM64_LEVEL_1*_Complex_I; table[57] = -QAM64_LEVEL_3 - QAM64_LEVEL_1*_Complex_I;
table[58] = -QAM64_LEVEL_4 - QAM64_LEVEL_2*_Complex_I; table[58] = -QAM64_LEVEL_4 - QAM64_LEVEL_2*_Complex_I;
table[59] = -QAM64_LEVEL_4 - QAM64_LEVEL_1*_Complex_I; table[59] = -QAM64_LEVEL_4 - QAM64_LEVEL_1*_Complex_I;
table[60] = -QAM64_LEVEL_3 - QAM64_LEVEL_3*_Complex_I; table[60] = -QAM64_LEVEL_3 - QAM64_LEVEL_3*_Complex_I;
table[61] = -QAM64_LEVEL_3 - QAM64_LEVEL_4*_Complex_I; table[61] = -QAM64_LEVEL_3 - QAM64_LEVEL_4*_Complex_I;
table[62] = -QAM64_LEVEL_4 - QAM64_LEVEL_3*_Complex_I; table[62] = -QAM64_LEVEL_4 - QAM64_LEVEL_3*_Complex_I;
table[63] = -QAM64_LEVEL_4 - QAM64_LEVEL_4*_Complex_I; table[63] = -QAM64_LEVEL_4 - QAM64_LEVEL_4*_Complex_I;
if (!compute_soft_demod) { if (!compute_soft_demod) {
return; return;
} }
/* Matrices identifying the zeros and ones of LTE-64QAM constellation */ /* Matrices identifying the zeros and ones of LTE-64QAM constellation */
for (i=0;i<32;i++) { for (i=0;i<32;i++) {
soft_table->idx[0][0][i] = i; /* symbols with a '0' at the bit0 (leftmost)*/ soft_table->idx[0][0][i] = i; /* symbols with a '0' at the bit0 (leftmost)*/
soft_table->idx[1][0][i] = i+32; /* symbols with a '1' at the bit0 (leftmost)*/ soft_table->idx[1][0][i] = i+32; /* symbols with a '1' at the bit0 (leftmost)*/
} }
/* symbols with a '0' ans '1' at the bit position 1: */ /* symbols with a '0' ans '1' at the bit position 1: */
for (i=0;i<16;i++) { for (i=0;i<16;i++) {
soft_table->idx[0][1][i] = i; soft_table->idx[0][1][i] = i;
soft_table->idx[0][1][i+16] = i+32; soft_table->idx[0][1][i+16] = i+32;
soft_table->idx[1][1][i] = i+16; soft_table->idx[1][1][i] = i+16;
soft_table->idx[1][1][i+16] = i+48; soft_table->idx[1][1][i+16] = i+48;
} }
/* symbols with a '0' ans '1' at the bit position 2: */ /* symbols with a '0' ans '1' at the bit position 2: */
for (i=0;i<8;i++) { for (i=0;i<8;i++) {
soft_table->idx[0][2][i] = i; soft_table->idx[0][2][i] = i;
soft_table->idx[0][2][i+8] = i+16; soft_table->idx[0][2][i+8] = i+16;
soft_table->idx[0][2][i+16] = i+32; soft_table->idx[0][2][i+16] = i+32;
soft_table->idx[0][2][i+24] = i+48; soft_table->idx[0][2][i+24] = i+48;
soft_table->idx[1][2][i] = i+8; soft_table->idx[1][2][i] = i+8;
soft_table->idx[1][2][i+8] = i+24; soft_table->idx[1][2][i+8] = i+24;
soft_table->idx[1][2][i+16] = i+40; soft_table->idx[1][2][i+16] = i+40;
soft_table->idx[1][2][i+24] = i+56; soft_table->idx[1][2][i+24] = i+56;
} }
/* symbols with a '0' ans '1' at the bit position 3: */ /* symbols with a '0' ans '1' at the bit position 3: */
for (j=0;j<8;j++) { for (j=0;j<8;j++) {
for (i=0;i<4;i++) { for (i=0;i<4;i++) {
soft_table->idx[0][3][i+4*j] = i + 8*j; soft_table->idx[0][3][i+4*j] = i + 8*j;
soft_table->idx[1][3][i+4*j] = i+4 + 8*j; soft_table->idx[1][3][i+4*j] = i+4 + 8*j;
} }
} }
/* symbols with a '0' ans '1' at the bit position 4: */ /* symbols with a '0' ans '1' at the bit position 4: */
for (j=0;j<16;j++) { for (j=0;j<16;j++) {
for (i=0;i<2;i++) { for (i=0;i<2;i++) {
soft_table->idx[0][4][i+2*j] = i + 4*j; soft_table->idx[0][4][i+2*j] = i + 4*j;
soft_table->idx[1][4][i+2*j] = i+2 + 4*j; soft_table->idx[1][4][i+2*j] = i+2 + 4*j;
} }
} }
/* symbols with a '0' ans '1' at the bit position 5: */ /* symbols with a '0' ans '1' at the bit position 5: */
for (i=0;i<32;i++) { for (i=0;i<32;i++) {
soft_table->idx[0][5][i] = 2*i; soft_table->idx[0][5][i] = 2*i;
soft_table->idx[1][5][i] = 2*i+1; soft_table->idx[1][5][i] = 2*i+1;
} }
} }

@ -30,15 +30,15 @@
#define QPSK_LEVEL 1/sqrt(2) #define QPSK_LEVEL 1/sqrt(2)
#define QAM16_LEVEL_1 1/sqrt(10) #define QAM16_LEVEL_1 1/sqrt(10)
#define QAM16_LEVEL_2 3/sqrt(10) #define QAM16_LEVEL_2 3/sqrt(10)
#define QAM64_LEVEL_1 1/sqrt(42) #define QAM64_LEVEL_1 1/sqrt(42)
#define QAM64_LEVEL_2 3/sqrt(42) #define QAM64_LEVEL_2 3/sqrt(42)
#define QAM64_LEVEL_3 5/sqrt(42) #define QAM64_LEVEL_3 5/sqrt(42)
#define QAM64_LEVEL_4 7/sqrt(42) #define QAM64_LEVEL_4 7/sqrt(42)
#define QAM64_LEVEL_x 2/sqrt(42) #define QAM64_LEVEL_x 2/sqrt(42)
/* this is not an QAM64 level, but, rather, an auxiliary value that can be used for computing the /* this is not an QAM64 level, but, rather, an auxiliary value that can be used for computing the
* symbol from the bit sequence */ * symbol from the bit sequence */

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save