3 * Copyright 2006 Free Software Foundation, Inc.
5 * This file is part of GNU Radio
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)
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.
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.
27 #include <decoder_viterbi.h>
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;
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
55 #include <mld/mld_timer.h>
58 decoder_viterbi::decoder_viterbi
59 (int sample_precision,
60 const encoder_convolutional* l_encoder)
62 // make sure that the encoder is "valid"
65 std::cerr << "decoder_viterbi: Error: Encoder is NULL.\n";
69 // make the metrics converter
71 // d_code_metrics = new code_metrics (
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";
82 d_encoder = (encoder_convolutional*) l_encoder;
83 d_trellis = (code_convolutional_trellis*) d_encoder->trellis ();
85 // fill the class variables
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 ();
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.
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";
112 // always start the fsm in the "init" state
114 d_fsm_state = fsm_dec_viterbi_init;
116 // create a vector of indexes to states when doing "up" or "termination";
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];
121 // get the total number of out bits per stream
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;
128 decoder_viterbi::~decoder_viterbi
131 // reverse over from allocation
133 delete [] d_up_term_states_ndx[0];
134 delete [] d_up_term_states_ndx[1];
136 // delete the state's structures
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;
144 delete [] t_state->d_connections;
146 delete [] d_states[0];
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;
154 delete [] t_state->d_connections;
156 delete [] d_states[1];
158 // delete the save buffer
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++);
164 delete [] d_save_buffer;
169 decoder_viterbi::reset_metrics
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;
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;
184 decoder_viterbi::zero_metrics
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;
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;
199 decoder_viterbi::decode_private
204 #if DO_TIME_THOUGHPUT
209 size_t t_state_print_bits = d_total_n_delays;
210 size_t t_mem_print_bits = d_total_n_delays;
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;
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";
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;
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;
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);
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";
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";
268 // nothing to consume; return the desired number of output items
269 return (noutput_items);
271 d_n_saved_bits_start_ndx = d_n_saved_bits = 0;
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";
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";
294 // jump to the correct state in the fsm
295 switch (d_fsm_state) {
296 case fsm_dec_viterbi_doing_up:
301 case (fsm_dec_viterbi_doing_middle):
302 #if DO_PRINT_DEBUG_FSM
303 std::cout << "Entered fsm_dec_viterbi_doing_middle\n";
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
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.
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";
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";
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";
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";
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 -> ";
364 t_metric += ((*t_in_buf++) * (*t_output_bit++));
365 #if DO_PRINT_DEBUG_MIDDLE_0
366 std::cout << t_metric << "\n";
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 -> ";
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";
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 ";
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 ";
395 std::cout << "s[" << n2bs(n,t_state_print_bits) << "] i[" <<
396 n2bs (q, d_n_code_inputs+1) << "]@ " << t_metric << "\n";
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;
403 // finished (for) this input value
405 // finished (for) this state
407 // done with all states and all inputs; now update the traceback structure
408 // change which d_states' index to use as starting
410 // get the state's index for the "to" set of new inputs to get the
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";
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) <<
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";
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
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
441 // finished (while) staying in this fsm state or not
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";
448 d_fsm_state = fsm_dec_viterbi_doing_term;
451 #if DO_PRINT_DEBUG_FSM
452 std::cout << "Exited fsm_dec_viterbi_doing_middle\n";
454 case (fsm_dec_viterbi_doing_term):
455 #if DO_PRINT_DEBUG_FSM
456 std::cout << "Entered fsm_dec_viterbi_doing_term\n";
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";
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.
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";
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";
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++));
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++));
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 ";
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 ";
535 std::cout << "s[" << n2bs(t_state_ndx,t_state_print_bits) <<
536 "] i[" << n2bs (0, d_n_code_inputs+1) << "]@ " << t_metric << "\n";
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;
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
546 // done with all states and all inputs; now update the traceback structure
547 // change which d_states' index to use as starting
549 // update the number of "up_term" states
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";
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) <<
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";
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
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
590 // finished (while) staying in this fsm state or not
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";
598 d_fsm_state = fsm_dec_viterbi_output;
600 #if DO_PRINT_DEBUG_FSM
601 std::cout << "Exited fsm_dec_viterbi_doing_term\n";
604 case (fsm_dec_viterbi_output):
605 #if DO_PRINT_DEBUG_FSM
606 std::cout << "Entered fsm_dec_viterbi_output.\n";
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
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++;
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";
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";
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";
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";
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;
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;
670 // get the correct out_buf reference to start with
671 t_out_buf = &(d_out_buf[d_time_count][t_max_state_ndx]);
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";
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";
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";
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;
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);
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";
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);
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;
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);
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";
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";
776 d_fsm_state = fsm_dec_viterbi_init;
777 #if DO_PRINT_DEBUG_FSM
778 std::cout << "Exited fsm_dec_viterbi_output\n";
781 case (fsm_dec_viterbi_init):
782 #if DO_PRINT_DEBUG_FSM
783 std::cout << "Entered fsm_dec_viterbi_init\n";
785 // this is called immediately (first input bit upon startup),
786 // or after termination of a trellis.
788 // reset states to the 0'th one
789 d_up_term_ndx = d_states_ndx = 0;
790 // zero the metrics for those states
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);
798 d_up_term_states_ndx[0][0] = 0;
800 // reset time count back to the start
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;
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";
818 d_fsm_state = fsm_dec_viterbi_doing_up;
819 #if DO_PRINT_DEBUG_FSM
820 std::cout << "Exited fsm_dec_viterbi_init\n";
823 // should never get here!
826 // done (switch) with FSM
828 // done (while) there are inputs
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";
844 consume_each (t_in_buf_ndx);
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) +
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";
861 if (t_leftover_bits != 0) {
862 // should never get here!
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);
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";
887 #if DO_TIME_THOUGHPUT
888 u_long d_t = end_timer (&t_tp);
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)) <<
900 decoder_viterbi::encode_loop_up ()
902 #if DO_PRINT_DEBUG_FSM
903 std::cout << "Starting fsm_dec_viterbi_doing_up\n";
906 // set the number of up_down indices
908 size_t t_n_up_down_ndx = 1 << (d_n_code_inputs *
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";
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
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";
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";
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
966 "to state index = " << t_connection->d_to_ndx << "\n" <<
967 "current metric = " << t_metric << "\n";
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 -> ";
978 t_metric += ((*t_in_buf++) * (*t_output_bit++));
979 #if DO_PRINT_DEBUG_UP
980 std::cout << t_metric << "\n";
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 -> ";
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";
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]
1007 traceback_t_ptr t_next_out_buf = &(d_out_buf[d_time_count+1]
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) <<
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";
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
1023 // finished (for) this "up_term" state
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
1029 // update the number of "up_term" states
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
1035 // finished (while) staying in this fsm state or not
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";
1043 d_fsm_state = fsm_dec_viterbi_doing_middle;
1045 #if DO_PRINT_DEBUG_FSM
1046 std::cout << "Exited fsm_dec_viterbi_doing_up\n";