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