IT++ Logo
siso_rsc.cpp
Go to the documentation of this file.
1
29#include <itpp/comm/siso.h>
30#include <itpp/base/itcompat.h>
31#include <limits>
32#ifndef INFINITY
33#define INFINITY std::numeric_limits<double>::infinity()
34#endif
35
36namespace itpp
37{
38void SISO::gen_rsctrellis(void)
39//generates 1/2 RSC trellis structure for binary symbols
40//the states are numbered from 0
41{
42 int mem_len = gen.cols()-1;
43 register int n,k,j;
44 itpp::bin feedback,out;
45 int buffer;
46
47 rsctrellis.numStates = (1<<mem_len);
48 rsctrellis.prevStates = new int[2*rsctrellis.numStates];
49 rsctrellis.nextStates = new int[2*rsctrellis.numStates];
50 rsctrellis.PARout = new double[2*rsctrellis.numStates];
51 rsctrellis.fm = new itpp::bin[rsctrellis.numStates];
52
53 itpp::bvec cases(mem_len);
54 for (n=0; n<2; n++)
55 {
56#pragma omp parallel for private(k, j, cases, feedback, out, buffer)
57 for (k=0; k<rsctrellis.numStates; k++)
58 {
59 cases = itpp::dec2bin(mem_len, k);
60 //feedback
61 feedback = (itpp::bin)n;
62 for (j=1; j<(mem_len+1); j++)
63 {
64 feedback ^= (gen(0,j)*cases[j-1]);
65 }
66 //out
67 out = feedback*gen(1,0);
68 for (j=1; j<(mem_len+1); j++)
69 {
70 out ^= (gen(1,j)*cases[j-1]);
71 }
72 rsctrellis.PARout[k+n*rsctrellis.numStates] = (out?1.0:0.0);//parity bit
73 rsctrellis.fm[k] = itpp::bin(n)^out;
74 //shift
75 for (j=mem_len-1; j>0; j--)
76 {
77 cases[j] = cases[j-1];
78 }
79 cases[0] = feedback;
80 //next and previous state
81 buffer = itpp::bin2dec(cases, true);
82 rsctrellis.nextStates[k+n*rsctrellis.numStates] = buffer;//next state
83 rsctrellis.prevStates[buffer+n*rsctrellis.numStates] = k;//previous state
84 }
85 }
86}
87
88void SISO::rsc_logMAP(itpp::vec &extrinsic_coded, itpp::vec &extrinsic_data,
89 const itpp::vec &intrinsic_coded, const itpp::vec &apriori_data)
90/*
91 logMAP (SISO) decoder for RSC of rate 1/2
92 extrinsic_coded - extrinsic information of coded bits
93 extrinsic_data - extrinsic information of data (informational) bits
94 intrinsic_coded - intrinsic information of coded (systematic and parity) bits
95 apriori_data - a priori information of data (informational) bits
96 Reference: Steven S. Pietrobon and Adrian S. Barbulescu, "A simplification of
97 the modified Bahl decoding algorithm for systematic convolutional codes", Proc. ISITA, 1994
98 */
99{
100 //get parameters
101 int N = apriori_data.length();
102 //other parameters
103 register int n,k;
104 double buffer;
105 int index;
106 double A_min, A_max;
107 double sum0, sum1;
108
109 //trellis generation
110 gen_rsctrellis();
111
112 //parameter initialization
113 double* Lc1I = new double[N];
114 double* Lc2I = new double[N];
115#pragma omp parallel for private(n)
116 for (n=0; n<N; n++)
117 {
118 Lc1I[n] = intrinsic_coded[2*n];
119 Lc2I[n] = intrinsic_coded[2*n+1];
120 }
121 double* A0 = new double[rsctrellis.numStates*N];
122 double* A1 = new double[rsctrellis.numStates*N];
123 double* A_mid = new double[N];
124 double* B0 = new double[rsctrellis.numStates*N];
125 double* B1 = new double[rsctrellis.numStates*N];
126 buffer = (tail?-INFINITY:0);//log(buffer)
127#pragma omp parallel for private(n,k)
128 for (n=0; n<N; n++)
129 {
130 for (k=0; k<rsctrellis.numStates; k++)
131 {
132 A0[k+n*rsctrellis.numStates] = -INFINITY;
133 A1[k+n*rsctrellis.numStates] = -INFINITY;
134 B0[k+n*rsctrellis.numStates] = buffer;
135 B1[k+n*rsctrellis.numStates] = buffer;
136 }
137 A_mid[n] = 0;
138 }
139
140 //A
141 A0[0] = Lc2I[0]*rsctrellis.PARout[0];//i=0
142 A1[0] = Lc1I[0]+apriori_data[0]+Lc2I[0]*rsctrellis.PARout[rsctrellis.numStates];//i=1
143 for (n=1; n<N; n++)
144 {
145 A_min = INFINITY;
146 A_max = 0;
147 for (k=0; k<rsctrellis.numStates; k++)
148 {
149 buffer = itpp::log_add(A0[rsctrellis.prevStates[k]+(n-1)*rsctrellis.numStates],
150 A1[rsctrellis.prevStates[k+rsctrellis.numStates]+(n-1)*rsctrellis.numStates]);//log(alpha0+alpha1)
151 A0[k+rsctrellis.numStates*n] = Lc2I[n]*rsctrellis.PARout[k]+buffer;
152 A1[k+rsctrellis.numStates*n] = Lc1I[n]+apriori_data[n]+
153 Lc2I[n]*rsctrellis.PARout[k+rsctrellis.numStates]+buffer;
154 //find min A(:,n)
155 A_min = std::min(A_min, A0[k+rsctrellis.numStates*n]);
156 //find max A(:,n)
157 A_max = std::max(A_max, A0[k+rsctrellis.numStates*n]);
158 }
159 //normalization
160 A_mid[n] = (A_min+A_max)/2;
161 if (std::isinf(A_mid[n]))
162 {
163 continue;
164 }
165 for (k=0; k<rsctrellis.numStates; k++)
166 {
167 A0[k+rsctrellis.numStates*n] -= A_mid[n];
168 A1[k+rsctrellis.numStates*n] -= A_mid[n];
169 }
170 }
171
172 //B
173 B0[rsctrellis.prevStates[0]+(N-1)*rsctrellis.numStates] = 0;
174 B1[rsctrellis.prevStates[rsctrellis.numStates]+(N-1)*rsctrellis.numStates] = 0;
175 for (n=N-2; n>=0; n--)
176 {
177 for (k=0; k<rsctrellis.numStates; k++)
178 {
179 index = rsctrellis.nextStates[k];
180 B0[k+rsctrellis.numStates*n] = itpp::log_add(B0[index+(n+1)*rsctrellis.numStates]+
181 Lc2I[n+1]*rsctrellis.PARout[index],
182 B1[index+(n+1)*rsctrellis.numStates]+
183 Lc1I[n+1]+apriori_data[n+1]+Lc2I[n+1]*rsctrellis.PARout[index+rsctrellis.numStates]);
184 index = rsctrellis.nextStates[k+rsctrellis.numStates];
185 B1[k+rsctrellis.numStates*n] = itpp::log_add(B0[index+(n+1)*rsctrellis.numStates]+
186 Lc2I[n+1]*rsctrellis.PARout[index],
187 B1[index+(n+1)*rsctrellis.numStates]+
188 Lc1I[n+1]+apriori_data[n+1]+Lc2I[n+1]*rsctrellis.PARout[index+rsctrellis.numStates]);
189
190 }
191 if (std::isinf(A_mid[n+1]))
192 {
193 continue;
194 }
195 for (k=0; k<rsctrellis.numStates; k++)
196 {
197 B0[k+rsctrellis.numStates*n] -= A_mid[n+1];
198 B1[k+rsctrellis.numStates*n] -= A_mid[n+1];
199 }
200 }
201
202 //updated LLR for information bits
203 extrinsic_data.set_size(N);
204 extrinsic_coded.set_size(2*N);
205#pragma omp parallel for private(n, k, sum0, sum1)
206 for (n=0; n<N; n++)
207 {
208 sum0 = 0;
209 sum1 = 0;
210 for (k=0; k<rsctrellis.numStates; k++)
211 {
212 sum1 += std::exp(A1[k+n*rsctrellis.numStates]+B1[k+n*rsctrellis.numStates]);
213 sum0 += std::exp(A0[k+n*rsctrellis.numStates]+B0[k+n*rsctrellis.numStates]);
214 }
215 extrinsic_data[n] = std::log(sum1/sum0)-apriori_data[n];//updated information must be independent of input LLR
216 extrinsic_coded[2*n] = std::log(sum1/sum0)-Lc1I[n];//this information is used in serial concatenations
217 }
218
219 //updated LLR for coded (parity) bits
220#pragma omp parallel for private(n, k, sum0, sum1)
221 for (n=0; n<N; n++)
222 {
223 sum0 = 0;
224 sum1 = 0;
225 for (k=0; k<rsctrellis.numStates; k++)
226 {
227 if (rsctrellis.fm[k])
228 {
229 sum1 += std::exp(A1[k+n*rsctrellis.numStates]+B1[k+n*rsctrellis.numStates]);
230 sum0 += std::exp(A0[k+n*rsctrellis.numStates]+B0[k+n*rsctrellis.numStates]);
231 }
232 else
233 {
234 sum0 += std::exp(A1[k+n*rsctrellis.numStates]+B1[k+n*rsctrellis.numStates]);
235 sum1 += std::exp(A0[k+n*rsctrellis.numStates]+B0[k+n*rsctrellis.numStates]);
236 }
237 }
238 extrinsic_coded[2*n+1] = std::log(sum0/sum1)-Lc2I[n];//updated information must be independent of input LLR
239 }
240
241 //destroy trellis
242 delete[] rsctrellis.prevStates;
243 delete[] rsctrellis.nextStates;
244 delete[] rsctrellis.PARout;
245 delete[] rsctrellis.fm;
246 //destroy MAP parameters
247 delete[] Lc1I;
248 delete[] Lc2I;
249 delete[] A0;
250 delete[] A1;
251 delete[] A_mid;
252 delete[] B0;
253 delete[] B1;
254}
255
256void SISO::rsc_maxlogMAP(itpp::vec &extrinsic_coded, itpp::vec &extrinsic_data,
257 const itpp::vec &intrinsic_coded, const itpp::vec &apriori_data)
258/*
259 maxlogMAP (SISO) decoder for RSC of rate 1/2
260 extrinsic_coded - extrinsic information of coded bits
261 extrinsic_data - extrinsic information of data (informational) bits
262 intrinsic_coded - intrinsic information of coded (systematic and parity) bits
263 apriori_data - a priori information of data (informational) bits
264 Reference: Steven S. Pietrobon and Adrian S. Barbulescu, "A simplification of
265 the modified Bahl decoding algorithm for systematic convolutional codes", Proc. ISITA, 1994
266 */
267{
268 //get parameters
269 int N = apriori_data.length();
270 //other parameters
271 register int n,k;
272 double buffer;
273 int index;
274 double A_min, A_max;
275 double sum0, sum1;
276
277 //trellis generation
278 gen_rsctrellis();
279
280 //parameter initialization
281 double* Lc1I = new double[N];
282 double* Lc2I = new double[N];
283#pragma omp parallel for private(n)
284 for (n=0; n<N; n++)
285 {
286 Lc1I[n] = intrinsic_coded[2*n];
287 Lc2I[n] = intrinsic_coded[2*n+1];
288 }
289 double* A0 = new double[rsctrellis.numStates*N];
290 double* A1 = new double[rsctrellis.numStates*N];
291 double* A_mid = new double[N];
292 double* B0 = new double[rsctrellis.numStates*N];
293 double* B1 = new double[rsctrellis.numStates*N];
294 buffer = (tail?-INFINITY:0);//log(buffer)
295#pragma omp parallel for private(n,k)
296 for (n=0; n<N; n++)
297 {
298 for (k=0; k<rsctrellis.numStates; k++)
299 {
300 A0[k+n*rsctrellis.numStates] = -INFINITY;
301 A1[k+n*rsctrellis.numStates] = -INFINITY;
302 B0[k+n*rsctrellis.numStates] = buffer;
303 B1[k+n*rsctrellis.numStates] = buffer;
304 }
305 A_mid[n] = 0;
306 }
307
308 //A
309 A0[0] = Lc2I[0]*rsctrellis.PARout[0];//i=0
310 A1[0] = Lc1I[0]+apriori_data[0]+Lc2I[0]*rsctrellis.PARout[rsctrellis.numStates];//i=1
311 for (n=1; n<N; n++)
312 {
313 A_min = INFINITY;
314 A_max = 0;
315 for (k=0; k<rsctrellis.numStates; k++)
316 {
317 buffer = std::max(A0[rsctrellis.prevStates[k]+(n-1)*rsctrellis.numStates],
318 A1[rsctrellis.prevStates[k+rsctrellis.numStates]+(n-1)*rsctrellis.numStates]);//log(alpha0+alpha1)
319 A0[k+rsctrellis.numStates*n] = Lc2I[n]*rsctrellis.PARout[k]+buffer;
320 A1[k+rsctrellis.numStates*n] = Lc1I[n]+apriori_data[n]+
321 Lc2I[n]*rsctrellis.PARout[k+rsctrellis.numStates]+buffer;
322 //find min A(:,n)
323 A_min = std::min(A_min, A0[k+rsctrellis.numStates*n]);
324 //find max A(:,n)
325 A_max = std::max(A_max, A0[k+rsctrellis.numStates*n]);
326 }
327 //normalization
328 A_mid[n] = (A_min+A_max)/2;
329 if (std::isinf(A_mid[n]))
330 continue;
331 for (k=0; k<rsctrellis.numStates; k++)
332 {
333 A0[k+rsctrellis.numStates*n] -= A_mid[n];
334 A1[k+rsctrellis.numStates*n] -= A_mid[n];
335 }
336 }
337 //B
338 B0[rsctrellis.prevStates[0]+(N-1)*rsctrellis.numStates] = 0;
339 B1[rsctrellis.prevStates[rsctrellis.numStates]+(N-1)*rsctrellis.numStates] = 0;
340 for (n=N-2; n>=0; n--)
341 {
342 for (k=0; k<rsctrellis.numStates; k++)
343 {
344 index = rsctrellis.nextStates[k];
345 B0[k+rsctrellis.numStates*n] = std::max(B0[index+(n+1)*rsctrellis.numStates]+
346 Lc2I[n+1]*rsctrellis.PARout[index],
347 B1[index+(n+1)*rsctrellis.numStates]+
348 Lc1I[n+1]+apriori_data[n+1]+Lc2I[n+1]*rsctrellis.PARout[index+rsctrellis.numStates]);
349 index = rsctrellis.nextStates[k+rsctrellis.numStates];
350 B1[k+rsctrellis.numStates*n] = std::max(B0[index+(n+1)*rsctrellis.numStates]+
351 Lc2I[n+1]*rsctrellis.PARout[index],
352 B1[index+(n+1)*rsctrellis.numStates]+
353 Lc1I[n+1]+apriori_data[n+1]+Lc2I[n+1]*rsctrellis.PARout[index+rsctrellis.numStates]);
354
355 }
356 if (std::isinf(A_mid[n+1]))
357 continue;
358 for (k=0; k<rsctrellis.numStates; k++)
359 {
360 B0[k+rsctrellis.numStates*n] -= A_mid[n+1];
361 B1[k+rsctrellis.numStates*n] -= A_mid[n+1];
362 }
363 }
364
365 //updated LLR for information bits
366 extrinsic_data.set_size(N);
367 extrinsic_coded.set_size(2*N);
368#pragma omp parallel for private(n, k, sum0, sum1)
369 for (n=0; n<N; n++)
370 {
371 sum0 = -INFINITY;
372 sum1 = -INFINITY;
373 for (k=0; k<rsctrellis.numStates; k++)
374 {
375 sum1 = std::max(sum1, A1[k+n*rsctrellis.numStates]+B1[k+n*rsctrellis.numStates]);
376 sum0 = std::max(sum0, A0[k+n*rsctrellis.numStates]+B0[k+n*rsctrellis.numStates]);
377 }
378 extrinsic_data[n] = (sum1-sum0)-apriori_data[n];//updated information must be independent of input LLR
379 extrinsic_coded[2*n] = (sum1-sum0)-Lc1I[n];
380 }
381
382 //updated LLR for coded (parity) bits
383#pragma omp parallel for private(n, k, sum0, sum1)
384 for (n=0; n<N; n++)
385 {
386 sum0 = -INFINITY;
387 sum1 = -INFINITY;
388 for (k=0; k<rsctrellis.numStates; k++)
389 {
390 if (rsctrellis.fm[k])
391 {
392 sum1 = std::max(sum1, A1[k+n*rsctrellis.numStates]+B1[k+n*rsctrellis.numStates]);
393 sum0 = std::max(sum0, A0[k+n*rsctrellis.numStates]+B0[k+n*rsctrellis.numStates]);
394 }
395 else
396 {
397 sum0 = std::max(sum0, A1[k+n*rsctrellis.numStates]+B1[k+n*rsctrellis.numStates]);
398 sum1 = std::max(sum1, A0[k+n*rsctrellis.numStates]+B0[k+n*rsctrellis.numStates]);
399 }
400 }
401 extrinsic_coded[2*n+1] = (sum0-sum1)-Lc2I[n];//updated information must be independent of input LLR
402 }
403 //destroy trellis
404 delete[] rsctrellis.prevStates;
405 delete[] rsctrellis.nextStates;
406 delete[] rsctrellis.PARout;
407 delete[] rsctrellis.fm;
408 //destroy MAP parameters
409 delete[] Lc1I;
410 delete[] Lc2I;
411 delete[] A0;
412 delete[] A1;
413 delete[] A_mid;
414 delete[] B0;
415 delete[] B1;
416}
417
418void SISO::rsc_sova(itpp::vec &extrinsic_data, const itpp::vec &intrinsic_coded,
419 const itpp::vec &apriori_data, const int &win_len)
420/* Soft Output Viterbi Algorithm (SOVA) optimized for 1/N encoders
421 * Output: extrinsic_data - extrinsic information of data bits
422 * Inputs: intrinsic_coded - intrinsic information of data bits
423 * apriori_data - a priori information of data bits
424 * win_len - window length used to represent the code trellis
425 *
426 * The original version has been written by Adrian Bohdanowicz (2003).
427 * It is assumed that the BPSK mapping is: 0 -> +1, 1 -> -1.
428 * Changes have been made to adapt the code for RSC codes of rate 1/2
429 * and for soft input informations.
430 * Improved SOVA has been implemented using a scaling factor and threshold for
431 * the reliability information (see Wang [2003]). Even so, PCCC performance
432 * are close to the original SOVA.
433 */
434{
435 //number of code outputs
436 int nb_outputs = gen.rows();
437
438 //setup internal variables based on RSC trellis
439 register int i,j,s;
440 gen_rsctrellis();//trellis generation for 1/2 RSC codes
441 int nb_states = rsctrellis.numStates;
442 itpp::Array<itpp::mat> bin_out(2);//contains code output for each initial state and code input
443 itpp::imat next_state(nb_states,2);//next state in the trellis
444 for (i=0; i<2; i++)
445 {
446 bin_out(i).set_size(nb_states, nb_outputs);
447 for (j=0; j<nb_states; j++)
448 {
449 bin_out(i)(j,0) = double(i);//systematic bit
450 bin_out(i)(j,1) = rsctrellis.PARout[j+i*nb_states];//parity bit
451 next_state(j,i) = rsctrellis.nextStates[j+i*nb_states];
452 }
453 }
454 itpp::vec bin_inp("0 1");//binary code inputs
455
456 int len = apriori_data.length();//number of decoding steps (total)
457
458 //allocate memory for the trellis window
459 itpp::mat metr(nb_states,win_len+1);//path metric buffer
460 metr.zeros();
461 metr += -INFINITY;
462 metr(0,0) = 0;//initial state => (0,0)
463 itpp::mat surv(nb_states,win_len+1);//survivor state buffer
464 surv.zeros();
465 itpp::mat inpt(nb_states,win_len+1);//survivor input buffer (dec. output)
466 inpt.zeros();
467 itpp::mat diff(nb_states,win_len+1);//path metric difference
468 diff.zeros();
469 itpp::mat comp(nb_states,win_len+1);//competitor state buffer
470 comp.zeros();
471 itpp::mat inpc(nb_states,win_len+1);//competitor input buffer
472 inpc.zeros();
473 //soft output (sign with reliability)
474 itpp::vec sft(len);
475 sft.zeros();
476 sft += INFINITY;
477
478 //decode all the bits
479 int Cur,Nxt,nxt,sur,b,tmp,idx;
480 itpp::vec buf(nb_outputs);
481 double llb,mtr,dif,cmp,inc,srv,inp;
482 itpp::vec bin(nb_outputs);
483 itpp::ivec cyclic_buffer(win_len);
484 extrinsic_data.set_size(len);
485 for (i = 0; i < len; i++)
486 {
487 //indices + precalculations
488 Cur = i%(win_len+1);//curr trellis (cycl. buf) position
489 Nxt = (i+1)%(win_len+1);//next trellis (cycl. buf) position
490 buf = intrinsic_coded(i*nb_outputs,(i+1)*nb_outputs-1);//intrinsic_info portion to be processed
491 llb = apriori_data(i);//SOVA: apriori_info portion to be processed
492 metr.set_col(Nxt, -INFINITY*itpp::ones(nb_states));
493
494 //forward recursion
495 for (s = 0; s<nb_states; s++)
496 {
497 for (j = 0; j<2; j++)
498 {
499 nxt = next_state(s,j);//state after transition
500 bin = bin_out(j).get_row(s);//transition output (encoder)
501 mtr = bin*buf+metr(s,Cur);//transition metric
502 mtr += bin_inp(j)*llb;//SOVA
503
504 if (metr(nxt,Nxt) < mtr)
505 {
506 diff(nxt,Nxt) = mtr-metr(nxt,Nxt);//SOVA
507 comp(nxt,Nxt) = surv(nxt,Nxt);//SOVA
508 inpc(nxt,Nxt) = inpt(nxt,Nxt);//SOVA
509
510 metr(nxt,Nxt) = mtr;//store the metric
511 surv(nxt,Nxt) = s;//store the survival state
512 inpt(nxt,Nxt) = j;//store the survival input
513 }
514 else
515 {
516 dif = metr(nxt,Nxt)-mtr;
517 if (dif <= diff(nxt,Nxt))
518 {
519 diff(nxt,Nxt) = dif;//SOVA
520 comp(nxt,Nxt) = s;//SOVA
521 inpc(nxt,Nxt) = j;//SOVA
522 }
523 }
524 }
525 }
526
527 //trace backwards
528 if (i < (win_len-1))
529 {
530 continue;
531 }//proceed if the buffer has been filled
532 mtr = itpp::max(metr.get_col(Nxt), sur);//find the initial state (max metric)
533 b = i;//temporary bit index
534 for (j=0; j<win_len; j++)//indices in a 'cyclic buffer' operation
535 {
536 cyclic_buffer(j) = (Nxt-j)%(win_len+1);
537 cyclic_buffer(j) = (cyclic_buffer(j)<0)?(cyclic_buffer(j)+win_len+1):cyclic_buffer(j);
538 }
539
540 for (j=0; j<win_len; j++)//for all the bits in the buffer
541 {
542 inp = inpt(sur,cyclic_buffer(j));//current bit-decoder output (encoder input)
543 extrinsic_data(b) = inp;//store the hard output
544
545 tmp = cyclic_buffer(j);
546 cmp = comp(sur, tmp);//SOVA: competitor state (previous)
547 inc = inpc(sur, tmp);//SOVA: competitor bit output
548 dif = diff(sur, tmp);//SOVA: corresp. path metric difference
549 srv = surv(sur, tmp);//SOVA: temporary survivor path state
550
551 for (s=j+1; s<=win_len; s++)//check all buffer bits srv and cmp paths
552 {
553 if (inp != inc)
554 {
555 idx = b-((s-1)-j);//calculate index: [enc.k*(b-(k-1)+j-1)+1:enc.k*(b-(k-1)+j)]
556 sft(idx) = std::min(sft(idx), dif);//update LLRs for bits that are different
557 }
558 if (srv == cmp)
559 {
560 break;
561 }//stop if surv and comp merge (no need to continue)
562 if (s == win_len)
563 {
564 break;
565 }//stop if the end (otherwise: error)
566 tmp = cyclic_buffer(s);
567 inp = inpt(int(srv), tmp);//previous surv bit
568 inc = inpt(int(cmp), tmp);//previous comp bit
569 srv = surv(int(srv), tmp);//previous surv state
570 cmp = surv(int(cmp), tmp);//previous comp state
571 }
572 sur = int(surv(sur, cyclic_buffer(j)));//state for the previous surv bit
573 b--;//update bit index
574 }
575 }
576
577 // provide soft output with +/- sign:
578 sft = threshold(sft, SOVA_threshold);
579 extrinsic_data =
580 itpp::elem_mult((2.0*extrinsic_data-1.0), SOVA_scaling_factor*sft)-apriori_data;
581
582 //free trellis memory
583 delete[] rsctrellis.prevStates;
584 delete[] rsctrellis.nextStates;
585 delete[] rsctrellis.PARout;
586 delete[] rsctrellis.fm;
587}
588
589void SISO::rsc_viterbi(itpp::vec &extrinsic_coded, itpp::vec &extrinsic_data,
590 const itpp::vec &intrinsic_coded, const itpp::vec &apriori_data, const int &win_len)
591/* Soft Input Soft Output module based on Viterbi algorithm
592 * Output: extrinsic_data - extrinsic information of data bits
593 * Inputs: intrinsic_coded - intrinsic information of data bits
594 * apriori_data - a priori information of data bits
595 * win_len - window length used to represent the code trellis
596 *
597 * The implemented algorithm follows M. Kerner and O. Amrani, ''Iterative Decoding
598 * Using Optimum Soft Input - Hard Output Module`` (2009), in:
599 * IEEE Transactions on Communications, 57:7(1881-1885)
600 */
601{
602 //number of code outputs
603 int nb_outputs = gen.rows();
604
605 //setup internal variables based on RSC trellis
606 register int i,j,s;
607 gen_rsctrellis();//trellis generation for 1/2 RSC codes
608 int nb_states = rsctrellis.numStates;
609 itpp::Array<itpp::mat> bin_out(2);//contains code output for each initial state and code input
610 itpp::imat next_state(nb_states,2);//next state in the trellis
611 for (i=0; i<2; i++)
612 {
613 bin_out(i).set_size(nb_states, nb_outputs);
614 for (j=0; j<nb_states; j++)
615 {
616 bin_out(i)(j,0) = double(i);//systematic bit
617 bin_out(i)(j,1) = rsctrellis.PARout[j+i*nb_states];//parity bit
618 next_state(j,i) = rsctrellis.nextStates[j+i*nb_states];
619 }
620 }
621 itpp::vec bin_inp("0 1");//binary code inputs
622
623 int len = apriori_data.length();//number of decoding steps (total)
624
625 //allocate memory for the trellis window
626 itpp::mat metr(nb_states,win_len+1);//path metric buffer
627 metr.zeros();
628 metr += -INFINITY;
629 metr(0,0) = 0;//initial state => (0,0)
630 itpp::mat surv(nb_states,win_len+1);//survivor state buffer
631 surv.zeros();
632 itpp::mat inpt(nb_states,win_len+1);//survivor input bits buffer (dec. output)
633 inpt.zeros();
634 itpp::mat parity(nb_states,win_len+1);//survivor parity bits buffer (dec. output)
635 parity.zeros();
636
637 //decode all the bits
638 int Cur,Nxt,nxt,sur,b;
639 itpp::vec buf(nb_outputs);
640 double llb,mtr;
641 itpp::vec bin(nb_outputs);
642 itpp::ivec cyclic_buffer(win_len);
643 extrinsic_coded.set_size(2*len);//initialize memory for output
644 extrinsic_data.set_size(len);
645 for (i = 0; i < len; i++)
646 {
647 //indices + precalculations
648 Cur = i%(win_len+1);//curr trellis (cycl. buf) position
649 Nxt = (i+1)%(win_len+1);//next trellis (cycl. buf) position
650 buf = intrinsic_coded(i*nb_outputs,(i+1)*nb_outputs-1);//intrinsic_info portion to be processed
651 llb = apriori_data(i);//SOVA: apriori_info portion to be processed
652 metr.set_col(Nxt, -INFINITY*itpp::ones(nb_states));
653
654 //forward recursion
655 for (s = 0; s<nb_states; s++)
656 {
657 for (j = 0; j<2; j++)
658 {
659 nxt = next_state(s,j);//state after transition
660 bin = bin_out(j).get_row(s);//transition output (encoder)
661 mtr = bin*buf+metr(s,Cur);//transition metric
662 mtr += bin_inp(j)*llb;//add a priori info contribution
663
664 if (metr(nxt,Nxt) < mtr)
665 {
666 metr(nxt,Nxt) = mtr;//store the metric
667 surv(nxt,Nxt) = s;//store the survival state
668 inpt(nxt,Nxt) = bin(0);//j;//store the survival input
669 parity(nxt,Nxt) = bin(1);//store survival parity bit
670 }
671 }
672 }
673
674 //trace backwards
675 if (i < (win_len-1))
676 {
677 continue;
678 }//proceed if the buffer has been filled
679 mtr = itpp::max(metr.get_col(Nxt), sur);//find the initial state (max metric)
680 b = i;//temporary bit index
681 for (j=0; j<win_len; j++)//indices in a 'cyclic buffer' operation
682 {
683 cyclic_buffer(j) = (Nxt-j)%(win_len+1);
684 cyclic_buffer(j) = (cyclic_buffer(j)<0)?(cyclic_buffer(j)+win_len+1):cyclic_buffer(j);
685 }
686
687 for (j=0; j<win_len; j++)//for all the bits in the buffer
688 {
689 extrinsic_data(b) = inpt(sur,cyclic_buffer(j));//current bit-decoder output (encoder input)
690 extrinsic_coded(2*b) = extrinsic_data(b);
691 extrinsic_coded(2*b+1) = parity(sur,cyclic_buffer(j));
692 sur = int(surv(sur, cyclic_buffer(j)));//state for the previous surv bit
693 b--;//update bit index
694 }
695 }
696
697 //free trellis memory
698 delete[] rsctrellis.prevStates;
699 delete[] rsctrellis.nextStates;
700 delete[] rsctrellis.PARout;
701 delete[] rsctrellis.fm;
702
703 //output only the hard output if the flag is true
704 if (Viterbi_hard_output_flag==true)
705 {
706 return;
707 }
708
709 // provide soft output (extrinsic information) for data bits
710 //compute flipped and non-flipped bits positions
711 itpp::bvec tmp(len);
712 for (i=0; i<len; i++)
713 {
714 tmp(i) = ((apriori_data(i)+intrinsic_coded(2*i))>=0)^(extrinsic_data(i)==1.0);
715 }
716 itpp::ivec *ptr_idx_matching = new itpp::ivec;
717 itpp::ivec *ptr_idx_nonmatching = new itpp::ivec;
718 *ptr_idx_matching = itpp::find(tmp==itpp::bin(0));
719 *ptr_idx_nonmatching = itpp::find(tmp==itpp::bin(1));
720 //Estimated Bit Error Rate
721 int idx_nonmatching_len = ptr_idx_nonmatching->length();
722 double error_rate = double(idx_nonmatching_len)/double(len);
723 //Logarithm of Likelihood Ratio
724 double LLR;
725 if (error_rate==0.0)
726 {
727 LLR = std::log(double(len));
728 } else if (error_rate==1.0)
729 {
730 LLR = -std::log(double(len));
731 } else
732 {
733 LLR = std::log((1.0-error_rate)/error_rate);
734 }
735 for (i=0; i<ptr_idx_matching->length(); i++)
736 {
737 extrinsic_data(ptr_idx_matching->get(i)) = Viterbi_scaling_factor[0]*
738 (2.0*extrinsic_data(ptr_idx_matching->get(i))-1.0)*LLR;
739 }
740 for (i=0; i<idx_nonmatching_len; i++)
741 {
742 extrinsic_data(ptr_idx_nonmatching->get(i)) = Viterbi_scaling_factor[1]*
743 (2.0*extrinsic_data(ptr_idx_nonmatching->get(i))-1.0)*LLR;
744 }
745 //extrinsic information
746 extrinsic_data -= apriori_data;
747
748 //provide soft output for coded bits
749 tmp.set_length(2*len);
750 for (i=0; i<(2*len); i++)
751 {
752 tmp(i) = (intrinsic_coded(i)>=0)^(extrinsic_coded(i)==1.0);
753 }
754 delete ptr_idx_matching;//free old memory
755 delete ptr_idx_nonmatching;
756 ptr_idx_matching = new itpp::ivec;//allocate memory for new vectors
757 ptr_idx_nonmatching = new itpp::ivec;
758 *ptr_idx_matching = itpp::find(tmp==itpp::bin(0));
759 *ptr_idx_nonmatching = itpp::find(tmp==itpp::bin(1));
760 //Estimated Bit Error Rate
761 idx_nonmatching_len = ptr_idx_nonmatching->length();
762 error_rate = double(idx_nonmatching_len)/double(2*len);
763 //Logarithm of Likelihood Ratio
764 if (error_rate==0.0)
765 {
766 LLR = std::log(double(2*len));
767 } else if (error_rate==1.0)
768 {
769 LLR = -std::log(double(2*len));
770 } else
771 {
772 LLR = std::log((1.0-error_rate)/error_rate);
773 }
774 for (i=0; i<ptr_idx_matching->length(); i++)
775 {
776 extrinsic_coded(ptr_idx_matching->get(i)) = Viterbi_scaling_factor[0]*
777 (2.0*extrinsic_coded(ptr_idx_matching->get(i))-1.0)*LLR;
778 }
779 for (i=0; i<idx_nonmatching_len; i++)
780 {
781 extrinsic_coded(ptr_idx_nonmatching->get(i)) = Viterbi_scaling_factor[1]*
782 (2.0*extrinsic_coded(ptr_idx_nonmatching->get(i))-1.0)*LLR;
783 }
784 delete ptr_idx_matching;
785 delete ptr_idx_nonmatching;
786 //extrinsic information
787 extrinsic_coded -= intrinsic_coded;
788}
789
790}
General array class.
Definition factory.h:40
static double threshold(const double &x, const double &value)
Functions used to limit values at a given +- threshold.
Definition siso.h:901
Binary arithmetic (boolean) class.
Definition binary.h:57
double log_add(double log_a, double log_b)
Safe substitute for log(exp(log_a) + exp(log_b))
Definition log_exp.cpp:40
T max(const Vec< T > &v)
Maximum value of vector.
Definition min_max.h:45
ivec find(const bvec &invector)
Return a integer vector with indicies where bvec == 1.
Definition specmat.cpp:40
ITPP_EXPORT vec ones(int size)
A float vector of ones.
IT++ compatibility types and functions.
itpp namespace
Definition itmex.h:37
ITPP_EXPORT int bin2dec(const bvec &inbvec, bool msb_first=true)
Convert a bvec to decimal int with the first bit as MSB if msb_first == true.
ITPP_EXPORT bvec dec2bin(int length, int index)
Convert a decimal int index to bvec using length bits in the representation.
Mat< Num_T > elem_mult(const Mat< Num_T > &m1, const Mat< Num_T > &m2)
Element wise multiplication of two matrices.
Definition mat.h:1582
Definitions for Soft Input Soft Output (SISO) modules class.
SourceForge Logo

Generated on Tue Dec 10 2024 04:49:37 for IT++ by Doxygen 1.12.0