1/* Test viterbi decoder speeds */
2#include "config.h"
3#include <stdio.h>
4#include <stdlib.h>
5#include <unistd.h>
6#include <time.h>
7#include <math.h>
8#include <memory.h>
9#include <sys/time.h>
10#include <sys/resource.h>
11#ifdef HAVE_GETOPT_H
12#include <getopt.h>
13#endif
14#include "fec.h"
15
16#if HAVE_GETOPT_LONG
17struct option Options[] = {
18  {"frame-length",1,NULL,'l'},
19  {"frame-count",1,NULL,'n'},
20  {"ebn0",1,NULL,'e'},
21  {"gain",1,NULL,'g'},
22  {"verbose",0,NULL,'v'},
23  {"force-altivec",0,NULL,'a'},
24  {"force-port",0,NULL,'p'},
25  {"force-mmx",0,NULL,'m'},
26  {"force-sse",0,NULL,'s'},
27  {"force-sse2",0,NULL,'t'},
28  {NULL},
29};
30#endif
31
32#define RATE (1./2.)
33#define MAXBYTES 10000
34
35double Gain = 32.0;
36int Verbose = 0;
37
38int main(int argc,char *argv[]){
39  int i,d,tr;
40  int sr=0,trials = 10000,errcnt,framebits=2048;
41  long long int tot_errs=0;
42  unsigned char bits[MAXBYTES];
43  unsigned char data[MAXBYTES];
44  unsigned char xordata[MAXBYTES];
45  unsigned char symbols[8*2*(MAXBYTES+6)];
46  void *vp;
47  extern char *optarg;
48  struct rusage start,finish;
49  double extime;
50  double gain,esn0,ebn0;
51  time_t t;
52  int badframes=0;
53
54  time(&t);
55  srandom(t);
56  ebn0 = -100;
57#if HAVE_GETOPT_LONG
58  while((d = getopt_long(argc,argv,"l:n:te:g:vapmst",Options,NULL)) != EOF){
59#else
60  while((d = getopt(argc,argv,"l:n:te:g:vapmst")) != EOF){
61#endif
62    switch(d){
63    case 'a':
64      Cpu_mode = ALTIVEC;
65      break;
66    case 'p':
67      Cpu_mode = PORT;
68      break;
69    case 'm':
70      Cpu_mode = MMX;
71      break;
72    case 's':
73      Cpu_mode = SSE;
74      break;
75    case 't':
76      Cpu_mode = SSE2;
77      break;
78    case 'l':
79      framebits = atoi(optarg);
80      break;
81    case 'n':
82      trials = atoi(optarg);
83      break;
84    case 'e':
85      ebn0 = atof(optarg);
86      break;
87    case 'g':
88      Gain = atof(optarg);
89      break;
90    case 'v':
91      Verbose++;
92      break;
93    }
94  }
95  if(framebits > 8*MAXBYTES){
96    fprintf(stderr,"Frame limited to %d bits\n",MAXBYTES*8);
97    framebits = MAXBYTES*8;
98  }
99  if((vp = create_viterbi27(framebits)) == NULL){
100    printf("create_viterbi27 failed\n");
101    exit(1);
102  }
103  if(ebn0 != -100){
104    esn0 = ebn0 + 10*log10((double)RATE); /* Es/No in dB */
105    /* Compute noise voltage. The 0.5 factor accounts for BPSK seeing
106     * only half the noise power, and the sqrt() converts power to
107     * voltage.
108     */
109    gain = 1./sqrt(0.5/pow(10.,esn0/10.));
110
111    printf("nframes = %d framesize = %d ebn0 = %.2f dB gain = %g\n",trials,framebits,ebn0,Gain);
112
113    for(tr=0;tr<trials;tr++){
114      /* Encode a frame of random data */
115      for(i=0;i<framebits+6;i++){
116	int bit = (i < framebits) ? (random() & 1) : 0;
117
118	sr = (sr << 1) | bit;
119	bits[i/8] = sr & 0xff;
120	symbols[2*i+0] = addnoise(parity(sr & V27POLYA),gain,Gain,127.5,255);
121	symbols[2*i+1] = addnoise(parity(sr & V27POLYB),gain,Gain,127.5,255);
122      }
123      /* Decode it and make sure we get the right answer */
124      /* Initialize Viterbi decoder */
125      init_viterbi27(vp,0);
126
127      /* Decode block */
128      update_viterbi27_blk(vp,symbols,framebits+6);
129
130      /* Do Viterbi chainback */
131      chainback_viterbi27(vp,data,framebits,0);
132      errcnt = 0;
133      for(i=0;i<framebits/8;i++){
134	int e = Bitcnt[xordata[i] = data[i] ^ bits[i]];
135	errcnt += e;
136	tot_errs += e;
137      }
138      if(errcnt != 0)
139	badframes++;
140      if(Verbose > 1 && errcnt != 0){
141	printf("frame %d, %d errors: ",tr,errcnt);
142	for(i=0;i<framebits/8;i++){
143	  printf("%02x",xordata[i]);
144	}
145	printf("\n");
146      }
147      if(Verbose)
148	printf("BER %lld/%lld (%10.3g) FER %d/%d (%10.3g)\r",
149	       tot_errs,(long long)framebits*(tr+1),tot_errs/((double)framebits*(tr+1)),
150	       badframes,tr+1,(double)badframes/(tr+1));
151      fflush(stdout);
152    }
153    if(Verbose > 1)
154      printf("nframes = %d framesize = %d ebn0 = %.2f dB gain = %g\n",trials,framebits,ebn0,Gain);
155    else if(Verbose == 0)
156      printf("BER %lld/%lld (%.3g) FER %d/%d (%.3g)\n",
157	     tot_errs,(long long)framebits*trials,tot_errs/((double)framebits*trials),
158	     badframes,tr+1,(double)badframes/(tr+1));
159    else
160      printf("\n");
161
162  } else {
163    /* Do time trials */
164    memset(symbols,127,sizeof(symbols));
165    printf("Starting time trials\n");
166    getrusage(RUSAGE_SELF,&start);
167    for(tr=0;tr < trials;tr++){
168      /* Initialize Viterbi decoder */
169      init_viterbi27(vp,0);
170
171      /* Decode block */
172      update_viterbi27_blk(vp,symbols,framebits);
173
174      /* Do Viterbi chainback */
175      chainback_viterbi27(vp,data,framebits,0);
176    }
177    getrusage(RUSAGE_SELF,&finish);
178    extime = finish.ru_utime.tv_sec - start.ru_utime.tv_sec + 1e-6*(finish.ru_utime.tv_usec - start.ru_utime.tv_usec);
179    printf("Execution time for %d %d-bit frames: %.2f sec\n",trials,
180	   framebits,extime);
181    printf("decoder speed: %g bits/s\n",trials*framebits/extime);
182  }
183  exit(0);
184}
185