aboutsummaryrefslogtreecommitdiffstats
path: root/lib/decoding
diff options
context:
space:
mode:
authorRoman Khassraf <roman@khassraf.at>2015-06-02 08:49:12 +0200
committerRoman Khassraf <roman@khassraf.at>2015-06-02 08:49:12 +0200
commitd71e658ecb283b962079c67dd60d6c0230d1f58b (patch)
treee5c45fada1af9d22de6bbfdab82724058f86dfc8 /lib/decoding
parentb85c0626d99ad9acbc997a06bf9b705e692e5e49 (diff)
Updated BitVector to recent source
Diffstat (limited to 'lib/decoding')
-rw-r--r--lib/decoding/BitVector.cpp520
-rw-r--r--lib/decoding/BitVector.h336
-rw-r--r--lib/decoding/Vector.h580
-rw-r--r--lib/decoding/VocoderFrame.h6
-rw-r--r--lib/decoding/tch_f_decoder_impl.cc6
-rw-r--r--lib/decoding/tch_f_decoder_impl.h1
6 files changed, 796 insertions, 653 deletions
diff --git a/lib/decoding/BitVector.cpp b/lib/decoding/BitVector.cpp
index 89d8d19..c0c097b 100644
--- a/lib/decoding/BitVector.cpp
+++ b/lib/decoding/BitVector.cpp
@@ -1,21 +1,26 @@
/*
-* Copyright 2008 Free Software Foundation, Inc.
+* Copyright 2008, 2009, 2014 Free Software Foundation, Inc.
+* Copyright 2014 Range Networks, Inc.
*
-* This software is distributed under the terms of the GNU Public License.
+*
+* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
+*
+* This use of this software may be subject to additional restrictions.
+* See the LEGAL file in the main directory for details.
- This program 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.
+ 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 General Public License for more details.
+ 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 General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
+ 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/>.
*/
@@ -24,50 +29,38 @@
#include "BitVector.h"
#include <iostream>
+#include <stdio.h>
+#include <sstream>
+#include <string.h>
+//#include <Logger.h>
using namespace std;
-/**
- 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.
-*/
-unsigned applyPoly(uint64_t val, uint64_t poly, unsigned order)
-{
- uint64_t prod = val & poly;
- unsigned sum = prod;
- for (unsigned i=1; i<order; i++) sum ^= prod>>i;
- return sum & 0x01;
-}
-
-
-
-
-
BitVector::BitVector(const char *valString)
- :Vector<char>(strlen(valString))
{
- uint32_t accum = 0;
- for (size_t i=0; i<size(); i++) {
- accum <<= 1;
- if (valString[i]=='1') accum |= 0x01;
- mStart[i] = accum;
+ // 1-30-2013 pat: I dont know what this was intended to do, but it did not create a normalized BitVector,
+ // and it could even fail if the accum overlows 8 bits.
+ //uint32_t accum = 0;
+ //for (size_t i=0; i<size(); i++) {
+ // accum <<= 1;
+ // if (valString[i]=='1') accum |= 0x01;
+ // mStart[i] = accum;
+ //}
+ vInit(strlen(valString));
+ char *rp = begin();
+ for (const char *cp = valString; *cp; cp++, rp++) {
+ *rp = (*cp == '1');
}
}
-
-
-
uint64_t BitVector::peekField(size_t readIndex, unsigned length) const
{
uint64_t accum = 0;
char *dp = mStart + readIndex;
- assert(dp+length <= mEnd);
+
for (unsigned i=0; i<length; i++) {
accum = (accum<<1) | ((*dp++) & 0x01);
}
@@ -75,6 +68,22 @@ uint64_t BitVector::peekField(size_t readIndex, unsigned length) const
}
+
+
+uint64_t BitVector::peekFieldReversed(size_t readIndex, unsigned length) const
+{
+ uint64_t accum = 0;
+ char *dp = mStart + readIndex + length - 1;
+ assert(dp<mEnd);
+ for (int i=(length-1); i>=0; i--) {
+ accum = (accum<<1) | ((*dp--) & 0x01);
+ }
+ return accum;
+}
+
+
+
+
uint64_t BitVector::readField(size_t& readIndex, unsigned length) const
{
const uint64_t retVal = peekField(readIndex,length);
@@ -83,21 +92,63 @@ uint64_t BitVector::readField(size_t& readIndex, unsigned length) const
}
+uint64_t BitVector::readFieldReversed(size_t& readIndex, unsigned length) const
+{
+
+ const uint64_t retVal = peekFieldReversed(readIndex,length);
+ readIndex += length;
+ return retVal;
+
+}
+
+
+
+
void BitVector::fillField(size_t writeIndex, uint64_t value, unsigned length)
{
- char *dpBase = mStart + writeIndex;
- char *dp = dpBase + length - 1;
- assert(dp < mEnd);
- while (dp>=dpBase) {
- *dp-- = value & 0x01;
- value >>= 1;
+ if (length != 0) {
+ char *dpBase = mStart + writeIndex;
+ char *dp = dpBase + length - 1;
+ assert(dp < mEnd);
+ while (dp>=dpBase) {
+ *dp-- = value & 0x01;
+ value >>= 1;
+ }
}
}
+
+void BitVector::fillFieldReversed(size_t writeIndex, uint64_t value, unsigned length)
+{
+ if (length != 0) {
+ char *dp = mStart + writeIndex;
+ char *dpEnd = dp + length - 1;
+ assert(dpEnd < mEnd);
+ while (dp<=dpEnd) {
+ *dp++ = value & 0x01;
+ value >>= 1;
+ }
+ }
+}
+
+
+
+
void BitVector::writeField(size_t& writeIndex, uint64_t value, unsigned length)
{
- fillField(writeIndex,value,length);
- writeIndex += length;
+ if (length != 0) {
+ fillField(writeIndex,value,length);
+ writeIndex += length;
+ }
+}
+
+
+void BitVector::writeFieldReversed(size_t& writeIndex, uint64_t value, unsigned length)
+{
+ if (length != 0) {
+ fillFieldReversed(writeIndex,value,length);
+ writeIndex += length;
+ }
}
@@ -136,6 +187,7 @@ void BitVector::reverse8()
void BitVector::LSB8MSB()
{
+ if (size()<8) return;
size_t size8 = 8*(size()/8);
size_t iTop = size8 - 8;
for (size_t i=0; i<=iTop; i+=8) segment(i,8).reverse8();
@@ -161,31 +213,6 @@ uint64_t BitVector::parity(Generator& gen) const
}
-void BitVector::encode(const ViterbiR2O4& coder, BitVector& target)
-{
- size_t sz = size();
- assert(sz*coder.iRate() == target.size());
-
- // Build a "history" array where each element contains the full history.
- uint32_t history[sz];
- uint32_t accum = 0;
- for (size_t i=0; i<sz; i++) {
- accum = (accum<<1) | bit(i);
- history[i] = accum;
- }
-
- // Look up histories in the pre-generated state table.
- char *op = target.begin();
- for (size_t i=0; i<sz; i++) {
- unsigned index = coder.cMask() & history[i];
- for (unsigned g=0; g<coder.iRate(); g++) {
- *op++ = coder.stateTable(g,index);
- }
- }
-}
-
-
-
unsigned BitVector::sum() const
{
unsigned sum = 0;
@@ -219,9 +246,6 @@ void BitVector::unmap(const unsigned *map, size_t mapSize, BitVector& dest) cons
-
-
-
ostream& operator<<(ostream& os, const BitVector& hv)
{
for (size_t i=0; i<hv.size(); i++) {
@@ -234,121 +258,6 @@ ostream& operator<<(ostream& os, const BitVector& hv)
-ViterbiR2O4::ViterbiR2O4()
-{
- assert(mDeferral < 32);
- mCoeffs[0] = 0x019;
- mCoeffs[1] = 0x01b;
- computeStateTables(0);
- computeStateTables(1);
- computeGeneratorTable();
-}
-
-
-
-
-void ViterbiR2O4::initializeStates()
-{
- for (unsigned i=0; i<mIStates; i++) clear(mSurvivors[i]);
- for (unsigned i=0; i<mNumCands; i++) clear(mCandidates[i]);
-}
-
-
-
-void ViterbiR2O4::computeStateTables(unsigned g)
-{
- assert(g<mIRate);
- for (unsigned state=0; state<mIStates; state++) {
- // 0 input
- uint32_t inputVal = state<<1;
- mStateTable[g][inputVal] = applyPoly(inputVal, mCoeffs[g], mOrder+1);
- // 1 input
- inputVal |= 1;
- mStateTable[g][inputVal] = applyPoly(inputVal, mCoeffs[g], mOrder+1);
- }
-}
-
-void ViterbiR2O4::computeGeneratorTable()
-{
- for (unsigned index=0; index<mIStates*2; index++) {
- mGeneratorTable[index] = (mStateTable[0][index]<<1) | mStateTable[1][index];
- }
-}
-
-
-
-
-
-
-void ViterbiR2O4::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;
- sp++;
- // 0 input extension
- mCandidates[i].cost = cost;
- mCandidates[i].oState = oStateShifted | mGeneratorTable[iState0 & mCMask];
- mCandidates[i].iState = iState0;
- // 1 input extension
- mCandidates[i+1].cost = cost;
- mCandidates[i+1].oState = oStateShifted | mGeneratorTable[iState1 & mCMask];
- mCandidates[i+1].iState = iState1;
- }
-}
-
-
-void ViterbiR2O4::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];
- // We examine input bits 2 at a time for a rate 1/2 coder.
- const unsigned mismatched = inSample ^ (thisCand.oState);
- thisCand.cost += cTab[mismatched&0x01][1] + cTab[(mismatched>>1)&0x01][0];
- }
-}
-
-
-void ViterbiR2O4::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 ViterbiR2O4::vCand& ViterbiR2O4::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 ViterbiR2O4::vCand& ViterbiR2O4::step(uint32_t inSample, const float *probs, const float *iprobs)
-{
- branchCandidates();
- getSoftCostMetrics(inSample,probs,iprobs);
- pruneCandidates();
- return minCost();
-}
-
-
uint64_t Parity::syndrome(const BitVector& receivedCodeword)
{
return receivedCodeword.syndrome(*this);
@@ -358,7 +267,7 @@ uint64_t Parity::syndrome(const BitVector& receivedCodeword)
void Parity::writeParityWord(const BitVector& data, BitVector& parityTarget, bool invert)
{
uint64_t pWord = data.parity(*this);
- if (invert) pWord = ~pWord;
+ if (invert) pWord = ~pWord;
parityTarget.fillField(0,pWord,size());
}
@@ -393,84 +302,54 @@ BitVector SoftVector::sliced() const
-void SoftVector::decode(ViterbiR2O4 &decoder, BitVector& target) const
+// (pat) Added 6-22-2012
+float SoftVector::getEnergy(float *plow) const
{
- const size_t sz = size();
- const unsigned deferral = decoder.deferral();
- const size_t ctsz = sz + deferral;
- assert(sz <= decoder.iRate()*target.size());
-
- // Build a "history" array where each element contains the full history.
- uint32_t history[ctsz];
- {
- BitVector bits = 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 = mStart;
- 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 correct.
- 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;
- }
+ const SoftVector &vec = *this;
+ int len = vec.size();
+ float avg = 0; float low = 1;
+ for (int i = 0; i < len; i++) {
+ float bit = vec[i];
+ float energy = 2*((bit < 0.5) ? (0.5-bit) : (bit-0.5));
+ if (energy < low) low = energy;
+ avg += energy/len;
}
-
- {
- 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
- const ViterbiR2O4::vCand &minCost = decoder.step(*ip, match, mismatch);
- ip += step;
- match += step;
- mismatch += step;
- // output
- if (oCount>=deferral) *op++ = (minCost.iState >> deferral);
- oCount++;
+ if (plow) { *plow = low; }
+ return avg;
+}
+
+// (pat) Added 1-2014. Compute SNR of a soft vector. Very similar to above.
+// Since we dont really know what the expected signal values are, we will assume that the signal is 0 or 1
+// and return the SNR on that basis.
+// SNR is power(signal) / power(noise) where power can be calculated as (RMS(signal) / RMS(noise))**2 of the values.
+// Since RMS is square-rooted, ie RMS = sqrt(1/n * (x1**2 + x2**2 ...)), we just add up the squares.
+// To compute RMS of the signal we will remove any constant offset, so the signal values are either 0.5 or -0.5,
+// so the RMS of the signal is just 0.5**2 * len; all we need to compute is the noise component.
+float SoftVector::getSNR() const
+{
+ float sumSquaresNoise = 0;
+ const SoftVector &vec = *this;
+ int len = vec.size();
+ if (len == 0) { return 0.0; }
+ for (int i = 0; i < len; i++) {
+ float bit = vec[i];
+ if (bit < 0.5) {
+ // Assume signal is 0.
+ sumSquaresNoise += (bit - 0.0) * (bit - 0.0);
+ } else {
+ // Assume signal is 1.
+ sumSquaresNoise += (bit - 1.0) * (bit - 1.0);
}
}
+ float sumSquaresSignal = 0.5 * 0.5 * len;
+ // I really want log10 of this to convert to dB, but log is expensive, and Harvind seems to like absolute SNR.
+ // Clamp max to 999; it shouldnt get up there but be sure. This also avoids divide by zero.
+ if (sumSquaresNoise * 1000 < sumSquaresSignal) return 999;
+ return sumSquaresSignal / sumSquaresNoise;
}
-
ostream& operator<<(ostream& os, const SoftVector& sv)
{
for (size_t i=0; i<sv.size(); i++) {
@@ -496,6 +375,22 @@ void BitVector::pack(unsigned char* targ) const
targ[bytes] = peekField(whole,rem) << (8-rem);
}
+string BitVector::packToString() const
+{
+ string result;
+ result.reserve((size()+7)/8);
+ // Tempting to call this->pack(result.c_str()) but technically c_str() is read-only.
+ unsigned bytes = size()/8;
+ for (unsigned i=0; i<bytes; i++) {
+ result.push_back(peekField(i*8,8));
+ }
+ unsigned whole = bytes*8;
+ unsigned rem = size() - whole;
+ if (rem==0) return result;
+ result.push_back(peekField(whole,rem) << (8-rem));
+ return result;
+}
+
void BitVector::unpack(const unsigned char* src)
{
@@ -507,7 +402,104 @@ void BitVector::unpack(const unsigned char* src)
unsigned whole = bytes*8;
unsigned rem = size() - whole;
if (rem==0) return;
- fillField(whole,src[bytes],rem);
+ fillField(whole,src[bytes] >> (8-rem),rem);
+}
+
+void BitVector::hex(ostream& os) const
+{
+ os << std::hex;
+ unsigned digits = size()/4;
+ size_t wp=0;
+ for (unsigned i=0; i<digits; i++) {
+ os << readField(wp,4);
+ }
+ os << std::dec;
+}
+
+std::string BitVector::hexstr() const
+{
+ std::ostringstream ss;
+ hex(ss);
+ return ss.str();
+}
+
+
+bool BitVector::unhex(const char* src)
+{
+ // Assumes MSB-first packing.
+ unsigned int val;
+ unsigned digits = size()/4;
+ for (unsigned i=0; i<digits; i++) {
+ if (sscanf(src+i, "%1x", &val) < 1) {
+ return false;
+ }
+ fillField(i*4,val,4);
+ }
+ unsigned whole = digits*4;
+ unsigned rem = size() - whole;
+ if (rem>0) {
+ if (sscanf(src+digits, "%1x", &val) < 1) {
+ return false;
+ }
+ fillField(whole,val,rem);
+ }
+ return true;
+}
+
+bool BitVector::operator==(const BitVector &other) const
+{
+ unsigned l = size();
+ return l == other.size() && 0==memcmp(begin(),other.begin(),l);
+}
+
+void BitVector::copyPunctured(BitVector &dst, const unsigned *puncture, const size_t plth)
+{
+ assert(size() - plth == dst.size());
+ char *srcp = mStart;
+ char *dstp = dst.mStart;
+ const unsigned *pend = puncture + plth;
+ while (srcp < mEnd) {
+ if (puncture < pend) {
+ int n = (*puncture++) - (srcp - mStart);
+ assert(n >= 0);
+ for (int i = 0; i < n; i++) {
+ assert(srcp < mEnd && dstp < dst.mEnd);
+ *dstp++ = *srcp++;
+ }
+ srcp++;
+ } else {
+ while (srcp < mEnd) {
+ assert(dstp < dst.mEnd);
+ *dstp++ = *srcp++;
+ }
+ }
+ }
+ assert(dstp == dst.mEnd && puncture == pend);
+}
+
+void SoftVector::copyUnPunctured(SoftVector &dst, const unsigned *puncture, const size_t plth)
+{
+ assert(size() + plth == dst.size());
+ float *srcp = mStart;
+ float *dstp = dst.mStart;
+ const unsigned *pend = puncture + plth;
+ while (dstp < dst.mEnd) {
+ if (puncture < pend) {
+ int n = (*puncture++) - (dstp - dst.mStart);
+ assert(n >= 0);
+ for (int i = 0; i < n; i++) {
+ assert(srcp < mEnd && dstp < dst.mEnd);
+ *dstp++ = *srcp++;
+ }
+ *dstp++ = 0.5;
+ } else {
+ while (srcp < mEnd) {
+ assert(dstp < dst.mEnd);
+ *dstp++ = *srcp++;
+ }
+ }
+ }
+ assert(dstp == dst.mEnd && puncture == pend);
}
// vim: ts=4 sw=4
diff --git a/lib/decoding/BitVector.h b/lib/decoding/BitVector.h
index 3019c2c..0f78b97 100644
--- a/lib/decoding/BitVector.h
+++ b/lib/decoding/BitVector.h
@@ -1,30 +1,35 @@
/*
-* Copyright 2008 Free Software Foundation, Inc.
+* Copyright 2008, 2009, 2014 Free Software Foundation, Inc.
+* Copyright 2014 Range Networks, Inc.
*
-* This software is distributed under the terms of the GNU Public License.
+* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
+*
+* This use of this software may be subject to additional restrictions.
+* See the LEGAL file in the main directory for details.
- This program 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.
+ 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 General Public License for more details.
+ 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 General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
+ 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/>.
*/
-#ifndef FECVECTORS_H
-#define FECVECTORS_H
+#ifndef BITVECTORS_H
+#define BITVECTORS_H
#include "Vector.h"
#include <stdint.h>
+#include <stdio.h>
class BitVector;
@@ -32,6 +37,7 @@ class SoftVector;
+
/** Shift-register (LFSR) generator. */
class Generator {
@@ -109,171 +115,83 @@ class Parity : public Generator {
};
-
-
-/**
- Class to represent convolutional coders/decoders of rate 1/2, memory length 4.
- This is the "workhorse" coder for most GSM channels.
-*/
-class ViterbiR2O4 {
-
- private:
- /**name Lots of precomputed elements so the compiler can optimize like hell. */
- //@{
- /**@name Core values. */
- //@{
- static const unsigned mIRate = 2; ///< reciprocal of rate
- static const unsigned mOrder = 4; ///< memory length of generators
- //@}
- /**@name Derived values. */
- //@{
- static const unsigned mIStates = 0x01 << mOrder; ///< number of states, number of survivors
- static const uint32_t mSMask = mIStates-1; ///< survivor mask
- static const uint32_t mCMask = (mSMask<<1) | 0x01; ///< candidate mask
- static const uint32_t mOMask = (0x01<<mIRate)-1; ///< ouput mask, all iRate low bits set
- static const unsigned mNumCands = mIStates*2; ///< number of candidates to generate during branching
- static const unsigned mDeferral = 6*mOrder; ///< deferral to be used
- //@}
- //@}
-
- /** Precomputed tables. */
- //@{
- uint32_t mCoeffs[mIRate]; ///< polynomial for each generator
- uint32_t mStateTable[mIRate][2*mIStates]; ///< precomputed generator output tables
- uint32_t mGeneratorTable[2*mIStates]; ///< precomputed coder output table
- //@}
-
- public:
-
- /**
- A candidate sequence in a Viterbi decoder.
- The 32-bit state register can support a deferral of 6 with a 4th-order coder.
- */
- typedef struct candStruct {
- uint32_t iState; ///< encoder input associated with this candidate
- uint32_t oState; ///< encoder output associated with this candidate
- float cost; ///< cost (metric value), float to support soft inputs
- } vCand;
-
- /** Clear a structure. */
- void clear(vCand& v)
- {
- v.iState=0;
- v.oState=0;
- v.cost=0;
- }
-
-
- private:
-
- /**@name Survivors and candidates. */
- //@{
- vCand mSurvivors[mIStates]; ///< current survivor pool
- vCand mCandidates[2*mIStates]; ///< current candidate pool
- //@}
-
- public:
-
- unsigned iRate() const { return mIRate; }
- uint32_t cMask() const { return mCMask; }
- uint32_t stateTable(unsigned g, unsigned i) const { return mStateTable[g][i]; }
- unsigned deferral() const { return mDeferral; }
-
-
- ViterbiR2O4();
-
- /** Set all cost metrics to zero. */
- void initializeStates();
-
- /**
- Full cycle of the Viterbi algorithm: branch, metrics, prune, select.
- @return reference to minimum-cost candidate.
- */
- const vCand& step(uint32_t inSample, const float *probs, const float *iprobs);
-
- private:
-
- /** Branch survivors into new candidates. */
- void branchCandidates();
-
- /** Compute cost metrics for soft-inputs. */
- void getSoftCostMetrics(uint32_t inSample, const float *probs, const float *iprobs);
-
- /** Select survivors from the candidate set. */
- void pruneCandidates();
-
- /** Find the minimum cost survivor. */
- const vCand& minCost() const;
-
- /**
- Precompute the state tables.
- @param g Generator index 0..((1/rate)-1)
- */
- void computeStateTables(unsigned g);
-
- /**
- Precompute the generator outputs.
- mCoeffs must be defined first.
- */
- void computeGeneratorTable();
-
-};
-
-
-
-
-class BitVector : public Vector<char> {
-
-
+// (pat) Nov 2013. I rationalized the behavior of BitVector and added assertions to core dump code
+// that relied on the bad aspects of the original behavior. See comments at VectorBase.
+class BitVector : public VectorBase<char>
+{
public:
-
/**@name Constructors. */
//@{
/**@name Casts of Vector constructors. */
- //@{
- BitVector(char* wData, char* wStart, char* wEnd)
- :Vector<char>(wData,wStart,wEnd)
- { }
- BitVector(size_t len=0):Vector<char>(len) {}
- BitVector(const Vector<char>& source):Vector<char>(source) {}
- BitVector(Vector<char>& source):Vector<char>(source) {}
- BitVector(const Vector<char>& source1, const Vector<char> source2):Vector<char>(source1,source2) {}
- //@}
+ BitVector(VectorDataType wData, char* wStart, char* wEnd) : VectorBase<char>(wData, wStart, wEnd) {}
+
+ // The one and only copy-constructor.
+ BitVector(const BitVector&other) : VectorBase<char>() {
+ VECTORDEBUG("BitVector(%p)",(void*)&other);
+ if (other.getData()) {
+ this->clone(other);
+ } else {
+ this->makeAlias(other);
+ }
+ }
- /** Construct from a string of "0" and "1". */
- BitVector(const char* valString);
- //@}
+ // (pat) Removed default value for len and added 'explicit'. Please do not remove 'explicit';
+ // it prevents auto-conversion of int to BitVector in constructors.
+ // Previous code was often ambiguous, especially for L3Frame and descendent constructors, leading to latent bugs.
+ explicit BitVector(size_t len) { this->vInit(len); }
+ BitVector() { this->vInit(0); }
- /** Index a single bit. */
- bool bit(size_t index) const
+ /** Build a BitVector by concatenation. */
+ BitVector(const BitVector& other1, const BitVector& other2) : VectorBase<char>()
{
- // We put this code in .h for fast inlining.
- const char *dp = mStart+index;
- assert(dp<mEnd);
- return (*dp) & 0x01;
+ assert(this->getData() == 0);
+ this->vConcat(other1,other2);
}
+ /** Construct from a string of "0" and "1". */
+ // (pat) Characters that are not '0' or '1' map to '0'.
+ BitVector(const char* valString);
+ //@}
+
/**@name Casts and overrides of Vector operators. */
//@{
+ // (pat) Please DO NOT add a const anywhere in this method. Use cloneSegment instead.
BitVector segment(size_t start, size_t span)
{
- char* wStart = mStart + start;
+ char* wStart = this->begin() + start;
char* wEnd = wStart + span;
- assert(wEnd<=mEnd);
+ assert(wEnd<=this->end());
+#if BITVECTOR_REFCNTS
+ return BitVector(mData,wStart,wEnd);
+#else
return BitVector(NULL,wStart,wEnd);
+#endif
}
- BitVector alias()
- { return segment(0,size()); }
+ // (pat) Historically the BitVector segment method had const and non-const versions with different behavior.
+ // I changed the name of the const version to cloneSegment and replaced all uses throughout OpenBTS.
+ const BitVector cloneSegment(size_t start, size_t span) const
+ {
+ BitVector seg = const_cast<BitVector*>(this)->segment(start,span);
+ // (pat) We are depending on the Return Value Optimization not to invoke the copy-constructor on the result,
+ // which would result in its immediate destruction while we are still using it.
+ BitVector result;
+ result.clone(seg);
+ return result;
+ }
- const BitVector segment(size_t start, size_t span) const
- { return (BitVector)(Vector<char>::segment(start,span)); }
+ BitVector alias() const {
+ return const_cast<BitVector*>(this)->segment(0,size());
+ }
BitVector head(size_t span) { return segment(0,span); }
- const BitVector head(size_t span) const { return segment(0,span); }
BitVector tail(size_t start) { return segment(start,size()-start); }
- const BitVector tail(size_t start) const { return segment(start,size()-start); }
+
+ // (pat) Please do NOT put the const version of head and tail back in, because historically they were messed up.
+ // Use cloneSegment instead.
+ //const BitVector head(size_t span) const { return segment(0,span); }
+ //const BitVector tail(size_t start) const { return segment(start,size()-start); }
//@}
@@ -285,8 +203,6 @@ class BitVector : public Vector<char> {
uint64_t syndrome(Generator& gen) const;
/** Calculate the parity word for the vector with the given Generator. */
uint64_t parity(Generator& gen) const;
- /** Encode the signal with the GSM rate 1/2 convolutional encoder. */
- void encode(const ViterbiR2O4& encoder, BitVector& target);
//@}
@@ -304,9 +220,16 @@ class BitVector : public Vector<char> {
/**@name Serialization and deserialization. */
//@{
uint64_t peekField(size_t readIndex, unsigned length) const;
+ uint64_t peekFieldReversed(size_t readIndex, unsigned length) const;
uint64_t readField(size_t& readIndex, unsigned length) const;
+ uint64_t readFieldReversed(size_t& readIndex, unsigned length) const;
void fillField(size_t writeIndex, uint64_t value, unsigned length);
+ void fillFieldReversed(size_t writeIndex, uint64_t value, unsigned length);
void writeField(size_t& writeIndex, uint64_t value, unsigned length);
+ void writeFieldReversed(size_t& writeIndex, uint64_t value, unsigned length);
+ void write0(size_t& writeIndex) { writeField(writeIndex,0,1); }
+ void write1(size_t& writeIndex) { writeField(writeIndex,1,1); }
+
//@}
/** Sum of bits. */
@@ -320,12 +243,76 @@ class BitVector : public Vector<char> {
/** Pack into a char array. */
void pack(unsigned char*) const;
+ // Same as pack but return a string.
+ std::string packToString() const;
- /** Unopack from a char array. */
+ /** Unpack from a char array. */
void unpack(const unsigned char*);
+ /** Make a hexdump string. */
+ void hex(std::ostream&) const;
+ std::string hexstr() const;
+
+ /** Unpack from a hexdump string.
+ * @returns true on success, false on error. */
+ bool unhex(const char*);
+
+ // For this method, 'other' should have been run through the copy-constructor already
+ // (unless it was newly created, ie foo.dup(L2Frame(...)), in which case we are screwed anyway)
+ // so the call to makeAlias is redundant.
+ // This only works if other is already an alias.
+ void dup(BitVector other) { assert(!this->getData()); makeAlias(other); assert(this->mStart == other.mStart); }
+ void dup(BitVector &other) { makeAlias(other); assert(this->mStart == other.mStart); }
+
+#if 0
+ void operator=(const BitVector& other) {
+ printf("BitVector::operator=\n");
+ assert(0);
+ //this->dup(other);
+ }
+#endif
+
+ bool operator==(const BitVector &other) const;
+
+ /** Copy to dst, not including those indexed in puncture. */
+ void copyPunctured(BitVector &dst, const unsigned *puncture, const size_t plth);
+
+ /** Index a single bit. */
+ // (pat) Cant have too many ways to do this, I guess.
+ bool bit(size_t index) const
+ {
+ // We put this code in .h for fast inlining.
+ const char *dp = this->begin()+index;
+ assert(dp<this->end());
+ return (*dp) & 0x01;
+ }
+
+ char& operator[](size_t index)
+ {
+ assert(this->mStart+index<this->mEnd);
+ return this->mStart[index];
+ }
+
+ const char& operator[](size_t index) const
+ {
+ assert(this->mStart+index<this->mEnd);
+ return this->mStart[index];
+ }
+
+ /** Set a bit */
+ void settfb(size_t index, int value)
+ {
+ char *dp = this->mStart+index;
+ assert(dp<this->mEnd);
+ *dp = value;
+ }
+
+ typedef char* iterator;
+ typedef const char* const_iterator;
};
+// (pat) BitVector2 was an intermediate step in fixing BitVector but is no longer needed.
+#define BitVector2 BitVector
std::ostream& operator<<(std::ostream&, const BitVector&);
@@ -348,7 +335,7 @@ class SoftVector: public Vector<float> {
/** Construct a SoftVector from a C string of "0", "1", and "X". */
SoftVector(const char* valString);
-
+
/** Construct a SoftVector from a BitVector. */
SoftVector(const BitVector& source);
@@ -395,8 +382,11 @@ class SoftVector: public Vector<float> {
const SoftVector tail(size_t start) const { return segment(start,size()-start); }
//@}
- /** Decode soft symbols with the GSM rate-1/2 Viterbi decoder. */
- void decode(ViterbiR2O4 &decoder, BitVector& target) const;
+ // (pat) How good is the SoftVector in the sense of the bits being solid?
+ // Result of 1 is perfect and 0 means all the bits were 0.5
+ // If plow is non-NULL, also return the lowest energy bit.
+ float getEnergy(float *low=0) const;
+ float getSNR() const;
/** Fill with "unknown" values. */
void unknown() { fill(0.5F); }
@@ -412,13 +402,29 @@ class SoftVector: public Vector<float> {
/** Slice the whole signal into bits. */
BitVector sliced() const;
-};
+ /** Copy to dst, adding in 0.5 for those indexed in puncture. */
+ void copyUnPunctured(SoftVector &dst, const unsigned *puncture, const size_t plth);
+ /** Return a soft bit. */
+ float softbit(size_t index) const
+ {
+ const float *dp = mStart+index;
+ assert(dp<mEnd);
+ return *dp;
+ }
+ /** Set a soft bit */
+ void settfb(size_t index, float value)
+ {
+ float *dp = mStart+index;
+ assert(dp<mEnd);
+ *dp = value;
+ }
+};
-std::ostream& operator<<(std::ostream&, const SoftVector&);
+std::ostream& operator<<(std::ostream&, const SoftVector&);
diff --git a/lib/decoding/Vector.h b/lib/decoding/Vector.h
index 88ab654..23b4dd3 100644
--- a/lib/decoding/Vector.h
+++ b/lib/decoding/Vector.h
@@ -1,23 +1,23 @@
/**@file Simplified Vector template with aliases. */
/*
* Copyright 2008 Free Software Foundation, Inc.
+* Copyright 2014 Range Networks, Inc.
*
-* This software is distributed under the terms of the GNU Public License.
+* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
-
- This program 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.
-
- 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 General Public License for more details.
-
- You should have received a copy of the GNU 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.
+ 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/>.
*/
@@ -29,225 +29,367 @@
#include <string.h>
#include <iostream>
#include <assert.h>
+#include <stdio.h>
+// We cant use Logger.h in this file...
+extern int gVectorDebug;
+//#define ENABLE_VECTORDEBUG
+#ifdef ENABLE_VECTORDEBUG
+#define VECTORDEBUG(...) { printf(__VA_ARGS__); printf(" this=%p [%p,%p,%p]\n",(void*)this,(void*)&mData,mStart,mEnd); }
+//#define VECTORDEBUG(msg) { std::cout<<msg<<std::endl; }
+#else
+#define VECTORDEBUG(...)
+#endif
-/**
- A simplified Vector template with aliases.
- Unlike std::vector, this class does not support dynamic resizing.
- Unlike std::vector, this class does support "aliases" and subvectors.
-*/
-template <class T> class Vector {
-
- // TODO -- Replace memcpy calls with for-loops.
-
- public:
-
- /**@name Iterator types. */
- //@{
- typedef T* iterator;
- typedef const T* const_iterator;
- //@}
-
- protected:
-
- T* mData; ///< allocated data block, if any
- T* mStart; ///< start of useful data
- T* mEnd; ///< end of useful data + 1
-
- public:
-
- /** Return the size of the Vector. */
- size_t size() const
- {
- assert(mStart>=mData);
- assert(mEnd>=mStart);
- return mEnd - mStart;
- }
-
- /** Return size in bytes. */
- size_t bytes() const { return size()*sizeof(T); }
-
- /** Change the size of the Vector, discarding content. */
- void resize(size_t newSize)
- {
- if (mData!=NULL) delete[] mData;
- if (newSize==0) mData=NULL;
- else mData = new T[newSize];
- mStart = mData;
- mEnd = mStart + newSize;
- }
-
- /** Release memory and clear pointers. */
- void clear() { resize(0); }
-
-
- /** Copy data from another vector. */
- void clone(const Vector<T>& other)
- {
- resize(other.size());
- memcpy(mData,other.mStart,other.bytes());
- }
-
-
-
-
- //@{
-
- /** Build an empty Vector of a given size. */
- Vector(size_t wSize=0):mData(NULL) { resize(wSize); }
-
- /** Build a Vector by shifting the data block. */
- Vector(Vector<T>& other)
- :mData(other.mData),mStart(other.mStart),mEnd(other.mEnd)
- { other.mData=NULL; }
-
- /** Build a Vector by copying another. */
- Vector(const Vector<T>& other):mData(NULL) { clone(other); }
-
- /** Build a Vector with explicit values. */
- Vector(T* wData, T* wStart, T* wEnd)
- :mData(wData),mStart(wStart),mEnd(wEnd)
- { }
-
- /** Build a vector from an existing block, NOT to be deleted upon destruction. */
- Vector(T* wStart, size_t span)
- :mData(NULL),mStart(wStart),mEnd(wStart+span)
- { }
-
- /** Build a Vector by concatenation. */
- Vector(const Vector<T>& other1, const Vector<T>& other2)
- :mData(NULL)
- {
- resize(other1.size()+other2.size());
- memcpy(mStart, other1.mStart, other1.bytes());
- memcpy(mStart+other1.size(), other2.mStart, other2.bytes());
- }
-
- //@}
-
- /** Destroy a Vector, deleting held memory. */
- ~Vector() { clear(); }
-
-
-
-
- //@{
-
- /** Assign from another Vector, shifting ownership. */
- void operator=(Vector<T>& other)
- {
- clear();
- mData=other.mData;
- mStart=other.mStart;
- mEnd=other.mEnd;
- other.mData=NULL;
- }
-
- /** Assign from another Vector, copying. */
- void operator=(const Vector<T>& other) { clone(other); }
-
- //@}
+#define BITVECTOR_REFCNTS 0
+#if BITVECTOR_REFCNTS
+// (pat) Started to add refcnts, decided against it for now.
+template <class T> class RCData : public RefCntBase {
+ public:
+ T* mPointer;
+};
+#endif
- //@{
-
- /** Return an alias to a segment of this Vector. */
- Vector<T> segment(size_t start, size_t span)
- {
- T* wStart = mStart + start;
- T* wEnd = wStart + span;
- assert(wEnd<=mEnd);
- return Vector<T>(NULL,wStart,wEnd);
- }
-
- /** Return an alias to a segment of this Vector. */
- const Vector<T> segment(size_t start, size_t span) const
- {
- T* wStart = mStart + start;
- T* wEnd = wStart + span;
- assert(wEnd<=mEnd);
- return Vector<T>(NULL,wStart,wEnd);
- }
-
- Vector<T> head(size_t span) { return segment(0,span); }
- const Vector<T> head(size_t span) const { return segment(0,span); }
- Vector<T> tail(size_t start) { return segment(start,size()-start); }
- const Vector<T> tail(size_t start) const { return segment(start,size()-start); }
-
- /**
- Copy part of this Vector to a segment of another Vector.
- @param other The other vector.
- @param start The start point in the other vector.
- @param span The number of elements to copy.
- */
- void copyToSegment(Vector<T>& other, size_t start, size_t span) const
- {
- T* base = other.mStart + start;
- assert(base+span<=other.mEnd);
- assert(mStart+span<=mEnd);
- memcpy(base,mStart,span*sizeof(T));
- }
- /** Copy all of this Vector to a segment of another Vector. */
- void copyToSegment(Vector<T>& other, size_t start=0) const { copyToSegment(other,start,size()); }
-
- void copyTo(Vector<T>& other) const { copyToSegment(other,0,size()); }
-
- /**
- Copy a segment of this vector into another.
- @param other The other vector (to copt into starting at 0.)
- @param start The start point in this vector.
- @param span The number of elements to copy.
- */
- void segmentCopyTo(Vector<T>& other, size_t start, size_t span)
- {
- T* base = mStart + start;
- assert(base+span<=mEnd);
- assert(other.mStart+span<=other.mEnd);
- memcpy(other.mStart,base,span*sizeof(T));
- }
-
- void fill(const T& val)
- {
- T* dp=mStart;
- while (dp<mEnd) *dp++=val;
- }
-
-
- //@}
-
-
- //@{
-
- T& operator[](size_t index)
- {
- assert(mStart+index<mEnd);
- return mStart[index];
- }
-
- const T& operator[](size_t index) const
- {
- assert(mStart+index<mEnd);
- return mStart[index];
- }
-
- const T* begin() const { return mStart; }
- T* begin() { return mStart; }
- const T* end() const { return mEnd; }
- T* end() { return mEnd; }
- //@}
+/**
+ A simplified Vector template with aliases.
+ Unlike std::vector, this class does not support dynamic resizing.
+ Unlike std::vector, this class does support "aliases" and subvectors.
+*/
+// (pat) Nov 2013: Vector and the derived classes BitVector and SoftVector were originally written with behavior
+// that differed for const and non-const cases, making them very difficult to use and resulting in many extremely
+// difficult to find bugs in the code base.
+// Ultimately these classes should all be converted to reference counted methodologies, but as an interim measure
+// I am rationalizing their behavior until we flush out all places in the code base that inadvertently depended
+// on the original behavior. This is done with assert statements in BitVector methods.
+// ====
+// What the behavior was probably supposed to be:
+// Vectors can 'own' the data they point to or not. Only one Vector 'owns' the memory at a time,
+// so that automatic destruction can be used. So whenever there is an operation that yields one
+// vector from another the options were: clone (allocate a new vector from memory), alias (make the
+// new vector point into the memory of the original vector) or shift (the new Vector steals the
+// memory ownership from the original vector.)
+// The const copy-constructor did a clone, the non-const copy constructor did a shiftMem, and the segment and
+// related methods (head, tail, etc) returned aliases.
+// Since a copy-constructor is inserted transparently in sometimes surprising places, this made the
+// class very difficult to use. Moreover, since the C++ standard specifies that a copy-constructor is used
+// to copy the return value from functions, it makes it literally impossible for a function to fully control
+// the return value. Our code has relied on the "Return Value Optimization" which says that the C++ compiler
+// may omit the copy-construction of the return value even if the copy-constructor has side-effects, which ours does.
+// This methodology is fundamentally incompatible with C++.
+// What the original behavior actually was:
+// class Vector:
+// The copy-constructor and assignment operators did a clone for the const case and a shift for the non-const case.
+// This is really horrible.
+// The segment methods were identical for const and non-const cases, always returning an alias.
+// This also resulted in zillions of redundant mallocs and copies throughout the code base.
+// class BitVector:
+// Copy-constructor:
+// BitVector did not have any copy-constructors, and I think the intent was that it would have the same behavior
+// as Vector, but that is not how C++ works: with no copy-constructor the default copy-constructor
+// uses only the const case, so only the const Vector copy-constructor was used. Therefore it always cloned,
+// and the code base relied heavily on the "Return Value Optimization" to work at all.
+// Assignment operator:
+// BitVector did not have one, so C++ makes a default one that calls Vector::operator=() as a side effect,
+// which did a clone; not sure if there was a non-const version and no longer care.
+// segment methods:
+// The non-const segment() returned an alias, and the const segment() returned a clone.
+// I think the intent was that the behavior should be the same as Vector, but there was a conversion
+// of the result of the const segment() method from Vector to BitVector which caused the Vector copy-constructor
+// to be (inadvertently) invoked, resulting in the const version of the segment method returning a clone.
+// What the behavior is now:
+// VectorBase:
+// There is a new VectorBase class that has only the common methods and extremely basic constructors.
+// The VectorBase class MUST NOT CONTAIN: copy constructors, non-trivial constructors called from derived classes,
+// or any method that returns a VectorBase type object. Why? Because any of the above when used in derived classes
+// can cause copy-constructor invocation, often surprisingly, obfuscating the code.
+// Each derived class must provide its own: copy-constructors and segment() and related methods, since we do not
+// want to inadvertently invoke a copy-constructor to convert the segment() result from VectorBase to the derived type.
+// BitVector:
+// The BitVector copy-constructor and assignment operator (inherited from VectorBase) paradigm is:
+// if the copied Vector owned memory, perform a clone so the new vector owns memory also,
+// otherwise just do a simple copy, which is another alias. This isnt perfect but works every place
+// in our code base and easier to use than the previous paradigm.
+// The segment method always returns an alias.
+// If you want a clone of a segment, use cloneSegment(), which replaces the previous: const segment(...) const method.
+// Note that the semantics of cloneSegment still rely on the Return Value Optimization. Oh well, we should use refcnts.
+// Vector:
+// I left Vector alone (except for rearrangement to separate out VectorBase.) Vector should just not be used.
+// SoftVector:
+// SoftVector and signalVector should be updated similar to BitVector, but I did not want to disturb them.
+// What the behavior should be:
+// All these should be reference-counted, similar to ByteVector.
+template <class T> class VectorBase
+{
+ // TODO -- Replace memcpy calls with for-loops. (pat) in case class T is not POD [Plain Old Data]
+ protected:
+#if BITVECTOR_REFCNTS
+ typedef RefCntPointer<RCData<T> > VectorDataType;
+#else
+ typedef T* VectorDataType;
+#endif
+ VectorDataType mData; ///< allocated data block.
+ T* mStart; ///< start of useful data
+ T* mEnd; ///< end of useful data + 1
+
+ // Init vector with specified size. Previous contents are completely discarded. This is only used for initialization.
+ void vInit(size_t elements)
+ {
+ mData = elements ? new T[elements] : NULL;
+ mStart = mData; // This is where mStart get set to zero
+ mEnd = mStart + elements;
+ }
+
+ /** Assign from another Vector, shifting ownership. */
+ // (pat) This should be eliminated, but it is used by Vector and descendents.
+ void shiftMem(VectorBase<T>&other)
+ {
+ VECTORDEBUG("VectorBase::shiftMem(%p)",(void*)&other);
+ this->clear();
+ this->mData=other.mData;
+ this->mStart=other.mStart;
+ this->mEnd=other.mEnd;
+ other.mData=NULL;
+ }
+
+ // Assign from another Vector, making this an alias to other.
+ void makeAlias(const VectorBase<T> &other)
+ {
+ if (this->getData()) {
+ assert(this->getData() != other.getData()); // Not possible by the semantics of Vector.
+ this->clear();
+ }
+ this->mStart=const_cast<T*>(other.mStart);
+ this->mEnd=const_cast<T*>(other.mEnd);
+ }
+
+ public:
+
+ /** Return the size of the Vector in units, ie, the number of T elements. */
+ size_t size() const
+ {
+ assert(mStart>=mData);
+ assert(mEnd>=mStart);
+ return mEnd - mStart;
+ }
+
+ /** Return size in bytes. */
+ size_t bytes() const { return this->size()*sizeof(T); }
+
+ /** Change the size of the Vector in items (not bytes), discarding content. */
+ void resize(size_t newElements) {
+ //VECTORDEBUG("VectorBase::resize("<<(void*)this<<","<<newElements<<")");
+ VECTORDEBUG("VectorBase::resize(%p,%d) %s",this,newElements, (mData?"delete":""));
+ if (mData!=NULL) delete[] mData;
+ vInit(newElements);
+ }
+
+ /** Release memory and clear pointers. */
+ void clear() { this->resize(0); }
+
+
+ /** Copy data from another vector. */
+ void clone(const VectorBase<T>& other) {
+ this->resize(other.size());
+ memcpy(mData,other.mStart,other.bytes());
+ }
+
+ void vConcat(const VectorBase<T>&other1, const VectorBase<T>&other2) {
+ this->resize(other1.size()+other2.size());
+ memcpy(this->mStart, other1.mStart, other1.bytes());
+ memcpy(this->mStart+other1.size(), other2.mStart, other2.bytes());
+ }
+
+ protected:
+
+ VectorBase() : mData(0), mStart(0), mEnd(0) {}
+
+ /** Build a Vector with explicit values. */
+ VectorBase(VectorDataType wData, T* wStart, T* wEnd) :mData(wData),mStart(wStart),mEnd(wEnd) {
+ //VECTORDEBUG("VectorBase("<<(void*)wData);
+ VECTORDEBUG("VectorBase(%p,%p,%p)",this->getData(),wStart,wEnd);
+ }
+
+ public:
+
+ /** Destroy a Vector, deleting held memory. */
+ ~VectorBase() {
+ //VECTORDEBUG("~VectorBase("<<(void*)this<<")");
+ VECTORDEBUG("~VectorBase(%p)",this);
+ this->clear();
+ }
+
+ bool isOwner() { return !!this->mData; } // Do we own any memory ourselves?
+
+ std::string inspect() const {
+ char buf[100];
+ snprintf(buf,100," mData=%p mStart=%p mEnd=%p ",(void*)mData,mStart,mEnd);
+ return std::string(buf);
+ }
+
+
+ /**
+ Copy part of this Vector to a segment of another Vector.
+ @param other The other vector.
+ @param start The start point in the other vector.
+ @param span The number of elements to copy.
+ */
+ void copyToSegment(VectorBase<T>& other, size_t start, size_t span) const
+ {
+ T* base = other.mStart + start;
+ assert(base+span<=other.mEnd);
+ assert(mStart+span<=mEnd);
+ memcpy(base,mStart,span*sizeof(T));
+ }
+
+ /** Copy all of this Vector to a segment of another Vector. */
+ void copyToSegment(VectorBase<T>& other, size_t start=0) const { copyToSegment(other,start,size()); }
+
+ void copyTo(VectorBase<T>& other) const { copyToSegment(other,0,size()); }
+
+ /**
+ Copy a segment of this vector into another.
+ @param other The other vector (to copt into starting at 0.)
+ @param start The start point in this vector.
+ @param span The number of elements to copy.
+ WARNING: This function does NOT resize the result - you must set the result size before entering.
+ */
+ void segmentCopyTo(VectorBase<T>& other, size_t start, size_t span) const
+ {
+ const T* base = mStart + start;
+ assert(base+span<=mEnd);
+ assert(other.mStart+span<=other.mEnd);
+ memcpy(other.mStart,base,span*sizeof(T));
+ }
+
+ void fill(const T& val)
+ {
+ T* dp=mStart;
+ while (dp<mEnd) *dp++=val;
+ }
+
+ void fill(const T& val, unsigned start, unsigned length)
+ {
+ T* dp=mStart+start;
+ T* end=dp+length;
+ assert(end<=mEnd);
+ while (dp<end) *dp++=val;
+ }
+
+ /** Assign from another Vector. */
+ // (pat) This is used for both const and non-const cases.
+ // If the original vector owned memory, clone it, otherwise just copy the segment data.
+ void operator=(const VectorBase<T>& other) {
+ //std::cout << "Vector=(this="<<this->inspect()<<",other="<<other.inspect()<<")"<<endl;
+ if (other.getData()) {
+ this->clone(other);
+ } else {
+ this->makeAlias(other);
+ }
+ //std::cout << "Vector= after(this="<<this->inspect()<<")"<<endl;
+ }
+
+
+ T& operator[](size_t index)
+ {
+ assert(mStart+index<mEnd);
+ return mStart[index];
+ }
+
+ const T& operator[](size_t index) const
+ {
+ assert(mStart+index<mEnd);
+ return mStart[index];
+ }
+
+ const T* begin() const { return this->mStart; }
+ T* begin() { return this->mStart; }
+ const T* end() const { return this->mEnd; }
+ T* end() { return this->mEnd; }
+#if BITVECTOR_REFCNTS
+ const T*getData() const { return this->mData.isNULL() ? 0 : this->mData->mPointer; }
+#else
+ const T*getData() const { return this->mData; }
+#endif
+};
+// (pat) Nov 2013. This class retains the original poor behavior. See comments at VectorBase
+template <class T> class Vector : public VectorBase<T>
+{
+ public:
+
+ /** Build an empty Vector of a given size. */
+ Vector(size_t wSize=0) { this->resize(wSize); }
+
+ /** Build a Vector by shifting the data block. */
+ Vector(Vector<T>& other) : VectorBase<T>(other.mData,other.mStart,other.mEnd) { other.mData=NULL; }
+
+ /** Build a Vector by copying another. */
+ Vector(const Vector<T>& other):VectorBase<T>() { this->clone(other); }
+
+ /** Build a Vector with explicit values. */
+ Vector(T* wData, T* wStart, T* wEnd) : VectorBase<T>(wData,wStart,wEnd) { }
+
+ /** Build a vector from an existing block, NOT to be deleted upon destruction. */
+ Vector(T* wStart, size_t span) : VectorBase<T>(NULL,wStart,wStart+span) { }
+
+ /** Build a Vector by concatenation. */
+ Vector(const Vector<T>& other1, const Vector<T>& other2):VectorBase<T>() {
+ assert(this->mData == 0);
+ this->vConcat(other1,other2);
+ }
+
+ //@{
+
+ /** Assign from another Vector, shifting ownership. */
+ void operator=(Vector<T>& other) { this->shiftMem(other); }
+
+ /** Assign from another Vector, copying. */
+ void operator=(const Vector<T>& other) { this->clone(other); }
+
+ /** Return an alias to a segment of this Vector. */
+ Vector<T> segment(size_t start, size_t span)
+ {
+ T* wStart = this->mStart + start;
+ T* wEnd = wStart + span;
+ assert(wEnd<=this->mEnd);
+ return Vector<T>(NULL,wStart,wEnd);
+ }
+
+ /** Return an alias to a segment of this Vector. */
+ const Vector<T> segment(size_t start, size_t span) const
+ {
+ T* wStart = this->mStart + start;
+ T* wEnd = wStart + span;
+ assert(wEnd<=this->mEnd);
+ return Vector<T>(NULL,wStart,wEnd);
+ }
+
+ Vector<T> head(size_t span) { return segment(0,span); }
+ const Vector<T> head(size_t span) const { return segment(0,span); }
+ Vector<T> tail(size_t start) { return segment(start,this->size()-start); }
+ const Vector<T> tail(size_t start) const { return segment(start,this->size()-start); }
+
+ /**@name Iterator types. */
+ //@{
+ typedef T* iterator;
+ typedef const T* const_iterator;
+ //@}
+
+ //@}
};
+
/** Basic print operator for Vector objects. */
template <class T>
std::ostream& operator<<(std::ostream& os, const Vector<T>& v)
{
- for (unsigned i=0; i<v.size(); i++) os << v[i] << " ";
- return os;
+ for (unsigned i=0; i<v.size(); i++) os << v[i] << " ";
+ return os;
}
diff --git a/lib/decoding/VocoderFrame.h b/lib/decoding/VocoderFrame.h
index 0c80973..28d57c3 100644
--- a/lib/decoding/VocoderFrame.h
+++ b/lib/decoding/VocoderFrame.h
@@ -1,7 +1,7 @@
#ifndef _VOCODERFRAME_H
#define _VOCODERFRAME_H
-#include "BitVector.h"
+#include "BitVector.h"
//#include "GSMCommon.h"
class VocoderFrame : public BitVector {
@@ -18,7 +18,7 @@ class VocoderFrame : public BitVector {
{ unpack(src); }
BitVector payload() { return tail(4); }
- const BitVector payload() const { return tail(4); }
+// const BitVector payload() const { return tail(4); }
};
@@ -36,7 +36,7 @@ class VocoderAMRFrame : public BitVector {
{ unpack(src); }
BitVector payload() { return tail(8); }
- const BitVector payload() const { return tail(8); }
+// const BitVector payload() const { return tail(8); }
};
diff --git a/lib/decoding/tch_f_decoder_impl.cc b/lib/decoding/tch_f_decoder_impl.cc
index 1680caa..283e0f0 100644
--- a/lib/decoding/tch_f_decoder_impl.cc
+++ b/lib/decoding/tch_f_decoder_impl.cc
@@ -133,7 +133,8 @@ namespace gr {
BitVector mDP(mU.head(224));
Parity mBlockCoder(0x10004820009ULL, 40, 224);
- mC.decode(mVCoder, mU);
+// mC.decode(mVCoder, mU);
+ mVCoder.decode(mC, mU);
mP.invert();
unsigned syndrome = mBlockCoder.syndrome(mDP);
@@ -165,7 +166,8 @@ namespace gr {
}
}
- mClass1_c.decode(mVCoder, mTCHU);
+ mVCoder.decode(mClass1_c, mTCHU);
+// mClass1_c.decode(mVCoder, mTCHU);
mClass2_c.sliced().copyToSegment(mTCHD, 182);
// 3.1.2.1
diff --git a/lib/decoding/tch_f_decoder_impl.h b/lib/decoding/tch_f_decoder_impl.h
index dfa1ac3..bb55afb 100644
--- a/lib/decoding/tch_f_decoder_impl.h
+++ b/lib/decoding/tch_f_decoder_impl.h
@@ -27,6 +27,7 @@
#include "GSM610Tables.h"
#include "GSM660Tables.h"
#include "GSM690Tables.h"
+#include "ViterbiR204.h"
#include <grgsm/decoding/tch_f_decoder.h>