Replacing tabs with spaces

master
Paul Sutton 11 years ago
commit 36a4a5612a

@ -36,44 +36,44 @@
#include "lte/utils/debug.h"
int cuhd_rssi_scan(void *uhd, float *freqs, float *rssi, int nof_bands, double fs, int nsamp) {
int i, j;
int ret = -1;
_Complex float *buffer;
double f;
int i, j;
int ret = -1;
_Complex float *buffer;
double f;
buffer = calloc(nsamp, sizeof(_Complex float));
if (!buffer) {
goto free_and_exit;
}
buffer = calloc(nsamp, sizeof(_Complex float));
if (!buffer) {
goto free_and_exit;
}
cuhd_set_rx_gain(uhd, 0.0);
cuhd_set_rx_srate(uhd, fs);
cuhd_set_rx_gain(uhd, 0.0);
cuhd_set_rx_srate(uhd, fs);
for (i=0;i<nof_bands;i++) {
cuhd_stop_rx_stream(uhd);
for (i=0;i<nof_bands;i++) {
cuhd_stop_rx_stream(uhd);
f = (double) freqs[i];
cuhd_set_rx_freq(uhd, f);
cuhd_rx_wait_lo_locked(uhd);
f = (double) freqs[i];
cuhd_set_rx_freq(uhd, f);
cuhd_rx_wait_lo_locked(uhd);
cuhd_start_rx_stream(uhd);
cuhd_start_rx_stream(uhd);
/* discard first samples */
for (j=0;j<2;j++) {
if (cuhd_recv(uhd, buffer, nsamp, 1) != nsamp) {
goto free_and_exit;
}
}
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);
if (VERBOSE_ISINFO()) {
printf("\n");
}
}
cuhd_stop_rx_stream(uhd);
/* discard first samples */
for (j=0;j<2;j++) {
if (cuhd_recv(uhd, buffer, nsamp, 1) != nsamp) {
goto free_and_exit;
}
}
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);
if (VERBOSE_ISINFO()) {
printf("\n");
}
}
cuhd_stop_rx_stream(uhd);
ret = 0;
ret = 0;
free_and_exit:
free(buffer);
return ret;
free(buffer);
return ret;
}

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

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

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

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

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

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

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

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

@ -38,7 +38,7 @@ extern "C" {
#include "lte/config.h"
typedef enum {
Ip, Q, Magnitude, Phase
Ip, Q, Magnitude, Phase
} plot_complex_id_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 void plot_complex_setTitle(plot_complex_t *h, char *title);
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_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);

@ -41,7 +41,7 @@ typedef void* plot_real_t;
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_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_setYAxisAutoScale(plot_real_t *h, bool on);
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 void plot_scatter_setTitle(plot_scatter_t *h, char *title);
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_setYAxisAutoScale(plot_scatter_t *h, bool on);
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 void plot_waterfall_setTitle(plot_waterfall_t *h, char *title);
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_setPlotYLabel(plot_waterfall_t *h, char *yLabel);
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 */
typedef struct LIBLTE_API{
int nof_ports;
int nof_symbols;
int nof_prb;
lte_cp_t cp;
refsignal_t refsignal[MAX_PORTS][NSLOTS_X_FRAME];
interpolate_fnc_t interp;
int nof_ports;
int nof_symbols;
int nof_prb;
lte_cp_t cp;
refsignal_t refsignal[MAX_PORTS][NSLOTS_X_FRAME];
interpolate_fnc_t interp;
}chest_t;
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 */
typedef struct LIBLTE_API{
chest_t obj;
struct chest_init {
int nof_symbols; // 7 for normal cp, 6 for extended
int nof_ports;
int nof_prb;
int cell_id; // set to -1 to init at runtime
} init;
cf_t *input;
int in_len;
struct chest_ctrl_in {
int slot_id; // slot id in the 10ms frame
int cell_id;
} ctrl_in;
cf_t *output[MAX_PORTS];
int out_len[MAX_PORTS];
chest_t obj;
struct chest_init {
int nof_symbols; // 7 for normal cp, 6 for extended
int nof_ports;
int nof_prb;
int cell_id; // set to -1 to init at runtime
} init;
cf_t *input;
int in_len;
struct chest_ctrl_in {
int slot_id; // slot id in the 10ms frame
int cell_id;
} ctrl_in;
cf_t *output[MAX_PORTS];
int out_len[MAX_PORTS];
}chest_hl;
#define DEFAULT_FRAME_SIZE 2048
#define DEFAULT_FRAME_SIZE 2048
LIBLTE_API int chest_initialize(chest_hl* h);
LIBLTE_API int chest_work(chest_hl* hl);

@ -43,24 +43,24 @@
typedef _Complex float cf_t;
typedef struct LIBLTE_API{
int time_idx;
int freq_idx;
cf_t simbol;
cf_t recv_simbol;
int time_idx;
int freq_idx;
cf_t simbol;
cf_t recv_simbol;
}ref_t;
typedef struct LIBLTE_API{
int nof_refs; // number of reference signals
int *symbols_ref; // 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 nof_prb;
ref_t *refs;
cf_t *ch_est;
int nof_refs; // number of reference signals
int *symbols_ref; // 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 nof_prb;
ref_t *refs;
cf_t *ch_est;
} refsignal_t;
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_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 */
typedef struct LIBLTE_API{
const cf_t* input;
int in_len;
struct ch_awgn_ctrl_in {
float variance; // Noise variance
} ctrl_in;
cf_t* output;
int out_len;
const cf_t* input;
int in_len;
struct ch_awgn_ctrl_in {
float variance; // Noise variance
} ctrl_in;
cf_t* output;
int out_len;
}ch_awgn_hl;
LIBLTE_API int ch_awgn_initialize(ch_awgn_hl* hl);

@ -31,38 +31,38 @@
#include "lte/config.h"
#define NSUBFRAMES_X_FRAME 10
#define NSUBFRAMES_X_FRAME 10
#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_CTRL 4
#define MAX_LAYERS 8
#define MAX_CODEWORDS 2
#define MAX_PORTS 4
#define MAX_PORTS_CTRL 4
#define MAX_LAYERS 8
#define MAX_CODEWORDS 2
#define LTE_CRC24A 0x1864CFB
#define LTE_CRC24B 0X1800063
#define LTE_CRC16 0x11021
#define LTE_CRC8 0x19B
#define LTE_CRC24A 0x1864CFB
#define LTE_CRC24B 0X1800063
#define LTE_CRC16 0x11021
#define LTE_CRC8 0x19B
typedef enum {CPNORM, CPEXT} lte_cp_t;
#define SIRNTI 0xFFFF
#define PRNTI 0xFFFE
#define MRNTI 0xFFFD
#define SIRNTI 0xFFFF
#define PRNTI 0xFFFE
#define MRNTI 0xFFFD
#define MAX_NSYMB 7
#define MAX_NSYMB 7
#define CPNORM_NSYMB 7
#define CPNORM_SF_NSYMB 2*CPNORM_NSYMB
#define CPNORM_0_LEN 160
#define CPNORM_LEN 144
#define CPNORM_NSYMB 7
#define CPNORM_SF_NSYMB 2*CPNORM_NSYMB
#define CPNORM_0_LEN 160
#define CPNORM_LEN 144
#define CPEXT_NSYMB 6
#define CPEXT_SF_NSYMB 2*CPEXT_NSYMB
#define CPEXT_LEN 512
#define CPEXT_7_5_LEN 1024
#define CPEXT_NSYMB 6
#define CPEXT_SF_NSYMB 2*CPEXT_NSYMB
#define CPEXT_LEN 512
#define CPEXT_7_5_LEN 1024
#define CP_ISNORM(cp) (cp==CPNORM)
#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_CPEXT(idx, symbol_sz) (idx*(symbol_sz+CP(symbol_sz, CPEXT_LEN)))
#define MAX_PRB 110
#define RE_X_RB 12
#define MAX_PRB 110
#define RE_X_RB 12
#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)
@ -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_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
typedef enum {
SINGLE_ANTENNA,TX_DIVERSITY, SPATIAL_MULTIPLEX
SINGLE_ANTENNA,TX_DIVERSITY, SPATIAL_MULTIPLEX
} lte_mimo_type_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{
int id;
float fd;
int id;
float fd;
}lte_earfcn_t;
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);

@ -41,13 +41,13 @@ typedef _Complex float cf_t; /* this is only a shortcut */
/* This is common for both directions */
typedef struct LIBLTE_API{
dft_plan_t fft_plan;
int nof_symbols;
int symbol_sz;
int nof_guards;
int nof_re;
lte_cp_t cp_type;
cf_t *tmp; // for removing zero padding
dft_plan_t fft_plan;
int nof_symbols;
int symbol_sz;
int nof_guards;
int nof_re;
lte_cp_t cp_type;
cf_t *tmp; // for removing zero padding
}lte_fft_t;
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"
typedef struct LIBLTE_API{
char *c;
int len;
char *c;
int len;
}sequence_t;
LIBLTE_API int sequence_init(sequence_t *q, int len);

@ -34,10 +34,10 @@
#include "lte/config.h"
typedef struct LIBLTE_API {
int R;
int K;
int poly[3];
bool tail_biting;
int R;
int K;
int poly[3];
bool tail_biting;
}convcoder_t;
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 */
typedef struct LIBLTE_API {
convcoder_t obj;
struct convcoder_ctrl_in {
int rate;
int constraint_length;
int tail_bitting;
int generator_0;
int generator_1;
int generator_2;
int frame_length;
} ctrl_in;
char *input;
int in_len;
char *output;
int out_len;
convcoder_t obj;
struct convcoder_ctrl_in {
int rate;
int constraint_length;
int tail_bitting;
int generator_0;
int generator_1;
int generator_2;
int frame_length;
} ctrl_in;
char *input;
int in_len;
char *output;
int out_len;
}convcoder_hl;
LIBLTE_API int convcoder_initialize(convcoder_hl* h);

@ -32,14 +32,14 @@
#include "lte/config.h"
typedef struct LIBLTE_API {
unsigned long table[256];
unsigned char byte;
int polynom;
int order;
unsigned long crcinit;
unsigned long crcmask;
unsigned long crchighbit;
unsigned int crc_out;
unsigned long table[256];
unsigned char byte;
int polynom;
int order;
unsigned long crcinit;
unsigned long crcmask;
unsigned long crchighbit;
unsigned int crc_out;
} crc_t;
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 */
typedef struct LIBLTE_API {
struct rm_conv_init {
int direction;
} init;
void *input; // input type may be char or float depending on hard
int in_len;
struct rm_conv_ctrl_in {
int E;
int S;
} ctrl_in;
void *output;
int out_len;
struct rm_conv_init {
int direction;
} init;
void *input; // input type may be char or float depending on hard
int in_len;
struct rm_conv_ctrl_in {
int E;
int S;
} ctrl_in;
void *output;
int out_len;
}rm_conv_hl;
LIBLTE_API int rm_conv_initialize(rm_conv_hl* h);

@ -40,9 +40,9 @@
#endif
typedef struct LIBLTE_API {
int buffer_len;
char *buffer;
int *d2_perm;
int buffer_len;
char *buffer;
int *d2_perm;
} rm_turbo_t;
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 */
typedef struct LIBLTE_API {
rm_turbo_t q;
struct rm_turbo_init {
int direction;
} init;
void *input; // input type may be char or float depending on hard
int in_len;
struct rm_turbo_ctrl_in {
int E;
int S;
int rv_idx;
} ctrl_in;
void *output;
int out_len;
rm_turbo_t q;
struct rm_turbo_init {
int direction;
} init;
void *input; // input type may be char or float depending on hard
int in_len;
struct rm_turbo_ctrl_in {
int E;
int S;
int rv_idx;
} ctrl_in;
void *output;
int out_len;
}rm_turbo_hl;
LIBLTE_API int rm_turbo_initialize(rm_turbo_hl* h);

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

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

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

@ -33,20 +33,20 @@
#include "lte/config.h"
typedef enum {
viterbi_27, viterbi_29, viterbi_37, viterbi_39
viterbi_27, viterbi_29, viterbi_37, viterbi_39
}viterbi_type_t;
typedef struct LIBLTE_API{
void *ptr;
int R;
int K;
unsigned int framebits;
bool tail_biting;
int poly[3];
int (*decode) (void*, unsigned char*, char*, int);
void (*free) (void*);
unsigned char *tmp;
unsigned char *symbols_uc;
void *ptr;
int R;
int K;
unsigned int framebits;
bool tail_biting;
int poly[3];
int (*decode) (void*, unsigned char*, char*, int);
void (*free) (void*);
unsigned char *tmp;
unsigned char *symbols_uc;
}viterbi_t;
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 */
typedef struct LIBLTE_API{
viterbi_t obj;
struct viterbi_init {
int rate;
int constraint_length;
int tail_bitting;
int generator_0;
int generator_1;
int generator_2;
int frame_length;
} init;
float *input;
int in_len;
char *output;
int out_len;
viterbi_t obj;
struct viterbi_init {
int rate;
int constraint_length;
int tail_bitting;
int generator_0;
int generator_1;
int generator_2;
int frame_length;
} init;
float *input;
int in_len;
char *output;
int out_len;
}viterbi_hl;
LIBLTE_API int viterbi_initialize(viterbi_hl* h);

@ -38,12 +38,12 @@
typedef _Complex float cf_t;
typedef struct LIBLTE_API{
int sztime; // Output signal size in the time domain
int szfreq; // Output signal size in the freq domain
int ntime; // 2-D Filter size in time domain
int nfreq; // 2-D Filter size in frequency domain
float **taps; // 2-D filter coefficients
cf_t *output; // Output signal
int sztime; // Output signal size in the time domain
int szfreq; // Output signal size in the freq domain
int ntime; // 2-D Filter size in time domain
int nfreq; // 2-D Filter size in frequency domain
float **taps; // 2-D filter coefficients
cf_t *output; // Output signal
} filter2d_t;
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 */
typedef struct LIBLTE_API{
unsigned int seed;
uint32_t *seq_buff;
int seq_buff_nwords;
int seq_cache_nbits;
int seq_cache_rp;
unsigned int seed;
uint32_t *seq_buff;
int seq_buff_nwords;
int seq_cache_nbits;
int seq_cache_rp;
}binsource_t;
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 */
typedef struct LIBLTE_API {
binsource_t obj;
struct binsource_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.
} init;
struct binsource_ctrl_in {
int nbits; // Number of bits to generate
} ctrl_in;
char* output;
int out_len;
binsource_t obj;
struct binsource_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.
} init;
struct binsource_ctrl_in {
int nbits; // Number of bits to generate
} ctrl_in;
char* output;
int out_len;
}binsource_hl;
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);
#endif // BINSOURCE_

@ -37,8 +37,8 @@
/* Low-level API */
typedef struct LIBLTE_API {
FILE *f;
data_type_t type;
FILE *f;
data_type_t type;
}filesink_t;
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 */
typedef struct LIBLTE_API {
filesink_t obj;
struct filesink_init {
char *file_name;
int block_length;
int data_type;
} init;
void* input;
int in_len;
filesink_t obj;
struct filesink_init {
char *file_name;
int block_length;
int data_type;
} init;
void* input;
int in_len;
}filesink_hl;
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);
#endif // FILESINK_

@ -37,8 +37,8 @@
/* Low-level API */
typedef struct LIBLTE_API {
FILE *f;
data_type_t type;
FILE *f;
data_type_t type;
}filesource_t;
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 */
typedef struct LIBLTE_API {
filesource_t obj;
struct filesource_init {
char *file_name;
int block_length;
int data_type;
} init;
struct filesource_ctrl_in {
int nsamples; // Number of samples to read
} ctrl_in;
void* output;
int out_len;
filesource_t obj;
struct filesource_init {
char *file_name;
int block_length;
int data_type;
} init;
struct filesource_ctrl_in {
int nsamples; // Number of samples to read
} ctrl_in;
void* output;
int out_len;
}filesource_hl;
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);
#endif // FILESOURCE_

