OpenBTS-UMTS/CommonLibs/TurboCoder.cpp

655 lines
15 KiB
C++

/*
* OpenBTS provides an open source alternative to legacy telco protocols and
* traditionally complex, proprietary hardware systems.
*
* Copyright 2008, 2009 Free Software Foundation, Inc.
* Copyright 2011-2014 Range Networks, Inc.
*
* This software is distributed under the terms of the GNU Affero General
* Public License version 3. See the COPYING and NOTICE files in the main
* directory for licensing information.
*
* 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 "TurboCoder.h"
#include <iostream>
#include <cstdlib>
#include <stdio.h>
#include <sstream>
using namespace std;
/** (pat) This is the old version. There is a new version in BitVector.cpp
Apply a Galois polymonial to a binary seqeunce.
@param val The input sequence.
@param poly The polynomial.
@param order The order of the polynomial.
@return Single-bit result.
*/
static unsigned applyPolyOld(uint64_t val, uint64_t poly)
{
uint64_t prod = val & poly;
prod = (prod ^ (prod >> 32));
prod = (prod ^ (prod >> 16));
prod = (prod ^ (prod >> 8));
prod = (prod ^ (prod >> 4));
prod = (prod ^ (prod >> 2));
prod = (prod ^ (prod >> 1));
return prod & 0x01;
}
int turboCoderConstituentEncoder(int &D, int inbit)
{
int D0 = D;
int D1 = D >> 1;
int D2 = D >> 2;
int nextin = (inbit ^ D1 ^ D2) & 1;
int zk = (D2 ^ D0 ^ nextin) & 1;
D = (D << 1) | nextin;
return zk;
}
void turboCoderTrellisTermination(int &D, int &xk, int &zk)
{
int D0 = D;
int D1 = D >> 1;
int D2 = D >> 2;
xk = (D2 ^ D1) & 1;
zk = (D2 ^ D0) & 1;
D = D << 1;
}
void BitVector::encode(const ViterbiTurbo& coder, BitVector& target, TurboInterleaver& wInterleaver)
{
assert(target.size() == size() * 3 + 12);
int CE1 = 0;
int CE2 = 0;
char *outPtr = target.begin();
vector<int> permutation = wInterleaver.permutation();
for (unsigned i = 0; i < size(); i++) {
int inbit1 = mStart[i];
int inbit2 = mStart[permutation[i]];
*outPtr++ = inbit1;
*outPtr++ = turboCoderConstituentEncoder(CE1, inbit1);
*outPtr++ = turboCoderConstituentEncoder(CE2, inbit2);
}
int xk, zk;
for (int i = 0; i < 3; i++) {
turboCoderTrellisTermination(CE1, xk, zk);
*outPtr++ = xk;
*outPtr++ = zk;
}
for (int i = 0; i < 3; i++) {
turboCoderTrellisTermination(CE2, xk, zk);
*outPtr++ = xk;
*outPtr++ = zk;
}
}
ViterbiTurbo::ViterbiTurbo()
{
assert(mDeferral < 32);
mCoeffs[0] = 0x01;
mCoeffs[1] = 0x0b;
computeStateTables(0);
computeStateTables(1);
computeGeneratorTable();
}
void ViterbiTurbo::initializeStates()
{
for (unsigned i=0; i<mIStates; i++) clear(mSurvivors[i]);
for (unsigned i=0; i<mNumCands; i++) clear(mCandidates[i]);
}
void ViterbiTurbo::computeStateTables(unsigned g)
{
assert(g<mIRate);
for (unsigned state=0; state<mIStates; state++) {
// 0 input
uint64_t inputVal = state<<1;
mStateTable[g][inputVal] = applyPolyOld(inputVal, mCoeffs[g]);
// 1 input
inputVal |= 1;
mStateTable[g][inputVal] = applyPolyOld(inputVal, mCoeffs[g]);
}
}
void ViterbiTurbo::computeGeneratorTable()
{
for (unsigned index=0; index<mIStates*2; index++) {
mGeneratorTable[index] = (mStateTable[0][index]<<1) | mStateTable[1][index];
}
}
void ViterbiTurbo::branchCandidates()
{
// Branch to generate new input states.
const vCand *sp = mSurvivors;
for (unsigned i=0; i<mNumCands; i+=2) {
// extend and suffix
const uint32_t iState0 = (sp->iState) << 1; // input state for 0
const uint32_t iState1 = iState0 | 0x01; // input state for 1
const uint32_t oStateShifted = (sp->oState) << mIRate; // shifted output
const float cost = sp->cost;
const char D1 = (sp->rState) >> 1;
const char D2 = (sp->rState) >> 2;
const char fb = (D1 ^ D2) & 1; // feedback that affects the real next state
const uint32_t rState0 = ((sp->rState << 1) ^ fb) << 0;
const uint32_t rState1 = rState0 ^ 1;
sp++;
// 0 input extension
mCandidates[i].cost = cost;
mCandidates[i].oState = oStateShifted | (mGeneratorTable[0] & 2) | (mGeneratorTable[rState0 & mCMask] & 1);
mCandidates[i].iState = iState0;
mCandidates[i].rState = rState0;
// 1 input extension
mCandidates[i+1].cost = cost;
mCandidates[i+1].oState = oStateShifted | (mGeneratorTable[1] & 2) | (mGeneratorTable[rState1 & mCMask] & 1);
mCandidates[i+1].iState = iState1;
mCandidates[i+1].rState = rState1;
}
}
/*
* Here's my thinking about decoding to soft decoder outputs:
* It can't be exact because it's np-hard. So I figure simulate digital
* encoder inputs and encoder outputs, keep a rough estimate of confidence
* when comparing simulated encoder outputs to decoder inputs, and use that
* confidence to make the decoder output soft. My rough estimate of
* confidence in a simulated encoder output (hard) to decoder input (soft) is exact match
* (0 : 0.0 or 1 : 1.0) is 100%, exact mismatch (0 : 1.0 or 1 to 0.0) is 0%,
* and interpolate linearly between them. I combine those confidences by
* averaging. Here I add all the confidences, later to divide by how many were added.
* The infrastructure was already in place for cost to minimize rather than
* confidence to maximize, so I save cost = 1 - confidence.
* See SoftVector::decode to see how these get turned into decoder outputs.
*/
void ViterbiTurbo::getSoftCostMetrics(const float *inSample)
{
for (unsigned i=0; i<mNumCands; i++) {
vCand& thisCand = mCandidates[i];
// We examine input bits 2 at a time for a rate 1/2 coder.
thisCand.cost += (
((thisCand.oState & 1) ? (1.0 - inSample[0]) : inSample[0]) +
((thisCand.oState & 2) ? (1.0 - inSample[-1]) : inSample[-1]));
}
}
void ViterbiTurbo::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 ViterbiTurbo::vCand* ViterbiTurbo::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 ViterbiTurbo::vCand* ViterbiTurbo::step(const float *inSample)
{
branchCandidates();
getSoftCostMetrics(inSample);
pruneCandidates();
return minCost();
}
/*
* The deferral queue:
* Unlike the other Viterbi algorithms, above, this one doesn't put
* arbitrary values into the decoder input vector, and use unknown for
* both a match and mismatch. That created extra noise in the decoder output.
* Instead, this one simply flushes the last deferral values
* from the last best candidate, using the confidence from that candidate.
*
* Computing soft output values:
* Get average cost by dividing by how many costs got added.
* Confidence = 1 - average cost.
* Digital output @ confidence -> soft output:
* 0 @ 0% -> 0.5
* 0 @ 100% -> 0.0
* 1 @ 0% -> 0.5
* 1 @ 100% -> 1.0
* interpolate linearly
*/
void SoftVector::decode(ViterbiTurbo &decoder, SoftVector& target) const
{
int K = target.size();
assert(size() == (unsigned)(2 * K));
const unsigned deferral = decoder.deferral();
decoder.initializeStates();
const unsigned step = decoder.iRate();
// input pointer
const float *ip = mStart + step - 1;
// output pointer
float *op = target.begin();
// fill up the deferral queue
for (unsigned i = 0; i < deferral; i++, ip += step) {
decoder.step(ip);
}
const ViterbiTurbo::vCand *minCost = 0;
float confidence = 0;
// the normal stuff
int avgCount = (deferral + 1) * 2;
for (unsigned i = 0; i < K-deferral; i++, ip += step, avgCount += 2) {
minCost = decoder.step(ip);
confidence = 1.0 - (minCost->cost / (float)avgCount);
//cout << "i: " << i << " cost: " << minCost->cost << " conf: " << confidence << endl;
*op++ = ((minCost->iState >> deferral) & 1) ?
(confidence + 1.0) / 2.0 :
(1.0 - confidence) / 2.0 ;
}
// flush the deferral queue
for (int i = deferral-1; i >= 0; i--) {
*op++ = ((minCost->iState >> i) & 1) ?
(confidence + 1.0) / 2.0 :
(1.0 - confidence) / 2.0 ;
}
}
void SoftVector::decode(ViterbiTurbo &decoder, BitVector& target, TurboInterleaver& wInterleaver) const
{
assert(size() == target.size() * 3 + 12);
int K = (size() - 12) / 3;
SoftVector xkzk(2 * K);
// extract xk and zk
for (int i = 0; i < K; i++) {
xkzk[i*2] = mStart[i*3]; // xk
xkzk[i*2+1] = mStart[i*3+1]; // zk
}
// first pass decode
SoftVector t(K);
xkzk.decode(decoder, t);
// interleave
SoftVector ti(K);
wInterleaver.interleave(t, ti);
// interleave ti with z'k
SoftVector tizpk(2 * K);
for (int i = 0; i < K; i++) {
tizpk[i*2] = ti[i];
tizpk[i*2+1] = mStart[i*3+2];
}
// second pass decode
SoftVector tt(K);
tizpk.decode(decoder, tt);
// de-interleave
wInterleaver.unInterleave(tt, target);
//target = t.sliced();
}
int haltDecode = 0;
void SoftVector::decode(ViterbiTurbo &decoder, SoftVector& target, TurboInterleaver& wInterleaver) const
{
std::cout << size() << " " << target.size() << endl;
assert(size() == target.size() * 3 + 12);
int K = (size() - 12) / 3;
SoftVector xkzk(2 * K);
SoftVector guh(K);
// extract xk and zk
for (int i = 0; i < K; i++) {
xkzk[i*2] = guh[i] = mStart[i*3]; // xk
xkzk[i*2+1] = mStart[i*3+1]; // zk
}
// first pass decode
SoftVector t(K);
xkzk.decode(decoder, t);
std::cout << "t: " << t << endl;
// interleave
SoftVector ti(K);
for (int i = 0; i < K; i++) {
guh[i] = 0.5*(0*guh[i] + 2*t[i]);
}
wInterleaver.interleave(guh/*t*/, ti);
// interleave ti with z'k
SoftVector tizpk(2 * K);
for (int i = 0; i < K; i++) {
tizpk[i*2] = ti[i];
tizpk[i*2+1] = mStart[i*3+2];
}
// second pass decode
SoftVector tt(K);
tizpk.decode(decoder, tt);
// de-interleave
SoftVector tempTarget(target.size());
wInterleaver.unInterleave(tt, tempTarget);
SoftVector tempOutput = *this;
for (int i = 0; i < K; i++) {
tempOutput[3*i] = 0.5*(tempTarget[i]+tempOutput[3*i]);
}
haltDecode++;
if (haltDecode < 1) {
tempOutput.decode(decoder,target,wInterleaver);
}
else {
haltDecode = 0;
target = tempTarget;
}
//target = t;
}
// UMTS FEC turbo coder internal interleaver, 25.212, 4.2.3.2.3
// The interleaving is so stunningly complicated that a permutation
// vector needs to be initialized when the channel is created,
// then interleaving works off the permutation vector.
TurboInterleaver::TurboInterleaver(int K)
{
static const int pv[] = {
7, 3,
11, 2,
13, 2,
17, 3,
19, 2,
23, 5,
29, 2,
31, 3,
37, 2,
41, 6,
43, 3,
47, 5,
53, 2,
59, 2,
61, 2,
67, 2,
71, 7,
73, 5,
79, 3,
83, 2,
89, 3,
97, 5,
101, 2,
103, 5,
107, 2,
109, 6,
113, 3,
127, 3,
131, 2,
137, 3,
139, 2,
149, 2,
151, 6,
157, 5,
163, 2,
167, 5,
173, 2,
179, 2,
181, 2,
191, 19,
193, 5,
197, 2,
199, 3,
211, 2,
223, 3,
227, 2,
229, 6,
233, 3,
239, 7,
241, 7,
251, 6,
257, 3,
0, 0
};
static const int irpp5[] = {4, 3, 2, 1, 0};
static const int irpp10[] = {9, 8, 7, 6, 5, 4, 3, 2, 1, 0};
static const int irpp20[] = {19, 9, 14, 4, 0, 2, 5, 7, 12, 18, 16, 13, 17, 15, 3, 1, 6, 11, 8, 10};
static const int irpp20a[] = {19, 9, 14, 4, 0, 2, 5, 7, 12, 18, 10, 8, 13, 17, 3, 1, 16, 6, 15, 11};
if (K == 0) {
mPermutation.resize(0);
return;
}
assert(K >= 40 && K <= 5114);
mPermutation.resize(K);
// 4.2.3.2.3.1 step 1
int R;
if (K <= 159) {
R = 5;
} else if (K <= 200) {
R = 10;
} else if (K <= 480) {
R = 20;
} else if (K <= 530) {
R = 10;
} else {
R = 20;
}
// 4.2.3.2.3.1 step 2
int C, p;
int v = 0; // init to shut up compiler warning
if (K >= 481 && K <= 530) {
p = 53;
C = p;
} else {
for (int pvptr = 0; ; pvptr += 2) {
p = pv[pvptr];
v = pv[pvptr+1];
assert(p != 0);
if (K <= R * (p+1)) break;
}
if (K <= R * (p-1)) {
C = p-1;
} else if (R * (p-1) < K && K <= R*p) {
C = p;
} else if (R * p < K) {
C = p+1;
} else {
assert(0);
}
}
// 4.2.3.2.3.1 step 3
vector<int> matrix(R*C);
for (int i = 0; i < K; i++) {
matrix[i] = i;
}
for (int i = K; i < R * C; i++) {
matrix[i] = -1;
}
// 4.2.3.2.3.2 step 1
// already have v
// 4.2.3.2.3.2 step 2
vector<int> s(p-1);
s[0] = 1;
for (int j = 1; j <= p-2; j++) {
s[j] = (v * s[j-1]) % p;
}
// 4.2.3.2.3.2 step 3
// resuse the prime number list in table 2
vector<int> q(R);
q[0] = 1;
int pvptr = 0;
for (int i = 1; i <= R-1; i++) {
while (1) {
q[i] = pv[pvptr];
pvptr += 2;
assert(q[i] != 0);
assert(q[i] > 6);
assert(q[i] > q[i-1]);
if (gcd(q[i], p-1) == 1) break;
}
}
// 4.2.3.2.3.2 step 4
vector<int> r(R);
const int *T;
if (K <= 159) {
T = irpp5;
assert(R == 5);
} else if (K <= 200) {
T = irpp10;
assert(R == 10);
} else if (K <= 480) {
T = irpp20a;
assert(R == 20);
} else if (K <= 530) {
T = irpp10;
assert(R == 10);
} else if (K <= 2280) {
T = irpp20a;
assert(R == 20);
} else if (K <= 2480) {
T = irpp20;
assert(R == 20);
} else if (K <= 3160) {
T = irpp20a;
assert(R == 20);
} else if (K <= 3210) {
T = irpp20;
assert(R == 20);
} else {
T = irpp20a;
assert(R == 20);
}
for (int i = 0; i <= R-1; i++) {
r[T[i]] = q[i];
}
// 4.2.3.2.3.2 step 5
for (int i = 0; i < R; i++) {
vector<int> U(C);
for (int j = 0; j <= p-2; j++) {
U[j] = s[(j * r[i]) % (p-1)];
}
if (C == p) {
U[p-1] = 0;
} else if (C == p+1) {
U[p-1] = 0;
U[p] = p;
if (K == R*C && i == R-1) {
int t = U[p];
U[p] = U[0];
U[0] = t;
}
} else if (C == p-1) {
for (int j = 0; j <= p-2; j++) {
U[j] = U[j] - 1;
}
} else {
assert(0);
}
// now permute row i of matrix based on U
vector<int> t(C);
for (int j = 0; j < C; j++) {
t[j] = matrix[i*C + U[j]];
}
for (int j = 0; j < C; j++) {
matrix[i*C + j] = t[j];
}
}
// 4.2.3.2.3.2 step 6 and 4.2.3.2.3.3
// combine the inter-row permutation with "reading out the bits"
// where reading out the bits is actually setting mPermutation
int outptr = 0;
// read out the columns in order
// read out the rows in the order of T
for (int col = 0; col < C; col++) {
//std::cout << endl;
for (int row = 0; row < R; row++) {
int v = matrix[col + C*T[row]];
if (v < 0) continue; // ignore padding
//std::cout << v << " ";
mPermutation[outptr++] = v;
}
}
//std::cout << endl;
assert(outptr == K);
}
int TurboInterleaver::gcd(int x, int y)
{
if (x > y) {
return x % y == 0 ? y : gcd(y, x % y);
} else {
return y % x == 0 ? x : gcd(x, y % x);
}
}
void TurboInterleaver::interleave(SoftVector &in, SoftVector &out)
{
assert(in.size() == mPermutation.size());
assert(out.size() == mPermutation.size());
for (unsigned i = 0; i < in.size(); i++) {
out[i] = in[mPermutation[i]];
}
}
void TurboInterleaver::unInterleave(SoftVector &in, BitVector &out)
{
assert(in.size() == mPermutation.size());
assert(out.size() == mPermutation.size());
for (unsigned i = 0; i < in.size(); i++) {
out[mPermutation[i]] = in[i] > 0.5 ? 1 : 0;
}
}
void TurboInterleaver::unInterleave(SoftVector &in, SoftVector &out)
{
assert(in.size() == mPermutation.size());
assert(out.size() == mPermutation.size());
for (unsigned i = 0; i < in.size(); i++) {
out[mPermutation[i]] = in[i];
}
}