diff options
Diffstat (limited to 'lib/decoding/openbts/BitVector.cpp')
-rw-r--r-- | lib/decoding/openbts/BitVector.cpp | 525 |
1 files changed, 525 insertions, 0 deletions
diff --git a/lib/decoding/openbts/BitVector.cpp b/lib/decoding/openbts/BitVector.cpp new file mode 100644 index 0000000..00730f6 --- /dev/null +++ b/lib/decoding/openbts/BitVector.cpp @@ -0,0 +1,525 @@ +/* + * Copyright 2008, 2009, 2014 Free Software Foundation, Inc. + * Copyright 2014 Range Networks, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * This use of this software may be subject to additional restrictions. + * See the LEGAL file in the main directory for details. + */ + +#include "BitVector.h" +#include <iostream> +#include <stdio.h> +#include <sstream> +#include <string.h> +//#include <Logger.h> + +using namespace std; + + + +BitVector::BitVector(const char *valString) +{ + // 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; + + for (unsigned i=0; i<length; i++) { + accum = (accum<<1) | ((*dp++) & 0x01); + } + return accum; +} + + + + +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); + readIndex += length; + return retVal; +} + + +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) +{ + 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) +{ + 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; + } +} + + +void BitVector::invert() +{ + for (size_t i=0; i<size(); i++) { + mStart[i] = ~mStart[i]; + } +} + + + + +void BitVector::reverse8() +{ + assert(size()>=8); + + char tmp0 = mStart[0]; + mStart[0] = mStart[7]; + mStart[7] = tmp0; + + char tmp1 = mStart[1]; + mStart[1] = mStart[6]; + mStart[6] = tmp1; + + char tmp2 = mStart[2]; + mStart[2] = mStart[5]; + mStart[5] = tmp2; + + char tmp3 = mStart[3]; + mStart[3] = mStart[4]; + mStart[4] = tmp3; +} + + + +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(); +} + + + +uint64_t BitVector::syndrome(Generator& gen) const +{ + gen.clear(); + const char *dp = mStart; + while (dp<mEnd) gen.syndromeShift(*dp++); + return gen.state(); +} + + +uint64_t BitVector::parity(Generator& gen) const +{ + gen.clear(); + const char *dp = mStart; + while (dp<mEnd) gen.encoderShift(*dp++); + return gen.state(); +} + + +unsigned BitVector::sum() const +{ + unsigned sum = 0; + for (size_t i=0; i<size(); i++) sum += mStart[i] & 0x01; + return sum; +} + + + + +void BitVector::map(const unsigned *map, size_t mapSize, BitVector& dest) const +{ + for (unsigned i=0; i<mapSize; i++) { + dest.mStart[i] = mStart[map[i]]; + } +} + + + + +void BitVector::unmap(const unsigned *map, size_t mapSize, BitVector& dest) const +{ + for (unsigned i=0; i<mapSize; i++) { + dest.mStart[map[i]] = mStart[i]; + } +} + + + + + + + +ostream& operator<<(ostream& os, const BitVector& hv) +{ + for (size_t i=0; i<hv.size(); i++) { + if (hv.bit(i)) os << '1'; + else os << '0'; + } + return os; +} + + + + +uint64_t Parity::syndrome(const BitVector& receivedCodeword) +{ + return receivedCodeword.syndrome(*this); +} + + +void Parity::writeParityWord(const BitVector& data, BitVector& parityTarget, bool invert) +{ + uint64_t pWord = data.parity(*this); + if (invert) pWord = ~pWord; + parityTarget.fillField(0,pWord,size()); +} + + + + + + + + + +SoftVector::SoftVector(const BitVector& source) +{ + resize(source.size()); + for (size_t i=0; i<size(); i++) { + if (source.bit(i)) mStart[i]=1.0F; + else mStart[i]=0.0F; + } +} + + +BitVector SoftVector::sliced() const +{ + size_t sz = size(); + BitVector newSig(sz); + for (size_t i=0; i<sz; i++) { + if (mStart[i]>0.5F) newSig[i]=1; + else newSig[i] = 0; + } + return newSig; +} + + + +// (pat) Added 6-22-2012 +float SoftVector::getEnergy(float *plow) const +{ + 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; + } + 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++) { + if (sv[i]<0.25) os << "0"; + else if (sv[i]>0.75) os << "1"; + else os << "-"; + } + return os; +} + + + +void BitVector::pack(unsigned char* targ) const +{ + // Assumes MSB-first packing. + unsigned bytes = size()/8; + for (unsigned i=0; i<bytes; i++) { + targ[i] = peekField(i*8,8); + } + unsigned whole = bytes*8; + unsigned rem = size() - whole; + if (rem==0) return; + targ[bytes] = peekField(whole,rem) << (8-rem); +} + +void BitVector::pack2(unsigned char* targ) const +{ + unsigned int i; + unsigned char curbyte = 0; + + for (i = 0; i < size(); i++) + { + uint8_t bitnum = 7 - (i % 8); + curbyte |= ((char)bit(i) << bitnum); + if(i % 8 == 7){ + *targ++ = curbyte; + curbyte = 0; + } + } + + // Assumes MSB-first packing. +// unsigned bytes = size()/8; +// for (unsigned i=0; i<bytes; i++) { +// targ[i] = peekField(i*8,8); +// } +// unsigned whole = bytes*8; +// unsigned rem = size() - whole; +// if (rem==0) return; +// 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) +{ + // Assumes MSB-first packing. + unsigned bytes = size()/8; + for (unsigned i=0; i<bytes; i++) { + fillField(i*8,src[i],8); + } + unsigned whole = bytes*8; + unsigned rem = size() - whole; + if (rem==0) return; + 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 |