@ -40,9 +40,9 @@
/* Low-level API */
typedef struct LIBLTE_API {
int sockfd;
struct sockaddr_in servaddr;
data_type_t type;
int sockfd;
struct sockaddr_in servaddr;
data_type_t type;
}udpsink_t;
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 */
typedef struct LIBLTE_API {
udpsink_t obj;
struct udpsink_init {
char *address;
int port;
int block_length;
int data_type;
} init;
void* input;
int in_len;
udpsink_t obj;
struct udpsink_init {
char *address;
int port;
int block_length;
int data_type;
} init;
void* input;
int in_len;
}udpsink_hl;
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);
#endif // UDPSINK_

@ -41,9 +41,9 @@
/* Low-level API */
typedef struct LIBLTE_API {
int sockfd;
struct sockaddr_in servaddr;
data_type_t type;
int sockfd;
struct sockaddr_in servaddr;
data_type_t type;
}udpsource_t;
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 */
typedef struct LIBLTE_API {
udpsource_t obj;
struct udpsource_init {
char *address;
int port;
int data_type;
} init;
struct udpsource_ctrl_in {
int nsamples; // Number of samples to read
} ctrl_in;
void* output;
int out_len;
udpsource_t obj;
struct udpsource_init {
char *address;
int port;
int data_type;
} init;
struct udpsource_ctrl_in {
int nsamples; // Number of samples to read
} ctrl_in;
void* output;
int out_len;
}udpsource_hl;
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);
#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_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,
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,
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"
@ -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_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,
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,
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_

@ -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_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,
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"
*/
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],
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],
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);
#endif // PRECODING_H_

@ -38,7 +38,7 @@
typedef _Complex float cf_t;
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;
@ -50,16 +50,16 @@ LIBLTE_API int demod_hard_demodulate(demod_hard_t* q, cf_t* symbols, char *bits,
/* High-level API */
typedef struct LIBLTE_API {
demod_hard_t obj;
struct demod_hard_init {
enum modem_std std; // Symbol mapping standard (see modem_table.h)
} init;
demod_hard_t obj;
struct demod_hard_init {
enum modem_std std; // Symbol mapping standard (see modem_table.h)
} init;
cf_t* input;
int in_len;
cf_t* input;
int in_len;
char* output;
int out_len;
char* output;
int out_len;
}demod_hard_hl;
LIBLTE_API int demod_hard_initialize(demod_hard_hl* hl);

@ -38,9 +38,9 @@
enum alg { EXACT, APPROX };
typedef struct LIBLTE_API {
float sigma; // noise power
enum alg alg_type; // soft demapping algorithm (EXACT or APPROX)
modem_table_t *table; // symbol mapping table (see modem_table.h)
float sigma; // noise power
enum alg alg_type; // soft demapping algorithm (EXACT or APPROX)
modem_table_t *table; // symbol mapping table (see modem_table.h)
}demod_soft_t;
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 */
typedef struct LIBLTE_API {
demod_soft_t obj;
modem_table_t table;
demod_soft_t obj;
modem_table_t table;
struct demod_soft_init{
enum modem_std std; // symbol mapping standard (see modem_table.h)
} init;
enum modem_std std; // symbol mapping standard (see modem_table.h)
} init;
const cf_t* input;
int in_len;
const cf_t* input;
int in_len;
struct demod_soft_ctrl_in {
float sigma; // Estimated noise variance
enum alg alg_type; // soft demapping algorithm (EXACT or APPROX)
}ctrl_in;
struct demod_soft_ctrl_in {
float sigma; // Estimated noise variance
enum alg alg_type; // soft demapping algorithm (EXACT or APPROX)
}ctrl_in;
float* output;
int out_len;
float* output;
int out_len;
}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 */
typedef struct LIBLTE_API {
modem_table_t obj;
struct mod_init {
enum modem_std std; // symbol mapping standard (see modem_table.h)
} init;
modem_table_t obj;
struct mod_init {
enum modem_std std; // symbol mapping standard (see modem_table.h)
} init;
const char* input;
int in_len;
const char* input;
int in_len;
cf_t* output;
int out_len;
cf_t* output;
int out_len;
}mod_hl;
LIBLTE_API int mod_initialize(mod_hl* hl);

@ -38,20 +38,20 @@
typedef _Complex float cf_t;
typedef struct LIBLTE_API {
int idx[2][6][32];
int idx[2][6][32];
}soft_table_t;
typedef struct LIBLTE_API {
cf_t* symbol_table; // bit-to-symbol mapping
soft_table_t soft_table; // symbol-to-bit mapping (used in soft demodulating)
int nsymbols; // number of modulation symbols
int nbits_x_symbol; // number of bits per symbol
cf_t* symbol_table; // bit-to-symbol mapping
soft_table_t soft_table; // symbol-to-bit mapping (used in soft demodulating)
int nsymbols; // number of modulation symbols
int nbits_x_symbol; // number of bits per symbol
}modem_table_t;
// Modulation standards
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);

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

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

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

@ -45,10 +45,10 @@
typedef _Complex float cf_t;
#define PDCCH_NOF_SEARCH_MODES 3
#define PDCCH_NOF_SEARCH_MODES 3
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;
/*
@ -56,40 +56,40 @@ typedef enum {
* DCI messages as defined in Section 7.1 of 36.213
*/
typedef struct LIBLTE_API {
int nof_candidates;
dci_candidate_t *candidates[NSUBFRAMES_X_FRAME];
int nof_candidates;
dci_candidate_t *candidates[NSUBFRAMES_X_FRAME];
}pdcch_search_t;
/* PDCCH object */
typedef struct LIBLTE_API {
int cell_id;
lte_cp_t cp;
int nof_prb;
int nof_bits;
int nof_symbols;
int nof_ports;
int nof_regs;
int nof_cce;
pdcch_search_t search_mode[PDCCH_NOF_SEARCH_MODES];
pdcch_search_mode_t current_search_mode;
regs_t *regs;
/* buffers */
cf_t *ce[MAX_PORTS_CTRL];
cf_t *pdcch_symbols[MAX_PORTS_CTRL];
cf_t *pdcch_x[MAX_PORTS_CTRL];
cf_t *pdcch_d;
char *pdcch_e;
float *pdcch_llr;
/* tx & rx objects */
modem_table_t mod;
demod_soft_t demod;
sequence_t seq_pdcch[NSUBFRAMES_X_FRAME];
viterbi_t decoder;
crc_t crc;
int cell_id;
lte_cp_t cp;
int nof_prb;
int nof_bits;
int nof_symbols;
int nof_ports;
int nof_regs;
int nof_cce;
pdcch_search_t search_mode[PDCCH_NOF_SEARCH_MODES];
pdcch_search_mode_t current_search_mode;
regs_t *regs;
/* buffers */
cf_t *ce[MAX_PORTS_CTRL];
cf_t *pdcch_symbols[MAX_PORTS_CTRL];
cf_t *pdcch_x[MAX_PORTS_CTRL];
cf_t *pdcch_d;
char *pdcch_e;
float *pdcch_llr;
/* tx & rx objects */
modem_table_t mod;
demod_soft_t demod;
sequence_t seq_pdcch[NSUBFRAMES_X_FRAME];
viterbi_t decoder;
crc_t crc;
}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);
@ -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],
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,
int nsubframe, float ebno);
int nsubframe, float ebno);
LIBLTE_API void pdcch_init_search_si(pdcch_t *q);
LIBLTE_API void pdcch_set_search_si(pdcch_t *q);

@ -40,52 +40,52 @@
typedef _Complex float cf_t;
#define PHICH_NORM_NSEQUENCES 8
#define PHICH_EXT_NSEQUENCES 4
#define PHICH_MAX_SEQUENCES PHICH_NORM_NSEQUENCES
#define PHICH_NBITS 3
#define PHICH_NORM_MSYMB PHICH_NBITS * 4
#define PHICH_EXT_MSYMB PHICH_NBITS * 2
#define PHICH_MAX_NSYMB PHICH_NORM_MSYMB
#define PHICH_NORM_C 1
#define PHICH_EXT_C 2
#define PHICH_NORM_NSF 4
#define PHICH_EXT_NSF 2
#define PHICH_NORM_NSEQUENCES 8
#define PHICH_EXT_NSEQUENCES 4
#define PHICH_MAX_SEQUENCES PHICH_NORM_NSEQUENCES
#define PHICH_NBITS 3
#define PHICH_NORM_MSYMB PHICH_NBITS * 4
#define PHICH_EXT_MSYMB PHICH_NBITS * 2
#define PHICH_MAX_NSYMB PHICH_NORM_MSYMB
#define PHICH_NORM_C 1
#define PHICH_EXT_C 2
#define PHICH_NORM_NSF 4
#define PHICH_EXT_NSF 2
/* phich object */
typedef struct LIBLTE_API {
lte_cp_t cp;
int nof_prb;
int nof_tx_ports;
lte_cp_t cp;
int nof_prb;
int nof_tx_ports;
/* handler to REGs resource mapper */
regs_t *regs;
/* handler to REGs resource mapper */
regs_t *regs;
/* buffers */
cf_t ce[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_d[PHICH_MAX_NSYMB];
cf_t phich_d0[PHICH_MAX_NSYMB];
cf_t phich_z[PHICH_NBITS];
/* buffers */
cf_t ce[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_d[PHICH_MAX_NSYMB];
cf_t phich_d0[PHICH_MAX_NSYMB];
cf_t phich_z[PHICH_NBITS];
/* bit message */
char data[PHICH_NBITS];
/* bit message */
char data[PHICH_NBITS];
/* tx & rx objects */
modem_table_t mod;
demod_hard_t demod;
sequence_t seq_phich[NSUBFRAMES_X_FRAME];
/* tx & rx objects */
modem_table_t mod;
demod_hard_t demod;
sequence_t seq_phich[NSUBFRAMES_X_FRAME];
}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 void phich_free(phich_t *q);
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,
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]);

@ -38,86 +38,86 @@
*/
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;
typedef struct LIBLTE_API {
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.
uint8_t tbs_idx;
uint8_t mcs_idx;
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.
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.
uint8_t tbs_idx;
uint8_t mcs_idx;
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.
}ra_mcs_t;
typedef enum {
alloc_type0 = 0, alloc_type1 = 1, alloc_type2 = 2
alloc_type0 = 0, alloc_type1 = 1, alloc_type2 = 2
}ra_type_t;
typedef struct LIBLTE_API {
uint32_t rbg_bitmask;
uint32_t rbg_bitmask;
}ra_type0_t;
typedef struct LIBLTE_API {
uint32_t vrb_bitmask;
uint8_t rbg_subset;
bool shift;
uint32_t vrb_bitmask;
uint8_t rbg_subset;
bool shift;
}ra_type1_t;
typedef struct LIBLTE_API {
uint32_t riv; // if L_crb==0, DCI message packer will take this value directly
uint16_t L_crb;
uint16_t RB_start;
enum {nprb1a_2 = 0, nprb1a_3 = 1} n_prb1a;
enum {t2_ng1 = 0, t2_ng2 = 1} n_gap;
enum {t2_loc = 0, t2_dist = 1} mode;
uint32_t riv; // if L_crb==0, DCI message packer will take this value directly
uint16_t L_crb;
uint16_t RB_start;
enum {nprb1a_2 = 0, nprb1a_3 = 1} n_prb1a;
enum {t2_ng1 = 0, t2_ng2 = 1} n_gap;
enum {t2_loc = 0, t2_dist = 1} mode;
}ra_type2_t;
typedef struct LIBLTE_API {
unsigned short rnti;
ra_type_t alloc_type;
union {
ra_type0_t type0_alloc;
ra_type1_t type1_alloc;
ra_type2_t type2_alloc;
};
ra_mcs_t mcs;
uint8_t harq_process;
uint8_t rv_idx;
bool ndi;
unsigned short rnti;
ra_type_t alloc_type;
union {
ra_type0_t type0_alloc;
ra_type1_t type1_alloc;
ra_type2_t type2_alloc;
};
ra_mcs_t mcs;
uint8_t harq_process;
uint8_t rv_idx;
bool ndi;
} ra_pdsch_t;
typedef struct LIBLTE_API {
/* 36.213 Table 8.4-2: hop_half is 0 for < 10 Mhz and 10 for > 10 Mh.
* hop_quart is 00 for > 10 Mhz and hop_quart_neg is 01 for > 10 Mhz.
*/
enum {
hop_disabled = -1,
hop_quart = 0,
hop_quart_neg = 1,
hop_half = 2,
hop_type_2 = 3
} freq_hop_fl;
ra_type2_t type2_alloc;
ra_mcs_t mcs;
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).
bool ndi;
bool cqi_request;
/* 36.213 Table 8.4-2: hop_half is 0 for < 10 Mhz and 10 for > 10 Mh.
* hop_quart is 00 for > 10 Mhz and hop_quart_neg is 01 for > 10 Mhz.
*/
enum {
hop_disabled = -1,
hop_quart = 0,
hop_quart_neg = 1,
hop_half = 2,
hop_type_2 = 3
} freq_hop_fl;
ra_type2_t type2_alloc;
ra_mcs_t mcs;
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).
bool ndi;
bool cqi_request;
} ra_pusch_t;
typedef struct LIBLTE_API {
uint8_t prb_idx[110];
int nof_prb;
uint8_t prb_idx[110];
int nof_prb;
}ra_prb_slot_t;
typedef struct LIBLTE_API {
ra_prb_slot_t slot1;
ra_prb_slot_t slot2;
bool is_dist;
ra_prb_slot_t slot1;
ra_prb_slot_t slot2;
bool is_dist;
}ra_prb_t;

@ -33,49 +33,49 @@
#include "lte/config.h"
#include "lte/common/base.h"
#define REGS_PHICH_NSYM 12
#define REGS_PHICH_REGS_X_GROUP 3
#define REGS_PHICH_NSYM 12
#define REGS_PHICH_REGS_X_GROUP 3
#define REGS_PCFICH_NSYM 16
#define REGS_PCFICH_NREGS 4
#define REGS_PCFICH_NSYM 16
#define REGS_PCFICH_NREGS 4
#define REGS_RE_X_REG 4
#define REGS_RE_X_REG 4
typedef _Complex float cf_t;
typedef struct LIBLTE_API {
int k[4];
int k0;
int l;
bool assigned;
int k[4];
int k0;
int l;
bool assigned;
}regs_reg_t;
typedef struct LIBLTE_API {
int nof_regs;
regs_reg_t **regs;
int nof_regs;
regs_reg_t **regs;
}regs_ch_t;
typedef struct LIBLTE_API {
int cell_id;
int nof_prb;
int max_ctrl_symbols;
int cfi;
int ngroups_phich;
int nof_ports;
lte_cp_t cp;
phich_resources_t phich_res;
phich_length_t phich_len;
regs_ch_t pcfich;
regs_ch_t *phich; // there are several phich
regs_ch_t pdcch[3]; /* PDCCH indexing, permutation and interleaving is computed for
the three possible CFI value */
int nof_regs;
regs_reg_t *regs;
int cell_id;
int nof_prb;
int max_ctrl_symbols;
int cfi;
int ngroups_phich;
int nof_ports;
lte_cp_t cp;
phich_resources_t phich_res;
phich_length_t phich_len;
regs_ch_t pcfich;
regs_ch_t *phich; // there are several phich
regs_ch_t pdcch[3]; /* PDCCH indexing, permutation and interleaving is computed for
the three possible CFI value */
int nof_regs;
regs_reg_t *regs;
}regs_t;
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 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 */
/* channel integer values */
#define SCRAMBLING_PDSCH 0 /* also PUSCH */
#define SCRAMBLING_PCFICH 1
#define SCRAMBLING_PDCCH 2
#define SCRAMBLING_PBCH 3
#define SCRAMBLING_PMCH 4
#define SCRAMBLING_PUCCH 5
#define SCRAMBLING_PDSCH 0 /* also PUSCH */
#define SCRAMBLING_PCFICH 1
#define SCRAMBLING_PDCCH 2
#define SCRAMBLING_PBCH 3
#define SCRAMBLING_PMCH 4
#define SCRAMBLING_PUCCH 5
typedef struct LIBLTE_API {
sequence_t seq[NSUBFRAMES_X_FRAME];
sequence_t seq[NSUBFRAMES_X_FRAME];
}scrambling_t;
typedef struct LIBLTE_API {
scrambling_t obj;
struct scrambling_init {
int hard;
int q;
int cell_id;
int nrnti;
int nMBSFN;
int channel;
int nof_symbols; // 7 normal 6 extended
} init;
void *input; // input type may be char or float depending on hard
int in_len;
struct scrambling_ctrl_in {
int subframe;
} ctrl_in;
void *output;
int out_len;
scrambling_t obj;
struct scrambling_init {
int hard;
int q;
int cell_id;
int nrnti;
int nMBSFN;
int channel;
int nof_symbols; // 7 normal 6 extended
} init;
void *input; // input type may be char or float depending on hard
int in_len;
struct scrambling_ctrl_in {
int subframe;
} ctrl_in;
void *output;
int out_len;
}scrambling_hl;
#endif // SCRAMBLING_

