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 
36 namespace itpp
37 {
38 void 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 
88 void 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 
256 void 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 
418 void 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 
589 void 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 }
SourceForge Logo

Generated on Sat Jul 6 2013 10:54:23 for IT++ by Doxygen 1.8.2