/* * Reset decoder * * Set accumulated path metrics to zero. For termination other than * tail-biting, initialize the zero state as the encoder starting state. * Intialize with the maximum accumulated sum at length equal to the * constraint length. */ static void reset_decoder(vdecoder dec, CONV_TERM term) { int ns = dec.trellis.num_states; memset(dec.trellis.sums, 0, sizeof(short) * ns); if (term != CONV_TERM.TAIL_BITING) { dec.trellis.sums[0] = (short)(sbyte.MaxValue * dec.n * dec.k); } }
static void _traceback_rec(vdecoder dec, int state, sbyte *o, int len) { int i; int path; for (i = len - 1; i >= 0; i--) { path = (int)(dec.paths[i][state] + 1); o[i] = (sbyte)(path ^ dec.trellis.vals[state]); state = vstate_lshift(state, dec.k, (int)path); } }
/* * Traceback and generate decoded output * * For tail biting, find the largest accumulated path metric at the final state * followed by two trace back passes. For zero flushing the final state is * always zero with a single traceback path. */ static int traceback(vdecoder dec, sbyte *o, CONV_TERM term, int len) { int i, sum, max_p = -1, max = -1; int path, state = 0; if (term == CONV_TERM.TAIL_BITING) { for (i = 0; i < dec.trellis.num_states; i++) { sum = dec.trellis.sums[i]; if (sum > max) { max_p = max; max = sum; state = (int)i; } } if (max < 0) { throw new Exception(); } for (i = dec.len - 1; i >= len + TAIL_BITING_EXTRA; i--) { path = (int)(dec.paths[i][state] + 1); int prestate = state; state = vstate_lshift(state, dec.k, (int)path); //Console.WriteLine($"[Q] path={path}, state={state}, prestate={state}, k={dec.k}, i={i}"); } } else { for (i = dec.len - 1; i >= len; i--) { path = (int)(dec.paths[i][state] + 1); state = vstate_lshift(state, dec.k, (int)path); } } if (dec.recursive != 0) { _traceback_rec(dec, state, o, len); } else { state = _traceback(dec, state, o, len, term == CONV_TERM.TAIL_BITING ? TAIL_BITING_EXTRA : 0); } /* Don't handle the odd case of recursize tail-biting codes */ return(max - max_p); }
static int _traceback(vdecoder dec, int state, sbyte *o, int len, int offset) { int i; int path; for (i = len - 1; i >= 0; i--) { path = (int)(dec.paths[i + offset][state] + 1); o[i] = dec.trellis.vals[state]; state = vstate_lshift(state, dec.k, (int)path); } return(state); }
static void reset_vdec(vdecoder dec, lte_conv_code code) { dec.n = code.n; dec.k = code.k; dec.recursive = code.rgen != 0 ? 1 : 0; dec.intrvl = short.MaxValue / (dec.n * sbyte.MaxValue) - dec.k; if (dec.n != 3 || dec.k != 7) { throw new Exception(); } if (code.term == CONV_TERM.FLUSH) { dec.len = code.len + code.k - 1; } else { dec.len = code.len + TAIL_BITING_EXTRA * 2; } }
/* * Allocate decoder object * * Subtract the constraint length K on the normalization interval to * accommodate the initialization path metric at state zero. */ static vdecoder alloc_vdec(lte_conv_code code) { int i, ns; ns = NUM_STATES(code.k); vdecoder dec = new vdecoder(); dec.n = code.n; dec.k = code.k; dec.recursive = code.rgen != 0 ? 1 : 0; dec.intrvl = short.MaxValue / (dec.n * sbyte.MaxValue) - dec.k; if (dec.n != 3 || dec.k != 7) { throw new Exception(); } if (code.term == CONV_TERM.FLUSH) { dec.len = code.len + code.k - 1; } else { dec.len = code.len + TAIL_BITING_EXTRA * 2; } dec.trellis = generate_trellis(code); dec.pathsBuffer = UnsafeBuffer.Create(sizeof(short *) * dec.len * ns); dec.pathsPtr = (short *)dec.pathsBuffer; dec.paths = new short *[dec.len]; for (i = 0; i < dec.len; i++) { dec.paths[i] = &dec.pathsPtr[i * ns]; } return(dec); }
/* * Forward trellis recursion * * Generate branch metrics and path metrics with a combined function. Only * accumulated path metric sums and path selections are stored. Normalize on * the interval specified by the decoder. */ static void _conv_decode(vdecoder dec, sbyte *seq, CONV_TERM term, int len) { int i, j = 0; vtrellis trellis = dec.trellis; if (term == CONV_TERM.TAIL_BITING) { j = len - TAIL_BITING_EXTRA; } for (i = 0; i < dec.len; i++, j++) { if (term == CONV_TERM.TAIL_BITING && j == len) { j = 0; } gen_metrics_k7_n3(&seq[dec.n * j], trellis.outputs, trellis.sums, dec.paths[i], ((i % dec.intrvl) != 0 ? 0 : 1)); //flipped on purpose } }
/* Release decoder object */ static void free_vdec(vdecoder dec) { dec.pathsBuffer.Dispose(); }