mirror of
				https://github.com/saitohirga/WSJT-X.git
				synced 2025-10-30 20:40:28 -04:00 
			
		
		
		
	git-svn-id: svn+ssh://svn.code.sf.net/p/wsjt/wsjt/branches/wsjtx@6592 ab8295b8-cf94-4d9e-aec4-7959e3be5d79
		
			
				
	
	
		
			220 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			220 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* Viterbi decoder for arbitrary convolutional code
 | |
|  * viterbi27 and viterbi37 for the r=1/2 and r=1/3 K=7 codes are faster
 | |
|  * Copyright 1999 Phil Karn, KA9Q
 | |
|  * May be used under the terms of the GNU Public License
 | |
|  */
 | |
| 
 | |
| /* Select code here */
 | |
| 
 | |
| #define V216
 | |
| 
 | |
| 
 | |
| #ifdef V216
 | |
| #define	K 16			/* Constraint length */
 | |
| #define N 2			/* Number of symbols per data bit */
 | |
| #define Polys	Poly216		/* Select polynomials here */
 | |
| #endif
 | |
| 
 | |
| /* Rate 1/2 codes */
 | |
| unsigned int Poly216[] = {0126723, 0152711};	/* k = 16  */
 | |
| 
 | |
| #include <stdlib.h>
 | |
| #include <memory.h>
 | |
| 
 | |
| #define LONGBITS 32
 | |
| #define LOGLONGBITS 5
 | |
| 
 | |
| #undef max
 | |
| #define max(x,y) ((x) > (y) ? (x) : (y))
 | |
| #define D       (1 << max(0,K-LOGLONGBITS-1))
 | |
| #define MAXNBITS 200            /* Maximum frame size (user bits) */
 | |
| 
 | |
| extern unsigned char Partab[];	/* Parity lookup table */
 | |
| 
 | |
| int Syms[1 << K];
 | |
| int VDInit = 0;
 | |
| 
 | |
| int parity(int x)
 | |
| {
 | |
|   x ^= (x >> 16);
 | |
|   x ^= (x >> 8);
 | |
|   return Partab[x & 0xff];
 | |
| }
 | |
| 
 | |
| // Wrapper for calling "encode" from Fortran:
 | |
| //void __stdcall ENCODE(
 | |
| void enc216_(
 | |
| unsigned char data[],           // User data, 8 bits per byte
 | |
| int *nbits,                     // Number of user bits
 | |
| unsigned char symbols[],        // Encoded one-bit symbols, 8 per byte
 | |
| int *nsymbols,                  // Number of symbols
 | |
| int *kk,                        // K
 | |
| int *nn)                        // N
 | |
| {
 | |
|   int nbytes;
 | |
|   nbytes=(*nbits+7)/8;          // Always encode multiple of 8 information bits
 | |
|   enc216(symbols,data,nbytes,0,0); // Do the encoding
 | |
|   *nsymbols=(*nbits+K-1)*N;        // Return number of encoded symbols
 | |
|   *kk=K;
 | |
|   *nn=N;
 | |
| }
 | |
| 
 | |
| /* Convolutionally encode data into binary symbols */
 | |
|   enc216(unsigned char symbols[], unsigned char data[],
 | |
|        unsigned int nbytes, unsigned int startstate,
 | |
|        unsigned int endstate)
 | |