@ -41,11 +41,11 @@ typedef _Complex float cf_t;
#define CFO_CEXPTAB_SIZE 4096
typedef struct LIBLTE_API {
float last_freq;
float tol;
int nsamples;
cexptab_t tab;
cf_t *cur_cexp;
float last_freq;
float tol;
int nsamples;
cexptab_t tab;
cf_t *cur_cexp;
}cfo_t;
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 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 62
#define PSS_RE 6*12
#define PSS_LEN_FREQ 129 // FFT-based convolution removes 1 leaving it in 128
#define PSS_LEN 62
#define PSS_RE 6*12
@ -64,25 +64,25 @@ typedef _Complex float cf_t; /* this is only a shortcut */
typedef struct LIBLTE_API {
#ifdef CONVOLUTION_FFT
conv_fft_cc_t conv_fft;
conv_fft_cc_t conv_fft;
#endif
int frame_size;
int N_id_2;
float current_cfo;
bool cfo_auto; // default true
int nof_nosync_frames;
int nosync_timeout_frames; // default 5
float correlation_threshold; // default 10000
int frame_start_idx;
int fb_wp;
cf_t *pss_signal_freq;
cf_t *tmp_input;
float *conv_abs;
cf_t *frame_buffer;
cf_t *conv_output;
cf_t *tmp_nco;
int frame_size;
int N_id_2;
float current_cfo;
bool cfo_auto; // default true
int nof_nosync_frames;
int nosync_timeout_frames; // default 5
float correlation_threshold; // default 10000
int frame_start_idx;
int fb_wp;
cf_t *pss_signal_freq;
cf_t *tmp_input;
float *conv_abs;
cf_t *frame_buffer;
cf_t *conv_output;
cf_t *tmp_nco;
}pss_synch_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 */
typedef struct LIBLTE_API {
pss_synch_t obj;
struct pss_synch_init {
int frame_size; // if 0, 2048
int unsync_nof_pkts;
int N_id_2;
int do_cfo;
} init;
cf_t *input;
int in_len;
struct pss_synch_ctrl_in {
int correlation_threshold;
float manual_cfo;
} ctrl_in;
cf_t *output;
int out_len;
pss_synch_t obj;
struct pss_synch_init {
int frame_size; // if 0, 2048
int unsync_nof_pkts;
int N_id_2;
int do_cfo;
} init;
cf_t *input;
int in_len;
struct pss_synch_ctrl_in {
int correlation_threshold;
float manual_cfo;
} ctrl_in;
cf_t *output;
int out_len;
}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_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
*/
#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 N_SSS 31
#define SSS_LEN 2*N_SSS
#define N_SSS 31
#define SSS_LEN 2*N_SSS
struct sss_tables{
int z1[N_SSS][N_SSS];
int c[2][N_SSS];
int s[N_SSS][N_SSS];
int N_id_2;
int z1[N_SSS][N_SSS];
int c[2][N_SSS];
int s[N_SSS][N_SSS];
int N_id_2;
};
/* Allocate 32 complex to make it multiple of 32-byte AVX instructions alignment requirement.
* Should use vect_malloc() to make it platform agnostic.
*/
struct fc_tables{
cf_t z1[N_SSS+1][N_SSS+1];
cf_t c[2][N_SSS+1];
cf_t s[N_SSS+1][N_SSS+1];
cf_t z1[N_SSS+1][N_SSS+1];
cf_t c[2][N_SSS+1];
cf_t s[N_SSS+1][N_SSS+1];
};
/* Low-level API */
typedef struct LIBLTE_API {
dft_plan_t dftp_input;
dft_plan_t dftp_input;
float corr_peak_threshold;
int symbol_sz;
int subframe_sz;
float corr_peak_threshold;
int symbol_sz;
int subframe_sz;
int N_id_1_table[30][30];
struct fc_tables fc_tables;
int N_id_1_table[30][30];
struct fc_tables fc_tables;
}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 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_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 */
typedef struct LIBLTE_API {
sss_synch_t obj;
struct sss_synch_init {
int N_id_2;
} init;
cf_t *input;
int in_len;
struct sss_synch_ctrl_in {
int symbol_sz;
int subframe_sz;
int correlation_threshold;
} ctrl_in;
struct sss_synch_ctrl_out {
int subframe_idx;
int N_id_1;
} ctrl_out;
sss_synch_t obj;
struct sss_synch_init {
int N_id_2;
} init;
cf_t *input;
int in_len;
struct sss_synch_ctrl_in {
int symbol_sz;
int subframe_sz;
int correlation_threshold;
} ctrl_in;
struct sss_synch_ctrl_out {
int subframe_idx;
int N_id_1;
} ctrl_out;
}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_work(sss_synch_hl* hl);

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

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

@ -33,16 +33,16 @@
#include "lte/utils/dft.h"
typedef struct LIBLTE_API {
_Complex float *input_fft;
_Complex float *filter_fft;
_Complex float *output_fft;
_Complex float *output_fft2;
int input_len;
int filter_len;
int output_len;
dft_plan_t input_plan;
dft_plan_t filter_plan;
dft_plan_t output_plan;
_Complex float *input_fft;
_Complex float *filter_fft;
_Complex float *output_fft;
_Complex float *output_fft2;
int input_len;
int filter_len;
int output_len;
dft_plan_t input_plan;
dft_plan_t filter_plan;
dft_plan_t output_plan;
}conv_fft_cc_t;
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 "lte/config.h"
#define VERBOSE_DEBUG 2
#define VERBOSE_INFO 1
#define VERBOSE_NONE 0
#define VERBOSE_DEBUG 2
#define VERBOSE_INFO 1
#define VERBOSE_NONE 0
#include <sys/time.h>
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 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) \
fprintf(stdout, "[INFO]: " _fmt, __VA_ARGS__)
fprintf(stdout, "[INFO]: " _fmt, __VA_ARGS__)
#else // DEBUG_DISABLED

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

@ -31,10 +31,10 @@
#include "lte/config.h"
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,
int *output_padding_pre, int *output_padding_post, int nof_outputs,
int sample_sz);
int *output_padding_pre, int *output_padding_post, int nof_outputs,
int sample_sz);
#endif // MUX_

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

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

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

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

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

@ -35,243 +35,243 @@
#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,
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,
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,
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,
1120, 1152, 1184, 1216, 1248, 1280, 1312, 1344, 1376, 1408, 1440, 1472,
1504, 1536, 1568, 1600, 1632, 1664, 1696, 1728, 1760, 1792, 1824, 1856,
1888, 1920, 1952, 1984, 2016, 2048, 2112, 2176, 2240, 2304, 2368, 2432,
2496, 2560, 2624, 2688, 2752, 2816, 2880, 2944, 3008, 3072, 3136, 3200,
3264, 3328, 3392, 3456, 3520, 3584, 3648, 3712, 3776, 3840, 3904, 3968,
4032, 4096, 4160, 4224, 4288, 4352, 4416, 4480, 4544, 4608, 4672, 4736,
4800, 4864, 4928, 4992, 5056, 5120, 5184, 5248, 5312, 5376, 5440, 5504,
5568, 5632, 5696, 5760, 5824, 5888, 5952, 6016, 6080, 6144 };
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,
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,
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,
1120, 1152, 1184, 1216, 1248, 1280, 1312, 1344, 1376, 1408, 1440, 1472,
1504, 1536, 1568, 1600, 1632, 1664, 1696, 1728, 1760, 1792, 1824, 1856,
1888, 1920, 1952, 1984, 2016, 2048, 2112, 2176, 2240, 2304, 2368, 2432,
2496, 2560, 2624, 2688, 2752, 2816, 2880, 2944, 3008, 3072, 3136, 3200,
3264, 3328, 3392, 3456, 3520, 3584, 3648, 3712, 3776, 3840, 3904, 3968,
4032, 4096, 4160, 4224, 4288, 4352, 4416, 4480, 4544, 4608, 4672, 4736,
4800, 4864, 4928, 4992, 5056, 5120, 5184, 5248, 5312, 5376, 5440, 5504,
5568, 5632, 5696, 5760, 5824, 5888, 5952, 6016, 6080, 6144 };
int lte_cb_size(int index) {
if (index >= 0 && index < NOF_TC_CB_SIZES) {
return tc_cb_sizes[index];
} else {
return -1;
}
if (index >= 0 && index < NOF_TC_CB_SIZES) {
return tc_cb_sizes[index];
} else {
return -1;
}
}
int lte_find_cb_index(int long_cb) {
int j = 0;
while (j < NOF_TC_CB_SIZES && tc_cb_sizes[j] < long_cb) {
j++;
}
int j = 0;
while (j < NOF_TC_CB_SIZES && tc_cb_sizes[j] < long_cb) {
j++;
}
if (j == NOF_TC_CB_SIZES) {
return -1;
} else {
return j;
}
if (j == NOF_TC_CB_SIZES) {
return -1;
} else {
return j;
}
}
const int lte_symbol_sz(int nof_prb) {
if (nof_prb<=0) {
return -1;
}
if (nof_prb<=6) {
return 128;
} else if (nof_prb<=15) {
return 256;
} else if (nof_prb<=25) {
return 512;
} else if (nof_prb<=50) {
return 1024;
} else if (nof_prb<=75) {
return 1536;
} else if (nof_prb<=100) {
return 2048;
}
return -1;
if (nof_prb<=0) {
return -1;
}
if (nof_prb<=6) {
return 128;
} else if (nof_prb<=15) {
return 256;
} else if (nof_prb<=25) {
return 512;
} else if (nof_prb<=50) {
return 1024;
} else if (nof_prb<=75) {
return 1536;
} else if (nof_prb<=100) {
return 2048;
}
return -1;
}
int lte_voffset(int symbol_id, int cell_id, int nof_ports) {
if (nof_ports == 1 && symbol_id==0) {
return (cell_id+3) % 6;
} else {
return cell_id % 6;
}
if (nof_ports == 1 && symbol_id==0) {
return (cell_id+3) % 6;
} else {
return cell_id % 6;
}
}
/* Returns the number of available RE per PRB */
int lte_re_x_prb(int ns, int symbol, int nof_ports, int nof_symbols) {
if (symbol == 0) {
if (((ns % 2) == 0) || (ns == 1)) {
return RE_X_RB - 4;
} else {
if (nof_ports == 1) {
return RE_X_RB - 2;
} else {
return RE_X_RB - 4;
}
}
} else if (symbol == 1) {
if (ns == 1) {
return RE_X_RB - 4;
} else if (nof_ports == 4) {
return RE_X_RB - 4;
} else {
return RE_X_RB;
}
} else if (symbol == nof_symbols - 3) {
if (nof_ports == 1) {
return RE_X_RB - 2;
} else {
return RE_X_RB - 4;
}
} else {
return RE_X_RB;
}
if (symbol == 0) {
if (((ns % 2) == 0) || (ns == 1)) {
return RE_X_RB - 4;
} else {
if (nof_ports == 1) {
return RE_X_RB - 2;
} else {
return RE_X_RB - 4;
}
}
} else if (symbol == 1) {
if (ns == 1) {
return RE_X_RB - 4;
} else if (nof_ports == 4) {
return RE_X_RB - 4;
} else {
return RE_X_RB;
}
} else if (symbol == nof_symbols - 3) {
if (nof_ports == 1) {
return RE_X_RB - 2;
} else {
return RE_X_RB - 4;
}
} else {
return RE_X_RB;
}
}
struct lte_band {
int band;
float fd_low_mhz;
int earfcn_offset;
int earfcn_max;
enum band_geographical_area area;
int band;
float fd_low_mhz;
int earfcn_offset;
int earfcn_max;
enum band_geographical_area area;
};
struct lte_band lte_bands[NOF_LTE_BANDS] = {
{1, 2110, 0, 599, ALL},
{2, 1930, 600, 1199, NAR},
{3, 1805, 1200, 1949, ALL},
{4, 2110, 1950, 2399, NAR},
{5, 869, 2400, 2649, NAR},
{6, 875, 2650, 2749, APAC},
{7, 2620, 2750, 3449, EMEA},
{8, 925, 3450, 3799, ALL},
{9, 1844.9, 3800, 4149, APAC},
{10, 2110, 4150, 4749, NAR},
{11, 1475.9, 4750, 4949, JAPAN},
{12, 729, 5010, 5179, NAR},
{13, 746, 5180, 5279, NAR},
{14, 758, 5280, 5379, NAR},
{17, 734, 5730, 5849, NAR},
{18, 860, 5850, 5999, JAPAN},
{19, 875, 6000, 6149, JAPAN},
{20, 791, 6150, 6449, EMEA},
{21, 1495.9, 6450, 6599, JAPAN},
{22, 3500, 6600, 7399, NA},
{23, 2180, 7500, 7699, NAR},
{24, 1525, 7700, 8039, NAR},
{25, 1930, 8040, 8689, NAR},
{26, 859, 8690, 9039, NAR},
{27, 852, 9040, 9209, NAR},
{28, 758, 9210, 9659, APAC},
{29, 717, 9660, 9769, NAR},
{30, 2350, 9770, 9869, NAR},
{31, 462.5, 9870, 9919, CALA}
{1, 2110, 0, 599, ALL},
{2, 1930, 600, 1199, NAR},
{3, 1805, 1200, 1949, ALL},
{4, 2110, 1950, 2399, NAR},
{5, 869, 2400, 2649, NAR},
{6, 875, 2650, 2749, APAC},
{7, 2620, 2750, 3449, EMEA},
{8, 925, 3450, 3799, ALL},
{9, 1844.9, 3800, 4149, APAC},
{10, 2110, 4150, 4749, NAR},
{11, 1475.9, 4750, 4949, JAPAN},
{12, 729, 5010, 5179, NAR},
{13, 746, 5180, 5279, NAR},
{14, 758, 5280, 5379, NAR},
{17, 734, 5730, 5849, NAR},
{18, 860, 5850, 5999, JAPAN},
{19, 875, 6000, 6149, JAPAN},
{20, 791, 6150, 6449, EMEA},
{21, 1495.9, 6450, 6599, JAPAN},
{22, 3500, 6600, 7399, NA},
{23, 2180, 7500, 7699, NAR},
{24, 1525, 7700, 8039, NAR},
{25, 1930, 8040, 8689, NAR},
{26, 859, 8690, 9039, NAR},
{27, 852, 9040, 9209, NAR},
{28, 758, 9210, 9659, APAC},
{29, 717, 9660, 9769, NAR},
{30, 2350, 9770, 9869, NAR},
{31, 462.5, 9870, 9919, CALA}
};
#define EOF_BAND 9919
int lte_str2mimotype(char *mimo_type_str, lte_mimo_type_t *type) {
if (!strcmp(mimo_type_str, "single")) {
*type = SINGLE_ANTENNA;
} else if (!strcmp(mimo_type_str, "diversity")) {
*type = TX_DIVERSITY;
} else if (!strcmp(mimo_type_str, "multiplex")) {
*type = SPATIAL_MULTIPLEX;
} else {
return -1;
}
return 0;
if (!strcmp(mimo_type_str, "single")) {
*type = SINGLE_ANTENNA;
} else if (!strcmp(mimo_type_str, "diversity")) {
*type = TX_DIVERSITY;
} else if (!strcmp(mimo_type_str, "multiplex")) {
*type = SPATIAL_MULTIPLEX;
} else {
return -1;
}
return 0;
}
char *lte_mimotype2str(lte_mimo_type_t type) {
switch(type) {
case SINGLE_ANTENNA:
return "single";
case TX_DIVERSITY:
return "diversity";
case SPATIAL_MULTIPLEX:
return "multiplex";
}
return NULL;
switch(type) {
case SINGLE_ANTENNA:
return "single";
case TX_DIVERSITY:
return "diversity";
case SPATIAL_MULTIPLEX:
return "multiplex";
}
return NULL;
}
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) {
int i;
i=0;
while(i < NOF_LTE_BANDS && lte_bands[i].earfcn_offset<earfcn) {
i++;
}
if (i == NOF_LTE_BANDS) {
fprintf(stderr, "Error: EARFCN %d not found\n", earfcn);
return -1.0;
}
return get_fd(&lte_bands[i], earfcn);
int i;
i=0;
while(i < NOF_LTE_BANDS && lte_bands[i].earfcn_offset<earfcn) {
i++;
}
if (i == NOF_LTE_BANDS) {
fprintf(stderr, "Error: EARFCN %d not found\n", earfcn);
return -1.0;
}
return get_fd(&lte_bands[i], earfcn);
}
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 i, j;
int nof_earfcn;
i=0;
while(i < NOF_LTE_BANDS && lte_bands[i].band != band) {
i++;
}
if (i == NOF_LTE_BANDS) {
fprintf(stderr, "Error: Invalid band %d\n", band);
return -1;
}
if (end_earfcn == -1) {
end_earfcn = lte_bands[i].earfcn_max;
} else {
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);
return -1;
}
}
if (start_earfcn == -1) {
start_earfcn = lte_bands[i].earfcn_offset;
} else {
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);
return -1;
}
}
nof_earfcn = end_earfcn - start_earfcn;
int i, j;
int nof_earfcn;
i=0;
while(i < NOF_LTE_BANDS && lte_bands[i].band != band) {
i++;
}
if (i == NOF_LTE_BANDS) {
fprintf(stderr, "Error: Invalid band %d\n", band);
return -1;
}
if (end_earfcn == -1) {
end_earfcn = lte_bands[i].earfcn_max;
} else {
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);
return -1;
}
}
if (start_earfcn == -1) {
start_earfcn = lte_bands[i].earfcn_offset;
} else {
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);
return -1;
}
}
nof_earfcn = end_earfcn - start_earfcn;
if (nof_earfcn > max_elems) {
nof_earfcn = max_elems;
}
for (j=0;j<nof_earfcn;j++) {
earfcn[j].id = j + start_earfcn;
earfcn[j].fd = get_fd(&lte_bands[i], earfcn[j].id);
}
return j;
if (nof_earfcn > max_elems) {
nof_earfcn = max_elems;
}
for (j=0;j<nof_earfcn;j++) {
earfcn[j].id = j + start_earfcn;
earfcn[j].fd = get_fd(&lte_bands[i], earfcn[j].id);
}
return j;
}
int lte_band_get_fd_region(enum band_geographical_area region, lte_earfcn_t *earfcn, int max_elems) {
int i;
int n;
int nof_fd = 0;
for (i=0;i<NOF_LTE_BANDS && max_elems > 0;i++) {
if (lte_bands[i].area == region) {
n = lte_band_get_fd_band(i, &earfcn[nof_fd], -1, -1, max_elems);
if (n != -1) {
nof_fd += n;
max_elems -= n;
} else {
return -1;
}
}
}
return nof_fd;
int i;
int n;
int nof_fd = 0;
for (i=0;i<NOF_LTE_BANDS && max_elems > 0;i++) {
if (lte_bands[i].area == region) {
n = lte_band_get_fd_band(i, &earfcn[nof_fd], -1, -1, max_elems);
if (n != -1) {
nof_fd += n;
max_elems -= n;
} else {
return -1;
}
}
}
return nof_fd;
}

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

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

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

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

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

