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
17 struct 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 
35 double Gain = 32.0;
36 int Verbose = 0;
37 
main(int argc,char * argv[])38 int 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