| {
 | |
|   int i,j,k,n=-1;
 | |
|   unsigned int encstate = startstate;
 | |
| 
 | |
|   for(k=0; k<nbytes; k++) {
 | |
|     for(i=7;i>=0;i--){
 | |
|       encstate = (encstate + encstate) + ((data[k] >> i) & 1);
 | |
|       for(j=0;j<N;j++) {
 | |
| 	n=n+1;
 | |
| 	symbols[n] = parity(encstate & Polys[j]);
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   // Flush out with zero tail.  (No need, if tail-biting code.)
 | |
|   for(i=0; i<K-1;i++){
 | |
|     encstate = (encstate << 1) | ((endstate >> i) & 1);
 | |
|     for(j=0;j<N;j++) {
 | |
|       n=n+1;
 | |
|       symbols[n] = parity(encstate & Polys[j]);
 | |
|     }
 | |
|   }
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| // Wrapper for calling "viterbi" from Fortran:
 | |
| //void __stdcall VITERBI(
 | |
| void vit216_(
 | |
| unsigned char symbols[],  /* Raw deinterleaved input symbols */
 | |
| unsigned int *Nbits,	  /* Number of decoded information bits */
 | |
| int mettab[2][256],	  /* Metric table, [sent sym][rx symbol] */
 | |
| unsigned char ddec[],	  /* Decoded output data */
 | |
| long *Metric              /* Final path metric (bigger is better) */
 | |
| ){
 | |
|   long metric;
 | |
|   vit216(&metric,ddec,symbols,*Nbits,mettab,0,0);
 | |
|   *Metric=metric;
 | |
| }
 | |
| 
 | |
| /* Viterbi decoder */
 | |
| int vit216(
 | |
| 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 startstate,         /* Encoder starting state */
 | |
| unsigned int endstate            /* Encoder ending state */
 | |
| ){
 | |
|   int bitcnt = -(K-1);
 | |
|   long m0,m1;
 | |
|   int i,j,sym,ipp;
 | |
|   int mets[1 << N];
 | |
|   unsigned long paths[(MAXNBITS+K-1)*D];
 | |
|   unsigned long *pp,mask;
 | |
|   long cmetric[1 << (K-1)],nmetric[1 << (K-1)];
 | |
|   
 | |
|   memset(paths,0,sizeof(paths));
 | |
| 
 | |
|   // Initialize on first time through:
 | |
|   if(!VDInit){
 | |
|     for(i=0;i<(1<<K);i++){
 | |
|       sym = 0;
 | |
|       for(j=0;j<N;j++)
 | |
| 	sym = (sym << 1) + parity(i & Polys[j]);
 | |
|       Syms[i] = sym;
 | |
|     }
 | |
|     VDInit++;
 | |
|   }
 | |
| 
 | |
|   // Keep only lower K-1 bits of specified startstate and endstate
 | |
|   startstate &= ~((1<<(K-1)) - 1);
 | |
|   endstate &=   ~((1<<(K-1)) - 1);
 | |
| 
 | |
|   /* Initialize starting metrics */
 | |
|   for(i=0;i< 1<<(K-1);i++)
 | |
|     cmetric[i] = -999999;
 | |
|   cmetric[startstate] = 0;
 | |
| 
 | |
|   pp = paths;
 | |
|   ipp=0;
 | |
|   for(;;){ /* For each data bit */
 | |
|     /* Read input symbols and compute branch metrics */
 | |
|     for(i=0;i< 1<<N;i++){
 | |
|       mets[i] = 0;
 | |
|       for(j=0;j<N;j++){
 | |
| 	mets[i] += mettab[(i >> (N-j-1)) & 1][symbols[j]];
 | |
|       }
 | |
|     }
 | |
|     symbols += N;
 | |
|     /* Run the add-compare-select operations */
 | |
|     mask = 1;
 | |
|     for(i=0;i< 1 << (K-1);i+=2){
 | |
|       int b1,b2;
 | |
|       
 | |
|       b1 = mets[Syms[i]];
 | |
|       nmetric[i] = m0 = cmetric[i/2] + b1; 
 | |
|       b2 = mets[Syms[i+1]];
 | |
|       b1 -= b2;
 | |
|       m1 = cmetric[(i/2) + (1<<(K-2))] + b2;
 | |
| 
 | |
|       if(m1 > m0){
 | |
| 	nmetric[i] = m1;
 | |
| 	*pp |= mask;
 | |
|       }
 | |
| 
 | |
|       m0 -= b1;
 | |
|       nmetric[i+1] = m0;
 | |
|       m1 += b1;
 | |
| 
 | |
|       if(m1 > m0){
 | |
| 	nmetric[i+1] = m1;
 | |
| 	*pp |= mask << 1;
 | |
|       }
 | |
| 
 | |
|       mask <<= 2;
 | |
|       if(mask == 0){
 | |
| 	mask = 1;
 | |
| 	pp++;
 | |
| 	ipp++;
 | |
|       }
 | |
|     }
 | |
|     if(mask != 1){
 | |
|       pp++;
 | |
|       ipp++;
 | |
|     }
 | |
|     if(++bitcnt == nbits){
 | |
|       *metric = nmetric[endstate];
 | |
|       break;
 | |
|     }
 | |
|     memcpy(cmetric,nmetric,sizeof(cmetric));
 | |
|   }
 | |
| 
 | |
|   /* Chain back from terminal state to produce decoded data */
 | |
|   if(data == NULL)
 | |
|     return 0;/* Discard output */
 | |
|   memset(data,0,(nbits+7)/8); /* round up in case nbits % 8 != 0 */
 | |
| 
 | |
|   for(i=nbits-1;i >= 0;i--){
 | |
|     //    int a0,a1;
 | |
|     pp -= D;
 | |
|     ipp -= D;
 | |
|     m0=endstate >> LOGLONGBITS;
 | |
|     m1=1L << (endstate & (LONGBITS-1));
 | |
|     if(pp[m0] & m1) {
 | |
|       //      a0=nmetric[endstate];
 | |
|       endstate |= (1 << (K-1));
 | |
|       //      a1=nmetric[endstate];
 | |
|       data[i>>3] |= 0x80 >> (i&7);
 | |
|       //      printf("B  %d  %d  %d  %d\n",*metric,i,a0,a1);
 | |
|     }
 | |
|     endstate >>= 1;
 | |
|   }
 | |
|   return 0;
 | |
| }
 |