kopia lustrzana https://github.com/jamescoxon/dl-fldigi
260 wiersze
5.6 KiB
C++
260 wiersze
5.6 KiB
C++
// ----------------------------------------------------------------------------
|
|
// viterbi.cxx -- Viterbi decoder
|
|
//
|
|
// Copyright (C) 2006
|
|
// Dave Freese, W1HKJ
|
|
//
|
|
// Adapted from code contained in gmfsk source code distribution.
|
|
//
|
|
// This file is part of fldigi.
|
|
//
|
|
// Fldigi is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// Fldigi is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with fldigi. If not, see <http://www.gnu.org/licenses/>.
|
|
// ----------------------------------------------------------------------------
|
|
|
|
#include <config.h>
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <limits.h>
|
|
|
|
#include "viterbi.h"
|
|
#include "misc.h"
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
viterbi::viterbi(int k, int poly1, int poly2)
|
|
{
|
|
outsize = 1 << k;
|
|
nstates = 1 << (k - 1);
|
|
_k = k;
|
|
_poly1 = poly1;
|
|
_poly2 = poly2;
|
|
|
|
output = new int[outsize];
|
|
|
|
for (int i = 0; i < PATHMEM; i++) {
|
|
metrics[i] = new int[nstates];
|
|
history[i] = new int[nstates];
|
|
}
|
|
|
|
init();
|
|
}
|
|
|
|
viterbi::~viterbi()
|
|
{
|
|
if (output) delete [] output;
|
|
for (int i = 0; i < PATHMEM; i++) {
|
|
if (metrics[i]) delete [] metrics[i];
|
|
if (history[i]) delete [] history[i];
|
|
}
|
|
}
|
|
|
|
void viterbi::init(void)
|
|
{
|
|
if(output) {
|
|
_traceback = _k * 12; // takes >= 12 constraint lengths to calculate from an arbitrary state, when punctured
|
|
_chunksize = 8;
|
|
|
|
for (int i = 0; i < outsize; i++) {
|
|
output[i] = parity(_poly1 & i) | (parity(_poly2 & i) << 1);
|
|
}
|
|
|
|
for (int i = 0; i < 256; i++) {
|
|
mettab[0][i] = 128 - i;
|
|
mettab[1][i] = i - 128;
|
|
}
|
|
|
|
memset(sequence, 0, sizeof(sequence));
|
|
|
|
reset();
|
|
}
|
|
}
|
|
|
|
|
|
void viterbi::reset()
|
|
{
|
|
for (int i = 0; i < PATHMEM; i++) {
|
|
memset(metrics[i], 0, nstates * sizeof(int));
|
|
memset(history[i], 0, nstates * sizeof(int));
|
|
}
|
|
ptr = 0;
|
|
}
|
|
|
|
int viterbi::settraceback(int trace)
|
|
{
|
|
if (trace < 0 || trace > PATHMEM - 1)
|
|
return -1;
|
|
_traceback = trace;
|
|
return 0;
|
|
}
|
|
|
|
int viterbi::setchunksize(int chunk)
|
|
{
|
|
if (chunk < 1 || chunk > _traceback)
|
|
return -1;
|
|
_chunksize = chunk;
|
|
return 0;
|
|
}
|
|
|
|
int viterbi::traceback(int *metric)
|
|
{
|
|
int bestmetric, beststate;
|
|
unsigned int p, c = 0;
|
|
|
|
p = (ptr - 1) % PATHMEM;
|
|
|
|
// Find the state with the best metric
|
|
bestmetric = INT_MIN;
|
|
beststate = 0;
|
|
|
|
for (int i = 0; i < nstates; i++) {
|
|
if (metrics[p][i] > bestmetric) {
|
|
bestmetric = metrics[p][i];
|
|
beststate = i;
|
|
}
|
|
}
|
|
|
|
// Trace back 'traceback' steps, starting from the best state
|
|
sequence[p] = beststate;
|
|
|
|
for (int i = 0; i < _traceback; i++) {
|
|
unsigned int prev = (p - 1) % PATHMEM;
|
|
|
|
sequence[prev] = history[p][sequence[p]];
|
|
p = prev;
|
|
}
|
|
|
|
if (metric)
|
|
*metric = metrics[p][sequence[p]];
|
|
|
|
// Decode 'chunksize' bits
|
|
for (int i = 0; i < _chunksize; i++) {
|
|
// low bit of state is the previous input bit
|
|
c = (c << 1) | (sequence[p] & 1);
|
|
p = (p + 1) % PATHMEM;
|
|
}
|
|
|
|
if (metric)
|
|
*metric = metrics[p][sequence[p]] - *metric;
|
|
|
|
return c;
|
|
}
|
|
|
|
int viterbi::decode(unsigned char *sym, int *metric)
|
|
{
|
|
unsigned int currptr, prevptr;
|
|
int met[4];
|
|
|
|
currptr = ptr;
|
|
prevptr = (currptr - 1) % PATHMEM;
|
|
// if (prevptr < 0) prevptr = PATHMEM - 1;
|
|
|
|
met[0] = mettab[0][sym[1]] + mettab[0][sym[0]];
|
|
met[1] = mettab[0][sym[1]] + mettab[1][sym[0]];
|
|
met[2] = mettab[1][sym[1]] + mettab[0][sym[0]];
|
|
met[3] = mettab[1][sym[1]] + mettab[1][sym[0]];
|
|
|
|
// met[0] = 256 - sym[1] - sym[0];
|
|
// met[1] = sym[0] - sym[1];
|
|
// met[2] = sym[1] - sym[0];
|
|
// met[3] = sym[0] + sym[1] - 256;
|
|
|
|
for (int n = 0; n < nstates; n++) {
|
|
int p0, p1, s0, s1, m0, m1;
|
|
|
|
m0 = 0;
|
|
m1 = 0;
|
|
s0 = n;
|
|
s1 = n + nstates;
|
|
|
|
p0 = s0 >> 1;
|
|
p1 = s1 >> 1;
|
|
|
|
m0 = metrics[prevptr][p0] + met[output[s0]];
|
|
m1 = metrics[prevptr][p1] + met[output[s1]];
|
|
|
|
if (m0 > m1) {
|
|
metrics[currptr][n] = m0;
|
|
history[currptr][n] = p0;
|
|
} else {
|
|
metrics[currptr][n] = m1;
|
|
history[currptr][n] = p1;
|
|
}
|
|
}
|
|
|
|
ptr = (ptr + 1) % PATHMEM;
|
|
|
|
if ((ptr % _chunksize) == 0)
|
|
return traceback(metric);
|
|
|
|
if (metrics[currptr][0] > INT_MAX / 2) {
|
|
for (int i = 0; i < PATHMEM; i++)
|
|
for (int j = 0; j < nstates; j++)
|
|
metrics[i][j] -= INT_MAX / 2;
|
|
}
|
|
|
|
if (metrics[currptr][0] < INT_MIN / 2) {
|
|
for (int i = 0; i < PATHMEM; i++)
|
|
for (int j = 0; j < nstates; j++)
|
|
metrics[i][j] += INT_MIN / 2;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
#include <iostream>
|
|
encoder::encoder(int k, int poly1, int poly2)
|
|
{
|
|
int size = 1 << k; /* size of the output table */
|
|
output = new int[size];
|
|
_k = k;
|
|
_poly1 = poly1;
|
|
_poly2 = poly2;
|
|
|
|
init();
|
|
}
|
|
|
|
encoder::~encoder()
|
|
{
|
|
delete [] output;
|
|
}
|
|
|
|
int encoder::encode(int bit)
|
|
{
|
|
shreg = (shreg << 1) | !!bit;
|
|
|
|
return output[shreg & shregmask];
|
|
}
|
|
|
|
void encoder::init(void)
|
|
{
|
|
if(output) {
|
|
int size = 1 << _k; /* size of the output table */
|
|
|
|
// output contains 2 bits in positions 0 and 1 describing the state machine
|
|
// for each bit delay, ie: for k = 7 there are 128 possible state pairs.
|
|
// the modulo-2 addition for polynomial 1 is in bit 0
|
|
// the modulo-2 addition for polynomial 2 is in bit 1
|
|
// the allowable state outputs are 0, 1, 2 and 3
|
|
for (int i = 0; i < size; i++) {
|
|
output[i] = parity(_poly1 & i) | (parity(_poly2 & i) << 1);
|
|
}
|
|
shreg = 0;
|
|
shregmask = size - 1;
|
|
}
|
|
}
|
|
|
|
|