blob: 29a46e8c3303e45941159c3b68ad4edfe359eeea [file] [log] [blame]
Roman Khassrafaa8fa992015-06-02 09:20:03 +02001/*
Piotr Krysikb9a87a12017-08-23 15:59:28 +02002 * Copyright 2008, 2009, 2014 Free Software Foundation, Inc.
3 * Copyright 2014 Range Networks, Inc.
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Affero General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * This use of this software may be subject to additional restrictions.
19 * See the LEGAL file in the main directory for details.
20 */
Roman Khassrafaa8fa992015-06-02 09:20:03 +020021
22
23
24
25#include "BitVector.h"
26#include "ViterbiR204.h"
27#include <iostream>
28#include <stdio.h>
29#include <sstream>
30#include <string.h>
Piotr Krysik79233072018-02-27 08:34:03 +010031#include <cstdlib>
Roman Khassrafaa8fa992015-06-02 09:20:03 +020032
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 ViterbiBase::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
51unsigned ViterbiBase::applyPoly(uint64_t val, uint64_t poly)
52{
53 uint64_t prod = val & poly;
54 prod = (prod ^ (prod >> 32));
55 prod = (prod ^ (prod >> 16));
56 prod = (prod ^ (prod >> 8));
57 prod = (prod ^ (prod >> 4));
58 prod = (prod ^ (prod >> 2));
59 prod = (prod ^ (prod >> 1));
60 return prod & 0x01;
61}
62
63
64
65//void BitVector::encode(const ViterbiR2O4& coder, BitVector& target)
66void ViterbiR2O4::encode(const BitVector& in, BitVector& target) const
67{
68 const ViterbiR2O4& coder = *this;
69 size_t sz = in.size();
70
71 assert(sz*coder.iRate() == target.size());
72
73 // Build a "history" array where each element contains the full history.
Piotr Krysik79233072018-02-27 08:34:03 +010074 uint32_t * history = (uint32_t *) malloc(sizeof(uint32_t)*sz);
Roman Khassrafaa8fa992015-06-02 09:20:03 +020075 uint32_t accum = 0;
76 for (size_t i=0; i<sz; i++) {
77 accum = (accum<<1) | in.bit(i);
78 history[i] = accum;
79 }
80
81 // Look up histories in the pre-generated state table.
82 char *op = target.begin();
83 for (size_t i=0; i<sz; i++) {
84 unsigned index = coder.cMask() & history[i];
85 for (unsigned g=0; g<coder.iRate(); g++) {
86 *op++ = coder.stateTable(g,index);
87 }
88 }
Piotr Krysik79233072018-02-27 08:34:03 +010089 free(history);
Roman Khassrafaa8fa992015-06-02 09:20:03 +020090}
91
92
93ViterbiR2O4::ViterbiR2O4()
94{
95 assert(mDeferral < 32);
96 // (pat) The generator polynomials are: G0 = 1 + D**3 + D**4; and G1 = 1 + D + D**3 + D**4
97 mCoeffs[0] = 0x019; // G0 = D**4 + D**3 + 1; represented as binary 11001,
98 mCoeffs[1] = 0x01b; // G1 = + D**4 + D**3 + D + 1; represented as binary 11011
99 computeStateTables(0);
100 computeStateTables(1);
101 computeGeneratorTable();
102}
103
104
105void ViterbiR2O4::initializeStates()
106{
107 for (unsigned i=0; i<mIStates; i++) vitClear(mSurvivors[i]);
108 for (unsigned i=0; i<mNumCands; i++) vitClear(mCandidates[i]);
109}
110
111
112
113// (pat) The state machine has 16 states.
114// Each state has two possible next states corresponding to 0 or 1 inputs to original encoder.
115// which are saved in mStateTable in consecutive locations.
116// In other words the mStateTable second index is ((current_state <<1) + encoder_bit)
117// g is 0 or 1 for the first or second bit of the encoded stream, ie, the one we are decoding.
118void ViterbiR2O4::computeStateTables(unsigned g)
119{
120 assert(g<mIRate);
121 for (unsigned state=0; state<mIStates; state++) {
122 // 0 input
123 uint32_t inputVal = state<<1;
124 mStateTable[g][inputVal] = applyPoly(inputVal, mCoeffs[g], mOrder+1);
125 // 1 input
126 inputVal |= 1;
127 mStateTable[g][inputVal] = applyPoly(inputVal, mCoeffs[g], mOrder+1);
128 }
129}
130
131void ViterbiR2O4::computeGeneratorTable()
132{
133 for (unsigned index=0; index<mIStates*2; index++) {
134 mGeneratorTable[index] = (mStateTable[0][index]<<1) | mStateTable[1][index];
135 }
136}
137
138
139void ViterbiR2O4::branchCandidates()
140{
141 // Branch to generate new input states.
142 const vCand *sp = mSurvivors;
143 for (unsigned i=0; i<mNumCands; i+=2) {
144 // extend and suffix
145 const uint32_t iState0 = (sp->iState) << 1; // input state for 0
146 const uint32_t iState1 = iState0 | 0x01; // input state for 1
147 const uint32_t oStateShifted = (sp->oState) << mIRate; // shifted output (by 2)
148 const float cost = sp->cost;
149 int bec = sp->bitErrorCnt;
150 sp++;
151 // 0 input extension
152 mCandidates[i].cost = cost;
153 // mCMask is the low 5 bits, ie, full width of mGeneratorTable.
154 mCandidates[i].oState = oStateShifted | mGeneratorTable[iState0 & mCMask];
155 mCandidates[i].iState = iState0;
156 mCandidates[i].bitErrorCnt = bec;
157 // 1 input extension
158 mCandidates[i+1].cost = cost;
159 mCandidates[i+1].oState = oStateShifted | mGeneratorTable[iState1 & mCMask];
160 mCandidates[i+1].iState = iState1;
161 mCandidates[i+1].bitErrorCnt = bec;
162 }
163}
164
165
166void ViterbiR2O4::getSoftCostMetrics(const uint32_t inSample, const float *matchCost, const float *mismatchCost)
167{
168 const float *cTab[2] = {matchCost,mismatchCost};
169 for (unsigned i=0; i<mNumCands; i++) {
170 vCand& thisCand = mCandidates[i];
171 // We examine input bits 2 at a time for a rate 1/2 coder.
172 // (pat) mismatched will end up with bits in it for previous transitions,
173 // but we only use the bottom two bits of mismatched so it is ok.
174 const unsigned mismatched = inSample ^ (thisCand.oState);
175 // (pat) TODO: Are these two tests swapped?
176 thisCand.cost += cTab[mismatched&0x01][1] + cTab[(mismatched>>1)&0x01][0];
177 if (mismatched & 1) { thisCand.bitErrorCnt++; }
178 if (mismatched & 2) { thisCand.bitErrorCnt++; }
179 }
180}
181
182
183void ViterbiR2O4::pruneCandidates()
184{
185 const vCand* c1 = mCandidates; // 0-prefix
186 const vCand* c2 = mCandidates + mIStates; // 1-prefix
187 for (unsigned i=0; i<mIStates; i++) {
188 if (c1[i].cost < c2[i].cost) mSurvivors[i] = c1[i];
189 else mSurvivors[i] = c2[i];
190 }
191}
192
193
194const ViterbiR2O4::vCand& ViterbiR2O4::minCost() const
195{
196 int minIndex = 0;
197 float minCost = mSurvivors[0].cost;
198 for (unsigned i=1; i<mIStates; i++) {
199 const float thisCost = mSurvivors[i].cost;
200 if (thisCost>=minCost) continue;
201 minCost = thisCost;
202 minIndex=i;
203 }
204 return mSurvivors[minIndex];
205}
206
207
208const ViterbiR2O4::vCand* ViterbiR2O4::vstep(uint32_t inSample, const float *probs, const float *iprobs, bool isNotTailBits)
209{
210 branchCandidates();
211 // (pat) tail bits do not affect cost or error bit count of any branch.
212 if (isNotTailBits) getSoftCostMetrics(inSample,probs,iprobs);
213 pruneCandidates();
214 return &minCost();
215}
216
217
218void ViterbiR2O4::decode(const SoftVector &in, BitVector& target)
219{
220 ViterbiR2O4& decoder = *this;
221 const size_t sz = in.size();
222 const unsigned oSize = in.size() / decoder.iRate();
223 const unsigned deferral = decoder.deferral();
224 const size_t ctsz = sz + deferral*decoder.iRate();
225 assert(sz <= decoder.iRate()*target.size());
226
227 // Build a "history" array where each element contains the full history.
228 // (pat) We only use every other history element, so why are we setting them?
Piotr Krysik79233072018-02-27 08:34:03 +0100229 uint32_t * history = (uint32_t *)malloc(sizeof(uint32_t)*ctsz);
Roman Khassrafaa8fa992015-06-02 09:20:03 +0200230 {
231 BitVector bits = in.sliced();
232 uint32_t accum = 0;
233 for (size_t i=0; i<sz; i++) {
234 accum = (accum<<1) | bits.bit(i);
235 history[i] = accum;
236 }
237 // Repeat last bit at the end.
238 // (pat) TODO: really? Does this matter?
239 for (size_t i=sz; i<ctsz; i++) {
240 accum = (accum<<1) | (accum & 0x01);
241 history[i] = accum;
242 }
243 }
244
245 // Precompute metric tables.
Piotr Krysik79233072018-02-27 08:34:03 +0100246 float * matchCostTable = (float *)malloc(sizeof(float)*ctsz);
247 float * mismatchCostTable = (float *)malloc(sizeof(float)*ctsz);
Roman Khassrafaa8fa992015-06-02 09:20:03 +0200248 {
249 const float *dp = in.begin();
250 for (size_t i=0; i<sz; i++) {
251 // pVal is the probability that a bit is correct.
252 // ipVal is the probability that a bit is incorrect.
253 float pVal = dp[i];
254 if (pVal>0.5F) pVal = 1.0F-pVal;
255 float ipVal = 1.0F-pVal;
256 // This is a cheap approximation to an ideal cost function.
257 if (pVal<0.01F) pVal = 0.01;
258 if (ipVal<0.01F) ipVal = 0.01;
259 matchCostTable[i] = 0.25F/ipVal;
260 mismatchCostTable[i] = 0.25F/pVal;
261 }
262
263 // pad end of table with unknowns
264 // Note that these bits should not contribute to Bit Error Count.
265 for (size_t i=sz; i<ctsz; i++) {
266 matchCostTable[i] = 0.5F;
267 mismatchCostTable[i] = 0.5F;
268 }
269 }
270
271 {
272 decoder.initializeStates();
273 // Each sample of history[] carries its history.
274 // So we only have to process every iRate-th sample.
275 const unsigned step = decoder.iRate();
276 // input pointer
277 const uint32_t *ip = history + step - 1;
278 // output pointers
279 char *op = target.begin();
280 const char *const opt = target.end(); // (pat) Not right if target is larger than needed; should be: op + sz/2;
281 // table pointers
282 const float* match = matchCostTable;
283 const float* mismatch = mismatchCostTable;
284 size_t oCount = 0;
285 const ViterbiR2O4::vCand *minCost = NULL;
286 while (op<opt) {
287 // Viterbi algorithm
Vasil Velichkov924d1872018-03-27 21:08:00 +0300288 assert(match - matchCostTable < ctsz - 1);
289 assert(mismatch - mismatchCostTable < ctsz - 1);
Roman Khassrafaa8fa992015-06-02 09:20:03 +0200290 minCost = decoder.vstep(*ip, match, mismatch, oCount < oSize);
291 ip += step;
292 match += step;
293 mismatch += step;
294 // output
295 if (oCount>=deferral) *op++ = (minCost->iState >> deferral)&0x01;
296 oCount++;
297 }
298 // Dont think minCost == NULL can happen.
299 mBitErrorCnt = minCost ? minCost->bitErrorCnt : 0;
300 }
Piotr Krysik79233072018-02-27 08:34:03 +0100301 free(history);
302 free(matchCostTable);
303 free(mismatchCostTable);
Roman Khassrafaa8fa992015-06-02 09:20:03 +0200304}
305
306// vim: ts=4 sw=4