@ -38,28 +38,28 @@
#define RATE 3
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,
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, 1, 17, 9,
25, 5, 21, 13, 29, 3, 19, 11, 27, 7, 23, 15, 31 };
int rm_turbo_init(rm_turbo_t *q, int buffer_len) {
q->buffer_len = buffer_len;
q->buffer = malloc(buffer_len * sizeof(float));
if (!q->buffer) {
perror("malloc");
return -1;
}
q->d2_perm = malloc(buffer_len * sizeof(int) / 3 + 1);
if (!q->d2_perm) {
perror("malloc");
return -1;
}
return 0;
q->buffer_len = buffer_len;
q->buffer = malloc(buffer_len * sizeof(float));
if (!q->buffer) {
perror("malloc");
return -1;
}
q->d2_perm = malloc(buffer_len * sizeof(int) / 3 + 1);
if (!q->d2_perm) {
perror("malloc");
return -1;
}
return 0;
}
void rm_turbo_free(rm_turbo_t *q) {
if (q->buffer) {
free(q->buffer);
}
if (q->buffer) {
free(q->buffer);
}
}
/* 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) {
char *tmp = (char*) q->buffer;
int nrows, ndummy, K_p;
int i, j, k, s, kidx, N_cb, k0;
nrows = (int) (in_len / RATE - 1) / NCOLS + 1;
K_p = nrows * NCOLS;
if (3 * K_p > q->buffer_len) {
fprintf(stderr,
"Input too large. Max input length including dummy bits is %d\n",
q->buffer_len);
return -1;
}
ndummy = K_p - in_len / RATE;
if (ndummy < 0) {
ndummy = 0;
}
/* Sub-block interleaver (5.1.4.1.1) and bit collection */
k = 0;
for (s = 0; s < 2; s++) {
for (j = 0; j < NCOLS; j++) {
for (i = 0; i < nrows; i++) {
if (s == 0) {
kidx = k%K_p;
} else {
kidx = K_p + 2 * (k%K_p);
}
if (i * NCOLS + RM_PERM_TC[j] < ndummy) {
tmp[kidx] = TX_NULL;
} else {
tmp[kidx] = input[(i * NCOLS + RM_PERM_TC[j] - ndummy) * 3 + s];
}
k++;
}
}
}
// d_k^(2) goes through special permutation
for (k = 0; k < K_p; k++) {
kidx = (RM_PERM_TC[k / nrows] + NCOLS * (k % nrows) + 1) % K_p;
if ((kidx - ndummy) < 0) {
tmp[K_p + 2 * k + 1] = TX_NULL;
} else {
tmp[K_p + 2 * k + 1] = input[3 * (kidx - ndummy) + 2];
}
}
/* Bit selection and transmission 5.1.4.1.2 */
N_cb = 3 * K_p; // TODO: Soft buffer size limitation
k0 = nrows * (2 * (int) ceilf((float) N_cb / (float) (8 * nrows))
* rv_idx + 2);
k = 0;
j = 0;
while (k < out_len) {
if (tmp[(k0 + j) % N_cb] != TX_NULL) {
output[k] = tmp[(k0 + j) % N_cb];
k++;
}
j++;
}
return 0;
char *tmp = (char*) q->buffer;
int nrows, ndummy, K_p;
int i, j, k, s, kidx, N_cb, k0;
nrows = (int) (in_len / RATE - 1) / NCOLS + 1;
K_p = nrows * NCOLS;
if (3 * K_p > q->buffer_len) {
fprintf(stderr,
"Input too large. Max input length including dummy bits is %d\n",
q->buffer_len);
return -1;
}
ndummy = K_p - in_len / RATE;
if (ndummy < 0) {
ndummy = 0;
}
/* Sub-block interleaver (5.1.4.1.1) and bit collection */
k = 0;
for (s = 0; s < 2; s++) {
for (j = 0; j < NCOLS; j++) {
for (i = 0; i < nrows; i++) {
if (s == 0) {
kidx = k%K_p;
} else {
kidx = K_p + 2 * (k%K_p);
}
if (i * NCOLS + RM_PERM_TC[j] < ndummy) {
tmp[kidx] = TX_NULL;
} else {
tmp[kidx] = input[(i * NCOLS + RM_PERM_TC[j] - ndummy) * 3 + s];
}
k++;
}
}
}
// d_k^(2) goes through special permutation
for (k = 0; k < K_p; k++) {
kidx = (RM_PERM_TC[k / nrows] + NCOLS * (k % nrows) + 1) % K_p;
if ((kidx - ndummy) < 0) {
tmp[K_p + 2 * k + 1] = TX_NULL;
} else {
tmp[K_p + 2 * k + 1] = input[3 * (kidx - ndummy) + 2];
}
}
/* Bit selection and transmission 5.1.4.1.2 */
N_cb = 3 * K_p; // TODO: Soft buffer size limitation
k0 = nrows * (2 * (int) ceilf((float) N_cb / (float) (8 * nrows))
* rv_idx + 2);
k = 0;
j = 0;
while (k < out_len) {
if (tmp[(k0 + j) % N_cb] != TX_NULL) {
output[k] = tmp[(k0 + j) % N_cb];
k++;
}
j++;
}
return 0;
}
/* 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 nrows, ndummy, K_p, k0, N_cb, jp, kidx;
int i, j, k;
int d_i, d_j;
bool isdummy;
float *tmp = (float*) q->buffer;
nrows = (int) (out_len / RATE - 1) / NCOLS + 1;
K_p = nrows * NCOLS;
if (3 * K_p > q->buffer_len) {
fprintf(stderr,
"Input too large. Max input length including dummy bits is %d\n",
q->buffer_len);
return -1;
}
ndummy = K_p - out_len / RATE;
if (ndummy < 0) {
ndummy = 0;
}
for (i = 0; i < RATE * K_p; i++) {
tmp[i] = RX_NULL;
}
/* Undo bit collection. Account for dummy bits */
N_cb = 3 * K_p; // TODO: Soft buffer size limitation
k0 = nrows * (2 * (int) ceilf((float) N_cb / (float) (8 * nrows))
* rv_idx + 2);
k = 0;
j = 0;
while (k < in_len) {
jp = (k0 + j) % N_cb;
if (jp == 32 || jp == 95 || jp == 0) {
i=0;
}
if (jp < K_p || !(jp%2)) {
if (jp >= K_p) {
d_i = ((jp-K_p) / 2) / nrows;
d_j = ((jp-K_p) / 2) % nrows;
} else {
d_i = jp / nrows;
d_j = jp % nrows;
}
if (d_j * NCOLS + RM_PERM_TC[d_i] >= ndummy) {
isdummy = false;
} else {
isdummy = true;
}
} else {
int jpp = (jp-K_p-1)/2;
kidx = (RM_PERM_TC[jpp / nrows] + NCOLS * (jpp % nrows) + 1) % K_p;
q->d2_perm[kidx] = jpp; // save the permutation in a temporary buffer
if ((kidx - ndummy) < 0) {
isdummy = true;
} else {
isdummy = false;
}
}
if (!isdummy) {
if (tmp[jp] == RX_NULL) {
tmp[jp] = input[k];
} else if (input[k] != RX_NULL) {
tmp[jp] += input[k]; /* soft combine LLRs */
}
k++;
}
j++;
}
/* interleaving and bit selection */
for (i = 0; i < out_len / RATE; i++) {
d_i = (i + ndummy) / NCOLS;
d_j = (i + ndummy) % NCOLS;
for (j = 0; j < RATE; j++) {
if (j != 2) {
kidx = K_p * j + (j+1)*(RM_PERM_TC[d_j] * nrows + d_i);
} else {
// use the saved permuatation function to avoid computing the inverse
kidx = 2*q->d2_perm[(i+ndummy)%K_p]+K_p+1;
}
float o = tmp[kidx];
if (o != RX_NULL) {
output[i * RATE + j] = o;
} else {
output[i * RATE + j] = 0;
}
}
}
return 0;
int nrows, ndummy, K_p, k0, N_cb, jp, kidx;
int i, j, k;
int d_i, d_j;
bool isdummy;
float *tmp = (float*) q->buffer;
nrows = (int) (out_len / RATE - 1) / NCOLS + 1;
K_p = nrows * NCOLS;
if (3 * K_p > q->buffer_len) {
fprintf(stderr,
"Input too large. Max input length including dummy bits is %d\n",
q->buffer_len);
return -1;
}
ndummy = K_p - out_len / RATE;
if (ndummy < 0) {
ndummy = 0;
}
for (i = 0; i < RATE * K_p; i++) {
tmp[i] = RX_NULL;
}
/* Undo bit collection. Account for dummy bits */
N_cb = 3 * K_p; // TODO: Soft buffer size limitation
k0 = nrows * (2 * (int) ceilf((float) N_cb / (float) (8 * nrows))
* rv_idx + 2);
k = 0;
j = 0;
while (k < in_len) {
jp = (k0 + j) % N_cb;
if (jp == 32 || jp == 95 || jp == 0) {
i=0;
}
if (jp < K_p || !(jp%2)) {
if (jp >= K_p) {
d_i = ((jp-K_p) / 2) / nrows;
d_j = ((jp-K_p) / 2) % nrows;
} else {
d_i = jp / nrows;
d_j = jp % nrows;
}
if (d_j * NCOLS + RM_PERM_TC[d_i] >= ndummy) {
isdummy = false;
} else {
isdummy = true;
}
} else {
int jpp = (jp-K_p-1)/2;
kidx = (RM_PERM_TC[jpp / nrows] + NCOLS * (jpp % nrows) + 1) % K_p;
q->d2_perm[kidx] = jpp; // save the permutation in a temporary buffer
if ((kidx - ndummy) < 0) {
isdummy = true;
} else {
isdummy = false;
}
}
if (!isdummy) {
if (tmp[jp] == RX_NULL) {
tmp[jp] = input[k];
} else if (input[k] != RX_NULL) {
tmp[jp] += input[k]; /* soft combine LLRs */
}
k++;
}
j++;
}
/* interleaving and bit selection */
for (i = 0; i < out_len / RATE; i++) {
d_i = (i + ndummy) / NCOLS;
d_j = (i + ndummy) % NCOLS;
for (j = 0; j < RATE; j++) {
if (j != 2) {
kidx = K_p * j + (j+1)*(RM_PERM_TC[d_j] * nrows + d_i);
} else {
// use the saved permuatation function to avoid computing the inverse
kidx = 2*q->d2_perm[(i+ndummy)%K_p]+K_p+1;
}
float o = tmp[kidx];
if (o != RX_NULL) {
output[i * RATE + j] = o;
} else {
output[i * RATE + j] = 0;
}
}
}
return 0;
}
/** High-level API */
int rm_turbo_initialize(rm_turbo_hl* h) {
return rm_turbo_init(&h->q, 7000);
return rm_turbo_init(&h->q, 7000);
}
/** This function can be called in a subframe (1ms) basis */
int rm_turbo_work(rm_turbo_hl* hl) {
if (hl->init.direction) {
rm_turbo_tx(&hl->q, hl->input, hl->in_len, hl->output, hl->ctrl_in.E, hl->ctrl_in.rv_idx);
hl->out_len = hl->ctrl_in.E;
} else {
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;
}
return 0;
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);
hl->out_len = hl->ctrl_in.E;
} else {
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;
}
return 0;
}
int rm_turbo_stop(rm_turbo_hl* hl) {
rm_turbo_free(&hl->q);
return 0;
rm_turbo_free(&hl->q);
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,
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,
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,
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,
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,
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,
45, 45, 161, 89, 323, 47, 23, 47, 263 };
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
158, 80, 96, 902, 166, 336, 170, 86, 174, 176, 178, 120, 182, 184, 186,
94, 190, 480 };
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,
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,
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,
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,
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,
158, 80, 96, 902, 166, 336, 170, 86, 174, 176, 178, 120, 182, 184, 186,
94, 190, 480 };
int tc_interl_LTE_init(tc_interl_t *h, int long_cb) {
int cb_table_idx, f1, f2;
unsigned long long i, j;
cb_table_idx = lte_find_cb_index(long_cb);
if (cb_table_idx == -1) {
fprintf(stderr, "Can't find long_cb=%d in valid TC CB table\n", long_cb);
return -1;
}
h->forward = h->reverse = NULL;
h->forward = malloc(sizeof(int) * (long_cb));
if (!h->forward) {
return -1;
}
h->reverse = malloc(sizeof(int) * (long_cb));
if (!h->reverse) {
perror("malloc");
free(h->forward);
h->forward = h->reverse = NULL;
return -1;
}
f1 = f1_list[cb_table_idx];
f2 = f2_list[cb_table_idx];
DEBUG("table_idx: %d, f1: %d, f2: %d\n", cb_table_idx, f1, f2);
h->forward[0] = 0;
h->reverse[0] = 0;
for (i = 1; i < long_cb; i++) {
j = (f1*i + f2*i*i) % (long_cb);
h->forward[i] = j;
h->reverse[j] = i;
}
return 0;
int cb_table_idx, f1, f2;
unsigned long long i, j;
cb_table_idx = lte_find_cb_index(long_cb);
if (cb_table_idx == -1) {
fprintf(stderr, "Can't find long_cb=%d in valid TC CB table\n", long_cb);
return -1;
}
h->forward = h->reverse = NULL;
h->forward = malloc(sizeof(int) * (long_cb));
if (!h->forward) {
return -1;
}
h->reverse = malloc(sizeof(int) * (long_cb));
if (!h->reverse) {
perror("malloc");
free(h->forward);
h->forward = h->reverse = NULL;
return -1;
}
f1 = f1_list[cb_table_idx];
f2 = f2_list[cb_table_idx];
DEBUG("table_idx: %d, f1: %d, f2: %d\n", cb_table_idx, f1, f2);
h->forward[0] = 0;
h->reverse[0] = 0;
for (i = 1; i < long_cb; i++) {
j = (f1*i + f2*i*i) % (long_cb);
h->forward[i] = j;
h->reverse[j] = i;
}
return 0;
}

