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., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
27 #include "decoder_viterbi_full_block.h"
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;
36 #define DO_TIME_THOUGHPUT 0
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
55 #include <mld/mld_timer.h>
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)
66 // verify that the block size is non-zero
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";
74 // the traceback buffers are specific to the type of decoding
75 // (full/block, partial/block, partial/stream)
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.
81 d_n_traceback_els = d_n_total_inputs_per_stream + 1;
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".
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];
99 if (DO_PRINT_DEBUG_INST) {
101 "total # in bits / stream = " << d_n_total_inputs_per_stream << "\n" <<
102 "d_n_traceback_els = " << d_n_traceback_els << "\n";
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";
118 decoder_viterbi_full_block::~decoder_viterbi_full_block
121 // delete the traceback buffers
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++);
131 decoder_viterbi_full_block::update_traceback__up
132 (size_t from_state_ndx,
138 size_t t_state_print_bits = d_total_memory + 1;
139 size_t t_mem_print_bits = d_max_memory + 2;
141 // update the traceback structure, depending on which variety it is
142 // doing full trellis before decoding; use d_out_buf
144 // get the current state & output state
146 traceback_t_ptr t_out_buf = &(d_out_buf[d_time_count]
148 traceback_t_ptr t_next_out_buf = &(d_out_buf[d_time_count+1]
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) <<
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";
160 // and connect output to the current, set inputs on output
162 t_next_out_buf->d_prev = t_out_buf;
163 t_next_out_buf->d_inputs = l_input;
168 decoder_viterbi_full_block::update_traceback__middle
174 size_t t_state_print_bits = d_total_memory + 1;
175 size_t t_mem_print_bits = d_max_memory + 2;
177 // change which d_states' index to use as starting
181 // get the state's index for the "to" set of new inputs to get the
184 state_t_ptr t_state = d_states[d_states_ndx];
186 // update the traceback structure
187 // loop over all current states
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];
192 if (DO_PRINT_DEBUG_MIDDLE_1) {
193 std::cout << "d_o_b[" << d_time_count+1 << "] => d_o_b prev\n";
196 for (size_t n = d_n_states; n > 0; n--, t_state++) {
198 // simple: get the current state & output state
199 // and connect output to the current, set inputs on output
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]);
205 if (DO_PRINT_DEBUG_MIDDLE_1) {
206 std::cout << "s[" << n2bs(d_n_states-n,t_state_print_bits) <<
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";
213 t_out_buf->d_prev = t_prev_out_buf;
214 t_out_buf->d_inputs = t_state->d_max_input;
221 decoder_viterbi_full_block::update_traceback__term
227 size_t t_state_print_bits = d_total_memory + 1;
228 size_t t_mem_print_bits = d_max_memory + 2;
230 // done with all states and all inputs; now update the traceback structure
231 // change which d_states' index to use as starting
233 // update the number of "up_term" states
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";
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) <<
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";
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
274 decoder_viterbi_full_block::decode_private
275 (const char** in_buf,
280 #if DO_TIME_THOUGHPUT
285 size_t t_state_print_bits = d_total_memory + 1;
286 size_t t_mem_print_bits = d_max_memory + 2;
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;
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";
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;
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;
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);
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";
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";
342 // nothing to consume; return the desired number of output items
343 return (noutput_items);
345 d_n_saved_bits_start_ndx = d_n_saved_bits = 0;
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";
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";
368 // jump to the correct state in the fsm
370 case fsm_dec_doing_up:
371 #if DO_PRINT_DEBUG_FSM
372 std::cout << "Starting fsm_dec_doing_up\n";
374 // set the number of up_down indices
375 size_t t_n_up_down_ndx = 1 << (d_n_code_inputs *
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";
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
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";
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";
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
432 "to state index = " << t_connection->d_to_ndx << "\n" <<
433 "current metric = " << t_metric << "\n";
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 -> ";
444 t_metric += ((*t_in_buf++) * (*t_output_bit++));
445 #if DO_PRINT_DEBUG_UP
446 std::cout << t_metric << "\n";
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 -> ";
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";
462 // get the "to" state index
464 size_t t_to_ndx = t_connection->d_to_ndx;
466 // store the metric in the "to" state; should not have
469 t_to_state->d_max_metric = t_metric;
471 // add the "to" state index to the "up" state list
473 *t_next_state_ndx_ptr++ = t_to_ndx;
475 // update the traceback structure
477 update_traceback__up (t_state, t_to_state, q);
479 // next (for) input value
482 // next (for) "up_term" state
485 // increment the input buffer indices
487 increment_input_indices (false);
489 // increment the time counter
493 // change which up-term index to use
497 // increase the number of states to be used
499 t_n_up_down_ndx <<= d_n_code_inputs;
501 // change which d_states' index to use as starting
505 // next (while) input
508 // if reached the end of doing the "up" part of the trellis,
509 // switch states into the middle
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";
515 d_fsm = fsm_dec_doing_middle;
517 if (DO_PRINT_DEBUG_FSM) {
518 std::cout << "Exited fsm_dec_doing_up\n";
522 case (fsm_dec_doing_middle):
523 if (DO_PRINT_DEBUG_FSM) {
524 std::cout << "Entered fsm_dec_doing_middle\n";
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
531 while ((d_time_count < d_block_size_bits) &
532 (t_in_buf_ndx < t_ninput_items)) {
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
539 // reset the "to" state's metrics
541 reset_metrics (d_states_ndx ^ 1);
543 // get the state's index for each set of new inputs
545 state_t_ptr t_state = d_states[d_states_ndx];
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";
552 // loop over all current states
554 for (size_t n = 0; n < d_n_states; n++, t_state++) {
556 // loop over all possible input values, 1 bit per input stream
558 connection_t_ptr t_connection = t_state->d_connections;
560 if (DO_PRINT_DEBUG_MIDDLE_0) {
561 std::cout << "Looping over all 'middle' states: " <<
562 n << " of " << d_n_states << "\n";
565 for (size_t q = 0; q < d_n_input_combinations; q++, t_connection++) {
567 if (DO_PRINT_DEBUG_MIDDLE_0) {
568 std::cout << "Input = " << n2bs(q, d_n_code_inputs+1) << "\n";
571 // start with this state's metric
573 float t_metric = t_state->d_max_metric;
575 // get the "to" state
577 state_t_ptr t_to_state = t_connection->d_to;
579 // get that state's metric
581 float t_to_metric = t_to_state->d_max_metric;
583 // see if the computation is even needed;
584 // maximum change is d_n_code_outputs if all bits match exactly
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";
593 // metrics are close enough; do the computation and the
594 // compare get the output bits for this connection
596 float* t_output_bit = t_connection->d_output_bits;
597 if (d_do_mux_inputs == true) {
599 // if using mux'ed input streams, handle differently
601 const float* t_in_buf = &(in_buf[0][t_in_buf_ndx]);
603 // loop over all encoder-output values
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 -> ";
610 t_metric += ((*t_in_buf++) * (*t_output_bit++));
611 #if DO_PRINT_DEBUG_MIDDLE_0
612 std::cout << t_metric << "\n";
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 -> ";
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";
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 ";
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 ";
641 std::cout << "s[" << n2bs(n,t_state_print_bits) << "] i[" <<
642 n2bs (q, d_n_code_inputs+1) << "]@ " << t_metric << "\n";
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;
649 // next (for) input value
654 // done with all states and all inputs;
655 // update the traceback buffers
657 update_traceback__middle ();
659 // increment the input buffer indices
661 increment_input_indices ();
663 // increment the time counter
667 // check (while) staying in this fsm state or not
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";
675 d_fsm = fsm_dec_doing_term;
677 if (DO_PRINT_DEBUG_FSM) {
678 std::cout << "Exited fsm_dec_doing_middle\n";
682 case (fsm_dec_doing_term):
683 if (DO_PRINT_DEBUG_FSM) {
684 std::cout << "Entered fsm_dec_doing_term\n";
687 // set the "next" up_down index to the end of their states
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);
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
695 while ((t_time_count > 0) &
696 (t_in_buf_ndx < t_ninput_items)) {
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";
704 // FIXME: loop over just the "0" inputs
706 // use the "to" states, and compute the metric for each,
707 // compare & store it in the "to" state at the end of the
710 // reset the "to" state's metrics
712 reset_metrics (d_states_ndx ^ 1);
714 // reset the state's index for each set of new inputs
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];
719 // loop over all current stored "term" state indeces
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]);
725 // loop over just the all 0 input value (d_connections[0])
727 connection_t_ptr t_connection = t_state->d_connections;
729 // get the "to" state
731 state_t_ptr t_to_state = t_connection->d_to;
733 // start with this state's metric
735 float t_metric = t_state->d_max_metric;
737 // get that state's metric
739 float t_to_metric = t_to_state->d_max_metric;
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";
747 // see if the computation is even needed;
748 // maximum change is d_n_code_outputs if all bits match exactly
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";
757 // metrics are close enough; do the computation and the
758 // compare get the output bits for this connection
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++));
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++));
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 ";
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 ";
788 std::cout << "s[" << n2bs(t_state_ndx,t_state_print_bits) <<
789 "] i[" << n2bs (0, d_n_code_inputs+1) << "]@ " << t_metric << "\n";
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;
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
800 // update the traceback buffers
802 update_traceback__term ();
803 increment_input_indices (false);
805 // increment the time counters
810 // finished (while) staying in this fsm state or not
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";
820 d_fsm = fsm_dec_output;
822 if (DO_PRINT_DEBUG_FSM) {
823 std::cout << "Exited fsm_dec_doing_term\n";
827 case (fsm_dec_output):
828 if (DO_PRINT_DEBUG_FSM) {
829 std::cout << "Entered fsm_dec_output.\n";
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
837 // see where the output data will terminate
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++;
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";
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";
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";
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";
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;
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;
895 // get the correct out_buf reference to start with
896 t_out_buf = &(d_out_buf[d_time_count][t_max_state_ndx]);
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";
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";
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";
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;
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);
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";
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);
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;
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);
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";
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";
1001 d_fsm = fsm_dec_init;
1002 #if DO_PRINT_DEBUG_FSM
1003 std::cout << "Exited fsm_dec_output\n";
1006 case (fsm_dec_init):
1007 #if DO_PRINT_DEBUG_FSM
1008 std::cout << "Entered fsm_dec_init\n";
1010 // this is called immediately (first input bit upon startup),
1011 // or after termination of a trellis.
1013 // reset states to the 0'th one
1014 d_up_term_ndx = d_states_ndx = 0;
1015 // zero the metrics for those states
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);
1023 d_up_term_states_ndx[0][0] = 0;
1025 // reset time count back to the start
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;
1039 // set the fsm to "doing up"
1040 #if DO_PRINT_DEBUG_FSM
1041 std::cout << "Set FSM to fsm_dec_doing_up\n";
1043 d_fsm = fsm_dec_doing_up;
1044 #if DO_PRINT_DEBUG_FSM
1045 std::cout << "Exited fsm_dec_init\n";
1048 // should never get here!
1051 // done (switch) with FSM
1053 // done (while) there are inputs
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";
1069 consume_each (t_in_buf_ndx);
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) +
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";
1086 if (t_leftover_bits != 0) {
1087 // should never get here!
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);
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";
1112 #if DO_TIME_THOUGHPUT
1113 u_long d_t = end_timer (&t_tp);
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)) <<