diff options
author | Roman Khassraf <roman@khassraf.at> | 2015-06-02 08:49:12 +0200 |
---|---|---|
committer | Roman Khassraf <roman@khassraf.at> | 2015-06-02 08:49:12 +0200 |
commit | d71e658ecb283b962079c67dd60d6c0230d1f58b (patch) | |
tree | e5c45fada1af9d22de6bbfdab82724058f86dfc8 /lib/decoding | |
parent | b85c0626d99ad9acbc997a06bf9b705e692e5e49 (diff) |
Updated BitVector to recent source
Diffstat (limited to 'lib/decoding')
-rw-r--r-- | lib/decoding/BitVector.cpp | 520 | ||||
-rw-r--r-- | lib/decoding/BitVector.h | 336 | ||||
-rw-r--r-- | lib/decoding/Vector.h | 580 | ||||
-rw-r--r-- | lib/decoding/VocoderFrame.h | 6 | ||||
-rw-r--r-- | lib/decoding/tch_f_decoder_impl.cc | 6 | ||||
-rw-r--r-- | lib/decoding/tch_f_decoder_impl.h | 1 |
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> |