/* Test viterbi decoder speeds */ #include "config.h" #include #include #include #include #include #include #include #include #ifdef HAVE_GETOPT_H #include #endif #include "fec.h" #if HAVE_GETOPT_LONG struct option Options[] = { {"frame-length", 1, NULL, 'l'}, {"frame-count", 1, NULL, 'n'}, {"ebn0", 1, NULL, 'e'}, {"gain", 1, NULL, 'g'}, {"verbose", 0, NULL, 'v'}, {"force-altivec", 0, NULL, 'a'}, {"force-port", 0, NULL, 'p'}, {"force-mmx", 0, NULL, 'm'}, {"force-sse", 0, NULL, 's'}, {"force-sse2", 0, NULL, 't'}, {NULL}, }; #endif #define RATE (1./2.) #define MAXBYTES 10000 double Gain = 32.0; int Verbose = 0; int main(int argc, char *argv[]) { int i, d, tr; int sr = 0, trials = 10000, errcnt, framebits = 2048; long long int tot_errs = 0; unsigned char bits[MAXBYTES]; unsigned char data[MAXBYTES]; unsigned char xordata[MAXBYTES]; unsigned char symbols[8 * 2 * (MAXBYTES + 6)]; void *vp; extern char *optarg; struct rusage start, finish; double extime; double gain, esn0, ebn0; time_t t; int badframes = 0; time(&t); srandom(t); ebn0 = -100; #if HAVE_GETOPT_LONG while ((d = getopt_long(argc, argv, "l:n:te:g:vapmst", Options, NULL)) != EOF) { #else while ((d = getopt(argc, argv, "l:n:te:g:vapmst")) != EOF) { #endif switch (d) { case 'a': Cpu_mode = ALTIVEC; break; case 'p': Cpu_mode = PORT; break; case 'm': Cpu_mode = MMX; break; case 's': Cpu_mode = SSE; break; case 't': Cpu_mode = SSE2; break; case 'l': framebits = atoi(optarg); break; case 'n': trials = atoi(optarg); break; case 'e': ebn0 = atof(optarg); break; case 'g': Gain = atof(optarg); break; case 'v': Verbose++; break; } } if (framebits > 8 * MAXBYTES) { fprintf(stderr, "Frame limited to %d bits\n", MAXBYTES * 8); framebits = MAXBYTES * 8; } if ((vp = create_viterbi27(framebits)) == NULL) { printf("create_viterbi27 failed\n"); exit(1); } if (ebn0 != -100) { esn0 = ebn0 + 10 * log10((double)RATE); /* Es/No in dB */ /* Compute noise voltage. The 0.5 factor accounts for BPSK seeing * only half the noise power, and the sqrt() converts power to * voltage. */ gain = 1. / sqrt(0.5 / pow(10., esn0 / 10.)); printf("nframes = %d framesize = %d ebn0 = %.2f dB gain = %g\n", trials, framebits, ebn0, Gain); for (tr = 0; tr < trials; tr++) { /* Encode a frame of random data */ for (i = 0; i < framebits + 6; i++) { int bit = (i < framebits) ? (random() & 1) : 0; sr = (sr << 1) | bit; bits[i / 8] = sr & 0xff; symbols[2 * i + 0] = addnoise(parity(sr & V27POLYA), gain, Gain, 127.5, 255); symbols[2 * i + 1] = addnoise(parity(sr & V27POLYB), gain, Gain, 127.5, 255); } /* Decode it and make sure we get the right answer */ /* Initialize Viterbi decoder */ init_viterbi27(vp, 0); /* Decode block */ update_viterbi27_blk(vp, symbols, framebits + 6); /* Do Viterbi chainback */ chainback_viterbi27(vp, data, framebits, 0); errcnt = 0; for (i = 0; i < framebits / 8; i++) { int e = Bitcnt[xordata[i] = data[i] ^ bits[i]]; errcnt += e; tot_errs += e; } if (errcnt != 0) { badframes++; } if (Verbose > 1 && errcnt != 0) { printf("frame %d, %d errors: ", tr, errcnt); for (i = 0; i < framebits / 8; i++) { printf("%02x", xordata[i]); } printf("\n"); } if (Verbose) printf("BER %lld/%lld (%10.3g) FER %d/%d (%10.3g)\r", tot_errs, (long long)framebits * (tr + 1), tot_errs / ((double)framebits * (tr + 1)), badframes, tr + 1, (double)badframes / (tr + 1)); fflush(stdout); } if (Verbose > 1) { printf("nframes = %d framesize = %d ebn0 = %.2f dB gain = %g\n", trials, framebits, ebn0, Gain); } else if (Verbose == 0) printf("BER %lld/%lld (%.3g) FER %d/%d (%.3g)\n", tot_errs, (long long)framebits * trials, tot_errs / ((double)framebits * trials), badframes, tr + 1, (double)badframes / (tr + 1)); else { printf("\n"); } } else { /* Do time trials */ memset(symbols, 127, sizeof(symbols)); printf("Starting time trials\n"); getrusage(RUSAGE_SELF, &start); for (tr = 0; tr < trials; tr++) { /* Initialize Viterbi decoder */ init_viterbi27(vp, 0); /* Decode block */ update_viterbi27_blk(vp, symbols, framebits); /* Do Viterbi chainback */ chainback_viterbi27(vp, data, framebits, 0); } getrusage(RUSAGE_SELF, &finish); extime = finish.ru_utime.tv_sec - start.ru_utime.tv_sec + 1e-6 * (finish.ru_utime.tv_usec - start.ru_utime.tv_usec); printf("Execution time for %d %d-bit frames: %.2f sec\n", trials, framebits, extime); printf("decoder speed: %g bits/s\n", trials * framebits / extime); } exit(0); }