src/convcode.c

Go to the documentation of this file.
00001 /*
00002    libit - Library for basic source and channel coding functions
00003    Copyright (C) 2005-2005 Vivien Chappelier, Herve Jegou
00004 
00005    This library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Library General Public
00007    License as published by the Free Software Foundation; either
00008    version 2 of the License, or (at your option) any later version.
00009 
00010    This library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Library General Public License for more details.
00014 
00015    You should have received a copy of the GNU Library General Public
00016    License along with this library; if not, write to the Free
00017    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00018 */
00019 
00020 /*
00021   Convolutional codes
00022   Copyright (C) 2005 Vivien Chappelier
00023 */
00024 
00025 #include <it/types.h>
00026 #include <it/vec.h>
00027 #include <it/convcode.h>
00028 #include <it/io.h>
00029 #include <it/hmmalgo.h>
00030 
00031 #define bit(x, n) (((x) >> (n)) & 1)
00032 
00033 #define DECLARE_CONV_CODE(x, k, n) \
00034   int it_cc_generators_##x[k*n]
00035 
00036 /* some convolutional and recursive convolutional codes */
00037 DECLARE_CONV_CODE (conv_code_1, 1, 2) = {
00038 02, 03};
00039 
00040 DECLARE_CONV_CODE (conv_code_2, 1, 2) = {
00041 05, 07};
00042 
00043 DECLARE_CONV_CODE (conv_code_3, 1, 2) = {
00044 015, 017};
00045 
00046 DECLARE_CONV_CODE (conv_code_4, 1, 2) = {
00047 023, 033};
00048 
00049 DECLARE_CONV_CODE (conv_code_6, 1, 2) = {
00050 0133, 0171};
00051 
00052 /* local helper functions */
00053 static int fls (int c);
00054 static int encode_conv (it_convolutional_code_t * cc, int *state, int input,
00055       imat G, int Q, int k, int n);
00056 
00057 /* function prototypes */
00058 static void convolutional_code_destructor (it_object_t * it_this);
00059 static bvec convolutional_code_encode (it_convolutional_code_t * cc, bvec b);
00060 static ivec convolutional_code_encode_symbolic (it_convolutional_code_t * cc,
00061             ivec b);
00062 
00063 /* instanciation of a convolutional code */
00064 it_instanciate (it_convolutional_code_t)
00065 {
00066   imat generators;
00067   int  Q;
00068   int  i, j, c;
00069   int  s, n, k, l;
00070   int  state, symbol;
00071   int  n_states, n_symbols, n_labels;
00072 
00073   it_new_args_start ();
00074 
00075   it_construct (it_object_t);
00076   it_set_magic (it_this, it_convolutional_code_t);
00077 
00078   it_overload (it_this, it_object_t, destructor,
00079          convolutional_code_destructor);
00080 
00081   /* assign methods */
00082   it_this->encode = convolutional_code_encode;
00083   it_this->encode_symbolic = convolutional_code_encode_symbolic;
00084 
00085   /* construction */
00086   it_this->generators = generators = imat_clone (it_new_args_next (imat));
00087   it_this->Q = Q = it_new_args_next (int);
00088   it_this->k = k = imat_height (generators);
00089   it_this->n = n = imat_width (generators);
00090 
00091   /* find the total memory of the code */
00092   l = 0;
00093   for (j = 0; j < k; j++) {
00094     c = Q;
00095     for (i = 0; i < n; i++)
00096       c |= generators[j][i];
00097     l += fls (c) - 1;
00098   }
00099 
00100   /* allocate automaton */
00101   it_this->memory = l;
00102   it_this->n_states = n_states = 1 << l;
00103   it_this->n_symbols = n_symbols = 1 << k;
00104   it_this->n_labels = n_labels = 1 << n;
00105 
00106   it_this->automaton = imat_new_set (DUMM_NODE, 1 << n, n_states);
00107   it_this->output = imat_new (1 << k, n_states);
00108   it_this->input = imat_new_set (NULL_INDEX, 1 << n, n_states);
00109 
00110   /* start from the zero state */
00111   it_this->logalpha_0 = vec_new_set (-HUGE_VAL, n_states);
00112   it_this->logalpha_0[0] = 0.0;
00113 
00114   /* end in whatever state */
00115   it_this->logbeta_end = vec_new_zeros (n_states);
00116 
00117   /* each branch has equal a priori probability of being taken */
00118   it_this->next_state_logpt = mat_new_zeros (n_labels, n_states);
00119 
00120   /* compute label and next state for each state and symbol */
00121   for (state = 0; state < n_states; state++) {
00122     for (symbol = 0; symbol < n_symbols; symbol++) {
00123       s = state;
00124       c = encode_conv (it_this, &s, symbol, generators, Q, k, n);
00125 
00126       it_this->automaton[c][state] = s;
00127       it_this->output[symbol][state] = c;
00128       it_this->input[c][state] = symbol;
00129     }
00130   }
00131 
00132   it_new_args_stop ();
00133   return (it_this);
00134 }
00135 
00136 
00137 static void convolutional_code_destructor (it_object_t * it_this)
00138 {
00139   it_convolutional_code_t *convolutional_code =
00140     IT_CONVOLUTIONAL_CODE (it_this);
00141 
00142   if (convolutional_code->generators)
00143     imat_delete (convolutional_code->generators);
00144 
00145   vec_delete (convolutional_code->logalpha_0);
00146   vec_delete (convolutional_code->logbeta_end);
00147   mat_delete (convolutional_code->next_state_logpt);
00148   imat_delete (convolutional_code->automaton);
00149   imat_delete (convolutional_code->input);
00150   imat_delete (convolutional_code->output);
00151 
00152   /* call the parent destructor */
00153   convolutional_code->it_overloaded (destructor) (it_this);
00154 }
00155 
00156 
00157 static bvec convolutional_code_encode (it_convolutional_code_t * cc, bvec b)
00158 {
00159   int  i, j;
00160   int  k = cc->k;
00161   int  n = cc->n;
00162   idx_t L = bvec_length (b) / k;
00163   bvec r = bvec_new (L * n);
00164   int  state = 0;
00165   int  symbol;
00166   int  label;
00167 
00168   assert (L * k == bvec_length (b));
00169 
00170   for (i = 0; i < L; i++) {
00171     symbol = 0;
00172     /* read k bits */
00173     for (j = 0; j < k; j++) {
00174       assert (!(b[i * k + j] >> 1));
00175       symbol |= b[i * k + j] << (k - 1 - j);
00176     }
00177 
00178     /* get the label and next state for that symbol */
00179     label = it_cc_label (cc, state, symbol);
00180     state = it_cc_next (cc, state, symbol);
00181 
00182     /* write n bits */
00183     for (j = 0; j < n; j++)
00184       r[i * n + j] = bit (label, n - 1 - j);
00185   }
00186 
00187   return (r);
00188 }
00189 
00190 
00191 static ivec convolutional_code_encode_symbolic (it_convolutional_code_t * cc,
00192             ivec s)
00193 {
00194   int  i;
00195   int  L = ivec_length (s);
00196   ivec r = ivec_new (L);
00197   int  state = 0;
00198 
00199   for (i = 0; i < L; i++) {
00200     /* get the label and next state for that symbol */
00201     r[i] = it_cc_label (cc, state, s[i]);
00202     state = it_cc_next (cc, state, s[i]);
00203   }
00204   return (r);
00205 }
00206 
00207 
00208 /* ------------ helper functions  ------------------*/
00209 static int encode_conv (it_convolutional_code_t * cc, int *state, /* state of the coder */
00210       int input,  /* k bits */
00211       imat G, /* generator matrix [k][n] */
00212       int Q,  /* feedback polynomial */
00213       int k,  /* number of input bits */
00214       int n)
00215 {       /* number of output bits */
00216   int  i, j, b, r, t;
00217   int  c, s, l;
00218   int  m;
00219   int  feedback;
00220 
00221   s = *state;
00222   c = m = r = 0;
00223 
00224   for (j = 0; j < k; j++) {
00225 
00226     /* get the memory of this register */
00227     t = Q;
00228     for (i = 0; i < n; i++)
00229       t |= G[j][i];
00230     l = fls (t) - 1;
00231 
00232     /* compute feedback value */
00233     feedback = bit (input, j);
00234     for (i = 0; i < l; i++)
00235       feedback ^= bit (Q, i) & bit (s, i);
00236 
00237     /* generate redundancy bits */
00238     for (i = 0; i < n; i++) {
00239       c ^= (bit (G[j][i], l) & feedback) << i;
00240       for (b = 0; b < l; b++)
00241   c ^= (bit (G[j][i], b) & bit (s, b)) << i;
00242     }
00243 
00244     /* update coder state */
00245     r |= ((s & ((1 << l) - 1)) >> 1) << m;
00246     if (l)
00247       r |= feedback << (m + l - 1);
00248     s >>= l;
00249     m += l;
00250   }
00251 
00252   *state = r;
00253 
00254   return (c);
00255 }
00256 
00257 
00258 /* find last set bit */
00259 static int fls (int c)
00260 {
00261   int  l = 0;
00262 
00263   while (c) {
00264     l++;
00265     c >>= 1;
00266   }
00267   return (l);
00268 }
00269 
00270 
00271 ivec it_viterbi_decode_symbolic (it_convolutional_code_t * cc, mat metrics)
00272 {
00273   ivec branches;
00274   imat next_state = cc->automaton;
00275   mat  next_state_logpt = cc->next_state_logpt;
00276   vec  logalpha_0 = cc->logalpha_0;
00277   vec  logbeta_end = cc->logbeta_end;
00278   int  j, l, k;
00279 
00280   /* decode the most probable sequence */
00281   branches =
00282     logviterbi (metrics, next_state, next_state_logpt, logalpha_0,
00283     logbeta_end);
00284 
00285   /* find the path leading to that sequence */
00286   j = 0;
00287   for (k = 0; k < ivec_length (branches); k++) {
00288     l = branches[k];
00289     branches[k] = cc->input[l][j];
00290     j = next_state[l][j];
00291   }
00292 
00293   return (branches);
00294 }
00295 
00296 
00297 bvec it_viterbi_decode (it_convolutional_code_t * cc, mat metrics)
00298 {
00299   int  K, L;
00300   ivec branches;
00301   bvec r;
00302   int  i, j;
00303 
00304   K = cc->k;
00305   L = mat_width (metrics);
00306   branches = it_viterbi_decode_symbolic (cc, metrics);
00307   r = bvec_new (L * K);
00308 
00309   for (i = 0; i < L; i++)
00310     for (j = 0; j < K; j++)
00311       r[i * K + j] = bit (branches[i], K - 1 - j);
00312 
00313   ivec_delete (branches);
00314 
00315   return (r);
00316 }

Hosted by
Copyright (C) 2005-2006 Hervé Jégou
Vivien Chappelier
Francois Cayre
libit logo courtesy of Jonathan Delhumeau