1892 lines
50 KiB
C++
1892 lines
50 KiB
C++
/*
|
|
* Copyright 2013, 2014 Range Networks, Inc.
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Affero General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
|
|
* This program 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 Affero General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Affero General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
* This use of this software may be subject to additional restrictions.
|
|
* See the LEGAL file in the main directory for details.
|
|
*/
|
|
|
|
|
|
#include "BitVector.h"
|
|
#include "AmrCoder.h"
|
|
#include <iostream>
|
|
#include <stdio.h>
|
|
#include <sstream>
|
|
|
|
using namespace std;
|
|
|
|
|
|
|
|
ViterbiTCH_AFS12_2::ViterbiTCH_AFS12_2()
|
|
{
|
|
assert(mDeferral < 32);
|
|
mCoeffs[0] = 0x019;
|
|
mCoeffsFB[0] = 0x019;
|
|
mCoeffs[1] = 0x01b;
|
|
mCoeffsFB[1] = 0x019;
|
|
for (unsigned i = 0; i < mIRate; i++) {
|
|
computeStateTables(i);
|
|
}
|
|
computeGeneratorTable();
|
|
}
|
|
|
|
|
|
//void BitVector::encode(const ViterbiTCH_AFS12_2& coder, BitVector& target) const
|
|
void ViterbiTCH_AFS12_2::encode(const BitVector& in, BitVector& target) const
|
|
{
|
|
assert(in.size() == 250);
|
|
assert(target.size() == 508);
|
|
const char *u = in.begin();
|
|
char *C = target.begin();
|
|
const unsigned H = 4;
|
|
BitVector r(254+H);
|
|
for (int k = -H; k <= -1; k++) r[k+H] = 0;
|
|
for (unsigned k = 0; k <= 249; k++) {
|
|
r[k+H] = u[k] ^ r[k-3+H] ^ r[k-4+H];
|
|
C[2*k] = u[k];
|
|
C[2*k+1] = r[k+H] ^ r[k-1+H] ^ r[k-3+H] ^ r[k-4+H];
|
|
}
|
|
// termination
|
|
for (unsigned k = 250; k <= 253; k++) {
|
|
r[k+H] = 0;
|
|
C[2*k] = r[k-3+H] ^ r[k-4+H];
|
|
C[2*k+1] = r[k+H] ^ r[k-1+H] ^ r[k-3+H] ^ r[k-4+H];
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//void BitVector::encode(const ViterbiTCH_AFS10_2& coder, BitVector& target)
|
|
void ViterbiTCH_AFS10_2::encode(const BitVector& in, BitVector& target) const
|
|
{
|
|
assert(in.size() == 210);
|
|
assert(target.size() == 642);
|
|
const char *u = in.begin();
|
|
char *C = target.begin();
|
|
const unsigned H = 4;
|
|
BitVector r(214+H);
|
|
for (int k = -H; k <= -1; k++) r[k+H] = 0;
|
|
for (unsigned k = 0; k <= 209; k++) {
|
|
r[k+H] = u[k] ^ r[k-1+H] ^ r[k-2+H] ^ r[k-3+H] ^ r[k-4+H];
|
|
C[3*k] = r[k+H] ^ r[k-1+H] ^ r[k-3+H] ^ r[k-4+H];
|
|
C[3*k+1] = r[k+H] ^ r[k-2+H] ^ r[k-4+H];
|
|
C[3*k+2] = u[k];
|
|
}
|
|
// termination
|
|
for (unsigned k = 210; k <= 213; k++) {
|
|
r[k+H] = 0;
|
|
C[3*k] = r[k+H] ^ r[k-1+H] ^ r[k-3+H] ^ r[k-4+H];
|
|
C[3*k+1] = r[k+H] ^ r[k-2+H] ^ r[k-4+H];
|
|
C[3*k+2] = r[k-1+H] ^ r[k-2+H] ^ r[k-3+H] ^ r[k-4+H];
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//void BitVector::encode(const ViterbiTCH_AFS7_95& coder, BitVector& target)
|
|
void ViterbiTCH_AFS7_95::encode(const BitVector& in, BitVector& target) const
|
|
{
|
|
assert(in.size() == 165);
|
|
assert(target.size() == 513);
|
|
const char *u = in.begin();
|
|
char *C = target.begin();
|
|
const unsigned H = 6;
|
|
BitVector r(171+H);
|
|
for (int k = -H; k <= -1; k++) r[k+H] = 0;
|
|
for (unsigned k = 0; k <= 164; k++) {
|
|
r[k+H] = u[k] ^ r[k-2+H] ^ r[k-3+H] ^ r[k-5+H] ^ r[k-6+H];
|
|
C[3*k] = u[k];
|
|
C[3*k+1] = r[k+H] ^ r[k-1+H] ^ r[k-4+H] ^ r[k-6+H];
|
|
C[3*k+2] = r[k+H] ^ r[k-1+H] ^ r[k-2+H] ^ r[k-3+H] ^ r[k-4+H] ^ r[k-6+H];
|
|
}
|
|
// termination
|
|
for (unsigned k = 165; k <= 170; k++) {
|
|
r[k+H] = 0;
|
|
C[3*k] = r[k-2+H] ^ r[k-3+H] ^ r[k-5+H] ^ r[k-6+H];
|
|
C[3*k+1] = r[k+H] ^ r[k-1+H] ^ r[k-4+H] ^ r[k-6+H];
|
|
C[3*k+2] = r[k+H] ^ r[k-1+H] ^ r[k-2+H] ^ r[k-3+H] ^ r[k-4+H] ^ r[k-6+H];
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void ViterbiTCH_AFS7_4::encode(const BitVector& in, BitVector& target) const
|
|
{
|
|
assert(in.size() == 154);
|
|
assert(target.size() == 474);
|
|
const char *u = in.begin();
|
|
char *C = target.begin();
|
|
const unsigned H = 4;
|
|
BitVector r(158+H);
|
|
for (int k = -H; k <= -1; k++) r[k+H] = 0;
|
|
for (unsigned k = 0; k <= 153; k++) {
|
|
r[k+H] = u[k] ^ r[k-1+H] ^ r[k-2+H] ^ r[k-3+H] ^ r[k-4+H];
|
|
C[3*k] = r[k+H] ^ r[k-1+H] ^ r[k-3+H] ^ r[k-4+H];
|
|
C[3*k+1] = r[k+H] ^ r[k-2+H] ^ r[k-4+H];
|
|
C[3*k+2] = u[k];
|
|
}
|
|
// termination
|
|
for (unsigned k = 154; k <= 157; k++) {
|
|
r[k+H] = 0;
|
|
C[3*k] = r[k+H] ^ r[k-1+H] ^ r[k-3+H] ^ r[k-4+H];
|
|
C[3*k+1] = r[k+H] ^ r[k-2+H] ^ r[k-4+H];
|
|
C[3*k+2] = r[k-1+H] ^ r[k-2+H] ^ r[k-3+H] ^ r[k-4+H];
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void ViterbiTCH_AFS6_7::encode(const BitVector& in, BitVector& target) const
|
|
{
|
|
assert(in.size() == 140);
|
|
assert(target.size() == 576);
|
|
const char *u = in.begin();
|
|
char *C = target.begin();
|
|
const unsigned H = 4;
|
|
BitVector r(144+H);
|
|
for (int k = -H; k <= -1; k++) r[k+H] = 0;
|
|
for (unsigned k = 0; k <= 139; k++) {
|
|
r[k+H] = u[k] ^ r[k-1+H] ^ r[k-2+H] ^ r[k-3+H] ^ r[k-4+H];
|
|
C[4*k] = r[k+H] ^ r[k-1+H] ^ r[k-3+H] ^ r[k-4+H];
|
|
C[4*k+1] = r[k+H] ^ r[k-2+H] ^ r[k-4+H];
|
|
C[4*k+2] = u[k];
|
|
C[4*k+3] = u[k];
|
|
}
|
|
// termination
|
|
for (unsigned k = 140; k <= 143; k++) {
|
|
r[k+H] = 0;
|
|
C[4*k] = r[k+H] ^ r[k-1+H] ^ r[k-3+H] ^ r[k-4+H];
|
|
C[4*k+1] = r[k+H] ^ r[k-2+H] ^ r[k-4+H];
|
|
C[4*k+2] = r[k-1+H] ^ r[k-2+H] ^ r[k-3+H] ^ r[k-4+H];
|
|
C[4*k+3] = r[k-1+H] ^ r[k-2+H] ^ r[k-3+H] ^ r[k-4+H];
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void ViterbiTCH_AFS5_9::encode(const BitVector& in, BitVector& target) const
|
|
{
|
|
assert(in.size() == 124);
|
|
assert(target.size() == 520);
|
|
const char *u = in.begin();
|
|
char *C = target.begin();
|
|
const unsigned H = 6;
|
|
BitVector r(130+H);
|
|
for (int k = -H; k <= -1; k++) r[k+H] = 0;
|
|
for (unsigned k = 0; k <= 123; k++) {
|
|
r[k+H] = u[k] ^ r[k-1+H] ^ r[k-2+H] ^ r[k-3+H] ^ r[k-4+H] ^ r[k-6+H];
|
|
C[4*k] = r[k+H] ^ r[k-2+H] ^ r[k-3+H] ^ r[k-5+H] ^ r[k-6+H];
|
|
C[4*k+1] = r[k+H] ^ r[k-1+H] ^ r[k-4+H] ^ r[k-6+H];
|
|
C[4*k+2] = u[k];
|
|
C[4*k+3] = u[k];
|
|
}
|
|
// termination
|
|
for (unsigned k = 124; k <= 129; k++) {
|
|
r[k+H] = 0;
|
|
C[4*k] = r[k+H] ^ r[k-2+H] ^ r[k-3+H] ^ r[k-5+H] ^ r[k-6+H];
|
|
C[4*k+1] = r[k+H] ^ r[k-1+H] ^ r[k-4+H] ^ r[k-6+H];
|
|
C[4*k+2] = r[k-1+H] ^ r[k-2+H] ^ r[k-3+H] ^ r[k-4+H] ^ r[k-6+H];
|
|
C[4*k+3] = r[k-1+H] ^ r[k-2+H] ^ r[k-3+H] ^ r[k-4+H] ^ r[k-6+H];
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void ViterbiTCH_AFS5_15::encode(const BitVector& in, BitVector& target) const
|
|
{
|
|
assert(in.size() == 109);
|
|
assert(target.size() == 565);
|
|
const char *u = in.begin();
|
|
char *C = target.begin();
|
|
const unsigned H = 4;
|
|
BitVector r(113+H);
|
|
for (int k = -H; k <= -1; k++) r[k+H] = 0;
|
|
for (unsigned k = 0; k <= 108; k++) {
|
|
r[k+H] = u[k] ^ r[k-1+H] ^ r[k-2+H] ^ r[k-3+H] ^ r[k-4+H];
|
|
C[5*k] = r[k+H] ^ r[k-1+H] ^ r[k-3+H] ^ r[k-4+H];
|
|
C[5*k+1] = r[k+H] ^ r[k-1+H] ^ r[k-3+H] ^ r[k-4+H];
|
|
C[5*k+2] = r[k+H] ^ r[k-2+H] ^ r[k-4+H];
|
|
C[5*k+3] = u[k];
|
|
C[5*k+4] = u[k];
|
|
}
|
|
// termination
|
|
for (unsigned k = 109; k <= 112; k++) {
|
|
r[k+H] = 0;
|
|
C[5*k] = r[k+H] ^ r[k-1+H] ^ r[k-3+H] ^ r[k-4+H];
|
|
C[5*k+1] = r[k+H] ^ r[k-1+H] ^ r[k-3+H] ^ r[k-4+H];
|
|
C[5*k+2] = r[k+H] ^ r[k-2+H] ^ r[k-4+H];
|
|
C[5*k+3] = r[k-1+H] ^ r[k-2+H] ^ r[k-3+H] ^ r[k-4+H];
|
|
C[5*k+4] = r[k-1+H] ^ r[k-2+H] ^ r[k-3+H] ^ r[k-4+H];
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void ViterbiTCH_AFS4_75::encode(const BitVector& in, BitVector& target) const
|
|
{
|
|
assert(in.size() == 101);
|
|
assert(target.size() == 535);
|
|
const char *u = in.begin();
|
|
char *C = target.begin();
|
|
const unsigned H = 6;
|
|
BitVector r(107+H);
|
|
for (int k = -H; k <= -1; k++) r[k+H] = 0;
|
|
for (unsigned k = 0; k <= 100; k++) {
|
|
r[k+H] = u[k] ^ r[k-1+H] ^ r[k-2+H] ^ r[k-3+H] ^ r[k-4+H] ^ r[k-6+H];
|
|
C[5*k] = r[k+H] ^ r[k-2+H] ^ r[k-3+H] ^ r[k-5+H] ^ r[k-6+H];
|
|
C[5*k+1] = r[k+H] ^ r[k-2+H] ^ r[k-3+H] ^ r[k-5+H] ^ r[k-6+H];
|
|
C[5*k+2] = r[k+H] ^ r[k-1+H] ^ r[k-4+H] ^ r[k-6+H];
|
|
C[5*k+3] = u[k];
|
|
C[5*k+4] = u[k];
|
|
}
|
|
// termination
|
|
for (unsigned k = 101; k <= 106; k++) {
|
|
r[k+H] = 0;
|
|
C[5*k] = r[k+H] ^ r[k-2+H] ^ r[k-3+H] ^ r[k-5+H] ^ r[k-6+H];
|
|
C[5*k+1] = r[k+H] ^ r[k-2+H] ^ r[k-3+H] ^ r[k-5+H] ^ r[k-6+H];
|
|
C[5*k+2] = r[k+H] ^ r[k-1+H] ^ r[k-4+H] ^ r[k-6+H];
|
|
C[5*k+3] = r[k+H] ^ r[k-2+H] ^ r[k-3+H] ^ r[k-4+H] ^ r[k-6+H];
|
|
C[5*k+4] = r[k-1+H] ^ r[k-2+H] ^ r[k-3+H] ^ r[k-4+H] ^ r[k-6+H];
|
|
}
|
|
}
|
|
|
|
|
|
void ViterbiTCH_AFS12_2::initializeStates()
|
|
{
|
|
for (unsigned i=0; i<mIStates; i++) vitClear(mSurvivors[i]);
|
|
for (unsigned i=0; i<mNumCands; i++) vitClear(mCandidates[i]);
|
|
}
|
|
|
|
|
|
|
|
void ViterbiTCH_AFS12_2::computeStateTables(unsigned g)
|
|
{
|
|
assert(g<mIRate);
|
|
for (unsigned state=0; state<mIStates; state++) {
|
|
for (unsigned in = 0; in <= 1; in++) {
|
|
uint32_t inputVal = (state<<1) | in;
|
|
mStateTable[g][inputVal] = applyPoly(inputVal, mCoeffs[g] ^ mCoeffsFB[g], mOrder+1) ^ in;
|
|
}
|
|
}
|
|
}
|
|
|
|
void ViterbiTCH_AFS12_2::computeGeneratorTable()
|
|
{
|
|
for (unsigned index=0; index<mIStates*2; index++) {
|
|
uint32_t t = 0;
|
|
for (unsigned i = 0; i < mIRate; i++) {
|
|
t = (t << 1) | mStateTable[i][index];
|
|
}
|
|
mGeneratorTable[index] = t;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void ViterbiTCH_AFS12_2::branchCandidates()
|
|
{
|
|
// Branch to generate new input states.
|
|
const vCand *sp = mSurvivors;
|
|
for (unsigned cand=0; cand<mNumCands; cand+=2) {
|
|
uint32_t oStateShifted = (sp->oState) << mIRate;
|
|
for (unsigned in = 0; in <= 1; in++) {
|
|
mCandidates[cand+in].iState = ((sp->iState) << 1) | in;
|
|
mCandidates[cand+in].cost = sp->cost;
|
|
uint32_t outputs = oStateShifted;
|
|
for (unsigned out = 0; out < mIRate; out++) {
|
|
char feedback = applyPoly(sp->rState[out], mCoeffsFB[out] ^ 1, mOrder+1);
|
|
char rState = (((sp->rState[out]) ^ feedback) << 1) | in;
|
|
mCandidates[cand+in].rState[out] = rState;
|
|
outputs |= (mGeneratorTable[rState & mCMask] & (1 << (mIRate - out - 1)));
|
|
}
|
|
mCandidates[cand+in].oState = outputs;
|
|
}
|
|
sp++;
|
|
}
|
|
}
|
|
|
|
|
|
void ViterbiTCH_AFS12_2::getSoftCostMetrics(const uint32_t inSample, const float *matchCost, const float *mismatchCost)
|
|
{
|
|
const float *cTab[2] = {matchCost,mismatchCost};
|
|
for (unsigned i=0; i<mNumCands; i++) {
|
|
vCand& thisCand = mCandidates[i];
|
|
const unsigned mismatched = inSample ^ (thisCand.oState);
|
|
for (unsigned i = 0; i < mIRate; i++) {
|
|
thisCand.cost += cTab[(mismatched>>i)&0x01][mIRate-i-1];
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void ViterbiTCH_AFS12_2::pruneCandidates()
|
|
{
|
|
const vCand* c1 = mCandidates; // 0-prefix
|
|
const vCand* c2 = mCandidates + mIStates; // 1-prefix
|
|
for (unsigned i=0; i<mIStates; i++) {
|
|
if (c1[i].cost < c2[i].cost) mSurvivors[i] = c1[i];
|
|
else mSurvivors[i] = c2[i];
|
|
}
|
|
}
|
|
|
|
|
|
const ViterbiTCH_AFS12_2::vCand& ViterbiTCH_AFS12_2::minCost() const
|
|
{
|
|
int minIndex = 0;
|
|
float minCost = mSurvivors[0].cost;
|
|
for (unsigned i=1; i<mIStates; i++) {
|
|
const float thisCost = mSurvivors[i].cost;
|
|
if (thisCost>=minCost) continue;
|
|
minCost = thisCost;
|
|
minIndex=i;
|
|
}
|
|
return mSurvivors[minIndex];
|
|
}
|
|
|
|
|
|
const ViterbiTCH_AFS12_2::vCand& ViterbiTCH_AFS12_2::step(uint32_t inSample, const float *probs, const float *iprobs)
|
|
{
|
|
branchCandidates();
|
|
getSoftCostMetrics(inSample,probs,iprobs);
|
|
pruneCandidates();
|
|
return minCost();
|
|
}
|
|
|
|
|
|
|
|
void ViterbiTCH_AFS12_2::decode(const SoftVector &in, BitVector& target)
|
|
{
|
|
ViterbiTCH_AFS12_2 &decoder = *this;
|
|
const size_t sz = in.size() - 8;
|
|
const unsigned deferral = decoder.deferral();
|
|
const size_t ctsz = sz + deferral*decoder.iRate();
|
|
assert(sz == decoder.iRate()*target.size());
|
|
|
|
// Build a "history" array where each element contains the full history.
|
|
uint32_t history[ctsz];
|
|
{
|
|
BitVector bits = in.sliced();
|
|
uint32_t accum = 0;
|
|
for (size_t i=0; i<sz; i++) {
|
|
accum = (accum<<1) | bits.bit(i);
|
|
history[i] = accum;
|
|
}
|
|
// Repeat last bit at the end.
|
|
for (size_t i=sz; i<ctsz; i++) {
|
|
accum = (accum<<1) | (accum & 0x01);
|
|
history[i] = accum;
|
|
}
|
|
}
|
|
|
|
// Precompute metric tables.
|
|
float matchCostTable[ctsz];
|
|
float mismatchCostTable[ctsz];
|
|
{
|
|
const float *dp = in.begin();
|
|
for (size_t i=0; i<sz; i++) {
|
|
// pVal is the probability that a bit is correct.
|
|
// ipVal is the probability that a bit is incorrect.
|
|
float pVal = dp[i];
|
|
if (pVal>0.5F) pVal = 1.0F-pVal;
|
|
float ipVal = 1.0F-pVal;
|
|
// This is a cheap approximation to an ideal cost function.
|
|
if (pVal<0.01F) pVal = 0.01;
|
|
if (ipVal<0.01F) ipVal = 0.01;
|
|
matchCostTable[i] = 0.25F/ipVal;
|
|
mismatchCostTable[i] = 0.25F/pVal;
|
|
}
|
|
|
|
// pad end of table with unknowns
|
|
for (size_t i=sz; i<ctsz; i++) {
|
|
matchCostTable[i] = 0.5F;
|
|
mismatchCostTable[i] = 0.5F;
|
|
}
|
|
}
|
|
|
|
{
|
|
decoder.initializeStates();
|
|
// Each sample of history[] carries its history.
|
|
// So we only have to process every iRate-th sample.
|
|
const unsigned step = decoder.iRate();
|
|
// input pointer
|
|
const uint32_t *ip = history + step - 1;
|
|
// output pointers
|
|
char *op = target.begin();
|
|
const char *const opt = target.end();
|
|
// table pointers
|
|
const float* match = matchCostTable;
|
|
const float* mismatch = mismatchCostTable;
|
|
size_t oCount = 0;
|
|
while (op<opt) {
|
|
// Viterbi algorithm
|
|
assert(match-matchCostTable<(int)(sizeof(matchCostTable)/sizeof(matchCostTable[0])-1));
|
|
assert(mismatch-mismatchCostTable<(int)(sizeof(mismatchCostTable)/sizeof(mismatchCostTable[0])-1));
|
|
const ViterbiTCH_AFS12_2::vCand &minCost = decoder.step(*ip, match, mismatch);
|
|
ip += step;
|
|
match += step;
|
|
mismatch += step;
|
|
// output
|
|
if (oCount>=deferral) *op++ = (minCost.iState >> deferral)&0x01;
|
|
oCount++;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
ViterbiTCH_AFS10_2::ViterbiTCH_AFS10_2()
|
|
{
|
|
assert(mDeferral < 32);
|
|
mCoeffs[0] = 0x01b;
|
|
mCoeffsFB[0] = 0x01f;
|
|
mCoeffs[1] = 0x015;
|
|
mCoeffsFB[1] = 0x01f;
|
|
mCoeffs[2] = 0x01f;
|
|
mCoeffsFB[2] = 0x01f;
|
|
for (unsigned i = 0; i < mIRate; i++) {
|
|
computeStateTables(i);
|
|
}
|
|
computeGeneratorTable();
|
|
}
|
|
|
|
|
|
|
|
|
|
void ViterbiTCH_AFS10_2::initializeStates()
|
|
{
|
|
for (unsigned i=0; i<mIStates; i++) vitClear(mSurvivors[i]);
|
|
for (unsigned i=0; i<mNumCands; i++) vitClear(mCandidates[i]);
|
|
}
|
|
|
|
|
|
|
|
void ViterbiTCH_AFS10_2::computeStateTables(unsigned g)
|
|
{
|
|
assert(g<mIRate);
|
|
for (unsigned state=0; state<mIStates; state++) {
|
|
for (unsigned in = 0; in <= 1; in++) {
|
|
uint32_t inputVal = (state<<1) | in;
|
|
mStateTable[g][inputVal] = applyPoly(inputVal, mCoeffs[g] ^ mCoeffsFB[g], mOrder+1) ^ in;
|
|
}
|
|
}
|
|
}
|
|
|
|
void ViterbiTCH_AFS10_2::computeGeneratorTable()
|
|
{
|
|
for (unsigned index=0; index<mIStates*2; index++) {
|
|
uint32_t t = 0;
|
|
for (unsigned i = 0; i < mIRate; i++) {
|
|
t = (t << 1) | mStateTable[i][index];
|
|
}
|
|
mGeneratorTable[index] = t;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void ViterbiTCH_AFS10_2::branchCandidates()
|
|
{
|
|
// Branch to generate new input states.
|
|
const vCand *sp = mSurvivors;
|
|
for (unsigned cand=0; cand<mNumCands; cand+=2) {
|
|
uint32_t oStateShifted = (sp->oState) << mIRate;
|
|
for (unsigned in = 0; in <= 1; in++) {
|
|
mCandidates[cand+in].iState = ((sp->iState) << 1) | in;
|
|
mCandidates[cand+in].cost = sp->cost;
|
|
uint32_t outputs = oStateShifted;
|
|
for (unsigned out = 0; out < mIRate; out++) {
|
|
char feedback = applyPoly(sp->rState[out], mCoeffsFB[out] ^ 1, mOrder+1);
|
|
char rState = (((sp->rState[out]) ^ feedback) << 1) | in;
|
|
mCandidates[cand+in].rState[out] = rState;
|
|
outputs |= (mGeneratorTable[rState & mCMask] & (1 << (mIRate - out - 1)));
|
|
}
|
|
mCandidates[cand+in].oState = outputs;
|
|
}
|
|
sp++;
|
|
}
|
|
}
|
|
|
|
|
|
void ViterbiTCH_AFS10_2::getSoftCostMetrics(const uint32_t inSample, const float *matchCost, const float *mismatchCost)
|
|
{
|
|
const float *cTab[2] = {matchCost,mismatchCost};
|
|
for (unsigned i=0; i<mNumCands; i++) {
|
|
vCand& thisCand = mCandidates[i];
|
|
const unsigned mismatched = inSample ^ (thisCand.oState);
|
|
for (unsigned i = 0; i < mIRate; i++) {
|
|
thisCand.cost += cTab[(mismatched>>i)&0x01][mIRate-i-1];
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void ViterbiTCH_AFS10_2::pruneCandidates()
|
|
{
|
|
const vCand* c1 = mCandidates; // 0-prefix
|
|
const vCand* c2 = mCandidates + mIStates; // 1-prefix
|
|
for (unsigned i=0; i<mIStates; i++) {
|
|
if (c1[i].cost < c2[i].cost) mSurvivors[i] = c1[i];
|
|
else mSurvivors[i] = c2[i];
|
|
}
|
|
}
|
|
|
|
|
|
const ViterbiTCH_AFS10_2::vCand& ViterbiTCH_AFS10_2::minCost() const
|
|
{
|
|
int minIndex = 0;
|
|
float minCost = mSurvivors[0].cost;
|
|
for (unsigned i=1; i<mIStates; i++) {
|
|
const float thisCost = mSurvivors[i].cost;
|
|
if (thisCost>=minCost) continue;
|
|
minCost = thisCost;
|
|
minIndex=i;
|
|
}
|
|
return mSurvivors[minIndex];
|
|
}
|
|
|
|
|
|
const ViterbiTCH_AFS10_2::vCand& ViterbiTCH_AFS10_2::step(uint32_t inSample, const float *probs, const float *iprobs)
|
|
{
|
|
branchCandidates();
|
|
getSoftCostMetrics(inSample,probs,iprobs);
|
|
pruneCandidates();
|
|
return minCost();
|
|
}
|
|
|
|
|
|
|
|
void ViterbiTCH_AFS10_2::decode(const SoftVector &in, BitVector& target)
|
|
{
|
|
ViterbiTCH_AFS10_2 &decoder = *this;
|
|
const size_t sz = in.size() - 12;
|
|
const unsigned deferral = decoder.deferral();
|
|
const size_t ctsz = sz + deferral*decoder.iRate();
|
|
assert(sz == decoder.iRate()*target.size());
|
|
|
|
// Build a "history" array where each element contains the full history.
|
|
uint32_t history[ctsz];
|
|
{
|
|
BitVector bits = in.sliced();
|
|
uint32_t accum = 0;
|
|
for (size_t i=0; i<sz; i++) {
|
|
accum = (accum<<1) | bits.bit(i);
|
|
history[i] = accum;
|
|
}
|
|
// Repeat last bit at the end.
|
|
for (size_t i=sz; i<ctsz; i++) {
|
|
accum = (accum<<1) | (accum & 0x01);
|
|
history[i] = accum;
|
|
}
|
|
}
|
|
|
|
// Precompute metric tables.
|
|
float matchCostTable[ctsz];
|
|
float mismatchCostTable[ctsz];
|
|
{
|
|
const float *dp = in.begin();
|
|
for (size_t i=0; i<sz; i++) {
|
|
// pVal is the probability that a bit is correct.
|
|
// ipVal is the probability that a bit is incorrect.
|
|
float pVal = dp[i];
|
|
if (pVal>0.5F) pVal = 1.0F-pVal;
|
|
float ipVal = 1.0F-pVal;
|
|
// This is a cheap approximation to an ideal cost function.
|
|
if (pVal<0.01F) pVal = 0.01;
|
|
if (ipVal<0.01F) ipVal = 0.01;
|
|
matchCostTable[i] = 0.25F/ipVal;
|
|
mismatchCostTable[i] = 0.25F/pVal;
|
|
}
|
|
|
|
// pad end of table with unknowns
|
|
for (size_t i=sz; i<ctsz; i++) {
|
|
matchCostTable[i] = 0.5F;
|
|
mismatchCostTable[i] = 0.5F;
|
|
}
|
|
}
|
|
|
|
{
|
|
decoder.initializeStates();
|
|
// Each sample of history[] carries its history.
|
|
// So we only have to process every iRate-th sample.
|
|
const unsigned step = decoder.iRate();
|
|
// input pointer
|
|
const uint32_t *ip = history + step - 1;
|
|
// output pointers
|
|
char *op = target.begin();
|
|
const char *const opt = target.end();
|
|
// table pointers
|
|
const float* match = matchCostTable;
|
|
const float* mismatch = mismatchCostTable;
|
|
size_t oCount = 0;
|
|
while (op<opt) {
|
|
// Viterbi algorithm
|
|
assert(match-matchCostTable<(int)(sizeof(matchCostTable)/sizeof(matchCostTable[0])-1));
|
|
assert(mismatch-mismatchCostTable<(int)(sizeof(mismatchCostTable)/sizeof(mismatchCostTable[0])-1));
|
|
const ViterbiTCH_AFS10_2::vCand &minCost = decoder.step(*ip, match, mismatch);
|
|
ip += step;
|
|
match += step;
|
|
mismatch += step;
|
|
// output
|
|
if (oCount>=deferral) *op++ = (minCost.iState >> deferral)&0x01;
|
|
oCount++;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
ViterbiTCH_AFS7_95::ViterbiTCH_AFS7_95()
|
|
{
|
|
assert(mDeferral < 32);
|
|
mCoeffs[0] = 0x06d;
|
|
mCoeffsFB[0] = 0x06d;
|
|
mCoeffs[1] = 0x053;
|
|
mCoeffsFB[1] = 0x06d;
|
|
mCoeffs[2] = 0x05f;
|
|
mCoeffsFB[2] = 0x06d;
|
|
for (unsigned i = 0; i < mIRate; i++) {
|
|
computeStateTables(i);
|
|
}
|
|
computeGeneratorTable();
|
|
}
|
|
|
|
|
|
|
|
|
|
void ViterbiTCH_AFS7_95::initializeStates()
|
|
{
|
|
for (unsigned i=0; i<mIStates; i++) vitClear(mSurvivors[i]);
|
|
for (unsigned i=0; i<mNumCands; i++) vitClear(mCandidates[i]);
|
|
}
|
|
|
|
|
|
|
|
void ViterbiTCH_AFS7_95::computeStateTables(unsigned g)
|
|
{
|
|
assert(g<mIRate);
|
|
for (unsigned state=0; state<mIStates; state++) {
|
|
for (unsigned in = 0; in <= 1; in++) {
|
|
uint32_t inputVal = (state<<1) | in;
|
|
mStateTable[g][inputVal] = applyPoly(inputVal, mCoeffs[g] ^ mCoeffsFB[g], mOrder+1) ^ in;
|
|
}
|
|
}
|
|
}
|
|
|
|
void ViterbiTCH_AFS7_95::computeGeneratorTable()
|
|
{
|
|
for (unsigned index=0; index<mIStates*2; index++) {
|
|
uint32_t t = 0;
|
|
for (unsigned i = 0; i < mIRate; i++) {
|
|
t = (t << 1) | mStateTable[i][index];
|
|
}
|
|
mGeneratorTable[index] = t;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void ViterbiTCH_AFS7_95::branchCandidates()
|
|
{
|
|
// Branch to generate new input states.
|
|
const vCand *sp = mSurvivors;
|
|
for (unsigned cand=0; cand<mNumCands; cand+=2) {
|
|
uint32_t oStateShifted = (sp->oState) << mIRate;
|
|
for (unsigned in = 0; in <= 1; in++) {
|
|
mCandidates[cand+in].iState = ((sp->iState) << 1) | in;
|
|
mCandidates[cand+in].cost = sp->cost;
|
|
uint32_t outputs = oStateShifted;
|
|
for (unsigned out = 0; out < mIRate; out++) {
|
|
char feedback = applyPoly(sp->rState[out], mCoeffsFB[out] ^ 1, mOrder+1);
|
|
char rState = (((sp->rState[out]) ^ feedback) << 1) | in;
|
|
mCandidates[cand+in].rState[out] = rState;
|
|
outputs |= (mGeneratorTable[rState & mCMask] & (1 << (mIRate - out - 1)));
|
|
}
|
|
mCandidates[cand+in].oState = outputs;
|
|
}
|
|
sp++;
|
|
}
|
|
}
|
|
|
|
|
|
void ViterbiTCH_AFS7_95::getSoftCostMetrics(const uint32_t inSample, const float *matchCost, const float *mismatchCost)
|
|
{
|
|
const float *cTab[2] = {matchCost,mismatchCost};
|
|
for (unsigned i=0; i<mNumCands; i++) {
|
|
vCand& thisCand = mCandidates[i];
|
|
const unsigned mismatched = inSample ^ (thisCand.oState);
|
|
for (unsigned i = 0; i < mIRate; i++) {
|
|
thisCand.cost += cTab[(mismatched>>i)&0x01][mIRate-i-1];
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void ViterbiTCH_AFS7_95::pruneCandidates()
|
|
{
|
|
const vCand* c1 = mCandidates; // 0-prefix
|
|
const vCand* c2 = mCandidates + mIStates; // 1-prefix
|
|
for (unsigned i=0; i<mIStates; i++) {
|
|
if (c1[i].cost < c2[i].cost) mSurvivors[i] = c1[i];
|
|
else mSurvivors[i] = c2[i];
|
|
}
|
|
}
|
|
|
|
|
|
const ViterbiTCH_AFS7_95::vCand& ViterbiTCH_AFS7_95::minCost() const
|
|
{
|
|
int minIndex = 0;
|
|
float minCost = mSurvivors[0].cost;
|
|
for (unsigned i=1; i<mIStates; i++) {
|
|
const float thisCost = mSurvivors[i].cost;
|
|
if (thisCost>=minCost) continue;
|
|
minCost = thisCost;
|
|
minIndex=i;
|
|
}
|
|
return mSurvivors[minIndex];
|
|
}
|
|
|
|
|
|
const ViterbiTCH_AFS7_95::vCand& ViterbiTCH_AFS7_95::step(uint32_t inSample, const float *probs, const float *iprobs)
|
|
{
|
|
branchCandidates();
|
|
getSoftCostMetrics(inSample,probs,iprobs);
|
|
pruneCandidates();
|
|
return minCost();
|
|
}
|
|
|
|
|
|
|
|
void ViterbiTCH_AFS7_95::decode(const SoftVector &in, BitVector& target)
|
|
{
|
|
ViterbiTCH_AFS7_95 &decoder = *this;
|
|
const size_t sz = in.size() - 18;
|
|
const unsigned deferral = decoder.deferral();
|
|
const size_t ctsz = sz + deferral*decoder.iRate();
|
|
assert(sz == decoder.iRate()*target.size());
|
|
|
|
// Build a "history" array where each element contains the full history.
|
|
uint32_t history[ctsz];
|
|
{
|
|
BitVector bits = in.sliced();
|
|
uint32_t accum = 0;
|
|
for (size_t i=0; i<sz; i++) {
|
|
accum = (accum<<1) | bits.bit(i);
|
|
history[i] = accum;
|
|
}
|
|
// Repeat last bit at the end.
|
|
for (size_t i=sz; i<ctsz; i++) {
|
|
accum = (accum<<1) | (accum & 0x01);
|
|
history[i] = accum;
|
|
}
|
|
}
|
|
|
|
// Precompute metric tables.
|
|
float matchCostTable[ctsz];
|
|
float mismatchCostTable[ctsz];
|
|
{
|
|
const float *dp = in.begin();
|
|
for (size_t i=0; i<sz; i++) {
|
|
// pVal is the probability that a bit is correct.
|
|
// ipVal is the probability that a bit is incorrect.
|
|
float pVal = dp[i];
|
|
if (pVal>0.5F) pVal = 1.0F-pVal;
|
|
float ipVal = 1.0F-pVal;
|
|
// This is a cheap approximation to an ideal cost function.
|
|
if (pVal<0.01F) pVal = 0.01;
|
|
if (ipVal<0.01F) ipVal = 0.01;
|
|
matchCostTable[i] = 0.25F/ipVal;
|
|
mismatchCostTable[i] = 0.25F/pVal;
|
|
}
|
|
|
|
// pad end of table with unknowns
|
|
for (size_t i=sz; i<ctsz; i++) {
|
|
matchCostTable[i] = 0.5F;
|
|
mismatchCostTable[i] = 0.5F;
|
|
}
|
|
}
|
|
|
|
{
|
|
decoder.initializeStates();
|
|
// Each sample of history[] carries its history.
|
|
// So we only have to process every iRate-th sample.
|
|
const unsigned step = decoder.iRate();
|
|
// input pointer
|
|
const uint32_t *ip = history + step - 1;
|
|
// output pointers
|
|
char *op = target.begin();
|
|
const char *const opt = target.end();
|
|
// table pointers
|
|
const float* match = matchCostTable;
|
|
const float* mismatch = mismatchCostTable;
|
|
size_t oCount = 0;
|
|
while (op<opt) {
|
|
// Viterbi algorithm
|
|
assert(match-matchCostTable<(int)(sizeof(matchCostTable)/sizeof(matchCostTable[0])-1));
|
|
assert(mismatch-mismatchCostTable<(int)(sizeof(mismatchCostTable)/sizeof(mismatchCostTable[0])-1));
|
|
const ViterbiTCH_AFS7_95::vCand &minCost = decoder.step(*ip, match, mismatch);
|
|
ip += step;
|
|
match += step;
|
|
mismatch += step;
|
|
// output
|
|
if (oCount>=deferral) *op++ = (minCost.iState >> deferral)&0x01;
|
|
oCount++;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
ViterbiTCH_AFS7_4::ViterbiTCH_AFS7_4()
|
|
{
|
|
assert(mDeferral < 32);
|
|
mCoeffs[0] = 0x01b;
|
|
mCoeffsFB[0] = 0x01f;
|
|
mCoeffs[1] = 0x015;
|
|
mCoeffsFB[1] = 0x01f;
|
|
mCoeffs[2] = 0x01f;
|
|
mCoeffsFB[2] = 0x01f;
|
|
for (unsigned i = 0; i < mIRate; i++) {
|
|
computeStateTables(i);
|
|
}
|
|
computeGeneratorTable();
|
|
}
|
|
|
|
|
|
|
|
|
|
void ViterbiTCH_AFS7_4::initializeStates()
|
|
{
|
|
for (unsigned i=0; i<mIStates; i++) vitClear(mSurvivors[i]);
|
|
for (unsigned i=0; i<mNumCands; i++) vitClear(mCandidates[i]);
|
|
}
|
|
|
|
|
|
|
|
void ViterbiTCH_AFS7_4::computeStateTables(unsigned g)
|
|
{
|
|
assert(g<mIRate);
|
|
for (unsigned state=0; state<mIStates; state++) {
|
|
for (unsigned in = 0; in <= 1; in++) {
|
|
uint32_t inputVal = (state<<1) | in;
|
|
mStateTable[g][inputVal] = applyPoly(inputVal, mCoeffs[g] ^ mCoeffsFB[g], mOrder+1) ^ in;
|
|
}
|
|
}
|
|
}
|
|
|
|
void ViterbiTCH_AFS7_4::computeGeneratorTable()
|
|
{
|
|
for (unsigned index=0; index<mIStates*2; index++) {
|
|
uint32_t t = 0;
|
|
for (unsigned i = 0; i < mIRate; i++) {
|
|
t = (t << 1) | mStateTable[i][index];
|
|
}
|
|
mGeneratorTable[index] = t;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void ViterbiTCH_AFS7_4::branchCandidates()
|
|
{
|
|
// Branch to generate new input states.
|
|
const vCand *sp = mSurvivors;
|
|
for (unsigned cand=0; cand<mNumCands; cand+=2) {
|
|
uint32_t oStateShifted = (sp->oState) << mIRate;
|
|
for (unsigned in = 0; in <= 1; in++) {
|
|
mCandidates[cand+in].iState = ((sp->iState) << 1) | in;
|
|
mCandidates[cand+in].cost = sp->cost;
|
|
uint32_t outputs = oStateShifted;
|
|
for (unsigned out = 0; out < mIRate; out++) {
|
|
char feedback = applyPoly(sp->rState[out], mCoeffsFB[out] ^ 1, mOrder+1);
|
|
char rState = (((sp->rState[out]) ^ feedback) << 1) | in;
|
|
mCandidates[cand+in].rState[out] = rState;
|
|
outputs |= (mGeneratorTable[rState & mCMask] & (1 << (mIRate - out - 1)));
|
|
}
|
|
mCandidates[cand+in].oState = outputs;
|
|
}
|
|
sp++;
|
|
}
|
|
}
|
|
|
|
|
|
void ViterbiTCH_AFS7_4::getSoftCostMetrics(const uint32_t inSample, const float *matchCost, const float *mismatchCost)
|
|
{
|
|
const float *cTab[2] = {matchCost,mismatchCost};
|
|
for (unsigned i=0; i<mNumCands; i++) {
|
|
vCand& thisCand = mCandidates[i];
|
|
const unsigned mismatched = inSample ^ (thisCand.oState);
|
|
for (unsigned i = 0; i < mIRate; i++) {
|
|
thisCand.cost += cTab[(mismatched>>i)&0x01][mIRate-i-1];
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void ViterbiTCH_AFS7_4::pruneCandidates()
|
|
{
|
|
const vCand* c1 = mCandidates; // 0-prefix
|
|
const vCand* c2 = mCandidates + mIStates; // 1-prefix
|
|
for (unsigned i=0; i<mIStates; i++) {
|
|
if (c1[i].cost < c2[i].cost) mSurvivors[i] = c1[i];
|
|
else mSurvivors[i] = c2[i];
|
|
}
|
|
}
|
|
|
|
|
|
const ViterbiTCH_AFS7_4::vCand& ViterbiTCH_AFS7_4::minCost() const
|
|
{
|
|
int minIndex = 0;
|
|
float minCost = mSurvivors[0].cost;
|
|
for (unsigned i=1; i<mIStates; i++) {
|
|
const float thisCost = mSurvivors[i].cost;
|
|
if (thisCost>=minCost) continue;
|
|
minCost = thisCost;
|
|
minIndex=i;
|
|
}
|
|
return mSurvivors[minIndex];
|
|
}
|
|
|
|
|
|
const ViterbiTCH_AFS7_4::vCand& ViterbiTCH_AFS7_4::step(uint32_t inSample, const float *probs, const float *iprobs)
|
|
{
|
|
branchCandidates();
|
|
getSoftCostMetrics(inSample,probs,iprobs);
|
|
pruneCandidates();
|
|
return minCost();
|
|
}
|
|
|
|
|
|
|
|
void ViterbiTCH_AFS7_4::decode(const SoftVector &in, BitVector& target)
|
|
{
|
|
ViterbiTCH_AFS7_4 &decoder = *this;
|
|
const size_t sz = in.size() - 12;
|
|
const unsigned deferral = decoder.deferral();
|
|
const size_t ctsz = sz + deferral*decoder.iRate();
|
|
assert(sz == decoder.iRate()*target.size());
|
|
|
|
// Build a "history" array where each element contains the full history.
|
|
uint32_t history[ctsz];
|
|
{
|
|
BitVector bits = in.sliced();
|
|
uint32_t accum = 0;
|
|
for (size_t i=0; i<sz; i++) {
|
|
accum = (accum<<1) | bits.bit(i);
|
|
history[i] = accum;
|
|
}
|
|
// Repeat last bit at the end.
|
|
for (size_t i=sz; i<ctsz; i++) {
|
|
accum = (accum<<1) | (accum & 0x01);
|
|
history[i] = accum;
|
|
}
|
|
}
|
|
|
|
// Precompute metric tables.
|
|
float matchCostTable[ctsz];
|
|
float mismatchCostTable[ctsz];
|
|
{
|
|
const float *dp = in.begin();
|
|
for (size_t i=0; i<sz; i++) {
|
|
// pVal is the probability that a bit is correct.
|
|
// ipVal is the probability that a bit is incorrect.
|
|
float pVal = dp[i];
|
|
if (pVal>0.5F) pVal = 1.0F-pVal;
|
|
float ipVal = 1.0F-pVal;
|
|
// This is a cheap approximation to an ideal cost function.
|
|
if (pVal<0.01F) pVal = 0.01;
|
|
if (ipVal<0.01F) ipVal = 0.01;
|
|
matchCostTable[i] = 0.25F/ipVal;
|
|
mismatchCostTable[i] = 0.25F/pVal;
|
|
}
|
|
|
|
// pad end of table with unknowns
|
|
for (size_t i=sz; i<ctsz; i++) {
|
|
matchCostTable[i] = 0.5F;
|
|
mismatchCostTable[i] = 0.5F;
|
|
}
|
|
}
|
|
|
|
{
|
|
decoder.initializeStates();
|
|
// Each sample of history[] carries its history.
|
|
// So we only have to process every iRate-th sample.
|
|
const unsigned step = decoder.iRate();
|
|
// input pointer
|
|
const uint32_t *ip = history + step - 1;
|
|
// output pointers
|
|
char *op = target.begin();
|
|
const char *const opt = target.end();
|
|
// table pointers
|
|
const float* match = matchCostTable;
|
|
const float* mismatch = mismatchCostTable;
|
|
size_t oCount = 0;
|
|
while (op<opt) {
|
|
// Viterbi algorithm
|
|
assert(match-matchCostTable<(int)(sizeof(matchCostTable)/sizeof(matchCostTable[0])-1));
|
|
assert(mismatch-mismatchCostTable<(int)(sizeof(mismatchCostTable)/sizeof(mismatchCostTable[0])-1));
|
|
const ViterbiTCH_AFS7_4::vCand &minCost = decoder.step(*ip, match, mismatch);
|
|
ip += step;
|
|
match += step;
|
|
mismatch += step;
|
|
// output
|
|
if (oCount>=deferral) *op++ = (minCost.iState >> deferral)&0x01;
|
|
oCount++;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
ViterbiTCH_AFS6_7::ViterbiTCH_AFS6_7()
|
|
{
|
|
assert(mDeferral < 32);
|
|
mCoeffs[0] = 0x01b;
|
|
mCoeffsFB[0] = 0x01f;
|
|
mCoeffs[1] = 0x015;
|
|
mCoeffsFB[1] = 0x01f;
|
|
mCoeffs[2] = 0x01f;
|
|
mCoeffsFB[2] = 0x01f;
|
|
mCoeffs[3] = 0x01f;
|
|
mCoeffsFB[3] = 0x01f;
|
|
for (unsigned i = 0; i < mIRate; i++) {
|
|
computeStateTables(i);
|
|
}
|
|
computeGeneratorTable();
|
|
}
|
|
|
|
|
|
|
|
|
|
void ViterbiTCH_AFS6_7::initializeStates()
|
|
{
|
|
for (unsigned i=0; i<mIStates; i++) vitClear(mSurvivors[i]);
|
|
for (unsigned i=0; i<mNumCands; i++) vitClear(mCandidates[i]);
|
|
}
|
|
|
|
|
|
|
|
void ViterbiTCH_AFS6_7::computeStateTables(unsigned g)
|
|
{
|
|
assert(g<mIRate);
|
|
for (unsigned state=0; state<mIStates; state++) {
|
|
for (unsigned in = 0; in <= 1; in++) {
|
|
uint32_t inputVal = (state<<1) | in;
|
|
mStateTable[g][inputVal] = applyPoly(inputVal, mCoeffs[g] ^ mCoeffsFB[g], mOrder+1) ^ in;
|
|
}
|
|
}
|
|
}
|
|
|
|
void ViterbiTCH_AFS6_7::computeGeneratorTable()
|
|
{
|
|
for (unsigned index=0; index<mIStates*2; index++) {
|
|
uint32_t t = 0;
|
|
for (unsigned i = 0; i < mIRate; i++) {
|
|
t = (t << 1) | mStateTable[i][index];
|
|
}
|
|
mGeneratorTable[index] = t;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void ViterbiTCH_AFS6_7::branchCandidates()
|
|
{
|
|
// Branch to generate new input states.
|
|
const vCand *sp = mSurvivors;
|
|
for (unsigned cand=0; cand<mNumCands; cand+=2) {
|
|
uint32_t oStateShifted = (sp->oState) << mIRate;
|
|
for (unsigned in = 0; in <= 1; in++) {
|
|
mCandidates[cand+in].iState = ((sp->iState) << 1) | in;
|
|
mCandidates[cand+in].cost = sp->cost;
|
|
uint32_t outputs = oStateShifted;
|
|
for (unsigned out = 0; out < mIRate; out++) {
|
|
char feedback = applyPoly(sp->rState[out], mCoeffsFB[out] ^ 1, mOrder+1);
|
|
char rState = (((sp->rState[out]) ^ feedback) << 1) | in;
|
|
mCandidates[cand+in].rState[out] = rState;
|
|
outputs |= (mGeneratorTable[rState & mCMask] & (1 << (mIRate - out - 1)));
|
|
}
|
|
mCandidates[cand+in].oState = outputs;
|
|
}
|
|
sp++;
|
|
}
|
|
}
|
|
|
|
|
|
void ViterbiTCH_AFS6_7::getSoftCostMetrics(const uint32_t inSample, const float *matchCost, const float *mismatchCost)
|
|
{
|
|
const float *cTab[2] = {matchCost,mismatchCost};
|
|
for (unsigned i=0; i<mNumCands; i++) {
|
|
vCand& thisCand = mCandidates[i];
|
|
const unsigned mismatched = inSample ^ (thisCand.oState);
|
|
for (unsigned i = 0; i < mIRate; i++) {
|
|
thisCand.cost += cTab[(mismatched>>i)&0x01][mIRate-i-1];
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void ViterbiTCH_AFS6_7::pruneCandidates()
|
|
{
|
|
const vCand* c1 = mCandidates; // 0-prefix
|
|
const vCand* c2 = mCandidates + mIStates; // 1-prefix
|
|
for (unsigned i=0; i<mIStates; i++) {
|
|
if (c1[i].cost < c2[i].cost) mSurvivors[i] = c1[i];
|
|
else mSurvivors[i] = c2[i];
|
|
}
|
|
}
|
|
|
|
|
|
const ViterbiTCH_AFS6_7::vCand& ViterbiTCH_AFS6_7::minCost() const
|
|
{
|
|
int minIndex = 0;
|
|
float minCost = mSurvivors[0].cost;
|
|
for (unsigned i=1; i<mIStates; i++) {
|
|
const float thisCost = mSurvivors[i].cost;
|
|
if (thisCost>=minCost) continue;
|
|
minCost = thisCost;
|
|
minIndex=i;
|
|
}
|
|
return mSurvivors[minIndex];
|
|
}
|
|
|
|
|
|
const ViterbiTCH_AFS6_7::vCand& ViterbiTCH_AFS6_7::step(uint32_t inSample, const float *probs, const float *iprobs)
|
|
{
|
|
branchCandidates();
|
|
getSoftCostMetrics(inSample,probs,iprobs);
|
|
pruneCandidates();
|
|
return minCost();
|
|
}
|
|
|
|
|
|
|
|
void ViterbiTCH_AFS6_7::decode(const SoftVector &in, BitVector& target)
|
|
{
|
|
ViterbiTCH_AFS6_7 &decoder = *this;
|
|
const size_t sz = in.size() - 16;
|
|
const unsigned deferral = decoder.deferral();
|
|
const size_t ctsz = sz + deferral*decoder.iRate();
|
|
assert(sz == decoder.iRate()*target.size());
|
|
|
|
// Build a "history" array where each element contains the full history.
|
|
uint32_t history[ctsz];
|
|
{
|
|
BitVector bits = in.sliced();
|
|
uint32_t accum = 0;
|
|
for (size_t i=0; i<sz; i++) {
|
|
accum = (accum<<1) | bits.bit(i);
|
|
history[i] = accum;
|
|
}
|
|
// Repeat last bit at the end.
|
|
for (size_t i=sz; i<ctsz; i++) {
|
|
accum = (accum<<1) | (accum & 0x01);
|
|
history[i] = accum;
|
|
}
|
|
}
|
|
|
|
// Precompute metric tables.
|
|
float matchCostTable[ctsz];
|
|
float mismatchCostTable[ctsz];
|
|
{
|
|
const float *dp = in.begin();
|
|
for (size_t i=0; i<sz; i++) {
|
|
// pVal is the probability that a bit is correct.
|
|
// ipVal is the probability that a bit is incorrect.
|
|
float pVal = dp[i];
|
|
if (pVal>0.5F) pVal = 1.0F-pVal;
|
|
float ipVal = 1.0F-pVal;
|
|
// This is a cheap approximation to an ideal cost function.
|
|
if (pVal<0.01F) pVal = 0.01;
|
|
if (ipVal<0.01F) ipVal = 0.01;
|
|
matchCostTable[i] = 0.25F/ipVal;
|
|
mismatchCostTable[i] = 0.25F/pVal;
|
|
}
|
|
|
|
// pad end of table with unknowns
|
|
for (size_t i=sz; i<ctsz; i++) {
|
|
matchCostTable[i] = 0.5F;
|
|
mismatchCostTable[i] = 0.5F;
|
|
}
|
|
}
|
|
|
|
{
|
|
decoder.initializeStates();
|
|
// Each sample of history[] carries its history.
|
|
// So we only have to process every iRate-th sample.
|
|
const unsigned step = decoder.iRate();
|
|
// input pointer
|
|
const uint32_t *ip = history + step - 1;
|
|
// output pointers
|
|
char *op = target.begin();
|
|
const char *const opt = target.end();
|
|
// table pointers
|
|
const float* match = matchCostTable;
|
|
const float* mismatch = mismatchCostTable;
|
|
size_t oCount = 0;
|
|
while (op<opt) {
|
|
// Viterbi algorithm
|
|
assert(match-matchCostTable<(int)(sizeof(matchCostTable)/sizeof(matchCostTable[0])-1));
|
|
assert(mismatch-mismatchCostTable<(int)(sizeof(mismatchCostTable)/sizeof(mismatchCostTable[0])-1));
|
|
const ViterbiTCH_AFS6_7::vCand &minCost = decoder.step(*ip, match, mismatch);
|
|
ip += step;
|
|
match += step;
|
|
mismatch += step;
|
|
// output
|
|
if (oCount>=deferral) *op++ = (minCost.iState >> deferral)&0x01;
|
|
oCount++;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
ViterbiTCH_AFS5_9::ViterbiTCH_AFS5_9()
|
|
{
|
|
assert(mDeferral < 32);
|
|
mCoeffs[0] = 0x06d;
|
|
mCoeffsFB[0] = 0x05f;
|
|
mCoeffs[1] = 0x053;
|
|
mCoeffsFB[1] = 0x05f;
|
|
mCoeffs[2] = 0x05f;
|
|
mCoeffsFB[2] = 0x05f;
|
|
mCoeffs[3] = 0x05f;
|
|
mCoeffsFB[3] = 0x05f;
|
|
for (unsigned i = 0; i < mIRate; i++) {
|
|
computeStateTables(i);
|
|
}
|
|
computeGeneratorTable();
|
|
}
|
|
|
|
|
|
|
|
|
|
void ViterbiTCH_AFS5_9::initializeStates()
|
|
{
|
|
for (unsigned i=0; i<mIStates; i++) vitClear(mSurvivors[i]);
|
|
for (unsigned i=0; i<mNumCands; i++) vitClear(mCandidates[i]);
|
|
}
|
|
|
|
|
|
|
|
void ViterbiTCH_AFS5_9::computeStateTables(unsigned g)
|
|
{
|
|
assert(g<mIRate);
|
|
for (unsigned state=0; state<mIStates; state++) {
|
|
for (unsigned in = 0; in <= 1; in++) {
|
|
uint32_t inputVal = (state<<1) | in;
|
|
mStateTable[g][inputVal] = applyPoly(inputVal, mCoeffs[g] ^ mCoeffsFB[g], mOrder+1) ^ in;
|
|
}
|
|
}
|
|
}
|
|
|
|
void ViterbiTCH_AFS5_9::computeGeneratorTable()
|
|
{
|
|
for (unsigned index=0; index<mIStates*2; index++) {
|
|
uint32_t t = 0;
|
|
for (unsigned i = 0; i < mIRate; i++) {
|
|
t = (t << 1) | mStateTable[i][index];
|
|
}
|
|
mGeneratorTable[index] = t;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void ViterbiTCH_AFS5_9::branchCandidates()
|
|
{
|
|
// Branch to generate new input states.
|
|
const vCand *sp = mSurvivors;
|
|
for (unsigned cand=0; cand<mNumCands; cand+=2) {
|
|
uint32_t oStateShifted = (sp->oState) << mIRate;
|
|
for (unsigned in = 0; in <= 1; in++) {
|
|
mCandidates[cand+in].iState = ((sp->iState) << 1) | in;
|
|
mCandidates[cand+in].cost = sp->cost;
|
|
uint32_t outputs = oStateShifted;
|
|
for (unsigned out = 0; out < mIRate; out++) {
|
|
char feedback = applyPoly(sp->rState[out], mCoeffsFB[out] ^ 1, mOrder+1);
|
|
char rState = (((sp->rState[out]) ^ feedback) << 1) | in;
|
|
mCandidates[cand+in].rState[out] = rState;
|
|
outputs |= (mGeneratorTable[rState & mCMask] & (1 << (mIRate - out - 1)));
|
|
}
|
|
mCandidates[cand+in].oState = outputs;
|
|
}
|
|
sp++;
|
|
}
|
|
}
|
|
|
|
|
|
void ViterbiTCH_AFS5_9::getSoftCostMetrics(const uint32_t inSample, const float *matchCost, const float *mismatchCost)
|
|
{
|
|
const float *cTab[2] = {matchCost,mismatchCost};
|
|
for (unsigned i=0; i<mNumCands; i++) {
|
|
vCand& thisCand = mCandidates[i];
|
|
const unsigned mismatched = inSample ^ (thisCand.oState);
|
|
for (unsigned i = 0; i < mIRate; i++) {
|
|
thisCand.cost += cTab[(mismatched>>i)&0x01][mIRate-i-1];
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void ViterbiTCH_AFS5_9::pruneCandidates()
|
|
{
|
|
const vCand* c1 = mCandidates; // 0-prefix
|
|
const vCand* c2 = mCandidates + mIStates; // 1-prefix
|
|
for (unsigned i=0; i<mIStates; i++) {
|
|
if (c1[i].cost < c2[i].cost) mSurvivors[i] = c1[i];
|
|
else mSurvivors[i] = c2[i];
|
|
}
|
|
}
|
|
|
|
|
|
const ViterbiTCH_AFS5_9::vCand& ViterbiTCH_AFS5_9::minCost() const
|
|
{
|
|
int minIndex = 0;
|
|
float minCost = mSurvivors[0].cost;
|
|
for (unsigned i=1; i<mIStates; i++) {
|
|
const float thisCost = mSurvivors[i].cost;
|
|
if (thisCost>=minCost) continue;
|
|
minCost = thisCost;
|
|
minIndex=i;
|
|
}
|
|
return mSurvivors[minIndex];
|
|
}
|
|
|
|
|
|
const ViterbiTCH_AFS5_9::vCand& ViterbiTCH_AFS5_9::step(uint32_t inSample, const float *probs, const float *iprobs)
|
|
{
|
|
branchCandidates();
|
|
getSoftCostMetrics(inSample,probs,iprobs);
|
|
pruneCandidates();
|
|
return minCost();
|
|
}
|
|
|
|
|
|
|
|
void ViterbiTCH_AFS5_9::decode(const SoftVector &in, BitVector& target)
|
|
{
|
|
ViterbiTCH_AFS5_9 &decoder = *this;
|
|
const size_t sz = in.size() - 24;
|
|
const unsigned deferral = decoder.deferral();
|
|
const size_t ctsz = sz + deferral*decoder.iRate();
|
|
assert(sz == decoder.iRate()*target.size());
|
|
|
|
// Build a "history" array where each element contains the full history.
|
|
uint32_t history[ctsz];
|
|
{
|
|
BitVector bits = in.sliced();
|
|
uint32_t accum = 0;
|
|
for (size_t i=0; i<sz; i++) {
|
|
accum = (accum<<1) | bits.bit(i);
|
|
history[i] = accum;
|
|
}
|
|
// Repeat last bit at the end.
|
|
for (size_t i=sz; i<ctsz; i++) {
|
|
accum = (accum<<1) | (accum & 0x01);
|
|
history[i] = accum;
|
|
}
|
|
}
|
|
|
|
// Precompute metric tables.
|
|
float matchCostTable[ctsz];
|
|
float mismatchCostTable[ctsz];
|
|
{
|
|
const float *dp = in.begin();
|
|
for (size_t i=0; i<sz; i++) {
|
|
// pVal is the probability that a bit is correct.
|
|
// ipVal is the probability that a bit is incorrect.
|
|
float pVal = dp[i];
|
|
if (pVal>0.5F) pVal = 1.0F-pVal;
|
|
float ipVal = 1.0F-pVal;
|
|
// This is a cheap approximation to an ideal cost function.
|
|
if (pVal<0.01F) pVal = 0.01;
|
|
if (ipVal<0.01F) ipVal = 0.01;
|
|
matchCostTable[i] = 0.25F/ipVal;
|
|
mismatchCostTable[i] = 0.25F/pVal;
|
|
}
|
|
|
|
// pad end of table with unknowns
|
|
for (size_t i=sz; i<ctsz; i++) {
|
|
matchCostTable[i] = 0.5F;
|
|
mismatchCostTable[i] = 0.5F;
|
|
}
|
|
}
|
|
|
|
{
|
|
decoder.initializeStates();
|
|
// Each sample of history[] carries its history.
|
|
// So we only have to process every iRate-th sample.
|
|
const unsigned step = decoder.iRate();
|
|
// input pointer
|
|
const uint32_t *ip = history + step - 1;
|
|
// output pointers
|
|
char *op = target.begin();
|
|
const char *const opt = target.end();
|
|
// table pointers
|
|
const float* match = matchCostTable;
|
|
const float* mismatch = mismatchCostTable;
|
|
size_t oCount = 0;
|
|
while (op<opt) {
|
|
// Viterbi algorithm
|
|
assert(match-matchCostTable<(int)(sizeof(matchCostTable)/sizeof(matchCostTable[0])-1));
|
|
assert(mismatch-mismatchCostTable<(int)(sizeof(mismatchCostTable)/sizeof(mismatchCostTable[0])-1));
|
|
const ViterbiTCH_AFS5_9::vCand &minCost = decoder.step(*ip, match, mismatch);
|
|
ip += step;
|
|
match += step;
|
|
mismatch += step;
|
|
// output
|
|
if (oCount>=deferral) *op++ = (minCost.iState >> deferral)&0x01;
|
|
oCount++;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
ViterbiTCH_AFS5_15::ViterbiTCH_AFS5_15()
|
|
{
|
|
assert(mDeferral < 32);
|
|
mCoeffs[0] = 0x01b;
|
|
mCoeffsFB[0] = 0x01f;
|
|
mCoeffs[1] = 0x01b;
|
|
mCoeffsFB[1] = 0x01f;
|
|
mCoeffs[2] = 0x015;
|
|
mCoeffsFB[2] = 0x01f;
|
|
mCoeffs[3] = 0x01f;
|
|
mCoeffsFB[3] = 0x01f;
|
|
mCoeffs[4] = 0x01f;
|
|
mCoeffsFB[4] = 0x01f;
|
|
for (unsigned i = 0; i < mIRate; i++) {
|
|
computeStateTables(i);
|
|
}
|
|
computeGeneratorTable();
|
|
}
|
|
|
|
|
|
|
|
|
|
void ViterbiTCH_AFS5_15::initializeStates()
|
|
{
|
|
for (unsigned i=0; i<mIStates; i++) vitClear(mSurvivors[i]);
|
|
for (unsigned i=0; i<mNumCands; i++) vitClear(mCandidates[i]);
|
|
}
|
|
|
|
|
|
|
|
void ViterbiTCH_AFS5_15::computeStateTables(unsigned g)
|
|
{
|
|
assert(g<mIRate);
|
|
for (unsigned state=0; state<mIStates; state++) {
|
|
for (unsigned in = 0; in <= 1; in++) {
|
|
uint32_t inputVal = (state<<1) | in;
|
|
mStateTable[g][inputVal] = applyPoly(inputVal, mCoeffs[g] ^ mCoeffsFB[g], mOrder+1) ^ in;
|
|
}
|
|
}
|
|
}
|
|
|
|
void ViterbiTCH_AFS5_15::computeGeneratorTable()
|
|
{
|
|
for (unsigned index=0; index<mIStates*2; index++) {
|
|
uint32_t t = 0;
|
|
for (unsigned i = 0; i < mIRate; i++) {
|
|
t = (t << 1) | mStateTable[i][index];
|
|
}
|
|
mGeneratorTable[index] = t;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void ViterbiTCH_AFS5_15::branchCandidates()
|
|
{
|
|
// Branch to generate new input states.
|
|
const vCand *sp = mSurvivors;
|
|
for (unsigned cand=0; cand<mNumCands; cand+=2) {
|
|
uint32_t oStateShifted = (sp->oState) << mIRate;
|
|
for (unsigned in = 0; in <= 1; in++) {
|
|
mCandidates[cand+in].iState = ((sp->iState) << 1) | in;
|
|
mCandidates[cand+in].cost = sp->cost;
|
|
uint32_t outputs = oStateShifted;
|
|
for (unsigned out = 0; out < mIRate; out++) {
|
|
char feedback = applyPoly(sp->rState[out], mCoeffsFB[out] ^ 1, mOrder+1);
|
|
char rState = (((sp->rState[out]) ^ feedback) << 1) | in;
|
|
mCandidates[cand+in].rState[out] = rState;
|
|
outputs |= (mGeneratorTable[rState & mCMask] & (1 << (mIRate - out - 1)));
|
|
}
|
|
mCandidates[cand+in].oState = outputs;
|
|
}
|
|
sp++;
|
|
}
|
|
}
|
|
|
|
|
|
void ViterbiTCH_AFS5_15::getSoftCostMetrics(const uint32_t inSample, const float *matchCost, const float *mismatchCost)
|
|
{
|
|
const float *cTab[2] = {matchCost,mismatchCost};
|
|
for (unsigned i=0; i<mNumCands; i++) {
|
|
vCand& thisCand = mCandidates[i];
|
|
const unsigned mismatched = inSample ^ (thisCand.oState);
|
|
for (unsigned i = 0; i < mIRate; i++) {
|
|
thisCand.cost += cTab[(mismatched>>i)&0x01][mIRate-i-1];
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void ViterbiTCH_AFS5_15::pruneCandidates()
|
|
{
|
|
const vCand* c1 = mCandidates; // 0-prefix
|
|
const vCand* c2 = mCandidates + mIStates; // 1-prefix
|
|
for (unsigned i=0; i<mIStates; i++) {
|
|
if (c1[i].cost < c2[i].cost) mSurvivors[i] = c1[i];
|
|
else mSurvivors[i] = c2[i];
|
|
}
|
|
}
|
|
|
|
|
|
const ViterbiTCH_AFS5_15::vCand& ViterbiTCH_AFS5_15::minCost() const
|
|
{
|
|
int minIndex = 0;
|
|
float minCost = mSurvivors[0].cost;
|
|
for (unsigned i=1; i<mIStates; i++) {
|
|
const float thisCost = mSurvivors[i].cost;
|
|
if (thisCost>=minCost) continue;
|
|
minCost = thisCost;
|
|
minIndex=i;
|
|
}
|
|
return mSurvivors[minIndex];
|
|
}
|
|
|
|
|
|
const ViterbiTCH_AFS5_15::vCand& ViterbiTCH_AFS5_15::step(uint32_t inSample, const float *probs, const float *iprobs)
|
|
{
|
|
branchCandidates();
|
|
getSoftCostMetrics(inSample,probs,iprobs);
|
|
pruneCandidates();
|
|
return minCost();
|
|
}
|
|
|
|
|
|
|
|
void ViterbiTCH_AFS5_15::decode(const SoftVector &in, BitVector& target)
|
|
{
|
|
ViterbiTCH_AFS5_15 &decoder = *this;
|
|
const size_t sz = in.size() - 20;
|
|
const unsigned deferral = decoder.deferral();
|
|
const size_t ctsz = sz + deferral*decoder.iRate();
|
|
assert(sz == decoder.iRate()*target.size());
|
|
|
|
// Build a "history" array where each element contains the full history.
|
|
uint32_t history[ctsz];
|
|
{
|
|
BitVector bits = in.sliced();
|
|
uint32_t accum = 0;
|
|
for (size_t i=0; i<sz; i++) {
|
|
accum = (accum<<1) | bits.bit(i);
|
|
history[i] = accum;
|
|
}
|
|
// Repeat last bit at the end.
|
|
for (size_t i=sz; i<ctsz; i++) {
|
|
accum = (accum<<1) | (accum & 0x01);
|
|
history[i] = accum;
|
|
}
|
|
}
|
|
|
|
// Precompute metric tables.
|
|
float matchCostTable[ctsz];
|
|
float mismatchCostTable[ctsz];
|
|
{
|
|
const float *dp = in.begin();
|
|
for (size_t i=0; i<sz; i++) {
|
|
// pVal is the probability that a bit is correct.
|
|
// ipVal is the probability that a bit is incorrect.
|
|
float pVal = dp[i];
|
|
if (pVal>0.5F) pVal = 1.0F-pVal;
|
|
float ipVal = 1.0F-pVal;
|
|
// This is a cheap approximation to an ideal cost function.
|
|
if (pVal<0.01F) pVal = 0.01;
|
|
if (ipVal<0.01F) ipVal = 0.01;
|
|
matchCostTable[i] = 0.25F/ipVal;
|
|
mismatchCostTable[i] = 0.25F/pVal;
|
|
}
|
|
|
|
// pad end of table with unknowns
|
|
for (size_t i=sz; i<ctsz; i++) {
|
|
matchCostTable[i] = 0.5F;
|
|
mismatchCostTable[i] = 0.5F;
|
|
}
|
|
}
|
|
|
|
{
|
|
decoder.initializeStates();
|
|
// Each sample of history[] carries its history.
|
|
// So we only have to process every iRate-th sample.
|
|
const unsigned step = decoder.iRate();
|
|
// input pointer
|
|
const uint32_t *ip = history + step - 1;
|
|
// output pointers
|
|
char *op = target.begin();
|
|
const char *const opt = target.end();
|
|
// table pointers
|
|
const float* match = matchCostTable;
|
|
const float* mismatch = mismatchCostTable;
|
|
size_t oCount = 0;
|
|
while (op<opt) {
|
|
// Viterbi algorithm
|
|
assert(match-matchCostTable<(int)(sizeof(matchCostTable)/sizeof(matchCostTable[0])-1));
|
|
assert(mismatch-mismatchCostTable<(int)(sizeof(mismatchCostTable)/sizeof(mismatchCostTable[0])-1));
|
|
const ViterbiTCH_AFS5_15::vCand &minCost = decoder.step(*ip, match, mismatch);
|
|
ip += step;
|
|
match += step;
|
|
mismatch += step;
|
|
// output
|
|
if (oCount>=deferral) *op++ = (minCost.iState >> deferral)&0x01;
|
|
oCount++;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
ViterbiTCH_AFS4_75::ViterbiTCH_AFS4_75()
|
|
{
|
|
assert(mDeferral < 32);
|
|
mCoeffs[0] = 0x06d;
|
|
mCoeffsFB[0] = 0x05f;
|
|
mCoeffs[1] = 0x06d;
|
|
mCoeffsFB[1] = 0x05f;
|
|
mCoeffs[2] = 0x053;
|
|
mCoeffsFB[2] = 0x05f;
|
|
mCoeffs[3] = 0x05f;
|
|
mCoeffsFB[3] = 0x05f;
|
|
mCoeffs[4] = 0x05f;
|
|
mCoeffsFB[4] = 0x05f;
|
|
for (unsigned i = 0; i < mIRate; i++) {
|
|
computeStateTables(i);
|
|
}
|
|
computeGeneratorTable();
|
|
}
|
|
|
|
|
|
|
|
|
|
void ViterbiTCH_AFS4_75::initializeStates()
|
|
{
|
|
for (unsigned i=0; i<mIStates; i++) vitClear(mSurvivors[i]);
|
|
for (unsigned i=0; i<mNumCands; i++) vitClear(mCandidates[i]);
|
|
}
|
|
|
|
|
|
|
|
void ViterbiTCH_AFS4_75::computeStateTables(unsigned g)
|
|
{
|
|
assert(g<mIRate);
|
|
for (unsigned state=0; state<mIStates; state++) {
|
|
for (unsigned in = 0; in <= 1; in++) {
|
|
uint32_t inputVal = (state<<1) | in;
|
|
mStateTable[g][inputVal] = applyPoly(inputVal, mCoeffs[g] ^ mCoeffsFB[g], mOrder+1) ^ in;
|
|
}
|
|
}
|
|
}
|
|
|
|
void ViterbiTCH_AFS4_75::computeGeneratorTable()
|
|
{
|
|
for (unsigned index=0; index<mIStates*2; index++) {
|
|
uint32_t t = 0;
|
|
for (unsigned i = 0; i < mIRate; i++) {
|
|
t = (t << 1) | mStateTable[i][index];
|
|
}
|
|
mGeneratorTable[index] = t;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void ViterbiTCH_AFS4_75::branchCandidates()
|
|
{
|
|
// Branch to generate new input states.
|
|
const vCand *sp = mSurvivors;
|
|
for (unsigned cand=0; cand<mNumCands; cand+=2) {
|
|
uint32_t oStateShifted = (sp->oState) << mIRate;
|
|
for (unsigned in = 0; in <= 1; in++) {
|
|
mCandidates[cand+in].iState = ((sp->iState) << 1) | in;
|
|
mCandidates[cand+in].cost = sp->cost;
|
|
uint32_t outputs = oStateShifted;
|
|
for (unsigned out = 0; out < mIRate; out++) {
|
|
char feedback = applyPoly(sp->rState[out], mCoeffsFB[out] ^ 1, mOrder+1);
|
|
char rState = (((sp->rState[out]) ^ feedback) << 1) | in;
|
|
mCandidates[cand+in].rState[out] = rState;
|
|
outputs |= (mGeneratorTable[rState & mCMask] & (1 << (mIRate - out - 1)));
|
|
}
|
|
mCandidates[cand+in].oState = outputs;
|
|
}
|
|
sp++;
|
|
}
|
|
}
|
|
|
|
|
|
void ViterbiTCH_AFS4_75::getSoftCostMetrics(const uint32_t inSample, const float *matchCost, const float *mismatchCost)
|
|
{
|
|
const float *cTab[2] = {matchCost,mismatchCost};
|
|
for (unsigned i=0; i<mNumCands; i++) {
|
|
vCand& thisCand = mCandidates[i];
|
|
const unsigned mismatched = inSample ^ (thisCand.oState);
|
|
for (unsigned i = 0; i < mIRate; i++) {
|
|
thisCand.cost += cTab[(mismatched>>i)&0x01][mIRate-i-1];
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void ViterbiTCH_AFS4_75::pruneCandidates()
|
|
{
|
|
const vCand* c1 = mCandidates; // 0-prefix
|
|
const vCand* c2 = mCandidates + mIStates; // 1-prefix
|
|
for (unsigned i=0; i<mIStates; i++) {
|
|
if (c1[i].cost < c2[i].cost) mSurvivors[i] = c1[i];
|
|
else mSurvivors[i] = c2[i];
|
|
}
|
|
}
|
|
|
|
|
|
const ViterbiTCH_AFS4_75::vCand& ViterbiTCH_AFS4_75::minCost() const
|
|
{
|
|
int minIndex = 0;
|
|
float minCost = mSurvivors[0].cost;
|
|
for (unsigned i=1; i<mIStates; i++) {
|
|
const float thisCost = mSurvivors[i].cost;
|
|
if (thisCost>=minCost) continue;
|
|
minCost = thisCost;
|
|
minIndex=i;
|
|
}
|
|
return mSurvivors[minIndex];
|
|
}
|
|
|
|
|
|
const ViterbiTCH_AFS4_75::vCand& ViterbiTCH_AFS4_75::step(uint32_t inSample, const float *probs, const float *iprobs)
|
|
{
|
|
branchCandidates();
|
|
getSoftCostMetrics(inSample,probs,iprobs);
|
|
pruneCandidates();
|
|
return minCost();
|
|
}
|
|
|
|
|
|
|
|
void ViterbiTCH_AFS4_75::decode(const SoftVector &in, BitVector& target)
|
|
{
|
|
ViterbiTCH_AFS4_75 &decoder = *this;
|
|
const size_t sz = in.size() - 30;
|
|
const unsigned deferral = decoder.deferral();
|
|
const size_t ctsz = sz + deferral*decoder.iRate();
|
|
assert(sz == decoder.iRate()*target.size());
|
|
|
|
// Build a "history" array where each element contains the full history.
|
|
uint32_t history[ctsz];
|
|
{
|
|
BitVector bits = in.sliced();
|
|
uint32_t accum = 0;
|
|
for (size_t i=0; i<sz; i++) {
|
|
accum = (accum<<1) | bits.bit(i);
|
|
history[i] = accum;
|
|
}
|
|
// Repeat last bit at the end.
|
|
for (size_t i=sz; i<ctsz; i++) {
|
|
accum = (accum<<1) | (accum & 0x01);
|
|
history[i] = accum;
|
|
}
|
|
}
|
|
|
|
// Precompute metric tables.
|
|
float matchCostTable[ctsz];
|
|
float mismatchCostTable[ctsz];
|
|
{
|
|
const float *dp = in.begin();
|
|
for (size_t i=0; i<sz; i++) {
|
|
// pVal is the probability that a bit is correct.
|
|
// ipVal is the probability that a bit is incorrect.
|
|
float pVal = dp[i];
|
|
if (pVal>0.5F) pVal = 1.0F-pVal;
|
|
float ipVal = 1.0F-pVal;
|
|
// This is a cheap approximation to an ideal cost function.
|
|
if (pVal<0.01F) pVal = 0.01;
|
|
if (ipVal<0.01F) ipVal = 0.01;
|
|
matchCostTable[i] = 0.25F/ipVal;
|
|
mismatchCostTable[i] = 0.25F/pVal;
|
|
}
|
|
|
|
// pad end of table with unknowns
|
|
for (size_t i=sz; i<ctsz; i++) {
|
|
matchCostTable[i] = 0.5F;
|
|
mismatchCostTable[i] = 0.5F;
|
|
}
|
|
}
|
|
|
|
{
|
|
decoder.initializeStates();
|
|
// Each sample of history[] carries its history.
|
|
// So we only have to process every iRate-th sample.
|
|
const unsigned step = decoder.iRate();
|
|
// input pointer
|
|
const uint32_t *ip = history + step - 1;
|
|
// output pointers
|
|
char *op = target.begin();
|
|
const char *const opt = target.end();
|
|
// table pointers
|
|
const float* match = matchCostTable;
|
|
const float* mismatch = mismatchCostTable;
|
|
size_t oCount = 0;
|
|
while (op<opt) {
|
|
// Viterbi algorithm
|
|
assert(match-matchCostTable<(int)(sizeof(matchCostTable)/sizeof(matchCostTable[0])-1));
|
|
assert(mismatch-mismatchCostTable<(int)(sizeof(mismatchCostTable)/sizeof(mismatchCostTable[0])-1));
|
|
const ViterbiTCH_AFS4_75::vCand &minCost = decoder.step(*ip, match, mismatch);
|
|
ip += step;
|
|
match += step;
|
|
mismatch += step;
|
|
// output
|
|
if (oCount>=deferral) *op++ = (minCost.iState >> deferral)&0x01;
|
|
oCount++;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|