blob: 74878341bf0ecb3823b65b9dfea567208fb1c011 [file] [log] [blame]
dburgess82c46ff2011-10-07 02:40:51 +00001/*
2* Copyright 2008, 2009 Free Software Foundation, Inc.
3*
4*
5* This software is distributed under the terms of the GNU Affero Public License.
6* See the COPYING file in the main directory for details.
7*
8* This use of this software may be subject to additional restrictions.
9* See the LEGAL file in the main directory for details.
10
11 This program is free software: you can redistribute it and/or modify
12 it under the terms of the GNU Affero General Public License as published by
13 the Free Software Foundation, either version 3 of the License, or
14 (at your option) any later version.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU Affero General Public License for more details.
20
21 You should have received a copy of the GNU Affero General Public License
22 along with this program. If not, see <http://www.gnu.org/licenses/>.
23
24*/
25
26
27
28
29#include "BitVector.h"
30#include <iostream>
31#include <stdio.h>
kurtis.heimerl5a872472013-05-31 21:47:25 +000032#include <sstream>
dburgess82c46ff2011-10-07 02:40:51 +000033
34using namespace std;
35
36
37/**
38 Apply a Galois polymonial to a binary seqeunce.
39 @param val The input sequence.
40 @param poly The polynomial.
41 @param order The order of the polynomial.
42 @return Single-bit result.
43*/
44unsigned applyPoly(uint64_t val, uint64_t poly, unsigned order)
45{
46 uint64_t prod = val & poly;
47 unsigned sum = prod;
48 for (unsigned i=1; i<order; i++) sum ^= prod>>i;
49 return sum & 0x01;
50}
51
52
53
54
55
56
57BitVector::BitVector(const char *valString)
58 :Vector<char>(strlen(valString))
59{
60 uint32_t accum = 0;
61 for (size_t i=0; i<size(); i++) {
62 accum <<= 1;
63 if (valString[i]=='1') accum |= 0x01;
64 mStart[i] = accum;
65 }
66}
67
68
69
70
71
72uint64_t BitVector::peekField(size_t readIndex, unsigned length) const
73{
74 uint64_t accum = 0;
75 char *dp = mStart + readIndex;
76 assert(dp+length <= mEnd);
77 for (unsigned i=0; i<length; i++) {
78 accum = (accum<<1) | ((*dp++) & 0x01);
79 }
80 return accum;
81}
82
83
84
85
86uint64_t BitVector::peekFieldReversed(size_t readIndex, unsigned length) const
87{
88 uint64_t accum = 0;
89 char *dp = mStart + readIndex + length - 1;
90 assert(dp<mEnd);
91 for (int i=(length-1); i>=0; i--) {
92 accum = (accum<<1) | ((*dp--) & 0x01);
93 }
94 return accum;
95}
96
97
98
99
100uint64_t BitVector::readField(size_t& readIndex, unsigned length) const
101{
102 const uint64_t retVal = peekField(readIndex,length);
103 readIndex += length;
104 return retVal;
105}
106
107
108uint64_t BitVector::readFieldReversed(size_t& readIndex, unsigned length) const
109{
110 const uint64_t retVal = peekFieldReversed(readIndex,length);
111 readIndex += length;
112 return retVal;
113}
114
115
116
117
118
119void BitVector::fillField(size_t writeIndex, uint64_t value, unsigned length)
120{
121 char *dpBase = mStart + writeIndex;
122 char *dp = dpBase + length - 1;
123 assert(dp < mEnd);
124 while (dp>=dpBase) {
125 *dp-- = value & 0x01;
126 value >>= 1;
127 }
128}
129
130
131void BitVector::fillFieldReversed(size_t writeIndex, uint64_t value, unsigned length)
132{
133 char *dp = mStart + writeIndex;
134 char *dpEnd = dp + length - 1;
135 assert(dpEnd < mEnd);
136 while (dp<=dpEnd) {
137 *dp++ = value & 0x01;
138 value >>= 1;
139 }
140}
141
142
143
144
145void BitVector::writeField(size_t& writeIndex, uint64_t value, unsigned length)
146{
147 fillField(writeIndex,value,length);
148 writeIndex += length;
149}
150
151
152void BitVector::writeFieldReversed(size_t& writeIndex, uint64_t value, unsigned length)
153{
154 fillFieldReversed(writeIndex,value,length);
155 writeIndex += length;
156}
157
158
159void BitVector::invert()
160{
161 for (size_t i=0; i<size(); i++) {
162 mStart[i] = ~mStart[i];
163 }
164}
165
166
167
168
169void BitVector::reverse8()
170{
171 assert(size()>=8);
172
173 char tmp0 = mStart[0];
174 mStart[0] = mStart[7];
175 mStart[7] = tmp0;
176
177 char tmp1 = mStart[1];
178 mStart[1] = mStart[6];
179 mStart[6] = tmp1;
180
181 char tmp2 = mStart[2];
182 mStart[2] = mStart[5];
183 mStart[5] = tmp2;
184
185 char tmp3 = mStart[3];
186 mStart[3] = mStart[4];
187 mStart[4] = tmp3;
188}
189
190
191
192void BitVector::LSB8MSB()
193{
194 if (size()<8) return;
195 size_t size8 = 8*(size()/8);
196 size_t iTop = size8 - 8;
197 for (size_t i=0; i<=iTop; i+=8) segment(i,8).reverse8();
198}
199
200
201
202uint64_t BitVector::syndrome(Generator& gen) const
203{
204 gen.clear();
205 const char *dp = mStart;
206 while (dp<mEnd) gen.syndromeShift(*dp++);
207 return gen.state();
208}
209
210
211uint64_t BitVector::parity(Generator& gen) const
212{
213 gen.clear();
214 const char *dp = mStart;
215 while (dp<mEnd) gen.encoderShift(*dp++);
216 return gen.state();
217}
218
219
220void BitVector::encode(const ViterbiR2O4& coder, BitVector& target)
221{
222 size_t sz = size();
223 assert(sz*coder.iRate() == target.size());
224
225 // Build a "history" array where each element contains the full history.
226 uint32_t history[sz];
227 uint32_t accum = 0;
228 for (size_t i=0; i<sz; i++) {
229 accum = (accum<<1) | bit(i);
230 history[i] = accum;
231 }
232
233 // Look up histories in the pre-generated state table.
234 char *op = target.begin();
235 for (size_t i=0; i<sz; i++) {
236 unsigned index = coder.cMask() & history[i];
237 for (unsigned g=0; g<coder.iRate(); g++) {
238 *op++ = coder.stateTable(g,index);
239 }
240 }
241}
242
243
244
245unsigned BitVector::sum() const
246{
247 unsigned sum = 0;
248 for (size_t i=0; i<size(); i++) sum += mStart[i] & 0x01;
249 return sum;
250}
251
252
253
254
255void BitVector::map(const unsigned *map, size_t mapSize, BitVector& dest) const
256{
257 for (unsigned i=0; i<mapSize; i++) {
258 dest.mStart[i] = mStart[map[i]];
259 }
260}
261
262
263
264
265void BitVector::unmap(const unsigned *map, size_t mapSize, BitVector& dest) const
266{
267 for (unsigned i=0; i<mapSize; i++) {
268 dest.mStart[map[i]] = mStart[i];
269 }
270}
271
272
273
274
275
276
277
dburgess82c46ff2011-10-07 02:40:51 +0000278ostream& operator<<(ostream& os, const BitVector& hv)
279{
280 for (size_t i=0; i<hv.size(); i++) {
281 if (hv.bit(i)) os << '1';
282 else os << '0';
283 }
284 return os;
285}
286
287
288
289
290ViterbiR2O4::ViterbiR2O4()
291{
292 assert(mDeferral < 32);
293 mCoeffs[0] = 0x019;
294 mCoeffs[1] = 0x01b;
295 computeStateTables(0);
296 computeStateTables(1);
297 computeGeneratorTable();
298}
299
300
301
302
303void ViterbiR2O4::initializeStates()
304{
305 for (unsigned i=0; i<mIStates; i++) clear(mSurvivors[i]);
306 for (unsigned i=0; i<mNumCands; i++) clear(mCandidates[i]);
307}
308
309
310
311void ViterbiR2O4::computeStateTables(unsigned g)
312{
313 assert(g<mIRate);
314 for (unsigned state=0; state<mIStates; state++) {
315 // 0 input
316 uint32_t inputVal = state<<1;
317 mStateTable[g][inputVal] = applyPoly(inputVal, mCoeffs[g], mOrder+1);
318 // 1 input
319 inputVal |= 1;
320 mStateTable[g][inputVal] = applyPoly(inputVal, mCoeffs[g], mOrder+1);
321 }
322}
323
324void ViterbiR2O4::computeGeneratorTable()
325{
326 for (unsigned index=0; index<mIStates*2; index++) {
327 mGeneratorTable[index] = (mStateTable[0][index]<<1) | mStateTable[1][index];
328 }
329}
330
331
332
333
334
335
336void ViterbiR2O4::branchCandidates()
337{
338 // Branch to generate new input states.
339 const vCand *sp = mSurvivors;
340 for (unsigned i=0; i<mNumCands; i+=2) {
341 // extend and suffix
342 const uint32_t iState0 = (sp->iState) << 1; // input state for 0
343 const uint32_t iState1 = iState0 | 0x01; // input state for 1
344 const uint32_t oStateShifted = (sp->oState) << mIRate; // shifted output
345 const float cost = sp->cost;
346 sp++;
347 // 0 input extension
348 mCandidates[i].cost = cost;
349 mCandidates[i].oState = oStateShifted | mGeneratorTable[iState0 & mCMask];
350 mCandidates[i].iState = iState0;
351 // 1 input extension
352 mCandidates[i+1].cost = cost;
353 mCandidates[i+1].oState = oStateShifted | mGeneratorTable[iState1 & mCMask];
354 mCandidates[i+1].iState = iState1;
355 }
356}
357
358
359void ViterbiR2O4::getSoftCostMetrics(const uint32_t inSample, const float *matchCost, const float *mismatchCost)
360{
361 const float *cTab[2] = {matchCost,mismatchCost};
362 for (unsigned i=0; i<mNumCands; i++) {
363 vCand& thisCand = mCandidates[i];
364 // We examine input bits 2 at a time for a rate 1/2 coder.
365 const unsigned mismatched = inSample ^ (thisCand.oState);
366 thisCand.cost += cTab[mismatched&0x01][1] + cTab[(mismatched>>1)&0x01][0];
367 }
368}
369
370
371void ViterbiR2O4::pruneCandidates()
372{
373 const vCand* c1 = mCandidates; // 0-prefix
374 const vCand* c2 = mCandidates + mIStates; // 1-prefix
375 for (unsigned i=0; i<mIStates; i++) {
376 if (c1[i].cost < c2[i].cost) mSurvivors[i] = c1[i];
377 else mSurvivors[i] = c2[i];
378 }
379}
380
381
382const ViterbiR2O4::vCand& ViterbiR2O4::minCost() const
383{
384 int minIndex = 0;
385 float minCost = mSurvivors[0].cost;
386 for (unsigned i=1; i<mIStates; i++) {
387 const float thisCost = mSurvivors[i].cost;
388 if (thisCost>=minCost) continue;
389 minCost = thisCost;
390 minIndex=i;
391 }
392 return mSurvivors[minIndex];
393}
394
395
396const ViterbiR2O4::vCand& ViterbiR2O4::step(uint32_t inSample, const float *probs, const float *iprobs)
397{
398 branchCandidates();
399 getSoftCostMetrics(inSample,probs,iprobs);
400 pruneCandidates();
401 return minCost();
402}
403
404
405uint64_t Parity::syndrome(const BitVector& receivedCodeword)
406{
407 return receivedCodeword.syndrome(*this);
408}
409
410
411void Parity::writeParityWord(const BitVector& data, BitVector& parityTarget, bool invert)
412{
413 uint64_t pWord = data.parity(*this);
414 if (invert) pWord = ~pWord;
415 parityTarget.fillField(0,pWord,size());
416}
417
418
419
420
421
422
423
424
425
426SoftVector::SoftVector(const BitVector& source)
427{
428 resize(source.size());
429 for (size_t i=0; i<size(); i++) {
430 if (source.bit(i)) mStart[i]=1.0F;
431 else mStart[i]=0.0F;
432 }
433}
434
435
436BitVector SoftVector::sliced() const
437{
438 size_t sz = size();
439 BitVector newSig(sz);
440 for (size_t i=0; i<sz; i++) {
441 if (mStart[i]>0.5F) newSig[i]=1;
442 else newSig[i] = 0;
443 }
444 return newSig;
445}
446
447
448
449void SoftVector::decode(ViterbiR2O4 &decoder, BitVector& target) const
450{
451 const size_t sz = size();
452 const unsigned deferral = decoder.deferral();
453 const size_t ctsz = sz + deferral*decoder.iRate();
454 assert(sz <= decoder.iRate()*target.size());
455
456 // Build a "history" array where each element contains the full history.
457 uint32_t history[ctsz];
458 {
459 BitVector bits = sliced();
460 uint32_t accum = 0;
461 for (size_t i=0; i<sz; i++) {
462 accum = (accum<<1) | bits.bit(i);
463 history[i] = accum;
464 }
465 // Repeat last bit at the end.
466 for (size_t i=sz; i<ctsz; i++) {
467 accum = (accum<<1) | (accum & 0x01);
468 history[i] = accum;
469 }
470 }
471
472 // Precompute metric tables.
473 float matchCostTable[ctsz];
474 float mismatchCostTable[ctsz];
475 {
476 const float *dp = mStart;
477 for (size_t i=0; i<sz; i++) {
478 // pVal is the probability that a bit is correct.
479 // ipVal is the probability that a bit is incorrect.
480 float pVal = dp[i];
481 if (pVal>0.5F) pVal = 1.0F-pVal;
482 float ipVal = 1.0F-pVal;
483 // This is a cheap approximation to an ideal cost function.
484 if (pVal<0.01F) pVal = 0.01;
485 if (ipVal<0.01F) ipVal = 0.01;
486 matchCostTable[i] = 0.25F/ipVal;
487 mismatchCostTable[i] = 0.25F/pVal;
488 }
489
490 // pad end of table with unknowns
491 for (size_t i=sz; i<ctsz; i++) {
492 matchCostTable[i] = 0.5F;
493 mismatchCostTable[i] = 0.5F;
494 }
495 }
496
497 {
498 decoder.initializeStates();
499 // Each sample of history[] carries its history.
500 // So we only have to process every iRate-th sample.
501 const unsigned step = decoder.iRate();
502 // input pointer
503 const uint32_t *ip = history + step - 1;
504 // output pointers
505 char *op = target.begin();
506 const char *const opt = target.end();
507 // table pointers
508 const float* match = matchCostTable;
509 const float* mismatch = mismatchCostTable;
510 size_t oCount = 0;
511 while (op<opt) {
512 // Viterbi algorithm
513 assert(match-matchCostTable<sizeof(matchCostTable)/sizeof(matchCostTable[0])-1);
514 assert(mismatch-mismatchCostTable<sizeof(mismatchCostTable)/sizeof(mismatchCostTable[0])-1);
515 const ViterbiR2O4::vCand &minCost = decoder.step(*ip, match, mismatch);
516 ip += step;
517 match += step;
518 mismatch += step;
519 // output
520 if (oCount>=deferral) *op++ = (minCost.iState >> deferral)&0x01;
521 oCount++;
522 }
523 }
524}
525
526
527
kurtis.heimerl5a872472013-05-31 21:47:25 +0000528// (pat) Added 6-22-2012
529float SoftVector::getEnergy(float *plow) const
530{
531 const SoftVector &vec = *this;
532 int len = vec.size();
533 float avg = 0; float low = 1;
534 for (int i = 0; i < len; i++) {
535 float bit = vec[i];
536 float energy = 2*((bit < 0.5) ? (0.5-bit) : (bit-0.5));
537 if (energy < low) low = energy;
538 avg += energy/len;
539 }
540 if (plow) { *plow = low; }
541 return avg;
542}
543
dburgess82c46ff2011-10-07 02:40:51 +0000544
545ostream& operator<<(ostream& os, const SoftVector& sv)
546{
547 for (size_t i=0; i<sv.size(); i++) {
548 if (sv[i]<0.25) os << "0";
549 else if (sv[i]>0.75) os << "1";
550 else os << "-";
551 }
552 return os;
553}
554
555
556
557void BitVector::pack(unsigned char* targ) const
558{
559 // Assumes MSB-first packing.
560 unsigned bytes = size()/8;
561 for (unsigned i=0; i<bytes; i++) {
562 targ[i] = peekField(i*8,8);
563 }
564 unsigned whole = bytes*8;
565 unsigned rem = size() - whole;
566 if (rem==0) return;
567 targ[bytes] = peekField(whole,rem) << (8-rem);
568}
569
570
571void BitVector::unpack(const unsigned char* src)
572{
573 // Assumes MSB-first packing.
574 unsigned bytes = size()/8;
575 for (unsigned i=0; i<bytes; i++) {
576 fillField(i*8,src[i],8);
577 }
578 unsigned whole = bytes*8;
579 unsigned rem = size() - whole;
580 if (rem==0) return;
kurtis.heimerl7645fca2012-03-08 07:13:15 +0000581 fillField(whole,src[bytes] >> (8-rem),rem);
dburgess82c46ff2011-10-07 02:40:51 +0000582}
583
584void BitVector::hex(ostream& os) const
585{
586 os << std::hex;
587 unsigned digits = size()/4;
588 size_t wp=0;
589 for (unsigned i=0; i<digits; i++) {
590 os << readField(wp,4);
591 }
592 os << std::dec;
593}
594
kurtis.heimerl5a872472013-05-31 21:47:25 +0000595std::string BitVector::hexstr() const
596{
597 std::ostringstream ss;
598 hex(ss);
599 return ss.str();
600}
601
602
dburgess82c46ff2011-10-07 02:40:51 +0000603bool BitVector::unhex(const char* src)
604{
605 // Assumes MSB-first packing.
606 unsigned int val;
607 unsigned digits = size()/4;
608 for (unsigned i=0; i<digits; i++) {
609 if (sscanf(src+i, "%1x", &val) < 1) {
610 return false;
611 }
612 fillField(i*4,val,4);
613 }
614 unsigned whole = digits*4;
615 unsigned rem = size() - whole;
616 if (rem>0) {
617 if (sscanf(src+digits, "%1x", &val) < 1) {
618 return false;
619 }
620 fillField(whole,val,rem);
621 }
622 return true;
623}
624
625// vim: ts=4 sw=4