Updated FSF address in all files. Fixes ticket:51
[debian/gnuradio] / gr-error-correcting-codes / src / lib / libecc / code_convolutional_trellis.h
1 /* -*- c++ -*- */
2 /*
3  * Copyright 2006 Free Software Foundation, Inc.
4  * 
5  * This file is part of GNU Radio
6  * 
7  * GNU Radio 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 2, or (at your option)
10  * any later version.
11  * 
12  * GNU Radio 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 GNU Radio; see the file COPYING.  If not, write to
19  * the Free Software Foundation, Inc., 51 Franklin Street,
20  * Boston, MA 02110-1301, USA.
21  */
22
23 #ifndef INCLUDED_CODE_CONVOLUTIONAL_TRELLIS_H
24 #define INCLUDED_CODE_CONVOLUTIONAL_TRELLIS_H
25
26 #include "code_types.h"
27 #include <vector>
28
29 /*
30  * connection_t: describes an output connection from the current
31  *     time-bit memory state to the next time-bit memory state
32  *
33  * d_to_state: memory configuration of the "to" state
34  *
35  * d_output_bits: the output bits for this connection, mux'ed
36  */
37
38 typedef struct connection_t {
39   memory_t d_to_state;
40   memory_t d_output_bits;
41 } connection_t, *connection_t_ptr;
42
43 /*
44  * trellis_t: describes a single set of trellis connections, from a
45  *     time-bit to the next, forward transitions only
46  *
47  * This is a 2d "matrix", where the first dimention is the starting
48  *     memory state, and the second is the (combined) input as an
49  *     integer: e.g. for a 2 input code, if I1 = 0 and I2 = 1, then
50  *     the combined input is the "number" found by appending I2 and I1
51  *     together, in this case 10b = 3.
52  *
53  * The trellis is used to lookup information: given a starting state
54  *     and inputs, return the output bits and next state.
55  */
56
57 typedef std::vector<std::vector<connection_t> > trellis_t, *trellis_t_ptr;
58
59 class code_convolutional_trellis
60 {
61 /*!
62  * class code_convolutional_trellis
63  *
64  * Create a convolutional code trellis structure, but encoding,
65  * decoding, determining termination transitions, and anything else
66  * which might be useful.
67  *
68  * block_size_bits: if == 0, then do streaming encoding ("infinite"
69  *     trellis); otherwise this is the block size in bits to encode
70  *     before terminating the trellis.  This value -does not- include
71  *     any termination bits.
72  *
73  * n_code_inputs:
74  * n_code_outputs:
75  * code_generator: vector of integers (32 bit) representing the code
76  *     to be implemented.  E.g. "4" in binary is "100", which would be
77  *     "D^2" for code generation.  "6" == 110b == "D^2 + D"
78  *  ==> The vector is listed in order for each output stream, so if there
79  *     are 2 input streams (I1, I2) [specified in "n_code_inputs"]
80  *     and 2 output streams (O1, O2) [specified in "n_code_outputs"],
81  *     then the vector would be the code generator for:
82  *       [I1->O1, I2->O1, I1->O2, I2->O2]
83  *     with each element being an integer representation of the code.
84  *     The "octal" representation is used frequently in the literature
85  *     (e.g. [015, 06] == [1101, 0110] in binary) due to its close
86  *     relationship with binary (each number is 3 binary digits)
87  *     ... but any integer representation will suffice.
88  *
89  * do_termination: valid only if block_size_bits != 0, and defines
90  *     whether or not to use trellis termination.  Default is to use
91  *     termination when doing block coding.
92  *
93  * start_memory_state: when starting a new block, the starting memory
94  *     state to begin encoding; there will be a helper function to
95  *     assist in creating this value for a given set of inputs;
96  *     default is the "all zero" state.
97  * 
98  * end_memory_state: when terminating a block, the ending memory
99  *     state to stop encoding; there will be a helper function to
100  *     assist in creating this value for a given set of inputs;
101  *     default is the "all zero" state.
102  */
103
104 public:
105   inline code_convolutional_trellis
106   (int block_size_bits,
107    int n_code_inputs,
108    int n_code_outputs,
109    const std::vector<int> &code_generators,
110    bool do_termination = true,
111    int end_memory_state = 0)
112   {code_convolutional_trellis_init (block_size_bits,
113                                     n_code_inputs,
114                                     n_code_outputs,
115                                     code_generators,
116                                     NULL,
117                                     do_termination,
118                                     end_memory_state);};
119
120 /*!
121  * Encoder with feedback.
122  *
123  * code_feedback: vector of integers (32 bit) representing the code
124  *     feedback to be implemented (same as for the code_generator).
125  *     For this feedback type, the LSB ("& 1") is ignored (set to "1"
126  *     internally, since it's always 1) ... this (effectively)
127  *     represents the input bit for the given encoder, without which
128  *     there would be no encoding!  Each successive higher-order bit
129  *     represents the output of that delay block; for example "6" ==
130  *     110b == "D^2 + D" means use the current input bit + the output
131  *     of the second delay block.  Listing order is the same as for
132  *     the code_generator.
133  */
134
135   inline code_convolutional_trellis
136   (int block_size_bits,
137    int n_code_inputs,
138    int n_code_outputs,
139    const std::vector<int> &code_generators,
140    const std::vector<int> &code_feedback,
141    bool do_termination = true,
142    int end_memory_state = 0)
143   {code_convolutional_trellis_init (block_size_bits,
144                                     n_code_inputs,
145                                     n_code_outputs,
146                                     code_generators,
147                                     &code_feedback,
148                                     do_termination,
149                                     end_memory_state);};
150
151   virtual ~code_convolutional_trellis () {};
152
153 /* for remote access to internal info */
154
155   inline const size_t block_size_bits () {return (d_block_size_bits);};
156   inline const size_t n_code_inputs () {return (d_n_code_inputs);};
157   inline const size_t n_code_outputs () {return (d_n_code_outputs);};
158   inline const size_t n_states () {return (d_n_states);};
159   inline const size_t n_input_combinations ()
160   {return (d_n_input_combinations);};
161   inline const bool do_termination () {return (d_do_termination);};
162   inline const bool do_feedback () {return (d_do_feedback);};
163   inline const bool do_streaming () {return (d_do_streaming);};
164   inline const bool do_encode_soai () {return (d_do_encode_soai);};
165   inline const size_t total_n_delays () {return (d_total_n_delays);};
166   inline const size_t n_bits_to_term () {return (d_n_bits_to_term);};
167
168   virtual char sum_bits_mod2 (memory_t in_mem, size_t max_memory);
169   void get_termination_inputs (memory_t term_start_state,
170                                size_t bit_num,
171                                std::vector<char>& inputs) {
172     // no error checking ... be careful!
173     for (size_t m = 0; m < d_n_code_inputs; m++) {
174       inputs[m] = ((d_term_inputs[term_start_state][m]) >> bit_num) & 1;
175     }
176   };
177
178   // encode_lookup: given the starting state and inputs, return the
179   // resulting state and output bits.  Two versions: the first is
180   // better for decoding, while the second is better for encoding.
181
182   void encode_lookup (memory_t& state,
183                       const std::vector<char>& inputs,
184                       memory_t& out_bits);
185   void encode_lookup (memory_t& state,
186                       const std::vector<char>& inputs,
187                       std::vector<char>& out_bits);
188
189   // methods for setting and retrieving the state, inputs, and outputs.
190
191   void demux_state (memory_t in_state, std::vector<memory_t>& memories);
192   memory_t mux_state (const std::vector<memory_t>& memories);
193   void demux_inputs (memory_t inputs, std::vector<char>& in_vec);
194   memory_t mux_inputs (const std::vector<char>& in_vec);
195   void demux_outputs (memory_t outputs, std::vector<char>& out_vec);
196   memory_t mux_outputs (const std::vector<char>& out_vec);
197
198 protected:
199 #if 0
200 /*
201  * state_get_from(v,i,k): use to retrieve a given bit-memory state,
202  *     from the inputs:
203  *
204  * memory_t v: the value from which to retrieve the given state
205  * size_t i: for which input stream (0 to #I-1)
206  * size_t k: the number of memory slots per input (e.g. 1+D^2 -> 2)
207  */
208
209   inline memory_t state_get_from (memory_t v,
210                                   size_t i,
211                                   size_t k)
212   {return (((v)>>((i)*(k)))&((1<<(k))-1));};
213
214 /*
215  * state_add_to(s,v,i,k): use to create a given bit-memory state,
216  *     from the inputs:
217  *
218  * memory_t s: the state value to modify
219  * memory_t v: value to set the state to for this input
220  * size_t i: for which input stream (0 to #I-1)
221  * size_t k: the number of memory slots per input (e.g. 1+D^2 -> 2)
222  */
223
224   inline void state_add_to (memory_t s,
225                             memory_t v,
226                             size_t i,
227                             size_t k)
228   {(s)|=(((v)&((1<<(k))-1))<<((i)*(k)));};
229 #endif
230
231 /*
232  * maio(i,o): matrix access into a vector, knowing the # of code
233  *     outputs (from inside the class). References into a vector with
234  *     code inputs ordered by code output.
235  *
236  * 'i' is the 1st dimension - faster memory - the code input
237  * 'o' is the 2nd dimension - slower memory - the code output
238  *
239  * returns ((o*n_code_inputs) + i)
240  */
241
242   inline size_t maio(size_t i, size_t o) {return ((o*d_n_code_inputs) + i);};
243
244 /*
245  * maoi(i,o): matrix access into a vector, knowing the # of code
246  *     inputs (from inside the class). References into a vector with
247  *     code outputs ordered by code input.
248  *
249  * 'o' is the 1st dimension - faster memory - the code output
250  * 'i' is the 2nd dimension - slower memory - the code input
251  *
252  * returns ((i*n_code_outputs) + o)
253  */
254
255   inline size_t maoi(size_t i, size_t o) {return ((i*d_n_code_outputs) + o);};
256
257 /*
258  * max_bit_position (x): returns the bit-number of the highest "1" bit
259  * in the provided value, such that the LSB would return 0 and the MSB
260  * of a long would return 31.
261  */
262
263   inline size_t max_bit_position (memory_t x)
264   {
265     size_t t_code_mem = 0;
266     memory_t t_in_code = x >> 1;
267     while (t_in_code != 0) {
268       t_in_code >>= 1;
269       t_code_mem++;
270     }
271
272     return (t_code_mem);
273   }
274
275   // methods defined in this class
276
277   void code_convolutional_trellis_init
278   (int block_size_bits,
279    int n_code_inputs,
280    int n_code_outputs,
281    const std::vector<int>& code_generators,
282    const std::vector<int>* code_generators,
283    bool do_termination,
284    int end_memory_state);
285
286   void create_trellis ();
287   void create_termination_table (memory_t end_memory_state);
288   void encode_single (memory_t in_state,
289                       memory_t inputs,
290                       memory_t& out_state,
291                       memory_t& out_bits);
292   virtual void encode_single_soai ();
293   virtual void encode_single_siao ();
294   virtual void encode_single_soai_fb ();
295   virtual void encode_single_siao_fb ();
296
297   void get_memory_requirements (size_t m,
298                                 size_t n,
299                                 size_t& t_max_mem,
300                                 size_t& t_n_unique_fb_prev_start,
301                                 const std::vector<int>* code_feedback);
302
303   // variables
304
305   size_t d_block_size_bits, d_n_code_outputs;
306   size_t d_n_code_inputs, d_n_input_combinations;
307   bool d_do_streaming, d_do_termination, d_do_feedback, d_do_encode_soai;
308
309   // "max_delay" is the max # of delays for all unique generators (ff and fb), 
310
311   size_t d_max_delay;
312
313   // "n_memories" is the number of unique memories as determined by
314   // either the feedforward or feedback generators (not both).  For
315   // FF, this number equals either the number of code inputs (for
316   // SIAO) or outputs (for SOAI).
317
318   size_t d_n_memories;
319
320   // "total_n_delays" is the total # of delays, needed to determine the
321   // # of states in the decoder
322   // "n_states" = (2^total_n_delays) - 1 .. the number of memory states
323
324   size_t d_total_n_delays, d_n_states;
325
326   // "code generators" are stored internally in "maXY(i,o)" order this
327   // allows for looping over all a single output and computing all
328   // input parts sequentially.
329
330   std::vector<memory_t> d_code_generators;
331
332   // "feedback" are found as "d_n_memories" unique entries, and stored
333   // in at most 1 entry per I/O combination.  Listed in the same order
334   // as "d_io_num" entries show.
335
336   std::vector<memory_t> d_code_feedback;
337
338   // "n_delays" is a vector, the number of delays for the FB generator
339   // in the same [] location; also relates directly to the
340   // "max_mem_masks" in the same [] location.
341
342   std::vector<size_t> d_n_delays;
343
344   // "io_num" is a vector, mapping which FB in SIAO goes with which
345   // input, or which FB in SOAI goes with which output
346
347   std::vector<size_t> d_io_num;
348
349   // "max_mem_masks" are the memory masks, one per unique FB for SIAO;
350   // otherwise not used.
351
352   std::vector<size_t> d_states_ndx;
353
354   // "memory" are the actual stored delay bits, one memory for each
355   // unique FF or FB code generator;
356   // interpreted w/r.t. the actual FF and FB code generators and
357   // SOAI / SIAO realization;
358
359   std::vector<memory_t> d_max_mem_masks;
360
361   // "states_ndx" is a "matrix" whose contents are the indices into
362   // the "io_num" vector, telling which input goes with which
363   // state; uses the same "maXY(i,o)" as the code generators.
364
365   std::vector<memory_t> d_memory;
366
367   // "term_inputs" are the inputs required to terminate the trellis -
368   //     interpreted w/r.t. the actual FF and FB code generators and
369   //     SOAI / SIAO realization;
370   // first dimension is the memory state #;
371   // second dimension is the input stream #;
372   // bits are packed, with the first input being the LSB and the last
373   //     input being farthest away from the LSB.
374
375   typedef std::vector<std::vector<memory_t> > term_input_t;
376   term_input_t d_term_inputs;
377
378   // "n_bits_to_term" is the number of bits to terminate the trellis
379   // to the desired state, as determined by the termination table.
380   //    d_max_delay <= d_n_bits_to_term <= d_total_n_delays
381   // These numbers will vary depending on the realization.
382
383   size_t d_n_bits_to_term;
384
385   // "inputs" are the current input bits, in the LSB (&1) of each "char"
386
387   std::vector<char> d_current_inputs;
388
389   // "outputs" are the current output bits, in the LSB (&1) of each "char"
390
391   std::vector<char> d_current_outputs;
392
393   // "ind_outputs" are the current output bits, in the LSB (&1) of
394   // each "char", for each individual memory's computations; needed
395   // for soai-type feedback only
396
397   std::vector<char> d_ind_outputs;
398
399   // "trellis" is the single-stage memory state transition ("trellis")
400   // representation for this code; forward paths only
401
402   trellis_t d_trellis;
403 };
404
405 #endif /* INCLUDED_CODE_CONVOLUTIONAL_TRELLIS_H */