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