void ViterbiTCH_AFS4_75::encode(const BitVector& in, BitVector& target) const { assert(in.size() == 101); assert(target.size() == 535); const char *u = in.begin(); char *C = target.begin(); const unsigned H = 6; BitVector r(107+H); for (int k = -H; k <= -1; k++) r[k+H] = 0; for (unsigned k = 0; k <= 100; k++) { r[k+H] = u[k] ^ r[k-1+H] ^ r[k-2+H] ^ r[k-3+H] ^ r[k-4+H] ^ r[k-6+H]; C[5*k] = r[k+H] ^ r[k-2+H] ^ r[k-3+H] ^ r[k-5+H] ^ r[k-6+H]; C[5*k+1] = r[k+H] ^ r[k-2+H] ^ r[k-3+H] ^ r[k-5+H] ^ r[k-6+H]; C[5*k+2] = r[k+H] ^ r[k-1+H] ^ r[k-4+H] ^ r[k-6+H]; C[5*k+3] = u[k]; C[5*k+4] = u[k]; } // termination for (unsigned k = 101; k <= 106; k++) { r[k+H] = 0; C[5*k] = r[k+H] ^ r[k-2+H] ^ r[k-3+H] ^ r[k-5+H] ^ r[k-6+H]; C[5*k+1] = r[k+H] ^ r[k-2+H] ^ r[k-3+H] ^ r[k-5+H] ^ r[k-6+H]; C[5*k+2] = r[k+H] ^ r[k-1+H] ^ r[k-4+H] ^ r[k-6+H]; C[5*k+3] = r[k+H] ^ r[k-2+H] ^ r[k-3+H] ^ r[k-4+H] ^ r[k-6+H]; C[5*k+4] = r[k-1+H] ^ r[k-2+H] ^ r[k-3+H] ^ r[k-4+H] ^ r[k-6+H]; } }
void ViterbiTCH_AFS5_9::encode(const BitVector& in, BitVector& target) const { assert(in.size() == 124); assert(target.size() == 520); const char *u = in.begin(); char *C = target.begin(); const unsigned H = 6; BitVector r(130+H); for (int k = -H; k <= -1; k++) r[k+H] = 0; for (unsigned k = 0; k <= 123; k++) { r[k+H] = u[k] ^ r[k-1+H] ^ r[k-2+H] ^ r[k-3+H] ^ r[k-4+H] ^ r[k-6+H]; C[4*k] = r[k+H] ^ r[k-2+H] ^ r[k-3+H] ^ r[k-5+H] ^ r[k-6+H]; C[4*k+1] = r[k+H] ^ r[k-1+H] ^ r[k-4+H] ^ r[k-6+H]; C[4*k+2] = u[k]; C[4*k+3] = u[k]; } // termination for (unsigned k = 124; k <= 129; k++) { r[k+H] = 0; C[4*k] = r[k+H] ^ r[k-2+H] ^ r[k-3+H] ^ r[k-5+H] ^ r[k-6+H]; C[4*k+1] = r[k+H] ^ r[k-1+H] ^ r[k-4+H] ^ r[k-6+H]; C[4*k+2] = r[k-1+H] ^ r[k-2+H] ^ r[k-3+H] ^ r[k-4+H] ^ r[k-6+H]; C[4*k+3] = r[k-1+H] ^ r[k-2+H] ^ r[k-3+H] ^ r[k-4+H] ^ r[k-6+H]; } }
int testIterator (size_t n, size_t k) { commentator.start ("Testing BitSubvector::word_iterator", __FUNCTION__); bool pass = true; std::ostream &error = commentator.report (Commentator::LEVEL_IMPORTANT, INTERNAL_ERROR); BitVector<Endianness> v (n); BitVector<Endianness>::word_iterator w; unsigned int flip = 0; for (w = v.word_begin (); w != v.word_end (); ++w, flip = 1 - flip) *w = pattern[flip]; v.back_word () = pattern[flip]; size_t offset; for (offset = 0; offset <= n - k; ++offset) { BitSubvector<BitVector<Endianness>::iterator> vp (v.begin () + offset, v.begin () + (offset + k)); BitSubvector<BitVector<Endianness>::iterator>::word_iterator i; BitSubvector<BitVector<Endianness>::iterator>::const_word_iterator j1, j2; flip = ((offset / WordTraits<BitVector<Endianness>::word_type>::bits) % 2 == 0) ? 0 : 1; for (i = vp.word_begin (), j1 = vp.word_begin (), j2 = vp.word_begin (); i != vp.word_end (); ++i, ++j1, ++j2, flip = 1 - flip) { if (*j1 != *i) { error << "ERROR: error at offset " << offset << " (n = " << n << ", k = " << k << ")" << std::endl; error << "ERROR: word_iterator and const_word_iterator don't agree" << std::endl; error << "ERROR: word_iterator: " << std::hex << *i << std::endl; error << "ERROR: const_word_iterator: " << std::hex << *j1 << std::endl; pass = false; goto end_test; } BitVector<Endianness>::word_type val = *j1; *i ^= val; if (*j2 != 0) { error << "ERROR: error at offset " << offset << " (n = " << n << ", k = " << k << ")" << std::endl; error << "ERROR: Pattern should be 0 after clearing" << std::endl; error << "ERROR: Detected " << std::hex << *j2 << std::endl; pass = false; goto end_test; } *i ^= val; } } end_test: commentator.stop (MSG_STATUS (pass)); return pass; }
TEST(BoolManager, GetVector) { BoolManager bm; BitVector bv = bm.getBitVector("a", 2); ASSERT_EQ(bv.size(), 2); EXPECT_EQ(bv.begin()->toString(), "a[0]"); EXPECT_EQ((bv.begin() + 1)->toString(), "a[1]"); }
bool testWordLength (size_t n, size_t k) { commentator.start ("Testing word-length", __FUNCTION__); bool pass = true; std::ostream &error = commentator.report (Commentator::LEVEL_IMPORTANT, INTERNAL_ERROR); BitVector<Endianness> v (n); BitVector<Endianness>::word_iterator w; unsigned int flip = 0; for (w = v.word_begin (); w != v.word_end (); ++w, flip = 1 - flip) *w = pattern[flip]; size_t offset; size_t correct_len = k / WordTraits<BitVector<Endianness>::word_type>::bits; if (k % WordTraits<BitVector<Endianness>::word_type>::bits != 0) ++correct_len; --correct_len; // New semantics for (offset = 0; offset <= n - k; ++offset) { BitSubvector<BitVector<Endianness>::iterator> vp (v.begin () + offset, v.begin () + (offset + k)); BitSubvector<BitVector<Endianness>::iterator>::word_iterator i; BitSubvector<BitVector<Endianness>::iterator>::const_word_iterator j; size_t len; for (i = vp.word_begin (), len = 0; i != vp.word_end (); ++i, ++len); if (len != correct_len) { error << "ERROR: error at offset " << offset << std::endl; error << "ERROR: length for word_iterator should be " << correct_len << std::endl; error << "ERROR: but computed " << len << std::endl; pass = false; } for (j = vp.word_begin (), len = 0; j != vp.word_end (); ++j, ++len); if (len != correct_len) { error << "ERROR: error at offset " << offset << std::endl; error << "ERROR: length for const_word_iterator should be " << correct_len << std::endl; error << "ERROR: but computed " << len << std::endl; pass = false; } } commentator.stop (MSG_STATUS (pass)); return pass; }
bool testConstIterator (size_t n, size_t k) { commentator.start ("Testing BitSubvector::const_word_iterator", __FUNCTION__); bool pass = true; std::ostream &error = commentator.report (Commentator::LEVEL_IMPORTANT, INTERNAL_ERROR); BitVector<Endianness> v (n); BitVector<Endianness>::word_iterator w; unsigned int flip = 0; for (w = v.word_begin (); w != v.word_end (); ++w, flip = 1 - flip) *w = pattern[flip]; v.back_word () = pattern[flip]; size_t offset; for (offset = 0; offset <= n - k; ++offset) { BitSubvector<BitVector<Endianness>::const_iterator> vp (v.begin () + offset, v.begin () + (offset + k)); BitSubvector<BitVector<Endianness>::const_iterator>::const_word_iterator i; flip = ((offset / WordTraits<BitVector<Endianness>::word_type>::bits) % 2 == 0) ? 0 : 1; size_t idx = 0; for (i = vp.word_begin (); i != vp.word_end (); ++i, flip = 1 - flip, idx += WordTraits<BitVector<Endianness>::word_type>::bits) { BitVector<Endianness>::word_type check = connect (pattern[flip], pattern[1-flip], offset % WordTraits<BitVector<Endianness>::word_type>::bits); if (idx + WordTraits<BitVector<Endianness>::word_type>::bits > k) check &= Endianness::mask_left (k % WordTraits<BitVector<Endianness>::word_type>::bits); if (*i != check) { error << "ERROR: error at offset " << offset << std::endl; error << "ERROR: Pattern should be " << std::hex << check << std::endl; error << "ERROR: Detected " << std::hex << *i << std::endl; pass = false; goto end_test; } } } end_test: commentator.stop (MSG_STATUS (pass)); return pass; }
void rateMatchFunc(BitVector &in,BitVector &out, int eini) { int nin = in.size(); int nout = out.size(); if (nout == nin) { in.copyTo(out); return; } int eplus = 2 * nin; // eplus = a * Ni,j int eminus = 2 * (nout - nin); // eminus = a * abs(deltaNi,j) if (eminus < 0) { eminus = - eminus; } float e = eini; int m; // index of current bit, except zero-based as opposed to spec that is 1 based. char *inp = in.begin(); // cheating just a bit for efficiency. char *outp = out.begin(); char *outend = out.end(); if (nout < nin) { // Puncture bits as necessary. // Note from spec: loop termination Xi == Xij == number of bits before rate matching == nin. for (m=0; m < nin && outp < outend; m++) { e = e - eminus; if (e <= 0) { e = e + eplus; continue; // skip the bit. } *outp++ = inp[m]; } } else { // Repeat bits as necessary. for (m=0; m < nin && outp < outend; m++) { e = e - eminus; while (e <= 0) { if (outp >= outend) goto failed; *outp++ = inp[m]; // repeat the bit. e = e + eplus; } *outp++ = inp[m]; } } if (m != nin || outp != outend) { failed: LOG(ERR) << "rate matching mis-calculation, results:" <<LOGVAR(nin)<<LOGVAR(m)<<LOGVAR(nout)<<LOGVAR2(outp,outp-out.begin()) <<LOGVAR(e)<<LOGVAR(eplus)<<LOGVAR(eminus)<<LOGVAR(eini); } }
int testBackWord () { commentator.start ("Testing back_word", __FUNCTION__); bool pass = true; std::ostream &error = commentator.report (Commentator::LEVEL_IMPORTANT, INTERNAL_ERROR); static const int n = 3 * WordTraits<BitVector<Endianness>::word_type>::bits; static const int k = 16; BitVector<Endianness> v (n); BitVector<Endianness>::word_iterator w; size_t offset; unsigned int flip = 0; for (offset = 0; offset < WordTraits<BitVector<Endianness>::word_type>::bits; ++offset, flip = 1 - flip) { BitSubvector<BitVector<Endianness>::iterator> vp1 (v.begin () + offset, v.begin () + (offset + k)); BitSubvector<BitVector<Endianness>::const_iterator> vp2 (v.begin () + offset, v.begin () + (offset + WordTraits<BitVector<Endianness>::word_type>::bits)); vp1.back_word () = pattern[flip]; BitVector<Endianness>::word_type check = pattern[flip] & Endianness::mask_left (k); if (vp1.back_word () != check) { error << "ERROR: error at offset " << std::dec << offset << " (rereading back_word)" << std::endl; error << "ERROR: Pattern should be " << std::hex << check << std::endl; error << "ERROR: Detected " << std::hex << vp1.back_word () << std::endl; pass = false; } if (vp2.front_word () != check) { error << "ERROR: error at offset " << std::dec << offset << " (checking against a const subvector)" << std::endl; error << "ERROR: Pattern should be " << std::hex << check << std::endl; error << "ERROR: Detected " << std::hex << vp2.front_word () << std::endl; pass = false; } } commentator.stop (MSG_STATUS (pass)); return pass; }
//void BitVector::encode(const ViterbiTCH_AFS12_2& coder, BitVector& target) const void ViterbiTCH_AFS12_2::encode(const BitVector& in, BitVector& target) const { assert(in.size() == 250); assert(target.size() == 508); const char *u = in.begin(); char *C = target.begin(); const unsigned H = 4; BitVector r(254+H); for (int k = -H; k <= -1; k++) r[k+H] = 0; for (unsigned k = 0; k <= 249; k++) { r[k+H] = u[k] ^ r[k-3+H] ^ r[k-4+H]; C[2*k] = u[k]; C[2*k+1] = r[k+H] ^ r[k-1+H] ^ r[k-3+H] ^ r[k-4+H]; } // termination for (unsigned k = 250; k <= 253; k++) { r[k+H] = 0; C[2*k] = r[k-3+H] ^ r[k-4+H]; C[2*k+1] = r[k+H] ^ r[k-1+H] ^ r[k-3+H] ^ r[k-4+H]; } }
//void BitVector::encode(const ViterbiTCH_AFS7_95& coder, BitVector& target) void ViterbiTCH_AFS7_95::encode(const BitVector& in, BitVector& target) const { assert(in.size() == 165); assert(target.size() == 513); const char *u = in.begin(); char *C = target.begin(); const unsigned H = 6; BitVector r(171+H); for (int k = -H; k <= -1; k++) r[k+H] = 0; for (unsigned k = 0; k <= 164; k++) { r[k+H] = u[k] ^ r[k-2+H] ^ r[k-3+H] ^ r[k-5+H] ^ r[k-6+H]; C[3*k] = u[k]; C[3*k+1] = r[k+H] ^ r[k-1+H] ^ r[k-4+H] ^ r[k-6+H]; C[3*k+2] = r[k+H] ^ r[k-1+H] ^ r[k-2+H] ^ r[k-3+H] ^ r[k-4+H] ^ r[k-6+H]; } // termination for (unsigned k = 165; k <= 170; k++) { r[k+H] = 0; C[3*k] = r[k-2+H] ^ r[k-3+H] ^ r[k-5+H] ^ r[k-6+H]; C[3*k+1] = r[k+H] ^ r[k-1+H] ^ r[k-4+H] ^ r[k-6+H]; C[3*k+2] = r[k+H] ^ r[k-1+H] ^ r[k-2+H] ^ r[k-3+H] ^ r[k-4+H] ^ r[k-6+H]; } }
void ViterbiTCH_AFS7_4::encode(const BitVector& in, BitVector& target) const { assert(in.size() == 154); assert(target.size() == 474); const char *u = in.begin(); char *C = target.begin(); const unsigned H = 4; BitVector r(158+H); for (int k = -H; k <= -1; k++) r[k+H] = 0; for (unsigned k = 0; k <= 153; k++) { r[k+H] = u[k] ^ r[k-1+H] ^ r[k-2+H] ^ r[k-3+H] ^ r[k-4+H]; C[3*k] = r[k+H] ^ r[k-1+H] ^ r[k-3+H] ^ r[k-4+H]; C[3*k+1] = r[k+H] ^ r[k-2+H] ^ r[k-4+H]; C[3*k+2] = u[k]; } // termination for (unsigned k = 154; k <= 157; k++) { r[k+H] = 0; C[3*k] = r[k+H] ^ r[k-1+H] ^ r[k-3+H] ^ r[k-4+H]; C[3*k+1] = r[k+H] ^ r[k-2+H] ^ r[k-4+H]; C[3*k+2] = r[k-1+H] ^ r[k-2+H] ^ r[k-3+H] ^ r[k-4+H]; } }
void ViterbiTCH_AFS7_4::decode(const SoftVector &in, BitVector& target) { ViterbiTCH_AFS7_4 &decoder = *this; const size_t sz = in.size() - 12; const unsigned deferral = decoder.deferral(); const size_t ctsz = sz + deferral*decoder.iRate(); assert(sz == decoder.iRate()*target.size()); // Build a "history" array where each element contains the full history. uint32_t history[ctsz]; { BitVector bits = in.sliced(); uint32_t accum = 0; for (size_t i=0; i<sz; i++) { accum = (accum<<1) | bits.bit(i); history[i] = accum; } // Repeat last bit at the end. for (size_t i=sz; i<ctsz; i++) { accum = (accum<<1) | (accum & 0x01); history[i] = accum; } } // Precompute metric tables. float matchCostTable[ctsz]; float mismatchCostTable[ctsz]; { const float *dp = in.begin(); for (size_t i=0; i<sz; i++) { // pVal is the probability that a bit is correct. // ipVal is the probability that a bit is incorrect. float pVal = dp[i]; if (pVal>0.5F) pVal = 1.0F-pVal; float ipVal = 1.0F-pVal; // This is a cheap approximation to an ideal cost function. if (pVal<0.01F) pVal = 0.01; if (ipVal<0.01F) ipVal = 0.01; matchCostTable[i] = 0.25F/ipVal; mismatchCostTable[i] = 0.25F/pVal; } // pad end of table with unknowns for (size_t i=sz; i<ctsz; i++) { matchCostTable[i] = 0.5F; mismatchCostTable[i] = 0.5F; } } { decoder.initializeStates(); // Each sample of history[] carries its history. // So we only have to process every iRate-th sample. const unsigned step = decoder.iRate(); // input pointer const uint32_t *ip = history + step - 1; // output pointers char *op = target.begin(); const char *const opt = target.end(); // table pointers const float* match = matchCostTable; const float* mismatch = mismatchCostTable; size_t oCount = 0; while (op<opt) { // Viterbi algorithm assert(match-matchCostTable<(int)(sizeof(matchCostTable)/sizeof(matchCostTable[0])-1)); assert(mismatch-mismatchCostTable<(int)(sizeof(mismatchCostTable)/sizeof(mismatchCostTable[0])-1)); const ViterbiTCH_AFS7_4::vCand &minCost = decoder.step(*ip, match, mismatch); ip += step; match += step; mismatch += step; // output if (oCount>=deferral) *op++ = (minCost.iState >> deferral)&0x01; oCount++; } } }