📄 genviterbi.pl
字号:
# Perl script to generate C code for an encoder and# a Viterbi decoder for any specified rate 1/N, constraint length k <= 16# convolutional code.## Not recommended for large K codes, as it will generate a *very* large# program!# 24 October 1997 Phil Karn, KA9Q# Here are the polynomials for some optimum convolutional codes. Select only one# by uncommenting it# Rate 1/2 codes#@polys = (0x7,0x5); # k=3#@polys = (0xf,0xb); # k=4#@polys = (0x17, 0x19); # k=5#@polys = (0x13, 0x1b); # k=5, used in GSM?#@polys = (0x2f, 0x35); # k=6@polys = (0x6d,0x4f); # k=7; very popular with NASA and industry#@polys = (0x9f, 0xe5); # k=8#@polys = (0x1af, 0x11d); # k=9; used in IS-95 CDMA#@polys = (0x45dd, 0x69e3); # k = 15# Rate 1/3 codes#@polys = (0x7, 0x7, 0x5); #k = 3#@polys = (0xf, 0xb, 0xd); #k = 4#@polys = (0x1f, 0x1b, 0x15); #k = 5#@polys = (0x2f, 0x35, 0x39); #k = 6#@polys = (0x4f, 0x57, 0x6d); #k = 7; also popular with NASA and industry#@polys = (0xef, 0x9b, 0xa9); #k = 8#@polys = (0x1ed, 0x19b, 0x127); #k = 9; used in IS-95 CDMA# end of user-configurable stuff# Figure out constraint length by looking at the polynomials$bar = 0;foreach $i (@polys){ $bar |= $i;}$k = 0;while($bar != 0){ $k++; $bar >>= 1;}die "Max K=16 supported" if ($k > 16);$nsym = @polys;$nmets = 1 << $nsym;$smask = $nmets - 1;$K = 1 << ($k - 1);if($K/32 >= 1){ $D = $K/32;} else { $D = 1;}print "unsigned char Partab[] = { ";for $i (0 ... 255) { print parity($i),",";}print "};";print "/* Convolutional encoder */encode(unsigned char *symbols,unsigned char *data,unsigned int nbytes){ unsigned int encstate; int i; encstate = 0; while(nbytes-- != 0){ for(i=7;i>=0;i--){ encstate = (encstate << 1) | ((*data >> i) & 1);\n";foreach $poly (@polys) { if($k <= 8){ print "\t\t\t*symbols++ = Partab[encstate & $poly];\n"; } elsif($k <= 16){ print "\t\t\t*symbols++ = Partab[((encstate & $poly) ^ ((encstate & $poly) >> 8)) & 0xff];\n"; }} print "\t\t} data++; } return 0;}\n";print "/* Viterbi decoder */intviterbi(unsigned long *metric, /* Final path metric (returned value) */unsigned char *data, /* Decoded output data */unsigned char *symbols, /* Raw deinterleaved input symbols */unsigned int nbits, /* Number of output bits */int mettab[2][256] /* Metric table, [sent sym][rx symbol] */){ unsigned int bitcnt = 0; int beststate,i; long cmetric[$K],nmetric[$K]; register int m0,m1; /* This next line is arguably illegal C, but it works on * GCC and it avoids having to reference this heavily used * array through a pointer. If you can't compile this, use malloc. */ unsigned long paths[nbits*",$D,"*sizeof(unsigned long)]; unsigned long *pp; unsigned long dec; int mets[$nmets]; pp = paths; /* Initialize starting metrics to prefer 0 state */ cmetric[0] = 0; for(i=1;i<$K;i++) cmetric[i] = -999999; for(;;){\n";emitbits(0);# Too much loop unrolling, and we blow out of the Pentium instruction cacheif($k <= 7) { emitbits(1);} else { print "\t\tmemcpy(cmetric,nmetric,",$K*4,");\n";}print"\t} pp -= ",$D,"; /* Chain back from terminal state to produce decoded data */ memset(data,0,nbits/8); for(i=nbits-$k;i >= 0;i--){ if(pp[beststate >> 5] & (1 << (beststate & 31))){ beststate |= $K; /* 2^(K-1) */ data[i>>3] |= 0x80 >> (i&7); } beststate >>= 1; pp -= ",$D,"; } return 0;}\n";exit;sub emit_butterfly(@) { my $source,$dest,$sym,$odd,$i,$j; $i = shift; $j = $i * 2; $odd = shift; $sym = shift; if($odd){ $source = "nmetric"; $dest = "cmetric"; } else { $source = "cmetric"; $dest = "nmetric"; }print "\t\t/* state $i, symbols ", bsplit($sym,$nsym)," */ m0 = $source\[$i] + mets[$sym]; m1 = $source\[",($i+$K/2),"] + mets[",$smask ^ $sym,"]; $dest\[",2*$i,"] = m0; if(m1 > m0){ $dest\[",2*$i,"] = m1; dec |= ";printf "0x%lx",1 << ((2*$i) & 31);print "; } m0 -= (mets[$sym] - mets[",$smask^$sym,"]); m1 += (mets[$sym] - mets[",$smask^$sym,"]); $dest\[",2*$i+1,"] = m0; if(m1 > m0){ $dest\[",2*$i+1,"] = m1; dec |= ";printf "0x%lx",1 << ((2*$i+1) & 31);print "; }"}sub emitbits(@) { my $sym; $odd = shift; if($odd){ $dest = "cmetric"; } else { $dest = "nmetric"; } foreach $i (0 ... $nmets-1){ print "\t\tmets[$i] = "; @symbits = bsplit($i,$nsym); print "mettab[",pop @symbits,"][symbols[0]]"; foreach $j (1 ... $nsym-1){ print " + mettab[",pop @symbits,"][symbols[$j]]"; } print ";\n"; } print "\t\tsymbols += $nsym;\n"; foreach $i (0 ... $K/2-1){ $sym = 0; foreach $p (@polys){ $sym = $sym * 2 + parity((2*$i & $p)); } push @stuff,join ' ',$sym,$i; if(($i % 16) == 15){ print "\t\tdec = 0;\n"; foreach $sym (sort @stuff){ @a = split(' ',$sym); emit_butterfly($a[1],$odd, $a[0]); } @stuff = (); print "\t\t*pp++ = dec;\n"; } } if($K/2 < 16){ print "\t\tdec = 0;\n"; foreach $sym (sort @stuff){ @a = split(' ',$sym); emit_butterfly($a[0],$odd, $a[1]); } @stuff = (); print "\t\t*pp++ = dec;\n"; } print "\t\tif(++bitcnt == nbits){ beststate = 0; *metric = $dest\[beststate]; break; }\n";}sub bsplit(){ $x = shift; $n = shift; my @ret; while($n-- > 0){ push @ret,($x & 1); $x = $x >> 1; } return @ret;}sub parity(){ $x = shift; $x ^= ($x >> 16); $x ^= ($x >> 8); $x ^= ($x >> 4); $x ^= ($x >> 2); $x ^= ($x >> 1); return ($x & 1);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -