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