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.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
56 #include <mld/mld_timer.h>
62 decoder_viterbi::decoder_viterbi
63 (int sample_precision,
64 encoder_convolutional* l_encoder)
66 // make sure the sample precitions makes sense
68 if ((sample_precision < 0) | (sample_precision > 32)) {
69 std::cerr << "decoder_viterbi: "
70 "Requested sample_precision (" << sample_precision <<
71 "must be between 0 and 32.\n";
75 // make sure that the encoder is "valid"
78 std::cerr << "decoder_viterbi: Error: Encoder is a NULL pointer.\n";
82 // keep around a pointer to the encoder
84 d_encoder = l_encoder;
86 // fill the class variables
88 d_block_size_bits = d_encoder->block_size_bits ();
89 d_do_streaming = (d_block_size_bits == 0);
90 d_n_code_inputs = d_encoder->n_code_inputs ();
91 d_n_code_outputs = d_encoder->n_code_outputs ();
92 d_do_termination = d_encoder->do_termination ();
94 d_total_memory = d_encoder->total_memory ();
97 // NOTE: d_n_states is a 'long', and thus is quite limited in terms
98 // of max memory and # of input streams to 2^32 states This is OK,
99 // since that many states would be impossibly slow to decode! might
100 // make this a "long long" (64 bits) in the future
102 d_n_states = 1 << d_total_memory;
103 d_n_input_combinations = 1 << d_n_code_inputs;
105 // really nothing else to do here, since this class doesn't "know"
106 // how to process streaming versus block decoding, or partial
107 // trellis versus full-trellis. Those will be handled by
108 // sub-classes which inherit from this one.
110 if (DO_PRINT_DEBUG_INST_0) {
111 std::cout << "Init:\n" <<
112 "d_block_size_bits = " << d_block_size_bits << "\n" <<
113 "d_n_code_inputs = " << d_n_code_inputs << "\n" <<
114 "d_n_code_outputs = " << d_n_code_outputs << "\n" <<
115 "d_do_streaming = " <<
116 ((d_do_streaming == true) ? "true" : "false") << "\n" <<
117 "d_do_termination = " <<
118 ((d_do_termination == true) ? "true" : "false") << "\n" <<
119 "d_total_memory = " << d_total_memory << "\n" <<
120 "d_n_states = " << d_n_states << "\n" <<
121 "d_n_input_combinations = " << d_n_input_combinations << "\n";
124 // always start the fsm in the "init" state
126 d_fsm_state = fsm_dec_viterbi_init;
128 // create a vector of indexes to states when doing "up" or "termination";
130 d_up_term_states_ndx[0] = new size_t [d_n_states];
131 d_up_term_states_ndx[1] = new size_t [d_n_states];
133 // get the total number of out bits per stream
135 d_n_total_inputs_per_stream = d_block_size_bits;
136 if (d_do_termination == true)
137 d_n_total_inputs_per_stream += d_max_memory;
143 decoder_viterbi::~decoder_viterbi
146 // reverse over from allocation
148 delete [] d_up_term_states_ndx[0];
149 delete [] d_up_term_states_ndx[1];
151 // delete the state's structures
153 state_t_ptr t_state = d_states[0];
154 for (size_t n = d_n_states; n > 0; n--, t_state++) {
155 connection_t_ptr t_connection = t_state->d_connections;
156 for (size_t m = d_n_input_combinations; m > 0; m--, t_connection++) {
157 delete [] t_connection->d_output_bits;
159 delete [] t_state->d_connections;
161 delete [] d_states[0];
163 t_state = d_states[1];
164 for (size_t n = d_n_states; n > 0; n--, t_state++) {
165 connection_t_ptr t_connection = t_state->d_connections;
166 for (size_t m = d_n_input_combinations; m > 0; m--, t_connection++) {
167 delete [] t_connection->d_output_bits;
169 delete [] t_state->d_connections;
171 delete [] d_states[1];
173 // delete the save buffer
175 char** t_save_buffer = d_save_buffer;
176 for (size_t n = 0; n < d_n_code_inputs; n++) {
177 delete [] (*t_save_buffer++);
179 delete [] d_save_buffer;
183 decoder_viterbi::reset_metrics
186 state_t_ptr t_state = d_states[which&1];
187 for (size_t n = d_n_states; n > 0; n--, t_state++) {
188 t_state->d_max_metric = -1e10;
190 // probably don't need to do these, try removing them later
191 t_state->d_max_state_ndx = 0;
192 t_state->d_max_input = -1;
198 decoder_viterbi::zero_metrics
201 state_t_ptr t_state = d_states[which&1];
202 for (size_t n = d_n_states; n > 0; n--, t_state++) {
203 t_state->d_max_metric = 0;
205 // probably don't need to do these, try removing them later
206 t_state->d_max_state_ndx = -1;
207 t_state->d_max_input = -1;
215 decoder_viterbi::get_next_input
216 (const char** in_buf,
223 decoder_viterbi::decode_private
224 (const char** in_buf,
229 #if DO_TIME_THOUGHPUT
234 size_t t_state_print_bits = d_total_memory + 1;
235 size_t t_mem_print_bits = d_max_memory + 2;
237 // setup variables for quicker access
238 const char **in_buf = (const char **) &input_items[0];
239 char **out_buf = (char **) &output_items[0];
240 int t_in_buf_ndx = 0, t_out_buf_ndx = 0;
241 int t_out_bit_shift = 0;
242 int t_ninput_items = compute_n_input_metrics (noutput_items);
243 int t_noutput_bits = noutput_items;
245 #if DO_PRINT_DEBUG_INST
246 std::cout << "# output items = " << noutput_items << " (" <<
247 t_noutput_bytes << " Bytes, " << (t_noutput_bytes * g_num_bits_per_byte) <<
248 " bits), # input items = " << t_ninput_items << " Symbols\n";
249 for (size_t n = 0; n < ninput_items.size(); n++) {
250 std::cout << "# input items [" << n << "] = " << ninput_items[n] << "\n";
254 // put any leftover bits into the output
255 if (d_n_saved_bits != 0) {
256 // copy the leftover from the save buffer
257 // check to make sure it will all fit
258 size_t t_noutput_bits = t_noutput_bytes * g_num_bits_per_byte;
260 if (t_noutput_bits < d_n_saved_bits) {
261 // asking for fewer bits than available; set to copy
262 // just what's being asked for
263 t_n_copy = t_noutput_bytes;
265 // asking for at least as many bits as available; set to copy all
266 t_out_buf_ndx = d_n_saved_bits / g_num_bits_per_byte;
267 t_out_bit_shift = d_n_saved_bits % g_num_bits_per_byte;
268 t_n_copy = t_out_buf_ndx + (t_out_bit_shift != 0 ? 1 : 0);
270 // do the copy for all output streams (code inputs)
271 // copy starting at save buffer index "start"
272 for (size_t n = 0; n < d_n_code_inputs; n++)
273 bcopy (&(d_save_buffer[n][d_n_saved_bits_start_ndx]),
274 out_buf[n], t_n_copy);
275 #if DO_PRINT_DEBUG_INST
276 std::cout << "Copied " << t_n_copy << " Byte" <<
277 (t_n_copy != 1 ? "s" : "") << ": s_b[][" <<
278 d_n_saved_bits_start_ndx << "] => o_b[][0]\n" <<
279 "# saved bits = " << d_n_saved_bits <<
280 ", o_b_ndx = " << t_out_buf_ndx <<
281 ", bit shift = " << t_out_bit_shift << "\n";
283 // update the number of saved bits and start
284 if (t_noutput_bits < d_n_saved_bits) {
285 // asking for fewer bit than available: update
286 // the number of saved bits and their starting index
287 d_n_saved_bits_start_ndx += t_noutput_bytes;
288 d_n_saved_bits -= (t_noutput_bytes * g_num_bits_per_byte);
289 #if DO_PRINT_DEBUG_INST
290 std::cout << "Updated # saved bits = " << d_n_saved_bits <<
291 ", index = " << d_n_saved_bits_start_ndx << "\n";
293 // nothing to consume; return the desired number of output items
294 return (noutput_items);
296 d_n_saved_bits_start_ndx = d_n_saved_bits = 0;
299 #if DO_PRINT_DEBUG_INST
300 std::cout << "Starting FSM in state: " <<
301 (d_fsm_state == fsm_dec_viterbi_init ? "init" :
302 (d_fsm_state == fsm_dec_viterbi_doing_up ? "up" :
303 (d_fsm_state == fsm_dec_viterbi_doing_middle ? "middle" :
304 (d_fsm_state == fsm_dec_viterbi_doing_term ? "term" :
305 (d_fsm_state == fsm_dec_viterbi_output ? "output" : "unknown"))))) << "\n";
308 // while there are input items to create
309 while (t_out_buf_ndx < t_noutput_bytes) {
310 #if DO_PRINT_DEBUG_FMS
311 std::cout << "Starting 'while': processing " << t_in_buf_ndx << " of " <<
312 t_ninput_items << " items.\nJumping to state '" <<
313 (d_fsm_state == fsm_dec_viterbi_init ? "init" :
314 (d_fsm_state == fsm_dec_viterbi_doing_up ? "up" :
315 (d_fsm_state == fsm_dec_viterbi_doing_middle ? "middle" :
316 (d_fsm_state == fsm_dec_viterbi_doing_term ? "term" :
317 (d_fsm_state == fsm_dec_viterbi_output ? "output" : "unknown"))))) << "'\n";
319 // jump to the correct state in the fsm
320 switch (d_fsm_state) {
321 case fsm_dec_viterbi_doing_up:
322 #if DO_PRINT_DEBUG_FSM
323 std::cout << "Starting fsm_dec_viterbi_doing_up\n";
325 // set the number of up_down indices
326 size_t t_n_up_down_ndx = 1 << (d_n_code_inputs *
328 // stay in this state until the correct number of input symbols are
329 // reached; exit also if we run out of input symbols to process
330 while ((d_time_count < d_max_memory) &
331 (t_in_buf_ndx < t_ninput_items)) {
332 #if DO_PRINT_DEBUG_UP_0
333 std::cout << "Doing 'while' loop:\n" <<
334 "t_n_up_down_ndx = " << t_n_up_down_ndx << "\n" <<
335 "d_time_count = " << d_time_count << "\n" <<
336 "d_max_memory = " << d_max_memory << "\n" <<
337 "t_in_buf_ndx = " << t_in_buf_ndx << "\n" <<
338 "t_ninput_items = " << t_ninput_items << "\n";
340 // use the "from" states, loop over all inputs and compute the metric for
341 // each & store it in the "to" state at the end of the connection.
342 // no need to compare metrics yet, since none join into any given state
345 // reset the "to" state's metrics
346 // probably don't need to do this; try removing later
347 reset_metrics (d_states_ndx ^ 1);
348 #if DO_PRINT_DEBUG_UP
349 std::cout << "Reset Metrics\n";
353 // reset the state's index for each set of new inputs
354 size_t* t_state_ndx_ptr = d_up_term_states_ndx[d_up_term_ndx];
355 size_t* t_next_state_ndx_ptr = d_up_term_states_ndx[d_up_term_ndx ^ 1];
356 // loop over all current stored "up" states
357 for (size_t n = 0; n < t_n_up_down_ndx; n++) {
358 size_t t_state_ndx = *t_state_ndx_ptr++;
359 // get a pointer to this state's structure
360 state_t_ptr t_state = &(d_states[d_states_ndx][t_state_ndx]);
361 // get the connections for all inputs
362 connection_t_ptr t_connection = t_state->d_connections;
363 #if DO_PRINT_DEBUG_UP_0
364 std::cout << "Looping over all 'up' states:\n" <<
365 "n = " << n << "\n" <<
366 "t_n_up_down_ndx = " << t_n_up_down_ndx << "\n" <<
367 "d_states_ndx = " << d_states_ndx << "\n" <<
368 "t_state_ndx = " << t_state_ndx << "\n" <<
369 "d_n_input_combs = " << d_n_input_combinations << "\n" <<
370 "t_state = " << t_state << "\n" <<
371 "t_connection = " << t_connection << "\n";
373 // loop over all possible input values, 1 bit per input stream
374 for (size_t q = 0; q < d_n_input_combinations; q++, t_connection++) {
375 // find the "to" state for this connection
376 state_t_ptr t_to_state = t_connection->d_to;
377 // get the output bits for this connection
378 float* t_output_bit = t_connection->d_output_bits;
379 // start with this state's metric
380 float t_metric = t_state->d_max_metric;
381 #if DO_PRINT_DEBUG_UP_0
383 "to state index = " << t_connection->d_to_ndx << "\n" <<
384 "current metric = " << t_metric << "\n";
386 if (d_do_mux_inputs == true) {
387 // if using mux'ed input streams, handle differently
388 const float* t_in_buf = &(in_buf[0][t_in_buf_ndx]);
389 // loop over all encoder-output values
390 for (size_t r = d_n_code_outputs; r > 0; r--) {
391 #if DO_PRINT_DEBUG_UP
392 std::cout << "in_sym = " << *t_in_buf << ", code_out_bit = " <<
393 *t_output_bit << " ==> metric -> ";
395 t_metric += ((*t_in_buf++) * (*t_output_bit++));
396 #if DO_PRINT_DEBUG_UP
397 std::cout << t_metric << "\n";
401 // loop over all encoder-output values
402 for (size_t r = 0; r < d_n_code_outputs; r++) {
403 #if DO_PRINT_DEBUG_UP
404 std::cout << "in_sym = " << in_buf[r][t_in_buf_ndx] <<
405 ", code_out_bit = " << *t_output_bit << " ==> metric -> ";
407 t_metric += (in_buf[r][t_in_buf_ndx] * (*t_output_bit++));
408 #if DO_PRINT_DEBUG_UP
409 std::cout << t_metric << "\n";
413 // get the "to" state index
414 size_t t_to_ndx = t_connection->d_to_ndx;
415 // store the metric in the "to" state; should not have been used before
416 t_to_state->d_max_metric = t_metric;
417 // add the "to" state index to the "up" state list
418 *t_next_state_ndx_ptr++ = t_to_ndx;
419 // update the traceback structure, depending on which variety it is
420 // doing full trellis before decoding; use d_out_buf
421 // simple: get the current state & output state
422 traceback_t_ptr t_out_buf = &(d_out_buf[d_time_count]
424 traceback_t_ptr t_next_out_buf = &(d_out_buf[d_time_count+1]
426 #if DO_PRINT_DEBUG_UP_1
427 std::cout << "d_o_b[" << d_time_count+1 << "] => d_o_b prev\n" <<
428 "ndx[" << n << "] == " << t_state_ndx <<
429 ", s[" << n2bs(t_state_ndx,t_state_print_bits) <<
431 n2bs(t_state->d_max_state_ndx,t_state_print_bits) <<
432 ", input = " << n2bs(q, d_n_code_inputs+1) <<
433 ": " << t_next_out_buf << " => " << t_out_buf << "\n";
435 // and connect output to the current, set inputs on output
436 t_next_out_buf->d_prev = t_out_buf;
437 t_next_out_buf->d_inputs = q;
438 // finished (for) this input value
440 // finished (for) this "up_term" state
442 // increment the in_buf index, depending on mux'ing or not
443 t_in_buf_ndx += (d_do_mux_inputs == false) ? 1 : d_n_code_outputs;
444 // increment the time counter
446 // update the number of "up_term" states
448 // increase the number of using states
449 t_n_up_down_ndx <<= d_n_code_inputs;
450 // change which d_states' index to use as starting
452 // finished (while) staying in this fsm state or not
454 // if reached the end of doing the "up" part of the trellis,
455 // switch states into the middle
456 if (d_time_count == d_max_memory) {
457 #if DO_PRINT_DEBUG_FSM
458 std::cout << "Setting FSM to fsm_dec_viterbi_doing_middle\n";
460 d_fsm_state = fsm_dec_viterbi_doing_middle;
462 #if DO_PRINT_DEBUG_FSM
463 std::cout << "Exited fsm_dec_viterbi_doing_up\n";
466 case (fsm_dec_viterbi_doing_middle):
467 #if DO_PRINT_DEBUG_FSM
468 std::cout << "Entered fsm_dec_viterbi_doing_middle\n";
470 // stay in this state until the correct number of input symbols is
471 // reached (if doing block coding), or until there are no more input
473 while (((d_block_size_bits != 0) &
474 (d_time_count < d_block_size_bits) &
475 (t_in_buf_ndx < t_ninput_items)) |
476 ((d_block_size_bits == 0) &
477 (t_in_buf_ndx < t_ninput_items))) {
478 // use all states, loop over all inputs, compute the metric for
479 // each; compare the current metric with all previous stored metric in the
480 // endpoint of the connection to find the highest one.
482 // reset the "to" state's metrics
483 reset_metrics (d_states_ndx ^ 1);
484 // get the state's index for each set of new inputs
485 state_t_ptr t_state = d_states[d_states_ndx];
486 #if DO_PRINT_DEBUG_MIDDLE
487 std::cout << "Time Count " << (d_time_count+1) << " of " <<
488 d_block_size_bits << "\n" <<
489 "d_states_ndx = " << d_states_ndx << "\n";;
491 // loop over all current states
492 for (size_t n = 0; n < d_n_states; n++, t_state++) {
493 // loop over all possible input values, 1 bit per input stream
494 connection_t_ptr t_connection = t_state->d_connections;
495 #if DO_PRINT_DEBUG_MIDDLE_0
496 std::cout << "Looping over all 'middle' states: " <<
497 n << " of " << d_n_states << "\n";
499 for (size_t q = 0; q < d_n_input_combinations; q++, t_connection++) {
500 #if DO_PRINT_DEBUG_MIDDLE_0
501 std::cout << "Input = " << n2bs(q, d_n_code_inputs+1) << "\n";
503 // start with this state's metric
504 float t_metric = t_state->d_max_metric;
505 // get the "to" state
506 state_t_ptr t_to_state = t_connection->d_to;
507 // get that state's metric
508 float t_to_metric = t_to_state->d_max_metric;
509 // see if the computation is even needed;
510 // maximum change is d_n_code_outputs if all bits match exactly
511 if ((t_to_metric - t_metric) > ((float) 2*d_n_code_outputs)) {
512 #if DO_PRINT_DEBUG_MIDDLE_0
513 std::cout << "!not computing metric!\n";
517 // metrics are close enough; do the computation and the compare
518 // get the output bits for this connection
519 float* t_output_bit = t_connection->d_output_bits;
520 if (d_do_mux_inputs == true) {
521 // if using mux'ed input streams, handle differently
522 const float* t_in_buf = &(in_buf[0][t_in_buf_ndx]);
523 // loop over all encoder-output values
524 for (size_t r = d_n_code_outputs; r > 0; r--) {
525 #if DO_PRINT_DEBUG_MIDDLE_0
526 std::cout << "in_sym = " << *t_in_buf << ", code_out_bit = " <<
527 *t_output_bit << " ==> metric -> ";
529 t_metric += ((*t_in_buf++) * (*t_output_bit++));
530 #if DO_PRINT_DEBUG_MIDDLE_0
531 std::cout << t_metric << "\n";
535 // loop over all encoder-output values
536 for (size_t r = 0; r < d_n_code_outputs; r++) {
537 #if DO_PRINT_DEBUG_MIDDLE_0
538 std::cout << "in_sym = " << in_buf[r][t_in_buf_ndx] <<
539 ", code_out_bit = " << *t_output_bit << " ==> metric -> ";
541 t_metric += (in_buf[r][t_in_buf_ndx] * (*t_output_bit++));
542 #if DO_PRINT_DEBUG_MIDDLE_0
543 std::cout << t_metric << "\n";
547 // done with this input value; compare old and new metrics
548 if (t_metric > t_to_metric) {
549 #if DO_PRINT_DEBUG_MIDDLE
550 std::cout << "New Metric to s[" <<
551 n2bs (t_connection->d_to_ndx,t_state_print_bits) << "]: ";
552 if (t_to_state->d_max_metric == -1e10) {
553 std::cout << "setting to ";
555 std::cout << "was s[" <<
556 n2bs(t_to_state->d_max_state_ndx,t_state_print_bits) <<
557 "]i[" << n2bs (t_to_state->d_max_input, d_n_code_inputs+1) <<
558 "]@ " << t_to_state->d_max_metric << " now ";
560 std::cout << "s[" << n2bs(n,t_state_print_bits) << "] i[" <<
561 n2bs (q, d_n_code_inputs+1) << "]@ " << t_metric << "\n";
563 // new metric is better; copy that info into the "to" state
564 t_to_state->d_max_metric = t_metric;
565 t_to_state->d_max_state_ndx = n;
566 t_to_state->d_max_input = q;
568 // finished (for) this input value
570 // finished (for) this state
572 // done with all states and all inputs; now update the traceback structure
573 // change which d_states' index to use as starting
575 // get the state's index for the "to" set of new inputs to get the
577 t_state = d_states[d_states_ndx];
578 // update the traceback structure
579 // loop over all current states
580 traceback_t_ptr t_prev_out_bufs = d_out_buf[d_time_count];
581 traceback_t_ptr t_out_bufs = d_out_buf[d_time_count+1];
582 #if DO_PRINT_DEBUG_MIDDLE_1
583 std::cout << "d_o_b[" << d_time_count+1 << "] => d_o_b prev\n";
585 for (size_t n = d_n_states; n > 0; n--, t_state++) {
586 // simple: get the current state & output state
587 // and connect output to the current, set inputs on output
588 traceback_t_ptr t_out_buf = t_out_bufs++;
589 traceback_t_ptr t_prev_out_buf =
590 &(t_prev_out_bufs[t_state->d_max_state_ndx]);
591 #if DO_PRINT_DEBUG_MIDDLE_1
592 std::cout << "s[" << n2bs(d_n_states-n,t_state_print_bits) <<
594 n2bs(t_state->d_max_state_ndx,t_state_print_bits) <<
595 ", input = " << n2bs(t_state->d_max_input, d_n_code_inputs+1) <<
596 ": " << t_out_buf << " => " << t_prev_out_buf << "\n";
598 t_out_buf->d_prev = t_prev_out_buf;
599 t_out_buf->d_inputs = t_state->d_max_input;
600 // finished doing this state
602 // increment the in_buf index, depending on mux'ing or not
603 t_in_buf_ndx += (d_do_mux_inputs == false) ? 1 : d_n_code_outputs;
604 // increment the time counter
606 // finished (while) staying in this fsm state or not
608 if ((d_block_size_bits != 0) &
609 (d_time_count == d_block_size_bits)) {
610 #if DO_PRINT_DEBUG_FSM
611 std::cout << "Setting FSM to fsm_dec_viterbi_doing_term\n";
613 d_fsm_state = fsm_dec_viterbi_doing_term;
616 #if DO_PRINT_DEBUG_FSM
617 std::cout << "Exited fsm_dec_viterbi_doing_middle\n";
619 case (fsm_dec_viterbi_doing_term):
620 #if DO_PRINT_DEBUG_FSM
621 std::cout << "Entered fsm_dec_viterbi_doing_term\n";
623 // set the "next" up_down index to the end of their states
624 size_t t_time_count = d_max_memory - (d_time_count - d_block_size_bits);
625 t_n_up_down_ndx = 1 << (d_n_code_inputs * t_time_count);
626 // stay in this state until the correct number of input symbols are
627 // reached; exit also if we run out of input symbols to process
628 while ((t_time_count > 0) &
629 (t_in_buf_ndx < t_ninput_items)) {
630 #if DO_PRINT_DEBUG_TERM
631 std::cout << "Doing time " << (d_max_memory - t_time_count + 1) <<
632 " of " << d_max_memory << "; starting buf[" << t_in_buf_ndx <<
633 "] of [" << t_ninput_items << "]\n";
635 // use the "to" states,
636 // FIXME: loop over just the "0" inputs
637 // and compute the metric for
638 // each, compare & store it in the "to" state at the end of the connection.
640 // reset the "to" state's metrics
641 reset_metrics (d_states_ndx ^ 1);
642 // reset the state's index for each set of new inputs
643 size_t* t_state_ndx_ptr = d_up_term_states_ndx[d_up_term_ndx];
644 size_t* t_next_state_ndx_ptr = d_up_term_states_ndx[d_up_term_ndx ^ 1];
645 // loop over all current stored "term" state indeces
646 for (size_t n = 0; n < t_n_up_down_ndx; n++) {
647 size_t t_state_ndx = *t_state_ndx_ptr++;
648 state_t_ptr t_state = &(d_states[d_states_ndx][t_state_ndx]);
649 // loop over just the all 0 input value (d_connections[0])
650 connection_t_ptr t_connection = t_state->d_connections;
651 // get the "to" state
652 state_t_ptr t_to_state = t_connection->d_to;
653 // start with this state's metric
654 float t_metric = t_state->d_max_metric;
655 // get that state's metric
656 float t_to_metric = t_to_state->d_max_metric;
657 #if DO_PRINT_DEBUG_TERM
658 std::cout << "Term state " << (n+1) << " of " << t_n_up_down_ndx <<
659 "; using d_s[" << d_states_ndx << "][" <<
660 n2bs(t_state_ndx,t_state_print_bits) << "]\n";
662 // see if the computation is even needed;
663 // maximum change is d_n_code_outputs if all bits match exactly
664 if ((t_to_metric - t_metric) > ((float) 2*d_n_code_outputs)) {
665 #if DO_PRINT_DEBUG_TERM
666 std::cout << "!not computing metric!\n";
670 // metrics are close enough; do the computation and the compare
671 // get the output bits for this connection
672 float* t_output_bit = t_connection->d_output_bits;
673 if (d_do_mux_inputs == true) {
674 // if using mux'ed input streams, handle differently
675 const float* t_in_buf = &(in_buf[0][t_in_buf_ndx]);
676 // loop over all encoder-output values
677 for (size_t r = d_n_code_outputs; r > 0; r--) {
678 t_metric += ((*t_in_buf++) * (*t_output_bit++));
681 // loop over all encoder-output values
682 for (size_t r = 0; r < d_n_code_outputs; r++) {
683 t_metric += (in_buf[r][t_in_buf_ndx] * (*t_output_bit++));
686 // done with this input value; compare old and new metrics
687 // see if it's the best metric
688 if (t_metric > t_to_metric) {
689 #if DO_PRINT_DEBUG_TERM
690 std::cout << "New Metric to s[" <<
691 n2bs (t_connection->d_to_ndx,t_state_print_bits) << "]: ";
692 if (t_to_state->d_max_metric == -1e10) {
693 std::cout << "setting to ";
695 std::cout << "was s[" <<
696 n2bs(t_to_state->d_max_state_ndx,t_state_print_bits) <<
697 "]i[" << n2bs (t_to_state->d_max_input, d_n_code_inputs+1) <<
698 "]@ " << t_to_state->d_max_metric << " now ";
700 std::cout << "s[" << n2bs(t_state_ndx,t_state_print_bits) <<
701 "] i[" << n2bs (0, d_n_code_inputs+1) << "]@ " << t_metric << "\n";
703 t_to_state->d_max_metric = t_metric;
704 t_to_state->d_max_state_ndx = t_state_ndx;
705 t_to_state->d_max_input = 0;
707 // add the "to" state's index to the "next" set of state's indices list
708 *t_next_state_ndx_ptr++ = t_connection->d_to_ndx;
709 // finished (for) this state
711 // done with all states and all inputs; now update the traceback structure
712 // change which d_states' index to use as starting
714 // update the number of "up_term" states
716 // reduce the number of using states
717 t_n_up_down_ndx >>= d_n_code_inputs;
718 // reset the state's index for each set of new inputs
719 t_state_ndx_ptr = d_up_term_states_ndx[d_up_term_ndx];
720 // update the traceback structure
721 // loop over all current states
722 traceback_t_ptr t_prev_out_bufs = d_out_buf[d_time_count];
723 traceback_t_ptr t_out_bufs = d_out_buf[d_time_count+1];
724 #if DO_PRINT_DEBUG_TERM_1
725 std::cout << "d_o_b[" << d_time_count+1 << "] => d_o_b prev\n";
727 // loop over all current stored "term" state indices
728 for (size_t n = 0; n < t_n_up_down_ndx; n++) {
729 // get the start index and then pointer to each of the "to" states,
730 // which hold the newest "max" stuff
731 size_t t_state_ndx = *t_state_ndx_ptr++;
732 state_t_ptr t_state = &(d_states[d_states_ndx][t_state_ndx]);
733 // simple: get the current state & output state
734 // and connect output to the current, set inputs on output
735 traceback_t_ptr t_out_buf = &(t_out_bufs[t_state_ndx]);
736 traceback_t_ptr t_prev_out_buf =
737 &(t_prev_out_bufs[t_state->d_max_state_ndx]);
738 #if DO_PRINT_DEBUG_TERM_1
739 std::cout << "ndx[" << n << "] == " << t_state_ndx <<
740 ", s[" << n2bs(t_state_ndx,t_state_print_bits) <<
742 n2bs(t_state->d_max_state_ndx,t_state_print_bits) <<
743 ", input = " << n2bs(t_state->d_max_input, d_n_code_inputs+1) <<
744 ": " << t_out_buf << " => " << t_prev_out_buf << "\n";
746 t_out_buf->d_prev = t_prev_out_buf;
747 t_out_buf->d_inputs = t_state->d_max_input;
748 // finished (for) this state
750 // increment the in_buf index, depending on mux'ing or not
751 t_in_buf_ndx += (d_do_mux_inputs == false) ? 1 : d_n_code_outputs;
752 // increment the time counters
755 // finished (while) staying in this fsm state or not
757 if (t_time_count == 0) {
758 // finished this trellis, now move as much of the decoded input to the
759 // output buffer as possible
760 #if DO_PRINT_DEBUG_FSM
761 std::cout << "Setting FSM to fsm_dec_viterbi_output\n";
763 d_fsm_state = fsm_dec_viterbi_output;
765 #if DO_PRINT_DEBUG_FSM
766 std::cout << "Exited fsm_dec_viterbi_doing_term\n";
769 case (fsm_dec_viterbi_output):
770 #if DO_PRINT_DEBUG_FSM
771 std::cout << "Entered fsm_dec_viterbi_output.\n";
773 // this is done in reverse bit order (last time to first time)
774 // using the traceback structure in d_out_buf, starting with
775 // the maximum valued one in the last time slot, then using
776 // the traceback's "d_prev" link to trace the trellis back
778 // see where the output data will terminate
779 int t_next_out_buf_ndx = (t_out_buf_ndx +
780 (d_block_size_bits / g_num_bits_per_byte));
781 int t_next_out_bit_shift = (t_out_bit_shift +
782 (d_block_size_bits % g_num_bits_per_byte));
783 if (t_next_out_bit_shift >= g_num_bits_per_byte) {
784 t_next_out_bit_shift -= g_num_bits_per_byte;
785 t_next_out_buf_ndx++;
787 #if DO_PRINT_DEBUG_OUTPUT
788 std::cout << "First bit in at out[][" << t_out_buf_ndx << "].[" <<
789 t_out_bit_shift << "] -> " << d_block_size_bits << " bits == " <<
790 (d_block_size_bits / g_num_bits_per_byte) << " Byte" <<
791 ((d_block_size_bits / g_num_bits_per_byte) != 1 ? "s" : "") <<
792 " + " << (d_block_size_bits % g_num_bits_per_byte) << " bit" <<
793 ((d_block_size_bits % g_num_bits_per_byte) != 1 ? "s" : "") <<
794 "\nNext set of bits start at out[][" << t_next_out_buf_ndx <<
795 "].[" << t_next_out_bit_shift << "]\n";
797 // find the starting traceback structure
798 traceback_t_ptr t_out_buf;
799 if (d_do_termination == true) {
800 // FIXME: assume termination state == 0
801 #if DO_PRINT_DEBUG_OUTPUT_0
802 std::cout << "Using termination; going through trellis for " <<
803 d_max_memory << " bit" <<
804 ((d_max_memory != 1) ? "s" : "") << "\n";
806 t_out_buf = &(d_out_buf[d_time_count][0]);
807 #if DO_PRINT_DEBUG_OUTPUT_0
808 std::cout << "Starting traceback ptr " << t_out_buf << "\n";
810 // skip over the termination bits
811 for (size_t n = d_max_memory; n > 0; n--) {
812 t_out_buf = t_out_buf->d_prev;
813 #if DO_PRINT_DEBUG_OUTPUT_0
814 std::cout << "Next traceback ptr " << t_out_buf << "\n";
818 // no termination but doing block coding;
819 // FIXME: use the state with the bext metric
820 // get the state's index for each set of new inputs
821 state_t_ptr t_state = d_states[d_states_ndx];
822 float t_max_metric = t_state->d_max_metric;
823 size_t t_max_state_ndx = 0;
825 // loop over all current states
826 for (size_t n = 1; n < d_n_states; n++, t_state++) {
827 // start with this state's metric
828 float t_metric = t_state->d_max_metric;
829 // compare with current max
830 if (t_metric > t_max_metric) {
831 t_max_metric = t_metric;
835 // get the correct out_buf reference to start with
836 t_out_buf = &(d_out_buf[d_time_count][t_max_state_ndx]);
838 #if DO_PRINT_DEBUG_OUTPUT
839 std::cout << "Found starting traceback ptr " << t_out_buf <<
840 "; getting all " << d_block_size_bits << " bits per stream.\n";
842 // now we've got the starting traceback structure address;
843 // check to make sure there is enough space in each output buffer
844 size_t t_block_bit_ndx = d_block_size_bits;
845 if ((t_next_out_buf_ndx > t_noutput_bytes) |
846 ((t_next_out_buf_ndx == t_noutput_bytes) &
847 (t_next_out_bit_shift != 0))) {
848 // not enough space for all output bits;
849 // find the number of extra bits to save
850 size_t t_save_buf_ndx = t_next_out_buf_ndx - t_noutput_bytes;
851 size_t t_n_extra_bits = ((t_save_buf_ndx * g_num_bits_per_byte) +
852 t_next_out_bit_shift);
853 // set the number of saved bits
854 d_n_saved_bits = t_n_extra_bits;
855 // remove the extra bits from the number to copy to the output buffer
856 t_block_bit_ndx -= t_n_extra_bits;
857 // find the actual output buf index, once we get there
858 t_next_out_buf_ndx -= t_save_buf_ndx;
859 #if DO_PRINT_DEBUG_OUTPUT
860 std::cout << "Not enough output buffer space:\n" <<
861 "len (o_b) = " << t_noutput_bytes << " ==> " <<
862 t_n_extra_bits << " extra bit" <<
863 (t_n_extra_bits != 1 ? "s" : "") << " == " <<
864 t_save_buf_ndx << " Byte" <<
865 (t_save_buf_ndx != 1 ? "s" : "") << ", " <<
866 t_next_out_bit_shift << " bit" <<
867 (t_next_out_bit_shift != 1 ? "s" : "") << "\n";
869 // zero each output buffers' bytes
870 size_t t_n_zero = t_save_buf_ndx + (t_next_out_bit_shift ? 1 : 0);
871 #if DO_PRINT_DEBUG_OUTPUT
872 size_t t_n_out_bytes = ((d_block_size_bits / g_num_bits_per_byte) +
873 ((d_block_size_bits % g_num_bits_per_byte) ? 1 : 0));
874 std::cout << "Zeroing save buffer from for " << t_n_zero <<
875 " Byte" << (t_n_zero != 1 ? "s" : "") << " (of " <<
876 d_block_size_bits << " bit" <<
877 (d_block_size_bits != 1 ? "s" : "") << " == " << t_n_out_bytes <<
878 " Byte" << (t_n_out_bytes != 1 ? "s" : "") << ")\n";
880 for (size_t m = 0; m < d_n_code_inputs; m++)
881 bzero (d_save_buffer[m], t_n_zero);
882 // loop over all extra bits
883 for (size_t n = t_n_extra_bits; n > 0; n--) {
884 // first decrement the output bit & byte as necessary
885 if (--t_next_out_bit_shift < 0) {
886 t_next_out_bit_shift += g_num_bits_per_byte;
889 // get the encoder inputs to output
890 size_t t_inputs = t_out_buf->d_inputs;
891 // loop over all code inputs (decoder-outputs), 1 bit per stream
892 for (size_t m = 0; m < d_n_code_inputs; m++) {
893 d_save_buffer[m][t_save_buf_ndx] |=
894 ((t_inputs & 1) << t_next_out_bit_shift);
897 t_out_buf = t_out_buf->d_prev;
898 #if DO_PRINT_DEBUG_OUTPUT_0
899 std::cout << "Next traceback ptr " << t_out_buf << "\n";
902 // at exit, "t_out_buf_ndx" should be == t_noutput_bytes, and
903 // "t_out_bit_shift" should be 0; check these!
904 #if DO_PRINT_DEBUG_OUTPUT
905 std::cout << "n_o_b_ndx (" << t_next_out_buf_ndx << ") ?=? " <<
906 "#o_B (" << t_noutput_bytes << ") & t_o_b_sh (" <<
907 t_next_out_bit_shift << ") ?=? 0\n";
908 assert (t_next_out_buf_ndx == t_noutput_bytes);
909 assert (t_next_out_bit_shift == 0);
912 // set the correct output buffer index and bit shift
913 t_out_bit_shift = t_next_out_bit_shift;
914 t_out_buf_ndx = t_next_out_buf_ndx;
915 // copy any remaining bits looping backwards in bit-time
916 // through the traceback trellis
917 for (size_t n = t_block_bit_ndx; n > 0; n--) {
918 // first decrement the output bit & byte as necessary
919 if (--t_out_bit_shift < 0) {
920 t_out_bit_shift += g_num_bits_per_byte;
923 // get the encoder inputs to output
924 size_t t_inputs = t_out_buf->d_inputs;
925 // loop over all code inputs (decoder-outputs), 1 bit per stream
926 for (size_t m = 0; m < d_n_code_inputs; m++) {
927 out_buf[m][t_out_buf_ndx] |= ((t_inputs & 1) << t_out_bit_shift);
930 t_out_buf = t_out_buf->d_prev;
931 #if DO_PRINT_DEBUG_OUTPUT_0
932 std::cout << "Next traceback ptr " << t_out_buf << "\n";
935 // set the next output byte and bit-shift
936 t_out_bit_shift = t_next_out_bit_shift;
937 t_out_buf_ndx = t_next_out_buf_ndx;
938 #if DO_PRINT_DEBUG_FSM
939 std::cout << "Set FSM to fsm_dec_viterbi_init\n";
941 d_fsm_state = fsm_dec_viterbi_init;
942 #if DO_PRINT_DEBUG_FSM
943 std::cout << "Exited fsm_dec_viterbi_output\n";
946 case (fsm_dec_viterbi_init):
947 #if DO_PRINT_DEBUG_FSM
948 std::cout << "Entered fsm_dec_viterbi_init\n";
950 // this is called immediately (first input bit upon startup),
951 // or after termination of a trellis.
953 // reset states to the 0'th one
954 d_up_term_ndx = d_states_ndx = 0;
955 // zero the metrics for those states
958 // might not need to do this; check and see after it works
959 // reset up_term states and number so that there is 1 item, the "0" state.
960 bzero (d_up_term_states_ndx[0], sizeof (size_t) * d_n_states);
961 bzero (d_up_term_states_ndx[1], sizeof (size_t) * d_n_states);
963 d_up_term_states_ndx[0][0] = 0;
965 // reset time count back to the start
968 // reset the traceback structures
969 // might not need to do this; check and see after it works
970 traceback_t_hdl t_out_bufs = d_out_buf;
971 for (size_t n = d_n_traceback_els; n > 0; n--) {
972 traceback_t_ptr t_out_buf = (*t_out_bufs++);
973 for (size_t m = d_n_states; m > 0; m--, t_out_buf++) {
974 t_out_buf->d_prev = NULL;
975 t_out_buf->d_inputs = -1;
979 // set the fsm to "doing up"
980 #if DO_PRINT_DEBUG_FSM
981 std::cout << "Set FSM to fsm_dec_viterbi_doing_up\n";
983 d_fsm_state = fsm_dec_viterbi_doing_up;
984 #if DO_PRINT_DEBUG_FSM
985 std::cout << "Exited fsm_dec_viterbi_init\n";
988 // should never get here!
991 // done (switch) with FSM
993 // done (while) there are inputs
996 // consume all of the input items on all input streams
997 // "ninput_items[]" doesn't seem to be reliable,
998 // so compute this from the actual number of blocks processed
999 #if DO_PRINT_DEBUG_EXIT
1000 std::cout << "Exiting FSM in state: " <<
1001 (d_fsm_state == fsm_dec_viterbi_init ? "init" :
1002 (d_fsm_state == fsm_dec_viterbi_doing_up ? "up" :
1003 (d_fsm_state == fsm_dec_viterbi_doing_middle ? "middle" :
1004 (d_fsm_state == fsm_dec_viterbi_doing_term ? "term" :
1005 (d_fsm_state == fsm_dec_viterbi_output ? "output" : "unknown"))))) << "\n" <<
1006 "Consuming " << t_in_buf_ndx <<
1007 " input items on each input stream (of " << t_ninput_items << ").\n";
1009 consume_each (t_in_buf_ndx);
1011 // make sure the number of output items makes sense
1012 // t_out_buf_ndx always points to the current index
1013 // t_out_bit_shift always points to the next bit position to be written
1014 int t_leftover_bytes = t_out_buf_ndx % d_out_stream_el_size_bytes;
1015 int t_leftover_bits = ((t_leftover_bytes * g_num_bits_per_byte) +
1017 int t_noutput_items = noutput_items;
1018 #if DO_PRINT_DEBUG_EXIT
1019 std::cout << "Final o_b[" << t_out_buf_ndx << "][" <<
1020 t_out_bit_shift << "] of " << t_noutput_bytes <<
1021 ", el_size = " << d_out_stream_el_size_bytes <<
1022 ", lo_Bytes = " << t_leftover_bytes <<
1023 ", t_lo_bits = " << t_leftover_bits << "\n" <<
1024 "Desired # output items = " << noutput_items << "\n";
1026 if (t_leftover_bits != 0) {
1027 // should never get here!
1031 int t_ndx = t_out_buf_ndx - t_leftover_bytes;
1032 size_t t_n_copy = t_leftover_bytes + ((t_out_bit_shift != 0) ? 1 : 0);
1033 assert (t_n_copy <= d_out_stream_el_size_bytes);
1034 // copy the leftover into the save buffer
1035 for (size_t n = 0; n < d_n_code_inputs; n++) {
1036 bcopy (&(out_buf[n][t_ndx]), d_save_buffer[n], t_n_copy);
1038 t_noutput_items = t_ndx / d_out_stream_el_size_bytes;
1039 d_n_saved_bits = t_leftover_bits;
1040 #if DO_PRINT_DEBUG_EXIT
1041 std::cout << "Copied " << t_n_copy << " Byte" <<
1042 (t_n_copy != 1 ? "s" : "") << " from o_b[][" << t_ndx <<
1043 "] into each save buffer.\n" <<
1044 "Actual #output items = " << t_noutput_items <<
1045 ", # saved bit(s) = " << d_n_saved_bits << "\n";
1052 #if DO_TIME_THOUGHPUT
1053 u_long d_t = end_timer (&t_tp);
1055 std::cout << "dec_blk_conv_soft_full: Completed " << t_ninput_items <<
1056 " bits in " << d_t << " usec => " <<
1057 1e6*(((double)(t_ninput_items))/((double) d_t)) <<