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