Updated FSF address in all files. Fixes ticket:51
[debian/gnuradio] / gr-error-correcting-codes / src / lib / libecc / decoder_viterbi.cc
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 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include <decoder_viterbi.h>
28 #include <assert.h>
29 #include <iostream>
30
31 const int g_max_block_size_bits = 10000000;
32 const int g_max_num_streams = 10;
33 const int g_num_bits_per_byte = 8;
34
35 #define DO_TIME_THOUGHPUT 0
36 #define DO_PRINT_DEBUG_INST 0
37 #define DO_PRINT_DEBUG_INST_0 0
38 #define DO_PRINT_DEBUG_INST_1 0
39 #define DO_PRINT_DEBUG_INST_2 0
40 #define DO_PRINT_DEBUG_FSM 0
41 #define DO_PRINT_DEBUG_INIT 0
42 #define DO_PRINT_DEBUG_UP 0
43 #define DO_PRINT_DEBUG_UP_0 0
44 #define DO_PRINT_DEBUG_UP_1 0
45 #define DO_PRINT_DEBUG_MIDDLE 0
46 #define DO_PRINT_DEBUG_MIDDLE_0 0
47 #define DO_PRINT_DEBUG_MIDDLE_1 0
48 #define DO_PRINT_DEBUG_TERM 0
49 #define DO_PRINT_DEBUG_TERM_1 0
50 #define DO_PRINT_DEBUG_OUTPUT 0
51 #define DO_PRINT_DEBUG_OUTPUT_0 0
52 #define DO_PRINT_DEBUG_EXIT 0
53 #define DO_PRINT_DEBUG 0
54
55 #include <mld/mld_timer.h>
56 #include <mld/n2bs.h>
57
58 decoder_viterbi::decoder_viterbi
59 (int sample_precision,
60  const encoder_convolutional* l_encoder)
61 {
62   // make sure that the encoder is "valid"
63
64   if (! l_encoder) {
65     std::cerr << "decoder_viterbi: Error: Encoder is NULL.\n";
66     assert (0);
67   }
68
69   // make the metrics converter
70
71   //  d_code_metrics = new code_metrics (
72
73   if ((sample_precision < 0) | (sample_precision > 32)) {
74     std::cerr << "decoder_viterbi: "
75       "Requested sample_precision (" << sample_precision <<
76       ") must be between 0 and 32.\n";
77     assert (0);
78   }
79
80   // get the trellis
81
82   d_encoder = (encoder_convolutional*) l_encoder;
83   d_trellis = (code_convolutional_trellis*) d_encoder->trellis ();
84
85   // fill the class variables
86
87   d_block_size_bits = d_encoder->block_size_bits ();
88   d_n_code_inputs = d_encoder->n_code_inputs ();
89   d_n_code_outputs = d_encoder->n_code_outputs ();
90   d_do_termination = d_encoder->do_termination ();
91   d_total_n_delays = d_encoder->total_n_delays ();
92   d_n_states = d_trellis->n_states ();
93   d_n_input_combinations = d_trellis->n_input_combinations ();
94
95   // really nothing else to do here, since this class doesn't "know"
96   // how to process streaming versus block decoding, or partial
97   // trellis versus full-trellis.  Those will be handled by
98   // sub-classes which inherit from this one.
99
100   if (DO_PRINT_DEBUG_INST_0) {
101     std::cout << "Init:\n" <<
102       "d_block_size_bits          = " << d_block_size_bits << "\n" <<
103       "d_n_code_inputs            = " << d_n_code_inputs << "\n" <<
104       "d_n_code_outputs           = " << d_n_code_outputs << "\n" <<
105       "d_do_termination           = " <<
106       ((d_do_termination == true) ? "true" : "false") << "\n" <<
107       "d_total_n_delays           = " << d_total_n_delays << "\n" <<
108       "d_n_states                 = " << d_n_states << "\n" <<
109       "d_n_input_combinations     = " << d_n_input_combinations << "\n";
110   }
111
112   // always start the fsm in the "init" state
113
114   d_fsm_state = fsm_dec_viterbi_init;
115
116   // create a vector of indexes to states when doing "up" or "termination";
117
118   d_up_term_states_ndx[0] = new size_t [d_n_states];
119   d_up_term_states_ndx[1] = new size_t [d_n_states];
120
121   // get the total number of out bits per stream
122
123   d_n_total_inputs_per_stream = d_block_size_bits;
124   if (d_do_termination == true)
125     d_n_total_inputs_per_stream += d_total_n_delays;
126 }
127
128 decoder_viterbi::~decoder_viterbi
129 ()
130 {
131   // reverse over from allocation
132 #if 0
133   delete [] d_up_term_states_ndx[0];
134   delete [] d_up_term_states_ndx[1];
135
136   // delete the state's structures
137
138   state_t_ptr t_state = d_states[0];
139   for (size_t n = d_n_states; n > 0; n--, t_state++) {
140     connection_t_ptr t_connection = t_state->d_connections;
141     for (size_t m = d_n_input_combinations; m > 0; m--, t_connection++) {
142       delete [] t_connection->d_output_bits;
143     }
144     delete [] t_state->d_connections;
145   }
146   delete [] d_states[0];
147
148   t_state = d_states[1];
149   for (size_t n = d_n_states; n > 0; n--, t_state++) {
150     connection_t_ptr t_connection = t_state->d_connections;
151     for (size_t m = d_n_input_combinations; m > 0; m--, t_connection++) {
152       delete [] t_connection->d_output_bits;
153     }
154     delete [] t_state->d_connections;
155   }
156   delete [] d_states[1];
157
158   // delete the save buffer
159
160   char** t_save_buffer = d_save_buffer;
161   for (size_t n = 0; n < d_n_code_inputs; n++) {
162     delete [] (*t_save_buffer++);
163   }
164   delete [] d_save_buffer;
165 #endif
166 }
167
168 void
169 decoder_viterbi::reset_metrics
170 (u_char which)
171 {
172   state_t_ptr t_state = d_states[which&1];
173   for (size_t n = d_n_states; n > 0; n--, t_state++) {
174     t_state->d_max_metric = -1e10;
175 #if 0
176 // probably don't need to do these, try removing them later
177     t_state->d_max_state_ndx = 0;
178     t_state->d_max_input = -1;
179 #endif
180   }
181 }
182
183 void
184 decoder_viterbi::zero_metrics
185 (u_char which)
186 {
187   state_t_ptr t_state = d_states[which&1];
188   for (size_t n = d_n_states; n > 0; n--, t_state++) {
189     t_state->d_max_metric = 0;
190 #if 0
191 // probably don't need to do these, try removing them later
192     t_state->d_max_state_ndx = -1;
193     t_state->d_max_input = -1;
194 #endif
195   }
196 }
197
198 void
199 decoder_viterbi::decode_private
200 ()
201 {
202 #if 0
203
204 #if DO_TIME_THOUGHPUT
205   struct timeval t_tp;
206   start_timer (&t_tp);
207 #endif
208 #if DO_PRINT_DEBUG
209   size_t t_state_print_bits = d_total_n_delays;
210   size_t t_mem_print_bits = d_total_n_delays;
211 #endif
212 // setup variables for quicker access
213   const char **in_buf = (const char **) &input_items[0];
214   char **out_buf = (char **) &output_items[0];
215   int t_in_buf_ndx = 0, t_out_buf_ndx = 0;
216   int t_out_bit_shift = 0;
217   int t_ninput_items = compute_n_input_metrics (noutput_items);
218   int t_noutput_bits = noutput_items;
219
220 #if DO_PRINT_DEBUG_INST
221   std::cout << "# output items = " << noutput_items << " (" <<
222     t_noutput_bytes << " Bytes, " << (t_noutput_bytes * g_num_bits_per_byte) <<
223     " bits), # input items = " << t_ninput_items << " Symbols\n";
224   for (size_t n = 0; n < ninput_items.size(); n++) {
225     std::cout << "# input items [" << n << "] = " << ninput_items[n] << "\n";
226   }
227 #endif
228
229 // put any leftover bits into the output
230   if (d_n_saved_bits != 0) {
231 // copy the leftover from the save buffer
232 // check to make sure it will all fit
233     size_t t_noutput_bits = t_noutput_bytes * g_num_bits_per_byte;
234     size_t t_n_copy;
235     if (t_noutput_bits < d_n_saved_bits) {
236 // asking for fewer bits than available; set to copy
237 // just what's being asked for
238       t_n_copy = t_noutput_bytes;
239     } else {
240 // asking for at least as many bits as available; set to copy all
241       t_out_buf_ndx = d_n_saved_bits / g_num_bits_per_byte;
242       t_out_bit_shift = d_n_saved_bits % g_num_bits_per_byte;
243       t_n_copy = t_out_buf_ndx + (t_out_bit_shift != 0 ? 1 : 0);
244     }
245 // do the copy for all output streams (code inputs)
246 // copy starting at save buffer index "start"
247     for (size_t n = 0; n < d_n_code_inputs; n++)
248       bcopy (&(d_save_buffer[n][d_n_saved_bits_start_ndx]),
249              out_buf[n], t_n_copy);
250 #if DO_PRINT_DEBUG_INST
251     std::cout << "Copied " << t_n_copy << " Byte" <<
252       (t_n_copy != 1 ? "s" : "") << ": s_b[][" <<
253       d_n_saved_bits_start_ndx << "] => o_b[][0]\n" <<
254       "# saved bits = " << d_n_saved_bits <<
255       ", o_b_ndx = " << t_out_buf_ndx <<
256       ", bit shift = " << t_out_bit_shift << "\n";
257 #endif
258 //  update the number of saved bits and start
259     if (t_noutput_bits < d_n_saved_bits) {
260 // asking for fewer bit than available: update
261 // the number of saved bits and their starting index
262       d_n_saved_bits_start_ndx += t_noutput_bytes;
263       d_n_saved_bits -= (t_noutput_bytes * g_num_bits_per_byte);
264 #if DO_PRINT_DEBUG_INST
265       std::cout << "Updated # saved bits = " << d_n_saved_bits <<
266         ", index = " << d_n_saved_bits_start_ndx << "\n";
267 #endif
268 // nothing to consume; return the desired number of output items
269       return (noutput_items);
270     } else {
271       d_n_saved_bits_start_ndx = d_n_saved_bits = 0;
272     }
273   }
274 #if DO_PRINT_DEBUG_INST
275   std::cout << "Starting FSM in state: " <<
276     (d_fsm_state == fsm_dec_viterbi_init ? "init" :
277      (d_fsm_state == fsm_dec_viterbi_doing_up ? "up" :
278       (d_fsm_state == fsm_dec_viterbi_doing_middle ? "middle" :
279        (d_fsm_state == fsm_dec_viterbi_doing_term ? "term" :
280         (d_fsm_state == fsm_dec_viterbi_output ? "output" : "unknown"))))) << "\n";
281 #endif
282
283 // while there are input items to create
284   while (t_out_buf_ndx < t_noutput_bytes) {
285 #if DO_PRINT_DEBUG_FMS
286     std::cout << "Starting 'while': processing " << t_in_buf_ndx << " of " <<
287       t_ninput_items << " items.\nJumping to state '" <<
288       (d_fsm_state == fsm_dec_viterbi_init ? "init" :
289        (d_fsm_state == fsm_dec_viterbi_doing_up ? "up" :
290         (d_fsm_state == fsm_dec_viterbi_doing_middle ? "middle" :
291          (d_fsm_state == fsm_dec_viterbi_doing_term ? "term" :
292           (d_fsm_state == fsm_dec_viterbi_output ? "output" : "unknown"))))) << "'\n";
293 #endif
294 // jump to the correct state in the fsm
295     switch (d_fsm_state) {
296     case fsm_dec_viterbi_doing_up:
297 #if 0
298       encode_loop_up ();
299 #endif
300       break;
301     case (fsm_dec_viterbi_doing_middle):
302 #if DO_PRINT_DEBUG_FSM
303       std::cout << "Entered fsm_dec_viterbi_doing_middle\n";
304 #endif
305 // stay in this state until the correct number of input symbols is
306 // reached (if doing block coding), or until there are no more input
307 // symbols to parse
308       while (((d_block_size_bits != 0) &
309               (d_time_count < d_block_size_bits) &
310               (t_in_buf_ndx < t_ninput_items)) |
311              ((d_block_size_bits == 0) &
312               (t_in_buf_ndx < t_ninput_items))) {
313 // use all states, loop over all inputs, compute the metric for
314 // each; compare the current metric with all previous stored metric in the
315 // endpoint of the connection to find the highest one.
316
317 // reset the "to" state's metrics
318         reset_metrics (d_states_ndx ^ 1);
319 // get the state's index for each set of new inputs
320         state_t_ptr t_state = d_states[d_states_ndx];
321 #if DO_PRINT_DEBUG_MIDDLE
322         std::cout << "Time Count " << (d_time_count+1) << " of " <<
323           d_block_size_bits << "\n" <<
324           "d_states_ndx = " << d_states_ndx << "\n";
325 #endif
326 // loop over all current states
327         for (size_t n = 0; n < d_n_states; n++, t_state++) {
328 // loop over all possible input values, 1 bit per input stream
329           connection_t_ptr t_connection = t_state->d_connections;
330 #if DO_PRINT_DEBUG_MIDDLE_0
331           std::cout << "Looping over all 'middle' states: " <<
332             n << " of " << d_n_states << "\n";
333 #endif
334           for (size_t q = 0; q < d_n_input_combinations; q++, t_connection++) {
335 #if DO_PRINT_DEBUG_MIDDLE_0
336             std::cout << "Input = " << n2bs(q, d_n_code_inputs+1) << "\n";
337 #endif
338 // start with this state's metric
339             float t_metric = t_state->d_max_metric;
340 // get the "to" state
341             state_t_ptr t_to_state = t_connection->d_to;
342 // get that state's metric
343             float t_to_metric = t_to_state->d_max_metric;
344 // see if the computation is even needed;
345 // maximum change is d_n_code_outputs if all bits match exactly
346             if ((t_to_metric - t_metric) > ((float) 2*d_n_code_outputs)) {
347 #if DO_PRINT_DEBUG_MIDDLE_0
348               std::cout << "!not computing metric!\n";
349 #endif
350               continue;
351             }
352 // metrics are close enough; do the computation and the compare
353 // get the output bits for this connection
354             float* t_output_bit = t_connection->d_output_bits;
355             if (d_do_mux_inputs == true) {
356 // if using mux'ed input streams, handle differently
357               const float* t_in_buf = &(in_buf[0][t_in_buf_ndx]);
358 // loop over all encoder-output values
359               for (size_t r = d_n_code_outputs; r > 0; r--) {
360 #if DO_PRINT_DEBUG_MIDDLE_0
361                 std::cout << "in_sym = " << *t_in_buf << ", code_out_bit = " <<
362                   *t_output_bit << " ==> metric -> ";
363 #endif
364                 t_metric += ((*t_in_buf++) * (*t_output_bit++));
365 #if DO_PRINT_DEBUG_MIDDLE_0
366                 std::cout << t_metric << "\n";
367 #endif
368               }
369             } else {
370 // loop over all encoder-output values
371               for (size_t r = 0; r < d_n_code_outputs; r++) {
372 #if DO_PRINT_DEBUG_MIDDLE_0
373                 std::cout << "in_sym = " << in_buf[r][t_in_buf_ndx] <<
374                   ", code_out_bit = " << *t_output_bit << " ==> metric -> ";
375 #endif
376                 t_metric += (in_buf[r][t_in_buf_ndx] * (*t_output_bit++));
377 #if DO_PRINT_DEBUG_MIDDLE_0
378                 std::cout << t_metric << "\n";
379 #endif
380               }
381             }
382 // done with this input value; compare old and new metrics
383             if (t_metric > t_to_metric) {
384 #if DO_PRINT_DEBUG_MIDDLE
385               std::cout << "New Metric to s[" <<
386                 n2bs (t_connection->d_to_ndx,t_state_print_bits) << "]: ";
387               if (t_to_state->d_max_metric == -1e10) {
388                 std::cout << "setting to ";
389               } else {
390                 std::cout << "was s[" <<
391                   n2bs(t_to_state->d_max_state_ndx,t_state_print_bits) <<
392                   "]i[" << n2bs (t_to_state->d_max_input, d_n_code_inputs+1) <<
393                   "]@ " << t_to_state->d_max_metric << "  now ";
394               }
395               std::cout << "s[" << n2bs(n,t_state_print_bits) << "] i[" <<
396                 n2bs (q, d_n_code_inputs+1) << "]@ " << t_metric << "\n";
397 #endif
398 // new metric is better; copy that info into the "to" state
399               t_to_state->d_max_metric = t_metric;
400               t_to_state->d_max_state_ndx = n;
401               t_to_state->d_max_input = q;
402             }
403 // finished (for) this input value
404           }
405 // finished (for) this state
406         }
407 // done with all states and all inputs; now update the traceback structure
408 // change which d_states' index to use as starting
409         d_states_ndx ^= 1;
410 // get the state's index for the "to" set of new inputs to get the
411 // "max" stuff from
412         t_state = d_states[d_states_ndx];
413 // update the traceback structure
414 // loop over all current states
415         traceback_t_ptr t_prev_out_bufs = d_out_buf[d_time_count];
416         traceback_t_ptr t_out_bufs = d_out_buf[d_time_count+1];
417 #if DO_PRINT_DEBUG_MIDDLE_1
418         std::cout << "d_o_b[" << d_time_count+1 << "] => d_o_b prev\n";
419 #endif
420         for (size_t n = d_n_states; n > 0; n--, t_state++) {
421 // simple: get the current state & output state
422 // and connect output to the current, set inputs on output
423           traceback_t_ptr t_out_buf = t_out_bufs++;
424           traceback_t_ptr t_prev_out_buf =
425             &(t_prev_out_bufs[t_state->d_max_state_ndx]);
426 #if DO_PRINT_DEBUG_MIDDLE_1
427           std::cout << "s[" << n2bs(d_n_states-n,t_state_print_bits) <<
428             "]: max_ndx = " <<
429             n2bs(t_state->d_max_state_ndx,t_state_print_bits) <<
430             ", input = " << n2bs(t_state->d_max_input, d_n_code_inputs+1) <<
431             ": " << t_out_buf << " => " << t_prev_out_buf << "\n";
432 #endif
433           t_out_buf->d_prev = t_prev_out_buf;
434           t_out_buf->d_inputs = t_state->d_max_input;
435 // finished doing this state
436         }
437 // increment the in_buf index, depending on mux'ing or not
438         t_in_buf_ndx += (d_do_mux_inputs == false) ? 1 : d_n_code_outputs;
439 // increment the time counter
440         d_time_count++;
441 // finished (while) staying in this fsm state or not
442       }
443       if ((d_block_size_bits != 0) &
444           (d_time_count == d_block_size_bits)) {
445 #if DO_PRINT_DEBUG_FSM
446         std::cout << "Setting FSM to fsm_dec_viterbi_doing_term\n";
447 #endif
448         d_fsm_state = fsm_dec_viterbi_doing_term;
449       }
450       break;
451 #if DO_PRINT_DEBUG_FSM
452       std::cout << "Exited fsm_dec_viterbi_doing_middle\n";
453 #endif
454     case (fsm_dec_viterbi_doing_term):
455 #if DO_PRINT_DEBUG_FSM
456       std::cout << "Entered fsm_dec_viterbi_doing_term\n";
457 #endif
458 // set the "next" up_down index to the end of their states
459       size_t t_time_count = d_total_n_delays - (d_time_count - d_block_size_bits);
460       t_n_up_down_ndx = 1 << (d_n_code_inputs * t_time_count);
461 // stay in this state until the correct number of input symbols are
462 // reached; exit also if we run out of input symbols to process
463       while ((t_time_count > 0) &
464              (t_in_buf_ndx < t_ninput_items)) {
465 #if DO_PRINT_DEBUG_TERM
466         std::cout << "Doing time " << (d_total_n_delays - t_time_count + 1) <<
467           " of " << d_total_n_delays << "; starting buf[" << t_in_buf_ndx <<
468           "] of [" << t_ninput_items << "]\n";
469 #endif
470 // use the "to" states,
471 // FIXME: loop over just the "0" inputs
472 // and compute the metric for
473 // each, compare & store it in the "to" state at the end of the connection.
474
475 // reset the "to" state's metrics
476         reset_metrics (d_states_ndx ^ 1);
477 // reset the state's index for each set of new inputs
478         size_t* t_state_ndx_ptr = d_up_term_states_ndx[d_up_term_ndx];
479         size_t* t_next_state_ndx_ptr = d_up_term_states_ndx[d_up_term_ndx ^ 1];
480 // loop over all current stored "term" state indeces
481         for (size_t n = 0; n < t_n_up_down_ndx; n++) {
482           size_t t_state_ndx = *t_state_ndx_ptr++;
483           state_t_ptr t_state = &(d_states[d_states_ndx][t_state_ndx]);
484 // loop over just the all 0 input value (d_connections[0])
485           connection_t_ptr t_connection = t_state->d_connections;
486 // get the "to" state
487           state_t_ptr t_to_state = t_connection->d_to;
488 // start with this state's metric
489           float t_metric = t_state->d_max_metric;
490 // get that state's metric
491           float t_to_metric = t_to_state->d_max_metric;
492 #if DO_PRINT_DEBUG_TERM
493           std::cout << "Term state " << (n+1) << " of " << t_n_up_down_ndx <<
494             "; using d_s[" << d_states_ndx << "][" <<
495             n2bs(t_state_ndx,t_state_print_bits) << "]\n";
496 #endif
497 // see if the computation is even needed;
498 // maximum change is d_n_code_outputs if all bits match exactly
499           if ((t_to_metric - t_metric) > ((float) 2*d_n_code_outputs)) {
500 #if DO_PRINT_DEBUG_TERM
501             std::cout << "!not computing metric!\n";
502 #endif
503             continue;
504           }
505 // metrics are close enough; do the computation and the compare
506 // get the output bits for this connection
507           float* t_output_bit = t_connection->d_output_bits;
508           if (d_do_mux_inputs == true) {
509 // if using mux'ed input streams, handle differently
510             const float* t_in_buf = &(in_buf[0][t_in_buf_ndx]);
511 // loop over all encoder-output values
512             for (size_t r = d_n_code_outputs; r > 0; r--) {
513               t_metric += ((*t_in_buf++) * (*t_output_bit++));
514             }
515           } else {
516 // loop over all encoder-output values
517             for (size_t r = 0; r < d_n_code_outputs; r++) {
518               t_metric += (in_buf[r][t_in_buf_ndx] * (*t_output_bit++));
519             }
520           }
521 // done with this input value; compare old and new metrics
522 // see if it's the best metric
523           if (t_metric > t_to_metric) {
524 #if DO_PRINT_DEBUG_TERM
525             std::cout << "New Metric to s[" <<
526               n2bs (t_connection->d_to_ndx,t_state_print_bits) << "]: ";
527             if (t_to_state->d_max_metric == -1e10) {
528               std::cout << "setting to ";
529             } else {
530               std::cout << "was s[" <<
531                 n2bs(t_to_state->d_max_state_ndx,t_state_print_bits) <<
532                 "]i[" << n2bs (t_to_state->d_max_input, d_n_code_inputs+1) <<
533                 "]@ " << t_to_state->d_max_metric << "  now ";
534             }
535             std::cout << "s[" << n2bs(t_state_ndx,t_state_print_bits) <<
536               "] i[" << n2bs (0, d_n_code_inputs+1) << "]@ " << t_metric << "\n";
537 #endif
538             t_to_state->d_max_metric = t_metric;
539             t_to_state->d_max_state_ndx = t_state_ndx;
540             t_to_state->d_max_input = 0;
541           }
542 // add the "to" state's index to the "next" set of state's indices list
543           *t_next_state_ndx_ptr++ = t_connection->d_to_ndx;
544 // finished (for) this state
545         }
546 // done with all states and all inputs; now update the traceback structure
547 // change which d_states' index to use as starting
548         d_states_ndx ^= 1;
549 // update the number of "up_term" states
550         d_up_term_ndx ^= 1;
551 // reduce the number of using states
552         t_n_up_down_ndx >>= d_n_code_inputs;
553 // reset the state's index for each set of new inputs
554         t_state_ndx_ptr = d_up_term_states_ndx[d_up_term_ndx];
555 // update the traceback structure
556 // loop over all current states
557         traceback_t_ptr t_prev_out_bufs = d_out_buf[d_time_count];
558         traceback_t_ptr t_out_bufs = d_out_buf[d_time_count+1];
559 #if DO_PRINT_DEBUG_TERM_1
560         std::cout << "d_o_b[" << d_time_count+1 << "] => d_o_b prev\n";
561 #endif
562 // loop over all current stored "term" state indices
563         for (size_t n = 0; n < t_n_up_down_ndx; n++) {
564 // get the start index and then pointer to each of the "to" states,
565 // which hold the newest "max" stuff
566           size_t t_state_ndx = *t_state_ndx_ptr++;
567           state_t_ptr t_state = &(d_states[d_states_ndx][t_state_ndx]);
568 // simple: get the current state & output state
569 // and connect output to the current, set inputs on output
570           traceback_t_ptr t_out_buf = &(t_out_bufs[t_state_ndx]);
571           traceback_t_ptr t_prev_out_buf =
572             &(t_prev_out_bufs[t_state->d_max_state_ndx]);
573 #if DO_PRINT_DEBUG_TERM_1
574           std::cout << "ndx[" << n << "] == " << t_state_ndx <<
575             ", s[" << n2bs(t_state_ndx,t_state_print_bits) <<
576             "]: max_ndx = " <<
577             n2bs(t_state->d_max_state_ndx,t_state_print_bits) <<
578             ", input = " << n2bs(t_state->d_max_input, d_n_code_inputs+1) <<
579             ": " << t_out_buf << " => " << t_prev_out_buf << "\n";
580 #endif
581           t_out_buf->d_prev = t_prev_out_buf;
582           t_out_buf->d_inputs = t_state->d_max_input;
583 // finished (for) this state
584         }
585 // increment the in_buf index, depending on mux'ing or not
586         t_in_buf_ndx += (d_do_mux_inputs == false) ? 1 : d_n_code_outputs;
587 // increment the time counters
588         t_time_count--;
589         d_time_count++;
590 // finished (while) staying in this fsm state or not
591       }
592       if (t_time_count == 0) {
593 // finished this trellis, now move as much of the decoded input to the
594 // output buffer as possible
595 #if DO_PRINT_DEBUG_FSM
596         std::cout << "Setting FSM to fsm_dec_viterbi_output\n";
597 #endif
598         d_fsm_state = fsm_dec_viterbi_output;
599       }
600 #if DO_PRINT_DEBUG_FSM
601       std::cout << "Exited fsm_dec_viterbi_doing_term\n";
602 #endif
603       break;
604     case (fsm_dec_viterbi_output):
605 #if DO_PRINT_DEBUG_FSM
606       std::cout << "Entered fsm_dec_viterbi_output.\n";
607 #endif
608 // this is done in reverse bit order (last time to first time)
609 // using the traceback structure in d_out_buf, starting with
610 // the maximum valued one in the last time slot, then using
611 // the traceback's "d_prev" link to trace the trellis back
612
613 // see where the output data will terminate
614       int t_next_out_buf_ndx = (t_out_buf_ndx +
615                                 (d_block_size_bits / g_num_bits_per_byte));
616       int t_next_out_bit_shift = (t_out_bit_shift +
617                                   (d_block_size_bits % g_num_bits_per_byte));
618       if (t_next_out_bit_shift >= g_num_bits_per_byte) {
619         t_next_out_bit_shift -= g_num_bits_per_byte;
620         t_next_out_buf_ndx++;
621       }
622 #if DO_PRINT_DEBUG_OUTPUT
623       std::cout << "First bit in at out[][" << t_out_buf_ndx << "].[" <<
624         t_out_bit_shift << "] -> " << d_block_size_bits << " bits == " <<
625         (d_block_size_bits / g_num_bits_per_byte) << " Byte" <<
626         ((d_block_size_bits / g_num_bits_per_byte) != 1 ? "s" : "") <<
627         " + " << (d_block_size_bits % g_num_bits_per_byte) << " bit" <<
628         ((d_block_size_bits % g_num_bits_per_byte) != 1 ? "s" : "") <<
629         "\nNext set of bits start at out[][" << t_next_out_buf_ndx <<
630         "].[" << t_next_out_bit_shift << "]\n";
631 #endif
632 // find the starting traceback structure
633       traceback_t_ptr t_out_buf;
634       if (d_do_termination == true) {
635 // FIXME: assume termination state == 0
636 #if DO_PRINT_DEBUG_OUTPUT_0
637         std::cout << "Using termination; going through trellis for " <<
638           d_total_n_delays << " bit" <<
639           ((d_total_n_delays != 1) ? "s" : "") << "\n";
640 #endif
641         t_out_buf = &(d_out_buf[d_time_count][0]);
642 #if DO_PRINT_DEBUG_OUTPUT_0
643         std::cout << "Starting traceback ptr " << t_out_buf << "\n";
644 #endif
645 // skip over the termination bits
646         for (size_t n = d_total_n_delays; n > 0; n--) {
647           t_out_buf = t_out_buf->d_prev;
648 #if DO_PRINT_DEBUG_OUTPUT_0
649           std::cout << "Next traceback ptr " << t_out_buf << "\n";
650 #endif
651         }
652       } else {
653 // no termination but doing block coding;
654 // FIXME: use the state with the bext metric
655 // get the state's index for each set of new inputs
656         state_t_ptr t_state = d_states[d_states_ndx];
657         float t_max_metric = t_state->d_max_metric;
658         size_t t_max_state_ndx = 0;
659         t_state++;
660 // loop over all current states
661         for (size_t n = 1; n < d_n_states; n++, t_state++) {
662 // start with this state's metric
663           float t_metric = t_state->d_max_metric;
664 // compare with current max
665           if (t_metric > t_max_metric) {
666             t_max_metric = t_metric;
667             t_max_state_ndx = n;
668           }
669         }
670 // get the correct out_buf reference to start with
671         t_out_buf = &(d_out_buf[d_time_count][t_max_state_ndx]);
672       }
673 #if DO_PRINT_DEBUG_OUTPUT
674       std::cout << "Found starting traceback ptr " << t_out_buf <<
675         "; getting all " << d_block_size_bits << " bits per stream.\n";
676 #endif
677 // now we've got the starting traceback structure address;
678 // check to make sure there is enough space in each output buffer
679       size_t t_block_bit_ndx = d_block_size_bits;
680       if ((t_next_out_buf_ndx > t_noutput_bytes) |
681           ((t_next_out_buf_ndx == t_noutput_bytes) &
682            (t_next_out_bit_shift != 0))) {
683 // not enough space for all output bits;
684 // find the number of extra bits to save
685         size_t t_save_buf_ndx = t_next_out_buf_ndx - t_noutput_bytes;
686         size_t t_n_extra_bits = ((t_save_buf_ndx * g_num_bits_per_byte) +
687                                  t_next_out_bit_shift);
688 // set the number of saved bits
689         d_n_saved_bits = t_n_extra_bits;
690 // remove the extra bits from the number to copy to the output buffer
691         t_block_bit_ndx -= t_n_extra_bits;
692 // find the actual output buf index, once we get there
693         t_next_out_buf_ndx -= t_save_buf_ndx;
694 #if DO_PRINT_DEBUG_OUTPUT
695         std::cout << "Not enough output buffer space:\n" <<
696           "len (o_b) = " << t_noutput_bytes << " ==> " <<
697           t_n_extra_bits << " extra bit" <<
698           (t_n_extra_bits != 1 ? "s" : "") << " == " <<
699           t_save_buf_ndx << " Byte" <<
700           (t_save_buf_ndx != 1 ? "s" : "") << ", " <<
701           t_next_out_bit_shift << " bit" <<
702           (t_next_out_bit_shift != 1 ? "s" : "") << "\n";
703 #endif
704 // zero each output buffers' bytes
705         size_t t_n_zero = t_save_buf_ndx + (t_next_out_bit_shift ? 1 : 0);
706 #if DO_PRINT_DEBUG_OUTPUT
707         size_t t_n_out_bytes = ((d_block_size_bits / g_num_bits_per_byte) +
708                                 ((d_block_size_bits % g_num_bits_per_byte) ? 1 : 0));
709         std::cout << "Zeroing save buffer from for " << t_n_zero <<
710           " Byte" << (t_n_zero != 1 ? "s" : "") << " (of " <<
711           d_block_size_bits << " bit" <<
712           (d_block_size_bits != 1 ? "s" : "") << " == " << t_n_out_bytes <<
713           " Byte" << (t_n_out_bytes != 1 ? "s" : "") << ")\n";
714 #endif
715         for (size_t m = 0; m < d_n_code_inputs; m++)
716           bzero (d_save_buffer[m], t_n_zero);
717 // loop over all extra bits
718         for (size_t n = t_n_extra_bits; n > 0; n--) {
719 // first decrement the output bit & byte as necessary
720           if (--t_next_out_bit_shift < 0) {
721             t_next_out_bit_shift += g_num_bits_per_byte;
722             t_save_buf_ndx--;
723           }
724 // get the encoder inputs to output
725           size_t t_inputs = t_out_buf->d_inputs;
726 // loop over all code inputs (decoder-outputs), 1 bit per stream
727           for (size_t m = 0; m < d_n_code_inputs; m++) {
728             d_save_buffer[m][t_save_buf_ndx] |=
729               ((t_inputs & 1) << t_next_out_bit_shift);
730             t_inputs >>= 1;
731           }
732           t_out_buf = t_out_buf->d_prev;
733 #if DO_PRINT_DEBUG_OUTPUT_0
734           std::cout << "Next traceback ptr " << t_out_buf << "\n";
735 #endif
736         }
737 // at exit, "t_out_buf_ndx" should be == t_noutput_bytes, and
738 // "t_out_bit_shift" should be 0; check these!
739 #if DO_PRINT_DEBUG_OUTPUT
740         std::cout << "n_o_b_ndx (" << t_next_out_buf_ndx << ") ?=? " <<
741           "#o_B (" << t_noutput_bytes << ") & t_o_b_sh (" <<
742           t_next_out_bit_shift << ") ?=? 0\n";
743         assert (t_next_out_buf_ndx == t_noutput_bytes);
744         assert (t_next_out_bit_shift == 0);
745 #endif
746       }
747 // set the correct output buffer index and bit shift
748       t_out_bit_shift = t_next_out_bit_shift;
749       t_out_buf_ndx = t_next_out_buf_ndx;
750 // copy any remaining bits looping backwards in bit-time
751 // through the traceback trellis
752       for (size_t n = t_block_bit_ndx; n > 0; n--) {
753 // first decrement the output bit & byte as necessary
754         if (--t_out_bit_shift < 0) {
755           t_out_bit_shift += g_num_bits_per_byte;
756           t_out_buf_ndx--;
757         }
758 // get the encoder inputs to output
759         size_t t_inputs = t_out_buf->d_inputs;
760 // loop over all code inputs (decoder-outputs), 1 bit per stream
761         for (size_t m = 0; m < d_n_code_inputs; m++) {
762           out_buf[m][t_out_buf_ndx] |= ((t_inputs & 1) << t_out_bit_shift);
763           t_inputs >>= 1;
764         }
765         t_out_buf = t_out_buf->d_prev;
766 #if DO_PRINT_DEBUG_OUTPUT_0
767         std::cout << "Next traceback ptr " << t_out_buf << "\n";
768 #endif
769       }
770 // set the next output byte and bit-shift
771       t_out_bit_shift = t_next_out_bit_shift;
772       t_out_buf_ndx = t_next_out_buf_ndx;
773 #if DO_PRINT_DEBUG_FSM
774       std::cout << "Set FSM to fsm_dec_viterbi_init\n";
775 #endif
776       d_fsm_state = fsm_dec_viterbi_init;
777 #if DO_PRINT_DEBUG_FSM
778       std::cout << "Exited fsm_dec_viterbi_output\n";
779 #endif
780       break;
781     case (fsm_dec_viterbi_init):
782 #if DO_PRINT_DEBUG_FSM
783       std::cout << "Entered fsm_dec_viterbi_init\n";
784 #endif
785 // this is called immediately (first input bit upon startup),
786 // or after termination of a trellis.
787
788 // reset states to the 0'th one
789       d_up_term_ndx = d_states_ndx = 0;
790 // zero the metrics for those states
791       zero_metrics (0);
792 #if 0
793 // might not need to do this; check and see after it works
794 // reset up_term states and number so that there is 1 item, the "0" state.
795       bzero (d_up_term_states_ndx[0], sizeof (size_t) * d_n_states);
796       bzero (d_up_term_states_ndx[1], sizeof (size_t) * d_n_states);
797 #else
798       d_up_term_states_ndx[0][0] = 0;
799 #endif
800 // reset time count back to the start
801       d_time_count = 0;
802 #if 0
803 // reset the traceback structures
804 // might not need to do this; check and see after it works
805       traceback_t_hdl t_out_bufs = d_out_buf;
806       for (size_t n = d_n_traceback_els; n > 0; n--) {
807         traceback_t_ptr t_out_buf = (*t_out_bufs++);
808         for (size_t m = d_n_states; m > 0; m--, t_out_buf++) {
809           t_out_buf->d_prev = NULL;
810           t_out_buf->d_inputs = -1;
811         }
812       }
813 #endif
814 // set the fsm to "doing up"
815 #if DO_PRINT_DEBUG_FSM
816       std::cout << "Set FSM to fsm_dec_viterbi_doing_up\n";
817 #endif
818       d_fsm_state = fsm_dec_viterbi_doing_up;
819 #if DO_PRINT_DEBUG_FSM
820       std::cout << "Exited fsm_dec_viterbi_init\n";
821 #endif
822       break;
823 // should never get here!
824     default:
825       assert (0);
826 // done (switch) with FSM
827     }
828 // done (while) there are inputs
829   }
830
831 // consume all of the input items on all input streams
832 // "ninput_items[]" doesn't seem to be reliable,
833 // so compute this from the actual number of blocks processed
834 #if DO_PRINT_DEBUG_EXIT
835   std::cout << "Exiting FSM in state: " <<
836     (d_fsm_state == fsm_dec_viterbi_init ? "init" :
837      (d_fsm_state == fsm_dec_viterbi_doing_up ? "up" :
838       (d_fsm_state == fsm_dec_viterbi_doing_middle ? "middle" :
839        (d_fsm_state == fsm_dec_viterbi_doing_term ? "term" :
840         (d_fsm_state == fsm_dec_viterbi_output ? "output" : "unknown"))))) << "\n" <<
841     "Consuming " << t_in_buf_ndx <<
842     " input items on each input stream (of " << t_ninput_items << ").\n";
843 #endif
844   consume_each (t_in_buf_ndx);
845
846 // make sure the number of output items makes sense
847 // t_out_buf_ndx always points to the current index
848 // t_out_bit_shift always points to the next bit position to be written
849   int t_leftover_bytes = t_out_buf_ndx % d_out_stream_el_size_bytes;
850   int t_leftover_bits = ((t_leftover_bytes * g_num_bits_per_byte) +
851                          t_out_bit_shift);
852   int t_noutput_items = noutput_items;
853 #if DO_PRINT_DEBUG_EXIT
854   std::cout << "Final o_b[" << t_out_buf_ndx << "][" <<
855     t_out_bit_shift << "] of " << t_noutput_bytes <<
856     ", el_size = " << d_out_stream_el_size_bytes <<
857     ", lo_Bytes = " << t_leftover_bytes <<
858     ", t_lo_bits = " << t_leftover_bits << "\n" <<
859     "Desired # output items = " << noutput_items << "\n";
860 #endif
861   if (t_leftover_bits != 0) {
862     // should never get here!
863 #if 1
864     assert (0);
865 #else
866     int t_ndx = t_out_buf_ndx - t_leftover_bytes;
867     size_t t_n_copy = t_leftover_bytes + ((t_out_bit_shift != 0) ? 1 : 0);
868     assert (t_n_copy <= d_out_stream_el_size_bytes);
869 // copy the leftover into the save buffer
870     for (size_t n = 0; n < d_n_code_inputs; n++) {
871       bcopy (&(out_buf[n][t_ndx]), d_save_buffer[n], t_n_copy);
872     }
873     t_noutput_items = t_ndx / d_out_stream_el_size_bytes;
874     d_n_saved_bits = t_leftover_bits;
875 #if DO_PRINT_DEBUG_EXIT
876     std::cout << "Copied " << t_n_copy << " Byte" <<
877       (t_n_copy != 1 ? "s" : "") << " from o_b[][" << t_ndx <<
878       "] into each save buffer.\n" <<
879       "Actual #output items = " << t_noutput_items <<
880       ", # saved bit(s) = " << d_n_saved_bits << "\n";
881 #endif
882 #endif
883   }
884
885 #endif
886
887 #if DO_TIME_THOUGHPUT
888   u_long d_t = end_timer (&t_tp);
889
890   std::cout << "dec_blk_conv_soft_full: Completed " << t_ninput_items <<
891     " bits in " << d_t << " usec => " <<
892     1e6*(((double)(t_ninput_items))/((double) d_t)) <<
893     " b/s\n";
894 #endif
895 }
896
897 #if 0
898
899 void
900 decoder_viterbi::encode_loop_up ()
901 {
902 #if DO_PRINT_DEBUG_FSM
903   std::cout << "Starting fsm_dec_viterbi_doing_up\n";
904 #endif
905
906   // set the number of up_down indices
907
908   size_t t_n_up_down_ndx = 1 << (d_n_code_inputs *
909                                  d_time_count);
910
911 // stay in this state until the correct number of input symbols are
912 // reached; exit also if we run out of input symbols to process
913       while ((d_time_count < d_total_n_delays) &
914              (t_in_buf_ndx < t_ninput_items)) {
915 #if DO_PRINT_DEBUG_UP_0
916         std::cout << "Doing 'while' loop:\n" <<
917           "t_n_up_down_ndx    = " << t_n_up_down_ndx << "\n" <<
918           "d_time_count       = " << d_time_count << "\n" <<
919           "d_total_n_delays   = " << d_total_n_delays << "\n" <<
920           "t_in_buf_ndx       = " << t_in_buf_ndx << "\n" <<
921           "t_ninput_items     = " << t_ninput_items << "\n";
922 #endif
923 // use the "from" states, loop over all inputs and compute the metric for
924 // each & store it in the "to" state at the end of the connection.
925 // no need to compare metrics yet, since none join into any given state
926
927 #if 0
928 // reset the "to" state's metrics
929 // probably don't need to do this; try removing later
930         reset_metrics (d_states_ndx ^ 1);
931 #if DO_PRINT_DEBUG_UP
932         std::cout << "Reset Metrics\n";
933 #endif
934 #endif
935
936 // reset the state's index for each set of new inputs
937         size_t* t_state_ndx_ptr = d_up_term_states_ndx[d_up_term_ndx];
938         size_t* t_next_state_ndx_ptr = d_up_term_states_ndx[d_up_term_ndx ^ 1];
939 // loop over all current stored "up" states
940         for (size_t n = 0; n < t_n_up_down_ndx; n++) {
941           size_t t_state_ndx = *t_state_ndx_ptr++;
942 // get a pointer to this state's structure
943           state_t_ptr t_state = &(d_states[d_states_ndx][t_state_ndx]);
944 // get the connections for all inputs
945           connection_t_ptr t_connection = t_state->d_connections;
946 #if DO_PRINT_DEBUG_UP_0
947           std::cout << "Looping over all 'up' states:\n" <<
948             "n                  = " << n << "\n" <<
949             "t_n_up_down_ndx    = " << t_n_up_down_ndx << "\n" <<
950             "d_states_ndx       = " << d_states_ndx << "\n" <<
951             "t_state_ndx        = " << t_state_ndx << "\n" <<
952             "d_n_input_combs    = " << d_n_input_combinations << "\n" <<
953             "t_state            = " << t_state << "\n" <<
954             "t_connection       = " << t_connection << "\n";
955 #endif
956 // loop over all possible input values, 1 bit per input stream
957           for (size_t q = 0; q < d_n_input_combinations; q++, t_connection++) {
958 // find the "to" state for this connection
959             state_t_ptr t_to_state = t_connection->d_to;
960 // get the output bits for this connection
961             float* t_output_bit = t_connection->d_output_bits;
962 // start with this state's metric
963             float t_metric = t_state->d_max_metric;
964 #if DO_PRINT_DEBUG_UP_0
965             std::cout <<
966               "to state index     = " << t_connection->d_to_ndx << "\n" <<
967               "current metric     = " << t_metric << "\n";
968 #endif
969             if (d_do_mux_inputs == true) {
970 // if using mux'ed input streams, handle differently
971               const float* t_in_buf = &(in_buf[0][t_in_buf_ndx]);
972 // loop over all encoder-output values
973               for (size_t r = d_n_code_outputs; r > 0; r--) {
974 #if DO_PRINT_DEBUG_UP
975                 std::cout << "in_sym = " << *t_in_buf << ", code_out_bit = " <<
976                   *t_output_bit << " ==> metric -> ";
977 #endif
978                 t_metric += ((*t_in_buf++) * (*t_output_bit++));
979 #if DO_PRINT_DEBUG_UP
980                 std::cout << t_metric << "\n";
981 #endif
982               }
983             } else {
984 // loop over all encoder-output values
985               for (size_t r = 0; r < d_n_code_outputs; r++) {
986 #if DO_PRINT_DEBUG_UP
987                 std::cout << "in_sym = " << in_buf[r][t_in_buf_ndx] <<
988                   ", code_out_bit = " << *t_output_bit << " ==> metric -> ";
989 #endif
990                 t_metric += (in_buf[r][t_in_buf_ndx] * (*t_output_bit++));
991 #if DO_PRINT_DEBUG_UP
992                 std::cout << t_metric << "\n";
993 #endif
994               }
995             }
996 // get the "to" state index
997             size_t t_to_ndx = t_connection->d_to_ndx;
998 // store the metric in the "to" state; should not have been used before
999             t_to_state->d_max_metric = t_metric;
1000 // add the "to" state index to the "up" state list
1001             *t_next_state_ndx_ptr++ = t_to_ndx;
1002 // update the traceback structure, depending on which variety it is
1003 // doing full trellis before decoding; use d_out_buf
1004 // simple: get the current state & output state
1005             traceback_t_ptr t_out_buf = &(d_out_buf[d_time_count]
1006                                           [t_state_ndx]);
1007             traceback_t_ptr t_next_out_buf = &(d_out_buf[d_time_count+1]
1008                                                [t_to_ndx]);
1009 #if DO_PRINT_DEBUG_UP_1
1010             std::cout << "d_o_b[" << d_time_count+1 << "] => d_o_b prev\n" <<
1011               "ndx[" << n << "] == " << t_state_ndx <<
1012               ", s[" << n2bs(t_state_ndx,t_state_print_bits) <<
1013               "]: max_ndx = " <<
1014               n2bs(t_state->d_max_state_ndx,t_state_print_bits) <<
1015               ", input = " << n2bs(q, d_n_code_inputs+1) <<
1016               ": " << t_next_out_buf << " => " << t_out_buf << "\n";
1017 #endif
1018 // and connect output to the current, set inputs on output
1019             t_next_out_buf->d_prev = t_out_buf;
1020             t_next_out_buf->d_inputs = q;
1021 // finished (for) this input value
1022           }
1023 // finished (for) this "up_term" state
1024         }
1025 // increment the in_buf index, depending on mux'ing or not
1026         t_in_buf_ndx += (d_do_mux_inputs == false) ? 1 : d_n_code_outputs;
1027 // increment the time counter
1028         d_time_count++;
1029 // update the number of "up_term" states
1030         d_up_term_ndx ^= 1;
1031 // increase the number of using states
1032         t_n_up_down_ndx <<= d_n_code_inputs;
1033 // change which d_states' index to use as starting
1034         d_states_ndx ^= 1;
1035 // finished (while) staying in this fsm state or not
1036       }
1037 // if reached the end of doing the "up" part of the trellis,
1038 // switch states into the middle
1039       if (d_time_count == d_total_n_delays) {
1040 #if DO_PRINT_DEBUG_FSM
1041         std::cout << "Setting FSM to fsm_dec_viterbi_doing_middle\n";
1042 #endif
1043         d_fsm_state = fsm_dec_viterbi_doing_middle;
1044       }
1045 #if DO_PRINT_DEBUG_FSM
1046       std::cout << "Exited fsm_dec_viterbi_doing_up\n";
1047 #endif
1048 }
1049 #endif