www.pudn.com > fast.zip > coder.C


/* Modem for MIPS   AJF	  August 1996 
   V.32 encoding / decoding routines */ 
 
#include  
 
#include  
#include  
 
#include "modem.h" 
#include "coder.h" 
 
#define INF 1e6 
 
global c_complex ztab2[] = 
  { /* 2-bit constellation (ABDC) */ 
    /* also used by v32rx, v32tx */ 
    { -3.0, -1.0 }, { +1.0, -3.0 }, { -1.0, +3.0 }, { +3.0, +1.0 }, /* ABDC */ 
  }; 
 
static c_complex ztab4[] = 
  { /* 4-bit constellation */ 
    { +3.0, -3.0 }, { -1.0, +1.0 }, { -3.0, +3.0 }, { +1.0, -1.0 }, 
    { +3.0, +1.0 }, { -1.0, -3.0 }, { -3.0, -1.0 }, { +1.0, +3.0 }, 
    { -1.0, +3.0 }, { +3.0, -1.0 }, { +1.0, -3.0 }, { -3.0, +1.0 }, 
    { -3.0, -3.0 }, { +1.0, +1.0 }, { +3.0, +3.0 }, { -1.0, -1.0 }, 
  }; 
 
static uchar tfsmtab[NSTATES][NINPUTS] = 
  { /* trellis encoder fsm */ 
    { 0, 3, 2, 1 }, { 4, 5, 7, 6 }, { 1, 2, 3, 0 }, { 7, 6, 4, 5 }, 
    { 2, 1, 0, 3 }, { 6, 7, 5, 4 }, { 3, 0, 1, 2 }, { 5, 4, 6, 7 }, 
  }; 
 
static uchar nr_difftab[] =	/* for non-redundant (4800 bps) coding */ 
  { /* encoding:  indexed by Q1 Q2 I1 I2, gives Q3 Q4 
       decoding:  indexed by Q1 Q2 Q3 Q4, gives I1 I2 */ 
    1, 0, 3, 2,	 3, 1, 2, 0,  0, 2, 1, 3,  2, 3, 0, 1, 
  }; 
 
static uchar te_difftab[] =	/* for trellis encoding */ 
  { /* encoding:  indexed by Q1 Q2 I1 I2, gives Q3 Q4 */ 
    0, 1, 2, 3,	 1, 0, 3, 2,  2, 3, 1, 0,  3, 2, 0, 1, 
  }; 
 
static uchar td_difftab[] =	/* for trellis decoding */ 
  { /* decoding:  indexed by Q1 Q2 Q3 Q4, gives I1 I2 */ 
    0, 1, 2, 3,	 1, 0, 3, 2,  3, 2, 0, 1,  2, 3, 1, 0, 
  }; 
 
 
complex traininggen::get(int bc) 
  { int k; 
    if (bc < SEG_2) 
      { /* segment 1 : ABAB... */ 
	k = (bc & 1) ? 1 : 0; 
      } 
    else if (bc < SEG_3) 
      { /* segment 2 : CDCD... */ 
	k = (bc & 1) ? 2 : 3; 
      } 
    else 
      { /* segment 3 & 4 : scrambled sequence */ 
	int b1 = scr -> fwd(1); 
	int b2 = scr -> fwd(1); 
	if (bc < SEG_4) b2 = b1; 
	k = (b1 << 1) | b2; 
      } 
    return ztab2[k];	/* one of ABDC */ 
  } 
 
void encoder::setrate(ushort rw) 
  { rate = rw & (rb_4800 | rb_7200 | rb_9600 | rb_12000 | rb_14400); 
    t = 0; 
  } 
 
complex encoder::encode(int b) 
  { switch (rate) 
      { default: 
	    giveup("can't encode rate %04x", rate); 
 
	case rb_4800: 
	  { q = (q << 2) | b; 
	    int k = nr_difftab[q & 0xf]; 
	    q = (q & 0xc) | k; 
	    return ztab2[k]; 
	  } 
 
	case rb_7200: 
	  { q = (q << 2) | (b >> 1); 
	    int k = te_difftab[q & 0xf]; 
	    q = (q & 0xc) | k; 
	    int e = ((t & 1) << 3) | (k << 1) | (b & 1); 
	    t = tfsmtab[t][k];	/* advance trellis state */ 
	    return ztab4[e]; 
	  } 
      } 
  } 
 
void decoder::inittrellis()	/* private */ 
  { for (int i = 0; i < TLEN; i++) 
      { for (int j = 0; j < NSTATES; j++) 
	  { tnode *x = &trellis[i][j]; 
	    x -> path = 0;	/* 64 bits */ 
	    x -> svlen = (j == 0) ? 0.0 : INF; 
	    for (int k = 0; k < NINPUTS; k++) 
	      { int u = tfsmtab[j][k]; 
		tnode *y = &trellis[(i+1) % TLEN][u]; 
		x -> fwd[k] = y;    /* set up a path from node x to node y */ 
	      } 
	  } 
      } 
    tindex = 0; 
  } 
 