@ -31,7 +31,7 @@
#include "lte/fec/tc_interl.h"
#include "lte/fec/turbocoder.h"
#define TURBO_RATE 3
#define TURBO_RATE 3
int mcd(int x, int y);
@ -41,217 +41,217 @@ int mcd(int x, int y);
*
************************************************/
#define MAX_ROWS 20
#define MAX_COLS 256
#define MAX_ROWS 20
#define MAX_COLS 256
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,
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 };
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,
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,
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 };
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 };
void tc_interl_free(tc_interl_t *h) {
if (h->forward) {
free(h->forward);
}
if (h->reverse) {
free(h->reverse);
}
h->forward = h->reverse = NULL;
if (h->forward) {
free(h->forward);
}
if (h->reverse) {
free(h->reverse);
}
h->forward = h->reverse = NULL;
}
int tc_interl_UMTS_init(tc_interl_t *h, int long_cb) {
int i, j;
int res, prim, aux;
int kp, k;
int *per, *desper;
unsigned char v;
unsigned short p;
unsigned short s[MAX_COLS], q[MAX_ROWS], r[MAX_ROWS], T[MAX_ROWS];
unsigned short U[MAX_COLS * MAX_ROWS];
int M_Rows, M_Cols, M_long;
int i, j;
int res, prim, aux;
int kp, k;
int *per, *desper;
unsigned char v;
unsigned short p;
unsigned short s[MAX_COLS], q[MAX_ROWS], r[MAX_ROWS], T[MAX_ROWS];
unsigned short U[MAX_COLS * MAX_ROWS];
int M_Rows, M_Cols, M_long;
h->forward = h->reverse = NULL;
h->forward = malloc(sizeof(int) * (long_cb));
if (!h->forward) {
return -1;
}
h->reverse = malloc(sizeof(int) * (long_cb));
if (!h->reverse) {
perror("malloc");
free(h->forward);
h->forward = h->reverse = NULL;
return -1;
}
M_long = long_cb;
h->forward = h->reverse = NULL;
h->forward = malloc(sizeof(int) * (long_cb));
if (!h->forward) {
return -1;
}
h->reverse = malloc(sizeof(int) * (long_cb));
if (!h->reverse) {
perror("malloc");
free(h->forward);
h->forward = h->reverse = NULL;
return -1;
}
M_long = long_cb;
/* Find R*/
if ((40 <= M_long) && (M_long <= 159))
M_Rows = 5;
else if (((160 <= M_long) && (M_long <= 200))
|| ((481 <= M_long) && (M_long <= 530)))
M_Rows = 10;
else
M_Rows = 20;
/* Find R*/
if ((40 <= M_long) && (M_long <= 159))
M_Rows = 5;
else if (((160 <= M_long) && (M_long <= 200))
|| ((481 <= M_long) && (M_long <= 530)))
M_Rows = 10;
else
M_Rows = 20;
/* Find p i v*/
if ((481 <= M_long) && (M_long <= 530)) {
p = 53;
v = 2;
M_Cols = p;
} else {
i = 0;
do {
p = table_p[i];
v = table_v[i];
i++;
} while (M_long > (M_Rows * (p + 1)));
/* Find p i v*/
if ((481 <= M_long) && (M_long <= 530)) {
p = 53;
v = 2;
M_Cols = p;
} else {
i = 0;
do {
p = table_p[i];
v = table_v[i];
i++;
} while (M_long > (M_Rows * (p + 1)));
}
}
/* Find C*/
if ((M_long) <= (M_Rows) * ((p) - 1))
M_Cols = (p) - 1;
else if (((M_Rows) * (p - 1) < M_long) && (M_long <= (M_Rows) * (p)))
M_Cols = p;
else if ((M_Rows) * (p) < M_long)
M_Cols = (p) + 1;
/* Find C*/
if ((M_long) <= (M_Rows) * ((p) - 1))
M_Cols = (p) - 1;
else if (((M_Rows) * (p - 1) < M_long) && (M_long <= (M_Rows) * (p)))
M_Cols = p;
else if ((M_Rows) * (p) < M_long)
M_Cols = (p) + 1;
q[0] = 1;
prim = 6;
q[0] = 1;
prim = 6;
for (i = 1; i < M_Rows; i++) {
do {
prim++;
res = mcd(prim, p - 1);
} while (res != 1);
q[i] = prim;
}
for (i = 1; i < M_Rows; i++) {
do {
prim++;
res = mcd(prim, p - 1);
} while (res != 1);
q[i] = prim;
}
s[0] = 1;
for (i = 1; i < p - 1; i++) {
s[i] = (v * s[i - 1]) % p;
}
s[0] = 1;
for (i = 1; i < p - 1; i++) {
s[i] = (v * s[i - 1]) % p;
}
if (M_long <= 159 && M_long >= 40) {
T[0] = 4;
T[1] = 3;
T[2] = 2;
T[3] = 1;
T[4] = 0;
} else if ((M_long <= 200 && M_long >= 160)
|| (M_long <= 530 && M_long >= 481)) {
T[0] = 9;
T[1] = 8;
T[2] = 7;
T[3] = 6;
T[4] = 5;
T[5] = 4;
T[6] = 3;
T[7] = 2;
T[8] = 1;
T[9] = 0;
} else if ((M_long <= 2480 && M_long >= 2281)
|| (M_long <= 3210 && M_long >= 3161)) {
T[0] = 19;
T[1] = 9;
T[2] = 14;
T[3] = 4;
T[4] = 0;
T[5] = 2;
T[6] = 5;
T[7] = 7;
T[8] = 12;
T[9] = 18;
T[10] = 16;
T[11] = 13;
T[12] = 17;
T[13] = 15;
T[14] = 3;
T[15] = 1;
T[16] = 6;
T[17] = 11;
T[18] = 8;
T[19] = 10;
} else {
T[0] = 19;
T[1] = 9;
T[2] = 14;
T[3] = 4;
T[4] = 0;
T[5] = 2;
T[6] = 5;
T[7] = 7;
T[8] = 12;
T[9] = 18;
T[10] = 10;
T[11] = 8;
T[12] = 13;
T[13] = 17;
T[14] = 3;
T[15] = 1;
T[16] = 16;
T[17] = 6;
T[18] = 15;
T[19] = 11;
}
if (M_long <= 159 && M_long >= 40) {
T[0] = 4;
T[1] = 3;
T[2] = 2;
T[3] = 1;
T[4] = 0;
} else if ((M_long <= 200 && M_long >= 160)
|| (M_long <= 530 && M_long >= 481)) {
T[0] = 9;
T[1] = 8;
T[2] = 7;
T[3] = 6;
T[4] = 5;
T[5] = 4;
T[6] = 3;
T[7] = 2;
T[8] = 1;
T[9] = 0;
} else if ((M_long <= 2480 && M_long >= 2281)
|| (M_long <= 3210 && M_long >= 3161)) {
T[0] = 19;
T[1] = 9;
T[2] = 14;
T[3] = 4;
T[4] = 0;
T[5] = 2;
T[6] = 5;
T[7] = 7;
T[8] = 12;
T[9] = 18;
T[10] = 16;
T[11] = 13;
T[12] = 17;
T[13] = 15;
T[14] = 3;
T[15] = 1;
T[16] = 6;
T[17] = 11;
T[18] = 8;
T[19] = 10;
} else {
T[0] = 19;
T[1] = 9;
T[2] = 14;
T[3] = 4;
T[4] = 0;
T[5] = 2;
T[6] = 5;
T[7] = 7;
T[8] = 12;
T[9] = 18;
T[10] = 10;
T[11] = 8;
T[12] = 13;
T[13] = 17;
T[14] = 3;
T[15] = 1;
T[16] = 16;
T[17] = 6;
T[18] = 15;
T[19] = 11;
}
for (i = 0; i < M_Rows; i++) {
r[T[i]] = q[i];
}
for (i = 0; i < M_Rows; i++) {
r[T[i]] = q[i];
}
for (i = 0; i < M_Rows; i++) {
for (j = 0; j < p - 1; j++) {
U[i * M_Cols + j] = s[(j * r[i]) % (p - 1)];
if (M_Cols == (p - 1))
U[i * M_Cols + j] -= 1;
}
}
for (i = 0; i < M_Rows; i++) {
for (j = 0; j < p - 1; j++) {
U[i * M_Cols + j] = s[(j * r[i]) % (p - 1)];
if (M_Cols == (p - 1))
U[i * M_Cols + j] -= 1;
}
}
if (M_Cols == p) {
for (i = 0; i < M_Rows; i++)
U[i * M_Cols + p - 1] = 0;
} else if (M_Cols == p + 1) {
for (i = 0; i < M_Rows; i++) {
U[i * M_Cols + p - 1] = 0;
U[i * M_Cols + p] = p;
}
if (M_long == M_Cols * M_Rows) {
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 + 0] = aux;
}
}
if (M_Cols == p) {
for (i = 0; i < M_Rows; i++)
U[i * M_Cols + p - 1] = 0;
} else if (M_Cols == p + 1) {
for (i = 0; i < M_Rows; i++) {
U[i * M_Cols + p - 1] = 0;
U[i * M_Cols + p] = p;
}
if (M_long == M_Cols * M_Rows) {
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 + 0] = aux;
}
}
per = h->forward;
desper = h->reverse;
per = h->forward;
desper = h->reverse;
k = 0;
for (j = 0; j < M_Cols; j++) {
for (i = 0; i < M_Rows; i++) {
kp = T[i] * M_Cols + U[i * M_Cols + j];
if (kp < M_long) {
desper[kp] = k;
per[k] = kp;
k++;
}
}
}
k = 0;
for (j = 0; j < M_Cols; j++) {
for (i = 0; i < M_Rows; i++) {
kp = T[i] * M_Cols + U[i * M_Cols + j];
if (kp < M_long) {
desper[kp] = k;
per[k] = kp;
k++;
}
}
}
return 0;
return 0;
}
int mcd(int x, int y) {
int r = 1;
int r = 1;
while (r) {
r = x % y;
x = y;
y = r;
}
return x;
while (r) {
r = x % y;
x = y;
y = r;
}
return x;
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

@ -43,113 +43,113 @@
#define idx(a, b) ((a)*(q->szfreq)+b)
int filter2d_init(filter2d_t* q, float **taps, int ntime, int nfreq, int sztime,
int szfreq) {
int szfreq) {
int ret = -1;
bzero(q, sizeof(filter2d_t));
int ret = -1;
bzero(q, sizeof(filter2d_t));
if (matrix_init((void***)&q->taps, ntime, nfreq, sizeof(float))) {
goto free_and_exit;
}
if (matrix_init((void***)&q->taps, ntime, nfreq, sizeof(float))) {
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));
if (!q->output) {
goto free_and_exit;
}
q->output = vec_malloc((ntime+sztime)*(szfreq)*sizeof(cf_t));
if (!q->output) {
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->ntime = ntime;
q->szfreq = szfreq;
q->sztime = sztime;
q->nfreq = nfreq;
q->ntime = ntime;
q->szfreq = szfreq;
q->sztime = sztime;
ret = 0;
ret = 0;
free_and_exit: if (ret == -1) {
filter2d_free(q);
}
return ret;
free_and_exit: if (ret == -1) {
filter2d_free(q);
}
return ret;
}
void filter2d_free(filter2d_t *q) {
matrix_free((void**) q->taps, q->ntime);
if (q->output) {
free(q->output);
}
bzero(q, sizeof(filter2d_t));
matrix_free((void**) q->taps, q->ntime);
if (q->output) {
free(q->output);
}
bzero(q, sizeof(filter2d_t));
}
int filter2d_init_default(filter2d_t* q, int ntime, int nfreq, int sztime,
int szfreq) {
int szfreq) {
int i, j;
int ret = -1;
float **taps;
int i, j;
int ret = -1;
float **taps;
if (matrix_init((void***) &taps, ntime, nfreq, sizeof(float))) {
goto free_and_exit;
}
if (matrix_init((void***) &taps, ntime, nfreq, sizeof(float))) {
goto free_and_exit;
}
/* Compute the default 2-D interpolation mesh */
for (i = 0; i < ntime; i++) {
for (j = 0; j < nfreq; j++) {
if (j < nfreq / 2)
taps[i][j] = (j + 1.0) / (2.0 * intceil(nfreq, 2));
/* Compute the default 2-D interpolation mesh */
for (i = 0; i < ntime; i++) {
for (j = 0; j < nfreq; j++) {
if (j < nfreq / 2)
taps[i][j] = (j + 1.0) / (2.0 * intceil(nfreq, 2));
else if (j == nfreq / 2)
taps[i][j] = 0.5;
else if (j == nfreq / 2)
taps[i][j] = 0.5;
else if (j > nfreq / 2)
taps[i][j] = (nfreq - j) / (2.0 * intceil(nfreq, 2));
}
}
else if (j > nfreq / 2)
taps[i][j] = (nfreq - j) / (2.0 * intceil(nfreq, 2));
}
}
INFO("Using default interpolation matrix of size %dx%d\n", ntime, nfreq);
if (verbose >= VERBOSE_DEBUG) {
matrix_fprintf_f(stdout, taps, ntime, nfreq);
}
INFO("Using default interpolation matrix of size %dx%d\n", ntime, nfreq);
if (verbose >= VERBOSE_DEBUG) {
matrix_fprintf_f(stdout, taps, ntime, nfreq);
}
if (filter2d_init(q, taps, ntime, nfreq, sztime, szfreq)) {
goto free_and_exit;
}
if (filter2d_init(q, taps, ntime, nfreq, sztime, szfreq)) {
goto free_and_exit;
}
ret = 0;
ret = 0;
free_and_exit:
matrix_free((void**) taps, ntime);
return ret;
matrix_free((void**) taps, ntime);
return ret;
}
/* 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.
*/
void filter2d_reset(filter2d_t *q) {
int i;
for (i = 0; i < q->ntime; i++) {
memcpy(&q->output[idx(i,0)], &q->output[idx(q->sztime + i,0)],
sizeof(cf_t) * (q->szfreq));
}
for (; i < q->ntime + q->sztime; i++) {
memset(&q->output[idx(i,0)], 0, sizeof(cf_t) * (q->szfreq));
}
int i;
for (i = 0; i < q->ntime; i++) {
memcpy(&q->output[idx(i,0)], &q->output[idx(q->sztime + i,0)],
sizeof(cf_t) * (q->szfreq));
}
for (; i < q->ntime + q->sztime; i++) {
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
* and computes the output.
*/
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 nfreq = q->nfreq;
int ntime = q->ntime;
int nfreq = q->nfreq;
for (i = 0; i < ntime; i++) {
for (j = 0; j < nfreq; j++) {
q->output[idx(i+time_idx, j+freq_idx - nfreq/2)] += x * (cf_t)(q->taps[i][j]);
}
}
for (i = 0; i < ntime; i++) {
for (j = 0; j < nfreq; 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 */
static int gen_seq_buff(binsource_t* q, int nwords) {
if (q->seq_buff_nwords != nwords) {
free(q->seq_buff);
q->seq_buff_nwords = 0;
}
if (!q->seq_buff_nwords) {
q->seq_buff = malloc(nwords*sizeof(uint32_t));
if (!q->seq_buff) {
return -1;
}
q->seq_buff_nwords = nwords;
}
for (int i=0;i<q->seq_buff_nwords;i++) {
q->seq_buff[i] = rand_r(&q->seed);
}
return 0;
if (q->seq_buff_nwords != nwords) {
free(q->seq_buff);
q->seq_buff_nwords = 0;
}
if (!q->seq_buff_nwords) {
q->seq_buff = malloc(nwords*sizeof(uint32_t));
if (!q->seq_buff) {
return -1;
}
q->seq_buff_nwords = nwords;
}
for (int i=0;i<q->seq_buff_nwords;i++) {
q->seq_buff[i] = rand_r(&q->seed);
}
return 0;
}
/* Low-level API */
@ -61,62 +61,62 @@ static int gen_seq_buff(binsource_t* q, int nwords) {
* Initializes the binsource object.
*/
void binsource_init(binsource_t* q) {
bzero((void*) q,sizeof(binsource_t));
bzero((void*) q,sizeof(binsource_t));
}
/**
* Destroys binsource object
*/
void binsource_free(binsource_t* q) {
if (q->seq_buff) {
free(q->seq_buff);
}
bzero(q, sizeof(binsource_t));
if (q->seq_buff) {
free(q->seq_buff);
}
bzero(q, sizeof(binsource_t));
}
/**
* Sets a new seed
*/
void binsource_seed_set(binsource_t* q, unsigned int seed) {
q->seed = seed;
q->seed = seed;
}
/**
* Sets local time as seed.
*/
void binsource_seed_time(binsource_t *q) {
struct timeval t1;
gettimeofday(&t1, NULL);
q->seed = t1.tv_usec * t1.tv_sec;
struct timeval t1;
gettimeofday(&t1, NULL);
q->seed = t1.tv_usec * t1.tv_sec;
}
/**
* Generates a sequence of nbits random bits
*/
int binsource_cache_gen(binsource_t* q, int nbits) {
if (gen_seq_buff(q,DIV(nbits,32))) {
return -1;
}
q->seq_cache_nbits = nbits;
q->seq_cache_rp = 0;
return 0;
if (gen_seq_buff(q,DIV(nbits,32))) {
return -1;
}
q->seq_cache_nbits = nbits;
q->seq_cache_rp = 0;
return 0;
}
static int int_2_bits(uint32_t* src, char* dst, int nbits) {
int n;
n=nbits/32;
for (int i=0;i<n;i++) {
bit_pack(src[i],&dst,32);
}
bit_pack(src[n],&dst,nbits-n*32);
return n;
int n;
n=nbits/32;
for (int i=0;i<n;i++) {
bit_pack(src[i],&dst,32);
}
bit_pack(src[n],&dst,nbits-n*32);
return n;
}
/**
* 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) {
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) {
if (gen_seq_buff(q,DIV(nbits,32))) {
return -1;
}
int_2_bits(q->seq_buff,bits,nbits);
return 0;
if (gen_seq_buff(q,DIV(nbits,32))) {
return -1;
}
int_2_bits(q->seq_buff,bits,nbits);
return 0;
}
@ -139,42 +139,42 @@ int binsource_generate(binsource_t* q, char *bits, int nbits) {
/* High-Level API */
int binsource_initialize(binsource_hl* hl) {
binsource_init(&hl->obj);
if (hl->init.seed) {
binsource_seed_set(&hl->obj,hl->init.seed);
} else {
binsource_seed_time(&hl->obj);
}
binsource_init(&hl->obj);
if (hl->init.seed) {
binsource_seed_set(&hl->obj,hl->init.seed);
} else {
binsource_seed_time(&hl->obj);
}
if (hl->init.cache_seq_nbits) {
if (binsource_cache_gen(&hl->obj,hl->init.cache_seq_nbits)) {
return -1;
}
}
if (hl->init.cache_seq_nbits) {
if (binsource_cache_gen(&hl->obj,hl->init.cache_seq_nbits)) {
return -1;
}
}
return 0;
return 0;
}
int binsource_work(binsource_hl* hl) {
int ret = -1;
if (hl->init.cache_seq_nbits) {
binsource_cache_cpy(&hl->obj,hl->output,hl->ctrl_in.nbits);
ret = 0;
} else {
ret = binsource_generate(&hl->obj,hl->output,hl->ctrl_in.nbits);
}
if (!ret) {
hl->out_len = hl->ctrl_in.nbits;
} else {
hl->out_len = 0;
}
return ret;
int ret = -1;
if (hl->init.cache_seq_nbits) {
binsource_cache_cpy(&hl->obj,hl->output,hl->ctrl_in.nbits);
ret = 0;
} else {
ret = binsource_generate(&hl->obj,hl->output,hl->ctrl_in.nbits);
}
if (!ret) {
hl->out_len = hl->ctrl_in.nbits;
} else {
hl->out_len = 0;
}
return ret;
}
int binsource_stop(binsource_hl* hl) {
binsource_free(&hl->obj);
return 0;
binsource_free(&hl->obj);
return 0;
}

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

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

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

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

@ -36,41 +36,41 @@
int layermap_single(cf_t *d, cf_t *x, int nof_symbols) {
memcpy(x, d, sizeof(cf_t) * nof_symbols);
return nof_symbols;
memcpy(x, d, sizeof(cf_t) * nof_symbols);
return nof_symbols;
}
int layermap_diversity(cf_t *d, cf_t *x[MAX_LAYERS], int nof_layers, int nof_symbols) {
int i, j;
for (i=0;i<nof_symbols/nof_layers;i++) {
for (j=0;j<nof_layers;j++) {
x[j][i] = d[nof_layers*i+j];
}
}
return i;
int i, j;
for (i=0;i<nof_symbols/nof_layers;i++) {
for (j=0;j<nof_layers;j++) {
x[j][i] = d[nof_layers*i+j];
}
}
return i;
}
int layermap_multiplex(cf_t *d[MAX_CODEWORDS], cf_t *x[MAX_LAYERS], int nof_cw, int nof_layers,
int nof_symbols[MAX_CODEWORDS]) {
if (nof_cw == 1) {
return layermap_diversity(d[0], x, nof_layers, nof_symbols[0]);
} else {
int n[2];
n[0] = nof_layers / nof_cw;
n[1] = nof_layers - n[0];
if (nof_symbols[0] / n[0] == nof_symbols[1] / n[1]) {
layermap_diversity(d[0], x, n[0], nof_symbols[0]);
layermap_diversity(d[1], &x[n[0]], n[1], nof_symbols[1]);
return nof_symbols[0] / n[0];
} else {
fprintf(stderr, "Number of symbols in codewords 0 and 1 is not consistent (%d, %d)\n",
nof_symbols[0], nof_symbols[1]);
return -1;
}
}
return 0;
int nof_symbols[MAX_CODEWORDS]) {
if (nof_cw == 1) {
return layermap_diversity(d[0], x, nof_layers, nof_symbols[0]);
} else {
int n[2];
n[0] = nof_layers / nof_cw;
n[1] = nof_layers - n[0];
if (nof_symbols[0] / n[0] == nof_symbols[1] / n[1]) {
layermap_diversity(d[0], x, n[0], nof_symbols[0]);
layermap_diversity(d[1], &x[n[0]], n[1], nof_symbols[1]);
return nof_symbols[0] / n[0];
} else {
fprintf(stderr, "Number of symbols in codewords 0 and 1 is not consistent (%d, %d)\n",
nof_symbols[0], nof_symbols[1]);
return -1;
}
}
return 0;
}
/* 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)
*/
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) {
if (nof_cw > MAX_CODEWORDS) {
fprintf(stderr, "Maximum number of codewords is %d (nof_cw=%d)\n", MAX_CODEWORDS, nof_cw);
return -1;
}
if (nof_layers > MAX_LAYERS) {
fprintf(stderr, "Maximum number of layers is %d (nof_layers=%d)\n", MAX_LAYERS, nof_layers);
return -1;
}
if (nof_layers < nof_cw) {
fprintf(stderr, "Number of codewords must be lower or equal than number of layers\n");
return -1;
}
switch(type) {
case SINGLE_ANTENNA:
if (nof_cw == 1 && nof_layers == 1) {
return layermap_single(x[0], d[0], nof_symbols[0]);
} else {
fprintf(stderr, "Number of codewords and layers must be 1 for transmission on single antenna ports\n");
return -1;
}
break;
case TX_DIVERSITY:
if (nof_cw == 1) {
if (nof_layers == 2 || nof_layers == 4) {
return layermap_diversity(d[0], x, nof_layers, nof_symbols[0]);
} else {
fprintf(stderr, "Number of layers must be 2 or 4 for transmit diversity\n");
return -1;
}
} else {
fprintf(stderr, "Number of codewords must be 1 for transmit diversity\n");
return -1;
}
break;
case SPATIAL_MULTIPLEX:
return layermap_multiplex(d, x, nof_cw, nof_layers, nof_symbols);
break;
}
return 0;
int nof_symbols[MAX_CODEWORDS], lte_mimo_type_t type) {
if (nof_cw > MAX_CODEWORDS) {
fprintf(stderr, "Maximum number of codewords is %d (nof_cw=%d)\n", MAX_CODEWORDS, nof_cw);
return -1;
}
if (nof_layers > MAX_LAYERS) {
fprintf(stderr, "Maximum number of layers is %d (nof_layers=%d)\n", MAX_LAYERS, nof_layers);
return -1;
}
if (nof_layers < nof_cw) {
fprintf(stderr, "Number of codewords must be lower or equal than number of layers\n");
return -1;
}
switch(type) {
case SINGLE_ANTENNA:
if (nof_cw == 1 && nof_layers == 1) {
return layermap_single(x[0], d[0], nof_symbols[0]);
} else {
fprintf(stderr, "Number of codewords and layers must be 1 for transmission on single antenna ports\n");
return -1;
}
break;
case TX_DIVERSITY:
if (nof_cw == 1) {
if (nof_layers == 2 || nof_layers == 4) {
return layermap_diversity(d[0], x, nof_layers, nof_symbols[0]);
} else {
fprintf(stderr, "Number of layers must be 2 or 4 for transmit diversity\n");
return -1;
}
} else {
fprintf(stderr, "Number of codewords must be 1 for transmit diversity\n");
return -1;
}
break;
case SPATIAL_MULTIPLEX:
return layermap_multiplex(d, x, nof_cw, nof_layers, nof_symbols);
break;
}
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) {
memcpy(d, x, sizeof(cf_t) * nof_symbols);
return nof_symbols;
memcpy(d, x, sizeof(cf_t) * nof_symbols);
return nof_symbols;
}
int layerdemap_diversity(cf_t *x[MAX_LAYERS], cf_t *d, int nof_layers, int nof_layer_symbols) {
int i, j;
for (i=0;i<nof_layer_symbols;i++) {
for (j=0;j<nof_layers;j++) {
d[nof_layers*i+j] = x[j][i];
}
}
return nof_layer_symbols * nof_layers;
int i, j;
for (i=0;i<nof_layer_symbols;i++) {
for (j=0;j<nof_layers;j++) {
d[nof_layers*i+j] = x[j][i];
}
}
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 nof_layer_symbols, int nof_symbols[MAX_CODEWORDS]) {
if (nof_cw == 1) {
return layerdemap_diversity(x, d[0], nof_layers, nof_layer_symbols);
} else {
int n[2];
n[0] = nof_layers / nof_cw;
n[1] = nof_layers - n[0];
nof_symbols[0] = n[0] * 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[1] = layerdemap_diversity(&x[n[0]], d[1], n[1], nof_layer_symbols);
}
return 0;
int nof_layer_symbols, int nof_symbols[MAX_CODEWORDS]) {
if (nof_cw == 1) {
return layerdemap_diversity(x, d[0], nof_layers, nof_layer_symbols);
} else {
int n[2];
n[0] = nof_layers / nof_cw;
n[1] = nof_layers - n[0];
nof_symbols[0] = n[0] * 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[1] = layerdemap_diversity(&x[n[0]], d[1], n[1], nof_layer_symbols);
}
return 0;
}
/* 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
*/
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) {
if (nof_cw > MAX_CODEWORDS) {
fprintf(stderr, "Maximum number of codewords is %d (nof_cw=%d)\n", MAX_CODEWORDS, nof_cw);
return -1;
}
if (nof_layers > MAX_LAYERS) {
fprintf(stderr, "Maximum number of layers is %d (nof_layers=%d)\n", MAX_LAYERS, nof_layers);
return -1;
}
if (nof_layers < nof_cw) {
fprintf(stderr, "Number of codewords must be lower or equal than number of layers\n");
return -1;
}
switch(type) {
case SINGLE_ANTENNA:
if (nof_cw == 1 && nof_layers == 1) {
nof_symbols[0] = layerdemap_single(x[0], d[0], nof_layer_symbols);
nof_symbols[1] = 0;
} else {
fprintf(stderr, "Number of codewords and layers must be 1 for transmission on single antenna ports\n");
return -1;
}
break;
case TX_DIVERSITY:
if (nof_cw == 1) {
if (nof_layers == 2 || nof_layers == 4) {
nof_symbols[0] = layerdemap_diversity(x, d[0], nof_layers, nof_layer_symbols);
nof_symbols[1] = 0;
} else {
fprintf(stderr, "Number of layers must be 2 or 4 for transmit diversity\n");
return -1;
}
} else {
fprintf(stderr, "Number of codewords must be 1 for transmit diversity\n");
return -1;
}
break;
case SPATIAL_MULTIPLEX:
return layerdemap_multiplex(x, d, nof_layers, nof_cw, nof_layer_symbols, nof_symbols);
break;
}
return 0;
int nof_layer_symbols, int nof_symbols[MAX_CODEWORDS], lte_mimo_type_t type) {
if (nof_cw > MAX_CODEWORDS) {
fprintf(stderr, "Maximum number of codewords is %d (nof_cw=%d)\n", MAX_CODEWORDS, nof_cw);
return -1;
}
if (nof_layers > MAX_LAYERS) {
fprintf(stderr, "Maximum number of layers is %d (nof_layers=%d)\n", MAX_LAYERS, nof_layers);
return -1;
}
if (nof_layers < nof_cw) {
fprintf(stderr, "Number of codewords must be lower or equal than number of layers\n");
return -1;
}
switch(type) {
case SINGLE_ANTENNA:
if (nof_cw == 1 && nof_layers == 1) {
nof_symbols[0] = layerdemap_single(x[0], d[0], nof_layer_symbols);
nof_symbols[1] = 0;
} else {
fprintf(stderr, "Number of codewords and layers must be 1 for transmission on single antenna ports\n");
return -1;
}
break;
case TX_DIVERSITY:
if (nof_cw == 1) {
if (nof_layers == 2 || nof_layers == 4) {
nof_symbols[0] = layerdemap_diversity(x, d[0], nof_layers, nof_layer_symbols);
nof_symbols[1] = 0;
} else {
fprintf(stderr, "Number of layers must be 2 or 4 for transmit diversity\n");
return -1;
}
} else {
fprintf(stderr, "Number of codewords must be 1 for transmit diversity\n");
return -1;
}
break;
case SPATIAL_MULTIPLEX:
return layerdemap_multiplex(x, d, nof_layers, nof_cw, nof_layer_symbols, nof_symbols);
break;
}
return 0;
}

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

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

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

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

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

@ -48,23 +48,23 @@
*/
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 */
if (__real__ in[s] > 0) {
if ((__imag__ in[s] > 0) || (__real__ in[s] > -__imag__ in[s])) {
out[s] = 0x0;
} else {
out[s] = 0x1;
}
} else {
if ((__imag__ in[s] < 0) || (__imag__ in[s] < -__real__ in[s])) {
out[s] = 0x1;
} else {
out[s] = 0x0;
}
}
}
for (s=0; s<N; s++) { /* received symbols */
if (__real__ in[s] > 0) {
if ((__imag__ in[s] > 0) || (__real__ in[s] > -__imag__ in[s])) {
out[s] = 0x0;
} else {
out[s] = 0x1;
}
} else {
if ((__imag__ in[s] < 0) || (__imag__ in[s] < -__real__ in[s])) {
out[s] = 0x1;
} else {
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)
{
int s;
int s;
for (s=0; s<N; s++) {
if (__real__ in[s] > 0) {
out[2*s] = 0x0;
} else {
out[2*s] = 0x1;
}
if (__imag__ in[s] > 0) {
out[2*s+1] = 0x0;
} else {
out[2*s+1] = 0x1;
}
}
for (s=0; s<N; s++) {
if (__real__ in[s] > 0) {
out[2*s] = 0x0;
} else {
out[2*s] = 0x1;
}
if (__imag__ in[s] > 0) {
out[2*s+1] = 0x0;
} else {
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)
{
int s;
int s;
for (s=0; s<N; s++) {
if (__real__ in[s] > 0) {
out[4*s] = 0x0;
} else {
out[4*s] = 0x1;
}
for (s=0; s<N; s++) {
if (__real__ in[s] > 0) {
out[4*s] = 0x0;
} else {
out[4*s] = 0x1;
}
if ((__real__ in[s] > QAM16_THRESHOLD) || (__real__ in[s] < -QAM16_THRESHOLD)) {
out[4*s+2] = 0x1;
} else {
out[4*s+2] = 0x0;
}
if ((__real__ in[s] > QAM16_THRESHOLD) || (__real__ in[s] < -QAM16_THRESHOLD)) {
out[4*s+2] = 0x1;
} else {
out[4*s+2] = 0x0;
}
if (__imag__ in[s] > 0) {
out[4*s+1] = 0x0;
} else {
out[4*s+1] = 0x1;
}
if (__imag__ in[s] > 0) {
out[4*s+1] = 0x0;
} else {
out[4*s+1] = 0x1;
}
if ((__imag__ in[s] > QAM16_THRESHOLD) || (__imag__ in[s] < -QAM16_THRESHOLD)) {
out[4*s+3] = 0x1;
} else {
out[4*s+3] = 0x0;
}
}
if ((__imag__ in[s] > QAM16_THRESHOLD) || (__imag__ in[s] < -QAM16_THRESHOLD)) {
out[4*s+3] = 0x1;
} else {
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)
{
int s;
int s;
for (s=0; s<N; s++) {
/* bits associated with/obtained from in-phase component: b0, b2, b4 */
if (__real__ in[s] > 0){
out[6*s] = 0x0;
} else {
out[6*s] = 0x1;
}
if ((__real__ in[s] > QAM64_THRESHOLD_3) || (__real__ in[s] < -QAM64_THRESHOLD_3)) {
out[6*s+2] = 0x1;
out[6*s+4] = 0x1;
} else if ((__real__ in[s] > QAM64_THRESHOLD_2) || (__real__ in[s] < -QAM64_THRESHOLD_2)) {
out[6*s+2] = 0x1;
out[6*s+4] = 0x0;
} else if ((__real__ in[s] > QAM64_THRESHOLD_1) || (__real__ in[s] < -QAM64_THRESHOLD_1)) {
out[6*s+2] = 0x0;
out[6*s+4] = 0x0;
} else {
out[6*s+2] = 0x0;
out[6*s+4] = 0x1;
}
for (s=0; s<N; s++) {
/* bits associated with/obtained from in-phase component: b0, b2, b4 */
if (__real__ in[s] > 0){
out[6*s] = 0x0;
} else {
out[6*s] = 0x1;
}
if ((__real__ in[s] > QAM64_THRESHOLD_3) || (__real__ in[s] < -QAM64_THRESHOLD_3)) {
out[6*s+2] = 0x1;
out[6*s+4] = 0x1;
} else if ((__real__ in[s] > QAM64_THRESHOLD_2) || (__real__ in[s] < -QAM64_THRESHOLD_2)) {
out[6*s+2] = 0x1;
out[6*s+4] = 0x0;
} else if ((__real__ in[s] > QAM64_THRESHOLD_1) || (__real__ in[s] < -QAM64_THRESHOLD_1)) {
out[6*s+2] = 0x0;
out[6*s+4] = 0x0;
} else {
out[6*s+2] = 0x0;
out[6*s+4] = 0x1;
}
/* bits associated with/obtained from quadrature component: b1, b3, b5 */
if (__imag__ in[s] > 0){
out[6*s+1] = 0x0;
} else {
out[6*s+1] = 0x1;
}
if ((__imag__ in[s] > QAM64_THRESHOLD_3) || (__imag__ in[s] < -QAM64_THRESHOLD_3)) {
out[6*s+3] = 0x1;
out[6*s+5] = 0x1;
} else if ((__imag__ in[s] > QAM64_THRESHOLD_2) || (__imag__ in[s] < -QAM64_THRESHOLD_2)) {
out[6*s+3] = 0x1;
out[6*s+5] = 0x0;
} else if ((__imag__ in[s] > QAM64_THRESHOLD_1) || (__imag__ in[s] < -QAM64_THRESHOLD_1)) {
out[6*s+3] = 0x0;
out[6*s+5] = 0x0;
} else {
out[6*s+3] = 0x0;
out[6*s+5] = 0x1;
}
}
/* bits associated with/obtained from quadrature component: b1, b3, b5 */
if (__imag__ in[s] > 0){
out[6*s+1] = 0x0;
} else {
out[6*s+1] = 0x1;
}
if ((__imag__ in[s] > QAM64_THRESHOLD_3) || (__imag__ in[s] < -QAM64_THRESHOLD_3)) {
out[6*s+3] = 0x1;
out[6*s+5] = 0x1;
} else if ((__imag__ in[s] > QAM64_THRESHOLD_2) || (__imag__ in[s] < -QAM64_THRESHOLD_2)) {
out[6*s+3] = 0x1;
out[6*s+5] = 0x0;
} else if ((__imag__ in[s] > QAM64_THRESHOLD_1) || (__imag__ in[s] < -QAM64_THRESHOLD_1)) {
out[6*s+3] = 0x0;
out[6*s+5] = 0x0;
} else {
out[6*s+3] = 0x0;
out[6*s+5] = 0x1;
}
}
}

@ -30,10 +30,10 @@
/* Assume perfect amplitude and phase alignment.
* Check threshold values for real case
* or implement dynamic threshold adjustent as a function of received symbol amplitudes */
#define QAM16_THRESHOLD 2/sqrt(10)
#define QAM64_THRESHOLD_1 2/sqrt(42)
#define QAM64_THRESHOLD_2 4/sqrt(42)
#define QAM64_THRESHOLD_3 6/sqrt(42)
#define QAM16_THRESHOLD 2/sqrt(10)
#define QAM64_THRESHOLD_1 2/sqrt(42)
#define QAM64_THRESHOLD_2 4/sqrt(42)
#define QAM64_THRESHOLD_3 6/sqrt(42)
void hard_bpsk_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 */
void set_BPSKtable(cf_t* table, soft_table_t *soft_table, bool compute_soft_demod)
{
// LTE-BPSK constellation:
// Q
// | 0
//---------> I
// 1 |
table[0] = BPSK_LEVEL + BPSK_LEVEL*_Complex_I;
table[1] = -BPSK_LEVEL -BPSK_LEVEL*_Complex_I;
// LTE-BPSK constellation:
// Q
// | 0
//---------> I
// 1 |
table[0] = BPSK_LEVEL + BPSK_LEVEL*_Complex_I;
table[1] = -BPSK_LEVEL -BPSK_LEVEL*_Complex_I;
if (!compute_soft_demod) {
return;
}
if (!compute_soft_demod) {
return;
}
/* BSPK symbols containing a '0' and a '1' (only two symbols, 1 bit) */
soft_table->idx[0][0][0] = 0;
soft_table->idx[1][0][0] = 1;
/* BSPK symbols containing a '0' and a '1' (only two symbols, 1 bit) */
soft_table->idx[0][0][0] = 0;
soft_table->idx[1][0][0] = 1;
}
/**
* Set the QPSK modulation table */
void set_QPSKtable(cf_t* table, soft_table_t *soft_table, bool compute_soft_demod)
{
int i,j;
int i,j;
// LTE-QPSK constellation:
// Q
// 10 | 00
//-----------> I
// 11 | 01
table[0] = QPSK_LEVEL + QPSK_LEVEL*_Complex_I;
table[1] = QPSK_LEVEL - QPSK_LEVEL*_Complex_I;
table[2] = -QPSK_LEVEL + QPSK_LEVEL*_Complex_I;
table[3] = -QPSK_LEVEL - QPSK_LEVEL*_Complex_I;
for (i=0;i<6;i++) {
for (j=0;j<32;j++) {
soft_table->idx[0][i][j] = 0;
soft_table->idx[1][i][j] = 0;
}
}
// LTE-QPSK constellation:
// Q
// 10 | 00
//-----------> I
// 11 | 01
table[0] = QPSK_LEVEL + QPSK_LEVEL*_Complex_I;
table[1] = QPSK_LEVEL - QPSK_LEVEL*_Complex_I;
table[2] = -QPSK_LEVEL + QPSK_LEVEL*_Complex_I;
table[3] = -QPSK_LEVEL - QPSK_LEVEL*_Complex_I;
for (i=0;i<6;i++) {
for (j=0;j<32;j++) {
soft_table->idx[0][i][j] = 0;
soft_table->idx[1][i][j] = 0;
}
}
if (!compute_soft_demod) {
return;
}
if (!compute_soft_demod) {
return;
}
/* QSPK symbols containing a '0' at the different bit positions */
soft_table->idx[0][0][0] = 0;
soft_table->idx[0][0][1] = 1;
soft_table->idx[0][1][0] = 0;
soft_table->idx[0][1][1] = 2;
/* QSPK symbols containing a '1' at the different bit positions */
soft_table->idx[1][0][0] = 2;
soft_table->idx[1][0][1] = 3;
soft_table->idx[1][1][0] = 1;
soft_table->idx[1][1][1] = 3;
/* QSPK symbols containing a '0' at the different bit positions */
soft_table->idx[0][0][0] = 0;
soft_table->idx[0][0][1] = 1;
soft_table->idx[0][1][0] = 0;
soft_table->idx[0][1][1] = 2;
/* QSPK symbols containing a '1' at the different bit positions */
soft_table->idx[1][0][0] = 2;
soft_table->idx[1][0][1] = 3;
soft_table->idx[1][1][0] = 1;
soft_table->idx[1][1][1] = 3;
}
/**
* Set the 16QAM modulation table */
void set_16QAMtable(cf_t* table, soft_table_t *soft_table, bool compute_soft_demod)
{
int i,j;
// LTE-16QAM constellation:
// Q
// 1011 1001 | 0001 0011
// 1010 1000 | 0000 0010
//---------------------------------> I
// 1110 1100 | 0100 0110
// 1111 1101 | 0101 0111
table[0] = QAM16_LEVEL_1 + QAM16_LEVEL_1*_Complex_I;
table[1] = QAM16_LEVEL_1 + QAM16_LEVEL_2*_Complex_I;
table[2] = QAM16_LEVEL_2 + QAM16_LEVEL_1*_Complex_I;
table[3] = QAM16_LEVEL_2 + QAM16_LEVEL_2*_Complex_I;
table[4] = QAM16_LEVEL_1 - QAM16_LEVEL_1*_Complex_I;
table[5] = QAM16_LEVEL_1 - QAM16_LEVEL_2*_Complex_I;
table[6] = QAM16_LEVEL_2 - QAM16_LEVEL_1*_Complex_I;
table[7] = QAM16_LEVEL_2 - QAM16_LEVEL_2*_Complex_I;
table[8] = -QAM16_LEVEL_1 + QAM16_LEVEL_1*_Complex_I;
table[9] = -QAM16_LEVEL_1 + QAM16_LEVEL_2*_Complex_I;
table[10] = -QAM16_LEVEL_2 + QAM16_LEVEL_1*_Complex_I;
table[11] = -QAM16_LEVEL_2 + QAM16_LEVEL_2*_Complex_I;
table[12] = -QAM16_LEVEL_1 - QAM16_LEVEL_1*_Complex_I;
table[13] = -QAM16_LEVEL_1 - QAM16_LEVEL_2*_Complex_I;
table[14] = -QAM16_LEVEL_2 - QAM16_LEVEL_1*_Complex_I;
table[15] = -QAM16_LEVEL_2 - QAM16_LEVEL_2*_Complex_I;
for (i=0;i<6;i++) {
for (j=0;j<32;j++) {
soft_table->idx[0][i][j] = 0;
soft_table->idx[1][i][j] = 0;
}
}
if (!compute_soft_demod) {
return;
}
int i,j;
// LTE-16QAM constellation:
// Q
// 1011 1001 | 0001 0011
// 1010 1000 | 0000 0010
//---------------------------------> I
// 1110 1100 | 0100 0110
// 1111 1101 | 0101 0111
table[0] = QAM16_LEVEL_1 + QAM16_LEVEL_1*_Complex_I;
table[1] = QAM16_LEVEL_1 + QAM16_LEVEL_2*_Complex_I;
table[2] = QAM16_LEVEL_2 + QAM16_LEVEL_1*_Complex_I;
table[3] = QAM16_LEVEL_2 + QAM16_LEVEL_2*_Complex_I;
table[4] = QAM16_LEVEL_1 - QAM16_LEVEL_1*_Complex_I;
table[5] = QAM16_LEVEL_1 - QAM16_LEVEL_2*_Complex_I;
table[6] = QAM16_LEVEL_2 - QAM16_LEVEL_1*_Complex_I;
table[7] = QAM16_LEVEL_2 - QAM16_LEVEL_2*_Complex_I;
table[8] = -QAM16_LEVEL_1 + QAM16_LEVEL_1*_Complex_I;
table[9] = -QAM16_LEVEL_1 + QAM16_LEVEL_2*_Complex_I;
table[10] = -QAM16_LEVEL_2 + QAM16_LEVEL_1*_Complex_I;
table[11] = -QAM16_LEVEL_2 + QAM16_LEVEL_2*_Complex_I;
table[12] = -QAM16_LEVEL_1 - QAM16_LEVEL_1*_Complex_I;
table[13] = -QAM16_LEVEL_1 - QAM16_LEVEL_2*_Complex_I;
table[14] = -QAM16_LEVEL_2 - QAM16_LEVEL_1*_Complex_I;
table[15] = -QAM16_LEVEL_2 - QAM16_LEVEL_2*_Complex_I;
for (i=0;i<6;i++) {
for (j=0;j<32;j++) {
soft_table->idx[0][i][j] = 0;
soft_table->idx[1][i][j] = 0;
}
}
if (!compute_soft_demod) {
return;
}
/* Matrices identifying the zeros and ones of LTE-16QAM constellation */
for (i=0;i<8;i++) {
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)*/
}
/* symbols with a '0' ans '1' at the bit position 1: */
for (i=0;i<4;i++) {
soft_table->idx[0][1][i] = i;
soft_table->idx[0][1][i+4] = i+8;
soft_table->idx[1][1][i] = i+4;
soft_table->idx[1][1][i+4] = i+12;
}
/* symbols with a '0' ans '1' at the bit position 2: */
for (j=0;j<4;j++) {
for (i=0;i<2;i++) {
soft_table->idx[0][2][i+2*j] = i + 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: */
for (i=0;i<8;i++) {
soft_table->idx[0][3][i] = 2*i;
soft_table->idx[1][3][i] = 2*i+1;
}
/* Matrices identifying the zeros and ones of LTE-16QAM constellation */
for (i=0;i<8;i++) {
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)*/
}
/* symbols with a '0' ans '1' at the bit position 1: */
for (i=0;i<4;i++) {
soft_table->idx[0][1][i] = i;
soft_table->idx[0][1][i+4] = i+8;
soft_table->idx[1][1][i] = i+4;
soft_table->idx[1][1][i+4] = i+12;
}
/* symbols with a '0' ans '1' at the bit position 2: */
for (j=0;j<4;j++) {
for (i=0;i<2;i++) {
soft_table->idx[0][2][i+2*j] = i + 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: */
for (i=0;i<8;i++) {
soft_table->idx[0][3][i] = 2*i;
soft_table->idx[1][3][i] = 2*i+1;
}
}
/**
* Set the 64QAM modulation table */
void set_64QAMtable(cf_t* table, soft_table_t *soft_table, bool compute_soft_demod)
{
int i,j;
// LTE-64QAM constellation:
// 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[1] = QAM64_LEVEL_2 + QAM64_LEVEL_1*_Complex_I;
table[2] = QAM64_LEVEL_1 + QAM64_LEVEL_2*_Complex_I;
table[3] = QAM64_LEVEL_1 + QAM64_LEVEL_1*_Complex_I;
table[4] = QAM64_LEVEL_2 + QAM64_LEVEL_3*_Complex_I;
table[5] = QAM64_LEVEL_2 + QAM64_LEVEL_4*_Complex_I;
table[6] = QAM64_LEVEL_1 + QAM64_LEVEL_3*_Complex_I;
table[7] = QAM64_LEVEL_1 + QAM64_LEVEL_4*_Complex_I;
table[8] = QAM64_LEVEL_3 + QAM64_LEVEL_2*_Complex_I;
table[9] = QAM64_LEVEL_3 + QAM64_LEVEL_1*_Complex_I;
table[10] = QAM64_LEVEL_4 + QAM64_LEVEL_2*_Complex_I;
table[11] = QAM64_LEVEL_4 + QAM64_LEVEL_1*_Complex_I;
table[12] = QAM64_LEVEL_3 + QAM64_LEVEL_3*_Complex_I;
table[13] = QAM64_LEVEL_3 + QAM64_LEVEL_4*_Complex_I;
table[14] = QAM64_LEVEL_4 + QAM64_LEVEL_3*_Complex_I;
table[15] = QAM64_LEVEL_4 + QAM64_LEVEL_4*_Complex_I;
table[16] = QAM64_LEVEL_2 - QAM64_LEVEL_2*_Complex_I;
table[17] = QAM64_LEVEL_2 - QAM64_LEVEL_1*_Complex_I;
table[18] = QAM64_LEVEL_1 - QAM64_LEVEL_2*_Complex_I;
table[19] = QAM64_LEVEL_1 - QAM64_LEVEL_1*_Complex_I;
table[20] = QAM64_LEVEL_2 - QAM64_LEVEL_3*_Complex_I;
table[21] = QAM64_LEVEL_2 - QAM64_LEVEL_4*_Complex_I;
table[22] = QAM64_LEVEL_1 - QAM64_LEVEL_3*_Complex_I;
table[23] = QAM64_LEVEL_1 - QAM64_LEVEL_4*_Complex_I;
table[24] = QAM64_LEVEL_3 - QAM64_LEVEL_2*_Complex_I;
table[25] = QAM64_LEVEL_3 - QAM64_LEVEL_1*_Complex_I;
table[26] = QAM64_LEVEL_4 - QAM64_LEVEL_2*_Complex_I;
table[27] = QAM64_LEVEL_4 - QAM64_LEVEL_1*_Complex_I;
table[28] = QAM64_LEVEL_3 - QAM64_LEVEL_3*_Complex_I;
table[29] = QAM64_LEVEL_3 - QAM64_LEVEL_4*_Complex_I;
table[30] = QAM64_LEVEL_4 - QAM64_LEVEL_3*_Complex_I;
table[31] = QAM64_LEVEL_4 - QAM64_LEVEL_4*_Complex_I;
table[32] = -QAM64_LEVEL_2 + QAM64_LEVEL_2*_Complex_I;
table[33] = -QAM64_LEVEL_2 + QAM64_LEVEL_1*_Complex_I;
table[34] = -QAM64_LEVEL_1 + QAM64_LEVEL_2*_Complex_I;
table[35] = -QAM64_LEVEL_1 + QAM64_LEVEL_1*_Complex_I;
table[36] = -QAM64_LEVEL_2 + QAM64_LEVEL_3*_Complex_I;
table[37] = -QAM64_LEVEL_2 + QAM64_LEVEL_4*_Complex_I;
table[38] = -QAM64_LEVEL_1 + QAM64_LEVEL_3*_Complex_I;
table[39] = -QAM64_LEVEL_1 + QAM64_LEVEL_4*_Complex_I;
table[40] = -QAM64_LEVEL_3 + QAM64_LEVEL_2*_Complex_I;
table[41] = -QAM64_LEVEL_3 + QAM64_LEVEL_1*_Complex_I;
table[42] = -QAM64_LEVEL_4 + QAM64_LEVEL_2*_Complex_I;
table[43] = -QAM64_LEVEL_4 + QAM64_LEVEL_1*_Complex_I;
table[44] = -QAM64_LEVEL_3 + QAM64_LEVEL_3*_Complex_I;
table[45] = -QAM64_LEVEL_3 + QAM64_LEVEL_4*_Complex_I;
table[46] = -QAM64_LEVEL_4 + QAM64_LEVEL_3*_Complex_I;
table[47] = -QAM64_LEVEL_4 + QAM64_LEVEL_4*_Complex_I;
table[48] = -QAM64_LEVEL_2 - QAM64_LEVEL_2*_Complex_I;
table[49] = -QAM64_LEVEL_2 - QAM64_LEVEL_1*_Complex_I;
table[50] = -QAM64_LEVEL_1 - QAM64_LEVEL_2*_Complex_I;
table[51] = -QAM64_LEVEL_1 - QAM64_LEVEL_1*_Complex_I;
table[52] = -QAM64_LEVEL_2 - QAM64_LEVEL_3*_Complex_I;
table[53] = -QAM64_LEVEL_2 - QAM64_LEVEL_4*_Complex_I;
table[54] = -QAM64_LEVEL_1 - QAM64_LEVEL_3*_Complex_I;
table[55] = -QAM64_LEVEL_1 - QAM64_LEVEL_4*_Complex_I;
table[56] = -QAM64_LEVEL_3 - QAM64_LEVEL_2*_Complex_I;
table[57] = -QAM64_LEVEL_3 - QAM64_LEVEL_1*_Complex_I;
table[58] = -QAM64_LEVEL_4 - QAM64_LEVEL_2*_Complex_I;
table[59] = -QAM64_LEVEL_4 - QAM64_LEVEL_1*_Complex_I;
table[60] = -QAM64_LEVEL_3 - QAM64_LEVEL_3*_Complex_I;
table[61] = -QAM64_LEVEL_3 - QAM64_LEVEL_4*_Complex_I;
table[62] = -QAM64_LEVEL_4 - QAM64_LEVEL_3*_Complex_I;
table[63] = -QAM64_LEVEL_4 - QAM64_LEVEL_4*_Complex_I;
int i,j;
// LTE-64QAM constellation:
// 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[1] = QAM64_LEVEL_2 + QAM64_LEVEL_1*_Complex_I;
table[2] = QAM64_LEVEL_1 + QAM64_LEVEL_2*_Complex_I;
table[3] = QAM64_LEVEL_1 + QAM64_LEVEL_1*_Complex_I;
table[4] = QAM64_LEVEL_2 + QAM64_LEVEL_3*_Complex_I;
table[5] = QAM64_LEVEL_2 + QAM64_LEVEL_4*_Complex_I;
table[6] = QAM64_LEVEL_1 + QAM64_LEVEL_3*_Complex_I;
table[7] = QAM64_LEVEL_1 + QAM64_LEVEL_4*_Complex_I;
table[8] = QAM64_LEVEL_3 + QAM64_LEVEL_2*_Complex_I;
table[9] = QAM64_LEVEL_3 + QAM64_LEVEL_1*_Complex_I;
table[10] = QAM64_LEVEL_4 + QAM64_LEVEL_2*_Complex_I;
table[11] = QAM64_LEVEL_4 + QAM64_LEVEL_1*_Complex_I;
table[12] = QAM64_LEVEL_3 + QAM64_LEVEL_3*_Complex_I;
table[13] = QAM64_LEVEL_3 + QAM64_LEVEL_4*_Complex_I;
table[14] = QAM64_LEVEL_4 + QAM64_LEVEL_3*_Complex_I;
table[15] = QAM64_LEVEL_4 + QAM64_LEVEL_4*_Complex_I;
table[16] = QAM64_LEVEL_2 - QAM64_LEVEL_2*_Complex_I;
table[17] = QAM64_LEVEL_2 - QAM64_LEVEL_1*_Complex_I;
table[18] = QAM64_LEVEL_1 - QAM64_LEVEL_2*_Complex_I;
table[19] = QAM64_LEVEL_1 - QAM64_LEVEL_1*_Complex_I;
table[20] = QAM64_LEVEL_2 - QAM64_LEVEL_3*_Complex_I;
table[21] = QAM64_LEVEL_2 - QAM64_LEVEL_4*_Complex_I;
table[22] = QAM64_LEVEL_1 - QAM64_LEVEL_3*_Complex_I;
table[23] = QAM64_LEVEL_1 - QAM64_LEVEL_4*_Complex_I;
table[24] = QAM64_LEVEL_3 - QAM64_LEVEL_2*_Complex_I;
table[25] = QAM64_LEVEL_3 - QAM64_LEVEL_1*_Complex_I;
table[26] = QAM64_LEVEL_4 - QAM64_LEVEL_2*_Complex_I;
table[27] = QAM64_LEVEL_4 - QAM64_LEVEL_1*_Complex_I;
table[28] = QAM64_LEVEL_3 - QAM64_LEVEL_3*_Complex_I;
table[29] = QAM64_LEVEL_3 - QAM64_LEVEL_4*_Complex_I;
table[30] = QAM64_LEVEL_4 - QAM64_LEVEL_3*_Complex_I;
table[31] = QAM64_LEVEL_4 - QAM64_LEVEL_4*_Complex_I;
table[32] = -QAM64_LEVEL_2 + QAM64_LEVEL_2*_Complex_I;
table[33] = -QAM64_LEVEL_2 + QAM64_LEVEL_1*_Complex_I;
table[34] = -QAM64_LEVEL_1 + QAM64_LEVEL_2*_Complex_I;
table[35] = -QAM64_LEVEL_1 + QAM64_LEVEL_1*_Complex_I;
table[36] = -QAM64_LEVEL_2 + QAM64_LEVEL_3*_Complex_I;
table[37] = -QAM64_LEVEL_2 + QAM64_LEVEL_4*_Complex_I;
table[38] = -QAM64_LEVEL_1 + QAM64_LEVEL_3*_Complex_I;
table[39] = -QAM64_LEVEL_1 + QAM64_LEVEL_4*_Complex_I;
table[40] = -QAM64_LEVEL_3 + QAM64_LEVEL_2*_Complex_I;
table[41] = -QAM64_LEVEL_3 + QAM64_LEVEL_1*_Complex_I;
table[42] = -QAM64_LEVEL_4 + QAM64_LEVEL_2*_Complex_I;
table[43] = -QAM64_LEVEL_4 + QAM64_LEVEL_1*_Complex_I;
table[44] = -QAM64_LEVEL_3 + QAM64_LEVEL_3*_Complex_I;
table[45] = -QAM64_LEVEL_3 + QAM64_LEVEL_4*_Complex_I;
table[46] = -QAM64_LEVEL_4 + QAM64_LEVEL_3*_Complex_I;
table[47] = -QAM64_LEVEL_4 + QAM64_LEVEL_4*_Complex_I;
table[48] = -QAM64_LEVEL_2 - QAM64_LEVEL_2*_Complex_I;
table[49] = -QAM64_LEVEL_2 - QAM64_LEVEL_1*_Complex_I;
table[50] = -QAM64_LEVEL_1 - QAM64_LEVEL_2*_Complex_I;
table[51] = -QAM64_LEVEL_1 - QAM64_LEVEL_1*_Complex_I;
table[52] = -QAM64_LEVEL_2 - QAM64_LEVEL_3*_Complex_I;
table[53] = -QAM64_LEVEL_2 - QAM64_LEVEL_4*_Complex_I;
table[54] = -QAM64_LEVEL_1 - QAM64_LEVEL_3*_Complex_I;
table[55] = -QAM64_LEVEL_1 - QAM64_LEVEL_4*_Complex_I;
table[56] = -QAM64_LEVEL_3 - QAM64_LEVEL_2*_Complex_I;
table[57] = -QAM64_LEVEL_3 - QAM64_LEVEL_1*_Complex_I;
table[58] = -QAM64_LEVEL_4 - QAM64_LEVEL_2*_Complex_I;
table[59] = -QAM64_LEVEL_4 - QAM64_LEVEL_1*_Complex_I;
table[60] = -QAM64_LEVEL_3 - QAM64_LEVEL_3*_Complex_I;
table[61] = -QAM64_LEVEL_3 - QAM64_LEVEL_4*_Complex_I;
table[62] = -QAM64_LEVEL_4 - QAM64_LEVEL_3*_Complex_I;
table[63] = -QAM64_LEVEL_4 - QAM64_LEVEL_4*_Complex_I;
if (!compute_soft_demod) {
return;
}
if (!compute_soft_demod) {
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++) {
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)*/
}
/* symbols with a '0' ans '1' at the bit position 1: */
for (i=0;i<16;i++) {
soft_table->idx[0][1][i] = i;
soft_table->idx[0][1][i+16] = i+32;
soft_table->idx[1][1][i] = i+16;
soft_table->idx[1][1][i+16] = i+48;
}
/* symbols with a '0' ans '1' at the bit position 2: */
for (i=0;i<8;i++) {
soft_table->idx[0][2][i] = i;
soft_table->idx[0][2][i+8] = i+16;
soft_table->idx[0][2][i+16] = i+32;
soft_table->idx[0][2][i+24] = i+48;
soft_table->idx[1][2][i] = i+8;
soft_table->idx[1][2][i+8] = i+24;
soft_table->idx[1][2][i+16] = i+40;
soft_table->idx[1][2][i+24] = i+56;
}
/* symbols with a '0' ans '1' at the bit position 3: */
for (j=0;j<8;j++) {
for (i=0;i<4;i++) {
soft_table->idx[0][3][i+4*j] = i + 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: */
for (j=0;j<16;j++) {
for (i=0;i<2;i++) {
soft_table->idx[0][4][i+2*j] = i + 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: */
for (i=0;i<32;i++) {
soft_table->idx[0][5][i] = 2*i;
soft_table->idx[1][5][i] = 2*i+1;
}
for (i=0;i<32;i++) {
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)*/
}
/* symbols with a '0' ans '1' at the bit position 1: */
for (i=0;i<16;i++) {
soft_table->idx[0][1][i] = i;
soft_table->idx[0][1][i+16] = i+32;
soft_table->idx[1][1][i] = i+16;
soft_table->idx[1][1][i+16] = i+48;
}
/* symbols with a '0' ans '1' at the bit position 2: */
for (i=0;i<8;i++) {
soft_table->idx[0][2][i] = i;
soft_table->idx[0][2][i+8] = i+16;
soft_table->idx[0][2][i+16] = i+32;
soft_table->idx[0][2][i+24] = i+48;
soft_table->idx[1][2][i] = i+8;
soft_table->idx[1][2][i+8] = i+24;
soft_table->idx[1][2][i+16] = i+40;
soft_table->idx[1][2][i+24] = i+56;
}
/* symbols with a '0' ans '1' at the bit position 3: */
for (j=0;j<8;j++) {
for (i=0;i<4;i++) {
soft_table->idx[0][3][i+4*j] = i + 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: */
for (j=0;j<16;j++) {
for (i=0;i<2;i++) {
soft_table->idx[0][4][i+2*j] = i + 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: */
for (i=0;i<32;i++) {
soft_table->idx[0][5][i] = 2*i;
soft_table->idx[1][5][i] = 2*i+1;
}
}

@ -30,15 +30,15 @@
#define QPSK_LEVEL 1/sqrt(2)
#define QAM16_LEVEL_1 1/sqrt(10)
#define QAM16_LEVEL_2 3/sqrt(10)
#define QAM16_LEVEL_1 1/sqrt(10)
#define QAM16_LEVEL_2 3/sqrt(10)
#define QAM64_LEVEL_1 1/sqrt(42)
#define QAM64_LEVEL_2 3/sqrt(42)
#define QAM64_LEVEL_3 5/sqrt(42)
#define QAM64_LEVEL_4 7/sqrt(42)
#define QAM64_LEVEL_1 1/sqrt(42)
#define QAM64_LEVEL_2 3/sqrt(42)
#define QAM64_LEVEL_3 5/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
* symbol from the bit sequence */

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

Loading…
Cancel
Save