void decoder::printtrellis(char *fn) 
  { FILE *fi = fopen(fn, "w"); 
    if (fi == NULL) giveup("Can't create %s", fn); 
    for (int j = 0; j < NSTATES; j++) 
      { tnode *x = &trellis[tindex][j]; 
	fprintf(fi, "%d: %10.3f ", j, x -> svlen); 
	u64bit path = x -> path; 
	for (int i = 0; i < TLEN; i++) 
	  { int d = (path >> (TLEN-1)*3) & 7; 
	    putc('0' + d, fi); 
	    path <<= 3; 
	  } 
	putc('\n', fi); 
      } 
    fclose(fi); 
  } 
 
void decoder::setrate(ushort rw) 
  { rate = rw & (rb_4800 | rb_7200 | rb_9600 | rb_12000 | rb_14400); 
  } 
 
int decoder::decode(complex z) 
  { switch (rate) 
      { default: 
	    giveup("can't decode rate %04x", rate); 
 
	case rb_4800: 
	    q = (q << 1) | (2.0 * z.im > -z.re);	    /* b1 */ 
	    q = (q << 1) | (2.0 * z.re > +z.im);	    /* b2 */ 
	    return nr_difftab[q & 0xf];			    /* look up dibit from most recent 4 bits */ 
 
	case rb_7200: 
	  { pz = z;	/* remember for getez */ 
	    int r = viterbi(z); 
	    /* differentially decode and return result (3 bits) */ 
	    q = (q << 2) | (r >> 1);			    /* shift in y1, y2 from past r */ 
	    return (td_difftab[q & 0xf] << 1) | (r & 1);    /* diff. decode & return result */ 
	  } 
      } 
  } 
 
int decoder::viterbi(complex z)			/* private */ 
  { int ncol = (tindex+1) % TLEN;		/* index of next column */ 
    float metric[NSTATES];			/* dist^2 from z to closest point in j'th sub-constellation */ 
    uchar botbit[NSTATES];			/* unencoded bit */ 
    int jx = 0; 
    for (int j = 0; j < NSTATES; j++) 
      { float p0 = power(z - ztab4[jx++]); 
	float p1 = power(z - ztab4[jx++]); 
	if (p0 < p1) { metric[j] = p0; botbit[j] = 0; } 
	else { metric[j] = p1; botbit[j] = 1; } 
	trellis[ncol][j].svlen = INF; 
      } 
    for (int j = 0; j < NSTATES; j++) 
      { int t = (j & 1) << 2;			/* t bit */ 
	tnode *x = &trellis[tindex][j]; 
	float svlen = (x -> svlen) * 0.99;	/* length of survivor from x, reduced by a bit to ensure stability */ 
	for (int k = 0; k < NINPUTS; k++) 
	  { tnode *y = x -> fwd[k];		/* x .. y is the path */ 
	    float plen = svlen + metric[t+k];	/* work out total path length */ 
	    if (plen < y -> svlen) 
	      { y -> svlen = plen;		/* install as survivor */ 
		y -> path = (x -> path << 3) | (k << 1) | botbit[t+k]; 
	      } 
	  } 
      } 
    tindex = ncol;				/* move to next column */ 
    tnode *x = &trellis[tindex][0];		/* choose an arbitrary node at rh end */ 
    return (x -> path >> (TLEN-1)*3) & 7;	/* return bits about to drop off lh end */ 
  } 
 
static uchar ctab4[] = 
  { 0xf, 0x1, 0x3, 0xd, 
    0x5, 0x8, 0xa, 0x7, 
    0x6, 0xb, 0x9, 0x4, 
    0xc, 0x2, 0x0, 0xe, 
  }; 
 
complex decoder::getez() 
  { switch (rate) 
      { default: 
	    giveup("can't decode rate %04x", rate); 
 
	case rb_4800: 
	    return ztab2[q & 3];		/* return quantized version of z, one of ABDC	*/ 
 
	case rb_7200: 
	  { int r = 0; 
	    r = (r << 1) | (pz.re > +2.0 || pz.re < -2.0); 
	    r = (r << 1) | (pz.im > +2.0 || pz.im < -2.0); 
	    r = (r << 1) | (pz.re > 0.0); 
	    r = (r << 1) | (pz.im > 0.0); 
	    r = ctab4[r];			/* get 4-bit constellation posn */ 
	    return ztab4[r];			/* return quantized version of z */ 
	  } 
      } 
  }